craft/scripts/gen-sitesmith-catalog.mjs emits a compact JSON catalog (props with TS types/enums/defaults, token-aware colour props, animation + icon support, child rules, section recipes, templates, palettes) for the WHP panel prompt. src/sitesmith/catalog.drift.test.ts regenerates and compares to the committed whp file so drift fails. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
59 lines
2.8 KiB
TypeScript
59 lines
2.8 KiB
TypeScript
// Bundled by scripts/gen-sitesmith-catalog.mjs (esbuild, platform node) and run
|
|
// in Node. Collects everything that only exists at RUNTIME in the editor's real
|
|
// definitions: component craft defaults/rules, token vocabulary, palettes,
|
|
// section families and templates. The TypeScript prop TYPES come from the
|
|
// compiler API in the .mjs (types are erased at runtime).
|
|
import { componentResolver } from '../../src/components/resolver';
|
|
import { TOKEN_VARS, COLOR_TOKENS } from '../../src/utils/tokens';
|
|
import { PALETTES } from '../../src/constants/palettes';
|
|
import { BUILTIN_SECTIONS } from '../../src/sections/families';
|
|
import { SECTION_FAMILIES } from '../../src/sections/catalog';
|
|
import { allTemplates } from '../../src/templates/definitions';
|
|
import { CANVAS_TYPES, SHELL_INNER } from '../../src/utils/craft-tree';
|
|
import { DEFAULT_SITE_DESIGN } from '../../src/state/SiteDesignContext';
|
|
|
|
type Tpl = { type: string; props: Record<string, any>; children?: Tpl[] };
|
|
|
|
/** "Section[Heading,TextBlock,ButtonLink]": the structural skeleton of a tree. */
|
|
function recipe(n: Tpl): string {
|
|
const kids = (n.children ?? []).map(recipe);
|
|
// collapse runs of identical siblings: Container*3
|
|
const out: string[] = [];
|
|
for (const k of kids) {
|
|
const last = out[out.length - 1];
|
|
const m = last && last.match(/^(.*)\*(\d+)$/);
|
|
if (last === k) out[out.length - 1] = `${k}*2`;
|
|
else if (m && m[1] === k) out[out.length - 1] = `${k}*${Number(m[2]) + 1}`;
|
|
else out.push(k);
|
|
}
|
|
return out.length ? `${n.type}[${out.join(',')}]` : n.type;
|
|
}
|
|
|
|
export function collect() {
|
|
const components: Record<string, any> = {};
|
|
for (const [name, comp] of Object.entries(componentResolver) as [string, any][]) {
|
|
components[name] = {
|
|
defaults: comp.craft?.props ?? {},
|
|
displayName: comp.craft?.displayName ?? name,
|
|
isCanvas: CANVAS_TYPES.has(name),
|
|
shellInner: SHELL_INNER[name] ?? null,
|
|
canMoveInFalse: false,
|
|
};
|
|
}
|
|
return {
|
|
components,
|
|
tokenVars: TOKEN_VARS.map(([v, k]) => ({ var: v, designKey: k, default: (DEFAULT_SITE_DESIGN as any)[k] })),
|
|
colorTokens: COLOR_TOKENS.map((t) => t.key),
|
|
palettes: PALETTES.map((p) => ({ id: p.id, name: p.name, ...p.design, fonts: p.fonts ?? null })),
|
|
families: SECTION_FAMILIES.filter((f) => f.id !== 'custom'),
|
|
sections: BUILTIN_SECTIONS.map((s) => ({ id: s.id, name: s.name, family: s.family, keywords: s.keywords, recipe: recipe(s.tree as Tpl) })),
|
|
templates: allTemplates.map((t) => ({
|
|
id: t.id, name: t.name, category: t.category, description: t.description, multiPage: t.isMultiPage,
|
|
design: t.design,
|
|
pages: t.pages.map((p) => ({ name: p.name, slug: p.slug, recipe: p.content.components.map((c) => recipe(c as Tpl)) })),
|
|
header: t.header.components.map((c) => recipe(c as Tpl)),
|
|
footer: t.footer.components.map((c) => recipe(c as Tpl)),
|
|
})),
|
|
};
|
|
}
|