@barefootjs/test 0.17.1 → 0.18.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.
Files changed (2) hide show
  1. package/dist/index.js +337 -71
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -187437,6 +187437,7 @@ function convertNode(node, raw) {
187437
187437
  if (callee.property === "flat") {
187438
187438
  const depthNode = node.arguments[0];
187439
187439
  let flatDepth;
187440
+ let depthExpr;
187440
187441
  if (depthNode === undefined) {
187441
187442
  flatDepth = 1;
187442
187443
  } else if (import_typescript.default.isIdentifier(depthNode) && depthNode.text === "Infinity") {
@@ -187449,16 +187450,23 @@ function convertNode(node, raw) {
187449
187450
  n = -Number(depthNode.operand.text);
187450
187451
  }
187451
187452
  if (n === undefined || Number.isNaN(n)) {
187452
- return {
187453
- kind: "unsupported",
187454
- raw,
187455
- reason: `\`.flat(depth)\` needs a literal integer or \`Infinity\` depth — a computed depth can't be resolved at template time. Use a literal depth, or pre-compute the value before the template.`
187456
- };
187453
+ const parsedDepth = convertNode(depthNode, raw);
187454
+ if (checkSupport(parsedDepth).supported) {
187455
+ depthExpr = parsedDepth;
187456
+ flatDepth = 1;
187457
+ } else {
187458
+ return {
187459
+ kind: "unsupported",
187460
+ raw,
187461
+ reason: `\`.flat(depth)\` needs a literal integer, \`Infinity\`, or a supported dynamic depth expression — this depth can't be resolved. Use a literal depth, a supported expression (prop/signal/arithmetic), or pre-compute the value before the template.`
187462
+ };
187463
+ }
187464
+ } else {
187465
+ const truncated = Math.trunc(n);
187466
+ flatDepth = truncated < 0 ? 0 : truncated;
187457
187467
  }
187458
- const truncated = Math.trunc(n);
187459
- flatDepth = truncated < 0 ? 0 : truncated;
187460
187468
  }
187461
- return { kind: "array-method", method: "flat", object: callee.object, args: [], flatDepth };
187469
+ return depthExpr !== undefined ? { kind: "array-method", method: "flat", object: callee.object, args: [], flatDepth, depthExpr } : { kind: "array-method", method: "flat", object: callee.object, args: [], flatDepth };
187462
187470
  }
187463
187471
  if (callee.property === "toLowerCase") {
187464
187472
  return { kind: "array-method", method: "toLowerCase", object: callee.object, args };
@@ -188003,6 +188011,8 @@ function validateRestUsage(expr, restName, excludedTopKeys) {
188003
188011
  walk(e.object);
188004
188012
  for (const a of e.args)
188005
188013
  walk(a);
188014
+ if (e.method === "flat" && e.depthExpr)
188015
+ walk(e.depthExpr);
188006
188016
  return;
188007
188017
  case "literal":
188008
188018
  case "unsupported":
@@ -188088,6 +188098,8 @@ function collectIdentifiers(expr, out) {
188088
188098
  case "array-method":
188089
188099
  collectIdentifiers(expr.object, out);
188090
188100
  expr.args.forEach((e) => collectIdentifiers(e, out));
188101
+ if (expr.method === "flat" && expr.depthExpr)
188102
+ collectIdentifiers(expr.depthExpr, out);
188091
188103
  return;
188092
188104
  case "literal":
188093
188105
  case "regex":
@@ -188145,7 +188157,14 @@ function substituteDestructuredFields(expr, fieldMap, syntheticParam, restName)
188145
188157
  return { kind: "array-literal", elements: e.elements.map(walk) };
188146
188158
  case "array-method":
188147
188159
  if (e.method === "flat") {
188148
- return { kind: "array-method", method: "flat", object: walk(e.object), args: [], flatDepth: e.flatDepth };
188160
+ return {
188161
+ kind: "array-method",
188162
+ method: "flat",
188163
+ object: walk(e.object),
188164
+ args: [],
188165
+ flatDepth: e.flatDepth,
188166
+ ...e.depthExpr ? { depthExpr: walk(e.depthExpr) } : {}
188167
+ };
188149
188168
  }
188150
188169
  return { kind: "array-method", method: e.method, object: walk(e.object), args: e.args.map(walk) };
188151
188170
  case "literal":
@@ -188242,6 +188261,11 @@ function checkSupport(expr) {
188242
188261
  if (!argSupport.supported)
188243
188262
  return argSupport;
188244
188263
  }
188264
+ if (expr.method === "flat" && expr.depthExpr) {
188265
+ const depthSupport = checkSupport(expr.depthExpr);
188266
+ if (!depthSupport.supported)
188267
+ return depthSupport;
188268
+ }
188245
188269
  return { supported: true, level: "L2" };
188246
188270
  }
188247
188271
  case "call": {
@@ -188341,6 +188365,9 @@ function checkSupport(expr) {
188341
188365
  const leftSupport = checkSupport(expr.left);
188342
188366
  if (!leftSupport.supported)
188343
188367
  return leftSupport;
188368
+ if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
188369
+ return { supported: true, level: "L4" };
188370
+ }
188344
188371
  const rightSupport = checkSupport(expr.right);
188345
188372
  if (!rightSupport.supported)
188346
188373
  return rightSupport;
@@ -188535,7 +188562,10 @@ function usesPerPath(name, expr) {
188535
188562
  case "array-literal":
188536
188563
  return sum(e.elements);
188537
188564
  case "array-method":
188538
- return add(walk(e.object), e.method === "flat" ? { min: 0, max: 0 } : sum(e.args));
188565
+ if (e.method === "flat") {
188566
+ return add(walk(e.object), e.depthExpr ? walk(e.depthExpr) : { min: 0, max: 0 });
188567
+ }
188568
+ return add(walk(e.object), sum(e.args));
188539
188569
  case "object-literal":
188540
188570
  return sum(e.properties.map((p) => p.value));
188541
188571
  case "arrow":
@@ -188590,7 +188620,14 @@ function inlineBinding(expr, name, value) {
188590
188620
  return { kind: "array-literal", elements: e.elements.map((el) => walk(el, enclosing)) };
188591
188621
  case "array-method":
188592
188622
  if (e.method === "flat") {
188593
- return { kind: "array-method", method: "flat", object: walk(e.object, enclosing), args: [], flatDepth: e.flatDepth };
188623
+ return {
188624
+ kind: "array-method",
188625
+ method: "flat",
188626
+ object: walk(e.object, enclosing),
188627
+ args: [],
188628
+ flatDepth: e.flatDepth,
188629
+ ...e.depthExpr ? { depthExpr: walk(e.depthExpr, enclosing) } : {}
188630
+ };
188594
188631
  }
188595
188632
  return { kind: "array-method", method: e.method, object: walk(e.object, enclosing), args: e.args.map((a) => walk(a, enclosing)) };
188596
188633
  case "object-literal":
@@ -188726,6 +188763,9 @@ function stringifyParsedExpr(expr) {
188726
188763
  return `[${expr.elements.map(stringifyParsedExpr).join(", ")}]`;
188727
188764
  case "array-method":
188728
188765
  if (expr.method === "flat") {
188766
+ if (expr.depthExpr) {
188767
+ return `${stringifyParsedExpr(expr.object)}.flat(${stringifyParsedExpr(expr.depthExpr)})`;
188768
+ }
188729
188769
  const d = expr.flatDepth;
188730
188770
  const depthSrc = d === "infinity" ? "Infinity" : String(d);
188731
188771
  return `${stringifyParsedExpr(expr.object)}.flat(${d === 1 ? "" : depthSrc})`;
@@ -189330,6 +189370,15 @@ function createAnalyzerContext(sourceFile, filePath) {
189330
189370
  checker: null,
189331
189371
  componentBodyBlock: null,
189332
189372
  getJS(node) {
189373
+ let ownSourceFile;
189374
+ try {
189375
+ ownSourceFile = node.getSourceFile();
189376
+ } catch {
189377
+ ownSourceFile = undefined;
189378
+ }
189379
+ if (ownSourceFile && ownSourceFile !== sourceFile) {
189380
+ return node.getText(ownSourceFile);
189381
+ }
189333
189382
  return reconstructWithoutTypes(node, sourceFile, this.typeExcludeRanges);
189334
189383
  }
189335
189384
  };
@@ -191306,6 +191355,7 @@ function extractProps(param, ctx) {
191306
191355
  loc: getSourceLocation(param, ctx.sourceFile, ctx.filePath),
191307
191356
  hasIgnoreDirective: ignored
191308
191357
  };
191358
+ const memberTypes = param.type ? collectMemberTypes(param.type, ctx) : null;
191309
191359
  for (const element of param.name.elements) {
191310
191360
  if (import_typescript8.default.isBindingElement(element) && import_typescript8.default.isIdentifier(element.name)) {
191311
191361
  const localName = element.name.text;
@@ -191314,10 +191364,12 @@ function extractProps(param, ctx) {
191314
191364
  ctx.restPropsName = localName;
191315
191365
  continue;
191316
191366
  }
191367
+ const sourcePropName = element.propertyName && import_typescript8.default.isIdentifier(element.propertyName) ? element.propertyName.text : localName;
191368
+ const resolvedType = memberTypes?.get(sourcePropName) ?? { kind: "unknown", raw: "unknown" };
191317
191369
  const defaultContainsArrow = element.initializer ? nodeContainsArrow(element.initializer) : false;
191318
191370
  ctx.propsParams.push({
191319
191371
  name: localName,
191320
- type: { kind: "unknown", raw: "unknown" },
191372
+ type: resolvedType,
191321
191373
  optional: !!element.initializer,
191322
191374
  defaultValue,
191323
191375
  defaultContainsArrow: defaultContainsArrow || undefined
@@ -191378,6 +191430,37 @@ function collectKeysFromMembers(members, ctx) {
191378
191430
  }
191379
191431
  return keys;
191380
191432
  }
191433
+ function collectMemberTypes(typeNode, ctx) {
191434
+ const isResolvablePrimitive = (info) => info.kind === "primitive" && (info.primitive === "string" || info.primitive === "number" || info.primitive === "boolean");
191435
+ const fromMembers = (members) => {
191436
+ const map = new Map;
191437
+ for (const member of members) {
191438
+ if (import_typescript8.default.isPropertySignature(member) && member.name && member.type && !member.questionToken) {
191439
+ const info = typeNodeToTypeInfo(member.type, ctx.sourceFile);
191440
+ if (info && isResolvablePrimitive(info)) {
191441
+ map.set(member.name.getText(ctx.sourceFile), info);
191442
+ }
191443
+ }
191444
+ }
191445
+ return map;
191446
+ };
191447
+ if (import_typescript8.default.isTypeLiteralNode(typeNode)) {
191448
+ return fromMembers(typeNode.members);
191449
+ }
191450
+ if (import_typescript8.default.isTypeReferenceNode(typeNode)) {
191451
+ const typeName = typeNode.typeName.getText(ctx.sourceFile);
191452
+ const typeDecl = findTypeDeclaration(typeName, ctx.sourceFile);
191453
+ if (!typeDecl)
191454
+ return null;
191455
+ if (import_typescript8.default.isInterfaceDeclaration(typeDecl)) {
191456
+ return fromMembers(typeDecl.members);
191457
+ }
191458
+ if (import_typescript8.default.isTypeAliasDeclaration(typeDecl) && import_typescript8.default.isTypeLiteralNode(typeDecl.type)) {
191459
+ return fromMembers(typeDecl.type.members);
191460
+ }
191461
+ }
191462
+ return null;
191463
+ }
191381
191464
  function extractPropsFromType(typeNode, ctx) {
191382
191465
  if (import_typescript8.default.isTypeLiteralNode(typeNode)) {
191383
191466
  extractPropsFromTypeMembers(typeNode.members, ctx);
@@ -192034,6 +192117,38 @@ var AttrValueOf = {
192034
192117
  }
192035
192118
  };
192036
192119
 
192120
+ // ../jsx/src/module-exports.ts
192121
+ function formatParamWithType(p) {
192122
+ const rest = p.isRest ? "..." : "";
192123
+ const optional = p.optional ? "?" : "";
192124
+ const typeAnnotation = p.type?.raw && p.type.raw !== "unknown" ? `: ${p.type.raw}` : "";
192125
+ const defaultPart = p.defaultValue !== undefined ? ` = ${p.defaultValue}` : "";
192126
+ return `${rest}${p.name}${optional}${typeAnnotation}${defaultPart}`;
192127
+ }
192128
+ function findReachableNames(primaryRefs, declarations) {
192129
+ const allNames = new Set(declarations.map((d) => d.name));
192130
+ const bodyMap = new Map(declarations.map((d) => [d.name, d.body]));
192131
+ const reachable = new Set;
192132
+ const queue = [];
192133
+ for (const name of allNames) {
192134
+ if (new RegExp(`\\b${name}\\b`).test(primaryRefs)) {
192135
+ reachable.add(name);
192136
+ queue.push(name);
192137
+ }
192138
+ }
192139
+ while (queue.length > 0) {
192140
+ const current = queue.shift();
192141
+ const body = bodyMap.get(current) || "";
192142
+ for (const name of allNames) {
192143
+ if (!reachable.has(name) && new RegExp(`\\b${name}\\b`).test(body)) {
192144
+ reachable.add(name);
192145
+ queue.push(name);
192146
+ }
192147
+ }
192148
+ }
192149
+ return reachable;
192150
+ }
192151
+
192037
192152
  // ../jsx/src/builtins.ts
192038
192153
  var CLIENT_BUILTIN_SOURCE = "@barefootjs/client";
192039
192154
  function isClientBuiltinName(name) {
@@ -193141,6 +193256,7 @@ function transformExpression(node, ctx) {
193141
193256
  return transformExpressionInner(expr, ctx, node, isClientOnly);
193142
193257
  }
193143
193258
  function transformExpressionInner(expr, ctx, node, isClientOnly) {
193259
+ expr = tryDesugarInterleaveTaggedTemplate(expr, ctx);
193144
193260
  checkBareSignalOrMemoIdentifier(expr, ctx);
193145
193261
  if (import_typescript11.default.isIdentifier(expr)) {
193146
193262
  const jsxNode = ctx.analyzer.jsxConstants.get(expr.text);
@@ -193682,11 +193798,10 @@ function isIteratorShapeCall(node) {
193682
193798
  return { array: node.expression.expression, shape: name };
193683
193799
  }
193684
193800
  function extractSortComparator(callback, _method, ctx) {
193685
- const unsupported = () => {
193686
- const raw = ctx.getJS(callback);
193687
- return {
193688
- result: null,
193689
- unsupportedReason: `Sort comparator '${raw}' is not a supported shape. Accepted:
193801
+ const outerRaw = ctx.getJS(callback);
193802
+ const unsupported = () => ({
193803
+ result: null,
193804
+ unsupportedReason: `Sort comparator '${outerRaw}' is not a supported shape. Accepted:
193690
193805
  ` + ` (a, b) => a - b
193691
193806
  ` + ` (a, b) => a.field - b.field
193692
193807
  ` + ` (a, b) => a.localeCompare(b)
@@ -193694,15 +193809,25 @@ function extractSortComparator(callback, _method, ctx) {
193694
193809
  ` + ` (a, b) => a.field > b.field ? 1 : a.field < b.field ? -1 : 0
193695
193810
  ` + ` any of the above '||'-chained for multi-key tie-breaks
193696
193811
  ` + `(reverse the operands for descending order).`
193697
- };
193698
- };
193699
- if (!import_typescript11.default.isArrowFunction(callback) && !import_typescript11.default.isFunctionExpression(callback)) {
193812
+ });
193813
+ let resolvedNode = callback;
193814
+ if (import_typescript11.default.isIdentifier(callback)) {
193815
+ const resolved = resolveSortComparatorIdentifier(callback.text, ctx);
193816
+ if (!resolved) {
193817
+ return {
193818
+ result: null,
193819
+ unsupportedReason: `Sort comparator '${outerRaw}' could not be resolved to a local function — ` + `declare it in the same file or inline it.`
193820
+ };
193821
+ }
193822
+ resolvedNode = resolved;
193823
+ }
193824
+ if (!import_typescript11.default.isArrowFunction(resolvedNode) && !import_typescript11.default.isFunctionExpression(resolvedNode)) {
193700
193825
  return {
193701
193826
  result: null,
193702
193827
  unsupportedReason: "Sort comparator must be an arrow function or function expression"
193703
193828
  };
193704
193829
  }
193705
- const arrow = tsNodeToParsedExpr(callback);
193830
+ const arrow = tsNodeToParsedExpr(resolvedNode);
193706
193831
  if (arrow.kind !== "arrow" || arrow.params.length !== 2)
193707
193832
  return unsupported();
193708
193833
  if (sortComparatorFromArrow(arrow) === null)
@@ -193716,6 +193841,21 @@ function extractSortComparator(callback, _method, ctx) {
193716
193841
  }
193717
193842
  };
193718
193843
  }
193844
+ function resolveSortComparatorIdentifier(name, ctx) {
193845
+ const constInfo = findLocalConst(name, ctx);
193846
+ const fnInfo = findLocalFunction(name, ctx);
193847
+ if (constInfo && fnInfo)
193848
+ return null;
193849
+ if (constInfo) {
193850
+ const ast = parseConstInitializer(constInfo);
193851
+ return ast && (import_typescript11.default.isArrowFunction(ast) || import_typescript11.default.isFunctionExpression(ast)) ? ast : null;
193852
+ }
193853
+ if (fnInfo) {
193854
+ const ast = parseFunctionInfoAsExpr(fnInfo);
193855
+ return ast && (import_typescript11.default.isArrowFunction(ast) || import_typescript11.default.isFunctionExpression(ast)) ? ast : null;
193856
+ }
193857
+ return null;
193858
+ }
193719
193859
  function extractFilterPredicate(callback, ctx) {
193720
193860
  if (!import_typescript11.default.isArrowFunction(callback))
193721
193861
  return { result: null };
@@ -193788,7 +193928,7 @@ function extractLoopParamBindings(pattern) {
193788
193928
  const appendDotAccess = (prefix, key) => {
193789
193929
  return isIdent(key) ? `${prefix}.${key}` : `${prefix}[${JSON.stringify(key)}]`;
193790
193930
  };
193791
- const walk = (p, prefix) => {
193931
+ const walk = (p, prefix, segments) => {
193792
193932
  if (unsupported)
193793
193933
  return;
193794
193934
  if (import_typescript11.default.isArrayBindingPattern(p)) {
@@ -193805,15 +193945,17 @@ function extractLoopParamBindings(pattern) {
193805
193945
  bindings.push({
193806
193946
  name: el.name.text,
193807
193947
  path: prefix,
193808
- rest: { kind: "array", from: index }
193948
+ rest: { kind: "array", from: index },
193949
+ segments
193809
193950
  });
193810
193951
  return;
193811
193952
  }
193812
193953
  const path = `${prefix}[${index}]`;
193954
+ const nextSegments = [...segments, { kind: "index", index }];
193813
193955
  if (import_typescript11.default.isIdentifier(el.name)) {
193814
- bindings.push({ name: el.name.text, path });
193956
+ bindings.push({ name: el.name.text, path, segments: nextSegments });
193815
193957
  } else {
193816
- walk(el.name, path);
193958
+ walk(el.name, path, nextSegments);
193817
193959
  }
193818
193960
  }
193819
193961
  return;
@@ -193830,7 +193972,8 @@ function extractLoopParamBindings(pattern) {
193830
193972
  bindings.push({
193831
193973
  name: el.name.text,
193832
193974
  path: prefix,
193833
- rest: { kind: "object", exclude: collectedKeys }
193975
+ rest: { kind: "object", exclude: collectedKeys },
193976
+ segments
193834
193977
  });
193835
193978
  return;
193836
193979
  }
@@ -193853,17 +193996,19 @@ function extractLoopParamBindings(pattern) {
193853
193996
  unsupported = true;
193854
193997
  return;
193855
193998
  }
193856
- collectedKeys.push({ key: keyText, isIdent: isIdent(keyText) });
193999
+ const keyIsIdent = isIdent(keyText);
194000
+ collectedKeys.push({ key: keyText, isIdent: keyIsIdent });
193857
194001
  const path = appendDotAccess(prefix, keyText);
194002
+ const nextSegments = [...segments, { kind: "field", key: keyText, isIdent: keyIsIdent }];
193858
194003
  if (import_typescript11.default.isIdentifier(el.name)) {
193859
- bindings.push({ name: el.name.text, path });
194004
+ bindings.push({ name: el.name.text, path, segments: nextSegments });
193860
194005
  } else {
193861
- walk(el.name, path);
194006
+ walk(el.name, path, nextSegments);
193862
194007
  }
193863
194008
  }
193864
194009
  };
193865
194010
  if (import_typescript11.default.isArrayBindingPattern(pattern) || import_typescript11.default.isObjectBindingPattern(pattern)) {
193866
- walk(pattern, "");
194011
+ walk(pattern, "", []);
193867
194012
  if (unsupported)
193868
194013
  return { unsupported: true };
193869
194014
  return bindings;
@@ -194632,6 +194777,7 @@ function getAttributeValue(attr, ctx) {
194632
194777
  expr = branchInit;
194633
194778
  }
194634
194779
  }
194780
+ expr = tryDesugarInterleaveTaggedTemplate(expr, ctx);
194635
194781
  if (import_typescript11.default.isAwaitExpression(expr)) {
194636
194782
  ctx.analyzer.errors.push(createError(ErrorCodes.STAGE_AWAIT_IN_TEMPLATE, getSourceLocation(expr, ctx.sourceFile, ctx.filePath)));
194637
194783
  return AttrValueOf.expression("undefined");
@@ -194767,6 +194913,14 @@ function findLocalConst(name, ctx) {
194767
194913
  const pool = fnScoped.length > 0 ? fnScoped : matches;
194768
194914
  return pool[pool.length - 1];
194769
194915
  }
194916
+ function findLocalFunction(name, ctx) {
194917
+ const matches = ctx.analyzer.localFunctions.filter((f) => f.name === name);
194918
+ if (matches.length === 0)
194919
+ return;
194920
+ const fnScoped = matches.filter((f) => !f.isModule);
194921
+ const pool = fnScoped.length > 0 ? fnScoped : matches;
194922
+ return pool[pool.length - 1];
194923
+ }
194770
194924
  function isDynamicTagLocal(name, ctx) {
194771
194925
  if (!hasDynamicTagBinding(name, ctx.sourceFile))
194772
194926
  return false;
@@ -194861,6 +195015,147 @@ function parseConstInitializerImpl(c) {
194861
195015
  function astText(node) {
194862
195016
  return node.getText(node.getSourceFile());
194863
195017
  }
195018
+ var functionInfoExprCache = new WeakMap;
195019
+ function parseFunctionInfoAsExpr(fn) {
195020
+ const cached = functionInfoExprCache.get(fn);
195021
+ if (cached !== undefined)
195022
+ return cached;
195023
+ const result = parseFunctionInfoAsExprImpl(fn);
195024
+ functionInfoExprCache.set(fn, result);
195025
+ return result;
195026
+ }
195027
+ function parseFunctionInfoAsExprImpl(fn) {
195028
+ if (!fn.body)
195029
+ return null;
195030
+ const params = fn.typedParams !== undefined ? fn.typedParams : fn.params.map(formatParamWithType).join(", ");
195031
+ const body = fn.typedBody ?? fn.body;
195032
+ const wrapped = `const __bf_resolve_fn__ = function(${params}) ${body}`;
195033
+ const sf = import_typescript11.default.createSourceFile("__bf_resolve_fn.ts", wrapped, import_typescript11.default.ScriptTarget.Latest, true, import_typescript11.default.ScriptKind.TS);
195034
+ const stmt = sf.statements[0];
195035
+ if (!stmt || !import_typescript11.default.isVariableStatement(stmt))
195036
+ return null;
195037
+ const decl = stmt.declarationList.declarations[0];
195038
+ if (!decl?.initializer)
195039
+ return null;
195040
+ return decl.initializer;
195041
+ }
195042
+ function tryDesugarInterleaveTaggedTemplate(expr, ctx) {
195043
+ if (!import_typescript11.default.isTaggedTemplateExpression(expr))
195044
+ return expr;
195045
+ if (!import_typescript11.default.isIdentifier(expr.tag))
195046
+ return expr;
195047
+ const resolvedTag = resolveInterleaveTagIdentifier(expr.tag.text, ctx);
195048
+ if (!resolvedTag)
195049
+ return expr;
195050
+ if (!isInterleaveTagFunction(resolvedTag))
195051
+ return expr;
195052
+ const rewritten = buildUntaggedTemplateLiteral(expr, ctx);
195053
+ return rewritten ?? expr;
195054
+ }
195055
+ function resolveInterleaveTagIdentifier(name, ctx) {
195056
+ const constInfo = findLocalConst(name, ctx);
195057
+ const fnInfo = findLocalFunction(name, ctx);
195058
+ if (constInfo && fnInfo)
195059
+ return null;
195060
+ if (constInfo) {
195061
+ const ast = parseConstInitializer(constInfo);
195062
+ return ast && (import_typescript11.default.isArrowFunction(ast) || import_typescript11.default.isFunctionExpression(ast)) ? ast : null;
195063
+ }
195064
+ if (fnInfo) {
195065
+ const ast = parseFunctionInfoAsExpr(fnInfo);
195066
+ return ast && (import_typescript11.default.isArrowFunction(ast) || import_typescript11.default.isFunctionExpression(ast)) ? ast : null;
195067
+ }
195068
+ return null;
195069
+ }
195070
+ function isInterleaveTagFunction(fn) {
195071
+ if (!import_typescript11.default.isArrowFunction(fn) && !import_typescript11.default.isFunctionExpression(fn))
195072
+ return false;
195073
+ if (fn.parameters.length !== 2)
195074
+ return false;
195075
+ const [partsParam, argsParam] = fn.parameters;
195076
+ if (!import_typescript11.default.isIdentifier(partsParam.name) || partsParam.dotDotDotToken)
195077
+ return false;
195078
+ if (!import_typescript11.default.isIdentifier(argsParam.name) || !argsParam.dotDotDotToken)
195079
+ return false;
195080
+ const parsed = tsNodeToParsedExpr(fn);
195081
+ if (parsed.kind !== "arrow")
195082
+ return false;
195083
+ return isInterleaveReduceCall(parsed.body, partsParam.name.text, argsParam.name.text);
195084
+ }
195085
+ function isInterleaveReduceCall(body, partsName, argsName) {
195086
+ if (body.kind !== "call" || body.args.length !== 2)
195087
+ return false;
195088
+ const { callee, args } = body;
195089
+ if (callee.kind !== "member" || callee.computed || callee.property !== "reduce")
195090
+ return false;
195091
+ if (callee.object.kind !== "identifier" || callee.object.name !== partsName)
195092
+ return false;
195093
+ const [callback, init] = args;
195094
+ if (init.kind !== "literal" || init.literalType !== "string" || init.value !== "")
195095
+ return false;
195096
+ if (callback.kind !== "arrow" || callback.params.length !== 3)
195097
+ return false;
195098
+ const [acc, p, i2] = callback.params;
195099
+ return isInterleaveReduceCallbackBody(callback.body, acc, p, i2, argsName);
195100
+ }
195101
+ function isInterleaveReduceCallbackBody(body, acc, p, i2, argsName) {
195102
+ if (body.kind !== "binary" || body.op !== "+")
195103
+ return false;
195104
+ const { left, right } = body;
195105
+ if (left.kind !== "binary" || left.op !== "+")
195106
+ return false;
195107
+ if (left.left.kind !== "identifier" || left.left.name !== acc)
195108
+ return false;
195109
+ if (left.right.kind !== "identifier" || left.right.name !== p)
195110
+ return false;
195111
+ return isInterleaveSpanExpr(right, i2, argsName);
195112
+ }
195113
+ function isInterleaveSpanExpr(expr, i2, argsName) {
195114
+ let inner = expr;
195115
+ if (inner.kind === "call" && inner.args.length === 1 && inner.callee.kind === "identifier" && inner.callee.name === "String") {
195116
+ inner = inner.args[0];
195117
+ }
195118
+ if (inner.kind !== "logical" || inner.op !== "??")
195119
+ return false;
195120
+ if (inner.right.kind !== "literal" || inner.right.literalType !== "string" || inner.right.value !== "") {
195121
+ return false;
195122
+ }
195123
+ const idx = inner.left;
195124
+ if (idx.kind !== "index-access")
195125
+ return false;
195126
+ if (idx.object.kind !== "identifier" || idx.object.name !== argsName)
195127
+ return false;
195128
+ if (idx.index.kind !== "identifier" || idx.index.name !== i2)
195129
+ return false;
195130
+ return true;
195131
+ }
195132
+ function buildUntaggedTemplateLiteral(node, ctx) {
195133
+ const template = node.template;
195134
+ let text;
195135
+ if (import_typescript11.default.isNoSubstitutionTemplateLiteral(template)) {
195136
+ text = "`" + (template.rawText ?? template.text) + "`";
195137
+ } else {
195138
+ let body = template.head.rawText ?? template.head.text;
195139
+ for (const span of template.templateSpans) {
195140
+ const spanText = ctx.getJS(span.expression);
195141
+ body += "${(" + spanText + ") ?? ''}";
195142
+ body += span.literal.rawText ?? span.literal.text;
195143
+ }
195144
+ text = "`" + body + "`";
195145
+ }
195146
+ const wrapped = `const __bf_resolve_tagged__ = (${text})`;
195147
+ const sf = import_typescript11.default.createSourceFile("__bf_resolve_tagged.tsx", wrapped, import_typescript11.default.ScriptTarget.Latest, true, import_typescript11.default.ScriptKind.TSX);
195148
+ const stmt = sf.statements[0];
195149
+ if (!stmt || !import_typescript11.default.isVariableStatement(stmt))
195150
+ return null;
195151
+ const decl = stmt.declarationList.declarations[0];
195152
+ if (!decl?.initializer)
195153
+ return null;
195154
+ const result = import_typescript11.default.isParenthesizedExpression(decl.initializer) ? decl.initializer.expression : decl.initializer;
195155
+ if (!import_typescript11.default.isTemplateExpression(result) && !import_typescript11.default.isNoSubstitutionTemplateLiteral(result))
195156
+ return null;
195157
+ return result;
195158
+ }
194864
195159
  function parseTernary(expr, ctx) {
194865
195160
  const whenTrueValue = getStringValue(expr.whenTrue);
194866
195161
  const whenFalseValue = getStringValue(expr.whenFalse);
@@ -195336,6 +195631,18 @@ var import_typescript12 = __toESM(require_typescript(), 1);
195336
195631
 
195337
195632
  // ../jsx/src/relocate.ts
195338
195633
  var import_typescript13 = __toESM(require_typescript(), 1);
195634
+
195635
+ // ../jsx/src/lowering-registry.ts
195636
+ var plugins = [];
195637
+ function registerLoweringPlugin(plugin) {
195638
+ const existing = plugins.findIndex((p) => p.name === plugin.name);
195639
+ if (existing >= 0)
195640
+ plugins[existing] = plugin;
195641
+ else
195642
+ plugins.push(plugin);
195643
+ }
195644
+
195645
+ // ../jsx/src/relocate.ts
195339
195646
  var REGISTRY_SAFE_BINDING_KINDS = new Set([
195340
195647
  "global",
195341
195648
  "module-import",
@@ -195633,38 +195940,6 @@ class SourceMapGenerator {
195633
195940
  }
195634
195941
  }
195635
195942
 
195636
- // ../jsx/src/module-exports.ts
195637
- function formatParamWithType(p) {
195638
- const rest = p.isRest ? "..." : "";
195639
- const optional = p.optional ? "?" : "";
195640
- const typeAnnotation = p.type?.raw && p.type.raw !== "unknown" ? `: ${p.type.raw}` : "";
195641
- const defaultPart = p.defaultValue !== undefined ? ` = ${p.defaultValue}` : "";
195642
- return `${rest}${p.name}${optional}${typeAnnotation}${defaultPart}`;
195643
- }
195644
- function findReachableNames(primaryRefs, declarations) {
195645
- const allNames = new Set(declarations.map((d) => d.name));
195646
- const bodyMap = new Map(declarations.map((d) => [d.name, d.body]));
195647
- const reachable = new Set;
195648
- const queue = [];
195649
- for (const name of allNames) {
195650
- if (new RegExp(`\\b${name}\\b`).test(primaryRefs)) {
195651
- reachable.add(name);
195652
- queue.push(name);
195653
- }
195654
- }
195655
- while (queue.length > 0) {
195656
- const current = queue.shift();
195657
- const body = bodyMap.get(current) || "";
195658
- for (const name of allNames) {
195659
- if (!reachable.has(name) && new RegExp(`\\b${name}\\b`).test(body)) {
195660
- reachable.add(name);
195661
- queue.push(name);
195662
- }
195663
- }
195664
- }
195665
- return reachable;
195666
- }
195667
-
195668
195943
  // ../jsx/src/preprocess-inline-jsx-callbacks.ts
195669
195944
  var import_typescript15 = __toESM(require_typescript(), 1);
195670
195945
 
@@ -196163,15 +196438,6 @@ function isOmitBranch(node) {
196163
196438
  }
196164
196439
  return false;
196165
196440
  }
196166
- // ../jsx/src/lowering-registry.ts
196167
- var plugins = [];
196168
- function registerLoweringPlugin(plugin) {
196169
- const existing = plugins.findIndex((p) => p.name === plugin.name);
196170
- if (existing >= 0)
196171
- plugins[existing] = plugin;
196172
- else
196173
- plugins.push(plugin);
196174
- }
196175
196441
  // ../jsx/src/builtin-lowering-plugins.ts
196176
196442
  var queryHrefPlugin = {
196177
196443
  name: "queryHref",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/test",
3
- "version": "0.17.1",
3
+ "version": "0.18.0",
4
4
  "description": "Test utilities for BarefootJS - IR-based component testing without a browser",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,7 +39,7 @@
39
39
  "directory": "packages/test"
40
40
  },
41
41
  "dependencies": {
42
- "@barefootjs/jsx": "0.17.1"
42
+ "@barefootjs/jsx": "0.18.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.0.0"