@contentrain/astro-kit 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +4 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/mapping/elementor.json +177 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -159,6 +159,8 @@ interface SectionSlot {
|
|
|
159
159
|
ordinal?: boolean;
|
|
160
160
|
/** The image is logo-sized (small as displayed): its facts say so. Photos and banners are not. */
|
|
161
161
|
small?: boolean;
|
|
162
|
+
/** The image is a portrait: a square-ish photo at least 200px across (a team member's face). Logos and banners are not. */
|
|
163
|
+
portrait?: boolean;
|
|
162
164
|
/**
|
|
163
165
|
* `intro`: the slot holds the leaves above the repeated columns (a section's heading and lead line), not the
|
|
164
166
|
* columns' own. Only with `when.repeat: 'columns'`; every other slot of such a rule reads inside a column.
|
|
@@ -212,6 +214,8 @@ interface SectionLeaf extends MappingNode {
|
|
|
212
214
|
ordinal?: boolean;
|
|
213
215
|
/** Facts' flag: the image is logo-sized as displayed. */
|
|
214
216
|
small?: boolean;
|
|
217
|
+
/** Facts' flag: the image is a square-ish photo, at least 200px across. */
|
|
218
|
+
portrait?: boolean;
|
|
215
219
|
}
|
|
216
220
|
/** Where a section sits (facts `index`/`count`) and what it is (`root`: facts `root`). */
|
|
217
221
|
interface SectionMeta {
|
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
|
|
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
|
@@ -154,6 +154,7 @@ function slotFits(slot, leaf, defaults) {
|
|
|
154
154
|
if (slot.numeric !== void 0 && slot.numeric !== (leaf.numeric === true)) return false;
|
|
155
155
|
if (slot.ordinal !== void 0 && slot.ordinal !== (leaf.ordinal === true)) return false;
|
|
156
156
|
if (slot.small !== void 0 && slot.small !== (leaf.small === true)) return false;
|
|
157
|
+
if (slot.portrait !== void 0 && slot.portrait !== (leaf.portrait === true)) return false;
|
|
157
158
|
const attrs = attrsOf(leaf, defaults);
|
|
158
159
|
return Object.entries(slot.attr ?? {}).every(([key, want]) => String(want).split("|").includes(String(attrs[key])));
|
|
159
160
|
}
|
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 /**\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}\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 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":"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"}
|
|
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 /**\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}\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 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":"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"}
|
package/mapping/elementor.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"format": "astro-kit-mapping@1",
|
|
3
3
|
"builder": "elementor",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "8",
|
|
5
5
|
"fallback": "prose",
|
|
6
6
|
"defaults": {
|
|
7
7
|
"elementor/video": {
|
|
@@ -479,6 +479,182 @@
|
|
|
479
479
|
"message": "@alert attr:alert_title || @alert dom:.elementor-alert-title"
|
|
480
480
|
}
|
|
481
481
|
},
|
|
482
|
+
{
|
|
483
|
+
"id": "steps.columns",
|
|
484
|
+
"component": "steps",
|
|
485
|
+
"variant": {
|
|
486
|
+
"layout": "row",
|
|
487
|
+
"style": "numbered"
|
|
488
|
+
},
|
|
489
|
+
"when": {
|
|
490
|
+
"columns": [
|
|
491
|
+
2,
|
|
492
|
+
3,
|
|
493
|
+
4,
|
|
494
|
+
5,
|
|
495
|
+
6
|
|
496
|
+
],
|
|
497
|
+
"repeat": "columns",
|
|
498
|
+
"root": "elementor/container"
|
|
499
|
+
},
|
|
500
|
+
"slots": {
|
|
501
|
+
"heading": {
|
|
502
|
+
"match": "elementor/heading",
|
|
503
|
+
"max": 1,
|
|
504
|
+
"scope": "intro"
|
|
505
|
+
},
|
|
506
|
+
"lead": {
|
|
507
|
+
"match": "elementor/text-editor",
|
|
508
|
+
"max": 1,
|
|
509
|
+
"scope": "intro"
|
|
510
|
+
},
|
|
511
|
+
"number": {
|
|
512
|
+
"match": "elementor/heading",
|
|
513
|
+
"min": 1,
|
|
514
|
+
"max": 1,
|
|
515
|
+
"ordinal": true
|
|
516
|
+
},
|
|
517
|
+
"title": {
|
|
518
|
+
"match": "elementor/heading",
|
|
519
|
+
"min": 1,
|
|
520
|
+
"max": 1,
|
|
521
|
+
"numeric": false
|
|
522
|
+
},
|
|
523
|
+
"text": {
|
|
524
|
+
"match": "elementor/text-editor",
|
|
525
|
+
"min": 1,
|
|
526
|
+
"max": 1
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
"props": {
|
|
530
|
+
"heading": "@heading attr:title || @heading dom:",
|
|
531
|
+
"intro": "@lead dom:"
|
|
532
|
+
},
|
|
533
|
+
"into": "items",
|
|
534
|
+
"each": "column",
|
|
535
|
+
"item": {
|
|
536
|
+
"title": "@title attr:title || @title dom:",
|
|
537
|
+
"text": "@text dom:"
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
"id": "pricing.columns",
|
|
542
|
+
"component": "pricing",
|
|
543
|
+
"when": {
|
|
544
|
+
"columns": [
|
|
545
|
+
2,
|
|
546
|
+
3,
|
|
547
|
+
4
|
|
548
|
+
],
|
|
549
|
+
"repeat": "columns",
|
|
550
|
+
"root": "elementor/container"
|
|
551
|
+
},
|
|
552
|
+
"slots": {
|
|
553
|
+
"heading": {
|
|
554
|
+
"match": "elementor/heading",
|
|
555
|
+
"max": 1,
|
|
556
|
+
"scope": "intro"
|
|
557
|
+
},
|
|
558
|
+
"lead": {
|
|
559
|
+
"match": "elementor/text-editor",
|
|
560
|
+
"max": 1,
|
|
561
|
+
"scope": "intro"
|
|
562
|
+
},
|
|
563
|
+
"name": {
|
|
564
|
+
"match": "elementor/heading",
|
|
565
|
+
"min": 1,
|
|
566
|
+
"max": 1,
|
|
567
|
+
"numeric": false
|
|
568
|
+
},
|
|
569
|
+
"price": {
|
|
570
|
+
"match": "elementor/heading",
|
|
571
|
+
"min": 1,
|
|
572
|
+
"max": 1,
|
|
573
|
+
"numeric": true
|
|
574
|
+
},
|
|
575
|
+
"period": {
|
|
576
|
+
"match": "elementor/text-editor",
|
|
577
|
+
"max": 1
|
|
578
|
+
},
|
|
579
|
+
"features": {
|
|
580
|
+
"match": "elementor/icon-list",
|
|
581
|
+
"min": 1,
|
|
582
|
+
"max": 1
|
|
583
|
+
},
|
|
584
|
+
"button": {
|
|
585
|
+
"match": "elementor/button",
|
|
586
|
+
"max": 1
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
"props": {
|
|
590
|
+
"heading": "@heading attr:title || @heading dom:",
|
|
591
|
+
"intro": "@lead dom:"
|
|
592
|
+
},
|
|
593
|
+
"into": "plans",
|
|
594
|
+
"each": "column",
|
|
595
|
+
"item": {
|
|
596
|
+
"name": "@name attr:title || @name dom:",
|
|
597
|
+
"price": "@price attr:title || @price dom:",
|
|
598
|
+
"period": "@period dom:",
|
|
599
|
+
"features": "@features html:",
|
|
600
|
+
"ctaLabel": "@button attr:text || @button dom:.elementor-button-text",
|
|
601
|
+
"ctaHref": "@button attr:link.url || @button dom:a@href"
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
"id": "team.columns",
|
|
606
|
+
"component": "team",
|
|
607
|
+
"when": {
|
|
608
|
+
"columns": [
|
|
609
|
+
2,
|
|
610
|
+
3,
|
|
611
|
+
4
|
|
612
|
+
],
|
|
613
|
+
"repeat": "columns",
|
|
614
|
+
"root": "elementor/container"
|
|
615
|
+
},
|
|
616
|
+
"slots": {
|
|
617
|
+
"heading": {
|
|
618
|
+
"match": "elementor/heading",
|
|
619
|
+
"max": 1,
|
|
620
|
+
"scope": "intro"
|
|
621
|
+
},
|
|
622
|
+
"lead": {
|
|
623
|
+
"match": "elementor/text-editor",
|
|
624
|
+
"max": 1,
|
|
625
|
+
"scope": "intro"
|
|
626
|
+
},
|
|
627
|
+
"photo": {
|
|
628
|
+
"match": "elementor/image",
|
|
629
|
+
"min": 1,
|
|
630
|
+
"max": 1,
|
|
631
|
+
"portrait": true
|
|
632
|
+
},
|
|
633
|
+
"name": {
|
|
634
|
+
"match": "elementor/heading",
|
|
635
|
+
"min": 1,
|
|
636
|
+
"max": 1,
|
|
637
|
+
"numeric": false
|
|
638
|
+
},
|
|
639
|
+
"role": {
|
|
640
|
+
"match": "elementor/text-editor",
|
|
641
|
+
"min": 1,
|
|
642
|
+
"max": 1
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
"props": {
|
|
646
|
+
"heading": "@heading attr:title || @heading dom:",
|
|
647
|
+
"intro": "@lead dom:"
|
|
648
|
+
},
|
|
649
|
+
"into": "items",
|
|
650
|
+
"each": "column",
|
|
651
|
+
"item": {
|
|
652
|
+
"name": "@name attr:title || @name dom:",
|
|
653
|
+
"role": "@role dom:",
|
|
654
|
+
"image": "@photo attr:image.url || @photo img:img@src",
|
|
655
|
+
"imageAlt": "@photo img:img@alt"
|
|
656
|
+
}
|
|
657
|
+
},
|
|
482
658
|
{
|
|
483
659
|
"id": "split.image-text",
|
|
484
660
|
"component": "split",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentrain/astro-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.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.33.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.10.0",
|