Convert all API endpoint URLs to SX expression format

Every URL at sx-web.org now uses bracketed SX expressions — pages AND
API endpoints. defhandler :path values, sx-get/sx-post/sx-delete attrs,
code examples, and Python route decorators all converted.

- Add SxAtomConverter to handlers.py for parameter matching inside
  expression URLs (e.g. /(api.(item.<sx:item_id>)))
- Convert ~50 defhandler :path values in ref-api.sx and examples.sx
- Convert ~90 sx-get/sx-post/sx-delete URLs in reference.sx, examples.sx
- Convert ~30 code example URLs in examples-content.sx
- Convert ~30 API URLs in pages.py (Python string code examples)
- Convert ~70 page navigation URLs in pages.py
- Convert 7 Python route decorators in routes.py
- Convert ~10 reactive API URLs in marshes.sx
- Add API redirect patterns to sx_router.py (301 for old paths)
- Remove /api/ skip in app.py redirects (old API paths now redirect)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 10:02:26 +00:00
parent da1ca6009a
commit feecbb66ba
11 changed files with 358 additions and 299 deletions

View File

@@ -280,6 +280,51 @@ async def eval_sx_url(raw_path: str) -> Any:
# ---------------------------------------------------------------------------
_REDIRECT_PATTERNS = [
# --- API endpoint redirects (most specific first) ---
# Reference API: /geography/hypermedia/reference/api/item/<id>
(re.compile(r"^/geography/hypermedia/reference/api/item/(.+?)/?$"),
lambda m: f"/(geography.(hypermedia.(reference.(api.(item.{m.group(1)})))))"),
# Reference API: /geography/hypermedia/reference/api/<name>
(re.compile(r"^/geography/hypermedia/reference/api/(.+?)/?$"),
lambda m: f"/(geography.(hypermedia.(reference.(api.{m.group(1)}))))"),
# Example API: sub-paths with params
(re.compile(r"^/geography/hypermedia/examples/api/editrow/(.+?)/cancel/?$"),
lambda m: f"/(geography.(hypermedia.(example.(api.(editrow-cancel.{m.group(1)})))))"),
(re.compile(r"^/geography/hypermedia/examples/api/editrow/(.+?)/?$"),
lambda m: f"/(geography.(hypermedia.(example.(api.(editrow.{m.group(1)})))))"),
(re.compile(r"^/geography/hypermedia/examples/api/delete/(.+?)/?$"),
lambda m: f"/(geography.(hypermedia.(example.(api.(delete.{m.group(1)})))))"),
(re.compile(r"^/geography/hypermedia/examples/api/tabs/(.+?)/?$"),
lambda m: f"/(geography.(hypermedia.(example.(api.(tabs.{m.group(1)})))))"),
# Example API: sub-paths collapsed to hyphens
(re.compile(r"^/geography/hypermedia/examples/api/edit/cancel/?$"),
"/(geography.(hypermedia.(example.(api.edit-cancel))))"),
(re.compile(r"^/geography/hypermedia/examples/api/progress/start/?$"),
"/(geography.(hypermedia.(example.(api.progress-start))))"),
(re.compile(r"^/geography/hypermedia/examples/api/progress/status/?$"),
"/(geography.(hypermedia.(example.(api.progress-status))))"),
(re.compile(r"^/geography/hypermedia/examples/api/validate/submit/?$"),
"/(geography.(hypermedia.(example.(api.validate-submit))))"),
(re.compile(r"^/geography/hypermedia/examples/api/dialog/close/?$"),
"/(geography.(hypermedia.(example.(api.dialog-close))))"),
(re.compile(r"^/geography/hypermedia/examples/api/putpatch/edit-all/?$"),
"/(geography.(hypermedia.(example.(api.putpatch-edit-all))))"),
(re.compile(r"^/geography/hypermedia/examples/api/putpatch/cancel/?$"),
"/(geography.(hypermedia.(example.(api.putpatch-cancel))))"),
# Example API: simple names
(re.compile(r"^/geography/hypermedia/examples/api/(.+?)/?$"),
lambda m: f"/(geography.(hypermedia.(example.(api.{m.group(1)}))))"),
# Reactive API: sub-paths collapsed
(re.compile(r"^/geography/reactive/api/search/(.+?)/?$"),
lambda m: f"/(geography.(reactive.(api.search-{m.group(1)})))"),
(re.compile(r"^/geography/reactive/api/(.+?)/?$"),
lambda m: f"/(geography.(reactive.(api.{m.group(1)})))"),
# --- Page redirects ---
# More specific first
(re.compile(r"^/language/specs/explore/(.+?)/?$"),
lambda m: f"/(language.(spec.(explore.{m.group(1)})))"),