@barefootjs/test 0.1.2 → 0.1.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 +300 -24
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -187670,6 +187670,7 @@ function createAnalyzerContext(sourceFile, filePath) {
187670
187670
  jsxConstants: new Map,
187671
187671
  inlineableJsxConsts: new Map,
187672
187672
  jsxFunctions: new Map,
187673
+ jsxMultiReturnFunctions: new Map,
187673
187674
  reactiveFactories: new Map,
187674
187675
  signalTupleRefs: new Map,
187675
187676
  propsType: null,
@@ -187801,20 +187802,11 @@ init_path();
187801
187802
  var ErrorCodes = {
187802
187803
  MISSING_USE_CLIENT: "BF001",
187803
187804
  CLIENT_IMPORTING_SERVER: "BF003",
187804
- UNKNOWN_SIGNAL: "BF010",
187805
187805
  SIGNAL_OUTSIDE_COMPONENT: "BF011",
187806
- INVALID_SIGNAL_USAGE: "BF012",
187807
- INVALID_JSX_EXPRESSION: "BF020",
187808
187806
  UNSUPPORTED_JSX_PATTERN: "BF021",
187809
- INVALID_JSX_ATTRIBUTE: "BF022",
187810
187807
  MISSING_KEY_IN_LIST: "BF023",
187811
187808
  MISSING_KEY_IN_NESTED_LIST: "BF024",
187812
187809
  UNSUPPORTED_DESTRUCTURE_REST: "BF025",
187813
- TYPE_INFERENCE_FAILED: "BF030",
187814
- PROPS_TYPE_MISMATCH: "BF031",
187815
- COMPONENT_NOT_FOUND: "BF040",
187816
- CIRCULAR_DEPENDENCY: "BF041",
187817
- INVALID_COMPONENT_NAME: "BF042",
187818
187810
  PROPS_DESTRUCTURING: "BF043",
187819
187811
  SIGNAL_GETTER_NOT_CALLED: "BF044",
187820
187812
  JSX_IN_LOCAL_FUNCTION: "BF045",
@@ -187833,20 +187825,11 @@ var ErrorCodes = {
187833
187825
  var errorMessages = {
187834
187826
  [ErrorCodes.MISSING_USE_CLIENT]: "'use client' directive required for components with createSignal or event handlers",
187835
187827
  [ErrorCodes.CLIENT_IMPORTING_SERVER]: "Client component cannot import server component",
187836
- [ErrorCodes.UNKNOWN_SIGNAL]: "Unknown signal reference",
187837
187828
  [ErrorCodes.SIGNAL_OUTSIDE_COMPONENT]: "Module-level reactive declaration (createSignal / createMemo) is not allowed. " + "The downstream codegen drops the declaration silently and every reference becomes a ReferenceError at SSR and at hydrate. " + "Move the declaration inside a component function so each mount gets its own state.",
187838
- [ErrorCodes.INVALID_SIGNAL_USAGE]: "Invalid signal usage",
187839
- [ErrorCodes.INVALID_JSX_EXPRESSION]: "Invalid JSX expression",
187840
187829
  [ErrorCodes.UNSUPPORTED_JSX_PATTERN]: "Unsupported JSX pattern",
187841
- [ErrorCodes.INVALID_JSX_ATTRIBUTE]: "Invalid JSX attribute",
187842
187830
  [ErrorCodes.MISSING_KEY_IN_LIST]: "Missing key attribute in list rendering. Add a key prop for efficient updates",
187843
187831
  [ErrorCodes.MISSING_KEY_IN_NESTED_LIST]: "Nested .map() loop requires key attribute for event delegation. Add a key prop to elements in the inner loop",
187844
187832
  [ErrorCodes.UNSUPPORTED_DESTRUCTURE_REST]: "Computed property key in .map() callback destructure is not supported. Rewrite the callback to destructure explicit bindings (e.g., `({ a, b }) => ...`) so the compiler can rewrite references to per-item signal accessors.",
187845
- [ErrorCodes.TYPE_INFERENCE_FAILED]: "Failed to infer type",
187846
- [ErrorCodes.PROPS_TYPE_MISMATCH]: "Props type mismatch",
187847
- [ErrorCodes.COMPONENT_NOT_FOUND]: "Component not found",
187848
- [ErrorCodes.CIRCULAR_DEPENDENCY]: "Circular dependency detected",
187849
- [ErrorCodes.INVALID_COMPONENT_NAME]: "Component name must start with uppercase letter",
187850
187833
  [ErrorCodes.PROPS_DESTRUCTURING]: "Props destructuring in function parameters breaks reactivity. Use props object directly.",
187851
187834
  [ErrorCodes.SIGNAL_GETTER_NOT_CALLED]: "Signal/memo getter passed without calling it. Use getter() to read the value.",
187852
187835
  [ErrorCodes.JSX_IN_LOCAL_FUNCTION]: "Local function returns JSX but cannot be inlined. Extract it as a top-level PascalCase component or use a single return statement.",
@@ -187858,7 +187841,7 @@ var errorMessages = {
187858
187841
  [ErrorCodes.STRIPPED_CLIENT_IMPORT_REFERENCED]: "Import was stripped from the client bundle but its binding is still referenced. Client components ('use client' .tsx) are not callable as plain functions from imperative .ts modules — render them as JSX from a 'use client' parent instead. If the flagged name is a local shadow rather than the stripped import, please file an issue.",
187859
187842
  [ErrorCodes.STAGE_REACTIVE_IN_TEMPLATE]: "Reactive binding (signal getter or memo) referenced from template scope. The template lambda runs at module scope without the reactive context, so the value cannot be evaluated at SSR. Wrap the JSX expression in /* @client */ to defer it to hydrate, or restructure so the template uses a prop or static value.",
187860
187843
  [ErrorCodes.STAGE_INIT_LOCAL_IN_TEMPLATE]: "Init-scope local referenced from template scope. The template lambda runs at module scope (via render() / renderChild()) and cannot reach init-body locals. Wrap the JSX expression in /* @client */, or lift the value to a prop or module-scope const.",
187861
- [ErrorCodes.STAGE_AWAIT_IN_TEMPLATE]: "AwaitExpression in template scope. The hydrate-time template lambda is synchronous; awaiting here would hang first render. Move the await into a server-side handler and pass the resolved value as a prop.",
187844
+ [ErrorCodes.STAGE_AWAIT_IN_TEMPLATE]: "AwaitExpression in template scope. The generated template and init functions are synchronous a bare `await` produces a SyntaxError at parse time. Move the await into the component body (before the return) or into an onMount/effect callback, and pass the resolved value to JSX.",
187862
187845
  [ErrorCodes.INLINE_JSX_CALLBACK_CAPTURE]: "Inline JSX-returning arrow function captures a non-module identifier. Extract the callback into a top-level 'use client' component (e.g. `function MyNode(n) { return <div/> }` then `renderNode={MyNode}`) or pass captured values via component props.",
187863
187846
  [ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY]: "Tuple destructuring of a non-reactive factory call. The compiler only recognizes createSignal / createMemo calls and same-file helpers that wrap them with a single `return [a, b]` exit."
187864
187847
  };
@@ -188947,6 +188930,139 @@ function extractSingleJsxReturn(body) {
188947
188930
  return null;
188948
188931
  return jsxReturn;
188949
188932
  }
188933
+ function extractMultiReturnJsxBranches(body) {
188934
+ const branches = [];
188935
+ let fallback = null;
188936
+ const stmts = body.statements;
188937
+ for (let i2 = 0;i2 < stmts.length; i2++) {
188938
+ const stmt = stmts[i2];
188939
+ if (import_typescript6.default.isIfStatement(stmt)) {
188940
+ let current = stmt;
188941
+ while (import_typescript6.default.isIfStatement(current)) {
188942
+ const ifStmt = current;
188943
+ if (!isDirectReturnBlock(ifStmt.thenStatement))
188944
+ return null;
188945
+ const jsxReturn = findJsxReturnInBlock(ifStmt.thenStatement);
188946
+ const nullReturn = findNullReturnInBlock(ifStmt.thenStatement);
188947
+ if (!jsxReturn && !nullReturn)
188948
+ return null;
188949
+ branches.push({ condition: ifStmt.expression, jsxReturn: jsxReturn ?? null });
188950
+ if (ifStmt.elseStatement) {
188951
+ if (import_typescript6.default.isIfStatement(ifStmt.elseStatement)) {
188952
+ current = ifStmt.elseStatement;
188953
+ continue;
188954
+ }
188955
+ if (!isDirectReturnBlock(ifStmt.elseStatement))
188956
+ return null;
188957
+ const elseJsx = findJsxReturnInBlock(ifStmt.elseStatement);
188958
+ if (elseJsx) {
188959
+ fallback = elseJsx;
188960
+ } else if (!findNullReturnInBlock(ifStmt.elseStatement)) {
188961
+ return null;
188962
+ }
188963
+ if (branches.length === 0)
188964
+ return null;
188965
+ return { branches, fallback };
188966
+ }
188967
+ break;
188968
+ }
188969
+ continue;
188970
+ }
188971
+ if (import_typescript6.default.isSwitchStatement(stmt)) {
188972
+ if (branches.length > 0)
188973
+ return null;
188974
+ if (!import_typescript6.default.isIdentifier(stmt.expression) && !import_typescript6.default.isPropertyAccessExpression(stmt.expression)) {
188975
+ return null;
188976
+ }
188977
+ const hasDefault = stmt.caseBlock.clauses.some((c) => import_typescript6.default.isDefaultClause(c));
188978
+ if (!hasDefault)
188979
+ return null;
188980
+ for (const clause of stmt.caseBlock.clauses) {
188981
+ const jsxReturn = findJsxReturnInCaseClause(clause);
188982
+ const nullReturn = findNullReturnInCaseClause(clause);
188983
+ if (!jsxReturn && !nullReturn)
188984
+ return null;
188985
+ if (import_typescript6.default.isCaseClause(clause)) {
188986
+ branches.push({
188987
+ condition: clause.expression,
188988
+ jsxReturn: jsxReturn ?? null
188989
+ });
188990
+ } else {
188991
+ fallback = jsxReturn ?? null;
188992
+ }
188993
+ }
188994
+ if (branches.length === 0)
188995
+ return null;
188996
+ return { branches, fallback, switchDiscriminant: stmt.expression };
188997
+ }
188998
+ if (import_typescript6.default.isReturnStatement(stmt) && stmt.expression) {
188999
+ const expr = unwrapJsxTransparent(stmt.expression);
189000
+ if (import_typescript6.default.isJsxElement(expr) || import_typescript6.default.isJsxSelfClosingElement(expr) || import_typescript6.default.isJsxFragment(expr)) {
189001
+ fallback = expr;
189002
+ } else if (expr.kind === import_typescript6.default.SyntaxKind.NullKeyword) {} else {
189003
+ return null;
189004
+ }
189005
+ continue;
189006
+ }
189007
+ if (import_typescript6.default.isVariableStatement(stmt))
189008
+ return null;
189009
+ return null;
189010
+ }
189011
+ if (branches.length === 0)
189012
+ return null;
189013
+ return { branches, fallback };
189014
+ }
189015
+ function isDirectReturnBlock(node) {
189016
+ if (import_typescript6.default.isReturnStatement(node))
189017
+ return true;
189018
+ if (import_typescript6.default.isBlock(node)) {
189019
+ let returnCount = 0;
189020
+ for (const stmt of node.statements) {
189021
+ if (import_typescript6.default.isReturnStatement(stmt)) {
189022
+ returnCount++;
189023
+ } else if (import_typescript6.default.isIfStatement(stmt) || import_typescript6.default.isSwitchStatement(stmt) || import_typescript6.default.isForStatement(stmt) || import_typescript6.default.isForOfStatement(stmt) || import_typescript6.default.isForInStatement(stmt) || import_typescript6.default.isWhileStatement(stmt) || import_typescript6.default.isDoStatement(stmt) || import_typescript6.default.isTryStatement(stmt)) {
189024
+ return false;
189025
+ }
189026
+ }
189027
+ return returnCount === 1;
189028
+ }
189029
+ return false;
189030
+ }
189031
+ function findNullReturnInBlock(node) {
189032
+ if (import_typescript6.default.isBlock(node)) {
189033
+ for (const stmt of node.statements) {
189034
+ if (import_typescript6.default.isReturnStatement(stmt) && stmt.expression) {
189035
+ const expr = unwrapJsxTransparent(stmt.expression);
189036
+ if (expr.kind === import_typescript6.default.SyntaxKind.NullKeyword)
189037
+ return true;
189038
+ }
189039
+ }
189040
+ }
189041
+ if (import_typescript6.default.isReturnStatement(node) && node.expression) {
189042
+ const expr = unwrapJsxTransparent(node.expression);
189043
+ if (expr.kind === import_typescript6.default.SyntaxKind.NullKeyword)
189044
+ return true;
189045
+ }
189046
+ return false;
189047
+ }
189048
+ function findJsxReturnInCaseClause(clause) {
189049
+ for (const stmt of clause.statements) {
189050
+ if (import_typescript6.default.isReturnStatement(stmt) && stmt.expression) {
189051
+ return extractJsxFromExpression(stmt.expression);
189052
+ }
189053
+ }
189054
+ return null;
189055
+ }
189056
+ function findNullReturnInCaseClause(clause) {
189057
+ for (const stmt of clause.statements) {
189058
+ if (import_typescript6.default.isReturnStatement(stmt) && stmt.expression) {
189059
+ const expr = unwrapJsxTransparent(stmt.expression);
189060
+ if (expr.kind === import_typescript6.default.SyntaxKind.NullKeyword)
189061
+ return true;
189062
+ }
189063
+ }
189064
+ return false;
189065
+ }
188950
189066
  function isMultiReturnJsxFunctionBody(body) {
188951
189067
  let returnCount = 0;
188952
189068
  let hasJsxReturn = false;
@@ -189030,6 +189146,15 @@ function collectFunction(node, ctx, _isModule, isExported = false) {
189030
189146
  jsxReturn,
189031
189147
  params: node.parameters.map((p) => p.name.getText(ctx.sourceFile))
189032
189148
  });
189149
+ } else {
189150
+ const multi = extractMultiReturnJsxBranches(node.body);
189151
+ if (multi) {
189152
+ isJsxFunction = true;
189153
+ ctx.jsxMultiReturnFunctions.set(name, {
189154
+ ...multi,
189155
+ params: node.parameters.map((p) => p.name.getText(ctx.sourceFile))
189156
+ });
189157
+ }
189033
189158
  }
189034
189159
  }
189035
189160
  const isAsync = node.modifiers?.some((m) => m.kind === import_typescript6.default.SyntaxKind.AsyncKeyword) ?? false;
@@ -189282,6 +189407,15 @@ function collectConstant(node, ctx, _isModule, declarationKind = "const", isExpo
189282
189407
  jsxReturn,
189283
189408
  params: init.parameters.map((p) => p.name.getText(ctx.sourceFile))
189284
189409
  });
189410
+ } else {
189411
+ const multi = extractMultiReturnJsxBranches(arrowBody);
189412
+ if (multi) {
189413
+ isJsxFunction = true;
189414
+ ctx.jsxMultiReturnFunctions.set(name, {
189415
+ ...multi,
189416
+ params: init.parameters.map((p) => p.name.getText(ctx.sourceFile))
189417
+ });
189418
+ }
189285
189419
  }
