0x-lang 0.1.8 → 0.1.10
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 +64 -2
- package/dist/generators/react.js.map +1 -1
- package/dist/generators/svelte.js +39 -3
- package/dist/generators/svelte.js.map +1 -1
- package/dist/generators/vue.js +39 -3
- package/dist/generators/vue.js.map +1 -1
- package/dist/parser.js +97 -6
- package/dist/parser.js.map +1 -1
- package/dist/tokenizer.js +1 -1
- 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
|
@@ -431,6 +431,13 @@ function genUINode(node, c) {
|
|
|
431
431
|
case 'Offline': return genOfflineUI(node, c);
|
|
432
432
|
case 'Retry': return `{/* retry: max=${genExpr(node.maxRetries, c)} */}`;
|
|
433
433
|
case 'Log': return `{/* log: ${genExpr(node.message, c)} */}`;
|
|
434
|
+
case 'Divider': return `<hr style={{ border: 'none', borderTop: '1px solid #e2e8f0', margin: '16px 0' }} />`;
|
|
435
|
+
case 'Progress': {
|
|
436
|
+
const pn = node;
|
|
437
|
+
const val = genExpr(pn.value, c);
|
|
438
|
+
const max = pn.props['max'] ? genExpr(pn.props['max'], c) : '100';
|
|
439
|
+
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>`;
|
|
440
|
+
}
|
|
434
441
|
default: return `{/* unsupported: ${node.type} */}`;
|
|
435
442
|
}
|
|
436
443
|
}
|
|
@@ -576,14 +583,27 @@ function genText(node, c) {
|
|
|
576
583
|
case 'strike': {
|
|
577
584
|
// strike={condition} → conditional textDecoration
|
|
578
585
|
const cond = genExpr(val, c);
|
|
579
|
-
style['textDecoration'] =
|
|
586
|
+
style['textDecoration'] = `${cond} ? 'line-through' : 'none'`;
|
|
587
|
+
dynamicKeys.add('textDecoration');
|
|
580
588
|
break;
|
|
581
589
|
}
|
|
582
590
|
}
|
|
583
591
|
}
|
|
584
592
|
const content = genTextContent(node.content, c);
|
|
585
593
|
const styleStr = Object.keys(style).length > 0 ? ` style={${genStyleObj(style, dynamicKeys)}}` : '';
|
|
586
|
-
|
|
594
|
+
// Badge prop: render a badge indicator next to content
|
|
595
|
+
const badgeExpr = node.props['badge'];
|
|
596
|
+
const tooltipExpr = node.props['tooltip'];
|
|
597
|
+
let result = `<span${styleStr}>${content}</span>`;
|
|
598
|
+
if (badgeExpr) {
|
|
599
|
+
const badge = genExpr(badgeExpr, c);
|
|
600
|
+
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>`;
|
|
601
|
+
}
|
|
602
|
+
if (tooltipExpr) {
|
|
603
|
+
const tooltip = genExpr(tooltipExpr, c);
|
|
604
|
+
result = `<span title={${tooltip}}>${badgeExpr ? result.replace(/^<span/, '<span') : `<span${styleStr}>${content}</span>`}</span>`;
|
|
605
|
+
}
|
|
606
|
+
return result;
|
|
587
607
|
}
|
|
588
608
|
function genButton(node, c) {
|
|
589
609
|
const label = genTextContent(node.label, c);
|
|
@@ -633,6 +653,7 @@ function genInput(node, c) {
|
|
|
633
653
|
function genImage(node, c) {
|
|
634
654
|
const src = genExpr(node.src, c);
|
|
635
655
|
const props = [`src={${src}}`];
|
|
656
|
+
const style = {};
|
|
636
657
|
for (const [key, val] of Object.entries(node.props)) {
|
|
637
658
|
const v = genExpr(val, c);
|
|
638
659
|
switch (key) {
|
|
@@ -645,8 +666,24 @@ function genImage(node, c) {
|
|
|
645
666
|
case 'alt':
|
|
646
667
|
props.push(`alt=${quoteJsx(v)}`);
|
|
647
668
|
break;
|
|
669
|
+
case 'round':
|
|
670
|
+
style['borderRadius'] = "'50%'";
|
|
671
|
+
break;
|
|
672
|
+
case 'radius':
|
|
673
|
+
style['borderRadius'] = `'${addPx(v)}'`;
|
|
674
|
+
break;
|
|
675
|
+
case 'size': {
|
|
676
|
+
const px = `'${addPx(v)}'`;
|
|
677
|
+
style['width'] = px;
|
|
678
|
+
style['height'] = px;
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
648
681
|
}
|
|
649
682
|
}
|
|
683
|
+
if (Object.keys(style).length > 0) {
|
|
684
|
+
const entries = Object.entries(style).map(([k, v]) => `${k}: ${v}`).join(', ');
|
|
685
|
+
props.push(`style={{ ${entries} }}`);
|
|
686
|
+
}
|
|
650
687
|
return `<img ${props.join(' ')} />`;
|
|
651
688
|
}
|
|
652
689
|
function genLink(node, c) {
|
|
@@ -824,13 +861,26 @@ function genExpr(expr, c) {
|
|
|
824
861
|
const method = expr.callee.property;
|
|
825
862
|
if (objName && c.states.has(objName)) {
|
|
826
863
|
const setter = 'set' + capitalize(objName);
|
|
864
|
+
const memberPath = extractMemberPath(expr.callee.object);
|
|
827
865
|
if (method === 'push') {
|
|
866
|
+
if (memberPath.length > 0) {
|
|
867
|
+
const arrayPath = 'prev.' + memberPath.join('.');
|
|
868
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `[...${arrayPath}, ${args}]`)})`;
|
|
869
|
+
}
|
|
828
870
|
return `${setter}(prev => [...prev, ${args}])`;
|
|
829
871
|
}
|
|
830
872
|
if (method === 'filter') {
|
|
873
|
+
if (memberPath.length > 0) {
|
|
874
|
+
const arrayPath = 'prev.' + memberPath.join('.');
|
|
875
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `${arrayPath}.filter(${args})`)})`;
|
|
876
|
+
}
|
|
831
877
|
return `${setter}(prev => prev.filter(${args}))`;
|
|
832
878
|
}
|
|
833
879
|
if (method === 'remove') {
|
|
880
|
+
if (memberPath.length > 0) {
|
|
881
|
+
const arrayPath = 'prev.' + memberPath.join('.');
|
|
882
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `${arrayPath}.filter(item => item.id !== ${args})`)})`;
|
|
883
|
+
}
|
|
834
884
|
return `${setter}(prev => prev.filter(item => item.id !== ${args}))`;
|
|
835
885
|
}
|
|
836
886
|
}
|
|
@@ -927,7 +977,19 @@ function genActionExpr(expr, c) {
|
|
|
927
977
|
const stateName = extractStateName(expr.target);
|
|
928
978
|
if (stateName && c.states.has(stateName)) {
|
|
929
979
|
const setter = 'set' + capitalize(stateName);
|
|
980
|
+
// Evaluate value in readOnly mode to prevent double setState wrapping
|
|
981
|
+
const prevReadOnly = c.readOnly;
|
|
982
|
+
c.readOnly = true;
|
|
930
983
|
const value = genExpr(expr.value, c);
|
|
984
|
+
c.readOnly = prevReadOnly;
|
|
985
|
+
const memberPath = extractMemberPath(expr.target);
|
|
986
|
+
if (memberPath.length > 0) {
|
|
987
|
+
if (expr.op === '=')
|
|
988
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, value)})`;
|
|
989
|
+
const opChar = expr.op.charAt(0);
|
|
990
|
+
const prevAccess = 'prev.' + memberPath.join('.');
|
|
991
|
+
return `${setter}(prev => ${buildSpreadUpdate('prev', memberPath, `${prevAccess} ${opChar} ${value}`)})`;
|
|
992
|
+
}
|
|
931
993
|
if (expr.op === '+=')
|
|
932
994
|
return `${setter}(prev => prev + ${value})`;
|
|
933
995
|
if (expr.op === '-=')
|