mirror of
https://github.com/rohitg00/awesome-openclaw.git
synced 2026-08-14 07:11:58 +00:00
chore: add static validation checks
Adds stdlib static validation for JSON, HTML, Vercel rewrites, and README anchors.
This commit is contained in:
@@ -12,6 +12,18 @@ This repo powers [openclawsearch.com](https://openclawsearch.com). The website *
|
||||
- Tables, code blocks, sections, and nav links are all generated from your markdown
|
||||
- `directory.html` is a separate curated page for ecosystem projects built with OpenClaw
|
||||
|
||||
## Validation
|
||||
|
||||
### Before opening a PR
|
||||
|
||||
Run the lightweight static checks:
|
||||
|
||||
```bash
|
||||
python3 scripts/validate_static.py
|
||||
```
|
||||
|
||||
This validates JSON, basic HTML structure, Vercel rewrite destinations, and README anchors for both GitHub and the website renderer.
|
||||
|
||||
## How to Add a Resource
|
||||
|
||||
1. Fork this repository
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Static validation
|
||||
|
||||
This repo is mostly static Markdown, HTML, JSON, and Vercel routing.
|
||||
|
||||
Run the lightweight local validation before opening PRs:
|
||||
|
||||
```bash
|
||||
python3 scripts/validate_static.py
|
||||
```
|
||||
|
||||
The script uses only the Python standard library and checks:
|
||||
|
||||
- JSON parsing.
|
||||
- basic HTML parser sanity.
|
||||
- Vercel rewrite destinations.
|
||||
- README internal anchor links for GitHub and the website renderer.
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Lightweight static validations for awesome-openclaw.
|
||||
|
||||
No third-party dependencies. Checks:
|
||||
- JSON files parse.
|
||||
- HTML files are parseable by Python's stdlib HTMLParser.
|
||||
- Vercel static rewrite destinations exist.
|
||||
- README internal anchors work for GitHub-style headings.
|
||||
- README anchors that the website will render are reported if the website slugger differs.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from html.parser import HTMLParser
|
||||
from pathlib import Path
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def fail(msg: str) -> None:
|
||||
print(f"ERROR: {msg}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def github_slug(text: str, counts: dict[str, int]) -> str:
|
||||
base = re.sub(r"<[^>]+>", "", text).strip().lower()
|
||||
base = re.sub(r"[^a-z0-9 -]", "", base)
|
||||
# GitHub removes punctuation before replacing each whitespace character,
|
||||
# so headings like "Serverless & PaaS" become "serverless--paas".
|
||||
base = re.sub(r"\s", "-", base).strip("-")
|
||||
n = counts.get(base, 0)
|
||||
counts[base] = n + 1
|
||||
return base if n == 0 else f"{base}-{n}"
|
||||
|
||||
|
||||
def website_slug(text: str, counts: dict[str, int]) -> str:
|
||||
# Mirror docs/website/index.html after the SEO/anchor PR.
|
||||
return github_slug(text, counts)
|
||||
|
||||
|
||||
def check_json() -> None:
|
||||
for path in ROOT.rglob("*.json"):
|
||||
if ".git" in path.parts:
|
||||
continue
|
||||
try:
|
||||
json.loads(path.read_text())
|
||||
except Exception as exc:
|
||||
fail(f"Invalid JSON in {path.relative_to(ROOT)}: {exc}")
|
||||
print("JSON OK")
|
||||
|
||||
|
||||
class Parser(HTMLParser):
|
||||
pass
|
||||
|
||||
|
||||
def check_html() -> None:
|
||||
for path in list((ROOT / "docs" / "website").glob("*.html")) + list((ROOT / "docs" / "blog").glob("*.html")) + list((ROOT / "docs" / "public").rglob("*.html")):
|
||||
parser = Parser()
|
||||
try:
|
||||
parser.feed(path.read_text(errors="ignore"))
|
||||
except Exception as exc:
|
||||
fail(f"HTML parse issue in {path.relative_to(ROOT)}: {exc}")
|
||||
print("HTML parse OK")
|
||||
|
||||
|
||||
def check_vercel() -> None:
|
||||
config = json.loads((ROOT / "vercel.json").read_text())
|
||||
missing: list[tuple[str, str]] = []
|
||||
for rewrite in config.get("rewrites", []):
|
||||
dest = rewrite.get("destination", "")
|
||||
if ":" in dest:
|
||||
continue
|
||||
p = ROOT / dest.lstrip("/")
|
||||
if not p.exists():
|
||||
missing.append((rewrite.get("source", ""), dest))
|
||||
if missing:
|
||||
fail("Missing Vercel rewrite destinations: " + repr(missing))
|
||||
print("Vercel rewrites OK")
|
||||
|
||||
|
||||
def heading_anchors(markdown: str, slug_fn) -> set[str]:
|
||||
counts: dict[str, int] = {}
|
||||
anchors: set[str] = set()
|
||||
for line in markdown.splitlines():
|
||||
match = re.match(r"^(#{1,6})\s+(.+?)\s*$", line)
|
||||
if match:
|
||||
anchors.add(slug_fn(match.group(2), counts))
|
||||
return anchors
|
||||
|
||||
|
||||
def readme_links(markdown: str) -> list[str]:
|
||||
return re.findall(r"\[[^\]]+\]\(#([^)]+)\)", markdown)
|
||||
|
||||
|
||||
def check_readme_anchors() -> None:
|
||||
readme = (ROOT / "README.md").read_text(errors="ignore")
|
||||
links = readme_links(readme)
|
||||
gh_anchors = heading_anchors(readme, github_slug)
|
||||
bad = [link for link in links if link not in gh_anchors]
|
||||
if bad:
|
||||
fail("README GitHub anchor links are broken: " + ", ".join(bad))
|
||||
web_anchors = heading_anchors(readme, website_slug)
|
||||
web_bad = [link for link in links if link not in web_anchors]
|
||||
if web_bad:
|
||||
fail("README website-rendered anchor links are broken: " + ", ".join(web_bad))
|
||||
print("README anchors OK")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
check_json()
|
||||
check_html()
|
||||
check_vercel()
|
||||
check_readme_anchors()
|
||||
print("All static validations passed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user