@matthesketh/utopia-compiler 0.1.0 → 0.2.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 +112 -31
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +112 -31
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -306,7 +306,9 @@ var TemplateParser = class {
|
|
|
306
306
|
}
|
|
307
307
|
expect(str) {
|
|
308
308
|
if (!this.lookingAt(str)) {
|
|
309
|
-
throw this.error(
|
|
309
|
+
throw this.error(
|
|
310
|
+
`Expected "${str}" but found "${this.source.slice(this.pos, this.pos + 20)}"`
|
|
311
|
+
);
|
|
310
312
|
}
|
|
311
313
|
this.pos += str.length;
|
|
312
314
|
}
|
|
@@ -370,7 +372,7 @@ function classifyDirective(name, value) {
|
|
|
370
372
|
return null;
|
|
371
373
|
}
|
|
372
374
|
function isDirectiveKind(s) {
|
|
373
|
-
return s === "on" || s === "bind" || s === "if" || s === "for" || s === "model";
|
|
375
|
+
return s === "on" || s === "bind" || s === "if" || s === "else" || s === "for" || s === "model";
|
|
374
376
|
}
|
|
375
377
|
var CodeGenerator = class {
|
|
376
378
|
constructor(options) {
|
|
@@ -402,13 +404,7 @@ var CodeGenerator = class {
|
|
|
402
404
|
this.helpers.add("setAttr");
|
|
403
405
|
this.emit(`setAttr(${fragVar}, '${escapeStr(this.scopeId)}', '')`);
|
|
404
406
|
}
|
|
405
|
-
|
|
406
|
-
const childVar = this.genNode(node, scope);
|
|
407
|
-
if (childVar) {
|
|
408
|
-
this.helpers.add("appendChild");
|
|
409
|
-
this.emit(`appendChild(${fragVar}, ${childVar})`);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
407
|
+
this.genChildren(fragVar, ast, scope);
|
|
412
408
|
this.emit(`return ${fragVar}`);
|
|
413
409
|
}
|
|
414
410
|
const helperList = Array.from(this.helpers).sort();
|
|
@@ -464,21 +460,10 @@ ${fnBody}
|
|
|
464
460
|
}
|
|
465
461
|
}
|
|
466
462
|
for (const dir of node.directives) {
|
|
467
|
-
if (dir.kind === "if" || dir.kind === "for") continue;
|
|
463
|
+
if (dir.kind === "if" || dir.kind === "else" || dir.kind === "for") continue;
|
|
468
464
|
this.genDirective(elVar, dir, scope);
|
|
469
465
|
}
|
|
470
|
-
this.
|
|
471
|
-
for (const child of node.children) {
|
|
472
|
-
const childVar = this.genNode(child, scope);
|
|
473
|
-
if (childVar) {
|
|
474
|
-
this.helpers.add("appendChild");
|
|
475
|
-
this.emit(`appendChild(${elVar}, ${childVar})`);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
const deferred = this.deferredCallsStack.pop();
|
|
479
|
-
for (const line of deferred) {
|
|
480
|
-
this.emit(line);
|
|
481
|
-
}
|
|
466
|
+
this.genChildren(elVar, node.children, scope);
|
|
482
467
|
return elVar;
|
|
483
468
|
}
|
|
484
469
|
// ---- Text & Interpolation -----------------------------------------------
|
|
@@ -518,7 +503,32 @@ ${fnBody}
|
|
|
518
503
|
this.helpers.add("addEventListener");
|
|
519
504
|
const event = dir.arg ?? "click";
|
|
520
505
|
const handler = this.resolveExpression(dir.expression, scope);
|
|
521
|
-
|
|
506
|
+
const modifiers = dir.modifiers;
|
|
507
|
+
const OPTION_MODS = /* @__PURE__ */ new Set(["once", "capture", "passive"]);
|
|
508
|
+
const handlerMods = modifiers.filter((m) => !OPTION_MODS.has(m));
|
|
509
|
+
const optionMods = modifiers.filter((m) => OPTION_MODS.has(m));
|
|
510
|
+
let handlerExpr = handler;
|
|
511
|
+
if (handlerMods.length > 0) {
|
|
512
|
+
const guards = [];
|
|
513
|
+
const calls = [];
|
|
514
|
+
for (const mod of handlerMods) {
|
|
515
|
+
switch (mod) {
|
|
516
|
+
case "prevent":
|
|
517
|
+
calls.push("_e.preventDefault()");
|
|
518
|
+
break;
|
|
519
|
+
case "stop":
|
|
520
|
+
calls.push("_e.stopPropagation()");
|
|
521
|
+
break;
|
|
522
|
+
case "self":
|
|
523
|
+
guards.push("if (_e.target !== _e.currentTarget) return");
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const body = [...guards, ...calls, `(${handler})(_e)`].join("; ");
|
|
528
|
+
handlerExpr = `(_e) => { ${body} }`;
|
|
529
|
+
}
|
|
530
|
+
const optionsStr = optionMods.length > 0 ? `, { ${optionMods.map((m) => `${m}: true`).join(", ")} }` : "";
|
|
531
|
+
this.emit(`addEventListener(${elVar}, '${escapeStr(event)}', ${handlerExpr}${optionsStr})`);
|
|
522
532
|
}
|
|
523
533
|
genBind(elVar, dir, scope) {
|
|
524
534
|
this.helpers.add("setAttr");
|
|
@@ -533,12 +543,10 @@ ${fnBody}
|
|
|
533
543
|
this.helpers.add("createEffect");
|
|
534
544
|
const signalRef = this.resolveExpression(dir.expression, scope);
|
|
535
545
|
this.emit(`createEffect(() => setAttr(${elVar}, 'value', ${signalRef}()))`);
|
|
536
|
-
this.emit(
|
|
537
|
-
`addEventListener(${elVar}, 'input', (e) => ${signalRef}.set(e.target.value))`
|
|
538
|
-
);
|
|
546
|
+
this.emit(`addEventListener(${elVar}, 'input', (e) => ${signalRef}.set(e.target.value))`);
|
|
539
547
|
}
|
|
540
548
|
// ---- Structural: u-if ---------------------------------------------------
|
|
541
|
-
genIf(node, dir, scope) {
|
|
549
|
+
genIf(node, dir, scope, elseNode) {
|
|
542
550
|
this.helpers.add("createIf");
|
|
543
551
|
const anchorVar = this.freshVar();
|
|
544
552
|
this.helpers.add("createComment");
|
|
@@ -560,7 +568,27 @@ ${fnBody}
|
|
|
560
568
|
}
|
|
561
569
|
this.emit(` return ${innerVar}`);
|
|
562
570
|
this.emit(`}`);
|
|
563
|
-
|
|
571
|
+
let elseArg = "";
|
|
572
|
+
if (elseNode) {
|
|
573
|
+
const falseFnVar = this.freshVar();
|
|
574
|
+
const strippedElse = {
|
|
575
|
+
...elseNode,
|
|
576
|
+
directives: elseNode.directives.filter((d) => d.kind !== "else")
|
|
577
|
+
};
|
|
578
|
+
const savedCode2 = this.code;
|
|
579
|
+
this.code = [];
|
|
580
|
+
const elseInnerVar = this.genElement(strippedElse, scope);
|
|
581
|
+
const elseLines = [...this.code];
|
|
582
|
+
this.code = savedCode2;
|
|
583
|
+
this.emit(`const ${falseFnVar} = () => {`);
|
|
584
|
+
for (const line of elseLines) {
|
|
585
|
+
this.emit(` ${line}`);
|
|
586
|
+
}
|
|
587
|
+
this.emit(` return ${elseInnerVar}`);
|
|
588
|
+
this.emit(`}`);
|
|
589
|
+
elseArg = `, ${falseFnVar}`;
|
|
590
|
+
}
|
|
591
|
+
this.emitOrDefer(`createIf(${anchorVar}, () => Boolean(${condition}), ${trueFnVar}${elseArg})`);
|
|
564
592
|
return anchorVar;
|
|
565
593
|
}
|
|
566
594
|
// ---- Structural: u-for --------------------------------------------------
|
|
@@ -569,7 +597,9 @@ ${fnBody}
|
|
|
569
597
|
const anchorVar = this.freshVar();
|
|
570
598
|
this.helpers.add("createComment");
|
|
571
599
|
this.emit(`const ${anchorVar} = createComment('u-for')`);
|
|
572
|
-
const forMatch = dir.expression.match(
|
|
600
|
+
const forMatch = dir.expression.match(
|
|
601
|
+
/^\s*(?:\(\s*(\w+)\s*(?:,\s*(\w+)\s*)?\)|(\w+))\s+in\s+(.+)$/
|
|
602
|
+
);
|
|
573
603
|
if (!forMatch) {
|
|
574
604
|
throw new Error(`Invalid u-for expression: "${dir.expression}"`);
|
|
575
605
|
}
|
|
@@ -578,9 +608,12 @@ ${fnBody}
|
|
|
578
608
|
const listExpr = this.resolveExpression(forMatch[4].trim(), scope);
|
|
579
609
|
const innerScope = new Set(scope);
|
|
580
610
|
innerScope.add(itemName);
|
|
611
|
+
const keyDir = node.directives.find((d) => d.kind === "bind" && d.arg === "key");
|
|
581
612
|
const strippedNode = {
|
|
582
613
|
...node,
|
|
583
|
-
directives: node.directives.filter(
|
|
614
|
+
directives: node.directives.filter(
|
|
615
|
+
(d) => d.kind !== "for" && !(d.kind === "bind" && d.arg === "key")
|
|
616
|
+
)
|
|
584
617
|
};
|
|
585
618
|
const savedCode = this.code;
|
|
586
619
|
this.code = [];
|
|
@@ -594,9 +627,57 @@ ${fnBody}
|
|
|
594
627
|
}
|
|
595
628
|
this.emit(` return ${innerVar}`);
|
|
596
629
|
this.emit(`}`);
|
|
597
|
-
|
|
630
|
+
let keyArg = "";
|
|
631
|
+
if (keyDir) {
|
|
632
|
+
const keyExpr = this.resolveExpression(keyDir.expression, innerScope);
|
|
633
|
+
keyArg = `, (${itemName}, ${indexName}) => ${keyExpr}`;
|
|
634
|
+
}
|
|
635
|
+
this.emitOrDefer(`createFor(${anchorVar}, () => ${listExpr}, ${renderFnVar}${keyArg})`);
|
|
598
636
|
return anchorVar;
|
|
599
637
|
}
|
|
638
|
+
// ---- Children processing (handles u-if / u-else pairing) ----------------
|
|
639
|
+
genChildren(parentVar, children, scope) {
|
|
640
|
+
this.deferredCallsStack.push([]);
|
|
641
|
+
let i = 0;
|
|
642
|
+
while (i < children.length) {
|
|
643
|
+
const child = children[i];
|
|
644
|
+
if (child.type === 1 /* Element */) {
|
|
645
|
+
const ifDir = child.directives.find((d) => d.kind === "if");
|
|
646
|
+
if (ifDir) {
|
|
647
|
+
let elseNode;
|
|
648
|
+
let skipTo = i + 1;
|
|
649
|
+
for (let j = i + 1; j < children.length; j++) {
|
|
650
|
+
const next = children[j];
|
|
651
|
+
if (next.type === 2 /* Text */ && !next.content.trim()) continue;
|
|
652
|
+
if (next.type === 1 /* Element */ && next.directives.some((d) => d.kind === "else")) {
|
|
653
|
+
elseNode = next;
|
|
654
|
+
skipTo = j + 1;
|
|
655
|
+
}
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
const childVar2 = this.genIf(child, ifDir, scope, elseNode);
|
|
659
|
+
this.helpers.add("appendChild");
|
|
660
|
+
this.emit(`appendChild(${parentVar}, ${childVar2})`);
|
|
661
|
+
i = skipTo;
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
if (child.directives.some((d) => d.kind === "else")) {
|
|
665
|
+
i++;
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
const childVar = this.genNode(child, scope);
|
|
670
|
+
if (childVar) {
|
|
671
|
+
this.helpers.add("appendChild");
|
|
672
|
+
this.emit(`appendChild(${parentVar}, ${childVar})`);
|
|
673
|
+
}
|
|
674
|
+
i++;
|
|
675
|
+
}
|
|
676
|
+
const deferred = this.deferredCallsStack.pop();
|
|
677
|
+
for (const line of deferred) {
|
|
678
|
+
this.emit(line);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
600
681
|
// ---- Component generation -----------------------------------------------
|
|
601
682
|
genComponent(node, scope) {
|
|
602
683
|
const compVar = this.freshVar();
|
package/dist/index.d.cts
CHANGED
|
@@ -84,7 +84,7 @@ interface Directive {
|
|
|
84
84
|
expression: string;
|
|
85
85
|
modifiers: string[];
|
|
86
86
|
}
|
|
87
|
-
type DirectiveKind = 'on' | 'bind' | 'if' | 'for' | 'model';
|
|
87
|
+
type DirectiveKind = 'on' | 'bind' | 'if' | 'else' | 'for' | 'model';
|
|
88
88
|
/** Exported for testing — parse a template string into an AST. */
|
|
89
89
|
declare function parseTemplate(source: string): TemplateNode[];
|
|
90
90
|
|
package/dist/index.d.ts
CHANGED
|
@@ -84,7 +84,7 @@ interface Directive {
|
|
|
84
84
|
expression: string;
|
|
85
85
|
modifiers: string[];
|
|
86
86
|
}
|
|
87
|
-
type DirectiveKind = 'on' | 'bind' | 'if' | 'for' | 'model';
|
|
87
|
+
type DirectiveKind = 'on' | 'bind' | 'if' | 'else' | 'for' | 'model';
|
|
88
88
|
/** Exported for testing — parse a template string into an AST. */
|
|
89
89
|
declare function parseTemplate(source: string): TemplateNode[];
|
|
90
90
|
|
package/dist/index.js
CHANGED
|
@@ -274,7 +274,9 @@ var TemplateParser = class {
|
|
|
274
274
|
}
|
|
275
275
|
expect(str) {
|
|
276
276
|
if (!this.lookingAt(str)) {
|
|
277
|
-
throw this.error(
|
|
277
|
+
throw this.error(
|
|
278
|
+
`Expected "${str}" but found "${this.source.slice(this.pos, this.pos + 20)}"`
|
|
279
|
+
);
|
|
278
280
|
}
|
|
279
281
|
this.pos += str.length;
|
|
280
282
|
}
|
|
@@ -338,7 +340,7 @@ function classifyDirective(name, value) {
|
|
|
338
340
|
return null;
|
|
339
341
|
}
|
|
340
342
|
function isDirectiveKind(s) {
|
|
341
|
-
return s === "on" || s === "bind" || s === "if" || s === "for" || s === "model";
|
|
343
|
+
return s === "on" || s === "bind" || s === "if" || s === "else" || s === "for" || s === "model";
|
|
342
344
|
}
|
|
343
345
|
var CodeGenerator = class {
|
|
344
346
|
constructor(options) {
|
|
@@ -370,13 +372,7 @@ var CodeGenerator = class {
|
|
|
370
372
|
this.helpers.add("setAttr");
|
|
371
373
|
this.emit(`setAttr(${fragVar}, '${escapeStr(this.scopeId)}', '')`);
|
|
372
374
|
}
|
|
373
|
-
|
|
374
|
-
const childVar = this.genNode(node, scope);
|
|
375
|
-
if (childVar) {
|
|
376
|
-
this.helpers.add("appendChild");
|
|
377
|
-
this.emit(`appendChild(${fragVar}, ${childVar})`);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
375
|
+
this.genChildren(fragVar, ast, scope);
|
|
380
376
|
this.emit(`return ${fragVar}`);
|
|
381
377
|
}
|
|
382
378
|
const helperList = Array.from(this.helpers).sort();
|
|
@@ -432,21 +428,10 @@ ${fnBody}
|
|
|
432
428
|
}
|
|
433
429
|
}
|
|
434
430
|
for (const dir of node.directives) {
|
|
435
|
-
if (dir.kind === "if" || dir.kind === "for") continue;
|
|
431
|
+
if (dir.kind === "if" || dir.kind === "else" || dir.kind === "for") continue;
|
|
436
432
|
this.genDirective(elVar, dir, scope);
|
|
437
433
|
}
|
|
438
|
-
this.
|
|
439
|
-
for (const child of node.children) {
|
|
440
|
-
const childVar = this.genNode(child, scope);
|
|
441
|
-
if (childVar) {
|
|
442
|
-
this.helpers.add("appendChild");
|
|
443
|
-
this.emit(`appendChild(${elVar}, ${childVar})`);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
const deferred = this.deferredCallsStack.pop();
|
|
447
|
-
for (const line of deferred) {
|
|
448
|
-
this.emit(line);
|
|
449
|
-
}
|
|
434
|
+
this.genChildren(elVar, node.children, scope);
|
|
450
435
|
return elVar;
|
|
451
436
|
}
|
|
452
437
|
// ---- Text & Interpolation -----------------------------------------------
|
|
@@ -486,7 +471,32 @@ ${fnBody}
|
|
|
486
471
|
this.helpers.add("addEventListener");
|
|
487
472
|
const event = dir.arg ?? "click";
|
|
488
473
|
const handler = this.resolveExpression(dir.expression, scope);
|
|
489
|
-
|
|
474
|
+
const modifiers = dir.modifiers;
|
|
475
|
+
const OPTION_MODS = /* @__PURE__ */ new Set(["once", "capture", "passive"]);
|
|
476
|
+
const handlerMods = modifiers.filter((m) => !OPTION_MODS.has(m));
|
|
477
|
+
const optionMods = modifiers.filter((m) => OPTION_MODS.has(m));
|
|
478
|
+
let handlerExpr = handler;
|
|
479
|
+
if (handlerMods.length > 0) {
|
|
480
|
+
const guards = [];
|
|
481
|
+
const calls = [];
|
|
482
|
+
for (const mod of handlerMods) {
|
|
483
|
+
switch (mod) {
|
|
484
|
+
case "prevent":
|
|
485
|
+
calls.push("_e.preventDefault()");
|
|
486
|
+
break;
|
|
487
|
+
case "stop":
|
|
488
|
+
calls.push("_e.stopPropagation()");
|
|
489
|
+
break;
|
|
490
|
+
case "self":
|
|
491
|
+
guards.push("if (_e.target !== _e.currentTarget) return");
|
|
492
|
+
break;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const body = [...guards, ...calls, `(${handler})(_e)`].join("; ");
|
|
496
|
+
handlerExpr = `(_e) => { ${body} }`;
|
|
497
|
+
}
|
|
498
|
+
const optionsStr = optionMods.length > 0 ? `, { ${optionMods.map((m) => `${m}: true`).join(", ")} }` : "";
|
|
499
|
+
this.emit(`addEventListener(${elVar}, '${escapeStr(event)}', ${handlerExpr}${optionsStr})`);
|
|
490
500
|
}
|
|
491
501
|
genBind(elVar, dir, scope) {
|
|
492
502
|
this.helpers.add("setAttr");
|
|
@@ -501,12 +511,10 @@ ${fnBody}
|
|
|
501
511
|
this.helpers.add("createEffect");
|
|
502
512
|
const signalRef = this.resolveExpression(dir.expression, scope);
|
|
503
513
|
this.emit(`createEffect(() => setAttr(${elVar}, 'value', ${signalRef}()))`);
|
|
504
|
-
this.emit(
|
|
505
|
-
`addEventListener(${elVar}, 'input', (e) => ${signalRef}.set(e.target.value))`
|
|
506
|
-
);
|
|
514
|
+
this.emit(`addEventListener(${elVar}, 'input', (e) => ${signalRef}.set(e.target.value))`);
|
|
507
515
|
}
|
|
508
516
|
// ---- Structural: u-if ---------------------------------------------------
|
|
509
|
-
genIf(node, dir, scope) {
|
|
517
|
+
genIf(node, dir, scope, elseNode) {
|
|
510
518
|
this.helpers.add("createIf");
|
|
511
519
|
const anchorVar = this.freshVar();
|
|
512
520
|
this.helpers.add("createComment");
|
|
@@ -528,7 +536,27 @@ ${fnBody}
|
|
|
528
536
|
}
|
|
529
537
|
this.emit(` return ${innerVar}`);
|
|
530
538
|
this.emit(`}`);
|
|
531
|
-
|
|
539
|
+
let elseArg = "";
|
|
540
|
+
if (elseNode) {
|
|
541
|
+
const falseFnVar = this.freshVar();
|
|
542
|
+
const strippedElse = {
|
|
543
|
+
...elseNode,
|
|
544
|
+
directives: elseNode.directives.filter((d) => d.kind !== "else")
|
|
545
|
+
};
|
|
546
|
+
const savedCode2 = this.code;
|
|
547
|
+
this.code = [];
|
|
548
|
+
const elseInnerVar = this.genElement(strippedElse, scope);
|
|
549
|
+
const elseLines = [...this.code];
|
|
550
|
+
this.code = savedCode2;
|
|
551
|
+
this.emit(`const ${falseFnVar} = () => {`);
|
|
552
|
+
for (const line of elseLines) {
|
|
553
|
+
this.emit(` ${line}`);
|
|
554
|
+
}
|
|
555
|
+
this.emit(` return ${elseInnerVar}`);
|
|
556
|
+
this.emit(`}`);
|
|
557
|
+
elseArg = `, ${falseFnVar}`;
|
|
558
|
+
}
|
|
559
|
+
this.emitOrDefer(`createIf(${anchorVar}, () => Boolean(${condition}), ${trueFnVar}${elseArg})`);
|
|
532
560
|
return anchorVar;
|
|
533
561
|
}
|
|
534
562
|
// ---- Structural: u-for --------------------------------------------------
|
|
@@ -537,7 +565,9 @@ ${fnBody}
|
|
|
537
565
|
const anchorVar = this.freshVar();
|
|
538
566
|
this.helpers.add("createComment");
|
|
539
567
|
this.emit(`const ${anchorVar} = createComment('u-for')`);
|
|
540
|
-
const forMatch = dir.expression.match(
|
|
568
|
+
const forMatch = dir.expression.match(
|
|
569
|
+
/^\s*(?:\(\s*(\w+)\s*(?:,\s*(\w+)\s*)?\)|(\w+))\s+in\s+(.+)$/
|
|
570
|
+
);
|
|
541
571
|
if (!forMatch) {
|
|
542
572
|
throw new Error(`Invalid u-for expression: "${dir.expression}"`);
|
|
543
573
|
}
|
|
@@ -546,9 +576,12 @@ ${fnBody}
|
|
|
546
576
|
const listExpr = this.resolveExpression(forMatch[4].trim(), scope);
|
|
547
577
|
const innerScope = new Set(scope);
|
|
548
578
|
innerScope.add(itemName);
|
|
579
|
+
const keyDir = node.directives.find((d) => d.kind === "bind" && d.arg === "key");
|
|
549
580
|
const strippedNode = {
|
|
550
581
|
...node,
|
|
551
|
-
directives: node.directives.filter(
|
|
582
|
+
directives: node.directives.filter(
|
|
583
|
+
(d) => d.kind !== "for" && !(d.kind === "bind" && d.arg === "key")
|
|
584
|
+
)
|
|
552
585
|
};
|
|
553
586
|
const savedCode = this.code;
|
|
554
587
|
this.code = [];
|
|
@@ -562,9 +595,57 @@ ${fnBody}
|
|
|
562
595
|
}
|
|
563
596
|
this.emit(` return ${innerVar}`);
|
|
564
597
|
this.emit(`}`);
|
|
565
|
-
|
|
598
|
+
let keyArg = "";
|
|
599
|
+
if (keyDir) {
|
|
600
|
+
const keyExpr = this.resolveExpression(keyDir.expression, innerScope);
|
|
601
|
+
keyArg = `, (${itemName}, ${indexName}) => ${keyExpr}`;
|
|
602
|
+
}
|
|
603
|
+
this.emitOrDefer(`createFor(${anchorVar}, () => ${listExpr}, ${renderFnVar}${keyArg})`);
|
|
566
604
|
return anchorVar;
|
|
567
605
|
}
|
|
606
|
+
// ---- Children processing (handles u-if / u-else pairing) ----------------
|
|
607
|
+
genChildren(parentVar, children, scope) {
|
|
608
|
+
this.deferredCallsStack.push([]);
|
|
609
|
+
let i = 0;
|
|
610
|
+
while (i < children.length) {
|
|
611
|
+
const child = children[i];
|
|
612
|
+
if (child.type === 1 /* Element */) {
|
|
613
|
+
const ifDir = child.directives.find((d) => d.kind === "if");
|
|
614
|
+
if (ifDir) {
|
|
615
|
+
let elseNode;
|
|
616
|
+
let skipTo = i + 1;
|
|
617
|
+
for (let j = i + 1; j < children.length; j++) {
|
|
618
|
+
const next = children[j];
|
|
619
|
+
if (next.type === 2 /* Text */ && !next.content.trim()) continue;
|
|
620
|
+
if (next.type === 1 /* Element */ && next.directives.some((d) => d.kind === "else")) {
|
|
621
|
+
elseNode = next;
|
|
622
|
+
skipTo = j + 1;
|
|
623
|
+
}
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
const childVar2 = this.genIf(child, ifDir, scope, elseNode);
|
|
627
|
+
this.helpers.add("appendChild");
|
|
628
|
+
this.emit(`appendChild(${parentVar}, ${childVar2})`);
|
|
629
|
+
i = skipTo;
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
if (child.directives.some((d) => d.kind === "else")) {
|
|
633
|
+
i++;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
const childVar = this.genNode(child, scope);
|
|
638
|
+
if (childVar) {
|
|
639
|
+
this.helpers.add("appendChild");
|
|
640
|
+
this.emit(`appendChild(${parentVar}, ${childVar})`);
|
|
641
|
+
}
|
|
642
|
+
i++;
|
|
643
|
+
}
|
|
644
|
+
const deferred = this.deferredCallsStack.pop();
|
|
645
|
+
for (const line of deferred) {
|
|
646
|
+
this.emit(line);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
568
649
|
// ---- Component generation -----------------------------------------------
|
|
569
650
|
genComponent(node, scope) {
|
|
570
651
|
const compVar = this.freshVar();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@matthesketh/utopia-compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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.
|
|
42
|
+
"@matthesketh/utopia-core": "0.2.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|