@contentrain/astro-kit 0.11.0 → 0.13.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/catalog.json +14 -0
- package/components/stats/Stats.astro +28 -12
- package/components/stats/fixtures.json +23 -0
- package/components/stats/meta.json +8 -0
- package/components/steps/Steps.astro +12 -4
- package/components/steps/fixtures.json +3 -1
- package/components/steps/meta.json +5 -0
- package/components/testimonial/Testimonial.astro +4 -1
- package/components/testimonial/fixtures.json +4 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +9 -0
- package/dist/index.mjs.map +1 -1
- package/mapping/divi.json +4 -1
- package/mapping/elementor.json +1 -0
- package/mapping/gutenberg.json +63 -1
- package/package.json +2 -2
package/catalog.json
CHANGED
|
@@ -2902,6 +2902,14 @@
|
|
|
2902
2902
|
],
|
|
2903
2903
|
"default": "sm",
|
|
2904
2904
|
"description": "The label under each figure: sm (small), base (body size) or lg (a counter title set like a subheading)."
|
|
2905
|
+
},
|
|
2906
|
+
"order": {
|
|
2907
|
+
"options": [
|
|
2908
|
+
"label-first",
|
|
2909
|
+
"value-first"
|
|
2910
|
+
],
|
|
2911
|
+
"default": "label-first",
|
|
2912
|
+
"description": "Which the page's text reads first, as the source does: label-first (an Elementor counter) or value-first (a Gutenberg figure heading over its label). The figure is drawn on top either way."
|
|
2905
2913
|
}
|
|
2906
2914
|
},
|
|
2907
2915
|
"props": {
|
|
@@ -3039,6 +3047,11 @@
|
|
|
3039
3047
|
"items": {
|
|
3040
3048
|
"type": "object",
|
|
3041
3049
|
"fields": {
|
|
3050
|
+
"number": {
|
|
3051
|
+
"type": "string",
|
|
3052
|
+
"label": "Number",
|
|
3053
|
+
"description": "The step's number as the source writes it (01, Step 2); empty: the list counts 1, 2, 3."
|
|
3054
|
+
},
|
|
3042
3055
|
"title": {
|
|
3043
3056
|
"type": "string",
|
|
3044
3057
|
"label": "Title",
|
|
@@ -3102,6 +3115,7 @@
|
|
|
3102
3115
|
"heading": "heading",
|
|
3103
3116
|
"intro": "intro",
|
|
3104
3117
|
"items": "items",
|
|
3118
|
+
"items[].number": "items[].number",
|
|
3105
3119
|
"items[].title": "items[].title",
|
|
3106
3120
|
"items[].text": "items[].text",
|
|
3107
3121
|
"items[].image": "items[].image",
|
|
@@ -7,7 +7,7 @@ import Section, { type Tone } from '../_shared/Section.astro'
|
|
|
7
7
|
const stats = tv({
|
|
8
8
|
slots: {
|
|
9
9
|
list: 'grid grid-cols-2 gap-6 md:gap-8',
|
|
10
|
-
item: 'flex
|
|
10
|
+
item: 'flex gap-1',
|
|
11
11
|
value: 'text-4xl [font-weight:var(--font-weight-heading,700)] tracking-tight tabular-nums md:text-5xl',
|
|
12
12
|
label: 'text-sm opacity-80',
|
|
13
13
|
},
|
|
@@ -25,8 +25,11 @@ const stats = tv({
|
|
|
25
25
|
tone: { default: {}, muted: {}, inverse: {}, accent: { label: 'opacity-100' } },
|
|
26
26
|
// The label under each figure: small, body size, or large (a counter title set like a subheading).
|
|
27
27
|
labelSize: { sm: {}, base: { label: 'text-base' }, lg: { label: 'text-lg' } },
|
|
28
|
+
// Which comes first in the page's text: the source's own order (a Gutenberg figure is a heading over its label, an
|
|
29
|
+
// Elementor counter names itself first). The figure is drawn on top either way.
|
|
30
|
+
order: { 'label-first': { item: 'flex-col-reverse' }, 'value-first': { item: 'flex-col' } },
|
|
28
31
|
},
|
|
29
|
-
defaultVariants: { columns: '3', style: 'plain', tone: 'default', labelSize: 'sm' },
|
|
32
|
+
defaultVariants: { columns: '3', style: 'plain', tone: 'default', labelSize: 'sm', order: 'label-first' },
|
|
30
33
|
})
|
|
31
34
|
|
|
32
35
|
interface Item {
|
|
@@ -43,13 +46,15 @@ interface Props {
|
|
|
43
46
|
columns?: '2' | '3' | '4' | undefined
|
|
44
47
|
style?: 'plain' | 'card' | undefined
|
|
45
48
|
labelSize?: 'sm' | 'base' | 'lg' | undefined
|
|
49
|
+
order?: 'label-first' | 'value-first' | undefined
|
|
46
50
|
tone?: Tone | undefined
|
|
47
51
|
id?: string | undefined
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
const { heading, intro, items, columns, style, labelSize, tone, id } = Astro.props
|
|
51
|
-
const s = stats({ columns, style, labelSize, tone })
|
|
54
|
+
const { heading, intro, items, columns, style, labelSize, order, tone, id } = Astro.props
|
|
55
|
+
const s = stats({ columns, style, labelSize, order, tone })
|
|
52
56
|
const headingId = heading && id ? `${id}-title` : undefined
|
|
57
|
+
// A <dl> names its term first, so figure-first is a plain list, read in the order it is drawn (WCAG 1.3.2).
|
|
53
58
|
---
|
|
54
59
|
<Section tone={tone} id={id} aria-labelledby={headingId}>
|
|
55
60
|
{(heading || intro) && (
|
|
@@ -58,12 +63,23 @@ const headingId = heading && id ? `${id}-title` : undefined
|
|
|
58
63
|
{intro && <p class:list={['text-lg', tone === 'accent' ? undefined : 'opacity-80']} data-kit-text>{intro}</p>}
|
|
59
64
|
</header>
|
|
60
65
|
)}
|
|
61
|
-
|
|
62
|
-
{
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
{order === 'value-first' ? (
|
|
67
|
+
<ul class={s.list()} role="list">
|
|
68
|
+
{items.map(item => (
|
|
69
|
+
<li class={s.item()}>
|
|
70
|
+
<p class={s.value()}>{item.prefix}{item.value}{item.suffix}</p>
|
|
71
|
+
<p class={s.label()}>{item.label}</p>
|
|
72
|
+
</li>
|
|
73
|
+
))}
|
|
74
|
+
</ul>
|
|
75
|
+
) : (
|
|
76
|
+
<dl class={s.list()}>
|
|
77
|
+
{items.map(item => (
|
|
78
|
+
<div class={s.item()}>
|
|
79
|
+
<dt class={s.label()}>{item.label}</dt>
|
|
80
|
+
<dd class={s.value()}>{item.prefix}{item.value}{item.suffix}</dd>
|
|
81
|
+
</div>
|
|
82
|
+
))}
|
|
83
|
+
</dl>
|
|
84
|
+
)}
|
|
69
85
|
</Section>
|
|
@@ -133,5 +133,28 @@
|
|
|
133
133
|
}
|
|
134
134
|
]
|
|
135
135
|
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "value-first",
|
|
139
|
+
"props": {
|
|
140
|
+
"heading": "Launch in numbers",
|
|
141
|
+
"order": "value-first",
|
|
142
|
+
"items": [
|
|
143
|
+
{
|
|
144
|
+
"value": "1,200",
|
|
145
|
+
"label": "Teams using Calm Status"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"value": "99.99",
|
|
149
|
+
"suffix": "%",
|
|
150
|
+
"label": "Uptime last year"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"value": "4",
|
|
154
|
+
"suffix": " min",
|
|
155
|
+
"label": "Median time to first update"
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
136
159
|
}
|
|
137
160
|
]
|
|
@@ -43,6 +43,14 @@
|
|
|
43
43
|
],
|
|
44
44
|
"default": "sm",
|
|
45
45
|
"description": "The label under each figure: sm (small), base (body size) or lg (a counter title set like a subheading)."
|
|
46
|
+
},
|
|
47
|
+
"order": {
|
|
48
|
+
"options": [
|
|
49
|
+
"label-first",
|
|
50
|
+
"value-first"
|
|
51
|
+
],
|
|
52
|
+
"default": "label-first",
|
|
53
|
+
"description": "Which the page's text reads first, as the source does: label-first (an Elementor counter) or value-first (a Gutenberg figure heading over its label). The figure is drawn on top either way."
|
|
46
54
|
}
|
|
47
55
|
},
|
|
48
56
|
"props": {
|
|
@@ -15,6 +15,7 @@ const steps = tv({
|
|
|
15
15
|
list: 'grid gap-8 [counter-reset:kit-step]',
|
|
16
16
|
step: 'flex gap-4 [counter-increment:kit-step]',
|
|
17
17
|
body: 'flex flex-col gap-2',
|
|
18
|
+
badge: 'shrink-0',
|
|
18
19
|
media: 'mb-2 overflow-hidden rounded-[var(--radius-image,var(--radius-card))]',
|
|
19
20
|
title: 'text-lg leading-snug [font-weight:var(--font-weight-heading,600)] text-balance',
|
|
20
21
|
text: 'text-pretty opacity-80',
|
|
@@ -24,16 +25,22 @@ const steps = tv({
|
|
|
24
25
|
list: { list: 'max-w-3xl' },
|
|
25
26
|
row: { list: 'sm:grid-cols-2 lg:auto-cols-fr lg:grid-flow-col lg:grid-cols-none', step: 'flex-col' },
|
|
26
27
|
},
|
|
27
|
-
// The number is drawn from a CSS counter, so the list stays one <ol> a screen reader counts itself.
|
|
28
|
+
// The number is drawn from a CSS counter, so the list stays one <ol> a screen reader counts itself. A number the
|
|
29
|
+
// source wrote (`01`) is the page's text and is shown as written, hidden from the screen reader that already counts.
|
|
28
30
|
style: {
|
|
29
|
-
numbered: {
|
|
30
|
-
|
|
31
|
+
numbered: {
|
|
32
|
+
step: "before:flex before:size-10 before:shrink-0 before:items-center before:justify-center before:rounded-full before:bg-accent before:font-semibold before:text-accent-ink before:content-[counter(kit-step)]",
|
|
33
|
+
badge: 'flex h-10 min-w-10 items-center justify-center self-start rounded-full bg-accent px-2 font-semibold text-accent-ink',
|
|
34
|
+
},
|
|
35
|
+
plain: { step: 'border-l-2 border-accent pl-4', badge: 'font-semibold tabular-nums' },
|
|
31
36
|
},
|
|
32
37
|
},
|
|
33
38
|
defaultVariants: { layout: 'list', style: 'numbered' },
|
|
34
39
|
})
|
|
35
40
|
|
|
36
41
|
interface Step {
|
|
42
|
+
/** The number as the source writes it (`01`, `Step 2`); without it the list counts itself. */
|
|
43
|
+
number?: string | undefined
|
|
37
44
|
title: string
|
|
38
45
|
text: string
|
|
39
46
|
/** The image's address. */
|
|
@@ -64,7 +71,8 @@ const headingId = heading && id ? `${id}-title` : undefined
|
|
|
64
71
|
)}
|
|
65
72
|
<ol class={s.list()}>
|
|
66
73
|
{items.map(step => (
|
|
67
|
-
<li class={s.step()}>
|
|
74
|
+
<li class={s.step({ class: step.number ? 'before:hidden' : undefined })}>
|
|
75
|
+
{step.number && <span class={s.badge()} aria-hidden="true">{step.number}</span>}
|
|
68
76
|
<div class={s.body()}>
|
|
69
77
|
{imageOf(step.image, step.imageAlt) && <div class={s.media()}><KitImage image={imageOf(step.image, step.imageAlt)!} sizes="(min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw" class="aspect-[3/2] w-full object-cover" /></div>}
|
|
70
78
|
<h3 class={s.title()}>{step.title}</h3>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
[
|
|
2
2
|
{"name": "list-numbered", "props": {"id": "how", "heading": "How it works", "intro": "Three steps from WordPress to a static site.", "items": [{"title": "Connect", "text": "Point us at your site; we read everything it publishes."}, {"title": "Review", "text": "Check the plan: every page, model and redirect."}, {"title": "Launch", "text": "Deploy the new site; every old address still works."}]}},
|
|
3
3
|
{"name": "row-plain-images", "props": {"layout": "row", "style": "plain", "heading": "Our process", "items": [{"title": "Discover", "text": "We learn the site and its readers.", "image": "/kit-fixtures/photo-1.svg"}, {"title": "Design", "text": "We draw the pages and the system.", "image": "/kit-fixtures/photo-2.svg"}, {"title": "Build", "text": "We ship it, fast and accessible.", "image": "/kit-fixtures/photo-3.svg", "imageAlt": "A laptop showing the finished site"}]}},
|
|
4
|
-
{"name": "row-numbered", "props": {"layout": "row", "items": [{"title": "Sign up", "text": "One minute, no card."}, {"title": "Import", "text": "Bring your content."}, {"title": "Edit", "text": "Change it in Studio."}, {"title": "Publish", "text": "Push and it is live."}]}}
|
|
4
|
+
{"name": "row-numbered", "props": {"layout": "row", "items": [{"title": "Sign up", "text": "One minute, no card."}, {"title": "Import", "text": "Bring your content."}, {"title": "Edit", "text": "Change it in Studio."}, {"title": "Publish", "text": "Push and it is live."}]}},
|
|
5
|
+
{"name": "source-numbers", "props": {"heading": "Getting started", "items": [{"number": "01", "title": "Connect", "text": "Point Calm Status at the services you already monitor."}, {"number": "02", "title": "Write", "text": "Pick the words customers see for each kind of problem."}, {"number": "03", "title": "Publish", "text": "Put the page live on your own domain."}]}},
|
|
6
|
+
{"name": "row-plain-source-numbers", "props": {"layout": "row", "style": "plain", "items": [{"number": "Step 1", "title": "Call", "text": "We learn what you make and who buys it."}, {"number": "Step 2", "title": "Design and build", "text": "Four weeks of weekly previews."}, {"number": "Step 3", "title": "Launch", "text": "We switch it on together."}]}}
|
|
5
7
|
]
|
|
@@ -46,6 +46,11 @@
|
|
|
46
46
|
"items": {
|
|
47
47
|
"type": "object",
|
|
48
48
|
"fields": {
|
|
49
|
+
"number": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"label": "Number",
|
|
52
|
+
"description": "The step's number as the source writes it (01, Step 2); empty: the list counts 1, 2, 3."
|
|
53
|
+
},
|
|
49
54
|
"title": {
|
|
50
55
|
"type": "string",
|
|
51
56
|
"label": "Title",
|
|
@@ -58,6 +58,9 @@ interface Props {
|
|
|
58
58
|
const { items, heading, layout, quoteSize, tone, id } = Astro.props
|
|
59
59
|
const s = testimonial({ layout, quoteSize, tone })
|
|
60
60
|
const headingId = heading && id ? `${id}-title` : undefined
|
|
61
|
+
// The quotation marks are drawn, not written: the quote's text is the source's words, read once. A quote the source
|
|
62
|
+
// already wrote inside marks keeps its own.
|
|
63
|
+
const quoted = (text: string) => /^\s*["'“‘„«‹「『]/.test(text)
|
|
61
64
|
---
|
|
62
65
|
{items.length > 0 && (
|
|
63
66
|
<Section tone={tone} spacing="md" id={id} aria-labelledby={headingId}>
|
|
@@ -65,7 +68,7 @@ const headingId = heading && id ? `${id}-title` : undefined
|
|
|
65
68
|
<div class={s.list()}>
|
|
66
69
|
{items.map(item => (
|
|
67
70
|
<figure class={s.card()}>
|
|
68
|
-
<blockquote class={s.quote()}><p
|
|
71
|
+
<blockquote class={s.quote()}><p class:list={[!quoted(item.quote) && "before:content-[open-quote] after:content-[close-quote]"]}>{item.quote}</p></blockquote>
|
|
69
72
|
<figcaption class={s.person()}>
|
|
70
73
|
{imageOf(item.avatar, item.avatarAlt) && <KitImage image={imageOf(item.avatar, item.avatarAlt)!} sizes="48px" class="size-12 shrink-0 rounded-full object-cover" />}
|
|
71
74
|
<span class="flex flex-col text-left">
|
|
@@ -34,5 +34,9 @@
|
|
|
34
34
|
{
|
|
35
35
|
"name": "single-quote-lg",
|
|
36
36
|
"props": { "layout": "single", "quoteSize": "lg", "items": [{ "quote": "We planned less and saw more.", "name": "Jonas Weber", "role": "Reader" }] }
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "grid-source-quoted",
|
|
40
|
+
"props": { "items": [{ "quote": "“We set it up before lunch.”", "name": "Grace Lin", "role": "Head of Support, Fernhill" }, { "quote": "People just read the page.", "name": "Omar Haddad", "role": "Support lead" }] }
|
|
37
41
|
}
|
|
38
42
|
]
|
package/dist/index.d.mts
CHANGED
|
@@ -190,6 +190,13 @@ interface SectionRule {
|
|
|
190
190
|
*/
|
|
191
191
|
repeat?: 'columns'; /** The section's root element(s): `core/cover`, `core/media-text` (a loose run of blocks is `run`). */
|
|
192
192
|
root?: string | string[];
|
|
193
|
+
/**
|
|
194
|
+
* Two slots in the order the source writes them: where both hold a leaf (in each column, with `repeat`), the first
|
|
195
|
+
* leaf of the one must come before the first of the other. `['figure', 'label']` is a figure written above its
|
|
196
|
+
* label, so a rule can pick the variant the source's reading order needs (G-text) and leave the other order to the
|
|
197
|
+
* next rule.
|
|
198
|
+
*/
|
|
199
|
+
order?: [string, string];
|
|
193
200
|
};
|
|
194
201
|
/**
|
|
195
202
|
* Named leaf groups. Each leaf, in document order, goes to the first declared slot that matches it and
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/catalog.ts","../src/mapping.ts","../src/copy.ts","../src/index.ts"],"mappings":";;;cAYa,cAAA;;KAGD,UAAA;AAAA,cACC,YAAA,WAAuB,UAAA;;cAGvB,cAAA,EAAgB,MAAA,CAAO,UAAA;;AAJpC;;;;iBAgBgB,gBAAA,CAAiB,OAAA,EAAS,UAAA,EAAY,IAAA;AAAA,KAK1C,WAAA;;KAGA,KAAA;AAAA,KAEA,OAAA,GAAU,QAAA;EACpB,WAAA;EAvBW;;;;EA4BX,OAAA;AAAA;;;;;cAOW,iBAAA,EAAiB,MAAA;;;;AAlB9B;cAwBa,gBAAA,GAAmB,IAAA;;iBAGhB,YAAA,CAAa,SAAA,EAAW,gBAAA,GAAmB,MAAA,SAAe,OAAA;;iBAe1D,gBAAA,CAAiB,IAAA;AAAA,UAIhB,UAAA;EACf,OAAA;EACA,OAAA;EACA,WAAA;AAAA;;UAIe,gBAAA;EACf,EAAA;EACA,IAAA;EACA,WAAA;EACA,QAAA,EAAU,WAAA;EA9CH;EAgDP,IAAA;EAzCW;EA2CX,MAAA;EACA,QAAA,EAAU,MAAA,SAAe,UAAA;EACzB,KAAA,EAAO,MAAA,SAAe,OAAA;EA7C8C;EA+CpE,KAAA,EAAO,MAAA;EACP,EAAA,EAAI,KAAA;;EAEJ,YAAA,EAAc,MAAA;EA5C4B;EA8C1C,OAAA,EAAS,OAAA,CAAQ,MAAA,CAAO,UAAA;EA3CE;EA6C1B,IAAA;EA7CsC;;;;EAkDtC,OAAA;IAAY,OAAA;IAAiB,OAAA;EAAA;EAlD2C;;;AAe1E;EAwCE,aAAA,GAAgB,MAAA;AAAA;;UAID,YAAA,SAAqB,gBAAA;EAxCrB;EA0Cf,KAAA;AAAA;AAAA,UAGe,UAAA;EACf,MAAA,SAAe,cAAA;EA5Cf;EA8CA,MAAA;EA7CW;EA+CX,YAAA,EAAc,MAAA;EACd,UAAA,EAAY,YAAA;AAAA;;iBAIE,eAAA,CAAgB,OAAA,EAAS,UAAA;;iBAgDzB,mBAAA,CAAoB,OAAA,EAAS,UAAA,EAAY,OAAA,WAAkB,YAAA;;;cCzJ9D,cAAA;AAAA,cAEA,qBAAA,EAAqB,MAAA;AAAA,UAEjB,WAAA;EDxBU;EC0BzB,KAAA;ED1ByB;EC4BzB,IAAA;IAAS,IAAA,GAAO,MAAA;IAA2C,KAAA;EAAA;EDzBvC;EC2BpB,SAAA;EACA,OAAA,GAAU,MAAA;ED3BoF;EC6B9F,IAAA;ED7BkC;EC+BlC,KAAA;EACA,KAAA,GAAQ,MAAA;EDxBT;EC0BC,IAAA;ED/B2B;ECiC3B,IAAA;EDrBc;ECuBd,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,YAAA;EACf,MAAA,SAAe,cAAA;EACf,OAAA,EAAS,UAAA;ED5B2C;EC8BpD,OAAA;ED9BgE;ECgChE,QAAA;ED3BqB;;;;ECgCrB,QAAA,GAAW,MAAA,SAAe,MAAA;EAC1B,KAAA,EAAO,WAAA;;;;AD5BT;;ECkCE,QAAA,GAAW,WAAA;AAAA;;;;;UAOI,WAAA;EACf,KAAA;EACA,IAAA,GAAO,MAAA;;EAEP,GAAA;EDhCoE;ECkCpE,GAAA;ED5BwE;EC8BxE,OAAA;ED9B8B;ECgC9B,OAAA;ED7Bc;EC+Bd,KAAA;;EAEA,QAAA;EDjCwE;ECmCxE,KAAA;EDnC+D;;;;ECwC/D,KAAA;AAAA;;;ADzBF;;;;UCkCiB,WAAA;ED9BA;ECgCf,EAAA;EACA,SAAA;EACA,OAAA,GAAU,MAAA;EACV,IAAA;IDjCA,+ECmCE,QAAA,6BDlCS;ICoCT,OAAA,sBDhCa;ICkCb,IAAA;IDlC6B;;;;ICuC7B,MAAA,cD7BK;IC+BL,IAAA;EAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/catalog.ts","../src/mapping.ts","../src/copy.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -174,6 +174,13 @@ function claimLeaves(rule, leaves, defaults, scope = "all") {
|
|
|
174
174
|
else if (rule.when?.only !== false) return null;
|
|
175
175
|
}
|
|
176
176
|
for (const [name, def] of slots) if (claimed[name].length < (def.min ?? 0)) return null;
|
|
177
|
+
const [first, then] = rule.when?.order ?? [];
|
|
178
|
+
const a = first ? claimed[first]?.[0] : void 0;
|
|
179
|
+
const b = then ? claimed[then]?.[0] : void 0;
|
|
180
|
+
if (a && b) {
|
|
181
|
+
const at = (path) => leaves.findIndex((l) => l.path === path);
|
|
182
|
+
if (at(a) > at(b)) return null;
|
|
183
|
+
}
|
|
177
184
|
return claimed;
|
|
178
185
|
}
|
|
179
186
|
/**
|
|
@@ -298,6 +305,8 @@ function validateSections(table, components) {
|
|
|
298
305
|
if (rule.when?.repeat === "columns" && rule.each !== "column") problems.push(`${at}: repeat columns needs each: column`);
|
|
299
306
|
if (rule.each === "column" && rule.when?.repeat !== "columns") problems.push(`${at}: each column needs when.repeat columns`);
|
|
300
307
|
for (const [name, slot] of Object.entries(rule.slots)) if (slot.scope === "intro" && rule.when?.repeat !== "columns") problems.push(`${at}: slot ${name} is scope intro, which needs when.repeat columns`);
|
|
308
|
+
for (const name of rule.when?.order ?? []) if (!rule.slots[name]) problems.push(`${at}: when.order names ${name}, which is not a slot`);
|
|
309
|
+
if (rule.when?.order && rule.slots[rule.when.order[0]]?.scope === "intro" !== (rule.slots[rule.when.order[1]]?.scope === "intro")) problems.push(`${at}: when.order compares an intro slot with a column slot`);
|
|
301
310
|
const readsSlots = (value, where, type, slotted, item = false) => {
|
|
302
311
|
const slots = sectionValueSlots(value);
|
|
303
312
|
if (!slots) {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/catalog.ts","../src/copy.ts","../src/mapping.ts","../src/index.ts"],"sourcesContent":["// The kit catalog: what each component is, what it takes, how it varies and\n// which WordPress builder elements it stands in for. Machine-readable, so the\n// migration writer chooses components by querying it instead of reading\n// source, and the builder mapping tables (mapping/*.json) are checked against\n// it.\n//\n// Props are described with Contentrain's own `FieldDef`, so a model field and\n// the prop it feeds are compared type to type.\n\nimport type { FieldDef } from '@contentrain/types'\nimport { fieldDepth, sectionFieldName } from '@contentrain/types'\n\nexport const CATALOG_FORMAT = 'astro-kit-catalog@1'\n\n/** The WordPress builders whose elements a component is fed from. */\nexport type KitBuilder = 'gutenberg' | 'elementor' | 'divi' | 'classic'\nexport const KIT_BUILDERS: readonly KitBuilder[] = ['gutenberg', 'elementor', 'divi', 'classic']\n\n/** Element-name prefix per builder, as `facts.json` names elements (`core/cover`, `elementor/heading`, `divi/et_pb_blurb`). */\nexport const BUILDER_PREFIX: Record<KitBuilder, string> = {\n gutenberg: 'core/',\n elementor: 'elementor/',\n divi: 'divi/',\n classic: 'classic/',\n}\n\n/**\n * Whether an element name belongs to a builder. Gutenberg blocks are namespaced by their plugin\n * (`core/cover`, `yoast-seo/breadcrumbs`, `uagb/container`), so any `<ns>/<name>` that is not another\n * builder's is a Gutenberg block.\n */\nexport function isBuilderElement(builder: KitBuilder, name: string): boolean {\n if (builder !== 'gutenberg') return name.startsWith(BUILDER_PREFIX[builder])\n return /^[a-z0-9-]+\\/[a-z0-9-]+(:[\\w-]+)?$/.test(name) && !KIT_BUILDERS.some(b => b !== 'gutenberg' && name.startsWith(BUILDER_PREFIX[b]))\n}\n\nexport type KitCategory = 'chrome' | 'section' | 'content' | 'primitive'\n\n/** Client JavaScript a component ships: none, a few lines of dependency-free script (`vanilla`), Embla (carousel), Zag.js (accessible widget) or the Studio runtime. */\nexport type KitJs = 'none' | 'vanilla' | 'embla' | 'zag' | 'studio'\n\nexport type KitProp = FieldDef & {\n description: string\n /**\n * `false`: a setting the plan or writer passes (heading level, a label from `ui:`, an anchor id), not page\n * content. A section's page-singleton field holds only the other props, its content props.\n */\n content?: false\n}\n\n/**\n * A content prop's name: camelCase, a capital only to start a word (`imageAlt`, not `imageURL`), so it\n * turns into exactly one Contentrain field name.\n */\nexport const CONTENT_PROP_NAME = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*$/\n\n/**\n * The page-singleton field a content prop is stored in (DECISIONS §7b): the prop name in snake_case, as\n * Contentrain field names are (`ctaLabel` → `cta_label`). The view passes each prop from its field.\n */\nexport const contentFieldName: (prop: string) => string = sectionFieldName\n\n/** The props a section's page-singleton field holds: all but the settings. */\nexport function contentProps(component: KitComponentMeta): Record<string, KitProp> {\n return Object.fromEntries(Object.entries(component.props).filter(([, prop]) => prop.content !== false))\n}\n\n/** Fields under a field, by dotted path (`items[].imageAlt`). */\nfunction fieldsByPath(fields: Record<string, FieldDef>, prefix = ''): Array<[string, FieldDef]> {\n const out: Array<[string, FieldDef]> = []\n for (const [name, field] of Object.entries(fields)) {\n out.push([prefix + name, field], ...fieldsByPath(field.fields ?? {}, `${prefix}${name}.`))\n if (typeof field.items === 'object') out.push(...fieldsByPath(field.items.fields ?? {}, `${prefix}${name}[].`))\n }\n return out\n}\n\n/** A content prop path as its page-singleton field path: every name in it through `contentFieldName`. */\nexport function contentFieldPath(path: string): string {\n return path.replace(/[A-Za-z0-9]+/g, contentFieldName)\n}\n\nexport interface KitVariant {\n options: string[]\n default: string\n description: string\n}\n\n/** One component as written in `components/<id>/meta.json`. */\nexport interface KitComponentMeta {\n id: string\n name: string\n description: string\n category: KitCategory\n /** Kit components this one renders. */\n uses: string[]\n /** Files it imports from `components/_shared/`. */\n shared: string[]\n variants: Record<string, KitVariant>\n props: Record<string, KitProp>\n /** Named slots → what goes in them. `default` is the unnamed slot. */\n slots: Record<string, string>\n js: KitJs\n /** npm packages the site needs for this component, name → range. */\n dependencies: Record<string, string>\n /** Builder elements this component replaces, by builder — what the mapping tables map from. */\n sources: Partial<Record<KitBuilder, string[]>>\n /** How it meets its accessibility pattern. */\n a11y: string\n /**\n * Sections only: the section's shape in a few words and the signals that show it in a source page, a\n * closed-set label for the classifier and the migration architect (`image beside heading + text`).\n */\n pattern?: { summary: string, signals: string[] }\n /**\n * Sections only, written by the catalog build: each content prop path (`slides[].ctaLabel`) → the\n * page-singleton field path that holds it (`slides[].cta_label`).\n */\n contentFields?: Record<string, string>\n}\n\n/** A catalog entry: the meta plus the files that make the component. */\nexport interface KitComponent extends KitComponentMeta {\n /** Paths relative to `components/<id>/`. */\n files: string[]\n}\n\nexport interface KitCatalog {\n format: typeof CATALOG_FORMAT\n /** Design tokens (Tailwind @theme names) the components read; the site must define them. */\n tokens: string[]\n /** npm packages every kit component needs. */\n dependencies: Record<string, string>\n components: KitComponent[]\n}\n\n/** Problems with a catalog, one line each; empty when it is sound. */\nexport function validateCatalog(catalog: KitCatalog): string[] {\n const problems: string[] = []\n const ids = new Set(catalog.components.map(c => c.id))\n for (const c of catalog.components) {\n const at = `component ${c.id}`\n if (!/^[a-z][a-z0-9-]*$/.test(c.id)) problems.push(`${at}: id must be kebab-case`)\n if (!c.files.length) problems.push(`${at}: no files`)\n for (const used of c.uses) if (!ids.has(used)) problems.push(`${at}: uses unknown component \"${used}\"`)\n for (const [axis, variant] of Object.entries(c.variants)) {\n if (!variant.options.includes(variant.default)) problems.push(`${at}: variant ${axis} default \"${variant.default}\" is not an option`)\n }\n for (const [name, prop] of Object.entries(c.props)) {\n if (!prop.description) problems.push(`${at}: prop ${name} has no description`)\n if (prop.type === 'select' && !prop.options?.length) problems.push(`${at}: select prop ${name} has no options`)\n }\n if (c.category === 'section') {\n // A section is stored as one object field of its page singleton: each content prop needs one field\n // name there, and that field must stay within two object levels.\n const content = contentProps(c)\n const paths = fieldsByPath(content)\n for (const [path, field] of paths) {\n if (!CONTENT_PROP_NAME.test(path.split(/\\.|\\[\\]\\./).at(-1)!)) problems.push(`${at}: content prop ${path} must be camelCase with one capital per word (or content: false)`)\n // Studio shows both to editors, and the plan reads them as the field's label and help text.\n if (!field.label) problems.push(`${at}: content prop ${path} has no label`)\n if (!field.description) problems.push(`${at}: content prop ${path} has no description`)\n }\n if (c.contentFields) {\n const expected = Object.fromEntries(paths.map(([path]) => [path, contentFieldPath(path)]))\n if (JSON.stringify(c.contentFields) !== JSON.stringify(expected)) problems.push(`${at}: contentFields is stale — rebuild the catalog`)\n }\n for (const [name, prop] of Object.entries(content)) {\n if (1 + fieldDepth(prop) > 2) problems.push(`${at}: content prop ${name} nests objects deeper than a page singleton allows`)\n }\n }\n for (const [builder, names] of Object.entries(c.sources) as Array<[KitBuilder, string[]]>) {\n const prefix = BUILDER_PREFIX[builder]\n for (const name of names) if (!isBuilderElement(builder, name)) problems.push(`${at}: source \"${name}\" is not a ${builder} element (${prefix}…)`)\n }\n }\n const seen = new Set<string>()\n for (const c of catalog.components) {\n if (seen.has(c.id)) problems.push(`component ${c.id}: listed twice`)\n seen.add(c.id)\n }\n return problems\n}\n\n/** Components that replace a builder element, e.g. `core/cover` → hero. */\nexport function componentsForSource(catalog: KitCatalog, element: string): KitComponent[] {\n return catalog.components.filter(c => Object.values(c.sources).some(names => names?.includes(element)))\n}\n","// Copying components into a site — the shadcn model: the site owns the\n// source, there is no runtime dependency on this package. A component is\n// copied with every kit component it renders and every shared file it\n// imports, under `src/components/kit/`, keeping the relative layout its\n// imports expect.\n\nimport { copyFile, mkdir } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport type { KitCatalog } from './catalog.js'\n\n/** Where kit files land in a site, relative to the site root. */\nexport const KIT_DIR = 'src/components/kit'\n\nexport interface CopyPlan {\n /** Components copied, the requested ones and everything they render, sorted. */\n components: string[]\n /** Site-relative destination → path relative to the kit's `components/` directory. */\n files: Record<string, string>\n /** npm packages the site needs, name → range. */\n dependencies: Record<string, string>\n}\n\nexport function planCopy(catalog: KitCatalog, ids: readonly string[]): CopyPlan {\n const byId = new Map(catalog.components.map(c => [c.id, c]))\n const wanted = new Set<string>()\n const visit = (id: string) => {\n if (wanted.has(id)) return\n const component = byId.get(id)\n if (!component) throw new Error(`astro-kit has no component \"${id}\". Known: ${[...byId.keys()].join(', ')}.`)\n wanted.add(id)\n for (const used of component.uses) visit(used)\n }\n for (const id of ids) visit(id)\n\n const files: Record<string, string> = {}\n const dependencies: Record<string, string> = { ...catalog.dependencies }\n for (const id of [...wanted].toSorted()) {\n const component = byId.get(id)!\n for (const file of component.files) files[`${KIT_DIR}/${id}/${file}`] = `${id}/${file}`\n for (const file of component.shared) files[`${KIT_DIR}/_shared/${file}`] = `_shared/${file}`\n Object.assign(dependencies, component.dependencies)\n }\n return { components: [...wanted].toSorted(), files, dependencies }\n}\n\n/** Carry out a plan: `kitRoot` is the kit's `components/` directory, `siteRoot` the site. */\nexport async function copyComponents(plan: CopyPlan, kitRoot: string, siteRoot: string): Promise<void> {\n await Promise.all(Object.entries(plan.files).map(async ([dest, source]) => {\n const target = join(siteRoot, dest)\n await mkdir(dirname(target), { recursive: true })\n await copyFile(join(kitRoot, source), target)\n }))\n}\n","// Builder mapping tables: which kit component a WordPress builder element\n// becomes, and where each of its props comes from. One versioned table per\n// builder (`mapping/<builder>.json`), written once and applied\n// deterministically to every site — the migration model is asked only about\n// elements no rule covers (Migrate's `unmapped_element` decision).\n//\n// A prop's source is one expression from a small closed set. The first six are\n// the project plan's values (`@contentrain/types` `PlanValue`) and bind\n// content; the rest read the builder element itself or the page it is on:\n//\n// field:<name> · media:<field> · ref:<field>.<field> · href:self|<field> · term:<field> · ui:<key> · const:<value>\n// site:<field> a field of the `site` singleton (`site:title`, `site:logo`)\n// menu:primary|footer the menu the starter shows in that area\n// page:<value> what the route knows: `page:base`, `page:current`, `page:total`, `page:breadcrumb`\n// attr:<name> a builder attribute (block attribute, Elementor setting, Divi shortcode attribute)\n// dom:<selector> text of the first match inside the element (empty selector: the element)\n// dom:<selector>@<attr> an attribute of it (`dom:a@href`)\n// img:<selector> an image as the kit's `ImageInput` (src, alt, width, height)\n// img:<selector>@src|@alt one part of that image, for a list item's flat `image` + `imageAlt` fields\n// link:<selector> a link as `{ label, href }`\n// html:<selector> inner markup, kept as Markdown (rich text)\n// class:<cls>=<a>|<b> <a> when the element, or an ancestor inside the matched element, has class\n// <cls> (`*` matches any run of characters); <b> otherwise. An empty branch\n// reads nothing and the prop keeps its default. `class:is-style-outline=ghost|primary`\n// is WordPress's outline button as the kit's ghost action.\n//\n// Section rules (`sections`) classify a whole page section by the leaves it holds and fill the component's\n// props from them: the same expressions, read from a named slot's leaf (`@title attr:title`).\n\nimport type { KitBuilder, KitCatalog, KitComponent } from './catalog.js'\nimport { isBuilderElement, KIT_BUILDERS } from './catalog.js'\n\nexport const MAPPING_FORMAT = 'astro-kit-mapping@1'\n\nexport const MAPPING_VALUE_PATTERN = /^(?:field:[\\w-]+|media:[\\w-]+|ref:[\\w-]+\\.[\\w-]+|href:(?:self|[\\w-]+)|term:[\\w-]+|ui:[\\w.-]+|const:(?:true|false|-?\\d+(?:\\.\\d+)?|[a-z][a-z0-9_-]{0,31})|site:[\\w-]+|menu:(?:primary|footer)|page:(?:base|current|total|breadcrumb)|attr:[\\w.-]+|class:[\\w*-]+=(?:[a-z][\\w-]*)?\\|(?:[a-z][\\w-]*)?|(?:dom|img|link|html):[^@]*(?:@[\\w-]+)?)$/\n\nexport interface MappingRule {\n /** Builder element, as the fact pack names it; a `:qualifier` narrows it (`core/template-part:header`). */\n match: string\n /** Extra conditions on the element. */\n when?: { attr?: Record<string, string | number | boolean>, class?: string }\n /** Kit component id. */\n component: string\n variant?: Record<string, string>\n /** Content the element lists rather than holds: one component per entry of the collection (`collection:posts`). */\n bind?: `collection:${string}`\n /** Consecutive sibling matches form one component (a row of Elementor icon boxes is one card grid). */\n group?: 'siblings'\n props?: Record<string, string>\n /** Array prop filled from repeated parts of the element (`each`) or the grouped siblings / bound entries. */\n into?: string\n /** Selector of the repeated parts inside the element, for `into`. */\n each?: string\n /** Props of one repeated part / sibling / entry, with sources relative to it. */\n item?: Record<string, string>\n}\n\nexport interface MappingTable {\n format: typeof MAPPING_FORMAT\n builder: KitBuilder\n /** Bumped on any rule change: plans record the version they applied. */\n version: string\n /** What an element no rule covers becomes when no decision is made: rich text. */\n fallback: 'prose'\n /**\n * Attribute values the builder leaves out of its data while they are at their default, per element:\n * Elementor saves no `video_type` for a YouTube video. `when.attr` and `attr:` read through them.\n */\n defaults?: Record<string, Record<string, string | number | boolean>>\n rules: MappingRule[]\n /**\n * Section rules: what a whole section of a page (an Elementor container, a Gutenberg group or columns,\n * a Divi section — facts `sections[]`) becomes, tried top to bottom before any element rule. The first\n * that matches wins; a section none matches falls through to the element `rules` inside it.\n */\n sections?: SectionRule[]\n}\n\n/**\n * A named group of a section's leaves: every leaf named `match` (and carrying `attr`) up to `max` of them.\n * `attr` values may list alternatives with `|` (`{ header_size: 'h1|h2' }`).\n */\nexport interface SectionSlot {\n match: string | string[]\n attr?: Record<string, string | number | boolean>\n /** At least this many leaves (default 0). */\n min?: number\n /** At most this many (default unbounded). */\n max?: number\n /** The leaf is a figure (`1,200`, `2018`, `$29`, `01`): its facts say so. `true` requires it, `false` rules it out. */\n numeric?: boolean\n /** The leaf is a step's ordinal (`1`, `01`, `Step 2` — at most two digits): its facts say so. A year or a count is a figure, not an ordinal. */\n ordinal?: boolean\n /** The image is logo-sized (small as displayed): its facts say so. Photos and banners are not. */\n small?: boolean\n /** The image is a portrait: a square-ish photo at least 200px across (a team member's face). Logos and banners are not. */\n portrait?: boolean\n /** The leaf's text is one short line — a name, a role, a label — not a description: its facts say so. */\n short?: boolean\n /**\n * `intro`: the slot holds the leaves above the repeated columns (a section's heading and lead line), not the\n * columns' own. Only with `when.repeat: 'columns'`; every other slot of such a rule reads inside a column.\n */\n scope?: 'intro'\n}\n\n/**\n * One section pattern. Values are the table's expressions, prefixed `@<slot> ` to read a slot's leaf\n * (`@title attr:title`); `a || b` takes the first non-empty (builder data first, rendered markup as fallback).\n * A slot of several leaves joins their text into a markdown prop; any other prop reads its first leaf.\n * A value without a slot reads the section's own root (a cover's background image, a container's setting).\n */\nexport interface SectionRule {\n /** Stable id (`hero.split`, `card-grid.icon-box`): plans record `<builder>:section:<id>`; JEW chooses among them. */\n id: string\n component: string\n variant?: Record<string, string>\n when?: {\n /** Where on the page: `first` is the page's first section, `last` its last. */\n position?: 'first' | 'last' | 'any'\n /** Column count(s) the section must have. */\n columns?: number | number[]\n /** Every leaf must fall into a slot (default true); false lets unclaimed leaves be. */\n only?: boolean\n /**\n * `columns`: each column must match the slots on its own (a row of team members, price plans); the leaves above\n * the row (`SectionMeta.intro`) go to the slots with `scope: 'intro'`.\n */\n repeat?: 'columns'\n /** The section's root element(s): `core/cover`, `core/media-text` (a loose run of blocks is `run`). */\n root?: string | string[]\n }\n /**\n * Named leaf groups. Each leaf, in document order, goes to the first declared slot that matches it and\n * still has room, so declare a specific slot (an `attr` filter) before a general one on the same element.\n */\n slots: Record<string, SectionSlot>\n props?: Record<string, string>\n /**\n * Array prop filled once per `each`: a slot's leaves (`@card`), the parts a selector finds inside them\n * (`@list figure.wp-block-image`, `@faq .elementor-accordion-item`: a gallery's images, an accordion's\n * items), or the columns (`column`, with `repeat: 'columns'`).\n */\n into?: string\n each?: string\n /** One array item: relative to the leaf (`each: '@slot'`) or to the column, where `@<slot>` is that column's slot. */\n item?: Record<string, string>\n}\n\n/** A section leaf as the fact pack gives it: a builder element with its `blocks:` path. */\nexport interface SectionLeaf extends MappingNode {\n path: string\n /** Facts' flag: the leaf's text is a figure (a number, an amount, a step number) — not the text itself. */\n numeric?: boolean\n /** Facts' flag: the leaf's text is an ordinal — one or two digits, nothing else. */\n ordinal?: boolean\n /** Facts' flag: the image is logo-sized as displayed. */\n small?: boolean\n /** Facts' flag: the image is a square-ish photo, at least 200px across. */\n portrait?: boolean\n /** Facts' flag: the leaf's text is one short line (at most 40 characters, no line break). */\n short?: boolean\n}\n\n/** Where a section sits (facts `index`/`count`) and what it is (`root`: facts `root`). */\nexport interface SectionMeta {\n index: number\n count: number\n root?: string | undefined\n /** The leaves above a row of columns, in the same wrapper (`Who we are` over its people): see `when.repeat`. */\n intro?: SectionLeaf[] | undefined\n}\n\n/** Leaf paths per slot; with `repeat: 'columns'`, also per column. */\nexport interface SectionMatch {\n slots: Record<string, string[]>\n columns?: Record<string, string[]>[]\n}\n\n/** The id a plan records for a section rule. */\nexport function sectionRuleId(builder: KitBuilder, rule: Pick<SectionRule, 'id'>): string {\n return `${builder}:section:${rule.id}`\n}\n\nconst SECTION_LAYOUT_LEAVES = new Set(['elementor/spacer', 'elementor/divider', 'core/spacer', 'core/separator', 'divi/et_pb_divider'])\n\nfunction slotFits(slot: SectionSlot, leaf: SectionLeaf, defaults?: MappingTable['defaults']): boolean {\n if (![slot.match].flat().includes(leaf.name)) return false\n // A flag the facts do not set reads as \"no\": a rule that asks for one never fires on facts that predate it.\n if (slot.numeric !== undefined && slot.numeric !== (leaf.numeric === true)) return false\n if (slot.ordinal !== undefined && slot.ordinal !== (leaf.ordinal === true)) return false\n if (slot.small !== undefined && slot.small !== (leaf.small === true)) return false\n if (slot.portrait !== undefined && slot.portrait !== (leaf.portrait === true)) return false\n if (slot.short !== undefined && slot.short !== (leaf.short === true)) return false\n const attrs = attrsOf(leaf, defaults)\n return Object.entries(slot.attr ?? {}).every(([key, want]) => String(want).split('|').includes(String(attrs[key])))\n}\n\n/**\n * Assign leaves to slots in document order, each to the first declared slot with room; null when the rule does not fit.\n * `scope` picks the slots in play: a repeated row's columns read the column slots, the leaves above it the intro slots;\n * any other section reads them all.\n */\nfunction claimLeaves(rule: SectionRule, leaves: SectionLeaf[], defaults?: MappingTable['defaults'], scope: 'all' | 'column' | 'intro' = 'all'): Record<string, string[]> | null {\n const slots = Object.entries(rule.slots).filter(([, def]) => scope === 'all' || (def.scope === 'intro') === (scope === 'intro'))\n const claimed: Record<string, string[]> = Object.fromEntries(slots.map(([name]) => [name, []]))\n for (const leaf of leaves) {\n if (SECTION_LAYOUT_LEAVES.has(leaf.name)) continue\n const slot = slots.find(([name, def]) => claimed[name]!.length < (def.max ?? Infinity) && slotFits(def, leaf, defaults))\n if (slot) claimed[slot[0]]!.push(leaf.path)\n else if (rule.when?.only !== false) return null\n }\n for (const [name, def] of slots) if (claimed[name]!.length < (def.min ?? 0)) return null\n return claimed\n}\n\n/**\n * Whether a section rule fits a section, and which leaves fill which slot. `columns` are the section's\n * columns left to right, each its leaves in document order (layout containers already opened).\n */\nexport function matchSection(rule: SectionRule, columns: SectionLeaf[][], meta: SectionMeta, defaults?: MappingTable['defaults']): SectionMatch | null {\n const when = rule.when ?? {}\n if (when.root !== undefined && !(meta.root !== undefined && [when.root].flat().includes(meta.root))) return null\n if (when.position === 'first' && meta.index !== 0) return null\n if (when.position === 'last' && meta.index !== meta.count - 1) return null\n if (when.columns !== undefined && ![when.columns].flat().includes(columns.length)) return null\n if (when.repeat === 'columns') {\n if (columns.length < 2) return null\n const intro = claimLeaves(rule, meta.intro ?? [], defaults, 'intro')\n if (!intro) return null\n const per = columns.map(leaves => claimLeaves(rule, leaves, defaults, 'column'))\n if (per.some(c => !c)) return null\n const slots: Record<string, string[]> = { ...intro }\n for (const [name, def] of Object.entries(rule.slots)) if (def.scope !== 'intro') slots[name] = per.flatMap(c => c![name]!)\n return { slots, columns: per as Record<string, string[]>[] }\n }\n // Without a repeat the leaves above the row are simply the section's first leaves, as before the facts split them off.\n const slots = claimLeaves(rule, [...(meta.intro ?? []), ...columns.flat()], defaults)\n return slots && { slots }\n}\n\n/** The first section rule of a table that fits, with its match. */\nexport function classifySection(table: MappingTable, columns: SectionLeaf[][], meta: SectionMeta): { rule: SectionRule, match: SectionMatch } | null {\n for (const rule of table.sections ?? []) {\n const match = matchSection(rule, columns, meta, table.defaults)\n if (match) return { rule, match }\n }\n return null\n}\n\n/** A section value: alternatives joined by ` || `, each an optional `@<slot> ` then a mapping value. Returns the slots it reads, or null when malformed. */\nexport function sectionValueSlots(value: string): string[] | null {\n const slots: string[] = []\n for (const alternative of value.split(' || ')) {\n const m = /^(?:@([a-z][\\w-]*) )?(.+)$/.exec(alternative)\n if (!m || !MAPPING_VALUE_PATTERN.test(m[2]!)) return null\n if (m[1]) slots.push(m[1])\n }\n return slots\n}\n\n/** Problems with a mapping table against the catalog, one line each; empty when it is sound. */\nexport function validateMapping(table: MappingTable, catalog: KitCatalog): string[] {\n const problems: string[] = []\n if (table.format !== MAPPING_FORMAT) problems.push(`format is not ${MAPPING_FORMAT}`)\n if (!KIT_BUILDERS.includes(table.builder)) problems.push(`unknown builder ${table.builder}`)\n if (!/^\\d+$/.test(table.version)) problems.push('version is not an integer string')\n for (const element of Object.keys(table.defaults ?? {})) if (!isBuilderElement(table.builder, element)) problems.push(`defaults ${element}: not a ${table.builder} element`)\n const components = new Map(catalog.components.map(c => [c.id, c]))\n const seen = new Set<string>()\n for (const rule of table.rules) {\n const at = `${table.builder} ${rule.match}${rule.when ? ' (when)' : ''}`\n const key = `${rule.match}|${JSON.stringify(rule.when ?? {})}`\n if (seen.has(key)) problems.push(`${at}: matched twice`)\n seen.add(key)\n if (!isBuilderElement(table.builder, rule.match)) problems.push(`${at}: not a ${table.builder} element`)\n const c = components.get(rule.component)\n if (!c) { problems.push(`${at}: component ${rule.component} is not in the catalog`); continue }\n for (const [axis, value] of Object.entries(rule.variant ?? {})) {\n // A variant is one option, or a `class:` choice between options read from the element.\n const choice = /^class:[\\w*-]+=([a-z][\\w-]*)?\\|([a-z][\\w-]*)?$/.exec(value)\n const options = choice ? [choice[1], choice[2]].filter((option): option is string => option !== undefined) : [value]\n if (!c.variants[axis]) problems.push(`${at}: ${c.id} has no variant axis ${axis}`)\n else for (const missing of options.filter(option => !c.variants[axis]!.options.includes(option))) problems.push(`${at}: ${c.id}.${axis} has no option ${missing}`)\n }\n for (const [prop, value] of Object.entries({ ...rule.props, ...(rule.into ? {} : rule.item) })) {\n if (!c.props[prop]) problems.push(`${at}: ${c.id} has no prop ${prop}`)\n if (!MAPPING_VALUE_PATTERN.test(value)) problems.push(`${at}: ${prop} = ${value} is not a mapping value`)\n }\n if (rule.into) {\n const target = c.props[rule.into]\n if (!target || target.type !== 'array') problems.push(`${at}: ${c.id}.${rule.into} is not an array prop`)\n const fields = target && typeof target.items === 'object' ? target.items.fields ?? {} : {}\n for (const [field, value] of Object.entries(rule.item ?? {})) {\n if (!fields[field]) problems.push(`${at}: ${c.id}.${rule.into}[] has no field ${field}`)\n if (!MAPPING_VALUE_PATTERN.test(value)) problems.push(`${at}: ${rule.into}[].${field} = ${value} is not a mapping value`)\n }\n if (!rule.each && !rule.group && !rule.bind) problems.push(`${at}: into ${rule.into} needs each, group or bind to say what repeats`)\n }\n if (rule.item && !rule.into && !rule.bind) problems.push(`${at}: item without into or bind`)\n const bound = new Set([...Object.keys(rule.props ?? {}), ...(rule.into ? [rule.into] : Object.keys(rule.item ?? {}))])\n for (const [prop, def] of Object.entries(c.props)) if (def.required && !bound.has(prop)) problems.push(`${at}: required prop ${c.id}.${prop} has no source`)\n }\n problems.push(...validateSections(table, components))\n return problems\n}\n\nfunction validateSections(table: MappingTable, components: Map<string, KitComponent>): string[] {\n const problems: string[] = []\n const seen = new Set<string>()\n for (const rule of table.sections ?? []) {\n const at = `${table.builder} section ${rule.id}`\n if (!/^[a-z][a-z0-9-]*(?:\\.[a-z0-9-]+)*$/.test(rule.id)) problems.push(`${at}: id is not dotted kebab-case`)\n if (seen.has(rule.id)) problems.push(`${at}: listed twice`)\n seen.add(rule.id)\n const c = components.get(rule.component)\n if (!c) { problems.push(`${at}: component ${rule.component} is not in the catalog`); continue }\n for (const [axis, value] of Object.entries(rule.variant ?? {})) {\n if (!c.variants[axis]) problems.push(`${at}: ${c.id} has no variant axis ${axis}`)\n else if (!c.variants[axis]!.options.includes(value)) problems.push(`${at}: ${c.id}.${axis} has no option ${value}`)\n }\n if (!Object.keys(rule.slots).length) problems.push(`${at}: no slots`)\n for (const [name, slot] of Object.entries(rule.slots)) {\n if (!/^[a-z][\\w-]*$/.test(name)) problems.push(`${at}: slot ${name} is not an identifier`)\n // A form or shortcode plugin (`classic/contact-form-7`) sits inside any builder's section, as the plan reads it from a shortcode.\n for (const element of [slot.match].flat()) if (!isBuilderElement(table.builder, element) && !isBuilderElement('classic', element)) problems.push(`${at}: slot ${name} matches ${element}, not a ${table.builder} or classic plugin element`)\n if (slot.min !== undefined && slot.max !== undefined && slot.min > slot.max) problems.push(`${at}: slot ${name} min > max`)\n }\n for (const root of [rule.when?.root ?? []].flat()) if (root !== 'run' && !isBuilderElement(table.builder, root)) problems.push(`${at}: root ${root} is not a ${table.builder} element or run`)\n if (rule.when?.repeat === 'columns' && rule.each !== 'column') problems.push(`${at}: repeat columns needs each: column`)\n if (rule.each === 'column' && rule.when?.repeat !== 'columns') problems.push(`${at}: each column needs when.repeat columns`)\n for (const [name, slot] of Object.entries(rule.slots)) if (slot.scope === 'intro' && rule.when?.repeat !== 'columns') problems.push(`${at}: slot ${name} is scope intro, which needs when.repeat columns`)\n const readsSlots = (value: string, where: string, type: string | undefined, slotted: boolean, item = false) => {\n const slots = sectionValueSlots(value)\n if (!slots) { problems.push(`${at}: ${where} = ${value} is not a section value`); return }\n if (!slotted && slots.length) problems.push(`${at}: ${where} reads a slot, but items of each ${rule.each} read their own leaf`)\n for (const slot of slots) {\n const def = rule.slots[slot]\n if (!def) problems.push(`${at}: ${where} reads undeclared slot ${slot}`)\n else if ((type === 'string' || type === 'text') && def.max !== 1) problems.push(`${at}: ${where} is ${type} but slot ${slot} may hold several leaves (max must be 1)`)\n else if (item && def.scope === 'intro') problems.push(`${at}: ${where} reads intro slot ${slot}, but the items of each column read their own column`)\n }\n }\n for (const [prop, value] of Object.entries(rule.props ?? {})) {\n const def = c.props[prop]\n if (!def) problems.push(`${at}: ${c.id} has no prop ${prop}`)\n readsSlots(value, prop, def?.type, true)\n }\n if (rule.into) {\n const target = c.props[rule.into]\n if (!target || target.type !== 'array') problems.push(`${at}: ${c.id}.${rule.into} is not an array prop`)\n if (!rule.each) problems.push(`${at}: into ${rule.into} needs each`)\n else if (rule.each !== 'column' && !rule.slots[/^@([a-z][\\w-]*)(?: \\S.*)?$/.exec(rule.each)?.[1] ?? '']) problems.push(`${at}: each ${rule.each} is not @<declared slot> [selector] or column`)\n const fields = target && typeof target.items === 'object' ? target.items.fields ?? {} : {}\n for (const [field, value] of Object.entries(rule.item ?? {})) {\n if (!fields[field]) problems.push(`${at}: ${c.id}.${rule.into}[] has no field ${field}`)\n readsSlots(value, `${rule.into}[].${field}`, fields[field]?.type, rule.each === 'column', true)\n }\n } else if (rule.item || rule.each) problems.push(`${at}: each/item without into`)\n const bound = new Set([...Object.keys(rule.props ?? {}), ...(rule.into ? [rule.into] : [])])\n for (const [prop, def] of Object.entries(c.props)) if (def.required && !bound.has(prop)) problems.push(`${at}: required prop ${c.id}.${prop} has no source`)\n }\n return problems\n}\n\n/** Catalog sources of a builder that no rule of its table matches, as an element rule or a section slot. */\nexport function unmappedSources(table: MappingTable, catalog: KitCatalog): string[] {\n const matched = new Set([...table.rules.map(r => r.match), ...(table.sections ?? []).flatMap(r => Object.values(r.slots).flatMap(s => [s.match].flat()))])\n const sources = catalog.components.flatMap((c: KitComponent) => c.sources[table.builder] ?? [])\n return [...new Set(sources)].filter(s => !matched.has(s)).toSorted()\n}\n\n/** Rules for an element, most specific (with `when` / qualifier) first. */\nexport function rulesFor(table: MappingTable, element: string): MappingRule[] {\n return table.rules\n .filter(r => r.match === element || r.match.split(':')[0] === element)\n .toSorted((a, b) => Number(!!b.when || b.match.includes(':')) - Number(!!a.when || a.match.includes(':')))\n}\n\n/** A builder element as the fact pack gives it (`FactBlock`): name, attributes, children. */\nexport interface MappingNode {\n name: string\n attrs?: Record<string, unknown>\n children?: MappingNode[]\n}\n\n/** An element's attributes with the builder's unsaved defaults filled in. */\nexport function attrsOf(node: MappingNode, defaults: MappingTable['defaults'] = {}): Record<string, unknown> {\n return { ...defaults[node.name], ...node.attrs }\n}\n\n/** Whether a rule's `match` (with an optional `:qualifier`) and `when.attr` fit an element. */\nexport function ruleMatches(rule: MappingRule, node: MappingNode, defaults?: MappingTable['defaults']): boolean {\n const [name, qualifier] = rule.match.split(':')\n if (name !== node.name) return false\n const attrs = attrsOf(node, defaults)\n // A qualifier names the element's role: a template part's area or slug, or a sub-part the fact pack marks.\n if (qualifier && ![attrs.area, attrs.slug, attrs.tagName, attrs.qualifier].includes(qualifier)) return false\n for (const [key, value] of Object.entries(rule.when?.attr ?? {})) if (attrs[key] !== value) return false\n if (rule.when?.class && !String(attrs.className ?? attrs.classes ?? '').split(/\\s+/).includes(rule.when.class)) return false\n return true\n}\n\n/**\n * Apply a table to a tree: the outermost matching element owns its whole subtree, and nothing inside\n * it is matched again — a header template part holding the site title and logo is one header, not three.\n */\nexport function claimMatches(nodes: MappingNode[], table: MappingTable, path = '0'): { path: string, node: MappingNode, rule: MappingRule }[] {\n return nodes.flatMap((node, i) => {\n const at = `${path}.${i}`\n const rule = rulesFor(table, node.name).find(r => ruleMatches(r, node, table.defaults))\n return rule ? [{ path: at, node, rule }] : claimMatches(node.children ?? [], table, at)\n })\n}\n","import { readFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { KitBuilder, KitCatalog } from './catalog.js'\nimport type { MappingTable } from './mapping.js'\n\nexport * from './catalog.js'\nexport * from './copy.js'\nexport * from './mapping.js'\n\nconst PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')\n\n/** The kit's `components/` directory — the source `copyComponents` copies from. */\nexport const KIT_COMPONENTS_DIR = join(PACKAGE_ROOT, 'components')\n\n/** A builder's mapping table (`mapping/<builder>.json`). */\nexport async function loadMapping(builder: KitBuilder): Promise<MappingTable> {\n return JSON.parse(await readFile(join(PACKAGE_ROOT, 'mapping', `${builder}.json`), 'utf8')) as MappingTable\n}\n\n/** The published catalog (`catalog.json`). */\nexport async function loadCatalog(): Promise<KitCatalog> {\n return JSON.parse(await readFile(join(PACKAGE_ROOT, 'catalog.json'), 'utf8')) as KitCatalog\n}\n"],"mappings":";;;;;AAYA,MAAa,iBAAiB;AAI9B,MAAa,eAAsC;CAAC;CAAa;CAAa;CAAQ;CAAU;;AAGhG,MAAa,iBAA6C;CACxD,WAAW;CACX,WAAW;CACX,MAAM;CACN,SAAS;CACV;;;;;;AAOD,SAAgB,iBAAiB,SAAqB,MAAuB;AAC3E,KAAI,YAAY,YAAa,QAAO,KAAK,WAAW,eAAe,SAAS;AAC5E,QAAO,qCAAqC,KAAK,KAAK,IAAI,CAAC,aAAa,MAAK,MAAK,MAAM,eAAe,KAAK,WAAW,eAAe,GAAG,CAAC;;;;;;AAqB5I,MAAa,oBAAoB;;;;;AAMjC,MAAa,mBAA6C;;AAG1D,SAAgB,aAAa,WAAsD;AACjF,QAAO,OAAO,YAAY,OAAO,QAAQ,UAAU,MAAM,CAAC,QAAQ,GAAG,UAAU,KAAK,YAAY,MAAM,CAAC;;;AAIzG,SAAS,aAAa,QAAkC,SAAS,IAA+B;CAC9F,MAAM,MAAiC,EAAE;AACzC,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAO,EAAE;AAClD,MAAI,KAAK,CAAC,SAAS,MAAM,MAAM,EAAE,GAAG,aAAa,MAAM,UAAU,EAAE,EAAE,GAAG,SAAS,KAAK,GAAG,CAAC;AAC1F,MAAI,OAAO,MAAM,UAAU,SAAU,KAAI,KAAK,GAAG,aAAa,MAAM,MAAM,UAAU,EAAE,EAAE,GAAG,SAAS,KAAK,KAAK,CAAC;;AAEjH,QAAO;;;AAIT,SAAgB,iBAAiB,MAAsB;AACrD,QAAO,KAAK,QAAQ,iBAAiB,iBAAiB;;;AA0DxD,SAAgB,gBAAgB,SAA+B;CAC7D,MAAM,WAAqB,EAAE;CAC7B,MAAM,MAAM,IAAI,IAAI,QAAQ,WAAW,KAAI,MAAK,EAAE,GAAG,CAAC;AACtD,MAAK,MAAM,KAAK,QAAQ,YAAY;EAClC,MAAM,KAAK,aAAa,EAAE;AAC1B,MAAI,CAAC,oBAAoB,KAAK,EAAE,GAAG,CAAE,UAAS,KAAK,GAAG,GAAG,yBAAyB;AAClF,MAAI,CAAC,EAAE,MAAM,OAAQ,UAAS,KAAK,GAAG,GAAG,YAAY;AACrD,OAAK,MAAM,QAAQ,EAAE,KAAM,KAAI,CAAC,IAAI,IAAI,KAAK,CAAE,UAAS,KAAK,GAAG,GAAG,4BAA4B,KAAK,GAAG;AACvG,OAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,EAAE,SAAS,CACtD,KAAI,CAAC,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,CAAE,UAAS,KAAK,GAAG,GAAG,YAAY,KAAK,YAAY,QAAQ,QAAQ,oBAAoB;AAEvI,OAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,EAAE,MAAM,EAAE;AAClD,OAAI,CAAC,KAAK,YAAa,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,qBAAqB;AAC9E,OAAI,KAAK,SAAS,YAAY,CAAC,KAAK,SAAS,OAAQ,UAAS,KAAK,GAAG,GAAG,gBAAgB,KAAK,iBAAiB;;AAEjH,MAAI,EAAE,aAAa,WAAW;GAG5B,MAAM,UAAU,aAAa,EAAE;GAC/B,MAAM,QAAQ,aAAa,QAAQ;AACnC,QAAK,MAAM,CAAC,MAAM,UAAU,OAAO;AACjC,QAAI,CAAC,kBAAkB,KAAK,KAAK,MAAM,YAAY,CAAC,GAAG,GAAG,CAAE,CAAE,UAAS,KAAK,GAAG,GAAG,iBAAiB,KAAK,kEAAkE;AAE1K,QAAI,CAAC,MAAM,MAAO,UAAS,KAAK,GAAG,GAAG,iBAAiB,KAAK,eAAe;AAC3E,QAAI,CAAC,MAAM,YAAa,UAAS,KAAK,GAAG,GAAG,iBAAiB,KAAK,qBAAqB;;AAEzF,OAAI,EAAE,eAAe;IACnB,MAAM,WAAW,OAAO,YAAY,MAAM,KAAK,CAAC,UAAU,CAAC,MAAM,iBAAiB,KAAK,CAAC,CAAC,CAAC;AAC1F,QAAI,KAAK,UAAU,EAAE,cAAc,KAAK,KAAK,UAAU,SAAS,CAAE,UAAS,KAAK,GAAG,GAAG,gDAAgD;;AAExI,QAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,QAAQ,CAChD,KAAI,IAAI,WAAW,KAAK,GAAG,EAAG,UAAS,KAAK,GAAG,GAAG,iBAAiB,KAAK,oDAAoD;;AAGhI,OAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,EAAE,QAAQ,EAAmC;GACzF,MAAM,SAAS,eAAe;AAC9B,QAAK,MAAM,QAAQ,MAAO,KAAI,CAAC,iBAAiB,SAAS,KAAK,CAAE,UAAS,KAAK,GAAG,GAAG,YAAY,KAAK,aAAa,QAAQ,YAAY,OAAO,IAAI;;;CAGrJ,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,KAAK,QAAQ,YAAY;AAClC,MAAI,KAAK,IAAI,EAAE,GAAG,CAAE,UAAS,KAAK,aAAa,EAAE,GAAG,gBAAgB;AACpE,OAAK,IAAI,EAAE,GAAG;;AAEhB,QAAO;;;AAIT,SAAgB,oBAAoB,SAAqB,SAAiC;AACxF,QAAO,QAAQ,WAAW,QAAO,MAAK,OAAO,OAAO,EAAE,QAAQ,CAAC,MAAK,UAAS,OAAO,SAAS,QAAQ,CAAC,CAAC;;;;;AC/KzG,MAAa,UAAU;AAWvB,SAAgB,SAAS,SAAqB,KAAkC;CAC9E,MAAM,OAAO,IAAI,IAAI,QAAQ,WAAW,KAAI,MAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;CAC5D,MAAM,yBAAS,IAAI,KAAa;CAChC,MAAM,SAAS,OAAe;AAC5B,MAAI,OAAO,IAAI,GAAG,CAAE;EACpB,MAAM,YAAY,KAAK,IAAI,GAAG;AAC9B,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,+BAA+B,GAAG,YAAY,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG;AAC7G,SAAO,IAAI,GAAG;AACd,OAAK,MAAM,QAAQ,UAAU,KAAM,OAAM,KAAK;;AAEhD,MAAK,MAAM,MAAM,IAAK,OAAM,GAAG;CAE/B,MAAM,QAAgC,EAAE;CACxC,MAAM,eAAuC,EAAE,GAAG,QAAQ,cAAc;AACxE,MAAK,MAAM,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE;EACvC,MAAM,YAAY,KAAK,IAAI,GAAG;AAC9B,OAAK,MAAM,QAAQ,UAAU,MAAO,OAAM,GAAG,QAAQ,GAAG,GAAG,GAAG,UAAU,GAAG,GAAG,GAAG;AACjF,OAAK,MAAM,QAAQ,UAAU,OAAQ,OAAM,GAAG,QAAQ,WAAW,UAAU,WAAW;AACtF,SAAO,OAAO,cAAc,UAAU,aAAa;;AAErD,QAAO;EAAE,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU;EAAE;EAAO;EAAc;;;AAIpE,eAAsB,eAAe,MAAgB,SAAiB,UAAiC;AACrG,OAAM,QAAQ,IAAI,OAAO,QAAQ,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,YAAY;EACzE,MAAM,SAAS,KAAK,UAAU,KAAK;AACnC,QAAM,MAAM,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AACjD,QAAM,SAAS,KAAK,SAAS,OAAO,EAAE,OAAO;GAC7C,CAAC;;;;ACnBL,MAAa,iBAAiB;AAE9B,MAAa,wBAAwB;;AAkJrC,SAAgB,cAAc,SAAqB,MAAuC;AACxF,QAAO,GAAG,QAAQ,WAAW,KAAK;;AAGpC,MAAM,wBAAwB,IAAI,IAAI;CAAC;CAAoB;CAAqB;CAAe;CAAkB;CAAqB,CAAC;AAEvI,SAAS,SAAS,MAAmB,MAAmB,UAA8C;AACpG,KAAI,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,SAAS,KAAK,KAAK,CAAE,QAAO;AAErD,KAAI,KAAK,YAAY,KAAA,KAAa,KAAK,aAAa,KAAK,YAAY,MAAO,QAAO;AACnF,KAAI,KAAK,YAAY,KAAA,KAAa,KAAK,aAAa,KAAK,YAAY,MAAO,QAAO;AACnF,KAAI,KAAK,UAAU,KAAA,KAAa,KAAK,WAAW,KAAK,UAAU,MAAO,QAAO;AAC7E,KAAI,KAAK,aAAa,KAAA,KAAa,KAAK,cAAc,KAAK,aAAa,MAAO,QAAO;AACtF,KAAI,KAAK,UAAU,KAAA,KAAa,KAAK,WAAW,KAAK,UAAU,MAAO,QAAO;CAC7E,MAAM,QAAQ,QAAQ,MAAM,SAAS;AACrC,QAAO,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,UAAU,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,SAAS,OAAO,MAAM,KAAK,CAAC,CAAC;;;;;;;AAQrH,SAAS,YAAY,MAAmB,QAAuB,UAAqC,QAAoC,OAAwC;CAC9K,MAAM,QAAQ,OAAO,QAAQ,KAAK,MAAM,CAAC,QAAQ,GAAG,SAAS,UAAU,SAAU,IAAI,UAAU,aAAc,UAAU,SAAS;CAChI,MAAM,UAAoC,OAAO,YAAY,MAAM,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC/F,MAAK,MAAM,QAAQ,QAAQ;AACzB,MAAI,sBAAsB,IAAI,KAAK,KAAK,CAAE;EAC1C,MAAM,OAAO,MAAM,MAAM,CAAC,MAAM,SAAS,QAAQ,MAAO,UAAU,IAAI,OAAO,aAAa,SAAS,KAAK,MAAM,SAAS,CAAC;AACxH,MAAI,KAAM,SAAQ,KAAK,IAAK,KAAK,KAAK,KAAK;WAClC,KAAK,MAAM,SAAS,MAAO,QAAO;;AAE7C,MAAK,MAAM,CAAC,MAAM,QAAQ,MAAO,KAAI,QAAQ,MAAO,UAAU,IAAI,OAAO,GAAI,QAAO;AACpF,QAAO;;;;;;AAOT,SAAgB,aAAa,MAAmB,SAA0B,MAAmB,UAA0D;CACrJ,MAAM,OAAO,KAAK,QAAQ,EAAE;AAC5B,KAAI,KAAK,SAAS,KAAA,KAAa,EAAE,KAAK,SAAS,KAAA,KAAa,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,SAAS,KAAK,KAAK,EAAG,QAAO;AAC5G,KAAI,KAAK,aAAa,WAAW,KAAK,UAAU,EAAG,QAAO;AAC1D,KAAI,KAAK,aAAa,UAAU,KAAK,UAAU,KAAK,QAAQ,EAAG,QAAO;AACtE,KAAI,KAAK,YAAY,KAAA,KAAa,CAAC,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,SAAS,QAAQ,OAAO,CAAE,QAAO;AAC1F,KAAI,KAAK,WAAW,WAAW;AAC7B,MAAI,QAAQ,SAAS,EAAG,QAAO;EAC/B,MAAM,QAAQ,YAAY,MAAM,KAAK,SAAS,EAAE,EAAE,UAAU,QAAQ;AACpE,MAAI,CAAC,MAAO,QAAO;EACnB,MAAM,MAAM,QAAQ,KAAI,WAAU,YAAY,MAAM,QAAQ,UAAU,SAAS,CAAC;AAChF,MAAI,IAAI,MAAK,MAAK,CAAC,EAAE,CAAE,QAAO;EAC9B,MAAM,QAAkC,EAAE,GAAG,OAAO;AACpD,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,MAAM,CAAE,KAAI,IAAI,UAAU,QAAS,OAAM,QAAQ,IAAI,SAAQ,MAAK,EAAG,MAAO;AAC1H,SAAO;GAAE;GAAO,SAAS;GAAmC;;CAG9D,MAAM,QAAQ,YAAY,MAAM,CAAC,GAAI,KAAK,SAAS,EAAE,EAAG,GAAG,QAAQ,MAAM,CAAC,EAAE,SAAS;AACrF,QAAO,SAAS,EAAE,OAAO;;;AAI3B,SAAgB,gBAAgB,OAAqB,SAA0B,MAAsE;AACnJ,MAAK,MAAM,QAAQ,MAAM,YAAY,EAAE,EAAE;EACvC,MAAM,QAAQ,aAAa,MAAM,SAAS,MAAM,MAAM,SAAS;AAC/D,MAAI,MAAO,QAAO;GAAE;GAAM;GAAO;;AAEnC,QAAO;;;AAIT,SAAgB,kBAAkB,OAAgC;CAChE,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,eAAe,MAAM,MAAM,OAAO,EAAE;EAC7C,MAAM,IAAI,6BAA6B,KAAK,YAAY;AACxD,MAAI,CAAC,KAAK,CAAC,sBAAsB,KAAK,EAAE,GAAI,CAAE,QAAO;AACrD,MAAI,EAAE,GAAI,OAAM,KAAK,EAAE,GAAG;;AAE5B,QAAO;;;AAIT,SAAgB,gBAAgB,OAAqB,SAA+B;CAClF,MAAM,WAAqB,EAAE;AAC7B,KAAI,MAAM,WAAA,sBAA2B,UAAS,KAAK,iBAAiB,iBAAiB;AACrF,KAAI,CAAC,aAAa,SAAS,MAAM,QAAQ,CAAE,UAAS,KAAK,mBAAmB,MAAM,UAAU;AAC5F,KAAI,CAAC,QAAQ,KAAK,MAAM,QAAQ,CAAE,UAAS,KAAK,mCAAmC;AACnF,MAAK,MAAM,WAAW,OAAO,KAAK,MAAM,YAAY,EAAE,CAAC,CAAE,KAAI,CAAC,iBAAiB,MAAM,SAAS,QAAQ,CAAE,UAAS,KAAK,YAAY,QAAQ,UAAU,MAAM,QAAQ,UAAU;CAC5K,MAAM,aAAa,IAAI,IAAI,QAAQ,WAAW,KAAI,MAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;CAClE,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,QAAQ,MAAM,OAAO;EAC9B,MAAM,KAAK,GAAG,MAAM,QAAQ,GAAG,KAAK,QAAQ,KAAK,OAAO,YAAY;EACpE,MAAM,MAAM,GAAG,KAAK,MAAM,GAAG,KAAK,UAAU,KAAK,QAAQ,EAAE,CAAC;AAC5D,MAAI,KAAK,IAAI,IAAI,CAAE,UAAS,KAAK,GAAG,GAAG,iBAAiB;AACxD,OAAK,IAAI,IAAI;AACb,MAAI,CAAC,iBAAiB,MAAM,SAAS,KAAK,MAAM,CAAE,UAAS,KAAK,GAAG,GAAG,UAAU,MAAM,QAAQ,UAAU;EACxG,MAAM,IAAI,WAAW,IAAI,KAAK,UAAU;AACxC,MAAI,CAAC,GAAG;AAAE,YAAS,KAAK,GAAG,GAAG,cAAc,KAAK,UAAU,wBAAwB;AAAE;;AACrF,OAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC,EAAE;GAE9D,MAAM,SAAS,iDAAiD,KAAK,MAAM;GAC3E,MAAM,UAAU,SAAS,CAAC,OAAO,IAAI,OAAO,GAAG,CAAC,QAAQ,WAA6B,WAAW,KAAA,EAAU,GAAG,CAAC,MAAM;AACpH,OAAI,CAAC,EAAE,SAAS,MAAO,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,uBAAuB,OAAO;OAC7E,MAAK,MAAM,WAAW,QAAQ,QAAO,WAAU,CAAC,EAAE,SAAS,MAAO,QAAQ,SAAS,OAAO,CAAC,CAAE,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,iBAAiB,UAAU;;AAEpK,OAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ;GAAE,GAAG,KAAK;GAAO,GAAI,KAAK,OAAO,EAAE,GAAG,KAAK;GAAO,CAAC,EAAE;AAC9F,OAAI,CAAC,EAAE,MAAM,MAAO,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,eAAe,OAAO;AACvE,OAAI,CAAC,sBAAsB,KAAK,MAAM,CAAE,UAAS,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,MAAM,yBAAyB;;AAE3G,MAAI,KAAK,MAAM;GACb,MAAM,SAAS,EAAE,MAAM,KAAK;AAC5B,OAAI,CAAC,UAAU,OAAO,SAAS,QAAS,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,KAAK,uBAAuB;GACzG,MAAM,SAAS,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,UAAU,EAAE,GAAG,EAAE;AAC1F,QAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC,EAAE;AAC5D,QAAI,CAAC,OAAO,OAAQ,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,KAAK,kBAAkB,QAAQ;AACxF,QAAI,CAAC,sBAAsB,KAAK,MAAM,CAAE,UAAS,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,KAAK,MAAM,KAAK,MAAM,yBAAyB;;AAE3H,OAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,SAAS,CAAC,KAAK,KAAM,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,KAAK,gDAAgD;;AAEtI,MAAI,KAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC,KAAK,KAAM,UAAS,KAAK,GAAG,GAAG,6BAA6B;EAC5F,MAAM,QAAQ,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC,EAAE,GAAI,KAAK,OAAO,CAAC,KAAK,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC,CAAE,CAAC;AACtH,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAE,MAAM,CAAE,KAAI,IAAI,YAAY,CAAC,MAAM,IAAI,KAAK,CAAE,UAAS,KAAK,GAAG,GAAG,kBAAkB,EAAE,GAAG,GAAG,KAAK,gBAAgB;;AAE9J,UAAS,KAAK,GAAG,iBAAiB,OAAO,WAAW,CAAC;AACrD,QAAO;;AAGT,SAAS,iBAAiB,OAAqB,YAAiD;CAC9F,MAAM,WAAqB,EAAE;CAC7B,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,QAAQ,MAAM,YAAY,EAAE,EAAE;EACvC,MAAM,KAAK,GAAG,MAAM,QAAQ,WAAW,KAAK;AAC5C,MAAI,CAAC,qCAAqC,KAAK,KAAK,GAAG,CAAE,UAAS,KAAK,GAAG,GAAG,+BAA+B;AAC5G,MAAI,KAAK,IAAI,KAAK,GAAG,CAAE,UAAS,KAAK,GAAG,GAAG,gBAAgB;AAC3D,OAAK,IAAI,KAAK,GAAG;EACjB,MAAM,IAAI,WAAW,IAAI,KAAK,UAAU;AACxC,MAAI,CAAC,GAAG;AAAE,YAAS,KAAK,GAAG,GAAG,cAAc,KAAK,UAAU,wBAAwB;AAAE;;AACrF,OAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC,CAC5D,KAAI,CAAC,EAAE,SAAS,MAAO,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,uBAAuB,OAAO;WACzE,CAAC,EAAE,SAAS,MAAO,QAAQ,SAAS,MAAM,CAAE,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,iBAAiB,QAAQ;AAErH,MAAI,CAAC,OAAO,KAAK,KAAK,MAAM,CAAC,OAAQ,UAAS,KAAK,GAAG,GAAG,YAAY;AACrE,OAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,KAAK,MAAM,EAAE;AACrD,OAAI,CAAC,gBAAgB,KAAK,KAAK,CAAE,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,uBAAuB;AAE1F,QAAK,MAAM,WAAW,CAAC,KAAK,MAAM,CAAC,MAAM,CAAE,KAAI,CAAC,iBAAiB,MAAM,SAAS,QAAQ,IAAI,CAAC,iBAAiB,WAAW,QAAQ,CAAE,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,WAAW,QAAQ,UAAU,MAAM,QAAQ,4BAA4B;AAC5O,OAAI,KAAK,QAAQ,KAAA,KAAa,KAAK,QAAQ,KAAA,KAAa,KAAK,MAAM,KAAK,IAAK,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,YAAY;;AAE7H,OAAK,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAE,KAAI,SAAS,SAAS,CAAC,iBAAiB,MAAM,SAAS,KAAK,CAAE,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,YAAY,MAAM,QAAQ,iBAAiB;AAC9L,MAAI,KAAK,MAAM,WAAW,aAAa,KAAK,SAAS,SAAU,UAAS,KAAK,GAAG,GAAG,qCAAqC;AACxH,MAAI,KAAK,SAAS,YAAY,KAAK,MAAM,WAAW,UAAW,UAAS,KAAK,GAAG,GAAG,yCAAyC;AAC5H,OAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,KAAK,MAAM,CAAE,KAAI,KAAK,UAAU,WAAW,KAAK,MAAM,WAAW,UAAW,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,kDAAkD;EAC1M,MAAM,cAAc,OAAe,OAAe,MAA0B,SAAkB,OAAO,UAAU;GAC7G,MAAM,QAAQ,kBAAkB,MAAM;AACtC,OAAI,CAAC,OAAO;AAAE,aAAS,KAAK,GAAG,GAAG,IAAI,MAAM,KAAK,MAAM,yBAAyB;AAAE;;AAClF,OAAI,CAAC,WAAW,MAAM,OAAQ,UAAS,KAAK,GAAG,GAAG,IAAI,MAAM,mCAAmC,KAAK,KAAK,sBAAsB;AAC/H,QAAK,MAAM,QAAQ,OAAO;IACxB,MAAM,MAAM,KAAK,MAAM;AACvB,QAAI,CAAC,IAAK,UAAS,KAAK,GAAG,GAAG,IAAI,MAAM,yBAAyB,OAAO;cAC9D,SAAS,YAAY,SAAS,WAAW,IAAI,QAAQ,EAAG,UAAS,KAAK,GAAG,GAAG,IAAI,MAAM,MAAM,KAAK,YAAY,KAAK,0CAA0C;aAC7J,QAAQ,IAAI,UAAU,QAAS,UAAS,KAAK,GAAG,GAAG,IAAI,MAAM,oBAAoB,KAAK,sDAAsD;;;AAGzJ,OAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,SAAS,EAAE,CAAC,EAAE;GAC5D,MAAM,MAAM,EAAE,MAAM;AACpB,OAAI,CAAC,IAAK,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,eAAe,OAAO;AAC7D,cAAW,OAAO,MAAM,KAAK,MAAM,KAAK;;AAE1C,MAAI,KAAK,MAAM;GACb,MAAM,SAAS,EAAE,MAAM,KAAK;AAC5B,OAAI,CAAC,UAAU,OAAO,SAAS,QAAS,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,KAAK,uBAAuB;AACzG,OAAI,CAAC,KAAK,KAAM,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,KAAK,aAAa;YAC3D,KAAK,SAAS,YAAY,CAAC,KAAK,MAAM,6BAA6B,KAAK,KAAK,KAAK,GAAG,MAAM,IAAK,UAAS,KAAK,GAAG,GAAG,SAAS,KAAK,KAAK,+CAA+C;GAC/L,MAAM,SAAS,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,MAAM,UAAU,EAAE,GAAG,EAAE;AAC1F,QAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC,EAAE;AAC5D,QAAI,CAAC,OAAO,OAAQ,UAAS,KAAK,GAAG,GAAG,IAAI,EAAE,GAAG,GAAG,KAAK,KAAK,kBAAkB,QAAQ;AACxF,eAAW,OAAO,GAAG,KAAK,KAAK,KAAK,SAAS,OAAO,QAAQ,MAAM,KAAK,SAAS,UAAU,KAAK;;aAExF,KAAK,QAAQ,KAAK,KAAM,UAAS,KAAK,GAAG,GAAG,0BAA0B;EACjF,MAAM,QAAQ,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC,EAAE,GAAI,KAAK,OAAO,CAAC,KAAK,KAAK,GAAG,EAAE,CAAE,CAAC;AAC5F,OAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,EAAE,MAAM,CAAE,KAAI,IAAI,YAAY,CAAC,MAAM,IAAI,KAAK,CAAE,UAAS,KAAK,GAAG,GAAG,kBAAkB,EAAE,GAAG,GAAG,KAAK,gBAAgB;;AAE9J,QAAO;;;AAIT,SAAgB,gBAAgB,OAAqB,SAA+B;CAClF,MAAM,UAAU,IAAI,IAAI,CAAC,GAAG,MAAM,MAAM,KAAI,MAAK,EAAE,MAAM,EAAE,IAAI,MAAM,YAAY,EAAE,EAAE,SAAQ,MAAK,OAAO,OAAO,EAAE,MAAM,CAAC,SAAQ,MAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CAC1J,MAAM,UAAU,QAAQ,WAAW,SAAS,MAAoB,EAAE,QAAQ,MAAM,YAAY,EAAE,CAAC;AAC/F,QAAO,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,CAAC,QAAO,MAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,UAAU;;;AAItE,SAAgB,SAAS,OAAqB,SAAgC;AAC5E,QAAO,MAAM,MACV,QAAO,MAAK,EAAE,UAAU,WAAW,EAAE,MAAM,MAAM,IAAI,CAAC,OAAO,QAAQ,CACrE,UAAU,GAAG,MAAM,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,SAAS,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,SAAS,IAAI,CAAC,CAAC;;;AAW9G,SAAgB,QAAQ,MAAmB,WAAqC,EAAE,EAA2B;AAC3G,QAAO;EAAE,GAAG,SAAS,KAAK;EAAO,GAAG,KAAK;EAAO;;;AAIlD,SAAgB,YAAY,MAAmB,MAAmB,UAA8C;CAC9G,MAAM,CAAC,MAAM,aAAa,KAAK,MAAM,MAAM,IAAI;AAC/C,KAAI,SAAS,KAAK,KAAM,QAAO;CAC/B,MAAM,QAAQ,QAAQ,MAAM,SAAS;AAErC,KAAI,aAAa,CAAC;EAAC,MAAM;EAAM,MAAM;EAAM,MAAM;EAAS,MAAM;EAAU,CAAC,SAAS,UAAU,CAAE,QAAO;AACvG,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,MAAM,QAAQ,EAAE,CAAC,CAAE,KAAI,MAAM,SAAS,MAAO,QAAO;AACnG,KAAI,KAAK,MAAM,SAAS,CAAC,OAAO,MAAM,aAAa,MAAM,WAAW,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,KAAK,KAAK,MAAM,CAAE,QAAO;AACvH,QAAO;;;;;;AAOT,SAAgB,aAAa,OAAsB,OAAqB,OAAO,KAA+D;AAC5I,QAAO,MAAM,SAAS,MAAM,MAAM;EAChC,MAAM,KAAK,GAAG,KAAK,GAAG;EACtB,MAAM,OAAO,SAAS,OAAO,KAAK,KAAK,CAAC,MAAK,MAAK,YAAY,GAAG,MAAM,MAAM,SAAS,CAAC;AACvF,SAAO,OAAO,CAAC;GAAE,MAAM;GAAI;GAAM;GAAM,CAAC,GAAG,aAAa,KAAK,YAAY,EAAE,EAAE,OAAO,GAAG;GACvF;;;;AClZJ,MAAM,eAAe,KAAK,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EAAE,KAAK;;AAGxE,MAAa,qBAAqB,KAAK,cAAc,aAAa;;AAGlE,eAAsB,YAAY,SAA4C;AAC5E,QAAO,KAAK,MAAM,MAAM,SAAS,KAAK,cAAc,WAAW,GAAG,QAAQ,OAAO,EAAE,OAAO,CAAC;;;AAI7F,eAAsB,cAAmC;AACvD,QAAO,KAAK,MAAM,MAAM,SAAS,KAAK,cAAc,eAAe,EAAE,OAAO,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/catalog.ts","../src/copy.ts","../src/mapping.ts","../src/index.ts"],"sourcesContent":["// The kit catalog: what each component is, what it takes, how it varies and\n// which WordPress builder elements it stands in for. Machine-readable, so the\n// migration writer chooses components by querying it instead of reading\n// source, and the builder mapping tables (mapping/*.json) are checked against\n// it.\n//\n// Props are described with Contentrain's own `FieldDef`, so a model field and\n// the prop it feeds are compared type to type.\n\nimport type { FieldDef } from '@contentrain/types'\nimport { fieldDepth, sectionFieldName } from '@contentrain/types'\n\nexport const CATALOG_FORMAT = 'astro-kit-catalog@1'\n\n/** The WordPress builders whose elements a component is fed from. */\nexport type KitBuilder = 'gutenberg' | 'elementor' | 'divi' | 'classic'\nexport const KIT_BUILDERS: readonly KitBuilder[] = ['gutenberg', 'elementor', 'divi', 'classic']\n\n/** Element-name prefix per builder, as `facts.json` names elements (`core/cover`, `elementor/heading`, `divi/et_pb_blurb`). */\nexport const BUILDER_PREFIX: Record<KitBuilder, string> = {\n gutenberg: 'core/',\n elementor: 'elementor/',\n divi: 'divi/',\n classic: 'classic/',\n}\n\n/**\n * Whether an element name belongs to a builder. Gutenberg blocks are namespaced by their plugin\n * (`core/cover`, `yoast-seo/breadcrumbs`, `uagb/container`), so any `<ns>/<name>` that is not another\n * builder's is a Gutenberg block.\n */\nexport function isBuilderElement(builder: KitBuilder, name: string): boolean {\n if (builder !== 'gutenberg') return name.startsWith(BUILDER_PREFIX[builder])\n return /^[a-z0-9-]+\\/[a-z0-9-]+(:[\\w-]+)?$/.test(name) && !KIT_BUILDERS.some(b => b !== 'gutenberg' && name.startsWith(BUILDER_PREFIX[b]))\n}\n\nexport type KitCategory = 'chrome' | 'section' | 'content' | 'primitive'\n\n/** Client JavaScript a component ships: none, a few lines of dependency-free script (`vanilla`), Embla (carousel), Zag.js (accessible widget) or the Studio runtime. */\nexport type KitJs = 'none' | 'vanilla' | 'embla' | 'zag' | 'studio'\n\nexport type KitProp = FieldDef & {\n description: string\n /**\n * `false`: a setting the plan or writer passes (heading level, a label from `ui:`, an anchor id), not page\n * content. A section's page-singleton field holds only the other props, its content props.\n */\n content?: false\n}\n\n/**\n * A content prop's name: camelCase, a capital only to start a word (`imageAlt`, not `imageURL`), so it\n * turns into exactly one Contentrain field name.\n */\nexport const CONTENT_PROP_NAME = /^[a-z][a-z0-9]*(?:[A-Z][a-z0-9]+)*$/\n\n/**\n * The page-singleton field a content prop is stored in (DECISIONS §7b): the prop name in snake_case, as\n * Contentrain field names are (`ctaLabel` → `cta_label`). The view passes each prop from its field.\n */\nexport const contentFieldName: (prop: string) => string = sectionFieldName\n\n/** The props a section's page-singleton field holds: all but the settings. */\nexport function contentProps(component: KitComponentMeta): Record<string, KitProp> {\n return Object.fromEntries(Object.entries(component.props).filter(([, prop]) => prop.content !== false))\n}\n\n/** Fields under a field, by dotted path (`items[].imageAlt`). */\nfunction fieldsByPath(fields: Record<string, FieldDef>, prefix = ''): Array<[string, FieldDef]> {\n const out: Array<[string, FieldDef]> = []\n for (const [name, field] of Object.entries(fields)) {\n out.push([prefix + name, field], ...fieldsByPath(field.fields ?? {}, `${prefix}${name}.`))\n if (typeof field.items === 'object') out.push(...fieldsByPath(field.items.fields ?? {}, `${prefix}${name}[].`))\n }\n return out\n}\n\n/** A content prop path as its page-singleton field path: every name in it through `contentFieldName`. */\nexport function contentFieldPath(path: string): string {\n return path.replace(/[A-Za-z0-9]+/g, contentFieldName)\n}\n\nexport interface KitVariant {\n options: string[]\n default: string\n description: string\n}\n\n/** One component as written in `components/<id>/meta.json`. */\nexport interface KitComponentMeta {\n id: string\n name: string\n description: string\n category: KitCategory\n /** Kit components this one renders. */\n uses: string[]\n /** Files it imports from `components/_shared/`. */\n shared: string[]\n variants: Record<string, KitVariant>\n props: Record<string, KitProp>\n /** Named slots → what goes in them. `default` is the unnamed slot. */\n slots: Record<string, string>\n js: KitJs\n /** npm packages the site needs for this component, name → range. */\n dependencies: Record<string, string>\n /** Builder elements this component replaces, by builder — what the mapping tables map from. */\n sources: Partial<Record<KitBuilder, string[]>>\n /** How it meets its accessibility pattern. */\n a11y: string\n /**\n * Sections only: the section's shape in a few words and the signals that show it in a source page, a\n * closed-set label for the classifier and the migration architect (`image beside heading + text`).\n */\n pattern?: { summary: string, signals: string[] }\n /**\n * Sections only, written by the catalog build: each content prop path (`slides[].ctaLabel`) → the\n * page-singleton field path that holds it (`slides[].cta_label`).\n */\n contentFields?: Record<string, string>\n}\n\n/** A catalog entry: the meta plus the files that make the component. */\nexport interface KitComponent extends KitComponentMeta {\n /** Paths relative to `components/<id>/`. */\n files: string[]\n}\n\nexport interface KitCatalog {\n format: typeof CATALOG_FORMAT\n /** Design tokens (Tailwind @theme names) the components read; the site must define them. */\n tokens: string[]\n /** npm packages every kit component needs. */\n dependencies: Record<string, string>\n components: KitComponent[]\n}\n\n/** Problems with a catalog, one line each; empty when it is sound. */\nexport function validateCatalog(catalog: KitCatalog): string[] {\n const problems: string[] = []\n const ids = new Set(catalog.components.map(c => c.id))\n for (const c of catalog.components) {\n const at = `component ${c.id}`\n if (!/^[a-z][a-z0-9-]*$/.test(c.id)) problems.push(`${at}: id must be kebab-case`)\n if (!c.files.length) problems.push(`${at}: no files`)\n for (const used of c.uses) if (!ids.has(used)) problems.push(`${at}: uses unknown component \"${used}\"`)\n for (const [axis, variant] of Object.entries(c.variants)) {\n if (!variant.options.includes(variant.default)) problems.push(`${at}: variant ${axis} default \"${variant.default}\" is not an option`)\n }\n for (const [name, prop] of Object.entries(c.props)) {\n if (!prop.description) problems.push(`${at}: prop ${name} has no description`)\n if (prop.type === 'select' && !prop.options?.length) problems.push(`${at}: select prop ${name} has no options`)\n }\n if (c.category === 'section') {\n // A section is stored as one object field of its page singleton: each content prop needs one field\n // name there, and that field must stay within two object levels.\n const content = contentProps(c)\n const paths = fieldsByPath(content)\n for (const [path, field] of paths) {\n if (!CONTENT_PROP_NAME.test(path.split(/\\.|\\[\\]\\./).at(-1)!)) problems.push(`${at}: content prop ${path} must be camelCase with one capital per word (or content: false)`)\n // Studio shows both to editors, and the plan reads them as the field's label and help text.\n if (!field.label) problems.push(`${at}: content prop ${path} has no label`)\n if (!field.description) problems.push(`${at}: content prop ${path} has no description`)\n }\n if (c.contentFields) {\n const expected = Object.fromEntries(paths.map(([path]) => [path, contentFieldPath(path)]))\n if (JSON.stringify(c.contentFields) !== JSON.stringify(expected)) problems.push(`${at}: contentFields is stale — rebuild the catalog`)\n }\n for (const [name, prop] of Object.entries(content)) {\n if (1 + fieldDepth(prop) > 2) problems.push(`${at}: content prop ${name} nests objects deeper than a page singleton allows`)\n }\n }\n for (const [builder, names] of Object.entries(c.sources) as Array<[KitBuilder, string[]]>) {\n const prefix = BUILDER_PREFIX[builder]\n for (const name of names) if (!isBuilderElement(builder, name)) problems.push(`${at}: source \"${name}\" is not a ${builder} element (${prefix}…)`)\n }\n }\n const seen = new Set<string>()\n for (const c of catalog.components) {\n if (seen.has(c.id)) problems.push(`component ${c.id}: listed twice`)\n seen.add(c.id)\n }\n return problems\n}\n\n/** Components that replace a builder element, e.g. `core/cover` → hero. */\nexport function componentsForSource(catalog: KitCatalog, element: string): KitComponent[] {\n return catalog.components.filter(c => Object.values(c.sources).some(names => names?.includes(element)))\n}\n","// Copying components into a site — the shadcn model: the site owns the\n// source, there is no runtime dependency on this package. A component is\n// copied with every kit component it renders and every shared file it\n// imports, under `src/components/kit/`, keeping the relative layout its\n// imports expect.\n\nimport { copyFile, mkdir } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport type { KitCatalog } from './catalog.js'\n\n/** Where kit files land in a site, relative to the site root. */\nexport const KIT_DIR = 'src/components/kit'\n\nexport interface CopyPlan {\n /** Components copied, the requested ones and everything they render, sorted. */\n components: string[]\n /** Site-relative destination → path relative to the kit's `components/` directory. */\n files: Record<string, string>\n /** npm packages the site needs, name → range. */\n dependencies: Record<string, string>\n}\n\nexport function planCopy(catalog: KitCatalog, ids: readonly string[]): CopyPlan {\n const byId = new Map(catalog.components.map(c => [c.id, c]))\n const wanted = new Set<string>()\n const visit = (id: string) => {\n if (wanted.has(id)) return\n const component = byId.get(id)\n if (!component) throw new Error(`astro-kit has no component \"${id}\". Known: ${[...byId.keys()].join(', ')}.`)\n wanted.add(id)\n for (const used of component.uses) visit(used)\n }\n for (const id of ids) visit(id)\n\n const files: Record<string, string> = {}\n const dependencies: Record<string, string> = { ...catalog.dependencies }\n for (const id of [...wanted].toSorted()) {\n const component = byId.get(id)!\n for (const file of component.files) files[`${KIT_DIR}/${id}/${file}`] = `${id}/${file}`\n for (const file of component.shared) files[`${KIT_DIR}/_shared/${file}`] = `_shared/${file}`\n Object.assign(dependencies, component.dependencies)\n }\n return { components: [...wanted].toSorted(), files, dependencies }\n}\n\n/** Carry out a plan: `kitRoot` is the kit's `components/` directory, `siteRoot` the site. */\nexport async function copyComponents(plan: CopyPlan, kitRoot: string, siteRoot: string): Promise<void> {\n await Promise.all(Object.entries(plan.files).map(async ([dest, source]) => {\n const target = join(siteRoot, dest)\n await mkdir(dirname(target), { recursive: true })\n await copyFile(join(kitRoot, source), target)\n }))\n}\n","// Builder mapping tables: which kit component a WordPress builder element\n// becomes, and where each of its props comes from. One versioned table per\n// builder (`mapping/<builder>.json`), written once and applied\n// deterministically to every site — the migration model is asked only about\n// elements no rule covers (Migrate's `unmapped_element` decision).\n//\n// A prop's source is one expression from a small closed set. The first six are\n// the project plan's values (`@contentrain/types` `PlanValue`) and bind\n// content; the rest read the builder element itself or the page it is on:\n//\n// field:<name> · media:<field> · ref:<field>.<field> · href:self|<field> · term:<field> · ui:<key> · const:<value>\n// site:<field> a field of the `site` singleton (`site:title`, `site:logo`)\n// menu:primary|footer the menu the starter shows in that area\n// page:<value> what the route knows: `page:base`, `page:current`, `page:total`, `page:breadcrumb`\n// attr:<name> a builder attribute (block attribute, Elementor setting, Divi shortcode attribute)\n// dom:<selector> text of the first match inside the element (empty selector: the element)\n// dom:<selector>@<attr> an attribute of it (`dom:a@href`)\n// img:<selector> an image as the kit's `ImageInput` (src, alt, width, height)\n// img:<selector>@src|@alt one part of that image, for a list item's flat `image` + `imageAlt` fields\n// link:<selector> a link as `{ label, href }`\n// html:<selector> inner markup, kept as Markdown (rich text)\n// class:<cls>=<a>|<b> <a> when the element, or an ancestor inside the matched element, has class\n// <cls> (`*` matches any run of characters); <b> otherwise. An empty branch\n// reads nothing and the prop keeps its default. `class:is-style-outline=ghost|primary`\n// is WordPress's outline button as the kit's ghost action.\n//\n// Section rules (`sections`) classify a whole page section by the leaves it holds and fill the component's\n// props from them: the same expressions, read from a named slot's leaf (`@title attr:title`).\n\nimport type { KitBuilder, KitCatalog, KitComponent } from './catalog.js'\nimport { isBuilderElement, KIT_BUILDERS } from './catalog.js'\n\nexport const MAPPING_FORMAT = 'astro-kit-mapping@1'\n\nexport const MAPPING_VALUE_PATTERN = /^(?:field:[\\w-]+|media:[\\w-]+|ref:[\\w-]+\\.[\\w-]+|href:(?:self|[\\w-]+)|term:[\\w-]+|ui:[\\w.-]+|const:(?:true|false|-?\\d+(?:\\.\\d+)?|[a-z][a-z0-9_-]{0,31})|site:[\\w-]+|menu:(?:primary|footer)|page:(?:base|current|total|breadcrumb)|attr:[\\w.-]+|class:[\\w*-]+=(?:[a-z][\\w-]*)?\\|(?:[a-z][\\w-]*)?|(?:dom|img|link|html):[^@]*(?:@[\\w-]+)?)$/\n\nexport interface MappingRule {\n /** Builder element, as the fact pack names it; a `:qualifier` narrows it (`core/template-part:header`). */\n match: string\n /** Extra conditions on the element. */\n when?: { attr?: Record<string, string | number | boolean>, class?: string }\n /** Kit component id. */\n component: string\n variant?: Record<string, string>\n /** Content the element lists rather than holds: one component per entry of the collection (`collection:posts`). */\n bind?: `collection:${string}`\n /** Consecutive sibling matches form one component (a row of Elementor icon boxes is one card grid). */\n group?: 'siblings'\n props?: Record<string, string>\n /** Array prop filled from repeated parts of the element (`each`) or the grouped siblings / bound entries. */\n into?: string\n /** Selector of the repeated parts inside the element, for `into`. */\n each?: string\n /** Props of one repeated part / sibling / entry, with sources relative to it. */\n item?: Record<string, string>\n}\n\nexport interface MappingTable {\n format: typeof MAPPING_FORMAT\n builder: KitBuilder\n /** Bumped on any rule change: plans record the version they applied. */\n version: string\n /** What an element no rule covers becomes when no decision is made: rich text. */\n fallback: 'prose'\n /**\n * Attribute values the builder leaves out of its data while they are at their default, per element:\n * Elementor saves no `video_type` for a YouTube video. `when.attr` and `attr:` read through them.\n */\n defaults?: Record<string, Record<string, string | number | boolean>>\n rules: MappingRule[]\n /**\n * Section rules: what a whole section of a page (an Elementor container, a Gutenberg group or columns,\n * a Divi section — facts `sections[]`) becomes, tried top to bottom before any element rule. The first\n * that matches wins; a section none matches falls through to the element `rules` inside it.\n */\n sections?: SectionRule[]\n}\n\n/**\n * A named group of a section's leaves: every leaf named `match` (and carrying `attr`) up to `max` of them.\n * `attr` values may list alternatives with `|` (`{ header_size: 'h1|h2' }`).\n */\nexport interface SectionSlot {\n match: string | string[]\n attr?: Record<string, string | number | boolean>\n /** At least this many leaves (default 0). */\n min?: number\n /** At most this many (default unbounded). */\n max?: number\n /** The leaf is a figure (`1,200`, `2018`, `$29`, `01`): its facts say so. `true` requires it, `false` rules it out. */\n numeric?: boolean\n /** The leaf is a step's ordinal (`1`, `01`, `Step 2` — at most two digits): its facts say so. A year or a count is a figure, not an ordinal. */\n ordinal?: boolean\n /** The image is logo-sized (small as displayed): its facts say so. Photos and banners are not. */\n small?: boolean\n /** The image is a portrait: a square-ish photo at least 200px across (a team member's face). Logos and banners are not. */\n portrait?: boolean\n /** The leaf's text is one short line — a name, a role, a label — not a description: its facts say so. */\n short?: boolean\n /**\n * `intro`: the slot holds the leaves above the repeated columns (a section's heading and lead line), not the\n * columns' own. Only with `when.repeat: 'columns'`; every other slot of such a rule reads inside a column.\n */\n scope?: 'intro'\n}\n\n/**\n * One section pattern. Values are the table's expressions, prefixed `@<slot> ` to read a slot's leaf\n * (`@title attr:title`); `a || b` takes the first non-empty (builder data first, rendered markup as fallback).\n * A slot of several leaves joins their text into a markdown prop; any other prop reads its first leaf.\n * A value without a slot reads the section's own root (a cover's background image, a container's setting).\n */\nexport interface SectionRule {\n /** Stable id (`hero.split`, `card-grid.icon-box`): plans record `<builder>:section:<id>`; JEW chooses among them. */\n id: string\n component: string\n variant?: Record<string, string>\n when?: {\n /** Where on the page: `first` is the page's first section, `last` its last. */\n position?: 'first' | 'last' | 'any'\n /** Column count(s) the section must have. */\n columns?: number | number[]\n /** Every leaf must fall into a slot (default true); false lets unclaimed leaves be. */\n only?: boolean\n /**\n * `columns`: each column must match the slots on its own (a row of team members, price plans); the leaves above\n * the row (`SectionMeta.intro`) go to the slots with `scope: 'intro'`.\n */\n repeat?: 'columns'\n /** The section's root element(s): `core/cover`, `core/media-text` (a loose run of blocks is `run`). */\n root?: string | string[]\n /**\n * Two slots in the order the source writes them: where both hold a leaf (in each column, with `repeat`), the first\n * leaf of the one must come before the first of the other. `['figure', 'label']` is a figure written above its\n * label, so a rule can pick the variant the source's reading order needs (G-text) and leave the other order to the\n * next rule.\n */\n order?: [string, string]\n }\n /**\n * Named leaf groups. Each leaf, in document order, goes to the first declared slot that matches it and\n * still has room, so declare a specific slot (an `attr` filter) before a general one on the same element.\n */\n slots: Record<string, SectionSlot>\n props?: Record<string, string>\n /**\n * Array prop filled once per `each`: a slot's leaves (`@card`), the parts a selector finds inside them\n * (`@list figure.wp-block-image`, `@faq .elementor-accordion-item`: a gallery's images, an accordion's\n * items), or the columns (`column`, with `repeat: 'columns'`).\n */\n into?: string\n each?: string\n /** One array item: relative to the leaf (`each: '@slot'`) or to the column, where `@<slot>` is that column's slot. */\n item?: Record<string, string>\n}\n\n/** A section leaf as the fact pack gives it: a builder element with its `blocks:` path. */\nexport interface SectionLeaf extends MappingNode {\n path: string\n /** Facts' flag: the leaf's text is a figure (a number, an amount, a step number) — not the text itself. */\n numeric?: boolean\n /** Facts' flag: the leaf's text is an ordinal — one or two digits, nothing else. */\n ordinal?: boolean\n /** Facts' flag: the image is logo-sized as displayed. */\n small?: boolean\n /** Facts' flag: the image is a square-ish photo, at least 200px across. */\n portrait?: boolean\n /** Facts' flag: the leaf's text is one short line (at most 40 characters, no line break). */\n short?: boolean\n}\n\n/** Where a section sits (facts `index`/`count`) and what it is (`root`: facts `root`). */\nexport interface SectionMeta {\n index: number\n count: number\n root?: string | undefined\n /** The leaves above a row of columns, in the same wrapper (`Who we are` over its people): see `when.repeat`. */\n intro?: SectionLeaf[] | undefined\n}\n\n/** Leaf paths per slot; with `repeat: 'columns'`, also per column. */\nexport interface SectionMatch {\n slots: Record<string, string[]>\n columns?: Record<string, string[]>[]\n}\n\n/** The id a plan records for a section rule. */\nexport function sectionRuleId(builder: KitBuilder, rule: Pick<SectionRule, 'id'>): string {\n return `${builder}:section:${rule.id}`\n}\n\nconst SECTION_LAYOUT_LEAVES = new Set(['elementor/spacer', 'elementor/divider', 'core/spacer', 'core/separator', 'divi/et_pb_divider'])\n\nfunction slotFits(slot: SectionSlot, leaf: SectionLeaf, defaults?: MappingTable['defaults']): boolean {\n if (![slot.match].flat().includes(leaf.name)) return false\n // A flag the facts do not set reads as \"no\": a rule that asks for one never fires on facts that predate it.\n if (slot.numeric !== undefined && slot.numeric !== (leaf.numeric === true)) return false\n if (slot.ordinal !== undefined && slot.ordinal !== (leaf.ordinal === true)) return false\n if (slot.small !== undefined && slot.small !== (leaf.small === true)) return false\n if (slot.portrait !== undefined && slot.portrait !== (leaf.portrait === true)) return false\n if (slot.short !== undefined && slot.short !== (leaf.short === true)) return false\n const attrs = attrsOf(leaf, defaults)\n return Object.entries(slot.attr ?? {}).every(([key, want]) => String(want).split('|').includes(String(attrs[key])))\n}\n\n/**\n * Assign leaves to slots in document order, each to the first declared slot with room; null when the rule does not fit.\n * `scope` picks the slots in play: a repeated row's columns read the column slots, the leaves above it the intro slots;\n * any other section reads them all.\n */\nfunction claimLeaves(rule: SectionRule, leaves: SectionLeaf[], defaults?: MappingTable['defaults'], scope: 'all' | 'column' | 'intro' = 'all'): Record<string, string[]> | null {\n const slots = Object.entries(rule.slots).filter(([, def]) => scope === 'all' || (def.scope === 'intro') === (scope === 'intro'))\n const claimed: Record<string, string[]> = Object.fromEntries(slots.map(([name]) => [name, []]))\n for (const leaf of leaves) {\n if (SECTION_LAYOUT_LEAVES.has(leaf.name)) continue\n const slot = slots.find(([name, def]) => claimed[name]!.length < (def.max ?? Infinity) && slotFits(def, leaf, defaults))\n if (slot) claimed[slot[0]]!.push(leaf.path)\n else if (rule.when?.only !== false) return null\n }\n for (const [name, def] of slots) if (claimed[name]!.length < (def.min ?? 0)) return null\n const [first, then] = rule.when?.order ?? []\n const a = first ? claimed[first]?.[0] : undefined\n const b = then ? claimed[then]?.[0] : undefined\n if (a && b) {\n const at = (path: string) => leaves.findIndex(l => l.path === path)\n if (at(a) > at(b)) return null\n }\n return claimed\n}\n\n/**\n * Whether a section rule fits a section, and which leaves fill which slot. `columns` are the section's\n * columns left to right, each its leaves in document order (layout containers already opened).\n */\nexport function matchSection(rule: SectionRule, columns: SectionLeaf[][], meta: SectionMeta, defaults?: MappingTable['defaults']): SectionMatch | null {\n const when = rule.when ?? {}\n if (when.root !== undefined && !(meta.root !== undefined && [when.root].flat().includes(meta.root))) return null\n if (when.position === 'first' && meta.index !== 0) return null\n if (when.position === 'last' && meta.index !== meta.count - 1) return null\n if (when.columns !== undefined && ![when.columns].flat().includes(columns.length)) return null\n if (when.repeat === 'columns') {\n if (columns.length < 2) return null\n const intro = claimLeaves(rule, meta.intro ?? [], defaults, 'intro')\n if (!intro) return null\n const per = columns.map(leaves => claimLeaves(rule, leaves, defaults, 'column'))\n if (per.some(c => !c)) return null\n const slots: Record<string, string[]> = { ...intro }\n for (const [name, def] of Object.entries(rule.slots)) if (def.scope !== 'intro') slots[name] = per.flatMap(c => c![name]!)\n return { slots, columns: per as Record<string, string[]>[] }\n }\n // Without a repeat the leaves above the row are simply the section's first leaves, as before the facts split them off.\n const slots = claimLeaves(rule, [...(meta.intro ?? []), ...columns.flat()], defaults)\n return slots && { slots }\n}\n\n/** The first section rule of a table that fits, with its match. */\nexport function classifySection(table: MappingTable, columns: SectionLeaf[][], meta: SectionMeta): { rule: SectionRule, match: SectionMatch } | null {\n for (const rule of table.sections ?? []) {\n const match = matchSection(rule, columns, meta, table.defaults)\n if (match) return { rule, match }\n }\n return null\n}\n\n/** A section value: alternatives joined by ` || `, each an optional `@<slot> ` then a mapping value. Returns the slots it reads, or null when malformed. */\nexport function sectionValueSlots(value: string): string[] | null {\n const slots: string[] = []\n for (const alternative of value.split(' || ')) {\n const m = /^(?:@([a-z][\\w-]*) )?(.+)$/.exec(alternative)\n if (!m || !MAPPING_VALUE_PATTERN.test(m[2]!)) return null\n if (m[1]) slots.push(m[1])\n }\n return slots\n}\n\n/** Problems with a mapping table against the catalog, one line each; empty when it is sound. */\nexport function validateMapping(table: MappingTable, catalog: KitCatalog): string[] {\n const problems: string[] = []\n if (table.format !== MAPPING_FORMAT) problems.push(`format is not ${MAPPING_FORMAT}`)\n if (!KIT_BUILDERS.includes(table.builder)) problems.push(`unknown builder ${table.builder}`)\n if (!/^\\d+$/.test(table.version)) problems.push('version is not an integer string')\n for (const element of Object.keys(table.defaults ?? {})) if (!isBuilderElement(table.builder, element)) problems.push(`defaults ${element}: not a ${table.builder} element`)\n const components = new Map(catalog.components.map(c => [c.id, c]))\n const seen = new Set<string>()\n for (const rule of table.rules) {\n const at = `${table.builder} ${rule.match}${rule.when ? ' (when)' : ''}`\n const key = `${rule.match}|${JSON.stringify(rule.when ?? {})}`\n if (seen.has(key)) problems.push(`${at}: matched twice`)\n seen.add(key)\n if (!isBuilderElement(table.builder, rule.match)) problems.push(`${at}: not a ${table.builder} element`)\n const c = components.get(rule.component)\n if (!c) { problems.push(`${at}: component ${rule.component} is not in the catalog`); continue }\n for (const [axis, value] of Object.entries(rule.variant ?? {})) {\n // A variant is one option, or a `class:` choice between options read from the element.\n const choice = /^class:[\\w*-]+=([a-z][\\w-]*)?\\|([a-z][\\w-]*)?$/.exec(value)\n const options = choice ? [choice[1], choice[2]].filter((option): option is string => option !== undefined) : [value]\n if (!c.variants[axis]) problems.push(`${at}: ${c.id} has no variant axis ${axis}`)\n else for (const missing of options.filter(option => !c.variants[axis]!.options.includes(option))) problems.push(`${at}: ${c.id}.${axis} has no option ${missing}`)\n }\n for (const [prop, value] of Object.entries({ ...rule.props, ...(rule.into ? {} : rule.item) })) {\n if (!c.props[prop]) problems.push(`${at}: ${c.id} has no prop ${prop}`)\n if (!MAPPING_VALUE_PATTERN.test(value)) problems.push(`${at}: ${prop} = ${value} is not a mapping value`)\n }\n if (rule.into) {\n const target = c.props[rule.into]\n if (!target || target.type !== 'array') problems.push(`${at}: ${c.id}.${rule.into} is not an array prop`)\n const fields = target && typeof target.items === 'object' ? target.items.fields ?? {} : {}\n for (const [field, value] of Object.entries(rule.item ?? {})) {\n if (!fields[field]) problems.push(`${at}: ${c.id}.${rule.into}[] has no field ${field}`)\n if (!MAPPING_VALUE_PATTERN.test(value)) problems.push(`${at}: ${rule.into}[].${field} = ${value} is not a mapping value`)\n }\n if (!rule.each && !rule.group && !rule.bind) problems.push(`${at}: into ${rule.into} needs each, group or bind to say what repeats`)\n }\n if (rule.item && !rule.into && !rule.bind) problems.push(`${at}: item without into or bind`)\n const bound = new Set([...Object.keys(rule.props ?? {}), ...(rule.into ? [rule.into] : Object.keys(rule.item ?? {}))])\n for (const [prop, def] of Object.entries(c.props)) if (def.required && !bound.has(prop)) problems.push(`${at}: required prop ${c.id}.${prop} has no source`)\n }\n problems.push(...validateSections(table, components))\n return problems\n}\n\nfunction validateSections(table: MappingTable, components: Map<string, KitComponent>): string[] {\n const problems: string[] = []\n const seen = new Set<string>()\n for (const rule of table.sections ?? []) {\n const at = `${table.builder} section ${rule.id}`\n if (!/^[a-z][a-z0-9-]*(?:\\.[a-z0-9-]+)*$/.test(rule.id)) problems.push(`${at}: id is not dotted kebab-case`)\n if (seen.has(rule.id)) problems.push(`${at}: listed twice`)\n seen.add(rule.id)\n const c = components.get(rule.component)\n if (!c) { problems.push(`${at}: component ${rule.component} is not in the catalog`); continue }\n for (const [axis, value] of Object.entries(rule.variant ?? {})) {\n if (!c.variants[axis]) problems.push(`${at}: ${c.id} has no variant axis ${axis}`)\n else if (!c.variants[axis]!.options.includes(value)) problems.push(`${at}: ${c.id}.${axis} has no option ${value}`)\n }\n if (!Object.keys(rule.slots).length) problems.push(`${at}: no slots`)\n for (const [name, slot] of Object.entries(rule.slots)) {\n if (!/^[a-z][\\w-]*$/.test(name)) problems.push(`${at}: slot ${name} is not an identifier`)\n // A form or shortcode plugin (`classic/contact-form-7`) sits inside any builder's section, as the plan reads it from a shortcode.\n for (const element of [slot.match].flat()) if (!isBuilderElement(table.builder, element) && !isBuilderElement('classic', element)) problems.push(`${at}: slot ${name} matches ${element}, not a ${table.builder} or classic plugin element`)\n if (slot.min !== undefined && slot.max !== undefined && slot.min > slot.max) problems.push(`${at}: slot ${name} min > max`)\n }\n for (const root of [rule.when?.root ?? []].flat()) if (root !== 'run' && !isBuilderElement(table.builder, root)) problems.push(`${at}: root ${root} is not a ${table.builder} element or run`)\n if (rule.when?.repeat === 'columns' && rule.each !== 'column') problems.push(`${at}: repeat columns needs each: column`)\n if (rule.each === 'column' && rule.when?.repeat !== 'columns') problems.push(`${at}: each column needs when.repeat columns`)\n for (const [name, slot] of Object.entries(rule.slots)) if (slot.scope === 'intro' && rule.when?.repeat !== 'columns') problems.push(`${at}: slot ${name} is scope intro, which needs when.repeat columns`)\n for (const name of rule.when?.order ?? []) if (!rule.slots[name]) problems.push(`${at}: when.order names ${name}, which is not a slot`)\n if (rule.when?.order && (rule.slots[rule.when.order[0]]?.scope === 'intro') !== (rule.slots[rule.when.order[1]]?.scope === 'intro')) problems.push(`${at}: when.order compares an intro slot with a column slot`)\n const readsSlots = (value: string, where: string, type: string | undefined, slotted: boolean, item = false) => {\n const slots = sectionValueSlots(value)\n if (!slots) { problems.push(`${at}: ${where} = ${value} is not a section value`); return }\n if (!slotted && slots.length) problems.push(`${at}: ${where} reads a slot, but items of each ${rule.each} read their own leaf`)\n for (const slot of slots) {\n const def = rule.slots[slot]\n if (!def) problems.push(`${at}: ${where} reads undeclared slot ${slot}`)\n else if ((type === 'string' || type === 'text') && def.max !== 1) problems.push(`${at}: ${where} is ${type} but slot ${slot} may hold several leaves (max must be 1)`)\n else if (item && def.scope === 'intro') problems.push(`${at}: ${where} reads intro slot ${slot}, but the items of each column read their own column`)\n }\n }\n for (const [prop, value] of Object.entries(rule.props ?? {})) {\n const def = c.props[prop]\n if (!def) problems.push(`${at}: ${c.id} has no prop ${prop}`)\n readsSlots(value, prop, def?.type, true)\n }\n if (rule.into) {\n const target = c.props[rule.into]\n if (!target || target.type !== 'array') problems.push(`${at}: ${c.id}.${rule.into} is not an array prop`)\n if (!rule.each) problems.push(`${at}: into ${rule.into} needs each`)\n else if (rule.each !== 'column' && !rule.slots[/^@([a-z][\\w-]*)(?: \\S.*)?$/.exec(rule.each)?.[1] ?? '']) problems.push(`${at}: each ${rule.each} is not @<declared slot> [selector] or column`)\n const fields = target && typeof target.items === 'object' ? target.items.fields ?? {} : {}\n for (const [field, value] of Object.entries(rule.item ?? {})) {\n if (!fields[field]) problems.push(`${at}: ${c.id}.${rule.into}[] has no field ${field}`)\n readsSlots(value, `${rule.into}[].${field}`, fields[field]?.type, rule.each === 'column', true)\n }\n } else if (rule.item || rule.each) problems.push(`${at}: each/item without into`)\n const bound = new Set([...Object.keys(rule.props ?? {}), ...(rule.into ? [rule.into] : [])])\n for (const [prop, def] of Object.entries(c.props)) if (def.required && !bound.has(prop)) problems.push(`${at}: required prop ${c.id}.${prop} has no source`)\n }\n return problems\n}\n\n/** Catalog sources of a builder that no rule of its table matches, as an element rule or a section slot. */\nexport function unmappedSources(table: MappingTable, catalog: KitCatalog): string[] {\n const matched = new Set([...table.rules.map(r => r.match), ...(table.sections ?? []).flatMap(r => Object.values(r.slots).flatMap(s => [s.match].flat()))])\n const sources = catalog.components.flatMap((c: KitComponent) => c.sources[table.builder] ?? [])\n return [...new Set(sources)].filter(s => !matched.has(s)).toSorted()\n}\n\n/** Rules for an element, most specific (with `when` / qualifier) first. */\nexport function rulesFor(table: MappingTable, element: string): MappingRule[] {\n return table.rules\n .filter(r => r.match === element || r.match.split(':')[0] === element)\n .toSorted((a, b) => Number(!!b.when || b.match.includes(':')) - Number(!!a.when || a.match.includes(':')))\n}\n\n/** A builder element as the fact pack gives it (`FactBlock`): name, attributes, children. */\nexport interface MappingNode {\n name: string\n attrs?: Record<string, unknown>\n children?: MappingNode[]\n}\n\n/** An element's attributes with the builder's unsaved defaults filled in. */\nexport function attrsOf(node: MappingNode, defaults: MappingTable['defaults'] = {}): Record<string, unknown> {\n return { ...defaults[node.name], ...node.attrs }\n}\n\n/** Whether a rule's `match` (with an optional `:qualifier`) and `when.attr` fit an element. */\nexport function ruleMatches(rule: MappingRule, node: MappingNode, defaults?: MappingTable['defaults']): boolean {\n const [name, qualifier] = rule.match.split(':')\n if (name !== node.name) return false\n const attrs = attrsOf(node, defaults)\n // A qualifier names the element's role: a template part's area or slug, or a sub-part the fact pack marks.\n if (qualifier && ![attrs.area, attrs.slug, attrs.tagName, attrs.qualifier].includes(qualifier)) return false\n for (const [key, value] of Object.entries(rule.when?.attr ?? {})) if (attrs[key] !== value) return false\n if (rule.when?.class && !String(attrs.className ?? attrs.classes ?? '').split(/\\s+/).includes(rule.when.class)) return false\n return true\n}\n\n/**\n * Apply a table to a tree: the outermost matching element owns its whole subtree, and nothing inside\n * it is matched again — a header template part holding the site title and logo is one header, not three.\n */\nexport function claimMatches(nodes: MappingNode[], table: MappingTable, path = '0'): { path: string, node: MappingNode, rule: MappingRule }[] {\n return nodes.flatMap((node, i) => {\n const at = `${path}.${i}`\n const rule = rulesFor(table, node.name).find(r => ruleMatches(r, node, table.defaults))\n return rule ? [{ path: at, node, rule }] : claimMatches(node.children ?? [], table, at)\n })\n}\n","import { readFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { KitBuilder, KitCatalog } from './catalog.js'\nimport type { MappingTable } from './mapping.js'\n\nexport * from './catalog.js'\nexport * from './copy.js'\nexport * from './mapping.js'\n\nconst PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..')\n\n/** The kit's `components/` directory — the source `copyComponents` copies from. */\nexport const KIT_COMPONENTS_DIR = join(PACKAGE_ROOT, 'components')\n\n/** A builder's mapping table (`mapping/<builder>.json`). */\nexport async function loadMapping(builder: KitBuilder): Promise<MappingTable> {\n return JSON.parse(await readFile(join(PACKAGE_ROOT, 'mapping', `${builder}.json`), 'utf8')) as MappingTable\n}\n\n/** The published catalog (`catalog.json`). */\nexport async function loadCatalog(): Promise<KitCatalog> {\n return JSON.parse(await readFile(join(PACKAGE_ROOT, 'catalog.json'), 'utf8')) as KitCatalog\n}\n"],"mappings":"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"}
|
package/mapping/divi.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "astro-kit-mapping@1",
|
|
3
3
|
"builder": "divi",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6",
|
|
5
5
|
"fallback": "prose",
|
|
6
6
|
"rules": [
|
|
7
7
|
{
|
|
@@ -413,6 +413,9 @@
|
|
|
413
413
|
{
|
|
414
414
|
"id": "stats.counter",
|
|
415
415
|
"component": "stats",
|
|
416
|
+
"variant": {
|
|
417
|
+
"order": "value-first"
|
|
418
|
+
},
|
|
416
419
|
"slots": {
|
|
417
420
|
"intro": {
|
|
418
421
|
"match": "divi/et_pb_text",
|
package/mapping/elementor.json
CHANGED
package/mapping/gutenberg.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "astro-kit-mapping@1",
|
|
3
3
|
"builder": "gutenberg",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "7",
|
|
5
5
|
"fallback": "prose",
|
|
6
6
|
"rules": [
|
|
7
7
|
{
|
|
@@ -662,6 +662,9 @@
|
|
|
662
662
|
{
|
|
663
663
|
"id": "stats.columns",
|
|
664
664
|
"component": "stats",
|
|
665
|
+
"variant": {
|
|
666
|
+
"order": "value-first"
|
|
667
|
+
},
|
|
665
668
|
"when": {
|
|
666
669
|
"columns": [
|
|
667
670
|
2,
|
|
@@ -674,6 +677,64 @@
|
|
|
674
677
|
"root": [
|
|
675
678
|
"core/columns",
|
|
676
679
|
"core/group"
|
|
680
|
+
],
|
|
681
|
+
"order": [
|
|
682
|
+
"figure",
|
|
683
|
+
"label"
|
|
684
|
+
]
|
|
685
|
+
},
|
|
686
|
+
"slots": {
|
|
687
|
+
"heading": {
|
|
688
|
+
"match": "core/heading",
|
|
689
|
+
"max": 1,
|
|
690
|
+
"scope": "intro"
|
|
691
|
+
},
|
|
692
|
+
"lead": {
|
|
693
|
+
"match": "core/paragraph",
|
|
694
|
+
"max": 1,
|
|
695
|
+
"scope": "intro"
|
|
696
|
+
},
|
|
697
|
+
"figure": {
|
|
698
|
+
"match": "core/heading",
|
|
699
|
+
"min": 1,
|
|
700
|
+
"max": 1,
|
|
701
|
+
"numeric": true
|
|
702
|
+
},
|
|
703
|
+
"label": {
|
|
704
|
+
"match": "core/paragraph",
|
|
705
|
+
"max": 1
|
|
706
|
+
}
|
|
707
|
+
},
|
|
708
|
+
"props": {
|
|
709
|
+
"heading": "@heading dom:",
|
|
710
|
+
"intro": "@lead dom:"
|
|
711
|
+
},
|
|
712
|
+
"into": "items",
|
|
713
|
+
"each": "column",
|
|
714
|
+
"item": {
|
|
715
|
+
"value": "@figure dom:",
|
|
716
|
+
"label": "@label dom:"
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
"id": "stats.columns-label-first",
|
|
721
|
+
"component": "stats",
|
|
722
|
+
"when": {
|
|
723
|
+
"columns": [
|
|
724
|
+
2,
|
|
725
|
+
3,
|
|
726
|
+
4,
|
|
727
|
+
5,
|
|
728
|
+
6
|
|
729
|
+
],
|
|
730
|
+
"repeat": "columns",
|
|
731
|
+
"root": [
|
|
732
|
+
"core/columns",
|
|
733
|
+
"core/group"
|
|
734
|
+
],
|
|
735
|
+
"order": [
|
|
736
|
+
"label",
|
|
737
|
+
"figure"
|
|
677
738
|
]
|
|
678
739
|
},
|
|
679
740
|
"slots": {
|
|
@@ -829,6 +890,7 @@
|
|
|
829
890
|
"into": "items",
|
|
830
891
|
"each": "column",
|
|
831
892
|
"item": {
|
|
893
|
+
"number": "@number dom:",
|
|
832
894
|
"title": "@title dom:",
|
|
833
895
|
"text": "@text dom:"
|
|
834
896
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentrain/astro-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Copy-in Astro components for Contentrain sites (shadcn model): typed props, tailwind-variants, zero JavaScript by default — with a machine-readable catalog",
|
|
6
6
|
"type": "module",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"mapping"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@contentrain/types": "1.
|
|
45
|
+
"@contentrain/types": "1.35.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.10.0",
|