@caelo-cms/shared 0.11.0 → 0.11.1
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/dist/ai-tools.d.ts +30 -144
- package/dist/ai-tools.d.ts.map +1 -1
- package/dist/ai-tools.js +41 -141
- package/dist/ai-tools.js.map +1 -1
- package/dist/build-page.d.ts +5 -5
- package/dist/build-page.js +9 -9
- package/dist/build-page.js.map +1 -1
- package/dist/content.d.ts +13 -2
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +45 -12
- package/dist/content.js.map +1 -1
- package/dist/css-scope-scan.js +1 -1
- package/dist/escaped-line-breaks.d.ts +44 -0
- package/dist/escaped-line-breaks.d.ts.map +1 -0
- package/dist/escaped-line-breaks.js +203 -0
- package/dist/escaped-line-breaks.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interactions.js +5 -5
- package/dist/interactions.js.map +1 -1
- package/dist/lists/default-types.d.ts +12 -0
- package/dist/lists/default-types.d.ts.map +1 -1
- package/dist/lists/default-types.js +36 -0
- package/dist/lists/default-types.js.map +1 -1
- package/dist/lists/fields.d.ts.map +1 -1
- package/dist/lists/fields.js +1 -0
- package/dist/lists/fields.js.map +1 -1
- package/dist/lists/render-data.d.ts +9 -0
- package/dist/lists/render-data.d.ts.map +1 -1
- package/dist/lists/render-deps.d.ts +4 -3
- package/dist/lists/render-deps.d.ts.map +1 -1
- package/dist/lists/render-deps.js +5 -3
- package/dist/lists/render-deps.js.map +1 -1
- package/dist/lists/resolve.d.ts +13 -0
- package/dist/lists/resolve.d.ts.map +1 -1
- package/dist/lists/resolve.js +95 -3
- package/dist/lists/resolve.js.map +1 -1
- package/dist/nested-module-render.d.ts +13 -0
- package/dist/nested-module-render.d.ts.map +1 -1
- package/dist/nested-module-render.js +34 -0
- package/dist/nested-module-render.js.map +1 -1
- package/dist/redirect-plan.d.ts +13 -0
- package/dist/redirect-plan.d.ts.map +1 -1
- package/dist/redirect-plan.js +22 -0
- package/dist/redirect-plan.js.map +1 -1
- package/dist/seo.d.ts +21 -0
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +32 -0
- package/dist/seo.js.map +1 -1
- package/dist/source-text-transport.d.ts +28 -2
- package/dist/source-text-transport.d.ts.map +1 -1
- package/dist/source-text-transport.js +12 -4
- package/dist/source-text-transport.js.map +1 -1
- package/dist/template-sections.d.ts.map +1 -1
- package/dist/template-sections.js +17 -4
- package/dist/template-sections.js.map +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/redos-hardening.test.ts +1 -0
- package/src/ai-tools-add-module-modes.test.ts +1 -1
- package/src/ai-tools.test.ts +7 -20
- package/src/ai-tools.ts +49 -153
- package/src/bug-intake.test.ts +1 -1
- package/src/build-page.ts +9 -9
- package/src/content.test.ts +26 -1
- package/src/content.ts +47 -13
- package/src/css-scope-scan.ts +1 -1
- package/src/escaped-line-breaks.ts +221 -0
- package/src/index.ts +1 -0
- package/src/interactions.ts +5 -5
- package/src/link-refs.test.ts +1 -0
- package/src/lists/default-types.ts +39 -0
- package/src/lists/fields.ts +1 -0
- package/src/lists/list-fixtures.test.ts +9 -3
- package/src/lists/render-data.ts +9 -0
- package/src/lists/render-deps.ts +6 -3
- package/src/lists/resolve.test.ts +182 -5
- package/src/lists/resolve.ts +101 -3
- package/src/nested-module-render.test.ts +39 -0
- package/src/nested-module-render.ts +35 -0
- package/src/redirect-plan.test.ts +25 -0
- package/src/redirect-plan.ts +24 -0
- package/src/seo.test.ts +58 -0
- package/src/seo.ts +49 -0
- package/src/source-text-transport.test.ts +98 -3
- package/src/source-text-transport.ts +15 -4
- package/src/template-engine-lists.test.ts +55 -0
- package/src/template-sections.ts +18 -4
- package/src/version.ts +1 -1
|
@@ -551,3 +551,58 @@ describe("lists — loud markers", () => {
|
|
|
551
551
|
expect(r.missingSlots).toEqual(["list-context-unavailable:bullets"]);
|
|
552
552
|
});
|
|
553
553
|
});
|
|
554
|
+
|
|
555
|
+
describe("lists — breadcrumbs and {{site_text.*}} (#1142)", () => {
|
|
556
|
+
const SITE_TEXTS = "00000000-0000-4000-8000-0000000000e1";
|
|
557
|
+
const withTexts = (pageId: string, texts: Record<string, string>): ListPageContext =>
|
|
558
|
+
createListRenderContext(
|
|
559
|
+
fixtureData({
|
|
560
|
+
lists: [
|
|
561
|
+
{
|
|
562
|
+
id: SITE_TEXTS,
|
|
563
|
+
slug: "site-texts",
|
|
564
|
+
name: "Site texts",
|
|
565
|
+
typeSlug: "site-texts",
|
|
566
|
+
items: Object.entries(texts).map(([key, text], i) => ({
|
|
567
|
+
id: uuid(900 + i),
|
|
568
|
+
node: "text",
|
|
569
|
+
values: { key, text },
|
|
570
|
+
})),
|
|
571
|
+
},
|
|
572
|
+
],
|
|
573
|
+
}),
|
|
574
|
+
).forPage(pageId, { linkResolver: fixtureLinkIndex().forPage(pageId) });
|
|
575
|
+
const CRUMBS: TemplateField = {
|
|
576
|
+
name: "crumbs",
|
|
577
|
+
kind: "list",
|
|
578
|
+
listType: "links",
|
|
579
|
+
bind: "source",
|
|
580
|
+
source: { kind: "system", name: "breadcrumbs" },
|
|
581
|
+
};
|
|
582
|
+
const NAV =
|
|
583
|
+
'<nav aria-label="{{site_text.breadcrumb_label}}"><ol>{{#crumbs}}<li>{{#is_current}}<span aria-current="page">{{short_title}}</span>{{/is_current}}{{^is_current}}<a href="{{link}}">{{short_title}}</a>{{/is_current}}</li>{{/crumbs}}</ol></nav>';
|
|
584
|
+
|
|
585
|
+
it("renders a trail home → current with the aria-label from the site texts", () => {
|
|
586
|
+
const r = render(NAV, [CRUMBS], {}, withTexts(PAGE.team, { breadcrumb_label: "Breadcrumb" }));
|
|
587
|
+
expect(r.html).toBe(
|
|
588
|
+
'<nav aria-label="Breadcrumb"><ol><li><a href="/">Home</a></li><li><a href="/about/">About</a></li><li><span aria-current="page">Team</span></li></ol></nav>',
|
|
589
|
+
);
|
|
590
|
+
expect(r.missingSlots).toEqual([]);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
it("a missing site text stays loud", () => {
|
|
594
|
+
const r = render(
|
|
595
|
+
'<nav aria-label="{{site_text.breadcrumb_label}}"></nav>',
|
|
596
|
+
[],
|
|
597
|
+
{},
|
|
598
|
+
withTexts(PAGE.team, {}),
|
|
599
|
+
);
|
|
600
|
+
expect(r.html).toBe('<nav aria-label="{{site_text.breadcrumb_label}}"></nav>');
|
|
601
|
+
expect(r.missingSlots).toContain("site-text-missing:breadcrumb_label");
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it("is loud without a list context", () => {
|
|
605
|
+
const r = render("{{site_text.breadcrumb_label}}", [], {}, null);
|
|
606
|
+
expect(r.missingSlots).toContain("list-context-unavailable:site_text");
|
|
607
|
+
});
|
|
608
|
+
});
|
package/src/template-sections.ts
CHANGED
|
@@ -68,6 +68,17 @@ const TAG_RE = /\{\{\s*([#^/>]\s*)?([a-zA-Z][a-zA-Z0-9_]*(?:\.[a-zA-Z0-9_]+)*)\s
|
|
|
68
68
|
const SECTION_NAME_RE = /^[a-z][a-z0-9_]*(?:\.[a-z0-9_]+)*$/;
|
|
69
69
|
const DOT_RE = /\{\{\s*\.\s*\}\}/g;
|
|
70
70
|
|
|
71
|
+
/** Dotted heads the list context answers, not an entry: `{{page.*}}`, `{{site_text.*}}`. */
|
|
72
|
+
const CONTEXT_HEADS = new Set(["page", "site_text"]);
|
|
73
|
+
|
|
74
|
+
function contextHead(name: string): string {
|
|
75
|
+
return (name.split(".")[0] ?? "").toLowerCase();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isContextHead(name: string): boolean {
|
|
79
|
+
return CONTEXT_HEADS.has(contextHead(name));
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
function tokenize(html: string): Token[] {
|
|
72
83
|
const out: Token[] = [];
|
|
73
84
|
TAG_RE.lastIndex = 0;
|
|
@@ -201,6 +212,9 @@ class SectionRenderer {
|
|
|
201
212
|
v = this.env.lists?.pageScope() ?? undefined;
|
|
202
213
|
if (v === undefined)
|
|
203
214
|
return parts.length > 1 || st.chain.length > 0 ? { missing: true } : undefined;
|
|
215
|
+
} else if (head === "site_text") {
|
|
216
|
+
v = this.env.lists?.siteTextScope();
|
|
217
|
+
if (v === undefined) return { missing: true };
|
|
204
218
|
} else {
|
|
205
219
|
for (let k = st.chain.length - 1; k >= 0 && v === undefined; k -= 1) {
|
|
206
220
|
v = st.chain[k]?.entry.get(head);
|
|
@@ -251,8 +265,8 @@ class SectionRenderer {
|
|
|
251
265
|
}
|
|
252
266
|
if ("missing" in v) {
|
|
253
267
|
const marker =
|
|
254
|
-
t.name
|
|
255
|
-
?
|
|
268
|
+
isContextHead(t.name) && this.env.lists === undefined
|
|
269
|
+
? `list-context-unavailable:${contextHead(t.name)}`
|
|
256
270
|
: this.notDeclared(t.name, st);
|
|
257
271
|
return this.raw(source, marker);
|
|
258
272
|
}
|
|
@@ -321,8 +335,8 @@ class SectionRenderer {
|
|
|
321
335
|
if (v !== undefined) {
|
|
322
336
|
if ("missing" in v) {
|
|
323
337
|
const marker =
|
|
324
|
-
t.name
|
|
325
|
-
?
|
|
338
|
+
isContextHead(t.name) && this.env.lists === undefined
|
|
339
|
+
? `list-context-unavailable:${contextHead(t.name)}`
|
|
326
340
|
: this.notDeclared(t.name, st);
|
|
327
341
|
return this.raw(source, marker);
|
|
328
342
|
}
|