@@ -30,7 +30,7 @@ else | |||
fi | |||
echo "running format validation..." | |||
./validate_format.rb $FORMAT_FILE | |||
./validate_format.py $FORMAT_FILE | |||
if [[ $? != 0 ]]; then | |||
echo "format validation failed!" | |||
exit 1 | |||
@@ -0,0 +1,111 @@ | |||
#!/usr/bin/env python3 | |||
import json | |||
import string | |||
import sys | |||
anchor = '###' | |||
auth_keys = ['apiKey', 'OAuth', 'X-Mashape-Key', 'No'] | |||
punctuation = ['.', '?', '!'] | |||
https_keys = ['Yes', 'No'] | |||
index_title = 0 | |||
index_desc = 1 | |||
index_auth = 2 | |||
index_https = 3 | |||
index_link = 4 | |||
errors = [] | |||
def add_error(line_num, message): | |||
"""adds an error to the dynamic error list""" | |||
err = '(L{:03d}) {}'.format(line_num+1, message) | |||
errors.append(err) | |||
def check_format(filename): | |||
""" | |||
validates that each line is formatted correctly, | |||
appending to error list as needed | |||
""" | |||
with open(filename) as fp: | |||
lines = list(line.rstrip() for line in fp) | |||
# START Alphabetical Order | |||
category = "" | |||
sections = {} | |||
section_line_num = {} | |||
for line_num, line in enumerate(lines): | |||
if line.startswith(anchor): | |||
category = line.split(anchor)[1].strip() | |||
sections[category] = [] | |||
section_line_num[category] = line_num | |||
continue | |||
if not line.startswith('|') or line.startswith('|---'): | |||
continue | |||
title = [x.strip() for x in line.split('|')[1:-1]][0].upper() | |||
sections[category].append(title) | |||
for category, entries in sections.items(): | |||
if sorted(entries) != entries: | |||
add_error(section_line_num[category], '{} section is not in alphabetical order'.format(category)) | |||
# END Alphabetical Order | |||
# START Check Entries | |||
for line_num, line in enumerate(lines): | |||
if not line.startswith('|') or line.startswith('|---'): | |||
continue | |||
segments = line.split('|')[1:-1] | |||
# START Global | |||
for segment in segments: | |||
# every line segment should start and end with exactly 1 space | |||
if len(segment) - len(segment.lstrip()) != 1 or len(segment) - len(segment.rstrip()) != 1: | |||
add_error(line_num, "each segment must start and end with exactly 1 space") | |||
# END Global | |||
segments = [seg.strip() for seg in segments] | |||
# START Description | |||
# first character should be capitalized | |||
char = segments[index_desc][0] | |||
if char.upper() != char: | |||
add_error(line_num, "first char of Description is not capitalized") | |||
# last character should not punctuation | |||
char = segments[index_desc][-1] | |||
if char in punctuation: | |||
add_error(line_num, "description should not end with {}".format(char)) | |||
# END Description | |||
# START Auth | |||
# values should conform to valid options only | |||
auth = segments[index_auth].replace('`', '') | |||
if auth not in auth_keys: | |||
add_error(line_num, "{} is not a valid Auth option".format(auth)) | |||
# END Auth | |||
# START HTTPS | |||
# values should conform to valid options only | |||
https = segments[index_https] | |||
if https not in https_keys: | |||
add_error(line_num, "{} is not a valid HTTPS option".format(https)) | |||
# END HTTPS | |||
# START Link | |||
# url should be wrapped in '[Go!]()' Markdown syntax | |||
link = segments[index_link] | |||
if not link.startswith('[Go!](') or not link.endswith(')'): | |||
add_error(line_num, 'link format should be "[Go!](LINK)"') | |||
# END Link | |||
# END Check Entries | |||
def main(): | |||
num_args = len(sys.argv) | |||
if num_args < 2: | |||
print("No .md file passed") | |||
sys.exit(1) | |||
check_format(sys.argv[1]) | |||
if len(errors) > 0: | |||
for err in errors: | |||
print(err) | |||
sys.exit(1) | |||
if __name__ == "__main__": | |||
main() |
@@ -1,111 +0,0 @@ | |||
#!/usr/bin/env ruby | |||
auth_keys = ['apiKey', 'OAuth', 'X-Mashape-Key', 'No'] | |||
punctuation = ['.', '?', '!'] | |||
https_keys = ['Yes', 'No'] | |||
INDEX_TITLE = 1 | |||
INDEX_DESCRIPTION = 2 | |||
INDEX_AUTH = 3 | |||
INDEX_HTTPS = 4 | |||
INDEX_LINK = 5 | |||
filename = ARGV[0] | |||
$errors = [] | |||
def add_error(line_num, val_index, message) | |||
case val_index | |||
when INDEX_TITLE | |||
segment = "Title" | |||
when INDEX_DESCRIPTION | |||
segment = "Description" | |||
when INDEX_AUTH | |||
segment = "Auth" | |||
when INDEX_HTTPS | |||
segment = "HTTPS" | |||
when INDEX_LINK | |||
segment = "Link" | |||
end | |||
$errors.push("(L%03d) %-14.14s #{message}" % [line_num, segment]) | |||
end | |||
################### CHECK ALPHABETICAL ORDER ################### | |||
section = '' | |||
sections = [] | |||
section_to_line_num = {} | |||
section_to_entries = Hash.new {|h,k| h[k] = Array.new } | |||
File.foreach(filename).with_index do | line, line_num | | |||
if line.start_with?('###') | |||
section = line.sub('###', '').lstrip.chop | |||
sections.push(section) | |||
section_to_line_num[section] = line_num + 1 | |||
end | |||
# Skip non-markdown table lines and table schema lines | |||
if !line.start_with?('|') || line.eql?("|---|---|---|---|---|\n") | |||
next | |||
end | |||
# char to check is the first column | |||
check_char = line.split("|")[1].strip.upcase | |||
section_to_entries[section].push(check_char) | |||
end | |||
sections.each do | sect | | |||
if section_to_entries[sect] != section_to_entries[sect].sort | |||
add_error(section_to_line_num[sect], INDEX_TITLE, "#{sect} section is not in alphabetical order") | |||
end | |||
end | |||
#################### CHECK LINE ENTRIES ######################## | |||
File.foreach(filename).with_index do | line, line_num | | |||
line_num += 1 | |||
# Skip non-markdown table lines and table schema lines | |||
if !line.start_with?('|') || line.eql?("|---|---|---|---|---|\n") | |||
next | |||
end | |||
values = line.split("|") | |||
################### GLOBAL ################### | |||
values.each.with_index do |val, val_index| | |||
msg = "" | |||
case val_index | |||
when INDEX_TITLE..INDEX_LINK | |||
# every line segment should start and end with exactly 1 space | |||
if val[/\A */].size != 1 || val[/ *\z/].size != 1 | |||
add_error(line_num, val_index, "string should start and end with exactly 1 space") | |||
end | |||
end | |||
end | |||
################# DESCRIPTION ################ | |||
# First character should be capitalized | |||
desc_val = values[INDEX_DESCRIPTION].lstrip.chop | |||
if !/[[:upper:]]/.match(desc_val[0]) | |||
add_error(line_num, INDEX_DESCRIPTION, "first char not uppercase") | |||
end | |||
# value should not be punctuated | |||
last_char = desc_val[desc_val.length-1] | |||
if punctuation.include?(last_char) | |||
add_error(line_num, INDEX_DESCRIPTION, "description should not end with \"#{last_char}\"") | |||
end | |||
#################### AUTH #################### | |||
# Values should conform to valid options only | |||
auth_val = values[INDEX_AUTH].lstrip.chop.tr('``', '') | |||
if !auth_keys.include?(auth_val) | |||
add_error(line_num, INDEX_AUTH, "not a valid option: #{auth_val}") | |||
end | |||
#################### HTTPS ################### | |||
# Values should be either "Yes" or "No" | |||
https_val = values[INDEX_HTTPS].lstrip.chop | |||
if !https_keys.include?(https_val) | |||
add_error(line_num, INDEX_HTTPS, "must use \"Yes\" or \"No\": #{https_val}") | |||
end | |||
#################### LINK #################### | |||
# Url should be wrapped in "[Go!]" view | |||
link_val = values[INDEX_LINK].lstrip.chop | |||
if !link_val.start_with?("[Go!](") || !link_val.end_with?(')') | |||
add_error(line_num, INDEX_LINK, "format should be \"[Go!](<LINK>)\": #{link_val}") | |||
end | |||
end | |||
$errors.each do | e | | |||
puts e | |||
end | |||
exit($errors.length) |