@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.
- package/dist/index.js +207 -34
- 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
|
|
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"
|
|
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"
|
|
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
|
|
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
|
-
|
|
190742
|
-
|
|
190743
|
-
|
|
190744
|
-
|
|
190745
|
-
|
|
190746
|
-
|
|
190747
|
-
|
|
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
|
-
|
|
193118
|
-
|
|
193119
|
-
|
|
193120
|
-
|
|
193121
|
-
|
|
193122
|
-
|
|
193123
|
-
|
|
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
|
|
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.
|
|
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.
|
|
42
|
+
"@barefootjs/jsx": "0.5.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.0.0"
|