@barefootjs/test 0.4.0 → 0.5.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.
Files changed (2) hide show
  1. package/dist/index.js +207 -34
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -190546,6 +190546,8 @@ function convertNode(node, raw) {
190546
190546
  ` + ` (a, b) => a.field - b.field
190547
190547
  ` + ` (a, b) => a.localeCompare(b)
190548
190548
  ` + ` (a, b) => a.field.localeCompare(b.field)
190549
+ ` + ` (a, b) => a.field > b.field ? 1 : -1 (relational ternary)
190550
+ ` + ` any of the above ||-chained for multi-key tie-breaks
190549
190551
  ` + `(reverse the operands for descending order). ` + `Wrap the call in /* @client */ to evaluate at hydration.`
190550
190552
  };
190551
190553
  }
@@ -190705,26 +190707,54 @@ function extractSortComparatorFromTS(node, method) {
190705
190707
  const paramA = pA.name.text;
190706
190708
  const paramB = pB.name.text;
190707
190709
  let body;
190708
- if (import_typescript8.default.isArrowFunction(node)) {
190709
- if (import_typescript8.default.isBlock(node.body))
190710
- return null;
190710
+ if (import_typescript8.default.isArrowFunction(node) && !import_typescript8.default.isBlock(node.body)) {
190711
190711
  body = node.body;
190712
190712
  } else {
190713
- const stmts = node.body.statements;
190713
+ const block = node.body;
190714
+ const stmts = block.statements;
190714
190715
  if (stmts.length !== 1 || !import_typescript8.default.isReturnStatement(stmts[0]) || !stmts[0].expression)
190715
190716
  return null;
190716
190717
  body = stmts[0].expression;
190717
190718
  }
190718
190719
  const raw = body.getText();
190720
+ const keys = [];
190721
+ for (const operand of flattenLogicalOr(body)) {
190722
+ const key = classifyLeafComparator(operand, paramA, paramB);
190723
+ if (!key)
190724
+ return null;
190725
+ keys.push(key);
190726
+ }
190727
+ if (keys.length === 0)
190728
+ return null;
190729
+ return { keys, raw, paramA, paramB, method };
190730
+ }
190731
+ function unwrapParens(expr) {
190732
+ let e = expr;
190733
+ while (import_typescript8.default.isParenthesizedExpression(e))
190734
+ e = e.expression;
190735
+ return e;
190736
+ }
190737
+ function flattenLogicalOr(expr) {
190738
+ const inner = unwrapParens(expr);
190739
+ if (import_typescript8.default.isBinaryExpression(inner) && inner.operatorToken.kind === import_typescript8.default.SyntaxKind.BarBarToken) {
190740
+ return [...flattenLogicalOr(inner.left), ...flattenLogicalOr(inner.right)];
190741
+ }
190742
+ return [inner];
190743
+ }
190744
+ function classifyLeafComparator(expr, paramA, paramB) {
190745
+ const body = unwrapParens(expr);
190719
190746
  if (import_typescript8.default.isBinaryExpression(body) && body.operatorToken.kind === import_typescript8.default.SyntaxKind.MinusToken) {
190720
- return classifyComparatorOperands(body.left, body.right, paramA, paramB, "numeric", method, raw);
190747
+ return classifyComparatorOperands(body.left, body.right, paramA, paramB, "numeric");
190721
190748
  }
190722
190749
  if (import_typescript8.default.isCallExpression(body) && import_typescript8.default.isPropertyAccessExpression(body.expression) && body.expression.name.text === "localeCompare" && body.arguments.length === 1) {
190723
- return classifyComparatorOperands(body.expression.expression, body.arguments[0], paramA, paramB, "string", method, raw);
190750
+ return classifyComparatorOperands(body.expression.expression, body.arguments[0], paramA, paramB, "string");
190751
+ }
190752
+ if (import_typescript8.default.isConditionalExpression(body)) {
190753
+ return classifyTernaryComparator(body, paramA, paramB);
190724
190754
  }
190725
190755
  return null;
190726
190756
  }
190727
- function classifyComparatorOperands(left, right, paramA, paramB, type2, method, raw) {
190757
+ function classifyComparatorOperands(left, right, paramA, paramB, type2) {
190728
190758
  const leftRef = classifySortOperand(left, paramA, paramB);
190729
190759
  const rightRef = classifySortOperand(right, paramA, paramB);
190730
190760
  if (!leftRef || !rightRef)
@@ -190737,15 +190767,89 @@ function classifyComparatorOperands(left, right, paramA, paramB, type2, method,
190737
190767
  return null;
190738
190768
  }
190739
190769
  const direction = leftRef.param === "A" ? "asc" : "desc";
190740
- return {
190741
- key: leftRef.key,
190742
- type: type2,
190743
- direction,
190744
- raw,
190745
- paramA,
190746
- paramB,
190747
- method
190748
- };
190770
+ return { key: leftRef.key, type: type2, direction };
190771
+ }
190772
+ function classifyTernaryComparator(node, paramA, paramB) {
190773
+ const cond = unwrapParens(node.condition);
190774
+ if (import_typescript8.default.isBinaryExpression(cond) && (cond.operatorToken.kind === import_typescript8.default.SyntaxKind.EqualsEqualsEqualsToken || cond.operatorToken.kind === import_typescript8.default.SyntaxKind.EqualsEqualsToken) && sameKeyOperands(cond.left, cond.right, paramA, paramB) && numericSign(node.whenTrue) === 0) {
190775
+ const elseBranch = unwrapParens(node.whenFalse);
190776
+ if (import_typescript8.default.isConditionalExpression(elseBranch)) {
190777
+ return classifyTernaryComparator(elseBranch, paramA, paramB);
190778
+ }
190779
+ return null;
190780
+ }
190781
+ if (!import_typescript8.default.isBinaryExpression(cond))
190782
+ return null;
190783
+ const op = cond.operatorToken.kind;
190784
+ const isGreater = op === import_typescript8.default.SyntaxKind.GreaterThanToken || op === import_typescript8.default.SyntaxKind.GreaterThanEqualsToken;
190785
+ const isLess = op === import_typescript8.default.SyntaxKind.LessThanToken || op === import_typescript8.default.SyntaxKind.LessThanEqualsToken;
190786
+ if (!isGreater && !isLess)
190787
+ return null;
190788
+ const leftRef = classifySortOperand(cond.left, paramA, paramB);
190789
+ const rightRef = classifySortOperand(cond.right, paramA, paramB);
190790
+ if (!leftRef || !rightRef)
190791
+ return null;
190792
+ if (leftRef.param === rightRef.param)
190793
+ return null;
190794
+ if (leftRef.key.kind !== rightRef.key.kind)
190795
+ return null;
190796
+ if (leftRef.key.kind === "field" && rightRef.key.kind === "field" && leftRef.key.field !== rightRef.key.field) {
190797
+ return null;
190798
+ }
190799
+ const trueSign = numericSign(node.whenTrue);
190800
+ if (trueSign === null || trueSign === 0)
190801
+ return null;
190802
+ if (!isBoundedTernaryElse(node.whenFalse, leftRef.key, paramA, paramB))
190803
+ return null;
190804
+ const greaterForA = leftRef.param === "A" ? isGreater : !isGreater;
190805
+ const asc = greaterForA ? trueSign > 0 : trueSign < 0;
190806
+ return { key: leftRef.key, type: "auto", direction: asc ? "asc" : "desc" };
190807
+ }
190808
+ function sameKeyOperands(left, right, paramA, paramB) {
190809
+ const l = classifySortOperand(left, paramA, paramB);
190810
+ const r = classifySortOperand(right, paramA, paramB);
190811
+ if (!l || !r)
190812
+ return false;
190813
+ if (l.param === r.param)
190814
+ return false;
190815
+ if (l.key.kind !== r.key.kind)
190816
+ return false;
190817
+ if (l.key.kind === "field" && r.key.kind === "field" && l.key.field !== r.key.field)
190818
+ return false;
190819
+ return true;
190820
+ }
190821
+ function numericSign(expr) {
190822
+ const e = unwrapParens(expr);
190823
+ if (import_typescript8.default.isPrefixUnaryExpression(e) && e.operator === import_typescript8.default.SyntaxKind.MinusToken) {
190824
+ const inner = numericSign(e.operand);
190825
+ return inner === null ? null : -inner;
190826
+ }
190827
+ if (import_typescript8.default.isNumericLiteral(e)) {
190828
+ const n = Number(e.text);
190829
+ if (Number.isNaN(n))
190830
+ return null;
190831
+ if (n === 0)
190832
+ return 0;
190833
+ return n > 0 ? 1 : -1;
190834
+ }
190835
+ return null;
190836
+ }
190837
+ function isBoundedTernaryElse(expr, key, paramA, paramB) {
190838
+ const e = unwrapParens(expr);
190839
+ if (numericSign(e) !== null)
190840
+ return true;
190841
+ if (import_typescript8.default.isConditionalExpression(e)) {
190842
+ const nested = classifyTernaryComparator(e, paramA, paramB);
190843
+ return nested !== null && sortKeyEquals(nested.key, key);
190844
+ }
190845
+ return false;
190846
+ }
190847
+ function sortKeyEquals(a, b) {
190848
+ if (a.kind !== b.kind)
190849
+ return false;
190850
+ if (a.kind === "field" && b.kind === "field")
190851
+ return a.field === b.field;
190852
+ return true;
190749
190853
  }
190750
190854
  function classifySortOperand(expr, paramA, paramB) {
190751
190855
  if (import_typescript8.default.isIdentifier(expr)) {
@@ -192577,6 +192681,23 @@ function containsJsxInExpression(node) {
192577
192681
  }
192578
192682
  return import_typescript11.default.forEachChild(node, containsJsxInExpression) ?? false;
192579
192683
  }
192684
+ function callsJsxHelper(node, ctx) {
192685
+ let found = false;
192686
+ const visit2 = (n) => {
192687
+ if (found)
192688
+ return;
192689
+ if (import_typescript11.default.isCallExpression(n) && import_typescript11.default.isIdentifier(n.expression)) {
192690
+ const name = n.expression.text;
192691
+ if (ctx.analyzer.jsxFunctions.has(name) || ctx.analyzer.jsxMultiReturnFunctions.has(name)) {
192692
+ found = true;
192693
+ return;
192694
+ }
192695
+ }
192696
+ import_typescript11.default.forEachChild(n, visit2);
192697
+ };
192698
+ visit2(node);
192699
+ return found;
192700
+ }
192580
192701
  function containsAwaitExpression(node) {
192581
192702
  if (import_typescript11.default.isAwaitExpression(node))
192582
192703
  return true;
@@ -192656,7 +192777,7 @@ function transformJsxExpression(expr, ctx, isClientOnly = false) {
192656
192777
  if (node.operatorToken.kind === import_typescript11.default.SyntaxKind.AmpersandAmpersandToken) {
192657
192778
  return transformLogicalAnd(node, ctx);
192658
192779
  }
192659
- if ((node.operatorToken.kind === import_typescript11.default.SyntaxKind.QuestionQuestionToken || node.operatorToken.kind === import_typescript11.default.SyntaxKind.BarBarToken) && containsJsxInExpression(node.right)) {
192780
+ if ((node.operatorToken.kind === import_typescript11.default.SyntaxKind.QuestionQuestionToken || node.operatorToken.kind === import_typescript11.default.SyntaxKind.BarBarToken) && (containsJsxInExpression(node.right) || callsJsxHelper(node.right, ctx))) {
192660
192781
  return transformNullishCoalescing(node, ctx);
192661
192782
  }
192662
192783
  return null;
@@ -193113,23 +193234,23 @@ function checkLoopKey(callback, ctx, isNested) {
193113
193234
  }
193114
193235
  while (import_typescript11.default.isParenthesizedExpression(body))
193115
193236
  body = body.expression;
193237
+ function checkJsxOperand(node) {
193238
+ let n = node;
193239
+ while (import_typescript11.default.isParenthesizedExpression(n))
193240
+ n = n.expression;
193241
+ if (import_typescript11.default.isJsxElement(n))
193242
+ checkOpening(n.openingElement);
193243
+ else if (import_typescript11.default.isJsxSelfClosingElement(n))
193244
+ checkOpening(n);
193245
+ }
193116
193246
  if (import_typescript11.default.isConditionalExpression(body)) {
193117
- const whenTrue = body.whenTrue;
193118
- const whenFalse = body.whenFalse;
193119
- let wt = whenTrue;
193120
- let wf = whenFalse;
193121
- while (import_typescript11.default.isParenthesizedExpression(wt))
193122
- wt = wt.expression;
193123
- while (import_typescript11.default.isParenthesizedExpression(wf))
193124
- wf = wf.expression;
193125
- if (import_typescript11.default.isJsxElement(wt))
193126
- checkOpening(wt.openingElement);
193127
- else if (import_typescript11.default.isJsxSelfClosingElement(wt))
193128
- checkOpening(wt);
193129
- if (import_typescript11.default.isJsxElement(wf))
193130
- checkOpening(wf.openingElement);
193131
- else if (import_typescript11.default.isJsxSelfClosingElement(wf))
193132
- checkOpening(wf);
193247
+ checkJsxOperand(body.whenTrue);
193248
+ checkJsxOperand(body.whenFalse);
193249
+ return;
193250
+ }
193251
+ if (import_typescript11.default.isBinaryExpression(body) && (body.operatorToken.kind === import_typescript11.default.SyntaxKind.AmpersandAmpersandToken || body.operatorToken.kind === import_typescript11.default.SyntaxKind.BarBarToken || body.operatorToken.kind === import_typescript11.default.SyntaxKind.QuestionQuestionToken)) {
193252
+ checkJsxOperand(body.left);
193253
+ checkJsxOperand(body.right);
193133
193254
  return;
193134
193255
  }
193135
193256
  if (import_typescript11.default.isJsxElement(body)) {
@@ -193152,6 +193273,38 @@ function loopBodyIsMultiRoot(children) {
193152
193273
  return false;
193153
193274
  return loopBodyIsMultiRoot(only.children);
193154
193275
  }
193276
+ function branchHasNoElement(node) {
193277
+ if (node.type === "element" || node.type === "component")
193278
+ return false;
193279
+ if (node.type === "conditional") {
193280
+ return branchHasNoElement(node.whenTrue) || branchHasNoElement(node.whenFalse);
193281
+ }
193282
+ if (node.type === "fragment") {
193283
+ const real = node.children.filter((c) => !(c.type === "text" && typeof c.value === "string" && !c.value.trim()));
193284
+ return real.length !== 1 || branchHasNoElement(real[0]);
193285
+ }
193286
+ return true;
193287
+ }
193288
+ function loopBodyItemConditional(children) {
193289
+ const real = children.filter((c) => !(c.type === "text" && typeof c.value === "string" && !c.value.trim()));
193290
+ if (real.length !== 1)
193291
+ return null;
193292
+ const only = real[0];
193293
+ if (only.type !== "conditional")
193294
+ return null;
193295
+ if (branchHasNoElement(only.whenTrue) || branchHasNoElement(only.whenFalse)) {
193296
+ return only;
193297
+ }
193298
+ return null;
193299
+ }
193300
+ function extractItemConditionalKey(cond) {
193301
+ const a = branchHasNoElement(cond.whenTrue) ? null : extractLoopKey(cond.whenTrue);
193302
+ const b = branchHasNoElement(cond.whenFalse) ? null : extractLoopKey(cond.whenFalse);
193303
+ if (a !== null && b !== null) {
193304
+ return normalizeKeyExpr(a) === normalizeKeyExpr(b) ? a : null;
193305
+ }
193306
+ return a ?? b;
193307
+ }
193155
193308
  function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
193156
193309
  const isNested = ctx.loopParams.size > 0;
193157
193310
  const propAccess = node.expression;
@@ -193314,6 +193467,19 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
193314
193467
  }
193315
193468
  if (index)
193316
193469
  ctx.loopParams.add(index);
193470
+ const tryTransformRenderableBody = (expr) => {
193471
+ if (!import_typescript11.default.isBinaryExpression(expr))
193472
+ return;
193473
+ const op = expr.operatorToken.kind;
193474
+ if (op !== import_typescript11.default.SyntaxKind.AmpersandAmpersandToken && op !== import_typescript11.default.SyntaxKind.BarBarToken && op !== import_typescript11.default.SyntaxKind.QuestionQuestionToken) {
193475
+ return;
193476
+ }
193477
+ if (!containsJsxInExpression(expr) && !callsJsxHelper(expr, ctx))
193478
+ return;
193479
+ const transformed = transformJsxExpression(expr, ctx, isClientOnly);
193480
+ if (transformed)
193481
+ children = [transformed];
193482
+ };
193317
193483
  const body = callback.body;
193318
193484
  if (import_typescript11.default.isJsxElement(body) || import_typescript11.default.isJsxSelfClosingElement(body) || import_typescript11.default.isJsxFragment(body)) {
193319
193485
  const transformed = transformNode(body, ctx);
@@ -193336,6 +193502,8 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
193336
193502
  children = [transformConditional(inner, ctx)];
193337
193503
  } else if (method === "flatMap" && import_typescript11.default.isArrayLiteralExpression(inner)) {
193338
193504
  children = transformArrayLiteralChildren(inner, ctx);
193505
+ } else {
193506
+ tryTransformRenderableBody(inner);
193339
193507
  }
193340
193508
  } else if (method === "flatMap" && import_typescript11.default.isArrayLiteralExpression(body)) {
193341
193509
  children = transformArrayLiteralChildren(body, ctx);
@@ -193384,6 +193552,8 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
193384
193552
  if (method === "flatMap" && children.length === 0) {
193385
193553
  flatMapCallback = buildFlatMapCallback(callback, body, ctx);
193386
193554
  }
193555
+ } else {
193556
+ tryTransformRenderableBody(body);
193387
193557
  }
193388
193558
  if (paramBindings) {
193389
193559
  for (const b of paramBindings)
@@ -193400,7 +193570,9 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
193400
193570
  if (import_typescript11.default.isArrowFunction(node.arguments[0]) && children.length > 0) {
193401
193571
  checkLoopKey(node.arguments[0], ctx, isNested);
193402
193572
  }
193403
- const key = children.length > 0 ? extractLoopKey(children[0]) : null;
193573
+ const itemConditional = children.length > 0 ? loopBodyItemConditional(children) : null;
193574
+ const bodyIsItemConditional = itemConditional !== null;
193575
+ const key = bodyIsItemConditional ? extractItemConditionalKey(itemConditional) : children.length > 0 ? extractLoopKey(children[0]) : null;
193404
193576
  let childComponent;
193405
193577
  if (children.length === 1 && children[0].type === "component") {
193406
193578
  const comp = children[0];
@@ -193439,6 +193611,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
193439
193611
  callsReactiveGetters: callsReactive || undefined,
193440
193612
  hasFunctionCalls: hasCalls || undefined,
193441
193613
  bodyIsMultiRoot: bodyIsMultiRoot || undefined,
193614
+ bodyIsItemConditional: bodyIsItemConditional || undefined,
193442
193615
  childComponent,
193443
193616
  nestedComponents,
193444
193617
  filterPredicate,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/test",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
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.4.0"
42
+ "@barefootjs/jsx": "0.5.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "typescript": "^5.0.0"