You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

142 lines
4.8 KiB

  1. #!/usr/bin/env python3
  2. import json
  3. import re
  4. import string
  5. import sys
  6. anchor = '###'
  7. min_entries_per_section = 3
  8. auth_keys = ['apiKey', 'OAuth', 'X-Mashape-Key', 'No']
  9. punctuation = ['.', '?', '!']
  10. https_keys = ['Yes', 'No']
  11. cors_keys = ['Yes', 'No', 'Unknown']
  12. index_title = 0
  13. index_desc = 1
  14. index_auth = 2
  15. index_https = 3
  16. index_cors = 4
  17. index_link = 5
  18. errors = []
  19. def add_error(line_num, message):
  20. """adds an error to the dynamic error list"""
  21. err = '(L{:03d}) {}'.format(line_num+1, message)
  22. errors.append(err)
  23. def check_format(filename):
  24. """
  25. validates that each line is formatted correctly,
  26. appending to error list as needed
  27. """
  28. with open(filename) as fp:
  29. lines = list(line.rstrip() for line in fp)
  30. # START Alphabetical Order
  31. category = ""
  32. sections = {}
  33. section_line_num = {}
  34. for line_num, line in enumerate(lines):
  35. if line.startswith(anchor):
  36. category = line.split(anchor)[1].strip()
  37. sections[category] = []
  38. section_line_num[category] = line_num
  39. continue
  40. if not line.startswith('|') or line.startswith('|---'):
  41. continue
  42. title = [x.strip() for x in line.split('|')[1:-1]][0].upper()
  43. sections[category].append(title)
  44. for category, entries in sections.items():
  45. if sorted(entries) != entries:
  46. add_error(section_line_num[category], "{} section is not in alphabetical order".format(category))
  47. # END Alphabetical Order
  48. # START Check Entries
  49. num_in_category = min_entries_per_section + 1
  50. category_line = 0
  51. anchor_re = re.compile('###\s\S+')
  52. for line_num, line in enumerate(lines):
  53. # check each section for the minimum number of entries
  54. if line.startswith(anchor):
  55. if not anchor_re.match(line):
  56. add_error(line_num, "section header is not formatted correctly")
  57. if num_in_category < min_entries_per_section:
  58. add_error(category_line, "{} section does not have the minimum {} entries (only has {})".format(
  59. category, min_entries_per_section, num_in_category))
  60. category = line.split(' ')[1]
  61. category_line = line_num
  62. num_in_category = 0
  63. continue
  64. if not line.startswith('|') or line.startswith('|---'):
  65. continue
  66. num_in_category += 1
  67. segments = line.split('|')[1:-1]
  68. # START Global
  69. for segment in segments:
  70. # every line segment should start and end with exactly 1 space
  71. if len(segment) - len(segment.lstrip()) != 1 or len(segment) - len(segment.rstrip()) != 1:
  72. add_error(line_num, "each segment must start and end with exactly 1 space")
  73. # END Global
  74. segments = [seg.strip() for seg in segments]
  75. # START Title
  76. title = segments[index_title].upper()
  77. if title.endswith(' API'):
  78. add_error(line_num, 'Title should not contain "API"')
  79. # END Title
  80. # START Description
  81. # first character should be capitalized
  82. char = segments[index_desc][0]
  83. if char.upper() != char:
  84. add_error(line_num, "first character of description is not capitalized")
  85. # last character should not punctuation
  86. char = segments[index_desc][-1]
  87. if char in punctuation:
  88. add_error(line_num, "description should not end with {}".format(char))
  89. # END Description
  90. # START Auth
  91. # values should conform to valid options only
  92. auth = segments[index_auth].replace('`', '')
  93. if auth not in auth_keys:
  94. add_error(line_num, "{} is not a valid Auth option".format(auth))
  95. # END Auth
  96. # START HTTPS
  97. # values should conform to valid options only
  98. https = segments[index_https]
  99. if https not in https_keys:
  100. add_error(line_num, "{} is not a valid HTTPS option".format(https))
  101. # END HTTPS
  102. # START CORS
  103. # values should conform to valid options only
  104. cors = segments[index_cors]
  105. if cors not in cors_keys:
  106. add_error(line_num, "{} is not a valid CORS option".format(cors))
  107. # END CORS
  108. # START Link
  109. # url should be wrapped in '[Go!]()' Markdown syntax
  110. link = segments[index_link]
  111. if not link.startswith('[Go!](http') or not link.endswith(')'):
  112. add_error(line_num, 'link syntax should be "[Go!](LINK)"')
  113. # END Link
  114. # END Check Entries
  115. def main():
  116. num_args = len(sys.argv)
  117. if num_args < 2:
  118. print("No file passed (file should contain Markdown table syntax)")
  119. sys.exit(1)
  120. check_format(sys.argv[1])
  121. if len(errors) > 0:
  122. for err in errors:
  123. print(err)
  124. sys.exit(1)
  125. if __name__ == "__main__":
  126. main()