@lokascript/compilation-service 3.1.1 → 3.3.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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CoreParserAdapter,
3
3
  createCoreParserAdapter
4
- } from "./chunk-T2AN3WRD.js";
4
+ } from "./chunk-PEL4Z7TK.js";
5
5
  import {
6
6
  SemanticParserAdapter,
7
7
  createSemanticAdapter
@@ -427,6 +427,13 @@ var AnalysisVisitor = class {
427
427
  }
428
428
  visitCommand(node) {
429
429
  this.commandsUsed.add(node.name);
430
+ if (["set", "increment", "decrement", "default"].includes(node.name)) {
431
+ const target = node.roles?.destination ?? node.roles?.patient ?? node.args?.[0];
432
+ const name = target?.type === "identifier" ? target.value : void 0;
433
+ if (name && /^[A-Za-z_]\w*$/.test(name)) {
434
+ this.registerVariable(name, "local", "write");
435
+ }
436
+ }
430
437
  switch (node.name) {
431
438
  case "fetch":
432
439
  this.hasAsync = true;
@@ -508,32 +515,37 @@ var AnalysisVisitor = class {
508
515
  if (node.whileCondition) {
509
516
  this.visit(node.whileCondition);
510
517
  }
511
- for (const child of node.body) {
512
- this.visit(child);
518
+ if (node.untilEvent !== void 0) {
519
+ this.hasAsync = true;
520
+ this.runtimeHelpers.add("wait");
521
+ if (node.untilEventTarget) this.visit(node.untilEventTarget);
513
522
  }
523
+ this.visitLoopBody(node);
514
524
  this.exitNesting();
515
525
  }
516
526
  visitForEach(node) {
517
527
  this.hasLoops = true;
518
528
  this.enterNesting();
519
529
  this.registerVariable(node.itemName, "local", "write");
520
- if (node.indexName) {
521
- this.registerVariable(node.indexName, "local", "write");
522
- }
523
530
  this.visit(node.collection);
524
- for (const child of node.body) {
525
- this.visit(child);
526
- }
531
+ this.visitLoopBody(node);
527
532
  this.exitNesting();
528
533
  }
529
534
  visitWhile(node) {
530
535
  this.hasLoops = true;
531
536
  this.enterNesting();
532
537
  this.visit(node.condition);
533
- for (const child of node.body) {
538
+ this.visitLoopBody(node);
539
+ this.exitNesting();
540
+ }
541
+ /** The parts every loop form shares: its `index` local, body, and `else`. */
542
+ visitLoopBody(node) {
543
+ if (node.indexName) {
544
+ this.registerVariable(node.indexName, "local", "write");
545
+ }
546
+ for (const child of [...node.body, ...node.elseBody ?? []]) {
534
547
  this.visit(child);
535
548
  }
536
- this.exitNesting();
537
549
  }
538
550
  visitVariable(node, access) {
539
551
  const name = node.name.startsWith(":") || node.name.startsWith("$") ? node.name.slice(1) : node.name;
@@ -686,11 +698,15 @@ function analyze(ast) {
686
698
  const analyzer = new Analyzer();
687
699
  return analyzer.analyze(ast);
688
700
  }
689
- var CLASS_COMMANDS = /* @__PURE__ */ new Set(["add", "remove", "toggle"]);
701
+ var TARGET_SLOTS = /* @__PURE__ */ new Map([
702
+ ["add", "to"],
703
+ ["remove", "from"],
704
+ ["toggle", "on"]
705
+ ]);
690
706
  function extractClassOp(node) {
691
707
  if (node.type !== "command") return null;
692
708
  const cmd = node;
693
- if (!CLASS_COMMANDS.has(cmd.name)) return null;
709
+ if (!TARGET_SLOTS.has(cmd.name)) return null;
694
710
  const args = cmd.args ?? [];
695
711
  if (args.length === 0) return null;
696
712
  const arg = args[0];
@@ -699,48 +715,32 @@ function extractClassOp(node) {
699
715
  if (!selector.startsWith(".")) return null;
700
716
  const className = selector.slice(1);
701
717
  if (!className) return null;
702
- return {
703
- command: cmd.name,
704
- className,
705
- hasExplicitTarget: !!cmd.target
706
- };
718
+ return { command: cmd.name, className };
707
719
  }
708
- function isSameTarget(a, b) {
709
- if (a.type !== "command" || b.type !== "command") return false;
710
- const cmdA = a;
711
- const cmdB = b;
712
- if (!cmdA.target && !cmdB.target) return true;
713
- if (cmdA.target && cmdB.target) {
714
- return getTargetKey(cmdA.target) === getTargetKey(cmdB.target);
715
- }
716
- return false;
720
+ function classTarget(cmd) {
721
+ if (cmd.target) return cmd.target;
722
+ const slot = cmd.modifiers?.[TARGET_SLOTS.get(cmd.name)];
723
+ return slot && typeof slot === "object" && "type" in slot ? slot : void 0;
717
724
  }
718
- function getTargetKey(target) {
719
- if (target.type === "selector") {
720
- return `selector:${target.value}`;
721
- }
722
- if (target.type === "identifier") {
723
- return `identifier:${target.value}`;
725
+ function batchTargetKey(cmd) {
726
+ const target = classTarget(cmd);
727
+ if (!target) return "me";
728
+ if (target.type === "identifier" && target.value === "me") return "me";
729
+ if (target.type === "selector" && /^#[\w-]+$/.test(target.value)) {
730
+ return target.value;
724
731
  }
725
732
  return null;
726
733
  }
727
- function resolveTarget(cmd) {
728
- if (!cmd.target) return "_ctx.me";
729
- if (cmd.target.type === "selector") {
730
- const sel = cmd.target.value;
731
- if (sel.startsWith("#") && !sel.includes(" ") && !sel.includes(".")) {
732
- return `document.getElementById('${sel.slice(1)}')`;
733
- }
734
- return `document.querySelector('${sel}')`;
735
- }
736
- if (cmd.target.type === "identifier") {
737
- const val = cmd.target.value;
738
- if (val === "me") return "_ctx.me";
739
- return val;
740
- }
741
- return "_ctx.me";
734
+ function resolveTarget(key) {
735
+ return key === "me" ? "_ctx.me" : `document.getElementById('${key.slice(1)}')`;
742
736
  }
743
- function createBatchNode(run) {
737
+ function reordersClass(run, op) {
738
+ return run.some((node) => {
739
+ const other = extractClassOp(node);
740
+ return other.command !== op.command && other.className === op.className;
741
+ });
742
+ }
743
+ function createBatchNode(run, targetKey) {
744
744
  const adds = [];
745
745
  const removes = [];
746
746
  const toggles = [];
@@ -758,10 +758,9 @@ function createBatchNode(run) {
758
758
  break;
759
759
  }
760
760
  }
761
- const target = resolveTarget(run[0]);
762
761
  return {
763
762
  type: "batchedClassOps",
764
- target,
763
+ target: resolveTarget(targetKey),
765
764
  adds,
766
765
  removes,
767
766
  toggles
@@ -770,9 +769,10 @@ function createBatchNode(run) {
770
769
  function batchBody(nodes) {
771
770
  const result = [];
772
771
  let currentRun = [];
772
+ let runKey = "";
773
773
  function flushRun() {
774
774
  if (currentRun.length >= 2) {
775
- result.push(createBatchNode(currentRun));
775
+ result.push(createBatchNode(currentRun, runKey));
776
776
  } else if (currentRun.length === 1) {
777
777
  result.push(currentRun[0]);
778
778
  }
@@ -780,12 +780,14 @@ function batchBody(nodes) {
780
780
  }
781
781
  for (const node of nodes) {
782
782
  const op = extractClassOp(node);
783
- if (op) {
784
- if (currentRun.length > 0 && isSameTarget(currentRun[0], node)) {
783
+ const key = op && batchTargetKey(node);
784
+ if (op && key) {
785
+ if (currentRun.length > 0 && key === runKey && !reordersClass(currentRun, op)) {
785
786
  currentRun.push(node);
786
787
  } else {
787
788
  flushRun();
788
789
  currentRun = [node];
790
+ runKey = key;
789
791
  }
790
792
  } else {
791
793
  flushRun();
@@ -1112,6 +1114,9 @@ var LoopUnrollingPass = class {
1112
1114
  if (this.usesIndex(body)) {
1113
1115
  return null;
1114
1116
  }
1117
+ if (repeatNode.indexName !== void 0 || repeatNode.elseBody !== void 0) {
1118
+ return null;
1119
+ }
1115
1120
  const unrolled = [];
1116
1121
  for (let i = 0; i < count; i++) {
1117
1122
  unrolled.push(...this.cloneBody(body));
@@ -1431,6 +1436,8 @@ var ExpressionCodegen = class {
1431
1436
  return this.generateTemplate(node);
1432
1437
  case "unary":
1433
1438
  return this.generateUnary(node);
1439
+ case "typeCheck":
1440
+ return this.generateTypeCheck(node);
1434
1441
  case "conditional":
1435
1442
  return this.generateConditional(node);
1436
1443
  case "sequence":
@@ -1505,6 +1512,9 @@ var ExpressionCodegen = class {
1505
1512
  this.ctx.requireHelper("globals");
1506
1513
  return `_rt.globals.get('${varName}')`;
1507
1514
  }
1515
+ if (this.ctx.analysis?.variables?.locals?.get(name)?.scope === "local") {
1516
+ return `_ctx.locals.get('${sanitizeIdentifier(name)}')`;
1517
+ }
1508
1518
  return sanitizeIdentifier(name);
1509
1519
  }
1510
1520
  }
@@ -1538,7 +1548,8 @@ var ExpressionCodegen = class {
1538
1548
  this.ctx.requireHelper("globals");
1539
1549
  return `_rt.globals.get('${varName}')`;
1540
1550
  case "element":
1541
- return `_ctx.me.${varName}`;
1551
+ this.ctx.requireHelper("elementVars");
1552
+ return `_rt.elementVars(_ctx.me).get('${varName}')`;
1542
1553
  default:
1543
1554
  return `_ctx.locals.get('${varName}')`;
1544
1555
  }
@@ -1551,19 +1562,40 @@ var ExpressionCodegen = class {
1551
1562
  const right = this.generate(node.right);
1552
1563
  const op = node.operator;
1553
1564
  switch (op) {
1554
- // Equality
1565
+ // Equality, with core's phrase forms of each (`n is equal to 3`).
1555
1566
  case "is":
1556
1567
  case "==":
1568
+ case "am":
1569
+ case "equals":
1570
+ case "is equal":
1571
+ case "is equal to":
1557
1572
  return `(${left} === ${right})`;
1558
1573
  case "is not":
1559
1574
  case "!=":
1575
+ case "is not equal":
1576
+ case "is not equal to":
1560
1577
  return `(${left} !== ${right})`;
1561
- // Comparison
1578
+ case "really equals":
1579
+ case "is really":
1580
+ case "is really equal to":
1581
+ return `(${left} === ${right})`;
1582
+ case "is not really":
1583
+ case "is not really equal to":
1584
+ return `(${left} !== ${right})`;
1585
+ // Comparison. Left as is, `(n is greater than 2)` is not JavaScript.
1562
1586
  case "<":
1563
1587
  case ">":
1564
1588
  case "<=":
1565
1589
  case ">=":
1566
1590
  return `(${left} ${op} ${right})`;
1591
+ case "is less than":
1592
+ return `(${left} < ${right})`;
1593
+ case "is greater than":
1594
+ return `(${left} > ${right})`;
1595
+ case "is less than or equal to":
1596
+ return `(${left} <= ${right})`;
1597
+ case "is greater than or equal to":
1598
+ return `(${left} >= ${right})`;
1567
1599
  // Arithmetic
1568
1600
  case "+":
1569
1601
  case "-":
@@ -1571,6 +1603,9 @@ var ExpressionCodegen = class {
1571
1603
  case "/":
1572
1604
  case "%":
1573
1605
  return `(${left} ${op} ${right})`;
1606
+ // Hyperscript's word for `%`; left as is, `(n mod 2)` is not JavaScript.
1607
+ case "mod":
1608
+ return `(${left} % ${right})`;
1574
1609
  // Logical
1575
1610
  case "and":
1576
1611
  case "&&":
@@ -1580,15 +1615,49 @@ var ExpressionCodegen = class {
1580
1615
  return `(${left} || ${right})`;
1581
1616
  // String/collection operators
1582
1617
  case "contains":
1618
+ case "contain":
1619
+ case "includes":
1620
+ case "include":
1583
1621
  this.ctx.requireHelper("contains");
1584
1622
  return `_rt.contains(${left}, ${right})`;
1623
+ case "does not contain":
1624
+ case "do not contain":
1625
+ case "does not contains":
1626
+ case "does not include":
1627
+ this.ctx.requireHelper("contains");
1628
+ return `!_rt.contains(${left}, ${right})`;
1629
+ // `matches` tests a selector, so a selector operand stays a string: the
1630
+ // element it would query is not a selector (`_rt.matches(el, el)`).
1585
1631
  case "matches":
1632
+ case "match":
1633
+ this.ctx.requireHelper("matches");
1634
+ return `_rt.matches(${left}, ${this.selectorText(node.right, right)})`;
1635
+ case "does not match":
1636
+ case "do not match":
1586
1637
  this.ctx.requireHelper("matches");
1587
- return `_rt.matches(${left}, ${right})`;
1638
+ return `!_rt.matches(${left}, ${this.selectorText(node.right, right)})`;
1639
+ // Membership, `n is in [1, 3]`: the right side contains the left.
1640
+ case "is in":
1641
+ case "am in":
1642
+ this.ctx.requireHelper("contains");
1643
+ return `_rt.contains(${right}, ${left})`;
1644
+ case "is not in":
1645
+ case "am not in":
1646
+ this.ctx.requireHelper("contains");
1647
+ return `!_rt.contains(${right}, ${left})`;
1588
1648
  case "starts with":
1589
1649
  return `${left}.startsWith(${right})`;
1590
1650
  case "ends with":
1591
1651
  return `${left}.endsWith(${right})`;
1652
+ // A scoped query, `<li/> in #list`: the matches inside the scope, as
1653
+ // both engines read it. JavaScript's `in` (the default below) tests a
1654
+ // property KEY, so `(document.querySelector('li') in …)` matched nothing.
1655
+ case "in":
1656
+ if (node.left.type === "selector") {
1657
+ const query = sanitizeSelector(node.left.value);
1658
+ return `${right}.querySelectorAll('${query}')`;
1659
+ }
1660
+ return `(${left} ${op} ${right})`;
1592
1661
  // Class check
1593
1662
  case "has":
1594
1663
  if (node.right.type === "selector") {
@@ -1616,13 +1685,18 @@ var ExpressionCodegen = class {
1616
1685
  return `(${left} ${op} ${right})`;
1617
1686
  }
1618
1687
  }
1688
+ /** A selector operand as its quoted text; any other operand as generated. */
1689
+ selectorText(node, generated) {
1690
+ return node.type === "selector" ? `'${sanitizeSelector(node.value)}'` : generated;
1691
+ }
1619
1692
  // ===========================================================================
1620
1693
  // MEMBER EXPRESSIONS
1621
1694
  // ===========================================================================
1622
1695
  generateMember(node) {
1623
1696
  const object = this.generate(node.object);
1624
- if (typeof node.property === "string") {
1625
- const prop = node.property;
1697
+ const property = node.property;
1698
+ const prop = typeof property === "string" ? property : !node.computed && property.type === "identifier" ? property.value ?? property.name : void 0;
1699
+ if (prop !== void 0) {
1626
1700
  if (prop.startsWith("*")) {
1627
1701
  const styleProp = prop.slice(1);
1628
1702
  return `${object}.style.${styleProp}`;
@@ -1804,6 +1878,12 @@ var ExpressionCodegen = class {
1804
1878
  // ===========================================================================
1805
1879
  // UNARY EXPRESSIONS
1806
1880
  // ===========================================================================
1881
+ /** `x is a Number`, as both engines test it: see the runtime's `typeCheck`. */
1882
+ generateTypeCheck(node) {
1883
+ this.ctx.requireHelper("typeCheck");
1884
+ const test = `_rt.typeCheck(${this.generate(node.value)}, ${JSON.stringify(node.typeName)}, ${node.nullOk})`;
1885
+ return node.negated ? `!${test}` : test;
1886
+ }
1807
1887
  generateUnary(node) {
1808
1888
  const operand = this.generate(node.operand);
1809
1889
  switch (node.operator) {
@@ -1816,6 +1896,22 @@ var ExpressionCodegen = class {
1816
1896
  return `+${operand}`;
1817
1897
  case "no":
1818
1898
  return `!${operand}`;
1899
+ // Core's postfix tests. Left as is, `exists#d1` is not JavaScript.
1900
+ case "exists":
1901
+ case "some":
1902
+ this.ctx.requireHelper("exists");
1903
+ return `_rt.exists(${operand})`;
1904
+ case "does not exist":
1905
+ this.ctx.requireHelper("exists");
1906
+ return `!_rt.exists(${operand})`;
1907
+ case "is empty":
1908
+ this.ctx.requireHelper("isEmpty");
1909
+ return `_rt.isEmpty(${operand})`;
1910
+ case "is not empty":
1911
+ this.ctx.requireHelper("isEmpty");
1912
+ return `!_rt.isEmpty(${operand})`;
1913
+ case "beep!":
1914
+ return `((v) => (console.log('%c[beep]', 'color: orange; font-weight: bold', v), v))(${operand})`;
1819
1915
  default:
1820
1916
  return `${node.operator}${operand}`;
1821
1917
  }
@@ -1834,6 +1930,30 @@ function generateExpression(node, ctx) {
1834
1930
  const codegen = new ExpressionCodegen(ctx);
1835
1931
  return codegen.generate(node);
1836
1932
  }
1933
+ var isNode = (value) => typeof value === "object" && value !== null && "type" in value;
1934
+ function commandTarget(node, ...slots) {
1935
+ if (node.target) return node.target;
1936
+ for (const slot of slots) {
1937
+ const found = slot === "arg" ? node.args?.[0] : node.modifiers?.[slot];
1938
+ if (isNode(found)) return found;
1939
+ }
1940
+ return void 0;
1941
+ }
1942
+ function isScopedQuery(node) {
1943
+ const binary = node;
1944
+ return binary?.type === "binary" && binary.operator === "in" && binary.left.type === "selector";
1945
+ }
1946
+ function allMatches(node, ctx) {
1947
+ if (isScopedQuery(node)) return ctx.generateExpression(node);
1948
+ if (node?.type !== "selector") return null;
1949
+ const selector = node.value;
1950
+ return /^#[\w-]+$/.test(selector) ? null : `document.querySelectorAll('${sanitizeSelector(selector)}')`;
1951
+ }
1952
+ function forEachTarget(node, ctx, op) {
1953
+ const all = allMatches(node, ctx);
1954
+ if (all) return `${all}.forEach(el => ${op("el")})`;
1955
+ return op(node ? ctx.generateExpression(node) : "_ctx.me");
1956
+ }
1837
1957
  var ToggleCodegen = class {
1838
1958
  constructor() {
1839
1959
  this.command = "toggle";
@@ -1841,22 +1961,15 @@ var ToggleCodegen = class {
1841
1961
  generate(node, ctx) {
1842
1962
  const args = node.args ?? [];
1843
1963
  if (args.length === 0) return null;
1844
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
1964
+ const targetNode = commandTarget(node, "on");
1845
1965
  const arg = args[0];
1846
1966
  if (arg.type === "selector") {
1847
1967
  const selector = arg.value;
1848
1968
  if (selector.startsWith(".")) {
1849
1969
  const className = sanitizeClassName(selector.slice(1));
1850
1970
  if (!className) return null;
1851
- if (target === "_ctx.me") {
1852
- return {
1853
- code: `_ctx.me.classList.toggle('${className}')`,
1854
- async: false,
1855
- sideEffects: true
1856
- };
1857
- }
1858
1971
  return {
1859
- code: `Array.from(document.querySelectorAll('${sanitizeSelector(selector.slice(1))}')).forEach(el => el.classList.toggle('${className}'))`,
1972
+ code: forEachTarget(targetNode, ctx, (el) => `${el}.classList.toggle('${className}')`),
1860
1973
  async: false,
1861
1974
  sideEffects: true
1862
1975
  };
@@ -1868,7 +1981,11 @@ var ToggleCodegen = class {
1868
1981
  const attrName = value.slice(1);
1869
1982
  ctx.requireHelper("toggleAttr");
1870
1983
  return {
1871
- code: `_rt.toggleAttr(${target}, '${sanitizeSelector(attrName)}')`,
1984
+ code: forEachTarget(
1985
+ targetNode,
1986
+ ctx,
1987
+ (el) => `_rt.toggleAttr(${el}, '${sanitizeSelector(attrName)}')`
1988
+ ),
1872
1989
  async: false,
1873
1990
  sideEffects: true
1874
1991
  };
@@ -1876,7 +1993,11 @@ var ToggleCodegen = class {
1876
1993
  }
1877
1994
  ctx.requireHelper("toggle");
1878
1995
  return {
1879
- code: `_rt.toggle(${ctx.generateExpression(arg)}, ${target})`,
1996
+ code: forEachTarget(
1997
+ targetNode,
1998
+ ctx,
1999
+ (el) => `_rt.toggle(${ctx.generateExpression(arg)}, ${el})`
2000
+ ),
1880
2001
  async: false,
1881
2002
  sideEffects: true
1882
2003
  };
@@ -1897,15 +2018,8 @@ var AddCodegen = class {
1897
2018
  if (selector.startsWith(".")) {
1898
2019
  const className = sanitizeClassName(selector.slice(1));
1899
2020
  if (!className) return null;
1900
- if (target === "_ctx.me") {
1901
- return {
1902
- code: `_ctx.me.classList.add('${className}')`,
1903
- async: false,
1904
- sideEffects: true
1905
- };
1906
- }
1907
2021
  return {
1908
- code: `${target}.classList.add('${className}')`,
2022
+ code: forEachTarget(targetSlot, ctx, (el) => `${el}.classList.add('${className}')`),
1909
2023
  async: false,
1910
2024
  sideEffects: true
1911
2025
  };
@@ -1928,7 +2042,11 @@ var AddCodegen = class {
1928
2042
  }
1929
2043
  ctx.requireHelper("addClass");
1930
2044
  return {
1931
- code: `_rt.addClass(${target}, ${ctx.generateExpression(arg)})`,
2045
+ code: forEachTarget(
2046
+ targetSlot,
2047
+ ctx,
2048
+ (el) => `_rt.addClass(${el}, ${ctx.generateExpression(arg)})`
2049
+ ),
1932
2050
  async: false,
1933
2051
  sideEffects: true
1934
2052
  };
@@ -1942,23 +2060,29 @@ var RemoveCodegen = class {
1942
2060
  const args = node.args ?? [];
1943
2061
  if (args.length === 0) {
1944
2062
  const targetSlot2 = node.target ?? node.modifiers?.from;
1945
- const target2 = targetSlot2 ? ctx.generateExpression(targetSlot2) : "_ctx.me";
1946
2063
  return {
1947
- code: `${target2}.remove()`,
2064
+ code: forEachTarget(targetSlot2, ctx, (el) => `${el}.remove()`),
1948
2065
  async: false,
1949
2066
  sideEffects: true
1950
2067
  };
1951
2068
  }
1952
2069
  const targetSlot = node.target ?? node.modifiers?.from;
1953
- const target = targetSlot ? ctx.generateExpression(targetSlot) : "_ctx.me";
1954
2070
  const arg = args[0];
2071
+ const isElement = arg.type === "selector" ? !/^[.@]/.test(arg.value) : arg.type === "identifier" && !String(arg.value ?? "").startsWith("@") || arg.type === "variable" || isScopedQuery(arg);
2072
+ if (!targetSlot && isElement) {
2073
+ return {
2074
+ code: forEachTarget(arg, ctx, (el) => `${el}.remove()`),
2075
+ async: false,
2076
+ sideEffects: true
2077
+ };
2078
+ }
1955
2079
  if (arg.type === "selector") {
1956
2080
  const selector = arg.value;
1957
2081
  if (selector.startsWith(".")) {
1958
2082
  const className = sanitizeClassName(selector.slice(1));
1959
2083
  if (!className) return null;
1960
2084
  return {
1961
- code: `${target}.classList.remove('${className}')`,
2085
+ code: forEachTarget(targetSlot, ctx, (el) => `${el}.classList.remove('${className}')`),
1962
2086
  async: false,
1963
2087
  sideEffects: true
1964
2088
  };
@@ -1966,12 +2090,42 @@ var RemoveCodegen = class {
1966
2090
  }
1967
2091
  ctx.requireHelper("removeClass");
1968
2092
  return {
1969
- code: `_rt.removeClass(${target}, ${ctx.generateExpression(arg)})`,
2093
+ code: forEachTarget(
2094
+ targetSlot,
2095
+ ctx,
2096
+ (el) => `_rt.removeClass(${el}, ${ctx.generateExpression(arg)})`
2097
+ ),
1970
2098
  async: false,
1971
2099
  sideEffects: true
1972
2100
  };
1973
2101
  }
1974
2102
  };
2103
+ function variableStore(node, ctx) {
2104
+ let name;
2105
+ let scope;
2106
+ if (node.type === "variable") {
2107
+ name = node.name;
2108
+ scope = node.scope;
2109
+ } else if (node.type === "identifier") {
2110
+ name = node.value ?? node.name ?? "";
2111
+ if (/^(\$|::)/.test(name)) scope = "global";
2112
+ else if (/^[A-Za-z_]\w*$/.test(name)) scope = "local";
2113
+ else return null;
2114
+ } else {
2115
+ return null;
2116
+ }
2117
+ const key = sanitizeIdentifier(name.replace(/^(\$|::|:)/, ""));
2118
+ if (scope === "global") {
2119
+ ctx.requireHelper("globals");
2120
+ return { read: `_rt.globals.get('${key}')`, write: (v) => `_rt.globals.set('${key}', ${v})` };
2121
+ }
2122
+ if (scope === "element") {
2123
+ ctx.requireHelper("elementVars");
2124
+ const store = `_rt.elementVars(_ctx.me)`;
2125
+ return { read: `${store}.get('${key}')`, write: (v) => `${store}.set('${key}', ${v})` };
2126
+ }
2127
+ return { read: `_ctx.locals.get('${key}')`, write: (v) => `_ctx.locals.set('${key}', ${v})` };
2128
+ }
1975
2129
  var SetCodegen = class {
1976
2130
  constructor() {
1977
2131
  this.command = "set";
@@ -1984,26 +2138,8 @@ var SetCodegen = class {
1984
2138
  const valueNode = roles?.patient ?? modifiers?.to ?? args[1];
1985
2139
  if (!targetNode || !valueNode) return null;
1986
2140
  const value = ctx.generateExpression(valueNode);
1987
- if (targetNode.type === "variable") {
1988
- const varNode = targetNode;
1989
- const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
1990
- const safeName = sanitizeIdentifier(name);
1991
- if (varNode.scope === "local") {
1992
- return {
1993
- code: `_ctx.locals.set('${safeName}', ${value})`,
1994
- async: false,
1995
- sideEffects: true
1996
- };
1997
- }
1998
- if (varNode.scope === "global") {
1999
- ctx.requireHelper("globals");
2000
- return {
2001
- code: `_rt.globals.set('${safeName}', ${value})`,
2002
- async: false,
2003
- sideEffects: true
2004
- };
2005
- }
2006
- }
2141
+ const store = variableStore(targetNode, ctx);
2142
+ if (store) return { code: store.write(value), async: false, sideEffects: true };
2007
2143
  if (targetNode.type === "possessive") {
2008
2144
  const possessive = targetNode;
2009
2145
  const obj = ctx.generateExpression(possessive.object);
@@ -2052,20 +2188,17 @@ var PutCodegen = class {
2052
2188
  const contentNode = roles?.patient ?? args[0];
2053
2189
  if (!contentNode) return null;
2054
2190
  const content = ctx.generateExpression(contentNode);
2055
- let target = "_ctx.me";
2056
- if (roles?.destination) {
2057
- target = ctx.generateExpression(roles.destination);
2058
- } else if (modifiers) {
2191
+ let targetNode = roles?.destination;
2192
+ if (!targetNode && modifiers) {
2059
2193
  for (const key of ["into", "before", "after"]) {
2060
2194
  if (modifiers[key] && typeof modifiers[key] === "object") {
2061
- target = ctx.generateExpression(modifiers[key]);
2195
+ targetNode = modifiers[key];
2062
2196
  break;
2063
2197
  }
2064
2198
  }
2065
2199
  }
2066
- if (target === "_ctx.me" && node.target) {
2067
- target = ctx.generateExpression(node.target);
2068
- }
2200
+ targetNode ?? (targetNode = node.target);
2201
+ const into = (op) => forEachTarget(targetNode, ctx, op);
2069
2202
  let modifier = "into";
2070
2203
  if (roles?.method && roles.method.value) {
2071
2204
  modifier = String(roles.method.value);
@@ -2077,39 +2210,39 @@ var PutCodegen = class {
2077
2210
  switch (modifier) {
2078
2211
  case "into":
2079
2212
  return {
2080
- code: `${target}.innerHTML = ${content}`,
2213
+ code: into((el) => `${el}.innerHTML = ${content}`),
2081
2214
  async: false,
2082
2215
  sideEffects: true
2083
2216
  };
2084
2217
  case "before":
2085
2218
  return {
2086
- code: `${target}.insertAdjacentHTML('beforebegin', ${content})`,
2219
+ code: into((el) => `${el}.insertAdjacentHTML('beforebegin', ${content})`),
2087
2220
  async: false,
2088
2221
  sideEffects: true
2089
2222
  };
2090
2223
  case "after":
2091
2224
  return {
2092
- code: `${target}.insertAdjacentHTML('afterend', ${content})`,
2225
+ code: into((el) => `${el}.insertAdjacentHTML('afterend', ${content})`),
2093
2226
  async: false,
2094
2227
  sideEffects: true
2095
2228
  };
2096
2229
  case "at start of":
2097
2230
  case "start":
2098
2231
  return {
2099
- code: `${target}.insertAdjacentHTML('afterbegin', ${content})`,
2232
+ code: into((el) => `${el}.insertAdjacentHTML('afterbegin', ${content})`),
2100
2233
  async: false,
2101
2234
  sideEffects: true
2102
2235
  };
2103
2236
  case "at end of":
2104
2237
  case "end":
2105
2238
  return {
2106
- code: `${target}.insertAdjacentHTML('beforeend', ${content})`,
2239
+ code: into((el) => `${el}.insertAdjacentHTML('beforeend', ${content})`),
2107
2240
  async: false,
2108
2241
  sideEffects: true
2109
2242
  };
2110
2243
  default:
2111
2244
  return {
2112
- code: `${target}.innerHTML = ${content}`,
2245
+ code: into((el) => `${el}.innerHTML = ${content}`),
2113
2246
  async: false,
2114
2247
  sideEffects: true
2115
2248
  };
@@ -2121,9 +2254,9 @@ var ShowCodegen = class {
2121
2254
  this.command = "show";
2122
2255
  }
2123
2256
  generate(node, ctx) {
2124
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2257
+ const targetNode = commandTarget(node, "arg");
2125
2258
  return {
2126
- code: `${target}.style.display = ''`,
2259
+ code: forEachTarget(targetNode, ctx, (el) => `${el}.style.display = ''`),
2127
2260
  async: false,
2128
2261
  sideEffects: true
2129
2262
  };
@@ -2134,9 +2267,22 @@ var HideCodegen = class {
2134
2267
  this.command = "hide";
2135
2268
  }
2136
2269
  generate(node, ctx) {
2137
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2270
+ const targetNode = commandTarget(node, "arg");
2271
+ return {
2272
+ code: forEachTarget(targetNode, ctx, (el) => `${el}.style.display = 'none'`),
2273
+ async: false,
2274
+ sideEffects: true
2275
+ };
2276
+ }
2277
+ };
2278
+ var EmptyCodegen = class {
2279
+ constructor() {
2280
+ this.command = "empty";
2281
+ }
2282
+ generate(node, ctx) {
2283
+ const targetNode = commandTarget(node, "arg");
2138
2284
  return {
2139
- code: `${target}.style.display = 'none'`,
2285
+ code: forEachTarget(targetNode, ctx, (el) => `${el}.replaceChildren()`),
2140
2286
  async: false,
2141
2287
  sideEffects: true
2142
2288
  };
@@ -2147,7 +2293,8 @@ var FocusCodegen = class {
2147
2293
  this.command = "focus";
2148
2294
  }
2149
2295
  generate(node, ctx) {
2150
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2296
+ const targetNode = commandTarget(node, "arg");
2297
+ const target = targetNode ? ctx.generateExpression(targetNode) : "_ctx.me";
2151
2298
  return {
2152
2299
  code: `${target}.focus()`,
2153
2300
  async: false,
@@ -2160,7 +2307,8 @@ var BlurCodegen = class {
2160
2307
  this.command = "blur";
2161
2308
  }
2162
2309
  generate(node, ctx) {
2163
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2310
+ const targetNode = commandTarget(node, "arg");
2311
+ const target = targetNode ? ctx.generateExpression(targetNode) : "_ctx.me";
2164
2312
  return {
2165
2313
  code: `${target}.blur()`,
2166
2314
  async: false,
@@ -2281,11 +2429,11 @@ var SendCodegen = class {
2281
2429
  const args = node.args ?? [];
2282
2430
  if (args.length === 0) return null;
2283
2431
  const eventName = ctx.generateExpression(args[0]);
2284
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2432
+ const targetNode = commandTarget(node, "on", "to");
2285
2433
  const detail = args.length > 1 ? ctx.generateExpression(args[1]) : "undefined";
2286
2434
  ctx.requireHelper("send");
2287
2435
  return {
2288
- code: `_rt.send(${target}, ${eventName}, ${detail})`,
2436
+ code: forEachTarget(targetNode, ctx, (el) => `_rt.send(${el}, ${eventName}, ${detail})`),
2289
2437
  async: false,
2290
2438
  sideEffects: true
2291
2439
  };
@@ -2303,25 +2451,10 @@ var IncrementCodegen = class {
2303
2451
  if (!target) return null;
2304
2452
  const amountNode = roles?.quantity ?? modifiers?.by ?? args[1];
2305
2453
  const amount = amountNode ? ctx.generateExpression(amountNode) : "1";
2306
- if (target.type === "variable") {
2307
- const varNode = target;
2308
- const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
2309
- const safeName = sanitizeIdentifier(name);
2310
- if (varNode.scope === "local") {
2311
- return {
2312
- code: `_ctx.locals.set('${safeName}', (_ctx.locals.get('${safeName}') || 0) + ${amount})`,
2313
- async: false,
2314
- sideEffects: true
2315
- };
2316
- }
2317
- if (varNode.scope === "global") {
2318
- ctx.requireHelper("globals");
2319
- return {
2320
- code: `_rt.globals.set('${safeName}', (_rt.globals.get('${safeName}') || 0) + ${amount})`,
2321
- async: false,
2322
- sideEffects: true
2323
- };
2324
- }
2454
+ const store = variableStore(target, ctx);
2455
+ if (store) {
2456
+ const code = store.write(`(Number(${store.read}) || 0) + ${amount}`);
2457
+ return { code, async: false, sideEffects: true };
2325
2458
  }
2326
2459
  const targetCode = ctx.generateExpression(target);
2327
2460
  return {
@@ -2343,25 +2476,10 @@ var DecrementCodegen = class {
2343
2476
  if (!target) return null;
2344
2477
  const amountNode = roles?.quantity ?? modifiers?.by ?? args[1];
2345
2478
  const amount = amountNode ? ctx.generateExpression(amountNode) : "1";
2346
- if (target.type === "variable") {
2347
- const varNode = target;
2348
- const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
2349
- const safeName = sanitizeIdentifier(name);
2350
- if (varNode.scope === "local") {
2351
- return {
2352
- code: `_ctx.locals.set('${safeName}', (_ctx.locals.get('${safeName}') || 0) - ${amount})`,
2353
- async: false,
2354
- sideEffects: true
2355
- };
2356
- }
2357
- if (varNode.scope === "global") {
2358
- ctx.requireHelper("globals");
2359
- return {
2360
- code: `_rt.globals.set('${safeName}', (_rt.globals.get('${safeName}') || 0) - ${amount})`,
2361
- async: false,
2362
- sideEffects: true
2363
- };
2364
- }
2479
+ const store = variableStore(target, ctx);
2480
+ if (store) {
2481
+ const code = store.write(`(Number(${store.read}) || 0) - ${amount}`);
2482
+ return { code, async: false, sideEffects: true };
2365
2483
  }
2366
2484
  const targetCode = ctx.generateExpression(target);
2367
2485
  return {
@@ -2426,17 +2544,37 @@ var CallCodegen = class {
2426
2544
  };
2427
2545
  }
2428
2546
  };
2547
+ var SCROLL_BLOCK = {
2548
+ top: "start",
2549
+ middle: "center",
2550
+ bottom: "end",
2551
+ nearest: "nearest"
2552
+ };
2553
+ var SCROLL_INLINE = { left: "start", center: "center", right: "end" };
2554
+ function scrollOptions(modifiers) {
2555
+ const word = (slot) => {
2556
+ const value = modifiers?.[slot]?.value;
2557
+ return typeof value === "string" ? value : void 0;
2558
+ };
2559
+ const position = word("position") ?? "";
2560
+ const options = [];
2561
+ if (SCROLL_BLOCK[position]) options.push(`block: '${SCROLL_BLOCK[position]}'`);
2562
+ if (SCROLL_INLINE[position]) options.push(`inline: '${SCROLL_INLINE[position]}'`);
2563
+ const behavior = modifiers?.smooth ? "smooth" : word("behavior");
2564
+ options.push(
2565
+ `behavior: '${behavior === "smooth" || behavior === "instant" ? behavior : "auto"}'`
2566
+ );
2567
+ return `{ ${options.join(", ")} }`;
2568
+ }
2429
2569
  var ScrollCodegen = class {
2430
2570
  constructor() {
2431
2571
  this.command = "scroll";
2432
2572
  }
2433
2573
  generate(node, ctx) {
2434
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2435
- const mods = node.modifiers;
2436
- const smooth = mods?.smooth || mods?.behavior?.value === "smooth";
2437
- const behavior = smooth ? "'smooth'" : "'auto'";
2574
+ const targetNode = commandTarget(node, "arg", "of");
2575
+ const target = targetNode ? ctx.generateExpression(targetNode) : "_ctx.me";
2438
2576
  return {
2439
- code: `${target}.scrollIntoView({ behavior: ${behavior} })`,
2577
+ code: `${target}.scrollIntoView(${scrollOptions(node.modifiers)})`,
2440
2578
  async: false,
2441
2579
  sideEffects: true
2442
2580
  };
@@ -2446,7 +2584,7 @@ var TakeCodegen = class {
2446
2584
  constructor() {
2447
2585
  this.command = "take";
2448
2586
  }
2449
- generate(node, _ctx) {
2587
+ generate(node, ctx) {
2450
2588
  const args = node.args ?? [];
2451
2589
  if (args.length === 0) return null;
2452
2590
  const arg = args[0];
@@ -2455,6 +2593,19 @@ var TakeCodegen = class {
2455
2593
  if (!selector.startsWith(".")) return null;
2456
2594
  const className = sanitizeClassName(selector.slice(1));
2457
2595
  if (!className) return null;
2596
+ const source = commandTarget(node, "from");
2597
+ if (source) {
2598
+ let from = allMatches(source, ctx);
2599
+ if (!from) {
2600
+ ctx.requireHelper("toArray");
2601
+ from = `_rt.toArray(${ctx.generateExpression(source)})`;
2602
+ }
2603
+ return {
2604
+ code: `(() => { ${from}.forEach(el => el.classList.remove('${className}')); _ctx.me.classList.add('${className}'); })()`,
2605
+ async: false,
2606
+ sideEffects: true
2607
+ };
2608
+ }
2458
2609
  return {
2459
2610
  code: `(() => { const _me = _ctx.me; _me.parentElement?.querySelectorAll('.${className}').forEach(el => el.classList.remove('${className}')); _me.classList.add('${className}'); })()`,
2460
2611
  async: false,
@@ -2486,49 +2637,85 @@ ${elseBody}
2486
2637
  }
2487
2638
  return code;
2488
2639
  }
2640
+ function emitLoop(parts) {
2641
+ const pass = [
2642
+ ...parts.elseBody !== void 0 ? ["_ran = true;"] : [],
2643
+ ...parts.enter ? [parts.enter] : [],
2644
+ ...parts.indexName ? [`_ctx.locals.set('${sanitizeIdentifier(parts.indexName)}', _i);`] : [],
2645
+ parts.body
2646
+ ].join("\n");
2647
+ const step = parts.step ? `_i++, ${parts.step}` : "_i++";
2648
+ const loop = parts.bottomTested ? (
2649
+ // A `continue` jumps straight to the test, so the counter moves there.
2650
+ `let _i = 0;
2651
+ do {
2652
+ ${pass}
2653
+ } while ((${step}, ${parts.test}));`
2654
+ ) : `for (let _i = 0; ${parts.test}; ${step}) {
2655
+ ${pass}
2656
+ }`;
2657
+ if (parts.elseBody === void 0) return parts.bottomTested ? `{
2658
+ ${loop}
2659
+ }` : loop;
2660
+ return `{
2661
+ let _ran = false;
2662
+ ${loop}
2663
+ if (!_ran) {
2664
+ ${parts.elseBody}
2665
+ }
2666
+ }`;
2667
+ }
2489
2668
  function generateRepeat(node, ctx, generateBody) {
2490
2669
  const exprCodegen = new ExpressionCodegen(ctx);
2491
- const body = generateBody(node.body);
2670
+ const shared = {
2671
+ indexName: node.indexName,
2672
+ body: generateBody(node.body),
2673
+ elseBody: node.elseBody ? generateBody(node.elseBody) : void 0
2674
+ };
2492
2675
  if (node.count !== void 0) {
2493
2676
  const count = typeof node.count === "number" ? String(node.count) : exprCodegen.generate(node.count);
2494
- return `for (let _i = 0; _i < ${count}; _i++) {
2495
- _ctx.locals.set('index', _i);
2496
- ${body}
2497
- }`;
2677
+ return emitLoop({ ...shared, test: `_i < ${count}`, indexName: node.indexName ?? "index" });
2498
2678
  }
2499
2679
  if (node.whileCondition) {
2500
- const condition = exprCodegen.generate(node.whileCondition);
2501
- return `while (${condition}) {
2502
- ${body}
2503
- }`;
2680
+ return emitLoop({ ...shared, test: exprCodegen.generate(node.whileCondition) });
2504
2681
  }
2505
- return `while (true) {
2506
- ${body}
2682
+ if (node.untilEvent !== void 0) {
2683
+ ctx.requireHelper("wait");
2684
+ const target = node.untilEventTarget ? exprCodegen.generate(node.untilEventTarget) : "_ctx.me";
2685
+ return `{
2686
+ let _fired = false;
2687
+ ${target}.addEventListener(${JSON.stringify(node.untilEvent)}, () => { _fired = true; }, { once: true });
2688
+ ${emitLoop({ ...shared, test: "!_fired", step: "await _rt.wait(0)" })}
2507
2689
  }`;
2690
+ }
2691
+ return emitLoop({ ...shared, test: "true" });
2508
2692
  }
2509
2693
  function generateForEach(node, ctx, generateBody) {
2510
2694
  const exprCodegen = new ExpressionCodegen(ctx);
2511
- const collection = exprCodegen.generate(node.collection);
2695
+ const source = node.collection;
2696
+ const collection = source.type === "selector" && !String(source.value).startsWith("#") ? `document.querySelectorAll('${sanitizeSelector(String(source.value))}')` : exprCodegen.generate(source);
2512
2697
  const itemName = sanitizeIdentifier(node.itemName);
2513
- const indexName = node.indexName ? sanitizeIdentifier(node.indexName) : "index";
2514
- const body = generateBody(node.body);
2515
2698
  return `{
2516
2699
  const _collection = ${collection};
2517
- const _arr = Array.isArray(_collection) ? _collection : Array.from(_collection);
2518
- for (let _i = 0; _i < _arr.length; _i++) {
2519
- _ctx.locals.set('${itemName}', _arr[_i]);
2520
- _ctx.locals.set('${indexName}', _i);
2521
- ${body}
2522
- }
2700
+ const _arr = _collection == null ? [] : Array.isArray(_collection) ? _collection : Array.from(_collection);
2701
+ ${emitLoop({
2702
+ test: "_i < _arr.length",
2703
+ enter: `_ctx.locals.set('${itemName}', _arr[_i]);`,
2704
+ indexName: node.indexName ?? "index",
2705
+ body: generateBody(node.body),
2706
+ elseBody: node.elseBody ? generateBody(node.elseBody) : void 0
2707
+ })}
2523
2708
  }`;
2524
2709
  }
2525
2710
  function generateWhile(node, ctx, generateBody) {
2526
2711
  const exprCodegen = new ExpressionCodegen(ctx);
2527
- const condition = exprCodegen.generate(node.condition);
2528
- const body = generateBody(node.body);
2529
- return `while (${condition}) {
2530
- ${body}
2531
- }`;
2712
+ return emitLoop({
2713
+ test: exprCodegen.generate(node.condition),
2714
+ bottomTested: node.bottomTested,
2715
+ indexName: node.indexName,
2716
+ body: generateBody(node.body),
2717
+ elseBody: node.elseBody ? generateBody(node.elseBody) : void 0
2718
+ });
2532
2719
  }
2533
2720
  var UnlessCodegen = class {
2534
2721
  constructor() {
@@ -2571,25 +2758,10 @@ var DefaultCodegen = class {
2571
2758
  const valueNode = roles?.patient ?? modifiers?.to ?? args[1];
2572
2759
  if (!targetNode || !valueNode) return null;
2573
2760
  const value = ctx.generateExpression(valueNode);
2574
- if (targetNode.type === "variable") {
2575
- const varNode = targetNode;
2576
- const name = varNode.name.startsWith(":") ? varNode.name.slice(1) : varNode.name;
2577
- const safeName = sanitizeIdentifier(name);
2578
- if (varNode.scope === "local") {
2579
- return {
2580
- code: `if (_ctx.locals.get('${safeName}') == null) _ctx.locals.set('${safeName}', ${value})`,
2581
- async: false,
2582
- sideEffects: true
2583
- };
2584
- }
2585
- if (varNode.scope === "global") {
2586
- ctx.requireHelper("globals");
2587
- return {
2588
- code: `if (_rt.globals.get('${safeName}') == null) _rt.globals.set('${safeName}', ${value})`,
2589
- async: false,
2590
- sideEffects: true
2591
- };
2592
- }
2761
+ const store = variableStore(targetNode, ctx);
2762
+ if (store) {
2763
+ const code = `if (${store.read} == null) ${store.write(value)}`;
2764
+ return { code, async: false, sideEffects: true };
2593
2765
  }
2594
2766
  return null;
2595
2767
  }
@@ -2605,6 +2777,15 @@ var GoCodegen = class {
2605
2777
  if (mods?.back) {
2606
2778
  return { code: "history.back()", async: false, sideEffects: true };
2607
2779
  }
2780
+ if (mods?.position || mods?.behavior) {
2781
+ const element = roles?.destination ?? args[0];
2782
+ if (!element) return null;
2783
+ return {
2784
+ code: `${ctx.generateExpression(element)}.scrollIntoView(${scrollOptions(mods)})`,
2785
+ async: false,
2786
+ sideEffects: true
2787
+ };
2788
+ }
2608
2789
  const target = mods?.url ?? roles?.destination ?? args[0];
2609
2790
  if (!target) return null;
2610
2791
  if (target.type === "identifier") {
@@ -2616,9 +2797,10 @@ var GoCodegen = class {
2616
2797
  return { code: "history.forward()", async: false, sideEffects: true };
2617
2798
  }
2618
2799
  }
2619
- const url = ctx.generateExpression(target);
2800
+ ctx.requireHelper("go");
2801
+ const newWindow = mods?.in !== void 0 ? ", true" : "";
2620
2802
  return {
2621
- code: `window.location.href = ${url}`,
2803
+ code: `_rt.go(${ctx.generateExpression(target)}${newWindow})`,
2622
2804
  async: false,
2623
2805
  sideEffects: true
2624
2806
  };
@@ -2634,7 +2816,8 @@ var AppendCodegen = class {
2634
2816
  const contentNode = roles?.patient ?? args[0];
2635
2817
  if (!contentNode) return null;
2636
2818
  const content = ctx.generateExpression(contentNode);
2637
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
2819
+ const targetNode = commandTarget(node, "to");
2820
+ const target = targetNode ? ctx.generateExpression(targetNode) : "_ctx.me";
2638
2821
  return {
2639
2822
  code: `${target}.insertAdjacentHTML('beforeend', ${content})`,
2640
2823
  async: false,
@@ -3013,7 +3196,8 @@ var SettleCodegen = class {
3013
3196
  this.command = "settle";
3014
3197
  }
3015
3198
  generate(node, ctx) {
3016
- const target = node.target ? ctx.generateExpression(node.target) : "_ctx.me";
3199
+ const targetNode = commandTarget(node, "arg");
3200
+ const target = targetNode ? ctx.generateExpression(targetNode) : "_ctx.me";
3017
3201
  const mods = node.modifiers;
3018
3202
  const timeoutNode = mods?.for;
3019
3203
  const timeout = timeoutNode ? ctx.generateExpression(timeoutNode) : "5000";
@@ -3133,6 +3317,7 @@ var commandCodegens = /* @__PURE__ */ new Map([
3133
3317
  ["put", new PutCodegen()],
3134
3318
  ["show", new ShowCodegen()],
3135
3319
  ["hide", new HideCodegen()],
3320
+ ["empty", new EmptyCodegen()],
3136
3321
  ["focus", new FocusCodegen()],
3137
3322
  ["blur", new BlurCodegen()],
3138
3323
  ["log", new LogCodegen()],
@@ -3259,6 +3444,8 @@ var EventHandlerCodegen = class {
3259
3444
  return generateForEach(node, this.ctx, (nodes) => this.generateBody(nodes));
3260
3445
  case "while":
3261
3446
  return generateWhile(node, this.ctx, (nodes) => this.generateBody(nodes));
3447
+ case "sequence":
3448
+ return this.generateBody(node.commands);
3262
3449
  case "event": {
3263
3450
  const nested = node;
3264
3451
  return this.generateBody(nested.body ?? []);
@@ -4131,15 +4318,8 @@ var AOTCompiler = class {
4131
4318
  * Create a codegen context.
4132
4319
  */
4133
4320
  createCodegenContext(handlerId, analysis, options) {
4134
- const selectorCache = /* @__PURE__ */ new Map();
4135
4321
  const requiredHelpers = /* @__PURE__ */ new Set();
4136
4322
  let idCounter = 0;
4137
- for (const info of analysis.expressions.selectors) {
4138
- if (info.canCache && info.usages.length > 1) {
4139
- const cacheKey = "_sel_" + sanitizeIdentifier(info.selector).slice(0, 20) + "_" + idCounter++;
4140
- selectorCache.set(info.selector, cacheKey);
4141
- }
4142
- }
4143
4323
  const exprCodegenRef = { current: null };
4144
4324
  const ctx = {
4145
4325
  handlerId,
@@ -4152,8 +4332,12 @@ var AOTCompiler = class {
4152
4332
  },
4153
4333
  implicitTarget: "_ctx.me",
4154
4334
  localVarDeclarations: "",
4155
- canCacheSelector: (selector) => selectorCache.has(selector),
4156
- getCachedSelector: (selector) => selectorCache.get(selector) ?? `document.querySelector('${selector}')`,
4335
+ // A selector is queried each time it is evaluated, as on both engines. The
4336
+ // cache named a variable nothing declared (`_sel__d1_0`: a handler naming
4337
+ // #d1 twice threw), and a declared one goes stale when the handler
4338
+ // replaces the element.
4339
+ canCacheSelector: () => false,
4340
+ getCachedSelector: (selector) => `document.querySelector('${selector}')`,
4157
4341
  requireHelper: (name) => {
4158
4342
  requiredHelpers.add(name);
4159
4343
  },
@@ -4223,7 +4407,7 @@ async function compileHyperscript(code, options) {
4223
4407
  async function createMultilingualCompiler() {
4224
4408
  const compiler = new AOTCompiler();
4225
4409
  try {
4226
- const { createCoreParserAdapter: createCoreParserAdapter2 } = await import("./core-parser-adapter-W5UPZR4X-B6CKOVA3.js");
4410
+ const { createCoreParserAdapter: createCoreParserAdapter2 } = await import("./core-parser-adapter-W5UPZR4X-QSTMJ42V.js");
4227
4411
  compiler.setParser(await createCoreParserAdapter2());
4228
4412
  } catch {
4229
4413
  }
@@ -4276,4 +4460,4 @@ export {
4276
4460
  sanitizeSelector,
4277
4461
  scanFiles
4278
4462
  };
4279
- //# sourceMappingURL=dist-WWPF6XTQ.js.map
4463
+ //# sourceMappingURL=dist-6EMM5HXE.js.map