olova 2.0.72 → 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,25 +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
- try {
1030
- const generated = generate2(node).code;
1031
- const code = t.isBlockStatement(node) ? `(() => ${generated})` : `(${generated})`;
1032
- traverse(parseModule(code), {
1033
- JSXElement() {
1034
- found = true;
1035
- },
1036
- JSXFragment() {
1037
- found = true;
1038
- }
1039
- });
1040
- } catch {
1041
- found = false;
1042
- }
1043
- return found;
1052
+ return nodeHasJsx(node);
1044
1053
  };
1045
1054
  traverse(ast, {
1046
1055
  FunctionDeclaration(path) {
@@ -1062,12 +1071,8 @@ function collectScriptInfo(script) {
1062
1071
  allSignalNames,
1063
1072
  jsxFunctionNames
1064
1073
  );
1065
- const parsed = parseModule(`(${transformed.code})`);
1066
- const statement = parsed.program.body[0];
1067
- if (statement && t.isExpressionStatement(statement)) {
1068
- path.replaceWith(statement.expression);
1069
- path.skip();
1070
- }
1074
+ path.replaceWith(parseStandaloneExpression(transformed.code));
1075
+ path.skip();
1071
1076
  },
1072
1077
  JSXFragment(path) {
1073
1078
  const transformed = transformExpression(
@@ -1076,12 +1081,8 @@ function collectScriptInfo(script) {
1076
1081
  allSignalNames,
1077
1082
  jsxFunctionNames
1078
1083
  );
1079
- const parsed = parseModule(`(${transformed.code})`);
1080
- const statement = parsed.program.body[0];
1081
- if (statement && t.isExpressionStatement(statement)) {
1082
- path.replaceWith(statement.expression);
1083
- path.skip();
1084
- }
1084
+ path.replaceWith(parseStandaloneExpression(transformed.code));
1085
+ path.skip();
1085
1086
  }
1086
1087
  });
1087
1088
  if (needsGlobalRuntime) {
@@ -1115,7 +1116,7 @@ function collectScriptInfo(script) {
1115
1116
  };
1116
1117
  }
1117
1118
  function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames = /* @__PURE__ */ new Set(), scopeId) {
1118
- const ast = parseModule(`(${expr})`);
1119
+ const ast = createExpressionFile(parseStandaloneExpression(expr));
1119
1120
  let containsJsx = false;
1120
1121
  const jsxScopeAttr = createScopeAttr(scopeId);
1121
1122
  traverse(ast, {
@@ -1177,16 +1178,7 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1177
1178
  const toStringCall = (input) => t.callExpression(t.identifier("__olovaToString"), [input]);
1178
1179
  const escapeCall = (input) => t.callExpression(t.identifier("__olovaEscape"), [input]);
1179
1180
  const expressionContainsJsx = (input) => {
1180
- let found = false;
1181
- traverse(parseModule(`(${generate2(input).code})`), {
1182
- JSXElement() {
1183
- found = true;
1184
- },
1185
- JSXFragment() {
1186
- found = true;
1187
- }
1188
- });
1189
- return found;
1181
+ return nodeHasJsx(input);
1190
1182
  };
1191
1183
  const expressionProducesHtml = (input) => {
1192
1184
  if (!input) {
@@ -1196,19 +1188,18 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1196
1188
  return true;
1197
1189
  }
1198
1190
  let found = false;
1199
- traverse(parseModule(`(${generate2(input).code})`), {
1200
- CallExpression(path) {
1201
- 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)) {
1202
1202
  found = true;
1203
- path.stop();
1204
- return;
1205
- }
1206
- if (t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.property) && (path.node.callee.property.name === "map" || path.node.callee.property.name === "flatMap")) {
1207
- const [firstArg] = path.node.arguments;
1208
- if (t.isIdentifier(firstArg) && jsxFunctionNames.has(firstArg.name) || nodeContainsRenderableFunction(firstArg, jsxFunctionNames)) {
1209
- found = true;
1210
- path.stop();
1211
- }
1212
1203
  }
1213
1204
  }
1214
1205
  });
@@ -1251,7 +1242,7 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1251
1242
  return walkMember(name);
1252
1243
  };
