@decantr/core 1.0.0-beta.1
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.ts +205 -0
- package/dist/index.js +472 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { EssenceFile, StructurePage } from '@decantr/essence-spec';
|
|
2
|
+
import { Pattern, ResolvedPreset, Recipe, ContentResolver } from '@decantr/registry';
|
|
3
|
+
|
|
4
|
+
type IRNodeType = 'app' | 'shell' | 'page' | 'pattern' | 'grid' | 'slot' | 'nav' | 'store';
|
|
5
|
+
interface IRSpatial {
|
|
6
|
+
gap: string;
|
|
7
|
+
padding?: string;
|
|
8
|
+
responsive?: {
|
|
9
|
+
breakpoint: string;
|
|
10
|
+
cols: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
type IRHookType = 'search' | 'filter' | 'selection' | 'sort';
|
|
14
|
+
interface IRWiringSignal {
|
|
15
|
+
name: string;
|
|
16
|
+
setter: string;
|
|
17
|
+
init: string;
|
|
18
|
+
hookType: IRHookType;
|
|
19
|
+
}
|
|
20
|
+
interface IRWiring {
|
|
21
|
+
signals: IRWiringSignal[];
|
|
22
|
+
props: Record<string, Record<string, string>>;
|
|
23
|
+
hooks: IRHookType[];
|
|
24
|
+
hookProps: Record<string, Record<string, string>>;
|
|
25
|
+
}
|
|
26
|
+
interface IRPatternMeta {
|
|
27
|
+
patternId: string;
|
|
28
|
+
preset: string;
|
|
29
|
+
alias: string;
|
|
30
|
+
layout: string;
|
|
31
|
+
contained: boolean;
|
|
32
|
+
standalone: boolean;
|
|
33
|
+
code: {
|
|
34
|
+
imports: string;
|
|
35
|
+
example: string;
|
|
36
|
+
} | null;
|
|
37
|
+
components: string[];
|
|
38
|
+
}
|
|
39
|
+
interface IRVisualEffect {
|
|
40
|
+
decorators: string[];
|
|
41
|
+
intensity: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
interface IRCardWrapping {
|
|
44
|
+
mode: 'always' | 'minimal' | 'none';
|
|
45
|
+
headerLabel: string;
|
|
46
|
+
background?: string;
|
|
47
|
+
}
|
|
48
|
+
interface IRNavItem {
|
|
49
|
+
href: string;
|
|
50
|
+
icon: string;
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
interface IRShellConfig {
|
|
54
|
+
type: string;
|
|
55
|
+
brand: string;
|
|
56
|
+
nav: IRNavItem[];
|
|
57
|
+
inset: boolean;
|
|
58
|
+
recipe: IRRecipeDecoration | null;
|
|
59
|
+
}
|
|
60
|
+
interface IRRecipeDecoration {
|
|
61
|
+
root: string;
|
|
62
|
+
nav: string;
|
|
63
|
+
header: string;
|
|
64
|
+
brand: string;
|
|
65
|
+
navLabel: string;
|
|
66
|
+
navStyle: string;
|
|
67
|
+
defaultNavState: string;
|
|
68
|
+
dimensions: {
|
|
69
|
+
navWidth?: string;
|
|
70
|
+
headerHeight?: string;
|
|
71
|
+
} | null;
|
|
72
|
+
}
|
|
73
|
+
interface IRTheme {
|
|
74
|
+
style: string;
|
|
75
|
+
mode: string;
|
|
76
|
+
shape: string | null;
|
|
77
|
+
recipe: string;
|
|
78
|
+
isAddon: boolean;
|
|
79
|
+
}
|
|
80
|
+
interface IRRoute {
|
|
81
|
+
path: string;
|
|
82
|
+
pageId: string;
|
|
83
|
+
}
|
|
84
|
+
interface IRNode {
|
|
85
|
+
type: IRNodeType;
|
|
86
|
+
id: string;
|
|
87
|
+
children: IRNode[];
|
|
88
|
+
spatial?: IRSpatial;
|
|
89
|
+
meta?: Record<string, unknown>;
|
|
90
|
+
}
|
|
91
|
+
interface IRAppNode extends IRNode {
|
|
92
|
+
type: 'app';
|
|
93
|
+
theme: IRTheme;
|
|
94
|
+
routes: IRRoute[];
|
|
95
|
+
routing: 'hash' | 'history';
|
|
96
|
+
shell: IRShellNode;
|
|
97
|
+
store: IRStoreNode;
|
|
98
|
+
features: string[];
|
|
99
|
+
}
|
|
100
|
+
interface IRShellNode extends IRNode {
|
|
101
|
+
type: 'shell';
|
|
102
|
+
config: IRShellConfig;
|
|
103
|
+
}
|
|
104
|
+
interface IRPageNode extends IRNode {
|
|
105
|
+
type: 'page';
|
|
106
|
+
pageId: string;
|
|
107
|
+
surface: string;
|
|
108
|
+
wiring: IRWiring | null;
|
|
109
|
+
}
|
|
110
|
+
interface IRPatternNode extends IRNode {
|
|
111
|
+
type: 'pattern';
|
|
112
|
+
pattern: IRPatternMeta;
|
|
113
|
+
card: IRCardWrapping | null;
|
|
114
|
+
visualEffects: IRVisualEffect | null;
|
|
115
|
+
wireProps: Record<string, string> | null;
|
|
116
|
+
}
|
|
117
|
+
interface IRBreakpointEntry {
|
|
118
|
+
at: string;
|
|
119
|
+
cols: number;
|
|
120
|
+
}
|
|
121
|
+
interface IRGridNode extends IRNode {
|
|
122
|
+
type: 'grid';
|
|
123
|
+
cols: number;
|
|
124
|
+
spans: Record<string, number> | null;
|
|
125
|
+
breakpoint: string | null;
|
|
126
|
+
breakpoints?: IRBreakpointEntry[] | null;
|
|
127
|
+
responsive?: 'viewport' | 'container' | null;
|
|
128
|
+
}
|
|
129
|
+
interface IRNavNode extends IRNode {
|
|
130
|
+
type: 'nav';
|
|
131
|
+
items: IRNavItem[];
|
|
132
|
+
}
|
|
133
|
+
interface IRStoreNode extends IRNode {
|
|
134
|
+
type: 'store';
|
|
135
|
+
pageSignals: {
|
|
136
|
+
name: string;
|
|
137
|
+
pascalName: string;
|
|
138
|
+
}[];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface PipelineOptions {
|
|
142
|
+
/** Path to content directory (patterns, archetypes, recipes) */
|
|
143
|
+
contentRoot: string;
|
|
144
|
+
/** Override paths for local content resolution */
|
|
145
|
+
overridePaths?: string[];
|
|
146
|
+
/** Only resolve specific page(s) */
|
|
147
|
+
pageFilter?: string;
|
|
148
|
+
}
|
|
149
|
+
interface PipelineResult {
|
|
150
|
+
/** The framework-agnostic intermediate representation */
|
|
151
|
+
ir: IRAppNode;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Run the Design Pipeline:
|
|
155
|
+
* 1. Validate Essence against schema + guard rules
|
|
156
|
+
* 2. Resolve all references (patterns, recipe, wiring) from registry
|
|
157
|
+
* 3. Build framework-agnostic IR tree
|
|
158
|
+
* 4. Return IR (no code generation — that's the consumer's job)
|
|
159
|
+
*/
|
|
160
|
+
declare function runPipeline(essence: EssenceFile, options: PipelineOptions): Promise<PipelineResult>;
|
|
161
|
+
|
|
162
|
+
interface ResolvedPatternEntry {
|
|
163
|
+
pattern: Pattern;
|
|
164
|
+
preset: ResolvedPreset;
|
|
165
|
+
}
|
|
166
|
+
/** Build IR tree for a single page from its resolved structure + patterns */
|
|
167
|
+
declare function buildPageIR(page: StructurePage, resolvedPatterns: Map<string, ResolvedPatternEntry>, wiring: IRWiring | null, recipe: Recipe | null, density: {
|
|
168
|
+
gap: string;
|
|
169
|
+
}): IRPageNode;
|
|
170
|
+
|
|
171
|
+
interface ResolvedPage {
|
|
172
|
+
page: StructurePage;
|
|
173
|
+
patterns: Map<string, {
|
|
174
|
+
pattern: Pattern;
|
|
175
|
+
preset: ResolvedPreset;
|
|
176
|
+
}>;
|
|
177
|
+
wiring: IRWiring | null;
|
|
178
|
+
}
|
|
179
|
+
interface ResolvedEssence {
|
|
180
|
+
essence: EssenceFile;
|
|
181
|
+
pages: ResolvedPage[];
|
|
182
|
+
recipe: Recipe | null;
|
|
183
|
+
density: {
|
|
184
|
+
gap: string;
|
|
185
|
+
level: string;
|
|
186
|
+
};
|
|
187
|
+
theme: IRTheme;
|
|
188
|
+
shell: IRShellConfig;
|
|
189
|
+
routes: IRRoute[];
|
|
190
|
+
features: string[];
|
|
191
|
+
}
|
|
192
|
+
declare function resolveVisualEffects(recipe: Recipe, pattern: Pattern, _slot?: string): IRVisualEffect | null;
|
|
193
|
+
/** Resolve all external references in an Essence file */
|
|
194
|
+
declare function resolveEssence(essence: EssenceFile, resolver: ContentResolver): Promise<ResolvedEssence>;
|
|
195
|
+
|
|
196
|
+
/** Depth-first walk of IR tree, calling visitor on each node */
|
|
197
|
+
declare function walkIR(node: IRNode, visitor: (node: IRNode, parent: IRNode | null) => void, parent?: IRNode | null): void;
|
|
198
|
+
/** Find all nodes of a specific type */
|
|
199
|
+
declare function findNodes<T extends IRNode>(root: IRNode, type: string): T[];
|
|
200
|
+
/** Count total patterns in an IR tree */
|
|
201
|
+
declare function countPatterns(root: IRNode): number;
|
|
202
|
+
/** Validate IR tree structure (no orphaned grids, patterns have meta, etc.) */
|
|
203
|
+
declare function validateIR(root: IRNode): string[];
|
|
204
|
+
|
|
205
|
+
export { type IRAppNode, type IRBreakpointEntry, type IRCardWrapping, type IRGridNode, type IRHookType, type IRNavItem, type IRNavNode, type IRNode, type IRNodeType, type IRPageNode, type IRPatternMeta, type IRPatternNode, type IRRecipeDecoration, type IRRoute, type IRShellConfig, type IRShellNode, type IRSpatial, type IRStoreNode, type IRTheme, type IRVisualEffect, type IRWiring, type IRWiringSignal, type PipelineOptions, type PipelineResult, type ResolvedEssence, type ResolvedPage, buildPageIR, countPatterns, findNodes, resolveEssence, resolveVisualEffects, runPipeline, validateIR, walkIR };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
// src/pipeline.ts
|
|
2
|
+
import { validateEssence } from "@decantr/essence-spec";
|
|
3
|
+
import { createResolver } from "@decantr/registry";
|
|
4
|
+
|
|
5
|
+
// src/resolve.ts
|
|
6
|
+
import { isSimple, isSectioned, computeDensity } from "@decantr/essence-spec";
|
|
7
|
+
import { resolvePatternPreset, detectWirings } from "@decantr/registry";
|
|
8
|
+
var NAV_ICONS = {
|
|
9
|
+
overview: "layout-dashboard",
|
|
10
|
+
dashboard: "layout-dashboard",
|
|
11
|
+
home: "home",
|
|
12
|
+
analytics: "bar-chart-3",
|
|
13
|
+
settings: "settings",
|
|
14
|
+
users: "users",
|
|
15
|
+
billing: "credit-card",
|
|
16
|
+
reports: "file-text",
|
|
17
|
+
catalog: "grid",
|
|
18
|
+
products: "package",
|
|
19
|
+
orders: "shopping-cart",
|
|
20
|
+
messages: "message-square",
|
|
21
|
+
notifications: "bell",
|
|
22
|
+
activity: "activity",
|
|
23
|
+
search: "search",
|
|
24
|
+
profile: "user",
|
|
25
|
+
team: "users",
|
|
26
|
+
integrations: "puzzle",
|
|
27
|
+
api: "code",
|
|
28
|
+
docs: "book-open",
|
|
29
|
+
help: "help-circle",
|
|
30
|
+
projects: "folder",
|
|
31
|
+
workflows: "git-branch",
|
|
32
|
+
monitoring: "monitor",
|
|
33
|
+
security: "shield",
|
|
34
|
+
storage: "database",
|
|
35
|
+
deployments: "rocket",
|
|
36
|
+
logs: "scroll-text"
|
|
37
|
+
};
|
|
38
|
+
var CORE_STYLES = /* @__PURE__ */ new Set(["auradecantism"]);
|
|
39
|
+
function isPatternRef(item) {
|
|
40
|
+
return typeof item === "object" && "pattern" in item;
|
|
41
|
+
}
|
|
42
|
+
function isColumnLayout(item) {
|
|
43
|
+
return typeof item === "object" && "cols" in item;
|
|
44
|
+
}
|
|
45
|
+
function extractLayoutRefs(layout) {
|
|
46
|
+
const refs = [];
|
|
47
|
+
for (const item of layout) {
|
|
48
|
+
if (typeof item === "string") {
|
|
49
|
+
refs.push({ id: item });
|
|
50
|
+
} else if (isPatternRef(item)) {
|
|
51
|
+
refs.push({ id: item.pattern, explicitPreset: item.preset, alias: item.as });
|
|
52
|
+
} else if (isColumnLayout(item)) {
|
|
53
|
+
for (const col of item.cols) {
|
|
54
|
+
refs.push({ id: col });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return refs;
|
|
59
|
+
}
|
|
60
|
+
function flattenLayoutForWiring(layout) {
|
|
61
|
+
const flat = [];
|
|
62
|
+
for (const item of layout) {
|
|
63
|
+
if (typeof item === "string") {
|
|
64
|
+
flat.push(item);
|
|
65
|
+
} else if (isPatternRef(item)) {
|
|
66
|
+
flat.push(item);
|
|
67
|
+
} else if (isColumnLayout(item)) {
|
|
68
|
+
for (const col of item.cols) {
|
|
69
|
+
flat.push(col);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return flat;
|
|
74
|
+
}
|
|
75
|
+
function routePath(pageId, index) {
|
|
76
|
+
if (index === 0) return "/";
|
|
77
|
+
if (pageId.endsWith("-detail")) {
|
|
78
|
+
return `/${pageId}/:id`;
|
|
79
|
+
}
|
|
80
|
+
return `/${pageId}`;
|
|
81
|
+
}
|
|
82
|
+
function pascalCase(str) {
|
|
83
|
+
return str.split(/[-_]/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
84
|
+
}
|
|
85
|
+
function capitalize(str) {
|
|
86
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
87
|
+
}
|
|
88
|
+
function buildNavItems(pages) {
|
|
89
|
+
return pages.map((page, i) => ({
|
|
90
|
+
href: routePath(page.id, i),
|
|
91
|
+
icon: NAV_ICONS[page.id] || "circle",
|
|
92
|
+
label: capitalize(page.id.replace(/-/g, " "))
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
function buildRecipeDecoration(recipe) {
|
|
96
|
+
const shell = recipe.shell;
|
|
97
|
+
const shellAny = shell;
|
|
98
|
+
return {
|
|
99
|
+
root: shell.root || "",
|
|
100
|
+
nav: shell.nav || "",
|
|
101
|
+
header: shell.header || "",
|
|
102
|
+
brand: shellAny["brand"] || "",
|
|
103
|
+
navLabel: shellAny["navLabel"] || "",
|
|
104
|
+
// AUTO: default nav style is 'pill' per Decantr framework convention
|
|
105
|
+
navStyle: shell.nav_style || "pill",
|
|
106
|
+
defaultNavState: shellAny["default_nav_state"] || "expanded",
|
|
107
|
+
dimensions: shell.dimensions || null
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function buildTheme(essence, isAddon) {
|
|
111
|
+
return {
|
|
112
|
+
style: essence.theme.style,
|
|
113
|
+
mode: essence.theme.mode,
|
|
114
|
+
shape: essence.theme.shape || null,
|
|
115
|
+
recipe: essence.theme.recipe,
|
|
116
|
+
isAddon
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function convertWiring(wiringResults) {
|
|
120
|
+
if (wiringResults.length === 0) return null;
|
|
121
|
+
const signals = [];
|
|
122
|
+
const props = {};
|
|
123
|
+
const hookProps = {};
|
|
124
|
+
const hookSet = /* @__PURE__ */ new Set();
|
|
125
|
+
for (const result of wiringResults) {
|
|
126
|
+
for (const signal of result.signals) {
|
|
127
|
+
if (!signals.some((s) => s.name === signal.name)) {
|
|
128
|
+
const setter = "set" + signal.name.charAt(0).toUpperCase() + signal.name.slice(1);
|
|
129
|
+
signals.push({
|
|
130
|
+
name: signal.name,
|
|
131
|
+
setter,
|
|
132
|
+
init: signal.init,
|
|
133
|
+
hookType: signal.hookType
|
|
134
|
+
});
|
|
135
|
+
hookSet.add(signal.hookType);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const [alias, aliasProps] of Object.entries(result.props)) {
|
|
139
|
+
props[alias] = { ...props[alias], ...aliasProps };
|
|
140
|
+
}
|
|
141
|
+
for (const [alias, aliasHookProps] of Object.entries(result.hookProps)) {
|
|
142
|
+
hookProps[alias] = { ...hookProps[alias], ...aliasHookProps };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { signals, props, hooks: [...hookSet], hookProps };
|
|
146
|
+
}
|
|
147
|
+
function resolveVisualEffects(recipe, pattern, _slot) {
|
|
148
|
+
if (!recipe.visual_effects?.enabled) return null;
|
|
149
|
+
const typeMapping = recipe.visual_effects.type_mapping || {};
|
|
150
|
+
const componentFallback = recipe.visual_effects.component_fallback || {};
|
|
151
|
+
const intensity = recipe.visual_effects.intensity || "medium";
|
|
152
|
+
const intensityValues = recipe.visual_effects.intensity_values || {};
|
|
153
|
+
let decorators = [];
|
|
154
|
+
for (const comp of pattern.components || []) {
|
|
155
|
+
const effectType = componentFallback[comp];
|
|
156
|
+
if (effectType && typeMapping[effectType]) {
|
|
157
|
+
decorators = [...decorators, ...typeMapping[effectType]];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (decorators.length === 0) return null;
|
|
161
|
+
decorators = [...new Set(decorators)];
|
|
162
|
+
return {
|
|
163
|
+
decorators,
|
|
164
|
+
intensity: intensityValues[intensity] || {}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function resolveEssence(essence, resolver) {
|
|
168
|
+
let simpleEssence;
|
|
169
|
+
if (isSimple(essence)) {
|
|
170
|
+
simpleEssence = essence;
|
|
171
|
+
} else if (isSectioned(essence)) {
|
|
172
|
+
const sectioned = essence;
|
|
173
|
+
const firstSection = sectioned.sections[0];
|
|
174
|
+
simpleEssence = {
|
|
175
|
+
version: sectioned.version,
|
|
176
|
+
archetype: firstSection.archetype,
|
|
177
|
+
theme: firstSection.theme,
|
|
178
|
+
personality: sectioned.personality,
|
|
179
|
+
platform: sectioned.platform,
|
|
180
|
+
structure: firstSection.structure,
|
|
181
|
+
features: firstSection.features || [],
|
|
182
|
+
density: sectioned.density,
|
|
183
|
+
guard: sectioned.guard,
|
|
184
|
+
target: sectioned.target
|
|
185
|
+
};
|
|
186
|
+
} else {
|
|
187
|
+
throw new Error("Invalid essence format");
|
|
188
|
+
}
|
|
189
|
+
let recipe = null;
|
|
190
|
+
const recipeResult = await resolver.resolve("recipe", simpleEssence.theme.recipe);
|
|
191
|
+
if (recipeResult) {
|
|
192
|
+
recipe = recipeResult.item;
|
|
193
|
+
}
|
|
194
|
+
const recipeSpatial = recipe?.spatial_hints;
|
|
195
|
+
const density = computeDensity(simpleEssence.personality, recipeSpatial ? {
|
|
196
|
+
density_bias: recipeSpatial.density_bias,
|
|
197
|
+
content_gap_shift: recipeSpatial.content_gap_shift
|
|
198
|
+
} : void 0);
|
|
199
|
+
const isAddon = !CORE_STYLES.has(simpleEssence.theme.style);
|
|
200
|
+
const theme = buildTheme(simpleEssence, isAddon);
|
|
201
|
+
const resolvedPages = [];
|
|
202
|
+
for (const page of simpleEssence.structure) {
|
|
203
|
+
const refs = extractLayoutRefs(page.layout);
|
|
204
|
+
const patterns = /* @__PURE__ */ new Map();
|
|
205
|
+
for (const ref of refs) {
|
|
206
|
+
const patternResult = await resolver.resolve("pattern", ref.id);
|
|
207
|
+
if (patternResult) {
|
|
208
|
+
const preset = resolvePatternPreset(
|
|
209
|
+
patternResult.item,
|
|
210
|
+
ref.explicitPreset,
|
|
211
|
+
recipe?.pattern_preferences?.default_presets
|
|
212
|
+
);
|
|
213
|
+
const key = ref.alias || ref.id;
|
|
214
|
+
patterns.set(key, { pattern: patternResult.item, preset });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const wiringResults = detectWirings(flattenLayoutForWiring(page.layout));
|
|
218
|
+
const wiring = convertWiring(wiringResults);
|
|
219
|
+
resolvedPages.push({ page, patterns, wiring });
|
|
220
|
+
}
|
|
221
|
+
const shellType = simpleEssence.structure[0]?.shell || "sidebar-main";
|
|
222
|
+
const brand = pascalCase(simpleEssence.archetype);
|
|
223
|
+
const nav = buildNavItems(simpleEssence.structure);
|
|
224
|
+
const recipeDecoration = recipe ? buildRecipeDecoration(recipe) : null;
|
|
225
|
+
const shell = {
|
|
226
|
+
type: shellType,
|
|
227
|
+
brand,
|
|
228
|
+
nav,
|
|
229
|
+
inset: false,
|
|
230
|
+
recipe: recipeDecoration
|
|
231
|
+
};
|
|
232
|
+
const routes = simpleEssence.structure.map((page, i) => ({
|
|
233
|
+
path: routePath(page.id, i),
|
|
234
|
+
pageId: page.id
|
|
235
|
+
}));
|
|
236
|
+
return {
|
|
237
|
+
essence,
|
|
238
|
+
pages: resolvedPages,
|
|
239
|
+
recipe,
|
|
240
|
+
density: { gap: density.content_gap, level: density.level },
|
|
241
|
+
theme,
|
|
242
|
+
shell,
|
|
243
|
+
routes,
|
|
244
|
+
features: simpleEssence.features ?? []
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/ir.ts
|
|
249
|
+
function isPatternRef2(item) {
|
|
250
|
+
return typeof item === "object" && "pattern" in item;
|
|
251
|
+
}
|
|
252
|
+
function isColumnLayout2(item) {
|
|
253
|
+
return typeof item === "object" && "cols" in item;
|
|
254
|
+
}
|
|
255
|
+
function shouldWrapInCard(pattern, preset, recipe) {
|
|
256
|
+
const layout = preset.layout.layout;
|
|
257
|
+
if (layout === "hero" || layout === "row") return false;
|
|
258
|
+
if (pattern.contained === false) return false;
|
|
259
|
+
const cardWrapping = recipe?.spatial_hints?.card_wrapping;
|
|
260
|
+
if (cardWrapping === "none") return false;
|
|
261
|
+
if (cardWrapping === "minimal") {
|
|
262
|
+
return Object.keys(pattern.presets).length > 0;
|
|
263
|
+
}
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
function buildCardWrapping(pattern, recipe) {
|
|
267
|
+
const mode = recipe?.spatial_hints?.card_wrapping || "always";
|
|
268
|
+
const overrides = recipe?.pattern_overrides?.[pattern.id];
|
|
269
|
+
return {
|
|
270
|
+
mode,
|
|
271
|
+
headerLabel: pattern.name,
|
|
272
|
+
background: overrides?.background?.join(" ")
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function buildPatternNode(patternId, alias, resolved, wiring, recipe, density) {
|
|
276
|
+
const pattern = resolved?.pattern;
|
|
277
|
+
const preset = resolved?.preset;
|
|
278
|
+
const layout = preset?.layout.layout || "column";
|
|
279
|
+
const isStandalone = layout === "hero" || layout === "row";
|
|
280
|
+
const contained = pattern && preset ? shouldWrapInCard(pattern, preset, recipe) : false;
|
|
281
|
+
const components = pattern?.components || [];
|
|
282
|
+
const patternMeta = {
|
|
283
|
+
patternId,
|
|
284
|
+
preset: preset?.preset || "default",
|
|
285
|
+
alias,
|
|
286
|
+
layout,
|
|
287
|
+
contained,
|
|
288
|
+
standalone: isStandalone,
|
|
289
|
+
code: preset?.code ? { imports: preset.code.imports, example: preset.code.example } : null,
|
|
290
|
+
components
|
|
291
|
+
};
|
|
292
|
+
const card = contained && !isStandalone && pattern ? buildCardWrapping(pattern, recipe) : null;
|
|
293
|
+
const wireProps = wiring?.props[alias] || wiring?.props[patternId] || null;
|
|
294
|
+
return {
|
|
295
|
+
type: "pattern",
|
|
296
|
+
id: alias,
|
|
297
|
+
children: [],
|
|
298
|
+
pattern: patternMeta,
|
|
299
|
+
card,
|
|
300
|
+
visualEffects: null,
|
|
301
|
+
wireProps,
|
|
302
|
+
spatial: { gap: density.gap }
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function buildPageIR(page, resolvedPatterns, wiring, recipe, density) {
|
|
306
|
+
const children = [];
|
|
307
|
+
for (const item of page.layout) {
|
|
308
|
+
if (typeof item === "string") {
|
|
309
|
+
const resolved = resolvedPatterns.get(item);
|
|
310
|
+
children.push(buildPatternNode(item, item, resolved, wiring, recipe, density));
|
|
311
|
+
} else if (isPatternRef2(item)) {
|
|
312
|
+
const alias = item.as || item.pattern;
|
|
313
|
+
const resolved = resolvedPatterns.get(alias) || resolvedPatterns.get(item.pattern);
|
|
314
|
+
children.push(buildPatternNode(item.pattern, alias, resolved, wiring, recipe, density));
|
|
315
|
+
} else if (isColumnLayout2(item)) {
|
|
316
|
+
const cols = item.cols;
|
|
317
|
+
const breakpoint = item.at || null;
|
|
318
|
+
const spans = item.span || null;
|
|
319
|
+
let normalizedSpans = null;
|
|
320
|
+
if (spans) {
|
|
321
|
+
normalizedSpans = {};
|
|
322
|
+
for (const col of cols) {
|
|
323
|
+
normalizedSpans[col] = spans[col] || 1;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const gridChildren = [];
|
|
327
|
+
for (const col of cols) {
|
|
328
|
+
const resolved = resolvedPatterns.get(col);
|
|
329
|
+
gridChildren.push(buildPatternNode(col, col, resolved, wiring, recipe, density));
|
|
330
|
+
}
|
|
331
|
+
const totalCols = normalizedSpans ? Object.values(normalizedSpans).reduce((a, b) => a + b, 0) : cols.length;
|
|
332
|
+
const breakpoints = item.breakpoints?.map((bp) => ({ at: bp.at, cols: bp.cols })) || null;
|
|
333
|
+
const responsive = item.responsive || null;
|
|
334
|
+
const gridNode = {
|
|
335
|
+
type: "grid",
|
|
336
|
+
id: `grid-${cols.join("-")}`,
|
|
337
|
+
children: gridChildren,
|
|
338
|
+
cols: totalCols,
|
|
339
|
+
spans: normalizedSpans,
|
|
340
|
+
breakpoint,
|
|
341
|
+
breakpoints,
|
|
342
|
+
responsive,
|
|
343
|
+
spatial: { gap: density.gap }
|
|
344
|
+
};
|
|
345
|
+
children.push(gridNode);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const surface = page.surface || `_flex _col _gap${density.gap} _p4 _overflow[auto] _flex1`;
|
|
349
|
+
return {
|
|
350
|
+
type: "page",
|
|
351
|
+
id: page.id,
|
|
352
|
+
children,
|
|
353
|
+
pageId: page.id,
|
|
354
|
+
surface,
|
|
355
|
+
wiring
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/pipeline.ts
|
|
360
|
+
function pascalCase2(str) {
|
|
361
|
+
return str.split(/[-_]/).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
362
|
+
}
|
|
363
|
+
async function runPipeline(essence, options) {
|
|
364
|
+
const validation = validateEssence(essence);
|
|
365
|
+
if (!validation.valid) {
|
|
366
|
+
throw new Error(`Invalid essence: ${validation.errors.join(", ")}`);
|
|
367
|
+
}
|
|
368
|
+
const resolver = createResolver({
|
|
369
|
+
contentRoot: options.contentRoot,
|
|
370
|
+
overridePaths: options.overridePaths
|
|
371
|
+
});
|
|
372
|
+
const resolved = await resolveEssence(essence, resolver);
|
|
373
|
+
const pageNodes = [];
|
|
374
|
+
for (const rp of resolved.pages) {
|
|
375
|
+
const pageIR = buildPageIR(
|
|
376
|
+
rp.page,
|
|
377
|
+
rp.patterns,
|
|
378
|
+
rp.wiring,
|
|
379
|
+
resolved.recipe,
|
|
380
|
+
{ gap: resolved.density.gap }
|
|
381
|
+
);
|
|
382
|
+
pageNodes.push(pageIR);
|
|
383
|
+
}
|
|
384
|
+
let filteredPages = pageNodes;
|
|
385
|
+
if (options.pageFilter) {
|
|
386
|
+
filteredPages = pageNodes.filter((p) => p.pageId === options.pageFilter);
|
|
387
|
+
}
|
|
388
|
+
const shellNode = {
|
|
389
|
+
type: "shell",
|
|
390
|
+
id: "shell",
|
|
391
|
+
children: [],
|
|
392
|
+
config: resolved.shell
|
|
393
|
+
};
|
|
394
|
+
const storeNode = {
|
|
395
|
+
type: "store",
|
|
396
|
+
id: "store",
|
|
397
|
+
children: [],
|
|
398
|
+
pageSignals: pageNodes.map((p) => ({
|
|
399
|
+
name: p.pageId,
|
|
400
|
+
pascalName: pascalCase2(p.pageId)
|
|
401
|
+
}))
|
|
402
|
+
};
|
|
403
|
+
const appNode = {
|
|
404
|
+
type: "app",
|
|
405
|
+
id: "app",
|
|
406
|
+
children: filteredPages,
|
|
407
|
+
theme: resolved.theme,
|
|
408
|
+
routes: resolved.routes,
|
|
409
|
+
routing: resolved.essence.platform?.routing || "hash",
|
|
410
|
+
shell: shellNode,
|
|
411
|
+
store: storeNode,
|
|
412
|
+
features: resolved.features
|
|
413
|
+
};
|
|
414
|
+
return { ir: appNode };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/ir-helpers.ts
|
|
418
|
+
function walkIR(node, visitor, parent = null) {
|
|
419
|
+
visitor(node, parent);
|
|
420
|
+
for (const child of node.children) {
|
|
421
|
+
walkIR(child, visitor, node);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function findNodes(root, type) {
|
|
425
|
+
const results = [];
|
|
426
|
+
walkIR(root, (node) => {
|
|
427
|
+
if (node.type === type) {
|
|
428
|
+
results.push(node);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
return results;
|
|
432
|
+
}
|
|
433
|
+
function countPatterns(root) {
|
|
434
|
+
return findNodes(root, "pattern").length;
|
|
435
|
+
}
|
|
436
|
+
function validateIR(root) {
|
|
437
|
+
const errors = [];
|
|
438
|
+
walkIR(root, (node, parent) => {
|
|
439
|
+
if (node.type === "grid") {
|
|
440
|
+
const grid = node;
|
|
441
|
+
if (grid.children.length === 0) {
|
|
442
|
+
errors.push(`Grid node "${grid.id}" has no children`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (node.type === "pattern") {
|
|
446
|
+
const pattern = node;
|
|
447
|
+
if (!pattern.pattern) {
|
|
448
|
+
errors.push(`Pattern node "${pattern.id}" is missing pattern meta`);
|
|
449
|
+
}
|
|
450
|
+
if (!pattern.pattern.patternId) {
|
|
451
|
+
errors.push(`Pattern node "${pattern.id}" has no patternId`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (node.type === "page") {
|
|
455
|
+
if (!node.id) {
|
|
456
|
+
errors.push("Page node is missing id");
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
return errors;
|
|
461
|
+
}
|
|
462
|
+
export {
|
|
463
|
+
buildPageIR,
|
|
464
|
+
countPatterns,
|
|
465
|
+
findNodes,
|
|
466
|
+
resolveEssence,
|
|
467
|
+
resolveVisualEffects,
|
|
468
|
+
runPipeline,
|
|
469
|
+
validateIR,
|
|
470
|
+
walkIR
|
|
471
|
+
};
|
|
472
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pipeline.ts","../src/resolve.ts","../src/ir.ts","../src/ir-helpers.ts"],"sourcesContent":["import type { IRAppNode, IRShellNode, IRStoreNode, IRPageNode } from './types.js';\nimport type { EssenceFile } from '@decantr/essence-spec';\nimport { validateEssence } from '@decantr/essence-spec';\nimport { createResolver } from '@decantr/registry';\nimport { resolveEssence } from './resolve.js';\nimport { buildPageIR } from './ir.js';\n\nfunction pascalCase(str: string): string {\n return str.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');\n}\n\nexport interface PipelineOptions {\n /** Path to content directory (patterns, archetypes, recipes) */\n contentRoot: string;\n\n /** Override paths for local content resolution */\n overridePaths?: string[];\n\n /** Only resolve specific page(s) */\n pageFilter?: string;\n}\n\nexport interface PipelineResult {\n /** The framework-agnostic intermediate representation */\n ir: IRAppNode;\n}\n\n/**\n * Run the Design Pipeline:\n * 1. Validate Essence against schema + guard rules\n * 2. Resolve all references (patterns, recipe, wiring) from registry\n * 3. Build framework-agnostic IR tree\n * 4. Return IR (no code generation — that's the consumer's job)\n */\nexport async function runPipeline(\n essence: EssenceFile,\n options: PipelineOptions,\n): Promise<PipelineResult> {\n // 1. Validate\n const validation = validateEssence(essence);\n if (!validation.valid) {\n throw new Error(`Invalid essence: ${validation.errors.join(', ')}`);\n }\n\n // 2. Create resolver and resolve\n const resolver = createResolver({\n contentRoot: options.contentRoot,\n overridePaths: options.overridePaths,\n });\n\n const resolved = await resolveEssence(essence, resolver);\n\n // 3. Build IR pages\n const pageNodes: IRPageNode[] = [];\n for (const rp of resolved.pages) {\n const pageIR = buildPageIR(\n rp.page,\n rp.patterns,\n rp.wiring,\n resolved.recipe,\n { gap: resolved.density.gap },\n );\n pageNodes.push(pageIR);\n }\n\n // Apply page filter\n let filteredPages = pageNodes;\n if (options.pageFilter) {\n filteredPages = pageNodes.filter(p => p.pageId === options.pageFilter);\n }\n\n // 4. Build shell node\n const shellNode: IRShellNode = {\n type: 'shell',\n id: 'shell',\n children: [],\n config: resolved.shell,\n };\n\n // 5. Build store node\n const storeNode: IRStoreNode = {\n type: 'store',\n id: 'store',\n children: [],\n pageSignals: pageNodes.map(p => ({\n name: p.pageId,\n pascalName: pascalCase(p.pageId),\n })),\n };\n\n // 6. Assemble app node\n const appNode: IRAppNode = {\n type: 'app',\n id: 'app',\n children: filteredPages,\n theme: resolved.theme,\n routes: resolved.routes,\n routing: (resolved.essence as { platform?: { routing?: string } }).platform?.routing as 'hash' | 'history' || 'hash',\n shell: shellNode,\n store: storeNode,\n features: resolved.features,\n };\n\n return { ir: appNode };\n}\n","import type {\n EssenceFile, Essence, SectionedEssence, StructurePage,\n LayoutItem, PatternRef, ColumnLayout,\n} from '@decantr/essence-spec';\nimport { isSimple, isSectioned, computeDensity } from '@decantr/essence-spec';\nimport type { ContentResolver, Pattern, Recipe, ResolvedPreset } from '@decantr/registry';\nimport { resolvePatternPreset, detectWirings } from '@decantr/registry';\nimport type {\n IRWiring, IRWiringSignal, IRShellConfig, IRNavItem,\n IRRecipeDecoration, IRTheme, IRRoute, IRVisualEffect,\n} from './types.js';\n\nexport interface ResolvedPage {\n page: StructurePage;\n patterns: Map<string, { pattern: Pattern; preset: ResolvedPreset }>;\n wiring: IRWiring | null;\n}\n\nexport interface ResolvedEssence {\n essence: EssenceFile;\n pages: ResolvedPage[];\n recipe: Recipe | null;\n density: { gap: string; level: string };\n theme: IRTheme;\n shell: IRShellConfig;\n routes: IRRoute[];\n features: string[];\n}\n\n// ─── Icon Mapping ─────────────────────────────────────────────\n\nconst NAV_ICONS: Record<string, string> = {\n overview: 'layout-dashboard',\n dashboard: 'layout-dashboard',\n home: 'home',\n analytics: 'bar-chart-3',\n settings: 'settings',\n users: 'users',\n billing: 'credit-card',\n reports: 'file-text',\n catalog: 'grid',\n products: 'package',\n orders: 'shopping-cart',\n messages: 'message-square',\n notifications: 'bell',\n activity: 'activity',\n search: 'search',\n profile: 'user',\n team: 'users',\n integrations: 'puzzle',\n api: 'code',\n docs: 'book-open',\n help: 'help-circle',\n projects: 'folder',\n workflows: 'git-branch',\n monitoring: 'monitor',\n security: 'shield',\n storage: 'database',\n deployments: 'rocket',\n logs: 'scroll-text',\n};\n\n// ─── Core styles that don't need explicit addon registration ──\n\nconst CORE_STYLES = new Set(['auradecantism']);\n\n// ─── Helpers ──────────────────────────────────────────────────\n\nfunction isPatternRef(item: LayoutItem): item is PatternRef {\n return typeof item === 'object' && 'pattern' in item;\n}\n\nfunction isColumnLayout(item: LayoutItem): item is ColumnLayout {\n return typeof item === 'object' && 'cols' in item;\n}\n\nfunction extractLayoutRefs(layout: LayoutItem[]): { id: string; explicitPreset?: string; alias?: string }[] {\n const refs: { id: string; explicitPreset?: string; alias?: string }[] = [];\n for (const item of layout) {\n if (typeof item === 'string') {\n refs.push({ id: item });\n } else if (isPatternRef(item)) {\n refs.push({ id: item.pattern, explicitPreset: item.preset, alias: item.as });\n } else if (isColumnLayout(item)) {\n for (const col of item.cols) {\n refs.push({ id: col });\n }\n }\n }\n return refs;\n}\n\n/** Flatten a layout array so column children are promoted to top-level for wiring detection */\nfunction flattenLayoutForWiring(layout: LayoutItem[]): LayoutItem[] {\n const flat: LayoutItem[] = [];\n for (const item of layout) {\n if (typeof item === 'string') {\n flat.push(item);\n } else if (isPatternRef(item)) {\n flat.push(item);\n } else if (isColumnLayout(item)) {\n // Promote column children as string refs\n for (const col of item.cols) {\n flat.push(col);\n }\n }\n }\n return flat;\n}\n\nfunction routePath(pageId: string, index: number): string {\n if (index === 0) return '/';\n // AUTO: Pages ending in \"-detail\" get a dynamic :id route parameter\n if (pageId.endsWith('-detail')) {\n return `/${pageId}/:id`;\n }\n return `/${pageId}`;\n}\n\nfunction pascalCase(str: string): string {\n return str.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');\n}\n\nfunction capitalize(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nfunction buildNavItems(pages: StructurePage[]): IRNavItem[] {\n return pages.map((page, i) => ({\n href: routePath(page.id, i),\n icon: NAV_ICONS[page.id] || 'circle',\n label: capitalize(page.id.replace(/-/g, ' ')),\n }));\n}\n\nfunction buildRecipeDecoration(recipe: Recipe): IRRecipeDecoration {\n const shell = recipe.shell;\n // The JSON may have additional fields not in the strict type\n const shellAny = shell as unknown as Record<string, unknown>;\n return {\n root: shell.root || '',\n nav: shell.nav || '',\n header: shell.header || '',\n brand: (shellAny['brand'] as string) || '',\n navLabel: (shellAny['navLabel'] as string) || '',\n // AUTO: default nav style is 'pill' per Decantr framework convention\n navStyle: shell.nav_style || 'pill',\n defaultNavState: (shellAny['default_nav_state'] as string) || 'expanded',\n dimensions: shell.dimensions || null,\n };\n}\n\nfunction buildTheme(essence: Essence, isAddon: boolean): IRTheme {\n return {\n style: essence.theme.style,\n mode: essence.theme.mode,\n shape: essence.theme.shape || null,\n recipe: essence.theme.recipe,\n isAddon,\n };\n}\n\nfunction convertWiring(wiringResults: ReturnType<typeof detectWirings>): IRWiring | null {\n if (wiringResults.length === 0) return null;\n\n const signals: IRWiringSignal[] = [];\n const props: Record<string, Record<string, string>> = {};\n const hookProps: Record<string, Record<string, string>> = {};\n const hookSet = new Set<IRWiringSignal['hookType']>();\n\n for (const result of wiringResults) {\n for (const signal of result.signals) {\n // Avoid duplicate signals\n if (!signals.some(s => s.name === signal.name)) {\n const setter = 'set' + signal.name.charAt(0).toUpperCase() + signal.name.slice(1);\n signals.push({\n name: signal.name,\n setter,\n init: signal.init,\n hookType: signal.hookType,\n });\n hookSet.add(signal.hookType);\n }\n }\n for (const [alias, aliasProps] of Object.entries(result.props)) {\n props[alias] = { ...props[alias], ...aliasProps };\n }\n // AUTO: Merge hook-based prop mappings\n for (const [alias, aliasHookProps] of Object.entries(result.hookProps)) {\n hookProps[alias] = { ...hookProps[alias], ...aliasHookProps };\n }\n }\n\n return { signals, props, hooks: [...hookSet], hookProps };\n}\n\n// ─── Visual Effects Resolution ────────────────────────────────\n\nexport function resolveVisualEffects(\n recipe: Recipe,\n pattern: Pattern,\n _slot?: string,\n): IRVisualEffect | null {\n if (!recipe.visual_effects?.enabled) return null;\n\n const typeMapping = recipe.visual_effects.type_mapping || {};\n const componentFallback = recipe.visual_effects.component_fallback || {};\n const intensity = recipe.visual_effects.intensity || 'medium';\n const intensityValues = recipe.visual_effects.intensity_values || {};\n\n // Check pattern tags / components against type_mapping\n let decorators: string[] = [];\n\n // Check if any pattern components match the component_fallback\n for (const comp of pattern.components || []) {\n const effectType = componentFallback[comp];\n if (effectType && typeMapping[effectType]) {\n decorators = [...decorators, ...typeMapping[effectType]];\n }\n }\n\n if (decorators.length === 0) return null;\n\n // Deduplicate\n decorators = [...new Set(decorators)];\n\n return {\n decorators,\n intensity: intensityValues[intensity] || {},\n };\n}\n\n// ─── Main Resolution ─────────────────────────────────────────\n\n/** Resolve all external references in an Essence file */\nexport async function resolveEssence(\n essence: EssenceFile,\n resolver: ContentResolver,\n): Promise<ResolvedEssence> {\n // Extract the simple essence (handle sectioned by flattening first section for now)\n let simpleEssence: Essence;\n if (isSimple(essence)) {\n simpleEssence = essence;\n } else if (isSectioned(essence)) {\n const sectioned = essence as SectionedEssence;\n const firstSection = sectioned.sections[0];\n simpleEssence = {\n version: sectioned.version,\n archetype: firstSection.archetype,\n theme: firstSection.theme,\n personality: sectioned.personality,\n platform: sectioned.platform,\n structure: firstSection.structure,\n features: firstSection.features || [],\n density: sectioned.density,\n guard: sectioned.guard,\n target: sectioned.target,\n };\n } else {\n throw new Error('Invalid essence format');\n }\n\n // 1. Recipe resolution\n let recipe: Recipe | null = null;\n const recipeResult = await resolver.resolve('recipe', simpleEssence.theme.recipe);\n if (recipeResult) {\n recipe = recipeResult.item;\n }\n\n // 2. Density computation\n const recipeSpatial = recipe?.spatial_hints;\n const density = computeDensity(simpleEssence.personality, recipeSpatial ? {\n density_bias: recipeSpatial.density_bias,\n content_gap_shift: recipeSpatial.content_gap_shift,\n } : undefined);\n\n // 3. Theme\n const isAddon = !CORE_STYLES.has(simpleEssence.theme.style);\n const theme = buildTheme(simpleEssence, isAddon);\n\n // 4. Resolve each page\n const resolvedPages: ResolvedPage[] = [];\n for (const page of simpleEssence.structure) {\n const refs = extractLayoutRefs(page.layout);\n const patterns = new Map<string, { pattern: Pattern; preset: ResolvedPreset }>();\n\n for (const ref of refs) {\n const patternResult = await resolver.resolve('pattern', ref.id);\n if (patternResult) {\n const preset = resolvePatternPreset(\n patternResult.item,\n ref.explicitPreset,\n recipe?.pattern_preferences?.default_presets,\n );\n const key = ref.alias || ref.id;\n patterns.set(key, { pattern: patternResult.item, preset });\n }\n }\n\n // Detect wiring (flatten cols so column children are visible)\n const wiringResults = detectWirings(flattenLayoutForWiring(page.layout));\n const wiring = convertWiring(wiringResults);\n\n resolvedPages.push({ page, patterns, wiring });\n }\n\n // 5. Shell config\n const shellType = simpleEssence.structure[0]?.shell || 'sidebar-main';\n const brand = pascalCase(simpleEssence.archetype);\n const nav = buildNavItems(simpleEssence.structure);\n const recipeDecoration = recipe ? buildRecipeDecoration(recipe) : null;\n\n const shell: IRShellConfig = {\n type: shellType,\n brand,\n nav,\n inset: false,\n recipe: recipeDecoration,\n };\n\n // 6. Routes\n const routes: IRRoute[] = simpleEssence.structure.map((page, i) => ({\n path: routePath(page.id, i),\n pageId: page.id,\n }));\n\n return {\n essence,\n pages: resolvedPages,\n recipe,\n density: { gap: density.content_gap, level: density.level },\n theme,\n shell,\n routes,\n features: simpleEssence.features ?? [],\n };\n}\n","import type {\n IRPageNode, IRPatternNode, IRGridNode, IRWiring,\n IRCardWrapping, IRPatternMeta, IRVisualEffect, IRNode,\n} from './types.js';\nimport type { StructurePage, LayoutItem, PatternRef, ColumnLayout } from '@decantr/essence-spec';\nimport type { Pattern, Recipe, ResolvedPreset } from '@decantr/registry';\n\nexport interface ResolvedPatternEntry {\n pattern: Pattern;\n preset: ResolvedPreset;\n}\n\nfunction isPatternRef(item: LayoutItem): item is PatternRef {\n return typeof item === 'object' && 'pattern' in item;\n}\n\nfunction isColumnLayout(item: LayoutItem): item is ColumnLayout {\n return typeof item === 'object' && 'cols' in item;\n}\n\nfunction pascalCase(str: string): string {\n return str.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');\n}\n\nfunction getPatternAlias(item: LayoutItem): string {\n if (typeof item === 'string') return item;\n if (isPatternRef(item)) return item.as || item.pattern;\n return '';\n}\n\nfunction getPatternId(item: LayoutItem): string {\n if (typeof item === 'string') return item;\n if (isPatternRef(item)) return item.pattern;\n return '';\n}\n\nfunction shouldWrapInCard(\n pattern: Pattern,\n preset: ResolvedPreset,\n recipe: Recipe | null,\n): boolean {\n // Hero/row/stack layouts are standalone\n const layout = preset.layout.layout;\n if (layout === 'hero' || layout === 'row') return false;\n\n // Pattern explicitly opts out\n if (pattern.contained === false) return false;\n\n // Recipe says no cards\n const cardWrapping = recipe?.spatial_hints?.card_wrapping;\n if (cardWrapping === 'none') return false;\n\n // Minimal: only wrap if pattern has presets (complex pattern)\n if (cardWrapping === 'minimal') {\n return Object.keys(pattern.presets).length > 0;\n }\n\n // Default: wrap\n return true;\n}\n\nfunction buildCardWrapping(\n pattern: Pattern,\n recipe: Recipe | null,\n): IRCardWrapping {\n const mode = recipe?.spatial_hints?.card_wrapping || 'always';\n const overrides = recipe?.pattern_overrides?.[pattern.id];\n return {\n mode: mode as IRCardWrapping['mode'],\n headerLabel: pattern.name,\n background: overrides?.background?.join(' '),\n };\n}\n\nfunction buildPatternNode(\n patternId: string,\n alias: string,\n resolved: ResolvedPatternEntry | undefined,\n wiring: IRWiring | null,\n recipe: Recipe | null,\n density: { gap: string },\n): IRPatternNode {\n const pattern = resolved?.pattern;\n const preset = resolved?.preset;\n\n const layout = preset?.layout.layout || 'column';\n const isStandalone = layout === 'hero' || layout === 'row';\n const contained = pattern && preset ? shouldWrapInCard(pattern, preset, recipe) : false;\n const components = pattern?.components || [];\n\n const patternMeta: IRPatternMeta = {\n patternId,\n preset: preset?.preset || 'default',\n alias,\n layout,\n contained,\n standalone: isStandalone,\n code: preset?.code ? { imports: preset.code.imports, example: preset.code.example } : null,\n components,\n };\n\n const card = contained && !isStandalone && pattern\n ? buildCardWrapping(pattern, recipe)\n : null;\n\n const wireProps = wiring?.props[alias] || wiring?.props[patternId] || null;\n\n return {\n type: 'pattern',\n id: alias,\n children: [],\n pattern: patternMeta,\n card,\n visualEffects: null,\n wireProps,\n spatial: { gap: density.gap },\n };\n}\n\n/** Build IR tree for a single page from its resolved structure + patterns */\nexport function buildPageIR(\n page: StructurePage,\n resolvedPatterns: Map<string, ResolvedPatternEntry>,\n wiring: IRWiring | null,\n recipe: Recipe | null,\n density: { gap: string },\n): IRPageNode {\n const children: IRNode[] = [];\n\n for (const item of page.layout) {\n if (typeof item === 'string') {\n // Simple string → full-width pattern\n const resolved = resolvedPatterns.get(item);\n children.push(buildPatternNode(item, item, resolved, wiring, recipe, density));\n } else if (isPatternRef(item)) {\n // PatternRef → pattern with optional preset/alias\n const alias = item.as || item.pattern;\n const resolved = resolvedPatterns.get(alias) || resolvedPatterns.get(item.pattern);\n children.push(buildPatternNode(item.pattern, alias, resolved, wiring, recipe, density));\n } else if (isColumnLayout(item)) {\n // ColumnLayout → grid with pattern children\n const cols = item.cols;\n const breakpoint = item.at || null;\n const spans = item.span || null;\n\n // Normalize spans: fill in missing columns with weight 1\n let normalizedSpans: Record<string, number> | null = null;\n if (spans) {\n normalizedSpans = {};\n for (const col of cols) {\n normalizedSpans[col] = spans[col] || 1;\n }\n }\n\n const gridChildren: IRNode[] = [];\n for (const col of cols) {\n const resolved = resolvedPatterns.get(col);\n gridChildren.push(buildPatternNode(col, col, resolved, wiring, recipe, density));\n }\n\n const totalCols = normalizedSpans\n ? Object.values(normalizedSpans).reduce((a, b) => a + b, 0)\n : cols.length;\n\n // AUTO: Pass through multi-breakpoint and container query config from ColumnLayout\n const breakpoints = item.breakpoints?.map(bp => ({ at: bp.at, cols: bp.cols })) || null;\n const responsive = item.responsive || null;\n\n const gridNode: IRGridNode = {\n type: 'grid',\n id: `grid-${cols.join('-')}`,\n children: gridChildren,\n cols: totalCols,\n spans: normalizedSpans,\n breakpoint,\n breakpoints,\n responsive,\n spatial: { gap: density.gap },\n };\n children.push(gridNode);\n }\n }\n\n const surface = page.surface || `_flex _col _gap${density.gap} _p4 _overflow[auto] _flex1`;\n\n return {\n type: 'page',\n id: page.id,\n children,\n pageId: page.id,\n surface,\n wiring,\n };\n}\n","import type { IRNode, IRPatternNode, IRGridNode } from './types.js';\n\n/** Depth-first walk of IR tree, calling visitor on each node */\nexport function walkIR(\n node: IRNode,\n visitor: (node: IRNode, parent: IRNode | null) => void,\n parent: IRNode | null = null,\n): void {\n visitor(node, parent);\n for (const child of node.children) {\n walkIR(child, visitor, node);\n }\n}\n\n/** Find all nodes of a specific type */\nexport function findNodes<T extends IRNode>(root: IRNode, type: string): T[] {\n const results: T[] = [];\n walkIR(root, (node) => {\n if (node.type === type) {\n results.push(node as T);\n }\n });\n return results;\n}\n\n/** Count total patterns in an IR tree */\nexport function countPatterns(root: IRNode): number {\n return findNodes(root, 'pattern').length;\n}\n\n/** Validate IR tree structure (no orphaned grids, patterns have meta, etc.) */\nexport function validateIR(root: IRNode): string[] {\n const errors: string[] = [];\n\n walkIR(root, (node, parent) => {\n if (node.type === 'grid') {\n const grid = node as IRGridNode;\n if (grid.children.length === 0) {\n errors.push(`Grid node \"${grid.id}\" has no children`);\n }\n }\n\n if (node.type === 'pattern') {\n const pattern = node as IRPatternNode;\n if (!pattern.pattern) {\n errors.push(`Pattern node \"${pattern.id}\" is missing pattern meta`);\n }\n if (!pattern.pattern.patternId) {\n errors.push(`Pattern node \"${pattern.id}\" has no patternId`);\n }\n }\n\n if (node.type === 'page') {\n if (!node.id) {\n errors.push('Page node is missing id');\n }\n }\n });\n\n return errors;\n}\n"],"mappings":"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","names":["isPatternRef","isColumnLayout","isPatternRef","isColumnLayout","pascalCase"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@decantr/core",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "Decantr core — Design Pipeline IR engine for AI-generated UI",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/decantr-ai/decantr.git",
|
|
9
|
+
"directory": "packages/core"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://decantr.ai",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "dist/index.js",
|
|
14
|
+
"types": "dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": ["dist"],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsup",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@decantr/essence-spec": "workspace:*",
|
|
32
|
+
"@decantr/registry": "workspace:*"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {}
|
|
35
|
+
}
|