@barefootjs/test 0.21.3 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +649 -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,9 @@ 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"
|
|
189743
189769
|
};
|
|
189744
189770
|
var errorMessages = {
|
|
189745
189771
|
[ErrorCodes.MISSING_USE_CLIENT]: "'use client' directive required for components with createSignal or event handlers",
|
|
@@ -189763,7 +189789,9 @@ var errorMessages = {
|
|
|
189763
189789
|
[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
189790
|
[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
189791
|
[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."
|
|
189792
|
+
[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.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."
|
|
189767
189795
|
};
|
|
189768
189796
|
function createError(code2, loc, options) {
|
|
189769
189797
|
if (code2 === undefined || !(code2 in errorMessages)) {
|
|
@@ -190032,6 +190060,10 @@ function analyzeComponent(source, filePath, targetComponentName, program) {
|
|
|
190032
190060
|
}
|
|
190033
190061
|
const ctx = createAnalyzerContext(sourceFile, filePath);
|
|
190034
190062
|
ctx.checker = checker;
|
|
190063
|
+
ctx.reactiveFactories = prescan.factories;
|
|
190064
|
+
ctx.declinedReactiveFactories = prescan.declined;
|
|
190065
|
+
ctx.reactiveShapedHelpers = prescan.reactiveShaped;
|
|
190066
|
+
ctx.cleanFactoryImports = prescan.cleanFactoryImports;
|
|
190035
190067
|
const brandImportLoc = findBrandPackageImportLoc(sourceFile, filePath);
|
|
190036
190068
|
if (!hadSharedProgram && brandImportLoc !== null) {
|
|
190037
190069
|
ctx.errors.push(createError(ErrorCodes.SHARED_PROGRAM_REQUIRED, brandImportLoc));
|
|
@@ -190937,6 +190969,7 @@ var CLIENT_EXPORTS = new Set([
|
|
|
190937
190969
|
"cleanupPortalPlaceholder",
|
|
190938
190970
|
"createSearchParams",
|
|
190939
190971
|
"queryHref",
|
|
190972
|
+
"formatDate",
|
|
190940
190973
|
"Async",
|
|
190941
190974
|
"Region"
|
|
190942
190975
|
]);
|
|
@@ -192164,27 +192197,241 @@ var REACTIVE_PRIMITIVES = new Set([
|
|
|
192164
192197
|
function prescanReactiveFactoriesInSource(source, filePath) {
|
|
192165
192198
|
const sourceFile = import_typescript8.default.createSourceFile(filePath + ".prescan", source, import_typescript8.default.ScriptTarget.Latest, true, import_typescript8.default.ScriptKind.TSX);
|
|
192166
192199
|
const factories = new Map;
|
|
192200
|
+
const declined = new Map;
|
|
192201
|
+
const reactiveShaped = new Set;
|
|
192202
|
+
const cleanFactoryImports = new Set;
|
|
192167
192203
|
function visitTop(node) {
|
|
192168
192204
|
if (import_typescript8.default.isFunctionDeclaration(node) && node.name && node.body) {
|
|
192169
|
-
const
|
|
192170
|
-
if (
|
|
192171
|
-
|
|
192205
|
+
const det = detectReactiveFactory(node, sourceFile, filePath);
|
|
192206
|
+
if (!det)
|
|
192207
|
+
return;
|
|
192208
|
+
switch (det.kind) {
|
|
192209
|
+
case "factory":
|
|
192210
|
+
factories.set(node.name.text, det.info);
|
|
192211
|
+
break;
|
|
192212
|
+
case "declined":
|
|
192213
|
+
declined.set(node.name.text, det.declined);
|
|
192214
|
+
break;
|
|
192215
|
+
case "reactive-shaped":
|
|
192216
|
+
reactiveShaped.add(node.name.text);
|
|
192217
|
+
break;
|
|
192218
|
+
}
|
|
192172
192219
|
}
|
|
192173
192220
|
}
|
|
192174
192221
|
import_typescript8.default.forEachChild(sourceFile, visitTop);
|
|
192175
|
-
|
|
192222
|
+
const result = { factories, declined, reactiveShaped, cleanFactoryImports, sourceFile };
|
|
192223
|
+
prescanImportedReactiveFactories(sourceFile, filePath, result);
|
|
192224
|
+
return result;
|
|
192225
|
+
}
|
|
192226
|
+
function prescanImportedReactiveFactories(entrySourceFile, filePath, result) {
|
|
192227
|
+
const candidateCallees = new Set;
|
|
192228
|
+
function collectCandidates(node) {
|
|
192229
|
+
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)) {
|
|
192230
|
+
candidateCallees.add(node.initializer.expression.text);
|
|
192231
|
+
}
|
|
192232
|
+
import_typescript8.default.forEachChild(node, collectCandidates);
|
|
192233
|
+
}
|
|
192234
|
+
collectCandidates(entrySourceFile);
|
|
192235
|
+
if (candidateCallees.size === 0)
|
|
192236
|
+
return;
|
|
192237
|
+
const importsToCheck = [];
|
|
192238
|
+
for (const stmt of entrySourceFile.statements) {
|
|
192239
|
+
if (!import_typescript8.default.isImportDeclaration(stmt))
|
|
192240
|
+
continue;
|
|
192241
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192242
|
+
continue;
|
|
192243
|
+
const src = stmt.moduleSpecifier.text;
|
|
192244
|
+
if (!src.startsWith("./") && !src.startsWith("../"))
|
|
192245
|
+
continue;
|
|
192246
|
+
if (stmt.importClause?.isTypeOnly)
|
|
192247
|
+
continue;
|
|
192248
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
192249
|
+
if (!namedBindings || !import_typescript8.default.isNamedImports(namedBindings))
|
|
192250
|
+
continue;
|
|
192251
|
+
const specs = [];
|
|
192252
|
+
for (const el of namedBindings.elements) {
|
|
192253
|
+
if (el.isTypeOnly)
|
|
192254
|
+
continue;
|
|
192255
|
+
const local = el.name.text;
|
|
192256
|
+
if (!candidateCallees.has(local))
|
|
192257
|
+
continue;
|
|
192258
|
+
specs.push({ exported: (el.propertyName ?? el.name).text, local });
|
|
192259
|
+
}
|
|
192260
|
+
if (specs.length === 0)
|
|
192261
|
+
continue;
|
|
192262
|
+
importsToCheck.push({ src, specs });
|
|
192263
|
+
}
|
|
192264
|
+
if (importsToCheck.length === 0)
|
|
192265
|
+
return;
|
|
192266
|
+
for (const { src, specs } of importsToCheck) {
|
|
192267
|
+
const resolved = resolveRelativeImportToFile(src, filePath);
|
|
192268
|
+
if (!resolved)
|
|
192269
|
+
continue;
|
|
192270
|
+
let content;
|
|
192271
|
+
try {
|
|
192272
|
+
content = fs.readFileSync(resolved, "utf8");
|
|
192273
|
+
} catch {
|
|
192274
|
+
continue;
|
|
192275
|
+
}
|
|
192276
|
+
const alreadyKnown = (name) => result.factories.has(name) || result.declined.has(name) || result.reactiveShaped.has(name);
|
|
192277
|
+
const hasAnyPrimitiveText = [...REACTIVE_PRIMITIVES].some((p) => content.includes(p));
|
|
192278
|
+
if (!hasAnyPrimitiveText) {
|
|
192279
|
+
for (const spec of specs) {
|
|
192280
|
+
if (!alreadyKnown(spec.local))
|
|
192281
|
+
result.cleanFactoryImports.add(spec.local);
|
|
192282
|
+
}
|
|
192283
|
+
continue;
|
|
192284
|
+
}
|
|
192285
|
+
const helperSf = import_typescript8.default.createSourceFile(resolved + ".prescan", content, import_typescript8.default.ScriptTarget.Latest, true, import_typescript8.default.ScriptKind.TSX);
|
|
192286
|
+
const localFns = new Map;
|
|
192287
|
+
const exportedFns = new Map;
|
|
192288
|
+
for (const stmt of helperSf.statements) {
|
|
192289
|
+
if (import_typescript8.default.isFunctionDeclaration(stmt) && stmt.name && stmt.body) {
|
|
192290
|
+
localFns.set(stmt.name.text, stmt);
|
|
192291
|
+
const hasExportModifier = stmt.modifiers?.some((m) => m.kind === import_typescript8.default.SyntaxKind.ExportKeyword) ?? false;
|
|
192292
|
+
const hasDefaultModifier = stmt.modifiers?.some((m) => m.kind === import_typescript8.default.SyntaxKind.DefaultKeyword) ?? false;
|
|
192293
|
+
if (hasExportModifier && !hasDefaultModifier) {
|
|
192294
|
+
exportedFns.set(stmt.name.text, stmt);
|
|
192295
|
+
}
|
|
192296
|
+
}
|
|
192297
|
+
}
|
|
192298
|
+
for (const stmt of helperSf.statements) {
|
|
192299
|
+
if (import_typescript8.default.isExportDeclaration(stmt) && stmt.exportClause && import_typescript8.default.isNamedExports(stmt.exportClause) && !stmt.moduleSpecifier && !stmt.isTypeOnly) {
|
|
192300
|
+
for (const el of stmt.exportClause.elements) {
|
|
192301
|
+
if (el.isTypeOnly)
|
|
192302
|
+
continue;
|
|
192303
|
+
const fn = localFns.get((el.propertyName ?? el.name).text);
|
|
192304
|
+
if (fn)
|
|
192305
|
+
exportedFns.set(el.name.text, fn);
|
|
192306
|
+
}
|
|
192307
|
+
}
|
|
192308
|
+
}
|
|
192309
|
+
const moduleBindings = collectHelperModuleValueBindings(helperSf);
|
|
192310
|
+
for (const spec of specs) {
|
|
192311
|
+
if (alreadyKnown(spec.local))
|
|
192312
|
+
continue;
|
|
192313
|
+
const fn = exportedFns.get(spec.exported);
|
|
192314
|
+
if (!fn) {
|
|
192315
|
+
result.cleanFactoryImports.add(spec.local);
|
|
192316
|
+
continue;
|
|
192317
|
+
}
|
|
192318
|
+
const det = detectReactiveFactory(fn, helperSf, resolved);
|
|
192319
|
+
if (!det) {
|
|
192320
|
+
result.cleanFactoryImports.add(spec.local);
|
|
192321
|
+
continue;
|
|
192322
|
+
}
|
|
192323
|
+
switch (det.kind) {
|
|
192324
|
+
case "reactive-shaped":
|
|
192325
|
+
result.reactiveShaped.add(spec.local);
|
|
192326
|
+
break;
|
|
192327
|
+
case "declined":
|
|
192328
|
+
result.declined.set(spec.local, det.declined);
|
|
192329
|
+
break;
|
|
192330
|
+
case "factory": {
|
|
192331
|
+
const offending = moduleCaptureCheck(fn, det.info, moduleBindings, fn.name.text);
|
|
192332
|
+
if (offending.length > 0) {
|
|
192333
|
+
result.declined.set(spec.local, {
|
|
192334
|
+
code: "BF112",
|
|
192335
|
+
detail: `'${offending.join("', '")}'`,
|
|
192336
|
+
loc: det.info.loc
|
|
192337
|
+
});
|
|
192338
|
+
} else {
|
|
192339
|
+
det.info.sourceFilePath = resolved;
|
|
192340
|
+
result.factories.set(spec.local, det.info);
|
|
192341
|
+
}
|
|
192342
|
+
break;
|
|
192343
|
+
}
|
|
192344
|
+
}
|
|
192345
|
+
}
|
|
192346
|
+
}
|
|
192347
|
+
}
|
|
192348
|
+
function collectHelperModuleValueBindings(sf) {
|
|
192349
|
+
const names = new Set;
|
|
192350
|
+
for (const stmt of sf.statements) {
|
|
192351
|
+
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
192352
|
+
const out = [];
|
|
192353
|
+
for (const decl of stmt.declarationList.declarations) {
|
|
192354
|
+
addBindingNames(decl.name, out);
|
|
192355
|
+
}
|
|
192356
|
+
for (const n of out)
|
|
192357
|
+
names.add(n);
|
|
192358
|
+
continue;
|
|
192359
|
+
}
|
|
192360
|
+
if ((import_typescript8.default.isFunctionDeclaration(stmt) || import_typescript8.default.isClassDeclaration(stmt) || import_typescript8.default.isEnumDeclaration(stmt)) && stmt.name) {
|
|
192361
|
+
names.add(stmt.name.text);
|
|
192362
|
+
continue;
|
|
192363
|
+
}
|
|
192364
|
+
if (import_typescript8.default.isImportDeclaration(stmt)) {
|
|
192365
|
+
if (stmt.importClause?.isTypeOnly)
|
|
192366
|
+
continue;
|
|
192367
|
+
if (!import_typescript8.default.isStringLiteral(stmt.moduleSpecifier))
|
|
192368
|
+
continue;
|
|
192369
|
+
const src = stmt.moduleSpecifier.text;
|
|
192370
|
+
if (src === "@barefootjs/client" || src === "@barefootjs/client/runtime")
|
|
192371
|
+
continue;
|
|
192372
|
+
if (stmt.importClause?.name)
|
|
192373
|
+
names.add(stmt.importClause.name.text);
|
|
192374
|
+
const namedBindings = stmt.importClause?.namedBindings;
|
|
192375
|
+
if (namedBindings && import_typescript8.default.isNamedImports(namedBindings)) {
|
|
192376
|
+
for (const el of namedBindings.elements) {
|
|
192377
|
+
if (el.isTypeOnly)
|
|
192378
|
+
continue;
|
|
192379
|
+
names.add(el.name.text);
|
|
192380
|
+
}
|
|
192381
|
+
}
|
|
192382
|
+
if (namedBindings && import_typescript8.default.isNamespaceImport(namedBindings)) {
|
|
192383
|
+
names.add(namedBindings.name.text);
|
|
192384
|
+
}
|
|
192385
|
+
}
|
|
192386
|
+
}
|
|
192387
|
+
return names;
|
|
192388
|
+
}
|
|
192389
|
+
function moduleCaptureCheck(fn, info, moduleBindings, selfName) {
|
|
192390
|
+
if (!fn.body)
|
|
192391
|
+
return [];
|
|
192392
|
+
const free = extractFreeIdentifiersFromNode(fn.body);
|
|
192393
|
+
const exclude = new Set(info.params);
|
|
192394
|
+
for (const b of info.localBindings)
|
|
192395
|
+
exclude.add(b);
|
|
192396
|
+
for (const r of info.returnTupleIdentifiers)
|
|
192397
|
+
exclude.add(r);
|
|
192398
|
+
for (const p of REACTIVE_PRIMITIVES)
|
|
192399
|
+
exclude.add(p);
|
|
192400
|
+
exclude.add(selfName);
|
|
192401
|
+
const offending = [];
|
|
192402
|
+
for (const id of free) {
|
|
192403
|
+
if (exclude.has(id))
|
|
192404
|
+
continue;
|
|
192405
|
+
if (moduleBindings.has(id))
|
|
192406
|
+
offending.push(id);
|
|
192407
|
+
}
|
|
192408
|
+
return offending.sort();
|
|
192176
192409
|
}
|
|
192177
192410
|
function detectReactiveFactory(node, sourceFile, filePath) {
|
|
192178
192411
|
if (!node.body || !node.name)
|
|
192179
192412
|
return null;
|
|
192180
|
-
let
|
|
192413
|
+
let hasReactiveCall = false;
|
|
192414
|
+
function checkForReactive(n) {
|
|
192415
|
+
if (hasReactiveCall)
|
|
192416
|
+
return;
|
|
192417
|
+
if (import_typescript8.default.isCallExpression(n) && import_typescript8.default.isIdentifier(n.expression) && REACTIVE_PRIMITIVES.has(n.expression.text)) {
|
|
192418
|
+
hasReactiveCall = true;
|
|
192419
|
+
return;
|
|
192420
|
+
}
|
|
192421
|
+
import_typescript8.default.forEachChild(n, checkForReactive);
|
|
192422
|
+
}
|
|
192423
|
+
checkForReactive(node.body);
|
|
192424
|
+
if (!hasReactiveCall)
|
|
192425
|
+
return null;
|
|
192426
|
+
const loc = getSourceLocation(node, sourceFile, filePath);
|
|
192427
|
+
let returnExpr = null;
|
|
192181
192428
|
let returnCount = 0;
|
|
192182
192429
|
for (const stmt of node.body.statements) {
|
|
192183
192430
|
if (!import_typescript8.default.isReturnStatement(stmt))
|
|
192184
192431
|
continue;
|
|
192185
192432
|
returnCount++;
|
|
192186
192433
|
if (!stmt.expression)
|
|
192187
|
-
return
|
|
192434
|
+
return { kind: "reactive-shaped" };
|
|
192188
192435
|
let expr = stmt.expression;
|
|
192189
192436
|
while (import_typescript8.default.isParenthesizedExpression(expr))
|
|
192190
192437
|
expr = expr.expression;
|
|
@@ -192192,33 +192439,42 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192192
192439
|
expr = expr.expression;
|
|
192193
192440
|
if (import_typescript8.default.isTypeAssertionExpression(expr))
|
|
192194
192441
|
expr = expr.expression;
|
|
192195
|
-
|
|
192196
|
-
return null;
|
|
192197
|
-
tupleReturn = expr;
|
|
192442
|
+
returnExpr = expr;
|
|
192198
192443
|
}
|
|
192199
|
-
if (returnCount !== 1 || !
|
|
192200
|
-
return
|
|
192444
|
+
if (returnCount !== 1 || !returnExpr)
|
|
192445
|
+
return { kind: "reactive-shaped" };
|
|
192201
192446
|
const returnTupleIdentifiers = [];
|
|
192202
|
-
|
|
192203
|
-
|
|
192204
|
-
|
|
192205
|
-
|
|
192206
|
-
|
|
192207
|
-
|
|
192208
|
-
|
|
192209
|
-
|
|
192210
|
-
|
|
192211
|
-
|
|
192212
|
-
|
|
192213
|
-
|
|
192214
|
-
|
|
192215
|
-
|
|
192447
|
+
let returnKind;
|
|
192448
|
+
if (import_typescript8.default.isArrayLiteralExpression(returnExpr)) {
|
|
192449
|
+
returnKind = "tuple";
|
|
192450
|
+
for (const el of returnExpr.elements) {
|
|
192451
|
+
if (!import_typescript8.default.isIdentifier(el))
|
|
192452
|
+
return { kind: "reactive-shaped" };
|
|
192453
|
+
returnTupleIdentifiers.push(el.text);
|
|
192454
|
+
}
|
|
192455
|
+
if (returnTupleIdentifiers.length === 0)
|
|
192456
|
+
return { kind: "reactive-shaped" };
|
|
192457
|
+
} else if (import_typescript8.default.isObjectLiteralExpression(returnExpr)) {
|
|
192458
|
+
returnKind = "object";
|
|
192459
|
+
const hasNonShorthand = returnExpr.properties.some((p) => !import_typescript8.default.isShorthandPropertyAssignment(p));
|
|
192460
|
+
if (hasNonShorthand) {
|
|
192461
|
+
return {
|
|
192462
|
+
kind: "declined",
|
|
192463
|
+
declined: {
|
|
192464
|
+
code: "BF111",
|
|
192465
|
+
detail: `return object of '${node.name.text}' uses non-shorthand properties`,
|
|
192466
|
+
loc
|
|
192467
|
+
}
|
|
192468
|
+
};
|
|
192216
192469
|
}
|
|
192217
|
-
|
|
192470
|
+
for (const p of returnExpr.properties) {
|
|
192471
|
+
returnTupleIdentifiers.push(p.name.text);
|
|
192472
|
+
}
|
|
192473
|
+
if (returnTupleIdentifiers.length === 0)
|
|
192474
|
+
return { kind: "reactive-shaped" };
|
|
192475
|
+
} else {
|
|
192476
|
+
return { kind: "reactive-shaped" };
|
|
192218
192477
|
}
|
|
192219
|
-
checkForReactive(node.body);
|
|
192220
|
-
if (!hasReactiveCall)
|
|
192221
|
-
return null;
|
|
192222
192478
|
const localBindings = [];
|
|
192223
192479
|
for (const stmt of node.body.statements) {
|
|
192224
192480
|
if (import_typescript8.default.isVariableStatement(stmt)) {
|
|
@@ -192231,19 +192487,24 @@ function detectReactiveFactory(node, sourceFile, filePath) {
|
|
|
192231
192487
|
}
|
|
192232
192488
|
const bodyStatements = node.body.statements.filter((s) => !import_typescript8.default.isReturnStatement(s)).map((s) => s.getText(sourceFile)).join(`
|
|
192233
192489
|
`);
|
|
192234
|
-
const params =
|
|
192235
|
-
|
|
192236
|
-
|
|
192237
|
-
|
|
192238
|
-
|
|
192239
|
-
|
|
192240
|
-
return
|
|
192490
|
+
const params = [];
|
|
192491
|
+
for (const p of node.parameters) {
|
|
192492
|
+
if (import_typescript8.default.isIdentifier(p.name)) {
|
|
192493
|
+
params.push(p.name.text);
|
|
192494
|
+
continue;
|
|
192495
|
+
}
|
|
192496
|
+
return { kind: "reactive-shaped" };
|
|
192497
|
+
}
|
|
192241
192498
|
return {
|
|
192242
|
-
|
|
192243
|
-
|
|
192244
|
-
|
|
192245
|
-
|
|
192246
|
-
|
|
192499
|
+
kind: "factory",
|
|
192500
|
+
info: {
|
|
192501
|
+
params,
|
|
192502
|
+
bodySource: bodyStatements,
|
|
192503
|
+
returnTupleIdentifiers,
|
|
192504
|
+
returnKind,
|
|
192505
|
+
localBindings,
|
|
192506
|
+
loc
|
|
192507
|
+
}
|
|
192247
192508
|
};
|
|
192248
192509
|
}
|
|
192249
192510
|
function addBindingNames(name, out) {
|
|
@@ -192281,8 +192542,6 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192281
192542
|
});
|
|
192282
192543
|
}
|
|
192283
192544
|
function maybeRewriteDecl(stmt, decl) {
|
|
192284
|
-
if (!import_typescript8.default.isArrayBindingPattern(decl.name))
|
|
192285
|
-
return;
|
|
192286
192545
|
if (!decl.initializer || !import_typescript8.default.isCallExpression(decl.initializer))
|
|
192287
192546
|
return;
|
|
192288
192547
|
if (!import_typescript8.default.isIdentifier(decl.initializer.expression))
|
|
@@ -192291,7 +192550,21 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192291
192550
|
const factory = factories.get(factoryName);
|
|
192292
192551
|
if (!factory)
|
|
192293
192552
|
return;
|
|
192294
|
-
|
|
192553
|
+
if (import_typescript8.default.isArrayBindingPattern(decl.name)) {
|
|
192554
|
+
if (factory.returnKind !== "tuple")
|
|
192555
|
+
return;
|
|
192556
|
+
rewriteTupleDecl(stmt, decl.name, decl.initializer, factory);
|
|
192557
|
+
return;
|
|
192558
|
+
}
|
|
192559
|
+
if (import_typescript8.default.isObjectBindingPattern(decl.name)) {
|
|
192560
|
+
if (factory.returnKind !== "object")
|
|
192561
|
+
return;
|
|
192562
|
+
rewriteObjectDecl(stmt, decl.name, decl.initializer, factory);
|
|
192563
|
+
return;
|
|
192564
|
+
}
|
|
192565
|
+
}
|
|
192566
|
+
function rewriteTupleDecl(stmt, pattern, call, factory) {
|
|
192567
|
+
const elements = pattern.elements;
|
|
192295
192568
|
if (elements.length !== factory.returnTupleIdentifiers.length)
|
|
192296
192569
|
return;
|
|
192297
192570
|
const callerNames = [];
|
|
@@ -192300,15 +192573,43 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192300
192573
|
return;
|
|
192301
192574
|
callerNames.push(el.name.text);
|
|
192302
192575
|
}
|
|
192303
|
-
const
|
|
192576
|
+
const excludeFromSuffixRename = new Set(factory.params);
|
|
192577
|
+
for (const r of factory.returnTupleIdentifiers)
|
|
192578
|
+
excludeFromSuffixRename.add(r);
|
|
192579
|
+
const renameReturnToCallerNames = new Map;
|
|
192580
|
+
for (let i2 = 0;i2 < factory.returnTupleIdentifiers.length; i2++) {
|
|
192581
|
+
renameReturnToCallerNames.set(factory.returnTupleIdentifiers[i2], callerNames[i2]);
|
|
192582
|
+
}
|
|
192583
|
+
inlineFactoryCallAtSite(stmt, factory, call.arguments, excludeFromSuffixRename, renameReturnToCallerNames);
|
|
192584
|
+
}
|
|
192585
|
+
function rewriteObjectDecl(stmt, pattern, call, factory) {
|
|
192586
|
+
const destructured = new Set;
|
|
192587
|
+
for (const el of pattern.elements) {
|
|
192588
|
+
if (el.dotDotDotToken)
|
|
192589
|
+
return;
|
|
192590
|
+
if (el.propertyName)
|
|
192591
|
+
return;
|
|
192592
|
+
if (el.initializer)
|
|
192593
|
+
return;
|
|
192594
|
+
if (!import_typescript8.default.isIdentifier(el.name))
|
|
192595
|
+
return;
|
|
192596
|
+
if (!factory.returnTupleIdentifiers.includes(el.name.text))
|
|
192597
|
+
return;
|
|
192598
|
+
destructured.add(el.name.text);
|
|
192599
|
+
}
|
|
192600
|
+
const excludeFromSuffixRename = new Set(factory.params);
|
|
192601
|
+
for (const d of destructured)
|
|
192602
|
+
excludeFromSuffixRename.add(d);
|
|
192603
|
+
inlineFactoryCallAtSite(stmt, factory, call.arguments, excludeFromSuffixRename, null);
|
|
192604
|
+
}
|
|
192605
|
+
function inlineFactoryCallAtSite(stmt, factory, args, excludeFromSuffixRename, renameReturnToCallerNames) {
|
|
192606
|
+
const argTexts = args.map((a) => a.getText(sourceFile));
|
|
192304
192607
|
const thisCallIndex = callSiteIndex++;
|
|
192305
192608
|
const suffix = `_bf${thisCallIndex}`;
|
|
192306
192609
|
let body = factory.bodySource;
|
|
192307
192610
|
const internalRenames = new Set(factory.localBindings);
|
|
192308
|
-
for (const
|
|
192309
|
-
internalRenames.delete(
|
|
192310
|
-
for (const r of factory.returnTupleIdentifiers)
|
|
192311
|
-
internalRenames.delete(r);
|
|
192611
|
+
for (const ex of excludeFromSuffixRename)
|
|
192612
|
+
internalRenames.delete(ex);
|
|
192312
192613
|
for (const name of internalRenames) {
|
|
192313
192614
|
body = body.replace(new RegExp(`\\b${escapeRegex(name)}\\b`, "g"), name + suffix);
|
|
192314
192615
|
}
|
|
@@ -192319,10 +192620,10 @@ function rewriteFactoryCallsInSource(source, prescan) {
|
|
|
192319
192620
|
const wrapped = atomicArg.test(a.trim()) ? a.trim() : `(${a})`;
|
|
192320
192621
|
body = body.replace(new RegExp(`\\b${escapeRegex(p)}\\b`, "g"), wrapped);
|
|
192321
192622
|
}
|
|
192322
|
-
|
|
192323
|
-
const n
|
|
192324
|
-
|
|
192325
|
-
|
|
192623
|
+
if (renameReturnToCallerNames) {
|
|
192624
|
+
for (const [n, caller] of renameReturnToCallerNames) {
|
|
192625
|
+
body = body.replace(new RegExp(`\\b${escapeRegex(n)}\\b`, "g"), caller);
|
|
192626
|
+
}
|
|
192326
192627
|
}
|
|
192327
192628
|
edits.push({
|
|
192328
192629
|
start: stmt.getStart(sourceFile),
|
|
@@ -192352,6 +192653,12 @@ function isPascalCaseComponentFn(node) {
|
|
|
192352
192653
|
function escapeRegex(s) {
|
|
192353
192654
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
192354
192655
|
}
|
|
192656
|
+
function declinedFactoryMessage(callee, d) {
|
|
192657
|
+
if (d.code === "BF112") {
|
|
192658
|
+
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
|
+
}
|
|
192660
|
+
return `Reactive factory '${callee}' cannot be inlined: ${d.detail}.`;
|
|
192661
|
+
}
|
|
192355
192662
|
function validateReactiveFactoryCalls(ctx) {
|
|
192356
192663
|
if (!ctx.componentNode)
|
|
192357
192664
|
return;
|
|
@@ -192362,25 +192669,103 @@ function validateReactiveFactoryCalls(ctx) {
|
|
|
192362
192669
|
if (!import_typescript8.default.isVariableStatement(stmt))
|
|
192363
192670
|
continue;
|
|
192364
192671
|
for (const decl of stmt.declarationList.declarations) {
|
|
192365
|
-
if (!import_typescript8.default.isArrayBindingPattern(decl.name))
|
|
192366
|
-
continue;
|
|
192367
192672
|
if (!decl.initializer || !import_typescript8.default.isCallExpression(decl.initializer))
|
|
192368
192673
|
continue;
|
|
192369
192674
|
if (!import_typescript8.default.isIdentifier(decl.initializer.expression))
|
|
192370
192675
|
continue;
|
|
192371
192676
|
const callee = decl.initializer.expression.text;
|
|
192372
|
-
|
|
192373
|
-
|
|
192374
|
-
|
|
192677
|
+
const loc = getSourceLocation(stmt, ctx.sourceFile, ctx.filePath);
|
|
192678
|
+
if (import_typescript8.default.isArrayBindingPattern(decl.name)) {
|
|
192679
|
+
if (callee === "createSignal" || callee === "createMemo")
|
|
192680
|
+
continue;
|
|
192681
|
+
if (resolveEnvSignalKey(decl.initializer, ctx))
|
|
192682
|
+
continue;
|
|
192683
|
+
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192684
|
+
if (declinedEntry) {
|
|
192685
|
+
ctx.errors.push(createError(declinedEntry.code === "BF112" ? ErrorCodes.REACTIVE_FACTORY_MODULE_CAPTURE : ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED, loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192686
|
+
continue;
|
|
192687
|
+
}
|
|
192688
|
+
const objectFactory = ctx.reactiveFactories.get(callee);
|
|
192689
|
+
if (objectFactory && objectFactory.returnKind === "object") {
|
|
192690
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192691
|
+
severity: "error",
|
|
192692
|
+
message: `'${callee}' is a reactive factory that returns an object — destructure ` + `it with a matching object pattern: const { ${objectFactory.returnTupleIdentifiers.join(", ")} } = ${callee}(...)`
|
|
192693
|
+
}));
|
|
192694
|
+
continue;
|
|
192695
|
+
}
|
|
192696
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192697
|
+
severity: "error",
|
|
192698
|
+
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, ...]\`).`,
|
|
192699
|
+
suggestion: {
|
|
192700
|
+
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.`
|
|
192701
|
+
}
|
|
192702
|
+
}));
|
|
192375
192703
|
continue;
|
|
192376
|
-
|
|
192704
|
+
}
|
|
192705
|
+
if (import_typescript8.default.isObjectBindingPattern(decl.name)) {
|
|
192706
|
+
validateObjectFactoryDestructure(ctx, decl.name, callee, loc);
|
|
192707
|
+
}
|
|
192708
|
+
}
|
|
192709
|
+
}
|
|
192710
|
+
}
|
|
192711
|
+
function validateObjectFactoryDestructure(ctx, pattern, callee, loc) {
|
|
192712
|
+
const factory = ctx.reactiveFactories.get(callee);
|
|
192713
|
+
if (factory) {
|
|
192714
|
+
if (factory.returnKind === "tuple") {
|
|
192715
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192377
192716
|
severity: "error",
|
|
192378
|
-
message: `
|
|
192379
|
-
|
|
192380
|
-
|
|
192381
|
-
|
|
192717
|
+
message: `'${callee}' is a reactive factory that returns a tuple — destructure ` + `it positionally: const [${factory.returnTupleIdentifiers.join(", ")}] = ${callee}(...)`
|
|
192718
|
+
}));
|
|
192719
|
+
return;
|
|
192720
|
+
}
|
|
192721
|
+
const hasUnsupportedElement = pattern.elements.some((el) => !!el.propertyName || !!el.initializer || !!el.dotDotDotToken || !import_typescript8.default.isIdentifier(el.name));
|
|
192722
|
+
if (hasUnsupportedElement) {
|
|
192723
|
+
ctx.errors.push(createError(ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED, loc, {
|
|
192724
|
+
severity: "error",
|
|
192725
|
+
message: `Object destructure of reactive factory '${callee}' uses a property ` + `rename, default, or rest element; only shorthand destructuring of ` + `{ ${factory.returnTupleIdentifiers.join(", ")} } is supported.`
|
|
192726
|
+
}));
|
|
192727
|
+
return;
|
|
192728
|
+
}
|
|
192729
|
+
const unknown = pattern.elements.map((el) => import_typescript8.default.isIdentifier(el.name) ? el.name.text : "").filter((name) => name && !factory.returnTupleIdentifiers.includes(name));
|
|
192730
|
+
if (unknown.length > 0) {
|
|
192731
|
+
const label = unknown.length === 1 ? "property" : "properties";
|
|
192732
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192733
|
+
severity: "error",
|
|
192734
|
+
message: `Object destructure of reactive factory '${callee}' references ${label} ` + `'${unknown.join("', '")}' not present in its return { ${factory.returnTupleIdentifiers.join(", ")} }.`
|
|
192382
192735
|
}));
|
|
192736
|
+
return;
|
|
192383
192737
|
}
|
|
192738
|
+
return;
|
|
192739
|
+
}
|
|
192740
|
+
const declinedEntry = ctx.declinedReactiveFactories.get(callee);
|
|
192741
|
+
if (declinedEntry) {
|
|
192742
|
+
ctx.errors.push(createError(declinedEntry.code === "BF112" ? ErrorCodes.REACTIVE_FACTORY_MODULE_CAPTURE : ErrorCodes.REACTIVE_FACTORY_RENAME_UNSUPPORTED, loc, { severity: "error", message: declinedFactoryMessage(callee, declinedEntry) }));
|
|
192743
|
+
return;
|
|
192744
|
+
}
|
|
192745
|
+
if (ctx.reactiveShapedHelpers.has(callee)) {
|
|
192746
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192747
|
+
severity: "error",
|
|
192748
|
+
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)."
|
|
192749
|
+
}));
|
|
192750
|
+
return;
|
|
192751
|
+
}
|
|
192752
|
+
if (ctx.cleanFactoryImports.has(callee))
|
|
192753
|
+
return;
|
|
192754
|
+
let matchedImportSource = null;
|
|
192755
|
+
for (const imp of ctx.imports) {
|
|
192756
|
+
if (imp.isTypeOnly)
|
|
192757
|
+
continue;
|
|
192758
|
+
const spec = imp.specifiers.find((s) => !s.isTypeOnly && (s.alias ?? s.name) === callee);
|
|
192759
|
+
if (spec) {
|
|
192760
|
+
matchedImportSource = imp.source;
|
|
192761
|
+
break;
|
|
192762
|
+
}
|
|
192763
|
+
}
|
|
192764
|
+
if (matchedImportSource !== null && !matchedImportSource.startsWith("@barefootjs/") && /^(use|create)[A-Z]/.test(callee)) {
|
|
192765
|
+
ctx.errors.push(createError(ErrorCodes.UNRECOGNIZED_REACTIVE_FACTORY, loc, {
|
|
192766
|
+
severity: "error",
|
|
192767
|
+
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.`
|
|
192768
|
+
}));
|
|
192384
192769
|
}
|
|
192385
192770
|
}
|
|
192386
192771
|
|
|
@@ -192792,6 +193177,114 @@ function resolveFreeRefs(node, env) {
|
|
|
192792
193177
|
return resolveFreeRefsInternal(node, env, new Set);
|
|
192793
193178
|
}
|
|
192794
193179
|
|
|
193180
|
+
// ../jsx/src/to-locale-date-lowering.ts
|
|
193181
|
+
var TO_LOCALE_TZ_RE = /^(?:UTC|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/;
|
|
193182
|
+
var PROBE_UTC = new Date(Date.UTC(2001, 1, 3));
|
|
193183
|
+
var patternCache = new Map;
|
|
193184
|
+
function resolveLocaleDatePattern(locale) {
|
|
193185
|
+
const cached = patternCache.get(locale);
|
|
193186
|
+
if (cached !== undefined)
|
|
193187
|
+
return cached;
|
|
193188
|
+
const derived = derivePattern(locale);
|
|
193189
|
+
patternCache.set(locale, derived);
|
|
193190
|
+
return derived;
|
|
193191
|
+
}
|
|
193192
|
+
function derivePattern(locale) {
|
|
193193
|
+
let parts;
|
|
193194
|
+
try {
|
|
193195
|
+
const dtf = new Intl.DateTimeFormat(locale, { timeZone: "UTC" });
|
|
193196
|
+
const resolved = dtf.resolvedOptions();
|
|
193197
|
+
if (resolved.calendar !== "gregory" || resolved.numberingSystem !== "latn")
|
|
193198
|
+
return null;
|
|
193199
|
+
parts = dtf.formatToParts(PROBE_UTC);
|
|
193200
|
+
} catch {
|
|
193201
|
+
return null;
|
|
193202
|
+
}
|
|
193203
|
+
let pattern = "";
|
|
193204
|
+
for (const part of parts) {
|
|
193205
|
+
switch (part.type) {
|
|
193206
|
+
case "year":
|
|
193207
|
+
if (part.value !== "2001")
|
|
193208
|
+
return null;
|
|
193209
|
+
pattern += "YYYY";
|
|
193210
|
+
break;
|
|
193211
|
+
case "month":
|
|
193212
|
+
if (part.value === "2")
|
|
193213
|
+
pattern += "M";
|
|
193214
|
+
else if (part.value === "02")
|
|
193215
|
+
pattern += "MM";
|
|
193216
|
+
else
|
|
193217
|
+
return null;
|
|
193218
|
+
break;
|
|
193219
|
+
case "day":
|
|
193220
|
+
if (part.value === "3")
|
|
193221
|
+
pattern += "D";
|
|
193222
|
+
else if (part.value === "03")
|
|
193223
|
+
pattern += "DD";
|
|
193224
|
+
else
|
|
193225
|
+
return null;
|
|
193226
|
+
break;
|
|
193227
|
+
case "literal":
|
|
193228
|
+
if (/[YMD]/.test(part.value))
|
|
193229
|
+
return null;
|
|
193230
|
+
pattern += part.value;
|
|
193231
|
+
break;
|
|
193232
|
+
default:
|
|
193233
|
+
return null;
|
|
193234
|
+
}
|
|
193235
|
+
}
|
|
193236
|
+
if (!pattern.includes("YYYY") || !/M/.test(pattern) || !/D/.test(pattern))
|
|
193237
|
+
return null;
|
|
193238
|
+
return pattern;
|
|
193239
|
+
}
|
|
193240
|
+
function matchToLocaleDateStringCall(callee, args, metadata) {
|
|
193241
|
+
if (callee.kind !== "member" || callee.computed)
|
|
193242
|
+
return null;
|
|
193243
|
+
if (callee.property !== "toLocaleDateString" || args.length !== 2)
|
|
193244
|
+
return null;
|
|
193245
|
+
const [locale, options] = args;
|
|
193246
|
+
if (locale.kind !== "literal" || locale.literalType !== "string")
|
|
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")
|
|
193252
|
+
return null;
|
|
193253
|
+
if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
|
|
193254
|
+
return null;
|
|
193255
|
+
const tz = String(prop.value.value);
|
|
193256
|
+
if (!TO_LOCALE_TZ_RE.test(tz))
|
|
193257
|
+
return null;
|
|
193258
|
+
const receiverType = resolveReceiverType(callee.object, metadata, new Map);
|
|
193259
|
+
if (!receiverType || receiverType.kind !== "interface")
|
|
193260
|
+
return null;
|
|
193261
|
+
const typeName = baseTypeName(receiverType.raw);
|
|
193262
|
+
if (typeName !== "Date")
|
|
193263
|
+
return null;
|
|
193264
|
+
if (metadata.typeDefinitions.some((d) => d.name === typeName))
|
|
193265
|
+
return null;
|
|
193266
|
+
const pattern = resolveLocaleDatePattern(String(locale.value));
|
|
193267
|
+
if (pattern === null)
|
|
193268
|
+
return null;
|
|
193269
|
+
return {
|
|
193270
|
+
kind: "helper-call",
|
|
193271
|
+
helper: "format_date",
|
|
193272
|
+
args: [
|
|
193273
|
+
callee.object,
|
|
193274
|
+
{ kind: "literal", value: pattern, literalType: "string" },
|
|
193275
|
+
{ kind: "literal", value: tz, literalType: "string" }
|
|
193276
|
+
]
|
|
193277
|
+
};
|
|
193278
|
+
}
|
|
193279
|
+
var toLocaleDatePlugin = {
|
|
193280
|
+
name: "toLocaleDateString",
|
|
193281
|
+
prepare(metadata) {
|
|
193282
|
+
if (!metadata.propsType || !typeReachesDate(metadata.propsType, metadata, new Set))
|
|
193283
|
+
return null;
|
|
193284
|
+
return (callee, args) => matchToLocaleDateStringCall(callee, args, metadata);
|
|
193285
|
+
}
|
|
193286
|
+
};
|
|
193287
|
+
|
|
192795
193288
|
// ../jsx/src/jsx-to-ir.ts
|
|
192796
193289
|
var CLIENT_DIRECTIVE_INTERIOR_RE2 = /^\s*@client\s*$/;
|
|
192797
193290
|
var BLOCK_COMMENT_RE2 = /\/\*([\s\S]*?)\*\//g;
|
|
@@ -192886,6 +193379,19 @@ function getDateLoweringMatcher(ctx) {
|
|
|
192886
193379
|
}
|
|
192887
193380
|
return ctx._dateLoweringMatcher;
|
|
192888
193381
|
}
|
|
193382
|
+
function getToLocaleDateLoweringMatcher(ctx) {
|
|
193383
|
+
if (ctx._toLocaleDateLoweringMatcher === undefined) {
|
|
193384
|
+
const a = ctx.analyzer;
|
|
193385
|
+
const metadataSlice = {
|
|
193386
|
+
propsType: a.propsType,
|
|
193387
|
+
propsObjectName: a.propsObjectName,
|
|
193388
|
+
propsParams: a.propsParams,
|
|
193389
|
+
typeDefinitions: a.typeDefinitions
|
|
193390
|
+
};
|
|
193391
|
+
ctx._toLocaleDateLoweringMatcher = toLocaleDatePlugin.prepare(metadataSlice);
|
|
193392
|
+
}
|
|
193393
|
+
return ctx._toLocaleDateLoweringMatcher;
|
|
193394
|
+
}
|
|
192889
193395
|
function lowerDateCalls(text, expr, ctx) {
|
|
192890
193396
|
const matcher = getDateLoweringMatcher(ctx);
|
|
192891
193397
|
if (!matcher)
|
|
@@ -192914,8 +193420,38 @@ function lowerDateCalls(text, expr, ctx) {
|
|
|
192914
193420
|
}
|
|
192915
193421
|
return restore(result);
|
|
192916
193422
|
}
|
|
193423
|
+
function lowerToLocaleDateCalls(text, expr, ctx) {
|
|
193424
|
+
const matcher = getToLocaleDateLoweringMatcher(ctx);
|
|
193425
|
+
if (!matcher)
|
|
193426
|
+
return text;
|
|
193427
|
+
const candidates = [];
|
|
193428
|
+
function visit2(n) {
|
|
193429
|
+
if (import_typescript11.default.isCallExpression(n) && n.arguments.length === 2 && import_typescript11.default.isPropertyAccessExpression(n.expression) && !n.expression.questionDotToken && n.expression.name.text === "toLocaleDateString") {
|
|
193430
|
+
candidates.push(n);
|
|
193431
|
+
}
|
|
193432
|
+
import_typescript11.default.forEachChild(n, visit2);
|
|
193433
|
+
}
|
|
193434
|
+
visit2(expr);
|
|
193435
|
+
if (candidates.length === 0)
|
|
193436
|
+
return text;
|
|
193437
|
+
const { protect, restore, replaceProtectedCall } = createTemplateAwareStringProtector();
|
|
193438
|
+
let result = protect(text);
|
|
193439
|
+
for (const call of candidates) {
|
|
193440
|
+
const propAccess = call.expression;
|
|
193441
|
+
const node = matcher(tsNodeToParsedExpr(propAccess), call.arguments.map((a) => tsNodeToParsedExpr(a)));
|
|
193442
|
+
if (!node || node.kind !== "helper-call" || node.helper !== "format_date")
|
|
193443
|
+
continue;
|
|
193444
|
+
const [, patternArg, tzArg] = node.args;
|
|
193445
|
+
if (patternArg?.kind !== "literal" || tzArg?.kind !== "literal")
|
|
193446
|
+
continue;
|
|
193447
|
+
const receiverText = ctx.getJS(propAccess.expression);
|
|
193448
|
+
const matchText = ctx.getJS(call);
|
|
193449
|
+
result = replaceProtectedCall(result, matchText, () => `formatDate(${receiverText}, ${JSON.stringify(patternArg.value)}, ${JSON.stringify(tzArg.value)})`);
|
|
193450
|
+
}
|
|
193451
|
+
return restore(result);
|
|
193452
|
+
}
|
|
192917
193453
|
function rewriteBarePropRefs2(text, expr, ctx) {
|
|
192918
|
-
const dateLowered = lowerDateCalls(text, expr, ctx);
|
|
193454
|
+
const dateLowered = lowerToLocaleDateCalls(lowerDateCalls(text, expr, ctx), expr, ctx);
|
|
192919
193455
|
let propNames = getDestructuredPropNames(ctx);
|
|
192920
193456
|
if (!propNames)
|
|
192921
193457
|
return dateLowered === text ? undefined : dateLowered;
|
|
@@ -196332,7 +196868,7 @@ var ENV_SIGNAL_READERS = new Map([
|
|
|
196332
196868
|
function queryHrefLocalNames(metadata) {
|
|
196333
196869
|
const names = new Set;
|
|
196334
196870
|
for (const imp of metadata.imports) {
|
|
196335
|
-
if (!
|
|
196871
|
+
if (!CLIENT_HELPER_SOURCES.has(imp.source) || imp.isTypeOnly)
|
|
196336
196872
|
continue;
|
|
196337
196873
|
for (const s of imp.specifiers) {
|
|
196338
196874
|
if (s.isTypeOnly || s.isNamespace || s.isDefault)
|
|
@@ -196343,10 +196879,24 @@ function queryHrefLocalNames(metadata) {
|
|
|
196343
196879
|
}
|
|
196344
196880
|
return names;
|
|
196345
196881
|
}
|
|
196346
|
-
var
|
|
196882
|
+
var CLIENT_HELPER_SOURCES = new Set([
|
|
196347
196883
|
"@barefootjs/client",
|
|
196348
196884
|
"@barefootjs/client/runtime"
|
|
196349
196885
|
]);
|
|
196886
|
+
function formatDateLocalNames(metadata) {
|
|
196887
|
+
const names = new Set;
|
|
196888
|
+
for (const imp of metadata.imports) {
|
|
196889
|
+
if (!CLIENT_HELPER_SOURCES.has(imp.source) || imp.isTypeOnly)
|
|
196890
|
+
continue;
|
|
196891
|
+
for (const s of imp.specifiers) {
|
|
196892
|
+
if (s.isTypeOnly || s.isNamespace || s.isDefault)
|
|
196893
|
+
continue;
|
|
196894
|
+
if (s.name === "formatDate")
|
|
196895
|
+
names.add(s.alias ?? s.name);
|
|
196896
|
+
}
|
|
196897
|
+
}
|
|
196898
|
+
return names;
|
|
196899
|
+
}
|
|
196350
196900
|
|
|
196351
196901
|
// ../jsx/src/ir-to-client-js/emit-reactive.ts
|
|
196352
196902
|
var import_typescript14 = __toESM(require_typescript(), 1);
|
|
@@ -196955,6 +197505,29 @@ function isOmitBranch(node) {
|
|
|
196955
197505
|
}
|
|
196956
197506
|
return false;
|
|
196957
197507
|
}
|
|
197508
|
+
// ../jsx/src/format-date-lowering.ts
|
|
197509
|
+
var UTC_LITERAL = { kind: "literal", value: "UTC", literalType: "string" };
|
|
197510
|
+
function matchFormatDateCall(callee, args, locals) {
|
|
197511
|
+
if (callee.kind !== "identifier" || !locals.has(callee.name))
|
|
197512
|
+
return null;
|
|
197513
|
+
if (args.length < 2 || args.length > 3)
|
|
197514
|
+
return null;
|
|
197515
|
+
return {
|
|
197516
|
+
kind: "helper-call",
|
|
197517
|
+
helper: "format_date",
|
|
197518
|
+
args: [args[0], args[1], args[2] ?? UTC_LITERAL]
|
|
197519
|
+
};
|
|
197520
|
+
}
|
|
197521
|
+
var formatDatePlugin = {
|
|
197522
|
+
name: "formatDate",
|
|
197523
|
+
prepare(metadata) {
|
|
197524
|
+
const locals = formatDateLocalNames(metadata);
|
|
197525
|
+
if (locals.size === 0)
|
|
197526
|
+
return null;
|
|
197527
|
+
return (callee, args) => matchFormatDateCall(callee, args, locals);
|
|
197528
|
+
}
|
|
197529
|
+
};
|
|
197530
|
+
|
|
196958
197531
|
// ../jsx/src/builtin-lowering-plugins.ts
|
|
196959
197532
|
var queryHrefPlugin = {
|
|
196960
197533
|
name: "queryHref",
|
|
@@ -196968,7 +197541,12 @@ var queryHrefPlugin = {
|
|
|
196968
197541
|
};
|
|
196969
197542
|
}
|
|
196970
197543
|
};
|
|
196971
|
-
var BUILTIN_LOWERING_PLUGINS = [
|
|
197544
|
+
var BUILTIN_LOWERING_PLUGINS = [
|
|
197545
|
+
queryHrefPlugin,
|
|
197546
|
+
datePlugin,
|
|
197547
|
+
formatDatePlugin,
|
|
197548
|
+
toLocaleDatePlugin
|
|
197549
|
+
];
|
|
196972
197550
|
function registerBuiltinLoweringPlugins() {
|
|
196973
197551
|
for (const plugin of BUILTIN_LOWERING_PLUGINS)
|
|
196974
197552
|
registerLoweringPlugin(plugin);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/test",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Test utilities for BarefootJS - IR-based component testing without a browser",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"directory": "packages/test"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@barefootjs/jsx": "0.
|
|
42
|
+
"@barefootjs/jsx": "0.23.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.0.0"
|