@caelo-cms/shared 0.10.65 → 0.10.66
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/markup-structure.d.ts +9 -1
- package/dist/markup-structure.d.ts.map +1 -1
- package/dist/markup-structure.js +90 -13
- package/dist/markup-structure.js.map +1 -1
- package/dist/module-id-tag.d.ts +26 -0
- package/dist/module-id-tag.d.ts.map +1 -0
- package/dist/module-id-tag.js +39 -0
- package/dist/module-id-tag.js.map +1 -0
- package/dist/nested-module-render.d.ts +4 -0
- package/dist/nested-module-render.d.ts.map +1 -1
- package/dist/nested-module-render.js +7 -1
- package/dist/nested-module-render.js.map +1 -1
- package/dist/preview-compose.d.ts +2 -1
- package/dist/preview-compose.d.ts.map +1 -1
- package/dist/preview-compose.js +3 -24
- package/dist/preview-compose.js.map +1 -1
- package/dist/release-manifest.d.ts +5 -0
- package/dist/release-manifest.d.ts.map +1 -1
- package/dist/release-manifest.js +13 -0
- package/dist/release-manifest.js.map +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/markup-structure.test.ts +85 -0
- package/src/markup-structure.ts +104 -10
- package/src/module-id-tag.ts +38 -0
- package/src/nested-module-render.test.ts +98 -5
- package/src/nested-module-render.ts +14 -1
- package/src/preview-compose-nested.test.ts +7 -2
- package/src/preview-compose.ts +4 -22
- package/src/release-manifest.ts +13 -0
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-manifest.js","sourceRoot":"","sources":["../src/release-manifest.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"release-manifest.js","sourceRoot":"","sources":["../src/release-manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* Format: SemVer 2.0.0. Pre-1.0 minor bumps are breaking; post-1.0
|
|
20
20
|
* follow standard SemVer.
|
|
21
21
|
*/
|
|
22
|
-
export declare const CAELO_VERSION = "0.10.
|
|
22
|
+
export declare const CAELO_VERSION = "0.10.66";
|
|
23
23
|
/**
|
|
24
24
|
* Deprecated alias for back-compat — early P17 work spelled this
|
|
25
25
|
* `CALEO_VERSION` (typo of "Caelo"). New code should import
|
|
@@ -31,7 +31,7 @@ export declare const CAELO_VERSION = "0.10.65";
|
|
|
31
31
|
*
|
|
32
32
|
* @deprecated use CAELO_VERSION
|
|
33
33
|
*/
|
|
34
|
-
export declare const CALEO_VERSION = "0.10.
|
|
34
|
+
export declare const CALEO_VERSION = "0.10.66";
|
|
35
35
|
/**
|
|
36
36
|
* Parsed shape — major/minor/patch + optional pre-release tag.
|
|
37
37
|
* Stable interface for callers that need to feature-gate (rare —
|
package/dist/version.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* Format: SemVer 2.0.0. Pre-1.0 minor bumps are breaking; post-1.0
|
|
21
21
|
* follow standard SemVer.
|
|
22
22
|
*/
|
|
23
|
-
export const CAELO_VERSION = "0.10.
|
|
23
|
+
export const CAELO_VERSION = "0.10.66";
|
|
24
24
|
/**
|
|
25
25
|
* Deprecated alias for back-compat — early P17 work spelled this
|
|
26
26
|
* `CALEO_VERSION` (typo of "Caelo"). New code should import
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caelo-cms/shared",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.66",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"description": "Shared Zod schemas + types + the two-pass HTML composer used by every Caelo CMS workspace package. Stable enough for plugin authors and embedders to depend on directly.",
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
stripMustache,
|
|
15
15
|
templateShape,
|
|
16
16
|
} from "./markup-structure.js";
|
|
17
|
+
import { tagModuleId } from "./module-id-tag.js";
|
|
17
18
|
|
|
18
19
|
const chain = (steps: string[]) =>
|
|
19
20
|
`<div class="chain">${steps
|
|
@@ -164,6 +165,90 @@ describe("templates and free regions", () => {
|
|
|
164
165
|
});
|
|
165
166
|
});
|
|
166
167
|
|
|
168
|
+
describe("#1027 — template children are matched by best fit, not first fit", () => {
|
|
169
|
+
// The three templates from the searchVIU audit: a classless (or less
|
|
170
|
+
// specific) left column before a classed right column. First-fit paired
|
|
171
|
+
// the left column's template node with the right column and reported
|
|
172
|
+
// the right column's own template markup as free HTML.
|
|
173
|
+
const DEMO_FORM =
|
|
174
|
+
'<div class="wrapc ctaform"><div><h2>{{title}}</h2><p>{{intro}}</p></div>' +
|
|
175
|
+
'<div class="box steps" data-steps data-topic="{{preselected_topic}}">' +
|
|
176
|
+
'<ol class="sbar"><li class="on">Thema</li><li>Kontakt</li><li>Termin</li></ol>' +
|
|
177
|
+
'<div class="step"><label>Thema</label><select name="topic"><option>SEO</option></select></div>' +
|
|
178
|
+
'<div class="step"><label>E-Mail</label><input type="email" name="email"></div>' +
|
|
179
|
+
'<div class="step"><button type="submit">Demo anfragen</button></div></div></div>';
|
|
180
|
+
const SPLIT_CHAT =
|
|
181
|
+
'<section class="split"><div class="rv"><h2>{{title}}</h2><p>{{lead}}</p></div>' +
|
|
182
|
+
'<div class="chat rv"><div class="q"><p>Wie steht meine Seite?</p></div>' +
|
|
183
|
+
'<div class="a"><p>Drei Seiten haben neue 404-Fehler.</p><ul><li>/a</li></ul></div></div></section>';
|
|
184
|
+
const HERO_WINDOW =
|
|
185
|
+
'<section class="hero"><div><h1>{{title}}</h1><p>{{lead}}</p><a class="btn" href="{{cta_href}}">{{cta}}</a></div>' +
|
|
186
|
+
'<div class="win"><div class="bar"><span></span><span></span></div>' +
|
|
187
|
+
'<div class="bd"><img src="{{image}}" alt=""><p class="cap">Monitoring</p></div></div></section>';
|
|
188
|
+
|
|
189
|
+
/** The rendered module: placeholders filled, root tagged as the composer does. */
|
|
190
|
+
const render = (template: string, fill = "x") =>
|
|
191
|
+
tagModuleId(template.replace(/\{\{\{?\w+\}?\}\}/g, fill), "m1");
|
|
192
|
+
const free = (template: string, rendered: string) => {
|
|
193
|
+
const root = moduleRoots(parseMarkup(rendered))[0];
|
|
194
|
+
if (!root) throw new Error("no module root");
|
|
195
|
+
return freeRegions(root, parseMarkup(stripMustache(template)));
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
for (const [name, template] of [
|
|
199
|
+
["Demo-Formular in drei Schritten (div before div.box.steps)", DEMO_FORM],
|
|
200
|
+
["Split mit KI-Chat (div.rv before div.chat.rv)", SPLIT_CHAT],
|
|
201
|
+
["Hero Produktseite mit Fenster (div before div.win)", HERO_WINDOW],
|
|
202
|
+
] as const) {
|
|
203
|
+
it(`${name}: its own rendered output has no free regions`, () => {
|
|
204
|
+
expect(free(template, render(template))).toEqual([]);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
it("a classless div before a div.card sibling: no free regions", () => {
|
|
209
|
+
const template =
|
|
210
|
+
'<div class="pair"><div><p>{{a}}</p></div><div class="card"><h3>{{t}}</h3><ul class="pts"><li>{{p}}</li></ul></div></div>';
|
|
211
|
+
expect(free(template, render(template))).toEqual([]);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("two classless siblings with different insides: the one that accounts wins", () => {
|
|
215
|
+
const template =
|
|
216
|
+
'<div class="two"><div><h2>{{t}}</h2><p>{{p}}</p></div><div><ul class="x"><li>{{i}}</li></ul></div></div>';
|
|
217
|
+
expect(free(template, render(template))).toEqual([]);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("a section repeating a classed child still matches every iteration", () => {
|
|
221
|
+
const template =
|
|
222
|
+
'<div class="grid"><div><h2>{{title}}</h2></div>{{#cards}}<div class="card"><p>{{.}}</p></div>{{/cards}}</div>';
|
|
223
|
+
const rendered = tagModuleId(
|
|
224
|
+
'<div class="grid"><div><h2>T</h2></div><div class="card"><p>a</p></div><div class="card"><p>b</p></div></div>',
|
|
225
|
+
"m1",
|
|
226
|
+
);
|
|
227
|
+
expect(free(template, rendered)).toEqual([]);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("stays fast when many rendered children each fit several template children", () => {
|
|
231
|
+
// Every rendered <div> fits all eight classless template <div>s, so the
|
|
232
|
+
// best-fit choice weighs each candidate; the per-pair memo keeps that
|
|
233
|
+
// linear in the rendered size.
|
|
234
|
+
const template = `<div class="wide">${"<div><div><p>{{t}}</p></div></div>".repeat(8)}</div>`;
|
|
235
|
+
const rendered = tagModuleId(
|
|
236
|
+
`<div class="wide">${"<div><div><p>x</p><span>y</span></div></div>".repeat(5000)}</div>`,
|
|
237
|
+
"m1",
|
|
238
|
+
);
|
|
239
|
+
const started = performance.now();
|
|
240
|
+
expect(free(template, rendered)?.length).toBe(5000);
|
|
241
|
+
expect(performance.now() - started).toBeLessThan(1000);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("markup pasted into a field value of such a template is still free (#820)", () => {
|
|
245
|
+
const pasted = chain(["a", "b"]);
|
|
246
|
+
const rendered = render(HERO_WINDOW).replace("<p>x</p>", `<p>x</p>${pasted}`);
|
|
247
|
+
const regions = free(HERO_WINDOW, rendered) ?? [];
|
|
248
|
+
expect(outermostPatterns(regions).map((f) => f.node.classes[0])).toEqual(["chain"]);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
167
252
|
describe("bounds", () => {
|
|
168
253
|
it("stops collecting elements at MAX_NODES", () => {
|
|
169
254
|
const html = "<div>".repeat(10) + "<i></i>".repeat(MAX_NODES + 100) + "</div>".repeat(10);
|
package/src/markup-structure.ts
CHANGED
|
@@ -256,7 +256,15 @@ export function templateShape(templateHtml: string): SubtreeShape | null {
|
|
|
256
256
|
* walked in step with the template tree; a rendered child that no template
|
|
257
257
|
* child can account for (same tag, template's classes all present) starts
|
|
258
258
|
* a free region. List sections still match, because every iteration of a
|
|
259
|
-
* section renders the same template child.
|
|
259
|
+
* section renders the same template child. Nested module roots
|
|
260
|
+
* (`data-caelo-module-id`) are skipped: their own template accounts for
|
|
261
|
+
* them.
|
|
262
|
+
*
|
|
263
|
+
* Several template children can account for one rendered child — a
|
|
264
|
+
* classless `<div>` accounts for any `<div>` — so the walk picks the best
|
|
265
|
+
* one ({@link pickTemplateChild}), not the first: taking the first paired
|
|
266
|
+
* a classless left column with the classed right column and reported the
|
|
267
|
+
* right column's template markup as free (#1027).
|
|
260
268
|
*
|
|
261
269
|
* @returns the free region roots, or null when the rendered root does not
|
|
262
270
|
* match the template root at all (a module the composer renders from
|
|
@@ -268,17 +276,103 @@ export function freeRegions(
|
|
|
268
276
|
): MarkupNode[] | null {
|
|
269
277
|
const tRoot = templateRoots[0];
|
|
270
278
|
if (!tRoot || !accounts(tRoot, rendered)) return null;
|
|
279
|
+
return [...attribute(rendered, tRoot, new Map()).free];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** How one rendered subtree attributes against one template subtree. */
|
|
283
|
+
interface Attribution {
|
|
284
|
+
/** The free region roots below the rendered node. */
|
|
285
|
+
readonly free: readonly MarkupNode[];
|
|
286
|
+
/** Elements inside those regions: the cost the best match minimises. */
|
|
287
|
+
readonly freeNodes: number;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
type AttributionMemo = Map<MarkupNode, Map<MarkupNode, Attribution>>;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Attribute the children of `r`, rendered from template node `t`.
|
|
294
|
+
* Memoised per (rendered, template) pair, because the best-match choice
|
|
295
|
+
* evaluates a rendered child against every candidate that accounts for
|
|
296
|
+
* it; each pair is computed once, so the walk stays polynomial.
|
|
297
|
+
*/
|
|
298
|
+
function attribute(r: MarkupNode, t: MarkupNode, memo: AttributionMemo): Attribution {
|
|
299
|
+
let byTemplate = memo.get(r);
|
|
300
|
+
const hit = byTemplate?.get(t);
|
|
301
|
+
if (hit) return hit;
|
|
271
302
|
const free: MarkupNode[] = [];
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
303
|
+
let freeNodes = 0;
|
|
304
|
+
// Template index of the previous rendered child's match: siblings
|
|
305
|
+
// render in template order (a section repeats one child in place).
|
|
306
|
+
let cursor = 0;
|
|
307
|
+
for (const c of r.children) {
|
|
308
|
+
if (c.moduleId !== null) continue;
|
|
309
|
+
const match = pickTemplateChild(c, t.children, cursor, memo);
|
|
310
|
+
if (match) {
|
|
311
|
+
cursor = match.index;
|
|
312
|
+
for (const f of match.attribution.free) free.push(f);
|
|
313
|
+
freeNodes += match.attribution.freeNodes;
|
|
314
|
+
} else {
|
|
315
|
+
free.push(c);
|
|
316
|
+
freeNodes += countNodes(c);
|
|
278
317
|
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
|
|
318
|
+
}
|
|
319
|
+
const out: Attribution = { free, freeNodes };
|
|
320
|
+
if (!byTemplate) {
|
|
321
|
+
byTemplate = new Map();
|
|
322
|
+
memo.set(r, byTemplate);
|
|
323
|
+
}
|
|
324
|
+
byTemplate.set(t, out);
|
|
325
|
+
return out;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* The template child that rendered `c`, among those that account for it:
|
|
330
|
+
* 1. the exact class set wins over a subset (`div.chat.rv` over `div.rv`),
|
|
331
|
+
* 2. then the most classes in common, so a classless template child
|
|
332
|
+
* wins only when no classed one accounts for `c`,
|
|
333
|
+
* 3. then the one whose subtree leaves the fewest elements unaccounted,
|
|
334
|
+
* 4. then sibling order: at or after the previous match, nearest first.
|
|
335
|
+
*/
|
|
336
|
+
function pickTemplateChild(
|
|
337
|
+
c: MarkupNode,
|
|
338
|
+
candidates: readonly MarkupNode[],
|
|
339
|
+
cursor: number,
|
|
340
|
+
memo: AttributionMemo,
|
|
341
|
+
): { readonly index: number; readonly attribution: Attribution } | null {
|
|
342
|
+
let best: {
|
|
343
|
+
readonly index: number;
|
|
344
|
+
readonly attribution: Attribution;
|
|
345
|
+
readonly rank: readonly number[];
|
|
346
|
+
} | null = null;
|
|
347
|
+
for (const [index, tc] of candidates.entries()) {
|
|
348
|
+
if (!accounts(tc, c)) continue;
|
|
349
|
+
const attribution = attribute(c, tc, memo);
|
|
350
|
+
const rank = [
|
|
351
|
+
tc.classes.length === c.classes.length ? 1 : 0,
|
|
352
|
+
tc.classes.length,
|
|
353
|
+
-attribution.freeNodes,
|
|
354
|
+
index >= cursor ? 1 : 0,
|
|
355
|
+
-Math.abs(index - cursor),
|
|
356
|
+
];
|
|
357
|
+
if (!best || outranks(rank, best.rank)) best = { index, attribution, rank };
|
|
358
|
+
}
|
|
359
|
+
return best;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function outranks(a: readonly number[], b: readonly number[]): boolean {
|
|
363
|
+
for (let i = 0; i < a.length; i++) {
|
|
364
|
+
const x = a[i] ?? 0;
|
|
365
|
+
const y = b[i] ?? 0;
|
|
366
|
+
if (x !== y) return x > y;
|
|
367
|
+
}
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Elements in a subtree, nested module roots excluded (they are not free). */
|
|
372
|
+
function countNodes(n: MarkupNode): number {
|
|
373
|
+
let count = 1;
|
|
374
|
+
for (const c of n.children) if (c.moduleId === null) count += countNodes(c);
|
|
375
|
+
return count;
|
|
282
376
|
}
|
|
283
377
|
|
|
284
378
|
function accounts(template: MarkupNode, rendered: MarkupNode): boolean {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The `data-caelo-module-id` stamp on a module's root element. Every
|
|
5
|
+
* module root carries it, page placements (the composer) and nested
|
|
6
|
+
* modules in `module` / `module-list` fields (nested-module-render.ts)
|
|
7
|
+
* alike, so anything reading rendered HTML — the live-edit overlay, the
|
|
8
|
+
* core `structure` and `links` quality checks — can tell which module
|
|
9
|
+
* rendered which element without another mapping (#1027).
|
|
10
|
+
*
|
|
11
|
+
* Its own file because both the composer and the nested renderer use
|
|
12
|
+
* it, and the composer already imports the nested renderer.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** The attribute every module root carries. */
|
|
16
|
+
export const MODULE_ID_ATTRIBUTE = "data-caelo-module-id";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Insert `data-caelo-module-id="<id>"` into the first opening tag of
|
|
20
|
+
* the module's HTML. Idempotent — an already-tagged first element keeps
|
|
21
|
+
* its id, so a nested module that renders as its parent's first element
|
|
22
|
+
* stays attributed to itself. Comments / DOCTYPE / leading whitespace
|
|
23
|
+
* before the first tag are tolerated. HTML without an opening tag (pure
|
|
24
|
+
* text, a failure comment) returns unchanged because there's nothing to
|
|
25
|
+
* attach to.
|
|
26
|
+
*
|
|
27
|
+
* @example tagModuleId("<p>hi</p>", "abc") // '<p data-caelo-module-id="abc">hi</p>'
|
|
28
|
+
*/
|
|
29
|
+
export function tagModuleId(html: string, moduleId: string): string {
|
|
30
|
+
if (!html) return html;
|
|
31
|
+
const firstOpen = /<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/;
|
|
32
|
+
const m = firstOpen.exec(html);
|
|
33
|
+
if (!m) return html;
|
|
34
|
+
const tagAttrs = m[2] ?? "";
|
|
35
|
+
if (/\sdata-caelo-module-id\s*=/.test(tagAttrs)) return html;
|
|
36
|
+
const replaced = `<${m[1]}${tagAttrs} ${MODULE_ID_ATTRIBUTE}="${moduleId}">`;
|
|
37
|
+
return html.slice(0, m.index) + replaced + html.slice(m.index + m[0].length);
|
|
38
|
+
}
|
|
@@ -53,6 +53,9 @@ const PARENT_CI_ID = "00000000-0000-0000-0000-00000000bbb1";
|
|
|
53
53
|
const CHILD_CI_ID = "00000000-0000-0000-0000-00000000bbb2";
|
|
54
54
|
const GRAND_CI_ID = "00000000-0000-0000-0000-00000000bbb3";
|
|
55
55
|
|
|
56
|
+
/** The id stamp every nested module root carries (#1027). */
|
|
57
|
+
const tag = (moduleId: string) => `data-caelo-module-id="${moduleId}"`;
|
|
58
|
+
|
|
56
59
|
describe("renderModuleWithContent — primitive substitution", () => {
|
|
57
60
|
it("replaces {{name}} with values[name] and tracks the touched module", () => {
|
|
58
61
|
const resolver = buildResolver(
|
|
@@ -154,7 +157,9 @@ describe("renderModuleWithContent — nested module slots", () => {
|
|
|
154
157
|
],
|
|
155
158
|
);
|
|
156
159
|
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
157
|
-
expect(r.html).toBe(
|
|
160
|
+
expect(r.html).toBe(
|
|
161
|
+
`<section><div ${tag(CHILD_MOD_ID)}><span ${tag(GRAND_MOD_ID)}>deep</span></div></section>`,
|
|
162
|
+
);
|
|
158
163
|
expect(r.missingSlots).toEqual([]);
|
|
159
164
|
// All three modules touched — caller uses this set for CSS/JS dedup.
|
|
160
165
|
expect(r.touchedModuleIds.has(PARENT_MOD_ID)).toBe(true);
|
|
@@ -201,7 +206,7 @@ describe("renderModuleWithContent — nested module slots", () => {
|
|
|
201
206
|
],
|
|
202
207
|
);
|
|
203
208
|
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
204
|
-
expect(r.html).toBe(
|
|
209
|
+
expect(r.html).toBe(`<ul><li ${tag(CHILD_MOD_ID)}>A</li><li ${tag(CHILD_MOD_ID)}>B</li></ul>`);
|
|
205
210
|
expect(r.missingSlots).toEqual([]);
|
|
206
211
|
});
|
|
207
212
|
});
|
|
@@ -697,7 +702,7 @@ describe("renderModuleWithContent — engine-routing parity (#71)", () => {
|
|
|
697
702
|
],
|
|
698
703
|
);
|
|
699
704
|
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
700
|
-
expect(r.html).toContain(
|
|
705
|
+
expect(r.html).toContain(`<article ${tag(CHILD_MOD_ID)}>OK</article>`);
|
|
701
706
|
expect(r.html).toContain("<!-- caelo:missing reason=module-list-malformed cards[1] -->");
|
|
702
707
|
expect(r.missingSlots).toContain("module-list-malformed:cards[1]");
|
|
703
708
|
});
|
|
@@ -781,7 +786,9 @@ describe("renderPlacedModule — the composer's entry point", () => {
|
|
|
781
786
|
resolver,
|
|
782
787
|
{},
|
|
783
788
|
);
|
|
784
|
-
expect(r.html).toBe(
|
|
789
|
+
expect(r.html).toBe(
|
|
790
|
+
`<section><div ${tag(CHILD_MOD_ID)}>Pro<a ${tag(GRAND_MOD_ID)}>Buy</a></div></section>`,
|
|
791
|
+
);
|
|
785
792
|
expect(r.failures).toEqual([]);
|
|
786
793
|
expect([...r.touchedModuleIds].sort()).toEqual([CHILD_MOD_ID, GRAND_MOD_ID].sort());
|
|
787
794
|
});
|
|
@@ -848,7 +855,7 @@ describe("renderPlacedModule — only template-referenced nested fields render",
|
|
|
848
855
|
resolver,
|
|
849
856
|
{},
|
|
850
857
|
);
|
|
851
|
-
expect(r.html).toBe(
|
|
858
|
+
expect(r.html).toBe(`<section><article ${tag(CHILD_MOD_ID)}>Pro</article></section>`);
|
|
852
859
|
expect(r.failures).toEqual([]);
|
|
853
860
|
expect(r.missingSlots).toEqual([]);
|
|
854
861
|
expect([...r.touchedModuleIds]).toEqual([CHILD_MOD_ID]);
|
|
@@ -885,3 +892,89 @@ describe("renderPlacedModule — only template-referenced nested fields render",
|
|
|
885
892
|
expect(r.failures).toEqual([{ field: "card", reason: `content-instance-missing:${GONE_CI}` }]);
|
|
886
893
|
});
|
|
887
894
|
});
|
|
895
|
+
|
|
896
|
+
describe("#1027 — nested module roots carry data-caelo-module-id", () => {
|
|
897
|
+
// The FAQ case from the searchVIU install: a module-list of FAQ items.
|
|
898
|
+
const faq: NestedModuleResource = {
|
|
899
|
+
moduleId: PARENT_MOD_ID,
|
|
900
|
+
slug: "faq",
|
|
901
|
+
html: '<div class="faq">{{#items}}{{/items}}{{>featured}}</div>',
|
|
902
|
+
css: "",
|
|
903
|
+
js: "",
|
|
904
|
+
fields: [
|
|
905
|
+
{ name: "items", kind: "module-list" },
|
|
906
|
+
{ name: "featured", kind: "module" },
|
|
907
|
+
],
|
|
908
|
+
};
|
|
909
|
+
const item: NestedModuleResource = {
|
|
910
|
+
moduleId: CHILD_MOD_ID,
|
|
911
|
+
slug: "faq-entry",
|
|
912
|
+
html: "<details><summary>{{question}}</summary><p>{{answer}}</p></details>",
|
|
913
|
+
css: "",
|
|
914
|
+
js: "",
|
|
915
|
+
fields: [
|
|
916
|
+
{ name: "question", kind: "text" },
|
|
917
|
+
{ name: "answer", kind: "text" },
|
|
918
|
+
],
|
|
919
|
+
};
|
|
920
|
+
const values = {
|
|
921
|
+
items: [
|
|
922
|
+
{ moduleId: CHILD_MOD_ID, contentInstanceId: CHILD_CI_ID },
|
|
923
|
+
{ moduleId: CHILD_MOD_ID, contentInstanceId: GRAND_CI_ID },
|
|
924
|
+
],
|
|
925
|
+
featured: { moduleId: CHILD_MOD_ID, contentInstanceId: CHILD_CI_ID },
|
|
926
|
+
};
|
|
927
|
+
const resolver = buildResolver(
|
|
928
|
+
[faq, item],
|
|
929
|
+
[
|
|
930
|
+
{ id: PARENT_CI_ID, moduleId: PARENT_MOD_ID, values, deletedAt: null },
|
|
931
|
+
{
|
|
932
|
+
id: CHILD_CI_ID,
|
|
933
|
+
moduleId: CHILD_MOD_ID,
|
|
934
|
+
values: { question: "Q1", answer: "A1" },
|
|
935
|
+
deletedAt: null,
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
id: GRAND_CI_ID,
|
|
939
|
+
moduleId: CHILD_MOD_ID,
|
|
940
|
+
values: { question: "Q2", answer: "A2" },
|
|
941
|
+
deletedAt: null,
|
|
942
|
+
},
|
|
943
|
+
],
|
|
944
|
+
);
|
|
945
|
+
const expected =
|
|
946
|
+
`<div class="faq"><details ${tag(CHILD_MOD_ID)}><summary>Q1</summary><p>A1</p></details>` +
|
|
947
|
+
`<details ${tag(CHILD_MOD_ID)}><summary>Q2</summary><p>A2</p></details>` +
|
|
948
|
+
`<details ${tag(CHILD_MOD_ID)}><summary>Q1</summary><p>A1</p></details></div>`;
|
|
949
|
+
|
|
950
|
+
it("tags module and module-list roots in the editor preview path", () => {
|
|
951
|
+
const r = renderModuleWithContent(PARENT_MOD_ID, PARENT_CI_ID, resolver);
|
|
952
|
+
// The placed module's own root is left to the composer (tagModuleId).
|
|
953
|
+
expect(r.html).toBe(expected);
|
|
954
|
+
expect(r.failures).toEqual([]);
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
it("tags them identically in the composer / static build path", () => {
|
|
958
|
+
const r = renderPlacedModule({ html: faq.html, fields: faq.fields, values }, resolver, {});
|
|
959
|
+
expect(r.html).toBe(expected);
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
it("leaves a failure comment untagged (no element to carry the id)", () => {
|
|
963
|
+
const r = renderPlacedModule(
|
|
964
|
+
{
|
|
965
|
+
html: faq.html,
|
|
966
|
+
fields: faq.fields,
|
|
967
|
+
values: {
|
|
968
|
+
items: [{ moduleId: CHILD_MOD_ID, contentInstanceId: "missing" }],
|
|
969
|
+
featured: values.featured,
|
|
970
|
+
},
|
|
971
|
+
},
|
|
972
|
+
resolver,
|
|
973
|
+
{},
|
|
974
|
+
);
|
|
975
|
+
expect(r.html).toBe(
|
|
976
|
+
'<div class="faq"><!-- caelo:missing reason=content-instance-missing missing -->' +
|
|
977
|
+
`<details ${tag(CHILD_MOD_ID)}><summary>Q1</summary><p>A1</p></details></div>`,
|
|
978
|
+
);
|
|
979
|
+
});
|
|
980
|
+
});
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
* comment + missingSlots entry. Same channel; the operator sees the
|
|
52
52
|
* gap in the preview, and the static generator refuses the build.
|
|
53
53
|
*
|
|
54
|
+
* Module ids: the root element of every nested module render carries
|
|
55
|
+
* `data-caelo-module-id` (#1027), the same stamp the composer puts on a
|
|
56
|
+
* page placement's root, in the preview and the static build alike.
|
|
57
|
+
*
|
|
54
58
|
* CSS + JS dedup: every unique module touched during recursion
|
|
55
59
|
* contributes its CSS + JS once. The caller collects the seen-set out
|
|
56
60
|
* of band so the page's <head>/<style> + footer scripts are stable.
|
|
@@ -58,6 +62,7 @@
|
|
|
58
62
|
|
|
59
63
|
import type { ModuleFieldKind } from "./content.js";
|
|
60
64
|
import { isLinkFailureMarker, type LinkResolver } from "./link-refs.js";
|
|
65
|
+
import { tagModuleId } from "./module-id-tag.js";
|
|
61
66
|
import { caeloMissingComment, renderTemplate, type TemplateField } from "./template-engine.js";
|
|
62
67
|
|
|
63
68
|
const MAX_RECURSION_DEPTH = 8;
|
|
@@ -343,7 +348,15 @@ function renderPartial(
|
|
|
343
348
|
): string | undefined {
|
|
344
349
|
const hit = nestedRefForPartial(key, fieldByName, values);
|
|
345
350
|
if (!hit) return undefined;
|
|
346
|
-
|
|
351
|
+
// #1027 — a nested module's root carries its own id, exactly like a
|
|
352
|
+
// page placement's (the composer tags those), so the live-edit overlay
|
|
353
|
+
// and the quality checks attribute its markup to the nested module
|
|
354
|
+
// instead of reading it as free HTML of the parent. A failure comment
|
|
355
|
+
// has no element and stays as it is.
|
|
356
|
+
return tagModuleId(
|
|
357
|
+
renderInner(hit.ref.moduleId, hit.ref.contentInstanceId, descend(ctx, hit.step)),
|
|
358
|
+
hit.ref.moduleId,
|
|
359
|
+
);
|
|
347
360
|
}
|
|
348
361
|
|
|
349
362
|
/**
|
|
@@ -30,6 +30,9 @@ const CARD_A = "00000000-0000-0000-0000-0000000ca001";
|
|
|
30
30
|
const CARD_B = "00000000-0000-0000-0000-0000000ca002";
|
|
31
31
|
const GONE = "00000000-0000-0000-0000-00000000dead";
|
|
32
32
|
|
|
33
|
+
/** The id stamp every nested module root carries (#1027). */
|
|
34
|
+
const tag = (moduleId: string) => `data-caelo-module-id="${moduleId}"`;
|
|
35
|
+
|
|
33
36
|
const card: NestedModuleResource = {
|
|
34
37
|
moduleId: CARD_MOD,
|
|
35
38
|
slug: "card",
|
|
@@ -89,7 +92,9 @@ describe("composePageWithLayout — nested modules", () => {
|
|
|
89
92
|
|
|
90
93
|
it("renders every module-list element with the nested resolver", () => {
|
|
91
94
|
const out = compose(grid(refs), resolver([card], instances));
|
|
92
|
-
expect(out.html).toContain(
|
|
95
|
+
expect(out.html).toContain(
|
|
96
|
+
`<article ${tag(CARD_MOD)}>Starter</article><article ${tag(CARD_MOD)}>Pro</article>`,
|
|
97
|
+
);
|
|
93
98
|
expect(out.html).not.toContain("needs recursive renderer");
|
|
94
99
|
expect(out.moduleFailures).toEqual([]);
|
|
95
100
|
});
|
|
@@ -104,7 +109,7 @@ describe("composePageWithLayout — nested modules", () => {
|
|
|
104
109
|
grid([refs[0], { moduleId: CARD_MOD, contentInstanceId: GONE }, "not-a-ref"]),
|
|
105
110
|
resolver([card], instances),
|
|
106
111
|
);
|
|
107
|
-
expect(out.html).toContain(
|
|
112
|
+
expect(out.html).toContain(`<article ${tag(CARD_MOD)}>Starter</article>`);
|
|
108
113
|
expect(out.moduleFailures).toEqual([
|
|
109
114
|
{
|
|
110
115
|
blockName: "content",
|
package/src/preview-compose.ts
CHANGED
|
@@ -29,6 +29,7 @@ import { BASE_TECHNICAL_CSS } from "./base-css.js";
|
|
|
29
29
|
import type { ModuleFieldKind } from "./content.js";
|
|
30
30
|
import { findInteractionIds, interactionAssets } from "./interactions.js";
|
|
31
31
|
import { type LinkResolver, resolveLinkRefsInHtml } from "./link-refs.js";
|
|
32
|
+
import { tagModuleId } from "./module-id-tag.js";
|
|
32
33
|
import {
|
|
33
34
|
type NestedModuleResource,
|
|
34
35
|
type NestedRenderFailure,
|
|
@@ -47,6 +48,9 @@ import { renderTemplate, type TemplateField } from "./template-engine.js";
|
|
|
47
48
|
import { renderThemeCss as renderThemeCssFromTokens } from "./theme-render.js";
|
|
48
49
|
import type { ThemeDocument } from "./themes.js";
|
|
49
50
|
|
|
51
|
+
// Re-exported so existing callers keep importing it from the composer.
|
|
52
|
+
export { tagModuleId };
|
|
53
|
+
|
|
50
54
|
export interface ComposeModule {
|
|
51
55
|
readonly moduleId: string;
|
|
52
56
|
readonly slug: string;
|
|
@@ -384,16 +388,6 @@ export function composePagePreview(input: ComposeInput): ComposeOutput {
|
|
|
384
388
|
};
|
|
385
389
|
}
|
|
386
390
|
|
|
387
|
-
/**
|
|
388
|
-
* Insert `data-caelo-module-id="<id>"` into the first opening tag of
|
|
389
|
-
* the module's HTML. Idempotent — re-tagging an already-tagged module
|
|
390
|
-
* is a no-op. Comments / DOCTYPE / leading whitespace before the first
|
|
391
|
-
* tag are tolerated. Modules that have no opening tag (pure text)
|
|
392
|
-
* return unchanged because there's nothing to attach to.
|
|
393
|
-
*
|
|
394
|
-
* Exported so callers (admin preview endpoint, static generator,
|
|
395
|
-
* tests) can reuse the same logic.
|
|
396
|
-
*/
|
|
397
391
|
/**
|
|
398
392
|
* P6.7.5 — return the items for a `nav-menu/<slug>` set when a module's
|
|
399
393
|
* slug starts with `nav-menu-`. Returns null when the module is not a
|
|
@@ -605,18 +599,6 @@ function recordFailures(
|
|
|
605
599
|
}
|
|
606
600
|
}
|
|
607
601
|
|
|
608
|
-
export function tagModuleId(html: string, moduleId: string): string {
|
|
609
|
-
if (!html) return html;
|
|
610
|
-
const firstOpen = /<([a-zA-Z][a-zA-Z0-9-]*)\b([^>]*)>/;
|
|
611
|
-
const m = firstOpen.exec(html);
|
|
612
|
-
if (!m) return html;
|
|
613
|
-
// Already tagged?
|
|
614
|
-
const tagAttrs = m[2] ?? "";
|
|
615
|
-
if (/\sdata-caelo-module-id\s*=/.test(tagAttrs)) return html;
|
|
616
|
-
const replaced = `<${m[1]}${tagAttrs} data-caelo-module-id="${moduleId}">`;
|
|
617
|
-
return html.slice(0, m.index) + replaced + html.slice(m.index + m[0].length);
|
|
618
|
-
}
|
|
619
|
-
|
|
620
602
|
/**
|
|
621
603
|
* P6.7.6 — layout-aware composer. Runs the template composer first,
|
|
622
604
|
* extracts the resulting body content, then renders the layout HTML
|
package/src/release-manifest.ts
CHANGED
|
@@ -40,6 +40,19 @@ export const ReleaseManifestSchema = z.object({
|
|
|
40
40
|
version: z.string().regex(SEMVER, "expected a SemVer version without a leading v"),
|
|
41
41
|
channel: z.enum(RELEASE_CHANNELS),
|
|
42
42
|
digests: z.object({ admin: digest, gateway: digest, ops: digest }),
|
|
43
|
+
/**
|
|
44
|
+
* #1025 — the linux/amd64 platform manifest inside each image index of
|
|
45
|
+
* `digests`. The release images are OCI indexes (buildx adds an
|
|
46
|
+
* attestation manifest even to a single-platform build), and Cloud Run
|
|
47
|
+
* records the platform manifest it resolved — not the index a deploy
|
|
48
|
+
* pinned — in a revision's `spec.containers[0].image` and
|
|
49
|
+
* `status.imageDigest`. Signing this form too lets an upgrader tell
|
|
50
|
+
* which release serves without a registry round trip. Absent on
|
|
51
|
+
* releases from before the field: optional, so manifestVersion stays 1
|
|
52
|
+
* and older readers ignore it; readers then list the index itself
|
|
53
|
+
* (content-addressed, so it cannot be forged either).
|
|
54
|
+
*/
|
|
55
|
+
platformDigests: z.object({ admin: digest, gateway: digest, ops: digest }).optional(),
|
|
43
56
|
minFromVersion: z.string().regex(SEMVER),
|
|
44
57
|
infraContractVersion: z.number().int().positive(),
|
|
45
58
|
migrations: z.object({
|