選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

validate_format.py 4.8 KiB

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