@refrakt-md/runes 0.38.0 → 0.40.0

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.
Files changed (106) hide show
  1. package/dist/attribute-presets.d.ts +3 -2
  2. package/dist/attribute-presets.d.ts.map +1 -1
  3. package/dist/attribute-presets.js +2 -1
  4. package/dist/attribute-presets.js.map +1 -1
  5. package/dist/collection-helpers.d.ts +21 -2
  6. package/dist/collection-helpers.d.ts.map +1 -1
  7. package/dist/collection-helpers.js +72 -15
  8. package/dist/collection-helpers.js.map +1 -1
  9. package/dist/composed-rune.d.ts +59 -0
  10. package/dist/composed-rune.d.ts.map +1 -0
  11. package/dist/composed-rune.js +129 -0
  12. package/dist/composed-rune.js.map +1 -0
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +73 -40
  15. package/dist/config.js.map +1 -1
  16. package/dist/data-pipeline.d.ts +24 -10
  17. package/dist/data-pipeline.d.ts.map +1 -1
  18. package/dist/data-pipeline.js +34 -56
  19. package/dist/data-pipeline.js.map +1 -1
  20. package/dist/file-ref-resolve.js +9 -13
  21. package/dist/file-ref-resolve.js.map +1 -1
  22. package/dist/index.d.ts +14 -4
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +19 -5
  25. package/dist/index.js.map +1 -1
  26. package/dist/lib/composition.d.ts +152 -0
  27. package/dist/lib/composition.d.ts.map +1 -0
  28. package/dist/lib/composition.js +1120 -0
  29. package/dist/lib/composition.js.map +1 -0
  30. package/dist/lib/index.d.ts +63 -4
  31. package/dist/lib/index.d.ts.map +1 -1
  32. package/dist/lib/index.js +137 -8
  33. package/dist/lib/index.js.map +1 -1
  34. package/dist/lib/preprocess.d.ts +64 -0
  35. package/dist/lib/preprocess.d.ts.map +1 -0
  36. package/dist/lib/preprocess.js +72 -0
  37. package/dist/lib/preprocess.js.map +1 -0
  38. package/dist/lib/registers.d.ts +132 -0
  39. package/dist/lib/registers.d.ts.map +1 -0
  40. package/dist/lib/registers.js +329 -0
  41. package/dist/lib/registers.js.map +1 -0
  42. package/dist/lib/resolver.d.ts +21 -1
  43. package/dist/lib/resolver.d.ts.map +1 -1
  44. package/dist/lib/resolver.js +41 -18
  45. package/dist/lib/resolver.js.map +1 -1
  46. package/dist/lib/schema-side-table.d.ts +26 -0
  47. package/dist/lib/schema-side-table.d.ts.map +1 -0
  48. package/dist/lib/schema-side-table.js +34 -0
  49. package/dist/lib/schema-side-table.js.map +1 -0
  50. package/dist/lib/schema-table.d.ts +59 -9
  51. package/dist/lib/schema-table.d.ts.map +1 -1
  52. package/dist/lib/schema-table.js +158 -22
  53. package/dist/lib/schema-table.js.map +1 -1
  54. package/dist/lib/slot-markers.d.ts +38 -0
  55. package/dist/lib/slot-markers.d.ts.map +1 -0
  56. package/dist/lib/slot-markers.js +105 -0
  57. package/dist/lib/slot-markers.js.map +1 -0
  58. package/dist/lib/slots.d.ts +99 -0
  59. package/dist/lib/slots.d.ts.map +1 -0
  60. package/dist/lib/slots.js +448 -0
  61. package/dist/lib/slots.js.map +1 -0
  62. package/dist/plugins.d.ts +3 -0
  63. package/dist/plugins.d.ts.map +1 -1
  64. package/dist/plugins.js +53 -4
  65. package/dist/plugins.js.map +1 -1
  66. package/dist/reference.d.ts +18 -0
  67. package/dist/reference.d.ts.map +1 -1
  68. package/dist/reference.js +34 -1
  69. package/dist/reference.js.map +1 -1
  70. package/dist/registers-pipeline.d.ts +51 -0
  71. package/dist/registers-pipeline.d.ts.map +1 -0
  72. package/dist/registers-pipeline.js +224 -0
  73. package/dist/registers-pipeline.js.map +1 -0
  74. package/dist/schema-row.d.ts +5 -0
  75. package/dist/schema-row.d.ts.map +1 -1
  76. package/dist/schema-row.js +1 -0
  77. package/dist/schema-row.js.map +1 -1
  78. package/dist/tags/data.d.ts +2 -2
  79. package/dist/tags/data.d.ts.map +1 -1
  80. package/dist/tags/data.js +6 -4
  81. package/dist/tags/data.js.map +1 -1
  82. package/dist/tags/figure.d.ts +10 -4
  83. package/dist/tags/figure.d.ts.map +1 -1
  84. package/dist/tags/figure.js +65 -20
  85. package/dist/tags/figure.js.map +1 -1
  86. package/dist/tags/include.d.ts +51 -7
  87. package/dist/tags/include.d.ts.map +1 -1
  88. package/dist/tags/include.js +216 -7
  89. package/dist/tags/include.js.map +1 -1
  90. package/dist/tags/sandbox.d.ts.map +1 -1
  91. package/dist/tags/sandbox.js +13 -3
  92. package/dist/tags/sandbox.js.map +1 -1
  93. package/dist/tags/snippet.d.ts +9 -10
  94. package/dist/tags/snippet.d.ts.map +1 -1
  95. package/dist/tags/snippet.js +213 -10
  96. package/dist/tags/snippet.js.map +1 -1
  97. package/dist/universal-attributes.d.ts +1 -1
  98. package/package.json +3 -3
  99. package/dist/include-pipeline.d.ts +0 -52
  100. package/dist/include-pipeline.d.ts.map +0 -1
  101. package/dist/include-pipeline.js +0 -206
  102. package/dist/include-pipeline.js.map +0 -1
  103. package/dist/snippet-pipeline.d.ts +0 -44
  104. package/dist/snippet-pipeline.d.ts.map +0 -1
  105. package/dist/snippet-pipeline.js +0 -307
  106. package/dist/snippet-pipeline.js.map +0 -1
