0x-lang 0.1.10 → 0.1.12
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/generators/react.js +65 -22
- package/dist/generators/react.js.map +1 -1
- package/dist/generators/svelte.js +19 -0
- package/dist/generators/svelte.js.map +1 -1
- package/dist/generators/vue.js +19 -0
- package/dist/generators/vue.js.map +1 -1
- package/dist/parser.d.ts +1 -1
- package/dist/parser.js +57 -12
- package/dist/parser.js.map +1 -1
- package/dist/tokenizer.js +60 -1
- package/dist/tokenizer.js.map +1 -1
- package/package.json +1 -1
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}`),
|
|
@@ -505,20 +533,24 @@ function genLayout(node, c) {
|
|
|
505
533
|
case 'grow':
|
|
506
534
|
style['flexGrow'] = v;
|
|
507
535
|
break;
|
|
508
|
-
case 'scroll':
|
|
509
|
-
|
|
536
|
+
case 'scroll': {
|
|
537
|
+
const sv = unquote(v);
|
|
538
|
+
style['overflow' + (sv === 'y' ? 'Y' : 'X')] = 'auto';
|
|
510
539
|
break;
|
|
540
|
+
}
|
|
511
541
|
case 'radius':
|
|
512
542
|
style['borderRadius'] = addPx(v);
|
|
513
543
|
break;
|
|
514
|
-
case 'shadow':
|
|
515
|
-
|
|
544
|
+
case 'shadow': {
|
|
545
|
+
const sv = unquote(v);
|
|
546
|
+
if (sv === 'sm')
|
|
516
547
|
style['boxShadow'] = '0 1px 2px rgba(0,0,0,0.1)';
|
|
517
|
-
else if (
|
|
548
|
+
else if (sv === 'md')
|
|
518
549
|
style['boxShadow'] = '0 4px 6px rgba(0,0,0,0.1)';
|
|
519
|
-
else if (
|
|
550
|
+
else if (sv === 'lg')
|
|
520
551
|
style['boxShadow'] = '0 10px 15px rgba(0,0,0,0.1)';
|
|
521
552
|
break;
|
|
553
|
+
}
|
|
522
554
|
}
|
|
523
555
|
}
|
|
524
556
|
// Apply style class
|
|
@@ -761,12 +793,14 @@ function genFor(node, c) {
|
|
|
761
793
|
function genShow(node, c) {
|
|
762
794
|
const cond = genExpr(node.condition, c);
|
|
763
795
|
const body = node.body.map(ch => genUINode(ch, c)).join('\n');
|
|
764
|
-
|
|
796
|
+
const wrapped = node.body.length === 1 ? body : `<>\n${body}\n</>`;
|
|
797
|
+
return `{${cond} && (\n${wrapped}\n)}`;
|
|
765
798
|
}
|
|
766
799
|
function genHide(node, c) {
|
|
767
800
|
const cond = genExpr(node.condition, c);
|
|
768
801
|
const body = node.body.map(ch => genUINode(ch, c)).join('\n');
|
|
769
|
-
|
|
802
|
+
const wrapped = node.body.length === 1 ? body : `<>\n${body}\n</>`;
|
|
803
|
+
return `{!${cond} && (\n${wrapped}\n)}`;
|
|
770
804
|
}
|
|
771
805
|
// ── Statements ──────────────────────────────────────
|
|
772
806
|
function genStatement(stmt, c) {
|
|
@@ -903,6 +937,8 @@ function genExpr(expr, c) {
|
|
|
903
937
|
return `[${els}]`;
|
|
904
938
|
}
|
|
905
939
|
case 'object_expr': {
|
|
940
|
+
if (expr.properties.length === 0)
|
|
941
|
+
return '{}';
|
|
906
942
|
const props = expr.properties.map(p => {
|
|
907
943
|
if (p.key === p.value.kind && p.value.kind === 'identifier') {
|
|
908
944
|
return p.key; // shorthand
|
|
@@ -1231,18 +1267,19 @@ function genTableUI(node, c) {
|
|
|
1231
1267
|
}
|
|
1232
1268
|
lines.push(`<table style={{ width: '100%', borderCollapse: 'collapse' }}>`);
|
|
1233
1269
|
// Header
|
|
1270
|
+
const thStyle = `padding: '12px 8px', borderBottom: '2px solid #e2e8f0', textAlign: 'left', fontWeight: 600`;
|
|
1234
1271
|
lines.push(`<thead>`);
|
|
1235
1272
|
lines.push(`<tr>`);
|
|
1236
1273
|
for (const col of node.columns) {
|
|
1237
1274
|
if (col.kind === 'select') {
|
|
1238
|
-
lines.push(`<th style={{
|
|
1275
|
+
lines.push(`<th style={{ ${thStyle} }}><input type="checkbox" /></th>`);
|
|
1239
1276
|
}
|
|
1240
1277
|
else if (col.kind === 'field') {
|
|
1241
|
-
const sortAttr = col.sortable ? ` style={{ cursor: 'pointer',
|
|
1278
|
+
const sortAttr = col.sortable ? ` style={{ cursor: 'pointer', ${thStyle} }}` : ` style={{ ${thStyle} }}`;
|
|
1242
1279
|
lines.push(`<th${sortAttr}>${col.label || col.field}</th>`);
|
|
1243
1280
|
}
|
|
1244
1281
|
else if (col.kind === 'actions') {
|
|
1245
|
-
lines.push(`<th style={{
|
|
1282
|
+
lines.push(`<th style={{ ${thStyle}, textAlign: 'right' }}>Actions</th>`);
|
|
1246
1283
|
}
|
|
1247
1284
|
}
|
|
1248
1285
|
lines.push(`</tr>`);
|
|
@@ -1406,16 +1443,22 @@ function genChartUI(node, c) {
|
|
|
1406
1443
|
lines.push(` {/* Chart: ${node.chartType} - ${node.name} */}`);
|
|
1407
1444
|
lines.push(` {/* Data: ${data}, X: ${x}, Y: ${y} */}`);
|
|
1408
1445
|
if (node.chartType === 'bar') {
|
|
1409
|
-
|
|
1410
|
-
lines.push(`
|
|
1411
|
-
lines.push(` {
|
|
1412
|
-
lines.push(`
|
|
1413
|
-
lines.push(`
|
|
1414
|
-
lines.push(` <
|
|
1415
|
-
lines.push(`
|
|
1446
|
+
c.imports.add('useMemo');
|
|
1447
|
+
lines.push(` {(() => {`);
|
|
1448
|
+
lines.push(` const maxVal = Math.max(...${data}.map(d => d[${y}]));`);
|
|
1449
|
+
lines.push(` return (`);
|
|
1450
|
+
lines.push(` <div style={{ display: 'flex', alignItems: 'flex-end', gap: '4px', height: '100%', padding: '20px 0' }}>`);
|
|
1451
|
+
lines.push(` <span style={{ fontSize: '14px', fontWeight: 'bold', position: 'absolute', top: 0 }}>{${title}}</span>`);
|
|
1452
|
+
lines.push(` {${data}.map((item, i) => (`);
|
|
1453
|
+
lines.push(` <div key={item?.id ?? i} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', height: '100%', justifyContent: 'flex-end' }}>`);
|
|
1454
|
+
lines.push(` <span style={{ fontSize: '12px', marginBottom: '4px' }}>{item[${y}]}</span>`);
|
|
1455
|
+
lines.push(` <div style={{ width: '100%', backgroundColor: ${color ? `item[${color}] || '#3182ce'` : "'#3182ce'"}, height: \`\${(item[${y}] / maxVal) * 100}%\`, borderRadius: '4px 4px 0 0', minHeight: '4px' }} />`);
|
|
1456
|
+
lines.push(` <span style={{ fontSize: '11px', marginTop: '4px', color: '#666' }}>{item[${x}]}</span>`);
|
|
1457
|
+
lines.push(` </div>`);
|
|
1458
|
+
lines.push(` ))}`);
|
|
1416
1459
|
lines.push(` </div>`);
|
|
1417
|
-
lines.push(` ))
|
|
1418
|
-
lines.push(`
|
|
1460
|
+
lines.push(` );`);
|
|
1461
|
+
lines.push(` })()}`);
|
|
1419
1462
|
}
|
|
1420
1463
|
else if (node.chartType === 'pie') {
|
|
1421
1464
|
lines.push(` <div style={{ position: 'relative', width: '200px', height: '200px', margin: '0 auto' }}>`);
|
|
@@ -1423,7 +1466,7 @@ function genChartUI(node, c) {
|
|
|
1423
1466
|
lines.push(` {/* Pie chart - use recharts/chart.js for production */}`);
|
|
1424
1467
|
lines.push(` {${data}.map((item, i) => (`);
|
|
1425
1468
|
lines.push(` <div key={item?.id ?? i} style={{ display: 'flex', alignItems: 'center', gap: '8px', marginTop: '8px' }}>`);
|
|
1426
|
-
lines.push(` <div style={{ width: '12px', height: '12px', borderRadius: '50%', backgroundColor: ['#3182ce','#38a169','#d69e2e','#e53e3e','#805ad5'][i % 5] }} />`);
|
|
1469
|
+
lines.push(` <div style={{ width: '12px', height: '12px', borderRadius: '50%', backgroundColor: ${color ? `item[${color}]` : `['#3182ce','#38a169','#d69e2e','#e53e3e','#805ad5'][i % 5]`} }} />`);
|
|
1427
1470
|
lines.push(` <span>{item[${x}]}: {item[${y}]}</span>`);
|
|
1428
1471
|
lines.push(` </div>`);
|
|
1429
1472
|
lines.push(` ))}`);
|
|
@@ -1732,7 +1775,7 @@ function genMediaUI(node, c) {
|
|
|
1732
1775
|
const src = genExpr(node.src, c);
|
|
1733
1776
|
if (node.mediaType === 'gallery') {
|
|
1734
1777
|
const cols = node.props['cols'] ? genExpr(node.props['cols'], c) : '3';
|
|
1735
|
-
return `<div style={{ display: 'grid', gridTemplateColumns: \`repeat(\${${cols}}, 1fr)\`, gap: '8px' }}>\n {${src}.map((img, i) => <img key={i} src={img} style={{ width: '100%', borderRadius: '8px', objectFit: 'cover' }} />)}\n</div>`;
|
|
1778
|
+
return `<div style={{ display: 'grid', gridTemplateColumns: \`repeat(\${${cols}}, 1fr)\`, gap: '8px' }}>\n {${src}.map((img, i) => <img key={img ?? i} src={img} style={{ width: '100%', borderRadius: '8px', objectFit: 'cover' }} />)}\n</div>`;
|
|
1736
1779
|
}
|
|
1737
1780
|
if (node.mediaType === 'video') {
|
|
1738
1781
|
return `<video src={${src}} controls style={{ width: '100%', borderRadius: '12px' }} />`;
|