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