diff --git a/.gitignore b/.gitignore index 41317ee4..dffe6c95 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /.cache/ /.vscode/ /.idea/ +__pycache__ +/build/ \ No newline at end of file diff --git a/hooks/airspace_validation.py b/hooks/airspace_validation.py new file mode 100644 index 00000000..06beb4bf --- /dev/null +++ b/hooks/airspace_validation.py @@ -0,0 +1,69 @@ +import re +import logging +import csv + +log = logging.getLogger("airspace_validation") + +errors = [] + +config_state = { + 'doValidation': True, + 'errorOnValidationFail': True +} + +class Cache: + waypoints = set() + sidstars = set() + +def on_config(config): + config_state['errorOnValidationFail'] = config.get('extra', {}).get('error_on_validation_fail', True) + + try: + with open('build/ap_aids.txt', newline='') as f: + reader = csv.reader(f, delimiter='\t') + for row in reader: + if row[4] in ('IFR_FIX', 'VOR', 'NDB'): + Cache.waypoints.add(row[1]) + + with open('build/procedures.txt', newline='') as f: + reader = csv.reader(f, delimiter='\t') + for row in reader: + if row[4] in ('STAR', 'SID'): + Cache.sidstars.add(f"{row[3]} {row[7]}".strip()) + except FileNotFoundError: + print("Data not found - skipping validation") + config_state['doValidation'] = False + + +def on_page_markdown(markdown, page, **kwargs): + if config_state['doValidation'] == False: + return + + if page.file.src_path.startswith("contribute/") or page.file.src_path.startswith("changelog"): + return + + sidstarpattern = r"[A-Z]{5}\s#[A-Z]" + waypointpattern = r"`([A-Z]{5})`" + + matches = re.findall(sidstarpattern, markdown) + + for match in matches: + sidstarwaypoint = match[:5] + sidstaralpha = match[-1] + if not f"{sidstarwaypoint} {sidstaralpha}" in Cache.sidstars: + errors.append(f"{page.file.src_path}: SID/STAR {match} found but not valid") + + matches = re.findall(waypointpattern, markdown) + + for match in matches: + if not match in Cache.waypoints: + errors.append(f"{page.file.src_path}: Waypoint {match} found but not valid") + +def on_post_build(config): + if errors: + log.warning("Validation issues found:") + for e in errors: + log.warning(f" - {e}") + + if config_state['errorOnValidationFail']: + raise SystemExit("Validation errors occurred - not continuing") diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..847297b4 --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +python = "3.11" diff --git a/mkdocs.yml b/mkdocs.yml index c6b0f585..c1b421bc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -53,7 +53,10 @@ plugins: height: auto zoomable: true draggable: false - + +# Build hooks +hooks: + - hooks/airspace_validation.py # Styling Front-end extra_css: @@ -62,9 +65,6 @@ extra_css: - stylesheets/navigation.css - stylesheets/custom-toc.css -toc: - - toc_class: custom-toc - # Extra Functions / Customizations extra: social: @@ -80,6 +80,9 @@ extra: analytics: provider: google property: G-TH1T6E4KK6 + # Uncomment to bypass validation checks + # error_on_validation_fail: false + # google analytics tag to be rotated during airac cycle workflow # Additional Markdown Extensions to use bundled icon sets