@barefootjs/vite 0.33.3 → 0.33.4

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 +100 -17
  2. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -3233,6 +3233,9 @@ function renderTemplateAttrPart(attr, attrName, wrap, restSpreadNames) {
3233
3233
  return "";
3234
3234
  }
3235
3235
  }
3236
+ function resolvedKeyAttrName(node, loopDepth) {
3237
+ return node.keyAttr ? keyAttrName2(loopDepth) : null;
3238
+ }
3236
3239
  function isMergeableAttr(a, ctx) {
3237
3240
  if (ctx.honorClientOnly && a.clientOnly)
3238
3241
  return false;
@@ -3409,8 +3412,11 @@ function irToHtmlTemplate(node, restSpreadNames, loopDepth = 0, loopParams, bran
3409
3412
  if (useMerge && isMergeableAttr(a, mergeCtx)) {
3410
3413
  return idx === firstMergeableIdx ? mergeCall : "";
3411
3414
  }
3412
- const attrName = a.name === "..." ? "..." : a.name === "key" ? keyAttrName2(loopDepth) : toHTMLAttrName(a.name);
3413
- return renderTemplateAttrPart(a, attrName, wrapExpr, restSpreadNames);
3415
+ if (a.name === "key") {
3416
+ const attrName = resolvedKeyAttrName(node, loopDepth);
3417
+ return attrName ? renderTemplateAttrPart(a, attrName, wrapExpr, restSpreadNames) : "";
3418
+ }
3419
+ return renderTemplateAttrPart(a, toHTMLAttrName(a.name), wrapExpr, restSpreadNames);
3414
3420
  }).filter(Boolean);
3415
3421
  const hoistedScopeAttr = maybeHoistedScopeAttr(inHoistedChildren, node);
3416
3422
  if (hoistedScopeAttr)
