0x-lang 0.1.18 → 0.1.19

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/ast.d.ts CHANGED
@@ -136,6 +136,7 @@ export interface ComponentCall extends BaseNode {
136
136
  type: 'ComponentCall';
137
137
  name: string;
138
138
  args: Record<string, Expression>;
139
+ children?: UINode[];
139
140
  }
140
141
  export interface IfBlock extends BaseNode {
141
142
  type: 'IfBlock';
@@ -189,6 +190,10 @@ export interface JsBlock extends BaseNode {
189
190
  type: 'JsBlock';
190
191
  code: string;
191
192
  }
193
+ export interface RawBlock extends BaseNode {
194
+ type: 'RawBlock';
195
+ code: string;
196
+ }
192
197
  export interface TopLevelVarDecl extends BaseNode {
193
198
  type: 'TopLevelVarDecl';
194
199
  keyword: 'const' | 'let';
@@ -909,8 +914,8 @@ export interface RtlNode extends BaseNode {
909
914
  enabled: boolean;
910
915
  props: Record<string, Expression>;
911
916
  }
912
- export type UINode = LayoutNode | TextNode | ButtonNode | InputNode | ImageNode | LinkNode | ToggleNode | SelectNode | IfBlock | ForBlock | ShowBlock | HideBlock | ComponentCall | CommentNode | TableNode | ChartNode | StatNode | NavNode | UploadNode | ModalNode | ToastNode | CrudNode | ListNode | LayoutShellNode | SlideOverNode | DrawerNode | CommandNode | ConfirmNode | PayNode | CartNode | MediaNode | NotificationNode | SearchNode | FilterNode | SocialNode | ProfileNode | HeroNode | FeaturesNode | PricingNode | FaqNode | TestimonialNode | FooterNode | AdminNode | SeoNode | A11yNode | AnimateNode | GestureNode | AiNode | AutomationNode | DevNode | EmitNode | ResponsiveNode | BreadcrumbNode | StatsGridNode | DividerNode | ProgressNode | ErrorNode | LoadingNode | OfflineNode | RetryNode | LogNode;
913
- export type ASTNode = AppNode | PageNode | ComponentNode | StateDecl | DerivedDecl | PropDecl | TypeDecl | StoreDecl | ApiDecl | FnDecl | OnMount | OnDestroy | WatchBlock | CheckDecl | StyleDecl | JsImport | UseImport | JsBlock | TopLevelVarDecl | ModelNode | DataDecl | FormDecl | AuthDecl | RealtimeDecl | RouteDecl | RoleDecl | AutomationNode | DevNode | DeployNode | EnvNode | DockerNode | CiNode | DomainNode | CdnNode | MonitorNode | BackupNode | EndpointNode | MiddlewareNode | QueueNode | CronNode | CacheNode | MigrateNode | SeedNode | WebhookNode | StorageNode | TestNode | E2eNode | MockNode | FixtureNode | I18nNode | LocaleNode | RtlNode | UINode;
917
+ export type UINode = LayoutNode | TextNode | ButtonNode | InputNode | ImageNode | LinkNode | ToggleNode | SelectNode | IfBlock | ForBlock | ShowBlock | HideBlock | ComponentCall | CommentNode | TableNode | ChartNode | StatNode | NavNode | UploadNode | ModalNode | ToastNode | CrudNode | ListNode | LayoutShellNode | SlideOverNode | DrawerNode | CommandNode | ConfirmNode | PayNode | CartNode | MediaNode | NotificationNode | SearchNode | FilterNode | SocialNode | ProfileNode | HeroNode | FeaturesNode | PricingNode | FaqNode | TestimonialNode | FooterNode | AdminNode | SeoNode | A11yNode | AnimateNode | GestureNode | AiNode | AutomationNode | DevNode | EmitNode | ResponsiveNode | BreadcrumbNode | StatsGridNode | DividerNode | ProgressNode | ErrorNode | LoadingNode | OfflineNode | RetryNode | LogNode | RawBlock;
918
+ export type ASTNode = AppNode | PageNode | ComponentNode | StateDecl | DerivedDecl | PropDecl | TypeDecl | StoreDecl | ApiDecl | FnDecl | OnMount | OnDestroy | WatchBlock | CheckDecl | StyleDecl | JsImport | UseImport | JsBlock | RawBlock | TopLevelVarDecl | ModelNode | DataDecl | FormDecl | AuthDecl | RealtimeDecl | RouteDecl | RoleDecl | AutomationNode | DevNode | DeployNode | EnvNode | DockerNode | CiNode | DomainNode | CdnNode | MonitorNode | BackupNode | EndpointNode | MiddlewareNode | QueueNode | CronNode | CacheNode | MigrateNode | SeedNode | WebhookNode | StorageNode | TestNode | E2eNode | MockNode | FixtureNode | I18nNode | LocaleNode | RtlNode | UINode;
914
919
  export interface CodeGenerator {
915
920
  target: string;
916
921
  generate(ast: PageNode | ComponentNode | AppNode): GeneratedCode;
@@ -102,6 +102,39 @@ api userApi:
102
102
  - \`chart\` — data visualization (bar, line, pie)
103
103
  - \`upload\` — file upload handler
104
104
 
105
+ ### CSS Classes & Passthrough Props
106
+ \`\`\`
107
+ layout col class="container mx-auto p-4":
108
+ text "Title" class="text-xl font-bold"
109
+ button "Save" -> save() class="btn btn-primary"
110
+ input name class="input" aria-label="Name" data-testid="name-input"
111
+ \`\`\`
112
+ - \`class\` prop adds className (React) or class (Vue/Svelte) — works with Tailwind, Bootstrap, etc.
113
+ - Unknown props (data-*, aria-*, role, etc.) are passed through as HTML attributes.
114
+
115
+ ### Raw Block (Framework Escape Hatch)
116
+ \`\`\`
117
+ raw:
118
+ <CustomComponent onSpecialEvent={handler} />
119
+ raw { <div dangerouslySetInnerHTML={{__html: content}} /> }
120
+ \`\`\`
121
+ - \`raw:\` inserts code directly into JSX/template output (different from \`js:\` which goes into script).
122
+ - Use for framework-specific code that 0x doesn't abstract.
123
+
124
+ ### Component with Children
125
+ \`\`\`
126
+ component Dialog(title="Settings"):
127
+ text "Content inside dialog"
128
+ button "Close" -> close()
129
+ \`\`\`
130
+ - When \`component\` call has \`:\`, children are wrapped inside the component tags.
131
+ - Without \`:\`, component renders as self-closing: \`component Card(item)\`
132
+
133
+ ### Performance (React Target)
134
+ - \`fn\` declarations are automatically wrapped in \`useCallback\` with auto-extracted deps.
135
+ - Components with props are wrapped in \`React.memo\` for render optimization.
136
+ - \`derived\` values use \`useMemo\` with auto-extracted deps.
137
+
105
138
  ### Styles
106
139
  \`\`\`
107
140
  style card:
@@ -1 +1 @@
1
- {"version":3,"file":"ai-bridge.js","sourceRoot":"","sources":["../../src/generators/ai-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai-bridge.js","sourceRoot":"","sources":["../../src/generators/ai-bridge.ts"],"names":[],"mappings":"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"}
@@ -277,6 +277,9 @@ function generateTopLevel(node) {
277
277
  case 'JsBlock':
278
278
  hookLines.push(child.code);
279
279
  break;
280
+ case 'RawBlock':
281
+ jsxParts.push(child.code);
282
+ break;
280
283
  case 'TopLevelVarDecl': {
281
284
  const tlv = child;
282
285
  hookLines.push(`${tlv.keyword} ${tlv.name} = ${genExpr(tlv.value, c)};`);
@@ -299,10 +302,13 @@ function generateTopLevel(node) {
299
302
  const propsArg = props.length > 0
300
303
  ? `{ ${props.map(p => p.defaultValue ? `${p.name} = ${genExpr(p.defaultValue, c)}` : p.name).join(', ')} }`
301
304
  : '';
305
+ // Build component
306
+ const isComponent = node.type === 'Component';
307
+ const needsMemo = isComponent && props.length > 0;
302
308
  // Build import line — only import hooks that are actually used
303
309
  const hookNames = Array.from(c.imports).sort();
304
310
  // Check if React.Fragment is used in JSX (for loops, show/hide with multiple children)
305
- const needsReact = jsxParts.some(p => p.includes('React.Fragment'));
311
+ const needsReact = jsxParts.some(p => p.includes('React.Fragment')) || needsMemo;
306
312
  const importLine = needsReact && hookNames.length > 0
307
313
  ? `import React, { ${hookNames.join(', ')} } from 'react';`
308
314
  : needsReact
@@ -327,8 +333,6 @@ function generateTopLevel(node) {
327
333
  userImports.push(`import ${ui.name} from '${ui.source}';`);
328
334
  }
329
335
  }
330
- // Build component
331
- const isComponent = node.type === 'Component';
332
336
  const exportKw = isComponent ? '' : 'export default ';
333
337
  // Add "use client" for Next.js SSR when client-side hooks are used
334
338
  const needsClient = c.imports.has('useState') || c.imports.has('useEffect') || c.imports.has('useRef') || c.imports.has('useCallback');
@@ -347,9 +351,14 @@ function generateTopLevel(node) {
347
351
  ' );',
348
352
  '}',
349
353
  ];
350
- // If component, also export it
354
+ // If component, also export it (with React.memo if it has props)
351
355
  if (isComponent) {
352
- lines.push('', `export { ${node.name} };`);
356
+ if (needsMemo) {
357
+ lines.push('', `const Memoized${node.name} = React.memo(${node.name});`, `export { Memoized${node.name} as ${node.name} };`);
358
+ }
359
+ else {
360
+ lines.push('', `export { ${node.name} };`);
361
+ }
353
362
  }
354
363
  return lines.filter(l => l !== undefined).join('\n');
355
364
  }
@@ -395,6 +404,7 @@ function genStore(node, c) {
395
404
  }
396
405
  // ── Functions ───────────────────────────────────────
397
406
  function genFunction(node, c) {
407
+ c.imports.add('useCallback');
398
408
  const params = node.params.map(p => p.name).join(', ');
399
409
  const asyncKw = node.isAsync ? 'async ' : '';
400
410
  const body = node.body.map(s => genStatement(s, c)).join('\n ');
@@ -402,7 +412,11 @@ function genFunction(node, c) {
402
412
  const requireChecks = node.requires.map(r => `if (!(${genExpr(r, c)})) throw new Error('Precondition failed');`).join('\n ');
403
413
  const allBody = [requireChecks, body].filter(Boolean).join('\n ');
404
414
  const sc = node.loc?.line ? `// 0x:L${node.loc.line}\n ` : '';
405
- return `${sc}const ${node.name} = ${asyncKw}(${params}) => {\n ${allBody}\n };`;
415
+ // Extract deps from function body (exclude function params)
416
+ const paramNames = new Set(node.params.map(p => p.name));
417
+ const { deps, warning } = extractDepsFromStmts(node.body, c, paramNames);
418
+ const warnComment = warning ? `${warning}\n ` : '';
419
+ return `${sc}${warnComment}const ${node.name} = useCallback(${asyncKw}(${params}) => {\n ${allBody}\n }, [${deps.join(', ')}]);`;
406
420
  }
407
421
  // ── Lifecycle ───────────────────────────────────────
408
422
  function genOnMount(node, c) {
@@ -451,6 +465,7 @@ function genUINode(node, c) {
451
465
  case 'ShowBlock': return genShow(node, c);
452
466
  case 'HideBlock': return genHide(node, c);
453
467
  case 'ComponentCall': return genComponentCall(node, c);
468
+ case 'RawBlock': return node.code;
454
469
  case 'Table': return genTableUI(node, c);
455
470
  case 'Chart': return genChartUI(node, c);
456
471
  case 'Stat': return genStatUI(node, c);
@@ -862,7 +877,13 @@ function genComponentCall(node, c) {
862
877
  parts.push(`${key}={${genExpr(val, c)}}`);
863
878
  }
864
879
  }
865
- return `<${node.name} ${parts.join(' ')} />`;
880
+ const propsStr = parts.length > 0 ? ` ${parts.join(' ')}` : '';
881
+ // Component with children: <Name props>{children}</Name>
882
+ if (node.children && node.children.length > 0) {
883
+ const childrenJsx = node.children.map(ch => genUINode(ch, c)).join('\n');
884
+ return `<${node.name}${propsStr}>\n${childrenJsx}\n</${node.name}>`;
885
+ }
886
+ return `<${node.name}${propsStr} />`;
866
887
  }
867
888
  // ── Control Flow ────────────────────────────────────
868
889
  // Wrap ternary branch body in fragment if it contains JS expressions ({...})
@@ -2583,6 +2604,26 @@ function extractDepsWithWarning(expr, c) {
2583
2604
  : null;
2584
2605
  return { deps: Array.from(deps), warning };
2585
2606
  }
2607
+ function extractDepsFromStmts(stmts, c, paramNames) {
2608
+ const deps = new Set();
2609
+ const unknowns = new Set();
2610
+ walkStmts(stmts, e => {
2611
+ if (e.kind === 'identifier') {
2612
+ if (paramNames.has(e.name))
2613
+ return; // Skip function params
2614
+ if (c.states.has(e.name) || c.derivedNames.has(e.name) || c.propNames.has(e.name)) {
2615
+ deps.add(e.name);
2616
+ }
2617
+ else if (!KNOWN_GLOBALS.has(e.name)) {
2618
+ unknowns.add(e.name);
2619
+ }
2620
+ }
2621
+ });
2622
+ const warning = unknowns.size > 0
2623
+ ? `/* 0x-warn: untracked deps: ${Array.from(unknowns).join(', ')} */`
2624
+ : null;
2625
+ return { deps: Array.from(deps), warning };
2626
+ }
2586
2627
  function walkExpr(expr, fn) {
2587
2628
  fn(expr);
2588
2629
  switch (expr.kind) {