@barefootjs/test 0.29.0 → 0.30.2

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 +356 -44
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -189319,20 +189319,115 @@ var SKELETON_PATH_FORCE_CLOSE_GROUPS = [
189319
189319
  ];
189320
189320
 
189321
189321
  // ../jsx/src/prop-rewrite.ts
189322
+ function collectBindingNames(name, out) {
189323
+ if (import_typescript5.default.isIdentifier(name)) {
189324
+ out.add(name.text);
189325
+ return;
189326
+ }
189327
+ for (const el of name.elements) {
189328
+ if (import_typescript5.default.isBindingElement(el))
189329
+ collectBindingNames(el.name, out);
189330
+ }
189331
+ }
189332
+ function scopeFrameOf(n) {
189333
+ if (import_typescript5.default.isFunctionLike(n)) {
189334
+ const frame = new Set;
189335
+ for (const p of n.parameters)
189336
+ collectBindingNames(p.name, frame);
189337
+ if ((import_typescript5.default.isFunctionExpression(n) || import_typescript5.default.isFunctionDeclaration(n)) && n.name)
189338
+ frame.add(n.name.text);
189339
+ return frame.size > 0 ? frame : null;
189340
+ }
189341
+ if (import_typescript5.default.isBlock(n)) {
189342
+ const frame = new Set;
189343
+ for (const st of n.statements) {
189344
+ if (import_typescript5.default.isVariableStatement(st)) {
189345
+ for (const d of st.declarationList.declarations)
189346
+ collectBindingNames(d.name, frame);
189347
+ } else if (import_typescript5.default.isFunctionDeclaration(st) && st.name) {
189348
+ frame.add(st.name.text);
189349
+ }
189350
+ }
189351
+ return frame.size > 0 ? frame : null;
189352
+ }
189353
+ if (import_typescript5.default.isCatchClause(n) && n.variableDeclaration) {
189354
+ const frame = new Set;
189355
+ collectBindingNames(n.variableDeclaration.name, frame);
189356
+ return frame.size > 0 ? frame : null;
189357
+ }
189358
+ return null;
189359
+ }
189360
+ function walkWithScope(root, visit) {
189361
+ const scopeStack = [];
189362
+ const isShadowed = (name) => scopeStack.some((frame) => frame.has(name));
189363
+ function rec(n, parent) {
189364
+ const frame = scopeFrameOf(n);
189365
+ if (frame)
189366
+ scopeStack.push(frame);
189367
+ if (import_typescript5.default.isIdentifier(n))
189368
+ visit(n, parent, isShadowed(n.text));
189369
+ import_typescript5.default.forEachChild(n, (child) => rec(child, n));
189370
+ if (frame)
189371
+ scopeStack.pop();
189372
+ }
189373
+ rec(root);
189374
+ }
189375
+ function isNonValuePosition(n, parent) {
189376
+ if (!parent)
189377
+ return false;
189378
+ if (import_typescript5.default.isPropertyAssignment(parent) && parent.name === n)
189379
+ return true;
189380
+ if (import_typescript5.default.isPropertyAccessExpression(parent) && parent.name === n)
189381
+ return true;
189382
+ if (import_typescript5.default.isQualifiedName(parent) && parent.right === n)
189383
+ return true;
189384
+ if ((import_typescript5.default.isParameter(parent) || import_typescript5.default.isVariableDeclaration(parent) || import_typescript5.default.isBindingElement(parent)) && parent.name === n)
189385
+ return true;
189386
+ if (import_typescript5.default.isTypeReferenceNode(parent))
189387
+ return true;
189388
+ return false;
189389
+ }
189322
189390
  function collectAstPropRefs(node, propNames, out) {
189323
- function visit(n, parent) {
189324
- if (import_typescript5.default.isIdentifier(n) && propNames.has(n.text)) {
189325
- if (parent && import_typescript5.default.isPropertyAssignment(parent) && parent.name === n)
189326
- return;
189327
- if (parent && import_typescript5.default.isShorthandPropertyAssignment(parent) && parent.name === n)
189328
- return;
189329
- if (parent && import_typescript5.default.isPropertyAccessExpression(parent) && parent.name === n)
189330
- return;
189331
- out.add(n.text);
189391
+ walkWithScope(node, (n, parent, shadowed) => {
189392
+ if (shadowed || !propNames.has(n.text))
189393
+ return;
189394
+ if (parent && import_typescript5.default.isShorthandPropertyAssignment(parent) && parent.name === n)
189395
+ return;
189396
+ if (isNonValuePosition(n, parent))
189397
+ return;
189398
+ out.add(n.text);
189399
+ });
189400
+ }
189401
+ function applyScopedPropRefRewrite(text, propRefs) {
189402
+ const prefix = "(";
189403
+ const sf = import_typescript5.default.createSourceFile("__bf_prop_rewrite.ts", `${prefix}${text}
189404
+ )`, import_typescript5.default.ScriptTarget.Latest, true);
189405
+ const parseDiagnostics = sf.parseDiagnostics;
189406
+ if (parseDiagnostics && parseDiagnostics.length > 0)
189407
+ return null;
189408
+ const edits = [];
189409
+ walkWithScope(sf, (n, parent, shadowed) => {
189410
+ if (shadowed || !propRefs.has(n.text))
189411
+ return;
189412
+ if (isNonValuePosition(n, parent))
189413
+ return;
189414
+ const start = n.getStart(sf) - prefix.length;
189415
+ const end = n.getEnd() - prefix.length;
189416
+ if (start < 0 || end > text.length)
189417
+ return;
189418
+ if (parent && import_typescript5.default.isShorthandPropertyAssignment(parent) && parent.name === n) {
189419
+ edits.push({ start, end, replacement: `${n.text}: ${PROPS_PARAM}.${n.text}` });
189420
+ return;
189332
189421
  }
189333
- import_typescript5.default.forEachChild(n, (child) => visit(child, n));
189422
+ edits.push({ start, end, replacement: `${PROPS_PARAM}.${n.text}` });
189423
+ });
189424
+ if (edits.length === 0)
189425
+ return text;
189426
+ let result = text;
189427
+ for (const edit of edits.sort((a, b) => b.start - a.start)) {
189428
+ result = result.slice(0, edit.start) + edit.replacement + result.slice(edit.end);
189334
189429
  }
189335
- visit(node);
189430
+ return result;
189336
189431
  }
189337
189432
  function applyRegexPropRefRewrite(text, propRefs) {
189338
189433
  const { protect, restore } = createTemplateAwareStringProtector();
@@ -189362,7 +189457,7 @@ function rewriteBarePropRefs(text, node, propNames, extraPropRefs) {
189362
189457
  }
189363
189458
  if (foundPropRefs.size === 0)
189364
189459
  return;
189365
- return applyRegexPropRefRewrite(text, foundPropRefs);
189460
+ return applyScopedPropRefRewrite(text, foundPropRefs) ?? applyRegexPropRefRewrite(text, foundPropRefs);
189366
189461
  }
189367
189462
 
189368
189463
  // ../jsx/src/instrumentation.ts
@@ -189720,6 +189815,30 @@ function typeNodeToTypeInfo(typeNode, sourceFile, rawOf) {
189720
189815
  if (import_typescript7.default.isArrayTypeNode(typeNode)) {
189721
189816
  return { kind: "array", raw, elementType: recurse(typeNode.elementType) };
189722
189817
  }
189818
+ if (import_typescript7.default.isLiteralTypeNode(typeNode)) {
189819
+ const lit = typeNode.literal;
189820
+ if (import_typescript7.default.isStringLiteral(lit) || import_typescript7.default.isNoSubstitutionTemplateLiteral(lit)) {
189821
+ return { kind: "primitive", raw, primitive: "string", literalValue: lit.text };
189822
+ }
189823
+ if (import_typescript7.default.isNumericLiteral(lit)) {
189824
+ return { kind: "primitive", raw, primitive: "number", literalValue: lit.text };
189825
+ }
189826
+ if (import_typescript7.default.isPrefixUnaryExpression(lit) && lit.operator === import_typescript7.default.SyntaxKind.MinusToken && import_typescript7.default.isNumericLiteral(lit.operand)) {
189827
+ return { kind: "primitive", raw, primitive: "number", literalValue: `-${lit.operand.text}` };
189828
+ }
189829
+ if (lit.kind === import_typescript7.default.SyntaxKind.TrueKeyword || lit.kind === import_typescript7.default.SyntaxKind.FalseKeyword) {
189830
+ return {
189831
+ kind: "primitive",
189832
+ raw,
189833
+ primitive: "boolean",
189834
+ literalValue: lit.kind === import_typescript7.default.SyntaxKind.TrueKeyword ? "true" : "false"
189835
+ };
189836
+ }
189837
+ if (lit.kind === import_typescript7.default.SyntaxKind.NullKeyword) {
189838
+ return { kind: "primitive", raw, primitive: "null" };
189839
+ }
189840
+ return { kind: "unknown", raw };
189841
+ }
189723
189842
  if (import_typescript7.default.isUnionTypeNode(typeNode)) {
189724
189843
  return { kind: "union", raw, unionTypes: typeNode.types.map(recurse) };
189725
189844
  }
@@ -189909,9 +190028,7 @@ function baseTypeName(raw) {
189909
190028
  return (idx === -1 ? raw : raw.slice(0, idx)).trim();
189910
190029
  }
189911
190030
  function isNullishArm(t) {
189912
- if (t.kind === "primitive" && (t.primitive === "null" || t.primitive === "undefined"))
189913
- return true;
189914
- return t.kind === "unknown" && (t.raw === "null" || t.raw === "undefined");
190031
+ return t.kind === "primitive" && (t.primitive === "null" || t.primitive === "undefined");
189915
190032
  }
189916
190033
  function stripUnion(type2) {
189917
190034
  if (!type2 || type2.kind !== "union" || !type2.unionTypes)
@@ -190631,14 +190748,17 @@ function collectSignal(node, ctx) {
190631
190748
  const pattern = node.name;
190632
190749
  const callExpr = node.initializer;
190633
190750
  const elements = pattern.elements;
190634
- if (elements.length < 1 || elements.length > 2 || !import_typescript8.default.isBindingElement(elements[0]) || !import_typescript8.default.isIdentifier(elements[0].name)) {
190751
+ const getterElided = elements.length === 2 && import_typescript8.default.isOmittedExpression(elements[0]);
190752
+ if (elements.length < 1 || elements.length > 2 || !getterElided && (!import_typescript8.default.isBindingElement(elements[0]) || !import_typescript8.default.isIdentifier(elements[0].name))) {
190635
190753
  return;
190636
190754
  }
190637
190755
  if (elements.length === 2 && (!import_typescript8.default.isBindingElement(elements[1]) || !import_typescript8.default.isIdentifier(elements[1].name))) {
190638
190756
  return;
190639
190757
  }
190640
- const getter = elements[0].name.text;
190641
190758
  const setter = elements.length === 2 && import_typescript8.default.isBindingElement(elements[1]) && import_typescript8.default.isIdentifier(elements[1].name) ? elements[1].name.text : null;
190759
+ if (getterElided && !setter)
190760
+ return;
190761
+ const getter = getterElided ? `__bfGet_${setter}` : elements[0].name.text;
190642
190762
  const initialValue = callExpr.arguments[0] ? ctx.getJS(callExpr.arguments[0]) : "";
190643
190763
  const typedInitialValue = callExpr.arguments[0] ? callExpr.arguments[0].getText(ctx.sourceFile) : undefined;
190644
190764
  let type2 = { kind: "unknown", raw: "unknown" };
@@ -190659,6 +190779,7 @@ function collectSignal(node, ctx) {
190659
190779
  ctx.signals.push({
190660
190780
  getter,
190661
190781
  setter,
190782
+ getterElided: getterElided || undefined,
190662
190783
  initialValue,
190663
190784
  typedInitialValue: typedInitialValue !== initialValue ? typedInitialValue : undefined,
190664
190785
  templateInitialValue,
@@ -190849,9 +190970,17 @@ function collectMemo(node, ctx) {
190849
190970
  const blockBody = arrowNode && import_typescript8.default.isArrowFunction(arrowNode) && import_typescript8.default.isBlock(arrowNode.body) ? arrowNode.body : undefined;
190850
190971
  const parsedBlock = blockBody ? parseBlockBodyTolerant(blockBody, ctx.sourceFile, (node2) => ctx.getJS(node2)) : undefined;
190851
190972
  const parsedBlockComplete = parsedBlock && blockBody ? parsedBlock.length === blockBody.statements.length : undefined;
190973
+ let templateComputation;
190974
+ if (!ctx.propsObjectName && callExpr.arguments[0]) {
190975
+ const propNames = new Set(ctx.propsParams.map((p) => p.name));
190976
+ if (propNames.size > 0) {
190977
+ templateComputation = rewriteBarePropRefs(computation, callExpr.arguments[0], propNames);
190978
+ }
190979
+ }
190852
190980
  ctx.memos.push({
190853
190981
  name,
190854
190982
  computation,
190983
+ templateComputation,
190855
190984
  parsedBlock,
190856
190985
  parsedBlockComplete,
190857
190986
  typedComputation: typedComputation !== computation ? typedComputation : undefined,
@@ -193925,8 +194054,10 @@ function deriveFormat(locale, probeOptions) {
193925
194054
  return { pattern, names };
193926
194055
  }
193927
194056
  function unionMemberLiteral(member) {
193928
- const m = /^'([^'\\]*)'$|^"([^"\\]*)"$/.exec(member.raw.trim());
193929
- return m ? m[1] ?? m[2] : null;
194057
+ if (member.kind === "primitive" && member.primitive === "string" && member.literalValue !== undefined) {
194058
+ return member.literalValue;
194059
+ }
194060
+ return null;
193930
194061
  }
193931
194062
  function resolveLocaleUnionMembers(locale, metadata) {
193932
194063
  let sourcePropName = null;
@@ -194531,6 +194662,13 @@ function jsxToIR(analyzer) {
194531
194662
  function buildIRRoot(analyzer) {
194532
194663
  if (analyzer.conditionalReturns.length > 0) {
194533
194664
  const ctx2 = createTransformContext(analyzer);
194665
+ const allReactiveNoLocals = analyzer.jsxReturn != null && analyzer.conditionalReturns.every((cr) => cr.scopeVariables.length === 0 && exprCallsReactiveGetters(cr.condition, ctx2));
194666
+ if (allReactiveNoLocals) {
194667
+ const chain = buildIfStatementChain(analyzer, ctx2, { asConditional: true });
194668
+ if (!chain)
194669
+ return null;
194670
+ return chain.type === "conditional" ? wrapInScopeElement(chain) : chain;
194671
+ }
194534
194672
  return buildIfStatementChain(analyzer, ctx2);
194535
194673
  }
194536
194674
  if (!analyzer.jsxReturn)
@@ -194686,11 +194824,52 @@ function transformJsxElement(node, ctx) {
194686
194824
  }
194687
194825
  return transformHtmlElement(node, ctx, tagName);
194688
194826
  }
194827
+ function lowerFormControlValueSsr(tagName, attrs, children) {
194828
+ if (tagName !== "textarea" && tagName !== "select")
194829
+ return;
194830
+ const valueAttr = attrs.find((a) => a.name === "value");
194831
+ if (!valueAttr || valueAttr.clientOnly || valueAttr.value.kind !== "expression")
194832
+ return;
194833
+ const { expr, templateExpr } = valueAttr.value;
194834
+ valueAttr.clientOnly = true;
194835
+ if (tagName === "textarea") {
194836
+ if (children.length > 0)
194837
+ return;
194838
+ children.push({
194839
+ type: "expression",
194840
+ expr,
194841
+ templateExpr: `escapeText(${templateExpr ?? expr})`,
194842
+ typeInfo: null,
194843
+ reactive: false,
194844
+ slotId: null,
194845
+ loc: valueAttr.loc,
194846
+ origin: { phase: "ssr", scope: "template", effect: "pure" }
194847
+ });
194848
+ return;
194849
+ }
194850
+ const selectedFor = (optValue) => AttrValueOf.expression(`(${expr}) === ${JSON.stringify(optValue)}`, templateExpr !== undefined ? { templateExpr: `(${templateExpr}) === ${JSON.stringify(optValue)}` } : undefined);
194851
+ const distribute = (nodes) => {
194852
+ for (const n of nodes) {
194853
+ if (n.type === "element" && n.tag === "option") {
194854
+ if (n.attrs.some((a) => a.name === "selected"))
194855
+ continue;
194856
+ const optValue = n.attrs.find((a) => a.name === "value");
194857
+ if (!optValue || optValue.value.kind !== "literal")
194858
+ continue;
194859
+ n.attrs.push({ name: "selected", value: selectedFor(optValue.value.value), loc: n.loc });
194860
+ } else if (n.type === "fragment" || n.type === "element" && n.tag === "optgroup") {
194861
+ distribute(n.children);
194862
+ }
194863
+ }
194864
+ };
194865
+ distribute(children);
194866
+ }
194689
194867
  function transformHtmlElement(node, ctx, tagName) {
194690
194868
  const { attrs, events, ref } = processAttributes(node.openingElement.attributes, ctx);
194691
194869
  const needsScope = ctx.isRoot;
194692
194870
  ctx.isRoot = false;
194693
194871
  const children = transformChildren(node.children, ctx);
194872
+ lowerFormControlValueSsr(tagName, attrs, children);
194694
194873
  const needsSlot = events.length > 0 || hasDynamicContent(children) || hasReactiveAttributes(attrs, ctx) || ref !== null;
194695
194874
  const slotId = needsSlot ? generateSlotId(ctx) : null;
194696
194875
  if (slotId) {
@@ -194722,6 +194901,8 @@ function transformSelfClosingElement(node, ctx) {
194722
194901
  return transformSelfClosingComponent(node, ctx, resolved ?? tagName);
194723
194902
  }
194724
194903
  const { attrs, events, ref } = processAttributes(node.attributes, ctx);
194904
+ const selfClosingChildren = [];
194905
+ lowerFormControlValueSsr(tagName, attrs, selfClosingChildren);
194725
194906
  const needsSlot = events.length > 0 || hasReactiveAttributes(attrs, ctx) || ref !== null;
194726
194907
  const slotId = needsSlot ? generateSlotId(ctx) : null;
194727
194908
  const needsScope = ctx.isRoot;
@@ -194732,7 +194913,7 @@ function transformSelfClosingElement(node, ctx) {
194732
194913
  attrs,
194733
194914
  events,
194734
194915
  ref,
194735
- children: [],
194916
+ children: selfClosingChildren,
194736
194917
  slotId,
194737
194918
  needsScope,
194738
194919
  loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath)
@@ -196115,6 +196296,15 @@ function branchHasNoElement(node) {
196115
196296
  }
196116
196297
  return true;
196117
196298
  }
196299
+ function tagLoopItemRootComponents(nodes) {
196300
+ for (const node of nodes) {
196301
+ if (node.type === "component") {
196302
+ node.loopItemRoot = true;
196303
+ } else if (node.type === "conditional") {
196304
+ tagLoopItemRootComponents([node.whenTrue, node.whenFalse]);
196305
+ }
196306
+ }
196307
+ }
196118
196308
  function loopBodyItemConditional(children) {
196119
196309
  const real = children.filter((c) => !(c.type === "text" && typeof c.value === "string" && !c.value.trim()));
196120
196310
  if (real.length !== 1)
@@ -196352,9 +196542,9 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196352
196542
  const pre = multiReturn.preamble ?? [];
196353
196543
  if (pre.length > 0) {
196354
196544
  preamble = preambleFromValueStatements(pre, ctx);
196355
- if (!isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
196545
+ if (!preamble.declarations && !isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
196356
196546
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, loc, {
196357
- 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.",
196547
+ message: "A .map() callback body with a preamble before its branches cannot be " + "lowered to a template: the preamble is not a sequence of value " + "declarations, so this backend has no per-row local to carry into the " + "branches.",
196358
196548
  suggestion: {
196359
196549
  message: "Add /* @client */ to evaluate this expression on the client only"
196360
196550
  }
@@ -196421,6 +196611,14 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196421
196611
  }
196422
196612
  if (valueStmts.length > 0) {
196423
196613
  preamble = preambleFromValueStatements(valueStmts, ctx);
196614
+ if (!preamble.declarations && !isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
196615
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(body, ctx.sourceFile, ctx.filePath), {
196616
+ message: "A .map() callback preamble that is not a sequence of value " + "declarations cannot be lowered to a template: this backend can " + "declare a per-row local, but cannot run arbitrary statements per row.",
196617
+ suggestion: {
196618
+ message: "Add /* @client */ to evaluate this expression on the client only"
196619
+ }
196620
+ }));
196621
+ }
196424
196622
  }
196425
196623
  }
196426
196624
  }
@@ -196506,6 +196704,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196506
196704
  }));
196507
196705
  preamble = undefined;
196508
196706
  }
196707
+ tagLoopItemRootComponents(children);
196509
196708
  let childComponent;
196510
196709
  if (children.length === 1 && children[0].type === "component") {
196511
196710
  const comp = children[0];
@@ -196526,6 +196725,9 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
196526
196725
  const isDirectPropArray = method !== "flatMap" && isArrayExprDirectPropRef(arrayExpr, ctx);
196527
196726
  const isStaticArray = !isSignalOrMemoArray(array, ctx) && !isDirectPropArray && !hasCalls && !objectIteration;
196528
196727
  const preambleRegions = preamble && !isStaticArray ? collectPreambleRegions(children, new Set(preamble.declaredNames), ctx) : undefined;
196728
+ if (preamble && !isStaticArray) {
196729
+ markPreambleAttrSlots(children, new Set(preamble.declaredNames), ctx);
196730
+ }
196529
196731
  const nestedComponents = collectNestedComponents(children).filter((c) => c.name !== childComponent?.name);
196530
196732
  return {
196531
196733
  type: "loop",
@@ -196750,20 +196952,66 @@ function collectPreambleRegions(nodes, declared, ctx) {
196750
196952
  visit2(nodes);
196751
196953
  return regions;
196752
196954
  }
196753
- function collectBindingNames(name, out) {
196955
+ function markPreambleAttrSlots(nodes, declared, ctx) {
196956
+ const readsDeclared = (attr) => {
196957
+ if (attr.name === "key")
196958
+ return false;
196959
+ const value = attr.value;
196960
+ if (value.kind !== "expression" && value.kind !== "template")
196961
+ return false;
196962
+ const refs = attr.freeIdentifiers ?? extractFreeIdentifiersFromText(attrValueText(value));
196963
+ for (const r of refs)
196964
+ if (declared.has(r))
196965
+ return true;
196966
+ return false;
196967
+ };
196968
+ const visit2 = (list) => {
196969
+ for (const node of list) {
196970
+ switch (node.type) {
196971
+ case "element":
196972
+ if (!node.slotId && node.attrs.some(readsDeclared))
196973
+ node.slotId = generateSlotId(ctx);
196974
+ visit2(node.children);
196975
+ break;
196976
+ case "fragment":
196977
+ visit2(node.children);
196978
+ break;
196979
+ case "conditional":
196980
+ visit2([node.whenTrue, ...node.whenFalse ? [node.whenFalse] : []]);
196981
+ break;
196982
+ }
196983
+ }
196984
+ };
196985
+ visit2(nodes);
196986
+ }
196987
+ function attrValueText(value) {
196988
+ if (value.kind === "expression")
196989
+ return value.expr;
196990
+ if (value.kind !== "template")
196991
+ return "";
196992
+ const out = [];
196993
+ for (const p of value.parts) {
196994
+ if (p.type === "ternary")
196995
+ out.push(p.condition, p.whenTrue, p.whenFalse);
196996
+ else if (p.type === "lookup")
196997
+ out.push(p.key);
196998
+ }
196999
+ return out.join(" ");
197000
+ }
197001
+ function collectBindingNames2(name, out) {
196754
197002
  if (import_typescript11.default.isIdentifier(name)) {
196755
197003
  out.add(name.text);
196756
197004
  return;
196757
197005
  }
196758
197006
  for (const el of name.elements) {
196759
197007
  if (import_typescript11.default.isBindingElement(el))
196760
- collectBindingNames(el.name, out);
197008
+ collectBindingNames2(el.name, out);
196761
197009
  }
196762
197010
  }
196763
197011
  function collectPreambleDeclaredNames(stmt, out) {
196764
197012
  if (import_typescript11.default.isVariableStatement(stmt)) {
196765
197013
  for (const decl of stmt.declarationList.declarations) {
196766
- collectBindingNames(decl.name, out);
197014
+ collectBindingNames2(decl.name, out);
196767
197015
  }
196768
197016
  } else if (import_typescript11.default.isFunctionDeclaration(stmt) && stmt.name) {
196769
197017
  out.add(stmt.name.text);
@@ -196787,9 +197035,32 @@ function preambleFromValueStatements(statements, ctx) {
196787
197035
  segments: trimPreambleSegments(segments),
196788
197036
  ssrText: tsxSourceText(typedParts.join(" ")),
196789
197037
  declaredNames: [...declared],
196790
- builderNames: []
197038
+ builderNames: [],
197039
+ declarations: neutralPreambleDeclarations(statements, ctx) ?? undefined
196791
197040
  };
196792
197041
  }
197042
+ function neutralPreambleDeclarations(statements, ctx) {
197043
+ const out = [];
197044
+ for (const stmt of statements) {
197045
+ if (!import_typescript11.default.isVariableStatement(stmt))
197046
+ return null;
197047
+ for (const decl of stmt.declarationList.declarations) {
197048
+ if (!import_typescript11.default.isIdentifier(decl.name))
197049
+ return null;
197050
+ if (!decl.initializer)
197051
+ return null;
197052
+ const valueParsed = tsNodeToParsedExpr(decl.initializer);
197053
+ if (!isSupported(valueParsed).supported)
197054
+ return null;
197055
+ out.push({
197056
+ name: decl.name.text,
197057
+ valueParsed,
197058
+ raw: decl.initializer.getText(ctx.sourceFile)
197059
+ });
197060
+ }
197061
+ }
197062
+ return out.length > 0 ? out : null;
197063
+ }
196793
197064
  function trimPreambleSegments(segments) {
196794
197065
  const last = segments[segments.length - 1];
196795
197066
  if (last?.kind === "js") {
@@ -197133,6 +197404,8 @@ function parseTemplateLiteral(expr, ctx) {
197133
197404
  }
197134
197405
  function tryResolveTemplateSpanFromConst(expr, ctx) {
197135
197406
  if (import_typescript11.default.isIdentifier(expr)) {
197407
+ if (ctx.loopParams.has(expr.text))
197408
+ return null;
197136
197409
  const constInfo = findLocalConst(expr.text, ctx.analyzer);
197137
197410
  if (!constInfo)
197138
197411
  return null;
@@ -197147,6 +197420,8 @@ function tryResolveTemplateSpanFromConst(expr, ctx) {
197147
197420
  if (import_typescript11.default.isElementAccessExpression(expr)) {
197148
197421
  if (!import_typescript11.default.isIdentifier(expr.expression))
197149
197422
  return null;
197423
+ if (ctx.loopParams.has(expr.expression.text))
197424
+ return null;
197150
197425
  const constInfo = findLocalConst(expr.expression.text, ctx.analyzer);
197151
197426
  if (!constInfo)
197152
197427
  return null;
@@ -197235,6 +197510,9 @@ function tryResolveIdentifierAsTemplateLiteral(ident, ctx) {
197235
197510
  if (import_typescript11.default.isNoSubstitutionTemplateLiteral(ast) || import_typescript11.default.isStringLiteral(ast)) {
197236
197511
  return [{ type: "string", value: ast.text }];
197237
197512
  }
197513
+ if (import_typescript11.default.isElementAccessExpression(ast) && !import_typescript11.default.isStringLiteralLike(ast.argumentExpression) && !import_typescript11.default.isNumericLiteral(ast.argumentExpression)) {
197514
+ return tryResolveTemplateSpanFromConst(ast, ctx);
197515
+ }
197238
197516
  if (!import_typescript11.default.isTemplateExpression(ast))
197239
197517
  return null;
197240
197518
  let resolvedAny = false;
@@ -197482,8 +197760,11 @@ function processComponentProps(attributes, ctx) {
197482
197760
  }
197483
197761
  let value = getAttributeValue(attr, ctx);
197484
197762
  if (value.kind === "template") {
197485
- value = AttrValueOf.expression(templatePartsToJsString(value.parts), {
197486
- parts: value.parts
197763
+ const collapsed = templatePartsToJsString(value.parts);
197764
+ const collapsedTemplate = templatePartsToJsString(value.parts, { useTemplate: true });
197765
+ value = AttrValueOf.expression(collapsed, {
197766
+ parts: value.parts,
197767
+ ...collapsedTemplate !== collapsed && { templateExpr: collapsedTemplate }
197487
197768
  });
197488
197769
  } else if (value.kind === "boolean-attr") {
197489
197770
  value = AttrValueOf.booleanShorthand();
@@ -197512,16 +197793,18 @@ function processComponentProps(attributes, ctx) {
197512
197793
  }
197513
197794
  return props;
197514
197795
  }
197515
- function templatePartsToJsString(parts) {
197796
+ function templatePartsToJsString(parts, opts) {
197516
197797
  let result = "`";
197517
197798
  for (const part of parts) {
197518
197799
  if (part.type === "string") {
197519
- result += part.value;
197800
+ result += opts?.useTemplate && part.templateValue ? part.templateValue : part.value;
197520
197801
  } else if (part.type === "ternary") {
197521
- result += `\${${part.condition} ? '${part.whenTrue}' : '${part.whenFalse}'}`;
197802
+ const cond = opts?.useTemplate && part.templateCondition ? part.templateCondition : part.condition;
197803
+ result += `\${${cond} ? '${part.whenTrue}' : '${part.whenFalse}'}`;
197522
197804
  } else if (part.type === "lookup") {
197805
+ const key = opts?.useTemplate && part.templateKey ? part.templateKey : part.key;
197523
197806
  const obj = "{" + Object.entries(part.cases).map(([k, v]) => `${JSON.stringify(k)}: ${JSON.stringify(v)}`).join(", ") + "}";
197524
- result += `\${(${obj})[${part.key}]}`;
197807
+ result += `\${(${obj})[${key}]}`;
197525
197808
  }
197526
197809
  }
197527
197810
  result += "`";
@@ -197732,11 +198015,12 @@ function replaceBranchLocalRefs(text, branchNames, resolve2) {
197732
198015
  const pattern = new RegExp(`(?<![\\w$])(${branchNames.join("|")})(?![\\w$])`, "g");
197733
198016
  return replaceInExprContexts(text, pattern, (_match, name) => resolve2(name));
197734
198017
  }
197735
- function buildIfStatementChain(analyzer, ctx) {
198018
+ function buildIfStatementChain(analyzer, ctx, opts) {
197736
198019
  const conditionalReturns = analyzer.conditionalReturns;
198020
+ const asConditional = opts?.asConditional === true;
197737
198021
  let alternate = null;
197738
198022
  if (analyzer.jsxReturn) {
197739
- ctx.isRoot = true;
198023
+ ctx.isRoot = !asConditional;
197740
198024
  alternate = transformNode(analyzer.jsxReturn, ctx);
197741
198025
  }
197742
198026
  for (let i2 = conditionalReturns.length - 1;i2 >= 0; i2--) {
@@ -197805,7 +198089,7 @@ function buildIfStatementChain(analyzer, ctx) {
197805
198089
  ctx.getJS = substitutedGetJS;
197806
198090
  ctx.analyzer.getJS = substitutedGetJS;
197807
198091
  }
197808
- ctx.isRoot = true;
198092
+ ctx.isRoot = !asConditional;
197809
198093
  let consequent;
197810
198094
  try {
197811
198095
  consequent = transformNode(condReturn.jsxReturn, ctx);
@@ -197835,6 +198119,27 @@ function buildIfStatementChain(analyzer, ctx) {
197835
198119
  }
197836
198120
  }
197837
198121
  const loc = getSourceLocation(condReturn.ifStatement, analyzer.sourceFile, analyzer.filePath);
198122
+ if (asConditional && alternate) {
198123
+ const conditional = {
198124
+ type: "conditional",
198125
+ condition,
198126
+ templateCondition,
198127
+ conditionType: null,
198128
+ reactive: true,
198129
+ whenTrue: consequent,
198130
+ whenFalse: alternate,
198131
+ slotId: generateSlotId(ctx),
198132
+ loc,
198133
+ origin: {
198134
+ phase: "tick",
198135
+ scope: "template",
198136
+ effect: "pure",
198137
+ freeRefs: resolveFreeRefs(condReturn.condition, makeBindingEnv(ctx))
198138
+ }
198139
+ };
198140
+ alternate = conditional;
198141
+ continue;
198142
+ }
197838
198143
  const ifStmt = {
197839
198144
  type: "if-statement",
197840
198145
  condition,
@@ -198124,6 +198429,13 @@ function formatDateLocalNames(metadata) {
198124
198429
  return names;
198125
198430
  }
198126
198431
 
198432
+ // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
198433
+ var import_typescript15 = __toESM(require_typescript(), 1);
198434
+ var NO_PREAMBLE = {
198435
+ lazySafe: true,
198436
+ facts: { declaredNames: new Set, freeNames: new Set }
198437
+ };
198438
+
198127
198439
  // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts
198128
198440
  var PURE_SOURCE_GLOBALS = new Set([
198129
198441
  "Object",
@@ -198168,7 +198480,7 @@ var INERT_BINDING_GLOBALS = new Set([
198168
198480
  ]);
198169
198481
 
198170
198482
  // ../jsx/src/ir-to-client-js/emit-reactive.ts
198171
- var import_typescript15 = __toESM(require_typescript(), 1);
198483
+ var import_typescript16 = __toESM(require_typescript(), 1);
198172
198484
 
198173
198485
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
198174
198486
  var NON_BUBBLING_EVENTS = new Set([
@@ -198183,7 +198495,7 @@ var NON_BUBBLING_EVENTS = new Set([
198183
198495
  ]);
198184
198496
 
198185
198497
  // ../jsx/src/ir-to-client-js/rewrite-props-object.ts
198186
- var import_typescript16 = __toESM(require_typescript(), 1);
198498
+ var import_typescript17 = __toESM(require_typescript(), 1);
198187
198499
 
198188
198500
  // ../jsx/src/ir-to-client-js/source-map.ts
198189
198501
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -198274,21 +198586,21 @@ class SourceMapGenerator {
198274
198586
  }
198275
198587
 
198276
198588
  // ../jsx/src/preprocess-inline-jsx-callbacks.ts
198277
- var import_typescript17 = __toESM(require_typescript(), 1);
198589
+ var import_typescript18 = __toESM(require_typescript(), 1);
198278
198590
 
198279
198591
  // ../jsx/src/ssr-defaults.ts
198280
- var import_typescript18 = __toESM(require_typescript(), 1);
198592
+ var import_typescript19 = __toESM(require_typescript(), 1);
198281
198593
  var UNRESOLVED = Symbol("unresolved");
198282
198594
  var NO_RETURN = Symbol("no-return");
198283
198595
 
198284
198596
  // ../jsx/src/augment-inherited-props.ts
198285
- var import_typescript19 = __toESM(require_typescript(), 1);
198597
+ var import_typescript20 = __toESM(require_typescript(), 1);
198286
198598
 
198287
198599
  // ../jsx/src/rich-type-refusal.ts
198288
198600
  var EMPTY_BINDINGS2 = new Map;
198289
198601
  // ../jsx/src/shared-program.ts
198290
198602
  init_path();
198291
- var import_typescript20 = __toESM(require_typescript(), 1);
198603
+ var import_typescript21 = __toESM(require_typescript(), 1);
198292
198604
  // ../jsx/src/adapters/interface.ts
198293
198605
  class BaseAdapter {
198294
198606
  renderChildren(children) {
@@ -198827,9 +199139,9 @@ function registerBuiltinLoweringPlugins() {
198827
199139
  registerLoweringPlugin(plugin);
198828
199140
  }
198829
199141
  // ../jsx/src/combine-client-js.ts
198830
- var import_typescript21 = __toESM(require_typescript(), 1);
198831
- // ../jsx/src/debug.ts
198832
199142
  var import_typescript22 = __toESM(require_typescript(), 1);
199143
+ // ../jsx/src/debug.ts
199144
+ var import_typescript23 = __toESM(require_typescript(), 1);
198833
199145
  function escapeForIdBoundary(name) {
198834
199146
  return name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
198835
199147
  }
@@ -198921,7 +199233,7 @@ function resolveSetters(handler, setterToSignal, fnSetters) {
198921
199233
  return refs;
198922
199234
  }
198923
199235
  // ../jsx/src/profiler.ts
198924
- var import_typescript23 = __toESM(require_typescript(), 1);
199236
+ var import_typescript24 = __toESM(require_typescript(), 1);
198925
199237
 
198926
199238
  // ../jsx/src/index.ts
198927
199239
  registerBuiltinLoweringPlugins();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/test",
3
- "version": "0.29.0",
3
+ "version": "0.30.2",
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.29.0"
42
+ "@barefootjs/jsx": "0.30.2"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.0.0"