@caelo-cms/shared 0.10.72 → 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 +103 -142
- package/dist/ai-tools.d.ts.map +1 -1
- package/dist/ai-tools.js +79 -167
- package/dist/ai-tools.js.map +1 -1
- package/dist/build-page.d.ts +115 -35
- package/dist/build-page.d.ts.map +1 -1
- package/dist/build-page.js +31 -12
- package/dist/build-page.js.map +1 -1
- package/dist/content.d.ts +214 -102
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +219 -84
- package/dist/content.js.map +1 -1
- package/dist/css-scope-scan.js +1 -1
- package/dist/css-var-aliases.d.ts +20 -0
- package/dist/css-var-aliases.d.ts.map +1 -0
- package/dist/css-var-aliases.js +95 -0
- package/dist/css-var-aliases.js.map +1 -0
- package/dist/css-var-scan.d.ts +0 -16
- package/dist/css-var-scan.d.ts.map +1 -1
- package/dist/css-var-scan.js +24 -0
- package/dist/css-var-scan.js.map +1 -1
- package/dist/edit-markers.d.ts +41 -5
- package/dist/edit-markers.d.ts.map +1 -1
- package/dist/edit-markers.js +47 -50
- package/dist/edit-markers.js.map +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 +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/interactions.js +6 -6
- package/dist/interactions.js.map +1 -1
- package/dist/link-canonicalise.d.ts.map +1 -1
- package/dist/link-canonicalise.js +7 -1
- package/dist/link-canonicalise.js.map +1 -1
- package/dist/link-refs.d.ts +1 -1
- package/dist/link-refs.js +3 -3
- package/dist/lists/address.d.ts +34 -0
- package/dist/lists/address.d.ts.map +1 -0
- package/dist/lists/address.js +43 -0
- package/dist/lists/address.js.map +1 -0
- package/dist/lists/default-types.d.ts +22 -0
- package/dist/lists/default-types.d.ts.map +1 -0
- package/dist/lists/default-types.js +127 -0
- package/dist/lists/default-types.js.map +1 -0
- package/dist/lists/fields.d.ts +152 -0
- package/dist/lists/fields.d.ts.map +1 -0
- package/dist/lists/fields.js +259 -0
- package/dist/lists/fields.js.map +1 -0
- package/dist/lists/index.d.ts +14 -0
- package/dist/lists/index.d.ts.map +1 -0
- package/dist/lists/index.js +15 -0
- package/dist/lists/index.js.map +1 -0
- package/dist/lists/item-attr.d.ts +26 -0
- package/dist/lists/item-attr.d.ts.map +1 -0
- package/dist/lists/item-attr.js +31 -0
- package/dist/lists/item-attr.js.map +1 -0
- package/dist/lists/items.d.ts +105 -0
- package/dist/lists/items.d.ts.map +1 -0
- package/dist/lists/items.js +304 -0
- package/dist/lists/items.js.map +1 -0
- package/dist/lists/list-type.d.ts +401 -0
- package/dist/lists/list-type.d.ts.map +1 -0
- package/dist/lists/list-type.js +275 -0
- package/dist/lists/list-type.js.map +1 -0
- package/dist/lists/model.d.ts +14 -0
- package/dist/lists/model.d.ts.map +1 -0
- package/dist/lists/model.js +15 -0
- package/dist/lists/model.js.map +1 -0
- package/dist/lists/page-type.d.ts +115 -0
- package/dist/lists/page-type.d.ts.map +1 -0
- package/dist/lists/page-type.js +66 -0
- package/dist/lists/page-type.js.map +1 -0
- package/dist/lists/refs.d.ts +13 -0
- package/dist/lists/refs.d.ts.map +1 -0
- package/dist/lists/refs.js +18 -0
- package/dist/lists/refs.js.map +1 -0
- package/dist/lists/render-data.d.ts +123 -0
- package/dist/lists/render-data.d.ts.map +1 -0
- package/dist/lists/render-data.js +3 -0
- package/dist/lists/render-data.js.map +1 -0
- package/dist/lists/render-deps.d.ts +69 -0
- package/dist/lists/render-deps.d.ts.map +1 -0
- package/dist/lists/render-deps.js +93 -0
- package/dist/lists/render-deps.js.map +1 -0
- package/dist/lists/resolve-values.d.ts +63 -0
- package/dist/lists/resolve-values.d.ts.map +1 -0
- package/dist/lists/resolve-values.js +181 -0
- package/dist/lists/resolve-values.js.map +1 -0
- package/dist/lists/resolve.d.ts +119 -0
- package/dist/lists/resolve.d.ts.map +1 -0
- package/dist/lists/resolve.js +970 -0
- package/dist/lists/resolve.js.map +1 -0
- package/dist/lists/scope.d.ts +81 -0
- package/dist/lists/scope.d.ts.map +1 -0
- package/dist/lists/scope.js +3 -0
- package/dist/lists/scope.js.map +1 -0
- package/dist/markup-structure.d.ts +8 -0
- package/dist/markup-structure.d.ts.map +1 -1
- package/dist/markup-structure.js +2 -0
- package/dist/markup-structure.js.map +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/nested-module-render.d.ts +38 -20
- package/dist/nested-module-render.d.ts.map +1 -1
- package/dist/nested-module-render.js +156 -31
- package/dist/nested-module-render.js.map +1 -1
- package/dist/page-log.d.ts +1 -1
- package/dist/preview-compose.d.ts +24 -21
- package/dist/preview-compose.d.ts.map +1 -1
- package/dist/preview-compose.js +34 -118
- package/dist/preview-compose.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 +43 -0
- package/dist/source-text-transport.d.ts.map +1 -0
- package/dist/source-text-transport.js +79 -0
- package/dist/source-text-transport.js.map +1 -0
- package/dist/template-engine.d.ts +44 -31
- package/dist/template-engine.d.ts.map +1 -1
- package/dist/template-engine.js +75 -174
- package/dist/template-engine.js.map +1 -1
- package/dist/template-sections.d.ts +69 -0
- package/dist/template-sections.d.ts.map +1 -0
- package/dist/template-sections.js +436 -0
- package/dist/template-sections.js.map +1 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +8 -1
- package/src/__tests__/redos-hardening.test.ts +51 -16
- package/src/ai-tools-add-module-modes.test.ts +51 -1
- package/src/ai-tools.test.ts +7 -10
- package/src/ai-tools.ts +90 -180
- package/src/bug-intake.test.ts +1 -1
- package/src/build-page.test.ts +34 -3
- package/src/build-page.ts +34 -11
- package/src/content.test.ts +137 -4
- package/src/content.ts +230 -85
- package/src/css-scope-scan.ts +1 -1
- package/src/css-var-aliases.test.ts +61 -0
- package/src/css-var-aliases.ts +109 -0
- package/src/css-var-scan.ts +9 -0
- package/src/edit-markers.test.ts +37 -21
- package/src/edit-markers.ts +52 -20
- package/src/escaped-line-breaks.ts +221 -0
- package/src/index.ts +4 -1
- package/src/interactions.ts +6 -6
- package/src/link-canonicalise.test.ts +36 -6
- package/src/link-canonicalise.ts +6 -1
- package/src/link-refs.test.ts +67 -42
- package/src/link-refs.ts +3 -3
- package/src/lists/address.ts +75 -0
- package/src/lists/default-types.ts +141 -0
- package/src/lists/fields.ts +286 -0
- package/src/lists/index.ts +16 -0
- package/src/lists/item-attr.test.ts +36 -0
- package/src/lists/item-attr.ts +49 -0
- package/src/lists/items.ts +402 -0
- package/src/lists/list-fixtures.test.ts +308 -0
- package/src/lists/list-type.ts +306 -0
- package/src/lists/lists.test.ts +328 -0
- package/src/lists/model.ts +16 -0
- package/src/lists/page-type.ts +71 -0
- package/src/lists/refs.ts +21 -0
- package/src/lists/render-data.ts +134 -0
- package/src/lists/render-deps.test.ts +132 -0
- package/src/lists/render-deps.ts +147 -0
- package/src/lists/resolve-values.ts +224 -0
- package/src/lists/resolve.test.ts +472 -0
- package/src/lists/resolve.ts +1246 -0
- package/src/lists/scope.ts +69 -0
- package/src/lists-compose-parity.test.ts +262 -0
- package/src/markup-structure.ts +10 -0
- package/src/nested-module-render.test.ts +147 -74
- package/src/nested-module-render.ts +120 -48
- package/src/preview-compose.test.ts +55 -19
- package/src/preview-compose.ts +59 -154
- 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 +158 -0
- package/src/source-text-transport.ts +81 -0
- package/src/template-engine-lists.test.ts +608 -0
- package/src/template-engine.test.ts +62 -80
- package/src/template-engine.ts +102 -245
- package/src/template-sections.ts +514 -0
- package/src/version.ts +1 -1
- package/dist/structured-sets.d.ts +0 -70
- package/dist/structured-sets.d.ts.map +0 -1
- package/dist/structured-sets.js +0 -92
- package/dist/structured-sets.js.map +0 -1
- package/src/structured-sets.ts +0 -114
- package/src/template-engine-data-lists.test.ts +0 -90
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { describe, expect, it } from "bun:test";
|
|
22
|
+
import { fixtureData, INSTANCE, ITEM, LIST, MODULE, PAGE } from "./lists/list-fixtures.test.js";
|
|
23
|
+
import { createListRenderContext } from "./lists/resolve.js";
|
|
22
24
|
import {
|
|
23
25
|
collectNestedRefs,
|
|
24
26
|
type NestedContentInstanceResource,
|
|
@@ -27,6 +29,7 @@ import {
|
|
|
27
29
|
type NestedRenderResolver,
|
|
28
30
|
renderModuleWithContent,
|
|
29
31
|
renderPlacedModule,
|
|
32
|
+
rewriteNestedRefs,
|
|
30
33
|
} from "./nested-module-render.js";
|
|
31
34
|
|
|
32
35
|
function buildResolver(
|
|
@@ -288,148 +291,214 @@ describe("renderModuleWithContent — empty optional module field (#1041)", () =
|
|
|
288
291
|
});
|
|
289
292
|
});
|
|
290
293
|
|
|
291
|
-
describe("renderModuleWithContent — list
|
|
292
|
-
|
|
294
|
+
describe("renderModuleWithContent — list fields (epic #1107)", () => {
|
|
295
|
+
const lists = createListRenderContext(fixtureData()).forPage(PAGE.home);
|
|
296
|
+
const T = (n: number) => `00000000-0000-4000-9000-${String(n).padStart(12, "0")}`;
|
|
297
|
+
const texts = (...t: string[]) =>
|
|
298
|
+
t.map((text, i) => ({ id: T(i + 1), node: "text", values: { text } }));
|
|
299
|
+
const PARENT_CI = "00000000-0000-4000-8000-00000000bbb1";
|
|
300
|
+
|
|
301
|
+
it("iterates a local list and addresses entries by the content instance", () => {
|
|
293
302
|
const resolver = buildResolver(
|
|
294
303
|
[
|
|
295
304
|
{
|
|
296
305
|
moduleId: PARENT_MOD_ID,
|
|
297
306
|
slug: "tag-cloud",
|
|
298
|
-
html: "<div>{{#tags}}<span>{{
|
|
307
|
+
html: "<div>{{#tags}}<span>{{text}}</span>{{/tags}}</div>",
|
|
299
308
|
css: "",
|
|
300
309
|
js: "",
|
|
301
|
-
fields: [{ name: "tags", kind: "
|
|
310
|
+
fields: [{ name: "tags", kind: "list", listType: "texts" }],
|
|
302
311
|
},
|
|
303
312
|
],
|
|
304
313
|
[
|
|
305
314
|
{
|
|
306
|
-
id:
|
|
315
|
+
id: PARENT_CI,
|
|
307
316
|
moduleId: PARENT_MOD_ID,
|
|
308
|
-
values: { tags:
|
|
317
|
+
values: { tags: texts("alpha", "beta") },
|
|
309
318
|
deletedAt: null,
|
|
310
319
|
},
|
|
311
320
|
],
|
|
312
321
|
);
|
|
313
|
-
const r = renderModuleWithContent(PARENT_MOD_ID,
|
|
314
|
-
expect(r.html).toBe(
|
|
322
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI, resolver, undefined, lists);
|
|
323
|
+
expect(r.html).toBe(
|
|
324
|
+
`<div><span data-caelo-list-item="instance/${PARENT_CI}/tags/${T(1)}">alpha</span>` +
|
|
325
|
+
`<span data-caelo-list-item="instance/${PARENT_CI}/tags/${T(2)}">beta</span></div>`,
|
|
326
|
+
);
|
|
315
327
|
expect(r.missingSlots).toEqual([]);
|
|
316
328
|
});
|
|
317
329
|
|
|
318
|
-
it("
|
|
330
|
+
it("an edit-marked copy keeps the real instance as the entries' address", () => {
|
|
319
331
|
const resolver = buildResolver(
|
|
320
332
|
[
|
|
321
333
|
{
|
|
322
334
|
moduleId: PARENT_MOD_ID,
|
|
323
|
-
slug: "
|
|
324
|
-
html: "
|
|
335
|
+
slug: "tag-cloud",
|
|
336
|
+
html: "{{#tags}}<i>{{text}}</i>{{/tags}}",
|
|
325
337
|
css: "",
|
|
326
338
|
js: "",
|
|
327
|
-
fields: [{ name: "
|
|
339
|
+
fields: [{ name: "tags", kind: "list", listType: "texts" }],
|
|
328
340
|
},
|
|
329
341
|
],
|
|
330
342
|
[
|
|
331
343
|
{
|
|
332
|
-
id:
|
|
344
|
+
id: "edit:content#0",
|
|
333
345
|
moduleId: PARENT_MOD_ID,
|
|
334
|
-
values: {
|
|
346
|
+
values: { tags: texts("a") },
|
|
335
347
|
deletedAt: null,
|
|
348
|
+
listHolderId: PARENT_CI,
|
|
336
349
|
},
|
|
337
350
|
],
|
|
338
351
|
);
|
|
339
|
-
const r = renderModuleWithContent(PARENT_MOD_ID,
|
|
340
|
-
expect(r.html).
|
|
352
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, "edit:content#0", resolver, undefined, lists);
|
|
353
|
+
expect(r.html).toContain(`instance/${PARENT_CI}/tags/`);
|
|
341
354
|
});
|
|
342
355
|
|
|
343
|
-
it("
|
|
356
|
+
it("falls back to the field default when the values entry is absent", () => {
|
|
344
357
|
const resolver = buildResolver(
|
|
345
358
|
[
|
|
346
359
|
{
|
|
347
360
|
moduleId: PARENT_MOD_ID,
|
|
348
361
|
slug: "tag-cloud",
|
|
349
|
-
html: "<div>{{#tags}}
|
|
362
|
+
html: "<div>{{#tags}}{{text}};{{/tags}}</div>",
|
|
350
363
|
css: "",
|
|
351
364
|
js: "",
|
|
352
365
|
fields: [
|
|
353
|
-
{
|
|
354
|
-
name: "tags",
|
|
355
|
-
kind: "text-list",
|
|
356
|
-
default: ["alpha", "beta"],
|
|
357
|
-
},
|
|
366
|
+
{ name: "tags", kind: "list", listType: "texts", default: texts("alpha", "beta") },
|
|
358
367
|
],
|
|
359
368
|
},
|
|
360
369
|
],
|
|
361
370
|
[{ id: PARENT_CI_ID, moduleId: PARENT_MOD_ID, values: {}, deletedAt: null }],
|
|
362
371
|
);
|
|
363
|
-
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
364
|
-
expect(r.html).toBe("<div
|
|
372
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver, undefined, lists);
|
|
373
|
+
expect(r.html).toBe("<div>alpha;beta;</div>");
|
|
365
374
|
});
|
|
366
375
|
|
|
367
|
-
it("
|
|
376
|
+
it("renders a list entry's embedded module through the recursion (depth + cycle guards apply)", () => {
|
|
368
377
|
const resolver = buildResolver(
|
|
369
378
|
[
|
|
370
379
|
{
|
|
371
380
|
moduleId: PARENT_MOD_ID,
|
|
372
|
-
slug: "
|
|
373
|
-
html:
|
|
381
|
+
slug: "mega",
|
|
382
|
+
html: "<nav>{{#mega}}{{#columns}}{{#is_promo}}<div>{{>teaser}}</div>{{/is_promo}}{{/columns}}{{/mega}}</nav>",
|
|
374
383
|
css: "",
|
|
375
384
|
js: "",
|
|
376
|
-
fields: [
|
|
385
|
+
fields: [
|
|
386
|
+
{
|
|
387
|
+
name: "mega",
|
|
388
|
+
kind: "list",
|
|
389
|
+
listType: "mega-menu",
|
|
390
|
+
bind: "shared",
|
|
391
|
+
list: `caelo:list/${LIST.mega}`,
|
|
392
|
+
},
|
|
393
|
+
],
|
|
377
394
|
},
|
|
378
|
-
],
|
|
379
|
-
[
|
|
380
395
|
{
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
{ label: "Contact", href: "/contact" },
|
|
388
|
-
],
|
|
389
|
-
},
|
|
390
|
-
deletedAt: null,
|
|
396
|
+
moduleId: MODULE.teaser,
|
|
397
|
+
slug: "teaser",
|
|
398
|
+
html: "<p>{{title}}</p>",
|
|
399
|
+
css: "",
|
|
400
|
+
js: "",
|
|
401
|
+
fields: [{ name: "title", kind: "text" }],
|
|
391
402
|
},
|
|
392
403
|
],
|
|
404
|
+
[
|
|
405
|
+
{ id: PARENT_CI_ID, moduleId: PARENT_MOD_ID, values: {}, deletedAt: null },
|
|
406
|
+
{ id: INSTANCE.teaser, moduleId: MODULE.teaser, values: { title: "Try" }, deletedAt: null },
|
|
407
|
+
],
|
|
393
408
|
);
|
|
394
|
-
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
409
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver, undefined, lists);
|
|
395
410
|
expect(r.html).toBe(
|
|
396
|
-
|
|
411
|
+
`<nav><div data-caelo-list-item="${LIST.mega}/${ITEM.promo}"><p ${tag(MODULE.teaser)}>Try</p></div></nav>`,
|
|
397
412
|
);
|
|
413
|
+
expect(r.touchedModuleIds.has(MODULE.teaser)).toBe(true);
|
|
398
414
|
expect(r.missingSlots).toEqual([]);
|
|
399
415
|
});
|
|
400
416
|
|
|
401
|
-
it("
|
|
417
|
+
it("a broken embedded module is attributed to the list entry", () => {
|
|
402
418
|
const resolver = buildResolver(
|
|
403
419
|
[
|
|
404
420
|
{
|
|
405
421
|
moduleId: PARENT_MOD_ID,
|
|
406
|
-
slug: "
|
|
407
|
-
html:
|
|
422
|
+
slug: "mega",
|
|
423
|
+
html: "{{#mega}}{{#columns}}{{#is_promo}}{{>teaser}}{{/is_promo}}{{/columns}}{{/mega}}",
|
|
408
424
|
css: "",
|
|
409
425
|
js: "",
|
|
410
|
-
fields: [
|
|
426
|
+
fields: [
|
|
427
|
+
{
|
|
428
|
+
name: "mega",
|
|
429
|
+
kind: "list",
|
|
430
|
+
listType: "mega-menu",
|
|
431
|
+
bind: "shared",
|
|
432
|
+
list: `caelo:list/${LIST.mega}`,
|
|
433
|
+
},
|
|
434
|
+
],
|
|
411
435
|
},
|
|
412
436
|
],
|
|
413
|
-
[
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
437
|
+
[{ id: PARENT_CI_ID, moduleId: PARENT_MOD_ID, values: {}, deletedAt: null }],
|
|
438
|
+
);
|
|
439
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver, undefined, lists);
|
|
440
|
+
expect(r.failures).toEqual([
|
|
441
|
+
{ field: `mega[${ITEM.promo}].teaser`, reason: `module-missing:${MODULE.teaser}` },
|
|
442
|
+
]);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it("collectNestedRefs finds module fields inside local list entries", () => {
|
|
446
|
+
expect(
|
|
447
|
+
collectNestedRefs({
|
|
448
|
+
mega: [
|
|
449
|
+
{
|
|
450
|
+
id: T(1),
|
|
451
|
+
node: "entry",
|
|
452
|
+
values: {},
|
|
453
|
+
children: [
|
|
454
|
+
{
|
|
455
|
+
id: T(2),
|
|
456
|
+
node: "promo",
|
|
457
|
+
values: { teaser: { moduleId: MODULE.teaser, contentInstanceId: INSTANCE.teaser } },
|
|
458
|
+
},
|
|
422
459
|
],
|
|
423
460
|
},
|
|
424
|
-
|
|
461
|
+
],
|
|
462
|
+
}),
|
|
463
|
+
).toEqual([{ moduleId: MODULE.teaser, contentInstanceId: INSTANCE.teaser }]);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it("rewriteNestedRefs remaps every ref collectNestedRefs finds and copies the rest", () => {
|
|
467
|
+
const COPY = "00000000-0000-4000-8000-00000000c0c0";
|
|
468
|
+
const values = {
|
|
469
|
+
heading: "Keep me",
|
|
470
|
+
cta: { moduleId: MODULE.teaser, contentInstanceId: INSTANCE.teaser },
|
|
471
|
+
cards: [{ moduleId: MODULE.teaser, contentInstanceId: INSTANCE.teaser }],
|
|
472
|
+
mega: [
|
|
473
|
+
{
|
|
474
|
+
id: T(1),
|
|
475
|
+
node: "entry",
|
|
476
|
+
values: { label: "Entry" },
|
|
477
|
+
children: [
|
|
478
|
+
{
|
|
479
|
+
id: T(2),
|
|
480
|
+
node: "promo",
|
|
481
|
+
values: { teaser: { moduleId: MODULE.teaser, contentInstanceId: INSTANCE.teaser } },
|
|
482
|
+
},
|
|
483
|
+
],
|
|
425
484
|
},
|
|
426
485
|
],
|
|
486
|
+
};
|
|
487
|
+
const rewritten = rewriteNestedRefs(values, (id) => {
|
|
488
|
+
if (id !== INSTANCE.teaser) throw new Error(`no copy for ${id}`);
|
|
489
|
+
return COPY;
|
|
490
|
+
});
|
|
491
|
+
expect(collectNestedRefs(rewritten)).toEqual([
|
|
492
|
+
{ moduleId: MODULE.teaser, contentInstanceId: COPY },
|
|
493
|
+
{ moduleId: MODULE.teaser, contentInstanceId: COPY },
|
|
494
|
+
{ moduleId: MODULE.teaser, contentInstanceId: COPY },
|
|
495
|
+
]);
|
|
496
|
+
expect(rewritten.heading).toBe("Keep me");
|
|
497
|
+
expect((rewritten.mega as { values: unknown }[])[0]?.values).toEqual({ label: "Entry" });
|
|
498
|
+
// The source is not mutated.
|
|
499
|
+
expect(collectNestedRefs(values).every((r) => r.contentInstanceId === INSTANCE.teaser)).toBe(
|
|
500
|
+
true,
|
|
427
501
|
);
|
|
428
|
-
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
429
|
-
expect(r.html).toContain('<a href="/">Home</a>');
|
|
430
|
-
expect(r.html).toContain('<a href="/about">About</a>');
|
|
431
|
-
expect(r.html).toContain("link-list-malformed");
|
|
432
|
-
expect(r.missingSlots.some((s) => s.startsWith("link-list-malformed"))).toBe(true);
|
|
433
502
|
});
|
|
434
503
|
});
|
|
435
504
|
|
|
@@ -668,7 +737,7 @@ describe("renderModuleWithContent — engine-routing parity (#71)", () => {
|
|
|
668
737
|
});
|
|
669
738
|
|
|
670
739
|
it("kind-mismatch on {{>name}} against a list field emits the exact legacy string", () => {
|
|
671
|
-
const expected = "kind-mismatch:items expected=module actual=
|
|
740
|
+
const expected = "kind-mismatch:items expected=module actual=list";
|
|
672
741
|
const resolver = buildResolver(
|
|
673
742
|
[
|
|
674
743
|
{
|
|
@@ -677,7 +746,7 @@ describe("renderModuleWithContent — engine-routing parity (#71)", () => {
|
|
|
677
746
|
html: "<aside>{{>items}}</aside>",
|
|
678
747
|
css: "",
|
|
679
748
|
js: "",
|
|
680
|
-
fields: [{ name: "items", kind: "
|
|
749
|
+
fields: [{ name: "items", kind: "list", listType: "texts" }],
|
|
681
750
|
},
|
|
682
751
|
],
|
|
683
752
|
[{ id: PARENT_CI_ID, moduleId: PARENT_MOD_ID, values: {}, deletedAt: null }],
|
|
@@ -713,32 +782,36 @@ describe("renderModuleWithContent — engine-routing parity (#71)", () => {
|
|
|
713
782
|
expect(r.missingSlots).toContain("module-ref-malformed:hero");
|
|
714
783
|
});
|
|
715
784
|
|
|
716
|
-
it("
|
|
785
|
+
it("list-malformed names the entry path and keeps the section raw", () => {
|
|
717
786
|
const resolver = buildResolver(
|
|
718
787
|
[
|
|
719
788
|
{
|
|
720
789
|
moduleId: PARENT_MOD_ID,
|
|
721
|
-
slug: "
|
|
722
|
-
html: "<ul>{{#items}}<li>{{
|
|
790
|
+
slug: "list-malformed",
|
|
791
|
+
html: "<ul>{{#items}}<li>{{text}}</li>{{/items}}</ul>",
|
|
723
792
|
css: "",
|
|
724
793
|
js: "",
|
|
725
|
-
fields: [{ name: "items", kind: "
|
|
794
|
+
fields: [{ name: "items", kind: "list", listType: "texts" }],
|
|
726
795
|
},
|
|
727
796
|
],
|
|
728
797
|
[
|
|
729
798
|
{
|
|
730
799
|
id: PARENT_CI_ID,
|
|
731
800
|
moduleId: PARENT_MOD_ID,
|
|
732
|
-
values: {
|
|
801
|
+
values: {
|
|
802
|
+
items: [
|
|
803
|
+
{ id: "00000000-0000-4000-9000-000000000001", node: "text", values: { text: "a" } },
|
|
804
|
+
{ bogus: true },
|
|
805
|
+
],
|
|
806
|
+
},
|
|
733
807
|
deletedAt: null,
|
|
734
808
|
},
|
|
735
809
|
],
|
|
736
810
|
);
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
expect(r.html).
|
|
740
|
-
expect(r.
|
|
741
|
-
expect(r.missingSlots).toContain("text-list-malformed:items[1]");
|
|
811
|
+
const lists = createListRenderContext(fixtureData()).forPage(null);
|
|
812
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver, undefined, lists);
|
|
813
|
+
expect(r.html).toBe("<ul>{{#items}}<li>{{text}}</li>{{/items}}</ul>");
|
|
814
|
+
expect(r.missingSlots).toContain("list-malformed:items[items[1]]");
|
|
742
815
|
});
|
|
743
816
|
|
|
744
817
|
it("module-list-malformed per element preserves the exact legacy marker", () => {
|