@refrakt-md/runes 0.7.2 → 0.8.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/config.d.ts.map +1 -1
- package/dist/config.js +81 -24
- package/dist/config.js.map +1 -1
- package/dist/documents/page.js +3 -3
- package/dist/documents/page.js.map +1 -1
- package/dist/examples.d.ts.map +1 -1
- package/dist/examples.js +5 -1
- package/dist/examples.js.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/annotations/annotation.d.ts +1 -1
- package/dist/lib/annotations/annotation.d.ts.map +1 -1
- package/dist/lib/annotations/annotation.js +20 -2
- package/dist/lib/annotations/annotation.js.map +1 -1
- package/dist/lib/component.d.ts +10 -2
- package/dist/lib/component.d.ts.map +1 -1
- package/dist/lib/component.js +16 -3
- package/dist/lib/component.js.map +1 -1
- package/dist/lib/index.d.ts +40 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +302 -3
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/model.d.ts +4 -0
- package/dist/lib/model.d.ts.map +1 -1
- package/dist/lib/model.js +17 -0
- package/dist/lib/model.js.map +1 -1
- package/dist/lib/renderable.d.ts.map +1 -1
- package/dist/lib/renderable.js +2 -1
- package/dist/lib/renderable.js.map +1 -1
- package/dist/lib/resolver.d.ts +73 -0
- package/dist/lib/resolver.d.ts.map +1 -0
- package/dist/lib/resolver.js +500 -0
- package/dist/lib/resolver.js.map +1 -0
- package/dist/nodes.js +2 -2
- package/dist/nodes.js.map +1 -1
- package/dist/packages.d.ts +2 -0
- package/dist/packages.d.ts.map +1 -1
- package/dist/packages.js +7 -0
- package/dist/packages.js.map +1 -1
- package/dist/registry.d.ts +8 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +16 -8
- package/dist/registry.js.map +1 -1
- package/dist/schema/annotate.d.ts +1 -1
- package/dist/schema/annotate.d.ts.map +1 -1
- package/dist/schema/annotate.js +1 -1
- package/dist/schema/annotate.js.map +1 -1
- package/dist/schema/bg.d.ts +11 -0
- package/dist/schema/bg.d.ts.map +1 -0
- package/dist/schema/bg.js +13 -0
- package/dist/schema/bg.js.map +1 -0
- package/dist/schema/budget.d.ts +1 -1
- package/dist/schema/budget.d.ts.map +1 -1
- package/dist/schema/budget.js +1 -1
- package/dist/schema/budget.js.map +1 -1
- package/dist/schema/form.d.ts +1 -1
- package/dist/schema/form.d.ts.map +1 -1
- package/dist/schema/form.js +1 -1
- package/dist/schema/form.js.map +1 -1
- package/dist/schema/gallery.d.ts +8 -0
- package/dist/schema/gallery.d.ts.map +1 -0
- package/dist/schema/gallery.js +10 -0
- package/dist/schema/gallery.js.map +1 -0
- package/dist/schema/pullquote.d.ts +1 -1
- package/dist/schema/pullquote.d.ts.map +1 -1
- package/dist/schema/pullquote.js +1 -1
- package/dist/schema/pullquote.js.map +1 -1
- package/dist/schema/showcase.d.ts +8 -0
- package/dist/schema/showcase.d.ts.map +1 -0
- package/dist/schema/showcase.js +10 -0
- package/dist/schema/showcase.js.map +1 -0
- package/dist/schema/sidenote.d.ts +1 -1
- package/dist/schema/sidenote.d.ts.map +1 -1
- package/dist/schema/sidenote.js +1 -1
- package/dist/schema/sidenote.js.map +1 -1
- package/dist/schema/tint.d.ts +5 -0
- package/dist/schema/tint.d.ts.map +1 -0
- package/dist/schema/tint.js +7 -0
- package/dist/schema/tint.js.map +1 -0
- package/dist/seo.d.ts +7 -7
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +99 -391
- package/dist/seo.js.map +1 -1
- package/dist/tags/accordion.d.ts.map +1 -1
- package/dist/tags/accordion.js +63 -55
- package/dist/tags/accordion.js.map +1 -1
- package/dist/tags/annotate.d.ts.map +1 -1
- package/dist/tags/annotate.js +31 -34
- package/dist/tags/annotate.js.map +1 -1
- package/dist/tags/bg.d.ts +10 -0
- package/dist/tags/bg.d.ts.map +1 -0
- package/dist/tags/bg.js +56 -0
- package/dist/tags/bg.js.map +1 -0
- package/dist/tags/breadcrumb.d.ts.map +1 -1
- package/dist/tags/breadcrumb.js +42 -39
- package/dist/tags/breadcrumb.js.map +1 -1
- package/dist/tags/budget.d.ts.map +1 -1
- package/dist/tags/budget.js +69 -96
- package/dist/tags/budget.js.map +1 -1
- package/dist/tags/chart.d.ts.map +1 -1
- package/dist/tags/chart.js +21 -38
- package/dist/tags/chart.js.map +1 -1
- package/dist/tags/codegroup.d.ts.map +1 -1
- package/dist/tags/codegroup.js +32 -34
- package/dist/tags/codegroup.js.map +1 -1
- package/dist/tags/common.d.ts +9 -0
- package/dist/tags/common.d.ts.map +1 -1
- package/dist/tags/common.js +32 -0
- package/dist/tags/common.js.map +1 -1
- package/dist/tags/compare.d.ts.map +1 -1
- package/dist/tags/compare.js +21 -31
- package/dist/tags/compare.js.map +1 -1
- package/dist/tags/conversation.d.ts.map +1 -1
- package/dist/tags/conversation.js +58 -62
- package/dist/tags/conversation.js.map +1 -1
- package/dist/tags/datatable.d.ts.map +1 -1
- package/dist/tags/datatable.js +23 -43
- package/dist/tags/datatable.js.map +1 -1
- package/dist/tags/details.d.ts.map +1 -1
- package/dist/tags/details.js +20 -39
- package/dist/tags/details.js.map +1 -1
- package/dist/tags/diagram.d.ts.map +1 -1
- package/dist/tags/diagram.js +22 -38
- package/dist/tags/diagram.js.map +1 -1
- package/dist/tags/diff.d.ts.map +1 -1
- package/dist/tags/diff.js +25 -44
- package/dist/tags/diff.js.map +1 -1
- package/dist/tags/embed.d.ts.map +1 -1
- package/dist/tags/embed.js +30 -43
- package/dist/tags/embed.js.map +1 -1
- package/dist/tags/error.d.ts.map +1 -1
- package/dist/tags/error.js +20 -35
- package/dist/tags/error.js.map +1 -1
- package/dist/tags/figure.d.ts.map +1 -1
- package/dist/tags/figure.js +27 -38
- package/dist/tags/figure.js.map +1 -1
- package/dist/tags/form.d.ts.map +1 -1
- package/dist/tags/form.js +157 -184
- package/dist/tags/form.js.map +1 -1
- package/dist/tags/gallery.d.ts +3 -0
- package/dist/tags/gallery.d.ts.map +1 -0
- package/dist/tags/gallery.js +63 -0
- package/dist/tags/gallery.js.map +1 -0
- package/dist/tags/grid.d.ts +2 -1
- package/dist/tags/grid.d.ts.map +1 -1
- package/dist/tags/grid.js +73 -45
- package/dist/tags/grid.js.map +1 -1
- package/dist/tags/hint.d.ts.map +1 -1
- package/dist/tags/hint.js +20 -27
- package/dist/tags/hint.js.map +1 -1
- package/dist/tags/layout.d.ts.map +1 -1
- package/dist/tags/layout.js +17 -27
- package/dist/tags/layout.js.map +1 -1
- package/dist/tags/mediatext.d.ts.map +1 -1
- package/dist/tags/mediatext.js +24 -37
- package/dist/tags/mediatext.js.map +1 -1
- package/dist/tags/nav.d.ts.map +1 -1
- package/dist/tags/nav.js +61 -76
- package/dist/tags/nav.js.map +1 -1
- package/dist/tags/pullquote.d.ts.map +1 -1
- package/dist/tags/pullquote.js +22 -34
- package/dist/tags/pullquote.js.map +1 -1
- package/dist/tags/region.d.ts.map +1 -1
- package/dist/tags/region.js +19 -32
- package/dist/tags/region.js.map +1 -1
- package/dist/tags/reveal.d.ts.map +1 -1
- package/dist/tags/reveal.js +35 -55
- package/dist/tags/reveal.js.map +1 -1
- package/dist/tags/sandbox.js +1 -1
- package/dist/tags/sandbox.js.map +1 -1
- package/dist/tags/showcase.d.ts +3 -0
- package/dist/tags/showcase.d.ts.map +1 -0
- package/dist/tags/showcase.js +72 -0
- package/dist/tags/showcase.js.map +1 -0
- package/dist/tags/sidenote.d.ts.map +1 -1
- package/dist/tags/sidenote.js +21 -29
- package/dist/tags/sidenote.js.map +1 -1
- package/dist/tags/tabs.d.ts.map +1 -1
- package/dist/tags/tabs.js +52 -58
- package/dist/tags/tabs.js.map +1 -1
- package/dist/tags/textblock.d.ts.map +1 -1
- package/dist/tags/textblock.js +27 -43
- package/dist/tags/textblock.js.map +1 -1
- package/dist/tags/tint.d.ts +12 -0
- package/dist/tags/tint.d.ts.map +1 -0
- package/dist/tags/tint.js +88 -0
- package/dist/tags/tint.js.map +1 -0
- package/dist/tags/toc.d.ts.map +1 -1
- package/dist/tags/toc.js +17 -32
- package/dist/tags/toc.js.map +1 -1
- package/package.json +3 -3
package/dist/lib/model.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ import { RenderableNodeCursor } from './renderable.js';
|
|
|
5
5
|
export declare class Model {
|
|
6
6
|
readonly node: Node;
|
|
7
7
|
readonly config: Config;
|
|
8
|
+
/** Extracted tint child node (set by processChildren before @group runs) */
|
|
9
|
+
_tintNode: Node | null;
|
|
10
|
+
/** Extracted bg child node (set by processChildren before @group runs) */
|
|
11
|
+
_bgNode: Node | null;
|
|
8
12
|
constructor(node: Node, config: Config);
|
|
9
13
|
processChildren(nodes: Node[]): Markdoc.Node[];
|
|
10
14
|
transform(): RenderableTreeNodes;
|
package/dist/lib/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAKvD,qBAAa,KAAK;
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5F,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAKvD,qBAAa,KAAK;aAOE,IAAI,EAAE,IAAI;aACV,MAAM,EAAE,MAAM;IAPhC,4EAA4E;IAC5E,SAAS,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC9B,0EAA0E;IAC1E,OAAO,EAAE,IAAI,GAAG,IAAI,CAAQ;gBAGV,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM;IAOhC,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE;IAwB7B,SAAS,IAAI,mBAAmB;IAIhC,iBAAiB,CACf,KAAK,GAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,KAAK,mBAAmB,CAAC,CAAC,CAAM,GACzH,oBAAoB;CAQxB"}
|
package/dist/lib/model.js
CHANGED
|
@@ -7,11 +7,28 @@ export class Model {
|
|
|
7
7
|
constructor(node, config) {
|
|
8
8
|
this.node = node;
|
|
9
9
|
this.config = config;
|
|
10
|
+
/** Extracted tint child node (set by processChildren before @group runs) */
|
|
11
|
+
this._tintNode = null;
|
|
12
|
+
/** Extracted bg child node (set by processChildren before @group runs) */
|
|
13
|
+
this._bgNode = null;
|
|
10
14
|
for (const annotation of GeneratedAttributeAnnotation.onClass(this.constructor, true)) {
|
|
11
15
|
annotation.create(node, config);
|
|
12
16
|
}
|
|
13
17
|
}
|
|
14
18
|
processChildren(nodes) {
|
|
19
|
+
// Extract tint tag before @group processing so it doesn't interfere
|
|
20
|
+
// with header/body splitting (tint has type 'tag', which breaks @group)
|
|
21
|
+
const tintIdx = nodes.findIndex(n => n.type === 'tag' && n.tag === 'tint');
|
|
22
|
+
if (tintIdx !== -1) {
|
|
23
|
+
this._tintNode = nodes[tintIdx];
|
|
24
|
+
nodes = [...nodes.slice(0, tintIdx), ...nodes.slice(tintIdx + 1)];
|
|
25
|
+
}
|
|
26
|
+
// Extract bg tag before @group processing (same pattern as tint)
|
|
27
|
+
const bgIdx = nodes.findIndex(n => n.type === 'tag' && n.tag === 'bg');
|
|
28
|
+
if (bgIdx !== -1) {
|
|
29
|
+
this._bgNode = nodes[bgIdx];
|
|
30
|
+
nodes = [...nodes.slice(0, bgIdx), ...nodes.slice(bgIdx + 1)];
|
|
31
|
+
}
|
|
15
32
|
let index = 0;
|
|
16
33
|
for (const annotation of AbstractGroupAnnotation.onClass(this.constructor, true)) {
|
|
17
34
|
index = annotation.create(nodes, index, this.config);
|
package/dist/lib/model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAGvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,OAAO,KAAK;
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/lib/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderable.d.ts","sourceRoot":"","sources":["../../src/lib/renderable.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"renderable.d.ts","sourceRoot":"","sources":["../../src/lib/renderable.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI7C,qBAAa,oBAAoB,CAAC,CAAC,SAAS,kBAAkB,GAAG,kBAAkB;aAGrD,KAAK,EAAE,CAAC,EAAE;IAFtC,OAAO,CAAC,MAAM,CAAK;gBAES,KAAK,EAAE,CAAC,EAAE;IAEtC,MAAM,CAAC,QAAQ,CAAC,OAAO,SAAS,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO;IAIjE,IAAI,CAAC,OAAO,SAAS,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAIpH,GAAG,CAAC,OAAO,SAAS,QAAQ,EAAE,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAK/E,IAAI,CAAC,QAAQ,SAAS,QAAQ,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAKjG,QAAQ;IAIR,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAAC,CAAC,CAAC;IAI7C,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,kBAAkB,GAAG,oBAAoB,CAAC,EAAE;IAK9D,OAAO;IAKP,KAAK,CAAC,KAAK,EAAE,MAAM;IAInB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;IAIjC,OAAO,IAAI,CAAC,EAAE;IAId,KAAK,IAAI,MAAM;IAIf,IAAI,IAAI,CAAC;CAGV"}
|
package/dist/lib/renderable.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Markdoc from '@markdoc/markdoc';
|
|
2
|
+
import { toKebabCase } from '@refrakt-md/transform';
|
|
2
3
|
import { walkTag } from '../util.js';
|
|
3
4
|
export class RenderableNodeCursor {
|
|
4
5
|
constructor(nodes) {
|
|
@@ -23,7 +24,7 @@ export class RenderableNodeCursor {
|
|
|
23
24
|
return this.tags('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
|
|
24
25
|
}
|
|
25
26
|
typeof(type) {
|
|
26
|
-
return new RenderableNodeCursor(this.nodes.filter(n => Markdoc.Tag.isTag(n) && n.attributes
|
|
27
|
+
return new RenderableNodeCursor(this.nodes.filter(n => Markdoc.Tag.isTag(n) && n.attributes['data-rune'] === toKebabCase(type)));
|
|
27
28
|
}
|
|
28
29
|
concat(...other) {
|
|
29
30
|
const nodes = other.map(o => o instanceof RenderableNodeCursor ? o.nodes : o).flat();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderable.js","sourceRoot":"","sources":["../../src/lib/renderable.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAGvC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,MAAM,OAAO,oBAAoB;IAG/B,YAA4B,KAAU;QAAV,UAAK,GAAL,KAAK,CAAK;QAF9B,WAAM,GAAG,CAAC,CAAC;IAEsB,CAAC;IAE1C,MAAM,CAAC,QAAQ,CAA2B,IAAS,EAAE,GAAY;QAC/D,OAAO,IAAI,oBAAoB,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,CAAyB,GAAY,EAAE,aAAkC,EAAE;QAC7E,OAAO,IAAI,oBAAoB,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,GAAG,CAA2B,GAAY;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,GAAG,CAA8B,CAAC;QAC1G,OAAO,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,CAA8B,GAAG,IAAc;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAK,IAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAuC,CAAC;QACxI,OAAO,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,CAAC,IAAY;QACjB,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"renderable.js","sourceRoot":"","sources":["../../src/lib/renderable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content model resolver engine.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions that resolve a rune's AST children against a declarative
|
|
5
|
+
* content model, producing named fields without per-rune imperative code.
|
|
6
|
+
*/
|
|
7
|
+
import type { Node } from '@markdoc/markdoc';
|
|
8
|
+
import type { ContentModel, ContentFieldDefinition, DelimitedModel, SectionsModel, ContentModelCondition, ItemModel, ResolvedContent } from '@refrakt-md/types';
|
|
9
|
+
export interface ResolveResult {
|
|
10
|
+
/** Resolved content fields. */
|
|
11
|
+
content: ResolvedContent;
|
|
12
|
+
/** Extracted tint child tag (if present). */
|
|
13
|
+
tintNode?: Node;
|
|
14
|
+
/** Extracted bg child tag (if present). */
|
|
15
|
+
bgNode?: Node;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check whether an AST node matches a field's `match` string.
|
|
19
|
+
*
|
|
20
|
+
* Supported match values:
|
|
21
|
+
* - `'paragraph'`, `'heading'`, `'image'`, `'blockquote'`, `'fence'`,
|
|
22
|
+
* `'hr'`, `'list'` — match on `node.type`
|
|
23
|
+
* - `'heading:N'` — heading with a specific level
|
|
24
|
+
* - `'list:ordered'` / `'list:unordered'` — list with a specific ordering
|
|
25
|
+
* - `'tag:NAME'` — a child rune tag with a specific tag name
|
|
26
|
+
* - `'any'` — matches any node
|
|
27
|
+
*/
|
|
28
|
+
export declare function matchesType(node: Node, match: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a sequence model: walk children in order, matching each against
|
|
31
|
+
* the next field in the model.
|
|
32
|
+
*
|
|
33
|
+
* - Optional fields are skipped when the next child doesn't match.
|
|
34
|
+
* - Greedy fields consume all consecutive matching nodes into an array.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSequence(children: Node[], fields: ContentFieldDefinition[]): ResolvedContent;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a delimited model: split children by delimiter nodes, then
|
|
39
|
+
* resolve each zone's content.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveDelimited(children: Node[], model: DelimitedModel): ResolvedContent;
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a sections model: split children at heading boundaries,
|
|
44
|
+
* optionally extracting heading data and emitting child rune tags.
|
|
45
|
+
*
|
|
46
|
+
* - Preamble (content before first section heading) is resolved via `fields`.
|
|
47
|
+
* - When `emitTag` is set, sections become AST tag nodes for child rune processing.
|
|
48
|
+
* - When `emitTag` is absent, sections are resolved objects with heading info + body.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveSections(children: Node[], model: SectionsModel): ResolvedContent;
|
|
51
|
+
/**
|
|
52
|
+
* Evaluate a content model condition against children and attributes.
|
|
53
|
+
*/
|
|
54
|
+
export declare function evaluateCondition(condition: ContentModelCondition, children: Node[], attributes: Record<string, unknown>): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve structured data from list item inline content.
|
|
57
|
+
*
|
|
58
|
+
* Two-phase extraction:
|
|
59
|
+
* 1. Match typed inline nodes (strong, em, link, image, code)
|
|
60
|
+
* 2. Collect remaining text, run regex pattern fields
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveListItems(listNode: Node, itemModel: ItemModel): Record<string, unknown>[];
|
|
63
|
+
/**
|
|
64
|
+
* Resolve a content model against AST children.
|
|
65
|
+
* Dispatches to the pattern-specific resolver based on `model.type`.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolve(children: Node[], model: ContentModel, attributes?: Record<string, unknown>): ResolvedContent;
|
|
68
|
+
/**
|
|
69
|
+
* Full resolution entry point: extracts special tags (tint, bg), then
|
|
70
|
+
* resolves the content model.
|
|
71
|
+
*/
|
|
72
|
+
export declare function resolveContentModel(children: Node[], model: ContentModel, attributes?: Record<string, unknown>): ResolveResult;
|
|
73
|
+
//# sourceMappingURL=resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/lib/resolver.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EACX,YAAY,EACZ,sBAAsB,EACtB,cAAc,EAEd,aAAa,EAGb,qBAAqB,EACrB,SAAS,EAGT,eAAe,EACf,MAAM,mBAAmB,CAAC;AAM3B,MAAM,WAAW,aAAa;IAC7B,+BAA+B;IAC/B,OAAO,EAAE,eAAe,CAAC;IAEzB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,IAAI,CAAC;IAEhB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,IAAI,CAAC;CACd;AAiCD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CA8B9D;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,IAAI,EAAE,EAChB,MAAM,EAAE,sBAAsB,EAAE,GAC9B,eAAe,CA0CjB;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,IAAI,EAAE,EAChB,KAAK,EAAE,cAAc,GACnB,eAAe,CA6BjB;AA8CD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,IAAI,EAAE,EAChB,KAAK,EAAE,aAAa,GAClB,eAAe,CA0FjB;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,qBAAqB,EAChC,QAAQ,EAAE,IAAI,EAAE,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAYT;AAiDD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,IAAI,EACd,SAAS,EAAE,SAAS,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAiH3B;AAMD;;;GAGG;AACH,wBAAgB,OAAO,CACtB,QAAQ,EAAE,IAAI,EAAE,EAChB,KAAK,EAAE,YAAY,EACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,eAAe,CAuBjB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,IAAI,EAAE,EAChB,KAAK,EAAE,YAAY,EACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,aAAa,CAIf"}
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content model resolver engine.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions that resolve a rune's AST children against a declarative
|
|
5
|
+
* content model, producing named fields without per-rune imperative code.
|
|
6
|
+
*/
|
|
7
|
+
import Markdoc from '@markdoc/markdoc';
|
|
8
|
+
const { Ast } = Markdoc;
|
|
9
|
+
/**
|
|
10
|
+
* Extract special child tags (tint, bg) from children before resolving.
|
|
11
|
+
* Returns the filtered children and extracted nodes.
|
|
12
|
+
*/
|
|
13
|
+
function extractSpecialTags(children) {
|
|
14
|
+
let tintNode;
|
|
15
|
+
let bgNode;
|
|
16
|
+
const filtered = children.filter(n => {
|
|
17
|
+
if (n.type === 'tag' && n.tag === 'tint') {
|
|
18
|
+
tintNode = n;
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (n.type === 'tag' && n.tag === 'bg') {
|
|
22
|
+
bgNode = n;
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
});
|
|
27
|
+
return { filtered, tintNode, bgNode };
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Type matching
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Check whether an AST node matches a field's `match` string.
|
|
34
|
+
*
|
|
35
|
+
* Supported match values:
|
|
36
|
+
* - `'paragraph'`, `'heading'`, `'image'`, `'blockquote'`, `'fence'`,
|
|
37
|
+
* `'hr'`, `'list'` — match on `node.type`
|
|
38
|
+
* - `'heading:N'` — heading with a specific level
|
|
39
|
+
* - `'list:ordered'` / `'list:unordered'` — list with a specific ordering
|
|
40
|
+
* - `'tag:NAME'` — a child rune tag with a specific tag name
|
|
41
|
+
* - `'any'` — matches any node
|
|
42
|
+
*/
|
|
43
|
+
export function matchesType(node, match) {
|
|
44
|
+
if (match === 'any')
|
|
45
|
+
return true;
|
|
46
|
+
// Pipe-separated alternatives: 'list|fence' matches either
|
|
47
|
+
if (match.includes('|')) {
|
|
48
|
+
return match.split('|').some(m => matchesType(node, m));
|
|
49
|
+
}
|
|
50
|
+
// heading:N
|
|
51
|
+
if (match.startsWith('heading:')) {
|
|
52
|
+
const level = parseInt(match.slice(8), 10);
|
|
53
|
+
return node.type === 'heading' && node.attributes?.level === level;
|
|
54
|
+
}
|
|
55
|
+
// list:ordered / list:unordered
|
|
56
|
+
if (match === 'list:ordered') {
|
|
57
|
+
return node.type === 'list' && node.attributes?.ordered === true;
|
|
58
|
+
}
|
|
59
|
+
if (match === 'list:unordered') {
|
|
60
|
+
return node.type === 'list' && node.attributes?.ordered !== true;
|
|
61
|
+
}
|
|
62
|
+
// tag:NAME
|
|
63
|
+
if (match.startsWith('tag:')) {
|
|
64
|
+
const tagName = match.slice(4);
|
|
65
|
+
return node.type === 'tag' && node.tag === tagName;
|
|
66
|
+
}
|
|
67
|
+
// Simple type match
|
|
68
|
+
return node.type === match;
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Sequence resolver
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
/**
|
|
74
|
+
* Resolve a sequence model: walk children in order, matching each against
|
|
75
|
+
* the next field in the model.
|
|
76
|
+
*
|
|
77
|
+
* - Optional fields are skipped when the next child doesn't match.
|
|
78
|
+
* - Greedy fields consume all consecutive matching nodes into an array.
|
|
79
|
+
*/
|
|
80
|
+
export function resolveSequence(children, fields) {
|
|
81
|
+
const result = {};
|
|
82
|
+
let childIndex = 0;
|
|
83
|
+
for (const field of fields) {
|
|
84
|
+
if (childIndex >= children.length) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const child = children[childIndex];
|
|
88
|
+
if (matchesType(child, field.match)) {
|
|
89
|
+
if (field.greedy) {
|
|
90
|
+
const collected = [];
|
|
91
|
+
while (childIndex < children.length &&
|
|
92
|
+
matchesType(children[childIndex], field.match)) {
|
|
93
|
+
collected.push(children[childIndex]);
|
|
94
|
+
childIndex++;
|
|
95
|
+
}
|
|
96
|
+
result[field.name] = collected;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
result[field.name] = child;
|
|
100
|
+
childIndex++;
|
|
101
|
+
}
|
|
102
|
+
// If this list field has an itemModel, extract structured data
|
|
103
|
+
if (field.itemModel) {
|
|
104
|
+
const node = result[field.name];
|
|
105
|
+
if (node && typeof node === 'object' && 'type' in node) {
|
|
106
|
+
result[`${field.name}Data`] = resolveListItems(node, field.itemModel);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (!field.optional) {
|
|
111
|
+
// Required field didn't match — skip the child and move on
|
|
112
|
+
childIndex++;
|
|
113
|
+
}
|
|
114
|
+
// If optional and doesn't match, just skip the field (don't advance child)
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Delimited resolver
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
/**
|
|
122
|
+
* Resolve a delimited model: split children by delimiter nodes, then
|
|
123
|
+
* resolve each zone's content.
|
|
124
|
+
*/
|
|
125
|
+
export function resolveDelimited(children, model) {
|
|
126
|
+
// Split children into groups at each delimiter
|
|
127
|
+
const groups = [[]];
|
|
128
|
+
for (const child of children) {
|
|
129
|
+
if (matchesType(child, model.delimiter)) {
|
|
130
|
+
groups.push([]);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
groups[groups.length - 1].push(child);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (model.dynamicZones && model.zoneModel) {
|
|
137
|
+
return {
|
|
138
|
+
zones: groups.map(group => resolve(group, model.zoneModel)),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// Named zones: each group maps to a declared zone by index
|
|
142
|
+
const result = {};
|
|
143
|
+
if (model.zones) {
|
|
144
|
+
for (let i = 0; i < model.zones.length; i++) {
|
|
145
|
+
const zone = model.zones[i];
|
|
146
|
+
const group = i < groups.length ? groups[i] : [];
|
|
147
|
+
result[zone.name] = resolveSequence(group, zone.fields);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Sections resolver
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
/** Extract plain text from a heading AST node by walking its children. */
|
|
156
|
+
function extractHeadingText(headingNode) {
|
|
157
|
+
const texts = [];
|
|
158
|
+
for (const child of headingNode.walk()) {
|
|
159
|
+
if (child.type === 'text' && child.attributes?.content) {
|
|
160
|
+
texts.push(child.attributes.content);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return texts.join(' ');
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Apply heading extract patterns to heading text, producing named fields.
|
|
167
|
+
* Each field's regex is applied in order; 'remainder' captures what's left.
|
|
168
|
+
*/
|
|
169
|
+
function applyHeadingExtract(text, extract) {
|
|
170
|
+
const result = {};
|
|
171
|
+
let remaining = text;
|
|
172
|
+
for (const field of extract.fields) {
|
|
173
|
+
if (field.pattern === 'remainder') {
|
|
174
|
+
result[field.name] = remaining.trim();
|
|
175
|
+
remaining = '';
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const match = remaining.match(field.pattern);
|
|
179
|
+
if (match) {
|
|
180
|
+
result[field.name] = (match[1] || match[0]).trim();
|
|
181
|
+
remaining = remaining.slice(match[0].length);
|
|
182
|
+
}
|
|
183
|
+
else if (!field.optional) {
|
|
184
|
+
result[field.name] = remaining.trim();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Resolve a sections model: split children at heading boundaries,
|
|
192
|
+
* optionally extracting heading data and emitting child rune tags.
|
|
193
|
+
*
|
|
194
|
+
* - Preamble (content before first section heading) is resolved via `fields`.
|
|
195
|
+
* - When `emitTag` is set, sections become AST tag nodes for child rune processing.
|
|
196
|
+
* - When `emitTag` is absent, sections are resolved objects with heading info + body.
|
|
197
|
+
*/
|
|
198
|
+
export function resolveSections(children, model) {
|
|
199
|
+
// 1. Determine heading level
|
|
200
|
+
const headingSpec = model.sectionHeading;
|
|
201
|
+
let level;
|
|
202
|
+
if (headingSpec.includes(':')) {
|
|
203
|
+
level = parseInt(headingSpec.split(':')[1], 10);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
// Auto-detect from first heading child
|
|
207
|
+
level = children.find(n => n.type === 'heading')?.attributes?.level;
|
|
208
|
+
}
|
|
209
|
+
if (level === undefined) {
|
|
210
|
+
// No headings found — everything is preamble
|
|
211
|
+
const preamble = model.fields
|
|
212
|
+
? resolveSequence(children, model.fields)
|
|
213
|
+
: {};
|
|
214
|
+
return { ...preamble, sections: [] };
|
|
215
|
+
}
|
|
216
|
+
// 2. Split at section-level headings
|
|
217
|
+
const preambleNodes = [];
|
|
218
|
+
const rawSections = [];
|
|
219
|
+
let current = null;
|
|
220
|
+
for (const child of children) {
|
|
221
|
+
if (child.type === 'heading' && child.attributes?.level === level) {
|
|
222
|
+
if (current)
|
|
223
|
+
rawSections.push(current);
|
|
224
|
+
current = { headingNode: child, body: [] };
|
|
225
|
+
}
|
|
226
|
+
else if (current) {
|
|
227
|
+
current.body.push(child);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
preambleNodes.push(child);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (current)
|
|
234
|
+
rawSections.push(current);
|
|
235
|
+
// 3. Resolve preamble fields
|
|
236
|
+
const preamble = model.fields
|
|
237
|
+
? resolveSequence(preambleNodes, model.fields)
|
|
238
|
+
: {};
|
|
239
|
+
// 4. Process each section
|
|
240
|
+
if (model.emitTag) {
|
|
241
|
+
// emitTag: convert sections to AST tag nodes
|
|
242
|
+
const tagNodes = rawSections.map(section => {
|
|
243
|
+
const headingText = extractHeadingText(section.headingNode);
|
|
244
|
+
const extracted = model.headingExtract
|
|
245
|
+
? applyHeadingExtract(headingText, model.headingExtract)
|
|
246
|
+
: {};
|
|
247
|
+
const attrs = {};
|
|
248
|
+
if (model.emitAttributes) {
|
|
249
|
+
for (const [key, ref] of Object.entries(model.emitAttributes)) {
|
|
250
|
+
if (ref === '$heading') {
|
|
251
|
+
attrs[key] = headingText;
|
|
252
|
+
}
|
|
253
|
+
else if (ref.startsWith('$')) {
|
|
254
|
+
attrs[key] = extracted[ref.slice(1)] ?? '';
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
attrs[key] = ref;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return new Ast.Node('tag', attrs, section.body, model.emitTag);
|
|
262
|
+
});
|
|
263
|
+
return { ...preamble, sections: tagNodes };
|
|
264
|
+
}
|
|
265
|
+
// No emitTag: return resolved section data
|
|
266
|
+
const resolvedSections = rawSections.map(section => {
|
|
267
|
+
const headingText = extractHeadingText(section.headingNode);
|
|
268
|
+
const extracted = model.headingExtract
|
|
269
|
+
? applyHeadingExtract(headingText, model.headingExtract)
|
|
270
|
+
: {};
|
|
271
|
+
const bodyResolved = resolve(section.body, model.sectionModel);
|
|
272
|
+
return {
|
|
273
|
+
$heading: headingText,
|
|
274
|
+
$headingNode: section.headingNode,
|
|
275
|
+
...Object.fromEntries(Object.entries(extracted).map(([k, v]) => [`$${k}`, v])),
|
|
276
|
+
...bodyResolved,
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
return { ...preamble, sections: resolvedSections };
|
|
280
|
+
}
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
// Conditional evaluation
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
/**
|
|
285
|
+
* Evaluate a content model condition against children and attributes.
|
|
286
|
+
*/
|
|
287
|
+
export function evaluateCondition(condition, children, attributes) {
|
|
288
|
+
if ('hasChild' in condition) {
|
|
289
|
+
return children.some(c => matchesType(c, condition.hasChild));
|
|
290
|
+
}
|
|
291
|
+
if ('in' in condition) {
|
|
292
|
+
const value = String(attributes[condition.attribute] ?? '');
|
|
293
|
+
return condition.in.includes(value);
|
|
294
|
+
}
|
|
295
|
+
if ('exists' in condition) {
|
|
296
|
+
return attributes[condition.attribute] != null && attributes[condition.attribute] !== '';
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Check whether a content model is conditional (has `when` branches).
|
|
302
|
+
*/
|
|
303
|
+
function isConditional(model) {
|
|
304
|
+
return 'when' in model && Array.isArray(model.when);
|
|
305
|
+
}
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
// Inline item model resolver
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
/** Extract plain text from an AST node by walking its children. */
|
|
310
|
+
function extractNodeText(n) {
|
|
311
|
+
if (n.type === 'text')
|
|
312
|
+
return n.attributes?.content ?? '';
|
|
313
|
+
const texts = [];
|
|
314
|
+
for (const child of n.walk()) {
|
|
315
|
+
if (child.type === 'text' && child.attributes?.content) {
|
|
316
|
+
texts.push(child.attributes.content);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return texts.join('');
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Find an inline match within a node, handling link-wrapping-strong patterns.
|
|
323
|
+
* E.g., `[**Name**](/url)` — a link wrapping bold text.
|
|
324
|
+
*/
|
|
325
|
+
function findInlineMatch(n, matchType) {
|
|
326
|
+
if (n.type === matchType)
|
|
327
|
+
return n;
|
|
328
|
+
// Check inside links for nested inline types
|
|
329
|
+
if (n.type === 'link' && matchType !== 'link') {
|
|
330
|
+
for (const child of n.children ?? []) {
|
|
331
|
+
if (child.type === matchType)
|
|
332
|
+
return child;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Check inside strong/em for nested types
|
|
336
|
+
if ((n.type === 'strong' || n.type === 'em') && matchType !== n.type) {
|
|
337
|
+
for (const child of n.children ?? []) {
|
|
338
|
+
if (child.type === matchType)
|
|
339
|
+
return child;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Resolve structured data from list item inline content.
|
|
346
|
+
*
|
|
347
|
+
* Two-phase extraction:
|
|
348
|
+
* 1. Match typed inline nodes (strong, em, link, image, code)
|
|
349
|
+
* 2. Collect remaining text, run regex pattern fields
|
|
350
|
+
*/
|
|
351
|
+
export function resolveListItems(listNode, itemModel) {
|
|
352
|
+
const listItems = listNode.children ?? [];
|
|
353
|
+
return listItems.map(listItem => {
|
|
354
|
+
const result = {};
|
|
355
|
+
// Flatten `inline` wrapper nodes — Markdoc wraps inline content in
|
|
356
|
+
// an `inline` node (item > inline > [strong, text, em, ...]).
|
|
357
|
+
// Block-level children (paragraph, list) remain at the item level.
|
|
358
|
+
const inlineChildren = [];
|
|
359
|
+
for (const child of listItem.children ?? []) {
|
|
360
|
+
if (child.type === 'inline') {
|
|
361
|
+
inlineChildren.push(...(child.children ?? []));
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
inlineChildren.push(child);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const consumed = new Set();
|
|
368
|
+
// Phase 1: Match typed inline nodes
|
|
369
|
+
// Soft-consumed: a child inside a wrapper was matched (e.g., strong
|
|
370
|
+
// inside a link). The wrapper is still available for a direct match.
|
|
371
|
+
const softConsumed = new Set();
|
|
372
|
+
for (const field of itemModel.fields) {
|
|
373
|
+
if (field.match === 'text')
|
|
374
|
+
continue; // handle in phase 2
|
|
375
|
+
// Nested list (cue points, sub-items)
|
|
376
|
+
if (field.match === 'list') {
|
|
377
|
+
const idx = inlineChildren.findIndex((c, i) => !consumed.has(i) && (c.type === 'list'));
|
|
378
|
+
if (idx >= 0) {
|
|
379
|
+
consumed.add(idx);
|
|
380
|
+
result[field.name] = field.itemModel
|
|
381
|
+
? resolveListItems(inlineChildren[idx], field.itemModel)
|
|
382
|
+
: inlineChildren[idx];
|
|
383
|
+
}
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
// Block-level children (paragraphs under list items)
|
|
387
|
+
if (field.match === 'paragraph' && field.greedy) {
|
|
388
|
+
const paragraphs = [];
|
|
389
|
+
inlineChildren.forEach((c, i) => {
|
|
390
|
+
if (!consumed.has(i) && c.type === 'paragraph') {
|
|
391
|
+
consumed.add(i);
|
|
392
|
+
paragraphs.push(c);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
if (paragraphs.length > 0)
|
|
396
|
+
result[field.name] = paragraphs;
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
// Inline node matching (strong, em, link, image, code)
|
|
400
|
+
for (let i = 0; i < inlineChildren.length; i++) {
|
|
401
|
+
// Skip hard-consumed; allow soft-consumed for direct matches
|
|
402
|
+
if (consumed.has(i))
|
|
403
|
+
continue;
|
|
404
|
+
if (softConsumed.has(i) && field.match !== inlineChildren[i].type)
|
|
405
|
+
continue;
|
|
406
|
+
const child = inlineChildren[i];
|
|
407
|
+
const matched = findInlineMatch(child, field.match);
|
|
408
|
+
if (matched) {
|
|
409
|
+
if (matched === child) {
|
|
410
|
+
// Direct match → hard consume
|
|
411
|
+
consumed.add(i);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
// Child-inside-wrapper → soft consume
|
|
415
|
+
softConsumed.add(i);
|
|
416
|
+
}
|
|
417
|
+
if (field.extract) {
|
|
418
|
+
// For extract, get the attribute from the wrapper (e.g., href from link)
|
|
419
|
+
const source = child.attributes?.[field.extract] != null ? child : matched;
|
|
420
|
+
result[field.name] = source.attributes?.[field.extract];
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
result[field.name] = extractNodeText(matched);
|
|
424
|
+
}
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
// Merge soft-consumed into consumed for text collection
|
|
430
|
+
for (const idx of softConsumed)
|
|
431
|
+
consumed.add(idx);
|
|
432
|
+
// Phase 2: Collect remaining text, run pattern fields
|
|
433
|
+
const textFields = itemModel.fields.filter(f => f.match === 'text');
|
|
434
|
+
if (textFields.length > 0) {
|
|
435
|
+
const remainingText = inlineChildren
|
|
436
|
+
.filter((_, i) => !consumed.has(i))
|
|
437
|
+
.filter(c => c.type === 'text' || c.type === 'softbreak')
|
|
438
|
+
.map(c => c.attributes?.content ?? '')
|
|
439
|
+
.join('')
|
|
440
|
+
.trim();
|
|
441
|
+
let textToProcess = remainingText;
|
|
442
|
+
for (const field of textFields) {
|
|
443
|
+
if (field.pattern === 'remainder') {
|
|
444
|
+
const trimmed = textToProcess.trim();
|
|
445
|
+
if (trimmed || !field.optional) {
|
|
446
|
+
result[field.name] = trimmed;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
else if (field.pattern instanceof RegExp) {
|
|
450
|
+
const match = textToProcess.match(field.pattern);
|
|
451
|
+
if (match) {
|
|
452
|
+
result[field.name] = match[1] ?? match[0];
|
|
453
|
+
textToProcess = textToProcess.replace(field.pattern, '');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return result;
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
// ---------------------------------------------------------------------------
|
|
462
|
+
// Top-level resolver
|
|
463
|
+
// ---------------------------------------------------------------------------
|
|
464
|
+
/**
|
|
465
|
+
* Resolve a content model against AST children.
|
|
466
|
+
* Dispatches to the pattern-specific resolver based on `model.type`.
|
|
467
|
+
*/
|
|
468
|
+
export function resolve(children, model, attributes) {
|
|
469
|
+
// Handle conditional models
|
|
470
|
+
if (isConditional(model)) {
|
|
471
|
+
for (const branch of model.when) {
|
|
472
|
+
if (evaluateCondition(branch.condition, children, attributes ?? {})) {
|
|
473
|
+
return resolve(children, branch.model, attributes);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return resolve(children, model.default, attributes);
|
|
477
|
+
}
|
|
478
|
+
switch (model.type) {
|
|
479
|
+
case 'sequence':
|
|
480
|
+
return resolveSequence(children, model.fields);
|
|
481
|
+
case 'sections':
|
|
482
|
+
return resolveSections(children, model);
|
|
483
|
+
case 'delimited':
|
|
484
|
+
return resolveDelimited(children, model);
|
|
485
|
+
case 'custom':
|
|
486
|
+
return { children: model.processChildren(children, attributes ?? {}) };
|
|
487
|
+
default:
|
|
488
|
+
return {};
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Full resolution entry point: extracts special tags (tint, bg), then
|
|
493
|
+
* resolves the content model.
|
|
494
|
+
*/
|
|
495
|
+
export function resolveContentModel(children, model, attributes) {
|
|
496
|
+
const { filtered, tintNode, bgNode } = extractSpecialTags(children);
|
|
497
|
+
const content = resolve(filtered, model, attributes);
|
|
498
|
+
return { content, tintNode, bgNode };
|
|
499
|
+
}
|
|
500
|
+
//# sourceMappingURL=resolver.js.map
|