@barefootjs/jsx 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5339,7 +5339,6 @@ var UNSUPPORTED_METHODS = new Set([
5339
5339
  "some",
5340
5340
  "forEach",
5341
5341
  "flatMap",
5342
- "flat",
5343
5342
  "replaceAll",
5344
5343
  "charAt",
5345
5344
  "charCodeAt",
@@ -5351,6 +5350,9 @@ var UNSUPPORTED_METHODS = new Set([
5351
5350
  "matchAll",
5352
5351
  "search"
5353
5352
  ]);
5353
+ var UNSUPPORTED_METHOD_REASONS = {
5354
+ forEach: `'.forEach()' returns undefined and has no template-position meaning. ` + `Use it for side effects inside an event handler or createEffect callback ` + `(client JS), or use '.map(...)' if you meant to render each item.`
5355
+ };
5354
5356
  var LOWERED_ARRAY_METHODS = new Set([
5355
5357
  "includes",
5356
5358
  "indexOf",
@@ -5438,6 +5440,32 @@ function convertNode(node, raw) {
5438
5440
  if (callee.property === "reverse" || callee.property === "toReversed") {
5439
5441
  return { kind: "array-method", method: callee.property, object: callee.object, args };
5440
5442
  }
5443
+ if (callee.property === "flat") {
5444
+ const depthNode = node.arguments[0];
5445
+ let flatDepth;
5446
+ if (depthNode === undefined) {
5447
+ flatDepth = 1;
5448
+ } else if (ts8.isIdentifier(depthNode) && depthNode.text === "Infinity") {
5449
+ flatDepth = "infinity";
5450
+ } else {
5451
+ let n;
5452
+ if (ts8.isNumericLiteral(depthNode)) {
5453
+ n = Number(depthNode.text);
5454
+ } else if (ts8.isPrefixUnaryExpression(depthNode) && depthNode.operator === ts8.SyntaxKind.MinusToken && ts8.isNumericLiteral(depthNode.operand)) {
5455
+ n = -Number(depthNode.operand.text);
5456
+ }
5457
+ if (n === undefined || Number.isNaN(n)) {
5458
+ return {
5459
+ kind: "unsupported",
5460
+ raw,
5461
+ reason: `\`.flat(depth)\` needs a literal integer or \`Infinity\` depth — a computed depth can't be resolved at template time. Use a literal depth, or pre-compute the value before the template.`
5462
+ };
5463
+ }
5464
+ const truncated = Math.trunc(n);
5465
+ flatDepth = truncated < 0 ? 0 : truncated;
5466
+ }
5467
+ return { kind: "array-method", method: "flat", object: callee.object, args: [], flatDepth };
5468
+ }
5441
5469
  if (callee.property === "toLowerCase") {
5442
5470
  return { kind: "array-method", method: "toLowerCase", object: callee.object, args };
5443
5471
  }
@@ -5521,6 +5549,50 @@ function convertNode(node, raw) {
5521
5549
  ` + `(reverse the operands for descending order). ` + `Wrap the call in /* @client */ to evaluate at hydration.`
5522
5550
  };
5523
5551
  }
5552
+ if ((callee.property === "reduce" || callee.property === "reduceRight") && node.arguments.length === 2) {
5553
+ const reduceOp = extractReduceOpFromTS(node.arguments[0], node.arguments[1]);
5554
+ if (reduceOp) {
5555
+ return {
5556
+ kind: "array-method",
5557
+ method: callee.property,
5558
+ object: callee.object,
5559
+ args: [],
5560
+ reduceOp
5561
+ };
5562
+ }
5563
+ const m = callee.property;
5564
+ return {
5565
+ kind: "unsupported",
5566
+ raw,
5567
+ reason: `Reduce shape not supported. Accepted (arithmetic fold, explicit init):
5568
+ ` + ` arr.${m}((acc, x) => acc + x, 0)
5569
+ ` + ` arr.${m}((acc, x) => acc + x.field, 0)
5570
+ ` + ` arr.${m}((acc, x) => acc * x.field, 1)
5571
+ ` + ` arr.${m}((acc, x) => acc + x.field, '') (string concat)
5572
+ ` + `The accumulator must be the left operand and the initial ` + `value a number / string literal. ` + `Wrap the call in /* @client */ to evaluate at hydration.`
5573
+ };
5574
+ }
5575
+ if (callee.property === "flatMap") {
5576
+ const flatMapOp = node.arguments.length === 1 ? extractFlatMapOpFromTS(node.arguments[0]) : null;
5577
+ if (flatMapOp) {
5578
+ return {
5579
+ kind: "array-method",
5580
+ method: "flatMap",
5581
+ object: callee.object,
5582
+ args: [],
5583
+ flatMapOp
5584
+ };
5585
+ }
5586
+ return {
5587
+ kind: "unsupported",
5588
+ raw,
5589
+ reason: `flatMap shape not supported. Accepted (self / field leaves, no thisArg):
5590
+ ` + ` arr.flatMap(i => i) (flatten one level)
5591
+ ` + ` arr.flatMap(i => i.field) (flatten a per-item array field)
5592
+ ` + ` arr.flatMap(i => [i.a, i.b]) (gather per-item fields)
5593
+ ` + `Richer callbacks (computed / nested access, arithmetic, calls, ` + `literal elements) and the 2-arg \`flatMap(fn, thisArg)\` form ` + `aren't lowered. Wrap the call in /* @client */ to evaluate at hydration.`
5594
+ };
5595
+ }
5524
5596
  }
5525
5597
  return { kind: "call", callee, args };
5526
5598
  }
@@ -5839,6 +5911,119 @@ function classifySortOperand(expr, paramA, paramB) {
5839
5911
  }
5840
5912
  return null;
5841
5913
  }
5914
+ function extractReduceOpFromTS(reducerNode, initNode) {
5915
+ const init = classifyReduceInit(initNode);
5916
+ if (!init)
5917
+ return null;
5918
+ if (!ts8.isArrowFunction(reducerNode) && !ts8.isFunctionExpression(reducerNode))
5919
+ return null;
5920
+ if (reducerNode.parameters.length !== 2)
5921
+ return null;
5922
+ const pAcc = reducerNode.parameters[0];
5923
+ const pItem = reducerNode.parameters[1];
5924
+ if (!ts8.isIdentifier(pAcc.name) || !ts8.isIdentifier(pItem.name))
5925
+ return null;
5926
+ const paramAcc = pAcc.name.text;
5927
+ const paramItem = pItem.name.text;
5928
+ let body;
5929
+ if (ts8.isArrowFunction(reducerNode) && !ts8.isBlock(reducerNode.body)) {
5930
+ body = reducerNode.body;
5931
+ } else {
5932
+ const block = reducerNode.body;
5933
+ const stmts = block.statements;
5934
+ if (stmts.length !== 1 || !ts8.isReturnStatement(stmts[0]) || !stmts[0].expression)
5935
+ return null;
5936
+ body = stmts[0].expression;
5937
+ }
5938
+ const raw = body.getText();
5939
+ const expr = unwrapParens(body);
5940
+ if (!ts8.isBinaryExpression(expr))
5941
+ return null;
5942
+ let op;
5943
+ if (expr.operatorToken.kind === ts8.SyntaxKind.PlusToken)
5944
+ op = "+";
5945
+ else if (expr.operatorToken.kind === ts8.SyntaxKind.AsteriskToken)
5946
+ op = "*";
5947
+ else
5948
+ return null;
5949
+ const left = unwrapParens(expr.left);
5950
+ if (!ts8.isIdentifier(left) || left.text !== paramAcc)
5951
+ return null;
5952
+ const key = classifyReduceKey(unwrapParens(expr.right), paramItem);
5953
+ if (!key)
5954
+ return null;
5955
+ const type = init.type;
5956
+ if (type === "string" && op !== "+")
5957
+ return null;
5958
+ return { op, key, type, init: init.value, raw, paramAcc, paramItem };
5959
+ }
5960
+ function extractFlatMapOpFromTS(cbNode) {
5961
+ if (!ts8.isArrowFunction(cbNode) && !ts8.isFunctionExpression(cbNode))
5962
+ return null;
5963
+ if (cbNode.parameters.length !== 1)
5964
+ return null;
5965
+ const p = cbNode.parameters[0];
5966
+ if (!ts8.isIdentifier(p.name))
5967
+ return null;
5968
+ const param = p.name.text;
5969
+ let body;
5970
+ if (ts8.isArrowFunction(cbNode) && !ts8.isBlock(cbNode.body)) {
5971
+ body = cbNode.body;
5972
+ } else {
5973
+ const block = cbNode.body;
5974
+ const stmts = block.statements;
5975
+ if (stmts.length !== 1 || !ts8.isReturnStatement(stmts[0]) || !stmts[0].expression)
5976
+ return null;
5977
+ body = stmts[0].expression;
5978
+ }
5979
+ const raw = body.getText();
5980
+ const inner = unwrapParens(body);
5981
+ if (ts8.isArrayLiteralExpression(inner)) {
5982
+ if (inner.elements.length === 0)
5983
+ return null;
5984
+ const elements = [];
5985
+ for (const el of inner.elements) {
5986
+ if (ts8.isSpreadElement(el) || ts8.isOmittedExpression(el))
5987
+ return null;
5988
+ const leaf2 = classifyReduceKey(unwrapParens(el), param);
5989
+ if (!leaf2)
5990
+ return null;
5991
+ elements.push(leaf2);
5992
+ }
5993
+ return { projection: { kind: "tuple", elements }, param, raw };
5994
+ }
5995
+ const leaf = classifyReduceKey(inner, param);
5996
+ if (!leaf)
5997
+ return null;
5998
+ return { projection: leaf, param, raw };
5999
+ }
6000
+ function classifyReduceKey(expr, paramItem) {
6001
+ if (ts8.isIdentifier(expr)) {
6002
+ return expr.text === paramItem ? { kind: "self" } : null;
6003
+ }
6004
+ if (ts8.isPropertyAccessExpression(expr) && ts8.isIdentifier(expr.expression)) {
6005
+ if (expr.expression.text === paramItem)
6006
+ return { kind: "field", field: expr.name.text };
6007
+ }
6008
+ return null;
6009
+ }
6010
+ function classifyReduceInit(node) {
6011
+ let n = unwrapParens(node);
6012
+ if (ts8.isPrefixUnaryExpression(n) && n.operator === ts8.SyntaxKind.MinusToken) {
6013
+ if (ts8.isNumericLiteral(n.operand))
6014
+ return { type: "numeric", value: "-" + n.operand.text };
6015
+ return null;
6016
+ }
6017
+ if (ts8.isNumericLiteral(n))
6018
+ return { type: "numeric", value: n.text };
6019
+ if (ts8.isStringLiteral(n)) {
6020
+ const raw = n.getText();
6021
+ if (raw.length < 2 || raw.slice(1, -1) !== n.text)
6022
+ return null;
6023
+ return { type: "string", value: n.text };
6024
+ }
6025
+ return null;
6026
+ }
5842
6027
  function collectDestructureBindings(pattern, pathPrefix, fieldMap, raw, excludedTopKeys) {
5843
6028
  let restName;
5844
6029
  for (const el of pattern.elements) {
@@ -6147,6 +6332,15 @@ function substituteDestructuredFields(expr, fieldMap, syntheticParam, restName)
6147
6332
  if (e.method === "sort" || e.method === "toSorted") {
6148
6333
  return { kind: "array-method", method: e.method, object: walk(e.object), args: [], comparator: e.comparator };
6149
6334
  }
6335
+ if (e.method === "reduce" || e.method === "reduceRight") {
6336
+ return { kind: "array-method", method: e.method, object: walk(e.object), args: [], reduceOp: e.reduceOp };
6337
+ }
6338
+ if (e.method === "flat") {
6339
+ return { kind: "array-method", method: "flat", object: walk(e.object), args: [], flatDepth: e.flatDepth };
6340
+ }
6341
+ if (e.method === "flatMap") {
6342
+ return { kind: "array-method", method: "flatMap", object: walk(e.object), args: [], flatMapOp: e.flatMapOp };
6343
+ }
6150
6344
  return { kind: "array-method", method: e.method, object: walk(e.object), args: e.args.map(walk) };
6151
6345
  case "literal":
6152
6346
  case "unsupported":
@@ -6267,7 +6461,8 @@ function checkSupport(expr) {
6267
6461
  return {
6268
6462
  supported: false,
6269
6463
  level: "L5_UNSUPPORTED",
6270
- reason: `Method '${methodName}()' has no template lowering and requires client-side evaluation. Wrap the expression in /* @client */ to defer it to hydration, or pre-compute the value before rendering.`
6464
+ selfContained: true,
6465
+ reason: UNSUPPORTED_METHOD_REASONS[methodName] ?? `'${methodName}()' can't render on the server. Pre-compute the value, or add /* @client */ for client-only (no SSR).`
6271
6466
  };
6272
6467
  }
6273
6468
  }
@@ -6491,6 +6686,20 @@ function exprToString(expr) {
6491
6686
  const { paramA, paramB, raw } = expr.comparator;
6492
6687
  return `${exprToString(expr.object)}.${expr.method}((${paramA},${paramB}) => ${raw})`;
6493
6688
  }
6689
+ if (expr.method === "reduce" || expr.method === "reduceRight") {
6690
+ const { paramAcc, paramItem, raw, type, init } = expr.reduceOp;
6691
+ const initSrc = type === "string" ? JSON.stringify(init) : init;
6692
+ return `${exprToString(expr.object)}.${expr.method}((${paramAcc},${paramItem}) => ${raw}, ${initSrc})`;
6693
+ }
6694
+ if (expr.method === "flat") {
6695
+ const d = expr.flatDepth;
6696
+ const depthSrc = d === "infinity" ? "Infinity" : String(d);
6697
+ return `${exprToString(expr.object)}.flat(${d === 1 ? "" : depthSrc})`;
6698
+ }
6699
+ if (expr.method === "flatMap") {
6700
+ const { param, raw } = expr.flatMapOp;
6701
+ return `${exprToString(expr.object)}.flatMap(${param} => ${raw})`;
6702
+ }
6494
6703
  return `${exprToString(expr.object)}.${expr.method}(${expr.args.map(exprToString).join(", ")})`;
6495
6704
  case "unsupported":
6496
6705
  return `[UNSUPPORTED: ${expr.raw}]`;
@@ -6536,6 +6745,20 @@ function stringifyParsedExpr(expr) {
6536
6745
  const { paramA, paramB, raw } = expr.comparator;
6537
6746
  return `${stringifyParsedExpr(expr.object)}.${expr.method}((${paramA},${paramB}) => ${raw})`;
6538
6747
  }
6748
+ if (expr.method === "reduce" || expr.method === "reduceRight") {
6749
+ const { paramAcc, paramItem, raw, type, init } = expr.reduceOp;
6750
+ const initSrc = type === "string" ? JSON.stringify(init) : init;
6751
+ return `${stringifyParsedExpr(expr.object)}.${expr.method}((${paramAcc},${paramItem}) => ${raw}, ${initSrc})`;
6752
+ }
6753
+ if (expr.method === "flat") {
6754
+ const d = expr.flatDepth;
6755
+ const depthSrc = d === "infinity" ? "Infinity" : String(d);
6756
+ return `${stringifyParsedExpr(expr.object)}.flat(${d === 1 ? "" : depthSrc})`;
6757
+ }
6758
+ if (expr.method === "flatMap") {
6759
+ const { param, raw } = expr.flatMapOp;
6760
+ return `${stringifyParsedExpr(expr.object)}.flatMap(${param} => ${raw})`;
6761
+ }
6539
6762
  return `${stringifyParsedExpr(expr.object)}.${expr.method}(${expr.args.map(stringifyParsedExpr).join(", ")})`;
6540
6763
  case "unsupported":
6541
6764
  return expr.raw;
@@ -10072,7 +10295,7 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
10072
10295
  }
10073
10296
  function decideLoopRendering(loop, siblingOffsets, ctx) {
10074
10297
  const hasNestedComps = (loop.nestedComponents?.length ?? 0) > 0;
10075
- const innerLoops = !loop.childComponent ? collectInnerLoops(loop.children, siblingOffsets, loop.param, ctx) : undefined;
10298
+ const innerLoops = collectInnerLoops(loop.children, siblingOffsets, loop.param, ctx);
10076
10299
  const hasInnerLoops = (innerLoops?.length ?? 0) > 0;
10077
10300
  const useElementReconciliation = !loop.childComponent && !loop.isStaticArray && (hasNestedComps || hasInnerLoops);
10078
10301
  return { useElementReconciliation, innerLoops };
@@ -12888,7 +13111,7 @@ function buildStaticArrayChildInitsPlan(ctx) {
12888
13111
  const innerComps = elem.nestedComponents.filter((c) => (c.loopDepth ?? 0) === innerLoop.depth && c.innerLoopArray === innerLoop.array);
12889
13112
  if (innerComps.length === 0)
12890
13113
  continue;
12891
- plans.push(buildInnerLoopNestedPlan(elem, innerLoop, innerComps));
13114
+ plans.push(elem.childComponent ? buildComponentRootedInnerLoopPlan(elem, innerLoop, innerComps) : buildInnerLoopNestedPlan(elem, innerLoop, innerComps));
12892
13115
  }
12893
13116
  }
12894
13117
  }