@@ -0,0 +1,448 @@
1
+ /**
2
+ * The slot declaration — SPEC-143.
3
+ *
4
+ * A rune whose every output slot comes from exactly one resolved field, wrapped
5
+ * but not restructured (D4), states that as data on `createContentModelSchema`
6
+ * instead of writing a `transform`:
7
+ *
8
+ * ```ts
9
+ * emits: {
10
+ * rune: 'work',
11
+ * tag: 'article',
12
+ * properties: { id: '', status: 'draft' },
13
+ * slots: {
14
+ * title: { as: 'region', el: 'header' },
15
+ * blurb: { from: 'description', as: 'region', omitWhenEmpty: true },
16
+ * body: { from: 'sections', as: 'region' },
17
+ * },
18
+ * },
19
+ * ```
20
+ *
21
+ * `makeSlotTransform` turns that into an ordinary transform function — a closure
22
+ * over the declaration, built once when the schema is constructed — and the
23
+ * schema calls it at the same single call site a hand-written transform uses.
24
+ * Nothing downstream can tell the two apart, which is what makes the
25
+ * byte-identical migration gate (D7) a property of the construction rather than
26
+ * a hope.
27
+ *
28
+ * What the declaration may say, and nothing more (D2): a slot's name, the field
29
+ * (or attribute) it comes from, whether it is a single `value` or a `region` of
30
+ * nodes with a boundary element, and whether it is omitted when empty. It
31
+ * cannot nest one slot in another, order slots, or create containers — those
32
+ * belong to the engine's `layout`. Every value is data (D9), so the declaration
33
+ * round-trips through JSON unchanged.
34
+ */
35
+ import Markdoc from '@markdoc/markdoc';
36
+ import { createComponentRenderable } from './component.js';
37
+ import { fieldMetas } from './field-metas.js';
38
+ import { selectStructuralModel } from './resolver.js';
39
+ const { Tag } = Markdoc;
40
+ /** The closed vocabulary of section roles — mirrors `SectionRole`. */
41
+ const SECTION_ROLES = [
42
+ 'header',
43
+ 'preamble',
44
+ 'title',
45
+ 'description',
46
+ 'body',
47
+ 'footer',
48
+ 'media',
49
+ ];
50
+ const EMITS_KEYS = new Set(['rune', 'tag', 'property', 'properties', 'slots']);
51
+ const SLOT_KEYS = new Set(['from', 'as', 'el', 'omitWhenEmpty', 'role']);
52
+ /** Keys that would make a slot structural. Named so the refusal can say why (D2). */
53
+ const STRUCTURE_KEYS = new Set([
54
+ 'slots',
55
+ 'children',
56
+ 'nest',
57
+ 'nested',
58
+ 'into',
59
+ 'parent',
60
+ 'wrap',
61
+ 'wrapper',
62
+ 'container',
63
+ 'group',
64
+ 'order',
65
+ 'position',
66
+ 'before',
67
+ 'after',
68
+ 'layout',
69
+ ]);
70
+ const ELEMENT = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
71
+ const SLOT_NAME = /^[a-z][a-zA-Z0-9]*(-[a-zA-Z0-9]+)*$/;
72
+ const RUNE_NAME = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
73
+ /**
74
+ * Reject anything that would not survive `JSON.parse(JSON.stringify(…))`
75
+ * unchanged — a function above all (D9), but also `undefined`, a non-finite
76
+ * number, or a class instance such as a `RegExp`.
77
+ */
78
+ function assertPlainData(value, path, fail) {
79
+ if (typeof value === 'function') {
80
+ fail(`${path} is a function. The declaration is data only (SPEC-143 D9).`);
81
+ }
82
+ if (value === undefined) {
83
+ fail(`${path} is undefined, which does not survive a JSON round-trip — omit the key.`);
84
+ }
85
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
86
+ return;
87
+ if (typeof value === 'number') {
88
+ if (!Number.isFinite(value))
89
+ fail(`${path} is not a finite number.`);
90
+ return;
91
+ }
92
+ if (Array.isArray(value)) {
93
+ value.forEach((v, i) => assertPlainData(v, `${path}[${i}]`, fail));
94
+ return;
95
+ }
96
+ if (typeof value === 'object') {
97
+ const proto = Object.getPrototypeOf(value);
98
+ if (proto !== Object.prototype && proto !== null) {
99
+ fail(`${path} is a ${proto?.constructor?.name ?? 'class'} instance, not plain data.`);
100
+ }
101
+ for (const [k, v] of Object.entries(value)) {
102
+ assertPlainData(v, `${path}.${k}`, fail);
103
+ }
104
+ return;
105
+ }
106
+ fail(`${path} has unsupported type ${typeof value}.`);
107
+ }
108
+ /**
109
+ * Every field the content model can resolve, across conditional branches. A
110
+ * model given as a function of attributes is sampled with no attributes —
111
+ * enough for a model that only varies its details, which is every model this
112
+ * declaration supports.
113
+ */
114
+ function collectFields(model) {
115
+ const fields = new Map();
116
+ const unsupported = new Set();
117
+ const visit = (m) => {
118
+ if ('when' in m) {
119
+ m.when.forEach((b) => visit(b.model));
120
+ visit(m.default);
121
+ return;
122
+ }
123
+ const s = m;
124
+ if (s.type === 'sequence' || s.type === 'sections') {
125
+ for (const f of s.fields ?? []) {
126
+ const prev = fields.get(f.name);
127
+ fields.set(f.name, { greedy: !!f.greedy || !!prev?.greedy, sections: false });
128
+ }
129
+ if (s.type === 'sections')
130
+ fields.set('sections', { greedy: true, sections: true });
131
+ }
132
+ else {
133
+ unsupported.add(s.type);
134
+ }
135
+ };
136
+ visit(typeof model === 'function' ? model({}) : model);
137
+ return { fields, unsupported };
138
+ }
139
+ /**
140
+ * Check a declaration against the rune's content model and normalise it.
141
+ * Throws, naming the rune and the offending slot, rather than applying any part
142
+ * of a declaration it cannot honour.
143
+ */
144
+ export function validateEmits(emits, contentModel) {
145
+ const runeLabel = emits && typeof emits === 'object' && typeof emits.rune === 'string'
146
+ ? `"${emits.rune}"`
147
+ : '(unnamed)';
148
+ const fail = (msg) => {
149
+ throw new Error(`Rune ${runeLabel}: invalid \`emits\` declaration — ${msg}`);
150
+ };
151
+ if (!emits || typeof emits !== 'object' || Array.isArray(emits))
152
+ fail('must be an object.');
153
+ assertPlainData(emits, 'emits', fail);
154
+ for (const key of Object.keys(emits)) {
155
+ if (!EMITS_KEYS.has(key)) {
156
+ fail(STRUCTURE_KEYS.has(key)
157
+ ? `\`${key}\` would declare structure. The declaration names slots only; nesting, ordering and containers are \`layout\`'s (SPEC-143 D2).`
158
+ : `unknown key \`${key}\` (expected ${[...EMITS_KEYS].join(', ')}).`);
159
+ }
160
+ }
161
+ if (typeof emits.rune !== 'string' || !RUNE_NAME.test(emits.rune)) {
162
+ fail('`rune` must be the kebab-case rune name.');
163
+ }
164
+ if (typeof emits.tag !== 'string' || !ELEMENT.test(emits.tag)) {
165
+ fail('`tag` must be an element name.');
166
+ }
167
+ if (emits.property !== undefined && typeof emits.property !== 'string') {
168
+ fail('`property` must be a string.');
169
+ }
170
+ const propertyKeys = new Set();
171
+ if (emits.properties !== undefined) {
172
+ if (typeof emits.properties !== 'object' || Array.isArray(emits.properties)) {
173
+ fail('`properties` must be an object.');
174
+ }
175
+ for (const [key, entry] of Object.entries(emits.properties)) {
176
+ propertyKeys.add(key);
177
+ if (typeof entry === 'string')
178
+ continue;
179
+ const ok = entry &&
180
+ typeof entry === 'object' &&
181
+ Array.isArray(entry.from) &&
182
+ entry.from.every((s) => typeof s === 'string' && /^(attrs|file)\.\S+$/.test(s)) &&
183
+ typeof entry.default === 'string' &&
184
+ Object.keys(entry).every((k) => k === 'from' || k === 'default');
185
+ if (!ok) {
186
+ fail(`property \`${key}\` must be a default string or { from: ["attrs.<name>" | "file.<name>", …], default: string }.`);
187
+ }
188
+ }
189
+ }
190
+ if (!emits.slots || typeof emits.slots !== 'object' || Array.isArray(emits.slots)) {
191
+ fail('`slots` must be an object of slot entries.');
192
+ }
193
+ const slotNames = Object.keys(emits.slots);
194
+ if (slotNames.length === 0)
195
+ fail('`slots` declares no slot.');
196
+ const { fields, unsupported } = collectFields(contentModel);
197
+ const normalized = [];
198
+ for (const name of slotNames) {
199
+ const where = `slot \`${name}\``;
200
+ if (!SLOT_NAME.test(name))
201
+ fail(`${where}: not a valid data-name.`);
202
+ if (propertyKeys.has(name)) {
203
+ fail(`${where} is also a property. Properties and slots share one flat namespace (ADR-008), and the two would carry one name on two nodes.`);
204
+ }
205
+ const raw = emits.slots[name];
206
+ const decl = typeof raw === 'string' ? { as: raw } : raw;
207
+ if (!decl || typeof decl !== 'object' || Array.isArray(decl)) {
208
+ fail(`${where} must be "value", "region" or a slot declaration.`);
209
+ }
210
+ for (const key of Object.keys(decl)) {
211
+ if (SLOT_KEYS.has(key))
212
+ continue;
213
+ fail(STRUCTURE_KEYS.has(key)
214
+ ? `${where}: \`${key}\` would nest, order or contain slots. A slot is flat — that is \`layout\`'s job (SPEC-143 D2).`
215
+ : `${where}: unknown key \`${key}\` (expected ${[...SLOT_KEYS].join(', ')}).`);
216
+ }
217
+ if (decl.as !== 'value' && decl.as !== 'region') {
218
+ fail(`${where}: \`as\` must be "value" or "region".`);
219
+ }
220
+ if (decl.el !== undefined && (typeof decl.el !== 'string' || !ELEMENT.test(decl.el))) {
221
+ fail(`${where}: \`el\` must be a single element name — a slot has one boundary, never a nested one (SPEC-143 D2).`);
222
+ }
223
+ if (decl.omitWhenEmpty !== undefined && typeof decl.omitWhenEmpty !== 'boolean') {
224
+ fail(`${where}: \`omitWhenEmpty\` must be a boolean.`);
225
+ }
226
+ if (decl.role !== undefined && !SECTION_ROLES.includes(decl.role)) {
227
+ fail(`${where}: \`role\` must be one of ${SECTION_ROLES.join(', ')}.`);
228
+ }
229
+ const from = decl.from ?? name;
230
+ if (typeof from !== 'string' || from === '')
231
+ fail(`${where}: \`from\` must be a string.`);
232
+ const slot = {
233
+ name,
234
+ kind: decl.as,
235
+ el: decl.el,
236
+ omitWhenEmpty: decl.omitWhenEmpty ?? false,
237
+ role: decl.role,
238
+ };
239
+ if (from.startsWith('attrs.')) {
240
+ slot.attr = from.slice('attrs.'.length);
241
+ if (!slot.attr)
242
+ fail(`${where}: \`from\` names no attribute.`);
243
+ if (decl.as !== 'value') {
244
+ fail(`${where}: an attribute is one value; it cannot be a region.`);
245
+ }
246
+ }
247
+ else {
248
+ if (from.includes('.')) {
249
+ fail(`${where}: \`from\` is a content field name or "attrs.<name>", not "${from}".`);
250
+ }
251
+ const info = fields.get(from);
252
+ if (!info) {
253
+ const known = [...fields.keys()];
254
+ fail(unsupported.size > 0 && known.length === 0
255
+ ? `${where}: the content model is ${[...unsupported].join(' / ')}, which the slot declaration does not read. Keep a \`transform\` (SPEC-143 D3).`
256
+ : `${where}: \`from: "${from}"\` names no field of the content model (fields: ${known.join(', ') || 'none'}).`);
257
+ }
258
+ slot.field = from;
259
+ if (decl.as === 'value') {
260
+ if (info.greedy) {
261
+ fail(`${where}: field \`${from}\` can resolve to several nodes, and a value slot names every node it emits — that is two nodes carrying data-name="${name}". Declare it \`as: "region"\`.`);
262
+ }
263
+ if (decl.el !== undefined) {
264
+ fail(`${where}: a value read from a field is already one node; there is nothing to wrap. Declare it \`as: "region"\` to give it a boundary.`);
265
+ }
266
+ }
267
+ }
268
+ normalized.push(slot);
269
+ }
270
+ return normalized;
271
+ }
272
+ function isRole(name) {
273
+ return name !== undefined && SECTION_ROLES.includes(name);
274
+ }
275
+ /**
276
+ * The `sections` join table a declaration implies — slot name → section role.
277
+ * A slot's role is the one it states, else its own name when that is a role,
278
+ * else its source field's name when that is one.
279
+ */
280
+ export function slotSections(emits) {
281
+ const out = {};
282
+ for (const [name, raw] of Object.entries(emits.slots)) {
283
+ const decl = typeof raw === 'string' ? { as: raw } : raw;
284
+ const from = decl.from ?? name;
285
+ const role = decl.role ?? (isRole(name) ? name : isRole(from) ? from : undefined);
286
+ if (role)
287
+ out[name] = role;
288
+ }
289
+ return out;
290
+ }
291
+ function asNodes(value) {
292
+ if (Array.isArray(value))
293
+ return value;
294
+ if (value != null)
295
+ return [value];
296
+ return [];
297
+ }
298
+ function render(value, config) {
299
+ return Markdoc.transform(asNodes(value), config);
300
+ }
301
+ /** Heading text → `data-name` slug, for a section with no canonical slug. */
302
+ function slugify(text) {
303
+ return text
304
+ .toLowerCase()
305
+ .replace(/[^a-z0-9]+/g, '-')
306
+ .replace(/^-|-$/g, '');
307
+ }
308
+ /**
309
+ * One resolved section entry (a `sections` model without `emitTag`) as a
310
+ * `<section>` named by its slug: its heading, then its resolved fields.
311
+ *
312
+ * The slug is the entry's own identity — the known section's language-stable
313
+ * `$canonicalSlug` (SPEC-035), else the heading text slugified — and a known
314
+ * section's heading carries `data-known-section` so a table of contents can
315
+ * pick the known sections out. A top-level thematic break in the body is the
316
+ * author's separator between thoughts, not content, and is dropped.
317
+ */
318
+ function renderSectionEntry(entry, config) {
319
+ const heading = entry.$heading ?? '';
320
+ const canonicalName = entry.$canonicalName;
321
+ const slug = entry.$canonicalSlug ?? slugify(heading);
322
+ const children = [];
323
+ const headingNode = entry.$headingNode;
324
+ if (headingNode) {
325
+ const renderedHeading = render([headingNode], config);
326
+ const first = renderedHeading[0];
327
+ if (canonicalName && Tag.isTag(first)) {
328
+ first.attributes['data-known-section'] = canonicalName;
329
+ }
330
+ children.push(...renderedHeading);
331
+ }
332
+ for (const [key, value] of Object.entries(entry)) {
333
+ if (key.startsWith('$'))
334
+ continue;
335
+ children.push(...render(value, config).filter((n) => !(Tag.isTag(n) && n.name === 'hr')));
336
+ }
337
+ return new Tag('section', { 'data-name': slug }, children);
338
+ }
339
+ /**
340
+ * Build the transform a declaration describes. Called once, when the schema is
341
+ * constructed; the closure it returns has the signature of a hand-written
342
+ * transform and is called where one would be.
343
+ */
344
+ export function makeSlotTransform(emits, contentModel) {
345
+ const slots = validateEmits(emits, contentModel);
346
+ const { rune, tag, property, properties } = emits;
347
+ return (resolved, attrs, config, node) => {
348
+ // D5 — whether sections arrive as resolved entries or as emitted child
349
+ // runes is the content model's `emitTag`; read it, per instance, from the
350
+ // branch the resolver actually took.
351
+ let structural;
352
+ const sectionsEmitTag = () => {
353
+ structural ??= selectStructuralModel(node.children, typeof contentModel === 'function' ? contentModel(attrs) : contentModel, attrs);
354
+ return structural.type === 'sections' ? structural.emitTag : undefined;
355
+ };
356
+ const refs = {};
357
+ const children = [];
358
+ for (const slot of slots) {
359
+ let out;
360
+ if (slot.attr !== undefined) {
361
+ const value = attrs[slot.attr];
362
+ if (slot.omitWhenEmpty && (value == null || value === ''))
363
+ continue;
364
+ out = new Tag(slot.el ?? 'span', {}, [value ?? '']);
365
+ }
366
+ else {
367
+ const field = slot.field;
368
+ let nodes;
369
+ if (field === 'sections' && sectionsEmitTag() === undefined) {
370
+ nodes = asNodes(resolved.sections).map((entry) => renderSectionEntry(entry, config));
371
+ }
372
+ else {
373
+ nodes = render(resolved[field], config);
374
+ }
375
+ if (slot.kind === 'value') {
376
+ if (nodes.length === 0)
377
+ continue;
378
+ const only = nodes[0];
379
+ if (nodes.length > 1 || !Tag.isTag(only)) {
380
+ throw new Error(`Rune "${rune}": value slot \`${slot.name}\` rendered ${nodes.length} node(s), not one element. A value slot names exactly one node.`);
381
+ }
382
+ out = only;
383
+ }
384
+ else {
385
+ if (nodes.length === 0 && slot.omitWhenEmpty)
386
+ continue;
387
+ out = new Tag(slot.el ?? 'div', {}, nodes);
388
+ }
389
+ }
390
+ refs[slot.name] = out;
391
+ children.push(out);
392
+ }
393
+ return createComponentRenderable({
394
+ rune,
395
+ tag: tag,
396
+ property,
397
+ properties: properties ? fieldMetas(attrs, config, properties) : undefined,
398
+ refs,
399
+ children,
400
+ });
401
+ };
402
+ }
403
+ /**
404
+ * A declaration with every default made explicit — what the generated transform
405
+ * will actually do, which is the thing a reviewer needs and the declaration's
406
+ * terseness hides.
407
+ */
408
+ export function describeSlots(emits, contentModel) {
409
+ const roles = slotSections(emits);
410
+ let emitTag;
411
+ if (contentModel) {
412
+ const m = typeof contentModel === 'function' ? contentModel({}) : contentModel;
413
+ const s = 'when' in m ? m.default : m;
414
+ if ('type' in s && s.type === 'sections')
415
+ emitTag = s.emitTag;
416
+ }
417
+ return Object.entries(emits.slots).map(([name, raw]) => {
418
+ const decl = typeof raw === 'string' ? { as: raw } : raw;
419
+ const from = decl.from ?? name;
420
+ const fromAttr = from.startsWith('attrs.');
421
+ const el = decl.as === 'region' ? (decl.el ?? 'div') : fromAttr ? (decl.el ?? 'span') : undefined;
422
+ return {
423
+ name,
424
+ from,
425
+ as: decl.as,
426
+ ...(el ? { el } : {}),
427
+ omitWhenEmpty: decl.omitWhenEmpty ?? false,
428
+ ...(roles[name] ? { role: roles[name] } : {}),
429
+ ...(from === 'sections' && contentModel
430
+ ? { sections: emitTag ? 'child runes' : 'entries' }
431
+ : {}),
432
+ };
433
+ });
434
+ }
435
+ /** One line per slot, for the text surfaces. */
436
+ export function formatSlotLine(slot) {
437
+ const parts = [slot.as];
438
+ if (slot.el)
439
+ parts.push(`<${slot.el}>`);
440
+ if (slot.omitWhenEmpty)
441
+ parts.push('omitted when empty');
442
+ if (slot.role)
443
+ parts.push(`role: ${slot.role}`);
444
+ if (slot.sections)
445
+ parts.push(`sections arrive as ${slot.sections}`);
446
+ return `${slot.name} <- ${slot.from} (${parts.join(', ')})`;
447
+ }
448
+ //# sourceMappingURL=slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slots.js","sourceRoot":"","sources":["../../src/lib/slots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAGvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;AAKxB,sEAAsE;AACtE,MAAM,aAAa,GAAG;IACrB,QAAQ;IACR,UAAU;IACV,OAAO;IACP,aAAa;IACb,MAAM;IACN,QAAQ;IACR,OAAO;CACE,CAAC;AAyDX,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/E,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC,CAAC;AACzE,qFAAqF;AACrF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC9B,OAAO;IACP,UAAU;IACV,MAAM;IACN,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,MAAM;IACN,SAAS;IACT,WAAW;IACX,OAAO;IACP,OAAO;IACP,UAAU;IACV,QAAQ;IACR,OAAO;IACP,QAAQ;CACR,CAAC,CAAC;AACH,MAAM,OAAO,GAAG,+BAA+B,CAAC;AAChD,MAAM,SAAS,GAAG,qCAAqC,CAAC;AACxD,MAAM,SAAS,GAAG,+BAA+B,CAAC;AAElD;;;;GAIG;AACH,SAAS,eAAe,CAAC,KAAc,EAAE,IAAY,EAAE,IAA4B;IAClF,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,GAAG,IAAI,6DAA6D,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,IAAI,yEAAyE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO;IACtF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,GAAG,IAAI,0BAA0B,CAAC,CAAC;QACrE,OAAO;IACR,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;QACnE,OAAO;IACR,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,IAAI,SAAS,KAAK,EAAE,WAAW,EAAE,IAAI,IAAI,OAAO,4BAA4B,CAAC,CAAC;QACvF,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YACvE,eAAe,CAAC,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO;IACR,CAAC;IACD,IAAI,CAAC,GAAG,IAAI,yBAAyB,OAAO,KAAK,GAAG,CAAC,CAAC;AACvD,CAAC;AAQD;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAoE;IAC1F,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,CAAe,EAAQ,EAAE;QACvC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;YACjB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACtC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACjB,OAAO;QACR,CAAC;QACD,MAAM,CAAC,GAAG,CAA2B,CAAC;QACtC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACpD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;gBAChC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAChC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;gBAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACP,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACF,CAAC,CAAC;IACF,KAAK,CAAC,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAuB,EACvB,YAA2E;IAE3E,MAAM,SAAS,GACd,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QACnE,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG;QACnB,CAAC,CAAC,WAAW,CAAC;IAChB,MAAM,IAAI,GAAG,CAAC,GAAW,EAAS,EAAE;QACnC,MAAM,IAAI,KAAK,CAAC,QAAQ,SAAS,qCAAqC,GAAG,EAAE,CAAC,CAAC;IAC9E,CAAC,CAAC;IAEF,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC5F,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAEtC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CACH,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;gBACtB,CAAC,CAAC,KAAK,GAAG,gIAAgI;gBAC1I,CAAC,CAAC,iBAAiB,GAAG,gBAAgB,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CACrE,CAAC;QACH,CAAC;IACF,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnE,IAAI,CAAC,0CAA0C,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/D,IAAI,CAAC,gCAAgC,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACxE,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7E,IAAI,CAAC,iCAAiC,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAC7D,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,SAAS;YACxC,MAAM,EAAE,GACP,KAAK;gBACL,OAAO,KAAK,KAAK,QAAQ;gBACzB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC/E,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;gBACjC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;YAClE,IAAI,CAAC,EAAE,EAAE,CAAC;gBACT,IAAI,CACH,cAAc,GAAG,gGAAgG,CACjH,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACnF,IAAI,CAAC,4CAA4C,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,IAAI,CAAC,2BAA2B,CAAC,CAAC;IAE9D,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;IAC5D,MAAM,UAAU,GAAqB,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,UAAU,IAAI,IAAI,CAAC;QACjC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,GAAG,KAAK,0BAA0B,CAAC,CAAC;QACpE,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,IAAI,CACH,GAAG,KAAK,8HAA8H,CACtI,CAAC;QACH,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAoB,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1E,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9D,IAAI,CAAC,GAAG,KAAK,mDAAmD,CAAC,CAAC;QACnE,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YACjC,IAAI,CACH,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;gBACtB,CAAC,CAAC,GAAG,KAAK,OAAO,GAAG,iGAAiG;gBACrH,CAAC,CAAC,GAAG,KAAK,mBAAmB,GAAG,gBAAgB,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAC9E,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YACjD,IAAI,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACtF,IAAI,CACH,GAAG,KAAK,qGAAqG,CAC7G,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACjF,IAAI,CAAC,GAAG,KAAK,wCAAwC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,CAAE,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1F,IAAI,CAAC,GAAG,KAAK,6BAA6B,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE;YAAE,IAAI,CAAC,GAAG,KAAK,8BAA8B,CAAC,CAAC;QAE1F,MAAM,IAAI,GAAmB;YAC5B,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,EAAE;YACb,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,KAAK;YAC1C,IAAI,EAAE,IAAI,CAAC,IAAI;SACf,CAAC;QACF,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,IAAI;gBAAE,IAAI,CAAC,GAAG,KAAK,gCAAgC,CAAC,CAAC;YAC/D,IAAI,IAAI,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;gBACzB,IAAI,CAAC,GAAG,KAAK,qDAAqD,CAAC,CAAC;YACrE,CAAC;QACF,CAAC;aAAM,CAAC;YACP,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACxB,IAAI,CAAC,GAAG,KAAK,8DAA8D,IAAI,IAAI,CAAC,CAAC;YACtF,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACX,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBACjC,IAAI,CACH,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;oBACzC,CAAC,CAAC,GAAG,KAAK,0BAA0B,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,iFAAiF;oBACjJ,CAAC,CAAC,GAAG,KAAK,cAAc,IAAI,oDAAoD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,IAAI,CAC/G,CAAC;YACH,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,IAAI,IAAI,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;gBACzB,IAAI,IAAK,CAAC,MAAM,EAAE,CAAC;oBAClB,IAAI,CACH,GAAG,KAAK,aAAa,IAAI,uHAAuH,IAAI,iCAAiC,CACrL,CAAC;gBACH,CAAC;gBACD,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;oBAC3B,IAAI,CACH,GAAG,KAAK,+HAA+H,CACvI,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC;QACD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,UAAU,CAAC;AACnB,CAAC;AAED,SAAS,MAAM,CAAC,IAAwB;IACvC,OAAO,IAAI,KAAK,SAAS,IAAK,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAAuB;IACnD,MAAM,GAAG,GAA6B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,GAAoB,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAClF,IAAI,IAAI;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAED,SAAS,OAAO,CAAC,KAAc;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAe,CAAC;IACjD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,CAAC,KAAa,CAAC,CAAC;IAC1C,OAAO,EAAE,CAAC;AACX,CAAC;AAED,SAAS,MAAM,CAAC,KAAc,EAAE,MAAc;IAC7C,OAAO,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,MAAM,CAAyB,CAAC;AAC1E,CAAC;AAED,6EAA6E;AAC7E,SAAS,OAAO,CAAC,IAAY;IAC5B,OAAO,IAAI;SACT,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,kBAAkB,CAAC,KAA8B,EAAE,MAAc;IACzE,MAAM,OAAO,GAAI,KAAK,CAAC,QAA+B,IAAI,EAAE,CAAC;IAC7D,MAAM,aAAa,GAAG,KAAK,CAAC,cAAoC,CAAC;IACjE,MAAM,IAAI,GAAI,KAAK,CAAC,cAAqC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9E,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,KAAK,CAAC,YAAgC,CAAC;IAC3D,IAAI,WAAW,EAAE,CAAC;QACjB,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,aAAa,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,KAAK,CAAC,UAAU,CAAC,oBAAoB,CAAC,GAAG,aAAa,CAAC;QACxD,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAChC,KAAuB,EACvB,YAA2E;IAO3E,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACjD,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAElD,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QACxC,uEAAuE;QACvE,0EAA0E;QAC1E,qCAAqC;QACrC,IAAI,UAA8C,CAAC;QACnD,MAAM,eAAe,GAAG,GAAuB,EAAE;YAChD,UAAU,KAAK,qBAAqB,CACnC,IAAI,CAAC,QAAQ,EACb,OAAO,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,EACvE,KAAK,CACL,CAAC;YACF,OAAO,UAAU,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,CAAC,CAAC;QAEF,MAAM,IAAI,GAA6C,EAAE,CAAC;QAC1D,MAAM,QAAQ,GAAyB,EAAE,CAAC;QAE1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,IAAI,GAAyC,CAAC;YAE9C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/B,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;oBAAE,SAAS;gBACpE,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,MAAM,EAAE,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAM,CAAC;gBAC1B,IAAI,KAA2B,CAAC;gBAChC,IAAI,KAAK,KAAK,UAAU,IAAI,eAAe,EAAE,KAAK,SAAS,EAAE,CAAC;oBAC7D,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAChD,kBAAkB,CAAC,KAA2C,EAAE,MAAM,CAAC,CACvE,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACP,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;gBACzC,CAAC;gBAED,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC3B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;wBAAE,SAAS;oBACjC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBACtB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBAC1C,MAAM,IAAI,KAAK,CACd,SAAS,IAAI,mBAAmB,IAAI,CAAC,IAAI,eAAe,KAAK,CAAC,MAAM,iEAAiE,CACrI,CAAC;oBACH,CAAC;oBACD,GAAG,GAAG,IAAI,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACP,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,aAAa;wBAAE,SAAS;oBACvD,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;gBAC5C,CAAC;YACF,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;YACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QAED,OAAO,yBAAyB,CAAC;YAChC,IAAI;YACJ,GAAG,EAAE,GAAY;YACjB,QAAQ;YACR,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;YAC1E,IAAI;YACJ,QAAQ;SACR,CAAC,CAAC;IACJ,CAAC,CAAC;AACH,CAAC;AAgBD;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAuB,EACvB,YAA4E;IAE5E,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,OAA2B,CAAC;IAChC,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,CAAC,GAAG,OAAO,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;QAC/E,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE;QACtD,MAAM,IAAI,GAAoB,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,EAAE,GACP,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxF,OAAO;YACN,IAAI;YACJ,IAAI;YACJ,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,KAAK;YAC1C,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7C,GAAG,CAAC,IAAI,KAAK,UAAU,IAAI,YAAY;gBACtC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAE,aAAuB,CAAC,CAAC,CAAE,SAAmB,EAAE;gBACzE,CAAC,CAAC,EAAE,CAAC;SACN,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,cAAc,CAAC,IAAmB;IACjD,MAAM,KAAK,GAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,aAAa;QAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACzD,IAAI,IAAI,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,IAAI,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACrE,OAAO,GAAG,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9D,CAAC"}
package/dist/plugins.d.ts CHANGED
@@ -114,4 +114,7 @@ export declare function discoverPluginFixtureManifest(npmPackageName: string): P
114
114
  * back to the first parsed). Backward-compatible with bare `<rune>.md` files.
