olova 2.0.71 → 2.0.73

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/compiler.js CHANGED
@@ -1,4 +1,4 @@
1
- import { parse } from '@babel/parser';
1
+ import { parse, parseExpression } from '@babel/parser';
2
2
  import generatorModule from '@babel/generator';
3
3
  import traverseModule from '@babel/traverse';
4
4
  import * as t from '@babel/types';
@@ -655,6 +655,33 @@ function parseModule(code) {
655
655
  plugins: ["typescript", "jsx"]
656
656
  });
657
657
  }
658
+ function parseStandaloneExpression(code) {
659
+ return parseExpression(code, {
660
+ plugins: ["typescript", "jsx"]
661
+ });
662
+ }
663
+ function createExpressionFile(expression) {
664
+ return t.file(
665
+ t.program([
666
+ t.expressionStatement(t.cloneNode(expression, true))
667
+ ])
668
+ );
669
+ }
670
+ function nodeHasJsx(node) {
671
+ if (!node) {
672
+ return false;
673
+ }
674
+ let found = false;
675
+ t.traverseFast(node, (child) => {
676
+ if (found) {
677
+ return;
678
+ }
679
+ if (t.isJSXElement(child) || t.isJSXFragment(child)) {
680
+ found = true;
681
+ }
682
+ });
683
+ return found;
684
+ }
658
685
  function runCompilePhase(phase, fn) {
659
686
  try {
660
687
  return fn();
@@ -1022,19 +1049,7 @@ function collectScriptInfo(script) {
1022
1049
  });
1023
1050
  addNestedMutationNotify(ast, stateNames);
1024
1051
  const nodeContainsJsx = (node) => {
1025
- if (!node) {
1026
- return false;
1027
- }
1028
- let found = false;
1029
- traverse(parseModule(`(${generate2(node).code})`), {
1030
- JSXElement() {
1031
- found = true;
1032
- },
1033
- JSXFragment() {
1034
- found = true;
1035
- }
1036
- });
1037
- return found;
1052
+ return nodeHasJsx(node);
1038
1053
  };
1039
1054
  traverse(ast, {
1040
1055
  FunctionDeclaration(path) {
@@ -1056,12 +1071,8 @@ function collectScriptInfo(script) {
1056
1071
  allSignalNames,
1057
1072
  jsxFunctionNames
1058
1073
  );
1059
- const parsed = parseModule(`(${transformed.code})`);
1060
- const statement = parsed.program.body[0];
1061
- if (statement && t.isExpressionStatement(statement)) {
1062
- path.replaceWith(statement.expression);
1063
- path.skip();
1064
- }
1074
+ path.replaceWith(parseStandaloneExpression(transformed.code));
1075
+ path.skip();
1065
1076
  },
1066
1077
  JSXFragment(path) {
1067
1078
  const transformed = transformExpression(
@@ -1070,12 +1081,8 @@ function collectScriptInfo(script) {
1070
1081
  allSignalNames,
1071
1082
  jsxFunctionNames
1072
1083
  );
1073
- const parsed = parseModule(`(${transformed.code})`);
1074
- const statement = parsed.program.body[0];
1075
- if (statement && t.isExpressionStatement(statement)) {
1076
- path.replaceWith(statement.expression);
1077
- path.skip();
1078
- }
1084
+ path.replaceWith(parseStandaloneExpression(transformed.code));
1085
+ path.skip();
1079
1086
  }
1080
1087
  });
1081
1088
  if (needsGlobalRuntime) {
@@ -1109,7 +1116,7 @@ function collectScriptInfo(script) {
1109
1116
  };
1110
1117
  }
1111
1118
  function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames = /* @__PURE__ */ new Set(), scopeId) {
1112
- const ast = parseModule(`(${expr})`);
1119
+ const ast = createExpressionFile(parseStandaloneExpression(expr));
1113
1120
  let containsJsx = false;
1114
1121
  const jsxScopeAttr = createScopeAttr(scopeId);
1115
1122
  traverse(ast, {
@@ -1171,16 +1178,7 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1171
1178
  const toStringCall = (input) => t.callExpression(t.identifier("__olovaToString"), [input]);
1172
1179
  const escapeCall = (input) => t.callExpression(t.identifier("__olovaEscape"), [input]);
1173
1180
  const expressionContainsJsx = (input) => {
1174
- let found = false;
1175
- traverse(parseModule(`(${generate2(input).code})`), {
1176
- JSXElement() {
1177
- found = true;
1178
- },
1179
- JSXFragment() {
1180
- found = true;
1181
- }
1182
- });
1183
- return found;
1181
+ return nodeHasJsx(input);
1184
1182
  };
1185
1183
  const expressionProducesHtml = (input) => {
1186
1184
  if (!input) {
@@ -1190,19 +1188,18 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1190
1188
  return true;
1191
1189
  }
1192
1190
  let found = false;
1193
- traverse(parseModule(`(${generate2(input).code})`), {
1194
- CallExpression(path) {
1195
- if (t.isIdentifier(path.node.callee) && jsxFunctionNames.has(path.node.callee.name)) {
1191
+ t.traverseFast(input, (child) => {
1192
+ if (found || !t.isCallExpression(child)) {
1193
+ return;
1194
+ }
1195
+ if (t.isIdentifier(child.callee) && jsxFunctionNames.has(child.callee.name)) {
1196
+ found = true;
1197
+ return;
1198
+ }
1199
+ if (t.isMemberExpression(child.callee) && t.isIdentifier(child.callee.property) && (child.callee.property.name === "map" || child.callee.property.name === "flatMap")) {
1200
+ const [firstArg] = child.arguments;
1201
+ if (t.isIdentifier(firstArg) && jsxFunctionNames.has(firstArg.name) || nodeContainsRenderableFunction(firstArg, jsxFunctionNames)) {
1196
1202
  found = true;
1197
- path.stop();
1198
- return;
1199
- }
1200
- if (t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.property) && (path.node.callee.property.name === "map" || path.node.callee.property.name === "flatMap")) {
1201
- const [firstArg] = path.node.arguments;
1202
- if (t.isIdentifier(firstArg) && jsxFunctionNames.has(firstArg.name) || nodeContainsRenderableFunction(firstArg, jsxFunctionNames)) {
1203
- found = true;
1204
- path.stop();
1205
- }
1206
1203
  }
1207
1204
  }
1208
1205
  });
@@ -1245,7 +1242,7 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1245
1242
  return walkMember(name);
1246
1243
  };
1247
1244
  const transformEmbeddedJsxExpression = (input) => {
1248
- const wrapped = parseModule(`(${generate2(input).code})`);
1245
+ const wrapped = createExpressionFile(input);
1249
1246
  let containsNestedJsx = false;
1250
1247
  traverse(wrapped, {
1251
1248
  JSXElement(path) {
@@ -1428,17 +1425,16 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1428
1425
  }
1429
1426
  });
1430
1427
  const statement = ast.program.body[0];
1431
- if (!statement || !t.isExpressionStatement(statement)) {
1428
+ const expression = statement && t.isExpressionStatement(statement) ? statement.expression : null;
1429
+ if (!expression) {
1432
1430
  return { code: expr.trim(), containsJsx };
1433
1431
  }
1434
- containsJsx = containsJsx || expressionProducesHtml(statement.expression);
1435
- return { code: generate2(statement.expression).code, containsJsx };
1432
+ containsJsx = containsJsx || expressionProducesHtml(expression);
1433
+ return { code: generate2(expression).code, containsJsx };
1436
1434
  }
1437
1435
  function parseExpressionNode(expr) {
1438
1436
  try {
1439
- const ast = parseModule(`(${expr})`);
1440
- const statement = ast.program.body[0];
1441
- return statement && t.isExpressionStatement(statement) ? statement.expression : null;
1437
+ return parseStandaloneExpression(expr);
1442
1438
  } catch {
1443
1439
  return null;
1444
1440
  }
@@ -1626,90 +1622,75 @@ function transformTemplate(template, stateNames, allSignalNames, jsxFunctionName
1626
1622
  const ifBindings = [];
1627
1623
  html = replaceTemplateExpressions(html, (expr) => {
1628
1624
  try {
1629
- const ast = parseModule(`(${expr})`);
1630
- const exprNode = ast.program.body[0];
1631
- if (t.isExpressionStatement(exprNode)) {
1632
- const node = exprNode.expression;
1633
- const containsJsxNode = (n) => {
1634
- let found = false;
1635
- traverse(parseModule(`(${generate2(n).code})`), {
1636
- JSXElement() {
1637
- found = true;
1638
- },
1639
- JSXFragment() {
1640
- found = true;
1641
- }
1625
+ const node = parseStandaloneExpression(expr);
1626
+ const containsJsxNode = (n) => nodeHasJsx(n);
1627
+ if (t.isLogicalExpression(node) && node.operator === "&&") {
1628
+ if (containsJsxNode(node.right)) {
1629
+ const id = `i${counters.if++}`;
1630
+ const condition = generate2(node.left).code;
1631
+ const trueBranchHtml = jsxToTemplateHtml(node.right);
1632
+ ifBindings.push({
1633
+ id,
1634
+ expr: transformExpression(
1635
+ condition,
1636
+ stateNames,
1637
+ allSignalNames,
1638
+ jsxFunctionNames,
1639
+ scopeId
1640
+ ).code,
1641
+ trueBranch: transformTemplate(
1642
+ trueBranchHtml,
1643
+ stateNames,
1644
+ allSignalNames,
1645
+ jsxFunctionNames,
1646
+ componentNames,
1647
+ counters,
1648
+ scopeId,
1649
+ devWarnings,
1650
+ filename
1651
+ )
1642
1652
  });
1643
- return found;
1644
- };
1645
- if (t.isLogicalExpression(node) && node.operator === "&&") {
1646
- if (containsJsxNode(node.right)) {
1647
- const id = `i${counters.if++}`;
1648
- const condition = generate2(node.left).code;
1649
- const trueBranchHtml = jsxToTemplateHtml(node.right);
1650
- ifBindings.push({
1651
- id,
1652
- expr: transformExpression(
1653
- condition,
1654
- stateNames,
1655
- allSignalNames,
1656
- jsxFunctionNames,
1657
- scopeId
1658
- ).code,
1659
- trueBranch: transformTemplate(
1660
- trueBranchHtml,
1661
- stateNames,
1662
- allSignalNames,
1663
- jsxFunctionNames,
1664
- componentNames,
1665
- counters,
1666
- scopeId,
1667
- devWarnings,
1668
- filename
1669
- )
1670
- });
1671
- return `__O_IF_${id}__`;
1672
- }
1673
- } else if (t.isConditionalExpression(node)) {
1674
- if (containsJsxNode(node.consequent) || containsJsxNode(node.alternate)) {
1675
- const id = `i${counters.if++}`;
1676
- const condition = generate2(node.test).code;
1677
- const trueBranchHtml = containsJsxNode(node.consequent) ? jsxToTemplateHtml(node.consequent) : `{${generate2(node.consequent).code}}`;
1678
- const falseBranchHtml = containsJsxNode(node.alternate) ? jsxToTemplateHtml(node.alternate) : `{${generate2(node.alternate).code}}`;
1679
- ifBindings.push({
1680
- id,
1681
- expr: transformExpression(
1682
- condition,
1683
- stateNames,
1684
- allSignalNames,
1685
- jsxFunctionNames,
1686
- scopeId
1687
- ).code,
1688
- trueBranch: transformTemplate(
1689
- trueBranchHtml,
1690
- stateNames,
1691
- allSignalNames,
1692
- jsxFunctionNames,
1693
- componentNames,
1694
- counters,
1695
- scopeId,
1696
- devWarnings,
1697
- filename
1698
- ),
1699
- falseBranch: transformTemplate(
1700
- falseBranchHtml,
1701
- stateNames,
1702
- allSignalNames,
1703
- jsxFunctionNames,
1704
- componentNames,
1705
- counters,
1706
- scopeId,
1707
- devWarnings,
1708
- filename
1709
- )
1710
- });
1711
- return `__O_IF_${id}__`;
1712
- }
1653
+ return `__O_IF_${id}__`;
1654
+ }
1655
+ } else if (t.isConditionalExpression(node)) {
1656
+ if (containsJsxNode(node.consequent) || containsJsxNode(node.alternate)) {
1657
+ const id = `i${counters.if++}`;
1658
+ const condition = generate2(node.test).code;
1659
+ const trueBranchHtml = containsJsxNode(node.consequent) ? jsxToTemplateHtml(node.consequent) : `{${generate2(node.consequent).code}}`;
1660
+ const falseBranchHtml = containsJsxNode(node.alternate) ? jsxToTemplateHtml(node.alternate) : `{${generate2(node.alternate).code}}`;
1661
+ ifBindings.push({
1662
+ id,
1663
+ expr: transformExpression(
1664
+ condition,
1665
+ stateNames,
1666
+ allSignalNames,
1667
+ jsxFunctionNames,
1668
+ scopeId
1669
+ ).code,
1670
+ trueBranch: transformTemplate(
1671
+ trueBranchHtml,
1672
+ stateNames,
1673
+ allSignalNames,
1674
+ jsxFunctionNames,
1675
+ componentNames,
1676
+ counters,
1677
+ scopeId,
1678
+ devWarnings,
1679
+ filename
1680
+ ),
1681
+ falseBranch: transformTemplate(
1682
+ falseBranchHtml,
1683
+ stateNames,
1684
+ allSignalNames,
1685
+ jsxFunctionNames,
1686
+ componentNames,
1687
+ counters,
1688
+ scopeId,
1689
+ devWarnings,
1690
+ filename
1691
+ )
1692
+ });
1693
+ return `__O_IF_${id}__`;
1713
1694
  }
1714
1695
  }
1715
1696
  } catch {
@@ -1855,9 +1836,7 @@ function transformTemplate(template, stateNames, allSignalNames, jsxFunctionName
1855
1836
  const rawValue = node.attrs.fallback;
1856
1837
  if (rawValue.startsWith("{") && rawValue.endsWith("}")) {
1857
1838
  const fallbackExpression = rawValue.slice(1, -1).trim();
1858
- const fallbackAst = parseModule(`(${fallbackExpression})`);
1859
- const fallbackStatement = fallbackAst.program.body[0];
1860
- const fallbackNode = fallbackStatement && t.isExpressionStatement(fallbackStatement) ? fallbackStatement.expression : null;
1839
+ const fallbackNode = parseExpressionNode(fallbackExpression);
1861
1840
  if (fallbackNode && (t.isJSXElement(fallbackNode) || t.isJSXFragment(fallbackNode))) {
1862
1841
  slotFactories.push({
1863
1842
  varName: `__slot_${id}_fallback`,