@barefootjs/test 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +682 -104
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -189765,7 +189765,9 @@ var ErrorCodes = {
|
|
|
189765
189765
|
INLINE_JSX_CALLBACK_CAPTURE: "BF080",
|
|
189766
189766
|
UNRECOGNIZED_REACTIVE_FACTORY: "BF110",
|
|
189767
189767
|
REACTIVE_FACTORY_RENAME_UNSUPPORTED: "BF111",
|
|
189768
|
-
REACTIVE_FACTORY_MODULE_CAPTURE: "BF112"
|
|
189768
|
+
REACTIVE_FACTORY_MODULE_CAPTURE: "BF112",
|
|
189769
|
+
REACTIVE_FACTORY_IMPORT_COLLISION: "BF113",
|
|
189770
|
+
REACTIVE_FACTORY_PARAM_SHADOWED: "BF114"
|
|
189769
189771
|
};
|
|
189770
189772
|
var errorMessages = {
|
|
189771
189773
|
[ErrorCodes.MISSING_USE_CLIENT]: "'use client' directive required for components with createSignal or event handlers",
|
|
@@ -189791,7 +189793,9 @@ var errorMessages = {
|
|
|
189791
189793
|
[ErrorCodes.INLINE_JSX_CALLBACK_CAPTURE]: "Inline JSX-returning arrow function captures a non-module identifier. Extract the callback into a top-level 'use client' component (e.g. `function MyNode(n) { return <div/> }` then `renderNode={MyNode}`) or pass captured values via component props.",
|
|
189792
189794
|
[ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY]: "Tuple destructuring of a non-reactive factory call. The compiler only recognizes createSignal / createMemo calls and same-file helpers that wrap them with a single `return [a, b]` exit.",
|
|
189793
189795
|
[ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED]: "Reactive factory object return/destructure must use shorthand properties only. " + "Property renames (`{ lists: myLists }`), defaults, and rest elements are not " + "supported — destructure with the factory's own property names.",
|
|
189794
|
-
[ErrorCodes.REACTIVE_FACTORY_MODULE_CAPTURE]: "Imported reactive factory references bindings from its own module scope, so its " + "body cannot be inlined into the component file. Move those helpers into the " + "component file, pass them to the factory as parameters, or define the factory " + "in the component file."
|
|
189796
|
+
[ErrorCodes.REACTIVE_FACTORY_MODULE_CAPTURE]: "Imported reactive factory references bindings from its own module scope, so its " + "body cannot be inlined into the component file. Move those helpers into the " + "component file, pass them to the factory as parameters, or define the factory " + "in the component file.",
|
|
189797
|
+
[ErrorCodes.REACTIVE_FACTORY_IMPORT_COLLISION]: "Inlining an imported reactive factory requires re-importing one of its helper " + "imports into this file, but that name is already bound here to something else. " + "Rename the conflicting binding in this file, or alias the import in the factory's own file.",
|
|
189798
|
+
[ErrorCodes.REACTIVE_FACTORY_PARAM_SHADOWED]: "Reactive factory parameter is shadowed by a nested declaration inside the factory body, so argument substitution at the inline site would be ambiguous. Rename the inner binding so it does not collide with the parameter."
|
|
189795
189799
|
};
|
|
189796
189800
|
function createError(code2, loc, options) {
|
|
189797
189801
|
if (code2 === undefined || !(code2 in errorMessages)) {
|
|
@@ -192223,6 +192227,75 @@ function prescanReactiveFactoriesInSource(source, filePath) {
|
|
|
192223
192227
|
prescanImportedReactiveFactories(sourceFile, filePath, result);
|
|
192224
192228
|
return result;
|
|
192225
192229
|
}
|
|
192230
|
+
function toComponentRelativeSpecifier(resolvedAbs, componentFilePath) {
|
|
192231
|
+
let rel = path_default.relative(path_default.dirname(componentFilePath), resolvedAbs).split(path_default.sep).join("/");
|
|
192232
|
+
rel = rel.replace(/\.(tsx|ts|jsx|js)$/, "");
|
|
192233
|
+
if (rel === "")
|
|
192234
|
+
rel = ".";
|
|
192235
|
+
if (!rel.startsWith("."))
|
|
192236
|
+
rel = "./" + rel;
|
|
192237
|
+
return rel;
|
|
192238
|
+
}
|
|
192239
|
+
function buildEntryImportIndex(sf, filePath) {
|
|
192240
|
+
const index = new Map;
|
|
192241
|
+
for (const stmt of sf.statements) {
|
|
192242
|
+
if (!import_typescript8.default.isImportDeclaration(stmt))
|
|
192243
|
+
continue;
|
|
192244
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192245
|
+
continue;
|
|
192246
|
+
if (stmt.importClause?.isTypeOnly)
|
|
192247
|
+
continue;
|
|
192248
|
+
const src = stmt.moduleSpecifier.text;
|
|
192249
|
+
const targetKey = src.startsWith("./") || src.startsWith("../") ? resolveRelativeImportToFile(src, filePath) ?? "unresolved:" + src : src;
|
|
192250
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
192251
|
+
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192252
|
+
for (const el of namedBindings.elements) {
|
|
192253
|
+
if (el.isTypeOnly)
|
|
192254
|
+
continue;
|
|
192255
|
+
index.set(el.name.text, { targetKey, exportedName: (el.propertyName ?? el.name).text });
|
|
192256
|
+
}
|
|
192257
|
+
}
|
|
192258
|
+
}
|
|
192259
|
+
return index;
|
|
192260
|
+
}
|
|
192261
|
+
function collectEntryBindingNames(sf) {
|
|
192262
|
+
const names = new Set;
|
|
192263
|
+
function visit2(node) {
|
|
192264
|
+
if (import_typescript8.default.isImportDeclaration(node) && node.importClause) {
|
|
192265
|
+
if (node.importClause.name)
|
|
192266
|
+
names.add(node.importClause.name.text);
|
|
192267
|
+
const namedBindings = node.importClause.namedBindings;
|
|
192268
|
+
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192269
|
+
for (const el of namedBindings.elements)
|
|
192270
|
+
names.add(el.name.text);
|
|
192271
|
+
}
|
|
192272
|
+
if (namedBindings && import_typescript8.default.isNamespaceImport(namedBindings)) {
|
|
192273
|
+
names.add(namedBindings.name.text);
|
|
192274
|
+
}
|
|
192275
|
+
}
|
|
192276
|
+
if (import_typescript8.default.isVariableDeclaration(node)) {
|
|
192277
|
+
const out = [];
|
|
192278
|
+
addBindingNames(node.name, out);
|
|
192279
|
+
for (const n of out)
|
|
192280
|
+
names.add(n);
|
|
192281
|
+
}
|
|
192282
|
+
if ((import_typescript8.default.isFunctionDeclaration(node) || import_typescript8.default.isClassDeclaration(node) || import_typescript8.default.isEnumDeclaration(node)) && node.name) {
|
|
192283
|
+
names.add(node.name.text);
|
|
192284
|
+
}
|
|
192285
|
+
if (import_typescript8.default.isFunctionLike(node)) {
|
|
192286
|
+
for (const p of node.parameters) {
|
|
192287
|
+
const out = [];
|
|
192288
|
+
addBindingNames(p.name, out);
|
|
192289
|
+
for (const n of out)
|
|
192290
|
+
names.add(n);
|
|
192291
|
+
}
|
|
192292
|
+
}
|
|
192293
|
+
import_typescript8.default.forEachChild(node, visit2);
|
|
192294
|
+
}
|
|
192295
|
+
visit2(sf);
|
|
192296
|
+
return names;
|
|
192297
|
+
}
|
|
192298
|
+
var MAX_REEXPORT_HOPS = 1;
|
|
192226
192299
|
function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
192227
192300
|
const candidateCallees = new Set;
|
|
192228
192301
|
function collectCandidates(node) {
|
|
@@ -192263,29 +192336,31 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192263
192336
|
}
|
|
192264
192337
|
if (importsToCheck.length === 0)
|
|
192265
192338
|
return;
|
|
192266
|
-
|
|
192267
|
-
|
|
192268
|
-
|
|
192269
|
-
|
|
192339
|
+
const entryBindingNames = collectEntryBindingNames(entrySourceFile);
|
|
192340
|
+
const entryImportIndex = buildEntryImportIndex(entrySourceFile, filePath);
|
|
192341
|
+
const plannedInjections = new Map;
|
|
192342
|
+
const helperCache = new Map;
|
|
192343
|
+
function loadHelperFile(abs) {
|
|
192344
|
+
const cached = helperCache.get(abs);
|
|
192345
|
+
if (cached !== undefined)
|
|
192346
|
+
return cached;
|
|
192270
192347
|
let content;
|
|
192271
192348
|
try {
|
|
192272
|
-
content = fs.readFileSync(
|
|
192349
|
+
content = fs.readFileSync(abs, "utf8");
|
|
192273
192350
|
} catch {
|
|
192274
|
-
|
|
192351
|
+
helperCache.set(abs, null);
|
|
192352
|
+
return null;
|
|
192275
192353
|
}
|
|
192276
|
-
const alreadyKnown = (name) => result.factories.has(name) || result.declined.has(name) || result.reactiveShaped.has(name);
|
|
192277
192354
|
const hasAnyPrimitiveText = [...REACTIVE_PRIMITIVES].some((p) => content.includes(p));
|
|
192278
|
-
|
|
192279
|
-
|
|
192280
|
-
|
|
192281
|
-
|
|
192282
|
-
}
|
|
192283
|
-
continue;
|
|
192355
|
+
const hasReexportText = content.includes("export") && content.includes("from");
|
|
192356
|
+
if (!hasAnyPrimitiveText && !hasReexportText) {
|
|
192357
|
+
helperCache.set(abs, "clean");
|
|
192358
|
+
return "clean";
|
|
192284
192359
|
}
|
|
192285
|
-
const
|
|
192360
|
+
const sf = import_typescript8.default.createSourceFile(abs + ".prescan", content, import_typescript8.default.ScriptTarget.Latest, true, import_typescript8.default.ScriptKind.TSX);
|
|
192286
192361
|
const localFns = new Map;
|
|
192287
192362
|
const exportedFns = new Map;
|
|
192288
|
-
for (const stmt of
|
|
192363
|
+
for (const stmt of sf.statements) {
|
|
192289
192364
|
if (import_typescript8.default.isFunctionDeclaration(stmt) && stmt.name && stmt.body) {
|
|
192290
192365
|
localFns.set(stmt.name.text, stmt);
|
|
192291
192366
|
const hasExportModifier = stmt.modifiers?.some((m) => m.kind === import_typescript8.default.SyntaxKind.ExportKeyword) ?? false;
|
|
@@ -192295,27 +192370,89 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192295
192370
|
}
|
|
192296
192371
|
}
|
|
192297
192372
|
}
|
|
192298
|
-
|
|
192299
|
-
|
|
192373
|
+
const reexports = new Map;
|
|
192374
|
+
let hasStarReexport = false;
|
|
192375
|
+
for (const stmt of sf.statements) {
|
|
192376
|
+
if (!import_typescript8.default.isExportDeclaration(stmt) || stmt.isTypeOnly)
|
|
192377
|
+
continue;
|
|
192378
|
+
if (!stmt.moduleSpecifier) {
|
|
192379
|
+
if (stmt.exportClause && import_typescript8.default.isNamedExports(stmt.exportClause)) {
|
|
192380
|
+
for (const el of stmt.exportClause.elements) {
|
|
192381
|
+
if (el.isTypeOnly)
|
|
192382
|
+
continue;
|
|
192383
|
+
const fn = localFns.get((el.propertyName ?? el.name).text);
|
|
192384
|
+
if (fn)
|
|
192385
|
+
exportedFns.set(el.name.text, fn);
|
|
192386
|
+
}
|
|
192387
|
+
}
|
|
192388
|
+
continue;
|
|
192389
|
+
}
|
|
192390
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192391
|
+
continue;
|
|
192392
|
+
if (stmt.exportClause && import_typescript8.default.isNamedExports(stmt.exportClause)) {
|
|
192300
192393
|
for (const el of stmt.exportClause.elements) {
|
|
192301
192394
|
if (el.isTypeOnly)
|
|
192302
192395
|
continue;
|
|
192303
|
-
|
|
192304
|
-
|
|
192305
|
-
|
|
192396
|
+
reexports.set(el.name.text, {
|
|
192397
|
+
source: stmt.moduleSpecifier.text,
|
|
192398
|
+
innerName: (el.propertyName ?? el.name).text
|
|
192399
|
+
});
|
|
192306
192400
|
}
|
|
192307
|
-
}
|
|
192401
|
+
} else if (!stmt.exportClause) {
|
|
192402
|
+
hasStarReexport = true;
|
|
192403
|
+
}
|
|
192404
|
+
}
|
|
192405
|
+
const moduleBindings = collectHelperModuleValueBindings(sf);
|
|
192406
|
+
const info = { sf, exportedFns, reexports, hasStarReexport, moduleBindings };
|
|
192407
|
+
helperCache.set(abs, info);
|
|
192408
|
+
return info;
|
|
192409
|
+
}
|
|
192410
|
+
function lookupExportedFactory(abs, exportedName, visited, hopsLeft) {
|
|
192411
|
+
if (visited.has(abs))
|
|
192412
|
+
return { kind: "unknown" };
|
|
192413
|
+
visited.add(abs);
|
|
192414
|
+
const file = loadHelperFile(abs);
|
|
192415
|
+
if (file === null)
|
|
192416
|
+
return { kind: "unknown" };
|
|
192417
|
+
if (file === "clean")
|
|
192418
|
+
return { kind: "clean" };
|
|
192419
|
+
const fn = file.exportedFns.get(exportedName);
|
|
192420
|
+
if (fn)
|
|
192421
|
+
return { kind: "fn", fn, file, definingPath: abs };
|
|
192422
|
+
const re = file.reexports.get(exportedName);
|
|
192423
|
+
if (re) {
|
|
192424
|
+
if (hopsLeft <= 0)
|
|
192425
|
+
return { kind: "unknown" };
|
|
192426
|
+
if (!re.source.startsWith("./") && !re.source.startsWith("../"))
|
|
192427
|
+
return { kind: "unknown" };
|
|
192428
|
+
const target = resolveRelativeImportToFile(re.source, abs);
|
|
192429
|
+
if (!target)
|
|
192430
|
+
return { kind: "unknown" };
|
|
192431
|
+
return lookupExportedFactory(target, re.innerName, visited, hopsLeft - 1);
|
|
192308
192432
|
}
|
|
192309
|
-
|
|
192433
|
+
if (file.hasStarReexport)
|
|
192434
|
+
return { kind: "unknown" };
|
|
192435
|
+
return { kind: "clean" };
|
|
192436
|
+
}
|
|
192437
|
+
for (const { src, specs } of importsToCheck) {
|
|
192438
|
+
const resolved = resolveRelativeImportToFile(src, filePath);
|
|
192439
|
+
if (!resolved)
|
|
192440
|
+
continue;
|
|
192441
|
+
const alreadyKnown = (name) => result.factories.has(name) || result.declined.has(name) || result.reactiveShaped.has(name);
|
|
192310
192442
|
for (const spec of specs) {
|
|
192311
192443
|
if (alreadyKnown(spec.local))
|
|
192312
192444
|
continue;
|
|
192313
|
-
const
|
|
192314
|
-
if (
|
|
192445
|
+
const found = lookupExportedFactory(resolved, spec.exported, new Set, MAX_REEXPORT_HOPS);
|
|
192446
|
+
if (found.kind === "clean") {
|
|
192315
192447
|
result.cleanFactoryImports.add(spec.local);
|
|
192316
192448
|
continue;
|
|
192317
192449
|
}
|
|
192318
|
-
|
|
192450
|
+
if (found.kind === "unknown")
|
|
192451
|
+
continue;
|
|
192452
|
+
const { fn, file, definingPath } = found;
|
|
192453
|
+
const helperSf = file.sf;
|
|
192454
|
+
const moduleBindings = file.moduleBindings;
|
|
192455
|
+
const det = detectReactiveFactory(fn, helperSf, definingPath);
|
|
192319
192456
|
if (!det) {
|
|
192320
192457
|
result.cleanFactoryImports.add(spec.local);
|
|
192321
192458
|
continue;
|
|
@@ -192328,17 +192465,64 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192328
192465
|
result.declined.set(spec.local, det.declined);
|
|
192329
192466
|
break;
|
|
192330
192467
|
case "factory": {
|
|
192331
|
-
const
|
|
192332
|
-
if (
|
|
192468
|
+
const capture = moduleCaptureCheck(fn, det.info, moduleBindings, fn.name.text);
|
|
192469
|
+
if (capture.captured.length > 0) {
|
|
192333
192470
|
result.declined.set(spec.local, {
|
|
192334
192471
|
code: "BF112",
|
|
192335
|
-
detail: `'${
|
|
192472
|
+
detail: `'${capture.captured.join("', '")}'`,
|
|
192336
192473
|
loc: det.info.loc
|
|
192337
192474
|
});
|
|
192338
|
-
|
|
192339
|
-
|
|
192340
|
-
|
|
192475
|
+
break;
|
|
192476
|
+
}
|
|
192477
|
+
const required = [];
|
|
192478
|
+
const pending = [];
|
|
192479
|
+
let declinedEntry = null;
|
|
192480
|
+
for (const ref of capture.importedRefs) {
|
|
192481
|
+
let specifier;
|
|
192482
|
+
let targetKey;
|
|
192483
|
+
if (ref.source.startsWith("./") || ref.source.startsWith("../")) {
|
|
192484
|
+
const abs = resolveRelativeImportToFile(ref.source, definingPath);
|
|
192485
|
+
if (!abs) {
|
|
192486
|
+
declinedEntry = {
|
|
192487
|
+
code: "BF112",
|
|
192488
|
+
detail: `'${ref.localName}' (import '${ref.source}' did not resolve from the helper file)`,
|
|
192489
|
+
loc: det.info.loc
|
|
192490
|
+
};
|
|
192491
|
+
break;
|
|
192492
|
+
}
|
|
192493
|
+
specifier = toComponentRelativeSpecifier(abs, filePath);
|
|
192494
|
+
targetKey = abs;
|
|
192495
|
+
} else {
|
|
192496
|
+
specifier = ref.source;
|
|
192497
|
+
targetKey = ref.source;
|
|
192498
|
+
}
|
|
192499
|
+
const existing = entryImportIndex.get(ref.localName);
|
|
192500
|
+
if (existing && existing.targetKey === targetKey && existing.exportedName === ref.exportedName) {
|
|
192501
|
+
continue;
|
|
192502
|
+
}
|
|
192503
|
+
const planned = plannedInjections.get(ref.localName);
|
|
192504
|
+
const collides = existing !== undefined || planned !== undefined && (planned.targetKey !== targetKey || planned.exportedName !== ref.exportedName) || planned === undefined && entryBindingNames.has(ref.localName);
|
|
192505
|
+
if (collides) {
|
|
192506
|
+
declinedEntry = {
|
|
192507
|
+
code: "BF113",
|
|
192508
|
+
detail: `'${ref.localName}' from '${specifier}'`,
|
|
192509
|
+
loc: det.info.loc
|
|
192510
|
+
};
|
|
192511
|
+
break;
|
|
192512
|
+
}
|
|
192513
|
+
pending.push([ref.localName, { targetKey, exportedName: ref.exportedName }]);
|
|
192514
|
+
required.push({ localName: ref.localName, exportedName: ref.exportedName, specifier });
|
|
192515
|
+
}
|
|
192516
|
+
if (declinedEntry) {
|
|
192517
|
+
result.declined.set(spec.local, declinedEntry);
|
|
192518
|
+
break;
|
|
192341
192519
|
}
|
|
192520
|
+
for (const [name, id] of pending)
|
|
192521
|
+
plannedInjections.set(name, id);
|
|
192522
|
+
det.info.sourceFilePath = definingPath;
|
|
192523
|
+
if (required.length > 0)
|
|
192524
|
+
det.info.requiredImports = required;
|
|
192525
|
+
result.factories.set(spec.local, det.info);
|
|
192342
192526
|
break;
|
|
192343
192527
|
}
|
|
192344
192528
|
}
|
|
@@ -192346,7 +192530,8 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192346
192530
|
}
|
|
192347
192531
|
}
|
|
192348
192532
|
function collectHelperModuleValueBindings(sf) {
|
|
192349
|
-
const
|
|
192533
|
+
const local = new Set;
|
|
192534
|
+
const imported = new Map;
|
|
192350
192535
|
for (const stmt of sf.statements) {
|
|
192351
192536
|
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
192352
192537
|
const out = [];
|
|
@@ -192354,11 +192539,11 @@ function collectHelperModuleValueBindings(sf) {
|
|
|
192354
192539
|
addBindingNames(decl.name, out);
|
|
192355
192540
|
}
|
|
192356
192541
|
for (const n of out)
|
|
192357
|
-
|
|
192542
|
+
local.add(n);
|
|
192358
192543
|
continue;
|
|
192359
192544
|
}
|
|
192360
192545
|
if ((import_typescript8.default.isFunctionDeclaration(stmt) || import_typescript8.default.isClassDeclaration(stmt) || import_typescript8.default.isEnumDeclaration(stmt)) && stmt.name) {
|
|
192361
|
-
|
|
192546
|
+
local.add(stmt.name.text);
|
|
192362
192547
|
continue;
|
|
192363
192548
|
}
|
|
192364
192549
|
if (import_typescript8.default.isImportDeclaration(stmt)) {
|
|
@@ -192370,25 +192555,25 @@ function collectHelperModuleValueBindings(sf) {
|
|
|
192370
192555
|
if (src === "@barefootjs/client" || src === "@barefootjs/client/runtime")
|
|
192371
192556
|
continue;
|
|
192372
192557
|
if (stmt.importClause?.name)
|
|
192373
|
-
|
|
192558
|
+
local.add(stmt.importClause.name.text);
|
|
192374
192559
|
const namedBindings = stmt.importClause?.namedBindings;
|
|
192375
192560
|
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192376
192561
|
for (const el of namedBindings.elements) {
|
|
192377
192562
|
if (el.isTypeOnly)
|
|
192378
192563
|
continue;
|
|
192379
|
-
|
|
192564
|
+
imported.set(el.name.text, { source: src, exportedName: (el.propertyName ?? el.name).text });
|
|
192380
192565
|
}
|
|
192381
192566
|
}
|
|
192382
192567
|
if (namedBindings && import_typescript8.default.isNamespaceImport(namedBindings)) {
|
|
192383
|
-
|
|
192568
|
+
local.add(namedBindings.name.text);
|
|
192384
192569
|
}
|
|
192385
192570
|
}
|
|
192386
192571
|
}
|
|
192387
|
-
return
|
|
192572
|
+
return { local, imported };
|
|
192388
192573
|
}
|
|
192389
192574
|
function moduleCaptureCheck(fn, info, moduleBindings, selfName) {
|
|
192390
192575
|
if (!fn.body)
|
|
192391
|
-
return [];
|
|
192576
|
+
return { captured: [], importedRefs: [] };
|
|
192392
192577
|
const free = extractFreeIdentifiersFromNode(fn.body);
|
|
192393
192578
|
const exclude = new Set(info.params);
|
|
192394
192579
|
for (const b of info.localBindings)
|
|
@@ -192398,14 +192583,22 @@ function moduleCaptureCheck(fn, info, moduleBindings, selfName) {
|
|
|
192398
192583
|
for (const p of REACTIVE_PRIMITIVES)
|
|
192399
192584
|
exclude.add(p);
|
|
192400
192585
|
exclude.add(selfName);
|
|
192401
|
-
const
|
|
192586
|
+
const captured = [];
|
|
192587
|
+
const importedRefs = [];
|
|
192402
192588
|
for (const id of free) {
|
|
192403
192589
|
if (exclude.has(id))
|
|
192404
192590
|
continue;
|
|
192405
|
-
if (moduleBindings.has(id))
|
|
192406
|
-
|
|
192591
|
+
if (moduleBindings.local.has(id)) {
|
|
192592
|
+
captured.push(id);
|
|
192593
|
+
continue;
|
|
192594
|
+
}
|
|
192595
|
+
const imp = moduleBindings.imported.get(id);
|
|
192596
|
+
if (imp)
|
|
192597
|
+
importedRefs.push({ localName: id, source: imp.source, exportedName: imp.exportedName });
|
|
192407
192598
|
}
|
|
192408
|
-
|
|
192599
|
+
captured.sort();
|
|
192600
|
+
importedRefs.sort((a, b) => a.localName < b.localName ? -1 : 1);
|
|
192601
|
+
return { captured, importedRefs };
|
|
192409
192602
|
}
|
|
192410
192603
|
function detectReactiveFactory(node, sourceFile, filePath) {
|
|
192411
192604
|
if (!node.body || !node.name)
|
|
@@ -192424,6 +192617,17 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192424
192617
|
if (!hasReactiveCall)
|
|
192425
192618
|
return null;
|
|
192426
192619
|
const loc = getSourceLocation(node, sourceFile, filePath);
|
|
192620
|
+
let totalReturnCount = 0;
|
|
192621
|
+
function countReturns(n) {
|
|
192622
|
+
if (import_typescript8.default.isFunctionLike(n))
|
|
192623
|
+
return;
|
|
192624
|
+
if (import_typescript8.default.isReturnStatement(n)) {
|
|
192625
|
+
totalReturnCount++;
|
|
192626
|
+
return;
|
|
192627
|
+
}
|
|
192628
|
+
import_typescript8.default.forEachChild(n, countReturns);
|
|
192629
|
+
}
|
|
192630
|
+
import_typescript8.default.forEachChild(node.body, countReturns);
|
|
192427
192631
|
let returnExpr = null;
|
|
192428
192632
|
let returnCount = 0;
|
|
192429
192633
|
for (const stmt of node.body.statements) {
|
|
@@ -192441,7 +192645,7 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192441
192645
|
expr = expr.expression;
|
|
192442
192646
|
returnExpr = expr;
|
|
192443
192647
|
}
|
|
192444
|
-
if (returnCount !== 1 || !returnExpr)
|
|
192648
|
+
if (totalReturnCount !== 1 || returnCount !== 1 || !returnExpr)
|
|
192445
192649
|
return { kind: "reactive-shaped" };
|
|
192446
192650
|
const returnTupleIdentifiers = [];
|
|
192447
192651
|
let returnKind;
|
|
@@ -192475,6 +192679,14 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192475
192679
|
} else {
|
|
192476
192680
|
return { kind: "reactive-shaped" };
|
|
192477
192681
|
}
|
|
192682
|
+
const params = [];
|
|
192683
|
+
for (const p of node.parameters) {
|
|
192684
|
+
if (import_typescript8.default.isIdentifier(p.name)) {
|
|
192685
|
+
params.push(p.name.text);
|
|
192686
|
+
continue;
|
|
192687
|
+
}
|
|
192688
|
+
return { kind: "reactive-shaped" };
|
|
192689
|
+
}
|
|
192478
192690
|
const localBindings = [];
|
|
192479
192691
|
for (const stmt of node.body.statements) {
|
|
192480
192692
|
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
@@ -192485,15 +192697,95 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192485
192697
|
localBindings.push(stmt.name.text);
|
|
192486
192698
|
}
|
|
192487
192699
|
}
|
|
192488
|
-
const
|
|
192700
|
+
const relevantNames = new Set([...params, ...localBindings, ...returnTupleIdentifiers]);
|
|
192701
|
+
const renameSites = [];
|
|
192702
|
+
let shadowedParam = null;
|
|
192703
|
+
function collectRenameSites(root, toBodyOffset) {
|
|
192704
|
+
function push(id, form) {
|
|
192705
|
+
renameSites.push({
|
|
192706
|
+
name: id.text,
|
|
192707
|
+
start: toBodyOffset(id.getStart(sourceFile)),
|
|
192708
|
+
end: toBodyOffset(id.getEnd()),
|
|
192709
|
+
form
|
|
192710
|
+
});
|
|
192711
|
+
}
|
|
192712
|
+
function classify(id) {
|
|
192713
|
+
if (!relevantNames.has(id.text))
|
|
192714
|
+
return;
|
|
192715
|
+
const p = id.parent;
|
|
192716
|
+
if (import_typescript8.default.isPropertyAccessExpression(p) && p.name === id)
|
|
192717
|
+
return;
|
|
192718
|
+
if (import_typescript8.default.isPropertyAssignment(p) && p.name === id)
|
|
192719
|
+
return;
|
|
192720
|
+
if (import_typescript8.default.isBindingElement(p) && p.propertyName === id)
|
|
192721
|
+
return;
|
|
192722
|
+
if ((import_typescript8.default.isMethodDeclaration(p) || import_typescript8.default.isGetAccessorDeclaration(p) || import_typescript8.default.isSetAccessorDeclaration(p) || import_typescript8.default.isPropertyDeclaration(p) || import_typescript8.default.isEnumMember(p)) && p.name === id)
|
|
192723
|
+
return;
|
|
192724
|
+
if (import_typescript8.default.isJsxAttribute(p) && p.name === id)
|
|
192725
|
+
return;
|
|
192726
|
+
if (import_typescript8.default.isLabeledStatement(p) && p.label === id || (import_typescript8.default.isBreakStatement(p) || import_typescript8.default.isContinueStatement(p)) && p.label === id)
|
|
192727
|
+
return;
|
|
192728
|
+
if ((import_typescript8.default.isJsxOpeningElement(p) || import_typescript8.default.isJsxSelfClosingElement(p) || import_typescript8.default.isJsxClosingElement(p)) && p.tagName === id && /^[a-z]/.test(id.text))
|
|
192729
|
+
return;
|
|
192730
|
+
if (import_typescript8.default.isShorthandPropertyAssignment(p) && p.name === id) {
|
|
192731
|
+
push(id, "shorthand");
|
|
192732
|
+
return;
|
|
192733
|
+
}
|
|
192734
|
+
if (import_typescript8.default.isBindingElement(p) && p.name === id && !p.propertyName && import_typescript8.default.isObjectBindingPattern(p.parent)) {
|
|
192735
|
+
if (params.includes(id.text))
|
|
192736
|
+
shadowedParam = id.text;
|
|
192737
|
+
push(id, "shorthand");
|
|
192738
|
+
return;
|
|
192739
|
+
}
|
|
192740
|
+
const isDecl = (import_typescript8.default.isVariableDeclaration(p) || import_typescript8.default.isParameter(p) || import_typescript8.default.isBindingElement(p) || import_typescript8.default.isFunctionDeclaration(p) || import_typescript8.default.isFunctionExpression(p) || import_typescript8.default.isClassDeclaration(p) || import_typescript8.default.isClassExpression(p)) && p.name === id;
|
|
192741
|
+
if (isDecl && params.includes(id.text))
|
|
192742
|
+
shadowedParam = id.text;
|
|
192743
|
+
push(id, "plain");
|
|
192744
|
+
}
|
|
192745
|
+
function visit2(n) {
|
|
192746
|
+
if (import_typescript8.default.isTypeNode(n) || import_typescript8.default.isTypeParameterDeclaration(n) || import_typescript8.default.isTypeAliasDeclaration(n) || import_typescript8.default.isInterfaceDeclaration(n))
|
|
192747
|
+
return;
|
|
192748
|
+
if (import_typescript8.default.isIdentifier(n)) {
|
|
192749
|
+
classify(n);
|
|
192750
|
+
return;
|
|
192751
|
+
}
|
|
192752
|
+
import_typescript8.default.forEachChild(n, visit2);
|
|
192753
|
+
}
|
|
192754
|
+
visit2(root);
|
|
192755
|
+
}
|
|
192756
|
+
const keptStatements = node.body.statements.filter((s) => !import_typescript8.default.isReturnStatement(s));
|
|
192757
|
+
const pieces = [];
|
|
192758
|
+
let base = 0;
|
|
192759
|
+
for (const stmt of keptStatements) {
|
|
192760
|
+
const text = stmt.getText(sourceFile);
|
|
192761
|
+
const stmtStart = stmt.getStart(sourceFile);
|
|
192762
|
+
collectRenameSites(stmt, (pos) => pos - stmtStart + base);
|
|
192763
|
+
pieces.push(text);
|
|
192764
|
+
base += text.length + 1;
|
|
192765
|
+
}
|
|
192766
|
+
const bodyStatements = pieces.join(`
|
|
192489
192767
|
`);
|
|
192490
|
-
|
|
192491
|
-
|
|
192492
|
-
|
|
192493
|
-
|
|
192494
|
-
|
|
192768
|
+
if (shadowedParam !== null) {
|
|
192769
|
+
return {
|
|
192770
|
+
kind: "declined",
|
|
192771
|
+
declined: {
|
|
192772
|
+
code: "BF114",
|
|
192773
|
+
detail: `parameter '${shadowedParam}' of '${node.name.text}' is shadowed by a nested declaration inside the factory body`,
|
|
192774
|
+
loc
|
|
192775
|
+
}
|
|
192776
|
+
};
|
|
192777
|
+
}
|
|
192778
|
+
for (const site of renameSites) {
|
|
192779
|
+
if (bodyStatements.slice(site.start, site.end) !== site.name) {
|
|
192780
|
+
return {
|
|
192781
|
+
kind: "declined",
|
|
192782
|
+
declined: {
|
|
192783
|
+
code: "BF111",
|
|
192784
|
+
detail: `internal rename-site offset mismatch for '${site.name}' — this is a compiler bug, ` + `please report it`,
|
|
192785
|
+
loc
|
|
192786
|
+
}
|
|
192787
|
+
};
|
|
192495
192788
|
}
|
|
192496
|
-
return { kind: "reactive-shaped" };
|
|
192497
192789
|
}
|
|
192498
192790
|
return {
|
|
192499
192791
|
kind: "factory",
|
|
@@ -192503,7 +192795,8 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192503
192795
|
returnTupleIdentifiers,
|
|
192504
192796
|
returnKind,
|
|
192505
192797
|
localBindings,
|
|
192506
|
-
loc
|
|
192798
|
+
loc,
|
|
192799
|
+
renameSites
|
|
192507
192800
|
}
|
|
192508
192801
|
};
|
|
192509
192802
|
}
|
|
@@ -192529,6 +192822,7 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192529
192822
|
const { factories, sourceFile } = prescan;
|
|
192530
192823
|
const edits = [];
|
|
192531
192824
|
let callSiteIndex = 0;
|
|
192825
|
+
const inlinedFactories = new Set;
|
|
192532
192826
|
function visitStmt(node, inComponent) {
|
|
192533
192827
|
if (import_typescript8.default.isVariableStatement(node) && inComponent) {
|
|
192534
192828
|
for (const decl of node.declarationList.declarations) {
|
|
@@ -192606,34 +192900,65 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192606
192900
|
const argTexts = args.map((a) => a.getText(sourceFile));
|
|
192607
192901
|
const thisCallIndex = callSiteIndex++;
|
|
192608
192902
|
const suffix = `_bf${thisCallIndex}`;
|
|
192609
|
-
|
|
192610
|
-
const
|
|
192611
|
-
|
|
192612
|
-
|
|
192613
|
-
|
|
192614
|
-
|
|
192903
|
+
const renames = new Map;
|
|
192904
|
+
for (const name of factory.localBindings) {
|
|
192905
|
+
if (!excludeFromSuffixRename.has(name))
|
|
192906
|
+
renames.set(name, name + suffix);
|
|
192907
|
+
}
|
|
192908
|
+
if (renameReturnToCallerNames) {
|
|
192909
|
+
for (const [n, caller] of renameReturnToCallerNames) {
|
|
192910
|
+
if (caller !== n)
|
|
192911
|
+
renames.set(n, caller);
|
|
192912
|
+
}
|
|
192615
192913
|
}
|
|
192616
192914
|
const atomicArg = /^(?:[\w$.]+|'[^'\\]*'|"[^"\\]*"|-?\d+(?:\.\d+)?)$/;
|
|
192617
192915
|
for (let i2 = 0;i2 < factory.params.length; i2++) {
|
|
192618
192916
|
const p = factory.params[i2];
|
|
192619
|
-
const a = argTexts[i2] ?? "undefined";
|
|
192620
|
-
|
|
192621
|
-
body = body.replace(new RegExp(`\\b${escapeRegex(p)}\\b`, "g"), wrapped);
|
|
192917
|
+
const a = (argTexts[i2] ?? "undefined").trim();
|
|
192918
|
+
renames.set(p, atomicArg.test(a) ? a : `(${a})`);
|
|
192622
192919
|
}
|
|
192623
|
-
|
|
192624
|
-
|
|
192625
|
-
|
|
192626
|
-
|
|
192920
|
+
let body = factory.bodySource;
|
|
192921
|
+
for (let i2 = factory.renameSites.length - 1;i2 >= 0; i2--) {
|
|
192922
|
+
const site = factory.renameSites[i2];
|
|
192923
|
+
const repl = renames.get(site.name);
|
|
192924
|
+
if (repl === undefined)
|
|
192925
|
+
continue;
|
|
192926
|
+
const text = site.form === "shorthand" ? `${site.name}: ${repl}` : repl;
|
|
192927
|
+
body = body.slice(0, site.start) + text + body.slice(site.end);
|
|
192627
192928
|
}
|
|
192628
192929
|
edits.push({
|
|
192629
192930
|
start: stmt.getStart(sourceFile),
|
|
192630
192931
|
end: stmt.getEnd(),
|
|
192631
192932
|
replacement: body
|
|
192632
192933
|
});
|
|
192934
|
+
inlinedFactories.add(factory);
|
|
192633
192935
|
}
|
|
192634
192936
|
visitStmt(sourceFile, false);
|
|
192635
192937
|
if (edits.length === 0)
|
|
192636
192938
|
return source;
|
|
192939
|
+
const importsBySpecifier = new Map;
|
|
192940
|
+
for (const f of inlinedFactories) {
|
|
192941
|
+
for (const r of f.requiredImports ?? []) {
|
|
192942
|
+
let names = importsBySpecifier.get(r.specifier);
|
|
192943
|
+
if (!names) {
|
|
192944
|
+
names = new Map;
|
|
192945
|
+
importsBySpecifier.set(r.specifier, names);
|
|
192946
|
+
}
|
|
192947
|
+
names.set(r.localName, r.exportedName);
|
|
192948
|
+
}
|
|
192949
|
+
}
|
|
192950
|
+
if (importsBySpecifier.size > 0) {
|
|
192951
|
+
const lines = [...importsBySpecifier].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([spec, names]) => {
|
|
192952
|
+
const specifiers = [...names].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([local, exported]) => exported === local ? local : `${exported} as ${local}`);
|
|
192953
|
+
return `import { ${specifiers.join(", ")} } from '${spec}'`;
|
|
192954
|
+
});
|
|
192955
|
+
const at = factoryImportInsertionOffset(sourceFile);
|
|
192956
|
+
edits.push({ start: at, end: at, replacement: at === 0 ? lines.join(`
|
|
192957
|
+
`) + `
|
|
192958
|
+
` : `
|
|
192959
|
+
` + lines.join(`
|
|
192960
|
+
`) });
|
|
192961
|
+
}
|
|
192637
192962
|
edits.sort((a, b) => b.start - a.start);
|
|
192638
192963
|
let out = source;
|
|
192639
192964
|
for (const e of edits) {
|
|
@@ -192641,6 +192966,20 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192641
192966
|
}
|
|
192642
192967
|
return out;
|
|
192643
192968
|
}
|
|
192969
|
+
function factoryImportInsertionOffset(sf) {
|
|
192970
|
+
let lastImportEnd = -1;
|
|
192971
|
+
let directiveEnd = -1;
|
|
192972
|
+
for (const stmt of sf.statements) {
|
|
192973
|
+
if (import_typescript8.default.isImportDeclaration(stmt)) {
|
|
192974
|
+
lastImportEnd = stmt.getEnd();
|
|
192975
|
+
continue;
|
|
192976
|
+
}
|
|
192977
|
+
if (directiveEnd === -1 && import_typescript8.default.isExpressionStatement(stmt) && import_typescript8.default.isStringLiteral(stmt.expression) && stmt.expression.text === "use client") {
|
|
192978
|
+
directiveEnd = stmt.getEnd();
|
|
192979
|
+
}
|
|
192980
|
+
}
|
|
192981
|
+
return lastImportEnd >= 0 ? lastImportEnd : directiveEnd >= 0 ? directiveEnd : 0;
|
|
192982
|
+
}
|
|
192644
192983
|
function isPascalCaseComponentFn(node) {
|
|
192645
192984
|
if (import_typescript8.default.isFunctionDeclaration(node) && node.name) {
|
|
192646
192985
|
return /^[A-Z]/.test(node.name.text);
|
|
@@ -192650,15 +192989,27 @@ function isPascalCaseComponentFn(node) {
|
|
|
192650
192989
|
}
|
|
192651
192990
|
return false;
|
|
192652
192991
|
}
|
|
192653
|
-
function escapeRegex(s) {
|
|
192654
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
192655
|
-
}
|
|
192656
192992
|
function declinedFactoryMessage(callee, d) {
|
|
192657
192993
|
if (d.code === "BF112") {
|
|
192658
192994
|
return `Reactive factory '${callee}' references ${d.detail} from its own module ` + `scope and cannot be inlined. Move the referenced helper(s) into this file, ` + `pass them as factory arguments, or inline the factory here.`;
|
|
192659
192995
|
}
|
|
192996
|
+
if (d.code === "BF113") {
|
|
192997
|
+
return `Reactive factory '${callee}' cannot be inlined: it needs ${d.detail} ` + `imported into this file, but that name is already bound here to something ` + `else. Rename the conflicting binding in this file, or alias the import in ` + `the factory's own file (import { x as y }).`;
|
|
192998
|
+
}
|
|
192660
192999
|
return `Reactive factory '${callee}' cannot be inlined: ${d.detail}.`;
|
|
192661
193000
|
}
|
|
193001
|
+
function declinedFactoryErrorCode(code2) {
|
|
193002
|
+
switch (code2) {
|
|
193003
|
+
case "BF112":
|
|
193004
|
+
return ErrorCodes.REACTIVE_FACTORY_MODULE_CAPTURE;
|
|
193005
|
+
case "BF113":
|
|
193006
|
+
return ErrorCodes.REACTIVE_FACTORY_IMPORT_COLLISION;
|
|
193007
|
+
case "BF114":
|
|
193008
|
+
return ErrorCodes.REACTIVE_FACTORY_PARAM_SHADOWED;
|
|
193009
|
+
default:
|
|
193010
|
+
return ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED;
|
|
193011
|
+
}
|
|
193012
|
+
}
|
|
192662
193013
|
function validateReactiveFactoryCalls(ctx) {
|
|
192663
193014
|
if (!ctx.componentNode)
|
|
192664
193015
|
return;
|
|
@@ -192682,7 +193033,7 @@ function validateReactiveFactoryCalls(ctx) {
|
|
|
192682
193033
|
continue;
|
|
192683
193034
|
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192684
193035
|
if (declinedEntry) {
|
|
192685
|
-
ctx.errors.push(createError(declinedEntry.code
|
|
193036
|
+
ctx.errors.push(createError(declinedFactoryErrorCode(declinedEntry.code), loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192686
193037
|
continue;
|
|
192687
193038
|
}
|
|
192688
193039
|
const objectFactory = ctx.reactiveFactories.get(callee);
|
|
@@ -192739,7 +193090,7 @@ function validateObjectFactoryDestructure(ctx, pattern, callee, loc) {
|
|
|
192739
193090
|
}
|
|
192740
193091
|
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192741
193092
|
if (declinedEntry) {
|
|
192742
|
-
ctx.errors.push(createError(declinedEntry.code
|
|
193093
|
+
ctx.errors.push(createError(declinedFactoryErrorCode(declinedEntry.code), loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192743
193094
|
return;
|
|
192744
193095
|
}
|
|
192745
193096
|
if (ctx.reactiveShapedHelpers.has(callee)) {
|
|
@@ -193180,19 +193531,83 @@ function resolveFreeRefs(node, env) {
|
|
|
193180
193531
|
// ../jsx/src/to-locale-date-lowering.ts
|
|
193181
193532
|
var TO_LOCALE_TZ_RE = /^(?:UTC|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
|
|
193182
193533
|
var PROBE_UTC = new Date(Date.UTC(2001, 1, 3));
|
|
193183
|
-
var
|
|
193184
|
-
|
|
193185
|
-
|
|
193534
|
+
var formatCache = new Map;
|
|
193535
|
+
var namesCache = new Map;
|
|
193536
|
+
function deriveMonthNames(locale, ctx) {
|
|
193537
|
+
return deriveNamesCached(`${locale}|m|${ctx}`, () => {
|
|
193538
|
+
const months2 = (width) => Array.from({ length: 12 }, (_, m) => probePart(locale, ctx === "formatting" ? { month: width, day: "numeric" } : { month: width }, Date.UTC(2001, m, 15), "month"));
|
|
193539
|
+
return [...months2("long"), ...months2("short")];
|
|
193540
|
+
});
|
|
193541
|
+
}
|
|
193542
|
+
function deriveWeekdayNames(locale, ctx) {
|
|
193543
|
+
return deriveNamesCached(`${locale}|w|${ctx}`, () => {
|
|
193544
|
+
const weekdays = (width) => Array.from({ length: 7 }, (_, d) => probePart(locale, ctx === "formatting" ? { weekday: width, month: "numeric", day: "numeric" } : { weekday: width }, Date.UTC(2023, 0, 1 + d), "weekday"));
|
|
193545
|
+
return [...weekdays("long"), ...weekdays("short")];
|
|
193546
|
+
});
|
|
193547
|
+
}
|
|
193548
|
+
function probePart(locale, options, utc, type2) {
|
|
193549
|
+
const parts = new Intl.DateTimeFormat(locale, { ...options, timeZone: "UTC" }).formatToParts(new Date(utc));
|
|
193550
|
+
const found = parts.find((p) => p.type === type2);
|
|
193551
|
+
if (!found || !found.value)
|
|
193552
|
+
throw new Error("missing part");
|
|
193553
|
+
return found.value;
|
|
193554
|
+
}
|
|
193555
|
+
function deriveNamesCached(key, derive) {
|
|
193556
|
+
const cached = namesCache.get(key);
|
|
193186
193557
|
if (cached !== undefined)
|
|
193187
193558
|
return cached;
|
|
193188
|
-
|
|
193189
|
-
|
|
193559
|
+
let derived;
|
|
193560
|
+
try {
|
|
193561
|
+
derived = derive();
|
|
193562
|
+
} catch {
|
|
193563
|
+
derived = null;
|
|
193564
|
+
}
|
|
193565
|
+
namesCache.set(key, derived);
|
|
193190
193566
|
return derived;
|
|
193191
193567
|
}
|
|
193192
|
-
function
|
|
193568
|
+
function resolveLocaleDateFormat(locale, probeOptions) {
|
|
193569
|
+
const key = `${locale}|${JSON.stringify(probeOptions, Object.keys(probeOptions).sort())}`;
|
|
193570
|
+
const cached = formatCache.get(key);
|
|
193571
|
+
if (cached !== undefined)
|
|
193572
|
+
return cached;
|
|
193573
|
+
const derived = deriveFormat(locale, probeOptions);
|
|
193574
|
+
formatCache.set(key, derived);
|
|
193575
|
+
return derived;
|
|
193576
|
+
}
|
|
193577
|
+
var VERIFY_UTC = new Date(Date.UTC(2001, 4, 13));
|
|
193578
|
+
function renderPatternAt(pattern, names, y, m, d, wd) {
|
|
193579
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
193580
|
+
return pattern.replace(/YYYY|MMMM|MMM|MM|DD|dddd|ddd|M|D/g, (token) => {
|
|
193581
|
+
switch (token) {
|
|
193582
|
+
case "YYYY":
|
|
193583
|
+
return String(y).padStart(4, "0");
|
|
193584
|
+
case "MMMM":
|
|
193585
|
+
return names[m - 1] ?? "";
|
|
193586
|
+
case "MMM":
|
|
193587
|
+
return names[12 + m - 1] ?? "";
|
|
193588
|
+
case "MM":
|
|
193589
|
+
return pad2(m);
|
|
193590
|
+
case "M":
|
|
193591
|
+
return String(m);
|
|
193592
|
+
case "DD":
|
|
193593
|
+
return pad2(d);
|
|
193594
|
+
case "D":
|
|
193595
|
+
return String(d);
|
|
193596
|
+
case "dddd":
|
|
193597
|
+
return names[24 + wd] ?? "";
|
|
193598
|
+
default:
|
|
193599
|
+
return names[31 + wd] ?? "";
|
|
193600
|
+
}
|
|
193601
|
+
});
|
|
193602
|
+
}
|
|
193603
|
+
function deriveFormat(locale, probeOptions) {
|
|
193604
|
+
let dtf;
|
|
193193
193605
|
let parts;
|
|
193194
193606
|
try {
|
|
193195
|
-
|
|
193607
|
+
dtf = new Intl.DateTimeFormat(locale, {
|
|
193608
|
+
...probeOptions,
|
|
193609
|
+
timeZone: "UTC"
|
|
193610
|
+
});
|
|
193196
193611
|
const resolved = dtf.resolvedOptions();
|
|
193197
193612
|
if (resolved.calendar !== "gregory" || resolved.numberingSystem !== "latn")
|
|
193198
193613
|
return null;
|
|
@@ -193200,7 +193615,18 @@ function derivePattern(locale) {
|
|
|
193200
193615
|
} catch {
|
|
193201
193616
|
return null;
|
|
193202
193617
|
}
|
|
193618
|
+
const monthTables = [
|
|
193619
|
+
deriveMonthNames(locale, "formatting"),
|
|
193620
|
+
deriveMonthNames(locale, "standalone")
|
|
193621
|
+
];
|
|
193622
|
+
const weekdayTables = [
|
|
193623
|
+
deriveWeekdayNames(locale, "formatting"),
|
|
193624
|
+
deriveWeekdayNames(locale, "standalone")
|
|
193625
|
+
];
|
|
193626
|
+
let monthTable = null;
|
|
193627
|
+
let weekdayTable = null;
|
|
193203
193628
|
let pattern = "";
|
|
193629
|
+
let usesNames = false;
|
|
193204
193630
|
for (const part of parts) {
|
|
193205
193631
|
switch (part.type) {
|
|
193206
193632
|
case "year":
|
|
@@ -193208,14 +193634,27 @@ function derivePattern(locale) {
|
|
|
193208
193634
|
return null;
|
|
193209
193635
|
pattern += "YYYY";
|
|
193210
193636
|
break;
|
|
193211
|
-
case "month":
|
|
193212
|
-
if (part.value === "2")
|
|
193637
|
+
case "month": {
|
|
193638
|
+
if (part.value === "2") {
|
|
193213
193639
|
pattern += "M";
|
|
193214
|
-
|
|
193640
|
+
break;
|
|
193641
|
+
}
|
|
193642
|
+
if (part.value === "02") {
|
|
193215
193643
|
pattern += "MM";
|
|
193644
|
+
break;
|
|
193645
|
+
}
|
|
193646
|
+
const wide = monthTables.find((t) => t && part.value === t[1]) ?? null;
|
|
193647
|
+
const abbr = wide ? null : monthTables.find((t) => t && part.value === t[12 + 1]) ?? null;
|
|
193648
|
+
if (wide)
|
|
193649
|
+
pattern += "MMMM";
|
|
193650
|
+
else if (abbr)
|
|
193651
|
+
pattern += "MMM";
|
|
193216
193652
|
else
|
|
193217
193653
|
return null;
|
|
193654
|
+
monthTable = wide ?? abbr;
|
|
193655
|
+
usesNames = true;
|
|
193218
193656
|
break;
|
|
193657
|
+
}
|
|
193219
193658
|
case "day":
|
|
193220
193659
|
if (part.value === "3")
|
|
193221
193660
|
pattern += "D";
|
|
@@ -193224,8 +193663,21 @@ function derivePattern(locale) {
|
|
|
193224
193663
|
else
|
|
193225
193664
|
return null;
|
|
193226
193665
|
break;
|
|
193666
|
+
case "weekday": {
|
|
193667
|
+
const wide = weekdayTables.find((t) => t && part.value === t[6]) ?? null;
|
|
193668
|
+
const abbr = wide ? null : weekdayTables.find((t) => t && part.value === t[7 + 6]) ?? null;
|
|
193669
|
+
if (wide)
|
|
193670
|
+
pattern += "dddd";
|
|
193671
|
+
else if (abbr)
|
|
193672
|
+
pattern += "ddd";
|
|
193673
|
+
else
|
|
193674
|
+
return null;
|
|
193675
|
+
weekdayTable = wide ?? abbr;
|
|
193676
|
+
usesNames = true;
|
|
193677
|
+
break;
|
|
193678
|
+
}
|
|
193227
193679
|
case "literal":
|
|
193228
|
-
if (/[YMD]/.test(part.value))
|
|
193680
|
+
if (/[YMD]/.test(part.value) || /ddd/.test(part.value))
|
|
193229
193681
|
return null;
|
|
193230
193682
|
pattern += part.value;
|
|
193231
193683
|
break;
|
|
@@ -193233,9 +193685,73 @@ function derivePattern(locale) {
|
|
|
193233
193685
|
return null;
|
|
193234
193686
|
}
|
|
193235
193687
|
}
|
|
193236
|
-
if (
|
|
193688
|
+
if (!/YYYY|MMMM|MMM|MM|M/.test(pattern) && !/DD|D/.test(pattern))
|
|
193237
193689
|
return null;
|
|
193238
|
-
|
|
193690
|
+
if (!usesNames)
|
|
193691
|
+
return { pattern, names: null };
|
|
193692
|
+
const names = [
|
|
193693
|
+
...monthTable ?? monthTables[0] ?? monthTables[1] ?? Array(24).fill(""),
|
|
193694
|
+
...weekdayTable ?? weekdayTables[0] ?? weekdayTables[1] ?? Array(14).fill("")
|
|
193695
|
+
];
|
|
193696
|
+
if (renderPatternAt(pattern, names, 2001, 5, 13, 0) !== dtf.format(VERIFY_UTC))
|
|
193697
|
+
return null;
|
|
193698
|
+
return { pattern, names };
|
|
193699
|
+
}
|
|
193700
|
+
function unionMemberLiteral(member) {
|
|
193701
|
+
const m = /^'([^'\\]*)'$|^"([^"\\]*)"$/.exec(member.raw.trim());
|
|
193702
|
+
return m ? m[1] ?? m[2] : null;
|
|
193703
|
+
}
|
|
193704
|
+
function resolveLocaleUnionMembers(locale, metadata) {
|
|
193705
|
+
let sourcePropName = null;
|
|
193706
|
+
if (metadata.propsObjectName) {
|
|
193707
|
+
if (locale.kind === "member" && !locale.computed && locale.object.kind === "identifier" && locale.object.name === metadata.propsObjectName) {
|
|
193708
|
+
sourcePropName = locale.property;
|
|
193709
|
+
}
|
|
193710
|
+
} else if (locale.kind === "identifier") {
|
|
193711
|
+
const name = locale.name;
|
|
193712
|
+
const param = metadata.propsParams?.find((pp) => pp.name === name);
|
|
193713
|
+
if (param)
|
|
193714
|
+
sourcePropName = param.sourceName ?? param.name;
|
|
193715
|
+
}
|
|
193716
|
+
if (!sourcePropName)
|
|
193717
|
+
return null;
|
|
193718
|
+
const target = sourcePropName;
|
|
193719
|
+
const prop = metadata.propsType?.properties?.find((p) => p.name === target);
|
|
193720
|
+
if (!prop || prop.optional)
|
|
193721
|
+
return null;
|
|
193722
|
+
const type2 = prop.type;
|
|
193723
|
+
if (type2.kind !== "union" || !type2.unionTypes || type2.unionTypes.length === 0)
|
|
193724
|
+
return null;
|
|
193725
|
+
const members = [];
|
|
193726
|
+
for (const member of type2.unionTypes) {
|
|
193727
|
+
const value = unionMemberLiteral(member);
|
|
193728
|
+
if (value === null)
|
|
193729
|
+
return null;
|
|
193730
|
+
members.push(value);
|
|
193731
|
+
}
|
|
193732
|
+
return members;
|
|
193733
|
+
}
|
|
193734
|
+
var strLit = (value) => ({ kind: "literal", value, literalType: "string" });
|
|
193735
|
+
function strArr(values) {
|
|
193736
|
+
return {
|
|
193737
|
+
kind: "array-literal",
|
|
193738
|
+
elements: values.map((v) => strLit(v)),
|
|
193739
|
+
raw: JSON.stringify(values)
|
|
193740
|
+
};
|
|
193741
|
+
}
|
|
193742
|
+
function foldMembers(locale, members, leaves, allEqual) {
|
|
193743
|
+
let expr = leaves[leaves.length - 1];
|
|
193744
|
+
if (allEqual)
|
|
193745
|
+
return expr;
|
|
193746
|
+
for (let i2 = leaves.length - 2;i2 >= 0; i2--) {
|
|
193747
|
+
expr = {
|
|
193748
|
+
kind: "conditional",
|
|
193749
|
+
test: { kind: "binary", op: "===", left: locale, right: strLit(members[i2]) },
|
|
193750
|
+
consequent: leaves[i2],
|
|
193751
|
+
alternate: expr
|
|
193752
|
+
};
|
|
193753
|
+
}
|
|
193754
|
+
return expr;
|
|
193239
193755
|
}
|
|
193240
193756
|
function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
193241
193757
|
if (callee.kind !== "member" || callee.computed)
|
|
@@ -193243,17 +193759,23 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
|
193243
193759
|
if (callee.property !== "toLocaleDateString" || args.length !== 2)
|
|
193244
193760
|
return null;
|
|
193245
193761
|
const [locale, options] = args;
|
|
193246
|
-
if (
|
|
193247
|
-
return null;
|
|
193248
|
-
if (options.kind !== "object-literal" || options.properties.length !== 1)
|
|
193762
|
+
if (options.kind !== "object-literal")
|
|
193249
193763
|
return null;
|
|
193250
|
-
|
|
193251
|
-
|
|
193252
|
-
|
|
193253
|
-
|
|
193254
|
-
|
|
193255
|
-
|
|
193256
|
-
|
|
193764
|
+
let tz = null;
|
|
193765
|
+
const probeOptions = {};
|
|
193766
|
+
for (const prop of options.properties) {
|
|
193767
|
+
if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
|
|
193768
|
+
return null;
|
|
193769
|
+
const value = String(prop.value.value);
|
|
193770
|
+
if (prop.key === "timeZone") {
|
|
193771
|
+
if (!TO_LOCALE_TZ_RE.test(value))
|
|
193772
|
+
return null;
|
|
193773
|
+
tz = value;
|
|
193774
|
+
} else {
|
|
193775
|
+
probeOptions[prop.key] = value;
|
|
193776
|
+
}
|
|
193777
|
+
}
|
|
193778
|
+
if (tz === null)
|
|
193257
193779
|
return null;
|
|
193258
193780
|
const receiverType = resolveReceiverType(callee.object, metadata, new Map);
|
|
193259
193781
|
if (!receiverType || receiverType.kind !== "interface")
|
|
@@ -193263,19 +193785,64 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
|
193263
193785
|
return null;
|
|
193264
193786
|
if (metadata.typeDefinitions.some((d) => d.name === typeName))
|
|
193265
193787
|
return null;
|
|
193266
|
-
|
|
193267
|
-
|
|
193788
|
+
if (locale.kind === "literal" && locale.literalType === "string") {
|
|
193789
|
+
const format3 = resolveLocaleDateFormat(String(locale.value), probeOptions);
|
|
193790
|
+
if (format3 === null)
|
|
193791
|
+
return null;
|
|
193792
|
+
return {
|
|
193793
|
+
kind: "helper-call",
|
|
193794
|
+
helper: "format_date",
|
|
193795
|
+
args: [callee.object, strLit(format3.pattern), strLit(tz), strArr(format3.names ?? [])]
|
|
193796
|
+
};
|
|
193797
|
+
}
|
|
193798
|
+
const members = resolveLocaleUnionMembers(locale, metadata);
|
|
193799
|
+
if (!members)
|
|
193268
193800
|
return null;
|
|
193801
|
+
const formats = [];
|
|
193802
|
+
for (const member of members) {
|
|
193803
|
+
const format3 = resolveLocaleDateFormat(member, probeOptions);
|
|
193804
|
+
if (format3 === null)
|
|
193805
|
+
return null;
|
|
193806
|
+
formats.push(format3);
|
|
193807
|
+
}
|
|
193808
|
+
const patterns = formats.map((f) => f.pattern);
|
|
193809
|
+
const nameTables = formats.map((f) => JSON.stringify(f.names ?? []));
|
|
193269
193810
|
return {
|
|
193270
193811
|
kind: "helper-call",
|
|
193271
193812
|
helper: "format_date",
|
|
193272
193813
|
args: [
|
|
193273
193814
|
callee.object,
|
|
193274
|
-
|
|
193275
|
-
|
|
193815
|
+
foldMembers(locale, members, patterns.map(strLit), new Set(patterns).size === 1),
|
|
193816
|
+
strLit(tz),
|
|
193817
|
+
foldMembers(locale, members, formats.map((f) => strArr(f.names ?? [])), new Set(nameTables).size === 1)
|
|
193276
193818
|
]
|
|
193277
193819
|
};
|
|
193278
193820
|
}
|
|
193821
|
+
function foldedArgToClientJs(arg, localeText) {
|
|
193822
|
+
if (arg.kind === "literal")
|
|
193823
|
+
return JSON.stringify(arg.value);
|
|
193824
|
+
if (arg.kind === "array-literal") {
|
|
193825
|
+
const values = [];
|
|
193826
|
+
for (const el of arg.elements) {
|
|
193827
|
+
if (el.kind !== "literal")
|
|
193828
|
+
return null;
|
|
193829
|
+
values.push(String(el.value));
|
|
193830
|
+
}
|
|
193831
|
+
return JSON.stringify(values);
|
|
193832
|
+
}
|
|
193833
|
+
if (arg.kind !== "conditional")
|
|
193834
|
+
return null;
|
|
193835
|
+
const t = arg.test;
|
|
193836
|
+
if (t.kind !== "binary" || t.op !== "===" || t.right.kind !== "literal")
|
|
193837
|
+
return null;
|
|
193838
|
+
if (arg.consequent.kind !== "literal" && arg.consequent.kind !== "array-literal")
|
|
193839
|
+
return null;
|
|
193840
|
+
const cons = foldedArgToClientJs(arg.consequent, localeText);
|
|
193841
|
+
const rest = foldedArgToClientJs(arg.alternate, localeText);
|
|
193842
|
+
if (cons === null || rest === null)
|
|
193843
|
+
return null;
|
|
193844
|
+
return `${localeText} === ${JSON.stringify(t.right.value)} ? ${cons} : ${rest}`;
|
|
193845
|
+
}
|
|
193279
193846
|
var toLocaleDatePlugin = {
|
|
193280
193847
|
name: "toLocaleDateString",
|
|
193281
193848
|
prepare(metadata) {
|
|
@@ -193441,12 +194008,22 @@ function lowerToLocaleDateCalls(text, expr, ctx) {
|
|
|
193441
194008
|
const node = matcher(tsNodeToParsedExpr(propAccess), call.arguments.map((a) => tsNodeToParsedExpr(a)));
|
|
193442
194009
|
if (!node || node.kind !== "helper-call" || node.helper !== "format_date")
|
|
193443
194010
|
continue;
|
|
193444
|
-
const [, patternArg, tzArg] = node.args;
|
|
193445
|
-
if (patternArg
|
|
194011
|
+
const [, patternArg, tzArg, namesArg] = node.args;
|
|
194012
|
+
if (!patternArg || tzArg?.kind !== "literal")
|
|
193446
194013
|
continue;
|
|
194014
|
+
const localeText = ctx.getJS(call.arguments[0]);
|
|
194015
|
+
const patternJs = foldedArgToClientJs(patternArg, localeText);
|
|
194016
|
+
if (patternJs === null)
|
|
194017
|
+
continue;
|
|
194018
|
+
let namesJs = null;
|
|
194019
|
+
if (namesArg && !(namesArg.kind === "array-literal" && namesArg.elements.length === 0)) {
|
|
194020
|
+
namesJs = foldedArgToClientJs(namesArg, localeText);
|
|
194021
|
+
if (namesJs === null)
|
|
194022
|
+
continue;
|
|
194023
|
+
}
|
|
193447
194024
|
const receiverText = ctx.getJS(propAccess.expression);
|
|
193448
194025
|
const matchText = ctx.getJS(call);
|
|
193449
|
-
result = replaceProtectedCall(result, matchText, () => `formatDate(${receiverText}, ${
|
|
194026
|
+
result = replaceProtectedCall(result, matchText, () => `formatDate(${receiverText}, ${patternJs}, ${JSON.stringify(tzArg.value)}${namesJs !== null ? `, ${namesJs}` : ""})`);
|
|
193450
194027
|
}
|
|
193451
194028
|
return restore(result);
|
|
193452
194029
|
}
|
|
@@ -197507,15 +198084,16 @@ function isOmitBranch(node) {
|
|
|
197507
198084
|
}
|
|
197508
198085
|
// ../jsx/src/format-date-lowering.ts
|
|
197509
198086
|
var UTC_LITERAL = { kind: "literal", value: "UTC", literalType: "string" };
|
|
198087
|
+
var EMPTY_NAMES = { kind: "array-literal", elements: [], raw: "[]" };
|
|
197510
198088
|
function matchFormatDateCall(callee, args, locals) {
|
|
197511
198089
|
if (callee.kind !== "identifier" || !locals.has(callee.name))
|
|
197512
198090
|
return null;
|
|
197513
|
-
if (args.length < 2 || args.length >
|
|
198091
|
+
if (args.length < 2 || args.length > 4)
|
|
197514
198092
|
return null;
|
|
197515
198093
|
return {
|
|
197516
198094
|
kind: "helper-call",
|
|
197517
198095
|
helper: "format_date",
|
|
197518
|
-
args: [args[0], args[1], args[2] ?? UTC_LITERAL]
|
|
198096
|
+
args: [args[0], args[1], args[2] ?? UTC_LITERAL, args[3] ?? EMPTY_NAMES]
|
|
197519
198097
|
};
|
|
197520
198098
|
}
|
|
197521
198099
|
var formatDatePlugin = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/test",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Test utilities for BarefootJS - IR-based component testing without a browser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"directory": "packages/test"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@barefootjs/jsx": "0.
|
|
42
|
+
"@barefootjs/jsx": "0.25.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.0.0"
|