@barefootjs/test 0.13.0 → 0.15.0

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 +159 -9
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -187487,6 +187487,18 @@ var SVG_XML_CAMEL_ATTRS = new Set([
187487
187487
  ]);
187488
187488
  // ../jsx/src/ir-to-client-js/utils.ts
187489
187489
  var PROPS_PARAM = "_p";
187490
+ // ../jsx/src/ir-to-client-js/component-scope.ts
187491
+ function computeFileScope(entryPath) {
187492
+ let h = 2166136261;
187493
+ for (let i2 = 0;i2 < entryPath.length; i2++) {
187494
+ h ^= entryPath.charCodeAt(i2);
187495
+ h = Math.imul(h, 16777619);
187496
+ }
187497
+ h ^= h >>> 13;
187498
+ h = Math.imul(h, 1540483477);
187499
+ return (h >>> 0).toString(16).padStart(8, "0");
187500
+ }
187501
+
187490
187502
  // ../jsx/src/ir-to-client-js/csr-substitute.ts
187491
187503
  var import_typescript3 = __toESM(require_typescript(), 1);
187492
187504
 
@@ -187995,6 +188007,7 @@ var ErrorCodes = {
187995
188007
  JSX_BRANCH_LOCAL_IN_CALLBACK: "BF047",
187996
188008
  SHARED_PROGRAM_REQUIRED: "BF050",
187997
188009
  WRONG_PACKAGE_IMPORT: "BF051",
188010
+ BUILTIN_REQUIRES_IMPORT: "BF054",
187998
188011
  UNDECLARED_INIT_STATEMENT_REFERENCE: "BF052",
187999
188012
  STRIPPED_CLIENT_IMPORT_REFERENCED: "BF053",
188000
188013
  STAGE_REACTIVE_IN_TEMPLATE: "BF060",
@@ -188018,6 +188031,7 @@ var errorMessages = {
188018
188031
  [ErrorCodes.JSX_BRANCH_LOCAL_IN_CALLBACK]: "JSX-typed local declared inside an `if`-block cannot be referenced from a callback body (ref / event handler). " + "Render it as a child instead: `<div ref={...}>{local}</div>`.",
188019
188032
  [ErrorCodes.SHARED_PROGRAM_REQUIRED]: "Shared ts.Program required for type-based reactivity classification. This source imports a Reactive<T>-branded library (e.g. @barefootjs/form) whose getters cannot be classified by regex alone. Pass `options.program` (built via `createProgramForCorpus`) so the analyzer can resolve the brand through the TypeChecker.",
188020
188033
  [ErrorCodes.WRONG_PACKAGE_IMPORT]: "Import from wrong package.",
188034
+ [ErrorCodes.BUILTIN_REQUIRES_IMPORT]: "Built-in <Async> / <Region> must be imported from '@barefootjs/client'. " + "The compiler recognises these tags by their import (not by tag name), " + "so an unimported tag with this name is treated as an undeclared component.",
188021
188035
  [ErrorCodes.UNDECLARED_INIT_STATEMENT_REFERENCE]: "Init statement references an undeclared identifier. Declare it at module scope, inside the component, or import it — otherwise ESM strict mode throws ReferenceError at runtime.",
188022
188036
  [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.",
188023
188037
  [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.",
@@ -188976,7 +188990,10 @@ var CLIENT_EXPORTS = new Set([
188976
188990
  "createPortal",
188977
188991
  "isSSRPortal",
188978
188992
  "findSiblingSlot",
188979
- "cleanupPortalPlaceholder"
188993
+ "cleanupPortalPlaceholder",
188994
+ "searchParams",
188995
+ "Async",
188996
+ "Region"
188980
188997
  ]);
188981
188998
  function collectAmbientGlobals(node, ctx) {
188982
188999
  if (import_typescript7.default.isVariableStatement(node)) {
@@ -189052,7 +189069,8 @@ function collectImport(node, ctx) {
189052
189069
  name: element.propertyName?.text ?? element.name.text,
189053
189070
  alias: element.propertyName ? element.name.text : null,
189054
189071
  isDefault: false,
189055
- isNamespace: false
189072
+ isNamespace: false,
189073
+ isTypeOnly: element.isTypeOnly
189056
189074
  });
189057
189075
  }
189058
189076
  }
@@ -190603,6 +190621,9 @@ function convertNode(node, raw) {
190603
190621
  if (callee.property === "trim") {
190604
190622
  return { kind: "array-method", method: "trim", object: callee.object, args };
190605
190623
  }
190624
+ if (callee.property === "toFixed") {
190625
+ return { kind: "array-method", method: "toFixed", object: callee.object, args };
190626
+ }
190606
190627
  if (callee.property === "split") {
190607
190628
  return { kind: "array-method", method: "split", object: callee.object, args };
190608
190629
  }
@@ -190736,13 +190757,19 @@ function convertNode(node, raw) {
190736
190757
  if (import_typescript8.default.isElementAccessExpression(node)) {
190737
190758
  const object = convertNode(node.expression, raw);
190738
190759
  const argNode = node.argumentExpression;
190760
+ if (!argNode) {
190761
+ return { kind: "unsupported", raw, reason: "Element access with no index expression" };
190762
+ }
190739
190763
  if (import_typescript8.default.isNumericLiteral(argNode)) {
190740
190764
  return { kind: "member", object, property: argNode.text, computed: true };
190741
190765
  }
190742
190766
  if (import_typescript8.default.isStringLiteral(argNode)) {
190743
190767
  return { kind: "member", object, property: argNode.text, computed: true };
190744
190768
  }
190745
- return { kind: "unsupported", raw, reason: "Complex computed property access" };
190769
+ const index = convertNode(argNode, raw);
190770
+ if (index.kind === "unsupported")
190771
+ return index;
190772
+ return { kind: "index-access", object, index };
190746
190773
  }
190747
190774
  if (import_typescript8.default.isBinaryExpression(node)) {
190748
190775
  const left = convertNode(node.left, raw);
@@ -191218,6 +191245,8 @@ function findImpureDefaultNode(expr) {
191218
191245
  return null;
191219
191246
  case "member":
191220
191247
  return findImpureDefaultNode(expr.object);
191248
+ case "index-access":
191249
+ return findImpureDefaultNode(expr.object) ?? findImpureDefaultNode(expr.index);
191221
191250
  case "unary":
191222
191251
  return findImpureDefaultNode(expr.argument);
191223
191252
  case "binary":
@@ -191371,6 +191400,10 @@ function collectIdentifiers(expr, out) {
191371
191400
  case "member":
191372
191401
  collectIdentifiers(expr.object, out);
191373
191402
  return;
191403
+ case "index-access":
191404
+ collectIdentifiers(expr.object, out);
191405
+ collectIdentifiers(expr.index, out);
191406
+ return;
191374
191407
  case "binary":
191375
191408
  case "logical":
191376
191409
  collectIdentifiers(expr.left, out);
@@ -191437,6 +191470,8 @@ function substituteDestructuredFields(expr, fieldMap, syntheticParam, restName)
191437
191470
  };
191438
191471
  }
191439
191472
  return { kind: "member", object: walk(e.object), property: e.property, computed: e.computed };
191473
+ case "index-access":
191474
+ return { kind: "index-access", object: walk(e.object), index: walk(e.index) };
191440
191475
  case "binary":
191441
191476
  return { kind: "binary", op: e.op, left: walk(e.left), right: walk(e.right) };
191442
191477
  case "logical":
@@ -191615,6 +191650,15 @@ function checkSupport(expr) {
191615
191650
  }
191616
191651
  return { supported: true, level: "L2" };
191617
191652
  }
191653
+ case "index-access": {
191654
+ const objSupport = checkSupport(expr.object);
191655
+ if (!objSupport.supported)
191656
+ return objSupport;
191657
+ const indexSupport = checkSupport(expr.index);
191658
+ if (!indexSupport.supported)
191659
+ return indexSupport;
191660
+ return { supported: true, level: "L2" };
191661
+ }
191618
191662
  case "binary": {
191619
191663
  const leftSupport = checkSupport(expr.left);
191620
191664
  if (!leftSupport.supported)
@@ -191685,6 +191729,8 @@ function containsHigherOrder(expr) {
191685
191729
  return expr.args.some(containsHigherOrder) || containsHigherOrder(expr.callee);
191686
191730
  case "member":
191687
191731
  return containsHigherOrder(expr.object);
191732
+ case "index-access":
191733
+ return containsHigherOrder(expr.object) || containsHigherOrder(expr.index);
191688
191734
  case "binary":
191689
191735
  return containsHigherOrder(expr.left) || containsHigherOrder(expr.right);
191690
191736
  case "unary":
@@ -191780,6 +191826,12 @@ function parseIfBranch(branch, sourceFile, getJS) {
191780
191826
  return [parsed];
191781
191827
  }
191782
191828
 
191829
+ // ../jsx/src/builtins.ts
191830
+ var CLIENT_BUILTIN_SOURCE = "@barefootjs/client";
191831
+ function isClientBuiltinName(name) {
191832
+ return name === "Async" || name === "Region";
191833
+ }
191834
+
191783
191835
  // ../jsx/src/reactivity-checker.ts
191784
191836
  var import_typescript9 = __toESM(require_typescript(), 1);
191785
191837
  var REACTIVE_BRAND = "__reactive";
@@ -192218,6 +192270,7 @@ function createTransformContext(analyzer) {
192218
192270
  filePath: analyzer.filePath,
192219
192271
  slotIdCounter: 0,
192220
192272
  asyncIdCounter: 0,
192273
+ regionIdCounter: 0,
192221
192274
  loopMarkerCounter: 0,
192222
192275
  spreadIdCounter: 0,
192223
192276
  isRoot: true,
@@ -192405,14 +192458,72 @@ function transformNode(node, ctx) {
192405
192458
  }
192406
192459
  return null;
192407
192460
  }
192461
+ function clientBuiltinTags(ctx) {
192462
+ if (ctx._clientBuiltinTags)
192463
+ return ctx._clientBuiltinTags;
192464
+ const map = new Map;
192465
+ for (const imp of ctx.analyzer.imports) {
192466
+ if (imp.source !== CLIENT_BUILTIN_SOURCE || imp.isTypeOnly)
192467
+ continue;
192468
+ for (const spec of imp.specifiers) {
192469
+ if (spec.isDefault || spec.isNamespace || spec.isTypeOnly)
192470
+ continue;
192471
+ if (isClientBuiltinName(spec.name)) {
192472
+ map.set(spec.alias ?? spec.name, spec.name);
192473
+ }
192474
+ }
192475
+ }
192476
+ ctx._clientBuiltinTags = map;
192477
+ return map;
192478
+ }
192479
+ function isNameBound(ctx, name) {
192480
+ const a = ctx.analyzer;
192481
+ if (a.ambientGlobals.has(name))
192482
+ return true;
192483
+ if (a.localFunctions.some((f) => f.name === name))
192484
+ return true;
192485
+ if (a.localConstants.some((c) => c.name === name))
192486
+ return true;
192487
+ for (const imp of a.imports) {
192488
+ if (imp.isTypeOnly)
192489
+ continue;
192490
+ for (const spec of imp.specifiers) {
192491
+ if (spec.isTypeOnly)
192492
+ continue;
192493
+ if ((spec.alias ?? spec.name) === name)
192494
+ return true;
192495
+ }
192496
+ }
192497
+ return false;
192498
+ }
192499
+ function reportBuiltinNotImported(ctx, node, tagName) {
192500
+ ctx.analyzer.errors.push(createError(ErrorCodes.BUILTIN_REQUIRES_IMPORT, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
192501
+ severity: "error",
192502
+ message: `<${tagName}> must be imported from '${CLIENT_BUILTIN_SOURCE}' to be recognised as a compiler built-in.`,
192503
+ suggestion: {
192504
+ message: `Add: import { ${tagName} } from '${CLIENT_BUILTIN_SOURCE}'`
192505
+ }
192506
+ }));
192507
+ }
192508
+ function dispatchClientBuiltin(tagName, ctx, diagNode, transformAsync, transformRegion) {
192509
+ const builtin = clientBuiltinTags(ctx).get(tagName);
192510
+ if (builtin === "Async")
192511
+ return transformAsync();
192512
+ if (builtin === "Region")
192513
+ return transformRegion();
192514
+ if (isClientBuiltinName(tagName) && !isNameBound(ctx, tagName)) {
192515
+ reportBuiltinNotImported(ctx, diagNode, tagName);
192516
+ }
192517
+ return null;
192518
+ }
192408
192519
  function transformJsxElement(node, ctx) {
192409
192520
  const tagName = node.openingElement.tagName.getText(ctx.sourceFile);
192410
192521
  if (tagName.endsWith(".Provider") && /^[A-Z]/.test(tagName)) {
192411
192522
  return transformProviderElement(node, ctx, tagName);
192412
192523
  }
192413
- if (tagName === "Async") {
192414
- return transformAsyncElement(node, ctx);
192415
- }
192524
+ const builtin = dispatchClientBuiltin(tagName, ctx, node.openingElement, () => transformAsyncElement(node, ctx), () => transformRegionElement(node, ctx));
192525
+ if (builtin)
192526
+ return builtin;
192416
192527
  const isComponent = /^[A-Z]/.test(tagName);
192417
192528
  if (isComponent) {
192418
192529
  const resolved = resolveMemberExpressionTag(node.openingElement.tagName, ctx);
@@ -192447,9 +192558,9 @@ function transformSelfClosingElement(node, ctx) {
192447
192558
  if (tagName.endsWith(".Provider") && /^[A-Z]/.test(tagName)) {
192448
192559
  return transformSelfClosingProviderElement(node, ctx, tagName);
192449
192560
  }
192450
- if (tagName === "Async") {
192451
- return transformSelfClosingAsyncElement(node, ctx);
192452
- }
192561
+ const builtin = dispatchClientBuiltin(tagName, ctx, node, () => transformSelfClosingAsyncElement(node, ctx), () => transformSelfClosingRegionElement(node, ctx));
192562
+ if (builtin)
192563
+ return builtin;
192453
192564
  const isComponent = /^[A-Z]/.test(tagName);
192454
192565
  if (isComponent) {
192455
192566
  const resolved = resolveMemberExpressionTag(node.tagName, ctx);
@@ -192573,6 +192684,44 @@ function transformSelfClosingAsyncElement(node, ctx) {
192573
192684
  loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath)
192574
192685
  };
192575
192686
  }
192687
+ function regionId(ctx) {
192688
+ return `${computeFileScope(ctx.filePath)}:${ctx.regionIdCounter++}`;
192689
+ }
192690
+ function transformRegionElement(node, ctx) {
192691
+ const id = regionId(ctx);
192692
+ const needsScope = ctx.isRoot;
192693
+ ctx.isRoot = false;
192694
+ const children = transformChildren(node.children, ctx);
192695
+ return {
192696
+ type: "element",
192697
+ tag: "div",
192698
+ attrs: [],
192699
+ events: [],
192700
+ ref: null,
192701
+ children,
192702
+ slotId: null,
192703
+ needsScope,
192704
+ regionId: id,
192705
+ loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath)
192706
+ };
192707
+ }
192708
+ function transformSelfClosingRegionElement(node, ctx) {
192709
+ const id = regionId(ctx);
192710
+ const needsScope = ctx.isRoot;
192711
+ ctx.isRoot = false;
192712
+ return {
192713
+ type: "element",
192714
+ tag: "div",
192715
+ attrs: [],
192716
+ events: [],
192717
+ ref: null,
192718
+ children: [],
192719
+ slotId: null,
192720
+ needsScope,
192721
+ regionId: id,
192722
+ loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath)
192723
+ };
192724
+ }
192576
192725
  function transformComponentElement(node, ctx, name) {
192577
192726
  const props = processComponentProps(node.openingElement.attributes, ctx);
192578
192727
  ctx.isRoot = false;
@@ -195177,6 +195326,7 @@ var import_typescript15 = __toESM(require_typescript(), 1);
195177
195326
  // ../jsx/src/ssr-defaults.ts
195178
195327
  var import_typescript16 = __toESM(require_typescript(), 1);
195179
195328
  var UNRESOLVED = Symbol("unresolved");
195329
+ var NO_RETURN = Symbol("no-return");
195180
195330
  // ../jsx/src/shared-program.ts
195181
195331
  init_path();
195182
195332
  var import_typescript17 = __toESM(require_typescript(), 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/test",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
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.13.0"
42
+ "@barefootjs/jsx": "0.15.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.0.0"