0x-lang 0.1.17 → 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 +7 -2
- package/dist/compiler.js +1 -1
- package/dist/compiler.js.map +1 -1
- package/dist/generators/ai-bridge.js +33 -0
- package/dist/generators/ai-bridge.js.map +1 -1
- package/dist/generators/react.js +59 -10
- package/dist/generators/react.js.map +1 -1
- package/dist/generators/shared.js +5 -0
- package/dist/generators/shared.js.map +1 -1
- package/dist/generators/svelte.js +10 -1
- package/dist/generators/svelte.js.map +1 -1
- package/dist/generators/vue.js +10 -1
- package/dist/generators/vue.js.map +1 -1
- package/dist/parser.js +74 -5
- package/dist/parser.js.map +1 -1
- package/dist/tokenizer.js +1 -1
- package/dist/tokenizer.js.map +1 -1
- package/dist/validator.js +4 -0
- package/dist/validator.js.map +1 -1
- package/package.json +1 -1
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;
|
package/dist/compiler.js
CHANGED
|
@@ -42,7 +42,7 @@ export function compile(source, options) {
|
|
|
42
42
|
}
|
|
43
43
|
// Post-process: strip source map comments and V3 source map if disabled
|
|
44
44
|
if (options.sourceMap === false) {
|
|
45
|
-
result = { ...result, code: result.code.replace(/\{\/\* 0x:L\d+ \*\/\}/g, '').replace(/<!-- 0x:L\d+ -->/g, ''), sourceMap: undefined };
|
|
45
|
+
result = { ...result, code: result.code.replace(/\{\/\* 0x:L\d+ \*\/\}/g, '').replace(/<!-- 0x:L\d+ -->/g, '').replace(/\/\/ 0x:L\d+\n\s*/g, ''), sourceMap: undefined };
|
|
46
46
|
}
|
|
47
47
|
else if (result.sourceMap) {
|
|
48
48
|
// Append inline sourceMappingURL as base64 data URL
|
package/dist/compiler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.js","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,uBAAuB;AAEvB,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAgB1C,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,OAAuB;IAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAE1B,8BAA8B;IAC9B,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClG,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,IAAI,MAAqB,CAAC;IAC1B,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;QACvB,KAAK,OAAO;YACV,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;YAC5B,MAAM;QACR,KAAK,KAAK;YACR,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;YAC1B,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM;QACR,KAAK,SAAS;YACZ,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM;QACR,KAAK,cAAc;YACjB,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;YAClC,MAAM;QACR,KAAK,WAAW;YACd,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAChC,MAAM;QACR;YACE,MAAM,IAAI,KAAK,CAAC,mBAAmB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,wEAAwE;IACxE,IAAI,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE,CAAC;QAChC,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"compiler.js","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"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"}
|
|
@@ -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":"AAAA,qBAAqB;AACrB,iFAAiF;AAKjF,6FAA6F;AAC7F,MAAM,UAAU,eAAe;IAC7B,OAAO
|
|
1
|
+
{"version":3,"file":"ai-bridge.js","sourceRoot":"","sources":["../../src/generators/ai-bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/generators/react.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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);
|
|
@@ -579,9 +594,17 @@ function genLayout(node, c) {
|
|
|
579
594
|
break;
|
|
580
595
|
case 'scroll': {
|
|
581
596
|
const sv = unquote(v);
|
|
582
|
-
|
|
597
|
+
if (sv === 'y')
|
|
598
|
+
style['overflowY'] = 'auto';
|
|
599
|
+
else if (sv === 'x')
|
|
600
|
+
style['overflowX'] = 'auto';
|
|
601
|
+
else
|
|
602
|
+
style['overflow'] = 'auto';
|
|
583
603
|
break;
|
|
584
604
|
}
|
|
605
|
+
case 'wrap':
|
|
606
|
+
style['flexWrap'] = 'wrap';
|
|
607
|
+
break;
|
|
585
608
|
case 'radius':
|
|
586
609
|
style['borderRadius'] = addPx(v);
|
|
587
610
|
break;
|
|
@@ -683,11 +706,11 @@ function genText(node, c) {
|
|
|
683
706
|
let result = `${sc}<span${classAttr}${styleStr}${extra}>${content}</span>`;
|
|
684
707
|
if (badgeExpr) {
|
|
685
708
|
const badge = genExpr(badgeExpr, c);
|
|
686
|
-
result = `<span style={{ position: 'relative', display: 'inline-flex', alignItems: 'center' }}>\n<span${styleStr}>${content}</span>\n<span style={{ marginLeft: '6px', padding: '2px 6px', fontSize: '12px', fontWeight: 'bold', borderRadius: '9999px', backgroundColor: '#ef4444', color: '#fff', minWidth: '20px', textAlign: 'center' }}>{${badge}}</span>\n</span>`;
|
|
709
|
+
result = `<span${classAttr} style={{ position: 'relative', display: 'inline-flex', alignItems: 'center' }}>\n<span${styleStr}>${content}</span>\n<span style={{ marginLeft: '6px', padding: '2px 6px', fontSize: '12px', fontWeight: 'bold', borderRadius: '9999px', backgroundColor: '#ef4444', color: '#fff', minWidth: '20px', textAlign: 'center' }}>{${badge}}</span>\n</span>`;
|
|
687
710
|
}
|
|
688
711
|
if (tooltipExpr) {
|
|
689
712
|
const tooltip = genExpr(tooltipExpr, c);
|
|
690
|
-
result = `<span title={${tooltip}}>${badgeExpr ? result.replace(/^<span
|
|
713
|
+
result = `<span${classAttr} title={${tooltip}}>${badgeExpr ? result.replace(/^<span[^>]*>/, '<span>') : `<span${styleStr}>${content}</span>`}</span>`;
|
|
691
714
|
}
|
|
692
715
|
return result;
|
|
693
716
|
}
|
|
@@ -854,7 +877,13 @@ function genComponentCall(node, c) {
|
|
|
854
877
|
parts.push(`${key}={${genExpr(val, c)}}`);
|
|
855
878
|
}
|
|
856
879
|
}
|
|
857
|
-
|
|
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} />`;
|
|
858
887
|
}
|
|
859
888
|
// ── Control Flow ────────────────────────────────────
|
|
860
889
|
// Wrap ternary branch body in fragment if it contains JS expressions ({...})
|
|
@@ -2575,6 +2604,26 @@ function extractDepsWithWarning(expr, c) {
|
|
|
2575
2604
|
: null;
|
|
2576
2605
|
return { deps: Array.from(deps), warning };
|
|
2577
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
|
+
}
|
|
2578
2627
|
function walkExpr(expr, fn) {
|
|
2579
2628
|
fn(expr);
|
|
2580
2629
|
switch (expr.kind) {
|