docs(readme): restructure and rewrite entire README (#248) #48
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docs | |
| on: | |
| pull_request: | |
| paths: | |
| - "**/*.md" | |
| - ".github/ISSUE_TEMPLATE/**" | |
| - ".github/PULL_REQUEST_TEMPLATE.md" | |
| - ".github/workflows/docs.yml" | |
| push: | |
| branches: [main] | |
| paths: | |
| - "**/*.md" | |
| - ".github/ISSUE_TEMPLATE/**" | |
| - ".github/PULL_REQUEST_TEMPLATE.md" | |
| - ".github/workflows/docs.yml" | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: docs-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| links: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Validate active relative Markdown links | |
| run: | | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| import re | |
| import sys | |
| files = [ | |
| Path("README.md"), | |
| Path("use-cases/README.md"), | |
| Path("methods/README.md"), | |
| Path("benchmarks/README.md"), | |
| Path("AGENTS.md"), | |
| Path(".github/CONTRIBUTING.md"), | |
| Path(".github/CODE_OF_CONDUCT.md"), | |
| Path(".github/SECURITY.md"), | |
| ] | |
| missing = [] | |
| for path in files: | |
| if not path.exists(): | |
| continue | |
| text = path.read_text() | |
| active = re.sub(r"<!--.*?-->", "", text, flags=re.S) | |
| for raw in re.findall(r"\[[^\]]*\]\(([^)]+)\)", active): | |
| link = raw.split("#", 1)[0] | |
| if not link or link.startswith(("http://", "https://", "mailto:")): | |
| continue | |
| target = (path.parent / link).resolve() | |
| try: | |
| target.relative_to(Path.cwd().resolve()) | |
| except ValueError: | |
| missing.append((path, raw, "outside repository")) | |
| continue | |
| if not target.exists(): | |
| missing.append((path, raw, "missing")) | |
| if missing: | |
| for path, raw, reason in missing: | |
| print(f"{path}: {raw} -> {reason}") | |
| sys.exit(1) | |
| print("Active relative Markdown links resolve.") | |
| PY | |
| - name: Validate use-case banner links | |
| run: | | |
| python3 - <<'PY' | |
| from pathlib import Path | |
| import re | |
| import sys | |
| files = { | |
| Path("README.md"): "## Use Cases", | |
| Path("use-cases/README.md"): "## Use Case Catalogue", | |
| } | |
| failures = [] | |
| warnings = [] | |
| primary_link_pattern = re.compile( | |
| r"^\[(?:Code|Plugin|Live Demo|Learn more)\]\(([^)]+)\)", | |
| flags=re.M, | |
| ) | |
| for path, heading in files.items(): | |
| text = path.read_text() | |
| start = text.find(heading) | |
| if start == -1: | |
| failures.append(f"{path}: missing {heading}") | |
| continue | |
| table_start = text.find("<table>", start) | |
| table_end = text.find("</table>", table_start) | |
| if table_start == -1 or table_end == -1: | |
| failures.append(f"{path}: missing use-case table") | |
| continue | |
| table = text[table_start:table_end] | |
| cells = re.findall(r"<td[^>]*>(.*?)</td>", table, flags=re.S) | |
| for index, cell in enumerate(cells, start=1): | |
| title_match = re.search(r"####\s+(.+)", cell) | |
| title = title_match.group(1).strip() if title_match else f"use case {index}" | |
| banner_match = re.search(r"\[!\[[^\]]*\]\([^)]+\)\]\(([^)]+)\)", cell) | |
| primary_match = primary_link_pattern.search(cell) | |
| if not banner_match and primary_match: | |
| warnings.append(f"{path}: {title}: primary link has no linked banner") | |
| elif banner_match and not primary_match: | |
| failures.append(f"{path}: {title}: missing primary link") | |
| elif banner_match and primary_match and banner_match.group(1) != primary_match.group(1): | |
| failures.append( | |
| f"{path}: {title}: banner link {banner_match.group(1)} " | |
| f"does not match primary link {primary_match.group(1)}" | |
| ) | |
| if warnings: | |
| print("\n".join(f"warning: {warning}" for warning in warnings)) | |
| if failures: | |
| print("\n".join(failures)) | |
| sys.exit(1) | |
| print("Use-case banner links match primary links.") | |
| PY | |
| - name: Validate issue template YAML | |
| run: | | |
| ruby -e 'require "yaml"; Dir[".github/ISSUE_TEMPLATE/*.yml"].sort.each { |p| YAML.load_file(p); puts "YAML ok: #{p}" }' |