0x-lang 0.1.9 → 0.1.11
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 +10 -1
- package/dist/generators/react.js +90 -7
- package/dist/generators/react.js.map +1 -1
- package/dist/generators/svelte.js +56 -2
- package/dist/generators/svelte.js.map +1 -1
- package/dist/generators/vue.js +56 -2
- package/dist/generators/vue.js.map +1 -1
- package/dist/parser.js +78 -2
- package/dist/parser.js.map +1 -1
- package/dist/tokenizer.js +61 -2
- package/dist/tokenizer.js.map +1 -1
- package/package.json +1 -1
package/dist/ast.d.ts
CHANGED
|
@@ -700,6 +700,15 @@ export interface BreadcrumbNode extends BaseNode {
|
|
|
700
700
|
type: 'Breadcrumb';
|
|
701
701
|
props: Record<string, Expression>;
|
|
702
702
|
}
|
|
703
|
+
export interface DividerNode extends BaseNode {
|
|
704
|
+
type: 'Divider';
|
|
705
|
+
props: Record<string, Expression>;
|
|
706
|
+
}
|
|
707
|
+
export interface ProgressNode extends BaseNode {
|
|
708
|
+
type: 'Progress';
|
|
709
|
+
value: Expression;
|
|
710
|
+
props: Record<string, Expression>;
|
|
711
|
+
}
|
|
703
712
|
export interface StatsGridNode extends BaseNode {
|
|
704
713
|
type: 'StatsGrid';
|
|
705
714
|
cols: number;
|
|
@@ -893,7 +902,7 @@ export interface RtlNode extends BaseNode {
|
|
|
893
902
|
enabled: boolean;
|
|
894
903
|
props: Record<string, Expression>;
|
|
895
904
|
}
|
|
896
|
-
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 | ErrorNode | LoadingNode | OfflineNode | RetryNode | LogNode;
|
|
905
|
+
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;
|
|
897
906
|
export type ASTNode = AppNode | PageNode | ComponentNode | StateDecl | DerivedDecl | PropDecl | TypeDecl | StoreDecl | ApiDecl | FnDecl | OnMount | OnDestroy | WatchBlock | CheckDecl | StyleDecl | JsImport | UseImport | JsBlock | 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;
|
|
898
907
|
export interface CodeGenerator {
|
|
899
908
|
target: string;
|
package/dist/generators/react.js
CHANGED
|
@@ -249,6 +249,16 @@ function generateTopLevel(node) {
|
|
|
249
249
|
case 'Rtl':
|
|
250
250
|
// Handled at top level
|
|
251
251
|
break;
|
|
252
|
+
case 'JsImport':
|
|
253
|
+
// Handled separately in import section
|
|
254
|
+
break;
|
|
255
|
+
case 'UseImport':
|
|
256
|
+
// use X from "source" → import + hook call
|
|
257
|
+
hookLines.push(`const ${child.name} = ${child.name}();`);
|
|
258
|
+
break;
|
|
259
|
+
case 'JsBlock':
|
|
260
|
+
hookLines.push(child.code);
|
|
261
|
+
break;
|
|
252
262
|
case 'StyleDecl':
|
|
253
263
|
// Collected already, used by reference
|
|
254
264
|
break;
|
|
@@ -273,12 +283,30 @@ function generateTopLevel(node) {
|
|
|
273
283
|
reactImports.push(...hookNames);
|
|
274
284
|
}
|
|
275
285
|
const importLine = `import ${reactImports[0]}, { ${hookNames.join(', ')} } from 'react';`;
|
|
286
|
+
// Collect user imports (js import / import / use)
|
|
287
|
+
const userImports = [];
|
|
288
|
+
for (const child of node.body) {
|
|
289
|
+
if (child.type === 'JsImport') {
|
|
290
|
+
const ji = child;
|
|
291
|
+
if (ji.isDefault) {
|
|
292
|
+
userImports.push(`import ${ji.specifiers[0]} from '${ji.source}';`);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
userImports.push(`import { ${ji.specifiers.join(', ')} } from '${ji.source}';`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else if (child.type === 'UseImport') {
|
|
299
|
+
const ui = child;
|
|
300
|
+
userImports.push(`import ${ui.name} from '${ui.source}';`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
276
303
|
// Build component
|
|
277
304
|
const isComponent = node.type === 'Component';
|
|
278
305
|
const exportKw = isComponent ? '' : 'export default ';
|
|
279
306
|
const lines = [
|
|
280
307
|
`// Generated by 0x`,
|
|
281
308
|
hookNames.length > 0 ? importLine : `import React from 'react';`,
|
|
309
|
+
...userImports,
|
|
282
310
|
'',
|
|
283
311
|
`${exportKw}function ${node.name}(${propsArg}) {`,
|
|
284
312
|
...hookLines.map(l => ` ${l}`),
|
|
@@ -431,6 +459,13 @@ function genUINode(node, c) {
|
|
|
431
459
|
case 'Offline': return genOfflineUI(node, c);
|
|
432
460
|
case 'Retry': return `{/* retry: max=${genExpr(node.maxRetries, c)} */}`;
|
|
433
461
|
case 'Log': return `{/* log: ${genExpr(node.message, c)} */}`;
|
|
462
|
+
case 'Divider': return `<hr style={{ border: 'none', borderTop: '1px solid #e2e8f0', margin: '16px 0' }} />`;
|
|
463
|
+
case 'Progress': {
|
|
464
|
+
const pn = node;
|
|
465
|
+
const val = genExpr(pn.value, c);
|
|
466
|
+
const max = pn.props['max'] ? genExpr(pn.props['max'], c) : '100';
|
|
467
|
+
return `<div style={{ width: '100%', backgroundColor: '#e2e8f0', borderRadius: '9999px', height: '8px', overflow: 'hidden' }}>\n<div style={{ width: \`\${(${val} / ${max}) * 100}%\`, backgroundColor: '#3b82f6', height: '100%', borderRadius: '9999px', transition: 'width 0.3s' }} />\n</div>`;
|
|
468
|
+
}
|
|
434
469
|
default: return `{/* unsupported: ${node.type} */}`;
|
|
435
470
|
}
|
|
436
471
|
}
|
|
@@ -498,20 +533,24 @@ function genLayout(node, c) {
|
|
|
498
533
|
case 'grow':
|
|
499
534
|
style['flexGrow'] = v;
|
|
500
535
|
break;
|
|
501
|
-
case 'scroll':
|
|
502
|
-
|
|
536
|
+
case 'scroll': {
|
|
537
|
+
const sv = unquote(v);
|
|
538
|
+
style['overflow' + (sv === 'y' ? 'Y' : 'X')] = 'auto';
|
|
503
539
|
break;
|
|
540
|
+
}
|
|
504
541
|
case 'radius':
|
|
505
542
|
style['borderRadius'] = addPx(v);
|
|
506
543
|
break;
|
|
507
|
-
case 'shadow':
|
|
508
|
-
|
|
544
|
+
case 'shadow': {
|
|
545
|
+
const sv = unquote(v);
|
|
546
|
+
if (sv === 'sm')
|
|
509
547
|
style['boxShadow'] = '0 1px 2px rgba(0,0,0,0.1)';
|
|
510
|
-
else if (
|
|
548
|
+
else if (sv === 'md')
|
|
511
549
|
style['boxShadow'] = '0 4px 6px rgba(0,0,0,0.1)';
|
|
512
|
-
else if (
|
|
550
|
+
else if (sv === 'lg')
|
|
513
551
|
style['boxShadow'] = '0 10px 15px rgba(0,0,0,0.1)';
|
|
514
552
|
break;
|
|
553
|
+
}
|
|
515
554
|
}
|
|
516
555
|
}
|
|
517
556
|
// Apply style class
|
|
@@ -584,7 +623,19 @@ function genText(node, c) {
|
|
|
584
623
|
}
|
|
585
624
|
const content = genTextContent(node.content, c);
|
|
586
625
|
const styleStr = Object.keys(style).length > 0 ? ` style={${genStyleObj(style, dynamicKeys)}}` : '';
|
|
587
|
-
|
|
626
|
+
// Badge prop: render a badge indicator next to content
|
|
627
|
+
const badgeExpr = node.props['badge'];
|
|
628
|
+
const tooltipExpr = node.props['tooltip'];
|
|
629
|
+
let result = `<span${styleStr}>${content}</span>`;
|
|
630
|
+
if (badgeExpr) {
|
|
631
|
+
const badge = genExpr(badgeExpr, c);
|
|
632
|
+
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>`;
|
|
633
|
+
}
|
|
634
|
+
if (tooltipExpr) {
|
|
635
|
+
const tooltip = genExpr(tooltipExpr, c);
|
|
636
|
+
result = `<span title={${tooltip}}>${badgeExpr ? result.replace(/^<span/, '<span') : `<span${styleStr}>${content}</span>`}</span>`;
|
|
637
|
+
}
|
|
638
|
+
return result;
|
|
588
639
|
}
|
|
589
640
|
function genButton(node, c) {
|
|
590
641
|
const label = genTextContent(node.label, c);
|
|
@@ -634,6 +685,7 @@ function genInput(node, c) {
|
|
|
634
685
|
function genImage(node, c) {
|
|
635
686
|
const src = genExpr(node.src, c);
|
|
636
687
|
const props = [`src={${src}}`];
|
|
688
|
+
const style = {};
|
|
637
689
|
for (const [key, val] of Object.entries(node.props)) {
|
|
638
690
|
const v = genExpr(val, c);
|
|
639
691
|
switch (key) {
|
|
@@ -646,8 +698,24 @@ function genImage(node, c) {
|
|
|
646
698
|
case 'alt':
|
|
647
699
|
props.push(`alt=${quoteJsx(v)}`);
|
|
648
700
|
break;
|
|
701
|
+
case 'round':
|
|
702
|
+
style['borderRadius'] = "'50%'";
|
|
703
|
+
break;
|
|
704
|
+
case 'radius':
|
|
705
|
+
style['borderRadius'] = `'${addPx(v)}'`;
|
|
706
|
+
break;
|
|
707
|
+
case 'size': {
|
|
708
|
+
const px = `'${addPx(v)}'`;
|
|
709
|
+
style['width'] = px;
|
|
710
|
+
style['height'] = px;
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
649
713
|
}
|
|
650
714
|
}
|
|
715
|
+
if (Object.keys(style).length > 0) {
|
|
716
|
+
const entries = Object.entries(style).map(([k, v]) => `${k}: ${v}`).join(', ');
|
|
717
|
+
props.push(`style={{ ${entries} }}`);
|
|
718
|
+
}
|
|
651
719
|
return `<img ${props.join(' ')} />`;
|
|
652
720
|
}
|
|
653
721
|
function genLink(node, c) {
|
|
@@ -825,13 +893,26 @@ function genExpr(expr, c) {
|
|
|
825
893
|
const method = expr.callee.property;
|
|
826
894
|
if (objName && c.states.has(objName)) {
|
|
827
895
|
const setter = 'set' + capitalize(objName);
|
|
896
|
+
const memberPath = extractMemberPath(expr.callee.object);
|
|
828
897
|
if (method === 'push') {
|
|
898
|
+
if (memberPath.length > 0) {
|
|
899
|
+
const arrayPath = 'prev.' + memberPath.join('.');
|
|
900
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `[...${arrayPath}, ${args}]`)})`;
|
|
901
|
+
}
|
|
829
902
|
return `${setter}(prev => [...prev, ${args}])`;
|
|
830
903
|
}
|
|
831
904
|
if (method === 'filter') {
|
|
905
|
+
if (memberPath.length > 0) {
|
|
906
|
+
const arrayPath = 'prev.' + memberPath.join('.');
|
|
907
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `${arrayPath}.filter(${args})`)})`;
|
|
908
|
+
}
|
|
832
909
|
return `${setter}(prev => prev.filter(${args}))`;
|
|
833
910
|
}
|
|
834
911
|
if (method === 'remove') {
|
|
912
|
+
if (memberPath.length > 0) {
|
|
913
|
+
const arrayPath = 'prev.' + memberPath.join('.');
|
|
914
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `${arrayPath}.filter(item => item.id !== ${args})`)})`;
|
|
915
|
+
}
|
|
835
916
|
return `${setter}(prev => prev.filter(item => item.id !== ${args}))`;
|
|
836
917
|
}
|
|
837
918
|
}
|
|
@@ -854,6 +935,8 @@ function genExpr(expr, c) {
|
|
|
854
935
|
return `[${els}]`;
|
|
855
936
|
}
|
|
856
937
|
case 'object_expr': {
|
|
938
|
+
if (expr.properties.length === 0)
|
|
939
|
+
return '{}';
|
|
857
940
|
const props = expr.properties.map(p => {
|
|
858
941
|
if (p.key === p.value.kind && p.value.kind === 'identifier') {
|
|
859
942
|
return p.key; // shorthand
|