@uniweb/core 0.26.0 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/index.js +1 -0
- package/src/page.js +17 -5
- package/src/route-match.js +46 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/core",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.2",
|
|
4
4
|
"description": "Core classes for the Uniweb platform - Uniweb, Website, Page, Block",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"vitest": "^4.1.7"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@uniweb/
|
|
48
|
-
"@uniweb/
|
|
47
|
+
"@uniweb/semantic-parser": "^1.4.0",
|
|
48
|
+
"@uniweb/theming": "^0.1.15"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"test": "vitest run"
|
package/src/index.js
CHANGED
package/src/page.js
CHANGED
|
@@ -600,11 +600,23 @@ export default class Page {
|
|
|
600
600
|
* is "give me the page to render *here*," not "give me the next URL
|
|
601
601
|
* with content."
|
|
602
602
|
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
603
|
+
* The case it exists for: an author requests `/docs`, the page is a folder
|
|
604
|
+
* with no content of its own, and its actual landing content lives in
|
|
605
|
+
* `/docs/intro` flagged `isIndex: true`.
|
|
606
|
+
*
|
|
607
|
+
* ⭐ **ONE CALLER, AND IT IS THE RULE FOR BOTH OF THE RENDERER'S TARGET FORMS:**
|
|
608
|
+
* `createPageRenderer().render()` (`@uniweb/runtime`) applies this after
|
|
609
|
+
* resolving, so a route and an already-resolved Page promote identically.
|
|
610
|
+
* Ruled 2026-09-12 [Diego], closing an asymmetry in which the same page rendered
|
|
611
|
+
* differently depending on which form the caller held — silently, with no error
|
|
612
|
+
* on either path.
|
|
613
|
+
*
|
|
614
|
+
* ⚠️ **It briefly had NO caller** (2026-09-12), after an SSR consumer replaced its
|
|
615
|
+
* hand-composed sequence with `render()`. An earlier version of this paragraph
|
|
616
|
+
* named that consumer and claimed the static build "pre-handles this differently
|
|
617
|
+
* via expandDynamicPages"; **both halves were wrong** — the static build never
|
|
618
|
+
* called this at all: it emits a redirect to the first descendant with content
|
|
619
|
+
* (`getNavigableRoute`) rather than promoting anything.
|
|
608
620
|
*
|
|
609
621
|
* @returns {Page} The page to render — `this` or its index child.
|
|
610
622
|
*/
|
package/src/route-match.js
CHANGED
|
@@ -556,3 +556,49 @@ export function stripLocalePrefix(route, activeLocale, defaultLocale) {
|
|
|
556
556
|
if (route.startsWith(`${prefix}/`)) return route.slice(prefix.length)
|
|
557
557
|
return route
|
|
558
558
|
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* ⭐ **THE PAGE A ROUTE NAMES — one rule, for every lane that asks the question.**
|
|
562
|
+
*
|
|
563
|
+
* Exact match first, then the parametric pages in page order, which is the order
|
|
564
|
+
* `Website#getPage` uses in the SPA. Captured params are decoded by
|
|
565
|
+
* `matchDynamicRoute` (a catch-all per segment), so the values are what a site's
|
|
566
|
+
* query binds against.
|
|
567
|
+
*
|
|
568
|
+
* ⛔ **Why this is a leaf rather than a thing each lane composes.** More than one
|
|
569
|
+
* lane asks *which page does this path name* — the SPA, the runtime's server-side
|
|
570
|
+
* prefetch, and a host's router. Our leaves (`normalizeRoute`, `isDynamicRoute`,
|
|
571
|
+
* `routePatternToRegex`) were importable and the RULE was not, so a consumer
|
|
572
|
+
* imported the parts and wrote the composition itself. **A renamed export breaks
|
|
573
|
+
* loudly; a re-implemented rule drifts silently.** A hand-written matcher spelled
|
|
574
|
+
* `:(\w+)` accepts a different param alphabet than our `[A-Za-z0-9_-]+`, so a
|
|
575
|
+
* hyphenated slug resolves in one copy and 404s in the other, with nothing failing
|
|
576
|
+
* anywhere. Import this; do not rebuild it.
|
|
577
|
+
*
|
|
578
|
+
* ⚠️ **A trailing slash is the same route, on BOTH branches** (`normalizeRoute`),
|
|
579
|
+
* which is what `Website#getPage` has always done. The runtime's own prefetch copy
|
|
580
|
+
* compared raw strings until 2026-09-12 and so disagreed with the SPA about
|
|
581
|
+
* `/about/` — the exact class of split this function exists to end.
|
|
582
|
+
*
|
|
583
|
+
* ⚖️ Matching is not resolving: a hit means the ROUTE exists. Whether the record
|
|
584
|
+
* behind a parametric page exists is a data question answered later.
|
|
585
|
+
*
|
|
586
|
+
* @param {Array<Object>|{pages?: Array<Object>}} source - the pages, or a payload holding them
|
|
587
|
+
* @param {string} route - the concrete path
|
|
588
|
+
* @returns {{ page: Object|null, params: Record<string,string> }} `page` is null when nothing matches
|
|
589
|
+
*/
|
|
590
|
+
export function findPageForRoute(source, route) {
|
|
591
|
+
const pages = Array.isArray(source) ? source : source?.pages
|
|
592
|
+
const list = Array.isArray(pages) ? pages : []
|
|
593
|
+
const wanted = normalizeRoute(route)
|
|
594
|
+
|
|
595
|
+
for (const page of list) {
|
|
596
|
+
if (typeof page?.route === 'string' && normalizeRoute(page.route) === wanted) return { page, params: {} }
|
|
597
|
+
}
|
|
598
|
+
for (const page of list) {
|
|
599
|
+
if (typeof page?.route !== 'string' || !isDynamicRoute(page.route)) continue
|
|
600
|
+
const hit = matchDynamicRoute(page.route, wanted)
|
|
601
|
+
if (hit) return { page, params: hit.params }
|
|
602
|
+
}
|
|
603
|
+
return { page: null, params: {} }
|
|
604
|
+
}
|