1253
1244
  const transformEmbeddedJsxExpression = (input) => {
1254
- const wrapped = parseModule(`(${generate2(input).code})`);
1245
+ const wrapped = createExpressionFile(input);
1255
1246
  let containsNestedJsx = false;
1256
1247
  traverse(wrapped, {
1257
1248
  JSXElement(path) {
@@ -1434,17 +1425,16 @@ function transformExpression(expr, stateNames, allSignalNames, jsxFunctionNames
1434
1425
  }
1435
1426
  });
1436
1427
  const statement = ast.program.body[0];
1437
- if (!statement || !t.isExpressionStatement(statement)) {
1428
+ const expression = statement && t.isExpressionStatement(statement) ? statement.expression : null;
1429
+ if (!expression) {
1438
1430
  return { code: expr.trim(), containsJsx };
1439
1431
  }
1440
- containsJsx = containsJsx || expressionProducesHtml(statement.expression);
1441
- return { code: generate2(statement.expression).code, containsJsx };
1432
+ containsJsx = containsJsx || expressionProducesHtml(expression);
1433
+ return { code: generate2(expression).code, containsJsx };
1442
1434
  }
1443
1435
  function parseExpressionNode(expr) {
1444
1436
  try {
1445
- const ast = parseModule(`(${expr})`);
1446
- const statement = ast.program.body[0];
1447
- return statement && t.isExpressionStatement(statement) ? statement.expression : null;
1437
+ return parseStandaloneExpression(expr);
1448
1438
  } catch {
1449
1439
  return null;
1450
1440
  }
@@ -1632,90 +1622,75 @@ function transformTemplate(template, stateNames, allSignalNames, jsxFunctionName
1632
1622
  const ifBindings = [];
1633
1623
  html = replaceTemplateExpressions(html, (expr) => {
1634
1624
  try {
1635
- const ast = parseModule(`(${expr})`);
1636
- const exprNode = ast.program.body[0];
1637
- if (t.isExpressionStatement(exprNode)) {
1638
- const node = exprNode.expression;
1639
- const containsJsxNode = (n) => {
1640
- let found = false;
1641
- traverse(parseModule(`(${generate2(n).code})`), {
1642
- JSXElement() {
1643
- found = true;
1644
- },
1645
- JSXFragment() {
1646
- found = true;
1647
- }
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
+ )
1648
1652
  });
1649
- return found;
1650
- };
1651
- if (t.isLogicalExpression(node) && node.operator === "&&") {
1652
- if (containsJsxNode(node.right)) {
1653
- const id = `i${counters.if++}`;
1654
- const condition = generate2(node.left).code;
1655
- const trueBranchHtml = jsxToTemplateHtml(node.right);
1656
- ifBindings.push({
1657
- id,
1658
- expr: transformExpression(
1659
- condition,
1660
- stateNames,
1661
- allSignalNames,
1662
- jsxFunctionNames,
1663
- scopeId
1664
- ).code,
1665
- trueBranch: transformTemplate(
1666
- trueBranchHtml,
1667
- stateNames,
1668
- allSignalNames,
1669
- jsxFunctionNames,
1670
- componentNames,
1671
- counters,
1672
- scopeId,
1673
- devWarnings,
1674
- filename
1675
- )
1676
- });
1677
- return `__O_IF_${id}__`;
1678
- }
1679
- } else if (t.isConditionalExpression(node)) {
1680
- if (containsJsxNode(node.consequent) || containsJsxNode(node.alternate)) {
1681
- const id = `i${counters.if++}`;
1682
- const condition = generate2(node.test).code;
1683
- const trueBranchHtml = containsJsxNode(node.consequent) ? jsxToTemplateHtml(node.consequent) : `{${generate2(node.consequent).code}}`;
1684
- const falseBranchHtml = containsJsxNode(node.alternate) ? jsxToTemplateHtml(node.alternate) : `{${generate2(node.alternate).code}}`;
1685
- ifBindings.push({
1686
- id,
1687
- expr: transformExpression(
1688
- condition,
1689
- stateNames,
1690
- allSignalNames,
1691
- jsxFunctionNames,
1692
- scopeId
1693
- ).code,
1694
- trueBranch: transformTemplate(
1695
- trueBranchHtml,
1696
- stateNames,
1697
- allSignalNames,
1698
- jsxFunctionNames,
1699
- componentNames,
1700
- counters,
1701
- scopeId,
1702
- devWarnings,
1703
- filename
1704
- ),
1705
- falseBranch: transformTemplate(
1706
- falseBranchHtml,
1707
- stateNames,
1708
- allSignalNames,
1709
- jsxFunctionNames,
1710
- componentNames,
1711
- counters,
1712
- scopeId,
1713
- devWarnings,
1714
- filename
1715
- )
1716
- });
1717
- return `__O_IF_${id}__`;
1718
- }
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}__`;
1719
1694
  }
1720
1695
  }
1721
1696
  } catch {
@@ -1861,9 +1836,7 @@ function transformTemplate(template, stateNames, allSignalNames, jsxFunctionName
1861
1836
  const rawValue = node.attrs.fallback;
1862
1837
  if (rawValue.startsWith("{") && rawValue.endsWith("}")) {
1863
1838
  const fallbackExpression = rawValue.slice(1, -1).trim();
1864
- const fallbackAst = parseModule(`(${fallbackExpression})`);
1865
- const fallbackStatement = fallbackAst.program.body[0];
1866
- const fallbackNode = fallbackStatement && t.isExpressionStatement(fallbackStatement) ? fallbackStatement.expression : null;
1839
+ const fallbackNode = parseExpressionNode(fallbackExpression);
1867
1840
  if (fallbackNode && (t.isJSXElement(fallbackNode) || t.isJSXFragment(fallbackNode))) {
1868
1841
  slotFactories.push({
1869
1842
  varName: `__slot_${id}_fallback`,