@barefootjs/test 0.21.4 → 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 +1057 -71
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -189221,18 +189221,39 @@ function createTemplateAwareStringProtector() {
|
|
|
189221
189221
|
stash.push(s);
|
|
189222
189222
|
return `__STRLIT_${i2}__`;
|
|
189223
189223
|
};
|
|
189224
|
+
const STRING_LIT_RE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g;
|
|
189224
189225
|
const protect = (s) => {
|
|
189225
189226
|
s = s.replace(/`([^`]*)`/g, (_full, inner) => {
|
|
189226
189227
|
const parts = splitTemplateInterpolations(inner);
|
|
189227
189228
|
return "`" + parts.map((p) => p.startsWith("${") ? p : save(p)).join("") + "`";
|
|
189228
189229
|
});
|
|
189229
|
-
s = s.replace(
|
|
189230
|
+
s = s.replace(STRING_LIT_RE, (m) => save(m));
|
|
189230
189231
|
return s;
|
|
189231
189232
|
};
|
|
189232
189233
|
const restore = (s) => {
|
|
189233
189234
|
return s.replace(/__STRLIT_(\d+)__/g, (_, i2) => stash[Number(i2)]);
|
|
189234
189235
|
};
|
|
189235
|
-
|
|
189236
|
+
const replaceProtectedCall = (haystack, needle, replacement) => {
|
|
189237
|
+
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
189238
|
+
const litValues = [];
|
|
189239
|
+
let pattern = "";
|
|
189240
|
+
let last = 0;
|
|
189241
|
+
for (const m of needle.matchAll(STRING_LIT_RE)) {
|
|
189242
|
+
pattern += escape(needle.slice(last, m.index));
|
|
189243
|
+
pattern += "__STRLIT_(\\d+)__";
|
|
189244
|
+
litValues.push(m[0]);
|
|
189245
|
+
last = m.index + m[0].length;
|
|
189246
|
+
}
|
|
189247
|
+
pattern += escape(needle.slice(last));
|
|
189248
|
+
for (const m of haystack.matchAll(new RegExp(pattern, "g"))) {
|
|
189249
|
+
const verified = m.slice(1).every((idx, i2) => stash[Number(idx)] === litValues[i2]);
|
|
189250
|
+
if (!verified)
|
|
189251
|
+
continue;
|
|
189252
|
+
return haystack.slice(0, m.index) + replacement() + haystack.slice(m.index + m[0].length);
|
|
189253
|
+
}
|
|
189254
|
+
return haystack;
|
|
189255
|
+
};
|
|
189256
|
+
return { protect, restore, replaceProtectedCall };
|
|
189236
189257
|
}
|
|
189237
189258
|
var VOID_ELEMENTS = new Set([
|
|
189238
189259
|
"area",
|
|
@@ -189551,6 +189572,9 @@ function createAnalyzerContext(sourceFile, filePath) {
|
|
|
189551
189572
|
jsxFunctions: new Map,
|
|
189552
189573
|
jsxMultiReturnFunctions: new Map,
|
|
189553
189574
|
reactiveFactories: new Map,
|
|
189575
|
+
declinedReactiveFactories: new Map,
|
|
189576
|
+
reactiveShapedHelpers: new Set,
|
|
189577
|
+
cleanFactoryImports: new Set,
|
|
189554
189578
|
signalTupleRefs: new Map,
|
|
189555
189579
|
propsType: null,
|
|
189556
189580
|
propsParams: [],
|
|
@@ -189739,7 +189763,10 @@ var ErrorCodes = {
|
|
|
189739
189763
|
STAGE_INIT_LOCAL_IN_TEMPLATE: "BF061",
|
|
189740
189764
|
STAGE_AWAIT_IN_TEMPLATE: "BF062",
|
|
189741
189765
|
INLINE_JSX_CALLBACK_CAPTURE: "BF080",
|
|
189742
|
-
UNRECOGNIZED_REACTIVE_FACTORY: "BF110"
|
|
189766
|
+
UNRECOGNIZED_REACTIVE_FACTORY: "BF110",
|
|
189767
|
+
REACTIVE_FACTORY_RENAME_UNSUPPORTED: "BF111",
|
|
189768
|
+
REACTIVE_FACTORY_MODULE_CAPTURE: "BF112",
|
|
189769
|
+
REACTIVE_FACTORY_IMPORT_COLLISION: "BF113"
|
|
189743
189770
|
};
|
|
189744
189771
|
var errorMessages = {
|
|
189745
189772
|
[ErrorCodes.MISSING_USE_CLIENT]: "'use client' directive required for components with createSignal or event handlers",
|
|
@@ -189763,7 +189790,10 @@ var errorMessages = {
|
|
|
189763
189790
|
[ErrorCodes.STAGE_INIT_LOCAL_IN_TEMPLATE]: "Init-scope local referenced from template scope. The template lambda runs at module scope (via render() / renderChild()) and cannot reach init-body locals. Wrap the JSX expression in /* @client */, or lift the value to a prop or module-scope const.",
|
|
189764
189791
|
[ErrorCodes.STAGE_AWAIT_IN_TEMPLATE]: "AwaitExpression in template scope. The generated template and init functions are synchronous — a bare `await` produces a SyntaxError at parse time. Move the await into the component body (before the return) or into an onMount/effect callback, and pass the resolved value to JSX.",
|
|
189765
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.",
|
|
189766
|
-
[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
|
+
[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.",
|
|
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.",
|
|
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."
|
|
189767
189797
|
};
|
|
189768
189798
|
function createError(code2, loc, options) {
|
|
189769
189799
|
if (code2 === undefined || !(code2 in errorMessages)) {
|
|
@@ -190032,6 +190062,10 @@ function analyzeComponent(source, filePath, targetComponentName, program) {
|
|
|
190032
190062
|
}
|
|
190033
190063
|
const ctx = createAnalyzerContext(sourceFile, filePath);
|
|
190034
190064
|
ctx.checker = checker;
|
|
190065
|
+
ctx.reactiveFactories = prescan.factories;
|
|
190066
|
+
ctx.declinedReactiveFactories = prescan.declined;
|
|
190067
|
+
ctx.reactiveShapedHelpers = prescan.reactiveShaped;
|
|
190068
|
+
ctx.cleanFactoryImports = prescan.cleanFactoryImports;
|
|
190035
190069
|
const brandImportLoc = findBrandPackageImportLoc(sourceFile, filePath);
|
|
190036
190070
|
if (!hadSharedProgram && brandImportLoc !== null) {
|
|
190037
190071
|
ctx.errors.push(createError(ErrorCodes.SHARED_PROGRAM_REQUIRED, brandImportLoc));
|
|
@@ -190937,6 +190971,7 @@ var CLIENT_EXPORTS = new Set([
|
|
|
190937
190971
|
"cleanupPortalPlaceholder",
|
|
190938
190972
|
"createSearchParams",
|
|
190939
190973
|
"queryHref",
|
|
190974
|
+
"formatDate",
|
|
190940
190975
|
"Async",
|
|
190941
190976
|
"Region"
|
|
190942
190977
|
]);
|
|
@@ -192164,27 +192199,368 @@ var REACTIVE_PRIMITIVES = new Set([
|
|
|
192164
192199
|
function prescanReactiveFactoriesInSource(source, filePath) {
|
|
192165
192200
|
const sourceFile = import_typescript8.default.createSourceFile(filePath + ".prescan", source, import_typescript8.default.ScriptTarget.Latest, true, import_typescript8.default.ScriptKind.TSX);
|
|
192166
192201
|
const factories = new Map;
|
|
192202
|
+
const declined = new Map;
|
|
192203
|
+
const reactiveShaped = new Set;
|
|
192204
|
+
const cleanFactoryImports = new Set;
|
|
192167
192205
|
function visitTop(node) {
|
|
192168
192206
|
if (import_typescript8.default.isFunctionDeclaration(node) && node.name && node.body) {
|
|
192169
|
-
const
|
|
192170
|
-
if (
|
|
192171
|
-
|
|
192207
|
+
const det = detectReactiveFactory(node, sourceFile, filePath);
|
|
192208
|
+
if (!det)
|
|
192209
|
+
return;
|
|
192210
|
+
switch (det.kind) {
|
|
192211
|
+
case "factory":
|
|
192212
|
+
factories.set(node.name.text, det.info);
|
|
192213
|
+
break;
|
|
192214
|
+
case "declined":
|
|
192215
|
+
declined.set(node.name.text, det.declined);
|
|
192216
|
+
break;
|
|
192217
|
+
case "reactive-shaped":
|
|
192218
|
+
reactiveShaped.add(node.name.text);
|
|
192219
|
+
break;
|
|
192220
|
+
}
|
|
192172
192221
|
}
|
|
192173
192222
|
}
|
|
192174
192223
|
import_typescript8.default.forEachChild(sourceFile, visitTop);
|
|
192175
|
-
|
|
192224
|
+
const result = { factories, declined, reactiveShaped, cleanFactoryImports, sourceFile };
|
|
192225
|
+
prescanImportedReactiveFactories(sourceFile, filePath, result);
|
|
192226
|
+
return result;
|
|
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
|
+
}
|
|
192296
|
+
function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
192297
|
+
const candidateCallees = new Set;
|
|
192298
|
+
function collectCandidates(node) {
|
|
192299
|
+
if (import_typescript8.default.isVariableDeclaration(node) && (import_typescript8.default.isArrayBindingPattern(node.name) || import_typescript8.default.isObjectBindingPattern(node.name)) && node.initializer && import_typescript8.default.isCallExpression(node.initializer) && import_typescript8.default.isIdentifier(node.initializer.expression)) {
|
|
192300
|
+
candidateCallees.add(node.initializer.expression.text);
|
|
192301
|
+
}
|
|
192302
|
+
import_typescript8.default.forEachChild(node, collectCandidates);
|
|
192303
|
+
}
|
|
192304
|
+
collectCandidates(entrySourceFile);
|
|
192305
|
+
if (candidateCallees.size === 0)
|
|
192306
|
+
return;
|
|
192307
|
+
const importsToCheck = [];
|
|
192308
|
+
for (const stmt of entrySourceFile.statements) {
|
|
192309
|
+
if (!import_typescript8.default.isImportDeclaration(stmt))
|
|
192310
|
+
continue;
|
|
192311
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192312
|
+
continue;
|
|
192313
|
+
const src = stmt.moduleSpecifier.text;
|
|
192314
|
+
if (!src.startsWith("./") && !src.startsWith("../"))
|
|
192315
|
+
continue;
|
|
192316
|
+
if (stmt.importClause?.isTypeOnly)
|
|
192317
|
+
continue;
|
|
192318
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
192319
|
+
if (!namedBindings || !import_typescript8.default.isNamedImports(namedBindings))
|
|
192320
|
+
continue;
|
|
192321
|
+
const specs = [];
|
|
192322
|
+
for (const el of namedBindings.elements) {
|
|
192323
|
+
if (el.isTypeOnly)
|
|
192324
|
+
continue;
|
|
192325
|
+
const local = el.name.text;
|
|
192326
|
+
if (!candidateCallees.has(local))
|
|
192327
|
+
continue;
|
|
192328
|
+
specs.push({ exported: (el.propertyName ?? el.name).text, local });
|
|
192329
|
+
}
|
|
192330
|
+
if (specs.length === 0)
|
|
192331
|
+
continue;
|
|
192332
|
+
importsToCheck.push({ src, specs });
|
|
192333
|
+
}
|
|
192334
|
+
if (importsToCheck.length === 0)
|
|
192335
|
+
return;
|
|
192336
|
+
const entryBindingNames = collectEntryBindingNames(entrySourceFile);
|
|
192337
|
+
const entryImportIndex = buildEntryImportIndex(entrySourceFile, filePath);
|
|
192338
|
+
const plannedInjections = new Map;
|
|
192339
|
+
for (const { src, specs } of importsToCheck) {
|
|
192340
|
+
const resolved = resolveRelativeImportToFile(src, filePath);
|
|
192341
|
+
if (!resolved)
|
|
192342
|
+
continue;
|
|
192343
|
+
let content;
|
|
192344
|
+
try {
|
|
192345
|
+
content = fs.readFileSync(resolved, "utf8");
|
|
192346
|
+
} catch {
|
|
192347
|
+
continue;
|
|
192348
|
+
}
|
|
192349
|
+
const alreadyKnown = (name) => result.factories.has(name) || result.declined.has(name) || result.reactiveShaped.has(name);
|
|
192350
|
+
const hasAnyPrimitiveText = [...REACTIVE_PRIMITIVES].some((p) => content.includes(p));
|
|
192351
|
+
if (!hasAnyPrimitiveText) {
|
|
192352
|
+
for (const spec of specs) {
|
|
192353
|
+
if (!alreadyKnown(spec.local))
|
|
192354
|
+
result.cleanFactoryImports.add(spec.local);
|
|
192355
|
+
}
|
|
192356
|
+
continue;
|
|
192357
|
+
}
|
|
192358
|
+
const helperSf = import_typescript8.default.createSourceFile(resolved + ".prescan", content, import_typescript8.default.ScriptTarget.Latest, true, import_typescript8.default.ScriptKind.TSX);
|
|
192359
|
+
const localFns = new Map;
|
|
192360
|
+
const exportedFns = new Map;
|
|
192361
|
+
for (const stmt of helperSf.statements) {
|
|
192362
|
+
if (import_typescript8.default.isFunctionDeclaration(stmt) && stmt.name && stmt.body) {
|
|
192363
|
+
localFns.set(stmt.name.text, stmt);
|
|
192364
|
+
const hasExportModifier = stmt.modifiers?.some((m) => m.kind === import_typescript8.default.SyntaxKind.ExportKeyword) ?? false;
|
|
192365
|
+
const hasDefaultModifier = stmt.modifiers?.some((m) => m.kind === import_typescript8.default.SyntaxKind.DefaultKeyword) ?? false;
|
|
192366
|
+
if (hasExportModifier && !hasDefaultModifier) {
|
|
192367
|
+
exportedFns.set(stmt.name.text, stmt);
|
|
192368
|
+
}
|
|
192369
|
+
}
|
|
192370
|
+
}
|
|
192371
|
+
for (const stmt of helperSf.statements) {
|
|
192372
|
+
if (import_typescript8.default.isExportDeclaration(stmt) && stmt.exportClause && import_typescript8.default.isNamedExports(stmt.exportClause) && !stmt.moduleSpecifier && !stmt.isTypeOnly) {
|
|
192373
|
+
for (const el of stmt.exportClause.elements) {
|
|
192374
|
+
if (el.isTypeOnly)
|
|
192375
|
+
continue;
|
|
192376
|
+
const fn = localFns.get((el.propertyName ?? el.name).text);
|
|
192377
|
+
if (fn)
|
|
192378
|
+
exportedFns.set(el.name.text, fn);
|
|
192379
|
+
}
|
|
192380
|
+
}
|
|
192381
|
+
}
|
|
192382
|
+
const moduleBindings = collectHelperModuleValueBindings(helperSf);
|
|
192383
|
+
for (const spec of specs) {
|
|
192384
|
+
if (alreadyKnown(spec.local))
|
|
192385
|
+
continue;
|
|
192386
|
+
const fn = exportedFns.get(spec.exported);
|
|
192387
|
+
if (!fn) {
|
|
192388
|
+
result.cleanFactoryImports.add(spec.local);
|
|
192389
|
+
continue;
|
|
192390
|
+
}
|
|
192391
|
+
const det = detectReactiveFactory(fn, helperSf, resolved);
|
|
192392
|
+
if (!det) {
|
|
192393
|
+
result.cleanFactoryImports.add(spec.local);
|
|
192394
|
+
continue;
|
|
192395
|
+
}
|
|
192396
|
+
switch (det.kind) {
|
|
192397
|
+
case "reactive-shaped":
|
|
192398
|
+
result.reactiveShaped.add(spec.local);
|
|
192399
|
+
break;
|
|
192400
|
+
case "declined":
|
|
192401
|
+
result.declined.set(spec.local, det.declined);
|
|
192402
|
+
break;
|
|
192403
|
+
case "factory": {
|
|
192404
|
+
const capture = moduleCaptureCheck(fn, det.info, moduleBindings, fn.name.text);
|
|
192405
|
+
if (capture.captured.length > 0) {
|
|
192406
|
+
result.declined.set(spec.local, {
|
|
192407
|
+
code: "BF112",
|
|
192408
|
+
detail: `'${capture.captured.join("', '")}'`,
|
|
192409
|
+
loc: det.info.loc
|
|
192410
|
+
});
|
|
192411
|
+
break;
|
|
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);
|
|
192462
|
+
break;
|
|
192463
|
+
}
|
|
192464
|
+
}
|
|
192465
|
+
}
|
|
192466
|
+
}
|
|
192467
|
+
}
|
|
192468
|
+
function collectHelperModuleValueBindings(sf) {
|
|
192469
|
+
const local = new Set;
|
|
192470
|
+
const imported = new Map;
|
|
192471
|
+
for (const stmt of sf.statements) {
|
|
192472
|
+
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
192473
|
+
const out = [];
|
|
192474
|
+
for (const decl of stmt.declarationList.declarations) {
|
|
192475
|
+
addBindingNames(decl.name, out);
|
|
192476
|
+
}
|
|
192477
|
+
for (const n of out)
|
|
192478
|
+
local.add(n);
|
|
192479
|
+
continue;
|
|
192480
|
+
}
|
|
192481
|
+
if ((import_typescript8.default.isFunctionDeclaration(stmt) || import_typescript8.default.isClassDeclaration(stmt) || import_typescript8.default.isEnumDeclaration(stmt)) && stmt.name) {
|
|
192482
|
+
local.add(stmt.name.text);
|
|
192483
|
+
continue;
|
|
192484
|
+
}
|
|
192485
|
+
if (import_typescript8.default.isImportDeclaration(stmt)) {
|
|
192486
|
+
if (stmt.importClause?.isTypeOnly)
|
|
192487
|
+
continue;
|
|
192488
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192489
|
+
continue;
|
|
192490
|
+
const src = stmt.moduleSpecifier.text;
|
|
192491
|
+
if (src === "@barefootjs/client" || src === "@barefootjs/client/runtime")
|
|
192492
|
+
continue;
|
|
192493
|
+
if (stmt.importClause?.name)
|
|
192494
|
+
local.add(stmt.importClause.name.text);
|
|
192495
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
192496
|
+
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192497
|
+
for (const el of namedBindings.elements) {
|
|
192498
|
+
if (el.isTypeOnly)
|
|
192499
|
+
continue;
|
|
192500
|
+
imported.set(el.name.text, { source: src, exportedName: (el.propertyName ?? el.name).text });
|
|
192501
|
+
}
|
|
192502
|
+
}
|
|
192503
|
+
if (namedBindings && import_typescript8.default.isNamespaceImport(namedBindings)) {
|
|
192504
|
+
local.add(namedBindings.name.text);
|
|
192505
|
+
}
|
|
192506
|
+
}
|
|
192507
|
+
}
|
|
192508
|
+
return { local, imported };
|
|
192509
|
+
}
|
|
192510
|
+
function moduleCaptureCheck(fn, info, moduleBindings, selfName) {
|
|
192511
|
+
if (!fn.body)
|
|
192512
|
+
return { captured: [], importedRefs: [] };
|
|
192513
|
+
const free = extractFreeIdentifiersFromNode(fn.body);
|
|
192514
|
+
const exclude = new Set(info.params);
|
|
192515
|
+
for (const b of info.localBindings)
|
|
192516
|
+
exclude.add(b);
|
|
192517
|
+
for (const r of info.returnTupleIdentifiers)
|
|
192518
|
+
exclude.add(r);
|
|
192519
|
+
for (const p of REACTIVE_PRIMITIVES)
|
|
192520
|
+
exclude.add(p);
|
|
192521
|
+
exclude.add(selfName);
|
|
192522
|
+
const captured = [];
|
|
192523
|
+
const importedRefs = [];
|
|
192524
|
+
for (const id of free) {
|
|
192525
|
+
if (exclude.has(id))
|
|
192526
|
+
continue;
|
|
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 });
|
|
192534
|
+
}
|
|
192535
|
+
captured.sort();
|
|
192536
|
+
importedRefs.sort((a, b) => a.localName < b.localName ? -1 : 1);
|
|
192537
|
+
return { captured, importedRefs };
|
|
192176
192538
|
}
|
|
192177
192539
|
function detectReactiveFactory(node, sourceFile, filePath) {
|
|
192178
192540
|
if (!node.body || !node.name)
|
|
192179
192541
|
return null;
|
|
192180
|
-
let
|
|
192542
|
+
let hasReactiveCall = false;
|
|
192543
|
+
function checkForReactive(n) {
|
|
192544
|
+
if (hasReactiveCall)
|
|
192545
|
+
return;
|
|
192546
|
+
if (import_typescript8.default.isCallExpression(n) && import_typescript8.default.isIdentifier(n.expression) && REACTIVE_PRIMITIVES.has(n.expression.text)) {
|
|
192547
|
+
hasReactiveCall = true;
|
|
192548
|
+
return;
|
|
192549
|
+
}
|
|
192550
|
+
import_typescript8.default.forEachChild(n, checkForReactive);
|
|
192551
|
+
}
|
|
192552
|
+
checkForReactive(node.body);
|
|
192553
|
+
if (!hasReactiveCall)
|
|
192554
|
+
return null;
|
|
192555
|
+
const loc = getSourceLocation(node, sourceFile, filePath);
|
|
192556
|
+
let returnExpr = null;
|
|
192181
192557
|
let returnCount = 0;
|
|
192182
192558
|
for (const stmt of node.body.statements) {
|
|
192183
192559
|
if (!import_typescript8.default.isReturnStatement(stmt))
|
|
192184
192560
|
continue;
|
|
192185
192561
|
returnCount++;
|
|
192186
192562
|
if (!stmt.expression)
|
|
192187
|
-
return
|
|
192563
|
+
return { kind: "reactive-shaped" };
|
|
192188
192564
|
let expr = stmt.expression;
|
|
192189
192565
|
while (import_typescript8.default.isParenthesizedExpression(expr))
|
|
192190
192566
|
expr = expr.expression;
|
|
@@ -192192,33 +192568,42 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192192
192568
|
expr = expr.expression;
|
|
192193
192569
|
if (import_typescript8.default.isTypeAssertionExpression(expr))
|
|
192194
192570
|
expr = expr.expression;
|
|
192195
|
-
|
|
192196
|
-
return null;
|
|
192197
|
-
tupleReturn = expr;
|
|
192571
|
+
returnExpr = expr;
|
|
192198
192572
|
}
|
|
192199
|
-
if (returnCount !== 1 || !
|
|
192200
|
-
return
|
|
192573
|
+
if (returnCount !== 1 || !returnExpr)
|
|
192574
|
+
return { kind: "reactive-shaped" };
|
|
192201
192575
|
const returnTupleIdentifiers = [];
|
|
192202
|
-
|
|
192203
|
-
|
|
192204
|
-
|
|
192205
|
-
|
|
192206
|
-
|
|
192207
|
-
|
|
192208
|
-
|
|
192209
|
-
|
|
192210
|
-
|
|
192211
|
-
|
|
192212
|
-
|
|
192213
|
-
|
|
192214
|
-
|
|
192215
|
-
|
|
192576
|
+
let returnKind;
|
|
192577
|
+
if (import_typescript8.default.isArrayLiteralExpression(returnExpr)) {
|
|
192578
|
+
returnKind = "tuple";
|
|
192579
|
+
for (const el of returnExpr.elements) {
|
|
192580
|
+
if (!import_typescript8.default.isIdentifier(el))
|
|
192581
|
+
return { kind: "reactive-shaped" };
|
|
192582
|
+
returnTupleIdentifiers.push(el.text);
|
|
192583
|
+
}
|
|
192584
|
+
if (returnTupleIdentifiers.length === 0)
|
|
192585
|
+
return { kind: "reactive-shaped" };
|
|
192586
|
+
} else if (import_typescript8.default.isObjectLiteralExpression(returnExpr)) {
|
|
192587
|
+
returnKind = "object";
|
|
192588
|
+
const hasNonShorthand = returnExpr.properties.some((p) => !import_typescript8.default.isShorthandPropertyAssignment(p));
|
|
192589
|
+
if (hasNonShorthand) {
|
|
192590
|
+
return {
|
|
192591
|
+
kind: "declined",
|
|
192592
|
+
declined: {
|
|
192593
|
+
code: "BF111",
|
|
192594
|
+
detail: `return object of '${node.name.text}' uses non-shorthand properties`,
|
|
192595
|
+
loc
|
|
192596
|
+
}
|
|
192597
|
+
};
|
|
192216
192598
|
}
|
|
192217
|
-
|
|
192599
|
+
for (const p of returnExpr.properties) {
|
|
192600
|
+
returnTupleIdentifiers.push(p.name.text);
|
|
192601
|
+
}
|
|
192602
|
+
if (returnTupleIdentifiers.length === 0)
|
|
192603
|
+
return { kind: "reactive-shaped" };
|
|
192604
|
+
} else {
|
|
192605
|
+
return { kind: "reactive-shaped" };
|
|
192218
192606
|
}
|
|
192219
|
-
checkForReactive(node.body);
|
|
192220
|
-
if (!hasReactiveCall)
|
|
192221
|
-
return null;
|
|
192222
192607
|
const localBindings = [];
|
|
192223
192608
|
for (const stmt of node.body.statements) {
|
|
192224
192609
|
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
@@ -192231,19 +192616,24 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192231
192616
|
}
|
|
192232
192617
|
const bodyStatements = node.body.statements.filter((s) => !import_typescript8.default.isReturnStatement(s)).map((s) => s.getText(sourceFile)).join(`
|
|
192233
192618
|
`);
|
|
192234
|
-
const params =
|
|
192235
|
-
|
|
192236
|
-
|
|
192237
|
-
|
|
192238
|
-
|
|
192239
|
-
|
|
192240
|
-
return
|
|
192619
|
+
const params = [];
|
|
192620
|
+
for (const p of node.parameters) {
|
|
192621
|
+
if (import_typescript8.default.isIdentifier(p.name)) {
|
|
192622
|
+
params.push(p.name.text);
|
|
192623
|
+
continue;
|
|
192624
|
+
}
|
|
192625
|
+
return { kind: "reactive-shaped" };
|
|
192626
|
+
}
|
|
192241
192627
|
return {
|
|
192242
|
-
|
|
192243
|
-
|
|
192244
|
-
|
|
192245
|
-
|
|
192246
|
-
|
|
192628
|
+
kind: "factory",
|
|
192629
|
+
info: {
|
|
192630
|
+
params,
|
|
192631
|
+
bodySource: bodyStatements,
|
|
192632
|
+
returnTupleIdentifiers,
|
|
192633
|
+
returnKind,
|
|
192634
|
+
localBindings,
|
|
192635
|
+
loc
|
|
192636
|
+
}
|
|
192247
192637
|
};
|
|
192248
192638
|
}
|
|
192249
192639
|
function addBindingNames(name, out) {
|
|
@@ -192268,6 +192658,7 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192268
192658
|
const { factories, sourceFile } = prescan;
|
|
192269
192659
|
const edits = [];
|
|
192270
192660
|
let callSiteIndex = 0;
|
|
192661
|
+
const inlinedFactories = new Set;
|
|
192271
192662
|
function visitStmt(node, inComponent) {
|
|
192272
192663
|
if (import_typescript8.default.isVariableStatement(node) && inComponent) {
|
|
192273
192664
|
for (const decl of node.declarationList.declarations) {
|
|
@@ -192281,8 +192672,6 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192281
192672
|
});
|
|
192282
192673
|
}
|
|
192283
192674
|
function maybeRewriteDecl(stmt, decl) {
|
|
192284
|
-
if (!import_typescript8.default.isArrayBindingPattern(decl.name))
|
|
192285
|
-
return;
|
|
192286
192675
|
if (!decl.initializer || !import_typescript8.default.isCallExpression(decl.initializer))
|
|
192287
192676
|
return;
|
|
192288
192677
|
if (!import_typescript8.default.isIdentifier(decl.initializer.expression))
|
|
@@ -192291,7 +192680,21 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192291
192680
|
const factory = factories.get(factoryName);
|
|
192292
192681
|
if (!factory)
|
|
192293
192682
|
return;
|
|
192294
|
-
|
|
192683
|
+
if (import_typescript8.default.isArrayBindingPattern(decl.name)) {
|
|
192684
|
+
if (factory.returnKind !== "tuple")
|
|
192685
|
+
return;
|
|
192686
|
+
rewriteTupleDecl(stmt, decl.name, decl.initializer, factory);
|
|
192687
|
+
return;
|
|
192688
|
+
}
|
|
192689
|
+
if (import_typescript8.default.isObjectBindingPattern(decl.name)) {
|
|
192690
|
+
if (factory.returnKind !== "object")
|
|
192691
|
+
return;
|
|
192692
|
+
rewriteObjectDecl(stmt, decl.name, decl.initializer, factory);
|
|
192693
|
+
return;
|
|
192694
|
+
}
|
|
192695
|
+
}
|
|
192696
|
+
function rewriteTupleDecl(stmt, pattern, call, factory) {
|
|
192697
|
+
const elements = pattern.elements;
|
|
192295
192698
|
if (elements.length !== factory.returnTupleIdentifiers.length)
|
|
192296
192699
|
return;
|
|
192297
192700
|
const callerNames = [];
|
|
@@ -192300,15 +192703,43 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192300
192703
|
return;
|
|
192301
192704
|
callerNames.push(el.name.text);
|
|
192302
192705
|
}
|
|
192303
|
-
const
|
|
192706
|
+
const excludeFromSuffixRename = new Set(factory.params);
|
|
192707
|
+
for (const r of factory.returnTupleIdentifiers)
|
|
192708
|
+
excludeFromSuffixRename.add(r);
|
|
192709
|
+
const renameReturnToCallerNames = new Map;
|
|
192710
|
+
for (let i2 = 0;i2 < factory.returnTupleIdentifiers.length; i2++) {
|
|
192711
|
+
renameReturnToCallerNames.set(factory.returnTupleIdentifiers[i2], callerNames[i2]);
|
|
192712
|
+
}
|
|
192713
|
+
inlineFactoryCallAtSite(stmt, factory, call.arguments, excludeFromSuffixRename, renameReturnToCallerNames);
|
|
192714
|
+
}
|
|
192715
|
+
function rewriteObjectDecl(stmt, pattern, call, factory) {
|
|
192716
|
+
const destructured = new Set;
|
|
192717
|
+
for (const el of pattern.elements) {
|
|
192718
|
+
if (el.dotDotDotToken)
|
|
192719
|
+
return;
|
|
192720
|
+
if (el.propertyName)
|
|
192721
|
+
return;
|
|
192722
|
+
if (el.initializer)
|
|
192723
|
+
return;
|
|
192724
|
+
if (!import_typescript8.default.isIdentifier(el.name))
|
|
192725
|
+
return;
|
|
192726
|
+
if (!factory.returnTupleIdentifiers.includes(el.name.text))
|
|
192727
|
+
return;
|
|
192728
|
+
destructured.add(el.name.text);
|
|
192729
|
+
}
|
|
192730
|
+
const excludeFromSuffixRename = new Set(factory.params);
|
|
192731
|
+
for (const d of destructured)
|
|
192732
|
+
excludeFromSuffixRename.add(d);
|
|
192733
|
+
inlineFactoryCallAtSite(stmt, factory, call.arguments, excludeFromSuffixRename, null);
|
|
192734
|
+
}
|
|
192735
|
+
function inlineFactoryCallAtSite(stmt, factory, args, excludeFromSuffixRename, renameReturnToCallerNames) {
|
|
192736
|
+
const argTexts = args.map((a) => a.getText(sourceFile));
|
|
192304
192737
|
const thisCallIndex = callSiteIndex++;
|
|
192305
192738
|
const suffix = `_bf${thisCallIndex}`;
|
|
192306
192739
|
let body = factory.bodySource;
|
|
192307
192740
|
const internalRenames = new Set(factory.localBindings);
|
|
192308
|
-
for (const
|
|
192309
|
-
internalRenames.delete(
|
|
192310
|
-
for (const r of factory.returnTupleIdentifiers)
|
|
192311
|
-
internalRenames.delete(r);
|
|
192741
|
+
for (const ex of excludeFromSuffixRename)
|
|
192742
|
+
internalRenames.delete(ex);
|
|
192312
192743
|
for (const name of internalRenames) {
|
|
192313
192744
|
body = body.replace(new RegExp(`\\b${escapeRegex(name)}\\b`, "g"), name + suffix);
|
|
192314
192745
|
}
|
|
@@ -192319,20 +192750,44 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192319
192750
|
const wrapped = atomicArg.test(a.trim()) ? a.trim() : `(${a})`;
|
|
192320
192751
|
body = body.replace(new RegExp(`\\b${escapeRegex(p)}\\b`, "g"), wrapped);
|
|
192321
192752
|
}
|
|
192322
|
-
|
|
192323
|
-
const n
|
|
192324
|
-
|
|
192325
|
-
|
|
192753
|
+
if (renameReturnToCallerNames) {
|
|
192754
|
+
for (const [n, caller] of renameReturnToCallerNames) {
|
|
192755
|
+
body = body.replace(new RegExp(`\\b${escapeRegex(n)}\\b`, "g"), caller);
|
|
192756
|
+
}
|
|
192326
192757
|
}
|
|
192327
192758
|
edits.push({
|
|
192328
192759
|
start: stmt.getStart(sourceFile),
|
|
192329
192760
|
end: stmt.getEnd(),
|
|
192330
192761
|
replacement: body
|
|
192331
192762
|
});
|
|
192763
|
+
inlinedFactories.add(factory);
|
|
192332
192764
|
}
|
|
192333
192765
|
visitStmt(sourceFile, false);
|
|
192334
192766
|
if (edits.length === 0)
|
|
192335
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
|
+
}
|
|
192336
192791
|
edits.sort((a, b) => b.start - a.start);
|
|
192337
192792
|
let out = source;
|
|
192338
192793
|
for (const e of edits) {
|
|
@@ -192340,6 +192795,20 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192340
192795
|
}
|
|
192341
192796
|
return out;
|
|
192342
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
|
+
}
|
|
192343
192812
|
function isPascalCaseComponentFn(node) {
|
|
192344
192813
|
if (import_typescript8.default.isFunctionDeclaration(node) && node.name) {
|
|
192345
192814
|
return /^[A-Z]/.test(node.name.text);
|
|
@@ -192352,6 +192821,25 @@ function isPascalCaseComponentFn(node) {
|
|
|
192352
192821
|
function escapeRegex(s) {
|
|
192353
192822
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
192354
192823
|
}
|
|
192824
|
+
function declinedFactoryMessage(callee, d) {
|
|
192825
|
+
if (d.code === "BF112") {
|
|
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.`;
|
|
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
|
+
}
|
|
192831
|
+
return `Reactive factory '${callee}' cannot be inlined: ${d.detail}.`;
|
|
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
|
+
}
|
|
192355
192843
|
function validateReactiveFactoryCalls(ctx) {
|
|
192356
192844
|
if (!ctx.componentNode)
|
|
192357
192845
|
return;
|
|
@@ -192362,26 +192850,104 @@ function validateReactiveFactoryCalls(ctx) {
|
|
|
192362
192850
|
if (!import_typescript8.default.isVariableStatement(stmt))
|
|
192363
192851
|
continue;
|
|
192364
192852
|
for (const decl of stmt.declarationList.declarations) {
|
|
192365
|
-
if (!import_typescript8.default.isArrayBindingPattern(decl.name))
|
|
192366
|
-
continue;
|
|
192367
192853
|
if (!decl.initializer || !import_typescript8.default.isCallExpression(decl.initializer))
|
|
192368
192854
|
continue;
|
|
192369
192855
|
if (!import_typescript8.default.isIdentifier(decl.initializer.expression))
|
|
192370
192856
|
continue;
|
|
192371
192857
|
const callee = decl.initializer.expression.text;
|
|
192372
|
-
|
|
192373
|
-
|
|
192374
|
-
|
|
192858
|
+
const loc = getSourceLocation(stmt, ctx.sourceFile, ctx.filePath);
|
|
192859
|
+
if (import_typescript8.default.isArrayBindingPattern(decl.name)) {
|
|
192860
|
+
if (callee === "createSignal" || callee === "createMemo")
|
|
192861
|
+
continue;
|
|
192862
|
+
if (resolveEnvSignalKey(decl.initializer, ctx))
|
|
192863
|
+
continue;
|
|
192864
|
+
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192865
|
+
if (declinedEntry) {
|
|
192866
|
+
ctx.errors.push(createError(declinedFactoryErrorCode(declinedEntry.code), loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192867
|
+
continue;
|
|
192868
|
+
}
|
|
192869
|
+
const objectFactory = ctx.reactiveFactories.get(callee);
|
|
192870
|
+
if (objectFactory && objectFactory.returnKind === "object") {
|
|
192871
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192872
|
+
severity: "error",
|
|
192873
|
+
message: `'${callee}' is a reactive factory that returns an object — destructure ` + `it with a matching object pattern: const { ${objectFactory.returnTupleIdentifiers.join(", ")} } = ${callee}(...)`
|
|
192874
|
+
}));
|
|
192875
|
+
continue;
|
|
192876
|
+
}
|
|
192877
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192878
|
+
severity: "error",
|
|
192879
|
+
message: `Tuple destructuring of '${callee}(...)': this helper is not a ` + `recognised reactive factory (createSignal / createMemo / a ` + `same-file helper that wraps them with a single \`return [a, b, ...]\`).`,
|
|
192880
|
+
suggestion: {
|
|
192881
|
+
message: `Inline the createSignal call at the call site, or move the ` + `helper into this file as a function that returns a tuple of ` + `identifiers at its single exit point.`
|
|
192882
|
+
}
|
|
192883
|
+
}));
|
|
192375
192884
|
continue;
|
|
192376
|
-
|
|
192885
|
+
}
|
|
192886
|
+
if (import_typescript8.default.isObjectBindingPattern(decl.name)) {
|
|
192887
|
+
validateObjectFactoryDestructure(ctx, decl.name, callee, loc);
|
|
192888
|
+
}
|
|
192889
|
+
}
|
|
192890
|
+
}
|
|
192891
|
+
}
|
|
192892
|
+
function validateObjectFactoryDestructure(ctx, pattern, callee, loc) {
|
|
192893
|
+
const factory = ctx.reactiveFactories.get(callee);
|
|
192894
|
+
if (factory) {
|
|
192895
|
+
if (factory.returnKind === "tuple") {
|
|
192896
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192377
192897
|
severity: "error",
|
|
192378
|
-
message: `
|
|
192379
|
-
suggestion: {
|
|
192380
|
-
message: `Inline the createSignal call at the call site, or move the ` + `helper into this file as a function that returns a tuple of ` + `identifiers at its single exit point.`
|
|
192381
|
-
}
|
|
192898
|
+
message: `'${callee}' is a reactive factory that returns a tuple — destructure ` + `it positionally: const [${factory.returnTupleIdentifiers.join(", ")}] = ${callee}(...)`
|
|
192382
192899
|
}));
|
|
192900
|
+
return;
|
|
192901
|
+
}
|
|
192902
|
+
const hasUnsupportedElement = pattern.elements.some((el) => !!el.propertyName || !!el.initializer || !!el.dotDotDotToken || !import_typescript8.default.isIdentifier(el.name));
|
|
192903
|
+
if (hasUnsupportedElement) {
|
|
192904
|
+
ctx.errors.push(createError(ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED, loc, {
|
|
192905
|
+
severity: "error",
|
|
192906
|
+
message: `Object destructure of reactive factory '${callee}' uses a property ` + `rename, default, or rest element; only shorthand destructuring of ` + `{ ${factory.returnTupleIdentifiers.join(", ")} } is supported.`
|
|
192907
|
+
}));
|
|
192908
|
+
return;
|
|
192909
|
+
}
|
|
192910
|
+
const unknown = pattern.elements.map((el) => import_typescript8.default.isIdentifier(el.name) ? el.name.text : "").filter((name) => name && !factory.returnTupleIdentifiers.includes(name));
|
|
192911
|
+
if (unknown.length > 0) {
|
|
192912
|
+
const label = unknown.length === 1 ? "property" : "properties";
|
|
192913
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192914
|
+
severity: "error",
|
|
192915
|
+
message: `Object destructure of reactive factory '${callee}' references ${label} ` + `'${unknown.join("', '")}' not present in its return { ${factory.returnTupleIdentifiers.join(", ")} }.`
|
|
192916
|
+
}));
|
|
192917
|
+
return;
|
|
192918
|
+
}
|
|
192919
|
+
return;
|
|
192920
|
+
}
|
|
192921
|
+
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192922
|
+
if (declinedEntry) {
|
|
192923
|
+
ctx.errors.push(createError(declinedFactoryErrorCode(declinedEntry.code), loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192924
|
+
return;
|
|
192925
|
+
}
|
|
192926
|
+
if (ctx.reactiveShapedHelpers.has(callee)) {
|
|
192927
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192928
|
+
severity: "error",
|
|
192929
|
+
message: `Object destructure of '${callee}(...)': this helper wraps a reactive ` + `primitive but does not match the inlinable factory shape (single ` + "`return { a, b }` of shorthand identifiers at its one exit point)."
|
|
192930
|
+
}));
|
|
192931
|
+
return;
|
|
192932
|
+
}
|
|
192933
|
+
if (ctx.cleanFactoryImports.has(callee))
|
|
192934
|
+
return;
|
|
192935
|
+
let matchedImportSource = null;
|
|
192936
|
+
for (const imp of ctx.imports) {
|
|
192937
|
+
if (imp.isTypeOnly)
|
|
192938
|
+
continue;
|
|
192939
|
+
const spec = imp.specifiers.find((s) => !s.isTypeOnly && (s.alias ?? s.name) === callee);
|
|
192940
|
+
if (spec) {
|
|
192941
|
+
matchedImportSource = imp.source;
|
|
192942
|
+
break;
|
|
192383
192943
|
}
|
|
192384
192944
|
}
|
|
192945
|
+
if (matchedImportSource !== null && !matchedImportSource.startsWith("@barefootjs/") && /^(use|create)[A-Z]/.test(callee)) {
|
|
192946
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192947
|
+
severity: "error",
|
|
192948
|
+
message: `Object destructure of imported '${callee}(...)': the compiler cannot ` + `inspect this import (non-relative or unresolvable path), so if it wraps ` + `createSignal/createMemo the destructured bindings will not be reactive. Move ` + `the helper to a relative-imported file or inline its body.`
|
|
192949
|
+
}));
|
|
192950
|
+
}
|
|
192385
192951
|
}
|
|
192386
192952
|
|
|
192387
192953
|
// ../jsx/src/jsx-to-ir.ts
|
|
@@ -192792,6 +193358,330 @@ function resolveFreeRefs(node, env) {
|
|
|
192792
193358
|
return resolveFreeRefsInternal(node, env, new Set);
|
|
192793
193359
|
}
|
|
192794
193360
|
|
|
193361
|
+
// ../jsx/src/to-locale-date-lowering.ts
|
|
193362
|
+
var TO_LOCALE_TZ_RE = /^(?:UTC|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
|
|
193363
|
+
var PROBE_UTC = new Date(Date.UTC(2001, 1, 3));
|
|
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);
|
|
193387
|
+
if (cached !== undefined)
|
|
193388
|
+
return cached;
|
|
193389
|
+
let derived;
|
|
193390
|
+
try {
|
|
193391
|
+
derived = derive();
|
|
193392
|
+
} catch {
|
|
193393
|
+
derived = null;
|
|
193394
|
+
}
|
|
193395
|
+
namesCache.set(key, derived);
|
|
193396
|
+
return derived;
|
|
193397
|
+
}
|
|
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;
|
|
193435
|
+
let parts;
|
|
193436
|
+
try {
|
|
193437
|
+
dtf = new Intl.DateTimeFormat(locale, {
|
|
193438
|
+
...probeOptions,
|
|
193439
|
+
timeZone: "UTC"
|
|
193440
|
+
});
|
|
193441
|
+
const resolved = dtf.resolvedOptions();
|
|
193442
|
+
if (resolved.calendar !== "gregory" || resolved.numberingSystem !== "latn")
|
|
193443
|
+
return null;
|
|
193444
|
+
parts = dtf.formatToParts(PROBE_UTC);
|
|
193445
|
+
} catch {
|
|
193446
|
+
return null;
|
|
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;
|
|
193458
|
+
let pattern = "";
|
|
193459
|
+
let usesNames = false;
|
|
193460
|
+
for (const part of parts) {
|
|
193461
|
+
switch (part.type) {
|
|
193462
|
+
case "year":
|
|
193463
|
+
if (part.value !== "2001")
|
|
193464
|
+
return null;
|
|
193465
|
+
pattern += "YYYY";
|
|
193466
|
+
break;
|
|
193467
|
+
case "month": {
|
|
193468
|
+
if (part.value === "2") {
|
|
193469
|
+
pattern += "M";
|
|
193470
|
+
break;
|
|
193471
|
+
}
|
|
193472
|
+
if (part.value === "02") {
|
|
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";
|
|
193482
|
+
else
|
|
193483
|
+
return null;
|
|
193484
|
+
monthTable = wide ?? abbr;
|
|
193485
|
+
usesNames = true;
|
|
193486
|
+
break;
|
|
193487
|
+
}
|
|
193488
|
+
case "day":
|
|
193489
|
+
if (part.value === "3")
|
|
193490
|
+
pattern += "D";
|
|
193491
|
+
else if (part.value === "03")
|
|
193492
|
+
pattern += "DD";
|
|
193493
|
+
else
|
|
193494
|
+
return null;
|
|
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
|
+
}
|
|
193509
|
+
case "literal":
|
|
193510
|
+
if (/[YMD]/.test(part.value) || /ddd/.test(part.value))
|
|
193511
|
+
return null;
|
|
193512
|
+
pattern += part.value;
|
|
193513
|
+
break;
|
|
193514
|
+
default:
|
|
193515
|
+
return null;
|
|
193516
|
+
}
|
|
193517
|
+
}
|
|
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))
|
|
193527
|
+
return null;
|
|
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;
|
|
193585
|
+
}
|
|
193586
|
+
function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
193587
|
+
if (callee.kind !== "member" || callee.computed)
|
|
193588
|
+
return null;
|
|
193589
|
+
if (callee.property !== "toLocaleDateString" || args.length !== 2)
|
|
193590
|
+
return null;
|
|
193591
|
+
const [locale, options] = args;
|
|
193592
|
+
if (options.kind !== "object-literal")
|
|
193593
|
+
return null;
|
|
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)
|
|
193609
|
+
return null;
|
|
193610
|
+
const receiverType = resolveReceiverType(callee.object, metadata, new Map);
|
|
193611
|
+
if (!receiverType || receiverType.kind !== "interface")
|
|
193612
|
+
return null;
|
|
193613
|
+
const typeName = baseTypeName(receiverType.raw);
|
|
193614
|
+
if (typeName !== "Date")
|
|
193615
|
+
return null;
|
|
193616
|
+
if (metadata.typeDefinitions.some((d) => d.name === typeName))
|
|
193617
|
+
return null;
|
|
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)
|
|
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 ?? []));
|
|
193640
|
+
return {
|
|
193641
|
+
kind: "helper-call",
|
|
193642
|
+
helper: "format_date",
|
|
193643
|
+
args: [
|
|
193644
|
+
callee.object,
|
|
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)
|
|
193648
|
+
]
|
|
193649
|
+
};
|
|
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
|
+
}
|
|
193676
|
+
var toLocaleDatePlugin = {
|
|
193677
|
+
name: "toLocaleDateString",
|
|
193678
|
+
prepare(metadata) {
|
|
193679
|
+
if (!metadata.propsType || !typeReachesDate(metadata.propsType, metadata, new Set))
|
|
193680
|
+
return null;
|
|
193681
|
+
return (callee, args) => matchToLocaleDateStringCall(callee, args, metadata);
|
|
193682
|
+
}
|
|
193683
|
+
};
|
|
193684
|
+
|
|
192795
193685
|
// ../jsx/src/jsx-to-ir.ts
|
|
192796
193686
|
var CLIENT_DIRECTIVE_INTERIOR_RE2 = /^\s*@client\s*$/;
|
|
192797
193687
|
var BLOCK_COMMENT_RE2 = /\/\*([\s\S]*?)\*\//g;
|
|
@@ -192886,6 +193776,19 @@ function getDateLoweringMatcher(ctx) {
|
|
|
192886
193776
|
}
|
|
192887
193777
|
return ctx._dateLoweringMatcher;
|
|
192888
193778
|
}
|
|
193779
|
+
function getToLocaleDateLoweringMatcher(ctx) {
|
|
193780
|
+
if (ctx._toLocaleDateLoweringMatcher === undefined) {
|
|
193781
|
+
const a = ctx.analyzer;
|
|
193782
|
+
const metadataSlice = {
|
|
193783
|
+
propsType: a.propsType,
|
|
193784
|
+
propsObjectName: a.propsObjectName,
|
|
193785
|
+
propsParams: a.propsParams,
|
|
193786
|
+
typeDefinitions: a.typeDefinitions
|
|
193787
|
+
};
|
|
193788
|
+
ctx._toLocaleDateLoweringMatcher = toLocaleDatePlugin.prepare(metadataSlice);
|
|
193789
|
+
}
|
|
193790
|
+
return ctx._toLocaleDateLoweringMatcher;
|
|
193791
|
+
}
|
|
192889
193792
|
function lowerDateCalls(text, expr, ctx) {
|
|
192890
193793
|
const matcher = getDateLoweringMatcher(ctx);
|
|
192891
193794
|
if (!matcher)
|
|
@@ -192914,8 +193817,48 @@ function lowerDateCalls(text, expr, ctx) {
|
|
|
192914
193817
|
}
|
|
192915
193818
|
return restore(result);
|
|
192916
193819
|
}
|
|
193820
|
+
function lowerToLocaleDateCalls(text, expr, ctx) {
|
|
193821
|
+
const matcher = getToLocaleDateLoweringMatcher(ctx);
|
|
193822
|
+
if (!matcher)
|
|
193823
|
+
return text;
|
|
193824
|
+
const candidates = [];
|
|
193825
|
+
function visit2(n) {
|
|
193826
|
+
if (import_typescript11.default.isCallExpression(n) && n.arguments.length === 2 && import_typescript11.default.isPropertyAccessExpression(n.expression) && !n.expression.questionDotToken && n.expression.name.text === "toLocaleDateString") {
|
|
193827
|
+
candidates.push(n);
|
|
193828
|
+
}
|
|
193829
|
+
import_typescript11.default.forEachChild(n, visit2);
|
|
193830
|
+
}
|
|
193831
|
+
visit2(expr);
|
|
193832
|
+
if (candidates.length === 0)
|
|
193833
|
+
return text;
|
|
193834
|
+
const { protect, restore, replaceProtectedCall } = createTemplateAwareStringProtector();
|
|
193835
|
+
let result = protect(text);
|
|
193836
|
+
for (const call of candidates) {
|
|
193837
|
+
const propAccess = call.expression;
|
|
193838
|
+
const node = matcher(tsNodeToParsedExpr(propAccess), call.arguments.map((a) => tsNodeToParsedExpr(a)));
|
|
193839
|
+
if (!node || node.kind !== "helper-call" || node.helper !== "format_date")
|
|
193840
|
+
continue;
|
|
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)
|
|
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
|
+
}
|
|
193854
|
+
const receiverText = ctx.getJS(propAccess.expression);
|
|
193855
|
+
const matchText = ctx.getJS(call);
|
|
193856
|
+
result = replaceProtectedCall(result, matchText, () => `formatDate(${receiverText}, ${patternJs}, ${JSON.stringify(tzArg.value)}${namesJs !== null ? `, ${namesJs}` : ""})`);
|
|
193857
|
+
}
|
|
193858
|
+
return restore(result);
|
|
193859
|
+
}
|
|
192917
193860
|
function rewriteBarePropRefs2(text, expr, ctx) {
|
|
192918
|
-
const dateLowered = lowerDateCalls(text, expr, ctx);
|
|
193861
|
+
const dateLowered = lowerToLocaleDateCalls(lowerDateCalls(text, expr, ctx), expr, ctx);
|
|
192919
193862
|
let propNames = getDestructuredPropNames(ctx);
|
|
192920
193863
|
if (!propNames)
|
|
192921
193864
|
return dateLowered === text ? undefined : dateLowered;
|
|
@@ -196332,7 +197275,7 @@ var ENV_SIGNAL_READERS = new Map([
|
|
|
196332
197275
|
function queryHrefLocalNames(metadata) {
|
|
196333
197276
|
const names = new Set;
|
|
196334
197277
|
for (const imp of metadata.imports) {
|
|
196335
|
-
if (!
|
|
197278
|
+
if (!CLIENT_HELPER_SOURCES.has(imp.source) || imp.isTypeOnly)
|
|
196336
197279
|
continue;
|
|
196337
197280
|
for (const s of imp.specifiers) {
|
|
196338
197281
|
if (s.isTypeOnly || s.isNamespace || s.isDefault)
|
|
@@ -196343,10 +197286,24 @@ function queryHrefLocalNames(metadata) {
|
|
|
196343
197286
|
}
|
|
196344
197287
|
return names;
|
|
196345
197288
|
}
|
|
196346
|
-
var
|
|
197289
|
+
var CLIENT_HELPER_SOURCES = new Set([
|
|
196347
197290
|
"@barefootjs/client",
|
|
196348
197291
|
"@barefootjs/client/runtime"
|
|
196349
197292
|
]);
|
|
197293
|
+
function formatDateLocalNames(metadata) {
|
|
197294
|
+
const names = new Set;
|
|
197295
|
+
for (const imp of metadata.imports) {
|
|
197296
|
+
if (!CLIENT_HELPER_SOURCES.has(imp.source) || imp.isTypeOnly)
|
|
197297
|
+
continue;
|
|
197298
|
+
for (const s of imp.specifiers) {
|
|
197299
|
+
if (s.isTypeOnly || s.isNamespace || s.isDefault)
|
|
197300
|
+
continue;
|
|
197301
|
+
if (s.name === "formatDate")
|
|
197302
|
+
names.add(s.alias ?? s.name);
|
|
197303
|
+
}
|
|
197304
|
+
}
|
|
197305
|
+
return names;
|
|
197306
|
+
}
|
|
196350
197307
|
|
|
196351
197308
|
// ../jsx/src/ir-to-client-js/emit-reactive.ts
|
|
196352
197309
|
var import_typescript14 = __toESM(require_typescript(), 1);
|
|
@@ -196955,6 +197912,30 @@ function isOmitBranch(node) {
|
|
|
196955
197912
|
}
|
|
196956
197913
|
return false;
|
|
196957
197914
|
}
|
|
197915
|
+
// ../jsx/src/format-date-lowering.ts
|
|
197916
|
+
var UTC_LITERAL = { kind: "literal", value: "UTC", literalType: "string" };
|
|
197917
|
+
var EMPTY_NAMES = { kind: "array-literal", elements: [], raw: "[]" };
|
|
197918
|
+
function matchFormatDateCall(callee, args, locals) {
|
|
197919
|
+
if (callee.kind !== "identifier" || !locals.has(callee.name))
|
|
197920
|
+
return null;
|
|
197921
|
+
if (args.length < 2 || args.length > 4)
|
|
197922
|
+
return null;
|
|
197923
|
+
return {
|
|
197924
|
+
kind: "helper-call",
|
|
197925
|
+
helper: "format_date",
|
|
197926
|
+
args: [args[0], args[1], args[2] ?? UTC_LITERAL, args[3] ?? EMPTY_NAMES]
|
|
197927
|
+
};
|
|
197928
|
+
}
|
|
197929
|
+
var formatDatePlugin = {
|
|
197930
|
+
name: "formatDate",
|
|
197931
|
+
prepare(metadata) {
|
|
197932
|
+
const locals = formatDateLocalNames(metadata);
|
|
197933
|
+
if (locals.size === 0)
|
|
197934
|
+
return null;
|
|
197935
|
+
return (callee, args) => matchFormatDateCall(callee, args, locals);
|
|
197936
|
+
}
|
|
197937
|
+
};
|
|
197938
|
+
|
|
196958
197939
|
// ../jsx/src/builtin-lowering-plugins.ts
|
|
196959
197940
|
var queryHrefPlugin = {
|
|
196960
197941
|
name: "queryHref",
|
|
@@ -196968,7 +197949,12 @@ var queryHrefPlugin = {
|
|
|
196968
197949
|
};
|
|
196969
197950
|
}
|
|
196970
197951
|
};
|
|
196971
|
-
var BUILTIN_LOWERING_PLUGINS = [
|
|
197952
|
+
var BUILTIN_LOWERING_PLUGINS = [
|
|
197953
|
+
queryHrefPlugin,
|
|
197954
|
+
datePlugin,
|
|
197955
|
+
formatDatePlugin,
|
|
197956
|
+
toLocaleDatePlugin
|
|
197957
|
+
];
|
|
196972
197958
|
function registerBuiltinLoweringPlugins() {
|
|
196973
197959
|
for (const plugin of BUILTIN_LOWERING_PLUGINS)
|
|
196974
197960
|
registerLoweringPlugin(plugin);
|
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"
|