from pathlib import Path import re import sys errors = [] def find_all(a_str, sub): for i, line in enumerate(a_str.splitlines()): column = 0 while True: column = line.find(sub, column) if column == -1: break yield i, column column += len(sub) section_regex = re.compile(r"^(=+|-+|\*+|~+)$") directive_regex = re.compile(r"^(\s*)\.\. (.*)::.*$") directive_arg_regex = re.compile(r"^(\s+):.*:\s*.*$") esphome_io_regex = re.compile(r"https://esphome.io/") for f in sorted(Path(".").glob("**/*.rst")): try: content = f.read_text("utf-8") except UnicodeDecodeError: errors.append( "File {} is not readable as UTF-8. Please set your editor to UTF-8 mode." "".format(f) ) continue if not content.endswith("\n"): errors.append( "Newline at end of file missing. Please insert an empty line at end " "of file {}".format(f) ) # Check tab character for line, col in find_all(content, "\t"): errors.append( "File {} contains tab character on line {}:{}. " "Please convert tabs to spaces.".format(f, line + 1, col) ) # Check windows newline for line, col in find_all(content, "\r"): errors.append( "File {} contains windows newline on line {}:{}. " "Please set your editor to unix newline mode.".format(f, line + 1, col) ) lines = content.splitlines(keepends=False) # for i, line in enumerate(lines): # if i == 0: # continue # # if not section_regex.match(line): # continue # line_above = lines[i - 1] # if len(line_above) != len(line): # errors.append("The title length must match the bar length below it. See {}:{}" # "".format(f, i+1)) # if i + 1 < len(lines) and lines[i + 1]: # errors.append("Empty line after heading is missing. Please insert an " # "empty line. See {}:{}".format(f, i+1)) for i, line in enumerate(lines): m = directive_regex.match(line) if m is None: continue base_indentation = len(m.group(1)) directive_name = m.group(2) if directive_name.startswith("|") or directive_name == "seo": continue # Match directive args for j in range(i + 1, len(lines)): if not directive_arg_regex.match(lines[j]): break else: # Reached end of file continue # Empty line must follow if lines[j]: errors.append( "Directive '{}' is not followed by an empty line. Please insert an " "empty line after {}:{}".format(directive_name, f, j) ) continue k = j + 1 for j in range(k, len(lines)): if not lines[j]: # Ignore Empty lines continue num_spaces = len(lines[j]) - len(lines[j].lstrip()) if num_spaces <= base_indentation: # Finished with this directive break num_indent = num_spaces - base_indentation if j == k and num_indent != 4: errors.append( "Directive '{}' must be indented with 4 spaces, not {}. See " "{}:{}".format(directive_name, num_indent, f, j + 1) ) break for i, line in enumerate(lines): if esphome_io_regex.search(line): if "privacy.rst" in str(f) or "web_server.rst" in str(f): continue errors.append( "All links to esphome.io should be relative, please remove esphome.io " "from URL. See {}:{}".format(f, i + 1) ) for error in errors: print(error) sys.exit(len(errors))