@refrakt-md/runes 0.43.0 → 0.44.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.
- package/dist/composed-rune.d.ts +9 -1
- package/dist/composed-rune.d.ts.map +1 -1
- package/dist/composed-rune.js +14 -2
- package/dist/composed-rune.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/composition-errors.d.ts +7 -0
- package/dist/lib/composition-errors.d.ts.map +1 -1
- package/dist/lib/composition-errors.js +7 -0
- package/dist/lib/composition-errors.js.map +1 -1
- package/dist/lib/composition-placement.d.ts +88 -0
- package/dist/lib/composition-placement.d.ts.map +1 -0
- package/dist/lib/composition-placement.js +180 -0
- package/dist/lib/composition-placement.js.map +1 -0
- package/dist/lib/composition.d.ts +54 -3
- package/dist/lib/composition.d.ts.map +1 -1
- package/dist/lib/composition.js +259 -38
- package/dist/lib/composition.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +123 -243
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/resolver.d.ts +5 -0
- package/dist/lib/resolver.d.ts.map +1 -1
- package/dist/lib/resolver.js +25 -3
- package/dist/lib/resolver.js.map +1 -1
- package/dist/lib/slot-markers.js +9 -1
- package/dist/lib/slot-markers.js.map +1 -1
- package/dist/lib/universal-attribute-defs.d.ts +12 -0
- package/dist/lib/universal-attribute-defs.d.ts.map +1 -0
- package/dist/lib/universal-attribute-defs.js +225 -0
- package/dist/lib/universal-attribute-defs.js.map +1 -0
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +36 -1
- package/dist/plugins.js.map +1 -1
- package/dist/project-runes.d.ts +9 -2
- package/dist/project-runes.d.ts.map +1 -1
- package/dist/project-runes.js +5 -5
- package/dist/project-runes.js.map +1 -1
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +9 -0
- package/dist/reference.js.map +1 -1
- package/dist/tags/section.d.ts.map +1 -1
- package/dist/tags/section.js +10 -0
- package/dist/tags/section.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composition-placement.js","sourceRoot":"","sources":["../../src/lib/composition-placement.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import type { RuneConfig } from '@refrakt-md/transform';
|
|
|
4
4
|
import type { SchemaTable } from './schema-table.js';
|
|
5
5
|
import { SchemaSideTable } from './schema-side-table.js';
|
|
6
6
|
import type { RegistersDeclaration } from './registers.js';
|
|
7
|
+
import type { AxisTarget, CompositionPlacements } from './composition-placement.js';
|
|
7
8
|
/**
|
|
8
9
|
* A composition template, as `createContentModelSchema` receives it — the third
|
|
9
10
|
* of D5's three mutually exclusive emit paths, beside `transform` and `emits`.
|
|
@@ -19,6 +20,8 @@ export interface CompositionTemplate {
|
|
|
19
20
|
body: string;
|
|
20
21
|
/** The `blocks` the rune declares — what `{% metablock %}` may name (D7). */
|
|
21
22
|
blocks?: readonly string[];
|
|
23
|
+
/** D34 — the definition's defaults for universal axes, by attribute. */
|
|
24
|
+
defaults?: Readonly<Record<string, string>>;
|
|
22
25
|
}
|
|
23
26
|
/** One node of a composition's expansion, as the contract records it (D6). */
|
|
24
27
|
export interface CompositionOutlineNode {
|
|
@@ -56,6 +59,31 @@ export interface CompositionInfo {
|
|
|
56
59
|
config?: RuneConfig;
|
|
57
60
|
/** The config key the engine finds it under. */
|
|
58
61
|
typeName?: string;
|
|
62
|
+
/** Where each universal axis lands (D33): its placement, the rune it lands
|
|
63
|
+
* on, or why it is not offered. For `inspect`, `contracts` and `reference`. */
|
|
64
|
+
axes: Record<string, AxisPlacementInfo>;
|
|
65
|
+
/** D34 — the definition's defaults, each with where it lands and any literal
|
|
66
|
+
* the template writes there, which wins over it. */
|
|
67
|
+
defaults?: Record<string, CompositionDefaultInfo>;
|
|
68
|
+
}
|
|
69
|
+
/** One `defaults` entry, as tooling reads it (D34). */
|
|
70
|
+
export interface CompositionDefaultInfo {
|
|
71
|
+
value: string;
|
|
72
|
+
placement: AxisTarget['placement'];
|
|
73
|
+
/** The placed rune it lands on; absent for a root-placed axis. */
|
|
74
|
+
rune?: string;
|
|
75
|
+
/** A literal the template writes on that rune, which the default yields to. */
|
|
76
|
+
literal?: string;
|
|
77
|
+
}
|
|
78
|
+
/** One axis's placement on a composed rune, as tooling reads it. */
|
|
79
|
+
export interface AxisPlacementInfo {
|
|
80
|
+
placement: AxisTarget['placement'];
|
|
81
|
+
/** The placed rune it lands on. */
|
|
82
|
+
rune?: string;
|
|
83
|
+
/** Offered, but dropped with a warning: there is no carrier (D24). */
|
|
84
|
+
dropped?: string;
|
|
85
|
+
/** Not offered, and why (D33.3). */
|
|
86
|
+
unavailable?: string;
|
|
59
87
|
}
|
|
60
88
|
/** Compositions by schema — the same pattern as `schemaTables`: tooling has only
|
|
61
89
|
* the schema to read from. */
|
|
@@ -77,9 +105,10 @@ export declare function frontmatterKeyLine(frontmatter: string, path: readonly s
|
|
|
77
105
|
* that becomes a property of the outer entity, not a peer of it (D9). */
|
|
78
106
|
export declare const SUBORDINATE_SCHEMA_TYPES: ReadonlySet<string>;
|
|
79
107
|
/**
|
|
80
|
-
* `{% slot name="x" each %}`
|
|
81
|
-
*
|
|
82
|
-
*
|
|
108
|
+
* `{% slot name="x" each %}` and `{% section chrome %}` are the spec's
|
|
109
|
+
* spellings (D26, D31), and Markdoc's tag grammar has no bare boolean
|
|
110
|
+
* attribute. Rewrite `each` inside slot tags, and `chrome` inside any tag, to
|
|
111
|
+
* `=true`, outside quoted values, before parsing.
|
|
83
112
|
*/
|
|
84
113
|
export declare function normaliseEach(body: string): string;
|
|
85
114
|
export interface CompiledComposition {
|
|
@@ -92,6 +121,19 @@ export interface CompiledComposition {
|
|
|
92
121
|
* placed node came from (ADR-046 decision 3).
|
|
93
122
|
*/
|
|
94
123
|
place: (resolved: ResolvedContent, attrs: Record<string, any>) => Node[];
|
|
124
|
+
/** Where the universal attributes land (D14, D31, D33). */
|
|
125
|
+
placements: CompositionPlacements;
|
|
126
|
+
/** One instance's attributes less the universal ones that moved off the root
|
|
127
|
+
* (or were dropped for want of a carrier). What the root keeps. */
|
|
128
|
+
rootAttributes: (attrs: Record<string, any>) => Record<string, any>;
|
|
129
|
+
/** The parsed template, as construction checked it. */
|
|
130
|
+
templateNodes: readonly Node[];
|
|
131
|
+
/** SPEC-182 D4 — the filled attributes the author also wrote, for the
|
|
132
|
+
* `fill-overridden` warning. */
|
|
133
|
+
overriddenFills: (resolved: ResolvedContent, written: Record<string, unknown>) => Array<{
|
|
134
|
+
attribute: string;
|
|
135
|
+
field: string;
|
|
136
|
+
}>;
|
|
95
137
|
}
|
|
96
138
|
export interface CompileCompositionOptions {
|
|
97
139
|
contentModel: ContentModel | ((attrs: Record<string, any>) => ContentModel);
|
|
@@ -125,6 +167,8 @@ export interface CompositionDefinition {
|
|
|
125
167
|
metaFields?: Record<string, unknown>;
|
|
126
168
|
blocks?: Record<string, unknown>;
|
|
127
169
|
provides?: string[];
|
|
170
|
+
/** D34 — defaults for universal axes, by attribute name. */
|
|
171
|
+
defaults?: Record<string, string>;
|
|
128
172
|
template: string;
|
|
129
173
|
/** 1-based line of the source on which the template body starts. */
|
|
130
174
|
templateLine: number;
|
|
@@ -149,6 +193,13 @@ export declare function parseCompositionDefinition(rune: string, source: string)
|
|
|
149
193
|
* resolves a field against the rune's modifier values, exactly as it does for a
|
|
150
194
|
* tree-owning rune — which must declare the same attributes as modifiers for
|
|
151
195
|
* its own blocks to fill.
|
|
196
|
+
*
|
|
197
|
+
* An enum attribute the template only forwards to a placed rune
|
|
198
|
+
* (`{% section media-position=$attrs["media-position"] %}`) is that rune's
|
|
199
|
+
* input, not a modifier of the composition: as a `data-*` on the empty root it
|
|
200
|
+
* would match the dimension rules meant for the rune it is forwarded to — a
|
|
201
|
+
* `data-media-position="cover"` root is laid out as a cover well. It stays in
|
|
202
|
+
* the field bag, which the schema row and registration read.
|
|
152
203
|
*/
|
|
153
204
|
export declare function composedRuneConfig(def: CompositionDefinition): RuneConfig;
|
|
154
205
|
/** One rune as the catalog-wide checks see it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../../src/lib/composition.ts"],"names":[],"mappings":"AA4DA,OAAO,KAAK,EACX,MAAM,EACN,IAAI,EAEJ,mBAAmB,EACnB,MAAM,EACN,eAAe,EAEf,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EAEX,YAAY,EAMZ,eAAe,EAIf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAKxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"composition.d.ts","sourceRoot":"","sources":["../../src/lib/composition.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/composition.js
CHANGED
|
@@ -68,6 +68,8 @@ import { SchemaSideTable } from './schema-side-table.js';
|
|
|
68
68
|
import { declareSlotMarkers, declareSlotMarkersOnNodes } from './slot-markers.js';
|
|
69
69
|
import { registersSources } from './registers.js';
|
|
70
70
|
import { parse } from '../parse.js';
|
|
71
|
+
import { universalAttributeDefinition } from './universal-attribute-defs.js';
|
|
72
|
+
import { moveAttributes, resolvePlacements } from './composition-placement.js';
|
|
71
73
|
const { Ast, Tag: MarkdocTag } = Markdoc;
|
|
72
74
|
/** Compositions by schema — the same pattern as `schemaTables`: tooling has only
|
|
73
75
|
* the schema to read from. */
|
|
@@ -212,6 +214,8 @@ function slotFields(model, fail) {
|
|
|
212
214
|
refs,
|
|
213
215
|
...(listItems ? { listItems } : {}),
|
|
214
216
|
...(ambiguousList ? { ambiguousList } : {}),
|
|
217
|
+
...(f.fills ? { fills: f.fills } : {}),
|
|
218
|
+
...(f.itemModel ? { itemFields: f.itemModel.fields.map((i) => i.name) } : {}),
|
|
215
219
|
});
|
|
216
220
|
};
|
|
217
221
|
if (s.type === 'sequence') {
|
|
@@ -259,47 +263,56 @@ function slotValues(model, resolved) {
|
|
|
259
263
|
// Template parsing and the construction-time checks
|
|
260
264
|
// ---------------------------------------------------------------------------
|
|
261
265
|
/**
|
|
262
|
-
* `{% slot name="x" each %}`
|
|
263
|
-
*
|
|
264
|
-
*
|
|
266
|
+
* `{% slot name="x" each %}` and `{% section chrome %}` are the spec's
|
|
267
|
+
* spellings (D26, D31), and Markdoc's tag grammar has no bare boolean
|
|
268
|
+
* attribute. Rewrite `each` inside slot tags, and `chrome` inside any tag, to
|
|
269
|
+
* `=true`, outside quoted values, before parsing.
|
|
265
270
|
*/
|
|
266
271
|
export function normaliseEach(body) {
|
|
267
|
-
return body.replace(/\{%-?\s*
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
i
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
if (ch === '"' || ch === "'") {
|
|
286
|
-
quote = ch;
|
|
287
|
-
out += ch;
|
|
288
|
-
i++;
|
|
272
|
+
return body.replace(/\{%-?\s*([a-z][\w-]*)\b([^%]*?)(-?%\})/g, (whole, tag, inner, close) => {
|
|
273
|
+
const bare = tag === 'slot' ? ['each', 'chrome'] : ['chrome'];
|
|
274
|
+
const out = bareToTrue(inner, bare);
|
|
275
|
+
return out === inner ? whole : whole.replace(inner + close, out + close);
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/** Rewrite each bare word in `words` to `word=true`, outside quoted values. */
|
|
279
|
+
function bareToTrue(inner, words) {
|
|
280
|
+
let out = '';
|
|
281
|
+
let quote = null;
|
|
282
|
+
let i = 0;
|
|
283
|
+
while (i < inner.length) {
|
|
284
|
+
const ch = inner[i];
|
|
285
|
+
if (quote) {
|
|
286
|
+
if (ch === '\\') {
|
|
287
|
+
out += inner.slice(i, i + 2);
|
|
288
|
+
i += 2;
|
|
289
289
|
continue;
|
|
290
290
|
}
|
|
291
|
+
if (ch === quote)
|
|
292
|
+
quote = null;
|
|
293
|
+
out += ch;
|
|
294
|
+
i++;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (ch === '"' || ch === "'") {
|
|
298
|
+
quote = ch;
|
|
299
|
+
out += ch;
|
|
300
|
+
i++;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (i === 0 || /\s/.test(inner[i - 1])) {
|
|
291
304
|
const rest = inner.slice(i);
|
|
292
|
-
const
|
|
293
|
-
if (
|
|
294
|
-
out +=
|
|
295
|
-
i +=
|
|
305
|
+
const word = words.find((w) => new RegExp(`^${w}(?![\\w=-])`).test(rest));
|
|
306
|
+
if (word) {
|
|
307
|
+
out += `${word}=true`;
|
|
308
|
+
i += word.length;
|
|
296
309
|
continue;
|
|
297
310
|
}
|
|
298
|
-
out += ch;
|
|
299
|
-
i++;
|
|
300
311
|
}
|
|
301
|
-
|
|
302
|
-
|
|
312
|
+
out += ch;
|
|
313
|
+
i++;
|
|
314
|
+
}
|
|
315
|
+
return out;
|
|
303
316
|
}
|
|
304
317
|
/** Variables a template node reads, by path, in attribute or content position. */
|
|
305
318
|
function variablePaths(value, out = []) {
|
|
@@ -370,6 +383,8 @@ export function compileComposition(template, options) {
|
|
|
370
383
|
const placedSlots = new Map();
|
|
371
384
|
const slotOrder = [];
|
|
372
385
|
const placements = [];
|
|
386
|
+
/** Every rune the template places, for the paint carrier and role owners. */
|
|
387
|
+
const templateRunes = [];
|
|
373
388
|
const checkVariables = (n, scope) => {
|
|
374
389
|
for (const path of variablePaths(n.attributes)) {
|
|
375
390
|
const [root, name] = path;
|
|
@@ -438,6 +453,7 @@ export function compileComposition(template, options) {
|
|
|
438
453
|
fail('composition-cycle', `it places \`{% ${n.tag} %}\`, which is the rune itself — a composition cycle.`);
|
|
439
454
|
}
|
|
440
455
|
placements.push({ rune: n.tag, ...(scope.parentRune ? { parent: scope.parentRune } : {}) });
|
|
456
|
+
templateRunes.push({ node: n, top: !scope.parentRune, inEach: !!scope.each });
|
|
441
457
|
const children = outlineOf(n.children, { ...scope, parentRune: n.tag });
|
|
442
458
|
return [{ rune: n.tag, ...(children.length > 0 ? { children } : {}) }];
|
|
443
459
|
}
|
|
@@ -476,6 +492,11 @@ export function compileComposition(template, options) {
|
|
|
476
492
|
if (!field) {
|
|
477
493
|
fail('slot-unknown-field', `slot \`${name}\` names no field of the content model (fields: ${[...fields.keys()].join(', ') || 'none'}) (D26).`);
|
|
478
494
|
}
|
|
495
|
+
if (field?.fills) {
|
|
496
|
+
fail('fill-placed', `slot \`${name}\` places field \`${name}\`, which fills ${Object.keys(field.fills)
|
|
497
|
+
.map((a) => `\`${a}\``)
|
|
498
|
+
.join(', ')}. A filling field is placed into the rune's values, which the template places through a meta block or \`$attrs\`; a slot as well would render it twice. Remove the slot (SPEC-182 D5).`);
|
|
499
|
+
}
|
|
479
500
|
if (placedSlots.has(name)) {
|
|
480
501
|
fail('slot-placed-twice', `slot \`${name}\` is placed twice. A slot is placed exactly once; two positions are two declared fields, or a theme's concern (D26).`);
|
|
481
502
|
}
|
|
@@ -538,8 +559,63 @@ export function compileComposition(template, options) {
|
|
|
538
559
|
return { metablock: name };
|
|
539
560
|
}
|
|
540
561
|
const outline = outlineOf(ast.children, {});
|
|
541
|
-
//
|
|
542
|
-
const
|
|
562
|
+
// D14, D31, D33 — the paint carrier and every axis's target.
|
|
563
|
+
const plan = resolvePlacements(rune, templateRunes, (code, msg, at) => {
|
|
564
|
+
current = at ?? current;
|
|
565
|
+
return fail(code, msg);
|
|
566
|
+
});
|
|
567
|
+
current = undefined;
|
|
568
|
+
// D34 — each default lands where the author's attribute would. One that
|
|
569
|
+
// lands nowhere is a definition error, not a silent no-op.
|
|
570
|
+
const defaultsByNode = new Map();
|
|
571
|
+
const defaultInfo = {};
|
|
572
|
+
for (const [name, value] of Object.entries(template.defaults ?? {})) {
|
|
573
|
+
const target = name === 'density'
|
|
574
|
+
? plan.carrier
|
|
575
|
+
? { placement: 'carrier', node: plan.carrier, rune: plan.carrier.tag }
|
|
576
|
+
: { placement: 'carrier', dropped: `\`${rune}\` places no rune to carry it` }
|
|
577
|
+
: plan.axes[plan.axisOf[name]];
|
|
578
|
+
if (!target)
|
|
579
|
+
continue;
|
|
580
|
+
if (target.placement === 'root') {
|
|
581
|
+
defaultInfo[name] = { value, placement: 'root' };
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
if (!('node' in target)) {
|
|
585
|
+
const why = 'dropped' in target ? target.dropped : target.unavailable;
|
|
586
|
+
throw new CompositionError('defaults-invalid', `Rune "${rune}": \`defaults.${name}\` lands nowhere: ${why} (D34).`);
|
|
587
|
+
}
|
|
588
|
+
const into = defaultsByNode.get(target.node) ?? {};
|
|
589
|
+
into[name] = value;
|
|
590
|
+
defaultsByNode.set(target.node, into);
|
|
591
|
+
const literal = target.node.attributes[name];
|
|
592
|
+
defaultInfo[name] = {
|
|
593
|
+
value,
|
|
594
|
+
placement: target.placement,
|
|
595
|
+
rune: target.rune,
|
|
596
|
+
...(literal !== undefined && typeof literal !== 'object' ? { literal: String(literal) } : {}),
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
// SPEC-182 D2 — `fills` names declared attributes and item-model fields.
|
|
600
|
+
for (const [name, field] of fields) {
|
|
601
|
+
if (!field.fills)
|
|
602
|
+
continue;
|
|
603
|
+
if (!field.itemFields) {
|
|
604
|
+
fail('fills-invalid', `field \`${name}\` declares \`fills\` but no \`itemModel\`: there is nothing to fill from. Give it an item model that reads the values (SPEC-182 D1).`);
|
|
605
|
+
}
|
|
606
|
+
for (const [attr, ref] of Object.entries(field.fills)) {
|
|
607
|
+
if (!declared.has(attr)) {
|
|
608
|
+
fail('fills-invalid', `field \`${name}\` fills \`${attr}\`, which the rune does not declare (declared: ${[...declared].join(', ') || 'none'}). Declare it under \`attributes\` (SPEC-182 D2).`);
|
|
609
|
+
}
|
|
610
|
+
const source = typeof ref === 'string' && ref.startsWith('$') ? ref.slice(1) : undefined;
|
|
611
|
+
if (!source || !field.itemFields.includes(source)) {
|
|
612
|
+
fail('fills-invalid', `field \`${name}\` fills \`${attr}\` from \`${ref}\`, which names no field of its item model (fields: ${field.itemFields.join(', ')}). Write it as \`$<field>\` (SPEC-182 D2).`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
// D11 — a field no slot places parses and then silently does not render. A
|
|
617
|
+
// filling field is placed into the rune's values (SPEC-182 D5).
|
|
618
|
+
const unplaced = [...fields.keys()].filter((f) => !placedSlots.has(f) && !fields.get(f).fills);
|
|
543
619
|
if (unplaced.length > 0) {
|
|
544
620
|
fail('field-unplaced', `content-model field${unplaced.length > 1 ? 's' : ''} ${unplaced.map((f) => `\`${f}\``).join(', ')} ${unplaced.length > 1 ? 'are' : 'is'} placed by no slot, so authored content would be dropped. Place ${unplaced.length > 1 ? 'each' : 'it'} with \`{% slot name="…" /%}\` (D11).`);
|
|
545
621
|
}
|
|
@@ -548,11 +624,22 @@ export function compileComposition(template, options) {
|
|
|
548
624
|
options.schema?.fallback?.type ??
|
|
549
625
|
Object.values(options.schema?.rows ?? {}).find((r) => r.type)?.type;
|
|
550
626
|
const nodeSources = registersNodeSources(options.registers, fields, declared);
|
|
627
|
+
const axes = {};
|
|
628
|
+
for (const [axis, target] of Object.entries(plan.axes)) {
|
|
629
|
+
axes[axis] = {
|
|
630
|
+
placement: target.placement,
|
|
631
|
+
...('rune' in target ? { rune: target.rune } : {}),
|
|
632
|
+
...('dropped' in target ? { dropped: target.dropped } : {}),
|
|
633
|
+
...('unavailable' in target ? { unavailable: target.unavailable } : {}),
|
|
634
|
+
};
|
|
635
|
+
}
|
|
551
636
|
const info = {
|
|
552
637
|
rune,
|
|
553
638
|
slots: slotOrder,
|
|
554
639
|
placements,
|
|
555
640
|
outline,
|
|
641
|
+
axes,
|
|
642
|
+
...(Object.keys(defaultInfo).length > 0 ? { defaults: defaultInfo } : {}),
|
|
556
643
|
...(schemaType ? { schemaType } : {}),
|
|
557
644
|
};
|
|
558
645
|
const attributeNames = [...declared];
|
|
@@ -565,6 +652,8 @@ export function compileComposition(template, options) {
|
|
|
565
652
|
resolved: slotValues(structural, resolved),
|
|
566
653
|
attrs: bound,
|
|
567
654
|
fields,
|
|
655
|
+
moves: moveAttributes(plan, attrs).moves,
|
|
656
|
+
defaults: defaultsByNode,
|
|
568
657
|
};
|
|
569
658
|
const placed = expand(ast.children, ctx);
|
|
570
659
|
// Top-level template nodes are the composed rune's own (D10). A slot
|
|
@@ -575,7 +664,11 @@ export function compileComposition(template, options) {
|
|
|
575
664
|
}
|
|
576
665
|
return placed;
|
|
577
666
|
};
|
|
578
|
-
const transform = (resolved, attrs, config) => {
|
|
667
|
+
const transform = (resolved, attrs, config, node) => {
|
|
668
|
+
// SPEC-182 D2 — values a paragraph fills become the rune's own, before
|
|
669
|
+
// anything reads them. `attrs` is the caller's object, filled in place, so
|
|
670
|
+
// the schema table applied after this transform reads them too.
|
|
671
|
+
Object.assign(attrs, filledAttributes(resolved, node?.attributes ?? {}));
|
|
579
672
|
const placed = place(resolved, attrs);
|
|
580
673
|
const children = Markdoc.transform(placed, templateConfig(config));
|
|
581
674
|
// The field bag holds every attribute the author set (or that defaulted):
|
|
@@ -597,7 +690,61 @@ export function compileComposition(template, options) {
|
|
|
597
690
|
copyRegisteredNodes(root, nodeSources);
|
|
598
691
|
return root;
|
|
599
692
|
};
|
|
600
|
-
|
|
693
|
+
/** SPEC-182 D2, D4 — what the filling fields supply, for the attributes the
|
|
694
|
+
* author did not write. The author's attribute always wins. */
|
|
695
|
+
const filledAttributes = (resolved, written) => {
|
|
696
|
+
const out = {};
|
|
697
|
+
const values = slotValues(structural, resolved);
|
|
698
|
+
for (const [name, field] of fields) {
|
|
699
|
+
if (!field.fills)
|
|
700
|
+
continue;
|
|
701
|
+
const record = values[`${name}Data`];
|
|
702
|
+
if (!record)
|
|
703
|
+
continue;
|
|
704
|
+
for (const [attr, ref] of Object.entries(field.fills)) {
|
|
705
|
+
if (written[attr] !== undefined)
|
|
706
|
+
continue;
|
|
707
|
+
const value = record[ref.slice(1)];
|
|
708
|
+
if (value !== undefined && value !== '')
|
|
709
|
+
out[attr] = value;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return out;
|
|
713
|
+
};
|
|
714
|
+
/** SPEC-182 D4 — attributes the author wrote that a paragraph would also have
|
|
715
|
+
* filled: the paragraph is consumed and does not render. */
|
|
716
|
+
const overriddenFills = (resolved, written) => {
|
|
717
|
+
const out = [];
|
|
718
|
+
const values = slotValues(structural, resolved);
|
|
719
|
+
for (const [name, field] of fields) {
|
|
720
|
+
if (!field.fills || !values[`${name}Data`])
|
|
721
|
+
continue;
|
|
722
|
+
for (const attr of Object.keys(field.fills)) {
|
|
723
|
+
if (written[attr] !== undefined)
|
|
724
|
+
out.push({ attribute: attr, field: name });
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return out;
|
|
728
|
+
};
|
|
729
|
+
const rootAttributes = (attrs) => {
|
|
730
|
+
const { moved } = moveAttributes(plan, attrs);
|
|
731
|
+
if (moved.size === 0)
|
|
732
|
+
return attrs;
|
|
733
|
+
const out = {};
|
|
734
|
+
for (const [name, value] of Object.entries(attrs))
|
|
735
|
+
if (!moved.has(name))
|
|
736
|
+
out[name] = value;
|
|
737
|
+
return out;
|
|
738
|
+
};
|
|
739
|
+
return {
|
|
740
|
+
transform,
|
|
741
|
+
info,
|
|
742
|
+
place,
|
|
743
|
+
placements: plan,
|
|
744
|
+
rootAttributes,
|
|
745
|
+
overriddenFills,
|
|
746
|
+
templateNodes: ast.children,
|
|
747
|
+
};
|
|
601
748
|
}
|
|
602
749
|
function asNodes(value) {
|
|
603
750
|
if (Array.isArray(value))
|
|
@@ -667,6 +814,19 @@ function substituteNode(node, ctx) {
|
|
|
667
814
|
}
|
|
668
815
|
attributes[key] = resolved;
|
|
669
816
|
}
|
|
817
|
+
if (node.type === 'tag') {
|
|
818
|
+
// D31 — the marker is the template's, consumed here: it reaches neither
|
|
819
|
+
// the placed rune's attributes nor the HTML.
|
|
820
|
+
delete attributes.chrome;
|
|
821
|
+
// D34.3 — author > template literal > definition default.
|
|
822
|
+
for (const [name, value] of Object.entries(ctx.defaults?.get(node) ?? {})) {
|
|
823
|
+
if (attributes[name] === undefined)
|
|
824
|
+
attributes[name] = value;
|
|
825
|
+
}
|
|
826
|
+
const moved = ctx.moves?.get(node);
|
|
827
|
+
if (moved)
|
|
828
|
+
Object.assign(attributes, moved);
|
|
829
|
+
}
|
|
670
830
|
return cloneNode(node, attributes, expand(node.children, ctx));
|
|
671
831
|
}
|
|
672
832
|
/** The items a list field resolved to, each with its `$each` binding and content. */
|
|
@@ -862,6 +1022,7 @@ const DEFINITION_KEYS = new Set([
|
|
|
862
1022
|
'metaFields',
|
|
863
1023
|
'blocks',
|
|
864
1024
|
'provides',
|
|
1025
|
+
'defaults',
|
|
865
1026
|
]);
|
|
866
1027
|
/** Keys that would give a composed rune styles of its own (D2). */
|
|
867
1028
|
const STYLE_KEYS = new Set(['css', 'style', 'styles', 'stylesheet', 'block', 'class']);
|
|
@@ -974,6 +1135,7 @@ export function parseCompositionDefinition(rune, source) {
|
|
|
974
1135
|
(!Array.isArray(fm.provides) || !fm.provides.every((p) => typeof p === 'string'))) {
|
|
975
1136
|
fail('invalid-value', '`provides` must be a list of names.', ['provides']);
|
|
976
1137
|
}
|
|
1138
|
+
const defaults = parseDefaults(fm.defaults, (code, msg, at) => fail(code, msg, ['defaults', ...(at ?? [])]));
|
|
977
1139
|
return {
|
|
978
1140
|
rune,
|
|
979
1141
|
tag,
|
|
@@ -986,12 +1148,46 @@ export function parseCompositionDefinition(rune, source) {
|
|
|
986
1148
|
...(fm.metaFields ? { metaFields: fm.metaFields } : {}),
|
|
987
1149
|
...(fm.blocks ? { blocks: fm.blocks } : {}),
|
|
988
1150
|
...(fm.provides ? { provides: fm.provides } : {}),
|
|
1151
|
+
...(defaults ? { defaults } : {}),
|
|
989
1152
|
template: match[2],
|
|
990
1153
|
// `---`, the frontmatter's lines, `---`: the body starts on the next.
|
|
991
1154
|
templateLine: frontmatter.split(/\r?\n/).length + 3,
|
|
992
1155
|
frontmatter,
|
|
993
1156
|
};
|
|
994
1157
|
}
|
|
1158
|
+
/** D34.6 — `density` has no author-facing attribute, so its scale is stated here. */
|
|
1159
|
+
const DENSITY_VALUES = ['full', 'compact', 'minimal'];
|
|
1160
|
+
/**
|
|
1161
|
+
* D34 — `defaults`: universal axes only, each with a value the axis accepts.
|
|
1162
|
+
* A rune's own attribute takes its default where it is declared.
|
|
1163
|
+
*/
|
|
1164
|
+
function parseDefaults(raw, fail) {
|
|
1165
|
+
if (raw === undefined)
|
|
1166
|
+
return undefined;
|
|
1167
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
1168
|
+
fail('defaults-invalid', '`defaults` must be a mapping of universal attributes to values.');
|
|
1169
|
+
}
|
|
1170
|
+
const out = {};
|
|
1171
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
1172
|
+
if (value === null || typeof value === 'object') {
|
|
1173
|
+
fail('defaults-invalid', `\`defaults.${key}\` must be a single value.`, [key]);
|
|
1174
|
+
}
|
|
1175
|
+
const text = String(value);
|
|
1176
|
+
const accepted = key === 'density'
|
|
1177
|
+
? DENSITY_VALUES
|
|
1178
|
+
: universalAttributeDefinition(key) === undefined
|
|
1179
|
+
? undefined
|
|
1180
|
+
: universalAttributeDefinition(key).matches;
|
|
1181
|
+
if (key !== 'density' && universalAttributeDefinition(key) === undefined) {
|
|
1182
|
+
fail('defaults-invalid', `\`defaults\` takes universal attributes only, and \`${key}\` is not one. A rune's own attribute takes its default where it is declared, under \`attributes\` (D34).`, [key]);
|
|
1183
|
+
}
|
|
1184
|
+
if (Array.isArray(accepted) && !accepted.includes(text)) {
|
|
1185
|
+
fail('defaults-invalid', `\`defaults.${key}\` is \`${text}\`, which \`${key}\` does not accept (${accepted.join(', ')}).`, [key]);
|
|
1186
|
+
}
|
|
1187
|
+
out[key] = text;
|
|
1188
|
+
}
|
|
1189
|
+
return out;
|
|
1190
|
+
}
|
|
995
1191
|
function parseAttributes(raw, sectionFail) {
|
|
996
1192
|
const fail = (code, msg) => sectionFail(code, msg);
|
|
997
1193
|
if (raw === undefined)
|
|
@@ -1042,6 +1238,7 @@ const FIELD_KEYS = new Set([
|
|
|
1042
1238
|
'itemModel',
|
|
1043
1239
|
'emitTag',
|
|
1044
1240
|
'emitAttributes',
|
|
1241
|
+
'fills',
|
|
1045
1242
|
]);
|
|
1046
1243
|
/** A field list as YAML writes it: a mapping keyed by name, or a list with `name`. */
|
|
1047
1244
|
function parseFields(raw, where, fail) {
|
|
@@ -1306,6 +1503,13 @@ function parseDelimitedModel(c, fail) {
|
|
|
1306
1503
|
* resolves a field against the rune's modifier values, exactly as it does for a
|
|
1307
1504
|
* tree-owning rune — which must declare the same attributes as modifiers for
|
|
1308
1505
|
* its own blocks to fill.
|
|
1506
|
+
*
|
|
1507
|
+
* An enum attribute the template only forwards to a placed rune
|
|
1508
|
+
* (`{% section media-position=$attrs["media-position"] %}`) is that rune's
|
|
1509
|
+
* input, not a modifier of the composition: as a `data-*` on the empty root it
|
|
1510
|
+
* would match the dimension rules meant for the rune it is forwarded to — a
|
|
1511
|
+
* `data-media-position="cover"` root is laid out as a cover well. It stays in
|
|
1512
|
+
* the field bag, which the schema row and registration read.
|
|
1309
1513
|
*/
|
|
1310
1514
|
export function composedRuneConfig(def) {
|
|
1311
1515
|
const read = new Set();
|
|
@@ -1317,22 +1521,39 @@ export function composedRuneConfig(def) {
|
|
|
1317
1521
|
read.add(ref);
|
|
1318
1522
|
}
|
|
1319
1523
|
}
|
|
1524
|
+
const forwarded = forwardedAttributes(def.template);
|
|
1320
1525
|
const modifiers = {};
|
|
1321
1526
|
for (const [name, attr] of Object.entries(def.attributes)) {
|
|
1322
|
-
if (!
|
|
1527
|
+
if (!read.has(name) && (!attr.matches || forwarded.has(name)))
|
|
1323
1528
|
continue;
|
|
1324
1529
|
modifiers[name] = {
|
|
1325
1530
|
source: 'meta',
|
|
1326
1531
|
...(attr.default !== undefined ? { default: String(attr.default) } : {}),
|
|
1327
1532
|
};
|
|
1328
1533
|
}
|
|
1534
|
+
// D34 — a root-placed axis's default is the generated config's, since a
|
|
1535
|
+
// template never writes on the root.
|
|
1536
|
+
const d = def.defaults ?? {};
|
|
1329
1537
|
return {
|
|
1538
|
+
composed: true,
|
|
1539
|
+
...(d.width ? { defaultWidth: d.width } : {}),
|
|
1540
|
+
...(d.spacing ? { defaultSpacing: d.spacing } : {}),
|
|
1541
|
+
...(d.inset ? { defaultInset: d.inset } : {}),
|
|
1330
1542
|
...(Object.keys(modifiers).length > 0 ? { modifiers } : {}),
|
|
1331
1543
|
...(def.metaFields ? { metaFields: def.metaFields } : {}),
|
|
1332
1544
|
...(def.blocks ? { blocks: def.blocks } : {}),
|
|
1333
1545
|
...(def.provides ? { provides: def.provides } : {}),
|
|
1334
1546
|
};
|
|
1335
1547
|
}
|
|
1548
|
+
/** The attributes a template passes to a placed rune as an attribute value:
|
|
1549
|
+
* `name=$attrs.x` or `name=$attrs["x"]`. */
|
|
1550
|
+
function forwardedAttributes(template) {
|
|
1551
|
+
const out = new Set();
|
|
1552
|
+
for (const m of template.matchAll(/[\w-]+\s*=\s*\$attrs(?:\.([\w-]+)|\[\s*["']([^"']+)["']\s*\])/g)) {
|
|
1553
|
+
out.add(m[1] ?? m[2]);
|
|
1554
|
+
}
|
|
1555
|
+
return out;
|
|
1556
|
+
}
|
|
1336
1557
|
/** The schema types a rune can emit at its root — its table's, and its `seoType`. */
|
|
1337
1558
|
function emittedTypes(entry, table) {
|
|
1338
1559
|
return [
|