@barefootjs/test 0.5.3 → 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 +261 -17
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -190459,15 +190459,7 @@ var UNSUPPORTED_METHODS = new Set([
|
|
|
190459
190459
|
"some",
|
|
190460
190460
|
"forEach",
|
|
190461
190461
|
"flatMap",
|
|
190462
|
-
"flat",
|
|
190463
|
-
"split",
|
|
190464
|
-
"startsWith",
|
|
190465
|
-
"endsWith",
|
|
190466
|
-
"replace",
|
|
190467
190462
|
"replaceAll",
|
|
190468
|
-
"repeat",
|
|
190469
|
-
"padStart",
|
|
190470
|
-
"padEnd",
|
|
190471
190463
|
"charAt",
|
|
190472
190464
|
"charCodeAt",
|
|
190473
190465
|
"codePointAt",
|
|
@@ -190478,6 +190470,15 @@ var UNSUPPORTED_METHODS = new Set([
|
|
|
190478
190470
|
"matchAll",
|
|
190479
190471
|
"search"
|
|
190480
190472
|
]);
|
|
190473
|
+
var UNSUPPORTED_METHOD_REASONS = {
|
|
190474
|
+
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.`
|
|
190475
|
+
};
|
|
190476
|
+
var LOWERED_ARRAY_METHODS = new Set([
|
|
190477
|
+
"includes",
|
|
190478
|
+
"indexOf",
|
|
190479
|
+
"lastIndexOf",
|
|
190480
|
+
"concat"
|
|
190481
|
+
]);
|
|
190481
190482
|
function parseExpression(expr) {
|
|
190482
190483
|
const trimmed = expr.trim();
|
|
190483
190484
|
if (!trimmed) {
|
|
@@ -190538,7 +190539,7 @@ function convertNode(node, raw) {
|
|
|
190538
190539
|
}
|
|
190539
190540
|
}
|
|
190540
190541
|
if (callee.kind === "member" && !callee.computed) {
|
|
190541
|
-
if (callee.property === "join"
|
|
190542
|
+
if (callee.property === "join") {
|
|
190542
190543
|
return { kind: "array-method", method: "join", object: callee.object, args };
|
|
190543
190544
|
}
|
|
190544
190545
|
if (callee.property === "includes" && args.length === 1) {
|
|
@@ -190547,27 +190548,103 @@ function convertNode(node, raw) {
|
|
|
190547
190548
|
if ((callee.property === "indexOf" || callee.property === "lastIndexOf") && args.length === 1) {
|
|
190548
190549
|
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
190549
190550
|
}
|
|
190550
|
-
if (callee.property === "at"
|
|
190551
|
+
if (callee.property === "at") {
|
|
190551
190552
|
return { kind: "array-method", method: "at", object: callee.object, args };
|
|
190552
190553
|
}
|
|
190553
|
-
if (callee.property === "concat" && args.length
|
|
190554
|
+
if (callee.property === "concat" && args.length <= 1) {
|
|
190554
190555
|
return { kind: "array-method", method: "concat", object: callee.object, args };
|
|
190555
190556
|
}
|
|
190556
|
-
if (callee.property === "slice"
|
|
190557
|
+
if (callee.property === "slice") {
|
|
190557
190558
|
return { kind: "array-method", method: "slice", object: callee.object, args };
|
|
190558
190559
|
}
|
|
190559
|
-
if (
|
|
190560
|
+
if (callee.property === "reverse" || callee.property === "toReversed") {
|
|
190560
190561
|
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
190561
190562
|
}
|
|
190562
|
-
if (callee.property === "
|
|
190563
|
+
if (callee.property === "flat") {
|
|
190564
|
+
const depthNode = node.arguments[0];
|
|
190565
|
+
let flatDepth;
|
|
190566
|
+
if (depthNode === undefined) {
|
|
190567
|
+
flatDepth = 1;
|
|
190568
|
+
} else if (import_typescript8.default.isIdentifier(depthNode) && depthNode.text === "Infinity") {
|
|
190569
|
+
flatDepth = "infinity";
|
|
190570
|
+
} else {
|
|
190571
|
+
let n;
|
|
190572
|
+
if (import_typescript8.default.isNumericLiteral(depthNode)) {
|
|
190573
|
+
n = Number(depthNode.text);
|
|
190574
|
+
} else if (import_typescript8.default.isPrefixUnaryExpression(depthNode) && depthNode.operator === import_typescript8.default.SyntaxKind.MinusToken && import_typescript8.default.isNumericLiteral(depthNode.operand)) {
|
|
190575
|
+
n = -Number(depthNode.operand.text);
|
|
190576
|
+
}
|
|
190577
|
+
if (n === undefined || Number.isNaN(n)) {
|
|
190578
|
+
return {
|
|
190579
|
+
kind: "unsupported",
|
|
190580
|
+
raw,
|
|
190581
|
+
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.`
|
|
190582
|
+
};
|
|
190583
|
+
}
|
|
190584
|
+
const truncated = Math.trunc(n);
|
|
190585
|
+
flatDepth = truncated < 0 ? 0 : truncated;
|
|
190586
|
+
}
|
|
190587
|
+
return { kind: "array-method", method: "flat", object: callee.object, args: [], flatDepth };
|
|
190588
|
+
}
|
|
190589
|
+
if (callee.property === "toLowerCase") {
|
|
190563
190590
|
return { kind: "array-method", method: "toLowerCase", object: callee.object, args };
|
|
190564
190591
|
}
|
|
190565
|
-
if (callee.property === "toUpperCase"
|
|
190592
|
+
if (callee.property === "toUpperCase") {
|
|
190566
190593
|
return { kind: "array-method", method: "toUpperCase", object: callee.object, args };
|
|
190567
190594
|
}
|
|
190568
|
-
if (callee.property === "trim"
|
|
190595
|
+
if (callee.property === "trim") {
|
|
190569
190596
|
return { kind: "array-method", method: "trim", object: callee.object, args };
|
|
190570
190597
|
}
|
|
190598
|
+
if (callee.property === "split") {
|
|
190599
|
+
return { kind: "array-method", method: "split", object: callee.object, args };
|
|
190600
|
+
}
|
|
190601
|
+
if (LOWERED_ARRAY_METHODS.has(callee.property)) {
|
|
190602
|
+
const argName = callee.property === "concat" ? "other" : "x";
|
|
190603
|
+
const detail = callee.property === "concat" ? "the variadic `.concat(a, b, …)` form" : `\`.${callee.property}(…)\` with ${args.length} argument(s)`;
|
|
190604
|
+
return {
|
|
190605
|
+
kind: "unsupported",
|
|
190606
|
+
raw,
|
|
190607
|
+
reason: `${detail} is not yet lowered to the Go/Mojo template adapters. Use the single-argument \`.${callee.property}(${argName})\` form, or pre-compute the value before the template.`
|
|
190608
|
+
};
|
|
190609
|
+
}
|
|
190610
|
+
if (callee.property === "startsWith" || callee.property === "endsWith") {
|
|
190611
|
+
if (args.length === 0) {
|
|
190612
|
+
return {
|
|
190613
|
+
kind: "unsupported",
|
|
190614
|
+
raw,
|
|
190615
|
+
reason: `\`.${callee.property}()\` with no search string is not lowered — JS coerces the missing argument to the string "undefined", a degenerate result. Pass an explicit search string, or pre-compute the value before the template.`
|
|
190616
|
+
};
|
|
190617
|
+
}
|
|
190618
|
+
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
190619
|
+
}
|
|
190620
|
+
if (callee.property === "replace") {
|
|
190621
|
+
if (args.length < 2) {
|
|
190622
|
+
return {
|
|
190623
|
+
kind: "unsupported",
|
|
190624
|
+
raw,
|
|
190625
|
+
reason: `\`.replace(${args.length === 0 ? "" : "pattern"})\` needs both a pattern and a replacement — JS coerces the missing argument to the string "undefined", a degenerate result. Pass both arguments, or pre-compute the value before the template.`
|
|
190626
|
+
};
|
|
190627
|
+
}
|
|
190628
|
+
const patternNode = node.arguments[0];
|
|
190629
|
+
if (patternNode && import_typescript8.default.isRegularExpressionLiteral(patternNode)) {
|
|
190630
|
+
return {
|
|
190631
|
+
kind: "unsupported",
|
|
190632
|
+
raw,
|
|
190633
|
+
reason: "String.prototype.replace supports only a string pattern + string replacement (the regex form is deferred); use a string pattern or wrap the expression in /* @client */"
|
|
190634
|
+
};
|
|
190635
|
+
}
|
|
190636
|
+
const badArg = args[0].kind === "unsupported" ? args[0] : args[1].kind === "unsupported" ? args[1] : undefined;
|
|
190637
|
+
if (badArg && badArg.kind === "unsupported") {
|
|
190638
|
+
return { kind: "unsupported", raw, reason: badArg.reason };
|
|
190639
|
+
}
|
|
190640
|
+
return { kind: "array-method", method: "replace", object: callee.object, args };
|
|
190641
|
+
}
|
|
190642
|
+
if (callee.property === "repeat") {
|
|
190643
|
+
return { kind: "array-method", method: "repeat", object: callee.object, args };
|
|
190644
|
+
}
|
|
190645
|
+
if (callee.property === "padStart" || callee.property === "padEnd") {
|
|
190646
|
+
return { kind: "array-method", method: callee.property, object: callee.object, args };
|
|
190647
|
+
}
|
|
190571
190648
|
if ((callee.property === "sort" || callee.property === "toSorted") && node.arguments.length === 1) {
|
|
190572
190649
|
const comparator = extractSortComparatorFromTS(node.arguments[0], callee.property);
|
|
190573
190650
|
if (comparator) {
|
|
@@ -190592,6 +190669,50 @@ function convertNode(node, raw) {
|
|
|
190592
190669
|
` + `(reverse the operands for descending order). ` + `Wrap the call in /* @client */ to evaluate at hydration.`
|
|
190593
190670
|
};
|
|
190594
190671
|
}
|
|
190672
|
+
if ((callee.property === "reduce" || callee.property === "reduceRight") && node.arguments.length === 2) {
|
|
190673
|
+
const reduceOp = extractReduceOpFromTS(node.arguments[0], node.arguments[1]);
|
|
190674
|
+
if (reduceOp) {
|
|
190675
|
+
return {
|
|
190676
|
+
kind: "array-method",
|
|
190677
|
+
method: callee.property,
|
|
190678
|
+
object: callee.object,
|
|
190679
|
+
args: [],
|
|
190680
|
+
reduceOp
|
|
190681
|
+
};
|
|
190682
|
+
}
|
|
190683
|
+
const m = callee.property;
|
|
190684
|
+
return {
|
|
190685
|
+
kind: "unsupported",
|
|
190686
|
+
raw,
|
|
190687
|
+
reason: `Reduce shape not supported. Accepted (arithmetic fold, explicit init):
|
|
190688
|
+
` + ` arr.${m}((acc, x) => acc + x, 0)
|
|
190689
|
+
` + ` arr.${m}((acc, x) => acc + x.field, 0)
|
|
190690
|
+
` + ` arr.${m}((acc, x) => acc * x.field, 1)
|
|
190691
|
+
` + ` arr.${m}((acc, x) => acc + x.field, '') (string concat)
|
|
190692
|
+
` + `The accumulator must be the left operand and the initial ` + `value a number / string literal. ` + `Wrap the call in /* @client */ to evaluate at hydration.`
|
|
190693
|
+
};
|
|
190694
|
+
}
|
|
190695
|
+
if (callee.property === "flatMap") {
|
|
190696
|
+
const flatMapOp = node.arguments.length === 1 ? extractFlatMapOpFromTS(node.arguments[0]) : null;
|
|
190697
|
+
if (flatMapOp) {
|
|
190698
|
+
return {
|
|
190699
|
+
kind: "array-method",
|
|
190700
|
+
method: "flatMap",
|
|
190701
|
+
object: callee.object,
|
|
190702
|
+
args: [],
|
|
190703
|
+
flatMapOp
|
|
190704
|
+
};
|
|
190705
|
+
}
|
|
190706
|
+
return {
|
|
190707
|
+
kind: "unsupported",
|
|
190708
|
+
raw,
|
|
190709
|
+
reason: `flatMap shape not supported. Accepted (self / field leaves, no thisArg):
|
|
190710
|
+
` + ` arr.flatMap(i => i) (flatten one level)
|
|
190711
|
+
` + ` arr.flatMap(i => i.field) (flatten a per-item array field)
|
|
190712
|
+
` + ` arr.flatMap(i => [i.a, i.b]) (gather per-item fields)
|
|
190713
|
+
` + `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.`
|
|
190714
|
+
};
|
|
190715
|
+
}
|
|
190595
190716
|
}
|
|
190596
190717
|
return { kind: "call", callee, args };
|
|
190597
190718
|
}
|
|
@@ -190910,6 +191031,119 @@ function classifySortOperand(expr, paramA, paramB) {
|
|
|
190910
191031
|
}
|
|
190911
191032
|
return null;
|
|
190912
191033
|
}
|
|
191034
|
+
function extractReduceOpFromTS(reducerNode, initNode) {
|
|
191035
|
+
const init = classifyReduceInit(initNode);
|
|
191036
|
+
if (!init)
|
|
191037
|
+
return null;
|
|
191038
|
+
if (!import_typescript8.default.isArrowFunction(reducerNode) && !import_typescript8.default.isFunctionExpression(reducerNode))
|
|
191039
|
+
return null;
|
|
191040
|
+
if (reducerNode.parameters.length !== 2)
|
|
191041
|
+
return null;
|
|
191042
|
+
const pAcc = reducerNode.parameters[0];
|
|
191043
|
+
const pItem = reducerNode.parameters[1];
|
|
191044
|
+
if (!import_typescript8.default.isIdentifier(pAcc.name) || !import_typescript8.default.isIdentifier(pItem.name))
|
|
191045
|
+
return null;
|
|
191046
|
+
const paramAcc = pAcc.name.text;
|
|
191047
|
+
const paramItem = pItem.name.text;
|
|
191048
|
+
let body;
|
|
191049
|
+
if (import_typescript8.default.isArrowFunction(reducerNode) && !import_typescript8.default.isBlock(reducerNode.body)) {
|
|
191050
|
+
body = reducerNode.body;
|
|
191051
|
+
} else {
|
|
191052
|
+
const block = reducerNode.body;
|
|
191053
|
+
const stmts = block.statements;
|
|
191054
|
+
if (stmts.length !== 1 || !import_typescript8.default.isReturnStatement(stmts[0]) || !stmts[0].expression)
|
|
191055
|
+
return null;
|
|
191056
|
+
body = stmts[0].expression;
|
|
191057
|
+
}
|
|
191058
|
+
const raw = body.getText();
|
|
191059
|
+
const expr = unwrapParens(body);
|
|
191060
|
+
if (!import_typescript8.default.isBinaryExpression(expr))
|
|
191061
|
+
return null;
|
|
191062
|
+
let op;
|
|
191063
|
+
if (expr.operatorToken.kind === import_typescript8.default.SyntaxKind.PlusToken)
|
|
191064
|
+
op = "+";
|
|
191065
|
+
else if (expr.operatorToken.kind === import_typescript8.default.SyntaxKind.AsteriskToken)
|
|
191066
|
+
op = "*";
|
|
191067
|
+
else
|
|
191068
|
+
return null;
|
|
191069
|
+
const left = unwrapParens(expr.left);
|
|
191070
|
+
if (!import_typescript8.default.isIdentifier(left) || left.text !== paramAcc)
|
|
191071
|
+
return null;
|
|
191072
|
+
const key = classifyReduceKey(unwrapParens(expr.right), paramItem);
|
|
191073
|
+
if (!key)
|
|
191074
|
+
return null;
|
|
191075
|
+
const type2 = init.type;
|
|
191076
|
+
if (type2 === "string" && op !== "+")
|
|
191077
|
+
return null;
|
|
191078
|
+
return { op, key, type: type2, init: init.value, raw, paramAcc, paramItem };
|
|
191079
|
+
}
|
|
191080
|
+
function extractFlatMapOpFromTS(cbNode) {
|
|
191081
|
+
if (!import_typescript8.default.isArrowFunction(cbNode) && !import_typescript8.default.isFunctionExpression(cbNode))
|
|
191082
|
+
return null;
|
|
191083
|
+
if (cbNode.parameters.length !== 1)
|
|
191084
|
+
return null;
|
|
191085
|
+
const p = cbNode.parameters[0];
|
|
191086
|
+
if (!import_typescript8.default.isIdentifier(p.name))
|
|
191087
|
+
return null;
|
|
191088
|
+
const param = p.name.text;
|
|
191089
|
+
let body;
|
|
191090
|
+
if (import_typescript8.default.isArrowFunction(cbNode) && !import_typescript8.default.isBlock(cbNode.body)) {
|
|
191091
|
+
body = cbNode.body;
|
|
191092
|
+
} else {
|
|
191093
|
+
const block = cbNode.body;
|
|
191094
|
+
const stmts = block.statements;
|
|
191095
|
+
if (stmts.length !== 1 || !import_typescript8.default.isReturnStatement(stmts[0]) || !stmts[0].expression)
|
|
191096
|
+
return null;
|
|
191097
|
+
body = stmts[0].expression;
|
|
191098
|
+
}
|
|
191099
|
+
const raw = body.getText();
|
|
191100
|
+
const inner = unwrapParens(body);
|
|
191101
|
+
if (import_typescript8.default.isArrayLiteralExpression(inner)) {
|
|
191102
|
+
if (inner.elements.length === 0)
|
|
191103
|
+
return null;
|
|
191104
|
+
const elements = [];
|
|
191105
|
+
for (const el of inner.elements) {
|
|
191106
|
+
if (import_typescript8.default.isSpreadElement(el) || import_typescript8.default.isOmittedExpression(el))
|
|
191107
|
+
return null;
|
|
191108
|
+
const leaf2 = classifyReduceKey(unwrapParens(el), param);
|
|
191109
|
+
if (!leaf2)
|
|
191110
|
+
return null;
|
|
191111
|
+
elements.push(leaf2);
|
|
191112
|
+
}
|
|
191113
|
+
return { projection: { kind: "tuple", elements }, param, raw };
|
|
191114
|
+
}
|
|
191115
|
+
const leaf = classifyReduceKey(inner, param);
|
|
191116
|
+
if (!leaf)
|
|
191117
|
+
return null;
|
|
191118
|
+
return { projection: leaf, param, raw };
|
|
191119
|
+
}
|
|
191120
|
+
function classifyReduceKey(expr, paramItem) {
|
|
191121
|
+
if (import_typescript8.default.isIdentifier(expr)) {
|
|
191122
|
+
return expr.text === paramItem ? { kind: "self" } : null;
|
|
191123
|
+
}
|
|
191124
|
+
if (import_typescript8.default.isPropertyAccessExpression(expr) && import_typescript8.default.isIdentifier(expr.expression)) {
|
|
191125
|
+
if (expr.expression.text === paramItem)
|
|
191126
|
+
return { kind: "field", field: expr.name.text };
|
|
191127
|
+
}
|
|
191128
|
+
return null;
|
|
191129
|
+
}
|
|
191130
|
+
function classifyReduceInit(node) {
|
|
191131
|
+
let n = unwrapParens(node);
|
|
191132
|
+
if (import_typescript8.default.isPrefixUnaryExpression(n) && n.operator === import_typescript8.default.SyntaxKind.MinusToken) {
|
|
191133
|
+
if (import_typescript8.default.isNumericLiteral(n.operand))
|
|
191134
|
+
return { type: "numeric", value: "-" + n.operand.text };
|
|
191135
|
+
return null;
|
|
191136
|
+
}
|
|
191137
|
+
if (import_typescript8.default.isNumericLiteral(n))
|
|
191138
|
+
return { type: "numeric", value: n.text };
|
|
191139
|
+
if (import_typescript8.default.isStringLiteral(n)) {
|
|
191140
|
+
const raw = n.getText();
|
|
191141
|
+
if (raw.length < 2 || raw.slice(1, -1) !== n.text)
|
|
191142
|
+
return null;
|
|
191143
|
+
return { type: "string", value: n.text };
|
|
191144
|
+
}
|
|
191145
|
+
return null;
|
|
191146
|
+
}
|
|
190913
191147
|
function collectDestructureBindings(pattern, pathPrefix, fieldMap, raw, excludedTopKeys) {
|
|
190914
191148
|
let restName;
|
|
190915
191149
|
for (const el of pattern.elements) {
|
|
@@ -191218,6 +191452,15 @@ function substituteDestructuredFields(expr, fieldMap, syntheticParam, restName)
|
|
|
191218
191452
|
if (e.method === "sort" || e.method === "toSorted") {
|
|
191219
191453
|
return { kind: "array-method", method: e.method, object: walk(e.object), args: [], comparator: e.comparator };
|
|
191220
191454
|
}
|
|
191455
|
+
if (e.method === "reduce" || e.method === "reduceRight") {
|
|
191456
|
+
return { kind: "array-method", method: e.method, object: walk(e.object), args: [], reduceOp: e.reduceOp };
|
|
191457
|
+
}
|
|
191458
|
+
if (e.method === "flat") {
|
|
191459
|
+
return { kind: "array-method", method: "flat", object: walk(e.object), args: [], flatDepth: e.flatDepth };
|
|
191460
|
+
}
|
|
191461
|
+
if (e.method === "flatMap") {
|
|
191462
|
+
return { kind: "array-method", method: "flatMap", object: walk(e.object), args: [], flatMapOp: e.flatMapOp };
|
|
191463
|
+
}
|
|
191221
191464
|
return { kind: "array-method", method: e.method, object: walk(e.object), args: e.args.map(walk) };
|
|
191222
191465
|
case "literal":
|
|
191223
191466
|
case "unsupported":
|
|
@@ -191338,7 +191581,8 @@ function checkSupport(expr) {
|
|
|
191338
191581
|
return {
|
|
191339
191582
|
supported: false,
|
|
191340
191583
|
level: "L5_UNSUPPORTED",
|
|
191341
|
-
|
|
191584
|
+
selfContained: true,
|
|
191585
|
+
reason: UNSUPPORTED_METHOD_REASONS[methodName] ?? `'${methodName}()' can't render on the server. Pre-compute the value, or add /* @client */ for client-only (no SSR).`
|
|
191342
191586
|
};
|
|
191343
191587
|
}
|
|
191344
191588
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/test",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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.6.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.0.0"
|