@@ -3535,7 +3541,9 @@ function buildLoopSkeletonTemplate(node, safe) {
3535
3541
  if (a.name === "dangerouslySetInnerHTML")
3536
3542
  return null;
3537
3543
  if (a.name === "key") {
3538
- attrParts.push(`${keyAttrName2(0)}=""`);
3544
+ if (resolvedKeyAttrName(node, 0)) {
3545
+ attrParts.push(`${keyAttrName2(0)}=""`);
3546
+ }
3539
3547
  continue;
3540
3548
  }
3541
3549
  const v = a.value;
@@ -3743,7 +3751,11 @@ function irToPlaceholderTemplate(node, restSpreadNames, loopDepth = 0, loopParam
3743
3751
  const attrParts = node.attrs.map((a) => {
3744
3752
  if (a.clientOnly)
3745
3753
  return "";
3746
- const attrName = a.name === "..." ? "..." : a.name === "key" ? keyAttrName2(loopDepth) : toHTMLAttrName(a.name);
3754
+ if (a.name === "key") {
3755
+ const attrName2 = resolvedKeyAttrName(node, loopDepth);
3756
+ return attrName2 ? renderTemplateAttrPart(a, attrName2, wrapExpr, restSpreadNames) : "";
3757
+ }
3758
+ const attrName = a.name === "..." ? "..." : toHTMLAttrName(a.name);
3747
3759
  return renderTemplateAttrPart(a, attrName, wrapExpr, restSpreadNames);
3748
3760
  }).filter(Boolean);
3749
3761
  if (node.slotId) {
@@ -4292,7 +4304,27 @@ function generateCsrTemplateWithOpts(node, opts) {
4292
4304
  return "";
4293
4305
  return `\${spreadAttrs(${transformExpr(v.expr, v.templateExpr)})}`;
4294
4306
  }
4295
- const attrName = a.name === "key" ? keyAttrName2(loopDepth) : toHTMLAttrName(a.name);
4307
+ if (a.name === "key") {
4308
+ const keyName = resolvedKeyAttrName(node, loopDepth);
4309
+ if (!keyName)
4310
+ return "";
4311
+ switch (v.kind) {
4312
+ case "boolean-attr":
4313
+ return keyName;
4314
+ case "literal":
4315
+ return `${keyName}="${escapeHtml(v.value)}"`;
4316
+ case "expression":
4317
+ return templateAttrExpr(keyName, transformExpr(v.expr, v.templateExpr), v.presenceOrUndefined);
4318
+ case "template": {
4319
+ const valueStr = attrValueToString(v, { useTemplate: true });
4320
+ return valueStr ? templateAttrExpr(keyName, transformExpr(valueStr)) : "";
4321
+ }
4322
+ case "boolean-shorthand":
4323
+ case "jsx-children":
4324
+ return "";
4325
+ }
4326
+ }
4327
+ const attrName = toHTMLAttrName(a.name);
4296
4328
  switch (v.kind) {
4297
4329
  case "boolean-attr":
4298
4330
  return attrName;
@@ -11687,6 +11719,10 @@ function extractLoopKey(node) {
11687
11719
  return null;
11688
11720
  return normalizeKeyExpr(a) === normalizeKeyExpr(b) ? a : null;
11689
11721
  }
11722
+ if (node.type === "fragment") {
11723
+ const first = node.children.find((c) => !(c.type === "text" && typeof c.value === "string" && !c.value.trim()));
11724
+ return first ? extractLoopKey(first) : null;
11725
+ }
11690
11726
  return null;
11691
11727
  }
11692
11728
  function keyAttrValueToExpr(v) {
@@ -11877,7 +11913,7 @@ function leafIsWirelessElement(el) {
11877
11913
  }
11878
11914
  if (ts13.isJsxAttribute(attr)) {
11879
11915
  const name = attr.name.getText();
11880
- if (/^on[A-Z]/.test(name)) {
11916
+ if (isEventHandlerAttrName(name)) {
11881
11917
  ok = false;
11882
11918
  return;
11883
11919
  }
@@ -11933,6 +11969,12 @@ function applyLoopKeyAttr(node, name, value) {
11933
11969
  if (node.type === "conditional") {
11934
11970
  applyLoopKeyAttr(node.whenTrue, name, value);
11935
11971
  applyLoopKeyAttr(node.whenFalse, name, value);
11972
+ return;
11973
+ }
11974
+ if (node.type === "fragment") {
11975
+ const first = node.children.find((c) => !(c.type === "text" && typeof c.value === "string" && !c.value.trim()));
11976
+ if (first)
11977
+ applyLoopKeyAttr(first, name, value);
11936
11978
  }
11937
11979
  }
11938
11980
  function loopBodyItemConditional(children) {
@@ -12165,7 +12207,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
12165
12207
  children = [foldMultiReturnBranches(multiReturn, ctx, loc, ctx.getJS)];
12166
12208
  const pre = multiReturn.preamble ?? [];
12167
12209
  if (pre.length > 0) {
12168
- preamble = preambleFromValueStatements(pre, ctx);
12210
+ preamble = preambleFromValueStatements(pre, ctx, body.statements);
12169
12211
  if (!preamble.declarations && !isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
12170
12212
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, loc, {
12171
12213
  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.",
@@ -12252,7 +12294,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
12252
12294
  valueStmts.push(stmt);
12253
12295
  }
12254
12296
  if (valueStmts.length > 0) {
12255
- preamble = preambleFromValueStatements(valueStmts, ctx);
12297
+ preamble = preambleFromValueStatements(valueStmts, ctx, body.statements);
12256
12298
  if (!preamble.declarations && !isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
12257
12299
  ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(body, ctx.sourceFile, ctx.filePath), {
12258
12300
  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.",
@@ -12318,11 +12360,11 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
12318
12360
  const bodyIsItemConditional = itemConditional !== null;
12319
12361
  const key = bodyIsItemConditional ? extractItemConditionalKey(itemConditional) : children.length > 0 ? extractLoopKey(children[0]) : null;
12320
12362
  if (key !== null) {
12321
- const resolvedKeyAttrName = keyAttrName(depth);
12363
+ const resolvedKeyAttrName2 = keyAttrName(depth);
12322
12364
  if (bodyIsItemConditional) {
12323
- applyLoopKeyAttr(itemConditional, resolvedKeyAttrName, key);
12365
+ applyLoopKeyAttr(itemConditional, resolvedKeyAttrName2, key);
12324
12366
  } else if (children.length > 0) {
12325
- applyLoopKeyAttr(children[0], resolvedKeyAttrName, key);
12367
+ applyLoopKeyAttr(children[0], resolvedKeyAttrName2, key);
12326
12368
  }
12327
12369
  }
12328
12370
  const declaredNameSet = preamble && preamble.declaredNames.length > 0 ? new Set(preamble.declaredNames) : undefined;
@@ -12715,7 +12757,7 @@ function computePreambleReactiveNames(statements, ctx) {
12715
12757
  }
12716
12758
  return reactiveNames;
12717
12759
  }
12718
- function preambleFromValueStatements(statements, ctx) {
12760
+ function preambleFromValueStatements(statements, ctx, bodyStatements) {
12719
12761
  const segments = [];
12720
12762
  const typedParts = [];
12721
12763
  const declared = new Set;
@@ -12735,11 +12777,11 @@ function preambleFromValueStatements(statements, ctx) {
12735
12777
  ssrText: tsxSourceText(typedParts.join(" ")),
12736
12778
  declaredNames: [...declared],
12737
12779
  builderNames: [],
12738
- declarations: neutralPreambleDeclarations(statements, ctx) ?? undefined,
12780
+ declarations: neutralPreambleDeclarations(statements, ctx, bodyStatements) ?? undefined,
12739
12781
  reactiveNames: reactiveNames.size > 0 ? [...reactiveNames] : undefined
12740
12782
  };
12741
12783
  }
12742
- function neutralPreambleDeclarations(statements, ctx) {
12784
+ function neutralPreambleDeclarations(statements, ctx, bodyStatements) {
12743
12785
  const out = [];
12744
12786
  for (const stmt of statements) {
12745
12787
  if (!ts13.isVariableStatement(stmt))
@@ -12749,6 +12791,11 @@ function neutralPreambleDeclarations(statements, ctx) {
12749
12791
  return null;
12750
12792
  if (!decl.initializer)
12751
12793
  return null;
12794
+ if (isFunctionLiteral(decl.initializer)) {
12795
+ if (everyReadIsEventHandlerPropValue(decl.name.text, bodyStatements))
12796
+ continue;
12797
+ return null;
12798
+ }
12752
12799
  const valueParsed = tsNodeToParsedExpr(decl.initializer);
12753
12800
  if (!isSupported(valueParsed).supported)
12754
12801
  return null;
@@ -12759,7 +12806,30 @@ function neutralPreambleDeclarations(statements, ctx) {
12759
12806
  });
12760
12807
  }
12761
12808
  }
12762
- return out.length > 0 ? out : null;
12809
+ return out;
12810
+ }
12811
+ function isFunctionLiteral(node) {
12812
+ return ts13.isArrowFunction(node) || ts13.isFunctionExpression(node);
12813
+ }
12814
+ function everyReadIsEventHandlerPropValue(name, bodyStatements) {
12815
+ const findDisallowedRead = (node) => {
12816
+ if (ts13.isIdentifier(node) && node.text === name) {
12817
+ const isBindingName = ts13.isVariableDeclaration(node.parent) && node.parent.name === node;
12818
+ const isPropertyName = ts13.isPropertyAccessExpression(node.parent) && node.parent.name === node;
12819
+ if (!isBindingName && !isPropertyName) {
12820
+ const jsxExpr = node.parent;
12821
+ const attr = jsxExpr.parent;
12822
+ const isEventHandlerAttrValue = ts13.isJsxExpression(jsxExpr) && ts13.isJsxAttribute(attr) && attr.initializer === jsxExpr && ts13.isIdentifier(attr.name) && isEventHandlerAttrName(attr.name.text);
12823
+ if (!isEventHandlerAttrValue)
12824
+ return true;
12825
+ }
12826
+ }
12827
+ return ts13.forEachChild(node, findDisallowedRead);
12828
+ };
12829
+ return !bodyStatements.some(findDisallowedRead);
12830
+ }
12831
+ function isEventHandlerAttrName(name) {
12832
+ return /^on[A-Z]/.test(name);
12763
12833
  }
12764
12834
  function trimPreambleSegments(segments) {
12765
12835
  const last = segments[segments.length - 1];
@@ -12956,7 +13026,7 @@ function processAttributes(attributes, ctx) {
12956
13026
  }
12957
13027
  continue;
12958
13028
  }
12959
- if (/^on[A-Z]/.test(rawName)) {
13029
+ if (isEventHandlerAttrName(rawName)) {
12960
13030
  if (attr.initializer && ts13.isJsxExpression(attr.initializer) && attr.initializer.expression) {
12961
13031
  const eventName = rawName.slice(2).toLowerCase();
12962
13032
  reportJsxBranchLocalInCallback(attr.initializer.expression, ctx);
@@ -15611,6 +15681,8 @@ function buildReferencesGraph(ctx, irRoot) {
15611
15681
  }
15612
15682
  for (const ev of el.events)
15613
15683
  addExprEdges(ROOT_SOURCE, ev.handler, "init-body");
15684
+ if (el.ref)
15685
+ addExprEdges(ROOT_SOURCE, el.ref, "init-body");
15614
15686
  descend();
15615
15687
  },
15616
15688
  component: ({ node: c, descend, descendJsxChildren }) => {
@@ -20519,12 +20591,15 @@ function stringifyComponentLoop(lines, plan) {
20519
20591
  keyExpr,
20520
20592
  nestedComps,
20521
20593
  childConditionalEffects,
20522
- profileLoopId
20594
+ profileLoopId,
20595
+ mapPreambleWrapped
20523
20596
  } = plan;
20524
20597
  const loopBfId = profileLoopId ? `, ${JSON.stringify(profileLoopId)}` : "";
20525
20598
  lines.push(` mapArray(() => ${arrayExpr}, ${containerVar}, ${keyFn}, (${paramHead}, ${indexParam}, __existing) => {`);
20526
20599
  if (paramUnwrap)
20527
20600
  lines.push(` ${paramUnwrap}`);
20601
+ if (mapPreambleWrapped)
20602
+ lines.push(` ${mapPreambleWrapped}`);
20528
20603
  const scopedComp = nameForRegistryRef(componentName);
20529
20604
  if (nestedComps.length === 0) {
20530
20605
  lines.push(` if (__existing) { initChild('${scopedComp}', __existing, ${componentPropsExpr}); return __existing }`);
@@ -21640,6 +21715,12 @@ function buildComponentLoopPlan(elem, profileComponentName) {
21640
21715
  const propsExpr = buildComponentPropsExpr2(elem.childComponent, elem.param);
21641
21716
  const keyExpr = wrapLoopParamAsAccessor(elem.key || "__idx", elem.param, elem.paramBindings);
21642
21717
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(elem.param, elem.paramBindings);
21718
+ const mapPreambleWrapped = elem.preamble ? renderPreamble(elem.preamble, {
21719
+ transformJs: (text) => wrapLoopParamAsAccessor(text, elem.param, elem.paramBindings),
21720
+ renderLeaf: () => {
21721
+ internalInvariant(false, "component-root loop received a JSX-bearing preamble — Phase 1 should have refused it");
21722
+ }
21723
+ }) : "";
21643
21724
  const outerNestedComps = (elem.nestedComponents ?? []).filter((c) => !c.loopDepth);
21644
21725
  const nestedComps = outerNestedComps.map((comp) => {
21645
21726
  const isTextOnly = comp.children?.length ? comp.children.every((c) => c.type === "expression" || c.type === "text" || isTextOnlyConditional(c)) : false;
@@ -21657,6 +21738,7 @@ function buildComponentLoopPlan(elem, profileComponentName) {
21657
21738
  return {
21658
21739
  kind: "component",
21659
21740
  rowConstruction: "dom-ops",
21741
+ mapPreambleWrapped,
21660
21742
  containerVar: `_${varSlotId(elem.slotId)}`,
21661
21743
  markerId: elem.markerId,
21662
21744
  arrayExpr: buildChainedArrayExpr(elem),
@@ -21839,6 +21921,7 @@ function emitLoopUpdates(lines, ctx, unsafeLocalNames) {
21839
21921
  lazyScope
21840
21922
  });
21841
21923
  internalInvariant(!(elem.preamble && elem.preamble.builderNames.length > 0 && plan.rowConstruction === "dom-ops"), `loop variant '${plan.kind}' declares dom-ops row construction but received a JSX-bearing preamble — add a Phase-1 refusal (or wire renderPreamble support) for this shape`);
21924
+ internalInvariant(!(elem.preamble && elem.preamble.declaredNames.length > 0 && ("mapPreambleWrapped" in plan) && plan.mapPreambleWrapped === ""), `loop variant '${plan.kind}' has a preamble with declared names (${elem.preamble?.declaredNames.join(", ")}) but its plan's mapPreambleWrapped is empty — wire it up or the emitted call site references a name nothing declares`);
21842
21925
  stringifyLoop(lines, plan);
21843
21926
  emitLoopEventDelegation(lines, elem, plan.kind, ctx.profile ? ctx.componentName : undefined);
21844
21927
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/vite",
3
- "version": "0.33.3",
3
+ "version": "0.33.4",
4
4
  "description": "Vite plugin for BarefootJS: Vite/Rollup owns bundling, hashing, chunking, tree-shaking and minification of client assets, BarefootJS keeps only the JSX to (template, client JS) compile",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,17 +38,17 @@
38
38
  "directory": "packages/vite"
39
39
  },
40
40
  "dependencies": {
41
- "@barefootjs/shared": "0.33.3"
41
+ "@barefootjs/shared": "0.33.4"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@barefootjs/jsx": ">=0.2.0",
45
45
  "vite": "^6.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@barefootjs/client": "0.33.3",
49
- "@barefootjs/go-template": "0.33.3",
50
- "@barefootjs/hono": "0.33.3",
51
- "@barefootjs/jsx": "0.33.3",
48
+ "@barefootjs/client": "0.33.4",
49
+ "@barefootjs/go-template": "0.33.4",
50
+ "@barefootjs/hono": "0.33.4",
51
+ "@barefootjs/jsx": "0.33.4",
52
52
  "typescript": "^5.0.0",
53
53
  "vite": "^6.0.0"
54
54
  }