@barefootjs/test 0.23.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +462 -54
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -189765,7 +189765,8 @@ 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"
|
|
189769
189770
|
};
|
|
189770
189771
|
var errorMessages = {
|
|
189771
189772
|
[ErrorCodes.MISSING_USE_CLIENT]: "'use client' directive required for components with createSignal or event handlers",
|
|
@@ -189791,7 +189792,8 @@ var errorMessages = {
|
|
|
189791
189792
|
[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
189793
|
[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
189794
|
[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."
|
|
189795
|
+
[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_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."
|
|
189795
189797
|
};
|
|
189796
189798
|
function createError(code2, loc, options) {
|
|
189797
189799
|
if (code2 === undefined || !(code2 in errorMessages)) {
|
|
@@ -192223,6 +192225,74 @@ function prescanReactiveFactoriesInSource(source, filePath) {
|
|
|
192223
192225
|
prescanImportedReactiveFactories(sourceFile, filePath, result);
|
|
192224
192226
|
return result;
|
|
192225
192227
|
}
|
|
192228
|
+
function toComponentRelativeSpecifier(resolvedAbs, componentFilePath) {
|
|
192229
|
+
let rel = path_default.relative(path_default.dirname(componentFilePath), resolvedAbs).split(path_default.sep).join("/");
|
|
192230
|
+
rel = rel.replace(/\.(tsx|ts|jsx|js)$/, "");
|
|
192231
|
+
if (rel === "")
|
|
192232
|
+
rel = ".";
|
|
192233
|
+
if (!rel.startsWith("."))
|
|
192234
|
+
rel = "./" + rel;
|
|
192235
|
+
return rel;
|
|
192236
|
+
}
|
|
192237
|
+
function buildEntryImportIndex(sf, filePath) {
|
|
192238
|
+
const index = new Map;
|
|
192239
|
+
for (const stmt of sf.statements) {
|
|
192240
|
+
if (!import_typescript8.default.isImportDeclaration(stmt))
|
|
192241
|
+
continue;
|
|
192242
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192243
|
+
continue;
|
|
192244
|
+
if (stmt.importClause?.isTypeOnly)
|
|
192245
|
+
continue;
|
|
192246
|
+
const src = stmt.moduleSpecifier.text;
|
|
192247
|
+
const targetKey = src.startsWith("./") || src.startsWith("../") ? resolveRelativeImportToFile(src, filePath) ?? "unresolved:" + src : src;
|
|
192248
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
192249
|
+
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192250
|
+
for (const el of namedBindings.elements) {
|
|
192251
|
+
if (el.isTypeOnly)
|
|
192252
|
+
continue;
|
|
192253
|
+
index.set(el.name.text, { targetKey, exportedName: (el.propertyName ?? el.name).text });
|
|
192254
|
+
}
|
|
192255
|
+
}
|
|
192256
|
+
}
|
|
192257
|
+
return index;
|
|
192258
|
+
}
|
|
192259
|
+
function collectEntryBindingNames(sf) {
|
|
192260
|
+
const names = new Set;
|
|
192261
|
+
function visit2(node) {
|
|
192262
|
+
if (import_typescript8.default.isImportDeclaration(node) && node.importClause) {
|
|
192263
|
+
if (node.importClause.name)
|
|
192264
|
+
names.add(node.importClause.name.text);
|
|
192265
|
+
const namedBindings = node.importClause.namedBindings;
|
|
192266
|
+
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192267
|
+
for (const el of namedBindings.elements)
|
|
192268
|
+
names.add(el.name.text);
|
|
192269
|
+
}
|
|
192270
|
+
if (namedBindings && import_typescript8.default.isNamespaceImport(namedBindings)) {
|
|
192271
|
+
names.add(namedBindings.name.text);
|
|
192272
|
+
}
|
|
192273
|
+
}
|
|
192274
|
+
if (import_typescript8.default.isVariableDeclaration(node)) {
|
|
192275
|
+
const out = [];
|
|
192276
|
+
addBindingNames(node.name, out);
|
|
192277
|
+
for (const n of out)
|
|
192278
|
+
names.add(n);
|
|
192279
|
+
}
|
|
192280
|
+
if ((import_typescript8.default.isFunctionDeclaration(node) || import_typescript8.default.isClassDeclaration(node) || import_typescript8.default.isEnumDeclaration(node)) && node.name) {
|
|
192281
|
+
names.add(node.name.text);
|
|
192282
|
+
}
|
|
192283
|
+
if (import_typescript8.default.isFunctionLike(node)) {
|
|
192284
|
+
for (const p of node.parameters) {
|
|
192285
|
+
const out = [];
|
|
192286
|
+
addBindingNames(p.name, out);
|
|
192287
|
+
for (const n of out)
|
|
192288
|
+
names.add(n);
|
|
192289
|
+
}
|
|
192290
|
+
}
|
|
192291
|
+
import_typescript8.default.forEachChild(node, visit2);
|
|
192292
|
+
}
|
|
192293
|
+
visit2(sf);
|
|
192294
|
+
return names;
|
|
192295
|
+
}
|
|
192226
192296
|
function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
192227
192297
|
const candidateCallees = new Set;
|
|
192228
192298
|
function collectCandidates(node) {
|
|
@@ -192263,6 +192333,9 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192263
192333
|
}
|
|
192264
192334
|
if (importsToCheck.length === 0)
|
|
192265
192335
|
return;
|
|
192336
|
+
const entryBindingNames = collectEntryBindingNames(entrySourceFile);
|
|
192337
|
+
const entryImportIndex = buildEntryImportIndex(entrySourceFile, filePath);
|
|
192338
|
+
const plannedInjections = new Map;
|
|
192266
192339
|
for (const { src, specs } of importsToCheck) {
|
|
192267
192340
|
const resolved = resolveRelativeImportToFile(src, filePath);
|
|
192268
192341
|
if (!resolved)
|
|
@@ -192328,17 +192401,64 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192328
192401
|
result.declined.set(spec.local, det.declined);
|
|
192329
192402
|
break;
|
|
192330
192403
|
case "factory": {
|
|
192331
|
-
const
|
|
192332
|
-
if (
|
|
192404
|
+
const capture = moduleCaptureCheck(fn, det.info, moduleBindings, fn.name.text);
|
|
192405
|
+
if (capture.captured.length > 0) {
|
|
192333
192406
|
result.declined.set(spec.local, {
|
|
192334
192407
|
code: "BF112",
|
|
192335
|
-
detail: `'${
|
|
192408
|
+
detail: `'${capture.captured.join("', '")}'`,
|
|
192336
192409
|
loc: det.info.loc
|
|
192337
192410
|
});
|
|
192338
|
-
|
|
192339
|
-
det.info.sourceFilePath = resolved;
|
|
192340
|
-
result.factories.set(spec.local, det.info);
|
|
192411
|
+
break;
|
|
192341
192412
|
}
|
|
192413
|
+
const required = [];
|
|
192414
|
+
const pending = [];
|
|
192415
|
+
let declinedEntry = null;
|
|
192416
|
+
for (const ref of capture.importedRefs) {
|
|
192417
|
+
let specifier;
|
|
192418
|
+
let targetKey;
|
|
192419
|
+
if (ref.source.startsWith("./") || ref.source.startsWith("../")) {
|
|
192420
|
+
const abs = resolveRelativeImportToFile(ref.source, resolved);
|
|
192421
|
+
if (!abs) {
|
|
192422
|
+
declinedEntry = {
|
|
192423
|
+
code: "BF112",
|
|
192424
|
+
detail: `'${ref.localName}' (import '${ref.source}' did not resolve from the helper file)`,
|
|
192425
|
+
loc: det.info.loc
|
|
192426
|
+
};
|
|
192427
|
+
break;
|
|
192428
|
+
}
|
|
192429
|
+
specifier = toComponentRelativeSpecifier(abs, filePath);
|
|
192430
|
+
targetKey = abs;
|
|
192431
|
+
} else {
|
|
192432
|
+
specifier = ref.source;
|
|
192433
|
+
targetKey = ref.source;
|
|
192434
|
+
}
|
|
192435
|
+
const existing = entryImportIndex.get(ref.localName);
|
|
192436
|
+
if (existing && existing.targetKey === targetKey && existing.exportedName === ref.exportedName) {
|
|
192437
|
+
continue;
|
|
192438
|
+
}
|
|
192439
|
+
const planned = plannedInjections.get(ref.localName);
|
|
192440
|
+
const collides = existing !== undefined || planned !== undefined && (planned.targetKey !== targetKey || planned.exportedName !== ref.exportedName) || planned === undefined && entryBindingNames.has(ref.localName);
|
|
192441
|
+
if (collides) {
|
|
192442
|
+
declinedEntry = {
|
|
192443
|
+
code: "BF113",
|
|
192444
|
+
detail: `'${ref.localName}' from '${specifier}'`,
|
|
192445
|
+
loc: det.info.loc
|
|
192446
|
+
};
|
|
192447
|
+
break;
|
|
192448
|
+
}
|
|
192449
|
+
pending.push([ref.localName, { targetKey, exportedName: ref.exportedName }]);
|
|
192450
|
+
required.push({ localName: ref.localName, exportedName: ref.exportedName, specifier });
|
|
192451
|
+
}
|
|
192452
|
+
if (declinedEntry) {
|
|
192453
|
+
result.declined.set(spec.local, declinedEntry);
|
|
192454
|
+
break;
|
|
192455
|
+
}
|
|
192456
|
+
for (const [name, id] of pending)
|
|
192457
|
+
plannedInjections.set(name, id);
|
|
192458
|
+
det.info.sourceFilePath = resolved;
|
|
192459
|
+
if (required.length > 0)
|
|
192460
|
+
det.info.requiredImports = required;
|
|
192461
|
+
result.factories.set(spec.local, det.info);
|
|
192342
192462
|
break;
|
|
192343
192463
|
}
|
|
192344
192464
|
}
|
|
@@ -192346,7 +192466,8 @@ function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
|
192346
192466
|
}
|
|
192347
192467
|
}
|
|
192348
192468
|
function collectHelperModuleValueBindings(sf) {
|
|
192349
|
-
const
|
|
192469
|
+
const local = new Set;
|
|
192470
|
+
const imported = new Map;
|
|
192350
192471
|
for (const stmt of sf.statements) {
|
|
192351
192472
|
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
192352
192473
|
const out = [];
|
|
@@ -192354,11 +192475,11 @@ function collectHelperModuleValueBindings(sf) {
|
|
|
192354
192475
|
addBindingNames(decl.name, out);
|
|
192355
192476
|
}
|
|
192356
192477
|
for (const n of out)
|
|
192357
|
-
|
|
192478
|
+
local.add(n);
|
|
192358
192479
|
continue;
|
|
192359
192480
|
}
|
|
192360
192481
|
if ((import_typescript8.default.isFunctionDeclaration(stmt) || import_typescript8.default.isClassDeclaration(stmt) || import_typescript8.default.isEnumDeclaration(stmt)) && stmt.name) {
|
|
192361
|
-
|
|
192482
|
+
local.add(stmt.name.text);
|
|
192362
192483
|
continue;
|
|
192363
192484
|
}
|
|
192364
192485
|
if (import_typescript8.default.isImportDeclaration(stmt)) {
|
|
@@ -192370,25 +192491,25 @@ function collectHelperModuleValueBindings(sf) {
|
|
|
192370
192491
|
if (src === "@barefootjs/client" || src === "@barefootjs/client/runtime")
|
|
192371
192492
|
continue;
|
|
192372
192493
|
if (stmt.importClause?.name)
|
|
192373
|
-
|
|
192494
|
+
local.add(stmt.importClause.name.text);
|
|
192374
192495
|
const namedBindings = stmt.importClause?.namedBindings;
|
|
192375
192496
|
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192376
192497
|
for (const el of namedBindings.elements) {
|
|
192377
192498
|
if (el.isTypeOnly)
|
|
192378
192499
|
continue;
|
|
192379
|
-
|
|
192500
|
+
imported.set(el.name.text, { source: src, exportedName: (el.propertyName ?? el.name).text });
|
|
192380
192501
|
}
|
|
192381
192502
|
}
|
|
192382
192503
|
if (namedBindings && import_typescript8.default.isNamespaceImport(namedBindings)) {
|
|
192383
|
-
|
|
192504
|
+
local.add(namedBindings.name.text);
|
|
192384
192505
|
}
|
|
192385
192506
|
}
|
|
192386
192507
|
}
|
|
192387
|
-
return
|
|
192508
|
+
return { local, imported };
|
|
192388
192509
|
}
|
|
192389
192510
|
function moduleCaptureCheck(fn, info, moduleBindings, selfName) {
|
|
192390
192511
|
if (!fn.body)
|
|
192391
|
-
return [];
|
|
192512
|
+
return { captured: [], importedRefs: [] };
|
|
192392
192513
|
const free = extractFreeIdentifiersFromNode(fn.body);
|
|
192393
192514
|
const exclude = new Set(info.params);
|
|
192394
192515
|
for (const b of info.localBindings)
|
|
@@ -192398,14 +192519,22 @@ function moduleCaptureCheck(fn, info, moduleBindings, selfName) {
|
|
|
192398
192519
|
for (const p of REACTIVE_PRIMITIVES)
|
|
192399
192520
|
exclude.add(p);
|
|
192400
192521
|
exclude.add(selfName);
|
|
192401
|
-
const
|
|
192522
|
+
const captured = [];
|
|
192523
|
+
const importedRefs = [];
|
|
192402
192524
|
for (const id of free) {
|
|
192403
192525
|
if (exclude.has(id))
|
|
192404
192526
|
continue;
|
|
192405
|
-
if (moduleBindings.has(id))
|
|
192406
|
-
|
|
192527
|
+
if (moduleBindings.local.has(id)) {
|
|
192528
|
+
captured.push(id);
|
|
192529
|
+
continue;
|
|
192530
|
+
}
|
|
192531
|
+
const imp = moduleBindings.imported.get(id);
|
|
192532
|
+
if (imp)
|
|
192533
|
+
importedRefs.push({ localName: id, source: imp.source, exportedName: imp.exportedName });
|
|
192407
192534
|
}
|
|
192408
|
-
|
|
192535
|
+
captured.sort();
|
|
192536
|
+
importedRefs.sort((a, b) => a.localName < b.localName ? -1 : 1);
|
|
192537
|
+
return { captured, importedRefs };
|
|
192409
192538
|
}
|
|
192410
192539
|
function detectReactiveFactory(node, sourceFile, filePath) {
|
|
192411
192540
|
if (!node.body || !node.name)
|
|
@@ -192529,6 +192658,7 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192529
192658
|
const { factories, sourceFile } = prescan;
|
|
192530
192659
|
const edits = [];
|
|
192531
192660
|
let callSiteIndex = 0;
|
|
192661
|
+
const inlinedFactories = new Set;
|
|
192532
192662
|
function visitStmt(node, inComponent) {
|
|
192533
192663
|
if (import_typescript8.default.isVariableStatement(node) && inComponent) {
|
|
192534
192664
|
for (const decl of node.declarationList.declarations) {
|
|
@@ -192630,10 +192760,34 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192630
192760
|
end: stmt.getEnd(),
|
|
192631
192761
|
replacement: body
|
|
192632
192762
|
});
|
|
192763
|
+
inlinedFactories.add(factory);
|
|
192633
192764
|
}
|
|
192634
192765
|
visitStmt(sourceFile, false);
|
|
192635
192766
|
if (edits.length === 0)
|
|
192636
192767
|
return source;
|
|
192768
|
+
const importsBySpecifier = new Map;
|
|
192769
|
+
for (const f of inlinedFactories) {
|
|
192770
|
+
for (const r of f.requiredImports ?? []) {
|
|
192771
|
+
let names = importsBySpecifier.get(r.specifier);
|
|
192772
|
+
if (!names) {
|
|
192773
|
+
names = new Map;
|
|
192774
|
+
importsBySpecifier.set(r.specifier, names);
|
|
192775
|
+
}
|
|
192776
|
+
names.set(r.localName, r.exportedName);
|
|
192777
|
+
}
|
|
192778
|
+
}
|
|
192779
|
+
if (importsBySpecifier.size > 0) {
|
|
192780
|
+
const lines = [...importsBySpecifier].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([spec, names]) => {
|
|
192781
|
+
const specifiers = [...names].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([local, exported]) => exported === local ? local : `${exported} as ${local}`);
|
|
192782
|
+
return `import { ${specifiers.join(", ")} } from '${spec}'`;
|
|
192783
|
+
});
|
|
192784
|
+
const at = factoryImportInsertionOffset(sourceFile);
|
|
192785
|
+
edits.push({ start: at, end: at, replacement: at === 0 ? lines.join(`
|
|
192786
|
+
`) + `
|
|
192787
|
+
` : `
|
|
192788
|
+
` + lines.join(`
|
|
192789
|
+
`) });
|
|
192790
|
+
}
|
|
192637
192791
|
edits.sort((a, b) => b.start - a.start);
|
|
192638
192792
|
let out = source;
|
|
192639
192793
|
for (const e of edits) {
|
|
@@ -192641,6 +192795,20 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192641
192795
|
}
|
|
192642
192796
|
return out;
|
|
192643
192797
|
}
|
|
192798
|
+
function factoryImportInsertionOffset(sf) {
|
|
192799
|
+
let lastImportEnd = -1;
|
|
192800
|
+
let directiveEnd = -1;
|
|
192801
|
+
for (const stmt of sf.statements) {
|
|
192802
|
+
if (import_typescript8.default.isImportDeclaration(stmt)) {
|
|
192803
|
+
lastImportEnd = stmt.getEnd();
|
|
192804
|
+
continue;
|
|
192805
|
+
}
|
|
192806
|
+
if (directiveEnd === -1 && import_typescript8.default.isExpressionStatement(stmt) && import_typescript8.default.isStringLiteral(stmt.expression) && stmt.expression.text === "use client") {
|
|
192807
|
+
directiveEnd = stmt.getEnd();
|
|
192808
|
+
}
|
|
192809
|
+
}
|
|
192810
|
+
return lastImportEnd >= 0 ? lastImportEnd : directiveEnd >= 0 ? directiveEnd : 0;
|
|
192811
|
+
}
|
|
192644
192812
|
function isPascalCaseComponentFn(node) {
|
|
192645
192813
|
if (import_typescript8.default.isFunctionDeclaration(node) && node.name) {
|
|
192646
192814
|
return /^[A-Z]/.test(node.name.text);
|
|
@@ -192657,8 +192825,21 @@ function declinedFactoryMessage(callee, d) {
|
|
|
192657
192825
|
if (d.code === "BF112") {
|
|
192658
192826
|
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
192827
|
}
|
|
192828
|
+
if (d.code === "BF113") {
|
|
192829
|
+
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 }).`;
|
|
192830
|
+
}
|
|
192660
192831
|
return `Reactive factory '${callee}' cannot be inlined: ${d.detail}.`;
|
|
192661
192832
|
}
|
|
192833
|
+
function declinedFactoryErrorCode(code2) {
|
|
192834
|
+
switch (code2) {
|
|
192835
|
+
case "BF112":
|
|
192836
|
+
return ErrorCodes.REACTIVE_FACTORY_MODULE_CAPTURE;
|
|
192837
|
+
case "BF113":
|
|
192838
|
+
return ErrorCodes.REACTIVE_FACTORY_IMPORT_COLLISION;
|
|
192839
|
+
default:
|
|
192840
|
+
return ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED;
|
|
192841
|
+
}
|
|
192842
|
+
}
|
|
192662
192843
|
function validateReactiveFactoryCalls(ctx) {
|
|
192663
192844
|
if (!ctx.componentNode)
|
|
192664
192845
|
return;
|
|
@@ -192682,7 +192863,7 @@ function validateReactiveFactoryCalls(ctx) {
|
|
|
192682
192863
|
continue;
|
|
192683
192864
|
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192684
192865
|
if (declinedEntry) {
|
|
192685
|
-
ctx.errors.push(createError(declinedEntry.code
|
|
192866
|
+
ctx.errors.push(createError(declinedFactoryErrorCode(declinedEntry.code), loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192686
192867
|
continue;
|
|
192687
192868
|
}
|
|
192688
192869
|
const objectFactory = ctx.reactiveFactories.get(callee);
|
|
@@ -192739,7 +192920,7 @@ function validateObjectFactoryDestructure(ctx, pattern, callee, loc) {
|
|
|
192739
192920
|
}
|
|
192740
192921
|
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192741
192922
|
if (declinedEntry) {
|
|
192742
|
-
ctx.errors.push(createError(declinedEntry.code
|
|
192923
|
+
ctx.errors.push(createError(declinedFactoryErrorCode(declinedEntry.code), loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192743
192924
|
return;
|
|
192744
192925
|
}
|
|
192745
192926
|
if (ctx.reactiveShapedHelpers.has(callee)) {
|
|
@@ -193180,19 +193361,83 @@ function resolveFreeRefs(node, env) {
|
|
|
193180
193361
|
// ../jsx/src/to-locale-date-lowering.ts
|
|
193181
193362
|
var TO_LOCALE_TZ_RE = /^(?:UTC|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
|
|
193182
193363
|
var PROBE_UTC = new Date(Date.UTC(2001, 1, 3));
|
|
193183
|
-
var
|
|
193184
|
-
|
|
193185
|
-
|
|
193364
|
+
var formatCache = new Map;
|
|
193365
|
+
var namesCache = new Map;
|
|
193366
|
+
function deriveMonthNames(locale, ctx) {
|
|
193367
|
+
return deriveNamesCached(`${locale}|m|${ctx}`, () => {
|
|
193368
|
+
const months2 = (width) => Array.from({ length: 12 }, (_, m) => probePart(locale, ctx === "formatting" ? { month: width, day: "numeric" } : { month: width }, Date.UTC(2001, m, 15), "month"));
|
|
193369
|
+
return [...months2("long"), ...months2("short")];
|
|
193370
|
+
});
|
|
193371
|
+
}
|
|
193372
|
+
function deriveWeekdayNames(locale, ctx) {
|
|
193373
|
+
return deriveNamesCached(`${locale}|w|${ctx}`, () => {
|
|
193374
|
+
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"));
|
|
193375
|
+
return [...weekdays("long"), ...weekdays("short")];
|
|
193376
|
+
});
|
|
193377
|
+
}
|
|
193378
|
+
function probePart(locale, options, utc, type2) {
|
|
193379
|
+
const parts = new Intl.DateTimeFormat(locale, { ...options, timeZone: "UTC" }).formatToParts(new Date(utc));
|
|
193380
|
+
const found = parts.find((p) => p.type === type2);
|
|
193381
|
+
if (!found || !found.value)
|
|
193382
|
+
throw new Error("missing part");
|
|
193383
|
+
return found.value;
|
|
193384
|
+
}
|
|
193385
|
+
function deriveNamesCached(key, derive) {
|
|
193386
|
+
const cached = namesCache.get(key);
|
|
193186
193387
|
if (cached !== undefined)
|
|
193187
193388
|
return cached;
|
|
193188
|
-
|
|
193189
|
-
|
|
193389
|
+
let derived;
|
|
193390
|
+
try {
|
|
193391
|
+
derived = derive();
|
|
193392
|
+
} catch {
|
|
193393
|
+
derived = null;
|
|
193394
|
+
}
|
|
193395
|
+
namesCache.set(key, derived);
|
|
193190
193396
|
return derived;
|
|
193191
193397
|
}
|
|
193192
|
-
function
|
|
193398
|
+
function resolveLocaleDateFormat(locale, probeOptions) {
|
|
193399
|
+
const key = `${locale}|${JSON.stringify(probeOptions, Object.keys(probeOptions).sort())}`;
|
|
193400
|
+
const cached = formatCache.get(key);
|
|
193401
|
+
if (cached !== undefined)
|
|
193402
|
+
return cached;
|
|
193403
|
+
const derived = deriveFormat(locale, probeOptions);
|
|
193404
|
+
formatCache.set(key, derived);
|
|
193405
|
+
return derived;
|
|
193406
|
+
}
|
|
193407
|
+
var VERIFY_UTC = new Date(Date.UTC(2001, 4, 13));
|
|
193408
|
+
function renderPatternAt(pattern, names, y, m, d, wd) {
|
|
193409
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
193410
|
+
return pattern.replace(/YYYY|MMMM|MMM|MM|DD|dddd|ddd|M|D/g, (token) => {
|
|
193411
|
+
switch (token) {
|
|
193412
|
+
case "YYYY":
|
|
193413
|
+
return String(y).padStart(4, "0");
|
|
193414
|
+
case "MMMM":
|
|
193415
|
+
return names[m - 1] ?? "";
|
|
193416
|
+
case "MMM":
|
|
193417
|
+
return names[12 + m - 1] ?? "";
|
|
193418
|
+
case "MM":
|
|
193419
|
+
return pad2(m);
|
|
193420
|
+
case "M":
|
|
193421
|
+
return String(m);
|
|
193422
|
+
case "DD":
|
|
193423
|
+
return pad2(d);
|
|
193424
|
+
case "D":
|
|
193425
|
+
return String(d);
|
|
193426
|
+
case "dddd":
|
|
193427
|
+
return names[24 + wd] ?? "";
|
|
193428
|
+
default:
|
|
193429
|
+
return names[31 + wd] ?? "";
|
|
193430
|
+
}
|
|
193431
|
+
});
|
|
193432
|
+
}
|
|
193433
|
+
function deriveFormat(locale, probeOptions) {
|
|
193434
|
+
let dtf;
|
|
193193
193435
|
let parts;
|
|
193194
193436
|
try {
|
|
193195
|
-
|
|
193437
|
+
dtf = new Intl.DateTimeFormat(locale, {
|
|
193438
|
+
...probeOptions,
|
|
193439
|
+
timeZone: "UTC"
|
|
193440
|
+
});
|
|
193196
193441
|
const resolved = dtf.resolvedOptions();
|
|
193197
193442
|
if (resolved.calendar !== "gregory" || resolved.numberingSystem !== "latn")
|
|
193198
193443
|
return null;
|
|
@@ -193200,7 +193445,18 @@ function derivePattern(locale) {
|
|
|
193200
193445
|
} catch {
|
|
193201
193446
|
return null;
|
|
193202
193447
|
}
|
|
193448
|
+
const monthTables = [
|
|
193449
|
+
deriveMonthNames(locale, "formatting"),
|
|
193450
|
+
deriveMonthNames(locale, "standalone")
|
|
193451
|
+
];
|
|
193452
|
+
const weekdayTables = [
|
|
193453
|
+
deriveWeekdayNames(locale, "formatting"),
|
|
193454
|
+
deriveWeekdayNames(locale, "standalone")
|
|
193455
|
+
];
|
|
193456
|
+
let monthTable = null;
|
|
193457
|
+
let weekdayTable = null;
|
|
193203
193458
|
let pattern = "";
|
|
193459
|
+
let usesNames = false;
|
|
193204
193460
|
for (const part of parts) {
|
|
193205
193461
|
switch (part.type) {
|
|
193206
193462
|
case "year":
|
|
@@ -193208,14 +193464,27 @@ function derivePattern(locale) {
|
|
|
193208
193464
|
return null;
|
|
193209
193465
|
pattern += "YYYY";
|
|
193210
193466
|
break;
|
|
193211
|
-
case "month":
|
|
193212
|
-
if (part.value === "2")
|
|
193467
|
+
case "month": {
|
|
193468
|
+
if (part.value === "2") {
|
|
193213
193469
|
pattern += "M";
|
|
193214
|
-
|
|
193470
|
+
break;
|
|
193471
|
+
}
|
|
193472
|
+
if (part.value === "02") {
|
|
193215
193473
|
pattern += "MM";
|
|
193474
|
+
break;
|
|
193475
|
+
}
|
|
193476
|
+
const wide = monthTables.find((t) => t && part.value === t[1]) ?? null;
|
|
193477
|
+
const abbr = wide ? null : monthTables.find((t) => t && part.value === t[12 + 1]) ?? null;
|
|
193478
|
+
if (wide)
|
|
193479
|
+
pattern += "MMMM";
|
|
193480
|
+
else if (abbr)
|
|
193481
|
+
pattern += "MMM";
|
|
193216
193482
|
else
|
|
193217
193483
|
return null;
|
|
193484
|
+
monthTable = wide ?? abbr;
|
|
193485
|
+
usesNames = true;
|
|
193218
193486
|
break;
|
|
193487
|
+
}
|
|
193219
193488
|
case "day":
|
|
193220
193489
|
if (part.value === "3")
|
|
193221
193490
|
pattern += "D";
|
|
@@ -193224,8 +193493,21 @@ function derivePattern(locale) {
|
|
|
193224
193493
|
else
|
|
193225
193494
|
return null;
|
|
193226
193495
|
break;
|
|
193496
|
+
case "weekday": {
|
|
193497
|
+
const wide = weekdayTables.find((t) => t && part.value === t[6]) ?? null;
|
|
193498
|
+
const abbr = wide ? null : weekdayTables.find((t) => t && part.value === t[7 + 6]) ?? null;
|
|
193499
|
+
if (wide)
|
|
193500
|
+
pattern += "dddd";
|
|
193501
|
+
else if (abbr)
|
|
193502
|
+
pattern += "ddd";
|
|
193503
|
+
else
|
|
193504
|
+
return null;
|
|
193505
|
+
weekdayTable = wide ?? abbr;
|
|
193506
|
+
usesNames = true;
|
|
193507
|
+
break;
|
|
193508
|
+
}
|
|
193227
193509
|
case "literal":
|
|
193228
|
-
if (/[YMD]/.test(part.value))
|
|
193510
|
+
if (/[YMD]/.test(part.value) || /ddd/.test(part.value))
|
|
193229
193511
|
return null;
|
|
193230
193512
|
pattern += part.value;
|
|
193231
193513
|
break;
|
|
@@ -193233,9 +193515,73 @@ function derivePattern(locale) {
|
|
|
193233
193515
|
return null;
|
|
193234
193516
|
}
|
|
193235
193517
|
}
|
|
193236
|
-
if (
|
|
193518
|
+
if (!/YYYY|MMMM|MMM|MM|M/.test(pattern) && !/DD|D/.test(pattern))
|
|
193519
|
+
return null;
|
|
193520
|
+
if (!usesNames)
|
|
193521
|
+
return { pattern, names: null };
|
|
193522
|
+
const names = [
|
|
193523
|
+
...monthTable ?? monthTables[0] ?? monthTables[1] ?? Array(24).fill(""),
|
|
193524
|
+
...weekdayTable ?? weekdayTables[0] ?? weekdayTables[1] ?? Array(14).fill("")
|
|
193525
|
+
];
|
|
193526
|
+
if (renderPatternAt(pattern, names, 2001, 5, 13, 0) !== dtf.format(VERIFY_UTC))
|
|
193237
193527
|
return null;
|
|
193238
|
-
return pattern;
|
|
193528
|
+
return { pattern, names };
|
|
193529
|
+
}
|
|
193530
|
+
function unionMemberLiteral(member) {
|
|
193531
|
+
const m = /^'([^'\\]*)'$|^"([^"\\]*)"$/.exec(member.raw.trim());
|
|
193532
|
+
return m ? m[1] ?? m[2] : null;
|
|
193533
|
+
}
|
|
193534
|
+
function resolveLocaleUnionMembers(locale, metadata) {
|
|
193535
|
+
let sourcePropName = null;
|
|
193536
|
+
if (metadata.propsObjectName) {
|
|
193537
|
+
if (locale.kind === "member" && !locale.computed && locale.object.kind === "identifier" && locale.object.name === metadata.propsObjectName) {
|
|
193538
|
+
sourcePropName = locale.property;
|
|
193539
|
+
}
|
|
193540
|
+
} else if (locale.kind === "identifier") {
|
|
193541
|
+
const name = locale.name;
|
|
193542
|
+
const param = metadata.propsParams?.find((pp) => pp.name === name);
|
|
193543
|
+
if (param)
|
|
193544
|
+
sourcePropName = param.sourceName ?? param.name;
|
|
193545
|
+
}
|
|
193546
|
+
if (!sourcePropName)
|
|
193547
|
+
return null;
|
|
193548
|
+
const target = sourcePropName;
|
|
193549
|
+
const prop = metadata.propsType?.properties?.find((p) => p.name === target);
|
|
193550
|
+
if (!prop || prop.optional)
|
|
193551
|
+
return null;
|
|
193552
|
+
const type2 = prop.type;
|
|
193553
|
+
if (type2.kind !== "union" || !type2.unionTypes || type2.unionTypes.length === 0)
|
|
193554
|
+
return null;
|
|
193555
|
+
const members = [];
|
|
193556
|
+
for (const member of type2.unionTypes) {
|
|
193557
|
+
const value = unionMemberLiteral(member);
|
|
193558
|
+
if (value === null)
|
|
193559
|
+
return null;
|
|
193560
|
+
members.push(value);
|
|
193561
|
+
}
|
|
193562
|
+
return members;
|
|
193563
|
+
}
|
|
193564
|
+
var strLit = (value) => ({ kind: "literal", value, literalType: "string" });
|
|
193565
|
+
function strArr(values) {
|
|
193566
|
+
return {
|
|
193567
|
+
kind: "array-literal",
|
|
193568
|
+
elements: values.map((v) => strLit(v)),
|
|
193569
|
+
raw: JSON.stringify(values)
|
|
193570
|
+
};
|
|
193571
|
+
}
|
|
193572
|
+
function foldMembers(locale, members, leaves, allEqual) {
|
|
193573
|
+
let expr = leaves[leaves.length - 1];
|
|
193574
|
+
if (allEqual)
|
|
193575
|
+
return expr;
|
|
193576
|
+
for (let i2 = leaves.length - 2;i2 >= 0; i2--) {
|
|
193577
|
+
expr = {
|
|
193578
|
+
kind: "conditional",
|
|
193579
|
+
test: { kind: "binary", op: "===", left: locale, right: strLit(members[i2]) },
|
|
193580
|
+
consequent: leaves[i2],
|
|
193581
|
+
alternate: expr
|
|
193582
|
+
};
|
|
193583
|
+
}
|
|
193584
|
+
return expr;
|
|
193239
193585
|
}
|
|
193240
193586
|
function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
193241
193587
|
if (callee.kind !== "member" || callee.computed)
|
|
@@ -193243,17 +193589,23 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
|
193243
193589
|
if (callee.property !== "toLocaleDateString" || args.length !== 2)
|
|
193244
193590
|
return null;
|
|
193245
193591
|
const [locale, options] = args;
|
|
193246
|
-
if (
|
|
193247
|
-
return null;
|
|
193248
|
-
if (options.kind !== "object-literal" || options.properties.length !== 1)
|
|
193249
|
-
return null;
|
|
193250
|
-
const prop = options.properties[0];
|
|
193251
|
-
if (prop.key !== "timeZone")
|
|
193592
|
+
if (options.kind !== "object-literal")
|
|
193252
193593
|
return null;
|
|
193253
|
-
|
|
193254
|
-
|
|
193255
|
-
const
|
|
193256
|
-
|
|
193594
|
+
let tz = null;
|
|
193595
|
+
const probeOptions = {};
|
|
193596
|
+
for (const prop of options.properties) {
|
|
193597
|
+
if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
|
|
193598
|
+
return null;
|
|
193599
|
+
const value = String(prop.value.value);
|
|
193600
|
+
if (prop.key === "timeZone") {
|
|
193601
|
+
if (!TO_LOCALE_TZ_RE.test(value))
|
|
193602
|
+
return null;
|
|
193603
|
+
tz = value;
|
|
193604
|
+
} else {
|
|
193605
|
+
probeOptions[prop.key] = value;
|
|
193606
|
+
}
|
|
193607
|
+
}
|
|
193608
|
+
if (tz === null)
|
|
193257
193609
|
return null;
|
|
193258
193610
|
const receiverType = resolveReceiverType(callee.object, metadata, new Map);
|
|
193259
193611
|
if (!receiverType || receiverType.kind !== "interface")
|
|
@@ -193263,19 +193615,64 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
|
193263
193615
|
return null;
|
|
193264
193616
|
if (metadata.typeDefinitions.some((d) => d.name === typeName))
|
|
193265
193617
|
return null;
|
|
193266
|
-
|
|
193267
|
-
|
|
193618
|
+
if (locale.kind === "literal" && locale.literalType === "string") {
|
|
193619
|
+
const format3 = resolveLocaleDateFormat(String(locale.value), probeOptions);
|
|
193620
|
+
if (format3 === null)
|
|
193621
|
+
return null;
|
|
193622
|
+
return {
|
|
193623
|
+
kind: "helper-call",
|
|
193624
|
+
helper: "format_date",
|
|
193625
|
+
args: [callee.object, strLit(format3.pattern), strLit(tz), strArr(format3.names ?? [])]
|
|
193626
|
+
};
|
|
193627
|
+
}
|
|
193628
|
+
const members = resolveLocaleUnionMembers(locale, metadata);
|
|
193629
|
+
if (!members)
|
|
193268
193630
|
return null;
|
|
193631
|
+
const formats = [];
|
|
193632
|
+
for (const member of members) {
|
|
193633
|
+
const format3 = resolveLocaleDateFormat(member, probeOptions);
|
|
193634
|
+
if (format3 === null)
|
|
193635
|
+
return null;
|
|
193636
|
+
formats.push(format3);
|
|
193637
|
+
}
|
|
193638
|
+
const patterns = formats.map((f) => f.pattern);
|
|
193639
|
+
const nameTables = formats.map((f) => JSON.stringify(f.names ?? []));
|
|
193269
193640
|
return {
|
|
193270
193641
|
kind: "helper-call",
|
|
193271
193642
|
helper: "format_date",
|
|
193272
193643
|
args: [
|
|
193273
193644
|
callee.object,
|
|
193274
|
-
|
|
193275
|
-
|
|
193645
|
+
foldMembers(locale, members, patterns.map(strLit), new Set(patterns).size === 1),
|
|
193646
|
+
strLit(tz),
|
|
193647
|
+
foldMembers(locale, members, formats.map((f) => strArr(f.names ?? [])), new Set(nameTables).size === 1)
|
|
193276
193648
|
]
|
|
193277
193649
|
};
|
|
193278
193650
|
}
|
|
193651
|
+
function foldedArgToClientJs(arg, localeText) {
|
|
193652
|
+
if (arg.kind === "literal")
|
|
193653
|
+
return JSON.stringify(arg.value);
|
|
193654
|
+
if (arg.kind === "array-literal") {
|
|
193655
|
+
const values = [];
|
|
193656
|
+
for (const el of arg.elements) {
|
|
193657
|
+
if (el.kind !== "literal")
|
|
193658
|
+
return null;
|
|
193659
|
+
values.push(String(el.value));
|
|
193660
|
+
}
|
|
193661
|
+
return JSON.stringify(values);
|
|
193662
|
+
}
|
|
193663
|
+
if (arg.kind !== "conditional")
|
|
193664
|
+
return null;
|
|
193665
|
+
const t = arg.test;
|
|
193666
|
+
if (t.kind !== "binary" || t.op !== "===" || t.right.kind !== "literal")
|
|
193667
|
+
return null;
|
|
193668
|
+
if (arg.consequent.kind !== "literal" && arg.consequent.kind !== "array-literal")
|
|
193669
|
+
return null;
|
|
193670
|
+
const cons = foldedArgToClientJs(arg.consequent, localeText);
|
|
193671
|
+
const rest = foldedArgToClientJs(arg.alternate, localeText);
|
|
193672
|
+
if (cons === null || rest === null)
|
|
193673
|
+
return null;
|
|
193674
|
+
return `${localeText} === ${JSON.stringify(t.right.value)} ? ${cons} : ${rest}`;
|
|
193675
|
+
}
|
|
193279
193676
|
var toLocaleDatePlugin = {
|
|
193280
193677
|
name: "toLocaleDateString",
|
|
193281
193678
|
prepare(metadata) {
|
|
@@ -193441,12 +193838,22 @@ function lowerToLocaleDateCalls(text, expr, ctx) {
|
|
|
193441
193838
|
const node = matcher(tsNodeToParsedExpr(propAccess), call.arguments.map((a) => tsNodeToParsedExpr(a)));
|
|
193442
193839
|
if (!node || node.kind !== "helper-call" || node.helper !== "format_date")
|
|
193443
193840
|
continue;
|
|
193444
|
-
const [, patternArg, tzArg] = node.args;
|
|
193445
|
-
if (patternArg
|
|
193841
|
+
const [, patternArg, tzArg, namesArg] = node.args;
|
|
193842
|
+
if (!patternArg || tzArg?.kind !== "literal")
|
|
193843
|
+
continue;
|
|
193844
|
+
const localeText = ctx.getJS(call.arguments[0]);
|
|
193845
|
+
const patternJs = foldedArgToClientJs(patternArg, localeText);
|
|
193846
|
+
if (patternJs === null)
|
|
193446
193847
|
continue;
|
|
193848
|
+
let namesJs = null;
|
|
193849
|
+
if (namesArg && !(namesArg.kind === "array-literal" && namesArg.elements.length === 0)) {
|
|
193850
|
+
namesJs = foldedArgToClientJs(namesArg, localeText);
|
|
193851
|
+
if (namesJs === null)
|
|
193852
|
+
continue;
|
|
193853
|
+
}
|
|
193447
193854
|
const receiverText = ctx.getJS(propAccess.expression);
|
|
193448
193855
|
const matchText = ctx.getJS(call);
|
|
193449
|
-
result = replaceProtectedCall(result, matchText, () => `formatDate(${receiverText}, ${
|
|
193856
|
+
result = replaceProtectedCall(result, matchText, () => `formatDate(${receiverText}, ${patternJs}, ${JSON.stringify(tzArg.value)}${namesJs !== null ? `, ${namesJs}` : ""})`);
|
|
193450
193857
|
}
|
|
193451
193858
|
return restore(result);
|
|
193452
193859
|
}
|
|
@@ -197507,15 +197914,16 @@ function isOmitBranch(node) {
|
|
|
197507
197914
|
}
|
|
197508
197915
|
// ../jsx/src/format-date-lowering.ts
|
|
197509
197916
|
var UTC_LITERAL = { kind: "literal", value: "UTC", literalType: "string" };
|
|
197917
|
+
var EMPTY_NAMES = { kind: "array-literal", elements: [], raw: "[]" };
|
|
197510
197918
|
function matchFormatDateCall(callee, args, locals) {
|
|
197511
197919
|
if (callee.kind !== "identifier" || !locals.has(callee.name))
|
|
197512
197920
|
return null;
|
|
197513
|
-
if (args.length < 2 || args.length >
|
|
197921
|
+
if (args.length < 2 || args.length > 4)
|
|
197514
197922
|
return null;
|
|
197515
197923
|
return {
|
|
197516
197924
|
kind: "helper-call",
|
|
197517
197925
|
helper: "format_date",
|
|
197518
|
-
args: [args[0], args[1], args[2] ?? UTC_LITERAL]
|
|
197926
|
+
args: [args[0], args[1], args[2] ?? UTC_LITERAL, args[3] ?? EMPTY_NAMES]
|
|
197519
197927
|
};
|
|
197520
197928
|
}
|
|
197521
197929
|
var formatDatePlugin = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/test",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Test utilities for BarefootJS - IR-based component testing without a browser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"directory": "packages/test"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@barefootjs/jsx": "0.
|
|
42
|
+
"@barefootjs/jsx": "0.24.1"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.0.0"
|