refactor: split the repo into self-contained validator, directory, quickstart, spec and site folders

validator/ holds mewslint (lint, css, fetch, DTD/CSS data); directory/ holds
the mews.page service (app, db, check, pages, cli) and depends on validator/;
quickstart/ holds mews-quickstart and md2mews.py for third parties who want
to create Mews content without cloning the repo; spec/ consolidates doc/ and
dtd/ with the canonical mews-0.1.css; site/ becomes a Pelican project with
the forward-facing pages as Markdown, the check form kept as a raw HTML
snippet. Root pyproject.toml is now a virtual uv workspace over validator,
directory and quickstart, with cross-cutting tests that span more than one
of them staying at the repo root. Makefile and flake.nix updated to match.
This commit is contained in:
randogoth 2026-10-13 12:29:23 +03:00
parent 5fa8708bd1
commit 060d4e00fd
90 changed files with 1290 additions and 287 deletions

View file

@ -1,102 +0,0 @@
#!/usr/bin/env python
"""Check mews-0.1.dtd against the XHTML Mobile 1.2 driver and the spec.
The Mews DTD is maintained by hand. It cannot be generated by stripping
xhtml-mobile12.dtd: that file is a driver which declares no elements (the
declarations live in the W3C and OMA module files it points to), DTD
attribute lists only ever add, a re-declared element is an error rather
than an override, and the rules that define Mews (the head model of
SPEC.md 3.3, the body variant classes of 5.3, the ban on nested tables
of 4.2, and lang and dir) do not exist in XHTML-MP to be kept.
This script verifies what the driver and the spec can check:
- the driver is the expected XHTML Mobile 1.2 driver, with event
attributes included and bidi ignored, so lang and dir are Mews
extensions (SPEC.md 3);
- the DTD declares exactly the elements SPEC.md 4.1 permits;
- the DTD keeps the driver's pre content model verbatim;
- the DTD keeps the li value and ol start attributes the driver adds.
Run with: uv run check_dtd.py
"""
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent
DRIVER_PATH = ROOT / "xhtml-mobile12.dtd"
DTD_PATH = ROOT / "mews-0.1.dtd"
DRIVER_FPI = "-//OMA//DTD XHTML Mobile 1.2//EN"
# The Mews element set (SPEC.md 4.1).
KEPT_ELEMENTS = (
"html head title body "
"h1 h2 h3 h4 h5 h6 "
"p blockquote pre address hr "
"em strong b i code kbd samp var q cite abbr dfn br "
"a "
"ul ol li dl dt dd "
"table caption tr th td "
"img "
"form fieldset label input select option optgroup textarea "
"meta link"
).split()
def entity(text, name):
match = re.search(r"<!ENTITY\s+%\s*" + re.escape(name) + r'\s+"([^"]*)"', text)
return match.group(1).strip() if match else None
def pre_content(text):
match = re.search(r'<!ENTITY\s+%\s*pre\.content\s+"(.*?)"\s*>', text, re.DOTALL)
return re.sub(r"\s+", " ", match.group(1)) if match else None
def attlist(text, element):
match = re.search(r"<!ATTLIST\s+" + element + r"\s+(.*?)\n>", text, re.DOTALL)
return match.group(1) if match else None
def main():
driver = DRIVER_PATH.read_text(encoding="utf-8")
dtd = DTD_PATH.read_text(encoding="utf-8")
errors = []
def check(condition, message):
if not condition:
errors.append(message)
check(entity(driver, "XHTML.version") == DRIVER_FPI, "driver is not XHTML Mobile 1.2")
check(
entity(driver, "xhtml-events.module") == "INCLUDE",
"driver must include event attributes; Mews drops them",
)
check(
entity(driver, "XHTML.bidi") == "IGNORE",
"driver must ignore bidi, so dir is a Mews extension",
)
declared = set(re.findall(r"<!ELEMENT\s+([\w:-]+)", dtd))
expected = set(KEPT_ELEMENTS)
check(
declared == expected,
f"elements differ from SPEC.md 4.1: {sorted(declared ^ expected)}",
)
check(pre_content(dtd) == pre_content(driver), "pre content model differs from the driver's")
check("value" in (attlist(dtd, "li") or ""), "li is missing the driver's value attribute")
check("start" in (attlist(dtd, "ol") or ""), "ol is missing the driver's start attribute")
if errors:
for message in errors:
print(f"error: {message}", file=sys.stderr)
sys.exit(1)
print(f"{DTD_PATH.name} matches the driver and SPEC.md 4.1 ({len(expected)} elements)")
if __name__ == "__main__":
main()