#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" export ROOT_DIR python3 <<'PY' import os import re import sys from pathlib import Path root = Path(os.environ["ROOT_DIR"]) wiki_root = root.parent / "ta4j-wiki" wiki_available = wiki_root.exists() docs_for_link_checks = [root / "README.md", root / "ta4j-examples" / "README.md"] if wiki_available: docs_for_link_checks.extend(sorted(wiki_root.glob("*.md"))) docs_for_command_checks = [ root / "README.md", root / "ta4j-examples" / "README.md", ] if wiki_available: docs_for_command_checks.extend( [ wiki_root / "Usage-examples.md", wiki_root / "Examples-Expected-Outputs.md", wiki_root / "Performance-Characterization.md", ] ) todo_forbidden_docs = [ root / "README.md", root / "ta4j-examples" / "README.md", ] if wiki_available: todo_forbidden_docs.extend( [ wiki_root / "Home.md", wiki_root / "Getting-started.md", wiki_root / "Backtesting.md", wiki_root / "Live-trading.md", wiki_root / "Canonical-User-Journey.md", wiki_root / "Execution-Decision-Matrix.md", wiki_root / "Migration-and-Version-Compatibility.md", wiki_root / "Examples-Expected-Outputs.md", wiki_root / "Performance-Characterization.md", ] ) required_canonical_docs = [ root / "README.md", root / "ta4j-examples" / "README.md", root / "ta4j-core" / "README.md", ] if wiki_available: required_canonical_docs.extend( [ wiki_root / "Home.md", wiki_root / "Getting-started.md", wiki_root / "Canonical-User-Journey.md", wiki_root / "Backtesting-Realism-Checklist.md", wiki_root / "Live-Trading-Runbook.md", wiki_root / "Troubleshooting-Hub.md", wiki_root / "Execution-Decision-Matrix.md", wiki_root / "Migration-and-Version-Compatibility.md", wiki_root / "Examples-Expected-Outputs.md", wiki_root / "Performance-Characterization.md", ] ) link_pattern = re.compile(r"\[[^\]]+\]\(([^)]+)\)") main_class_pattern = re.compile(r"-Dexec\.mainClass=([A-Za-z0-9_.]+)") errors = [] def normalize_target(raw_target: str) -> str: target = raw_target.strip() if " " in target and target.startswith(("http://", "https://")): target = target.split(" ", 1)[0] if "#" in target: target = target.split("#", 1)[0] if "?" in target: target = target.split("?", 1)[0] return target.strip() def check_markdown_links(path: Path) -> None: if not path.exists(): errors.append(f"Missing documentation file for link check: {path}") return content = path.read_text(encoding="utf-8") for match in link_pattern.finditer(content): raw_target = match.group(1).strip() target = normalize_target(raw_target) if not target: continue if target.startswith(("http://", "https://", "mailto:")): continue if target.startswith("#"): continue candidate = (path.parent / target).resolve() if not candidate.exists(): errors.append(f"{path}: broken relative link target '{raw_target}'") def check_exec_main_classes(path: Path) -> None: if not path.exists(): errors.append(f"Missing documentation file for command check: {path}") return content = path.read_text(encoding="utf-8") for main_class in main_class_pattern.findall(content): class_file = ( root / "ta4j-examples" / "src" / "main" / "java" / Path(*main_class.split(".")).with_suffix(".java") ) if not class_file.exists(): errors.append( f"{path}: -Dexec.mainClass points to missing class '{main_class}' ({class_file})" ) def check_for_todo_markers(path: Path) -> None: if not path.exists(): errors.append(f"Missing documentation file for TODO check: {path}") return content = path.read_text(encoding="utf-8") if "TODO" in content: errors.append(f"{path}: contains TODO marker in user-facing docs") for doc_path in docs_for_link_checks: check_markdown_links(doc_path) for doc_path in docs_for_command_checks: check_exec_main_classes(doc_path) for doc_path in todo_forbidden_docs: check_for_todo_markers(doc_path) for doc_path in required_canonical_docs: if not doc_path.exists(): errors.append(f"Missing canonical documentation artifact: {doc_path}") if errors: print("docs-integrity:fail") for error in errors: print(f"- {error}") sys.exit(1) if not wiki_available: print("docs-integrity:note ta4j-wiki checkout not found; skipping wiki checks") print("docs-integrity:pass") PY