115
115
  */
116
116
  export declare function discoverPluginFixtures(npmPackageName: string): Promise<Record<string, string>>;
117
+ /** Validate a loaded Plugin has required fields. Each rune entry carries
118
+ * exactly one of `transform` or `template` (SPEC-153 D11). */
119
+ export declare function validatePlugin(pkg: Plugin, npmName: string): void;
117
120
  //# sourceMappingURL=plugins.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
package/dist/plugins.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { selectLocaleBundle } from '@refrakt-md/transform';
2
2
  import { defineRune, runeTagMap } from './rune.js';
3
+ import { checkComposedCatalog, composedPluginRune } from './composed-rune.js';
4
+ import { compositionFor, composedTypeName } from './lib/composition.js';
3
5
  /** Reserved namespace names that cannot be used by user config or plugins. */
4
6
  const RESERVED_FILE_ROOT_NAMESPACES = new Set(['site']);
5
7
  /** Validate that a file-root namespace name is allowed. Throws on reserved
@@ -34,6 +36,23 @@ export async function loadPlugin(npmPackageName) {
34
36
  const runes = {};
35
37
  const fixtures = {};
36
38
  for (const [runeName, entry] of Object.entries(pkg.runes)) {
39
+ if (entry.template !== undefined) {
40
+ // SPEC-153 D11 — a composed rune: its schema and its block-less
41
+ // config are both built from the definition.
42
+ const composed = composedPluginRune(runeName, entry);
43
+ runes[runeName] = defineRune({
44
+ ...composed.rune,
45
+ name: runeName,
46
+ schema: composed.rune.schema,
47
+ description: entry.description ?? composed.rune.description,
48
+ aliases: entry.aliases ?? composed.rune.aliases,
49
+ seoType: entry.seoType,
50
+ authoringHints: entry.authoringHints,
51
+ });
52
+ if (entry.fixture)
53
+ fixtures[runeName] = entry.fixture;
54
+ continue;
55
+ }
37
56
  runes[runeName] = defineRune({
38
57
  name: runeName,
39
58
  schema: entry.transform,
@@ -198,6 +217,13 @@ export function mergePlugins(loaded, coreRuneNames, prefer) {
198
217
  themeRunes[key] = value;
199
218
  }
200
219
  }
220
+ // SPEC-145 D2a — a composed rune's config is generated from its
221
+ // definition, never hand-written beside it.
222
+ for (const rune of Object.values(loadedPkg.runes)) {
223
+ const info = compositionFor(rune.schema);
224
+ if (info?.config && info.typeName)
225
+ themeRunes[info.typeName] = info.config;
226
+ }
201
227
  if (loadedPkg.pkg.theme?.icons) {
202
228
  for (const [group, icons] of Object.entries(loadedPkg.pkg.theme.icons)) {
203
229
  themeIcons[group] = { ...themeIcons[group], ...icons };
@@ -209,6 +235,10 @@ export function mergePlugins(loaded, coreRuneNames, prefer) {
209
235
  }
210
236
  }
211
237
  }
238
+ // SPEC-145 — the composition checks that need every rune: cycles (by name),
239
+ // a composed type placed over a peer type (D9), a placed rune missing its
240
+ // required parent (D12). Here, at assembly, rather than at render.
241
+ checkComposedCatalog(runes, themeRunes);
212
242
  const extensions = {};
213
243
  for (const loadedPkg of loaded) {
214
244
  if (loadedPkg.pkg.extends) {
@@ -390,7 +420,9 @@ export async function discoverPluginFixtureManifest(npmPackageName) {
390
420
  }
391
421
  }
392
422
  catch {
393
- // Plugin not resolvable via require (e.g., workspace link) — skip file fixtures
423
+ // `<pkg>/package.json` did not resolve — the package is not installed, or it declares an
424
+ // `exports` map without a `./package.json` entry (ERR_PACKAGE_PATH_NOT_EXPORTED). A
425
+ // workspace link resolves fine. Skip file fixtures.
394
426
  }
395
427
  return manifest;
396
428
  }
@@ -436,8 +468,9 @@ function isPlugin(value) {
436
468
  typeof obj.runes === 'object' &&
437
469
  obj.runes !== null);
438
470
  }
439
- /** Validate a loaded Plugin has required fields */
440
- function validatePlugin(pkg, npmName) {
471
+ /** Validate a loaded Plugin has required fields. Each rune entry carries
472
+ * exactly one of `transform` or `template` (SPEC-153 D11). */
473
+ export function validatePlugin(pkg, npmName) {
441
474
  if (!pkg.name) {
442
475
  throw new Error(`Plugin "${npmName}" has an empty name field`);
443
476
  }
@@ -448,9 +481,25 @@ function validatePlugin(pkg, npmName) {
448
481
  throw new Error(`Plugin "${npmName}" defines no runes`);
449
482
  }
450
483
  for (const [name, entry] of Object.entries(pkg.runes)) {
484
+ if (entry.template !== undefined) {
485
+ if (entry.transform !== undefined) {
486
+ throw new Error(`Plugin "${npmName}" rune "${name}" carries both a \`transform\` and a composition \`template\`. ` +
487
+ `A rune has exactly one emit path (SPEC-145 D5, SPEC-153 D11): drop the transform to compose, or the template to build its own output.`);
488
+ }
489
+ if (typeof entry.template !== 'string') {
490
+ throw new Error(`Plugin "${npmName}" rune "${name}" has an invalid template. ` +
491
+ `Expected a composed rune definition: YAML frontmatter and a Markdoc template, as one string.`);
492
+ }
493
+ const configKey = composedTypeName(name);
494
+ if (pkg.theme?.runes?.[configKey] !== undefined) {
495
+ throw new Error(`Plugin "${npmName}" rune "${name}" is composed but also has a hand-written theme config (\`theme.runes.${configKey}\`). ` +
496
+ `A composed rune's config is generated from its definition, and it has no block and ships no CSS (SPEC-145 D2, D2a).`);
497
+ }
498
+ continue;
499
+ }
451
500
  if (!entry.transform || typeof entry.transform !== 'object') {
452
501
  throw new Error(`Plugin "${npmName}" rune "${name}" has an invalid transform. ` +
453
- `Expected a Markdoc Schema object (created via createContentModelSchema()).`);
502
+ `Expected a Markdoc Schema object (created via createContentModelSchema()), or a composition \`template\`.`);
454
503
  }
455
504
  }
456
505
  }