@@ -12949,6 +13172,25 @@ function buildInnerLoopNestedPlan(elem, innerLoop, innerComps) {
12949
13172
  comps
12950
13173
  };
12951
13174
  }
13175
+ function buildComponentRootedInnerLoopPlan(elem, innerLoop, innerComps) {
13176
+ const comps = innerComps.map((comp) => ({
13177
+ componentName: comp.name,
13178
+ selector: buildCompSelector(comp),
13179
+ propsExpr: buildStaticPropsExpr(comp.props)
13180
+ }));
13181
+ return {
13182
+ kind: "component-rooted-inner-loop",
13183
+ containerVar: `_${varSlotId(elem.slotId)}`,
13184
+ outerArrayExpr: elem.array,
13185
+ outerParam: elem.param,
13186
+ outerPreludeStatements: elem.mapPreamble ? [elem.mapPreamble] : [],
13187
+ innerArrayExpr: innerLoop.array,
13188
+ innerParam: innerLoop.param,
13189
+ innerPreludeStatements: innerLoop.mapPreamble ? [innerLoop.mapPreamble] : [],
13190
+ depth: innerLoop.depth,
13191
+ comps
13192
+ };
13193
+ }
12952
13194
  function buildStaticPropsExpr(props) {
12953
13195
  const entries = props.map((p) => {
12954
13196
  if (p.isEventHandler) {
@@ -12988,6 +13230,9 @@ function stringifyOne(lines, plan) {
12988
13230
  case "inner-loop-nested":
12989
13231
  emitInnerLoopNested(lines, plan);
12990
13232
  break;
13233
+ case "component-rooted-inner-loop":
13234
+ emitComponentRootedInnerLoop(lines, plan);
13235
+ break;
12991
13236
  }
12992
13237
  }
12993
13238
  function emitSingleComp(lines, plan) {
@@ -13067,6 +13312,44 @@ function emitInnerLoopNested(lines, plan) {
13067
13312
  lines.push(` }`);
13068
13313
  lines.push("");
13069
13314
  }
13315
+ function emitComponentRootedInnerLoop(lines, plan) {
13316
+ const {
13317
+ containerVar,
13318
+ outerArrayExpr,
13319
+ outerParam,
13320
+ outerPreludeStatements,
13321
+ innerArrayExpr,
13322
+ innerParam,
13323
+ innerPreludeStatements,
13324
+ depth,
13325
+ comps
13326
+ } = plan;
13327
+ const scopesVar = (i) => comps.length > 1 ? `__compScopes${i}` : "__compScopes";
13328
+ const cursorVar = (i) => comps.length > 1 ? `__ci${i}` : "__ci";
13329
+ const compElVar = (i) => comps.length > 1 ? `__compEl${i}` : "__compEl";
13330
+ lines.push(` // Initialize component-rooted inner-loop components (depth ${depth})`);
13331
+ lines.push(` if (${containerVar}) {`);
13332
+ comps.forEach((comp, i) => {
13333
+ lines.push(` const ${scopesVar(i)} = qsaChildScopes(${containerVar}, ${comp.selector})`);
13334
+ lines.push(` let ${cursorVar(i)} = 0`);
13335
+ });
13336
+ lines.push(` ${outerArrayExpr}.forEach((${outerParam}) => {`);
13337
+ for (const stmt of outerPreludeStatements) {
13338
+ lines.push(` ${stmt}`);
13339
+ }
13340
+ lines.push(` ${innerArrayExpr}.forEach((${innerParam}) => {`);
13341
+ for (const stmt of innerPreludeStatements) {
13342
+ lines.push(` ${stmt}`);
13343
+ }
13344
+ comps.forEach((comp, i) => {
13345
+ lines.push(` const ${compElVar(i)} = ${scopesVar(i)}[${cursorVar(i)}++]`);
13346
+ lines.push(` if (${compElVar(i)}) initChild('${nameForRegistryRef(comp.componentName)}', ${compElVar(i)}, ${comp.propsExpr})`);
13347
+ });
13348
+ lines.push(` })`);
13349
+ lines.push(` })`);
13350
+ lines.push(` }`);
13351
+ lines.push("");
13352
+ }
13070
13353
 
13071
13354
  // src/ir-to-client-js/phases/static-array-child-inits.ts
13072
13355
  function emitStaticArrayChildInits(lines, ctx) {
@@ -17345,6 +17628,15 @@ function emitParsedExpr(expr, emitter) {
17345
17628
  if (expr.method === "sort" || expr.method === "toSorted") {
17346
17629
  return emitter.sortMethod(expr.method, expr.object, expr.comparator, emit);
17347
17630
  }
17631
+ if (expr.method === "reduce" || expr.method === "reduceRight") {
17632
+ return emitter.reduceMethod(expr.method, expr.object, expr.reduceOp, emit);
17633
+ }
17634
+ if (expr.method === "flat") {
17635
+ return emitter.flatMethod(expr.object, expr.flatDepth, emit);
17636
+ }
17637
+ if (expr.method === "flatMap") {
17638
+ return emitter.flatMapMethod(expr.object, expr.flatMapOp, emit);
17639
+ }
17348
17640
  return emitter.arrayMethod(expr.method, expr.object, expr.args, emit);
17349
17641
  case "unsupported":
17350
17642
  return emitter.unsupported(expr.raw, expr.reason);
@@ -1 +1 @@
1
- {"version":3,"file":"collect-elements.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/collect-elements.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAoC,KAAK,MAAM,EAAmC,MAAM,UAAU,CAAA;AACtH,OAAO,KAAK,EAAE,eAAe,EAA+H,iBAAiB,EAA0B,oBAAoB,EAAc,UAAU,EAAE,MAAM,SAAS,CAAA;AAwGpQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA0C7E;AAyBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,wBAIpC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,cAAc,CAAC,EAAE,MAAM,EACvB,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,wBAAwB,GACjC,UAAU,EAAE,CAyId;AA+JD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,iBAAiB,UAAQ,GACxB,IAAI,CAsON;AA6VD;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,SAAS,OAAO,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAC5E,iBAAiB,CAUnB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,SAAS,OAAO,UAAU,EAAE,gBAAgB,EAAE,GACjE,oBAAoB,EAAE,CA4DxB"}
1
+ {"version":3,"file":"collect-elements.d.ts","sourceRoot":"","sources":["../../src/ir-to-client-js/collect-elements.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAoC,KAAK,MAAM,EAAmC,MAAM,UAAU,CAAA;AACtH,OAAO,KAAK,EAAE,eAAe,EAA+H,iBAAiB,EAA0B,oBAAoB,EAAc,UAAU,EAAE,MAAM,SAAS,CAAA;AAwGpQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA0C7E;AAyBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,4DAA4D;AAC5D,eAAO,MAAM,sBAAsB,EAAE,wBAIpC,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,cAAc,CAAC,EAAE,MAAM,EACvB,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,CAAC,EAAE,wBAAwB,GACjC,UAAU,EAAE,CAyId;AAqKD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,iBAAiB,UAAQ,GACxB,IAAI,CAsON;AA6VD;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,SAAS,OAAO,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAC5E,iBAAiB,CAUnB;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,eAAe,EACpB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACrC,SAAS,CAAC,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE,SAAS,OAAO,UAAU,EAAE,gBAAgB,EAAE,GACjE,oBAAoB,EAAE,CA4DxB"}
@@ -8,6 +8,10 @@
8
8
  * 2. `outer-nested` for each depth-0 entry in `elem.nestedComponents`.
9
9
  * 3. `inner-loop-nested` for each `elem.innerLoops` entry that has
10
10
  * matching depth-N components.
11
+ * 4. `component-rooted-inner-loop` instead of (3) when the outer item is
12
+ * itself a child component (#1725) — the inner `.map()` lives inside
13
+ * the component's JSX children, so it's addressed by a document-order
14
+ * zip rather than element offsets.
11
15
  *
12
16
  * Selector / propsExpr / offset decisions all resolve here. The
13
17
  * stringifier never inspects raw IR.
@@ -1 +1 @@
1
- {"version":3,"file":"build-static-array-child-init.d.ts","sourceRoot":"","sources":["../../../src/ir-to-client-js/plan/build-static-array-child-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAO/C,OAAO,KAAK,EAOV,yBAAyB,EAC1B,MAAM,2BAA2B,CAAA;AAElC,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,eAAe,GACnB,yBAAyB,CA6B3B"}
1
+ {"version":3,"file":"build-static-array-child-init.d.ts","sourceRoot":"","sources":["../../../src/ir-to-client-js/plan/build-static-array-child-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAO/C,OAAO,KAAK,EAQV,yBAAyB,EAC1B,MAAM,2BAA2B,CAAA;AAElC,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,eAAe,GACnB,yBAAyB,CAsC3B"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Plan types for `emitStaticArrayChildInits` — the three shapes that
2
+ * Plan types for `emitStaticArrayChildInits` — the shapes that
3
3
  * `static array` loops emit for child component initialisation:
4
4
  *
5
5
  * - `single-comp` — `loop.childComponent` ケース。一つの child component
@@ -8,6 +8,13 @@
8
8
  * `__iterEl.querySelector(...)` 経由で initChild。
9
9
  * - `inner-loop-nested` — depth > 0 の `nestedComponents`。outer + inner
10
10
  * forEach の二重ループで initChild。
11
+ * - `component-rooted-inner-loop`
12
+ * — outer の loop item root が **child component**
13
+ * (`loop.childComponent`) で、その JSX children に
14
+ * component の nested `.map()` を持つケース (#1725)。
15
+ * element offset では fragment-root passthrough の
16
+ * flatten 済み items に届かないため、document order
17
+ * の zip (`qsaChildScopes` + cursor) で initChild。
11
18
  *
12
19
  * All decisions (selector, propsExpr, offset expressions) are resolved at
13
20
  * build time so the stringifier becomes a deterministic walk.
@@ -122,6 +129,43 @@ export interface InnerLoopNestedInitPlan {
122
129
  /** Per-component initialisers emitted inside the inner forEach body. */
123
130
  comps: readonly InnerLoopComp[];
124
131
  }
125
- export type StaticArrayChildInitPlan = SingleCompInitPlan | OuterNestedInitPlan | InnerLoopNestedInitPlan;
132
+ /**
133
+ * Plan for an inner `.map()` of components living inside a **component-rooted**
134
+ * outer loop item (#1725). The outer loop body is a single child component
135
+ * (`loop.childComponent`, e.g. a `SelectGroup` passthrough) whose JSX
136
+ * `children` contain a nested `.map()` of components (e.g. `SelectItem`).
137
+ *
138
+ * `inner-loop-nested` can't be reused here: it addresses inner components via
139
+ * `containerVar.children[outerOffset]`, which assumes the outer loop item is a
140
+ * DOM **element**. A fragment-rooted passthrough component (`<>{children}</>`)
141
+ * emits no wrapper element, so its rendered items are flattened directly under
142
+ * the parent container with no per-group element to index.
143
+ *
144
+ * Instead this shape zips the inner component scopes — found in document order
145
+ * via `qsaChildScopes(container, <selector>)` — against the flattened
146
+ * `outer.forEach(o => inner.forEach(i => ...))` iteration. Document order is
147
+ * the SSR render order, so position `__ci++` pairs each scope with its data
148
+ * item regardless of whether the outer component root is an element or a
149
+ * fragment.
150
+ */
151
+ export interface ComponentRootedInnerLoopInitPlan {
152
+ kind: 'component-rooted-inner-loop';
153
+ containerVar: string;
154
+ /** Outer loop's array expression. */
155
+ outerArrayExpr: string;
156
+ outerParam: string;
157
+ /** Outer `.map()` callback preamble locals (#1064). */
158
+ outerPreludeStatements: PreludeStatements;
159
+ /** Inner loop's array expression (references the outer param). */
160
+ innerArrayExpr: string;
161
+ innerParam: string;
162
+ /** Inner `.map()` callback preamble locals (#1064). */
163
+ innerPreludeStatements: PreludeStatements;
164
+ /** Depth used in the leading comment line. */
165
+ depth: number;
166
+ /** Per-component initialisers emitted inside the inner forEach body. */
167
+ comps: readonly InnerLoopComp[];
168
+ }
169
+ export type StaticArrayChildInitPlan = SingleCompInitPlan | OuterNestedInitPlan | InnerLoopNestedInitPlan | ComponentRootedInnerLoopInitPlan;
126
170
  export type StaticArrayChildInitsPlan = readonly StaticArrayChildInitPlan[];
127
171
  //# sourceMappingURL=static-array-child-init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"static-array-child-init.d.ts","sourceRoot":"","sources":["../../../src/ir-to-client-js/plan/static-array-child-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AAExE,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAA;AAE9B,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,aAAa,CAAA;IACnB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAA;IACrB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAA;IACjB,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,sBAAsB,EAAE,iBAAiB,CAAA;IACzC,iEAAiE;IACjE,SAAS,EAAE,SAAS,CAAA;CACrB;AAED,qEAAqE;AACrE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,cAAc,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,+FAA+F;IAC/F,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,sBAAsB,EAAE,iBAAiB,CAAA;IACzC,SAAS,EAAE,SAAS,CAAA;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,mBAAmB,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,sBAAsB,EAAE,iBAAiB,CAAA;IACzC;;;;OAIG;IACH,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,iEAAiE;IACjE,eAAe,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,sBAAsB,EAAE,iBAAiB,CAAA;IACzC,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAA;IACb,wEAAwE;IACxE,KAAK,EAAE,SAAS,aAAa,EAAE,CAAA;CAChC;AAED,MAAM,MAAM,wBAAwB,GAChC,kBAAkB,GAClB,mBAAmB,GACnB,uBAAuB,CAAA;AAE3B,MAAM,MAAM,yBAAyB,GAAG,SAAS,wBAAwB,EAAE,CAAA"}
1
+ {"version":3,"file":"static-array-child-init.d.ts","sourceRoot":"","sources":["../../../src/ir-to-client-js/plan/static-array-child-init.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"static-array-child-init.d.ts","sourceRoot":"","sources":["../../../src/ir-to-client-js/stringify/static-array-child-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EAKV,yBAAyB,EAC1B,MAAM,iCAAiC,CAAA;AAGxC,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,yBAAyB,GAC/B,IAAI,CAIN"}
1
+ {"version":3,"file":"static-array-child-init.d.ts","sourceRoot":"","sources":["../../../src/ir-to-client-js/stringify/static-array-child-init.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EAMV,yBAAyB,EAC1B,MAAM,iCAAiC,CAAA;AAGxC,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,yBAAyB,GAC/B,IAAI,CAIN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/jsx",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "JSX compiler for BarefootJS - transforms JSX to server HTML + client JS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,7 +53,7 @@
53
53
  "directory": "packages/jsx"
54
54
  },
55
55
  "dependencies": {
56
- "@barefootjs/shared": "0.6.0"
56
+ "@barefootjs/shared": "0.6.1"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@barefootjs/client": ">=0.2.0",
@@ -1181,4 +1181,88 @@ describe('child components inside .map() (#344)', () => {
1181
1181
  expect(content).toContain('const __compEl =')
1182
1182
  expect(content).not.toContain('__compEl0')
1183
1183
  })
1184
+
1185
+ describe('nested .map() inside a component-rooted loop item (#1725)', () => {
1186
+ // The outer loop item root is a *component* (a passthrough wrapper like
1187
+ // `SelectGroup`), not an element. Its JSX children contain a nested
1188
+ // `.map()` of components. The parent init emitted `initChild` for the
1189
+ // outer wrapper but never descended into its children to init the inner
1190
+ // loop's components — they rendered from SSR but never hydrated (silent).
1191
+ test('emits initChild for the inner-loop component (component wrapper)', () => {
1192
+ const source = `
1193
+ 'use client'
1194
+
1195
+ export function Repro() {
1196
+ const GROUPS = [
1197
+ { id: 'a', items: [{ id: 'a1', label: 'A1' }] },
1198
+ { id: 'b', items: [{ id: 'b1', label: 'B1' }] },
1199
+ ]
1200
+ return (
1201
+ <div>
1202
+ {GROUPS.map(group => (
1203
+ <Group key={group.id}>
1204
+ {group.items.map(it => (
1205
+ <Item key={it.id} label={it.label} />
1206
+ ))}
1207
+ </Group>
1208
+ ))}
1209
+ </div>
1210
+ )
1211
+ }
1212
+ `
1213
+ const result = compileJSX(source, 'Repro.tsx', { adapter })
1214
+ expect(result.errors).toHaveLength(0)
1215
+
1216
+ const content = result.files.find(f => f.type === 'clientJs')!.content
1217
+ // Both the outer wrapper and the inner-loop component must init.
1218
+ expect(content).toContain("initChild('Group'")
1219
+ expect(content).toContain("initChild('Item'")
1220
+ // The inner component's props read the inner loop param.
1221
+ expect(content).toContain('return it.label')
1222
+ // Document-order zip shape — a flat cursor over the queried scopes
1223
+ // pairs each with its data item across the nested forEach. This shape
1224
+ // is fragment-root safe (no per-group wrapper element to index).
1225
+ expect(content).toContain('qsaChildScopes')
1226
+ expect(content).toMatch(/__compScopes\[__ci\+\+\]/)
1227
+ // No element-offset addressing (`__outerEl = ...children[...]`) — that
1228
+ // would break for a fragment-rooted passthrough.
1229
+ expect(content).not.toContain('__outerEl')
1230
+ })
1231
+
1232
+ test('multiple inner components each get their own document-order cursor', () => {
1233
+ const source = `
1234
+ 'use client'
1235
+
1236
+ export function Repro() {
1237
+ const GROUPS = [{ id: 'a', items: [{ id: 'a1', label: 'A1' }] }]
1238
+ return (
1239
+ <div>
1240
+ {GROUPS.map(group => (
1241
+ <Group key={group.id}>
1242
+ {group.items.map(it => (
1243
+ <>
1244
+ <Item key={it.id} label={it.label} />
1245
+ <Badge text={it.label} />
1246
+ </>
1247
+ ))}
1248
+ </Group>
1249
+ ))}
1250
+ </div>
1251
+ )
1252
+ }
1253
+ `
1254
+ const result = compileJSX(source, 'Repro.tsx', { adapter })
1255
+ expect(result.errors).toHaveLength(0)
1256
+
1257
+ const content = result.files.find(f => f.type === 'clientJs')!.content
1258
+ expect(content).toContain("initChild('Item'")
1259
+ expect(content).toContain("initChild('Badge'")
1260
+ // Distinct scope arrays + cursors so each comp consumes its own
1261
+ // document-order stream (no `const __compEl` redeclaration, #1664).
1262
+ expect(content).toContain('__compScopes0')
1263
+ expect(content).toContain('__compScopes1')
1264
+ expect(content).toMatch(/__ci0\+\+/)
1265
+ expect(content).toMatch(/__ci1\+\+/)
1266
+ })
1267
+ })
1184
1268
  })