@matthesketh/utopia-compiler 0.0.4 → 0.1.0
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/index.cjs +44 -10
- package/dist/index.js +44 -10
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -381,6 +381,7 @@ var CodeGenerator = class {
|
|
|
381
381
|
varCounter = 0;
|
|
382
382
|
helpers = /* @__PURE__ */ new Set();
|
|
383
383
|
scopeId;
|
|
384
|
+
deferredCallsStack = [];
|
|
384
385
|
generate(ast) {
|
|
385
386
|
const scope = /* @__PURE__ */ new Set();
|
|
386
387
|
const rootElements = ast.filter(
|
|
@@ -399,7 +400,7 @@ var CodeGenerator = class {
|
|
|
399
400
|
this.emit(`const ${fragVar} = createElement('div')`);
|
|
400
401
|
if (this.scopeId) {
|
|
401
402
|
this.helpers.add("setAttr");
|
|
402
|
-
this.emit(`setAttr(${fragVar}, '${this.scopeId}', '')`);
|
|
403
|
+
this.emit(`setAttr(${fragVar}, '${escapeStr(this.scopeId)}', '')`);
|
|
403
404
|
}
|
|
404
405
|
for (const node of ast) {
|
|
405
406
|
const childVar = this.genNode(node, scope);
|
|
@@ -452,7 +453,7 @@ ${fnBody}
|
|
|
452
453
|
this.emit(`const ${elVar} = createElement('${node.tag}')`);
|
|
453
454
|
if (this.scopeId) {
|
|
454
455
|
this.helpers.add("setAttr");
|
|
455
|
-
this.emit(`setAttr(${elVar}, '${this.scopeId}', '')`);
|
|
456
|
+
this.emit(`setAttr(${elVar}, '${escapeStr(this.scopeId)}', '')`);
|
|
456
457
|
}
|
|
457
458
|
for (const attr of node.attrs) {
|
|
458
459
|
this.helpers.add("setAttr");
|
|
@@ -466,6 +467,7 @@ ${fnBody}
|
|
|
466
467
|
if (dir.kind === "if" || dir.kind === "for") continue;
|
|
467
468
|
this.genDirective(elVar, dir, scope);
|
|
468
469
|
}
|
|
470
|
+
this.deferredCallsStack.push([]);
|
|
469
471
|
for (const child of node.children) {
|
|
470
472
|
const childVar = this.genNode(child, scope);
|
|
471
473
|
if (childVar) {
|
|
@@ -473,6 +475,10 @@ ${fnBody}
|
|
|
473
475
|
this.emit(`appendChild(${elVar}, ${childVar})`);
|
|
474
476
|
}
|
|
475
477
|
}
|
|
478
|
+
const deferred = this.deferredCallsStack.pop();
|
|
479
|
+
for (const line of deferred) {
|
|
480
|
+
this.emit(line);
|
|
481
|
+
}
|
|
476
482
|
return elVar;
|
|
477
483
|
}
|
|
478
484
|
// ---- Text & Interpolation -----------------------------------------------
|
|
@@ -554,7 +560,7 @@ ${fnBody}
|
|
|
554
560
|
}
|
|
555
561
|
this.emit(` return ${innerVar}`);
|
|
556
562
|
this.emit(`}`);
|
|
557
|
-
this.
|
|
563
|
+
this.emitOrDefer(`createIf(${anchorVar}, () => Boolean(${condition}), ${trueFnVar})`);
|
|
558
564
|
return anchorVar;
|
|
559
565
|
}
|
|
560
566
|
// ---- Structural: u-for --------------------------------------------------
|
|
@@ -588,7 +594,7 @@ ${fnBody}
|
|
|
588
594
|
}
|
|
589
595
|
this.emit(` return ${innerVar}`);
|
|
590
596
|
this.emit(`}`);
|
|
591
|
-
this.
|
|
597
|
+
this.emitOrDefer(`createFor(${anchorVar}, () => ${listExpr}, ${renderFnVar})`);
|
|
592
598
|
return anchorVar;
|
|
593
599
|
}
|
|
594
600
|
// ---- Component generation -----------------------------------------------
|
|
@@ -597,14 +603,14 @@ ${fnBody}
|
|
|
597
603
|
const propEntries = [];
|
|
598
604
|
for (const a of node.attrs) {
|
|
599
605
|
if (a.value !== null) {
|
|
600
|
-
propEntries.push(
|
|
606
|
+
propEntries.push(`'${escapeStr(a.name)}': '${escapeStr(a.value)}'`);
|
|
601
607
|
} else {
|
|
602
|
-
propEntries.push(
|
|
608
|
+
propEntries.push(`'${escapeStr(a.name)}': true`);
|
|
603
609
|
}
|
|
604
610
|
}
|
|
605
611
|
for (const d of node.directives) {
|
|
606
612
|
if (d.kind === "bind" && d.arg) {
|
|
607
|
-
propEntries.push(
|
|
613
|
+
propEntries.push(`'${escapeStr(d.arg)}': ${this.resolveExpression(d.expression, scope)}`);
|
|
608
614
|
}
|
|
609
615
|
}
|
|
610
616
|
const propsStr = propEntries.length > 0 ? `{ ${propEntries.join(", ")} }` : "{}";
|
|
@@ -631,9 +637,17 @@ ${fnBody}
|
|
|
631
637
|
emit(line) {
|
|
632
638
|
this.code.push(line);
|
|
633
639
|
}
|
|
640
|
+
emitOrDefer(line) {
|
|
641
|
+
const stack = this.deferredCallsStack;
|
|
642
|
+
if (stack.length > 0) {
|
|
643
|
+
stack[stack.length - 1].push(line);
|
|
644
|
+
} else {
|
|
645
|
+
this.emit(line);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
634
648
|
};
|
|
635
649
|
function isComponentTag(tag) {
|
|
636
|
-
return /^[A-Z]
|
|
650
|
+
return /^[A-Z][a-zA-Z0-9_$]*$/.test(tag);
|
|
637
651
|
}
|
|
638
652
|
function escapeStr(s) {
|
|
639
653
|
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -666,8 +680,28 @@ var ENTITY_MAP = {
|
|
|
666
680
|
};
|
|
667
681
|
function decodeEntities(text) {
|
|
668
682
|
return text.replace(/&(?:#(\d+)|#x([0-9a-fA-F]+)|(\w+));/g, (match, dec, hex, named) => {
|
|
669
|
-
if (dec)
|
|
670
|
-
|
|
683
|
+
if (dec) {
|
|
684
|
+
const code = parseInt(dec, 10);
|
|
685
|
+
if (code >= 0 && code <= 1114111) {
|
|
686
|
+
try {
|
|
687
|
+
return String.fromCodePoint(code);
|
|
688
|
+
} catch {
|
|
689
|
+
return match;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return match;
|
|
693
|
+
}
|
|
694
|
+
if (hex) {
|
|
695
|
+
const code = parseInt(hex, 16);
|
|
696
|
+
if (code >= 0 && code <= 1114111) {
|
|
697
|
+
try {
|
|
698
|
+
return String.fromCodePoint(code);
|
|
699
|
+
} catch {
|
|
700
|
+
return match;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return match;
|
|
704
|
+
}
|
|
671
705
|
if (named) return ENTITY_MAP[`&${named};`] ?? match;
|
|
672
706
|
return match;
|
|
673
707
|
});
|
package/dist/index.js
CHANGED
|
@@ -349,6 +349,7 @@ var CodeGenerator = class {
|
|
|
349
349
|
varCounter = 0;
|
|
350
350
|
helpers = /* @__PURE__ */ new Set();
|
|
351
351
|
scopeId;
|
|
352
|
+
deferredCallsStack = [];
|
|
352
353
|
generate(ast) {
|
|
353
354
|
const scope = /* @__PURE__ */ new Set();
|
|
354
355
|
const rootElements = ast.filter(
|
|
@@ -367,7 +368,7 @@ var CodeGenerator = class {
|
|
|
367
368
|
this.emit(`const ${fragVar} = createElement('div')`);
|
|
368
369
|
if (this.scopeId) {
|
|
369
370
|
this.helpers.add("setAttr");
|
|
370
|
-
this.emit(`setAttr(${fragVar}, '${this.scopeId}', '')`);
|
|
371
|
+
this.emit(`setAttr(${fragVar}, '${escapeStr(this.scopeId)}', '')`);
|
|
371
372
|
}
|
|
372
373
|
for (const node of ast) {
|
|
373
374
|
const childVar = this.genNode(node, scope);
|
|
@@ -420,7 +421,7 @@ ${fnBody}
|
|
|
420
421
|
this.emit(`const ${elVar} = createElement('${node.tag}')`);
|
|
421
422
|
if (this.scopeId) {
|
|
422
423
|
this.helpers.add("setAttr");
|
|
423
|
-
this.emit(`setAttr(${elVar}, '${this.scopeId}', '')`);
|
|
424
|
+
this.emit(`setAttr(${elVar}, '${escapeStr(this.scopeId)}', '')`);
|
|
424
425
|
}
|
|
425
426
|
for (const attr of node.attrs) {
|
|
426
427
|
this.helpers.add("setAttr");
|
|
@@ -434,6 +435,7 @@ ${fnBody}
|
|
|
434
435
|
if (dir.kind === "if" || dir.kind === "for") continue;
|
|
435
436
|
this.genDirective(elVar, dir, scope);
|
|
436
437
|
}
|
|
438
|
+
this.deferredCallsStack.push([]);
|
|
437
439
|
for (const child of node.children) {
|
|
438
440
|
const childVar = this.genNode(child, scope);
|
|
439
441
|
if (childVar) {
|
|
@@ -441,6 +443,10 @@ ${fnBody}
|
|
|
441
443
|
this.emit(`appendChild(${elVar}, ${childVar})`);
|
|
442
444
|
}
|
|
443
445
|
}
|
|
446
|
+
const deferred = this.deferredCallsStack.pop();
|
|
447
|
+
for (const line of deferred) {
|
|
448
|
+
this.emit(line);
|
|
449
|
+
}
|
|
444
450
|
return elVar;
|
|
445
451
|
}
|
|
446
452
|
// ---- Text & Interpolation -----------------------------------------------
|
|
@@ -522,7 +528,7 @@ ${fnBody}
|
|
|
522
528
|
}
|
|
523
529
|
this.emit(` return ${innerVar}`);
|
|
524
530
|
this.emit(`}`);
|
|
525
|
-
this.
|
|
531
|
+
this.emitOrDefer(`createIf(${anchorVar}, () => Boolean(${condition}), ${trueFnVar})`);
|
|
526
532
|
return anchorVar;
|
|
527
533
|
}
|
|
528
534
|
// ---- Structural: u-for --------------------------------------------------
|
|
@@ -556,7 +562,7 @@ ${fnBody}
|
|
|
556
562
|
}
|
|
557
563
|
this.emit(` return ${innerVar}`);
|
|
558
564
|
this.emit(`}`);
|
|
559
|
-
this.
|
|
565
|
+
this.emitOrDefer(`createFor(${anchorVar}, () => ${listExpr}, ${renderFnVar})`);
|
|
560
566
|
return anchorVar;
|
|
561
567
|
}
|
|
562
568
|
// ---- Component generation -----------------------------------------------
|
|
@@ -565,14 +571,14 @@ ${fnBody}
|
|
|
565
571
|
const propEntries = [];
|
|
566
572
|
for (const a of node.attrs) {
|
|
567
573
|
if (a.value !== null) {
|
|
568
|
-
propEntries.push(
|
|
574
|
+
propEntries.push(`'${escapeStr(a.name)}': '${escapeStr(a.value)}'`);
|
|
569
575
|
} else {
|
|
570
|
-
propEntries.push(
|
|
576
|
+
propEntries.push(`'${escapeStr(a.name)}': true`);
|
|
571
577
|
}
|
|
572
578
|
}
|
|
573
579
|
for (const d of node.directives) {
|
|
574
580
|
if (d.kind === "bind" && d.arg) {
|
|
575
|
-
propEntries.push(
|
|
581
|
+
propEntries.push(`'${escapeStr(d.arg)}': ${this.resolveExpression(d.expression, scope)}`);
|
|
576
582
|
}
|
|
577
583
|
}
|
|
578
584
|
const propsStr = propEntries.length > 0 ? `{ ${propEntries.join(", ")} }` : "{}";
|
|
@@ -599,9 +605,17 @@ ${fnBody}
|
|
|
599
605
|
emit(line) {
|
|
600
606
|
this.code.push(line);
|
|
601
607
|
}
|
|
608
|
+
emitOrDefer(line) {
|
|
609
|
+
const stack = this.deferredCallsStack;
|
|
610
|
+
if (stack.length > 0) {
|
|
611
|
+
stack[stack.length - 1].push(line);
|
|
612
|
+
} else {
|
|
613
|
+
this.emit(line);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
602
616
|
};
|
|
603
617
|
function isComponentTag(tag) {
|
|
604
|
-
return /^[A-Z]
|
|
618
|
+
return /^[A-Z][a-zA-Z0-9_$]*$/.test(tag);
|
|
605
619
|
}
|
|
606
620
|
function escapeStr(s) {
|
|
607
621
|
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
@@ -634,8 +648,28 @@ var ENTITY_MAP = {
|
|
|
634
648
|
};
|
|
635
649
|
function decodeEntities(text) {
|
|
636
650
|
return text.replace(/&(?:#(\d+)|#x([0-9a-fA-F]+)|(\w+));/g, (match, dec, hex, named) => {
|
|
637
|
-
if (dec)
|
|
638
|
-
|
|
651
|
+
if (dec) {
|
|
652
|
+
const code = parseInt(dec, 10);
|
|
653
|
+
if (code >= 0 && code <= 1114111) {
|
|
654
|
+
try {
|
|
655
|
+
return String.fromCodePoint(code);
|
|
656
|
+
} catch {
|
|
657
|
+
return match;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return match;
|
|
661
|
+
}
|
|
662
|
+
if (hex) {
|
|
663
|
+
const code = parseInt(hex, 16);
|
|
664
|
+
if (code >= 0 && code <= 1114111) {
|
|
665
|
+
try {
|
|
666
|
+
return String.fromCodePoint(code);
|
|
667
|
+
} catch {
|
|
668
|
+
return match;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return match;
|
|
672
|
+
}
|
|
639
673
|
if (named) return ENTITY_MAP[`&${named};`] ?? match;
|
|
640
674
|
return match;
|
|
641
675
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matthesketh/utopia-compiler",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Compiler for .utopia single-file components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dist"
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@matthesketh/utopia-core": "0.0
|
|
42
|
+
"@matthesketh/utopia-core": "0.1.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|