@barefootjs/test 0.26.2 → 0.26.3

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 +479 -141
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -187301,6 +187301,7 @@ var UNSUPPORTED_METHODS = new Set([
187301
187301
  "some",
187302
187302
  "forEach",
187303
187303
  "flatMap",
187304
+ "fill",
187304
187305
  "charAt",
187305
187306
  "charCodeAt",
187306
187307
  "codePointAt",
@@ -189191,6 +189192,16 @@ function computeFileScope(entryPath) {
189191
189192
 
189192
189193
  // ../jsx/src/ir-to-client-js/csr-substitute.ts
189193
189194
  var import_typescript4 = __toESM(require_typescript(), 1);
189195
+ function extractFreeIdentifiersFromText(text) {
189196
+ if (!text || text.trim().length === 0)
189197
+ return new Set;
189198
+ const sf = import_typescript4.default.createSourceFile("__free_ids__.ts", `(${text});`, import_typescript4.default.ScriptTarget.Latest, true, import_typescript4.default.ScriptKind.TS);
189199
+ const stmt = sf.statements[0];
189200
+ if (!stmt || !import_typescript4.default.isExpressionStatement(stmt))
189201
+ return new Set;
189202
+ const expr = import_typescript4.default.isParenthesizedExpression(stmt.expression) ? stmt.expression.expression : stmt.expression;
189203
+ return extractFreeIdentifiersFromNode(expr);
189204
+ }
189194
189205
 
189195
189206
  // ../jsx/src/ir-to-client-js/html-template.ts
189196
189207
  function splitTemplateInterpolations(inner) {
@@ -189412,6 +189423,39 @@ function reconstructWithoutTypes(node, sourceFile, ranges) {
189412
189423
  }
189413
189424
  return result;
189414
189425
  }
189426
+ function reconstructAsSegments(node, sourceFile, ranges, markers) {
189427
+ const nodeStart = node.getStart(sourceFile);
189428
+ const nodeEnd = node.getEnd();
189429
+ const fullText = sourceFile.text;
189430
+ const edits = [];
189431
+ for (const r of ranges) {
189432
+ if (r.end <= nodeStart || r.start >= nodeEnd)
189433
+ continue;
189434
+ edits.push({ start: r.start, end: r.end, marker: null });
189435
+ }
189436
+ markers.forEach((m, i2) => edits.push({ start: m.start, end: m.end, marker: i2 }));
189437
+ edits.sort((a, b) => a.start - b.start || b.end - a.end);
189438
+ const segments = [];
189439
+ let jsBuf = "";
189440
+ let pos = nodeStart;
189441
+ for (const edit of edits) {
189442
+ if (edit.start < pos)
189443
+ continue;
189444
+ jsBuf += fullText.slice(pos, edit.start);
189445
+ if (edit.marker !== null) {
189446
+ if (jsBuf)
189447
+ segments.push({ js: jsBuf });
189448
+ jsBuf = "";
189449
+ segments.push({ marker: edit.marker });
189450
+ }
189451
+ pos = edit.end;
189452
+ }
189453
+ if (pos < nodeEnd)
189454
+ jsBuf += fullText.slice(pos, nodeEnd);
189455
+ if (jsBuf)
189456
+ segments.push({ js: jsBuf });
189457
+ return segments;
189458
+ }
189415
189459
  function mergeRanges(ranges) {
189416
189460
  if (ranges.length === 0)
189417
189461
  return [];
@@ -189557,10 +189601,11 @@ function findAngleBracketAfter(lastTypeArg, fullText) {
189557
189601
  }
189558
189602
 
189559
189603
  // ../jsx/src/analyzer-context.ts
189560
- function createAnalyzerContext(sourceFile, filePath) {
189604
+ function createAnalyzerContext(sourceFile, filePath, acceptsCallbackBody) {
189561
189605
  return {
189562
189606
  sourceFile,
189563
189607
  filePath,
189608
+ acceptsCallbackBody,
189564
189609
  componentName: null,
189565
189610
  componentNode: null,
189566
189611
  hasDefaultExport: false,
@@ -189606,6 +189651,9 @@ function createAnalyzerContext(sourceFile, filePath) {
189606
189651
  } catch {
189607
189652
  ownSourceFile = undefined;
189608
189653
  }
189654
+ if (process.env.BF_ASSERT_NO_JSX_IN_GETJS === "1" && this.errors.length === 0 && nodeContainsJsx(node)) {
189655
+ throw new Error("getJS() called on a JSX-bearing node — raw JSX must never be spliced " + "into emitted output. Carry mixed content as structured segments " + "(MapCallbackPreamble / FlatMapCallback) instead.");
189656
+ }
189609
189657
  if (ownSourceFile && ownSourceFile !== sourceFile) {
189610
189658
  return node.getText(ownSourceFile);
189611
189659
  }
@@ -189613,6 +189661,11 @@ function createAnalyzerContext(sourceFile, filePath) {
189613
189661
  }
189614
189662
  };
189615
189663
  }
189664
+ function nodeContainsJsx(node) {
189665
+ if (import_typescript7.default.isJsxElement(node) || import_typescript7.default.isJsxSelfClosingElement(node) || import_typescript7.default.isJsxFragment(node))
189666
+ return true;
189667
+ return import_typescript7.default.forEachChild(node, nodeContainsJsx) ?? false;
189668
+ }
189616
189669
  function getSourceLocation(node, sourceFile, filePath) {
189617
189670
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
189618
189671
  const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
@@ -190038,7 +190091,7 @@ function createProgramForFile(source, filePath) {
190038
190091
  return null;
190039
190092
  }
190040
190093
  }
190041
- function analyzeComponent(source, filePath, targetComponentName, program) {
190094
+ function analyzeComponent(source, filePath, targetComponentName, program, acceptsCallbackBody) {
190042
190095
  incrementCounter("filesAnalyzed");
190043
190096
  const hadSharedProgram = program !== undefined;
190044
190097
  const prescan = prescanReactiveFactoriesInSource(source, filePath);
@@ -190071,7 +190124,7 @@ function analyzeComponent(source, filePath, targetComponentName, program) {
190071
190124
  checker = result.checker;
190072
190125
  }
190073
190126
  }
190074
- const ctx = createAnalyzerContext(sourceFile, filePath);
190127
+ const ctx = createAnalyzerContext(sourceFile, filePath, acceptsCallbackBody);
190075
190128
  ctx.checker = checker;
190076
190129
  ctx.reactiveFactories = prescan.factories;
190077
190130
  ctx.declinedReactiveFactories = prescan.declined;
@@ -191123,9 +191176,15 @@ function extractSingleJsxReturn(body) {
191123
191176
  return null;
191124
191177
  return jsxReturn;
191125
191178
  }
191126
- function extractMultiReturnJsxBranches(body) {
191179
+ function preambleUnsafe(preamble, branches, fallback) {
191180
+ if (preamble.length === 0)
191181
+ return false;
191182
+ return fallback === null || branches.some((b) => b.jsxReturn === null);
191183
+ }
191184
+ function extractMultiReturnJsxBranches(body, allowPreamble = false) {
191127
191185
  const branches = [];
191128
191186
  let fallback = null;
191187
+ const preamble = [];
191129
191188
  const stmts = body.statements;
191130
191189
  for (let i2 = 0;i2 < stmts.length; i2++) {
191131
191190
  const stmt = stmts[i2];
@@ -191155,7 +191214,9 @@ function extractMultiReturnJsxBranches(body) {
191155
191214
  }
191156
191215
  if (branches.length === 0)
191157
191216
  return null;
191158
- return { branches, fallback };
191217
+ if (preambleUnsafe(preamble, branches, fallback))
191218
+ return null;
191219
+ return { branches, fallback, preamble };
191159
191220
  }
191160
191221
  break;
191161
191222
  }
@@ -191170,23 +191231,38 @@ function extractMultiReturnJsxBranches(body) {
191170
191231
  const hasDefault = stmt.caseBlock.clauses.some((c) => import_typescript8.default.isDefaultClause(c));
191171
191232
  if (!hasDefault)
191172
191233
  return null;
191234
+ let pendingCases = [];
191173
191235
  for (const clause of stmt.caseBlock.clauses) {
191236
+ if (import_typescript8.default.isCaseClause(clause) && clause.statements.length === 0) {
191237
+ pendingCases.push(clause.expression);
191238
+ continue;
191239
+ }
191174
191240
  const jsxReturn = findJsxReturnInCaseClause(clause);
191175
191241
  const nullReturn = findNullReturnInCaseClause(clause);
191176
191242
  if (!jsxReturn && !nullReturn)
191177
191243
  return null;
191244
+ if (!caseClauseIsDirectReturn(clause))
191245
+ return null;
191178
191246
  if (import_typescript8.default.isCaseClause(clause)) {
191179
191247
  branches.push({
191180
191248
  condition: clause.expression,
191181
- jsxReturn: jsxReturn ?? null
191249
+ jsxReturn: jsxReturn ?? null,
191250
+ extraCaseConditions: pendingCases.length > 0 ? pendingCases : undefined
191182
191251
  });
191252
+ pendingCases = [];
191183
191253
  } else {
191254
+ if (pendingCases.length > 0)
191255
+ return null;
191184
191256
  fallback = jsxReturn ?? null;
191185
191257
  }
191186
191258
  }
191259
+ if (pendingCases.length > 0)
191260
+ return null;
191187
191261
  if (branches.length === 0)
191188
191262
  return null;
191189
- return { branches, fallback, switchDiscriminant: stmt.expression };
191263
+ if (preambleUnsafe(preamble, branches, fallback))
191264
+ return null;
191265
+ return { branches, fallback, switchDiscriminant: stmt.expression, preamble };
191190
191266
  }
191191
191267
  if (import_typescript8.default.isReturnStatement(stmt) && stmt.expression) {
191192
191268
  const expr = unwrapJsxTransparent(stmt.expression);
@@ -191197,13 +191273,22 @@ function extractMultiReturnJsxBranches(body) {
191197
191273
  }
191198
191274
  continue;
191199
191275
  }
191200
- if (import_typescript8.default.isVariableStatement(stmt))
191276
+ if (import_typescript8.default.isVariableStatement(stmt)) {
191277
+ const declFlags = stmt.declarationList.flags;
191278
+ const isConstOrLet = (declFlags & import_typescript8.default.NodeFlags.Const) !== 0 || (declFlags & import_typescript8.default.NodeFlags.Let) !== 0;
191279
+ if (allowPreamble && isConstOrLet && branches.length === 0 && fallback === null) {
191280
+ preamble.push(stmt);
191281
+ continue;
191282
+ }
191201
191283
  return null;
191284
+ }
191202
191285
  return null;
191203
191286
  }
191204
191287
  if (branches.length === 0)
191205
191288
  return null;
191206
- return { branches, fallback };
191289
+ if (preambleUnsafe(preamble, branches, fallback))
191290
+ return null;
191291
+ return { branches, fallback, preamble };
191207
191292
  }
191208
191293
  function isDirectReturnBlock(node) {
191209
191294
  if (import_typescript8.default.isReturnStatement(node))
@@ -191213,9 +191298,9 @@ function isDirectReturnBlock(node) {
191213
191298
  for (const stmt of node.statements) {
191214
191299
  if (import_typescript8.default.isReturnStatement(stmt)) {
191215
191300
  returnCount++;
191216
- } else if (import_typescript8.default.isIfStatement(stmt) || import_typescript8.default.isSwitchStatement(stmt) || import_typescript8.default.isForStatement(stmt) || import_typescript8.default.isForOfStatement(stmt) || import_typescript8.default.isForInStatement(stmt) || import_typescript8.default.isWhileStatement(stmt) || import_typescript8.default.isDoStatement(stmt) || import_typescript8.default.isTryStatement(stmt)) {
191217
- return false;
191301
+ continue;
191218
191302
  }
191303
+ return false;
191219
191304
  }
191220
191305
  return returnCount === 1;
191221
191306
  }
@@ -191246,6 +191331,24 @@ function findJsxReturnInCaseClause(clause) {
191246
191331
  }
191247
191332
  return null;
191248
191333
  }
191334
+ function caseClauseIsDirectReturn(clause) {
191335
+ let returnCount = 0;
191336
+ let seenReturn = false;
191337
+ for (const stmt of clause.statements) {
191338
+ if (import_typescript8.default.isReturnStatement(stmt)) {
191339
+ returnCount++;
191340
+ seenReturn = true;
191341
+ continue;
191342
+ }
191343
+ if (import_typescript8.default.isBreakStatement(stmt)) {
191344
+ if (!seenReturn)
191345
+ return false;
191346
+ continue;
191347
+ }
191348
+ return false;
191349
+ }
191350
+ return returnCount === 1;
191351
+ }
191249
191352
  function findNullReturnInCaseClause(clause) {
191250
191353
  for (const stmt of clause.statements) {
191251
191354
  if (import_typescript8.default.isReturnStatement(stmt) && stmt.expression) {
@@ -193261,6 +193364,9 @@ var REACTIVE_BINDING_KINDS = new Set([
193261
193364
  function isReactiveOrigin(origin) {
193262
193365
  return origin.freeRefs?.some((r) => REACTIVE_BINDING_KINDS.has(r.kind)) ?? false;
193263
193366
  }
193367
+ function tsxSourceText(raw) {
193368
+ return raw;
193369
+ }
193264
193370
  var AttrValueOf = {
193265
193371
  literal(value) {
193266
193372
  return { kind: "literal", value };
@@ -194391,8 +194497,13 @@ function attachParsedExpressions(node, analyzer, bound = EMPTY_BOUND) {
194391
194497
  for (const child of nested.children)
194392
194498
  attachParsedExpressions(child, analyzer, loopBound);
194393
194499
  }
194394
- for (const frag of node.flatMapCallback?.fragments ?? []) {
194395
- attachParsedExpressions(frag.ir, analyzer, loopBound);
194500
+ for (const seg of node.flatMapCallback?.segments ?? []) {
194501
+ if (seg.kind === "jsx")
194502
+ attachParsedExpressions(seg.ir, analyzer, loopBound);
194503
+ }
194504
+ for (const seg of node.preamble?.segments ?? []) {
194505
+ if (seg.kind === "jsx")
194506
+ attachParsedExpressions(seg.ir, analyzer, loopBound);
194396
194507
  }
194397
194508
  break;
194398
194509
  }
@@ -195027,74 +195138,78 @@ function transformMultiReturnJsxFunctionCall(callExpr, info, ctx) {
195027
195138
  ctx.analyzer.getJS = substitutedGetJS;
195028
195139
  try {
195029
195140
  const loc = getSourceLocation(callExpr, ctx.sourceFile, ctx.filePath);
195030
- const nullExpr = {
195031
- type: "expression",
195032
- expr: "null",
195033
- typeInfo: { kind: "primitive", raw: "null", primitive: "null" },
195034
- reactive: false,
195035
- slotId: null,
195036
- loc,
195037
- origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
195038
- };
195039
- let result = info.fallback ? transformNode(info.fallback, ctx) ?? nullExpr : nullExpr;
195040
- for (let i2 = info.branches.length - 1;i2 >= 0; i2--) {
195041
- const branch = info.branches[i2];
195042
- let conditionText;
195043
- if (info.switchDiscriminant) {
195044
- const discText = substitutedGetJS(info.switchDiscriminant);
195045
- const caseText = substitutedGetJS(branch.condition);
195046
- conditionText = `${discText} === ${caseText}`;
195047
- } else {
195048
- conditionText = substitutedGetJS(branch.condition);
195049
- }
195050
- const env = makeBindingEnv(ctx);
195051
- const caseFreeRefs = resolveFreeRefs(branch.condition, env);
195052
- const discFreeRefs = info.switchDiscriminant ? resolveFreeRefs(info.switchDiscriminant, env) : [];
195053
- const conditionOrigin = {
195054
- phase: "tick",
195055
- scope: "template",
195056
- effect: "pure",
195057
- freeRefs: [...discFreeRefs, ...caseFreeRefs]
195058
- };
195059
- const reactive = isReactiveExpression(conditionText, ctx, branch.condition) || isReactiveOrigin(conditionOrigin);
195060
- const loopParamReactive = !reactive && referencesLoopParam(conditionText, ctx);
195061
- const callsReactive = exprCallsReactiveGetters(branch.condition, ctx) || (info.switchDiscriminant ? exprCallsReactiveGetters(info.switchDiscriminant, ctx) : false);
195062
- const hasCalls = exprHasFunctionCalls(branch.condition) || (info.switchDiscriminant ? exprHasFunctionCalls(info.switchDiscriminant) : false);
195063
- const needsSlot = reactive || loopParamReactive || callsReactive || hasCalls;
195064
- const slotId = needsSlot ? generateSlotId(ctx) : null;
195065
- const whenTrue = branch.jsxReturn ? transformNode(branch.jsxReturn, ctx) ?? nullExpr : nullExpr;
195066
- let templateCondition;
195067
- if (info.switchDiscriminant) {
195068
- const discRewritten = rewriteBarePropRefs2(substitutedGetJS(info.switchDiscriminant), info.switchDiscriminant, ctx);
195069
- const caseRewritten = rewriteBarePropRefs2(substitutedGetJS(branch.condition), branch.condition, ctx);
195070
- const discPart = discRewritten ?? substitutedGetJS(info.switchDiscriminant);
195071
- const casePart = caseRewritten ?? substitutedGetJS(branch.condition);
195072
- templateCondition = `${discPart} === ${casePart}`;
195073
- } else {
195074
- templateCondition = rewriteBarePropRefs2(conditionText, branch.condition, ctx);
195075
- }
195076
- const conditional = {
195077
- type: "conditional",
195078
- condition: conditionText,
195079
- templateCondition,
195080
- conditionType: null,
195081
- reactive,
195082
- whenTrue,
195083
- whenFalse: result,
195084
- slotId,
195085
- callsReactiveGetters: callsReactive || undefined,
195086
- hasFunctionCalls: hasCalls || undefined,
195087
- loc,
195088
- origin: conditionOrigin
195089
- };
195090
- result = conditional;
195091
- }
195092
- return result;
195141
+ return foldMultiReturnBranches(info, ctx, loc, substitutedGetJS);
195093
195142
  } finally {
195094
195143
  ctx.getJS = originalCtxGetJS;
195095
195144
  ctx.analyzer.getJS = originalAnalyzerGetJS;
195096
195145
  }
195097
195146
  }
195147
+ function foldMultiReturnBranches(info, ctx, loc, getText) {
195148
+ const nullExpr = {
195149
+ type: "expression",
195150
+ expr: "null",
195151
+ typeInfo: { kind: "primitive", raw: "null", primitive: "null" },
195152
+ reactive: false,
195153
+ slotId: null,
195154
+ loc,
195155
+ origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
195156
+ };
195157
+ let result = info.fallback ? transformNode(info.fallback, ctx) ?? nullExpr : nullExpr;
195158
+ for (let i2 = info.branches.length - 1;i2 >= 0; i2--) {
195159
+ const branch = info.branches[i2];
195160
+ const caseConds = info.switchDiscriminant ? [branch.condition, ...branch.extraCaseConditions ?? []] : [branch.condition];
195161
+ let conditionText;
195162
+ if (info.switchDiscriminant) {
195163
+ const discText = getText(info.switchDiscriminant);
195164
+ conditionText = caseConds.map((c) => `(${discText}) === (${getText(c)})`).join(" || ");
195165
+ } else {
195166
+ conditionText = getText(branch.condition);
195167
+ }
195168
+ const env = makeBindingEnv(ctx);
195169
+ const caseFreeRefs = caseConds.flatMap((c) => resolveFreeRefs(c, env));
195170
+ const discFreeRefs = info.switchDiscriminant ? resolveFreeRefs(info.switchDiscriminant, env) : [];
195171
+ const conditionOrigin = {
195172
+ phase: "tick",
195173
+ scope: "template",
195174
+ effect: "pure",
195175
+ freeRefs: [...discFreeRefs, ...caseFreeRefs]
195176
+ };
195177
+ const reactive = isReactiveExpression(conditionText, ctx, branch.condition) || isReactiveOrigin(conditionOrigin);
195178
+ const loopParamReactive = !reactive && referencesLoopParam(conditionText, ctx);
195179
+ const callsReactive = caseConds.some((c) => exprCallsReactiveGetters(c, ctx)) || (info.switchDiscriminant ? exprCallsReactiveGetters(info.switchDiscriminant, ctx) : false);
195180
+ const hasCalls = caseConds.some((c) => exprHasFunctionCalls(c)) || (info.switchDiscriminant ? exprHasFunctionCalls(info.switchDiscriminant) : false);
195181
+ const needsSlot = reactive || loopParamReactive || callsReactive || hasCalls;
195182
+ const slotId = needsSlot ? generateSlotId(ctx) : null;
195183
+ const whenTrue = branch.jsxReturn ? transformNode(branch.jsxReturn, ctx) ?? nullExpr : nullExpr;
195184
+ let templateCondition;
195185
+ if (info.switchDiscriminant) {
195186
+ const discRewritten = rewriteBarePropRefs2(getText(info.switchDiscriminant), info.switchDiscriminant, ctx);
195187
+ const discPart = discRewritten ?? getText(info.switchDiscriminant);
195188
+ templateCondition = caseConds.map((c) => {
195189
+ const casePart = rewriteBarePropRefs2(getText(c), c, ctx) ?? getText(c);
195190
+ return `(${discPart}) === (${casePart})`;
195191
+ }).join(" || ");
195192
+ } else {
195193
+ templateCondition = rewriteBarePropRefs2(conditionText, branch.condition, ctx);
195194
+ }
195195
+ const conditional = {
195196
+ type: "conditional",
195197
+ condition: conditionText,
195198
+ templateCondition,
195199
+ conditionType: null,
195200
+ reactive,
195201
+ whenTrue,
195202
+ whenFalse: result,
195203
+ slotId,
195204
+ callsReactiveGetters: callsReactive || undefined,
195205
+ hasFunctionCalls: hasCalls || undefined,
195206
+ loc,
195207
+ origin: conditionOrigin
195208
+ };
195209
+ result = conditional;
195210
+ }
195211
+ return result;
195212
+ }
195098
195213
  function transformConditional(node, ctx) {
195099
195214
  const condition = ctx.getJS(node.condition);
195100
195215
  const conditionOrigin = {
@@ -195945,9 +196060,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
195945
196060
  let filterPredicate;
195946
196061
  let sortComparator;
195947
196062
  let chainOrder;
195948
- let mapPreamble;
195949
- let templateMapPreamble;
195950
- let typedMapPreamble;
196063
+ let preamble;
195951
196064
  let iterationShape;
195952
196065
  let objectIteration;
195953
196066
  const setArray = (node2) => {
@@ -195977,7 +196090,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
195977
196090
  const innerFilter = isFilterCall(sortInfo.array);
195978
196091
  const sortExtraction = extractSortComparator(sortInfo.callback, sortInfo.method, ctx);
195979
196092
  if (isClientOnly || !sortExtraction.result) {
195980
- if (!isClientOnly && sortExtraction.unsupportedReason) {
196093
+ if (!isClientOnly && sortExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("sort") ?? false)) {
195981
196094
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(sortInfo.callback, ctx.sourceFile, ctx.filePath), {
195982
196095
  message: `Expression cannot be compiled to marked template: ${sortExtraction.unsupportedReason}`,
195983
196096
  suggestion: {
@@ -195992,7 +196105,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
195992
196105
  chainOrder = "filter-sort";
195993
196106
  const filterExtraction = extractFilterPredicate(innerFilter.callback, ctx);
195994
196107
  if (isClientOnly || !filterExtraction.result) {
195995
- if (!isClientOnly && filterExtraction.unsupportedReason) {
196108
+ if (!isClientOnly && filterExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("filter") ?? false)) {
195996
196109
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(innerFilter.callback, ctx.sourceFile, ctx.filePath), {
195997
196110
  message: `Expression cannot be compiled to marked template: ${filterExtraction.unsupportedReason}`,
195998
196111
  suggestion: {
@@ -196015,7 +196128,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196015
196128
  const innerSort = isSortCall(filterInfo.array);
196016
196129
  const filterExtraction = extractFilterPredicate(filterInfo.callback, ctx);
196017
196130
  if (isClientOnly || !filterExtraction.result) {
196018
- if (!isClientOnly && filterExtraction.unsupportedReason) {
196131
+ if (!isClientOnly && filterExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("filter") ?? false)) {
196019
196132
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(filterInfo.callback, ctx.sourceFile, ctx.filePath), {
196020
196133
  message: `Expression cannot be compiled to marked template: ${filterExtraction.unsupportedReason}`,
196021
196134
  suggestion: {
@@ -196030,7 +196143,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196030
196143
  chainOrder = "sort-filter";
196031
196144
  const sortExtraction = extractSortComparator(innerSort.callback, innerSort.method, ctx);
196032
196145
  if (isClientOnly || !sortExtraction.result) {
196033
- if (!isClientOnly && sortExtraction.unsupportedReason) {
196146
+ if (!isClientOnly && sortExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("sort") ?? false)) {
196034
196147
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(innerSort.callback, ctx.sourceFile, ctx.filePath), {
196035
196148
  message: `Expression cannot be compiled to marked template: ${sortExtraction.unsupportedReason}`,
196036
196149
  suggestion: {
@@ -196145,7 +196258,24 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196145
196258
  } else if (method === "flatMap" && import_typescript11.default.isArrayLiteralExpression(body)) {
196146
196259
  children = transformArrayLiteralChildren(body, ctx);
196147
196260
  } else if (import_typescript11.default.isBlock(body)) {
196148
- const returnStmt = body.statements.find((s) => import_typescript11.default.isReturnStatement(s) && s.expression != null);
196261
+ const multiReturn = method !== "flatMap" ? extractMultiReturnJsxBranches(body, true) : null;
196262
+ if (multiReturn && multiReturn.branches.length > 0) {
196263
+ const loc = getSourceLocation(body, ctx.sourceFile, ctx.filePath);
196264
+ children = [foldMultiReturnBranches(multiReturn, ctx, loc, ctx.getJS)];
196265
+ const pre = multiReturn.preamble ?? [];
196266
+ if (pre.length > 0) {
196267
+ preamble = preambleFromValueStatements(pre, ctx);
196268
+ if (!isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
196269
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, loc, {
196270
+ message: "A .map() callback body with a `const`/`let` preamble before its " + "branches cannot be lowered to a template: the loop-local binding " + "cannot be carried into a conditional branch on this backend.",
196271
+ suggestion: {
196272
+ message: "Add /* @client */ to evaluate this expression on the client only"
196273
+ }
196274
+ }));
196275
+ }
196276
+ }
196277
+ }
196278
+ const returnStmt = children.length === 0 ? body.statements.find((s) => import_typescript11.default.isReturnStatement(s) && s.expression != null) : undefined;
196149
196279
  if (returnStmt && returnStmt.expression) {
196150
196280
  let returnExpr = returnStmt.expression;
196151
196281
  while (import_typescript11.default.isParenthesizedExpression(returnExpr)) {
@@ -196157,32 +196287,53 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196157
196287
  children = [transformed];
196158
196288
  }
196159
196289
  }
196160
- const preambleStmts = [];
196161
- const templatePreambleStmts = [];
196162
- const typedPreambleStmts = [];
196163
- let hasTypeDiff = false;
196164
- let hasTemplateDiff = false;
196290
+ let jsxPreambleStmt;
196165
196291
  for (const stmt of body.statements) {
196166
196292
  if (stmt === returnStmt)
196167
196293
  break;
196168
- const js = ctx.getJS(stmt);
196169
- const tjs = ctx.getTemplateJS(stmt);
196170
- const ts12 = stmt.getText(ctx.sourceFile);
196171
- preambleStmts.push(js.endsWith(";") ? js : js + ";");
196172
- templatePreambleStmts.push(tjs.endsWith(";") ? tjs : tjs + ";");
196173
- typedPreambleStmts.push(ts12.endsWith(";") ? ts12 : ts12 + ";");
196174
- if (js !== ts12)
196175
- hasTypeDiff = true;
196176
- if (js !== tjs)
196177
- hasTemplateDiff = true;
196294
+ if (containsJsxInExpression(stmt)) {
196295
+ jsxPreambleStmt = stmt;
196296
+ break;
196297
+ }
196178
196298
  }
196179
- if (preambleStmts.length > 0) {
196180
- mapPreamble = preambleStmts.join(" ");
196181
- if (hasTemplateDiff) {
196182
- templateMapPreamble = templatePreambleStmts.join(" ");
196299
+ if (jsxPreambleStmt) {
196300
+ const jsRuntime = isClientOnly || (ctx.analyzer.acceptsCallbackBody?.("map") ?? false);
196301
+ if (children.length === 0) {
196302
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(jsxPreambleStmt, ctx.sourceFile, ctx.filePath), {
196303
+ message: "A .map() callback that builds JSX in a statement before its " + "`return` must return a single JSX element that embeds the " + "built array — this return shape has no element root to host it.",
196304
+ suggestion: {
196305
+ message: "Wrap the result in one element root, e.g. `return <tr key={item.id}>{out}</tr>`."
196306
+ }
196307
+ }));
196308
+ } else if (!jsRuntime) {
196309
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(jsxPreambleStmt, ctx.sourceFile, ctx.filePath), {
196310
+ message: "A .map() callback that builds JSX in a statement before its " + "`return` (for example pushing elements into an array in a loop) " + "cannot be lowered to a template on this backend.",
196311
+ suggestion: {
196312
+ message: "Add /* @client */ to render this loop on the client only"
196313
+ }
196314
+ }));
196315
+ } else {
196316
+ const collected = buildPreambleSegments(body.statements, returnStmt, ctx);
196317
+ if (collected.refusalNode) {
196318
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(collected.refusalNode, ctx.sourceFile, ctx.filePath), {
196319
+ message: "A JSX element built in a .map() callback preamble cannot carry " + "event handlers, components, nested loops, or reactive expressions, " + "and cannot sit inside a template literal — the verbatim render " + "path builds it once, with no reactive wiring.",
196320
+ suggestion: {
196321
+ message: "Return the element directly (not through a preamble variable), " + "or add /* @client */ to render the loop on the client only."
196322
+ }
196323
+ }));
196324
+ } else {
196325
+ preamble = collected.preamble;
196326
+ }
196327
+ }
196328
+ } else {
196329
+ const valueStmts = [];
196330
+ for (const stmt of body.statements) {
196331
+ if (stmt === returnStmt)
196332
+ break;
196333
+ valueStmts.push(stmt);
196183
196334
  }
196184
- if (hasTypeDiff) {
196185
- typedMapPreamble = typedPreambleStmts.join(" ");
196335
+ if (valueStmts.length > 0) {
196336
+ preamble = preambleFromValueStatements(valueStmts, ctx);
196186
196337
  }
196187
196338
  }
196188
196339
  }
@@ -196211,6 +196362,31 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196211
196362
  const itemConditional = children.length > 0 ? loopBodyItemConditional(children) : null;
196212
196363
  const bodyIsItemConditional = itemConditional !== null;
196213
196364
  const key = bodyIsItemConditional ? extractItemConditionalKey(itemConditional) : children.length > 0 ? extractLoopKey(children[0]) : null;
196365
+ const declaredNameSet = preamble && preamble.declaredNames.length > 0 ? new Set(preamble.declaredNames) : undefined;
196366
+ if (key && declaredNameSet) {
196367
+ const keyRefs = extractFreeIdentifiersFromText(key);
196368
+ const usesLocal = [...keyRefs].some((r) => declaredNameSet.has(r));
196369
+ if (usesLocal) {
196370
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
196371
+ message: "A .map() loop key must be derivable from the loop item — it is " + "evaluated before the callback body runs, so it cannot reference a " + "value computed in the callback preamble.",
196372
+ suggestion: {
196373
+ message: "Derive the key directly from the loop item (e.g. key={item.id})."
196374
+ }
196375
+ }));
196376
+ }
196377
+ }
196378
+ if (preamble && preamble.builderNames.length > 0) {
196379
+ flagArrayChildExpressions(children, new Set(preamble.builderNames));
196380
+ }
196381
+ if (preamble && preamble.builderNames.length > 0 && children.length === 1 && children[0].type === "component") {
196382
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
196383
+ message: "A .map() callback that builds JSX in its preamble cannot return a " + "component: the built elements would reach the component as raw HTML " + "strings on the client but as JSX elements at SSR (a silent divergence).",
196384
+ suggestion: {
196385
+ message: "Return a plain element root that embeds the array, or move the " + "building logic inside the component."
196386
+ }
196387
+ }));
196388
+ preamble = undefined;
196389
+ }
196214
196390
  let childComponent;
196215
196391
  if (children.length === 1 && children[0].type === "component") {
196216
196392
  const comp = children[0];
@@ -196259,11 +196435,9 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196259
196435
  objectIteration,
196260
196436
  depth,
196261
196437
  clientOnly: isClientOnly || undefined,
196262
- mapPreamble,
196263
- templateMapPreamble,
196438
+ preamble,
196264
196439
  paramType,
196265
196440
  indexType,
196266
- typedMapPreamble,
196267
196441
  paramBindings,
196268
196442
  arrayFreeIdentifiers: extractFreeIdentifiersFromNode(arrayExpr),
196269
196443
  flatMapCallback,
@@ -196299,47 +196473,206 @@ function containsJsx(node) {
196299
196473
  function buildFlatMapCallback(callback, body, ctx) {
196300
196474
  if (!containsJsx(body))
196301
196475
  return;
196302
- const fragments = [];
196303
- const sourceText = ctx.sourceFile.text;
196304
- const bodyStart = body.getStart(ctx.sourceFile);
196305
- const bodyEnd = body.getEnd();
196306
- const bodyText = sourceText.slice(bodyStart, bodyEnd);
196307
- const jsxNodes = [];
196308
- function collectJsx(n) {
196476
+ const leafSpans = [];
196477
+ const leafIrs = [];
196478
+ let refusalNode;
196479
+ const collectJsx = (n, underTemplate) => {
196309
196480
  if (import_typescript11.default.isJsxElement(n) || import_typescript11.default.isJsxSelfClosingElement(n) || import_typescript11.default.isJsxFragment(n)) {
196310
- jsxNodes.push({
196311
- node: n,
196312
- start: n.getStart(ctx.sourceFile) - bodyStart,
196313
- end: n.getEnd() - bodyStart
196314
- });
196481
+ if (underTemplate)
196482
+ refusalNode ??= n;
196483
+ leafSpans.push({ start: n.getStart(ctx.sourceFile), end: n.getEnd() });
196484
+ const ir = transformNode(n, ctx);
196485
+ leafIrs.push(ir ?? { type: "text", value: "", loc: getSourceLocation(n, ctx.sourceFile, ctx.filePath) });
196315
196486
  return;
196316
196487
  }
196317
- n.forEachChild(collectJsx);
196318
- }
196319
- collectJsx(body);
196320
- if (jsxNodes.length === 0)
196488
+ const inTemplate = underTemplate || import_typescript11.default.isTemplateExpression(n) || import_typescript11.default.isTaggedTemplateExpression(n);
196489
+ n.forEachChild((c) => collectJsx(c, inTemplate));
196490
+ };
196491
+ collectJsx(body, false);
196492
+ if (leafSpans.length === 0)
196493
+ return;
196494
+ if (refusalNode) {
196495
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(refusalNode, ctx.sourceFile, ctx.filePath), {
196496
+ message: "A JSX element inside a template literal in a .flatMap() callback " + "body cannot be compiled.",
196497
+ suggestion: { message: "Build the element outside the template literal." }
196498
+ }));
196321
196499
  return;
196322
- let compiledBody = "";
196323
- let lastEnd = 0;
196324
- for (let i2 = 0;i2 < jsxNodes.length; i2++) {
196325
- const { node, start, end } = jsxNodes[i2];
196326
- const placeholder = `__BF_JSX_${i2}__`;
196327
- compiledBody += bodyText.slice(lastEnd, start) + placeholder;
196328
- lastEnd = end;
196329
- const ir = transformNode(node, ctx);
196330
- fragments.push({
196331
- placeholder,
196332
- ir: ir ?? { type: "text", value: "", loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath) }
196333
- });
196334
196500
  }
196335
- compiledBody += bodyText.slice(lastEnd);
196501
+ const pieces = reconstructAsSegments(body, ctx.sourceFile, ctx.analyzer.typeExcludeRanges, leafSpans);
196502
+ const segments = pieces.map((piece) => {
196503
+ if ("marker" in piece)
196504
+ return { kind: "jsx", ir: leafIrs[piece.marker] };
196505
+ const tpl = rewriteBarePropRefs2(piece.js, body, ctx);
196506
+ return tpl !== undefined && tpl !== piece.js ? { kind: "js", text: piece.js, templateText: tpl } : { kind: "js", text: piece.js };
196507
+ });
196336
196508
  const paramsText = callback.parameters.map((p) => p.getText(ctx.sourceFile)).join(", ");
196337
196509
  return {
196338
196510
  params: `(${paramsText})`,
196339
- body: compiledBody,
196340
- templateBody: compiledBody,
196341
- rawBody: bodyText,
196342
- fragments
196511
+ segments,
196512
+ rawBody: tsxSourceText(body.getText(ctx.sourceFile))
196513
+ };
196514
+ }
196515
+ function preambleFragmentNeedsWiring(ir) {
196516
+ switch (ir.type) {
196517
+ case "component":
196518
+ case "loop":
196519
+ return true;
196520
+ case "element":
196521
+ if (ir.events.length > 0)
196522
+ return true;
196523
+ if (ir.attrs.some((a) => a.name.startsWith("...")))
196524
+ return true;
196525
+ return ir.children.some(preambleFragmentNeedsWiring);
196526
+ case "expression":
196527
+ return ir.reactive === true;
196528
+ case "conditional":
196529
+ return preambleFragmentNeedsWiring(ir.whenTrue) || (ir.whenFalse ? preambleFragmentNeedsWiring(ir.whenFalse) : false);
196530
+ case "fragment":
196531
+ return ir.children.some(preambleFragmentNeedsWiring);
196532
+ default:
196533
+ return false;
196534
+ }
196535
+ }
196536
+ function flagArrayChildExpressions(nodes, declared) {
196537
+ for (const node of nodes) {
196538
+ switch (node.type) {
196539
+ case "expression": {
196540
+ const name = node.expr.trim();
196541
+ const refs = extractFreeIdentifiersFromText(node.expr);
196542
+ if (refs.size === 1 && refs.has(name) && declared.has(name)) {
196543
+ node.joinArrayChild = true;
196544
+ }
196545
+ break;
196546
+ }
196547
+ case "element":
196548
+ case "fragment":
196549
+ flagArrayChildExpressions(node.children, declared);
196550
+ break;
196551
+ case "conditional":
196552
+ flagArrayChildExpressions([node.whenTrue, ...node.whenFalse ? [node.whenFalse] : []], declared);
196553
+ break;
196554
+ }
196555
+ }
196556
+ }
196557
+ function collectBindingNames(name, out) {
196558
+ if (import_typescript11.default.isIdentifier(name)) {
196559
+ out.add(name.text);
196560
+ return;
196561
+ }
196562
+ for (const el of name.elements) {
196563
+ if (import_typescript11.default.isBindingElement(el))
196564
+ collectBindingNames(el.name, out);
196565
+ }
196566
+ }
196567
+ function collectPreambleDeclaredNames(stmt, out) {
196568
+ if (import_typescript11.default.isVariableStatement(stmt)) {
196569
+ for (const decl of stmt.declarationList.declarations) {
196570
+ collectBindingNames(decl.name, out);
196571
+ }
196572
+ } else if (import_typescript11.default.isFunctionDeclaration(stmt) && stmt.name) {
196573
+ out.add(stmt.name.text);
196574
+ }
196575
+ }
196576
+ function preambleFromValueStatements(statements, ctx) {
196577
+ const segments = [];
196578
+ const typedParts = [];
196579
+ const declared = new Set;
196580
+ for (const stmt of statements) {
196581
+ collectPreambleDeclaredNames(stmt, declared);
196582
+ const js0 = ctx.getJS(stmt);
196583
+ const tjs0 = ctx.getTemplateJS(stmt);
196584
+ const raw0 = stmt.getText(ctx.sourceFile);
196585
+ const js = (js0.endsWith(";") ? js0 : js0 + ";") + " ";
196586
+ const tjs = (tjs0.endsWith(";") ? tjs0 : tjs0 + ";") + " ";
196587
+ typedParts.push(raw0.endsWith(";") ? raw0 : raw0 + ";");
196588
+ segments.push(tjs !== js ? { kind: "js", text: js, templateText: tjs } : { kind: "js", text: js });
196589
+ }
196590
+ return {
196591
+ segments: trimPreambleSegments(segments),
196592
+ ssrText: tsxSourceText(typedParts.join(" ")),
196593
+ declaredNames: [...declared],
196594
+ builderNames: []
196595
+ };
196596
+ }
196597
+ function trimPreambleSegments(segments) {
196598
+ const last = segments[segments.length - 1];
196599
+ if (last?.kind === "js") {
196600
+ const text = last.text.trimEnd();
196601
+ const templateText = last.templateText?.trimEnd();
196602
+ segments[segments.length - 1] = templateText !== undefined ? { kind: "js", text, templateText } : { kind: "js", text };
196603
+ }
196604
+ return segments;
196605
+ }
196606
+ function buildPreambleSegments(statements, returnStmt, ctx) {
196607
+ const segments = [];
196608
+ const typedParts = [];
196609
+ const declared = new Set;
196610
+ const builders = new Set;
196611
+ let refusalNode;
196612
+ const recordBuilderTarget = (leaf, stmt) => {
196613
+ for (let n = leaf.parent;n && n !== stmt.parent; n = n.parent) {
196614
+ if (import_typescript11.default.isCallExpression(n) && import_typescript11.default.isPropertyAccessExpression(n.expression) && (n.expression.name.text === "push" || n.expression.name.text === "unshift") && import_typescript11.default.isIdentifier(n.expression.expression)) {
196615
+ builders.add(n.expression.expression.text);
196616
+ return;
196617
+ }
196618
+ if (import_typescript11.default.isVariableDeclaration(n) && import_typescript11.default.isIdentifier(n.name)) {
196619
+ builders.add(n.name.text);
196620
+ return;
196621
+ }
196622
+ }
196623
+ };
196624
+ for (const stmt of statements) {
196625
+ if (stmt === returnStmt)
196626
+ break;
196627
+ collectPreambleDeclaredNames(stmt, declared);
196628
+ const leafSpans = [];
196629
+ const leafIrs = [];
196630
+ const collect = (n, underTemplate) => {
196631
+ if (import_typescript11.default.isJsxElement(n) || import_typescript11.default.isJsxSelfClosingElement(n) || import_typescript11.default.isJsxFragment(n)) {
196632
+ if (underTemplate)
196633
+ refusalNode ??= n;
196634
+ recordBuilderTarget(n, stmt);
196635
+ leafSpans.push({ start: n.getStart(ctx.sourceFile), end: n.getEnd() });
196636
+ const ir = transformNode(n, ctx);
196637
+ if (ir && preambleFragmentNeedsWiring(ir))
196638
+ refusalNode ??= n;
196639
+ leafIrs.push(ir ?? { type: "text", value: "", loc: getSourceLocation(n, ctx.sourceFile, ctx.filePath) });
196640
+ return;
196641
+ }
196642
+ const inTemplate = underTemplate || import_typescript11.default.isTemplateExpression(n) || import_typescript11.default.isTaggedTemplateExpression(n);
196643
+ n.forEachChild((c) => collect(c, inTemplate));
196644
+ };
196645
+ collect(stmt, false);
196646
+ const raw0 = stmt.getText(ctx.sourceFile);
196647
+ typedParts.push(raw0.endsWith(";") ? raw0 : raw0 + ";");
196648
+ if (leafSpans.length === 0) {
196649
+ const js0 = ctx.getJS(stmt);
196650
+ const tjs0 = ctx.getTemplateJS(stmt);
196651
+ const js = (js0.endsWith(";") ? js0 : js0 + ";") + " ";
196652
+ const tjs = (tjs0.endsWith(";") ? tjs0 : tjs0 + ";") + " ";
196653
+ segments.push(tjs !== js ? { kind: "js", text: js, templateText: tjs } : { kind: "js", text: js });
196654
+ continue;
196655
+ }
196656
+ const pieces = reconstructAsSegments(stmt, ctx.sourceFile, ctx.analyzer.typeExcludeRanges, leafSpans);
196657
+ for (const piece of pieces) {
196658
+ if ("marker" in piece) {
196659
+ segments.push({ kind: "jsx", ir: leafIrs[piece.marker] });
196660
+ } else {
196661
+ const tpl = rewriteBarePropRefs2(piece.js, stmt, ctx);
196662
+ segments.push(tpl !== undefined && tpl !== piece.js ? { kind: "js", text: piece.js, templateText: tpl } : { kind: "js", text: piece.js });
196663
+ }
196664
+ }
196665
+ const sep2 = raw0.endsWith(";") ? " " : "; ";
196666
+ segments.push({ kind: "js", text: sep2 });
196667
+ }
196668
+ return {
196669
+ preamble: {
196670
+ segments: trimPreambleSegments(segments),
196671
+ ssrText: tsxSourceText(typedParts.join(" ")),
196672
+ declaredNames: [...declared],
196673
+ builderNames: [...builders]
196674
+ },
196675
+ refusalNode
196343
196676
  };
196344
196677
  }
196345
196678
  function collectNestedComponents(nodes) {
@@ -197726,6 +198059,7 @@ class BaseAdapter {
197726
198059
  // ../jsx/src/adapters/jsx-adapter.ts
197727
198060
  class JsxAdapter extends BaseAdapter {
197728
198061
  componentName = "";
198062
+ acceptsCallbackBody = () => true;
197729
198063
  formatImportSpecifiers(specifiers) {
197730
198064
  const defaultSpec = specifiers.find((s) => s.isDefault);
197731
198065
  const namespaceSpec = specifiers.find((s) => s.isNamespace);
@@ -198071,6 +198405,10 @@ export default ${this.componentName}` : "";
198071
198405
  const indexParam = loop.index ? `, ${loop.index}` : "";
198072
198406
  const children = this.renderChildren(loop.children);
198073
198407
  const safeChildren = children.startsWith("{") ? `<>${children}</>` : children;
198408
+ const preamble = loop.preamble?.ssrText;
198409
+ if (preamble) {
198410
+ return `{${loop.array}.map((${loop.param}${indexParam}) => { ${preamble} return ${safeChildren} })}`;
198411
+ }
198074
198412
  return `{${loop.array}.map((${loop.param}${indexParam}) => ${safeChildren})}`;
198075
198413
  }
198076
198414
  renderComponent(comp) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/test",
3
- "version": "0.26.2",
3
+ "version": "0.26.3",
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.26.2"
42
+ "@barefootjs/jsx": "0.26.3"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.0.0"