189286
189420
  } else {
189287
189421
  let body = arrowBody;
@@ -189541,7 +189675,7 @@ function inferTypeFromValue(value) {
189541
189675
  if (/\.(some|every|includes)\s*\([\s\S]*\)\s*$/.test(trimmed)) {
189542
189676
  return { kind: "primitive", raw: "boolean", primitive: "boolean" };
189543
189677
  }
189544
- if (/\.(indexOf|findIndex|lastIndexOf)\s*\([\s\S]*\)\s*$/.test(trimmed)) {
189678
+ if (/\.(indexOf|findIndex|findLastIndex|lastIndexOf)\s*\([\s\S]*\)\s*$/.test(trimmed)) {
189545
189679
  return { kind: "primitive", raw: "number", primitive: "number" };
189546
189680
  }
189547
189681
  if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
@@ -190144,8 +190278,6 @@ var UNSUPPORTED_METHODS = new Set([
190144
190278
  "reduceRight",
190145
190279
  "every",
190146
190280
  "some",
190147
- "findLast",
190148
- "findLastIndex",
190149
190281
  "forEach",
190150
190282
  "flatMap",
190151
190283
  "flat"
@@ -190188,7 +190320,7 @@ function convertNode(node, raw) {
190188
190320
  if (import_typescript7.default.isCallExpression(node)) {
190189
190321
  const callee = convertNode(node.expression, raw);
190190
190322
  const args = node.arguments.map((arg) => convertNode(arg, raw));
190191
- if (callee.kind === "member" && ["filter", "every", "some", "find", "findIndex"].includes(callee.property)) {
190323
+ if (callee.kind === "member" && ["filter", "every", "some", "find", "findIndex", "findLast", "findLastIndex"].includes(callee.property)) {
190192
190324
  if (args.length === 1 && args[0].kind === "arrow-fn") {
190193
190325
  const arrowFn = args[0];
190194
190326
  return {
@@ -192035,6 +192167,18 @@ function transformExpressionInner(expr, ctx, node, isClientOnly) {
192035
192167
  }
192036
192168
  return ir;
192037
192169
  }
192170
+ if (containsAwaitExpression(expr)) {
192171
+ ctx.analyzer.errors.push(createError(ErrorCodes.STAGE_AWAIT_IN_TEMPLATE, getSourceLocation(expr, ctx.sourceFile, ctx.filePath)));
192172
+ return {
192173
+ type: "expression",
192174
+ expr: "undefined",
192175
+ typeInfo: null,
192176
+ reactive: false,
192177
+ slotId: null,
192178
+ loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath),
192179
+ origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
192180
+ };
192181
+ }
192038
192182
  const exprText = ctx.getJS(expr);
192039
192183
  const freeRefs = resolveFreeRefs(expr, makeBindingEnv(ctx));
192040
192184
  const origin = {
@@ -192106,6 +192250,97 @@ function transformJsxFunctionCall(callExpr, jsxFunc, ctx, _isClientOnly) {
192106
192250
  ctx.analyzer.getJS = originalAnalyzerGetJS;
192107
192251
  }
192108
192252
  }
192253
+ function transformMultiReturnJsxFunctionCall(callExpr, info, ctx) {
192254
+ const substitutions = new Map;
192255
+ for (let i2 = 0;i2 < info.params.length; i2++) {
192256
+ const paramName = info.params[i2];
192257
+ const arg = callExpr.arguments[i2];
192258
+ if (arg) {
192259
+ substitutions.set(paramName, ctx.getJS(arg));
192260
+ }
192261
+ }
192262
+ const baseGetJS = ctx.analyzer.getJS.bind(ctx.analyzer);
192263
+ const originalCtxGetJS = ctx.getJS;
192264
+ const originalAnalyzerGetJS = ctx.analyzer.getJS;
192265
+ const substitutedGetJS = (node) => {
192266
+ let text = baseGetJS(node);
192267
+ for (const [paramName, argExpr] of substitutions) {
192268
+ text = text.replace(new RegExp(`\\b${paramName}\\b`, "g"), argExpr);
192269
+ }
192270
+ return text;
192271
+ };
192272
+ ctx.getJS = substitutedGetJS;
192273
+ ctx.analyzer.getJS = substitutedGetJS;
192274
+ try {
192275
+ const loc = getSourceLocation(callExpr, ctx.sourceFile, ctx.filePath);
192276
+ const nullExpr = {
192277
+ type: "expression",
192278
+ expr: "null",
192279
+ typeInfo: { kind: "primitive", raw: "null", primitive: "null" },
192280
+ reactive: false,
192281
+ slotId: null,
192282
+ loc,
192283
+ origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
192284
+ };
192285
+ let result = info.fallback ? transformNode(info.fallback, ctx) ?? nullExpr : nullExpr;
192286
+ for (let i2 = info.branches.length - 1;i2 >= 0; i2--) {
192287
+ const branch = info.branches[i2];
192288
+ let conditionText;
192289
+ if (info.switchDiscriminant) {
192290
+ const discText = substitutedGetJS(info.switchDiscriminant);
192291
+ const caseText = substitutedGetJS(branch.condition);
192292
+ conditionText = `${discText} === ${caseText}`;
192293
+ } else {
192294
+ conditionText = substitutedGetJS(branch.condition);
192295
+ }
192296
+ const env = makeBindingEnv(ctx);
192297
+ const caseFreeRefs = resolveFreeRefs(branch.condition, env);
192298
+ const discFreeRefs = info.switchDiscriminant ? resolveFreeRefs(info.switchDiscriminant, env) : [];
192299
+ const conditionOrigin = {
192300
+ phase: "tick",
192301
+ scope: "template",
192302
+ effect: "pure",
192303
+ freeRefs: [...discFreeRefs, ...caseFreeRefs]
192304
+ };
192305
+ const reactive = isReactiveExpression(conditionText, ctx, branch.condition) || isReactiveOrigin(conditionOrigin);
192306
+ const loopParamReactive = !reactive && referencesLoopParam(conditionText, ctx);
192307
+ const callsReactive = exprCallsReactiveGetters(branch.condition, ctx) || (info.switchDiscriminant ? exprCallsReactiveGetters(info.switchDiscriminant, ctx) : false);
192308
+ const hasCalls = exprHasFunctionCalls(branch.condition) || (info.switchDiscriminant ? exprHasFunctionCalls(info.switchDiscriminant) : false);
192309
+ const needsSlot = reactive || loopParamReactive || callsReactive || hasCalls;
192310
+ const slotId = needsSlot ? generateSlotId(ctx) : null;
192311
+ const whenTrue = branch.jsxReturn ? transformNode(branch.jsxReturn, ctx) ?? nullExpr : nullExpr;
192312
+ let templateCondition;
192313
+ if (info.switchDiscriminant) {
192314
+ const discRewritten = rewriteBarePropRefs2(substitutedGetJS(info.switchDiscriminant), info.switchDiscriminant, ctx);
192315
+ const caseRewritten = rewriteBarePropRefs2(substitutedGetJS(branch.condition), branch.condition, ctx);
192316
+ const discPart = discRewritten ?? substitutedGetJS(info.switchDiscriminant);
192317
+ const casePart = caseRewritten ?? substitutedGetJS(branch.condition);
192318
+ templateCondition = `${discPart} === ${casePart}`;
192319
+ } else {
192320
+ templateCondition = rewriteBarePropRefs2(conditionText, branch.condition, ctx);
192321
+ }
192322
+ const conditional = {
192323
+ type: "conditional",
192324
+ condition: conditionText,
192325
+ templateCondition,
192326
+ conditionType: null,
192327
+ reactive,
192328
+ whenTrue,
192329
+ whenFalse: result,
192330
+ slotId,
192331
+ callsReactiveGetters: callsReactive || undefined,
192332
+ hasFunctionCalls: hasCalls || undefined,
192333
+ loc,
192334
+ origin: conditionOrigin
192335
+ };
192336
+ result = conditional;
192337
+ }
192338
+ return result;
192339
+ } finally {
192340
+ ctx.getJS = originalCtxGetJS;
192341
+ ctx.analyzer.getJS = originalAnalyzerGetJS;
192342
+ }
192343
+ }
192109
192344
  function transformConditional(node, ctx) {
192110
192345
  const condition = ctx.getJS(node.condition);
192111
192346
  const conditionOrigin = {
@@ -192187,6 +192422,13 @@ function containsJsxInExpression(node) {
192187
192422
  }
192188
192423
  return import_typescript10.default.forEachChild(node, containsJsxInExpression) ?? false;
192189
192424
  }
192425
+ function containsAwaitExpression(node) {
192426
+ if (import_typescript10.default.isAwaitExpression(node))
192427
+ return true;
192428
+ if (import_typescript10.default.isFunctionDeclaration(node) || import_typescript10.default.isFunctionExpression(node) || import_typescript10.default.isArrowFunction(node))
192429
+ return false;
192430
+ return import_typescript10.default.forEachChild(node, containsAwaitExpression) ?? false;
192431
+ }
192190
192432
  function transformNullishCoalescing(node, ctx) {
192191
192433
  const leftText = ctx.getJS(node.left);
192192
192434
  const isNullish = node.operatorToken.kind === import_typescript10.default.SyntaxKind.QuestionQuestionToken;
@@ -192277,6 +192519,10 @@ function transformJsxExpression(expr, ctx, isClientOnly = false) {
192277
192519
  if (jsxFunc) {
192278
192520
  return transformJsxFunctionCall(node, jsxFunc, ctx, isClientOnly);
192279
192521
  }
192522
+ const multiJsxFunc = ctx.analyzer.jsxMultiReturnFunctions.get(callee.text);
192523
+ if (multiJsxFunc) {
192524
+ return transformMultiReturnJsxFunctionCall(node, multiJsxFunc, ctx);
192525
+ }
192280
192526
  }
192281
192527
  return null;
192282
192528
  }
@@ -192313,6 +192559,16 @@ function transformJsxExpression(expr, ctx, isClientOnly = false) {
192313
192559
  case import_typescript10.default.SyntaxKind.ArrayLiteralExpression:
192314
192560
  return null;
192315
192561
  case import_typescript10.default.SyntaxKind.AwaitExpression:
192562
+ ctx.analyzer.errors.push(createError(ErrorCodes.STAGE_AWAIT_IN_TEMPLATE, getSourceLocation(node, ctx.sourceFile, ctx.filePath)));
192563
+ return {
192564
+ type: "expression",
192565
+ expr: "undefined",
192566
+ typeInfo: null,
192567
+ reactive: false,
192568
+ slotId: null,
192569
+ loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath),
192570
+ origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
192571
+ };
192316
192572
  case import_typescript10.default.SyntaxKind.YieldExpression:
192317
192573
  return null;
192318
192574
  case import_typescript10.default.SyntaxKind.SpreadElement:
@@ -192964,7 +193220,8 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
192964
193220
  const bodyIsMultiRoot = loopBodyIsMultiRoot(children);
192965
193221
  const callsReactive = exprCallsReactiveGetters(arrayExpr, ctx);
192966
193222
  const hasCalls = exprHasFunctionCalls(arrayExpr);
192967
- const isStaticArray = !isSignalOrMemoArray(array, ctx) && !hasCalls;
193223
+ const isDirectPropArray = method !== "flatMap" && isArrayExprDirectPropRef(arrayExpr, ctx);
193224
+ const isStaticArray = !isSignalOrMemoArray(array, ctx) && !isDirectPropArray && !hasCalls;
192968
193225
  const nestedComponents = collectNestedComponents(children).filter((c) => c.name !== childComponent?.name);
192969
193226
  return {
192970
193227
  type: "loop",
@@ -192980,6 +193237,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
192980
193237
  slotId: null,
192981
193238
  markerId: `l${ctx.loopMarkerCounter++}`,
192982
193239
  isStaticArray,
193240
+ isPropDerivedArray: isDirectPropArray || undefined,
192983
193241
  callsReactiveGetters: callsReactive || undefined,
192984
193242
  hasFunctionCalls: hasCalls || undefined,
192985
193243
  bodyIsMultiRoot: bodyIsMultiRoot || undefined,
@@ -193239,6 +193497,10 @@ function getAttributeValue(attr, ctx) {
193239
193497
  expr = branchInit;
193240
193498
  }
193241
193499
  }
193500
+ if (import_typescript10.default.isAwaitExpression(expr)) {
193501
+ ctx.analyzer.errors.push(createError(ErrorCodes.STAGE_AWAIT_IN_TEMPLATE, getSourceLocation(expr, ctx.sourceFile, ctx.filePath)));
193502
+ return AttrValueOf.expression("undefined");
193503
+ }
193242
193504
  checkBareSignalOrMemoIdentifier(expr, ctx);
193243
193505
  if (attr.name.getText(ctx.sourceFile) === "style" && import_typescript10.default.isObjectLiteralExpression(expr)) {
193244
193506
  const cssString = tryStaticStyleObjectToCss(expr);
@@ -193560,6 +193822,20 @@ function checkBareSignalOrMemoIdentifier(expr, ctx) {
193560
193822
  }
193561
193823
  }
193562
193824
  }
193825
+ function isArrayExprDirectPropRef(arrayExpr, ctx) {
193826
+ const propNames = new Set(ctx.patterns.props.map((p) => p.name));
193827
+ const propsObjName = ctx.analyzer.propsObjectName;
193828
+ if (import_typescript10.default.isIdentifier(arrayExpr)) {
193829
+ return propNames.has(arrayExpr.text);
193830
+ }
193831
+ if (import_typescript10.default.isPropertyAccessExpression(arrayExpr) && propsObjName) {
193832
+ const obj = arrayExpr.expression;
193833
+ if (import_typescript10.default.isIdentifier(obj) && obj.text === propsObjName) {
193834
+ return true;
193835
+ }
193836
+ }
193837
+ return false;
193838
+ }
193563
193839
  function isSignalOrMemoArray(array, ctx) {
193564
193840
  for (const { pattern } of ctx.patterns.signals) {
193565
193841
  if (pattern.test(array))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/test",
3
- "version": "0.1.2",
3
+ "version": "0.1.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.1.2"
42
+ "@barefootjs/jsx": "0.1.3"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.0.0"