@allternit/ix 0.1.0 → 0.1.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/README.md +6 -6
- package/dist/adapters/json-render.d.ts +5 -5
- package/dist/adapters/json-render.js +12 -12
- package/dist/collab/visual-editor.d.ts +1 -1
- package/dist/collab/visual-editor.js +4 -4
- package/dist/collab/visual-editor.js.map +1 -1
- package/dist/collab/yjs-adapter.d.ts +1 -1
- package/dist/collab/yjs-adapter.js +2 -2
- package/dist/collab/yjs-adapter.js.map +1 -1
- package/dist/collab/yjs-client.js +1 -1
- package/dist/collab/yjs-client.js.map +1 -1
- package/dist/collab/yjs-types.js +1 -1
- package/dist/collab/yjs-types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/pipeline/llm-to-ix.d.ts +5 -5
- package/dist/pipeline/llm-to-ix.d.ts.map +1 -1
- package/dist/pipeline/llm-to-ix.js +6 -6
- package/dist/react/renderer.d.ts +2 -2
- package/dist/react/renderer.js +3 -3
- package/dist/react/renderer.js.map +1 -1
- package/dist/renderer/renderer.d.ts +1 -1
- package/dist/renderer/renderer.js +1 -1
- package/dist/runtime/capsule-runtime.d.ts +1 -1
- package/dist/runtime/capsule-runtime.js +1 -1
- package/dist/sdk/api.d.ts +3 -3
- package/dist/sdk/api.js +3 -3
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +2 -2
- package/dist/sdk/react.d.ts +2 -2
- package/dist/sdk/react.js +2 -2
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.js +1 -1
- package/dist/state/store.d.ts +1 -1
- package/dist/state/store.js +3 -3
- package/dist/state/store.js.map +1 -1
- package/dist/svelte/index.d.ts +1 -1
- package/dist/svelte/index.js +1 -1
- package/dist/svelte/renderer.d.ts +3 -3
- package/dist/svelte/renderer.js +4 -4
- package/dist/svelte/renderer.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.js +1 -1
- package/dist/vue/renderer.d.ts +3 -3
- package/dist/vue/renderer.js +5 -5
- package/dist/vue/renderer.js.map +1 -1
- package/package.json +8 -8
- package/dist/adapters/json-render.d.ts.bak +0 -211
- package/dist/adapters/json-render.js.bak +0 -576
- package/dist/catalog/registry.d.ts.bak +0 -65
- package/dist/catalog/registry.js.bak +0 -388
- package/dist/collab/capsule-registry.d.ts.bak +0 -114
- package/dist/collab/capsule-registry.js.bak +0 -271
- package/dist/collab/index.d.ts.bak +0 -21
- package/dist/collab/index.js.bak +0 -32
- package/dist/collab/visual-editor.d.ts.bak +0 -199
- package/dist/collab/visual-editor.js.bak +0 -259
- package/dist/collab/yjs-adapter.d.ts.bak +0 -95
- package/dist/collab/yjs-adapter.js.bak +0 -282
- package/dist/collab/yjs-client.d.ts.bak +0 -101
- package/dist/collab/yjs-client.js.bak +0 -193
- package/dist/collab/yjs-protocols.d.ts.bak +0 -128
- package/dist/collab/yjs-protocols.js.bak +0 -245
- package/dist/collab/yjs-types.d.ts.bak +0 -201
- package/dist/collab/yjs-types.js.bak +0 -45
- package/dist/index.d.ts.bak +0 -38
- package/dist/index.js.bak +0 -48
- package/dist/pipeline/llm-to-ix.d.ts.bak +0 -249
- package/dist/pipeline/llm-to-ix.js.bak +0 -992
- package/dist/react/index.d.ts.bak +0 -18
- package/dist/react/index.js.bak +0 -18
- package/dist/react/renderer.d.ts.bak +0 -47
- package/dist/react/renderer.js.bak +0 -420
- package/dist/renderer/renderer.d.ts.bak +0 -55
- package/dist/renderer/renderer.js.bak +0 -232
- package/dist/runtime/capsule-runtime.d.ts.bak +0 -227
- package/dist/runtime/capsule-runtime.js.bak +0 -563
- package/dist/runtime/policy-gates.d.ts.bak +0 -116
- package/dist/runtime/policy-gates.js.bak +0 -317
- package/dist/schema/ui-ir.d.ts.bak +0 -26
- package/dist/schema/ui-ir.js.bak +0 -51
- package/dist/sdk/api.d.ts.bak +0 -101
- package/dist/sdk/api.js.bak +0 -177
- package/dist/sdk/index.d.ts.bak +0 -9
- package/dist/sdk/index.js.bak +0 -10
- package/dist/sdk/react.d.ts.bak +0 -63
- package/dist/sdk/react.js.bak +0 -161
- package/dist/state/index.d.ts.bak +0 -8
- package/dist/state/index.js.bak +0 -8
- package/dist/state/patch.d.ts.bak +0 -73
- package/dist/state/patch.js.bak +0 -437
- package/dist/state/store.d.ts.bak +0 -50
- package/dist/state/store.js.bak +0 -246
- package/dist/svelte/index.d.ts.bak +0 -15
- package/dist/svelte/index.js.bak +0 -15
- package/dist/svelte/renderer.d.ts.bak +0 -35
- package/dist/svelte/renderer.js.bak +0 -317
- package/dist/types/index.d.ts.bak +0 -349
- package/dist/types/index.js.bak +0 -152
- package/dist/vue/index.d.ts.bak +0 -18
- package/dist/vue/index.js.bak +0 -18
- package/dist/vue/renderer.d.ts.bak +0 -46
- package/dist/vue/renderer.js.bak +0 -302
|
@@ -1,992 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LLM-to-IX Pipeline
|
|
3
|
-
*
|
|
4
|
-
* Converts LLM-generated UI descriptions to A2R-IX format.
|
|
5
|
-
*
|
|
6
|
-
* Supports multiple input formats:
|
|
7
|
-
* - Natural language descriptions
|
|
8
|
-
* - Vercel Labs json-render
|
|
9
|
-
* - JSX-like pseudo-code
|
|
10
|
-
* - Raw component trees
|
|
11
|
-
* - Markdown UI descriptions
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```typescript
|
|
15
|
-
* import { llmToIxPipeline } from '@allternit/ix/pipeline';
|
|
16
|
-
*
|
|
17
|
-
* const result = llmToIxPipeline({
|
|
18
|
-
* input: llmOutput,
|
|
19
|
-
* options: {
|
|
20
|
-
* applyStyling: true,
|
|
21
|
-
* theme: 'default',
|
|
22
|
-
* generateIds: true,
|
|
23
|
-
* }
|
|
24
|
-
* });
|
|
25
|
-
*
|
|
26
|
-
* console.log(result.tree); // IxRenderTree
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
import { jsonRenderAdapter } from '../adapters/json-render';
|
|
30
|
-
/**
|
|
31
|
-
* Convert LLM output to A2R-IX
|
|
32
|
-
*/
|
|
33
|
-
export function convertLLMToIX(input, options = {}) {
|
|
34
|
-
const warnings = [];
|
|
35
|
-
const inferredState = [];
|
|
36
|
-
// Detect input format
|
|
37
|
-
const format = detectInputFormat(input);
|
|
38
|
-
switch (format) {
|
|
39
|
-
case 'json-render':
|
|
40
|
-
return convertFromJsonRender(input, options);
|
|
41
|
-
case 'jsx-like':
|
|
42
|
-
return convertFromJSXLike(input, options);
|
|
43
|
-
case 'component-tree':
|
|
44
|
-
return convertFromComponentTree(input, options);
|
|
45
|
-
case 'natural-language':
|
|
46
|
-
return convertFromNaturalLanguage(input, options);
|
|
47
|
-
default:
|
|
48
|
-
warnings.push('Unknown input format, attempting generic conversion');
|
|
49
|
-
return convertGeneric(input, options);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Detect input format
|
|
54
|
-
*/
|
|
55
|
-
function detectInputFormat(input) {
|
|
56
|
-
if (!input)
|
|
57
|
-
return 'unknown';
|
|
58
|
-
// Check for json-render
|
|
59
|
-
if (jsonRenderAdapter.isValidSchema(input)) {
|
|
60
|
-
return 'json-render';
|
|
61
|
-
}
|
|
62
|
-
// Check for JSX-like (string with JSX syntax)
|
|
63
|
-
if (typeof input === 'string') {
|
|
64
|
-
const trimmed = input.trim();
|
|
65
|
-
if (trimmed.startsWith('<') && trimmed.endsWith('>')) {
|
|
66
|
-
return 'jsx-like';
|
|
67
|
-
}
|
|
68
|
-
if (trimmed.length >= 40 && !trimmed.startsWith('{')) {
|
|
69
|
-
return 'natural-language';
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Check for component tree object (including empty object)
|
|
73
|
-
if (typeof input === 'object' && input !== null && !Array.isArray(input)) {
|
|
74
|
-
const obj = input;
|
|
75
|
-
if (obj.components || obj.type || obj.root || Object.keys(obj).length === 0) {
|
|
76
|
-
return 'component-tree';
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return 'unknown';
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Convert from json-render format
|
|
83
|
-
*/
|
|
84
|
-
function convertFromJsonRender(schema, options) {
|
|
85
|
-
const warnings = [];
|
|
86
|
-
const inferredState = [];
|
|
87
|
-
const ui = jsonRenderAdapter.fromJsonRender(schema);
|
|
88
|
-
// Add IDs if needed
|
|
89
|
-
if (options.generateIds) {
|
|
90
|
-
addComponentIds(ui.components);
|
|
91
|
-
}
|
|
92
|
-
// Infer state from bindings
|
|
93
|
-
if (options.inferState) {
|
|
94
|
-
inferStateFromBindings(ui, inferredState);
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
ui,
|
|
98
|
-
warnings,
|
|
99
|
-
inferredState,
|
|
100
|
-
confidence: 0.95,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Convert from JSX-like string
|
|
105
|
-
*/
|
|
106
|
-
function convertFromJSXLike(jsxString, options) {
|
|
107
|
-
const warnings = [];
|
|
108
|
-
const inferredState = [];
|
|
109
|
-
try {
|
|
110
|
-
const parsed = parseJSXLike(jsxString);
|
|
111
|
-
// Check if parsing produced any components
|
|
112
|
-
if (parsed.length === 0) {
|
|
113
|
-
warnings.push('No valid JSX components found');
|
|
114
|
-
return {
|
|
115
|
-
ui: createEmptyUI(options.version),
|
|
116
|
-
warnings,
|
|
117
|
-
inferredState,
|
|
118
|
-
confidence: 0.3,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
const components = parsed.map((node) => jsxNodeToComponent(node));
|
|
122
|
-
const ui = {
|
|
123
|
-
version: options.version || '1.0.0',
|
|
124
|
-
components,
|
|
125
|
-
state: { variables: [] },
|
|
126
|
-
actions: [],
|
|
127
|
-
};
|
|
128
|
-
// Infer state
|
|
129
|
-
if (options.inferState) {
|
|
130
|
-
inferStateFromBindings(ui, inferredState);
|
|
131
|
-
}
|
|
132
|
-
return {
|
|
133
|
-
ui,
|
|
134
|
-
warnings,
|
|
135
|
-
inferredState,
|
|
136
|
-
confidence: 0.85,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
warnings.push(`Failed to parse JSX: ${error}`);
|
|
141
|
-
return {
|
|
142
|
-
ui: createEmptyUI(options.version),
|
|
143
|
-
warnings,
|
|
144
|
-
inferredState,
|
|
145
|
-
confidence: 0.3,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Parse JSX-like string to AST
|
|
151
|
-
*/
|
|
152
|
-
function parseJSXLike(jsx) {
|
|
153
|
-
// Simple JSX parser - in production, use a proper parser
|
|
154
|
-
const nodes = [];
|
|
155
|
-
const tagRegex = /<(\w+)([^>]*)>([\s\S]*?)<\/\1>|<(\w+)([^>]*)\/>/g;
|
|
156
|
-
let match;
|
|
157
|
-
while ((match = tagRegex.exec(jsx)) !== null) {
|
|
158
|
-
const type = (match[1] || match[4]) ?? 'div';
|
|
159
|
-
const propsString = match[2] || match[5] || '';
|
|
160
|
-
const children = match[3]?.trim();
|
|
161
|
-
const props = parseProps(propsString);
|
|
162
|
-
const childNodes = children ? parseJSXLike(children) : [];
|
|
163
|
-
nodes.push({
|
|
164
|
-
type,
|
|
165
|
-
props,
|
|
166
|
-
children: childNodes,
|
|
167
|
-
text: childNodes.length === 0 ? children : undefined,
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
return nodes;
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Parse props string
|
|
174
|
-
*/
|
|
175
|
-
function parseProps(propsString) {
|
|
176
|
-
const props = {};
|
|
177
|
-
// Support $ prefix for bindings: $value={path}
|
|
178
|
-
const propRegex = /(\$?\w+)={([^}]*)}|(\$?\w+)="([^"]*)"|(\$?\w+)='([^']*)'|(\$?\w+)/g;
|
|
179
|
-
let match;
|
|
180
|
-
while ((match = propRegex.exec(propsString)) !== null) {
|
|
181
|
-
const key = (match[1] || match[3] || match[5] || match[7]) ?? '';
|
|
182
|
-
if (!key)
|
|
183
|
-
continue;
|
|
184
|
-
let value = true; // Boolean prop
|
|
185
|
-
if (match[2]) {
|
|
186
|
-
// Expression: prop={value}
|
|
187
|
-
try {
|
|
188
|
-
value = JSON.parse(match[2]);
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
value = match[2]; // Raw string for expressions like user.name
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
else if (match[4]) {
|
|
195
|
-
// Double quoted: prop="value"
|
|
196
|
-
value = match[4];
|
|
197
|
-
}
|
|
198
|
-
else if (match[6]) {
|
|
199
|
-
// Single quoted: prop='value'
|
|
200
|
-
value = match[6];
|
|
201
|
-
}
|
|
202
|
-
props[key] = value;
|
|
203
|
-
}
|
|
204
|
-
return props;
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Convert JSX node to UIComponent
|
|
208
|
-
*/
|
|
209
|
-
function jsxNodeToComponent(node, parentId = 'root') {
|
|
210
|
-
const id = generateId();
|
|
211
|
-
const component = {
|
|
212
|
-
id,
|
|
213
|
-
type: node.type,
|
|
214
|
-
props: {},
|
|
215
|
-
};
|
|
216
|
-
// Process props
|
|
217
|
-
const bindings = [];
|
|
218
|
-
const events = [];
|
|
219
|
-
for (const [key, value] of Object.entries(node.props)) {
|
|
220
|
-
// Check for binding (starts with $)
|
|
221
|
-
if (key.startsWith('$')) {
|
|
222
|
-
const propName = key.slice(1);
|
|
223
|
-
// Handle both string values and object expressions
|
|
224
|
-
const statePath = typeof value === 'string'
|
|
225
|
-
? value
|
|
226
|
-
: value?.$expr || String(value);
|
|
227
|
-
bindings.push({
|
|
228
|
-
prop: propName,
|
|
229
|
-
statePath,
|
|
230
|
-
direction: 'one-way',
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
// Check for event handler
|
|
234
|
-
else if (key.startsWith('on')) {
|
|
235
|
-
events.push({
|
|
236
|
-
event: key,
|
|
237
|
-
action: value,
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
// Regular prop
|
|
241
|
-
else {
|
|
242
|
-
component.props[key] = value;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (bindings.length > 0) {
|
|
246
|
-
component.bindings = bindings;
|
|
247
|
-
}
|
|
248
|
-
if (events.length > 0) {
|
|
249
|
-
component.events = events;
|
|
250
|
-
}
|
|
251
|
-
// Process children
|
|
252
|
-
if (node.children.length > 0) {
|
|
253
|
-
component.children = node.children.map((child) => jsxNodeToComponent(child, id));
|
|
254
|
-
}
|
|
255
|
-
else if (node.text) {
|
|
256
|
-
component.props.children = node.text;
|
|
257
|
-
}
|
|
258
|
-
return component;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Convert from component tree object
|
|
262
|
-
*/
|
|
263
|
-
function convertFromComponentTree(tree, options) {
|
|
264
|
-
const warnings = [];
|
|
265
|
-
const inferredState = [];
|
|
266
|
-
try {
|
|
267
|
-
// Handle empty object
|
|
268
|
-
if (Object.keys(tree).length === 0) {
|
|
269
|
-
return {
|
|
270
|
-
ui: createEmptyUI(options.version),
|
|
271
|
-
warnings: ['Empty input provided'],
|
|
272
|
-
inferredState,
|
|
273
|
-
confidence: 0.1,
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
const components = tree.components
|
|
277
|
-
? tree.components.map((c) => convertTreeNode(c))
|
|
278
|
-
: tree.type
|
|
279
|
-
? [convertTreeNode(tree)]
|
|
280
|
-
: [];
|
|
281
|
-
const ui = {
|
|
282
|
-
version: options.version || '1.0.0',
|
|
283
|
-
components,
|
|
284
|
-
state: { variables: [] },
|
|
285
|
-
actions: [],
|
|
286
|
-
};
|
|
287
|
-
return {
|
|
288
|
-
ui,
|
|
289
|
-
warnings,
|
|
290
|
-
inferredState,
|
|
291
|
-
confidence: 0.8,
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
catch (error) {
|
|
295
|
-
warnings.push(`Failed to convert tree: ${error}`);
|
|
296
|
-
return {
|
|
297
|
-
ui: createEmptyUI(options.version),
|
|
298
|
-
warnings,
|
|
299
|
-
inferredState,
|
|
300
|
-
confidence: 0.4,
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Convert tree node to component
|
|
306
|
-
*/
|
|
307
|
-
function convertTreeNode(node) {
|
|
308
|
-
const component = {
|
|
309
|
-
id: generateId(),
|
|
310
|
-
type: node.type || 'Box',
|
|
311
|
-
props: node.props || {},
|
|
312
|
-
};
|
|
313
|
-
if (node.children) {
|
|
314
|
-
component.children = node.children.map((c) => convertTreeNode(c));
|
|
315
|
-
}
|
|
316
|
-
if (node.bindings) {
|
|
317
|
-
component.bindings = node.bindings;
|
|
318
|
-
}
|
|
319
|
-
if (node.events) {
|
|
320
|
-
component.events = node.events;
|
|
321
|
-
}
|
|
322
|
-
return component;
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Convert from natural language
|
|
326
|
-
*/
|
|
327
|
-
function convertFromNaturalLanguage(description, options) {
|
|
328
|
-
const warnings = [];
|
|
329
|
-
const inferredState = [];
|
|
330
|
-
warnings.push('Natural language conversion requires LLM assistance');
|
|
331
|
-
// This would typically call an LLM to generate the UI
|
|
332
|
-
// For now, return a placeholder
|
|
333
|
-
const ui = {
|
|
334
|
-
version: options.version || '1.0.0',
|
|
335
|
-
components: [
|
|
336
|
-
{
|
|
337
|
-
id: generateId(),
|
|
338
|
-
type: 'Text',
|
|
339
|
-
props: { children: 'Natural language conversion not yet implemented' },
|
|
340
|
-
},
|
|
341
|
-
],
|
|
342
|
-
state: { variables: [] },
|
|
343
|
-
actions: [],
|
|
344
|
-
};
|
|
345
|
-
return {
|
|
346
|
-
ui,
|
|
347
|
-
warnings,
|
|
348
|
-
inferredState,
|
|
349
|
-
confidence: 0.1,
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Generic conversion fallback
|
|
354
|
-
*/
|
|
355
|
-
function convertGeneric(input, options) {
|
|
356
|
-
const warnings = ['Using generic conversion'];
|
|
357
|
-
const inferredState = [];
|
|
358
|
-
// Try to coerce to component structure
|
|
359
|
-
let components = [];
|
|
360
|
-
if (Array.isArray(input)) {
|
|
361
|
-
components = input.map((item, i) => ({
|
|
362
|
-
id: `comp-${i}`,
|
|
363
|
-
type: item?.type || 'Box',
|
|
364
|
-
props: item?.props || {},
|
|
365
|
-
}));
|
|
366
|
-
}
|
|
367
|
-
else if (typeof input === 'object' && input !== null) {
|
|
368
|
-
components = [{
|
|
369
|
-
id: generateId(),
|
|
370
|
-
type: input.type || 'Box',
|
|
371
|
-
props: input.props || {},
|
|
372
|
-
}];
|
|
373
|
-
}
|
|
374
|
-
const ui = {
|
|
375
|
-
version: options.version || '1.0.0',
|
|
376
|
-
components,
|
|
377
|
-
state: { variables: [] },
|
|
378
|
-
actions: [],
|
|
379
|
-
};
|
|
380
|
-
return {
|
|
381
|
-
ui,
|
|
382
|
-
warnings,
|
|
383
|
-
inferredState,
|
|
384
|
-
confidence: 0.5,
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Add component IDs
|
|
389
|
-
*/
|
|
390
|
-
function addComponentIds(components, prefix = 'comp') {
|
|
391
|
-
components.forEach((comp, i) => {
|
|
392
|
-
if (!comp.id) {
|
|
393
|
-
comp.id = `${prefix}-${i}`;
|
|
394
|
-
}
|
|
395
|
-
if (comp.children) {
|
|
396
|
-
addComponentIds(comp.children, comp.id);
|
|
397
|
-
}
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
|
-
* Infer state from bindings
|
|
402
|
-
*/
|
|
403
|
-
function inferStateFromBindings(ui, inferredState) {
|
|
404
|
-
const statePaths = new Set();
|
|
405
|
-
function scanComponent(comp) {
|
|
406
|
-
comp.bindings?.forEach((binding) => {
|
|
407
|
-
statePaths.add(binding.statePath);
|
|
408
|
-
});
|
|
409
|
-
comp.children?.forEach(scanComponent);
|
|
410
|
-
}
|
|
411
|
-
ui.components.forEach(scanComponent);
|
|
412
|
-
statePaths.forEach((path) => {
|
|
413
|
-
const existing = ui.state.variables.find((v) => v.path === path);
|
|
414
|
-
if (!existing) {
|
|
415
|
-
inferredState.push({
|
|
416
|
-
path,
|
|
417
|
-
type: 'any',
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Generate unique ID
|
|
424
|
-
*/
|
|
425
|
-
function generateId() {
|
|
426
|
-
return `comp_${Math.random().toString(36).substr(2, 9)}`;
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Create empty UI
|
|
430
|
-
*/
|
|
431
|
-
function createEmptyUI(version) {
|
|
432
|
-
return {
|
|
433
|
-
version: version || '1.0.0',
|
|
434
|
-
components: [],
|
|
435
|
-
state: { variables: [] },
|
|
436
|
-
actions: [],
|
|
437
|
-
};
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* A2R-IX Built-in Themes
|
|
441
|
-
*/
|
|
442
|
-
const IX_THEMES = {
|
|
443
|
-
default: {
|
|
444
|
-
name: 'default',
|
|
445
|
-
colors: {
|
|
446
|
-
primary: '#3B82F6',
|
|
447
|
-
secondary: '#6B7280',
|
|
448
|
-
success: '#10B981',
|
|
449
|
-
warning: '#F59E0B',
|
|
450
|
-
error: '#EF4444',
|
|
451
|
-
background: '#FFFFFF',
|
|
452
|
-
surface: '#F9FAFB',
|
|
453
|
-
text: '#111827',
|
|
454
|
-
textMuted: '#6B7280',
|
|
455
|
-
border: '#E5E7EB',
|
|
456
|
-
},
|
|
457
|
-
spacing: {
|
|
458
|
-
xs: 4,
|
|
459
|
-
sm: 8,
|
|
460
|
-
md: 16,
|
|
461
|
-
lg: 24,
|
|
462
|
-
xl: 32,
|
|
463
|
-
},
|
|
464
|
-
typography: {
|
|
465
|
-
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
466
|
-
fontSize: {
|
|
467
|
-
xs: '12px',
|
|
468
|
-
sm: '14px',
|
|
469
|
-
md: '16px',
|
|
470
|
-
lg: '18px',
|
|
471
|
-
xl: '24px',
|
|
472
|
-
},
|
|
473
|
-
fontWeight: {
|
|
474
|
-
normal: 400,
|
|
475
|
-
medium: 500,
|
|
476
|
-
semibold: 600,
|
|
477
|
-
bold: 700,
|
|
478
|
-
},
|
|
479
|
-
},
|
|
480
|
-
borderRadius: {
|
|
481
|
-
sm: 4,
|
|
482
|
-
md: 8,
|
|
483
|
-
lg: 12,
|
|
484
|
-
full: 9999,
|
|
485
|
-
},
|
|
486
|
-
shadows: {
|
|
487
|
-
sm: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
488
|
-
md: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
489
|
-
lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
|
|
490
|
-
},
|
|
491
|
-
},
|
|
492
|
-
minimal: {
|
|
493
|
-
name: 'minimal',
|
|
494
|
-
colors: {
|
|
495
|
-
primary: '#000000',
|
|
496
|
-
secondary: '#666666',
|
|
497
|
-
success: '#00AA00',
|
|
498
|
-
warning: '#FFAA00',
|
|
499
|
-
error: '#FF0000',
|
|
500
|
-
background: '#FFFFFF',
|
|
501
|
-
surface: '#FFFFFF',
|
|
502
|
-
text: '#000000',
|
|
503
|
-
textMuted: '#666666',
|
|
504
|
-
border: '#DDDDDD',
|
|
505
|
-
},
|
|
506
|
-
spacing: {
|
|
507
|
-
xs: 4,
|
|
508
|
-
sm: 8,
|
|
509
|
-
md: 12,
|
|
510
|
-
lg: 16,
|
|
511
|
-
xl: 24,
|
|
512
|
-
},
|
|
513
|
-
typography: {
|
|
514
|
-
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
515
|
-
fontSize: {
|
|
516
|
-
xs: '11px',
|
|
517
|
-
sm: '13px',
|
|
518
|
-
md: '15px',
|
|
519
|
-
lg: '17px',
|
|
520
|
-
xl: '22px',
|
|
521
|
-
},
|
|
522
|
-
fontWeight: {
|
|
523
|
-
normal: 400,
|
|
524
|
-
medium: 500,
|
|
525
|
-
semibold: 600,
|
|
526
|
-
bold: 700,
|
|
527
|
-
},
|
|
528
|
-
},
|
|
529
|
-
borderRadius: {
|
|
530
|
-
sm: 0,
|
|
531
|
-
md: 0,
|
|
532
|
-
lg: 0,
|
|
533
|
-
full: 9999,
|
|
534
|
-
},
|
|
535
|
-
shadows: {
|
|
536
|
-
sm: 'none',
|
|
537
|
-
md: 'none',
|
|
538
|
-
lg: 'none',
|
|
539
|
-
},
|
|
540
|
-
},
|
|
541
|
-
compact: {
|
|
542
|
-
name: 'compact',
|
|
543
|
-
colors: {
|
|
544
|
-
primary: '#2563EB',
|
|
545
|
-
secondary: '#475569',
|
|
546
|
-
success: '#059669',
|
|
547
|
-
warning: '#D97706',
|
|
548
|
-
error: '#DC2626',
|
|
549
|
-
background: '#FAFAFA',
|
|
550
|
-
surface: '#FFFFFF',
|
|
551
|
-
text: '#18181B',
|
|
552
|
-
textMuted: '#71717A',
|
|
553
|
-
border: '#E4E4E7',
|
|
554
|
-
},
|
|
555
|
-
spacing: {
|
|
556
|
-
xs: 2,
|
|
557
|
-
sm: 4,
|
|
558
|
-
md: 8,
|
|
559
|
-
lg: 12,
|
|
560
|
-
xl: 16,
|
|
561
|
-
},
|
|
562
|
-
typography: {
|
|
563
|
-
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
564
|
-
fontSize: {
|
|
565
|
-
xs: '10px',
|
|
566
|
-
sm: '12px',
|
|
567
|
-
md: '14px',
|
|
568
|
-
lg: '16px',
|
|
569
|
-
xl: '20px',
|
|
570
|
-
},
|
|
571
|
-
fontWeight: {
|
|
572
|
-
normal: 400,
|
|
573
|
-
medium: 500,
|
|
574
|
-
semibold: 600,
|
|
575
|
-
bold: 700,
|
|
576
|
-
},
|
|
577
|
-
},
|
|
578
|
-
borderRadius: {
|
|
579
|
-
sm: 2,
|
|
580
|
-
md: 4,
|
|
581
|
-
lg: 6,
|
|
582
|
-
full: 9999,
|
|
583
|
-
},
|
|
584
|
-
shadows: {
|
|
585
|
-
sm: '0 1px 1px rgba(0, 0, 0, 0.03)',
|
|
586
|
-
md: '0 2px 4px rgba(0, 0, 0, 0.06)',
|
|
587
|
-
lg: '0 4px 8px rgba(0, 0, 0, 0.08)',
|
|
588
|
-
},
|
|
589
|
-
},
|
|
590
|
-
};
|
|
591
|
-
/**
|
|
592
|
-
* Get theme by name or return custom theme
|
|
593
|
-
*/
|
|
594
|
-
function getTheme(theme) {
|
|
595
|
-
if (typeof theme === 'string') {
|
|
596
|
-
return IX_THEMES[theme] || IX_THEMES.default;
|
|
597
|
-
}
|
|
598
|
-
return theme;
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Apply A2R-IX styling to component tree
|
|
602
|
-
*/
|
|
603
|
-
function applyStylingToTree(components, theme) {
|
|
604
|
-
return components.map((comp) => applyStylingToNode(comp, theme));
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* Apply A2R-IX styling to a single node
|
|
608
|
-
*/
|
|
609
|
-
function applyStylingToNode(comp, theme) {
|
|
610
|
-
const baseStyle = {};
|
|
611
|
-
let className = '';
|
|
612
|
-
// Apply component-specific default styles based on type
|
|
613
|
-
const componentType = comp.type.toLowerCase();
|
|
614
|
-
// Layout components
|
|
615
|
-
if (componentType === 'box' || componentType === 'stack' || componentType === 'flex') {
|
|
616
|
-
baseStyle.display = 'flex';
|
|
617
|
-
baseStyle.flexDirection = comp.props.flexDirection || 'column';
|
|
618
|
-
baseStyle.gap = theme.spacing.sm;
|
|
619
|
-
baseStyle.padding = theme.spacing.md;
|
|
620
|
-
}
|
|
621
|
-
if (componentType === 'stack') {
|
|
622
|
-
const direction = comp.props.direction;
|
|
623
|
-
baseStyle.flexDirection = direction === 'horizontal' ? 'row' : 'column';
|
|
624
|
-
baseStyle.alignItems = comp.props.align || 'stretch';
|
|
625
|
-
baseStyle.justifyContent = comp.props.justify || 'flex-start';
|
|
626
|
-
baseStyle.gap = comp.props.spacing || theme.spacing.sm;
|
|
627
|
-
}
|
|
628
|
-
// Typography components
|
|
629
|
-
if (componentType === 'text') {
|
|
630
|
-
baseStyle.fontSize = getFontSize(comp.props.variant, theme);
|
|
631
|
-
baseStyle.color = theme.colors.text;
|
|
632
|
-
baseStyle.fontFamily = theme.typography.fontFamily;
|
|
633
|
-
baseStyle.lineHeight = 1.5;
|
|
634
|
-
}
|
|
635
|
-
if (componentType === 'heading') {
|
|
636
|
-
const level = comp.props.level || 1;
|
|
637
|
-
baseStyle.fontSize = level === 1 ? theme.typography.fontSize.xl :
|
|
638
|
-
level === 2 ? theme.typography.fontSize.lg :
|
|
639
|
-
theme.typography.fontSize.md;
|
|
640
|
-
baseStyle.fontWeight = theme.typography.fontWeight.semibold;
|
|
641
|
-
baseStyle.color = theme.colors.text;
|
|
642
|
-
baseStyle.marginBottom = theme.spacing.md;
|
|
643
|
-
}
|
|
644
|
-
if (componentType === 'paragraph') {
|
|
645
|
-
baseStyle.fontSize = theme.typography.fontSize.md;
|
|
646
|
-
baseStyle.color = theme.colors.text;
|
|
647
|
-
baseStyle.lineHeight = 1.6;
|
|
648
|
-
baseStyle.marginBottom = theme.spacing.md;
|
|
649
|
-
}
|
|
650
|
-
// Input components
|
|
651
|
-
if (componentType === 'button') {
|
|
652
|
-
const variant = comp.props.variant || 'primary';
|
|
653
|
-
baseStyle.padding = `${theme.spacing.sm} ${theme.spacing.md}`;
|
|
654
|
-
baseStyle.borderRadius = theme.borderRadius.md;
|
|
655
|
-
baseStyle.fontSize = theme.typography.fontSize.sm;
|
|
656
|
-
baseStyle.fontWeight = theme.typography.fontWeight.medium;
|
|
657
|
-
baseStyle.cursor = 'pointer';
|
|
658
|
-
baseStyle.border = 'none';
|
|
659
|
-
baseStyle.transition = 'all 0.2s ease';
|
|
660
|
-
if (variant === 'primary') {
|
|
661
|
-
baseStyle.backgroundColor = theme.colors.primary;
|
|
662
|
-
baseStyle.color = '#FFFFFF';
|
|
663
|
-
}
|
|
664
|
-
else if (variant === 'secondary') {
|
|
665
|
-
baseStyle.backgroundColor = theme.colors.surface;
|
|
666
|
-
baseStyle.color = theme.colors.text;
|
|
667
|
-
baseStyle.border = `1px solid ${theme.colors.border}`;
|
|
668
|
-
}
|
|
669
|
-
else if (variant === 'ghost') {
|
|
670
|
-
baseStyle.backgroundColor = 'transparent';
|
|
671
|
-
baseStyle.color = theme.colors.primary;
|
|
672
|
-
}
|
|
673
|
-
else if (variant === 'danger') {
|
|
674
|
-
baseStyle.backgroundColor = theme.colors.error;
|
|
675
|
-
baseStyle.color = '#FFFFFF';
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
if (componentType === 'input' || componentType === 'textarea') {
|
|
679
|
-
baseStyle.padding = `${theme.spacing.sm} ${theme.spacing.md}`;
|
|
680
|
-
baseStyle.borderRadius = theme.borderRadius.md;
|
|
681
|
-
baseStyle.border = `1px solid ${theme.colors.border}`;
|
|
682
|
-
baseStyle.fontSize = theme.typography.fontSize.sm;
|
|
683
|
-
baseStyle.fontFamily = theme.typography.fontFamily;
|
|
684
|
-
baseStyle.outline = 'none';
|
|
685
|
-
baseStyle.transition = 'border-color 0.2s ease';
|
|
686
|
-
baseStyle.width = '100%';
|
|
687
|
-
baseStyle.boxSizing = 'border-box';
|
|
688
|
-
}
|
|
689
|
-
// Display components
|
|
690
|
-
if (componentType === 'card') {
|
|
691
|
-
baseStyle.backgroundColor = theme.colors.surface;
|
|
692
|
-
baseStyle.borderRadius = comp.props.borderRadius !== undefined
|
|
693
|
-
? `${comp.props.borderRadius}px`
|
|
694
|
-
: `${theme.borderRadius.lg}px`;
|
|
695
|
-
baseStyle.padding = comp.props.padding !== undefined
|
|
696
|
-
? `${comp.props.padding}px`
|
|
697
|
-
: `${theme.spacing.lg}px`;
|
|
698
|
-
const elevation = comp.props.elevation || 1;
|
|
699
|
-
baseStyle.boxShadow = elevation === 0 ? 'none' :
|
|
700
|
-
elevation === 1 ? theme.shadows.sm :
|
|
701
|
-
elevation === 2 ? theme.shadows.md :
|
|
702
|
-
theme.shadows.lg;
|
|
703
|
-
}
|
|
704
|
-
if (componentType === 'badge') {
|
|
705
|
-
const variant = comp.props.variant || 'default';
|
|
706
|
-
baseStyle.display = 'inline-flex';
|
|
707
|
-
baseStyle.alignItems = 'center';
|
|
708
|
-
baseStyle.padding = `${theme.spacing.xs} ${theme.spacing.sm}`;
|
|
709
|
-
baseStyle.borderRadius = theme.borderRadius.full;
|
|
710
|
-
baseStyle.fontSize = theme.typography.fontSize.xs;
|
|
711
|
-
baseStyle.fontWeight = theme.typography.fontWeight.medium;
|
|
712
|
-
const variantColors = {
|
|
713
|
-
default: { bg: theme.colors.surface, color: theme.colors.text },
|
|
714
|
-
success: { bg: '#D1FAE5', color: '#065F46' },
|
|
715
|
-
warning: { bg: '#FEF3C7', color: '#92400E' },
|
|
716
|
-
error: { bg: '#FEE2E2', color: '#991B1B' },
|
|
717
|
-
info: { bg: '#DBEAFE', color: '#1E40AF' },
|
|
718
|
-
};
|
|
719
|
-
const colors = variantColors[variant] || variantColors.default;
|
|
720
|
-
baseStyle.backgroundColor = colors.bg;
|
|
721
|
-
baseStyle.color = colors.color;
|
|
722
|
-
}
|
|
723
|
-
if (componentType === 'image') {
|
|
724
|
-
baseStyle.maxWidth = '100%';
|
|
725
|
-
baseStyle.height = 'auto';
|
|
726
|
-
baseStyle.objectFit = comp.props.objectFit || 'cover';
|
|
727
|
-
baseStyle.borderRadius = theme.borderRadius.md;
|
|
728
|
-
}
|
|
729
|
-
// Merge with component-specific styles
|
|
730
|
-
const mergedStyle = { ...baseStyle, ...(comp.style || {}) };
|
|
731
|
-
// Handle style props
|
|
732
|
-
if (comp.props.backgroundColor) {
|
|
733
|
-
mergedStyle.backgroundColor = comp.props.backgroundColor;
|
|
734
|
-
}
|
|
735
|
-
if (comp.props.borderRadius) {
|
|
736
|
-
mergedStyle.borderRadius = `${comp.props.borderRadius}px`;
|
|
737
|
-
}
|
|
738
|
-
if (comp.props.padding) {
|
|
739
|
-
mergedStyle.padding = `${comp.props.padding}px`;
|
|
740
|
-
}
|
|
741
|
-
if (comp.props.margin) {
|
|
742
|
-
mergedStyle.margin = `${comp.props.margin}px`;
|
|
743
|
-
}
|
|
744
|
-
if (comp.props.width) {
|
|
745
|
-
mergedStyle.width = comp.props.width;
|
|
746
|
-
}
|
|
747
|
-
if (comp.props.height) {
|
|
748
|
-
mergedStyle.height = comp.props.height;
|
|
749
|
-
}
|
|
750
|
-
// Build className from props
|
|
751
|
-
const classNameParts = [];
|
|
752
|
-
if (comp.props.className) {
|
|
753
|
-
classNameParts.push(comp.props.className);
|
|
754
|
-
}
|
|
755
|
-
className = classNameParts.join(' ') || undefined;
|
|
756
|
-
// Process children
|
|
757
|
-
const children = comp.children
|
|
758
|
-
? comp.children.map((child) => applyStylingToNode(child, theme))
|
|
759
|
-
: undefined;
|
|
760
|
-
return {
|
|
761
|
-
id: comp.id,
|
|
762
|
-
type: comp.type,
|
|
763
|
-
props: comp.props,
|
|
764
|
-
style: mergedStyle,
|
|
765
|
-
className,
|
|
766
|
-
children,
|
|
767
|
-
bindings: comp.bindings,
|
|
768
|
-
events: comp.events,
|
|
769
|
-
condition: comp.condition,
|
|
770
|
-
repeat: comp.repeat,
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
/**
|
|
774
|
-
* Get font size based on variant
|
|
775
|
-
*/
|
|
776
|
-
function getFontSize(variant, theme) {
|
|
777
|
-
if (!variant)
|
|
778
|
-
return theme.typography.fontSize.md;
|
|
779
|
-
const sizeMap = {
|
|
780
|
-
heading: theme.typography.fontSize.lg,
|
|
781
|
-
body: theme.typography.fontSize.md,
|
|
782
|
-
caption: theme.typography.fontSize.xs,
|
|
783
|
-
label: theme.typography.fontSize.sm,
|
|
784
|
-
};
|
|
785
|
-
return sizeMap[variant] || theme.typography.fontSize.md;
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Parse markdown UI description to component tree
|
|
789
|
-
*/
|
|
790
|
-
function parseMarkdownToComponents(markdown) {
|
|
791
|
-
const components = [];
|
|
792
|
-
const lines = markdown.split('\n').filter((line) => line.trim());
|
|
793
|
-
const currentList = null;
|
|
794
|
-
const listItems = [];
|
|
795
|
-
for (const line of lines) {
|
|
796
|
-
const trimmed = line.trim();
|
|
797
|
-
// Heading
|
|
798
|
-
if (trimmed.startsWith('#')) {
|
|
799
|
-
const level = trimmed.match(/^#+/)?.[0].length || 1;
|
|
800
|
-
const text = trimmed.replace(/^#+\s*/, '');
|
|
801
|
-
components.push({
|
|
802
|
-
id: generateId(),
|
|
803
|
-
type: 'Heading',
|
|
804
|
-
props: { level, children: text },
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
// Paragraph
|
|
808
|
-
else if (!trimmed.startsWith('-') && !trimmed.startsWith('*') && !trimmed.startsWith('>')) {
|
|
809
|
-
components.push({
|
|
810
|
-
id: generateId(),
|
|
811
|
-
type: 'Text',
|
|
812
|
-
props: { children: trimmed, variant: 'body' },
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
// List item
|
|
816
|
-
else if (trimmed.startsWith('-') || trimmed.startsWith('*')) {
|
|
817
|
-
const text = trimmed.replace(/^[-*]\s*/, '');
|
|
818
|
-
listItems.push({
|
|
819
|
-
id: generateId(),
|
|
820
|
-
type: 'Text',
|
|
821
|
-
props: { children: text },
|
|
822
|
-
});
|
|
823
|
-
}
|
|
824
|
-
// Blockquote
|
|
825
|
-
else if (trimmed.startsWith('>')) {
|
|
826
|
-
const text = trimmed.replace(/^>\s*/, '');
|
|
827
|
-
components.push({
|
|
828
|
-
id: generateId(),
|
|
829
|
-
type: 'Text',
|
|
830
|
-
props: { children: text, variant: 'caption', style: { fontStyle: 'italic', borderLeft: '3px solid #E5E7EB', paddingLeft: '12px' } },
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
// If we have list items, wrap them in a Stack
|
|
835
|
-
if (listItems.length > 0) {
|
|
836
|
-
components.push({
|
|
837
|
-
id: generateId(),
|
|
838
|
-
type: 'Stack',
|
|
839
|
-
props: { direction: 'vertical', spacing: 4 },
|
|
840
|
-
children: listItems,
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
return components;
|
|
844
|
-
}
|
|
845
|
-
/**
|
|
846
|
-
* LLM-to-IX Pipeline
|
|
847
|
-
*
|
|
848
|
-
* Main pipeline function that:
|
|
849
|
-
* 1. Parses LLM output (JSON or markdown)
|
|
850
|
-
* 2. Transforms to IX component tree
|
|
851
|
-
* 3. Applies A2R-IX styling
|
|
852
|
-
* 4. Returns IxRenderTree
|
|
853
|
-
*/
|
|
854
|
-
export function llmToIxPipeline(options) {
|
|
855
|
-
const startTime = Date.now();
|
|
856
|
-
const pipelineOptions = options.options || {};
|
|
857
|
-
// Parse input
|
|
858
|
-
const parseStart = Date.now();
|
|
859
|
-
const format = detectInputFormat(options.input);
|
|
860
|
-
let convertResult;
|
|
861
|
-
// Handle markdown input
|
|
862
|
-
if (format === 'natural-language' && typeof options.input === 'string') {
|
|
863
|
-
// Check if it looks like markdown
|
|
864
|
-
if (options.input.includes('#') || options.input.includes('- ') || options.input.includes('> ')) {
|
|
865
|
-
const components = parseMarkdownToComponents(options.input);
|
|
866
|
-
const ui = {
|
|
867
|
-
version: pipelineOptions.version || '1.0.0',
|
|
868
|
-
components,
|
|
869
|
-
state: { variables: [] },
|
|
870
|
-
actions: [],
|
|
871
|
-
};
|
|
872
|
-
convertResult = {
|
|
873
|
-
ui,
|
|
874
|
-
warnings: ['Parsed from markdown'],
|
|
875
|
-
inferredState: [],
|
|
876
|
-
confidence: 0.7,
|
|
877
|
-
};
|
|
878
|
-
}
|
|
879
|
-
else {
|
|
880
|
-
convertResult = convertFromNaturalLanguage(options.input, {
|
|
881
|
-
version: pipelineOptions.version,
|
|
882
|
-
generateIds: pipelineOptions.generateIds,
|
|
883
|
-
validate: pipelineOptions.validate,
|
|
884
|
-
inferState: pipelineOptions.inferState,
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
else {
|
|
889
|
-
convertResult = convertLLMToIX(options.input, {
|
|
890
|
-
version: pipelineOptions.version,
|
|
891
|
-
generateIds: pipelineOptions.generateIds,
|
|
892
|
-
validate: pipelineOptions.validate,
|
|
893
|
-
inferState: pipelineOptions.inferState,
|
|
894
|
-
});
|
|
895
|
-
}
|
|
896
|
-
const parseTime = Date.now() - parseStart;
|
|
897
|
-
// Transform to render tree
|
|
898
|
-
const transformStart = Date.now();
|
|
899
|
-
const theme = pipelineOptions.theme ? getTheme(pipelineOptions.theme) : IX_THEMES.default;
|
|
900
|
-
const styledComponents = pipelineOptions.applyStyling !== false
|
|
901
|
-
? applyStylingToTree(convertResult.ui.components, theme)
|
|
902
|
-
: convertResult.ui.components.map((comp) => ({
|
|
903
|
-
id: comp.id,
|
|
904
|
-
type: comp.type,
|
|
905
|
-
props: comp.props,
|
|
906
|
-
style: comp.style || {},
|
|
907
|
-
className: comp.className,
|
|
908
|
-
children: comp.children?.map((child) => ({
|
|
909
|
-
id: child.id,
|
|
910
|
-
type: child.type,
|
|
911
|
-
props: child.props,
|
|
912
|
-
style: child.style || {},
|
|
913
|
-
className: child.className,
|
|
914
|
-
children: child.children?.map((c) => ({
|
|
915
|
-
id: c.id,
|
|
916
|
-
type: c.type,
|
|
917
|
-
props: c.props,
|
|
918
|
-
style: c.style || {},
|
|
919
|
-
className: c.className,
|
|
920
|
-
})),
|
|
921
|
-
bindings: child.bindings,
|
|
922
|
-
events: child.events,
|
|
923
|
-
})),
|
|
924
|
-
bindings: comp.bindings,
|
|
925
|
-
events: comp.events,
|
|
926
|
-
condition: comp.condition,
|
|
927
|
-
repeat: comp.repeat,
|
|
928
|
-
}));
|
|
929
|
-
const transformTime = Date.now() - transformStart;
|
|
930
|
-
// Apply styling
|
|
931
|
-
const styleStart = Date.now();
|
|
932
|
-
const styles = {};
|
|
933
|
-
if (pipelineOptions.applyStyling !== false) {
|
|
934
|
-
// Generate CSS classes for components
|
|
935
|
-
styledComponents.forEach((comp) => {
|
|
936
|
-
styles[comp.id] = comp.style;
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
|
-
const styleTime = Date.now() - styleStart;
|
|
940
|
-
const totalTime = Date.now() - startTime;
|
|
941
|
-
// Build render tree
|
|
942
|
-
const tree = {
|
|
943
|
-
version: convertResult.ui.version,
|
|
944
|
-
components: styledComponents,
|
|
945
|
-
state: convertResult.ui.state,
|
|
946
|
-
actions: convertResult.ui.actions,
|
|
947
|
-
theme: pipelineOptions.applyStyling !== false ? theme : undefined,
|
|
948
|
-
styles: pipelineOptions.applyStyling !== false ? styles : undefined,
|
|
949
|
-
metadata: {
|
|
950
|
-
generatedAt: new Date().toISOString(),
|
|
951
|
-
},
|
|
952
|
-
};
|
|
953
|
-
return {
|
|
954
|
-
tree,
|
|
955
|
-
uiRoot: convertResult.ui,
|
|
956
|
-
warnings: convertResult.warnings,
|
|
957
|
-
inferredState: convertResult.inferredState,
|
|
958
|
-
confidence: convertResult.confidence,
|
|
959
|
-
metrics: {
|
|
960
|
-
parseTime,
|
|
961
|
-
transformTime,
|
|
962
|
-
styleTime,
|
|
963
|
-
totalTime,
|
|
964
|
-
},
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
/**
|
|
968
|
-
* LLM-to-IX Pipeline API
|
|
969
|
-
*/
|
|
970
|
-
export const llmToIX = {
|
|
971
|
-
/**
|
|
972
|
-
* Convert LLM output to IX format
|
|
973
|
-
*/
|
|
974
|
-
convert: convertLLMToIX,
|
|
975
|
-
/**
|
|
976
|
-
* Detect input format
|
|
977
|
-
*/
|
|
978
|
-
detectFormat: detectInputFormat,
|
|
979
|
-
/**
|
|
980
|
-
* Check if input is valid json-render
|
|
981
|
-
*/
|
|
982
|
-
isJsonRender: (input) => jsonRenderAdapter.isValidSchema(input),
|
|
983
|
-
/**
|
|
984
|
-
* Quick convert from json-render
|
|
985
|
-
*/
|
|
986
|
-
fromJsonRender: (schema, options) => convertFromJsonRender(schema, options || {}),
|
|
987
|
-
/**
|
|
988
|
-
* Quick convert from JSX-like
|
|
989
|
-
*/
|
|
990
|
-
fromJSX: (jsx, options) => convertFromJSXLike(jsx, options || {}),
|
|
991
|
-
};
|
|
992
|
-
//# sourceMappingURL=llm-to-ix.js.map
|