@barefootjs/test 0.26.2 → 0.26.3
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 +479 -141
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -187301,6 +187301,7 @@ var UNSUPPORTED_METHODS = new Set([
|
|
|
187301
187301
|
"some",
|
|
187302
187302
|
"forEach",
|
|
187303
187303
|
"flatMap",
|
|
187304
|
+
"fill",
|
|
187304
187305
|
"charAt",
|
|
187305
187306
|
"charCodeAt",
|
|
187306
187307
|
"codePointAt",
|
|
@@ -189191,6 +189192,16 @@ function computeFileScope(entryPath) {
|
|
|
189191
189192
|
|
|
189192
189193
|
// ../jsx/src/ir-to-client-js/csr-substitute.ts
|
|
189193
189194
|
var import_typescript4 = __toESM(require_typescript(), 1);
|
|
189195
|
+
function extractFreeIdentifiersFromText(text) {
|
|
189196
|
+
if (!text || text.trim().length === 0)
|
|
189197
|
+
return new Set;
|
|
189198
|
+
const sf = import_typescript4.default.createSourceFile("__free_ids__.ts", `(${text});`, import_typescript4.default.ScriptTarget.Latest, true, import_typescript4.default.ScriptKind.TS);
|
|
189199
|
+
const stmt = sf.statements[0];
|
|
189200
|
+
if (!stmt || !import_typescript4.default.isExpressionStatement(stmt))
|
|
189201
|
+
return new Set;
|
|
189202
|
+
const expr = import_typescript4.default.isParenthesizedExpression(stmt.expression) ? stmt.expression.expression : stmt.expression;
|
|
189203
|
+
return extractFreeIdentifiersFromNode(expr);
|
|
189204
|
+
}
|
|
189194
189205
|
|
|
189195
189206
|
// ../jsx/src/ir-to-client-js/html-template.ts
|
|
189196
189207
|
function splitTemplateInterpolations(inner) {
|
|
@@ -189412,6 +189423,39 @@ function reconstructWithoutTypes(node, sourceFile, ranges) {
|
|
|
189412
189423
|
}
|
|
189413
189424
|
return result;
|
|
189414
189425
|
}
|
|
189426
|
+
function reconstructAsSegments(node, sourceFile, ranges, markers) {
|
|
189427
|
+
const nodeStart = node.getStart(sourceFile);
|
|
189428
|
+
const nodeEnd = node.getEnd();
|
|
189429
|
+
const fullText = sourceFile.text;
|
|
189430
|
+
const edits = [];
|
|
189431
|
+
for (const r of ranges) {
|
|
189432
|
+
if (r.end <= nodeStart || r.start >= nodeEnd)
|
|
189433
|
+
continue;
|
|
189434
|
+
edits.push({ start: r.start, end: r.end, marker: null });
|
|
189435
|
+
}
|
|
189436
|
+
markers.forEach((m, i2) => edits.push({ start: m.start, end: m.end, marker: i2 }));
|
|
189437
|
+
edits.sort((a, b) => a.start - b.start || b.end - a.end);
|
|
189438
|
+
const segments = [];
|
|
189439
|
+
let jsBuf = "";
|
|
189440
|
+
let pos = nodeStart;
|
|
189441
|
+
for (const edit of edits) {
|
|
189442
|
+
if (edit.start < pos)
|
|
189443
|
+
continue;
|
|
189444
|
+
jsBuf += fullText.slice(pos, edit.start);
|
|
189445
|
+
if (edit.marker !== null) {
|
|
189446
|
+
if (jsBuf)
|
|
189447
|
+
segments.push({ js: jsBuf });
|
|
189448
|
+
jsBuf = "";
|
|
189449
|
+
segments.push({ marker: edit.marker });
|
|
189450
|
+
}
|
|
189451
|
+
pos = edit.end;
|
|
189452
|
+
}
|
|
189453
|
+
if (pos < nodeEnd)
|
|
189454
|
+
jsBuf += fullText.slice(pos, nodeEnd);
|
|
189455
|
+
if (jsBuf)
|
|
189456
|
+
segments.push({ js: jsBuf });
|
|
189457
|
+
return segments;
|
|
189458
|
+
}
|
|
189415
189459
|
function mergeRanges(ranges) {
|
|
189416
189460
|
if (ranges.length === 0)
|
|
189417
189461
|
return [];
|
|
@@ -189557,10 +189601,11 @@ function findAngleBracketAfter(lastTypeArg, fullText) {
|
|
|
189557
189601
|
}
|
|
189558
189602
|
|
|
189559
189603
|
// ../jsx/src/analyzer-context.ts
|
|
189560
|
-
function createAnalyzerContext(sourceFile, filePath) {
|
|
189604
|
+
function createAnalyzerContext(sourceFile, filePath, acceptsCallbackBody) {
|
|
189561
189605
|
return {
|
|
189562
189606
|
sourceFile,
|
|
189563
189607
|
filePath,
|
|
189608
|
+
acceptsCallbackBody,
|
|
189564
189609
|
componentName: null,
|
|
189565
189610
|
componentNode: null,
|
|
189566
189611
|
hasDefaultExport: false,
|
|
@@ -189606,6 +189651,9 @@ function createAnalyzerContext(sourceFile, filePath) {
|
|
|
189606
189651
|
} catch {
|
|
189607
189652
|
ownSourceFile = undefined;
|
|
189608
189653
|
}
|
|
189654
|
+
if (process.env.BF_ASSERT_NO_JSX_IN_GETJS === "1" && this.errors.length === 0 && nodeContainsJsx(node)) {
|
|
189655
|
+
throw new Error("getJS() called on a JSX-bearing node — raw JSX must never be spliced " + "into emitted output. Carry mixed content as structured segments " + "(MapCallbackPreamble / FlatMapCallback) instead.");
|
|
189656
|
+
}
|
|
189609
189657
|
if (ownSourceFile && ownSourceFile !== sourceFile) {
|
|
189610
189658
|
return node.getText(ownSourceFile);
|
|
189611
189659
|
}
|
|
@@ -189613,6 +189661,11 @@ function createAnalyzerContext(sourceFile, filePath) {
|
|
|
189613
189661
|
}
|
|
189614
189662
|
};
|
|
189615
189663
|
}
|
|
189664
|
+
function nodeContainsJsx(node) {
|
|
189665
|
+
if (import_typescript7.default.isJsxElement(node) || import_typescript7.default.isJsxSelfClosingElement(node) || import_typescript7.default.isJsxFragment(node))
|
|
189666
|
+
return true;
|
|
189667
|
+
return import_typescript7.default.forEachChild(node, nodeContainsJsx) ?? false;
|
|
189668
|
+
}
|
|
189616
189669
|
function getSourceLocation(node, sourceFile, filePath) {
|
|
189617
189670
|
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
189618
189671
|
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
@@ -190038,7 +190091,7 @@ function createProgramForFile(source, filePath) {
|
|
|
190038
190091
|
return null;
|
|
190039
190092
|
}
|
|
190040
190093
|
}
|
|
190041
|
-
function analyzeComponent(source, filePath, targetComponentName, program) {
|
|
190094
|
+
function analyzeComponent(source, filePath, targetComponentName, program, acceptsCallbackBody) {
|
|
190042
190095
|
incrementCounter("filesAnalyzed");
|
|
190043
190096
|
const hadSharedProgram = program !== undefined;
|
|
190044
190097
|
const prescan = prescanReactiveFactoriesInSource(source, filePath);
|
|
@@ -190071,7 +190124,7 @@ function analyzeComponent(source, filePath, targetComponentName, program) {
|
|
|
190071
190124
|
checker = result.checker;
|
|
190072
190125
|
}
|
|
190073
190126
|
}
|
|
190074
|
-
const ctx = createAnalyzerContext(sourceFile, filePath);
|
|
190127
|
+
const ctx = createAnalyzerContext(sourceFile, filePath, acceptsCallbackBody);
|
|
190075
190128
|
ctx.checker = checker;
|
|
190076
190129
|
ctx.reactiveFactories = prescan.factories;
|
|
190077
190130
|
ctx.declinedReactiveFactories = prescan.declined;
|
|
@@ -191123,9 +191176,15 @@ function extractSingleJsxReturn(body) {
|
|
|
191123
191176
|
return null;
|
|
191124
191177
|
return jsxReturn;
|
|
191125
191178
|
}
|
|
191126
|
-
function
|
|
191179
|
+
function preambleUnsafe(preamble, branches, fallback) {
|
|
191180
|
+
if (preamble.length === 0)
|
|
191181
|
+
return false;
|
|
191182
|
+
return fallback === null || branches.some((b) => b.jsxReturn === null);
|
|
191183
|
+
}
|
|
191184
|
+
function extractMultiReturnJsxBranches(body, allowPreamble = false) {
|
|
191127
191185
|
const branches = [];
|
|
191128
191186
|
let fallback = null;
|
|
191187
|
+
const preamble = [];
|
|
191129
191188
|
const stmts = body.statements;
|
|
191130
191189
|
for (let i2 = 0;i2 < stmts.length; i2++) {
|
|
191131
191190
|
const stmt = stmts[i2];
|
|
@@ -191155,7 +191214,9 @@ function extractMultiReturnJsxBranches(body) {
|
|
|
191155
191214
|
}
|
|
191156
191215
|
if (branches.length === 0)
|
|
191157
191216
|
return null;
|
|
191158
|
-
|
|
191217
|
+
if (preambleUnsafe(preamble, branches, fallback))
|
|
191218
|
+
return null;
|
|
191219
|
+
return { branches, fallback, preamble };
|
|
191159
191220
|
}
|
|
191160
191221
|
break;
|
|
191161
191222
|
}
|
|
@@ -191170,23 +191231,38 @@ function extractMultiReturnJsxBranches(body) {
|
|
|
191170
191231
|
const hasDefault = stmt.caseBlock.clauses.some((c) => import_typescript8.default.isDefaultClause(c));
|
|
191171
191232
|
if (!hasDefault)
|
|
191172
191233
|
return null;
|
|
191234
|
+
let pendingCases = [];
|
|
191173
191235
|
for (const clause of stmt.caseBlock.clauses) {
|
|
191236
|
+
if (import_typescript8.default.isCaseClause(clause) && clause.statements.length === 0) {
|
|
191237
|
+
pendingCases.push(clause.expression);
|
|
191238
|
+
continue;
|
|
191239
|
+
}
|
|
191174
191240
|
const jsxReturn = findJsxReturnInCaseClause(clause);
|
|
191175
191241
|
const nullReturn = findNullReturnInCaseClause(clause);
|
|
191176
191242
|
if (!jsxReturn && !nullReturn)
|
|
191177
191243
|
return null;
|
|
191244
|
+
if (!caseClauseIsDirectReturn(clause))
|
|
191245
|
+
return null;
|
|
191178
191246
|
if (import_typescript8.default.isCaseClause(clause)) {
|
|
191179
191247
|
branches.push({
|
|
191180
191248
|
condition: clause.expression,
|
|
191181
|
-
jsxReturn: jsxReturn ?? null
|
|
191249
|
+
jsxReturn: jsxReturn ?? null,
|
|
191250
|
+
extraCaseConditions: pendingCases.length > 0 ? pendingCases : undefined
|
|
191182
191251
|
});
|
|
191252
|
+
pendingCases = [];
|
|
191183
191253
|
} else {
|
|
191254
|
+
if (pendingCases.length > 0)
|
|
191255
|
+
return null;
|
|
191184
191256
|
fallback = jsxReturn ?? null;
|
|
191185
191257
|
}
|
|
191186
191258
|
}
|
|
191259
|
+
if (pendingCases.length > 0)
|
|
191260
|
+
return null;
|
|
191187
191261
|
if (branches.length === 0)
|
|
191188
191262
|
return null;
|
|
191189
|
-
|
|
191263
|
+
if (preambleUnsafe(preamble, branches, fallback))
|
|
191264
|
+
return null;
|
|
191265
|
+
return { branches, fallback, switchDiscriminant: stmt.expression, preamble };
|
|
191190
191266
|
}
|
|
191191
191267
|
if (import_typescript8.default.isReturnStatement(stmt) && stmt.expression) {
|
|
191192
191268
|
const expr = unwrapJsxTransparent(stmt.expression);
|
|
@@ -191197,13 +191273,22 @@ function extractMultiReturnJsxBranches(body) {
|
|
|
191197
191273
|
}
|
|
191198
191274
|
continue;
|
|
191199
191275
|
}
|
|
191200
|
-
if (import_typescript8.default.isVariableStatement(stmt))
|
|
191276
|
+
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
191277
|
+
const declFlags = stmt.declarationList.flags;
|
|
191278
|
+
const isConstOrLet = (declFlags & import_typescript8.default.NodeFlags.Const) !== 0 || (declFlags & import_typescript8.default.NodeFlags.Let) !== 0;
|
|
191279
|
+
if (allowPreamble && isConstOrLet && branches.length === 0 && fallback === null) {
|
|
191280
|
+
preamble.push(stmt);
|
|
191281
|
+
continue;
|
|
191282
|
+
}
|
|
191201
191283
|
return null;
|
|
191284
|
+
}
|
|
191202
191285
|
return null;
|
|
191203
191286
|
}
|
|
191204
191287
|
if (branches.length === 0)
|
|
191205
191288
|
return null;
|
|
191206
|
-
|
|
191289
|
+
if (preambleUnsafe(preamble, branches, fallback))
|
|
191290
|
+
return null;
|
|
191291
|
+
return { branches, fallback, preamble };
|
|
191207
191292
|
}
|
|
191208
191293
|
function isDirectReturnBlock(node) {
|
|
191209
191294
|
if (import_typescript8.default.isReturnStatement(node))
|
|
@@ -191213,9 +191298,9 @@ function isDirectReturnBlock(node) {
|
|
|
191213
191298
|
for (const stmt of node.statements) {
|
|
191214
191299
|
if (import_typescript8.default.isReturnStatement(stmt)) {
|
|
191215
191300
|
returnCount++;
|
|
191216
|
-
|
|
191217
|
-
return false;
|
|
191301
|
+
continue;
|
|
191218
191302
|
}
|
|
191303
|
+
return false;
|
|
191219
191304
|
}
|
|
191220
191305
|
return returnCount === 1;
|
|
191221
191306
|
}
|
|
@@ -191246,6 +191331,24 @@ function findJsxReturnInCaseClause(clause) {
|
|
|
191246
191331
|
}
|
|
191247
191332
|
return null;
|
|
191248
191333
|
}
|
|
191334
|
+
function caseClauseIsDirectReturn(clause) {
|
|
191335
|
+
let returnCount = 0;
|
|
191336
|
+
let seenReturn = false;
|
|
191337
|
+
for (const stmt of clause.statements) {
|
|
191338
|
+
if (import_typescript8.default.isReturnStatement(stmt)) {
|
|
191339
|
+
returnCount++;
|
|
191340
|
+
seenReturn = true;
|
|
191341
|
+
continue;
|
|
191342
|
+
}
|
|
191343
|
+
if (import_typescript8.default.isBreakStatement(stmt)) {
|
|
191344
|
+
if (!seenReturn)
|
|
191345
|
+
return false;
|
|
191346
|
+
continue;
|
|
191347
|
+
}
|
|
191348
|
+
return false;
|
|
191349
|
+
}
|
|
191350
|
+
return returnCount === 1;
|
|
191351
|
+
}
|
|
191249
191352
|
function findNullReturnInCaseClause(clause) {
|
|
191250
191353
|
for (const stmt of clause.statements) {
|
|
191251
191354
|
if (import_typescript8.default.isReturnStatement(stmt) && stmt.expression) {
|
|
@@ -193261,6 +193364,9 @@ var REACTIVE_BINDING_KINDS = new Set([
|
|
|
193261
193364
|
function isReactiveOrigin(origin) {
|
|
193262
193365
|
return origin.freeRefs?.some((r) => REACTIVE_BINDING_KINDS.has(r.kind)) ?? false;
|
|
193263
193366
|
}
|
|
193367
|
+
function tsxSourceText(raw) {
|
|
193368
|
+
return raw;
|
|
193369
|
+
}
|
|
193264
193370
|
var AttrValueOf = {
|
|
193265
193371
|
literal(value) {
|
|
193266
193372
|
return { kind: "literal", value };
|
|
@@ -194391,8 +194497,13 @@ function attachParsedExpressions(node, analyzer, bound = EMPTY_BOUND) {
|
|
|
194391
194497
|
for (const child of nested.children)
|
|
194392
194498
|
attachParsedExpressions(child, analyzer, loopBound);
|
|
194393
194499
|
}
|
|
194394
|
-
for (const
|
|
194395
|
-
|
|
194500
|
+
for (const seg of node.flatMapCallback?.segments ?? []) {
|
|
194501
|
+
if (seg.kind === "jsx")
|
|
194502
|
+
attachParsedExpressions(seg.ir, analyzer, loopBound);
|
|
194503
|
+
}
|
|
194504
|
+
for (const seg of node.preamble?.segments ?? []) {
|
|
194505
|
+
if (seg.kind === "jsx")
|
|
194506
|
+
attachParsedExpressions(seg.ir, analyzer, loopBound);
|
|
194396
194507
|
}
|
|
194397
194508
|
break;
|
|
194398
194509
|
}
|
|
@@ -195027,74 +195138,78 @@ function transformMultiReturnJsxFunctionCall(callExpr, info, ctx) {
|
|
|
195027
195138
|
ctx.analyzer.getJS = substitutedGetJS;
|
|
195028
195139
|
try {
|
|
195029
195140
|
const loc = getSourceLocation(callExpr, ctx.sourceFile, ctx.filePath);
|
|
195030
|
-
|
|
195031
|
-
type: "expression",
|
|
195032
|
-
expr: "null",
|
|
195033
|
-
typeInfo: { kind: "primitive", raw: "null", primitive: "null" },
|
|
195034
|
-
reactive: false,
|
|
195035
|
-
slotId: null,
|
|
195036
|
-
loc,
|
|
195037
|
-
origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
|
|
195038
|
-
};
|
|
195039
|
-
let result = info.fallback ? transformNode(info.fallback, ctx) ?? nullExpr : nullExpr;
|
|
195040
|
-
for (let i2 = info.branches.length - 1;i2 >= 0; i2--) {
|
|
195041
|
-
const branch = info.branches[i2];
|
|
195042
|
-
let conditionText;
|
|
195043
|
-
if (info.switchDiscriminant) {
|
|
195044
|
-
const discText = substitutedGetJS(info.switchDiscriminant);
|
|
195045
|
-
const caseText = substitutedGetJS(branch.condition);
|
|
195046
|
-
conditionText = `${discText} === ${caseText}`;
|
|
195047
|
-
} else {
|
|
195048
|
-
conditionText = substitutedGetJS(branch.condition);
|
|
195049
|
-
}
|
|
195050
|
-
const env = makeBindingEnv(ctx);
|
|
195051
|
-
const caseFreeRefs = resolveFreeRefs(branch.condition, env);
|
|
195052
|
-
const discFreeRefs = info.switchDiscriminant ? resolveFreeRefs(info.switchDiscriminant, env) : [];
|
|
195053
|
-
const conditionOrigin = {
|
|
195054
|
-
phase: "tick",
|
|
195055
|
-
scope: "template",
|
|
195056
|
-
effect: "pure",
|
|
195057
|
-
freeRefs: [...discFreeRefs, ...caseFreeRefs]
|
|
195058
|
-
};
|
|
195059
|
-
const reactive = isReactiveExpression(conditionText, ctx, branch.condition) || isReactiveOrigin(conditionOrigin);
|
|
195060
|
-
const loopParamReactive = !reactive && referencesLoopParam(conditionText, ctx);
|
|
195061
|
-
const callsReactive = exprCallsReactiveGetters(branch.condition, ctx) || (info.switchDiscriminant ? exprCallsReactiveGetters(info.switchDiscriminant, ctx) : false);
|
|
195062
|
-
const hasCalls = exprHasFunctionCalls(branch.condition) || (info.switchDiscriminant ? exprHasFunctionCalls(info.switchDiscriminant) : false);
|
|
195063
|
-
const needsSlot = reactive || loopParamReactive || callsReactive || hasCalls;
|
|
195064
|
-
const slotId = needsSlot ? generateSlotId(ctx) : null;
|
|
195065
|
-
const whenTrue = branch.jsxReturn ? transformNode(branch.jsxReturn, ctx) ?? nullExpr : nullExpr;
|
|
195066
|
-
let templateCondition;
|
|
195067
|
-
if (info.switchDiscriminant) {
|
|
195068
|
-
const discRewritten = rewriteBarePropRefs2(substitutedGetJS(info.switchDiscriminant), info.switchDiscriminant, ctx);
|
|
195069
|
-
const caseRewritten = rewriteBarePropRefs2(substitutedGetJS(branch.condition), branch.condition, ctx);
|
|
195070
|
-
const discPart = discRewritten ?? substitutedGetJS(info.switchDiscriminant);
|
|
195071
|
-
const casePart = caseRewritten ?? substitutedGetJS(branch.condition);
|
|
195072
|
-
templateCondition = `${discPart} === ${casePart}`;
|
|
195073
|
-
} else {
|
|
195074
|
-
templateCondition = rewriteBarePropRefs2(conditionText, branch.condition, ctx);
|
|
195075
|
-
}
|
|
195076
|
-
const conditional = {
|
|
195077
|
-
type: "conditional",
|
|
195078
|
-
condition: conditionText,
|
|
195079
|
-
templateCondition,
|
|
195080
|
-
conditionType: null,
|
|
195081
|
-
reactive,
|
|
195082
|
-
whenTrue,
|
|
195083
|
-
whenFalse: result,
|
|
195084
|
-
slotId,
|
|
195085
|
-
callsReactiveGetters: callsReactive || undefined,
|
|
195086
|
-
hasFunctionCalls: hasCalls || undefined,
|
|
195087
|
-
loc,
|
|
195088
|
-
origin: conditionOrigin
|
|
195089
|
-
};
|
|
195090
|
-
result = conditional;
|
|
195091
|
-
}
|
|
195092
|
-
return result;
|
|
195141
|
+
return foldMultiReturnBranches(info, ctx, loc, substitutedGetJS);
|
|
195093
195142
|
} finally {
|
|
195094
195143
|
ctx.getJS = originalCtxGetJS;
|
|
195095
195144
|
ctx.analyzer.getJS = originalAnalyzerGetJS;
|
|
195096
195145
|
}
|
|
195097
195146
|
}
|
|
195147
|
+
function foldMultiReturnBranches(info, ctx, loc, getText) {
|
|
195148
|
+
const nullExpr = {
|
|
195149
|
+
type: "expression",
|
|
195150
|
+
expr: "null",
|
|
195151
|
+
typeInfo: { kind: "primitive", raw: "null", primitive: "null" },
|
|
195152
|
+
reactive: false,
|
|
195153
|
+
slotId: null,
|
|
195154
|
+
loc,
|
|
195155
|
+
origin: { phase: "tick", scope: "template", effect: "pure", freeRefs: [] }
|
|
195156
|
+
};
|
|
195157
|
+
let result = info.fallback ? transformNode(info.fallback, ctx) ?? nullExpr : nullExpr;
|
|
195158
|
+
for (let i2 = info.branches.length - 1;i2 >= 0; i2--) {
|
|
195159
|
+
const branch = info.branches[i2];
|
|
195160
|
+
const caseConds = info.switchDiscriminant ? [branch.condition, ...branch.extraCaseConditions ?? []] : [branch.condition];
|
|
195161
|
+
let conditionText;
|
|
195162
|
+
if (info.switchDiscriminant) {
|
|
195163
|
+
const discText = getText(info.switchDiscriminant);
|
|
195164
|
+
conditionText = caseConds.map((c) => `(${discText}) === (${getText(c)})`).join(" || ");
|
|
195165
|
+
} else {
|
|
195166
|
+
conditionText = getText(branch.condition);
|
|
195167
|
+
}
|
|
195168
|
+
const env = makeBindingEnv(ctx);
|
|
195169
|
+
const caseFreeRefs = caseConds.flatMap((c) => resolveFreeRefs(c, env));
|
|
195170
|
+
const discFreeRefs = info.switchDiscriminant ? resolveFreeRefs(info.switchDiscriminant, env) : [];
|
|
195171
|
+
const conditionOrigin = {
|
|
195172
|
+
phase: "tick",
|
|
195173
|
+
scope: "template",
|
|
195174
|
+
effect: "pure",
|
|
195175
|
+
freeRefs: [...discFreeRefs, ...caseFreeRefs]
|
|
195176
|
+
};
|
|
195177
|
+
const reactive = isReactiveExpression(conditionText, ctx, branch.condition) || isReactiveOrigin(conditionOrigin);
|
|
195178
|
+
const loopParamReactive = !reactive && referencesLoopParam(conditionText, ctx);
|
|
195179
|
+
const callsReactive = caseConds.some((c) => exprCallsReactiveGetters(c, ctx)) || (info.switchDiscriminant ? exprCallsReactiveGetters(info.switchDiscriminant, ctx) : false);
|
|
195180
|
+
const hasCalls = caseConds.some((c) => exprHasFunctionCalls(c)) || (info.switchDiscriminant ? exprHasFunctionCalls(info.switchDiscriminant) : false);
|
|
195181
|
+
const needsSlot = reactive || loopParamReactive || callsReactive || hasCalls;
|
|
195182
|
+
const slotId = needsSlot ? generateSlotId(ctx) : null;
|
|
195183
|
+
const whenTrue = branch.jsxReturn ? transformNode(branch.jsxReturn, ctx) ?? nullExpr : nullExpr;
|
|
195184
|
+
let templateCondition;
|
|
195185
|
+
if (info.switchDiscriminant) {
|
|
195186
|
+
const discRewritten = rewriteBarePropRefs2(getText(info.switchDiscriminant), info.switchDiscriminant, ctx);
|
|
195187
|
+
const discPart = discRewritten ?? getText(info.switchDiscriminant);
|
|
195188
|
+
templateCondition = caseConds.map((c) => {
|
|
195189
|
+
const casePart = rewriteBarePropRefs2(getText(c), c, ctx) ?? getText(c);
|
|
195190
|
+
return `(${discPart}) === (${casePart})`;
|
|
195191
|
+
}).join(" || ");
|
|
195192
|
+
} else {
|
|
195193
|
+
templateCondition = rewriteBarePropRefs2(conditionText, branch.condition, ctx);
|
|
195194
|
+
}
|
|
195195
|
+
const conditional = {
|
|
195196
|
+
type: "conditional",
|
|
195197
|
+
condition: conditionText,
|
|
195198
|
+
templateCondition,
|
|
195199
|
+
conditionType: null,
|
|
195200
|
+
reactive,
|
|
195201
|
+
whenTrue,
|
|
195202
|
+
whenFalse: result,
|
|
195203
|
+
slotId,
|
|
195204
|
+
callsReactiveGetters: callsReactive || undefined,
|
|
195205
|
+
hasFunctionCalls: hasCalls || undefined,
|
|
195206
|
+
loc,
|
|
195207
|
+
origin: conditionOrigin
|
|
195208
|
+
};
|
|
195209
|
+
result = conditional;
|
|
195210
|
+
}
|
|
195211
|
+
return result;
|
|
195212
|
+
}
|
|
195098
195213
|
function transformConditional(node, ctx) {
|
|
195099
195214
|
const condition = ctx.getJS(node.condition);
|
|
195100
195215
|
const conditionOrigin = {
|
|
@@ -195945,9 +196060,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
195945
196060
|
let filterPredicate;
|
|
195946
196061
|
let sortComparator;
|
|
195947
196062
|
let chainOrder;
|
|
195948
|
-
let
|
|
195949
|
-
let templateMapPreamble;
|
|
195950
|
-
let typedMapPreamble;
|
|
196063
|
+
let preamble;
|
|
195951
196064
|
let iterationShape;
|
|
195952
196065
|
let objectIteration;
|
|
195953
196066
|
const setArray = (node2) => {
|
|
@@ -195977,7 +196090,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
195977
196090
|
const innerFilter = isFilterCall(sortInfo.array);
|
|
195978
196091
|
const sortExtraction = extractSortComparator(sortInfo.callback, sortInfo.method, ctx);
|
|
195979
196092
|
if (isClientOnly || !sortExtraction.result) {
|
|
195980
|
-
if (!isClientOnly && sortExtraction.unsupportedReason) {
|
|
196093
|
+
if (!isClientOnly && sortExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("sort") ?? false)) {
|
|
195981
196094
|
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(sortInfo.callback, ctx.sourceFile, ctx.filePath), {
|
|
195982
196095
|
message: `Expression cannot be compiled to marked template: ${sortExtraction.unsupportedReason}`,
|
|
195983
196096
|
suggestion: {
|
|
@@ -195992,7 +196105,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
195992
196105
|
chainOrder = "filter-sort";
|
|
195993
196106
|
const filterExtraction = extractFilterPredicate(innerFilter.callback, ctx);
|
|
195994
196107
|
if (isClientOnly || !filterExtraction.result) {
|
|
195995
|
-
if (!isClientOnly && filterExtraction.unsupportedReason) {
|
|
196108
|
+
if (!isClientOnly && filterExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("filter") ?? false)) {
|
|
195996
196109
|
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(innerFilter.callback, ctx.sourceFile, ctx.filePath), {
|
|
195997
196110
|
message: `Expression cannot be compiled to marked template: ${filterExtraction.unsupportedReason}`,
|
|
195998
196111
|
suggestion: {
|
|
@@ -196015,7 +196128,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
196015
196128
|
const innerSort = isSortCall(filterInfo.array);
|
|
196016
196129
|
const filterExtraction = extractFilterPredicate(filterInfo.callback, ctx);
|
|
196017
196130
|
if (isClientOnly || !filterExtraction.result) {
|
|
196018
|
-
if (!isClientOnly && filterExtraction.unsupportedReason) {
|
|
196131
|
+
if (!isClientOnly && filterExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("filter") ?? false)) {
|
|
196019
196132
|
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(filterInfo.callback, ctx.sourceFile, ctx.filePath), {
|
|
196020
196133
|
message: `Expression cannot be compiled to marked template: ${filterExtraction.unsupportedReason}`,
|
|
196021
196134
|
suggestion: {
|
|
@@ -196030,7 +196143,7 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
196030
196143
|
chainOrder = "sort-filter";
|
|
196031
196144
|
const sortExtraction = extractSortComparator(innerSort.callback, innerSort.method, ctx);
|
|
196032
196145
|
if (isClientOnly || !sortExtraction.result) {
|
|
196033
|
-
if (!isClientOnly && sortExtraction.unsupportedReason) {
|
|
196146
|
+
if (!isClientOnly && sortExtraction.unsupportedReason && !(ctx.analyzer.acceptsCallbackBody?.("sort") ?? false)) {
|
|
196034
196147
|
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(innerSort.callback, ctx.sourceFile, ctx.filePath), {
|
|
196035
196148
|
message: `Expression cannot be compiled to marked template: ${sortExtraction.unsupportedReason}`,
|
|
196036
196149
|
suggestion: {
|
|
@@ -196145,7 +196258,24 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
196145
196258
|
} else if (method === "flatMap" && import_typescript11.default.isArrayLiteralExpression(body)) {
|
|
196146
196259
|
children = transformArrayLiteralChildren(body, ctx);
|
|
196147
196260
|
} else if (import_typescript11.default.isBlock(body)) {
|
|
196148
|
-
const
|
|
196261
|
+
const multiReturn = method !== "flatMap" ? extractMultiReturnJsxBranches(body, true) : null;
|
|
196262
|
+
if (multiReturn && multiReturn.branches.length > 0) {
|
|
196263
|
+
const loc = getSourceLocation(body, ctx.sourceFile, ctx.filePath);
|
|
196264
|
+
children = [foldMultiReturnBranches(multiReturn, ctx, loc, ctx.getJS)];
|
|
196265
|
+
const pre = multiReturn.preamble ?? [];
|
|
196266
|
+
if (pre.length > 0) {
|
|
196267
|
+
preamble = preambleFromValueStatements(pre, ctx);
|
|
196268
|
+
if (!isClientOnly && !(ctx.analyzer.acceptsCallbackBody?.("map") ?? false)) {
|
|
196269
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, loc, {
|
|
196270
|
+
message: "A .map() callback body with a `const`/`let` preamble before its " + "branches cannot be lowered to a template: the loop-local binding " + "cannot be carried into a conditional branch on this backend.",
|
|
196271
|
+
suggestion: {
|
|
196272
|
+
message: "Add /* @client */ to evaluate this expression on the client only"
|
|
196273
|
+
}
|
|
196274
|
+
}));
|
|
196275
|
+
}
|
|
196276
|
+
}
|
|
196277
|
+
}
|
|
196278
|
+
const returnStmt = children.length === 0 ? body.statements.find((s) => import_typescript11.default.isReturnStatement(s) && s.expression != null) : undefined;
|
|
196149
196279
|
if (returnStmt && returnStmt.expression) {
|
|
196150
196280
|
let returnExpr = returnStmt.expression;
|
|
196151
196281
|
while (import_typescript11.default.isParenthesizedExpression(returnExpr)) {
|
|
@@ -196157,32 +196287,53 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
196157
196287
|
children = [transformed];
|
|
196158
196288
|
}
|
|
196159
196289
|
}
|
|
196160
|
-
|
|
196161
|
-
const templatePreambleStmts = [];
|
|
196162
|
-
const typedPreambleStmts = [];
|
|
196163
|
-
let hasTypeDiff = false;
|
|
196164
|
-
let hasTemplateDiff = false;
|
|
196290
|
+
let jsxPreambleStmt;
|
|
196165
196291
|
for (const stmt of body.statements) {
|
|
196166
196292
|
if (stmt === returnStmt)
|
|
196167
196293
|
break;
|
|
196168
|
-
|
|
196169
|
-
|
|
196170
|
-
|
|
196171
|
-
|
|
196172
|
-
templatePreambleStmts.push(tjs.endsWith(";") ? tjs : tjs + ";");
|
|
196173
|
-
typedPreambleStmts.push(ts12.endsWith(";") ? ts12 : ts12 + ";");
|
|
196174
|
-
if (js !== ts12)
|
|
196175
|
-
hasTypeDiff = true;
|
|
196176
|
-
if (js !== tjs)
|
|
196177
|
-
hasTemplateDiff = true;
|
|
196294
|
+
if (containsJsxInExpression(stmt)) {
|
|
196295
|
+
jsxPreambleStmt = stmt;
|
|
196296
|
+
break;
|
|
196297
|
+
}
|
|
196178
196298
|
}
|
|
196179
|
-
if (
|
|
196180
|
-
|
|
196181
|
-
if (
|
|
196182
|
-
|
|
196299
|
+
if (jsxPreambleStmt) {
|
|
196300
|
+
const jsRuntime = isClientOnly || (ctx.analyzer.acceptsCallbackBody?.("map") ?? false);
|
|
196301
|
+
if (children.length === 0) {
|
|
196302
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(jsxPreambleStmt, ctx.sourceFile, ctx.filePath), {
|
|
196303
|
+
message: "A .map() callback that builds JSX in a statement before its " + "`return` must return a single JSX element that embeds the " + "built array — this return shape has no element root to host it.",
|
|
196304
|
+
suggestion: {
|
|
196305
|
+
message: "Wrap the result in one element root, e.g. `return <tr key={item.id}>{out}</tr>`."
|
|
196306
|
+
}
|
|
196307
|
+
}));
|
|
196308
|
+
} else if (!jsRuntime) {
|
|
196309
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(jsxPreambleStmt, ctx.sourceFile, ctx.filePath), {
|
|
196310
|
+
message: "A .map() callback that builds JSX in a statement before its " + "`return` (for example pushing elements into an array in a loop) " + "cannot be lowered to a template on this backend.",
|
|
196311
|
+
suggestion: {
|
|
196312
|
+
message: "Add /* @client */ to render this loop on the client only"
|
|
196313
|
+
}
|
|
196314
|
+
}));
|
|
196315
|
+
} else {
|
|
196316
|
+
const collected = buildPreambleSegments(body.statements, returnStmt, ctx);
|
|
196317
|
+
if (collected.refusalNode) {
|
|
196318
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(collected.refusalNode, ctx.sourceFile, ctx.filePath), {
|
|
196319
|
+
message: "A JSX element built in a .map() callback preamble cannot carry " + "event handlers, components, nested loops, or reactive expressions, " + "and cannot sit inside a template literal — the verbatim render " + "path builds it once, with no reactive wiring.",
|
|
196320
|
+
suggestion: {
|
|
196321
|
+
message: "Return the element directly (not through a preamble variable), " + "or add /* @client */ to render the loop on the client only."
|
|
196322
|
+
}
|
|
196323
|
+
}));
|
|
196324
|
+
} else {
|
|
196325
|
+
preamble = collected.preamble;
|
|
196326
|
+
}
|
|
196327
|
+
}
|
|
196328
|
+
} else {
|
|
196329
|
+
const valueStmts = [];
|
|
196330
|
+
for (const stmt of body.statements) {
|
|
196331
|
+
if (stmt === returnStmt)
|
|
196332
|
+
break;
|
|
196333
|
+
valueStmts.push(stmt);
|
|
196183
196334
|
}
|
|
196184
|
-
if (
|
|
196185
|
-
|
|
196335
|
+
if (valueStmts.length > 0) {
|
|
196336
|
+
preamble = preambleFromValueStatements(valueStmts, ctx);
|
|
196186
196337
|
}
|
|
196187
196338
|
}
|
|
196188
196339
|
}
|
|
@@ -196211,6 +196362,31 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
196211
196362
|
const itemConditional = children.length > 0 ? loopBodyItemConditional(children) : null;
|
|
196212
196363
|
const bodyIsItemConditional = itemConditional !== null;
|
|
196213
196364
|
const key = bodyIsItemConditional ? extractItemConditionalKey(itemConditional) : children.length > 0 ? extractLoopKey(children[0]) : null;
|
|
196365
|
+
const declaredNameSet = preamble && preamble.declaredNames.length > 0 ? new Set(preamble.declaredNames) : undefined;
|
|
196366
|
+
if (key && declaredNameSet) {
|
|
196367
|
+
const keyRefs = extractFreeIdentifiersFromText(key);
|
|
196368
|
+
const usesLocal = [...keyRefs].some((r) => declaredNameSet.has(r));
|
|
196369
|
+
if (usesLocal) {
|
|
196370
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
|
|
196371
|
+
message: "A .map() loop key must be derivable from the loop item — it is " + "evaluated before the callback body runs, so it cannot reference a " + "value computed in the callback preamble.",
|
|
196372
|
+
suggestion: {
|
|
196373
|
+
message: "Derive the key directly from the loop item (e.g. key={item.id})."
|
|
196374
|
+
}
|
|
196375
|
+
}));
|
|
196376
|
+
}
|
|
196377
|
+
}
|
|
196378
|
+
if (preamble && preamble.builderNames.length > 0) {
|
|
196379
|
+
flagArrayChildExpressions(children, new Set(preamble.builderNames));
|
|
196380
|
+
}
|
|
196381
|
+
if (preamble && preamble.builderNames.length > 0 && children.length === 1 && children[0].type === "component") {
|
|
196382
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
|
|
196383
|
+
message: "A .map() callback that builds JSX in its preamble cannot return a " + "component: the built elements would reach the component as raw HTML " + "strings on the client but as JSX elements at SSR (a silent divergence).",
|
|
196384
|
+
suggestion: {
|
|
196385
|
+
message: "Return a plain element root that embeds the array, or move the " + "building logic inside the component."
|
|
196386
|
+
}
|
|
196387
|
+
}));
|
|
196388
|
+
preamble = undefined;
|
|
196389
|
+
}
|
|
196214
196390
|
let childComponent;
|
|
196215
196391
|
if (children.length === 1 && children[0].type === "component") {
|
|
196216
196392
|
const comp = children[0];
|
|
@@ -196259,11 +196435,9 @@ function transformMapCall(node, ctx, isClientOnly = false, method = "map") {
|
|
|
196259
196435
|
objectIteration,
|
|
196260
196436
|
depth,
|
|
196261
196437
|
clientOnly: isClientOnly || undefined,
|
|
196262
|
-
|
|
196263
|
-
templateMapPreamble,
|
|
196438
|
+
preamble,
|
|
196264
196439
|
paramType,
|
|
196265
196440
|
indexType,
|
|
196266
|
-
typedMapPreamble,
|
|
196267
196441
|
paramBindings,
|
|
196268
196442
|
arrayFreeIdentifiers: extractFreeIdentifiersFromNode(arrayExpr),
|
|
196269
196443
|
flatMapCallback,
|
|
@@ -196299,47 +196473,206 @@ function containsJsx(node) {
|
|
|
196299
196473
|
function buildFlatMapCallback(callback, body, ctx) {
|
|
196300
196474
|
if (!containsJsx(body))
|
|
196301
196475
|
return;
|
|
196302
|
-
const
|
|
196303
|
-
const
|
|
196304
|
-
|
|
196305
|
-
const
|
|
196306
|
-
const bodyText = sourceText.slice(bodyStart, bodyEnd);
|
|
196307
|
-
const jsxNodes = [];
|
|
196308
|
-
function collectJsx(n) {
|
|
196476
|
+
const leafSpans = [];
|
|
196477
|
+
const leafIrs = [];
|
|
196478
|
+
let refusalNode;
|
|
196479
|
+
const collectJsx = (n, underTemplate) => {
|
|
196309
196480
|
if (import_typescript11.default.isJsxElement(n) || import_typescript11.default.isJsxSelfClosingElement(n) || import_typescript11.default.isJsxFragment(n)) {
|
|
196310
|
-
|
|
196311
|
-
|
|
196312
|
-
|
|
196313
|
-
|
|
196314
|
-
});
|
|
196481
|
+
if (underTemplate)
|
|
196482
|
+
refusalNode ??= n;
|
|
196483
|
+
leafSpans.push({ start: n.getStart(ctx.sourceFile), end: n.getEnd() });
|
|
196484
|
+
const ir = transformNode(n, ctx);
|
|
196485
|
+
leafIrs.push(ir ?? { type: "text", value: "", loc: getSourceLocation(n, ctx.sourceFile, ctx.filePath) });
|
|
196315
196486
|
return;
|
|
196316
196487
|
}
|
|
196317
|
-
n.
|
|
196318
|
-
|
|
196319
|
-
|
|
196320
|
-
|
|
196488
|
+
const inTemplate = underTemplate || import_typescript11.default.isTemplateExpression(n) || import_typescript11.default.isTaggedTemplateExpression(n);
|
|
196489
|
+
n.forEachChild((c) => collectJsx(c, inTemplate));
|
|
196490
|
+
};
|
|
196491
|
+
collectJsx(body, false);
|
|
196492
|
+
if (leafSpans.length === 0)
|
|
196493
|
+
return;
|
|
196494
|
+
if (refusalNode) {
|
|
196495
|
+
ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(refusalNode, ctx.sourceFile, ctx.filePath), {
|
|
196496
|
+
message: "A JSX element inside a template literal in a .flatMap() callback " + "body cannot be compiled.",
|
|
196497
|
+
suggestion: { message: "Build the element outside the template literal." }
|
|
196498
|
+
}));
|
|
196321
196499
|
return;
|
|
196322
|
-
let compiledBody = "";
|
|
196323
|
-
let lastEnd = 0;
|
|
196324
|
-
for (let i2 = 0;i2 < jsxNodes.length; i2++) {
|
|
196325
|
-
const { node, start, end } = jsxNodes[i2];
|
|
196326
|
-
const placeholder = `__BF_JSX_${i2}__`;
|
|
196327
|
-
compiledBody += bodyText.slice(lastEnd, start) + placeholder;
|
|
196328
|
-
lastEnd = end;
|
|
196329
|
-
const ir = transformNode(node, ctx);
|
|
196330
|
-
fragments.push({
|
|
196331
|
-
placeholder,
|
|
196332
|
-
ir: ir ?? { type: "text", value: "", loc: getSourceLocation(node, ctx.sourceFile, ctx.filePath) }
|
|
196333
|
-
});
|
|
196334
196500
|
}
|
|
196335
|
-
|
|
196501
|
+
const pieces = reconstructAsSegments(body, ctx.sourceFile, ctx.analyzer.typeExcludeRanges, leafSpans);
|
|
196502
|
+
const segments = pieces.map((piece) => {
|
|
196503
|
+
if ("marker" in piece)
|
|
196504
|
+
return { kind: "jsx", ir: leafIrs[piece.marker] };
|
|
196505
|
+
const tpl = rewriteBarePropRefs2(piece.js, body, ctx);
|
|
196506
|
+
return tpl !== undefined && tpl !== piece.js ? { kind: "js", text: piece.js, templateText: tpl } : { kind: "js", text: piece.js };
|
|
196507
|
+
});
|
|
196336
196508
|
const paramsText = callback.parameters.map((p) => p.getText(ctx.sourceFile)).join(", ");
|
|
196337
196509
|
return {
|
|
196338
196510
|
params: `(${paramsText})`,
|
|
196339
|
-
|
|
196340
|
-
|
|
196341
|
-
|
|
196342
|
-
|
|
196511
|
+
segments,
|
|
196512
|
+
rawBody: tsxSourceText(body.getText(ctx.sourceFile))
|
|
196513
|
+
};
|
|
196514
|
+
}
|
|
196515
|
+
function preambleFragmentNeedsWiring(ir) {
|
|
196516
|
+
switch (ir.type) {
|
|
196517
|
+
case "component":
|
|
196518
|
+
case "loop":
|
|
196519
|
+
return true;
|
|
196520
|
+
case "element":
|
|
196521
|
+
if (ir.events.length > 0)
|
|
196522
|
+
return true;
|
|
196523
|
+
if (ir.attrs.some((a) => a.name.startsWith("...")))
|
|
196524
|
+
return true;
|
|
196525
|
+
return ir.children.some(preambleFragmentNeedsWiring);
|
|
196526
|
+
case "expression":
|
|
196527
|
+
return ir.reactive === true;
|
|
196528
|
+
case "conditional":
|
|
196529
|
+
return preambleFragmentNeedsWiring(ir.whenTrue) || (ir.whenFalse ? preambleFragmentNeedsWiring(ir.whenFalse) : false);
|
|
196530
|
+
case "fragment":
|
|
196531
|
+
return ir.children.some(preambleFragmentNeedsWiring);
|
|
196532
|
+
default:
|
|
196533
|
+
return false;
|
|
196534
|
+
}
|
|
196535
|
+
}
|
|
196536
|
+
function flagArrayChildExpressions(nodes, declared) {
|
|
196537
|
+
for (const node of nodes) {
|
|
196538
|
+
switch (node.type) {
|
|
196539
|
+
case "expression": {
|
|
196540
|
+
const name = node.expr.trim();
|
|
196541
|
+
const refs = extractFreeIdentifiersFromText(node.expr);
|
|
196542
|
+
if (refs.size === 1 && refs.has(name) && declared.has(name)) {
|
|
196543
|
+
node.joinArrayChild = true;
|
|
196544
|
+
}
|
|
196545
|
+
break;
|
|
196546
|
+
}
|
|
196547
|
+
case "element":
|
|
196548
|
+
case "fragment":
|
|
196549
|
+
flagArrayChildExpressions(node.children, declared);
|
|
196550
|
+
break;
|
|
196551
|
+
case "conditional":
|
|
196552
|
+
flagArrayChildExpressions([node.whenTrue, ...node.whenFalse ? [node.whenFalse] : []], declared);
|
|
196553
|
+
break;
|
|
196554
|
+
}
|
|
196555
|
+
}
|
|
196556
|
+
}
|
|
196557
|
+
function collectBindingNames(name, out) {
|
|
196558
|
+
if (import_typescript11.default.isIdentifier(name)) {
|
|
196559
|
+
out.add(name.text);
|
|
196560
|
+
return;
|
|
196561
|
+
}
|
|
196562
|
+
for (const el of name.elements) {
|
|
196563
|
+
if (import_typescript11.default.isBindingElement(el))
|
|
196564
|
+
collectBindingNames(el.name, out);
|
|
196565
|
+
}
|
|
196566
|
+
}
|
|
196567
|
+
function collectPreambleDeclaredNames(stmt, out) {
|
|
196568
|
+
if (import_typescript11.default.isVariableStatement(stmt)) {
|
|
196569
|
+
for (const decl of stmt.declarationList.declarations) {
|
|
196570
|
+
collectBindingNames(decl.name, out);
|
|
196571
|
+
}
|
|
196572
|
+
} else if (import_typescript11.default.isFunctionDeclaration(stmt) && stmt.name) {
|
|
196573
|
+
out.add(stmt.name.text);
|
|
196574
|
+
}
|
|
196575
|
+
}
|
|
196576
|
+
function preambleFromValueStatements(statements, ctx) {
|
|
196577
|
+
const segments = [];
|
|
196578
|
+
const typedParts = [];
|
|
196579
|
+
const declared = new Set;
|
|
196580
|
+
for (const stmt of statements) {
|
|
196581
|
+
collectPreambleDeclaredNames(stmt, declared);
|
|
196582
|
+
const js0 = ctx.getJS(stmt);
|
|
196583
|
+
const tjs0 = ctx.getTemplateJS(stmt);
|
|
196584
|
+
const raw0 = stmt.getText(ctx.sourceFile);
|
|
196585
|
+
const js = (js0.endsWith(";") ? js0 : js0 + ";") + " ";
|
|
196586
|
+
const tjs = (tjs0.endsWith(";") ? tjs0 : tjs0 + ";") + " ";
|
|
196587
|
+
typedParts.push(raw0.endsWith(";") ? raw0 : raw0 + ";");
|
|
196588
|
+
segments.push(tjs !== js ? { kind: "js", text: js, templateText: tjs } : { kind: "js", text: js });
|
|
196589
|
+
}
|
|
196590
|
+
return {
|
|
196591
|
+
segments: trimPreambleSegments(segments),
|
|
196592
|
+
ssrText: tsxSourceText(typedParts.join(" ")),
|
|
196593
|
+
declaredNames: [...declared],
|
|
196594
|
+
builderNames: []
|
|
196595
|
+
};
|
|
196596
|
+
}
|
|
196597
|
+
function trimPreambleSegments(segments) {
|
|
196598
|
+
const last = segments[segments.length - 1];
|
|
196599
|
+
if (last?.kind === "js") {
|
|
196600
|
+
const text = last.text.trimEnd();
|
|
196601
|
+
const templateText = last.templateText?.trimEnd();
|
|
196602
|
+
segments[segments.length - 1] = templateText !== undefined ? { kind: "js", text, templateText } : { kind: "js", text };
|
|
196603
|
+
}
|
|
196604
|
+
return segments;
|
|
196605
|
+
}
|
|
196606
|
+
function buildPreambleSegments(statements, returnStmt, ctx) {
|
|
196607
|
+
const segments = [];
|
|
196608
|
+
const typedParts = [];
|
|
196609
|
+
const declared = new Set;
|
|
196610
|
+
const builders = new Set;
|
|
196611
|
+
let refusalNode;
|
|
196612
|
+
const recordBuilderTarget = (leaf, stmt) => {
|
|
196613
|
+
for (let n = leaf.parent;n && n !== stmt.parent; n = n.parent) {
|
|
196614
|
+
if (import_typescript11.default.isCallExpression(n) && import_typescript11.default.isPropertyAccessExpression(n.expression) && (n.expression.name.text === "push" || n.expression.name.text === "unshift") && import_typescript11.default.isIdentifier(n.expression.expression)) {
|
|
196615
|
+
builders.add(n.expression.expression.text);
|
|
196616
|
+
return;
|
|
196617
|
+
}
|
|
196618
|
+
if (import_typescript11.default.isVariableDeclaration(n) && import_typescript11.default.isIdentifier(n.name)) {
|
|
196619
|
+
builders.add(n.name.text);
|
|
196620
|
+
return;
|
|
196621
|
+
}
|
|
196622
|
+
}
|
|
196623
|
+
};
|
|
196624
|
+
for (const stmt of statements) {
|
|
196625
|
+
if (stmt === returnStmt)
|
|
196626
|
+
break;
|
|
196627
|
+
collectPreambleDeclaredNames(stmt, declared);
|
|
196628
|
+
const leafSpans = [];
|
|
196629
|
+
const leafIrs = [];
|
|
196630
|
+
const collect = (n, underTemplate) => {
|
|
196631
|
+
if (import_typescript11.default.isJsxElement(n) || import_typescript11.default.isJsxSelfClosingElement(n) || import_typescript11.default.isJsxFragment(n)) {
|
|
196632
|
+
if (underTemplate)
|
|
196633
|
+
refusalNode ??= n;
|
|
196634
|
+
recordBuilderTarget(n, stmt);
|
|
196635
|
+
leafSpans.push({ start: n.getStart(ctx.sourceFile), end: n.getEnd() });
|
|
196636
|
+
const ir = transformNode(n, ctx);
|
|
196637
|
+
if (ir && preambleFragmentNeedsWiring(ir))
|
|
196638
|
+
refusalNode ??= n;
|
|
196639
|
+
leafIrs.push(ir ?? { type: "text", value: "", loc: getSourceLocation(n, ctx.sourceFile, ctx.filePath) });
|
|
196640
|
+
return;
|
|
196641
|
+
}
|
|
196642
|
+
const inTemplate = underTemplate || import_typescript11.default.isTemplateExpression(n) || import_typescript11.default.isTaggedTemplateExpression(n);
|
|
196643
|
+
n.forEachChild((c) => collect(c, inTemplate));
|
|
196644
|
+
};
|
|
196645
|
+
collect(stmt, false);
|
|
196646
|
+
const raw0 = stmt.getText(ctx.sourceFile);
|
|
196647
|
+
typedParts.push(raw0.endsWith(";") ? raw0 : raw0 + ";");
|
|
196648
|
+
if (leafSpans.length === 0) {
|
|
196649
|
+
const js0 = ctx.getJS(stmt);
|
|
196650
|
+
const tjs0 = ctx.getTemplateJS(stmt);
|
|
196651
|
+
const js = (js0.endsWith(";") ? js0 : js0 + ";") + " ";
|
|
196652
|
+
const tjs = (tjs0.endsWith(";") ? tjs0 : tjs0 + ";") + " ";
|
|
196653
|
+
segments.push(tjs !== js ? { kind: "js", text: js, templateText: tjs } : { kind: "js", text: js });
|
|
196654
|
+
continue;
|
|
196655
|
+
}
|
|
196656
|
+
const pieces = reconstructAsSegments(stmt, ctx.sourceFile, ctx.analyzer.typeExcludeRanges, leafSpans);
|
|
196657
|
+
for (const piece of pieces) {
|
|
196658
|
+
if ("marker" in piece) {
|
|
196659
|
+
segments.push({ kind: "jsx", ir: leafIrs[piece.marker] });
|
|
196660
|
+
} else {
|
|
196661
|
+
const tpl = rewriteBarePropRefs2(piece.js, stmt, ctx);
|
|
196662
|
+
segments.push(tpl !== undefined && tpl !== piece.js ? { kind: "js", text: piece.js, templateText: tpl } : { kind: "js", text: piece.js });
|
|
196663
|
+
}
|
|
196664
|
+
}
|
|
196665
|
+
const sep2 = raw0.endsWith(";") ? " " : "; ";
|
|
196666
|
+
segments.push({ kind: "js", text: sep2 });
|
|
196667
|
+
}
|
|
196668
|
+
return {
|
|
196669
|
+
preamble: {
|
|
196670
|
+
segments: trimPreambleSegments(segments),
|
|
196671
|
+
ssrText: tsxSourceText(typedParts.join(" ")),
|
|
196672
|
+
declaredNames: [...declared],
|
|
196673
|
+
builderNames: [...builders]
|
|
196674
|
+
},
|
|
196675
|
+
refusalNode
|
|
196343
196676
|
};
|
|
196344
196677
|
}
|
|
196345
196678
|
function collectNestedComponents(nodes) {
|
|
@@ -197726,6 +198059,7 @@ class BaseAdapter {
|
|
|
197726
198059
|
// ../jsx/src/adapters/jsx-adapter.ts
|
|
197727
198060
|
class JsxAdapter extends BaseAdapter {
|
|
197728
198061
|
componentName = "";
|
|
198062
|
+
acceptsCallbackBody = () => true;
|
|
197729
198063
|
formatImportSpecifiers(specifiers) {
|
|
197730
198064
|
const defaultSpec = specifiers.find((s) => s.isDefault);
|
|
197731
198065
|
const namespaceSpec = specifiers.find((s) => s.isNamespace);
|
|
@@ -198071,6 +198405,10 @@ export default ${this.componentName}` : "";
|
|
|
198071
198405
|
const indexParam = loop.index ? `, ${loop.index}` : "";
|
|
198072
198406
|
const children = this.renderChildren(loop.children);
|
|
198073
198407
|
const safeChildren = children.startsWith("{") ? `<>${children}</>` : children;
|
|
198408
|
+
const preamble = loop.preamble?.ssrText;
|
|
198409
|
+
if (preamble) {
|
|
198410
|
+
return `{${loop.array}.map((${loop.param}${indexParam}) => { ${preamble} return ${safeChildren} })}`;
|
|
198411
|
+
}
|
|
198074
198412
|
return `{${loop.array}.map((${loop.param}${indexParam}) => ${safeChildren})}`;
|
|
198075
198413
|
}
|
|
198076
198414
|
renderComponent(comp) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/test",
|
|
3
|
-
"version": "0.26.
|
|
3
|
+
"version": "0.26.3",
|
|
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.26.
|
|
42
|
+
"@barefootjs/jsx": "0.26.3"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.0.0"
|