@sarj/eslint-plugin 15.14.0 → 15.16.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.cjs +1678 -676
- package/dist/index.d.cts +35 -3
- package/dist/index.d.ts +35 -3
- package/dist/index.js +1675 -673
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1223,8 +1223,8 @@ function testCallMatrixStems(comments) {
|
|
|
1223
1223
|
const stems = /* @__PURE__ */ new Set();
|
|
1224
1224
|
for (const comment of comments) {
|
|
1225
1225
|
const body2 = stripCommentMarker(comment.value);
|
|
1226
|
-
const
|
|
1227
|
-
if (
|
|
1226
|
+
const stem4 = CALL_LABEL_RE.exec(body2)?.[1];
|
|
1227
|
+
if (stem4 !== void 0 && MULTIPLIER_PSEUDOCODE_RE.test(body2)) stems.add(stem4);
|
|
1228
1228
|
}
|
|
1229
1229
|
return stems;
|
|
1230
1230
|
}
|
|
@@ -4010,8 +4010,8 @@ function privateMemberFixes(context, services, owner, members, removePrivateKeyw
|
|
|
4010
4010
|
return;
|
|
4011
4011
|
}
|
|
4012
4012
|
if (node.type !== AST_NODE_TYPES14.MemberExpression) return;
|
|
4013
|
-
const
|
|
4014
|
-
if (
|
|
4013
|
+
const propertyName7 = node.property.type === AST_NODE_TYPES14.Identifier || node.property.type === AST_NODE_TYPES14.PrivateIdentifier ? node.property.name : node.property.type === AST_NODE_TYPES14.Literal && typeof node.property.value === "string" ? node.property.value : null;
|
|
4014
|
+
if (propertyName7 !== name) return;
|
|
4015
4015
|
const propertySymbol = symbolAt(services, checker, node.property);
|
|
4016
4016
|
if (node.computed || node.property.type !== AST_NODE_TYPES14.Identifier || node.object.type !== AST_NODE_TYPES14.ThisExpression || enclosingClass(node) !== owner || !symbols.some((symbol) => sameSymbol(symbol, propertySymbol))) {
|
|
4017
4017
|
unsafe = true;
|
|
@@ -4883,8 +4883,8 @@ var CJS_OBJECT_EXPORT_METHODS = /* @__PURE__ */ new Set(["assign", "defineProper
|
|
|
4883
4883
|
function fileParts(filename) {
|
|
4884
4884
|
const base = filename.replaceAll("\\", "/").split("/").at(-1) ?? "";
|
|
4885
4885
|
const extension = base.match(/(\.[cm]?[jt]sx?)$/u)?.[1] ?? ".ts";
|
|
4886
|
-
const [
|
|
4887
|
-
return { stem:
|
|
4886
|
+
const [stem4 = "", ...suffixes] = base.slice(0, -extension.length).split(".");
|
|
4887
|
+
return { stem: stem4, suffixes: suffixes.map((suffix) => suffix.toLowerCase()) };
|
|
4888
4888
|
}
|
|
4889
4889
|
function declaredNames(declaration) {
|
|
4890
4890
|
if (declaration.declare === true) return [];
|
|
@@ -5008,8 +5008,8 @@ var no_generic_single_export_module_default = createRule({
|
|
|
5008
5008
|
defaultOptions: [],
|
|
5009
5009
|
create(context) {
|
|
5010
5010
|
const file = fileParts(context.filename);
|
|
5011
|
-
const { stem:
|
|
5012
|
-
if (!GENERIC_STEMS.has(
|
|
5011
|
+
const { stem: stem4 } = file;
|
|
5012
|
+
if (!GENERIC_STEMS.has(stem4) || isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
5013
5013
|
let hasCommonJsExport = false;
|
|
5014
5014
|
return {
|
|
5015
5015
|
CallExpression(node) {
|
|
@@ -5029,12 +5029,12 @@ var no_generic_single_export_module_default = createRule({
|
|
|
5029
5029
|
const { name: exported, node } = onlyExport;
|
|
5030
5030
|
if (isConventionalFrameworkUtility(context.filename, exported)) return;
|
|
5031
5031
|
const exportedRole = exported.replaceAll(/[^a-z0-9]/giu, "").toLowerCase();
|
|
5032
|
-
const pathRole = [
|
|
5032
|
+
const pathRole = [stem4, ...file.suffixes].join("").replaceAll(/[^a-z0-9]/giu, "");
|
|
5033
5033
|
if (exportedRole === pathRole && file.suffixes.length > 0) return;
|
|
5034
5034
|
context.report({
|
|
5035
5035
|
node,
|
|
5036
5036
|
messageId: "genericSingleExport",
|
|
5037
|
-
data: { stem:
|
|
5037
|
+
data: { stem: stem4, exported }
|
|
5038
5038
|
});
|
|
5039
5039
|
}
|
|
5040
5040
|
};
|
|
@@ -5351,7 +5351,7 @@ var no_positional_tuple_return_default = createRule({
|
|
|
5351
5351
|
const aliases = typeAliases(context.sourceCode.ast);
|
|
5352
5352
|
const reportedFunctions = /* @__PURE__ */ new WeakSet();
|
|
5353
5353
|
const functionStack = [];
|
|
5354
|
-
const
|
|
5354
|
+
const report2 = (annotation, name) => {
|
|
5355
5355
|
const tuple = tupleReturnType(annotation, aliases);
|
|
5356
5356
|
if (tuple === null || tuple.elementTypes.length < MIN_ELEMENTS) return;
|
|
5357
5357
|
context.report({
|
|
@@ -5385,7 +5385,7 @@ var no_positional_tuple_return_default = createRule({
|
|
|
5385
5385
|
if (name === null) {
|
|
5386
5386
|
return;
|
|
5387
5387
|
}
|
|
5388
|
-
|
|
5388
|
+
report2(annotation, name);
|
|
5389
5389
|
};
|
|
5390
5390
|
const enterFunction = (node) => {
|
|
5391
5391
|
functionStack.push(node);
|
|
@@ -5410,34 +5410,34 @@ var no_positional_tuple_return_default = createRule({
|
|
|
5410
5410
|
},
|
|
5411
5411
|
TSDeclareFunction(node) {
|
|
5412
5412
|
if (node.id === null || node.returnType === void 0 || node.parent.type !== AST_NODE_TYPES21.ExportNamedDeclaration && node.parent.type !== AST_NODE_TYPES21.ExportDefaultDeclaration && !specifierExports.has(node.id.name)) return;
|
|
5413
|
-
|
|
5413
|
+
report2(node.returnType.typeAnnotation, node.id.name);
|
|
5414
5414
|
},
|
|
5415
5415
|
TSCallSignatureDeclaration(node) {
|
|
5416
5416
|
const owner = owningInterface(node);
|
|
5417
5417
|
if (owner === null || !isExportedInterface(owner, typeExports) || node.returnType === void 0) return;
|
|
5418
|
-
|
|
5418
|
+
report2(node.returnType.typeAnnotation, `${owner.id.name}.call`);
|
|
5419
5419
|
},
|
|
5420
5420
|
TSMethodSignature(node) {
|
|
5421
5421
|
const owner = owningInterface(node);
|
|
5422
5422
|
const alias = owningTypeAlias(node);
|
|
5423
|
-
const
|
|
5424
|
-
if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || node.returnType === void 0 ||
|
|
5425
|
-
|
|
5423
|
+
const memberName6 = staticMemberName3(node.key);
|
|
5424
|
+
if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || node.returnType === void 0 || memberName6 === null) return;
|
|
5425
|
+
report2(node.returnType.typeAnnotation, `${owner?.id.name ?? alias?.id.name ?? "type"}.${memberName6}`);
|
|
5426
5426
|
},
|
|
5427
5427
|
TSTypeAliasDeclaration(node) {
|
|
5428
5428
|
if (!typeExports.has(node.id.name)) return;
|
|
5429
5429
|
const returnType = callableReturnType(node.typeAnnotation, aliases);
|
|
5430
|
-
if (returnType !== null)
|
|
5430
|
+
if (returnType !== null) report2(returnType, node.id.name);
|
|
5431
5431
|
},
|
|
5432
5432
|
TSPropertySignature(node) {
|
|
5433
5433
|
const owner = owningInterface(node);
|
|
5434
5434
|
const alias = owningTypeAlias(node);
|
|
5435
5435
|
const annotation = node.typeAnnotation?.typeAnnotation;
|
|
5436
|
-
const
|
|
5437
|
-
if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) ||
|
|
5436
|
+
const memberName6 = staticMemberName3(node.key);
|
|
5437
|
+
if ((owner === null || !isExportedInterface(owner, typeExports)) && (alias === null || !typeExports.has(alias.id.name)) || memberName6 === null || annotation === void 0) return;
|
|
5438
5438
|
const returnType = callableReturnType(annotation, aliases);
|
|
5439
5439
|
if (returnType !== null) {
|
|
5440
|
-
|
|
5440
|
+
report2(returnType, `${owner?.id.name ?? alias?.id.name ?? "type"}.${memberName6}`);
|
|
5441
5441
|
}
|
|
5442
5442
|
},
|
|
5443
5443
|
PropertyDefinition(node) {
|
|
@@ -5448,7 +5448,7 @@ var no_positional_tuple_return_default = createRule({
|
|
|
5448
5448
|
const returnType = callableReturnType(annotation, aliases);
|
|
5449
5449
|
if (returnType !== null) {
|
|
5450
5450
|
const name = node.key.type === AST_NODE_TYPES21.Identifier ? node.key.name : "property";
|
|
5451
|
-
|
|
5451
|
+
report2(returnType, name);
|
|
5452
5452
|
}
|
|
5453
5453
|
}
|
|
5454
5454
|
};
|
|
@@ -5924,7 +5924,7 @@ var no_restricted_library_load_default = createRule({
|
|
|
5924
5924
|
defaultOptions: [{ libraries: [] }],
|
|
5925
5925
|
create(context, [options]) {
|
|
5926
5926
|
const restrictions = options.libraries;
|
|
5927
|
-
function
|
|
5927
|
+
function report2(node, source) {
|
|
5928
5928
|
const restriction = restrictions.find(
|
|
5929
5929
|
(entry) => matchesModule(source, entry.module)
|
|
5930
5930
|
);
|
|
@@ -5950,7 +5950,7 @@ var no_restricted_library_load_default = createRule({
|
|
|
5950
5950
|
return {
|
|
5951
5951
|
ImportExpression(node) {
|
|
5952
5952
|
const source = literalModule(node.source);
|
|
5953
|
-
if (source !== null)
|
|
5953
|
+
if (source !== null) report2(node.source, source);
|
|
5954
5954
|
},
|
|
5955
5955
|
CallExpression(node) {
|
|
5956
5956
|
let requireIdentifier = null;
|
|
@@ -5961,12 +5961,12 @@ var no_restricted_library_load_default = createRule({
|
|
|
5961
5961
|
}
|
|
5962
5962
|
if (requireIdentifier === null || !isUnshadowedRequire(requireIdentifier)) return;
|
|
5963
5963
|
const source = literalModule(node.arguments[0]);
|
|
5964
|
-
if (source !== null)
|
|
5964
|
+
if (source !== null) report2(node.arguments[0], source);
|
|
5965
5965
|
},
|
|
5966
5966
|
TSImportEqualsDeclaration(node) {
|
|
5967
5967
|
if (node.moduleReference.type !== AST_NODE_TYPES23.TSExternalModuleReference) return;
|
|
5968
5968
|
const source = literalModule(node.moduleReference.expression);
|
|
5969
|
-
if (source !== null)
|
|
5969
|
+
if (source !== null) report2(node.moduleReference.expression, source);
|
|
5970
5970
|
}
|
|
5971
5971
|
};
|
|
5972
5972
|
}
|
|
@@ -7782,7 +7782,7 @@ var no_sleep_in_test_body_default = createRule({
|
|
|
7782
7782
|
if (!isTestFile(context.filename)) {
|
|
7783
7783
|
return {};
|
|
7784
7784
|
}
|
|
7785
|
-
const
|
|
7785
|
+
const report2 = (node) => {
|
|
7786
7786
|
if (!isImmediatelyConsumedSleep(node)) {
|
|
7787
7787
|
return;
|
|
7788
7788
|
}
|
|
@@ -7795,12 +7795,12 @@ var no_sleep_in_test_body_default = createRule({
|
|
|
7795
7795
|
return {
|
|
7796
7796
|
NewExpression(node) {
|
|
7797
7797
|
if (isPromiseSleep(node)) {
|
|
7798
|
-
|
|
7798
|
+
report2(node);
|
|
7799
7799
|
}
|
|
7800
7800
|
},
|
|
7801
7801
|
CallExpression(node) {
|
|
7802
7802
|
if (isHelperSleep(node)) {
|
|
7803
|
-
|
|
7803
|
+
report2(node);
|
|
7804
7804
|
}
|
|
7805
7805
|
}
|
|
7806
7806
|
};
|
|
@@ -10251,7 +10251,7 @@ function reportClass2(context, services, owner) {
|
|
|
10251
10251
|
}
|
|
10252
10252
|
function isConvertible(member) {
|
|
10253
10253
|
if (member.type !== AST_NODE_TYPES43.MethodDefinition && member.type !== AST_NODE_TYPES43.PropertyDefinition && member.type !== AST_NODE_TYPES43.AccessorProperty) return false;
|
|
10254
|
-
return member.accessibility === "private" && !member.computed && member.key.type === AST_NODE_TYPES43.Identifier && member.decorators.length === 0 && !("declare" in member && member.declare) && !member.override && !(member.type === AST_NODE_TYPES43.MethodDefinition && member.value.body === null);
|
|
10254
|
+
return member.accessibility === "private" && !(member.type === AST_NODE_TYPES43.MethodDefinition && member.kind === "constructor") && !member.computed && member.key.type === AST_NODE_TYPES43.Identifier && member.decorators.length === 0 && !("declare" in member && member.declare) && !member.override && !(member.type === AST_NODE_TYPES43.MethodDefinition && member.value.body === null);
|
|
10255
10255
|
}
|
|
10256
10256
|
var prefer_ecmascript_private_members_default = createRule({
|
|
10257
10257
|
name: "prefer-ecmascript-private-members",
|
|
@@ -10449,9 +10449,9 @@ var INPUT_MODULE = /(?:^|\/)components\/ui\/input$/u;
|
|
|
10449
10449
|
var INPUT_GROUP_MODULE = /(?:^|\/)components\/ui\/input-group$/u;
|
|
10450
10450
|
var MAX_JSX_DISTANCE = 2;
|
|
10451
10451
|
var SEARCH_EXPORTS = ["Search", "SearchIcon", "LucideSearch"];
|
|
10452
|
-
function localNamedImports(node,
|
|
10452
|
+
function localNamedImports(node, importedName7) {
|
|
10453
10453
|
return node.specifiers.filter(
|
|
10454
|
-
(specifier) => specifier.type === AST_NODE_TYPES45.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES45.Identifier ? specifier.imported.name : specifier.imported.value) ===
|
|
10454
|
+
(specifier) => specifier.type === AST_NODE_TYPES45.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES45.Identifier ? specifier.imported.name : specifier.imported.value) === importedName7
|
|
10455
10455
|
).map((specifier) => specifier.local.name);
|
|
10456
10456
|
}
|
|
10457
10457
|
function elementName(node) {
|
|
@@ -11664,8 +11664,67 @@ var prefer_module_level_schema_default = createRule({
|
|
|
11664
11664
|
}
|
|
11665
11665
|
});
|
|
11666
11666
|
|
|
11667
|
+
// src/rules/prefer-named-complex-return-type.ts
|
|
11668
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES50 } from "@typescript-eslint/utils";
|
|
11669
|
+
var PREFER_NAMED_COMPLEX_RETURN_TYPE_DOCUMENTATION = {
|
|
11670
|
+
summary: "Prefer a named contract for structurally complex function return types.",
|
|
11671
|
+
rationale: "A large inline return annotation hides a reusable domain concept and makes signatures difficult to scan.",
|
|
11672
|
+
remediation: "Extract the return annotation to a named type or interface and reference that contract from the signature.",
|
|
11673
|
+
category: "maintainability",
|
|
11674
|
+
limitations: [
|
|
11675
|
+
"Only explicit object types with at least three members and unions with at least three object variants are reported.",
|
|
11676
|
+
"Generic wrappers such as Promise and Readonly are unwrapped one level at a time; inferred return types are outside this rule."
|
|
11677
|
+
],
|
|
11678
|
+
examples: [
|
|
11679
|
+
{ id: "named-result", title: "Name a multi-state result", outcome: "no-match", files: [{ path: "src/queue.ts", source: "type ClaimResult = { state: 'idle' } | { state: 'waiting'; retryAt: number } | { state: 'claimed'; id: string }; export function claim(): ClaimResult { return { state: 'idle' }; }" }], focusPath: "src/queue.ts", expectedCount: 0, public: true },
|
|
11680
|
+
{ id: "inline-result", title: "Do not inline a multi-state result", outcome: "match", files: [{ path: "src/queue.ts", source: "export function claim(): { state: 'idle' } | { state: 'waiting'; retryAt: number } | { state: 'claimed'; id: string } { return { state: 'idle' }; }" }], focusPath: "src/queue.ts", expectedCount: 1, public: true }
|
|
11681
|
+
]
|
|
11682
|
+
};
|
|
11683
|
+
function unwrap4(node) {
|
|
11684
|
+
if (node.type === AST_NODE_TYPES50.TSTypeReference && node.typeArguments?.params.length === 1) {
|
|
11685
|
+
const [inner] = node.typeArguments.params;
|
|
11686
|
+
if (inner !== void 0) return unwrap4(inner);
|
|
11687
|
+
}
|
|
11688
|
+
return node;
|
|
11689
|
+
}
|
|
11690
|
+
function report(context, node) {
|
|
11691
|
+
const annotation = node.returnType?.typeAnnotation;
|
|
11692
|
+
if (annotation !== void 0 && isComplex(annotation)) {
|
|
11693
|
+
context.report({ node: annotation, messageId: "nameComplexReturnType" });
|
|
11694
|
+
}
|
|
11695
|
+
}
|
|
11696
|
+
function isComplex(node) {
|
|
11697
|
+
const type = unwrap4(node);
|
|
11698
|
+
if (type.type === AST_NODE_TYPES50.TSTypeLiteral) return type.members.length >= 3;
|
|
11699
|
+
if (type.type !== AST_NODE_TYPES50.TSUnionType || type.types.length < 3) return false;
|
|
11700
|
+
return type.types.every((member) => unwrap4(member).type === AST_NODE_TYPES50.TSTypeLiteral);
|
|
11701
|
+
}
|
|
11702
|
+
var prefer_named_complex_return_type_default = createRule({
|
|
11703
|
+
name: "prefer-named-complex-return-type",
|
|
11704
|
+
documentation: PREFER_NAMED_COMPLEX_RETURN_TYPE_DOCUMENTATION,
|
|
11705
|
+
meta: {
|
|
11706
|
+
type: "suggestion",
|
|
11707
|
+
docs: { description: "Prefer a named contract for structurally complex function return types." },
|
|
11708
|
+
schema: [],
|
|
11709
|
+
messages: {
|
|
11710
|
+
nameComplexReturnType: "Extract this structurally complex return annotation to a named type or interface."
|
|
11711
|
+
}
|
|
11712
|
+
},
|
|
11713
|
+
defaultOptions: [],
|
|
11714
|
+
create(context) {
|
|
11715
|
+
if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
11716
|
+
return {
|
|
11717
|
+
ArrowFunctionExpression: (node) => report(context, node),
|
|
11718
|
+
FunctionDeclaration: (node) => report(context, node),
|
|
11719
|
+
FunctionExpression: (node) => report(context, node),
|
|
11720
|
+
TSDeclareFunction: (node) => report(context, node),
|
|
11721
|
+
TSMethodSignature: (node) => report(context, node)
|
|
11722
|
+
};
|
|
11723
|
+
}
|
|
11724
|
+
});
|
|
11725
|
+
|
|
11667
11726
|
// src/rules/prefer-native-random-uuid.ts
|
|
11668
|
-
import { AST_NODE_TYPES as
|
|
11727
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES51, ASTUtils as ASTUtils14 } from "@typescript-eslint/utils";
|
|
11669
11728
|
var PREFER_NATIVE_RANDOM_UUID_DOCUMENTATION = {
|
|
11670
11729
|
summary: "Prefer `globalThis.crypto.randomUUID()` over resolved zero-argument UUID v4 bindings from the `uuid` package.",
|
|
11671
11730
|
rationale: "The platform implementation avoids an unnecessary dependency for standard random UUID generation.",
|
|
@@ -11679,7 +11738,7 @@ var PREFER_NATIVE_RANDOM_UUID_DOCUMENTATION = {
|
|
|
11679
11738
|
]
|
|
11680
11739
|
};
|
|
11681
11740
|
function requireUuid(node) {
|
|
11682
|
-
return node?.type ===
|
|
11741
|
+
return node?.type === AST_NODE_TYPES51.CallExpression && node.callee.type === AST_NODE_TYPES51.Identifier && node.callee.name === "require" && node.arguments.length === 1 && node.arguments[0]?.type === AST_NODE_TYPES51.Literal && node.arguments[0].value === "uuid";
|
|
11683
11742
|
}
|
|
11684
11743
|
var prefer_native_random_uuid_default = createRule({
|
|
11685
11744
|
name: "prefer-native-random-uuid",
|
|
@@ -11707,7 +11766,7 @@ var prefer_native_random_uuid_default = createRule({
|
|
|
11707
11766
|
const variable = resolve(identifier);
|
|
11708
11767
|
if (variable !== null) destination.add(variable);
|
|
11709
11768
|
}
|
|
11710
|
-
function
|
|
11769
|
+
function report2(node) {
|
|
11711
11770
|
context.report({
|
|
11712
11771
|
node,
|
|
11713
11772
|
messageId: "preferNative",
|
|
@@ -11723,48 +11782,291 @@ var prefer_native_random_uuid_default = createRule({
|
|
|
11723
11782
|
ImportDeclaration(node) {
|
|
11724
11783
|
if (node.source.value !== "uuid") return;
|
|
11725
11784
|
for (const specifier of node.specifiers) {
|
|
11726
|
-
if (specifier.type ===
|
|
11785
|
+
if (specifier.type === AST_NODE_TYPES51.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES51.Identifier ? specifier.imported.name === "v4" : specifier.imported.value === "v4")) {
|
|
11727
11786
|
record(specifier.local, directBindings);
|
|
11728
|
-
} else if (specifier.type ===
|
|
11787
|
+
} else if (specifier.type === AST_NODE_TYPES51.ImportNamespaceSpecifier) {
|
|
11729
11788
|
record(specifier.local, namespaceBindings);
|
|
11730
11789
|
}
|
|
11731
11790
|
}
|
|
11732
11791
|
},
|
|
11733
11792
|
VariableDeclarator(node) {
|
|
11734
11793
|
if (node.parent.kind !== "const" || !requireUuid(node.init)) return;
|
|
11735
|
-
if (node.init?.type !==
|
|
11794
|
+
if (node.init?.type !== AST_NODE_TYPES51.CallExpression || node.init.callee.type !== AST_NODE_TYPES51.Identifier || (resolve(node.init.callee)?.defs.length ?? 0) > 0) {
|
|
11736
11795
|
return;
|
|
11737
11796
|
}
|
|
11738
|
-
if (node.id.type ===
|
|
11797
|
+
if (node.id.type === AST_NODE_TYPES51.Identifier) {
|
|
11739
11798
|
record(node.id, namespaceBindings);
|
|
11740
11799
|
return;
|
|
11741
11800
|
}
|
|
11742
|
-
if (node.id.type !==
|
|
11801
|
+
if (node.id.type !== AST_NODE_TYPES51.ObjectPattern) return;
|
|
11743
11802
|
for (const property of node.id.properties) {
|
|
11744
|
-
if (property.type ===
|
|
11803
|
+
if (property.type === AST_NODE_TYPES51.Property && !property.computed && (property.key.type === AST_NODE_TYPES51.Identifier && property.key.name === "v4" || property.key.type === AST_NODE_TYPES51.Literal && property.key.value === "v4") && property.value.type === AST_NODE_TYPES51.Identifier) {
|
|
11745
11804
|
record(property.value, directBindings);
|
|
11746
11805
|
}
|
|
11747
11806
|
}
|
|
11748
11807
|
},
|
|
11749
11808
|
"CallExpression:exit"(node) {
|
|
11750
11809
|
if (node.arguments.length !== 0) return;
|
|
11751
|
-
if (node.callee.type ===
|
|
11810
|
+
if (node.callee.type === AST_NODE_TYPES51.Identifier) {
|
|
11752
11811
|
const variable2 = resolve(node.callee);
|
|
11753
|
-
if (variable2 !== null && directBindings.has(variable2))
|
|
11812
|
+
if (variable2 !== null && directBindings.has(variable2)) report2(node);
|
|
11754
11813
|
return;
|
|
11755
11814
|
}
|
|
11756
|
-
if (node.callee.type !==
|
|
11815
|
+
if (node.callee.type !== AST_NODE_TYPES51.MemberExpression || node.callee.computed || node.callee.object.type !== AST_NODE_TYPES51.Identifier || node.callee.property.type !== AST_NODE_TYPES51.Identifier || node.callee.property.name !== "v4") {
|
|
11757
11816
|
return;
|
|
11758
11817
|
}
|
|
11759
11818
|
const variable = resolve(node.callee.object);
|
|
11760
|
-
if (variable !== null && namespaceBindings.has(variable))
|
|
11819
|
+
if (variable !== null && namespaceBindings.has(variable)) report2(node);
|
|
11820
|
+
}
|
|
11821
|
+
};
|
|
11822
|
+
}
|
|
11823
|
+
});
|
|
11824
|
+
|
|
11825
|
+
// src/rules/prefer-node-crypto-hash.ts
|
|
11826
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES52, ASTUtils as ASTUtils15 } from "@typescript-eslint/utils";
|
|
11827
|
+
var PREFER_NODE_CRYPTO_HASH_DOCUMENTATION = {
|
|
11828
|
+
summary: "Prefer the modern one-shot node:crypto hash API when streaming state is unnecessary.",
|
|
11829
|
+
rationale: "A createHash-update-digest chain allocates mutable streaming state for a single in-memory value; Node's built-in hash function expresses the one-shot operation directly and can use its optimized fast path.",
|
|
11830
|
+
remediation: "Import hash from node:crypto and replace a single-update chain with hash(algorithm, value, encoding). Keep createHash for streams or multiple incremental updates.",
|
|
11831
|
+
category: "performance",
|
|
11832
|
+
limitations: [
|
|
11833
|
+
"Only bindings and inline calls with statically proven provenance from crypto or node:crypto are analyzed; arbitrary assignments and dynamic module specifiers are excluded.",
|
|
11834
|
+
"Only a literal algorithm with exactly one update call is reported; streaming and incremental hashes remain valid."
|
|
11835
|
+
],
|
|
11836
|
+
examples: [
|
|
11837
|
+
{ id: "one-shot-hash", title: "Use Node's one-shot hash API", outcome: "no-match", files: [{ path: "case.ts", source: "import { hash } from 'node:crypto'; export const digest = hash('sha256', 'value', 'hex');" }], focusPath: "case.ts", expectedCount: 0, public: true },
|
|
11838
|
+
{ id: "mutable-one-shot-chain", title: "Avoid mutable state for one value", outcome: "match", files: [{ path: "case.ts", source: "import { createHash } from 'node:crypto'; export const digest = createHash('sha256').update('value').digest('hex');" }], focusPath: "case.ts", expectedCount: 1, public: true }
|
|
11839
|
+
]
|
|
11840
|
+
};
|
|
11841
|
+
function memberName3(node) {
|
|
11842
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES52.Identifier) return node.property.name;
|
|
11843
|
+
if (node.computed && node.property.type === AST_NODE_TYPES52.Literal && typeof node.property.value === "string") {
|
|
11844
|
+
return node.property.value;
|
|
11845
|
+
}
|
|
11846
|
+
return null;
|
|
11847
|
+
}
|
|
11848
|
+
function isCryptoLoader(node, resolve) {
|
|
11849
|
+
if (node.type !== AST_NODE_TYPES52.CallExpression || node.arguments.length !== 1) return false;
|
|
11850
|
+
const [argument] = node.arguments;
|
|
11851
|
+
if (argument === void 0 || argument.type === AST_NODE_TYPES52.SpreadElement || !isCryptoSpecifier(argument)) {
|
|
11852
|
+
return false;
|
|
11853
|
+
}
|
|
11854
|
+
if (node.callee.type === AST_NODE_TYPES52.Identifier) {
|
|
11855
|
+
return node.callee.name === "require" && isUnshadowedBuiltinIdentifier(node.callee, resolve);
|
|
11856
|
+
}
|
|
11857
|
+
return node.callee.type === AST_NODE_TYPES52.MemberExpression && node.callee.object.type === AST_NODE_TYPES52.Identifier && node.callee.object.name === "process" && isUnshadowedBuiltinIdentifier(node.callee.object, resolve) && memberName3(node.callee) === "getBuiltinModule";
|
|
11858
|
+
}
|
|
11859
|
+
function isCryptoSpecifier(node) {
|
|
11860
|
+
return node.type === AST_NODE_TYPES52.Literal && (node.value === "crypto" || node.value === "node:crypto");
|
|
11861
|
+
}
|
|
11862
|
+
function isUnshadowedBuiltinIdentifier(identifier, resolve) {
|
|
11863
|
+
const variable = resolve(identifier);
|
|
11864
|
+
return variable === null || variable.defs.length === 0;
|
|
11865
|
+
}
|
|
11866
|
+
function propertyName3(node) {
|
|
11867
|
+
if (!node.computed && node.key.type === AST_NODE_TYPES52.Identifier) return node.key.name;
|
|
11868
|
+
if (node.key.type === AST_NODE_TYPES52.Literal && typeof node.key.value === "string") {
|
|
11869
|
+
return node.key.value;
|
|
11870
|
+
}
|
|
11871
|
+
return null;
|
|
11872
|
+
}
|
|
11873
|
+
var prefer_node_crypto_hash_default = createRule({
|
|
11874
|
+
name: "prefer-node-crypto-hash",
|
|
11875
|
+
documentation: PREFER_NODE_CRYPTO_HASH_DOCUMENTATION,
|
|
11876
|
+
meta: { type: "problem", docs: { description: PREFER_NODE_CRYPTO_HASH_DOCUMENTATION.summary }, schema: [], messages: { preferNodeCryptoHash: "Prefer the modern one-shot node:crypto hash API when streaming state is unnecessary." } },
|
|
11877
|
+
defaultOptions: [],
|
|
11878
|
+
create(context) {
|
|
11879
|
+
const directBindings = /* @__PURE__ */ new Set();
|
|
11880
|
+
const namespaceBindings = /* @__PURE__ */ new Set();
|
|
11881
|
+
function resolve(identifier) {
|
|
11882
|
+
return ASTUtils15.findVariable(
|
|
11883
|
+
context.sourceCode.getScope(identifier),
|
|
11884
|
+
identifier.name
|
|
11885
|
+
);
|
|
11886
|
+
}
|
|
11887
|
+
function record(identifier, destination) {
|
|
11888
|
+
const variable = resolve(identifier);
|
|
11889
|
+
if (variable !== null) destination.add(variable);
|
|
11890
|
+
}
|
|
11891
|
+
return {
|
|
11892
|
+
ImportDeclaration(node) {
|
|
11893
|
+
if (node.source.value !== "crypto" && node.source.value !== "node:crypto") return;
|
|
11894
|
+
for (const specifier of node.specifiers) {
|
|
11895
|
+
if (specifier.type === AST_NODE_TYPES52.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES52.ImportDefaultSpecifier) {
|
|
11896
|
+
record(specifier.local, namespaceBindings);
|
|
11897
|
+
} else if (specifier.type === AST_NODE_TYPES52.ImportSpecifier && importedName5(specifier.imported) === "createHash") {
|
|
11898
|
+
record(specifier.local, directBindings);
|
|
11899
|
+
}
|
|
11900
|
+
}
|
|
11901
|
+
},
|
|
11902
|
+
VariableDeclarator(node) {
|
|
11903
|
+
if (node.parent.kind !== "const" || node.init === null || !isCryptoLoader(node.init, resolve)) {
|
|
11904
|
+
return;
|
|
11905
|
+
}
|
|
11906
|
+
if (node.id.type === AST_NODE_TYPES52.Identifier) {
|
|
11907
|
+
record(node.id, namespaceBindings);
|
|
11908
|
+
return;
|
|
11909
|
+
}
|
|
11910
|
+
if (node.id.type !== AST_NODE_TYPES52.ObjectPattern) return;
|
|
11911
|
+
for (const property of node.id.properties) {
|
|
11912
|
+
if (property.type === AST_NODE_TYPES52.Property && propertyName3(property) === "createHash" && property.value.type === AST_NODE_TYPES52.Identifier) {
|
|
11913
|
+
record(property.value, directBindings);
|
|
11914
|
+
}
|
|
11915
|
+
}
|
|
11916
|
+
},
|
|
11917
|
+
CallExpression(node) {
|
|
11918
|
+
if (!isMemberCall(node, "digest")) return;
|
|
11919
|
+
const update = node.callee.object;
|
|
11920
|
+
if (update.type !== AST_NODE_TYPES52.CallExpression || update.arguments.length !== 1 || !isMemberCall(update, "update"))
|
|
11921
|
+
return;
|
|
11922
|
+
const create = update.callee.object;
|
|
11923
|
+
if (create.type !== AST_NODE_TYPES52.CallExpression || create.arguments.length !== 1 || create.arguments[0]?.type !== AST_NODE_TYPES52.Literal || typeof create.arguments[0].value !== "string" || !isCreateHashCall(
|
|
11924
|
+
create,
|
|
11925
|
+
directBindings,
|
|
11926
|
+
namespaceBindings,
|
|
11927
|
+
resolve
|
|
11928
|
+
))
|
|
11929
|
+
return;
|
|
11930
|
+
context.report({ node, messageId: "preferNodeCryptoHash" });
|
|
11931
|
+
}
|
|
11932
|
+
};
|
|
11933
|
+
}
|
|
11934
|
+
});
|
|
11935
|
+
function importedName5(node) {
|
|
11936
|
+
return node.type === AST_NODE_TYPES52.Identifier ? node.name : node.value;
|
|
11937
|
+
}
|
|
11938
|
+
function isMemberCall(node, name) {
|
|
11939
|
+
return node.callee.type === AST_NODE_TYPES52.MemberExpression && memberName3(node.callee) === name;
|
|
11940
|
+
}
|
|
11941
|
+
function isCreateHashCall(node, directBindings, namespaceBindings, resolve) {
|
|
11942
|
+
if (node.callee.type === AST_NODE_TYPES52.Identifier) {
|
|
11943
|
+
const variable2 = resolve(node.callee);
|
|
11944
|
+
return variable2 !== null && directBindings.has(variable2);
|
|
11945
|
+
}
|
|
11946
|
+
if (node.callee.type !== AST_NODE_TYPES52.MemberExpression || memberName3(node.callee) !== "createHash") {
|
|
11947
|
+
return false;
|
|
11948
|
+
}
|
|
11949
|
+
if (isCryptoLoader(node.callee.object, resolve)) return true;
|
|
11950
|
+
if (node.callee.object.type !== AST_NODE_TYPES52.Identifier) return false;
|
|
11951
|
+
const variable = resolve(node.callee.object);
|
|
11952
|
+
return variable !== null && namespaceBindings.has(variable);
|
|
11953
|
+
}
|
|
11954
|
+
|
|
11955
|
+
// src/rules/prefer-node-fs-promises.ts
|
|
11956
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES53 } from "@typescript-eslint/utils";
|
|
11957
|
+
var PREFER_NODE_FS_PROMISES_DOCUMENTATION = {
|
|
11958
|
+
summary: "Prefer promise-based Node.js filesystem APIs over synchronous calls in production modules.",
|
|
11959
|
+
rationale: "Synchronous filesystem work blocks the event loop and can stall unrelated daemon, server, and worker tasks.",
|
|
11960
|
+
remediation: "Import the promise API from node:fs/promises and await it; use FileHandle.sync only where a documented durability boundary requires it.",
|
|
11961
|
+
category: "performance",
|
|
11962
|
+
limitations: [
|
|
11963
|
+
"Tests and generated files are excluded.",
|
|
11964
|
+
"ESLint rule implementations under src/rules are excluded because visitor creation and execution are synchronous by contract.",
|
|
11965
|
+
"Only statically identifiable node:fs loads are inspected; filesystem objects passed through arbitrary functions or assignments require type-aware analysis."
|
|
11966
|
+
],
|
|
11967
|
+
examples: [
|
|
11968
|
+
{ id: "async-read", title: "Use the promise API", outcome: "no-match", files: [{ path: "src/store.ts", source: "import { readFile } from 'node:fs/promises'; export async function load(path: string) { return readFile(path, 'utf8'); }" }], focusPath: "src/store.ts", expectedCount: 0, public: true },
|
|
11969
|
+
{ id: "sync-read", title: "Do not block on a synchronous read", outcome: "match", files: [{ path: "src/store.ts", source: "import { readFileSync } from 'node:fs'; export function load(path: string) { return readFileSync(path, 'utf8'); }" }], focusPath: "src/store.ts", expectedCount: 1, public: true }
|
|
11970
|
+
]
|
|
11971
|
+
};
|
|
11972
|
+
function memberName4(node) {
|
|
11973
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES53.Identifier) return node.property.name;
|
|
11974
|
+
if (node.computed && node.property.type === AST_NODE_TYPES53.Literal && typeof node.property.value === "string") {
|
|
11975
|
+
return node.property.value;
|
|
11976
|
+
}
|
|
11977
|
+
return null;
|
|
11978
|
+
}
|
|
11979
|
+
function unwrapAwait2(node) {
|
|
11980
|
+
return node.type === AST_NODE_TYPES53.AwaitExpression ? node.argument : node;
|
|
11981
|
+
}
|
|
11982
|
+
function isFsLoader(node) {
|
|
11983
|
+
const expression = unwrapAwait2(node);
|
|
11984
|
+
if (expression.type === AST_NODE_TYPES53.ImportExpression) return isFsSpecifier(expression.source);
|
|
11985
|
+
if (expression.type !== AST_NODE_TYPES53.CallExpression || expression.arguments.length !== 1) return false;
|
|
11986
|
+
const [argument] = expression.arguments;
|
|
11987
|
+
if (argument === void 0 || argument.type === AST_NODE_TYPES53.SpreadElement || !isFsSpecifier(argument)) return false;
|
|
11988
|
+
if (expression.callee.type === AST_NODE_TYPES53.Identifier) return expression.callee.name === "require";
|
|
11989
|
+
return expression.callee.type === AST_NODE_TYPES53.MemberExpression && expression.callee.object.type === AST_NODE_TYPES53.Identifier && expression.callee.object.name === "process" && memberName4(expression.callee) === "getBuiltinModule";
|
|
11990
|
+
}
|
|
11991
|
+
function isFsSpecifier(node) {
|
|
11992
|
+
return node.type === AST_NODE_TYPES53.Literal && (node.value === "node:fs" || node.value === "fs");
|
|
11993
|
+
}
|
|
11994
|
+
function propertyName4(node) {
|
|
11995
|
+
if (!node.computed && node.key.type === AST_NODE_TYPES53.Identifier) return node.key.name;
|
|
11996
|
+
if (node.key.type === AST_NODE_TYPES53.Literal && typeof node.key.value === "string") return node.key.value;
|
|
11997
|
+
return null;
|
|
11998
|
+
}
|
|
11999
|
+
var prefer_node_fs_promises_default = createRule({
|
|
12000
|
+
name: "prefer-node-fs-promises",
|
|
12001
|
+
documentation: PREFER_NODE_FS_PROMISES_DOCUMENTATION,
|
|
12002
|
+
meta: {
|
|
12003
|
+
type: "suggestion",
|
|
12004
|
+
docs: { description: "Prefer promise-based Node.js filesystem APIs over synchronous calls in production modules." },
|
|
12005
|
+
schema: [],
|
|
12006
|
+
messages: {
|
|
12007
|
+
preferAsyncFs: "Node filesystem API `{{name}}` is synchronous; use the promise API and await it."
|
|
12008
|
+
}
|
|
12009
|
+
},
|
|
12010
|
+
defaultOptions: [],
|
|
12011
|
+
create(context) {
|
|
12012
|
+
const normalizedFilename = context.filename.replaceAll("\\", "/");
|
|
12013
|
+
if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text) || normalizedFilename.includes("src/rules/"))
|
|
12014
|
+
return {};
|
|
12015
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
12016
|
+
return {
|
|
12017
|
+
ImportDeclaration(node) {
|
|
12018
|
+
if (node.source.value !== "node:fs" && node.source.value !== "fs") return;
|
|
12019
|
+
const synchronousImports = [];
|
|
12020
|
+
for (const specifier of node.specifiers) {
|
|
12021
|
+
if (specifier.type === AST_NODE_TYPES53.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES53.ImportDefaultSpecifier) {
|
|
12022
|
+
namespaces.add(specifier.local.name);
|
|
12023
|
+
continue;
|
|
12024
|
+
}
|
|
12025
|
+
if (specifier.type === AST_NODE_TYPES53.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES53.Identifier && specifier.imported.name.endsWith("Sync")) synchronousImports.push(specifier.imported.name);
|
|
12026
|
+
}
|
|
12027
|
+
if (synchronousImports.length > 0) {
|
|
12028
|
+
context.report({
|
|
12029
|
+
node,
|
|
12030
|
+
messageId: "preferAsyncFs",
|
|
12031
|
+
data: { name: synchronousImports.join(", ") }
|
|
12032
|
+
});
|
|
12033
|
+
}
|
|
12034
|
+
},
|
|
12035
|
+
VariableDeclarator(node) {
|
|
12036
|
+
if (node.init === null || !isFsLoader(node.init) && (node.init.type !== AST_NODE_TYPES53.Identifier || !namespaces.has(node.init.name)))
|
|
12037
|
+
return;
|
|
12038
|
+
if (node.id.type === AST_NODE_TYPES53.Identifier) {
|
|
12039
|
+
namespaces.add(node.id.name);
|
|
12040
|
+
return;
|
|
12041
|
+
}
|
|
12042
|
+
if (node.id.type !== AST_NODE_TYPES53.ObjectPattern) return;
|
|
12043
|
+
const synchronousImports = node.id.properties.flatMap((property) => {
|
|
12044
|
+
if (property.type !== AST_NODE_TYPES53.Property) return [];
|
|
12045
|
+
const name = propertyName4(property);
|
|
12046
|
+
return name?.endsWith("Sync") === true ? [name] : [];
|
|
12047
|
+
});
|
|
12048
|
+
if (synchronousImports.length > 0) {
|
|
12049
|
+
context.report({
|
|
12050
|
+
node,
|
|
12051
|
+
messageId: "preferAsyncFs",
|
|
12052
|
+
data: { name: synchronousImports.join(", ") }
|
|
12053
|
+
});
|
|
12054
|
+
}
|
|
12055
|
+
},
|
|
12056
|
+
MemberExpression(node) {
|
|
12057
|
+
const name = memberName4(node);
|
|
12058
|
+
if (name?.endsWith("Sync") !== true) return;
|
|
12059
|
+
const object = unwrapAwait2(node.object);
|
|
12060
|
+
if (object.type === AST_NODE_TYPES53.Identifier && namespaces.has(object.name) || isFsLoader(object)) {
|
|
12061
|
+
context.report({ node, messageId: "preferAsyncFs", data: { name } });
|
|
12062
|
+
}
|
|
11761
12063
|
}
|
|
11762
12064
|
};
|
|
11763
12065
|
}
|
|
11764
12066
|
});
|
|
11765
12067
|
|
|
11766
12068
|
// src/rules/prefer-non-nullable-collection.ts
|
|
11767
|
-
import { AST_NODE_TYPES as
|
|
12069
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES54, ASTUtils as ASTUtils16 } from "@typescript-eslint/utils";
|
|
11768
12070
|
var PREFER_NON_NULLABLE_COLLECTION_DOCUMENTATION = {
|
|
11769
12071
|
summary: "Suggest non-null arrays only when local control flow proves the nullish state is equivalent to an empty collection.",
|
|
11770
12072
|
rationale: "A redundant nullish collection state spreads defaults and guards through consumers without carrying information.",
|
|
@@ -11777,36 +12079,36 @@ var PREFER_NON_NULLABLE_COLLECTION_DOCUMENTATION = {
|
|
|
11777
12079
|
]
|
|
11778
12080
|
};
|
|
11779
12081
|
var ARRAY_TYPE_NAMES = /* @__PURE__ */ new Set(["Array", "ReadonlyArray"]);
|
|
11780
|
-
function
|
|
12082
|
+
function propertyName5(node) {
|
|
11781
12083
|
const key = node.key;
|
|
11782
12084
|
if (node.computed) return null;
|
|
11783
|
-
if (key.type ===
|
|
11784
|
-
if (key.type ===
|
|
12085
|
+
if (key.type === AST_NODE_TYPES54.Identifier) return key.name;
|
|
12086
|
+
if (key.type === AST_NODE_TYPES54.Literal && typeof key.value === "string") return key.value;
|
|
11785
12087
|
return null;
|
|
11786
12088
|
}
|
|
11787
12089
|
function isArrayType(node) {
|
|
11788
|
-
if (node.type ===
|
|
11789
|
-
return node.type ===
|
|
12090
|
+
if (node.type === AST_NODE_TYPES54.TSArrayType) return true;
|
|
12091
|
+
return node.type === AST_NODE_TYPES54.TSTypeReference && node.typeName.type === AST_NODE_TYPES54.Identifier && ARRAY_TYPE_NAMES.has(node.typeName.name);
|
|
11790
12092
|
}
|
|
11791
12093
|
function nullableProperty(node) {
|
|
11792
12094
|
if (node.optional) return null;
|
|
11793
|
-
const name =
|
|
12095
|
+
const name = propertyName5(node);
|
|
11794
12096
|
const annotation = node.typeAnnotation?.typeAnnotation;
|
|
11795
|
-
if (name === null || annotation?.type !==
|
|
12097
|
+
if (name === null || annotation?.type !== AST_NODE_TYPES54.TSUnionType) return null;
|
|
11796
12098
|
const concrete = annotation.types.filter(
|
|
11797
|
-
(member) => member.type !==
|
|
12099
|
+
(member) => member.type !== AST_NODE_TYPES54.TSNullKeyword && member.type !== AST_NODE_TYPES54.TSUndefinedKeyword
|
|
11798
12100
|
);
|
|
11799
12101
|
if (concrete.length === 0 || !concrete.every(isArrayType)) return null;
|
|
11800
|
-
const acceptsNull = annotation.types.some((member) => member.type ===
|
|
12102
|
+
const acceptsNull = annotation.types.some((member) => member.type === AST_NODE_TYPES54.TSNullKeyword);
|
|
11801
12103
|
const acceptsUndefined = annotation.types.some(
|
|
11802
|
-
(member) => member.type ===
|
|
12104
|
+
(member) => member.type === AST_NODE_TYPES54.TSUndefinedKeyword
|
|
11803
12105
|
);
|
|
11804
12106
|
if (!acceptsNull && !acceptsUndefined) return null;
|
|
11805
12107
|
return { name, node, acceptsNull, acceptsUndefined };
|
|
11806
12108
|
}
|
|
11807
12109
|
function shapeProperties(members) {
|
|
11808
12110
|
return members.flatMap((member) => {
|
|
11809
|
-
if (member.type !==
|
|
12111
|
+
if (member.type !== AST_NODE_TYPES54.TSPropertySignature) return [];
|
|
11810
12112
|
const property = nullableProperty(member);
|
|
11811
12113
|
return property === null ? [] : [property];
|
|
11812
12114
|
});
|
|
@@ -11814,14 +12116,14 @@ function shapeProperties(members) {
|
|
|
11814
12116
|
function typeIndex(program) {
|
|
11815
12117
|
const index = /* @__PURE__ */ new Map();
|
|
11816
12118
|
for (const statement of program.body) {
|
|
11817
|
-
const exported = statement.type ===
|
|
12119
|
+
const exported = statement.type === AST_NODE_TYPES54.ExportNamedDeclaration;
|
|
11818
12120
|
const declaration = exported ? statement.declaration : statement;
|
|
11819
|
-
if (declaration?.type ===
|
|
12121
|
+
if (declaration?.type === AST_NODE_TYPES54.TSInterfaceDeclaration) {
|
|
11820
12122
|
index.set(declaration.id.name, {
|
|
11821
12123
|
exported,
|
|
11822
12124
|
properties: shapeProperties(declaration.body.body)
|
|
11823
12125
|
});
|
|
11824
|
-
} else if (declaration?.type ===
|
|
12126
|
+
} else if (declaration?.type === AST_NODE_TYPES54.TSTypeAliasDeclaration && declaration.typeAnnotation.type === AST_NODE_TYPES54.TSTypeLiteral) {
|
|
11825
12127
|
index.set(declaration.id.name, {
|
|
11826
12128
|
exported,
|
|
11827
12129
|
properties: shapeProperties(declaration.typeAnnotation.members)
|
|
@@ -11831,42 +12133,42 @@ function typeIndex(program) {
|
|
|
11831
12133
|
return index;
|
|
11832
12134
|
}
|
|
11833
12135
|
function emptyArray(node) {
|
|
11834
|
-
return node.type ===
|
|
12136
|
+
return node.type === AST_NODE_TYPES54.ArrayExpression && node.elements.length === 0;
|
|
11835
12137
|
}
|
|
11836
12138
|
function sameAccess(node, access) {
|
|
11837
12139
|
if (access.kind === "identifier") {
|
|
11838
|
-
return node.type ===
|
|
12140
|
+
return node.type === AST_NODE_TYPES54.Identifier && node.name === access.name;
|
|
11839
12141
|
}
|
|
11840
|
-
return node.type ===
|
|
12142
|
+
return node.type === AST_NODE_TYPES54.MemberExpression && !node.computed && node.object.type === AST_NODE_TYPES54.Identifier && node.object.name === access.object && node.property.type === AST_NODE_TYPES54.Identifier && node.property.name === access.property;
|
|
11841
12143
|
}
|
|
11842
12144
|
function isNullGuard(node, access) {
|
|
11843
|
-
if (node.type ===
|
|
11844
|
-
if (node.type !==
|
|
12145
|
+
if (node.type === AST_NODE_TYPES54.UnaryExpression && node.operator === "!" && (sameAccess(node.argument, access) || optionalMemberLengthOf(node.argument, access))) return true;
|
|
12146
|
+
if (node.type !== AST_NODE_TYPES54.BinaryExpression || !["==", "==="].includes(node.operator)) {
|
|
11845
12147
|
return false;
|
|
11846
12148
|
}
|
|
11847
|
-
const nullish = (value) => value.type ===
|
|
12149
|
+
const nullish = (value) => value.type === AST_NODE_TYPES54.Literal && value.value === null || value.type === AST_NODE_TYPES54.Identifier && value.name === "undefined";
|
|
11848
12150
|
return sameAccess(node.left, access) && nullish(node.right) || sameAccess(node.right, access) && nullish(node.left);
|
|
11849
12151
|
}
|
|
11850
12152
|
function isEmptyGuard(node, access) {
|
|
11851
|
-
if (node.type ===
|
|
11852
|
-
if (node.type !==
|
|
12153
|
+
if (node.type === AST_NODE_TYPES54.UnaryExpression && node.operator === "!" && memberLengthOf(node.argument, access)) return true;
|
|
12154
|
+
if (node.type !== AST_NODE_TYPES54.BinaryExpression || !["==", "===", "<="].includes(node.operator)) {
|
|
11853
12155
|
return false;
|
|
11854
12156
|
}
|
|
11855
|
-
const zero = (value) => value.type ===
|
|
12157
|
+
const zero = (value) => value.type === AST_NODE_TYPES54.Literal && value.value === 0;
|
|
11856
12158
|
return memberLengthOf(node.left, access) && zero(node.right) || memberLengthOf(node.right, access) && zero(node.left);
|
|
11857
12159
|
}
|
|
11858
12160
|
function memberLengthOf(node, access) {
|
|
11859
|
-
const target = node.type ===
|
|
11860
|
-
return target.type ===
|
|
12161
|
+
const target = node.type === AST_NODE_TYPES54.ChainExpression ? node.expression : node;
|
|
12162
|
+
return target.type === AST_NODE_TYPES54.MemberExpression && !target.computed && target.property.type === AST_NODE_TYPES54.Identifier && target.property.name === "length" && sameAccess(target.object, access);
|
|
11861
12163
|
}
|
|
11862
12164
|
function optionalMemberLengthOf(node, access) {
|
|
11863
|
-
return node.type ===
|
|
12165
|
+
return node.type === AST_NODE_TYPES54.ChainExpression && node.expression.type === AST_NODE_TYPES54.MemberExpression && node.expression.optional && memberLengthOf(node, access);
|
|
11864
12166
|
}
|
|
11865
12167
|
function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
|
|
11866
|
-
if (fn.body.type !==
|
|
12168
|
+
if (fn.body.type !== AST_NODE_TYPES54.BlockStatement) return false;
|
|
11867
12169
|
const first = fn.body.body[0];
|
|
11868
|
-
if (first?.type !==
|
|
11869
|
-
const terminating = first.consequent.type ===
|
|
12170
|
+
if (first?.type !== AST_NODE_TYPES54.IfStatement) return false;
|
|
12171
|
+
const terminating = first.consequent.type === AST_NODE_TYPES54.ReturnStatement || first.consequent.type === AST_NODE_TYPES54.ThrowStatement || first.consequent.type === AST_NODE_TYPES54.BlockStatement && first.consequent.body.length === 1 && (first.consequent.body[0]?.type === AST_NODE_TYPES54.ReturnStatement || first.consequent.body[0]?.type === AST_NODE_TYPES54.ThrowStatement);
|
|
11870
12172
|
if (!terminating) return false;
|
|
11871
12173
|
if (contains(first.consequent, visitorKeys, (node) => sameAccess(node, access))) return false;
|
|
11872
12174
|
return contains(first.test, visitorKeys, (node) => isNullGuard(node, access)) && contains(first.test, visitorKeys, (node) => isEmptyGuard(node, access));
|
|
@@ -11884,29 +12186,29 @@ function contains(node, visitorKeys, predicate) {
|
|
|
11884
12186
|
function belongsToFunction(node, fn) {
|
|
11885
12187
|
let current = node;
|
|
11886
12188
|
while (current !== void 0 && current !== fn) {
|
|
11887
|
-
if (current !== node && (current.type ===
|
|
12189
|
+
if (current !== node && (current.type === AST_NODE_TYPES54.ArrowFunctionExpression || current.type === AST_NODE_TYPES54.FunctionDeclaration || current.type === AST_NODE_TYPES54.FunctionExpression)) return false;
|
|
11888
12190
|
current = current.parent;
|
|
11889
12191
|
}
|
|
11890
12192
|
return current === fn;
|
|
11891
12193
|
}
|
|
11892
12194
|
function directlyCoalesced(node) {
|
|
11893
12195
|
const parent = node.parent;
|
|
11894
|
-
return parent?.type ===
|
|
12196
|
+
return parent?.type === AST_NODE_TYPES54.LogicalExpression && parent.left === node && (parent.operator === "??" || parent.operator === "||") && emptyArray(parent.right);
|
|
11895
12197
|
}
|
|
11896
12198
|
function identifierIsOnlyCoalesced(context, binding, fn) {
|
|
11897
|
-
const variable =
|
|
12199
|
+
const variable = ASTUtils16.findVariable(context.sourceCode.getScope(binding), binding.name);
|
|
11898
12200
|
if (variable === null || variable.references.length === 0) return false;
|
|
11899
12201
|
return variable.references.every(
|
|
11900
12202
|
(reference) => belongsToFunction(reference.identifier, fn) && directlyCoalesced(reference.identifier)
|
|
11901
12203
|
);
|
|
11902
12204
|
}
|
|
11903
12205
|
function memberIsOnlyCoalesced(context, object, property, fn) {
|
|
11904
|
-
const variable =
|
|
12206
|
+
const variable = ASTUtils16.findVariable(context.sourceCode.getScope(object), object.name);
|
|
11905
12207
|
if (variable === null) return false;
|
|
11906
12208
|
const accesses = variable.references.flatMap((reference) => {
|
|
11907
12209
|
if (!belongsToFunction(reference.identifier, fn)) return [null];
|
|
11908
12210
|
const parent = reference.identifier.parent;
|
|
11909
|
-
if (parent?.type ===
|
|
12211
|
+
if (parent?.type === AST_NODE_TYPES54.MemberExpression && !parent.computed && parent.object === reference.identifier && parent.property.type === AST_NODE_TYPES54.Identifier && parent.property.name === property) return [parent];
|
|
11910
12212
|
return [];
|
|
11911
12213
|
});
|
|
11912
12214
|
return accesses.length > 0 && accesses.every((access) => access !== null && directlyCoalesced(access));
|
|
@@ -11932,8 +12234,8 @@ var prefer_non_nullable_collection_default = createRule({
|
|
|
11932
12234
|
let shapes = /* @__PURE__ */ new Map();
|
|
11933
12235
|
const evidence = /* @__PURE__ */ new Map();
|
|
11934
12236
|
function propertiesFor(annotation) {
|
|
11935
|
-
if (annotation?.type ===
|
|
11936
|
-
if (annotation?.type ===
|
|
12237
|
+
if (annotation?.type === AST_NODE_TYPES54.TSTypeLiteral) return shapeProperties(annotation.members);
|
|
12238
|
+
if (annotation?.type === AST_NODE_TYPES54.TSTypeReference && annotation.typeName.type === AST_NODE_TYPES54.Identifier) {
|
|
11937
12239
|
const shape = shapes.get(annotation.typeName.name);
|
|
11938
12240
|
return shape?.exported === false ? shape.properties : [];
|
|
11939
12241
|
}
|
|
@@ -11946,21 +12248,21 @@ var prefer_non_nullable_collection_default = createRule({
|
|
|
11946
12248
|
}
|
|
11947
12249
|
function checkFunction(fn) {
|
|
11948
12250
|
for (const rawParameter of fn.params) {
|
|
11949
|
-
const parameter = rawParameter.type ===
|
|
11950
|
-
if (parameter.type ===
|
|
12251
|
+
const parameter = rawParameter.type === AST_NODE_TYPES54.AssignmentPattern ? rawParameter.left : rawParameter;
|
|
12252
|
+
if (parameter.type === AST_NODE_TYPES54.ObjectPattern) {
|
|
11951
12253
|
const properties2 = propertiesFor(parameter.typeAnnotation?.typeAnnotation);
|
|
11952
12254
|
for (const property of properties2) {
|
|
11953
12255
|
const bindingProperty = parameter.properties.find(
|
|
11954
|
-
(entry) => entry.type ===
|
|
12256
|
+
(entry) => entry.type === AST_NODE_TYPES54.Property && !entry.computed && entry.key.type === AST_NODE_TYPES54.Identifier && entry.key.name === property.name
|
|
11955
12257
|
);
|
|
11956
12258
|
if (bindingProperty === void 0) continue;
|
|
11957
12259
|
const value = bindingProperty.value;
|
|
11958
|
-
const binding = value.type ===
|
|
11959
|
-
if (binding.type !==
|
|
12260
|
+
const binding = value.type === AST_NODE_TYPES54.AssignmentPattern ? value.left : value;
|
|
12261
|
+
if (binding.type !== AST_NODE_TYPES54.Identifier) {
|
|
11960
12262
|
record(property, false);
|
|
11961
12263
|
continue;
|
|
11962
12264
|
}
|
|
11963
|
-
if (value.type ===
|
|
12265
|
+
if (value.type === AST_NODE_TYPES54.AssignmentPattern && emptyArray(value.right) && property.acceptsUndefined && !property.acceptsNull) {
|
|
11964
12266
|
record(property, true);
|
|
11965
12267
|
continue;
|
|
11966
12268
|
}
|
|
@@ -11972,7 +12274,7 @@ var prefer_non_nullable_collection_default = createRule({
|
|
|
11972
12274
|
}
|
|
11973
12275
|
continue;
|
|
11974
12276
|
}
|
|
11975
|
-
if (parameter.type !==
|
|
12277
|
+
if (parameter.type !== AST_NODE_TYPES54.Identifier) continue;
|
|
11976
12278
|
const properties = propertiesFor(parameter.typeAnnotation?.typeAnnotation);
|
|
11977
12279
|
for (const property of properties) {
|
|
11978
12280
|
const access = {
|
|
@@ -12000,7 +12302,7 @@ var prefer_non_nullable_collection_default = createRule({
|
|
|
12000
12302
|
context.report({
|
|
12001
12303
|
node,
|
|
12002
12304
|
messageId: "preferNonNullableCollection",
|
|
12003
|
-
data: { name:
|
|
12305
|
+
data: { name: propertyName5(node) ?? "collection" }
|
|
12004
12306
|
});
|
|
12005
12307
|
}
|
|
12006
12308
|
}
|
|
@@ -12010,8 +12312,8 @@ var prefer_non_nullable_collection_default = createRule({
|
|
|
12010
12312
|
|
|
12011
12313
|
// src/rules/prefer-nullish-filter-predicate.ts
|
|
12012
12314
|
import {
|
|
12013
|
-
AST_NODE_TYPES as
|
|
12014
|
-
ASTUtils as
|
|
12315
|
+
AST_NODE_TYPES as AST_NODE_TYPES55,
|
|
12316
|
+
ASTUtils as ASTUtils17,
|
|
12015
12317
|
ESLintUtils as ESLintUtils5
|
|
12016
12318
|
} from "@typescript-eslint/utils";
|
|
12017
12319
|
import ts3 from "typescript";
|
|
@@ -12057,7 +12359,7 @@ var PREFER_NULLISH_FILTER_PREDICATE_DOCUMENTATION = {
|
|
|
12057
12359
|
]
|
|
12058
12360
|
};
|
|
12059
12361
|
function isUnshadowedBoolean(node, context) {
|
|
12060
|
-
const variable =
|
|
12362
|
+
const variable = ASTUtils17.findVariable(context.sourceCode.getScope(node), node.name);
|
|
12061
12363
|
return variable === null || variable.defs.length === 0;
|
|
12062
12364
|
}
|
|
12063
12365
|
function isBuiltinArrayFilter(node, services) {
|
|
@@ -12116,7 +12418,7 @@ function isProvablyTruthy(type, checker) {
|
|
|
12116
12418
|
}
|
|
12117
12419
|
function availableParameterName(node, context) {
|
|
12118
12420
|
for (const name of ["value", "item", "element", "candidate"]) {
|
|
12119
|
-
if (
|
|
12421
|
+
if (ASTUtils17.findVariable(context.sourceCode.getScope(node), name) === null) return name;
|
|
12120
12422
|
}
|
|
12121
12423
|
return null;
|
|
12122
12424
|
}
|
|
@@ -12147,7 +12449,7 @@ var prefer_nullish_filter_predicate_default = createRule({
|
|
|
12147
12449
|
CallExpression(node) {
|
|
12148
12450
|
const callee = node.callee;
|
|
12149
12451
|
const callback = node.arguments[0];
|
|
12150
|
-
if (node.arguments.length !== 1 || callback?.type !==
|
|
12452
|
+
if (node.arguments.length !== 1 || callback?.type !== AST_NODE_TYPES55.Identifier || callback.name !== "Boolean" || callee.type !== AST_NODE_TYPES55.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES55.Identifier || callee.property.name !== "filter" || !isUnshadowedBoolean(callback, context) || !isBuiltinArrayFilter(callee, services)) return;
|
|
12151
12453
|
const elementType = arrayElementType(callee.object, services);
|
|
12152
12454
|
const checker = services.program.getTypeChecker();
|
|
12153
12455
|
if (elementType === null || !isNullishPlusTruthy(elementType, checker)) return;
|
|
@@ -12170,9 +12472,9 @@ var prefer_nullish_filter_predicate_default = createRule({
|
|
|
12170
12472
|
|
|
12171
12473
|
// src/rules/prefer-await-in-async-return.ts
|
|
12172
12474
|
import {
|
|
12173
|
-
ASTUtils as
|
|
12475
|
+
ASTUtils as ASTUtils18,
|
|
12174
12476
|
ESLintUtils as ESLintUtils6,
|
|
12175
|
-
AST_NODE_TYPES as
|
|
12477
|
+
AST_NODE_TYPES as AST_NODE_TYPES56
|
|
12176
12478
|
} from "@typescript-eslint/utils";
|
|
12177
12479
|
import * as ts4 from "typescript";
|
|
12178
12480
|
var PREFER_AWAIT_IN_ASYNC_RETURN_DOCUMENTATION = {
|
|
@@ -12215,10 +12517,10 @@ var PREFER_AWAIT_IN_ASYNC_RETURN_DOCUMENTATION = {
|
|
|
12215
12517
|
};
|
|
12216
12518
|
function directAsyncReturnOwner(node) {
|
|
12217
12519
|
const parent = node.parent;
|
|
12218
|
-
if (parent.type ===
|
|
12520
|
+
if (parent.type === AST_NODE_TYPES56.ArrowFunctionExpression && parent.body === node) {
|
|
12219
12521
|
return parent.async && !parent.generator ? parent : null;
|
|
12220
12522
|
}
|
|
12221
|
-
if (parent.type !==
|
|
12523
|
+
if (parent.type !== AST_NODE_TYPES56.ReturnStatement || parent.argument !== node) {
|
|
12222
12524
|
return null;
|
|
12223
12525
|
}
|
|
12224
12526
|
let owner = parent.parent;
|
|
@@ -12228,15 +12530,15 @@ function directAsyncReturnOwner(node) {
|
|
|
12228
12530
|
return owner !== void 0 && owner.async && !owner.generator ? owner : null;
|
|
12229
12531
|
}
|
|
12230
12532
|
function isRuntimeFunction(node) {
|
|
12231
|
-
return node.type ===
|
|
12533
|
+
return node.type === AST_NODE_TYPES56.ArrowFunctionExpression || node.type === AST_NODE_TYPES56.FunctionDeclaration || node.type === AST_NODE_TYPES56.FunctionExpression;
|
|
12232
12534
|
}
|
|
12233
12535
|
function promiseThenReceiver(node) {
|
|
12234
12536
|
const callee = node.callee;
|
|
12235
|
-
if (callee.type !==
|
|
12537
|
+
if (callee.type !== AST_NODE_TYPES56.MemberExpression || callee.computed || callee.optional || callee.property.type !== AST_NODE_TYPES56.Identifier || callee.property.name !== "then" || node.optional || node.arguments.length !== 1) {
|
|
12236
12538
|
return null;
|
|
12237
12539
|
}
|
|
12238
12540
|
const callback = node.arguments[0];
|
|
12239
|
-
if (callback === void 0 || callback.type !==
|
|
12541
|
+
if (callback === void 0 || callback.type !== AST_NODE_TYPES56.ArrowFunctionExpression && callback.type !== AST_NODE_TYPES56.FunctionExpression) {
|
|
12240
12542
|
return null;
|
|
12241
12543
|
}
|
|
12242
12544
|
return callee.object;
|
|
@@ -12284,25 +12586,25 @@ var prefer_await_in_async_return_default = createRule({
|
|
|
12284
12586
|
if (services === null) return {};
|
|
12285
12587
|
const frameworkLoaders = /* @__PURE__ */ new Set();
|
|
12286
12588
|
const rememberFrameworkLoader = (identifier) => {
|
|
12287
|
-
const variable =
|
|
12589
|
+
const variable = ASTUtils18.findVariable(context.sourceCode.getScope(identifier), identifier.name);
|
|
12288
12590
|
if (variable !== null) frameworkLoaders.add(variable);
|
|
12289
12591
|
};
|
|
12290
12592
|
const isFrameworkLoaderCallback = (owner) => {
|
|
12291
12593
|
const parent = owner.parent;
|
|
12292
|
-
if (parent.type !==
|
|
12293
|
-
const variable =
|
|
12594
|
+
if (parent.type !== AST_NODE_TYPES56.CallExpression || parent.arguments[0] !== owner || parent.callee.type !== AST_NODE_TYPES56.Identifier) return false;
|
|
12595
|
+
const variable = ASTUtils18.findVariable(context.sourceCode.getScope(parent.callee), parent.callee.name);
|
|
12294
12596
|
return variable !== null && frameworkLoaders.has(variable);
|
|
12295
12597
|
};
|
|
12296
12598
|
return {
|
|
12297
12599
|
ImportDeclaration(node) {
|
|
12298
12600
|
if (node.source.value === "react") {
|
|
12299
12601
|
for (const specifier of node.specifiers) {
|
|
12300
|
-
if (specifier.type ===
|
|
12602
|
+
if (specifier.type === AST_NODE_TYPES56.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES56.Identifier ? specifier.imported.name : specifier.imported.value) === "lazy") rememberFrameworkLoader(specifier.local);
|
|
12301
12603
|
}
|
|
12302
12604
|
}
|
|
12303
12605
|
if (node.source.value === "next/dynamic") {
|
|
12304
12606
|
for (const specifier of node.specifiers) {
|
|
12305
|
-
if (specifier.type ===
|
|
12607
|
+
if (specifier.type === AST_NODE_TYPES56.ImportDefaultSpecifier) rememberFrameworkLoader(specifier.local);
|
|
12306
12608
|
}
|
|
12307
12609
|
}
|
|
12308
12610
|
},
|
|
@@ -12320,7 +12622,7 @@ var prefer_await_in_async_return_default = createRule({
|
|
|
12320
12622
|
});
|
|
12321
12623
|
|
|
12322
12624
|
// src/rules/prefer-schema-for-api-payload.ts
|
|
12323
|
-
import { AST_NODE_TYPES as
|
|
12625
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES57 } from "@typescript-eslint/utils";
|
|
12324
12626
|
var PREFER_SCHEMA_FOR_API_PAYLOAD_DOCUMENTATION = {
|
|
12325
12627
|
summary: "Require Zod (or similar) schema validation on `response.json()` / `JSON.parse()` results before property access.",
|
|
12326
12628
|
rationale: "External JSON is untrusted at runtime even when its expected TypeScript shape is known statically.",
|
|
@@ -12332,12 +12634,12 @@ var PREFER_SCHEMA_FOR_API_PAYLOAD_DOCUMENTATION = {
|
|
|
12332
12634
|
{ id: "unvalidated-payload", title: "Do not trust response JSON directly", outcome: "match", files: [{ path: "src/client.ts", source: "async function load(response) { const body = await response.json(); return body.id; }" }], focusPath: "src/client.ts", expectedCount: 1, public: true }
|
|
12333
12635
|
]
|
|
12334
12636
|
};
|
|
12335
|
-
var
|
|
12637
|
+
var unwrap5 = (node) => {
|
|
12336
12638
|
let current = node;
|
|
12337
12639
|
while (current !== null && current !== void 0) {
|
|
12338
|
-
if (current.type ===
|
|
12640
|
+
if (current.type === AST_NODE_TYPES57.TSAsExpression || current.type === AST_NODE_TYPES57.TSTypeAssertion || current.type === AST_NODE_TYPES57.TSNonNullExpression || current.type === AST_NODE_TYPES57.TSSatisfiesExpression) {
|
|
12339
12641
|
current = current.expression;
|
|
12340
|
-
} else if (current.type ===
|
|
12642
|
+
} else if (current.type === AST_NODE_TYPES57.ChainExpression) {
|
|
12341
12643
|
current = current.expression;
|
|
12342
12644
|
} else {
|
|
12343
12645
|
break;
|
|
@@ -12351,24 +12653,24 @@ var PROMISE_CHAIN_METHODS = /* @__PURE__ */ new Set([
|
|
|
12351
12653
|
"finally"
|
|
12352
12654
|
]);
|
|
12353
12655
|
var isSchemaParseReference = (node) => {
|
|
12354
|
-
const inner =
|
|
12355
|
-
return inner !== null && inner.type ===
|
|
12656
|
+
const inner = unwrap5(node);
|
|
12657
|
+
return inner !== null && inner.type === AST_NODE_TYPES57.MemberExpression && !inner.computed && inner.property.type === AST_NODE_TYPES57.Identifier && (inner.property.name === "parse" || inner.property.name === "safeParse");
|
|
12356
12658
|
};
|
|
12357
12659
|
var isRawPayloadSource = (node, isKnownLocalText) => {
|
|
12358
|
-
let current =
|
|
12660
|
+
let current = unwrap5(node);
|
|
12359
12661
|
if (current === null) return false;
|
|
12360
|
-
if (current.type ===
|
|
12361
|
-
current =
|
|
12662
|
+
if (current.type === AST_NODE_TYPES57.AwaitExpression) {
|
|
12663
|
+
current = unwrap5(current.argument);
|
|
12362
12664
|
}
|
|
12363
|
-
if (current === null || current.type !==
|
|
12665
|
+
if (current === null || current.type !== AST_NODE_TYPES57.CallExpression) {
|
|
12364
12666
|
return false;
|
|
12365
12667
|
}
|
|
12366
|
-
const callee =
|
|
12367
|
-
if (callee === null || callee.type !==
|
|
12668
|
+
const callee = unwrap5(current.callee);
|
|
12669
|
+
if (callee === null || callee.type !== AST_NODE_TYPES57.MemberExpression) {
|
|
12368
12670
|
return false;
|
|
12369
12671
|
}
|
|
12370
|
-
const property =
|
|
12371
|
-
if (property === null || property.type !==
|
|
12672
|
+
const property = unwrap5(callee.property);
|
|
12673
|
+
if (property === null || property.type !== AST_NODE_TYPES57.Identifier) {
|
|
12372
12674
|
return false;
|
|
12373
12675
|
}
|
|
12374
12676
|
if (property.name === "json") {
|
|
@@ -12377,18 +12679,18 @@ var isRawPayloadSource = (node, isKnownLocalText) => {
|
|
|
12377
12679
|
if (PROMISE_CHAIN_METHODS.has(property.name)) {
|
|
12378
12680
|
return !current.arguments.some(isSchemaParseReference) && isRawPayloadSource(callee.object);
|
|
12379
12681
|
}
|
|
12380
|
-
const object =
|
|
12381
|
-
return property.name === "parse" && object !== null && object.type ===
|
|
12682
|
+
const object = unwrap5(callee.object);
|
|
12683
|
+
return property.name === "parse" && object !== null && object.type === AST_NODE_TYPES57.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]) && isKnownLocalText?.(current.arguments[0]) !== true;
|
|
12382
12684
|
};
|
|
12383
12685
|
var FILE_READ_RE = /^(readFile|readFileSync|readJson|readJsonSync|readJSON)$/;
|
|
12384
12686
|
var isDirectLocalFileRead = (node) => {
|
|
12385
|
-
let current =
|
|
12386
|
-
if (current?.type ===
|
|
12387
|
-
current =
|
|
12687
|
+
let current = unwrap5(node);
|
|
12688
|
+
if (current?.type === AST_NODE_TYPES57.AwaitExpression) {
|
|
12689
|
+
current = unwrap5(current.argument);
|
|
12388
12690
|
}
|
|
12389
|
-
if (current?.type !==
|
|
12390
|
-
const callee =
|
|
12391
|
-
const name = callee?.type ===
|
|
12691
|
+
if (current?.type !== AST_NODE_TYPES57.CallExpression) return false;
|
|
12692
|
+
const callee = unwrap5(current.callee);
|
|
12693
|
+
const name = callee?.type === AST_NODE_TYPES57.Identifier ? callee.name : callee?.type === AST_NODE_TYPES57.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES57.Identifier ? callee.property.name : null;
|
|
12392
12694
|
return name !== null && FILE_READ_RE.test(name);
|
|
12393
12695
|
};
|
|
12394
12696
|
var isLocalFileRead = (node) => {
|
|
@@ -12415,15 +12717,15 @@ var isLocalFileRead = (node) => {
|
|
|
12415
12717
|
var ASSERTION_CALLEE_RE = /^(expect|assert|should|invariant)$/;
|
|
12416
12718
|
var isInsideAssertion = (node) => {
|
|
12417
12719
|
for (let current = node.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
12418
|
-
if (current.type !==
|
|
12720
|
+
if (current.type !== AST_NODE_TYPES57.CallExpression) continue;
|
|
12419
12721
|
let callee = current.callee;
|
|
12420
|
-
while (callee.type ===
|
|
12722
|
+
while (callee.type === AST_NODE_TYPES57.MemberExpression) {
|
|
12421
12723
|
callee = callee.object;
|
|
12422
12724
|
}
|
|
12423
|
-
if (callee.type ===
|
|
12725
|
+
if (callee.type === AST_NODE_TYPES57.CallExpression) {
|
|
12424
12726
|
callee = callee.callee;
|
|
12425
12727
|
}
|
|
12426
|
-
if (callee.type ===
|
|
12728
|
+
if (callee.type === AST_NODE_TYPES57.Identifier && ASSERTION_CALLEE_RE.test(callee.name)) {
|
|
12427
12729
|
return true;
|
|
12428
12730
|
}
|
|
12429
12731
|
}
|
|
@@ -12442,22 +12744,22 @@ var GUARD_NAME_RE = /^(?:is|validate|parse|assert|decode|coerce)[A-Z]/;
|
|
|
12442
12744
|
var isValidationRead = (node) => {
|
|
12443
12745
|
let current = node;
|
|
12444
12746
|
let parent = current.parent;
|
|
12445
|
-
while (parent !== null && parent !== void 0 && (parent.type ===
|
|
12747
|
+
while (parent !== null && parent !== void 0 && (parent.type === AST_NODE_TYPES57.TSAsExpression || parent.type === AST_NODE_TYPES57.TSTypeAssertion || parent.type === AST_NODE_TYPES57.TSNonNullExpression || parent.type === AST_NODE_TYPES57.TSSatisfiesExpression || parent.type === AST_NODE_TYPES57.ChainExpression)) {
|
|
12446
12748
|
current = parent;
|
|
12447
12749
|
parent = parent.parent;
|
|
12448
12750
|
}
|
|
12449
12751
|
if (parent === null || parent === void 0) return false;
|
|
12450
|
-
if (parent.type ===
|
|
12752
|
+
if (parent.type === AST_NODE_TYPES57.UnaryExpression && parent.operator === "typeof" && parent.argument === current) {
|
|
12451
12753
|
return true;
|
|
12452
12754
|
}
|
|
12453
|
-
if (parent.type !==
|
|
12755
|
+
if (parent.type !== AST_NODE_TYPES57.CallExpression || !parent.arguments.some((arg) => arg === current)) {
|
|
12454
12756
|
return false;
|
|
12455
12757
|
}
|
|
12456
12758
|
const callee = parent.callee;
|
|
12457
|
-
if (callee.type ===
|
|
12759
|
+
if (callee.type === AST_NODE_TYPES57.MemberExpression && !callee.computed && callee.object.type === AST_NODE_TYPES57.Identifier && callee.object.name === "Array" && callee.property.type === AST_NODE_TYPES57.Identifier && callee.property.name === "isArray") {
|
|
12458
12760
|
return parent.arguments.length === 1;
|
|
12459
12761
|
}
|
|
12460
|
-
return callee.type ===
|
|
12762
|
+
return callee.type === AST_NODE_TYPES57.Identifier && GUARD_NAME_RE.test(callee.name);
|
|
12461
12763
|
};
|
|
12462
12764
|
var PRIMITIVE_TYPEOF_RESULTS = /* @__PURE__ */ new Set([
|
|
12463
12765
|
"bigint",
|
|
@@ -12468,13 +12770,13 @@ var PRIMITIVE_TYPEOF_RESULTS = /* @__PURE__ */ new Set([
|
|
|
12468
12770
|
"undefined"
|
|
12469
12771
|
]);
|
|
12470
12772
|
var bindingValidationPolarity = (test, bindingName) => {
|
|
12471
|
-
if (test.type ===
|
|
12773
|
+
if (test.type === AST_NODE_TYPES57.UnaryExpression && test.operator === "!") {
|
|
12472
12774
|
const inner = bindingValidationPolarity(test.argument, bindingName);
|
|
12473
12775
|
return inner === "valid-when-true" ? "valid-when-false" : inner === "valid-when-false" ? "valid-when-true" : null;
|
|
12474
12776
|
}
|
|
12475
|
-
if (test.type ===
|
|
12476
|
-
const typeofName = (node) => node.type ===
|
|
12477
|
-
const literalType = (node) => node.type ===
|
|
12777
|
+
if (test.type === AST_NODE_TYPES57.BinaryExpression) {
|
|
12778
|
+
const typeofName = (node) => node.type === AST_NODE_TYPES57.UnaryExpression && node.operator === "typeof" && node.argument.type === AST_NODE_TYPES57.Identifier ? node.argument.name : null;
|
|
12779
|
+
const literalType = (node) => node.type === AST_NODE_TYPES57.Literal && typeof node.value === "string" && PRIMITIVE_TYPEOF_RESULTS.has(node.value) ? node.value : null;
|
|
12478
12780
|
const matches = typeofName(test.left) === bindingName && literalType(test.right) !== null || typeofName(test.right) === bindingName && literalType(test.left) !== null;
|
|
12479
12781
|
if (!matches) return null;
|
|
12480
12782
|
if (test.operator === "===" || test.operator === "==") {
|
|
@@ -12482,9 +12784,9 @@ var bindingValidationPolarity = (test, bindingName) => {
|
|
|
12482
12784
|
}
|
|
12483
12785
|
return test.operator === "!==" || test.operator === "!=" ? "valid-when-false" : null;
|
|
12484
12786
|
}
|
|
12485
|
-
return test.type ===
|
|
12787
|
+
return test.type === AST_NODE_TYPES57.CallExpression && test.arguments.length === 1 && test.arguments[0]?.type === AST_NODE_TYPES57.Identifier && test.arguments[0].name === bindingName && test.callee.type === AST_NODE_TYPES57.MemberExpression && !test.callee.computed && test.callee.object.type === AST_NODE_TYPES57.Identifier && test.callee.object.name === "Array" && test.callee.property.type === AST_NODE_TYPES57.Identifier && test.callee.property.name === "isArray" ? "valid-when-true" : null;
|
|
12486
12788
|
};
|
|
12487
|
-
var plainMemberAccess = (node) => node.type ===
|
|
12789
|
+
var plainMemberAccess = (node) => node.type === AST_NODE_TYPES57.MemberExpression && !node.computed && node.object.type === AST_NODE_TYPES57.Identifier && node.property.type === AST_NODE_TYPES57.Identifier ? { object: node.object.name, property: node.property.name } : null;
|
|
12488
12790
|
var isSamePlainMember = (node, access) => {
|
|
12489
12791
|
const candidate2 = plainMemberAccess(node);
|
|
12490
12792
|
return candidate2 !== null && candidate2.object === access.object && candidate2.property === access.property;
|
|
@@ -12492,19 +12794,19 @@ var isSamePlainMember = (node, access) => {
|
|
|
12492
12794
|
var nodeWithin2 = (node, container) => node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
|
|
12493
12795
|
var isUseWithinValidatedBranch = (node, bindingName) => {
|
|
12494
12796
|
for (let current = node.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
12495
|
-
if (current.type ===
|
|
12797
|
+
if (current.type === AST_NODE_TYPES57.ConditionalExpression) {
|
|
12496
12798
|
const polarity = bindingValidationPolarity(current.test, bindingName);
|
|
12497
12799
|
if (polarity === "valid-when-true" && nodeWithin2(node, current.consequent) || polarity === "valid-when-false" && nodeWithin2(node, current.alternate)) {
|
|
12498
12800
|
return true;
|
|
12499
12801
|
}
|
|
12500
12802
|
}
|
|
12501
|
-
if (current.type ===
|
|
12803
|
+
if (current.type === AST_NODE_TYPES57.IfStatement) {
|
|
12502
12804
|
const polarity = bindingValidationPolarity(current.test, bindingName);
|
|
12503
12805
|
if (polarity === "valid-when-true" && nodeWithin2(node, current.consequent) || polarity === "valid-when-false" && current.alternate !== null && nodeWithin2(node, current.alternate)) {
|
|
12504
12806
|
return true;
|
|
12505
12807
|
}
|
|
12506
12808
|
}
|
|
12507
|
-
if (current.type ===
|
|
12809
|
+
if (current.type === AST_NODE_TYPES57.FunctionDeclaration || current.type === AST_NODE_TYPES57.FunctionExpression || current.type === AST_NODE_TYPES57.ArrowFunctionExpression) {
|
|
12508
12810
|
return false;
|
|
12509
12811
|
}
|
|
12510
12812
|
}
|
|
@@ -12512,32 +12814,32 @@ var isUseWithinValidatedBranch = (node, bindingName) => {
|
|
|
12512
12814
|
};
|
|
12513
12815
|
var isMemberUseWithinValidatedBranch = (node, access) => {
|
|
12514
12816
|
for (let current = node.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
12515
|
-
if (current.type ===
|
|
12817
|
+
if (current.type === AST_NODE_TYPES57.ConditionalExpression) {
|
|
12516
12818
|
const polarity = memberValidationPolarity(current.test, access);
|
|
12517
12819
|
if (polarity === "valid-when-true" && nodeWithin2(node, current.consequent) || polarity === "valid-when-false" && nodeWithin2(node, current.alternate)) {
|
|
12518
12820
|
return true;
|
|
12519
12821
|
}
|
|
12520
12822
|
}
|
|
12521
|
-
if (current.type ===
|
|
12823
|
+
if (current.type === AST_NODE_TYPES57.IfStatement) {
|
|
12522
12824
|
const polarity = memberValidationPolarity(current.test, access);
|
|
12523
12825
|
if (polarity === "valid-when-true" && nodeWithin2(node, current.consequent) || polarity === "valid-when-false" && current.alternate !== null && nodeWithin2(node, current.alternate)) {
|
|
12524
12826
|
return true;
|
|
12525
12827
|
}
|
|
12526
12828
|
}
|
|
12527
|
-
if (current.type ===
|
|
12829
|
+
if (current.type === AST_NODE_TYPES57.FunctionDeclaration || current.type === AST_NODE_TYPES57.FunctionExpression || current.type === AST_NODE_TYPES57.ArrowFunctionExpression) {
|
|
12528
12830
|
return false;
|
|
12529
12831
|
}
|
|
12530
12832
|
}
|
|
12531
12833
|
return false;
|
|
12532
12834
|
};
|
|
12533
12835
|
var memberValidationPolarity = (test, access) => {
|
|
12534
|
-
if (test.type ===
|
|
12836
|
+
if (test.type === AST_NODE_TYPES57.UnaryExpression && test.operator === "!") {
|
|
12535
12837
|
const inner = memberValidationPolarity(test.argument, access);
|
|
12536
12838
|
return inner === "valid-when-true" ? "valid-when-false" : inner === "valid-when-false" ? "valid-when-true" : null;
|
|
12537
12839
|
}
|
|
12538
|
-
if (test.type ===
|
|
12539
|
-
const isMatchingTypeof = (node) => node.type ===
|
|
12540
|
-
const isPrimitiveType = (node) => node.type ===
|
|
12840
|
+
if (test.type === AST_NODE_TYPES57.BinaryExpression) {
|
|
12841
|
+
const isMatchingTypeof = (node) => node.type === AST_NODE_TYPES57.UnaryExpression && node.operator === "typeof" && isSamePlainMember(node.argument, access);
|
|
12842
|
+
const isPrimitiveType = (node) => node.type === AST_NODE_TYPES57.Literal && typeof node.value === "string" && PRIMITIVE_TYPEOF_RESULTS.has(node.value);
|
|
12541
12843
|
if (!(isMatchingTypeof(test.left) && isPrimitiveType(test.right) || isMatchingTypeof(test.right) && isPrimitiveType(test.left))) {
|
|
12542
12844
|
return null;
|
|
12543
12845
|
}
|
|
@@ -12546,15 +12848,15 @@ var memberValidationPolarity = (test, access) => {
|
|
|
12546
12848
|
}
|
|
12547
12849
|
return test.operator === "!==" || test.operator === "!=" ? "valid-when-false" : null;
|
|
12548
12850
|
}
|
|
12549
|
-
return test.type ===
|
|
12851
|
+
return test.type === AST_NODE_TYPES57.CallExpression && test.arguments.length === 1 && test.arguments[0] !== void 0 && test.arguments[0].type !== AST_NODE_TYPES57.SpreadElement && isSamePlainMember(test.arguments[0], access) && test.callee.type === AST_NODE_TYPES57.MemberExpression && !test.callee.computed && test.callee.object.type === AST_NODE_TYPES57.Identifier && test.callee.object.name === "Array" && test.callee.property.type === AST_NODE_TYPES57.Identifier && test.callee.property.name === "isArray" ? "valid-when-true" : null;
|
|
12550
12852
|
};
|
|
12551
12853
|
var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
12552
12854
|
const isValidationReference = (identifier) => {
|
|
12553
12855
|
for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
12554
|
-
if ((current.type ===
|
|
12856
|
+
if ((current.type === AST_NODE_TYPES57.BinaryExpression || current.type === AST_NODE_TYPES57.CallExpression || current.type === AST_NODE_TYPES57.UnaryExpression) && bindingValidationPolarity(current, identifier.name) !== null) {
|
|
12555
12857
|
return true;
|
|
12556
12858
|
}
|
|
12557
|
-
if (current.type !==
|
|
12859
|
+
if (current.type !== AST_NODE_TYPES57.UnaryExpression && current.type !== AST_NODE_TYPES57.MemberExpression && current.type !== AST_NODE_TYPES57.CallExpression) {
|
|
12558
12860
|
return false;
|
|
12559
12861
|
}
|
|
12560
12862
|
}
|
|
@@ -12562,7 +12864,7 @@ var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
|
12562
12864
|
};
|
|
12563
12865
|
const isGuardedUse = (identifier) => {
|
|
12564
12866
|
for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
12565
|
-
if (current.type ===
|
|
12867
|
+
if (current.type === AST_NODE_TYPES57.ConditionalExpression) {
|
|
12566
12868
|
const polarity = bindingValidationPolarity(current.test, identifier.name);
|
|
12567
12869
|
if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
|
|
12568
12870
|
return true;
|
|
@@ -12571,7 +12873,7 @@ var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
|
12571
12873
|
return true;
|
|
12572
12874
|
}
|
|
12573
12875
|
}
|
|
12574
|
-
if (current.type ===
|
|
12876
|
+
if (current.type === AST_NODE_TYPES57.IfStatement) {
|
|
12575
12877
|
const polarity = bindingValidationPolarity(current.test, identifier.name);
|
|
12576
12878
|
if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
|
|
12577
12879
|
return true;
|
|
@@ -12580,14 +12882,14 @@ var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
|
12580
12882
|
return true;
|
|
12581
12883
|
}
|
|
12582
12884
|
}
|
|
12583
|
-
if (current.type ===
|
|
12885
|
+
if (current.type === AST_NODE_TYPES57.FunctionDeclaration || current.type === AST_NODE_TYPES57.FunctionExpression || current.type === AST_NODE_TYPES57.ArrowFunctionExpression) {
|
|
12584
12886
|
return false;
|
|
12585
12887
|
}
|
|
12586
12888
|
}
|
|
12587
12889
|
return false;
|
|
12588
12890
|
};
|
|
12589
12891
|
const declarator = member.parent;
|
|
12590
|
-
if (declarator.type !==
|
|
12892
|
+
if (declarator.type !== AST_NODE_TYPES57.VariableDeclarator || declarator.init !== member || declarator.id.type !== AST_NODE_TYPES57.Identifier || declarator.parent.type !== AST_NODE_TYPES57.VariableDeclaration || declarator.parent.kind !== "const") {
|
|
12591
12893
|
return false;
|
|
12592
12894
|
}
|
|
12593
12895
|
const extracted = context.sourceCode.getDeclaredVariables(declarator)[0];
|
|
@@ -12595,7 +12897,7 @@ var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
|
12595
12897
|
let hasValueUse = false;
|
|
12596
12898
|
for (const reference of extracted.references) {
|
|
12597
12899
|
const identifier = reference.identifier;
|
|
12598
|
-
if (identifier.type !==
|
|
12900
|
+
if (identifier.type !== AST_NODE_TYPES57.Identifier) return false;
|
|
12599
12901
|
if (nodeWithin2(identifier, declarator)) continue;
|
|
12600
12902
|
if (isValidationReference(identifier)) continue;
|
|
12601
12903
|
hasValueUse = true;
|
|
@@ -12608,17 +12910,17 @@ var isGuardTestPosition = (node) => {
|
|
|
12608
12910
|
let parent = current.parent;
|
|
12609
12911
|
while (parent !== void 0 && parent !== null) {
|
|
12610
12912
|
switch (parent.type) {
|
|
12611
|
-
case
|
|
12612
|
-
case
|
|
12613
|
-
case
|
|
12913
|
+
case AST_NODE_TYPES57.UnaryExpression:
|
|
12914
|
+
case AST_NODE_TYPES57.LogicalExpression:
|
|
12915
|
+
case AST_NODE_TYPES57.ChainExpression:
|
|
12614
12916
|
current = parent;
|
|
12615
12917
|
parent = parent.parent;
|
|
12616
12918
|
continue;
|
|
12617
|
-
case
|
|
12618
|
-
case
|
|
12619
|
-
case
|
|
12620
|
-
case
|
|
12621
|
-
case
|
|
12919
|
+
case AST_NODE_TYPES57.IfStatement:
|
|
12920
|
+
case AST_NODE_TYPES57.ConditionalExpression:
|
|
12921
|
+
case AST_NODE_TYPES57.WhileStatement:
|
|
12922
|
+
case AST_NODE_TYPES57.DoWhileStatement:
|
|
12923
|
+
case AST_NODE_TYPES57.ForStatement:
|
|
12622
12924
|
return parent.test === current;
|
|
12623
12925
|
default:
|
|
12624
12926
|
return false;
|
|
@@ -12627,8 +12929,8 @@ var isGuardTestPosition = (node) => {
|
|
|
12627
12929
|
return false;
|
|
12628
12930
|
};
|
|
12629
12931
|
var unvalidatedVariableRef = (node, scope, tracked) => {
|
|
12630
|
-
const unwrapped =
|
|
12631
|
-
if (unwrapped === null || unwrapped.type !==
|
|
12932
|
+
const unwrapped = unwrap5(node);
|
|
12933
|
+
if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES57.Identifier) {
|
|
12632
12934
|
return null;
|
|
12633
12935
|
}
|
|
12634
12936
|
const variable = findVariable2(scope, unwrapped.name);
|
|
@@ -12656,8 +12958,8 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12656
12958
|
const aliasGroups = /* @__PURE__ */ new Map();
|
|
12657
12959
|
const localFileTextVariables = /* @__PURE__ */ new Set();
|
|
12658
12960
|
const localFileTextRef = (node, scope) => {
|
|
12659
|
-
const unwrapped =
|
|
12660
|
-
if (unwrapped?.type !==
|
|
12961
|
+
const unwrapped = unwrap5(node);
|
|
12962
|
+
if (unwrapped?.type !== AST_NODE_TYPES57.Identifier) return null;
|
|
12661
12963
|
const variable = findVariable2(scope, unwrapped.name);
|
|
12662
12964
|
return variable !== null && localFileTextVariables.has(variable) ? variable : null;
|
|
12663
12965
|
};
|
|
@@ -12726,7 +13028,7 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12726
13028
|
return {
|
|
12727
13029
|
VariableDeclarator(node) {
|
|
12728
13030
|
const scope = context.sourceCode.getScope(node);
|
|
12729
|
-
if (node.id.type ===
|
|
13031
|
+
if (node.id.type === AST_NODE_TYPES57.Identifier) {
|
|
12730
13032
|
const variable = context.sourceCode.getDeclaredVariables(node)[0];
|
|
12731
13033
|
if (variable !== void 0) {
|
|
12732
13034
|
updateLocalFileText(variable, node.init, scope);
|
|
@@ -12734,7 +13036,7 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12734
13036
|
trackInitializer(node, scope);
|
|
12735
13037
|
return;
|
|
12736
13038
|
}
|
|
12737
|
-
if (node.id.type ===
|
|
13039
|
+
if (node.id.type === AST_NODE_TYPES57.ObjectPattern || node.id.type === AST_NODE_TYPES57.ArrayPattern) {
|
|
12738
13040
|
if (isRawPayloadSource(
|
|
12739
13041
|
node.init,
|
|
12740
13042
|
(candidate2) => localFileTextRef(candidate2, scope) !== null
|
|
@@ -12751,7 +13053,7 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12751
13053
|
},
|
|
12752
13054
|
AssignmentExpression(node) {
|
|
12753
13055
|
const scope = context.sourceCode.getScope(node);
|
|
12754
|
-
if (node.left.type ===
|
|
13056
|
+
if (node.left.type === AST_NODE_TYPES57.Identifier) {
|
|
12755
13057
|
const variable = findVariable2(scope, node.left.name);
|
|
12756
13058
|
if (variable === null) return;
|
|
12757
13059
|
const isLocalText = (candidate2) => localFileTextRef(candidate2, scope) !== null;
|
|
@@ -12765,7 +13067,7 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12765
13067
|
}
|
|
12766
13068
|
return;
|
|
12767
13069
|
}
|
|
12768
|
-
if (node.left.type ===
|
|
13070
|
+
if (node.left.type === AST_NODE_TYPES57.ObjectPattern || node.left.type === AST_NODE_TYPES57.ArrayPattern) {
|
|
12769
13071
|
if (isRawPayloadSource(
|
|
12770
13072
|
node.right,
|
|
12771
13073
|
(candidate2) => localFileTextRef(candidate2, scope) !== null
|
|
@@ -12785,15 +13087,15 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12785
13087
|
}
|
|
12786
13088
|
},
|
|
12787
13089
|
CallExpression(node) {
|
|
12788
|
-
if (node.callee.type !==
|
|
13090
|
+
if (node.callee.type !== AST_NODE_TYPES57.Identifier) return;
|
|
12789
13091
|
if (!GUARD_NAME_RE.test(node.callee.name) && !isGuardTestPosition(node)) {
|
|
12790
13092
|
return;
|
|
12791
13093
|
}
|
|
12792
13094
|
const scope = context.sourceCode.getScope(node);
|
|
12793
13095
|
for (const arg of node.arguments) {
|
|
12794
|
-
if (arg.type ===
|
|
12795
|
-
const unwrapped =
|
|
12796
|
-
if (unwrapped === null || unwrapped.type !==
|
|
13096
|
+
if (arg.type === AST_NODE_TYPES57.SpreadElement) continue;
|
|
13097
|
+
const unwrapped = unwrap5(arg);
|
|
13098
|
+
if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES57.Identifier) {
|
|
12797
13099
|
continue;
|
|
12798
13100
|
}
|
|
12799
13101
|
const variable = findVariable2(scope, unwrapped.name);
|
|
@@ -12804,20 +13106,20 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12804
13106
|
if (isInsideAssertion(node)) return;
|
|
12805
13107
|
if (isValidationRead(node)) return;
|
|
12806
13108
|
const scope = context.sourceCode.getScope(node);
|
|
12807
|
-
const obj =
|
|
13109
|
+
const obj = unwrap5(node.object);
|
|
12808
13110
|
if (isRawPayloadSource(
|
|
12809
13111
|
obj,
|
|
12810
13112
|
(candidate2) => localFileTextRef(candidate2, scope) !== null
|
|
12811
13113
|
)) {
|
|
12812
13114
|
const parent = node.parent;
|
|
12813
|
-
if (parent.type ===
|
|
13115
|
+
if (parent.type === AST_NODE_TYPES57.CallExpression && parent.callee === node && node.property.type === AST_NODE_TYPES57.Identifier && (node.property.name === "parse" || node.property.name === "safeParse" || PROMISE_CHAIN_METHODS.has(node.property.name))) {
|
|
12814
13116
|
return;
|
|
12815
13117
|
}
|
|
12816
13118
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
12817
13119
|
return;
|
|
12818
13120
|
}
|
|
12819
|
-
const variable = obj?.type ===
|
|
12820
|
-
if (variable !== null && obj?.type ===
|
|
13121
|
+
const variable = obj?.type === AST_NODE_TYPES57.Identifier ? unvalidatedVariableRef(obj, scope, unvalidatedVariables) : null;
|
|
13122
|
+
if (variable !== null && obj?.type === AST_NODE_TYPES57.Identifier) {
|
|
12821
13123
|
if (isUseWithinValidatedBranch(node, obj.name)) {
|
|
12822
13124
|
return;
|
|
12823
13125
|
}
|
|
@@ -12836,8 +13138,142 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
12836
13138
|
}
|
|
12837
13139
|
});
|
|
12838
13140
|
|
|
13141
|
+
// src/rules/prefer-shared-zod-enum.ts
|
|
13142
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES58 } from "@typescript-eslint/utils";
|
|
13143
|
+
var PREFER_SHARED_ZOD_ENUM_DOCUMENTATION = {
|
|
13144
|
+
summary: "Give literal Zod enum domains one reusable module-level schema.",
|
|
13145
|
+
rationale: "Inline or repeated literal domains hide a reusable contract and allow equivalent fields to drift independently.",
|
|
13146
|
+
remediation: "Declare a module-level named Zod enum schema and reuse it at each field or contract site.",
|
|
13147
|
+
category: "maintainability",
|
|
13148
|
+
limitations: ["Only direct z.enum calls with string-literal arrays are inspected; computed domains require review."],
|
|
13149
|
+
examples: [
|
|
13150
|
+
{ id: "shared-provider", title: "Reuse a named enum schema", outcome: "no-match", files: [{ path: "src/provider.ts", source: "import { z } from 'zod'; const ProviderSchema = z.enum(['agy', 'claude', 'sol']); const JobSchema = z.object({ provider: ProviderSchema }); const StatusSchema = z.object({ provider: ProviderSchema.optional() });" }], focusPath: "src/provider.ts", expectedCount: 0, public: true },
|
|
13151
|
+
{ id: "inline-provider", title: "Do not inline enum domains in object fields", outcome: "match", files: [{ path: "src/provider.ts", source: "import { z } from 'zod'; const JobSchema = z.object({ provider: z.enum(['agy', 'claude', 'sol']) });" }], focusPath: "src/provider.ts", expectedCount: 1, public: true }
|
|
13152
|
+
]
|
|
13153
|
+
};
|
|
13154
|
+
function literalDomain(node) {
|
|
13155
|
+
const [argument] = node.arguments;
|
|
13156
|
+
if (argument?.type !== AST_NODE_TYPES58.ArrayExpression || argument.elements.length < 2) return null;
|
|
13157
|
+
const values = [];
|
|
13158
|
+
for (const element of argument.elements) {
|
|
13159
|
+
if (element?.type !== AST_NODE_TYPES58.Literal || typeof element.value !== "string") return null;
|
|
13160
|
+
values.push(element.value);
|
|
13161
|
+
}
|
|
13162
|
+
return values;
|
|
13163
|
+
}
|
|
13164
|
+
function isModuleLevelNamedSchema(node) {
|
|
13165
|
+
let current = node;
|
|
13166
|
+
while (current.parent?.type === AST_NODE_TYPES58.MemberExpression && current.parent.object === current) {
|
|
13167
|
+
current = current.parent;
|
|
13168
|
+
if (current.parent?.type === AST_NODE_TYPES58.CallExpression && current.parent.callee === current) current = current.parent;
|
|
13169
|
+
}
|
|
13170
|
+
const declarator = current.parent;
|
|
13171
|
+
if (declarator?.type !== AST_NODE_TYPES58.VariableDeclarator || declarator.init !== current || declarator.id.type !== AST_NODE_TYPES58.Identifier || declarator.parent.type !== AST_NODE_TYPES58.VariableDeclaration) return false;
|
|
13172
|
+
const declarationParent = declarator.parent.parent;
|
|
13173
|
+
return declarationParent.type === AST_NODE_TYPES58.Program || declarationParent.type === AST_NODE_TYPES58.ExportNamedDeclaration && declarationParent.parent.type === AST_NODE_TYPES58.Program;
|
|
13174
|
+
}
|
|
13175
|
+
var prefer_shared_zod_enum_default = createRule({
|
|
13176
|
+
name: "prefer-shared-zod-enum",
|
|
13177
|
+
documentation: PREFER_SHARED_ZOD_ENUM_DOCUMENTATION,
|
|
13178
|
+
meta: {
|
|
13179
|
+
type: "suggestion",
|
|
13180
|
+
docs: { description: "Give literal Zod enum domains one reusable module-level schema." },
|
|
13181
|
+
schema: [],
|
|
13182
|
+
messages: {
|
|
13183
|
+
shareEnumDomain: "Extract this literal Zod enum to one module-level named schema and reuse it."
|
|
13184
|
+
}
|
|
13185
|
+
},
|
|
13186
|
+
defaultOptions: [],
|
|
13187
|
+
create(context) {
|
|
13188
|
+
if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
13189
|
+
const zodBindings = /* @__PURE__ */ new Set();
|
|
13190
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13191
|
+
return {
|
|
13192
|
+
ImportDeclaration(node) {
|
|
13193
|
+
if (!isZodModule(node.source.value)) return;
|
|
13194
|
+
for (const specifier of node.specifiers) {
|
|
13195
|
+
if (specifier.type === AST_NODE_TYPES58.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES58.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES58.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES58.Identifier && specifier.imported.name === "z") zodBindings.add(specifier.local.name);
|
|
13196
|
+
}
|
|
13197
|
+
},
|
|
13198
|
+
CallExpression(node) {
|
|
13199
|
+
if (node.callee.type !== AST_NODE_TYPES58.MemberExpression || node.callee.computed || node.callee.object.type !== AST_NODE_TYPES58.Identifier || !zodBindings.has(node.callee.object.name) || node.callee.property.type !== AST_NODE_TYPES58.Identifier || node.callee.property.name !== "enum") return;
|
|
13200
|
+
const domain = literalDomain(node);
|
|
13201
|
+
if (domain === null) return;
|
|
13202
|
+
const key = JSON.stringify(domain);
|
|
13203
|
+
const inline = !isModuleLevelNamedSchema(node);
|
|
13204
|
+
if (inline || seen.has(key))
|
|
13205
|
+
context.report({ node, messageId: "shareEnumDomain" });
|
|
13206
|
+
else seen.add(key);
|
|
13207
|
+
}
|
|
13208
|
+
};
|
|
13209
|
+
}
|
|
13210
|
+
});
|
|
13211
|
+
|
|
13212
|
+
// src/rules/prefer-switch-for-repeated-equality.ts
|
|
13213
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES59 } from "@typescript-eslint/utils";
|
|
13214
|
+
var PREFER_SWITCH_FOR_REPEATED_EQUALITY_DOCUMENTATION = {
|
|
13215
|
+
summary: "Prefer switch over long if/else-if chains that compare one value for strict equality.",
|
|
13216
|
+
rationale: "A switch makes finite dispatch cases visually uniform and easier to extend without duplicating the discriminant.",
|
|
13217
|
+
remediation: "Replace three or more strict-equality branches over the same discriminant with a switch; keep if statements for ranges, guards, and heterogeneous predicates.",
|
|
13218
|
+
category: "maintainability",
|
|
13219
|
+
limitations: [
|
|
13220
|
+
"Only direct if/else-if chains with at least three strict-equality tests are reported.",
|
|
13221
|
+
"Case values may be literals, enum-like member references, or upper-case named constants; dynamic expressions are excluded.",
|
|
13222
|
+
"The rule deliberately ignores compound predicates, loose equality, ranges, and chains that compare different discriminants."
|
|
13223
|
+
],
|
|
13224
|
+
examples: [
|
|
13225
|
+
{ id: "switch-dispatch", title: "Make finite dispatch explicit", outcome: "no-match", files: [{ path: "src/render.ts", source: "switch (kind) { case 'a': return a(); case 'b': return b(); case 'c': return c(); default: return fallback(); }" }], focusPath: "src/render.ts", expectedCount: 0, public: true },
|
|
13226
|
+
{ id: "repeated-equality", title: "Avoid repeating the discriminant", outcome: "match", files: [{ path: "src/render.ts", source: "if (kind === 'a') return a(); else if (kind === 'b') return b(); else if (kind === 'c') return c();" }], focusPath: "src/render.ts", expectedCount: 1, public: true }
|
|
13227
|
+
]
|
|
13228
|
+
};
|
|
13229
|
+
function discriminantText(sourceCode, test) {
|
|
13230
|
+
if (test.type !== AST_NODE_TYPES59.BinaryExpression || test.operator !== "===") return null;
|
|
13231
|
+
const leftIsCase = isCaseValue(test.left);
|
|
13232
|
+
const rightIsCase = isCaseValue(test.right);
|
|
13233
|
+
if (leftIsCase === rightIsCase) return null;
|
|
13234
|
+
return sourceCode.getText(leftIsCase ? test.right : test.left);
|
|
13235
|
+
}
|
|
13236
|
+
function isCaseValue(node) {
|
|
13237
|
+
if (node.type === AST_NODE_TYPES59.Literal) return true;
|
|
13238
|
+
if (node.type === AST_NODE_TYPES59.Identifier) return /^[A-Z][A-Z0-9_]*$/u.test(node.name);
|
|
13239
|
+
if (node.type !== AST_NODE_TYPES59.MemberExpression || node.computed) return false;
|
|
13240
|
+
return node.property.type === AST_NODE_TYPES59.Identifier && (node.object.type === AST_NODE_TYPES59.Identifier || isCaseValue(node.object));
|
|
13241
|
+
}
|
|
13242
|
+
var prefer_switch_for_repeated_equality_default = createRule({
|
|
13243
|
+
name: "prefer-switch-for-repeated-equality",
|
|
13244
|
+
documentation: PREFER_SWITCH_FOR_REPEATED_EQUALITY_DOCUMENTATION,
|
|
13245
|
+
meta: {
|
|
13246
|
+
type: "suggestion",
|
|
13247
|
+
docs: { description: "Prefer switch over long if/else-if chains that compare one value for strict equality." },
|
|
13248
|
+
schema: [],
|
|
13249
|
+
messages: {
|
|
13250
|
+
preferSwitch: "This if/else-if chain repeatedly compares `{{discriminant}}`; use a switch for the finite cases."
|
|
13251
|
+
}
|
|
13252
|
+
},
|
|
13253
|
+
defaultOptions: [],
|
|
13254
|
+
create(context) {
|
|
13255
|
+
return {
|
|
13256
|
+
IfStatement(node) {
|
|
13257
|
+
if (node.parent.type === AST_NODE_TYPES59.IfStatement && node.parent.alternate === node) return;
|
|
13258
|
+
const first = discriminantText(context.sourceCode, node.test);
|
|
13259
|
+
if (first === null) return;
|
|
13260
|
+
let count = 1;
|
|
13261
|
+
let current = node.alternate;
|
|
13262
|
+
while (current?.type === AST_NODE_TYPES59.IfStatement) {
|
|
13263
|
+
if (discriminantText(context.sourceCode, current.test) !== first) return;
|
|
13264
|
+
count += 1;
|
|
13265
|
+
current = current.alternate;
|
|
13266
|
+
}
|
|
13267
|
+
if (count >= 3) {
|
|
13268
|
+
context.report({ node, messageId: "preferSwitch", data: { discriminant: first } });
|
|
13269
|
+
}
|
|
13270
|
+
}
|
|
13271
|
+
};
|
|
13272
|
+
}
|
|
13273
|
+
});
|
|
13274
|
+
|
|
12839
13275
|
// src/rules/prefer-semantic-colors.ts
|
|
12840
|
-
import { AST_NODE_TYPES as
|
|
13276
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES60 } from "@typescript-eslint/utils";
|
|
12841
13277
|
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
12842
13278
|
import { dirname, join, parse } from "path";
|
|
12843
13279
|
|
|
@@ -12949,7 +13385,7 @@ var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
|
|
|
12949
13385
|
var isInsideSvg = (node) => {
|
|
12950
13386
|
let current = node.parent;
|
|
12951
13387
|
while (current !== void 0 && current !== null) {
|
|
12952
|
-
if (current.type ===
|
|
13388
|
+
if (current.type === AST_NODE_TYPES60.JSXElement) {
|
|
12953
13389
|
const name = jsxElementName(current);
|
|
12954
13390
|
if (name !== null && isSvgLikeElementName(name)) return true;
|
|
12955
13391
|
}
|
|
@@ -12959,8 +13395,8 @@ var isInsideSvg = (node) => {
|
|
|
12959
13395
|
};
|
|
12960
13396
|
function jsxElementName(node) {
|
|
12961
13397
|
const name = node.openingElement.name;
|
|
12962
|
-
if (name.type ===
|
|
12963
|
-
if (name.type ===
|
|
13398
|
+
if (name.type === AST_NODE_TYPES60.JSXIdentifier) return name.name;
|
|
13399
|
+
if (name.type === AST_NODE_TYPES60.JSXMemberExpression && name.property.type === AST_NODE_TYPES60.JSXIdentifier) {
|
|
12964
13400
|
return name.property.name;
|
|
12965
13401
|
}
|
|
12966
13402
|
return null;
|
|
@@ -12986,7 +13422,7 @@ function isSvgLikeElementName(name) {
|
|
|
12986
13422
|
var isInsideIconFactoryPath = (node) => {
|
|
12987
13423
|
let current = node.parent;
|
|
12988
13424
|
while (current !== void 0 && current !== null) {
|
|
12989
|
-
if (current.type ===
|
|
13425
|
+
if (current.type === AST_NODE_TYPES60.Property && propName(current.key) === "path" && current.parent.type === AST_NODE_TYPES60.ObjectExpression && current.parent.parent.type === AST_NODE_TYPES60.CallExpression && current.parent.parent.callee.type === AST_NODE_TYPES60.Identifier && current.parent.parent.callee.name === "createIcon") {
|
|
12990
13426
|
return true;
|
|
12991
13427
|
}
|
|
12992
13428
|
current = current.parent;
|
|
@@ -13120,12 +13556,12 @@ var expandWorkspaceGlob = (root, glob) => {
|
|
|
13120
13556
|
return readdirSync(parent, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => join(parent, entry.name));
|
|
13121
13557
|
};
|
|
13122
13558
|
var propName = (key) => {
|
|
13123
|
-
if (key.type ===
|
|
13124
|
-
if (key.type ===
|
|
13559
|
+
if (key.type === AST_NODE_TYPES60.Identifier) return key.name;
|
|
13560
|
+
if (key.type === AST_NODE_TYPES60.Literal && typeof key.value === "string") return key.value;
|
|
13125
13561
|
return null;
|
|
13126
13562
|
};
|
|
13127
13563
|
var staticallyImportsEmailOrPdfRenderer = (program) => program.body.some((statement) => {
|
|
13128
|
-
if (statement.type !==
|
|
13564
|
+
if (statement.type !== AST_NODE_TYPES60.ImportDeclaration && statement.type !== AST_NODE_TYPES60.ExportNamedDeclaration && statement.type !== AST_NODE_TYPES60.ExportAllDeclaration) {
|
|
13129
13565
|
return false;
|
|
13130
13566
|
}
|
|
13131
13567
|
return statement.source !== null && typeof statement.source.value === "string" && EMAIL_OR_PDF_MODULE_RE.test(statement.source.value);
|
|
@@ -13162,43 +13598,43 @@ var prefer_semantic_colors_default = createRule({
|
|
|
13162
13598
|
}
|
|
13163
13599
|
let importsEmailOrPdfRenderer = false;
|
|
13164
13600
|
const pendingReports = [];
|
|
13165
|
-
const
|
|
13601
|
+
const report2 = (node, messageId, data) => {
|
|
13166
13602
|
pendingReports.push({ node, messageId, data });
|
|
13167
13603
|
};
|
|
13168
13604
|
const reportClasses = (value, node) => {
|
|
13169
13605
|
for (const token of classTokens(value)) {
|
|
13170
13606
|
const base = tailwindBase(token);
|
|
13171
13607
|
if (RAW_PALETTE_RE.test(base)) {
|
|
13172
|
-
|
|
13608
|
+
report2(node, "rawPalette", { class: token });
|
|
13173
13609
|
} else if (ARBITRARY_COLOR_RE.test(base) && !CSS_VAR_REFERENCE_RE.test(base)) {
|
|
13174
|
-
|
|
13610
|
+
report2(node, "arbitraryColor", { class: token });
|
|
13175
13611
|
}
|
|
13176
13612
|
}
|
|
13177
13613
|
};
|
|
13178
13614
|
const checkClassNode = (node) => {
|
|
13179
13615
|
if (node === null) return;
|
|
13180
13616
|
switch (node.type) {
|
|
13181
|
-
case
|
|
13617
|
+
case AST_NODE_TYPES60.Literal:
|
|
13182
13618
|
if (typeof node.value === "string") reportClasses(node.value, node);
|
|
13183
13619
|
break;
|
|
13184
|
-
case
|
|
13620
|
+
case AST_NODE_TYPES60.TemplateLiteral:
|
|
13185
13621
|
for (const quasi of node.quasis) reportClasses(quasi.value.cooked ?? "", quasi);
|
|
13186
13622
|
break;
|
|
13187
|
-
case
|
|
13623
|
+
case AST_NODE_TYPES60.ArrayExpression:
|
|
13188
13624
|
for (const element of node.elements) {
|
|
13189
|
-
if (element !== null && element.type !==
|
|
13625
|
+
if (element !== null && element.type !== AST_NODE_TYPES60.SpreadElement) checkClassNode(element);
|
|
13190
13626
|
}
|
|
13191
13627
|
break;
|
|
13192
|
-
case
|
|
13628
|
+
case AST_NODE_TYPES60.ObjectExpression:
|
|
13193
13629
|
for (const property of node.properties) {
|
|
13194
|
-
if (property.type ===
|
|
13630
|
+
if (property.type === AST_NODE_TYPES60.Property) checkClassNode(property.value);
|
|
13195
13631
|
}
|
|
13196
13632
|
break;
|
|
13197
|
-
case
|
|
13633
|
+
case AST_NODE_TYPES60.ConditionalExpression:
|
|
13198
13634
|
checkClassNode(node.consequent);
|
|
13199
13635
|
checkClassNode(node.alternate);
|
|
13200
13636
|
break;
|
|
13201
|
-
case
|
|
13637
|
+
case AST_NODE_TYPES60.LogicalExpression:
|
|
13202
13638
|
checkClassNode(node.right);
|
|
13203
13639
|
break;
|
|
13204
13640
|
default:
|
|
@@ -13206,32 +13642,32 @@ var prefer_semantic_colors_default = createRule({
|
|
|
13206
13642
|
}
|
|
13207
13643
|
};
|
|
13208
13644
|
const checkColorValueNode = (node) => {
|
|
13209
|
-
if (node.type ===
|
|
13210
|
-
|
|
13645
|
+
if (node.type === AST_NODE_TYPES60.Literal && typeof node.value === "string" && RAW_COLOR_VALUE_RE.test(node.value) && !CSS_VAR_REFERENCE_RE.test(node.value)) {
|
|
13646
|
+
report2(node, "inlineColor", { value: node.value });
|
|
13211
13647
|
}
|
|
13212
13648
|
};
|
|
13213
13649
|
return {
|
|
13214
13650
|
"JSXAttribute[name.name='className']"(node) {
|
|
13215
13651
|
if (node.value === null) return;
|
|
13216
|
-
if (node.value.type ===
|
|
13217
|
-
else if (node.value.type ===
|
|
13218
|
-
if (node.value.expression.type !==
|
|
13652
|
+
if (node.value.type === AST_NODE_TYPES60.Literal) checkClassNode(node.value);
|
|
13653
|
+
else if (node.value.type === AST_NODE_TYPES60.JSXExpressionContainer) {
|
|
13654
|
+
if (node.value.expression.type !== AST_NODE_TYPES60.JSXEmptyExpression) {
|
|
13219
13655
|
checkClassNode(node.value.expression);
|
|
13220
13656
|
}
|
|
13221
13657
|
}
|
|
13222
13658
|
},
|
|
13223
13659
|
CallExpression(node) {
|
|
13224
|
-
if (node.callee.type ===
|
|
13660
|
+
if (node.callee.type === AST_NODE_TYPES60.Identifier && node.callee.name === "require" && node.arguments[0]?.type === AST_NODE_TYPES60.Literal && typeof node.arguments[0].value === "string" && EMAIL_OR_PDF_MODULE_RE.test(node.arguments[0].value)) {
|
|
13225
13661
|
importsEmailOrPdfRenderer = true;
|
|
13226
13662
|
}
|
|
13227
|
-
if (node.callee.type ===
|
|
13663
|
+
if (node.callee.type === AST_NODE_TYPES60.Identifier && CLASS_FNS.has(node.callee.name)) {
|
|
13228
13664
|
for (const arg of node.arguments) {
|
|
13229
|
-
if (arg.type !==
|
|
13665
|
+
if (arg.type !== AST_NODE_TYPES60.SpreadElement) checkClassNode(arg);
|
|
13230
13666
|
}
|
|
13231
13667
|
}
|
|
13232
13668
|
},
|
|
13233
13669
|
VariableDeclarator(node) {
|
|
13234
|
-
if (node.id.type ===
|
|
13670
|
+
if (node.id.type === AST_NODE_TYPES60.Identifier && CLASS_NAME_RE.test(node.id.name)) {
|
|
13235
13671
|
checkClassNode(node.init);
|
|
13236
13672
|
}
|
|
13237
13673
|
},
|
|
@@ -13241,9 +13677,9 @@ var prefer_semantic_colors_default = createRule({
|
|
|
13241
13677
|
},
|
|
13242
13678
|
// SVG artwork colors are exempt; component presentation colors still report.
|
|
13243
13679
|
"JSXAttribute[name.name=/^(fill|stroke|color)$/]"(node) {
|
|
13244
|
-
if (node.value?.type !==
|
|
13680
|
+
if (node.value?.type !== AST_NODE_TYPES60.Literal) return;
|
|
13245
13681
|
const owner = node.parent.name;
|
|
13246
|
-
if (owner.type ===
|
|
13682
|
+
if (owner.type === AST_NODE_TYPES60.JSXIdentifier && SVG_SHAPE_PRIMITIVES.has(owner.name)) {
|
|
13247
13683
|
return;
|
|
13248
13684
|
}
|
|
13249
13685
|
if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
|
|
@@ -13257,7 +13693,7 @@ var prefer_semantic_colors_default = createRule({
|
|
|
13257
13693
|
if (name !== null && STYLE_COLOR_PROPS.has(name)) checkColorValueNode(node.value);
|
|
13258
13694
|
},
|
|
13259
13695
|
ImportExpression(node) {
|
|
13260
|
-
if (node.source.type ===
|
|
13696
|
+
if (node.source.type === AST_NODE_TYPES60.Literal && typeof node.source.value === "string" && EMAIL_OR_PDF_MODULE_RE.test(node.source.value)) {
|
|
13261
13697
|
importsEmailOrPdfRenderer = true;
|
|
13262
13698
|
}
|
|
13263
13699
|
},
|
|
@@ -13459,7 +13895,7 @@ var prefer_server_actions_default = createRule({
|
|
|
13459
13895
|
});
|
|
13460
13896
|
|
|
13461
13897
|
// src/rules/prefer-whole-object-assertion.ts
|
|
13462
|
-
import { AST_NODE_TYPES as
|
|
13898
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES61 } from "@typescript-eslint/utils";
|
|
13463
13899
|
var MERGEABLE_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
|
|
13464
13900
|
var SYNTHETIC_LITERAL_MATCHERS = /* @__PURE__ */ new Map([
|
|
13465
13901
|
["toBeNull", "null"],
|
|
@@ -13484,11 +13920,11 @@ var PREFER_WHOLE_OBJECT_ASSERTION_DOCUMENTATION = {
|
|
|
13484
13920
|
};
|
|
13485
13921
|
function literalText(node, getText) {
|
|
13486
13922
|
switch (node.type) {
|
|
13487
|
-
case
|
|
13923
|
+
case AST_NODE_TYPES61.Literal:
|
|
13488
13924
|
return "regex" in node ? null : getText(node);
|
|
13489
|
-
case
|
|
13925
|
+
case AST_NODE_TYPES61.TemplateLiteral:
|
|
13490
13926
|
return node.expressions.length === 0 ? getText(node) : null;
|
|
13491
|
-
case
|
|
13927
|
+
case AST_NODE_TYPES61.UnaryExpression:
|
|
13492
13928
|
return NUMERIC_SIGNS2.has(node.operator) && literalText(node.argument, getText) !== null ? getText(node) : null;
|
|
13493
13929
|
default:
|
|
13494
13930
|
return null;
|
|
@@ -13496,15 +13932,15 @@ function literalText(node, getText) {
|
|
|
13496
13932
|
}
|
|
13497
13933
|
function isPureReceiver(node) {
|
|
13498
13934
|
switch (node.type) {
|
|
13499
|
-
case
|
|
13500
|
-
case
|
|
13935
|
+
case AST_NODE_TYPES61.Identifier:
|
|
13936
|
+
case AST_NODE_TYPES61.ThisExpression:
|
|
13501
13937
|
return true;
|
|
13502
|
-
case
|
|
13938
|
+
case AST_NODE_TYPES61.MemberExpression:
|
|
13503
13939
|
if (node.optional) {
|
|
13504
13940
|
return false;
|
|
13505
13941
|
}
|
|
13506
13942
|
if (node.computed) {
|
|
13507
|
-
return node.property.type ===
|
|
13943
|
+
return node.property.type === AST_NODE_TYPES61.Literal && isPureReceiver(node.object);
|
|
13508
13944
|
}
|
|
13509
13945
|
return isPureReceiver(node.object);
|
|
13510
13946
|
default:
|
|
@@ -13512,7 +13948,7 @@ function isPureReceiver(node) {
|
|
|
13512
13948
|
}
|
|
13513
13949
|
}
|
|
13514
13950
|
function literalIndex(node) {
|
|
13515
|
-
if (node.type !==
|
|
13951
|
+
if (node.type !== AST_NODE_TYPES61.Literal || typeof node.value !== "number") {
|
|
13516
13952
|
return null;
|
|
13517
13953
|
}
|
|
13518
13954
|
return Number.isInteger(node.value) && node.value >= 0 ? node.value : null;
|
|
@@ -13520,8 +13956,8 @@ function literalIndex(node) {
|
|
|
13520
13956
|
function propertyAccess(node) {
|
|
13521
13957
|
const path = [];
|
|
13522
13958
|
let current = node;
|
|
13523
|
-
while (current.type ===
|
|
13524
|
-
if (current.property.type !==
|
|
13959
|
+
while (current.type === AST_NODE_TYPES61.MemberExpression && !current.computed && !current.optional) {
|
|
13960
|
+
if (current.property.type !== AST_NODE_TYPES61.Identifier || COLLECTION_PROPERTIES.has(current.property.name) || LITERAL_KEY_HAZARDS.has(current.property.name)) return null;
|
|
13525
13961
|
path.unshift(current.property.name);
|
|
13526
13962
|
current = current.object;
|
|
13527
13963
|
}
|
|
@@ -13549,24 +13985,24 @@ var prefer_whole_object_assertion_default = createRule({
|
|
|
13549
13985
|
}
|
|
13550
13986
|
const { sourceCode } = context;
|
|
13551
13987
|
function parseAssertion(statement) {
|
|
13552
|
-
if (statement.type !==
|
|
13988
|
+
if (statement.type !== AST_NODE_TYPES61.ExpressionStatement) {
|
|
13553
13989
|
return null;
|
|
13554
13990
|
}
|
|
13555
13991
|
const call = statement.expression;
|
|
13556
|
-
if (call.type !==
|
|
13992
|
+
if (call.type !== AST_NODE_TYPES61.CallExpression) {
|
|
13557
13993
|
return null;
|
|
13558
13994
|
}
|
|
13559
13995
|
const callee = call.callee;
|
|
13560
|
-
if (callee.type !==
|
|
13996
|
+
if (callee.type !== AST_NODE_TYPES61.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES61.Identifier) {
|
|
13561
13997
|
return null;
|
|
13562
13998
|
}
|
|
13563
13999
|
const matcher = callee.property.name;
|
|
13564
14000
|
const expectCall = callee.object;
|
|
13565
|
-
if (expectCall.type !==
|
|
14001
|
+
if (expectCall.type !== AST_NODE_TYPES61.CallExpression || expectCall.callee.type !== AST_NODE_TYPES61.Identifier || expectCall.callee.name !== "expect" || expectCall.arguments.length !== 1) {
|
|
13566
14002
|
return null;
|
|
13567
14003
|
}
|
|
13568
14004
|
const actual = expectCall.arguments[0];
|
|
13569
|
-
if (actual === void 0 || actual.type !==
|
|
14005
|
+
if (actual === void 0 || actual.type !== AST_NODE_TYPES61.MemberExpression || actual.optional) {
|
|
13570
14006
|
return null;
|
|
13571
14007
|
}
|
|
13572
14008
|
if (!isPureReceiver(actual.object)) {
|
|
@@ -13595,7 +14031,7 @@ var prefer_whole_object_assertion_default = createRule({
|
|
|
13595
14031
|
return null;
|
|
13596
14032
|
}
|
|
13597
14033
|
const expected = call.arguments[0];
|
|
13598
|
-
if (call.arguments.length !== 1 || expected === void 0 || expected.type ===
|
|
14034
|
+
if (call.arguments.length !== 1 || expected === void 0 || expected.type === AST_NODE_TYPES61.SpreadElement) {
|
|
13599
14035
|
return null;
|
|
13600
14036
|
}
|
|
13601
14037
|
const literal = literalText(expected, (node) => sourceCode.getText(node));
|
|
@@ -13736,7 +14172,7 @@ var prefer_whole_object_assertion_default = createRule({
|
|
|
13736
14172
|
});
|
|
13737
14173
|
|
|
13738
14174
|
// src/rules/repeated-static-call-cases.ts
|
|
13739
|
-
import { AST_NODE_TYPES as
|
|
14175
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES62, ASTUtils as ASTUtils19 } from "@typescript-eslint/utils";
|
|
13740
14176
|
var REPEATED_STATIC_CALL_CASES_DOCUMENTATION = {
|
|
13741
14177
|
summary: "Report three or more consecutive literal call assertions that should be independently named test cases.",
|
|
13742
14178
|
rationale: "Copy-pasted cases obscure the input table and stop later cases from being reported after the first failure.",
|
|
@@ -13757,67 +14193,67 @@ var EXPECT_MODIFIERS = /* @__PURE__ */ new Set(["not", "rejects", "resolves"]);
|
|
|
13757
14193
|
var SNAPSHOT_MATCHERS = /snapshot/iu;
|
|
13758
14194
|
var MIN_CASES2 = 3;
|
|
13759
14195
|
function staticMemberName5(node) {
|
|
13760
|
-
if (!node.computed && node.property.type ===
|
|
13761
|
-
if (node.computed && node.property.type ===
|
|
14196
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES62.Identifier) return node.property.name;
|
|
14197
|
+
if (node.computed && node.property.type === AST_NODE_TYPES62.Literal && typeof node.property.value === "string") return node.property.value;
|
|
13762
14198
|
return null;
|
|
13763
14199
|
}
|
|
13764
|
-
function
|
|
13765
|
-
const variable =
|
|
14200
|
+
function importedName6(identifier, context, modules) {
|
|
14201
|
+
const variable = ASTUtils19.findVariable(context.sourceCode.getScope(identifier), identifier.name);
|
|
13766
14202
|
if (variable === null || variable.defs.length === 0) return identifier.name;
|
|
13767
14203
|
for (const definition of variable.defs) {
|
|
13768
|
-
if (definition.node.type !==
|
|
14204
|
+
if (definition.node.type !== AST_NODE_TYPES62.ImportSpecifier) continue;
|
|
13769
14205
|
const declaration = definition.node.parent;
|
|
13770
|
-
if (declaration.type !==
|
|
14206
|
+
if (declaration.type !== AST_NODE_TYPES62.ImportDeclaration || typeof declaration.source.value !== "string" || !modules.has(declaration.source.value)) continue;
|
|
13771
14207
|
const imported = definition.node.imported;
|
|
13772
|
-
return imported.type ===
|
|
14208
|
+
return imported.type === AST_NODE_TYPES62.Identifier ? imported.name : String(imported.value);
|
|
13773
14209
|
}
|
|
13774
14210
|
return null;
|
|
13775
14211
|
}
|
|
13776
14212
|
function isDirectTestCallback2(node, context) {
|
|
13777
|
-
if (node.type !==
|
|
14213
|
+
if (node.type !== AST_NODE_TYPES62.ArrowFunctionExpression && node.type !== AST_NODE_TYPES62.FunctionExpression) return false;
|
|
13778
14214
|
const call = node.parent;
|
|
13779
|
-
if (call?.type !==
|
|
14215
|
+
if (call?.type !== AST_NODE_TYPES62.CallExpression || !call.arguments.includes(node)) return false;
|
|
13780
14216
|
const root = testRoot2(call.callee);
|
|
13781
|
-
return root !== null && TEST_NAMES2.has(
|
|
14217
|
+
return root !== null && TEST_NAMES2.has(importedName6(root, context, TEST_MODULES4) ?? "");
|
|
13782
14218
|
}
|
|
13783
14219
|
function testRoot2(callee) {
|
|
13784
|
-
if (callee.type ===
|
|
13785
|
-
if (callee.type !==
|
|
14220
|
+
if (callee.type === AST_NODE_TYPES62.Identifier) return callee;
|
|
14221
|
+
if (callee.type !== AST_NODE_TYPES62.MemberExpression) return null;
|
|
13786
14222
|
const modifier = staticMemberName5(callee);
|
|
13787
14223
|
return modifier !== null && TEST_MODIFIERS4.has(modifier) ? testRoot2(callee.object) : null;
|
|
13788
14224
|
}
|
|
13789
14225
|
function isStatic(node) {
|
|
13790
|
-
if (node.type ===
|
|
14226
|
+
if (node.type === AST_NODE_TYPES62.TSAsExpression || node.type === AST_NODE_TYPES62.TSTypeAssertion || node.type === AST_NODE_TYPES62.TSSatisfiesExpression || node.type === AST_NODE_TYPES62.TSNonNullExpression) return isStatic(node.expression);
|
|
13791
14227
|
switch (node.type) {
|
|
13792
|
-
case
|
|
14228
|
+
case AST_NODE_TYPES62.Literal:
|
|
13793
14229
|
return true;
|
|
13794
|
-
case
|
|
14230
|
+
case AST_NODE_TYPES62.TemplateLiteral:
|
|
13795
14231
|
return node.expressions.length === 0;
|
|
13796
|
-
case
|
|
14232
|
+
case AST_NODE_TYPES62.UnaryExpression:
|
|
13797
14233
|
return (node.operator === "+" || node.operator === "-") && isStatic(node.argument);
|
|
13798
|
-
case
|
|
13799
|
-
return node.elements.every((item) => item !== null && item.type !==
|
|
13800
|
-
case
|
|
13801
|
-
return node.properties.every((property) => property.type ===
|
|
14234
|
+
case AST_NODE_TYPES62.ArrayExpression:
|
|
14235
|
+
return node.elements.every((item) => item !== null && item.type !== AST_NODE_TYPES62.SpreadElement && isStatic(item));
|
|
14236
|
+
case AST_NODE_TYPES62.ObjectExpression:
|
|
14237
|
+
return node.properties.every((property) => property.type === AST_NODE_TYPES62.Property && !property.computed && property.kind === "init" && property.value.type !== AST_NODE_TYPES62.AssignmentPattern && isStatic(property.value));
|
|
13802
14238
|
default:
|
|
13803
14239
|
return false;
|
|
13804
14240
|
}
|
|
13805
14241
|
}
|
|
13806
14242
|
function staticShape(node) {
|
|
13807
|
-
if (node.type ===
|
|
14243
|
+
if (node.type === AST_NODE_TYPES62.TSAsExpression || node.type === AST_NODE_TYPES62.TSTypeAssertion || node.type === AST_NODE_TYPES62.TSSatisfiesExpression || node.type === AST_NODE_TYPES62.TSNonNullExpression) return staticShape(node.expression);
|
|
13808
14244
|
switch (node.type) {
|
|
13809
|
-
case
|
|
14245
|
+
case AST_NODE_TYPES62.Literal:
|
|
13810
14246
|
return `literal:${typeof node.value}`;
|
|
13811
|
-
case
|
|
14247
|
+
case AST_NODE_TYPES62.TemplateLiteral:
|
|
13812
14248
|
return "template";
|
|
13813
|
-
case
|
|
14249
|
+
case AST_NODE_TYPES62.UnaryExpression:
|
|
13814
14250
|
return `unary:${node.operator}:${staticShape(node.argument)}`;
|
|
13815
|
-
case
|
|
13816
|
-
return `array(${node.elements.map((item) => item === null || item.type ===
|
|
13817
|
-
case
|
|
14251
|
+
case AST_NODE_TYPES62.ArrayExpression:
|
|
14252
|
+
return `array(${node.elements.map((item) => item === null || item.type === AST_NODE_TYPES62.SpreadElement ? "invalid" : staticShape(item)).join(",")})`;
|
|
14253
|
+
case AST_NODE_TYPES62.ObjectExpression:
|
|
13818
14254
|
return `object(${node.properties.map((property) => {
|
|
13819
|
-
if (property.type !==
|
|
13820
|
-
const key = property.key.type ===
|
|
14255
|
+
if (property.type !== AST_NODE_TYPES62.Property || property.computed || property.value.type === AST_NODE_TYPES62.AssignmentPattern) return "invalid";
|
|
14256
|
+
const key = property.key.type === AST_NODE_TYPES62.Identifier ? property.key.name : String(property.key.value);
|
|
13821
14257
|
return `${key}:${staticShape(property.value)}`;
|
|
13822
14258
|
}).join(",")})`;
|
|
13823
14259
|
default:
|
|
@@ -13825,16 +14261,16 @@ function staticShape(node) {
|
|
|
13825
14261
|
}
|
|
13826
14262
|
}
|
|
13827
14263
|
function assertionShape(statement, context) {
|
|
13828
|
-
if (statement.type !==
|
|
14264
|
+
if (statement.type !== AST_NODE_TYPES62.ExpressionStatement || statement.expression.type !== AST_NODE_TYPES62.CallExpression) return null;
|
|
13829
14265
|
const matcherCall = statement.expression;
|
|
13830
|
-
if (matcherCall.callee.type !==
|
|
14266
|
+
if (matcherCall.callee.type !== AST_NODE_TYPES62.MemberExpression || matcherCall.callee.computed || matcherCall.callee.property.type !== AST_NODE_TYPES62.Identifier || matcherCall.arguments.length !== 1) return null;
|
|
13831
14267
|
const matcher = matcherCall.callee.property.name;
|
|
13832
14268
|
if (SNAPSHOT_MATCHERS.test(matcher)) return null;
|
|
13833
14269
|
const chain = expectCallFromMatcher(matcherCall.callee);
|
|
13834
|
-
if (chain === null || chain.call.callee.type !==
|
|
14270
|
+
if (chain === null || chain.call.callee.type !== AST_NODE_TYPES62.Identifier || importedName6(chain.call.callee, context, ASSERTION_MODULES3) !== "expect" || chain.call.arguments.length !== 1) return null;
|
|
13835
14271
|
const observed = chain.call.arguments[0];
|
|
13836
14272
|
const expected = matcherCall.arguments[0];
|
|
13837
|
-
if (observed?.type !==
|
|
14273
|
+
if (observed?.type !== AST_NODE_TYPES62.CallExpression || observed.callee.type !== AST_NODE_TYPES62.Identifier || observed.arguments.length === 0 || observed.arguments.some((arg) => arg.type === AST_NODE_TYPES62.SpreadElement || !isStatic(arg)) || expected?.type === AST_NODE_TYPES62.SpreadElement || expected === void 0 || !isStatic(expected)) return null;
|
|
13838
14274
|
const skeleton = `${observed.callee.name}/${observed.arguments.map((item) => staticShape(item)).join(",")}/${chain.modifiers.join(".")}/${matcher}/${staticShape(expected)}`;
|
|
13839
14275
|
const values = [...observed.arguments, expected].map((item) => context.sourceCode.getText(item)).join("\0");
|
|
13840
14276
|
return { statement, skeleton, values };
|
|
@@ -13842,13 +14278,13 @@ function assertionShape(statement, context) {
|
|
|
13842
14278
|
function expectCallFromMatcher(node) {
|
|
13843
14279
|
const modifiers = [];
|
|
13844
14280
|
let receiver = node.object;
|
|
13845
|
-
while (receiver.type ===
|
|
14281
|
+
while (receiver.type === AST_NODE_TYPES62.MemberExpression) {
|
|
13846
14282
|
const modifier = staticMemberName5(receiver);
|
|
13847
14283
|
if (modifier === null || !EXPECT_MODIFIERS.has(modifier)) return null;
|
|
13848
14284
|
modifiers.unshift(modifier);
|
|
13849
14285
|
receiver = receiver.object;
|
|
13850
14286
|
}
|
|
13851
|
-
return receiver.type ===
|
|
14287
|
+
return receiver.type === AST_NODE_TYPES62.CallExpression ? { call: receiver, modifiers } : null;
|
|
13852
14288
|
}
|
|
13853
14289
|
var repeated_static_call_cases_default = createRule({
|
|
13854
14290
|
name: "repeated-static-call-cases",
|
|
@@ -13868,7 +14304,7 @@ var repeated_static_call_cases_default = createRule({
|
|
|
13868
14304
|
return {
|
|
13869
14305
|
"CallExpression > ArrowFunctionExpression, CallExpression > FunctionExpression"(node) {
|
|
13870
14306
|
const call = node.parent;
|
|
13871
|
-
if (call?.type ===
|
|
14307
|
+
if (call?.type === AST_NODE_TYPES62.CallExpression) {
|
|
13872
14308
|
const duplicate = duplicateTestBodyCandidate(call, sourceCode);
|
|
13873
14309
|
if (duplicate !== null && duplicate.body === node) {
|
|
13874
14310
|
const groups = duplicateGroups.get(duplicate.container) ?? /* @__PURE__ */ new Map();
|
|
@@ -13878,7 +14314,7 @@ var repeated_static_call_cases_default = createRule({
|
|
|
13878
14314
|
duplicateGroups.set(duplicate.container, groups);
|
|
13879
14315
|
}
|
|
13880
14316
|
}
|
|
13881
|
-
if (!isDirectTestCallback2(node, context) || node.body.type !==
|
|
14317
|
+
if (!isDirectTestCallback2(node, context) || node.body.type !== AST_NODE_TYPES62.BlockStatement) return;
|
|
13882
14318
|
let run = [];
|
|
13883
14319
|
const flush = () => {
|
|
13884
14320
|
if (run.length >= MIN_CASES2 && new Set(run.map((item) => item.values)).size > 1) {
|
|
@@ -13919,7 +14355,7 @@ var repeated_static_call_cases_default = createRule({
|
|
|
13919
14355
|
});
|
|
13920
14356
|
|
|
13921
14357
|
// src/rules/prefer-zod-infer.ts
|
|
13922
|
-
import { AST_NODE_TYPES as
|
|
14358
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES63 } from "@typescript-eslint/utils";
|
|
13923
14359
|
var PREFER_ZOD_INFER_DOCUMENTATION = {
|
|
13924
14360
|
summary: "Derive a type from its Zod schema with `z.infer` instead of hand-writing a twin declaration beside it.",
|
|
13925
14361
|
rationale: "A derived type stays synchronized when the runtime schema changes.",
|
|
@@ -13972,47 +14408,47 @@ var ZOD_TYPE_CONSTRAINTS = /* @__PURE__ */ new Set([
|
|
|
13972
14408
|
"Schema"
|
|
13973
14409
|
]);
|
|
13974
14410
|
var LEAF_NODE_TYPES = {
|
|
13975
|
-
string: [
|
|
13976
|
-
email: [
|
|
13977
|
-
url: [
|
|
13978
|
-
uuid: [
|
|
13979
|
-
ulid: [
|
|
13980
|
-
cuid: [
|
|
13981
|
-
cuid2: [
|
|
13982
|
-
nanoid: [
|
|
13983
|
-
iso: [
|
|
13984
|
-
number: [
|
|
13985
|
-
int: [
|
|
13986
|
-
float32: [
|
|
13987
|
-
float64: [
|
|
13988
|
-
boolean: [
|
|
13989
|
-
bigint: [
|
|
13990
|
-
symbol: [
|
|
13991
|
-
any: [
|
|
13992
|
-
unknown: [
|
|
13993
|
-
never: [
|
|
13994
|
-
void: [
|
|
13995
|
-
null: [
|
|
13996
|
-
undefined: [
|
|
13997
|
-
literal: [
|
|
13998
|
-
date: [
|
|
13999
|
-
array: [
|
|
14000
|
-
tuple: [
|
|
14001
|
-
object: [
|
|
14002
|
-
strictObject: [
|
|
14003
|
-
looseObject: [
|
|
14004
|
-
record: [
|
|
14005
|
-
map: [
|
|
14006
|
-
set: [
|
|
14007
|
-
promise: [
|
|
14008
|
-
enum: [
|
|
14009
|
-
nativeEnum: [
|
|
14010
|
-
union: [
|
|
14011
|
-
discriminatedUnion: [
|
|
14012
|
-
intersection: [
|
|
14411
|
+
string: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14412
|
+
email: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14413
|
+
url: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14414
|
+
uuid: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14415
|
+
ulid: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14416
|
+
cuid: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14417
|
+
cuid2: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14418
|
+
nanoid: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14419
|
+
iso: [AST_NODE_TYPES63.TSStringKeyword],
|
|
14420
|
+
number: [AST_NODE_TYPES63.TSNumberKeyword],
|
|
14421
|
+
int: [AST_NODE_TYPES63.TSNumberKeyword],
|
|
14422
|
+
float32: [AST_NODE_TYPES63.TSNumberKeyword],
|
|
14423
|
+
float64: [AST_NODE_TYPES63.TSNumberKeyword],
|
|
14424
|
+
boolean: [AST_NODE_TYPES63.TSBooleanKeyword],
|
|
14425
|
+
bigint: [AST_NODE_TYPES63.TSBigIntKeyword],
|
|
14426
|
+
symbol: [AST_NODE_TYPES63.TSSymbolKeyword],
|
|
14427
|
+
any: [AST_NODE_TYPES63.TSAnyKeyword],
|
|
14428
|
+
unknown: [AST_NODE_TYPES63.TSUnknownKeyword],
|
|
14429
|
+
never: [AST_NODE_TYPES63.TSNeverKeyword],
|
|
14430
|
+
void: [AST_NODE_TYPES63.TSVoidKeyword],
|
|
14431
|
+
null: [AST_NODE_TYPES63.TSNullKeyword],
|
|
14432
|
+
undefined: [AST_NODE_TYPES63.TSUndefinedKeyword],
|
|
14433
|
+
literal: [AST_NODE_TYPES63.TSLiteralType],
|
|
14434
|
+
date: [AST_NODE_TYPES63.TSTypeReference],
|
|
14435
|
+
array: [AST_NODE_TYPES63.TSArrayType, AST_NODE_TYPES63.TSTypeReference],
|
|
14436
|
+
tuple: [AST_NODE_TYPES63.TSTupleType],
|
|
14437
|
+
object: [AST_NODE_TYPES63.TSTypeLiteral, AST_NODE_TYPES63.TSTypeReference],
|
|
14438
|
+
strictObject: [AST_NODE_TYPES63.TSTypeLiteral, AST_NODE_TYPES63.TSTypeReference],
|
|
14439
|
+
looseObject: [AST_NODE_TYPES63.TSTypeLiteral, AST_NODE_TYPES63.TSTypeReference],
|
|
14440
|
+
record: [AST_NODE_TYPES63.TSTypeReference, AST_NODE_TYPES63.TSTypeLiteral],
|
|
14441
|
+
map: [AST_NODE_TYPES63.TSTypeReference],
|
|
14442
|
+
set: [AST_NODE_TYPES63.TSTypeReference],
|
|
14443
|
+
promise: [AST_NODE_TYPES63.TSTypeReference],
|
|
14444
|
+
enum: [AST_NODE_TYPES63.TSUnionType, AST_NODE_TYPES63.TSTypeReference, AST_NODE_TYPES63.TSLiteralType],
|
|
14445
|
+
nativeEnum: [AST_NODE_TYPES63.TSUnionType, AST_NODE_TYPES63.TSTypeReference, AST_NODE_TYPES63.TSLiteralType],
|
|
14446
|
+
union: [AST_NODE_TYPES63.TSUnionType, AST_NODE_TYPES63.TSTypeReference],
|
|
14447
|
+
discriminatedUnion: [AST_NODE_TYPES63.TSUnionType, AST_NODE_TYPES63.TSTypeReference],
|
|
14448
|
+
intersection: [AST_NODE_TYPES63.TSIntersectionType, AST_NODE_TYPES63.TSTypeReference]
|
|
14013
14449
|
};
|
|
14014
14450
|
function primitiveLiteralKey(node) {
|
|
14015
|
-
if (node.type !==
|
|
14451
|
+
if (node.type !== AST_NODE_TYPES63.Literal) {
|
|
14016
14452
|
return null;
|
|
14017
14453
|
}
|
|
14018
14454
|
if (node.value === null) {
|
|
@@ -14044,13 +14480,13 @@ function staticZodDomain(leaf, call) {
|
|
|
14044
14480
|
}
|
|
14045
14481
|
if (leaf === "literal") {
|
|
14046
14482
|
const [argument] = call.arguments;
|
|
14047
|
-
if (argument === void 0 || argument.type ===
|
|
14483
|
+
if (argument === void 0 || argument.type === AST_NODE_TYPES63.SpreadElement) {
|
|
14048
14484
|
return null;
|
|
14049
14485
|
}
|
|
14050
|
-
if (argument.type ===
|
|
14486
|
+
if (argument.type === AST_NODE_TYPES63.ArrayExpression) {
|
|
14051
14487
|
return exactDomain(
|
|
14052
14488
|
argument.elements.map(
|
|
14053
|
-
(element) => element === null || element.type ===
|
|
14489
|
+
(element) => element === null || element.type === AST_NODE_TYPES63.SpreadElement ? null : primitiveLiteralKey(element)
|
|
14054
14490
|
)
|
|
14055
14491
|
);
|
|
14056
14492
|
}
|
|
@@ -14058,13 +14494,13 @@ function staticZodDomain(leaf, call) {
|
|
|
14058
14494
|
}
|
|
14059
14495
|
if (leaf === "enum") {
|
|
14060
14496
|
const [argument] = call.arguments;
|
|
14061
|
-
if (argument === void 0 || argument.type ===
|
|
14497
|
+
if (argument === void 0 || argument.type === AST_NODE_TYPES63.SpreadElement) {
|
|
14062
14498
|
return null;
|
|
14063
14499
|
}
|
|
14064
|
-
if (argument.type ===
|
|
14500
|
+
if (argument.type === AST_NODE_TYPES63.ArrayExpression) {
|
|
14065
14501
|
return exactDomain(
|
|
14066
14502
|
argument.elements.map((element) => {
|
|
14067
|
-
if (element === null || element.type ===
|
|
14503
|
+
if (element === null || element.type === AST_NODE_TYPES63.SpreadElement) {
|
|
14068
14504
|
return null;
|
|
14069
14505
|
}
|
|
14070
14506
|
const key = primitiveLiteralKey(element);
|
|
@@ -14072,10 +14508,10 @@ function staticZodDomain(leaf, call) {
|
|
|
14072
14508
|
})
|
|
14073
14509
|
);
|
|
14074
14510
|
}
|
|
14075
|
-
if (argument.type ===
|
|
14511
|
+
if (argument.type === AST_NODE_TYPES63.ObjectExpression) {
|
|
14076
14512
|
return exactDomain(
|
|
14077
14513
|
argument.properties.map((property) => {
|
|
14078
|
-
if (property.type !==
|
|
14514
|
+
if (property.type !== AST_NODE_TYPES63.Property || property.computed || property.kind !== "init" || property.method || property.shorthand) {
|
|
14079
14515
|
return null;
|
|
14080
14516
|
}
|
|
14081
14517
|
const key = primitiveLiteralKey(property.value);
|
|
@@ -14102,15 +14538,15 @@ function sameDomain(left, right) {
|
|
|
14102
14538
|
return true;
|
|
14103
14539
|
}
|
|
14104
14540
|
function isExportedDeclaration(node) {
|
|
14105
|
-
return node.parent?.type ===
|
|
14541
|
+
return node.parent?.type === AST_NODE_TYPES63.ExportNamedDeclaration;
|
|
14106
14542
|
}
|
|
14107
14543
|
function isModuleLevelConst(node) {
|
|
14108
14544
|
const declaration = node.parent;
|
|
14109
|
-
if (declaration.type !==
|
|
14545
|
+
if (declaration.type !== AST_NODE_TYPES63.VariableDeclaration || declaration.kind !== "const") {
|
|
14110
14546
|
return false;
|
|
14111
14547
|
}
|
|
14112
14548
|
const container = declaration.parent;
|
|
14113
|
-
return container.type ===
|
|
14549
|
+
return container.type === AST_NODE_TYPES63.Program || container.type === AST_NODE_TYPES63.ExportNamedDeclaration && container.parent.type === AST_NODE_TYPES63.Program;
|
|
14114
14550
|
}
|
|
14115
14551
|
function normalizeSchemaName(name) {
|
|
14116
14552
|
return name.replace(/Schema$/i, "").replace(/^Z(?=[A-Z])/, "").toLowerCase();
|
|
@@ -14119,20 +14555,20 @@ function normalizeTypeName(name) {
|
|
|
14119
14555
|
return name.replace(/Type$/, "").toLowerCase();
|
|
14120
14556
|
}
|
|
14121
14557
|
function unwrapNullish(annotation) {
|
|
14122
|
-
if (annotation.type !==
|
|
14558
|
+
if (annotation.type !== AST_NODE_TYPES63.TSUnionType) {
|
|
14123
14559
|
return {
|
|
14124
14560
|
core: annotation,
|
|
14125
|
-
nullable: annotation.type ===
|
|
14561
|
+
nullable: annotation.type === AST_NODE_TYPES63.TSNullKeyword
|
|
14126
14562
|
};
|
|
14127
14563
|
}
|
|
14128
14564
|
const rest = [];
|
|
14129
14565
|
let nullable = false;
|
|
14130
14566
|
for (const member of annotation.types) {
|
|
14131
|
-
if (member.type ===
|
|
14567
|
+
if (member.type === AST_NODE_TYPES63.TSNullKeyword) {
|
|
14132
14568
|
nullable = true;
|
|
14133
14569
|
continue;
|
|
14134
14570
|
}
|
|
14135
|
-
if (member.type ===
|
|
14571
|
+
if (member.type === AST_NODE_TYPES63.TSUndefinedKeyword) {
|
|
14136
14572
|
continue;
|
|
14137
14573
|
}
|
|
14138
14574
|
rest.push(member);
|
|
@@ -14166,18 +14602,18 @@ function leafAgrees(field, annotation) {
|
|
|
14166
14602
|
return null;
|
|
14167
14603
|
}
|
|
14168
14604
|
if (leaf === "date") {
|
|
14169
|
-
return core.type ===
|
|
14605
|
+
return core.type === AST_NODE_TYPES63.TSTypeReference && core.typeName.type === AST_NODE_TYPES63.Identifier && core.typeName.name === "Date";
|
|
14170
14606
|
}
|
|
14171
14607
|
return expected.includes(core.type);
|
|
14172
14608
|
}
|
|
14173
14609
|
function typeLiteralDomain(annotation) {
|
|
14174
|
-
const members = annotation.type ===
|
|
14610
|
+
const members = annotation.type === AST_NODE_TYPES63.TSUnionType ? annotation.types : [annotation];
|
|
14175
14611
|
const keys = [];
|
|
14176
14612
|
for (const member of members) {
|
|
14177
|
-
if (member.type ===
|
|
14613
|
+
if (member.type === AST_NODE_TYPES63.TSNullKeyword) {
|
|
14178
14614
|
continue;
|
|
14179
14615
|
}
|
|
14180
|
-
if (member.type !==
|
|
14616
|
+
if (member.type !== AST_NODE_TYPES63.TSLiteralType) {
|
|
14181
14617
|
return null;
|
|
14182
14618
|
}
|
|
14183
14619
|
keys.push(primitiveLiteralKey(member.literal));
|
|
@@ -14185,11 +14621,11 @@ function typeLiteralDomain(annotation) {
|
|
|
14185
14621
|
return exactDomain(keys);
|
|
14186
14622
|
}
|
|
14187
14623
|
function staticStringUnionDomain(node) {
|
|
14188
|
-
if (node.type !==
|
|
14624
|
+
if (node.type !== AST_NODE_TYPES63.TSUnionType) {
|
|
14189
14625
|
return null;
|
|
14190
14626
|
}
|
|
14191
14627
|
const keys = node.types.map((member) => {
|
|
14192
|
-
if (member.type !==
|
|
14628
|
+
if (member.type !== AST_NODE_TYPES63.TSLiteralType) {
|
|
14193
14629
|
return null;
|
|
14194
14630
|
}
|
|
14195
14631
|
const key = primitiveLiteralKey(member.literal);
|
|
@@ -14257,14 +14693,14 @@ var prefer_zod_infer_default = createRule({
|
|
|
14257
14693
|
function zodCallChain(node) {
|
|
14258
14694
|
const chain = [];
|
|
14259
14695
|
let current = node;
|
|
14260
|
-
while (current.type ===
|
|
14696
|
+
while (current.type === AST_NODE_TYPES63.CallExpression) {
|
|
14261
14697
|
const callee = current.callee;
|
|
14262
|
-
if (callee.type !==
|
|
14698
|
+
if (callee.type !== AST_NODE_TYPES63.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES63.Identifier) {
|
|
14263
14699
|
return null;
|
|
14264
14700
|
}
|
|
14265
14701
|
chain.push(current);
|
|
14266
14702
|
const receiver = callee.object;
|
|
14267
|
-
if (receiver.type ===
|
|
14703
|
+
if (receiver.type === AST_NODE_TYPES63.Identifier) {
|
|
14268
14704
|
return zodNamespaces.has(receiver.name) ? chain.reverse() : null;
|
|
14269
14705
|
}
|
|
14270
14706
|
current = receiver;
|
|
@@ -14273,14 +14709,14 @@ var prefer_zod_infer_default = createRule({
|
|
|
14273
14709
|
}
|
|
14274
14710
|
function methodName2(call) {
|
|
14275
14711
|
const callee = call.callee;
|
|
14276
|
-
return callee.type ===
|
|
14712
|
+
return callee.type === AST_NODE_TYPES63.MemberExpression && callee.property.type === AST_NODE_TYPES63.Identifier ? callee.property.name : "";
|
|
14277
14713
|
}
|
|
14278
14714
|
function recordZodImport(node) {
|
|
14279
14715
|
if (!isZodModule(node.source.value)) {
|
|
14280
14716
|
return;
|
|
14281
14717
|
}
|
|
14282
14718
|
for (const specifier of node.specifiers) {
|
|
14283
|
-
if (specifier.type ===
|
|
14719
|
+
if (specifier.type === AST_NODE_TYPES63.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES63.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES63.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES63.Identifier && specifier.imported.name === "z") {
|
|
14284
14720
|
zodNamespaces.add(specifier.local.name);
|
|
14285
14721
|
}
|
|
14286
14722
|
}
|
|
@@ -14290,13 +14726,13 @@ var prefer_zod_infer_default = createRule({
|
|
|
14290
14726
|
let current = node;
|
|
14291
14727
|
let leaf = null;
|
|
14292
14728
|
let leafCall = null;
|
|
14293
|
-
while (current.type ===
|
|
14729
|
+
while (current.type === AST_NODE_TYPES63.CallExpression) {
|
|
14294
14730
|
const callee = current.callee;
|
|
14295
|
-
if (callee.type !==
|
|
14731
|
+
if (callee.type !== AST_NODE_TYPES63.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES63.Identifier) {
|
|
14296
14732
|
break;
|
|
14297
14733
|
}
|
|
14298
14734
|
const receiver = callee.object;
|
|
14299
|
-
if (receiver.type ===
|
|
14735
|
+
if (receiver.type === AST_NODE_TYPES63.Identifier && zodNamespaces.has(receiver.name)) {
|
|
14300
14736
|
leaf = callee.property.name;
|
|
14301
14737
|
leafCall = current;
|
|
14302
14738
|
break;
|
|
@@ -14327,30 +14763,30 @@ var prefer_zod_infer_default = createRule({
|
|
|
14327
14763
|
return domain instanceof Set && domain.size >= 2 ? domain : null;
|
|
14328
14764
|
}
|
|
14329
14765
|
function inferredSchemaName(node) {
|
|
14330
|
-
if (node.type !==
|
|
14766
|
+
if (node.type !== AST_NODE_TYPES63.TSTypeReference || node.typeName.type !== AST_NODE_TYPES63.TSQualifiedName || node.typeName.left.type !== AST_NODE_TYPES63.Identifier || !zodNamespaces.has(node.typeName.left.name) || node.typeName.right.name !== "infer") {
|
|
14331
14767
|
return null;
|
|
14332
14768
|
}
|
|
14333
14769
|
const arguments_ = node.typeArguments?.params ?? [];
|
|
14334
14770
|
const [argument] = arguments_;
|
|
14335
|
-
return arguments_.length === 1 && argument?.type ===
|
|
14771
|
+
return arguments_.length === 1 && argument?.type === AST_NODE_TYPES63.TSTypeQuery && argument.exprName.type === AST_NODE_TYPES63.Identifier ? argument.exprName.name : null;
|
|
14336
14772
|
}
|
|
14337
14773
|
function recordLiteralUnions(members, owner, ownerName, exported) {
|
|
14338
14774
|
for (const member of members) {
|
|
14339
|
-
if (member.type !==
|
|
14775
|
+
if (member.type !== AST_NODE_TYPES63.TSPropertySignature || member.computed || member.optional || member.readonly || member.typeAnnotation === void 0) {
|
|
14340
14776
|
continue;
|
|
14341
14777
|
}
|
|
14342
14778
|
const key = member.key;
|
|
14343
|
-
const
|
|
14344
|
-
if (
|
|
14779
|
+
const propertyName7 = key.type === AST_NODE_TYPES63.Identifier ? key.name : key.type === AST_NODE_TYPES63.Literal && typeof key.value === "string" ? key.value : null;
|
|
14780
|
+
if (propertyName7 === null) {
|
|
14345
14781
|
continue;
|
|
14346
14782
|
}
|
|
14347
|
-
const propertyTokens = nameTokens(
|
|
14783
|
+
const propertyTokens = nameTokens(propertyName7);
|
|
14348
14784
|
if (propertyTokens.length < 2) {
|
|
14349
14785
|
continue;
|
|
14350
14786
|
}
|
|
14351
14787
|
const annotation = member.typeAnnotation.typeAnnotation;
|
|
14352
14788
|
const domain = staticStringUnionDomain(annotation);
|
|
14353
|
-
if (domain === null || annotation.type !==
|
|
14789
|
+
if (domain === null || annotation.type !== AST_NODE_TYPES63.TSUnionType) {
|
|
14354
14790
|
continue;
|
|
14355
14791
|
}
|
|
14356
14792
|
literalUnionOccurrences.push({
|
|
@@ -14359,7 +14795,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
14359
14795
|
node: annotation,
|
|
14360
14796
|
owner,
|
|
14361
14797
|
ownerName,
|
|
14362
|
-
propertyName:
|
|
14798
|
+
propertyName: propertyName7,
|
|
14363
14799
|
propertyTokens
|
|
14364
14800
|
});
|
|
14365
14801
|
}
|
|
@@ -14381,16 +14817,16 @@ var prefer_zod_infer_default = createRule({
|
|
|
14381
14817
|
return null;
|
|
14382
14818
|
}
|
|
14383
14819
|
const shape = base.arguments[0];
|
|
14384
|
-
if (shape === void 0 || shape.type !==
|
|
14820
|
+
if (shape === void 0 || shape.type !== AST_NODE_TYPES63.ObjectExpression) {
|
|
14385
14821
|
return null;
|
|
14386
14822
|
}
|
|
14387
14823
|
const fields = /* @__PURE__ */ new Map();
|
|
14388
14824
|
for (const property of shape.properties) {
|
|
14389
|
-
if (property.type !==
|
|
14825
|
+
if (property.type !== AST_NODE_TYPES63.Property || property.computed) {
|
|
14390
14826
|
return null;
|
|
14391
14827
|
}
|
|
14392
14828
|
const { key } = property;
|
|
14393
|
-
const name = key.type ===
|
|
14829
|
+
const name = key.type === AST_NODE_TYPES63.Identifier ? key.name : key.type === AST_NODE_TYPES63.Literal && typeof key.value === "string" ? key.value : null;
|
|
14394
14830
|
if (name === null) {
|
|
14395
14831
|
return null;
|
|
14396
14832
|
}
|
|
@@ -14401,11 +14837,11 @@ var prefer_zod_infer_default = createRule({
|
|
|
14401
14837
|
function typeMembers(members) {
|
|
14402
14838
|
const result = /* @__PURE__ */ new Map();
|
|
14403
14839
|
for (const member of members) {
|
|
14404
|
-
if (member.type !==
|
|
14840
|
+
if (member.type !== AST_NODE_TYPES63.TSPropertySignature || member.computed) {
|
|
14405
14841
|
return null;
|
|
14406
14842
|
}
|
|
14407
14843
|
const { key } = member;
|
|
14408
|
-
const name = key.type ===
|
|
14844
|
+
const name = key.type === AST_NODE_TYPES63.Identifier ? key.name : key.type === AST_NODE_TYPES63.Literal && typeof key.value === "string" ? key.value : null;
|
|
14409
14845
|
if (name === null) {
|
|
14410
14846
|
return null;
|
|
14411
14847
|
}
|
|
@@ -14420,8 +14856,8 @@ var prefer_zod_infer_default = createRule({
|
|
|
14420
14856
|
return result.size === 0 ? null : result;
|
|
14421
14857
|
}
|
|
14422
14858
|
function collectConstrainedNames(node) {
|
|
14423
|
-
if (node.type ===
|
|
14424
|
-
if (node.typeName.type ===
|
|
14859
|
+
if (node.type === AST_NODE_TYPES63.TSTypeReference) {
|
|
14860
|
+
if (node.typeName.type === AST_NODE_TYPES63.Identifier) {
|
|
14425
14861
|
constrainedTypeNames.add(node.typeName.name);
|
|
14426
14862
|
}
|
|
14427
14863
|
for (const argument of node.typeArguments?.params ?? []) {
|
|
@@ -14429,11 +14865,11 @@ var prefer_zod_infer_default = createRule({
|
|
|
14429
14865
|
}
|
|
14430
14866
|
return;
|
|
14431
14867
|
}
|
|
14432
|
-
if (node.type ===
|
|
14868
|
+
if (node.type === AST_NODE_TYPES63.TSArrayType) {
|
|
14433
14869
|
collectConstrainedNames(node.elementType);
|
|
14434
14870
|
return;
|
|
14435
14871
|
}
|
|
14436
|
-
if (node.type ===
|
|
14872
|
+
if (node.type === AST_NODE_TYPES63.TSUnionType || node.type === AST_NODE_TYPES63.TSIntersectionType) {
|
|
14437
14873
|
for (const member of node.types) {
|
|
14438
14874
|
collectConstrainedNames(member);
|
|
14439
14875
|
}
|
|
@@ -14477,7 +14913,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
14477
14913
|
return {
|
|
14478
14914
|
Program(node) {
|
|
14479
14915
|
for (const statement of node.body) {
|
|
14480
|
-
if (statement.type ===
|
|
14916
|
+
if (statement.type === AST_NODE_TYPES63.ImportDeclaration) {
|
|
14481
14917
|
recordZodImport(statement);
|
|
14482
14918
|
}
|
|
14483
14919
|
}
|
|
@@ -14486,7 +14922,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
14486
14922
|
recordZodImport(node);
|
|
14487
14923
|
},
|
|
14488
14924
|
VariableDeclarator(node) {
|
|
14489
|
-
if (node.id.type !==
|
|
14925
|
+
if (node.id.type !== AST_NODE_TYPES63.Identifier || node.init == null) {
|
|
14490
14926
|
return;
|
|
14491
14927
|
}
|
|
14492
14928
|
const fields = schemaFields(node.init);
|
|
@@ -14503,14 +14939,14 @@ var prefer_zod_infer_default = createRule({
|
|
|
14503
14939
|
},
|
|
14504
14940
|
/** Records `XSchema.transform(...)` and equivalent module-level reshaping. */
|
|
14505
14941
|
"MemberExpression[computed=false]"(node) {
|
|
14506
|
-
if (node.object.type ===
|
|
14942
|
+
if (node.object.type === AST_NODE_TYPES63.Identifier && node.property.type === AST_NODE_TYPES63.Identifier && MODULE_LEVEL_RESHAPERS.has(node.property.name)) {
|
|
14507
14943
|
reshapedSchemaNames.add(node.object.name);
|
|
14508
14944
|
}
|
|
14509
14945
|
},
|
|
14510
14946
|
/** Records every type argument carried by a Zod constraint. */
|
|
14511
14947
|
TSTypeReference(node) {
|
|
14512
14948
|
const { typeName } = node;
|
|
14513
|
-
const referenced = typeName.type ===
|
|
14949
|
+
const referenced = typeName.type === AST_NODE_TYPES63.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES63.TSQualifiedName && typeName.right.type === AST_NODE_TYPES63.Identifier ? typeName.right.name : null;
|
|
14514
14950
|
if (referenced === null || !ZOD_TYPE_CONSTRAINTS.has(referenced)) {
|
|
14515
14951
|
return;
|
|
14516
14952
|
}
|
|
@@ -14542,7 +14978,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
14542
14978
|
typeName: node.id.name
|
|
14543
14979
|
});
|
|
14544
14980
|
}
|
|
14545
|
-
if (node.typeParameters !== void 0 || node.typeAnnotation.type !==
|
|
14981
|
+
if (node.typeParameters !== void 0 || node.typeAnnotation.type !== AST_NODE_TYPES63.TSTypeLiteral) {
|
|
14546
14982
|
return;
|
|
14547
14983
|
}
|
|
14548
14984
|
const members = typeMembers(node.typeAnnotation.members);
|
|
@@ -14643,7 +15079,7 @@ var prefer_zod_infer_default = createRule({
|
|
|
14643
15079
|
// src/rules/require-assert-never.ts
|
|
14644
15080
|
import {
|
|
14645
15081
|
ESLintUtils as ESLintUtils7,
|
|
14646
|
-
AST_NODE_TYPES as
|
|
15082
|
+
AST_NODE_TYPES as AST_NODE_TYPES64
|
|
14647
15083
|
} from "@typescript-eslint/utils";
|
|
14648
15084
|
import ts5 from "typescript";
|
|
14649
15085
|
var REQUIRE_ASSERT_NEVER_DOCUMENTATION = {
|
|
@@ -14657,14 +15093,14 @@ var REQUIRE_ASSERT_NEVER_DOCUMENTATION = {
|
|
|
14657
15093
|
]
|
|
14658
15094
|
};
|
|
14659
15095
|
var isRuntimeHandlingStatement = (statement) => {
|
|
14660
|
-
if (statement.type ===
|
|
14661
|
-
if (statement.type ===
|
|
15096
|
+
if (statement.type === AST_NODE_TYPES64.EmptyStatement) return false;
|
|
15097
|
+
if (statement.type === AST_NODE_TYPES64.BreakStatement) {
|
|
14662
15098
|
return statement.label !== null;
|
|
14663
15099
|
}
|
|
14664
|
-
if (statement.type ===
|
|
15100
|
+
if (statement.type === AST_NODE_TYPES64.TSTypeAliasDeclaration || statement.type === AST_NODE_TYPES64.TSInterfaceDeclaration) {
|
|
14665
15101
|
return false;
|
|
14666
15102
|
}
|
|
14667
|
-
if (statement.type ===
|
|
15103
|
+
if (statement.type === AST_NODE_TYPES64.BlockStatement) {
|
|
14668
15104
|
return statement.body.some(isRuntimeHandlingStatement);
|
|
14669
15105
|
}
|
|
14670
15106
|
return true;
|
|
@@ -14680,7 +15116,7 @@ var isCommentOnlyNoopDefault = (defaultCase, sourceCode) => {
|
|
|
14680
15116
|
return colonToken !== null && sourceCode.getCommentsAfter(colonToken).length > 0;
|
|
14681
15117
|
}
|
|
14682
15118
|
const only = defaultCase.consequent[0];
|
|
14683
|
-
if (only !== void 0 && defaultCase.consequent.length === 1 && only.type ===
|
|
15119
|
+
if (only !== void 0 && defaultCase.consequent.length === 1 && only.type === AST_NODE_TYPES64.BlockStatement && !only.body.some(isRuntimeHandlingStatement)) {
|
|
14684
15120
|
return sourceCode.getCommentsInside(only).length > 0;
|
|
14685
15121
|
}
|
|
14686
15122
|
return false;
|
|
@@ -14763,7 +15199,7 @@ var require_assert_never_default = createRule({
|
|
|
14763
15199
|
});
|
|
14764
15200
|
|
|
14765
15201
|
// src/rules/require-fetch-timeout.ts
|
|
14766
|
-
import { AST_NODE_TYPES as
|
|
15202
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES65, ASTUtils as ASTUtils20 } from "@typescript-eslint/utils";
|
|
14767
15203
|
var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
|
|
14768
15204
|
summary: "Require an abort `signal` (e.g. `AbortSignal.timeout(ms)`) on global `fetch()` calls so stalled upstreams cannot hang the caller forever.",
|
|
14769
15205
|
rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
|
|
@@ -14789,14 +15225,14 @@ function matchesAnyPattern3(filename, patterns) {
|
|
|
14789
15225
|
return false;
|
|
14790
15226
|
}
|
|
14791
15227
|
function initProvablyLacksSignal(init) {
|
|
14792
|
-
if (init.type !==
|
|
15228
|
+
if (init.type !== AST_NODE_TYPES65.ObjectExpression) {
|
|
14793
15229
|
return false;
|
|
14794
15230
|
}
|
|
14795
15231
|
for (const prop of init.properties) {
|
|
14796
|
-
if (prop.type ===
|
|
15232
|
+
if (prop.type === AST_NODE_TYPES65.SpreadElement) {
|
|
14797
15233
|
return false;
|
|
14798
15234
|
}
|
|
14799
|
-
if (prop.key.type ===
|
|
15235
|
+
if (prop.key.type === AST_NODE_TYPES65.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES65.Literal && prop.key.value === "signal") {
|
|
14800
15236
|
return false;
|
|
14801
15237
|
}
|
|
14802
15238
|
if (prop.computed) {
|
|
@@ -14806,7 +15242,7 @@ function initProvablyLacksSignal(init) {
|
|
|
14806
15242
|
return true;
|
|
14807
15243
|
}
|
|
14808
15244
|
function isInlineUrl(node, resolvesToGlobal) {
|
|
14809
|
-
return node.type ===
|
|
15245
|
+
return node.type === AST_NODE_TYPES65.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES65.TemplateLiteral || node.type === AST_NODE_TYPES65.NewExpression && node.callee.type === AST_NODE_TYPES65.Identifier && node.callee.name === "URL" && resolvesToGlobal(node.callee);
|
|
14810
15246
|
}
|
|
14811
15247
|
var require_fetch_timeout_default = createRule({
|
|
14812
15248
|
name: "require-fetch-timeout",
|
|
@@ -14844,30 +15280,30 @@ var require_fetch_timeout_default = createRule({
|
|
|
14844
15280
|
}
|
|
14845
15281
|
function resolvesToGlobal(identifier) {
|
|
14846
15282
|
const scope = context.sourceCode.getScope(identifier);
|
|
14847
|
-
const variable =
|
|
15283
|
+
const variable = ASTUtils20.findVariable(scope, identifier.name);
|
|
14848
15284
|
return variable === null || variable.defs.length === 0;
|
|
14849
15285
|
}
|
|
14850
15286
|
function isGlobalFetchCall2(callee) {
|
|
14851
|
-
if (callee.type ===
|
|
15287
|
+
if (callee.type === AST_NODE_TYPES65.Identifier) {
|
|
14852
15288
|
return callee.name === "fetch" && resolvesToGlobal(callee);
|
|
14853
15289
|
}
|
|
14854
|
-
return callee.type ===
|
|
15290
|
+
return callee.type === AST_NODE_TYPES65.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES65.Identifier && callee.property.name === "fetch" && callee.object.type === AST_NODE_TYPES65.Identifier && GLOBAL_OBJECTS2.has(callee.object.name) && resolvesToGlobal(callee.object);
|
|
14855
15291
|
}
|
|
14856
15292
|
function localConstInitProvablyLacksSignal(identifier) {
|
|
14857
|
-
const variable =
|
|
15293
|
+
const variable = ASTUtils20.findVariable(
|
|
14858
15294
|
context.sourceCode.getScope(identifier),
|
|
14859
15295
|
identifier.name
|
|
14860
15296
|
);
|
|
14861
15297
|
if (variable?.defs.length !== 1) return false;
|
|
14862
15298
|
const definition = variable.defs[0];
|
|
14863
|
-
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init?.type !==
|
|
15299
|
+
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init?.type !== AST_NODE_TYPES65.ObjectExpression || !initProvablyLacksSignal(definition.node.init)) {
|
|
14864
15300
|
return false;
|
|
14865
15301
|
}
|
|
14866
15302
|
for (const reference of variable.references) {
|
|
14867
15303
|
const ref = reference.identifier;
|
|
14868
15304
|
if (ref === identifier || ref === definition.name) continue;
|
|
14869
15305
|
const member = ref.parent;
|
|
14870
|
-
if (member.type !==
|
|
15306
|
+
if (member.type !== AST_NODE_TYPES65.MemberExpression || member.object !== ref || member.computed || member.property.type !== AST_NODE_TYPES65.Identifier || member.property.name === "signal" || member.parent.type !== AST_NODE_TYPES65.AssignmentExpression || member.parent.left !== member) {
|
|
14871
15307
|
return false;
|
|
14872
15308
|
}
|
|
14873
15309
|
}
|
|
@@ -14882,7 +15318,7 @@ var require_fetch_timeout_default = createRule({
|
|
|
14882
15318
|
if (node.arguments.length === 1 && first !== void 0 && !isInlineUrl(first, resolvesToGlobal)) {
|
|
14883
15319
|
return;
|
|
14884
15320
|
}
|
|
14885
|
-
if (init === void 0 || initProvablyLacksSignal(init) || init.type ===
|
|
15321
|
+
if (init === void 0 || initProvablyLacksSignal(init) || init.type === AST_NODE_TYPES65.Identifier && localConstInitProvablyLacksSignal(init)) {
|
|
14886
15322
|
context.report({ node, messageId: "missingSignal" });
|
|
14887
15323
|
}
|
|
14888
15324
|
}
|
|
@@ -14890,8 +15326,141 @@ var require_fetch_timeout_default = createRule({
|
|
|
14890
15326
|
}
|
|
14891
15327
|
});
|
|
14892
15328
|
|
|
15329
|
+
// src/rules/require-interface-for-exported-class.ts
|
|
15330
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES66 } from "@typescript-eslint/utils";
|
|
15331
|
+
var REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION = {
|
|
15332
|
+
summary: "Require exported concrete classes with public behavior to declare a contract.",
|
|
15333
|
+
rationale: "Consumers coupled only to a concrete class cannot substitute implementations or state the supported public capability independently of implementation details.",
|
|
15334
|
+
remediation: "Declare a focused interface and add an implements clause, or inherit from an intentional base contract.",
|
|
15335
|
+
category: "architecture",
|
|
15336
|
+
limitations: [
|
|
15337
|
+
"The warning-stage rule checks module-level class declarations and direct class-expression values exported directly, through local export specifiers, or through a default identifier; re-exports and expressions wrapped in other calls require review.",
|
|
15338
|
+
"An extends clause satisfies the contract only when its target is a locally declared abstract class; imported base-class contracts require an explicit implements clause.",
|
|
15339
|
+
"Static factories and data-only classes without public instance methods are outside the contract requirement."
|
|
15340
|
+
],
|
|
15341
|
+
examples: [
|
|
15342
|
+
{
|
|
15343
|
+
id: "implemented-store-contract",
|
|
15344
|
+
title: "Export behavior through a focused contract",
|
|
15345
|
+
outcome: "no-match",
|
|
15346
|
+
files: [
|
|
15347
|
+
{
|
|
15348
|
+
path: "src/artifact-store.ts",
|
|
15349
|
+
source: "export interface ArtifactStorage { read(id: string): Promise<Uint8Array>; } export class ArtifactStore implements ArtifactStorage { async read(id: string) { return new Uint8Array(); } }"
|
|
15350
|
+
}
|
|
15351
|
+
],
|
|
15352
|
+
focusPath: "src/artifact-store.ts",
|
|
15353
|
+
expectedCount: 0,
|
|
15354
|
+
public: true
|
|
15355
|
+
},
|
|
15356
|
+
{
|
|
15357
|
+
id: "concrete-only-store",
|
|
15358
|
+
title: "Do not export behavior only through a concrete class",
|
|
15359
|
+
outcome: "match",
|
|
15360
|
+
files: [
|
|
15361
|
+
{
|
|
15362
|
+
path: "src/artifact-store.ts",
|
|
15363
|
+
source: "export class ArtifactStore { async read(id: string) { return new Uint8Array(); } }"
|
|
15364
|
+
}
|
|
15365
|
+
],
|
|
15366
|
+
focusPath: "src/artifact-store.ts",
|
|
15367
|
+
expectedCount: 1,
|
|
15368
|
+
public: true
|
|
15369
|
+
}
|
|
15370
|
+
]
|
|
15371
|
+
};
|
|
15372
|
+
function hasPublicInstanceBehavior(node) {
|
|
15373
|
+
return node.body.body.some((member) => {
|
|
15374
|
+
if (member.type === AST_NODE_TYPES66.MethodDefinition) {
|
|
15375
|
+
return member.kind !== "constructor" && !member.static && member.accessibility !== "private" && member.accessibility !== "protected" && member.key.type !== AST_NODE_TYPES66.PrivateIdentifier;
|
|
15376
|
+
}
|
|
15377
|
+
if (member.type !== AST_NODE_TYPES66.PropertyDefinition || member.static)
|
|
15378
|
+
return false;
|
|
15379
|
+
if (member.accessibility === "private" || member.accessibility === "protected" || member.key.type === AST_NODE_TYPES66.PrivateIdentifier) return false;
|
|
15380
|
+
return member.value?.type === AST_NODE_TYPES66.ArrowFunctionExpression || member.value?.type === AST_NODE_TYPES66.FunctionExpression || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES66.TSFunctionType;
|
|
15381
|
+
});
|
|
15382
|
+
}
|
|
15383
|
+
function classBindings(statement) {
|
|
15384
|
+
const declaration = statement.type === AST_NODE_TYPES66.ExportNamedDeclaration ? statement.declaration : statement;
|
|
15385
|
+
if (declaration?.type === AST_NODE_TYPES66.ClassDeclaration) {
|
|
15386
|
+
return declaration.id === null ? [] : [{ declaration, name: declaration.id.name }];
|
|
15387
|
+
}
|
|
15388
|
+
if (declaration?.type !== AST_NODE_TYPES66.VariableDeclaration) return [];
|
|
15389
|
+
return declaration.declarations.flatMap(
|
|
15390
|
+
(item) => item.id.type === AST_NODE_TYPES66.Identifier && item.init?.type === AST_NODE_TYPES66.ClassExpression ? [{ declaration: item.init, name: item.id.name }] : []
|
|
15391
|
+
);
|
|
15392
|
+
}
|
|
15393
|
+
var require_interface_for_exported_class_default = createRule({
|
|
15394
|
+
name: "require-interface-for-exported-class",
|
|
15395
|
+
documentation: REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION,
|
|
15396
|
+
meta: {
|
|
15397
|
+
type: "suggestion",
|
|
15398
|
+
docs: {
|
|
15399
|
+
description: "Require exported concrete classes with public behavior to declare a contract."
|
|
15400
|
+
},
|
|
15401
|
+
schema: [],
|
|
15402
|
+
messages: {
|
|
15403
|
+
requireContract: "Exported class `{{name}}` has public behavior but no declared interface or base contract; add a focused contract and implement it."
|
|
15404
|
+
}
|
|
15405
|
+
},
|
|
15406
|
+
defaultOptions: [],
|
|
15407
|
+
create(context) {
|
|
15408
|
+
if (isTestFile(context.filename) || isStoryFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
15409
|
+
return {
|
|
15410
|
+
"Program:exit"(program) {
|
|
15411
|
+
const classes = /* @__PURE__ */ new Map();
|
|
15412
|
+
const abstractBases = /* @__PURE__ */ new Set();
|
|
15413
|
+
for (const statement of program.body) {
|
|
15414
|
+
for (const binding of classBindings(statement)) {
|
|
15415
|
+
classes.set(binding.name, binding.declaration);
|
|
15416
|
+
if (binding.declaration.abstract) abstractBases.add(binding.name);
|
|
15417
|
+
}
|
|
15418
|
+
}
|
|
15419
|
+
const exported = /* @__PURE__ */ new Map();
|
|
15420
|
+
for (const statement of program.body) {
|
|
15421
|
+
if (statement.type === AST_NODE_TYPES66.ExportNamedDeclaration) {
|
|
15422
|
+
for (const binding of classBindings(statement)) {
|
|
15423
|
+
exported.set(binding.declaration, binding.name);
|
|
15424
|
+
}
|
|
15425
|
+
if (statement.source !== null || statement.exportKind === "type") continue;
|
|
15426
|
+
for (const specifier of statement.specifiers) {
|
|
15427
|
+
if (specifier.exportKind === "type") continue;
|
|
15428
|
+
const candidate2 = classes.get(specifier.local.name);
|
|
15429
|
+
if (candidate2 === void 0) continue;
|
|
15430
|
+
const exportedName = specifier.exported.type === AST_NODE_TYPES66.Identifier ? specifier.exported.name : specifier.exported.value;
|
|
15431
|
+
exported.set(candidate2, exportedName);
|
|
15432
|
+
}
|
|
15433
|
+
continue;
|
|
15434
|
+
}
|
|
15435
|
+
if (statement.type !== AST_NODE_TYPES66.ExportDefaultDeclaration) continue;
|
|
15436
|
+
if (statement.declaration.type === AST_NODE_TYPES66.ClassDeclaration || statement.declaration.type === AST_NODE_TYPES66.ClassExpression) {
|
|
15437
|
+
exported.set(
|
|
15438
|
+
statement.declaration,
|
|
15439
|
+
statement.declaration.id?.name ?? "default"
|
|
15440
|
+
);
|
|
15441
|
+
} else if (statement.declaration.type === AST_NODE_TYPES66.Identifier) {
|
|
15442
|
+
const candidate2 = classes.get(statement.declaration.name);
|
|
15443
|
+
if (candidate2 !== void 0) {
|
|
15444
|
+
exported.set(candidate2, statement.declaration.name);
|
|
15445
|
+
}
|
|
15446
|
+
}
|
|
15447
|
+
}
|
|
15448
|
+
for (const [declaration, exportedName] of exported) {
|
|
15449
|
+
const extendsLocalAbstractBase = declaration.superClass?.type === AST_NODE_TYPES66.Identifier && abstractBases.has(declaration.superClass.name);
|
|
15450
|
+
if (declaration.abstract || declaration.implements.length > 0 || extendsLocalAbstractBase || !hasPublicInstanceBehavior(declaration)) continue;
|
|
15451
|
+
context.report({
|
|
15452
|
+
node: declaration.id ?? declaration,
|
|
15453
|
+
messageId: "requireContract",
|
|
15454
|
+
data: { name: exportedName }
|
|
15455
|
+
});
|
|
15456
|
+
}
|
|
15457
|
+
}
|
|
15458
|
+
};
|
|
15459
|
+
}
|
|
15460
|
+
});
|
|
15461
|
+
|
|
14893
15462
|
// src/rules/require-port-for-service.ts
|
|
14894
|
-
import { AST_NODE_TYPES as
|
|
15463
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES67 } from "@typescript-eslint/utils";
|
|
14895
15464
|
var REQUIRE_PORT_FOR_SERVICE_DOCUMENTATION = {
|
|
14896
15465
|
summary: "Advise when an exported service with injected collaborators has public methods not covered by its declared ports.",
|
|
14897
15466
|
rationale: "A declared port keeps consumers coupled to the service capability instead of its concrete implementation.",
|
|
@@ -14916,45 +15485,45 @@ var ROUTER_FACTORY_NAME = "Router";
|
|
|
14916
15485
|
var FRAMEWORK_HTTP_TYPES = /* @__PURE__ */ new Set(["Request", "Response", "NextFunction"]);
|
|
14917
15486
|
var STORAGE_ASSIGNMENT_OPERATORS = /* @__PURE__ */ new Set(["=", "&&=", "??=", "||="]);
|
|
14918
15487
|
var staticMemberName6 = (member) => {
|
|
14919
|
-
if (member.property.type ===
|
|
14920
|
-
if (!member.computed && member.property.type ===
|
|
14921
|
-
return member.computed && member.property.type ===
|
|
15488
|
+
if (member.property.type === AST_NODE_TYPES67.PrivateIdentifier) return `#${member.property.name}`;
|
|
15489
|
+
if (!member.computed && member.property.type === AST_NODE_TYPES67.Identifier) return member.property.name;
|
|
15490
|
+
return member.computed && member.property.type === AST_NODE_TYPES67.Literal && typeof member.property.value === "string" ? member.property.value : null;
|
|
14922
15491
|
};
|
|
14923
15492
|
var detachedValueExports = (program) => {
|
|
14924
15493
|
const names = /* @__PURE__ */ new Set();
|
|
14925
15494
|
for (const statement of program.body) {
|
|
14926
|
-
if (statement.type ===
|
|
15495
|
+
if (statement.type === AST_NODE_TYPES67.ExportNamedDeclaration && statement.declaration === null && statement.source === null && statement.exportKind !== "type") {
|
|
14927
15496
|
for (const specifier of statement.specifiers) {
|
|
14928
15497
|
if (specifier.exportKind !== "type") names.add(specifier.local.name);
|
|
14929
15498
|
}
|
|
14930
|
-
} else if (statement.type ===
|
|
15499
|
+
} else if (statement.type === AST_NODE_TYPES67.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES67.Identifier) {
|
|
14931
15500
|
names.add(statement.declaration.name);
|
|
14932
|
-
} else if (statement.type ===
|
|
15501
|
+
} else if (statement.type === AST_NODE_TYPES67.TSExportAssignment && statement.expression.type === AST_NODE_TYPES67.Identifier) {
|
|
14933
15502
|
names.add(statement.expression.name);
|
|
14934
15503
|
}
|
|
14935
15504
|
}
|
|
14936
15505
|
return names;
|
|
14937
15506
|
};
|
|
14938
|
-
var isExportedClass2 = (node, detached) => node.parent.type ===
|
|
15507
|
+
var isExportedClass2 = (node, detached) => node.parent.type === AST_NODE_TYPES67.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES67.ExportDefaultDeclaration || node.id !== null && detached.has(node.id.name);
|
|
14939
15508
|
var readTypeReference = (annotation) => {
|
|
14940
|
-
if (annotation?.type ===
|
|
15509
|
+
if (annotation?.type === AST_NODE_TYPES67.TSUnionType) {
|
|
14941
15510
|
const members = annotation.types.filter(
|
|
14942
|
-
(member) => member.type !==
|
|
15511
|
+
(member) => member.type !== AST_NODE_TYPES67.TSUndefinedKeyword && member.type !== AST_NODE_TYPES67.TSNullKeyword
|
|
14943
15512
|
);
|
|
14944
15513
|
annotation = members.length === 1 ? members[0] : void 0;
|
|
14945
15514
|
}
|
|
14946
|
-
if (annotation === void 0 || annotation.type !==
|
|
15515
|
+
if (annotation === void 0 || annotation.type !== AST_NODE_TYPES67.TSTypeReference) return null;
|
|
14947
15516
|
const { typeName } = annotation;
|
|
14948
|
-
const rightmost = typeName.type ===
|
|
15517
|
+
const rightmost = typeName.type === AST_NODE_TYPES67.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES67.TSQualifiedName ? typeName.right.name : null;
|
|
14949
15518
|
if (rightmost === null) return null;
|
|
14950
15519
|
return { typeName: rightmost, display: qualifiedName(typeName) };
|
|
14951
15520
|
};
|
|
14952
|
-
var qualifiedName = (name) => name.type ===
|
|
15521
|
+
var qualifiedName = (name) => name.type === AST_NODE_TYPES67.Identifier ? name.name : name.type === AST_NODE_TYPES67.TSQualifiedName ? `${qualifiedName(name.left)}.${name.right.name}` : "";
|
|
14953
15522
|
var propertySignatureTypes = (members) => {
|
|
14954
15523
|
const types = /* @__PURE__ */ new Map();
|
|
14955
15524
|
for (const member of members) {
|
|
14956
|
-
if (member.type !==
|
|
14957
|
-
if (member.computed || member.key.type !==
|
|
15525
|
+
if (member.type !== AST_NODE_TYPES67.TSPropertySignature) continue;
|
|
15526
|
+
if (member.computed || member.key.type !== AST_NODE_TYPES67.Identifier) continue;
|
|
14958
15527
|
const reference = readTypeReference(member.typeAnnotation?.typeAnnotation);
|
|
14959
15528
|
if (reference === null) continue;
|
|
14960
15529
|
types.set(member.key.name, reference);
|
|
@@ -14965,18 +15534,18 @@ var fileTypeIndex = (program) => {
|
|
|
14965
15534
|
const objects = /* @__PURE__ */ new Map();
|
|
14966
15535
|
const functionAliases = /* @__PURE__ */ new Set();
|
|
14967
15536
|
for (const statement of program.body) {
|
|
14968
|
-
const declaration = statement.type ===
|
|
14969
|
-
if (declaration?.type ===
|
|
15537
|
+
const declaration = statement.type === AST_NODE_TYPES67.ExportNamedDeclaration ? statement.declaration : statement;
|
|
15538
|
+
if (declaration?.type === AST_NODE_TYPES67.TSInterfaceDeclaration) {
|
|
14970
15539
|
objects.set(declaration.id.name, propertySignatureTypes(declaration.body.body));
|
|
14971
15540
|
continue;
|
|
14972
15541
|
}
|
|
14973
|
-
if (declaration?.type !==
|
|
15542
|
+
if (declaration?.type !== AST_NODE_TYPES67.TSTypeAliasDeclaration) continue;
|
|
14974
15543
|
const aliased = declaration.typeAnnotation;
|
|
14975
|
-
if (aliased.type ===
|
|
15544
|
+
if (aliased.type === AST_NODE_TYPES67.TSFunctionType || aliased.type === AST_NODE_TYPES67.TSConstructorType) {
|
|
14976
15545
|
functionAliases.add(declaration.id.name);
|
|
14977
15546
|
continue;
|
|
14978
15547
|
}
|
|
14979
|
-
const literals = aliased.type ===
|
|
15548
|
+
const literals = aliased.type === AST_NODE_TYPES67.TSTypeLiteral ? [aliased] : aliased.type === AST_NODE_TYPES67.TSIntersectionType ? aliased.types.filter((part) => part.type === AST_NODE_TYPES67.TSTypeLiteral) : [];
|
|
14980
15549
|
if (literals.length === 0) continue;
|
|
14981
15550
|
const merged = /* @__PURE__ */ new Map();
|
|
14982
15551
|
for (const literal of literals) {
|
|
@@ -15005,10 +15574,10 @@ var readConstructor = (ctor, declared, typeParameters) => {
|
|
|
15005
15574
|
while (pending.length > 0) {
|
|
15006
15575
|
const current = pending.pop();
|
|
15007
15576
|
if (current === void 0) break;
|
|
15008
|
-
if (current.type ===
|
|
15009
|
-
const expression = current.type ===
|
|
15010
|
-
const storedField = expression?.type ===
|
|
15011
|
-
if (expression?.type !==
|
|
15577
|
+
if (current.type === AST_NODE_TYPES67.ArrowFunctionExpression || current.type === AST_NODE_TYPES67.FunctionExpression || current.type === AST_NODE_TYPES67.FunctionDeclaration || current.type === AST_NODE_TYPES67.ClassExpression || current.type === AST_NODE_TYPES67.ClassDeclaration) continue;
|
|
15578
|
+
const expression = current.type === AST_NODE_TYPES67.ExpressionStatement ? current.expression : null;
|
|
15579
|
+
const storedField = expression?.type === AST_NODE_TYPES67.AssignmentExpression && expression.left.type === AST_NODE_TYPES67.MemberExpression && expression.left.object.type === AST_NODE_TYPES67.ThisExpression ? staticMemberName6(expression.left) : null;
|
|
15580
|
+
if (expression?.type !== AST_NODE_TYPES67.AssignmentExpression || !STORAGE_ASSIGNMENT_OPERATORS.has(expression.operator) || expression.left.type !== AST_NODE_TYPES67.MemberExpression || expression.left.object.type !== AST_NODE_TYPES67.ThisExpression || storedField === null) {
|
|
15012
15581
|
for (const key of Object.keys(current)) {
|
|
15013
15582
|
if (key === "parent") continue;
|
|
15014
15583
|
const value = current[key];
|
|
@@ -15021,14 +15590,14 @@ var readConstructor = (ctor, declared, typeParameters) => {
|
|
|
15021
15590
|
continue;
|
|
15022
15591
|
}
|
|
15023
15592
|
let source = expression.right;
|
|
15024
|
-
while (source.type ===
|
|
15025
|
-
if (source.type ===
|
|
15593
|
+
while (source.type === AST_NODE_TYPES67.TSNonNullExpression || source.type === AST_NODE_TYPES67.TSAsExpression || source.type === AST_NODE_TYPES67.TSSatisfiesExpression || source.type === AST_NODE_TYPES67.TSTypeAssertion) source = source.expression;
|
|
15594
|
+
if (source.type === AST_NODE_TYPES67.NewExpression) {
|
|
15026
15595
|
constructedFields += 1;
|
|
15027
|
-
} else if (source.type ===
|
|
15596
|
+
} else if (source.type === AST_NODE_TYPES67.Identifier) {
|
|
15028
15597
|
const fields = storedFieldsFrom.get(source.name) ?? /* @__PURE__ */ new Set();
|
|
15029
15598
|
fields.add(storedField);
|
|
15030
15599
|
storedFieldsFrom.set(source.name, fields);
|
|
15031
|
-
} else if (source.type ===
|
|
15600
|
+
} else if (source.type === AST_NODE_TYPES67.MemberExpression && source.object.type === AST_NODE_TYPES67.Identifier) {
|
|
15032
15601
|
const fields = storedFieldsFrom.get(source.object.name) ?? /* @__PURE__ */ new Set();
|
|
15033
15602
|
fields.add(storedField);
|
|
15034
15603
|
storedFieldsFrom.set(source.object.name, fields);
|
|
@@ -15046,7 +15615,7 @@ var readConstructor = (ctor, declared, typeParameters) => {
|
|
|
15046
15615
|
const collaborators = [];
|
|
15047
15616
|
for (const parameter of ctor.value.params) {
|
|
15048
15617
|
for (const reference of parameterCollaborators(parameter, declared, storedMemberFieldsFrom)) {
|
|
15049
|
-
const fields = parameter.type ===
|
|
15618
|
+
const fields = parameter.type === AST_NODE_TYPES67.TSParameterProperty ? [reference.name] : reference.fields.length > 0 ? reference.fields : [...storedFieldsFrom.get(reference.name) ?? []];
|
|
15050
15619
|
if (fields.length === 0) continue;
|
|
15051
15620
|
if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
|
|
15052
15621
|
if (CONFIGISH_NAME_RE.test(reference.name)) continue;
|
|
@@ -15061,8 +15630,8 @@ var readConstructor = (ctor, declared, typeParameters) => {
|
|
|
15061
15630
|
};
|
|
15062
15631
|
var parameterCollaborators = (parameter, declared, storedMemberFieldsFrom) => {
|
|
15063
15632
|
let target = parameter;
|
|
15064
|
-
if (target.type ===
|
|
15065
|
-
if (target.type ===
|
|
15633
|
+
if (target.type === AST_NODE_TYPES67.AssignmentPattern) target = target.left;
|
|
15634
|
+
if (target.type === AST_NODE_TYPES67.ObjectPattern) {
|
|
15066
15635
|
return objectPatternCollaborators(target, declared);
|
|
15067
15636
|
}
|
|
15068
15637
|
const named2 = namedParameterCollaborator(parameter);
|
|
@@ -15071,9 +15640,9 @@ var parameterCollaborators = (parameter, declared, storedMemberFieldsFrom) => {
|
|
|
15071
15640
|
};
|
|
15072
15641
|
var namedBagCollaborators = (annotated, declared, storedMemberFieldsFrom) => {
|
|
15073
15642
|
let target = annotated;
|
|
15074
|
-
if (target.type ===
|
|
15075
|
-
if (target.type ===
|
|
15076
|
-
if (target.type !==
|
|
15643
|
+
if (target.type === AST_NODE_TYPES67.TSParameterProperty) target = target.parameter;
|
|
15644
|
+
if (target.type === AST_NODE_TYPES67.AssignmentPattern) target = target.left;
|
|
15645
|
+
if (target.type !== AST_NODE_TYPES67.Identifier) return [];
|
|
15077
15646
|
const members = bagMemberTypes(target.typeAnnotation?.typeAnnotation, declared);
|
|
15078
15647
|
if (members === null) return [];
|
|
15079
15648
|
const storedMembers = storedMemberFieldsFrom.get(target.name);
|
|
@@ -15089,9 +15658,9 @@ var namedBagCollaborators = (annotated, declared, storedMemberFieldsFrom) => {
|
|
|
15089
15658
|
};
|
|
15090
15659
|
var namedParameterCollaborator = (annotated) => {
|
|
15091
15660
|
let target = annotated;
|
|
15092
|
-
if (target.type ===
|
|
15093
|
-
if (target.type ===
|
|
15094
|
-
if (target.type !==
|
|
15661
|
+
if (target.type === AST_NODE_TYPES67.TSParameterProperty) target = target.parameter;
|
|
15662
|
+
if (target.type === AST_NODE_TYPES67.AssignmentPattern) target = target.left;
|
|
15663
|
+
if (target.type !== AST_NODE_TYPES67.Identifier) return null;
|
|
15095
15664
|
const reference = readTypeReference(target.typeAnnotation?.typeAnnotation);
|
|
15096
15665
|
if (reference === null) return null;
|
|
15097
15666
|
return { name: target.name, ...reference, fields: [] };
|
|
@@ -15103,11 +15672,11 @@ var objectPatternCollaborators = (pattern, declared) => {
|
|
|
15103
15672
|
if (members === null) return [];
|
|
15104
15673
|
const collaborators = [];
|
|
15105
15674
|
for (const property of pattern.properties) {
|
|
15106
|
-
if (property.type !==
|
|
15107
|
-
if (property.key.type !==
|
|
15675
|
+
if (property.type !== AST_NODE_TYPES67.Property || property.computed) continue;
|
|
15676
|
+
if (property.key.type !== AST_NODE_TYPES67.Identifier) continue;
|
|
15108
15677
|
const key = property.key.name;
|
|
15109
|
-
const bound = property.value.type ===
|
|
15110
|
-
if (bound.type !==
|
|
15678
|
+
const bound = property.value.type === AST_NODE_TYPES67.AssignmentPattern ? property.value.left : property.value;
|
|
15679
|
+
if (bound.type !== AST_NODE_TYPES67.Identifier) continue;
|
|
15111
15680
|
if (CONFIGISH_NAME_RE.test(key)) continue;
|
|
15112
15681
|
const reference = members.get(key);
|
|
15113
15682
|
if (reference === void 0) continue;
|
|
@@ -15117,21 +15686,21 @@ var objectPatternCollaborators = (pattern, declared) => {
|
|
|
15117
15686
|
};
|
|
15118
15687
|
var bagMemberTypes = (annotation, declared) => {
|
|
15119
15688
|
if (annotation === void 0) return null;
|
|
15120
|
-
if (annotation.type ===
|
|
15689
|
+
if (annotation.type === AST_NODE_TYPES67.TSTypeLiteral) {
|
|
15121
15690
|
return propertySignatureTypes(annotation.members);
|
|
15122
15691
|
}
|
|
15123
|
-
if (annotation.type !==
|
|
15692
|
+
if (annotation.type !== AST_NODE_TYPES67.TSTypeReference || annotation.typeName.type !== AST_NODE_TYPES67.Identifier) {
|
|
15124
15693
|
return null;
|
|
15125
15694
|
}
|
|
15126
15695
|
return declared().objects.get(annotation.typeName.name) ?? null;
|
|
15127
15696
|
};
|
|
15128
15697
|
var isFrameworkWiring = (body2) => subtreeHas(body2, (node) => {
|
|
15129
|
-
if (node.type ===
|
|
15698
|
+
if (node.type === AST_NODE_TYPES67.CallExpression) {
|
|
15130
15699
|
const { callee } = node;
|
|
15131
|
-
if (callee.type ===
|
|
15132
|
-
return callee.type ===
|
|
15700
|
+
if (callee.type === AST_NODE_TYPES67.Identifier) return callee.name === ROUTER_FACTORY_NAME;
|
|
15701
|
+
return callee.type === AST_NODE_TYPES67.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES67.Identifier && callee.property.name === ROUTER_FACTORY_NAME;
|
|
15133
15702
|
}
|
|
15134
|
-
return node.type ===
|
|
15703
|
+
return node.type === AST_NODE_TYPES67.TSTypeReference && node.typeName.type === AST_NODE_TYPES67.TSQualifiedName && FRAMEWORK_HTTP_TYPES.has(node.typeName.right.name);
|
|
15135
15704
|
});
|
|
15136
15705
|
var subtreeHas = (root, found) => {
|
|
15137
15706
|
let hit = false;
|
|
@@ -15158,19 +15727,19 @@ var invokedInstanceField = (call) => {
|
|
|
15158
15727
|
const direct = instanceField(call.callee);
|
|
15159
15728
|
if (direct !== null) return direct;
|
|
15160
15729
|
let callee = call.callee;
|
|
15161
|
-
while (callee.type ===
|
|
15162
|
-
return callee.type ===
|
|
15730
|
+
while (callee.type === AST_NODE_TYPES67.ChainExpression || callee.type === AST_NODE_TYPES67.TSAsExpression || callee.type === AST_NODE_TYPES67.TSNonNullExpression || callee.type === AST_NODE_TYPES67.TSSatisfiesExpression || callee.type === AST_NODE_TYPES67.TSTypeAssertion) callee = callee.expression;
|
|
15731
|
+
return callee.type === AST_NODE_TYPES67.MemberExpression ? instanceField(callee.object) : null;
|
|
15163
15732
|
};
|
|
15164
15733
|
var instanceField = (candidate2) => {
|
|
15165
15734
|
let node = candidate2;
|
|
15166
|
-
while (node.type ===
|
|
15167
|
-
return node.type ===
|
|
15735
|
+
while (node.type === AST_NODE_TYPES67.ChainExpression || node.type === AST_NODE_TYPES67.TSAsExpression || node.type === AST_NODE_TYPES67.TSNonNullExpression || node.type === AST_NODE_TYPES67.TSSatisfiesExpression || node.type === AST_NODE_TYPES67.TSTypeAssertion) node = node.expression;
|
|
15736
|
+
return node.type === AST_NODE_TYPES67.MemberExpression && node.object.type === AST_NODE_TYPES67.ThisExpression ? staticMemberName6(node) : null;
|
|
15168
15737
|
};
|
|
15169
15738
|
var behaviorallyInvokedFields = (body2) => {
|
|
15170
15739
|
const invoked = /* @__PURE__ */ new Set();
|
|
15171
15740
|
const visit = (current) => {
|
|
15172
|
-
if (current.type ===
|
|
15173
|
-
if (current.type ===
|
|
15741
|
+
if (current.type === AST_NODE_TYPES67.ClassDeclaration || current.type === AST_NODE_TYPES67.ClassExpression || current.type === AST_NODE_TYPES67.FunctionDeclaration || current.type === AST_NODE_TYPES67.FunctionExpression) return;
|
|
15742
|
+
if (current.type === AST_NODE_TYPES67.CallExpression) {
|
|
15174
15743
|
const field = invokedInstanceField(current);
|
|
15175
15744
|
if (field !== null) invoked.add(field);
|
|
15176
15745
|
}
|
|
@@ -15183,14 +15752,14 @@ var behaviorallyInvokedFields = (body2) => {
|
|
|
15183
15752
|
}
|
|
15184
15753
|
};
|
|
15185
15754
|
for (const member of body2.body) {
|
|
15186
|
-
if (member.type ===
|
|
15187
|
-
if (member.type ===
|
|
15755
|
+
if (member.type === AST_NODE_TYPES67.StaticBlock || member.static) continue;
|
|
15756
|
+
if (member.type === AST_NODE_TYPES67.MethodDefinition) {
|
|
15188
15757
|
if (member.value.body !== null && member.value.body !== void 0) visit(member.value.body);
|
|
15189
15758
|
continue;
|
|
15190
15759
|
}
|
|
15191
|
-
if (member.type !==
|
|
15760
|
+
if (member.type !== AST_NODE_TYPES67.PropertyDefinition || member.value === null) continue;
|
|
15192
15761
|
visit(
|
|
15193
|
-
member.value.type ===
|
|
15762
|
+
member.value.type === AST_NODE_TYPES67.ArrowFunctionExpression ? member.value.body : member.value
|
|
15194
15763
|
);
|
|
15195
15764
|
}
|
|
15196
15765
|
return invoked;
|
|
@@ -15210,25 +15779,26 @@ var isTransportWrapper = (className, collaborators, program) => {
|
|
|
15210
15779
|
var fileInterfaceNames = (program) => {
|
|
15211
15780
|
const names = [];
|
|
15212
15781
|
for (const statement of program.body) {
|
|
15213
|
-
const declaration = statement.type ===
|
|
15214
|
-
if (declaration?.type ===
|
|
15782
|
+
const declaration = statement.type === AST_NODE_TYPES67.ExportNamedDeclaration ? statement.declaration : statement;
|
|
15783
|
+
if (declaration?.type === AST_NODE_TYPES67.TSInterfaceDeclaration) names.push(declaration.id.name);
|
|
15215
15784
|
}
|
|
15216
15785
|
return names;
|
|
15217
15786
|
};
|
|
15218
15787
|
var publicMethodNames = (body2, functionAliases) => {
|
|
15219
15788
|
const names = [];
|
|
15220
15789
|
for (const member of body2.body) {
|
|
15221
|
-
if (member.type ===
|
|
15790
|
+
if (member.type === AST_NODE_TYPES67.PropertyDefinition) {
|
|
15222
15791
|
if (member.static || member.accessibility === "private" || member.accessibility === "protected") continue;
|
|
15223
|
-
if (member.
|
|
15224
|
-
|
|
15792
|
+
if (member.key.type === AST_NODE_TYPES67.PrivateIdentifier) continue;
|
|
15793
|
+
if (member.value?.type !== AST_NODE_TYPES67.ArrowFunctionExpression && member.value?.type !== AST_NODE_TYPES67.FunctionExpression && member.typeAnnotation?.typeAnnotation.type !== AST_NODE_TYPES67.TSFunctionType && !(member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES67.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === AST_NODE_TYPES67.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name))) continue;
|
|
15794
|
+
names.push(member.key.type === AST_NODE_TYPES67.Identifier ? member.key.name : "\u2026");
|
|
15225
15795
|
continue;
|
|
15226
15796
|
}
|
|
15227
|
-
if (member.type !==
|
|
15797
|
+
if (member.type !== AST_NODE_TYPES67.MethodDefinition) continue;
|
|
15228
15798
|
if (member.kind !== "method" || member.static) continue;
|
|
15229
15799
|
if (member.accessibility === "private" || member.accessibility === "protected") continue;
|
|
15230
|
-
if (member.key.type ===
|
|
15231
|
-
if (member.key.type ===
|
|
15800
|
+
if (member.key.type === AST_NODE_TYPES67.PrivateIdentifier) continue;
|
|
15801
|
+
if (member.key.type === AST_NODE_TYPES67.Identifier) names.push(member.key.name);
|
|
15232
15802
|
else names.push("\u2026");
|
|
15233
15803
|
}
|
|
15234
15804
|
return names;
|
|
@@ -15236,13 +15806,13 @@ var publicMethodNames = (body2, functionAliases) => {
|
|
|
15236
15806
|
var isFluentConstructionObject = (node, getText) => {
|
|
15237
15807
|
if (node.id === null) return false;
|
|
15238
15808
|
const methods = node.body.body.filter(
|
|
15239
|
-
(member) => member.type ===
|
|
15809
|
+
(member) => member.type === AST_NODE_TYPES67.MethodDefinition && member.kind === "method" && !member.static && member.accessibility !== "private" && member.accessibility !== "protected" && member.value.body !== null
|
|
15240
15810
|
);
|
|
15241
15811
|
if (methods.length === 0) return false;
|
|
15242
15812
|
return methods.every((member) => {
|
|
15243
15813
|
const result = member.value.returnType?.typeAnnotation;
|
|
15244
15814
|
if (result === void 0) return false;
|
|
15245
|
-
const returnsOwnType = result.type ===
|
|
15815
|
+
const returnsOwnType = result.type === AST_NODE_TYPES67.TSTypeReference && result.typeName.type === AST_NODE_TYPES67.Identifier && result.typeName.name === node.id?.name;
|
|
15246
15816
|
return returnsOwnType || FLUENT_BUILDER_NAME_RE.test(node.id?.name ?? "") && FLUENT_RESULT_TYPE_RE.test(getText(result));
|
|
15247
15817
|
});
|
|
15248
15818
|
};
|
|
@@ -15250,10 +15820,10 @@ function localClassAbstractness(program) {
|
|
|
15250
15820
|
const classes = /* @__PURE__ */ new Map();
|
|
15251
15821
|
const parents = /* @__PURE__ */ new Map();
|
|
15252
15822
|
for (const statement of program.body) {
|
|
15253
|
-
const declaration = statement.type ===
|
|
15254
|
-
if (declaration?.type ===
|
|
15823
|
+
const declaration = statement.type === AST_NODE_TYPES67.ExportNamedDeclaration || statement.type === AST_NODE_TYPES67.ExportDefaultDeclaration ? statement.declaration : statement;
|
|
15824
|
+
if (declaration?.type === AST_NODE_TYPES67.ClassDeclaration && declaration.id !== null) {
|
|
15255
15825
|
classes.set(declaration.id.name, declaration.abstract === true);
|
|
15256
|
-
if (declaration.superClass?.type ===
|
|
15826
|
+
if (declaration.superClass?.type === AST_NODE_TYPES67.Identifier) {
|
|
15257
15827
|
parents.set(declaration.id.name, declaration.superClass.name);
|
|
15258
15828
|
}
|
|
15259
15829
|
}
|
|
@@ -15275,43 +15845,43 @@ function localInterfaceSurfaces(program) {
|
|
|
15275
15845
|
const parents = /* @__PURE__ */ new Map();
|
|
15276
15846
|
const functionAliases = /* @__PURE__ */ new Set();
|
|
15277
15847
|
for (const statement of program.body) {
|
|
15278
|
-
const declaration = statement.type ===
|
|
15279
|
-
if (declaration?.type ===
|
|
15848
|
+
const declaration = statement.type === AST_NODE_TYPES67.ExportNamedDeclaration ? statement.declaration : statement;
|
|
15849
|
+
if (declaration?.type === AST_NODE_TYPES67.TSTypeAliasDeclaration && (declaration.typeAnnotation.type === AST_NODE_TYPES67.TSFunctionType || declaration.typeAnnotation.type === AST_NODE_TYPES67.TSConstructorType)) functionAliases.add(declaration.id.name);
|
|
15280
15850
|
}
|
|
15281
15851
|
for (const statement of program.body) {
|
|
15282
|
-
const declaration = statement.type ===
|
|
15283
|
-
if (declaration?.type ===
|
|
15852
|
+
const declaration = statement.type === AST_NODE_TYPES67.ExportNamedDeclaration ? statement.declaration : statement;
|
|
15853
|
+
if (declaration?.type === AST_NODE_TYPES67.TSTypeAliasDeclaration) {
|
|
15284
15854
|
const callables2 = interfaces.get(declaration.id.name) ?? /* @__PURE__ */ new Set();
|
|
15285
|
-
const parts = declaration.typeAnnotation.type ===
|
|
15855
|
+
const parts = declaration.typeAnnotation.type === AST_NODE_TYPES67.TSIntersectionType ? declaration.typeAnnotation.types : [declaration.typeAnnotation];
|
|
15286
15856
|
const inherited = parents.get(declaration.id.name) ?? [];
|
|
15287
15857
|
for (const part of parts) {
|
|
15288
|
-
if (part.type ===
|
|
15858
|
+
if (part.type === AST_NODE_TYPES67.TSTypeReference && part.typeName.type === AST_NODE_TYPES67.Identifier) {
|
|
15289
15859
|
inherited.push(part.typeName.name);
|
|
15290
15860
|
continue;
|
|
15291
15861
|
}
|
|
15292
|
-
if (part.type !==
|
|
15862
|
+
if (part.type !== AST_NODE_TYPES67.TSTypeLiteral) continue;
|
|
15293
15863
|
for (const member of part.members) {
|
|
15294
|
-
if (member.type !==
|
|
15295
|
-
if (member.computed || member.key.type !==
|
|
15296
|
-
if (member.type ===
|
|
15864
|
+
if (member.type !== AST_NODE_TYPES67.TSMethodSignature && member.type !== AST_NODE_TYPES67.TSPropertySignature) continue;
|
|
15865
|
+
if (member.computed || member.key.type !== AST_NODE_TYPES67.Identifier) continue;
|
|
15866
|
+
if (member.type === AST_NODE_TYPES67.TSMethodSignature) {
|
|
15297
15867
|
callables2.add(member.key.name);
|
|
15298
15868
|
continue;
|
|
15299
15869
|
}
|
|
15300
|
-
if (member.type !==
|
|
15870
|
+
if (member.type !== AST_NODE_TYPES67.TSPropertySignature) continue;
|
|
15301
15871
|
const annotation = member.typeAnnotation?.typeAnnotation;
|
|
15302
|
-
if (annotation?.type ===
|
|
15872
|
+
if (annotation?.type === AST_NODE_TYPES67.TSFunctionType || annotation?.type === AST_NODE_TYPES67.TSTypeReference && annotation.typeName.type === AST_NODE_TYPES67.Identifier && functionAliases.has(annotation.typeName.name)) callables2.add(member.key.name);
|
|
15303
15873
|
}
|
|
15304
15874
|
}
|
|
15305
15875
|
interfaces.set(declaration.id.name, callables2);
|
|
15306
15876
|
parents.set(declaration.id.name, inherited);
|
|
15307
15877
|
continue;
|
|
15308
15878
|
}
|
|
15309
|
-
if (declaration?.type !==
|
|
15879
|
+
if (declaration?.type !== AST_NODE_TYPES67.TSInterfaceDeclaration) continue;
|
|
15310
15880
|
const callables = interfaces.get(declaration.id.name) ?? /* @__PURE__ */ new Set();
|
|
15311
15881
|
for (const member of declaration.body.body) {
|
|
15312
|
-
if (member.type !==
|
|
15313
|
-
if (member.computed || member.key.type !==
|
|
15314
|
-
if (member.type ===
|
|
15882
|
+
if (member.type !== AST_NODE_TYPES67.TSMethodSignature && member.type !== AST_NODE_TYPES67.TSPropertySignature) continue;
|
|
15883
|
+
if (member.computed || member.key.type !== AST_NODE_TYPES67.Identifier) continue;
|
|
15884
|
+
if (member.type === AST_NODE_TYPES67.TSMethodSignature || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES67.TSFunctionType || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES67.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === AST_NODE_TYPES67.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name)) callables.add(member.key.name);
|
|
15315
15885
|
}
|
|
15316
15886
|
interfaces.set(declaration.id.name, callables);
|
|
15317
15887
|
parents.set(
|
|
@@ -15319,7 +15889,7 @@ function localInterfaceSurfaces(program) {
|
|
|
15319
15889
|
[
|
|
15320
15890
|
...parents.get(declaration.id.name) ?? [],
|
|
15321
15891
|
...declaration.extends.flatMap(
|
|
15322
|
-
(heritage) => heritage.expression.type ===
|
|
15892
|
+
(heritage) => heritage.expression.type === AST_NODE_TYPES67.Identifier ? [heritage.expression.name] : ["*"]
|
|
15323
15893
|
)
|
|
15324
15894
|
]
|
|
15325
15895
|
);
|
|
@@ -15346,7 +15916,7 @@ function localInterfaceSurfaces(program) {
|
|
|
15346
15916
|
}
|
|
15347
15917
|
function hasServicePort(node, methods, classes, interfaces) {
|
|
15348
15918
|
if (node.superClass !== null) {
|
|
15349
|
-
if (node.superClass.type !==
|
|
15919
|
+
if (node.superClass.type !== AST_NODE_TYPES67.Identifier) return true;
|
|
15350
15920
|
const localAbstract = classes.get(node.superClass.name);
|
|
15351
15921
|
if (localAbstract === void 0 || localAbstract) return true;
|
|
15352
15922
|
}
|
|
@@ -15358,7 +15928,7 @@ function hasServicePort(node, methods, classes, interfaces) {
|
|
|
15358
15928
|
if (node.implements.length === 0) return false;
|
|
15359
15929
|
const combined = /* @__PURE__ */ new Set();
|
|
15360
15930
|
for (const implementation of node.implements) {
|
|
15361
|
-
if (implementation.expression.type !==
|
|
15931
|
+
if (implementation.expression.type !== AST_NODE_TYPES67.Identifier) return true;
|
|
15362
15932
|
const name = implementation.expression.name;
|
|
15363
15933
|
const localAbstract = classes.get(name);
|
|
15364
15934
|
if (localAbstract === true) return true;
|
|
@@ -15401,7 +15971,7 @@ var require_port_for_service_default = createRule({
|
|
|
15401
15971
|
if (node.abstract === true) return;
|
|
15402
15972
|
if (node.decorators.length > 0) return;
|
|
15403
15973
|
const ctor = node.body.body.find(
|
|
15404
|
-
(member) => member.type ===
|
|
15974
|
+
(member) => member.type === AST_NODE_TYPES67.MethodDefinition && member.kind === "constructor" && member.value.body !== null && member.value.body !== void 0
|
|
15405
15975
|
);
|
|
15406
15976
|
if (ctor === void 0) return;
|
|
15407
15977
|
const constructorFacts = readConstructor(
|
|
@@ -15435,8 +16005,292 @@ var require_port_for_service_default = createRule({
|
|
|
15435
16005
|
}
|
|
15436
16006
|
});
|
|
15437
16007
|
|
|
16008
|
+
// src/rules/require-sql-access-class.ts
|
|
16009
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES68 } from "@typescript-eslint/utils";
|
|
16010
|
+
var DIRECT_EXECUTION_METHODS = /* @__PURE__ */ new Set([
|
|
16011
|
+
"all",
|
|
16012
|
+
"batch",
|
|
16013
|
+
"dump",
|
|
16014
|
+
"exec",
|
|
16015
|
+
"execute",
|
|
16016
|
+
"get",
|
|
16017
|
+
"pragma",
|
|
16018
|
+
"prepare",
|
|
16019
|
+
"query",
|
|
16020
|
+
"run",
|
|
16021
|
+
"transaction"
|
|
16022
|
+
]);
|
|
16023
|
+
var BUILDER_TERMINAL_METHODS = /* @__PURE__ */ new Set([
|
|
16024
|
+
"execute",
|
|
16025
|
+
"executeQuery",
|
|
16026
|
+
"executeTakeFirst",
|
|
16027
|
+
"executeTakeFirstOrThrow",
|
|
16028
|
+
"stream"
|
|
16029
|
+
]);
|
|
16030
|
+
var BUILDER_METHODS = /* @__PURE__ */ new Set([
|
|
16031
|
+
"delete",
|
|
16032
|
+
"insert",
|
|
16033
|
+
"select",
|
|
16034
|
+
"update"
|
|
16035
|
+
]);
|
|
16036
|
+
var BUILDER_SHORT_TERMINALS = /* @__PURE__ */ new Set([
|
|
16037
|
+
"all",
|
|
16038
|
+
"get",
|
|
16039
|
+
"run"
|
|
16040
|
+
]);
|
|
16041
|
+
var MODEL_EXECUTION_METHODS = /* @__PURE__ */ new Set([
|
|
16042
|
+
"aggregate",
|
|
16043
|
+
"count",
|
|
16044
|
+
"create",
|
|
16045
|
+
"createMany",
|
|
16046
|
+
"createManyAndReturn",
|
|
16047
|
+
"delete",
|
|
16048
|
+
"deleteMany",
|
|
16049
|
+
"findFirst",
|
|
16050
|
+
"findFirstOrThrow",
|
|
16051
|
+
"findMany",
|
|
16052
|
+
"findUnique",
|
|
16053
|
+
"findUniqueOrThrow",
|
|
16054
|
+
"groupBy",
|
|
16055
|
+
"update",
|
|
16056
|
+
"updateMany",
|
|
16057
|
+
"updateManyAndReturn",
|
|
16058
|
+
"upsert"
|
|
16059
|
+
]);
|
|
16060
|
+
var DATABASE_NAMES = /^(?:db|database|connection|pool|prisma|query|transaction|tx)$/iu;
|
|
16061
|
+
var REQUIRE_SQL_ACCESS_CLASS_DOCUMENTATION = {
|
|
16062
|
+
summary: "Keep SQL reads and writes inside a class that receives its database dependency.",
|
|
16063
|
+
rationale: "Free-function database access hides connection ownership and makes transaction, retry, observability, and test boundaries inconsistent.",
|
|
16064
|
+
remediation: "Move the query into a repository or store class and inject the pool, connection, transaction, or typed database binding through its constructor.",
|
|
16065
|
+
category: "architecture",
|
|
16066
|
+
limitations: [
|
|
16067
|
+
"The rule recognizes conventional database receiver names, Cloudflare DB bindings, direct pool.query calls, explicit query-builder terminals, and Prisma-style model delegates; unusually named or heavily aliased clients require architectural review.",
|
|
16068
|
+
"Query construction without a recognized execution terminal is intentionally not reported.",
|
|
16069
|
+
"Constructor injection inherited from a base class or transformed through a wrapper is not inferred by this syntax-only rule."
|
|
16070
|
+
],
|
|
16071
|
+
examples: [
|
|
16072
|
+
{
|
|
16073
|
+
id: "injected-repository",
|
|
16074
|
+
title: "Own queries in an injected repository",
|
|
16075
|
+
outcome: "no-match",
|
|
16076
|
+
files: [
|
|
16077
|
+
{
|
|
16078
|
+
path: "src/user-repository.ts",
|
|
16079
|
+
source: "export class UserRepository { constructor(private readonly db: Database.Database) {} find(id: string) { return this.db.prepare('SELECT id FROM user WHERE id = ?').get(id); } }"
|
|
16080
|
+
}
|
|
16081
|
+
],
|
|
16082
|
+
focusPath: "src/user-repository.ts",
|
|
16083
|
+
expectedCount: 0,
|
|
16084
|
+
public: true
|
|
16085
|
+
},
|
|
16086
|
+
{
|
|
16087
|
+
id: "free-query",
|
|
16088
|
+
title: "Do not execute SQL in a free function",
|
|
16089
|
+
outcome: "match",
|
|
16090
|
+
files: [
|
|
16091
|
+
{
|
|
16092
|
+
path: "src/users.ts",
|
|
16093
|
+
source: "export function find(database: Database.Database, id: string) { return database.prepare('SELECT id FROM user WHERE id = ?').get(id); }"
|
|
16094
|
+
}
|
|
16095
|
+
],
|
|
16096
|
+
focusPath: "src/users.ts",
|
|
16097
|
+
expectedCount: 1,
|
|
16098
|
+
public: true
|
|
16099
|
+
}
|
|
16100
|
+
]
|
|
16101
|
+
};
|
|
16102
|
+
function memberName5(node) {
|
|
16103
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES68.Identifier)
|
|
16104
|
+
return node.property.name;
|
|
16105
|
+
if (node.computed && node.property.type === AST_NODE_TYPES68.Literal && typeof node.property.value === "string")
|
|
16106
|
+
return node.property.value;
|
|
16107
|
+
return null;
|
|
16108
|
+
}
|
|
16109
|
+
function isDatabaseOperation(method, receiver) {
|
|
16110
|
+
if (DIRECT_EXECUTION_METHODS.has(method) && databaseReceiver(receiver))
|
|
16111
|
+
return true;
|
|
16112
|
+
if (!expressionHasDatabaseMarker(receiver)) return false;
|
|
16113
|
+
if (BUILDER_TERMINAL_METHODS.has(method) || MODEL_EXECUTION_METHODS.has(method)) return true;
|
|
16114
|
+
return BUILDER_SHORT_TERMINALS.has(method) && expressionCallsBuilder(receiver);
|
|
16115
|
+
}
|
|
16116
|
+
function databaseReceiver(node) {
|
|
16117
|
+
if (node.type === AST_NODE_TYPES68.Identifier)
|
|
16118
|
+
return DATABASE_NAMES.test(node.name);
|
|
16119
|
+
if (node.type !== AST_NODE_TYPES68.MemberExpression) return false;
|
|
16120
|
+
const name = memberName5(node);
|
|
16121
|
+
return name === "DB" || name !== null && DATABASE_NAMES.test(name);
|
|
16122
|
+
}
|
|
16123
|
+
function databaseRootMember(node) {
|
|
16124
|
+
let current = node;
|
|
16125
|
+
for (; ; ) {
|
|
16126
|
+
if (current.type === AST_NODE_TYPES68.ChainExpression) {
|
|
16127
|
+
current = current.expression;
|
|
16128
|
+
continue;
|
|
16129
|
+
}
|
|
16130
|
+
if (current.type === AST_NODE_TYPES68.TSAsExpression || current.type === AST_NODE_TYPES68.TSNonNullExpression || current.type === AST_NODE_TYPES68.TSTypeAssertion) {
|
|
16131
|
+
current = current.expression;
|
|
16132
|
+
continue;
|
|
16133
|
+
}
|
|
16134
|
+
if (current.type === AST_NODE_TYPES68.CallExpression) {
|
|
16135
|
+
if (current.callee.type !== AST_NODE_TYPES68.MemberExpression) return null;
|
|
16136
|
+
current = current.callee.object;
|
|
16137
|
+
continue;
|
|
16138
|
+
}
|
|
16139
|
+
if (current.type === AST_NODE_TYPES68.MemberExpression) {
|
|
16140
|
+
if (current.object.type === AST_NODE_TYPES68.ThisExpression)
|
|
16141
|
+
return memberName5(current);
|
|
16142
|
+
current = current.object;
|
|
16143
|
+
continue;
|
|
16144
|
+
}
|
|
16145
|
+
return current.type === AST_NODE_TYPES68.Identifier ? current.name : null;
|
|
16146
|
+
}
|
|
16147
|
+
}
|
|
16148
|
+
function expressionHasDatabaseMarker(node) {
|
|
16149
|
+
let current = node;
|
|
16150
|
+
for (; ; ) {
|
|
16151
|
+
if (current.type === AST_NODE_TYPES68.ChainExpression) {
|
|
16152
|
+
current = current.expression;
|
|
16153
|
+
continue;
|
|
16154
|
+
}
|
|
16155
|
+
if (current.type === AST_NODE_TYPES68.TSAsExpression || current.type === AST_NODE_TYPES68.TSNonNullExpression || current.type === AST_NODE_TYPES68.TSTypeAssertion) {
|
|
16156
|
+
current = current.expression;
|
|
16157
|
+
continue;
|
|
16158
|
+
}
|
|
16159
|
+
if (current.type === AST_NODE_TYPES68.CallExpression) {
|
|
16160
|
+
if (current.callee.type !== AST_NODE_TYPES68.MemberExpression) return false;
|
|
16161
|
+
current = current.callee.object;
|
|
16162
|
+
continue;
|
|
16163
|
+
}
|
|
16164
|
+
if (current.type === AST_NODE_TYPES68.MemberExpression) {
|
|
16165
|
+
const name = memberName5(current);
|
|
16166
|
+
if (name === "DB" || name !== null && DATABASE_NAMES.test(name))
|
|
16167
|
+
return true;
|
|
16168
|
+
current = current.object;
|
|
16169
|
+
continue;
|
|
16170
|
+
}
|
|
16171
|
+
return current.type === AST_NODE_TYPES68.Identifier && DATABASE_NAMES.test(current.name);
|
|
16172
|
+
}
|
|
16173
|
+
}
|
|
16174
|
+
function expressionCallsBuilder(node) {
|
|
16175
|
+
let current = node;
|
|
16176
|
+
for (; ; ) {
|
|
16177
|
+
if (current.type === AST_NODE_TYPES68.ChainExpression) {
|
|
16178
|
+
current = current.expression;
|
|
16179
|
+
continue;
|
|
16180
|
+
}
|
|
16181
|
+
if (current.type === AST_NODE_TYPES68.TSAsExpression || current.type === AST_NODE_TYPES68.TSNonNullExpression || current.type === AST_NODE_TYPES68.TSTypeAssertion) {
|
|
16182
|
+
current = current.expression;
|
|
16183
|
+
continue;
|
|
16184
|
+
}
|
|
16185
|
+
if (current.type === AST_NODE_TYPES68.CallExpression) {
|
|
16186
|
+
if (current.callee.type !== AST_NODE_TYPES68.MemberExpression) return false;
|
|
16187
|
+
const name = memberName5(current.callee);
|
|
16188
|
+
if (name !== null && BUILDER_METHODS.has(name)) return true;
|
|
16189
|
+
current = current.callee.object;
|
|
16190
|
+
continue;
|
|
16191
|
+
}
|
|
16192
|
+
if (current.type !== AST_NODE_TYPES68.MemberExpression) return false;
|
|
16193
|
+
current = current.object;
|
|
16194
|
+
}
|
|
16195
|
+
}
|
|
16196
|
+
function owningClass2(node) {
|
|
16197
|
+
let current = node.parent;
|
|
16198
|
+
while (current != null) {
|
|
16199
|
+
if (current.type === AST_NODE_TYPES68.ClassDeclaration || current.type === AST_NODE_TYPES68.ClassExpression)
|
|
16200
|
+
return current;
|
|
16201
|
+
current = current.parent;
|
|
16202
|
+
}
|
|
16203
|
+
return null;
|
|
16204
|
+
}
|
|
16205
|
+
function injectedMembers(owner) {
|
|
16206
|
+
const injected = /* @__PURE__ */ new Set();
|
|
16207
|
+
const constructor = owner.body.body.find(
|
|
16208
|
+
(member) => member.type === AST_NODE_TYPES68.MethodDefinition && member.kind === "constructor"
|
|
16209
|
+
);
|
|
16210
|
+
if (constructor === void 0) return injected;
|
|
16211
|
+
const parameters = /* @__PURE__ */ new Set();
|
|
16212
|
+
for (const parameter of constructor.value.params) {
|
|
16213
|
+
for (const name of parameterNames(parameter)) parameters.add(name);
|
|
16214
|
+
if (parameter.type !== AST_NODE_TYPES68.TSParameterProperty) continue;
|
|
16215
|
+
const value = parameter.parameter.type === AST_NODE_TYPES68.AssignmentPattern ? parameter.parameter.left : parameter.parameter;
|
|
16216
|
+
if (value.type === AST_NODE_TYPES68.Identifier) injected.add(value.name);
|
|
16217
|
+
}
|
|
16218
|
+
const body2 = constructor.value.body;
|
|
16219
|
+
if (body2 === null) return injected;
|
|
16220
|
+
for (const statement of body2.body) {
|
|
16221
|
+
if (statement.type !== AST_NODE_TYPES68.ExpressionStatement || statement.expression.type !== AST_NODE_TYPES68.AssignmentExpression || statement.expression.operator !== "=") continue;
|
|
16222
|
+
const { left, right } = statement.expression;
|
|
16223
|
+
if (left.type !== AST_NODE_TYPES68.MemberExpression) continue;
|
|
16224
|
+
const target = thisRootMember(left);
|
|
16225
|
+
if (target === null) continue;
|
|
16226
|
+
const source = right.type === AST_NODE_TYPES68.Identifier ? right.name : right.type === AST_NODE_TYPES68.MemberExpression && right.object.type === AST_NODE_TYPES68.Identifier ? right.object.name : null;
|
|
16227
|
+
if (source !== null && parameters.has(source)) injected.add(target);
|
|
16228
|
+
}
|
|
16229
|
+
return injected;
|
|
16230
|
+
}
|
|
16231
|
+
function thisRootMember(node) {
|
|
16232
|
+
let current = node;
|
|
16233
|
+
let root = null;
|
|
16234
|
+
while (current.type === AST_NODE_TYPES68.MemberExpression) {
|
|
16235
|
+
const name = memberName5(current);
|
|
16236
|
+
if (name === null) return null;
|
|
16237
|
+
root = name;
|
|
16238
|
+
current = current.object;
|
|
16239
|
+
}
|
|
16240
|
+
return current.type === AST_NODE_TYPES68.ThisExpression ? root : null;
|
|
16241
|
+
}
|
|
16242
|
+
function parameterNames(parameter) {
|
|
16243
|
+
let value = parameter;
|
|
16244
|
+
if (value.type === AST_NODE_TYPES68.TSParameterProperty) value = value.parameter;
|
|
16245
|
+
if (value.type === AST_NODE_TYPES68.AssignmentPattern) value = value.left;
|
|
16246
|
+
if (value.type === AST_NODE_TYPES68.Identifier) return /* @__PURE__ */ new Set([value.name]);
|
|
16247
|
+
if (value.type !== AST_NODE_TYPES68.ObjectPattern) return /* @__PURE__ */ new Set();
|
|
16248
|
+
return new Set(
|
|
16249
|
+
value.properties.flatMap((property) => {
|
|
16250
|
+
if (property.type === AST_NODE_TYPES68.RestElement)
|
|
16251
|
+
return property.argument.type === AST_NODE_TYPES68.Identifier ? [property.argument.name] : [];
|
|
16252
|
+
const target = property.value.type === AST_NODE_TYPES68.AssignmentPattern ? property.value.left : property.value;
|
|
16253
|
+
return target.type === AST_NODE_TYPES68.Identifier ? [target.name] : [];
|
|
16254
|
+
})
|
|
16255
|
+
);
|
|
16256
|
+
}
|
|
16257
|
+
var require_sql_access_class_default = createRule({
|
|
16258
|
+
name: "require-sql-access-class",
|
|
16259
|
+
documentation: REQUIRE_SQL_ACCESS_CLASS_DOCUMENTATION,
|
|
16260
|
+
meta: {
|
|
16261
|
+
type: "suggestion",
|
|
16262
|
+
docs: {
|
|
16263
|
+
description: "Keep SQL reads and writes inside a class that receives its database dependency."
|
|
16264
|
+
},
|
|
16265
|
+
schema: [],
|
|
16266
|
+
messages: {
|
|
16267
|
+
moveSqlIntoClass: "Move this database operation into a repository or store class with an injected connection or pool."
|
|
16268
|
+
}
|
|
16269
|
+
},
|
|
16270
|
+
defaultOptions: [],
|
|
16271
|
+
create(context) {
|
|
16272
|
+
if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text))
|
|
16273
|
+
return {};
|
|
16274
|
+
return {
|
|
16275
|
+
CallExpression(node) {
|
|
16276
|
+
if (node.callee.type !== AST_NODE_TYPES68.MemberExpression)
|
|
16277
|
+
return;
|
|
16278
|
+
const method = memberName5(node.callee);
|
|
16279
|
+
if (method === null || !isDatabaseOperation(method, node.callee.object))
|
|
16280
|
+
return;
|
|
16281
|
+
const owner = owningClass2(node);
|
|
16282
|
+
if (owner !== null) {
|
|
16283
|
+
const root = databaseRootMember(node.callee.object);
|
|
16284
|
+
if (root !== null && injectedMembers(owner).has(root)) return;
|
|
16285
|
+
}
|
|
16286
|
+
context.report({ node, messageId: "moveSqlIntoClass" });
|
|
16287
|
+
}
|
|
16288
|
+
};
|
|
16289
|
+
}
|
|
16290
|
+
});
|
|
16291
|
+
|
|
15438
16292
|
// src/rules/require-static-next-matcher.ts
|
|
15439
|
-
import { AST_NODE_TYPES as
|
|
16293
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES69 } from "@typescript-eslint/utils";
|
|
15440
16294
|
var REQUIRE_STATIC_NEXT_MATCHER_DOCUMENTATION = {
|
|
15441
16295
|
summary: "Require Next.js middleware and proxy matcher configuration to contain only build-time literals.",
|
|
15442
16296
|
rationale: "Next.js must statically analyze matcher values at build time; computed values are ignored.",
|
|
@@ -15449,34 +16303,34 @@ var REQUIRE_STATIC_NEXT_MATCHER_DOCUMENTATION = {
|
|
|
15449
16303
|
};
|
|
15450
16304
|
var NEXT_ENTRY_FILE = /(?:^|[/\\])(?:middleware|proxy)\.[cm]?[jt]sx?$/u;
|
|
15451
16305
|
function unwrapExpression3(node) {
|
|
15452
|
-
if (node.type ===
|
|
16306
|
+
if (node.type === AST_NODE_TYPES69.TSAsExpression || node.type === AST_NODE_TYPES69.TSSatisfiesExpression || node.type === AST_NODE_TYPES69.TSNonNullExpression || node.type === AST_NODE_TYPES69.TSTypeAssertion) {
|
|
15453
16307
|
return unwrapExpression3(node.expression);
|
|
15454
16308
|
}
|
|
15455
16309
|
return node;
|
|
15456
16310
|
}
|
|
15457
16311
|
function isStaticValue(node) {
|
|
15458
16312
|
const value = unwrapExpression3(node);
|
|
15459
|
-
if (value.type ===
|
|
16313
|
+
if (value.type === AST_NODE_TYPES69.Literal) {
|
|
15460
16314
|
return true;
|
|
15461
16315
|
}
|
|
15462
|
-
if (value.type ===
|
|
16316
|
+
if (value.type === AST_NODE_TYPES69.TemplateLiteral) {
|
|
15463
16317
|
return value.expressions.length === 0;
|
|
15464
16318
|
}
|
|
15465
|
-
if (value.type ===
|
|
16319
|
+
if (value.type === AST_NODE_TYPES69.ArrayExpression) {
|
|
15466
16320
|
return value.elements.every(
|
|
15467
|
-
(element) => element !== null && element.type !==
|
|
16321
|
+
(element) => element !== null && element.type !== AST_NODE_TYPES69.SpreadElement && isStaticValue(element)
|
|
15468
16322
|
);
|
|
15469
16323
|
}
|
|
15470
|
-
if (value.type ===
|
|
16324
|
+
if (value.type === AST_NODE_TYPES69.ObjectExpression) {
|
|
15471
16325
|
return value.properties.every(
|
|
15472
|
-
(property) => property.type ===
|
|
16326
|
+
(property) => property.type === AST_NODE_TYPES69.Property && property.kind === "init" && !property.computed && property.value.type !== AST_NODE_TYPES69.AssignmentPattern && isStaticValue(property.value)
|
|
15473
16327
|
);
|
|
15474
16328
|
}
|
|
15475
16329
|
return false;
|
|
15476
16330
|
}
|
|
15477
|
-
function
|
|
16331
|
+
function propertyName6(property) {
|
|
15478
16332
|
if (property.computed) return null;
|
|
15479
|
-
if (property.key.type ===
|
|
16333
|
+
if (property.key.type === AST_NODE_TYPES69.Identifier) return property.key.name;
|
|
15480
16334
|
return typeof property.key.value === "string" ? property.key.value : null;
|
|
15481
16335
|
}
|
|
15482
16336
|
var require_static_next_matcher_default = createRule({
|
|
@@ -15499,19 +16353,19 @@ var require_static_next_matcher_default = createRule({
|
|
|
15499
16353
|
}
|
|
15500
16354
|
return {
|
|
15501
16355
|
ExportNamedDeclaration(node) {
|
|
15502
|
-
if (node.declaration?.type !==
|
|
16356
|
+
if (node.declaration?.type !== AST_NODE_TYPES69.VariableDeclaration) {
|
|
15503
16357
|
return;
|
|
15504
16358
|
}
|
|
15505
16359
|
for (const declaration of node.declaration.declarations) {
|
|
15506
|
-
if (declaration.id.type !==
|
|
16360
|
+
if (declaration.id.type !== AST_NODE_TYPES69.Identifier || declaration.id.name !== "config" || declaration.init === null) {
|
|
15507
16361
|
continue;
|
|
15508
16362
|
}
|
|
15509
16363
|
const config = unwrapExpression3(declaration.init);
|
|
15510
|
-
if (config.type !==
|
|
16364
|
+
if (config.type !== AST_NODE_TYPES69.ObjectExpression) {
|
|
15511
16365
|
continue;
|
|
15512
16366
|
}
|
|
15513
16367
|
for (const property of config.properties) {
|
|
15514
|
-
if (property.type !==
|
|
16368
|
+
if (property.type !== AST_NODE_TYPES69.Property || propertyName6(property) !== "matcher" || property.value.type === AST_NODE_TYPES69.AssignmentPattern) {
|
|
15515
16369
|
continue;
|
|
15516
16370
|
}
|
|
15517
16371
|
if (!isStaticValue(property.value)) {
|
|
@@ -15525,7 +16379,7 @@ var require_static_next_matcher_default = createRule({
|
|
|
15525
16379
|
});
|
|
15526
16380
|
|
|
15527
16381
|
// src/rules/require-use-form-default-values.ts
|
|
15528
|
-
import { ASTUtils as
|
|
16382
|
+
import { ASTUtils as ASTUtils21 } from "@typescript-eslint/utils";
|
|
15529
16383
|
var REQUIRE_USE_FORM_DEFAULT_VALUES_DOCUMENTATION = {
|
|
15530
16384
|
summary: "react-hook-form useForm call without defaultValues",
|
|
15531
16385
|
rationale: "Without an explicit initial value, fields can change from uncontrolled to controlled as data arrives, reset behavior becomes ambiguous, and the form's initial shape no longer documents the values users can edit.",
|
|
@@ -15579,13 +16433,13 @@ var require_use_form_default_values_default = createRule({
|
|
|
15579
16433
|
if (node.source.value !== "react-hook-form") return;
|
|
15580
16434
|
for (const specifier of node.specifiers) {
|
|
15581
16435
|
if (specifier.type !== "ImportSpecifier" || (specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value) !== "useForm") continue;
|
|
15582
|
-
const variable =
|
|
16436
|
+
const variable = ASTUtils21.findVariable(context.sourceCode.getScope(specifier.local), specifier.local.name);
|
|
15583
16437
|
if (variable) importedHooks.add(variable);
|
|
15584
16438
|
}
|
|
15585
16439
|
},
|
|
15586
16440
|
CallExpression(node) {
|
|
15587
16441
|
if (node.callee.type !== "Identifier") return;
|
|
15588
|
-
const variable =
|
|
16442
|
+
const variable = ASTUtils21.findVariable(context.sourceCode.getScope(node.callee), node.callee.name);
|
|
15589
16443
|
const options = node.arguments[0];
|
|
15590
16444
|
if (!variable || !importedHooks.has(variable) || options !== void 0 && options.type !== "ObjectExpression" || hasDefaultValues(options)) return;
|
|
15591
16445
|
context.report({ node, messageId: "requireUseFormDefaultValues" });
|
|
@@ -15662,8 +16516,8 @@ var require_use_server_in_actions_file_default = createRule({
|
|
|
15662
16516
|
|
|
15663
16517
|
// src/rules/require-zod-form-validation.ts
|
|
15664
16518
|
import {
|
|
15665
|
-
AST_NODE_TYPES as
|
|
15666
|
-
ASTUtils as
|
|
16519
|
+
AST_NODE_TYPES as AST_NODE_TYPES70,
|
|
16520
|
+
ASTUtils as ASTUtils22
|
|
15667
16521
|
} from "@typescript-eslint/utils";
|
|
15668
16522
|
var REQUIRE_ZOD_FORM_VALIDATION_DOCUMENTATION = {
|
|
15669
16523
|
summary: "Require Zod validation (`Schema.parse(...)` / `Schema.safeParse(...)`) when reading values out of a `FormData` object.",
|
|
@@ -15689,14 +16543,14 @@ var FORM_VALUE_METHODS = /* @__PURE__ */ new Set(["get", "getAll"]);
|
|
|
15689
16543
|
var zodReceiverRoot = (node) => {
|
|
15690
16544
|
let current = node;
|
|
15691
16545
|
while (true) {
|
|
15692
|
-
if (current.type ===
|
|
16546
|
+
if (current.type === AST_NODE_TYPES70.Identifier) {
|
|
15693
16547
|
return current;
|
|
15694
16548
|
}
|
|
15695
|
-
if (current.type ===
|
|
16549
|
+
if (current.type === AST_NODE_TYPES70.CallExpression) {
|
|
15696
16550
|
current = current.callee;
|
|
15697
16551
|
continue;
|
|
15698
16552
|
}
|
|
15699
|
-
if (current.type ===
|
|
16553
|
+
if (current.type === AST_NODE_TYPES70.MemberExpression) {
|
|
15700
16554
|
current = current.object;
|
|
15701
16555
|
continue;
|
|
15702
16556
|
}
|
|
@@ -15705,12 +16559,12 @@ var zodReceiverRoot = (node) => {
|
|
|
15705
16559
|
};
|
|
15706
16560
|
var isFormDataMethodCall = (node) => {
|
|
15707
16561
|
let current = node;
|
|
15708
|
-
if (current.type ===
|
|
16562
|
+
if (current.type === AST_NODE_TYPES70.AwaitExpression) {
|
|
15709
16563
|
current = current.argument;
|
|
15710
16564
|
}
|
|
15711
|
-
if (current.type !==
|
|
16565
|
+
if (current.type !== AST_NODE_TYPES70.CallExpression) return false;
|
|
15712
16566
|
const callee = current.callee;
|
|
15713
|
-
return callee.type ===
|
|
16567
|
+
return callee.type === AST_NODE_TYPES70.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES70.Identifier && callee.property.name === "formData";
|
|
15714
16568
|
};
|
|
15715
16569
|
var require_zod_form_validation_default = createRule({
|
|
15716
16570
|
name: "require-zod-form-validation",
|
|
@@ -15731,7 +16585,7 @@ var require_zod_form_validation_default = createRule({
|
|
|
15731
16585
|
return {};
|
|
15732
16586
|
}
|
|
15733
16587
|
const zodBindings = /* @__PURE__ */ new Set();
|
|
15734
|
-
const resolvedBinding = (identifier) =>
|
|
16588
|
+
const resolvedBinding = (identifier) => ASTUtils22.findVariable(
|
|
15735
16589
|
context.sourceCode.getScope(identifier),
|
|
15736
16590
|
identifier.name
|
|
15737
16591
|
);
|
|
@@ -15741,16 +16595,16 @@ var require_zod_form_validation_default = createRule({
|
|
|
15741
16595
|
return false;
|
|
15742
16596
|
}
|
|
15743
16597
|
const definition = binding.defs[0];
|
|
15744
|
-
if (definition?.type !== "Variable" || definition.node.type !==
|
|
16598
|
+
if (definition?.type !== "Variable" || definition.node.type !== AST_NODE_TYPES70.VariableDeclarator) {
|
|
15745
16599
|
return false;
|
|
15746
16600
|
}
|
|
15747
16601
|
const init = definition.node.init;
|
|
15748
|
-
return init?.type ===
|
|
16602
|
+
return init?.type === AST_NODE_TYPES70.ObjectExpression || init?.type === AST_NODE_TYPES70.ArrayExpression || init?.type === AST_NODE_TYPES70.Literal || init?.type === AST_NODE_TYPES70.ArrowFunctionExpression || init?.type === AST_NODE_TYPES70.FunctionExpression;
|
|
15749
16603
|
};
|
|
15750
16604
|
const isZodParseCall = (node) => {
|
|
15751
|
-
if (node.type !==
|
|
16605
|
+
if (node.type !== AST_NODE_TYPES70.CallExpression) return false;
|
|
15752
16606
|
const callee = node.callee;
|
|
15753
|
-
if (callee.type !==
|
|
16607
|
+
if (callee.type !== AST_NODE_TYPES70.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES70.Identifier || !ZOD_PARSE_METHODS.has(callee.property.name)) {
|
|
15754
16608
|
return false;
|
|
15755
16609
|
}
|
|
15756
16610
|
const root = zodReceiverRoot(callee.object);
|
|
@@ -15759,14 +16613,14 @@ var require_zod_form_validation_default = createRule({
|
|
|
15759
16613
|
return binding !== null && zodBindings.has(binding) || (root.name === "z" || ZOD_SCHEMA_NAME_RE.test(root.name)) && !isProvablyNonZodLocal(root);
|
|
15760
16614
|
};
|
|
15761
16615
|
const isFormSourceIdentifier = (node) => {
|
|
15762
|
-
if (node.type !==
|
|
16616
|
+
if (node.type !== AST_NODE_TYPES70.Identifier) return false;
|
|
15763
16617
|
const conventionalName = /formdata/i.test(node.name);
|
|
15764
16618
|
let scope = context.sourceCode.getScope(node);
|
|
15765
16619
|
while (scope !== null) {
|
|
15766
16620
|
const variable = scope.set.get(node.name);
|
|
15767
16621
|
if (variable !== void 0 && variable.defs.length === 1) {
|
|
15768
16622
|
const def = variable.defs[0];
|
|
15769
|
-
if (def !== void 0 && def.type === "Variable" && def.node.type ===
|
|
16623
|
+
if (def !== void 0 && def.type === "Variable" && def.node.type === AST_NODE_TYPES70.VariableDeclarator && def.node.init !== null) {
|
|
15770
16624
|
return isFormDataMethodCall(def.node.init);
|
|
15771
16625
|
}
|
|
15772
16626
|
return def?.type === "Parameter" && conventionalName;
|
|
@@ -15777,8 +16631,8 @@ var require_zod_form_validation_default = createRule({
|
|
|
15777
16631
|
};
|
|
15778
16632
|
const isFormDataGetCall = (node) => {
|
|
15779
16633
|
const callee = node.callee;
|
|
15780
|
-
if (callee.type !==
|
|
15781
|
-
if (callee.property.type !==
|
|
16634
|
+
if (callee.type !== AST_NODE_TYPES70.MemberExpression) return false;
|
|
16635
|
+
if (callee.property.type !== AST_NODE_TYPES70.Identifier || !FORM_VALUE_METHODS.has(callee.property.name)) {
|
|
15782
16636
|
return false;
|
|
15783
16637
|
}
|
|
15784
16638
|
return isFormSourceIdentifier(callee.object);
|
|
@@ -15794,16 +16648,16 @@ var require_zod_form_validation_default = createRule({
|
|
|
15794
16648
|
const hasZodParseAncestor = (node) => zodParseAncestor(node) !== null;
|
|
15795
16649
|
const isInstanceofNarrowing = (node) => {
|
|
15796
16650
|
const parent = node.parent;
|
|
15797
|
-
return parent !== null && parent !== void 0 && parent.type ===
|
|
16651
|
+
return parent !== null && parent !== void 0 && parent.type === AST_NODE_TYPES70.BinaryExpression && parent.operator === "instanceof" && parent.left === node && parent.right.type === AST_NODE_TYPES70.Identifier && (parent.right.name === "File" || parent.right.name === "Blob");
|
|
15798
16652
|
};
|
|
15799
16653
|
const boundDeclarator = (node) => {
|
|
15800
16654
|
let current = node;
|
|
15801
16655
|
let parent = current.parent;
|
|
15802
|
-
while ((parent.type ===
|
|
16656
|
+
while ((parent.type === AST_NODE_TYPES70.TSAsExpression || parent.type === AST_NODE_TYPES70.TSSatisfiesExpression || parent.type === AST_NODE_TYPES70.TSNonNullExpression || parent.type === AST_NODE_TYPES70.ChainExpression) && parent.expression === current) {
|
|
15803
16657
|
current = parent;
|
|
15804
16658
|
parent = current.parent;
|
|
15805
16659
|
}
|
|
15806
|
-
if (parent.type ===
|
|
16660
|
+
if (parent.type === AST_NODE_TYPES70.VariableDeclarator && parent.init === current && parent.id.type === AST_NODE_TYPES70.Identifier) {
|
|
15807
16661
|
return parent;
|
|
15808
16662
|
}
|
|
15809
16663
|
return null;
|
|
@@ -15812,7 +16666,7 @@ var require_zod_form_validation_default = createRule({
|
|
|
15812
16666
|
let current = node;
|
|
15813
16667
|
while (current.parent !== void 0) {
|
|
15814
16668
|
const parent = current.parent;
|
|
15815
|
-
if (parent.type ===
|
|
16669
|
+
if (parent.type === AST_NODE_TYPES70.BlockStatement || parent.type === AST_NODE_TYPES70.Program) {
|
|
15816
16670
|
return current;
|
|
15817
16671
|
}
|
|
15818
16672
|
current = parent;
|
|
@@ -15821,12 +16675,12 @@ var require_zod_form_validation_default = createRule({
|
|
|
15821
16675
|
};
|
|
15822
16676
|
const zodParseMethod = (call) => {
|
|
15823
16677
|
const callee = call.callee;
|
|
15824
|
-
return callee.type ===
|
|
16678
|
+
return callee.type === AST_NODE_TYPES70.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES70.Identifier ? callee.property.name : null;
|
|
15825
16679
|
};
|
|
15826
16680
|
const hasConditionalAncestorBeforeStatement = (node, statement) => {
|
|
15827
16681
|
let current = node.parent;
|
|
15828
16682
|
while (current !== void 0 && current !== statement) {
|
|
15829
|
-
if (current.type ===
|
|
16683
|
+
if (current.type === AST_NODE_TYPES70.LogicalExpression || current.type === AST_NODE_TYPES70.ConditionalExpression) {
|
|
15830
16684
|
return true;
|
|
15831
16685
|
}
|
|
15832
16686
|
current = current.parent;
|
|
@@ -15836,7 +16690,7 @@ var require_zod_form_validation_default = createRule({
|
|
|
15836
16690
|
const isAwaitedBeforeStatement = (node, statement) => {
|
|
15837
16691
|
let current = node.parent;
|
|
15838
16692
|
while (current !== void 0 && current !== statement) {
|
|
15839
|
-
if (current.type ===
|
|
16693
|
+
if (current.type === AST_NODE_TYPES70.AwaitExpression) return true;
|
|
15840
16694
|
current = current.parent;
|
|
15841
16695
|
}
|
|
15842
16696
|
return false;
|
|
@@ -15849,7 +16703,7 @@ var require_zod_form_validation_default = createRule({
|
|
|
15849
16703
|
if (declarationStatement === null || validationStatement === null || declarationStatement.parent !== validationStatement.parent || validationStatement.range[0] <= declarationStatement.range[1] || hasConditionalAncestorBeforeStatement(parse2, validationStatement)) {
|
|
15850
16704
|
return null;
|
|
15851
16705
|
}
|
|
15852
|
-
if (validationStatement.type !==
|
|
16706
|
+
if (validationStatement.type !== AST_NODE_TYPES70.VariableDeclaration && validationStatement.type !== AST_NODE_TYPES70.ExpressionStatement) {
|
|
15853
16707
|
return null;
|
|
15854
16708
|
}
|
|
15855
16709
|
const method = zodParseMethod(parse2);
|
|
@@ -15861,16 +16715,16 @@ var require_zod_form_validation_default = createRule({
|
|
|
15861
16715
|
};
|
|
15862
16716
|
const isSafePrevalidationInspection = (identifier) => {
|
|
15863
16717
|
const parent = identifier.parent;
|
|
15864
|
-
if (parent.type ===
|
|
16718
|
+
if (parent.type === AST_NODE_TYPES70.UnaryExpression && parent.operator === "typeof") {
|
|
15865
16719
|
return true;
|
|
15866
16720
|
}
|
|
15867
|
-
if (parent.type !==
|
|
16721
|
+
if (parent.type !== AST_NODE_TYPES70.BinaryExpression || parent.left !== identifier) {
|
|
15868
16722
|
return false;
|
|
15869
16723
|
}
|
|
15870
16724
|
if (parent.operator === "instanceof") {
|
|
15871
|
-
return parent.right.type ===
|
|
16725
|
+
return parent.right.type === AST_NODE_TYPES70.Identifier && (parent.right.name === "File" || parent.right.name === "Blob");
|
|
15872
16726
|
}
|
|
15873
|
-
return ["===", "!==", "==", "!="].includes(parent.operator) && (parent.right.type ===
|
|
16727
|
+
return ["===", "!==", "==", "!="].includes(parent.operator) && (parent.right.type === AST_NODE_TYPES70.Literal && parent.right.value === null || parent.right.type === AST_NODE_TYPES70.Identifier && parent.right.name === "undefined");
|
|
15874
16728
|
};
|
|
15875
16729
|
const isDescendantOf = (node, ancestor) => {
|
|
15876
16730
|
let current = node;
|
|
@@ -15881,23 +16735,23 @@ var require_zod_form_validation_default = createRule({
|
|
|
15881
16735
|
return false;
|
|
15882
16736
|
};
|
|
15883
16737
|
const blockTerminates = (node) => {
|
|
15884
|
-
if (node.type ===
|
|
16738
|
+
if (node.type === AST_NODE_TYPES70.ReturnStatement || node.type === AST_NODE_TYPES70.ThrowStatement) {
|
|
15885
16739
|
return true;
|
|
15886
16740
|
}
|
|
15887
|
-
if (node.type !==
|
|
16741
|
+
if (node.type !== AST_NODE_TYPES70.BlockStatement || node.body.length === 0) return false;
|
|
15888
16742
|
const last = node.body.at(-1);
|
|
15889
16743
|
return last !== void 0 && blockTerminates(last);
|
|
15890
16744
|
};
|
|
15891
16745
|
const narrowingIf = (identifier) => {
|
|
15892
16746
|
const comparison = identifier.parent;
|
|
15893
|
-
if (comparison?.type !==
|
|
16747
|
+
if (comparison?.type !== AST_NODE_TYPES70.BinaryExpression || comparison.operator !== "instanceof" || comparison.left !== identifier || comparison.right.type !== AST_NODE_TYPES70.Identifier || comparison.right.name !== "File" && comparison.right.name !== "Blob") {
|
|
15894
16748
|
return null;
|
|
15895
16749
|
}
|
|
15896
16750
|
const maybeNegation = comparison.parent;
|
|
15897
|
-
const negated = maybeNegation?.type ===
|
|
16751
|
+
const negated = maybeNegation?.type === AST_NODE_TYPES70.UnaryExpression && maybeNegation.operator === "!";
|
|
15898
16752
|
const test = negated ? maybeNegation : comparison;
|
|
15899
16753
|
const branch = test.parent;
|
|
15900
|
-
return branch?.type ===
|
|
16754
|
+
return branch?.type === AST_NODE_TYPES70.IfStatement && branch.test === test ? { branch, positive: !negated } : null;
|
|
15901
16755
|
};
|
|
15902
16756
|
const useDominatedByNarrowing = (use, narrowings) => narrowings.some(({ branch, positive }) => {
|
|
15903
16757
|
if (positive) return isDescendantOf(use, branch.consequent);
|
|
@@ -15917,7 +16771,7 @@ var require_zod_form_validation_default = createRule({
|
|
|
15917
16771
|
const variable = context.sourceCode.getDeclaredVariables(declarator)[0];
|
|
15918
16772
|
if (variable === void 0) return false;
|
|
15919
16773
|
const references = variable.references.filter((reference) => !reference.isWriteOnly()).map((reference) => reference.identifier).filter(
|
|
15920
|
-
(identifier) => identifier.type ===
|
|
16774
|
+
(identifier) => identifier.type === AST_NODE_TYPES70.Identifier
|
|
15921
16775
|
);
|
|
15922
16776
|
if (references.length === 0) return false;
|
|
15923
16777
|
const narrowings = references.map(narrowingIf).filter(
|
|
@@ -15943,7 +16797,7 @@ var require_zod_form_validation_default = createRule({
|
|
|
15943
16797
|
ImportDeclaration(node) {
|
|
15944
16798
|
if (!isZodModule(node.source.value)) return;
|
|
15945
16799
|
for (const specifier of node.specifiers) {
|
|
15946
|
-
if (specifier.type ===
|
|
16800
|
+
if (specifier.type === AST_NODE_TYPES70.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES70.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES70.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES70.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
|
|
15947
16801
|
const binding = resolvedBinding(specifier.local);
|
|
15948
16802
|
if (binding !== null) zodBindings.add(binding);
|
|
15949
16803
|
}
|
|
@@ -16028,7 +16882,7 @@ var store_insert_requires_on_conflict_default = createRule({
|
|
|
16028
16882
|
});
|
|
16029
16883
|
|
|
16030
16884
|
// src/rules/stepdown.ts
|
|
16031
|
-
import { AST_NODE_TYPES as
|
|
16885
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES71, ASTUtils as ASTUtils23 } from "@typescript-eslint/utils";
|
|
16032
16886
|
var STEPDOWN_DOCUMENTATION = {
|
|
16033
16887
|
summary: "Place a private helper below its sole direct same-scope caller.",
|
|
16034
16888
|
rationale: "Caller-first ordering lets a reader follow the main flow before descending into implementation details.",
|
|
@@ -16048,7 +16902,7 @@ var STEPDOWN_DOCUMENTATION = {
|
|
|
16048
16902
|
]
|
|
16049
16903
|
};
|
|
16050
16904
|
function isFunction(node) {
|
|
16051
|
-
return node.type ===
|
|
16905
|
+
return node.type === AST_NODE_TYPES71.ArrowFunctionExpression || node.type === AST_NODE_TYPES71.FunctionDeclaration || node.type === AST_NODE_TYPES71.FunctionExpression;
|
|
16052
16906
|
}
|
|
16053
16907
|
function reportMisordered(context, candidates, scopeDefinitions, calls, pinned, canMove = () => true, makeFix) {
|
|
16054
16908
|
const byName = new Map(scopeDefinitions.map((definition) => [definition.name, definition]));
|
|
@@ -16145,8 +16999,8 @@ function moduleScope(context, program) {
|
|
|
16145
16999
|
for (const node of declarations) counts.set(node.name, (counts.get(node.name) ?? 0) + 1);
|
|
16146
17000
|
const overloadNames = new Set(
|
|
16147
17001
|
program.body.flatMap((statement) => {
|
|
16148
|
-
const node = statement.type ===
|
|
16149
|
-
return node?.type ===
|
|
17002
|
+
const node = statement.type === AST_NODE_TYPES71.ExportNamedDeclaration ? statement.declaration : statement;
|
|
17003
|
+
return node?.type === AST_NODE_TYPES71.TSDeclareFunction && node.id !== null ? [node.id.name] : [];
|
|
16150
17004
|
})
|
|
16151
17005
|
);
|
|
16152
17006
|
const exported = exportedNames(program);
|
|
@@ -16170,7 +17024,7 @@ function moduleScope(context, program) {
|
|
|
16170
17024
|
const nearestFunction2 = [...ancestors].reverse().find(isFunction);
|
|
16171
17025
|
const parent = identifier.parent;
|
|
16172
17026
|
const callerDefinition = nearestFunction2 === void 0 ? void 0 : byFunction.get(nearestFunction2);
|
|
16173
|
-
if (callerDefinition === void 0 || parent.type !==
|
|
17027
|
+
if (callerDefinition === void 0 || parent.type !== AST_NODE_TYPES71.CallExpression || parent.callee !== identifier) {
|
|
16174
17028
|
pinned.add(definition.name);
|
|
16175
17029
|
continue;
|
|
16176
17030
|
}
|
|
@@ -16185,38 +17039,38 @@ function moduleScope(context, program) {
|
|
|
16185
17039
|
function exportedNames(program) {
|
|
16186
17040
|
const names = /* @__PURE__ */ new Set();
|
|
16187
17041
|
for (const statement of program.body) {
|
|
16188
|
-
if (statement.type !==
|
|
16189
|
-
if (statement.declaration?.type ===
|
|
17042
|
+
if (statement.type !== AST_NODE_TYPES71.ExportNamedDeclaration || statement.exportKind === "type" || statement.source !== null) continue;
|
|
17043
|
+
if (statement.declaration?.type === AST_NODE_TYPES71.FunctionDeclaration && statement.declaration.id !== null) {
|
|
16190
17044
|
names.add(statement.declaration.id.name);
|
|
16191
17045
|
}
|
|
16192
|
-
if (statement.declaration?.type ===
|
|
17046
|
+
if (statement.declaration?.type === AST_NODE_TYPES71.VariableDeclaration) {
|
|
16193
17047
|
for (const declarator of statement.declaration.declarations) {
|
|
16194
|
-
if (declarator.id.type ===
|
|
17048
|
+
if (declarator.id.type === AST_NODE_TYPES71.Identifier) names.add(declarator.id.name);
|
|
16195
17049
|
}
|
|
16196
17050
|
}
|
|
16197
17051
|
for (const specifier of statement.specifiers) {
|
|
16198
|
-
if (specifier.exportKind !== "type" && specifier.local.type ===
|
|
17052
|
+
if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES71.Identifier) {
|
|
16199
17053
|
names.add(specifier.local.name);
|
|
16200
17054
|
}
|
|
16201
17055
|
}
|
|
16202
17056
|
}
|
|
16203
17057
|
for (const statement of program.body) {
|
|
16204
|
-
if (statement.type ===
|
|
16205
|
-
if (statement.type ===
|
|
17058
|
+
if (statement.type === AST_NODE_TYPES71.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES71.Identifier) names.add(statement.declaration.name);
|
|
17059
|
+
if (statement.type === AST_NODE_TYPES71.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES71.FunctionDeclaration && statement.declaration.id !== null) names.add(statement.declaration.id.name);
|
|
16206
17060
|
}
|
|
16207
17061
|
return names;
|
|
16208
17062
|
}
|
|
16209
17063
|
function moduleDefinitions(program) {
|
|
16210
17064
|
const definitions = [];
|
|
16211
17065
|
for (const statement of program.body) {
|
|
16212
|
-
const node = statement.type ===
|
|
16213
|
-
if (node?.type ===
|
|
17066
|
+
const node = statement.type === AST_NODE_TYPES71.ExportNamedDeclaration || statement.type === AST_NODE_TYPES71.ExportDefaultDeclaration ? statement.declaration : statement;
|
|
17067
|
+
if (node?.type === AST_NODE_TYPES71.FunctionDeclaration && node.id !== null && node.body !== null) {
|
|
16214
17068
|
definitions.push({ name: node.id.name, node, functionNode: node, bindingNode: node });
|
|
16215
17069
|
continue;
|
|
16216
17070
|
}
|
|
16217
|
-
if (node?.type !==
|
|
17071
|
+
if (node?.type !== AST_NODE_TYPES71.VariableDeclaration || node.kind !== "const") continue;
|
|
16218
17072
|
for (const declarator of node.declarations) {
|
|
16219
|
-
if (declarator.id.type ===
|
|
17073
|
+
if (declarator.id.type === AST_NODE_TYPES71.Identifier && declarator.init !== null && isFunction(declarator.init)) {
|
|
16220
17074
|
definitions.push({
|
|
16221
17075
|
name: declarator.id.name,
|
|
16222
17076
|
node: declarator,
|
|
@@ -16229,21 +17083,21 @@ function moduleDefinitions(program) {
|
|
|
16229
17083
|
return definitions;
|
|
16230
17084
|
}
|
|
16231
17085
|
function methodName(node) {
|
|
16232
|
-
if (node.key.type ===
|
|
16233
|
-
return !node.computed && node.key.type ===
|
|
17086
|
+
if (node.key.type === AST_NODE_TYPES71.PrivateIdentifier) return `#${node.key.name}`;
|
|
17087
|
+
return !node.computed && node.key.type === AST_NODE_TYPES71.Identifier ? node.key.name : null;
|
|
16234
17088
|
}
|
|
16235
17089
|
function referencedMethod(context, node, classVariables) {
|
|
16236
|
-
const objectVariable = node.object.type ===
|
|
17090
|
+
const objectVariable = node.object.type === AST_NODE_TYPES71.Identifier ? ASTUtils23.findVariable(context.sourceCode.getScope(node.object), node.object.name) : null;
|
|
16237
17091
|
const isClassReference = objectVariable !== null && classVariables.has(objectVariable);
|
|
16238
|
-
if (node.object.type !==
|
|
16239
|
-
if (node.property.type ===
|
|
16240
|
-
if (!node.computed && node.property.type ===
|
|
16241
|
-
return node.computed && node.property.type ===
|
|
17092
|
+
if (node.object.type !== AST_NODE_TYPES71.ThisExpression && !isClassReference) return null;
|
|
17093
|
+
if (node.property.type === AST_NODE_TYPES71.PrivateIdentifier) return `#${node.property.name}`;
|
|
17094
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES71.Identifier) return node.property.name;
|
|
17095
|
+
return node.computed && node.property.type === AST_NODE_TYPES71.Literal && typeof node.property.value === "string" ? node.property.value : null;
|
|
16242
17096
|
}
|
|
16243
17097
|
function referencedPropertyName(node) {
|
|
16244
|
-
if (node.property.type ===
|
|
16245
|
-
if (!node.computed && node.property.type ===
|
|
16246
|
-
return node.computed && node.property.type ===
|
|
17098
|
+
if (node.property.type === AST_NODE_TYPES71.PrivateIdentifier) return `#${node.property.name}`;
|
|
17099
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES71.Identifier) return node.property.name;
|
|
17100
|
+
return node.computed && node.property.type === AST_NODE_TYPES71.Literal && typeof node.property.value === "string" ? node.property.value : null;
|
|
16247
17101
|
}
|
|
16248
17102
|
function walk2(node, visitorKeys, visit, nestedFunction = false) {
|
|
16249
17103
|
visit(node, nestedFunction);
|
|
@@ -16259,7 +17113,7 @@ function walk2(node, visitorKeys, visit, nestedFunction = false) {
|
|
|
16259
17113
|
}
|
|
16260
17114
|
function classScope(context, node, computedReferenceNames) {
|
|
16261
17115
|
const methods = node.body.body.filter(
|
|
16262
|
-
(member) => member.type ===
|
|
17116
|
+
(member) => member.type === AST_NODE_TYPES71.MethodDefinition
|
|
16263
17117
|
);
|
|
16264
17118
|
const counts = /* @__PURE__ */ new Map();
|
|
16265
17119
|
for (const method of methods) {
|
|
@@ -16267,8 +17121,8 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16267
17121
|
if (name !== null) counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
16268
17122
|
}
|
|
16269
17123
|
for (const member of node.body.body) {
|
|
16270
|
-
if (member.type !==
|
|
16271
|
-
const name = !member.computed && member.key.type ===
|
|
17124
|
+
if (member.type !== AST_NODE_TYPES71.TSAbstractMethodDefinition) continue;
|
|
17125
|
+
const name = !member.computed && member.key.type === AST_NODE_TYPES71.Identifier ? member.key.name : null;
|
|
16272
17126
|
if (name !== null) counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
16273
17127
|
}
|
|
16274
17128
|
const scopeDefinitions = methods.flatMap((method) => {
|
|
@@ -16277,7 +17131,7 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16277
17131
|
});
|
|
16278
17132
|
const definitions = methods.flatMap((method) => {
|
|
16279
17133
|
const name = methodName(method);
|
|
16280
|
-
const isPrivate = method.accessibility === "private" || method.key.type ===
|
|
17134
|
+
const isPrivate = method.accessibility === "private" || method.key.type === AST_NODE_TYPES71.PrivateIdentifier;
|
|
16281
17135
|
return name !== null && isPrivate && counts.get(name) === 1 && method.decorators.length === 0 ? [{ name, node: method }] : [];
|
|
16282
17136
|
});
|
|
16283
17137
|
if (definitions.length === 0) return;
|
|
@@ -16286,11 +17140,11 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16286
17140
|
const pinned = /* @__PURE__ */ new Set();
|
|
16287
17141
|
const classVariables = /* @__PURE__ */ new Set();
|
|
16288
17142
|
if (node.id !== null) {
|
|
16289
|
-
const internal =
|
|
17143
|
+
const internal = ASTUtils23.findVariable(context.sourceCode.getScope(node), node.id.name);
|
|
16290
17144
|
if (internal !== null) classVariables.add(internal);
|
|
16291
17145
|
}
|
|
16292
|
-
if (node.type ===
|
|
16293
|
-
const outer =
|
|
17146
|
+
if (node.type === AST_NODE_TYPES71.ClassExpression && node.parent.type === AST_NODE_TYPES71.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES71.Identifier) {
|
|
17147
|
+
const outer = ASTUtils23.findVariable(context.sourceCode.getScope(node.parent), node.parent.id.name);
|
|
16294
17148
|
if (outer !== null) classVariables.add(outer);
|
|
16295
17149
|
}
|
|
16296
17150
|
for (const method of methods) {
|
|
@@ -16306,27 +17160,27 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16306
17160
|
}
|
|
16307
17161
|
const thisValue = (value) => {
|
|
16308
17162
|
let current = value;
|
|
16309
|
-
while (current?.type ===
|
|
16310
|
-
return current?.type ===
|
|
17163
|
+
while (current?.type === AST_NODE_TYPES71.TSAsExpression || current?.type === AST_NODE_TYPES71.TSSatisfiesExpression || current?.type === AST_NODE_TYPES71.TSNonNullExpression) current = current.expression;
|
|
17164
|
+
return current?.type === AST_NODE_TYPES71.ThisExpression;
|
|
16311
17165
|
};
|
|
16312
17166
|
const collectAlias = (current, nestedFunction) => {
|
|
16313
|
-
if (nestedFunction || current.type !==
|
|
16314
|
-
if (current.type ===
|
|
16315
|
-
const binding = current.type ===
|
|
16316
|
-
const value = current.type ===
|
|
17167
|
+
if (nestedFunction || current.type !== AST_NODE_TYPES71.VariableDeclarator && current.type !== AST_NODE_TYPES71.AssignmentPattern) return;
|
|
17168
|
+
if (current.type === AST_NODE_TYPES71.VariableDeclarator && (current.parent.type !== AST_NODE_TYPES71.VariableDeclaration || current.parent.kind !== "const")) return;
|
|
17169
|
+
const binding = current.type === AST_NODE_TYPES71.VariableDeclarator ? current.id : current.left;
|
|
17170
|
+
const value = current.type === AST_NODE_TYPES71.VariableDeclarator ? current.init : current.right;
|
|
16317
17171
|
if (!thisValue(value)) return;
|
|
16318
|
-
if (binding.type ===
|
|
17172
|
+
if (binding.type === AST_NODE_TYPES71.ObjectPattern) {
|
|
16319
17173
|
for (const property of binding.properties) {
|
|
16320
|
-
if (property.type ===
|
|
17174
|
+
if (property.type === AST_NODE_TYPES71.RestElement) {
|
|
16321
17175
|
for (const name of privateNames) pinned.add(name);
|
|
16322
|
-
} else if (property.key.type ===
|
|
17176
|
+
} else if (property.key.type === AST_NODE_TYPES71.Identifier && privateNames.has(property.key.name)) {
|
|
16323
17177
|
pinned.add(property.key.name);
|
|
16324
17178
|
}
|
|
16325
17179
|
}
|
|
16326
17180
|
return;
|
|
16327
17181
|
}
|
|
16328
|
-
if (binding.type !==
|
|
16329
|
-
const variable =
|
|
17182
|
+
if (binding.type !== AST_NODE_TYPES71.Identifier) return;
|
|
17183
|
+
const variable = ASTUtils23.findVariable(context.sourceCode.getScope(binding), binding.name);
|
|
16330
17184
|
if (variable !== null) {
|
|
16331
17185
|
methodClassVariables.add(variable);
|
|
16332
17186
|
methodAliases.add(variable);
|
|
@@ -16339,16 +17193,16 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16339
17193
|
walk2(statement, context.sourceCode.visitorKeys, collectAlias);
|
|
16340
17194
|
}
|
|
16341
17195
|
const visitCall = (current, nestedFunction) => {
|
|
16342
|
-
if (current.type ===
|
|
17196
|
+
if (current.type === AST_NODE_TYPES71.VariableDeclarator && current.id.type === AST_NODE_TYPES71.ObjectPattern && thisValue(current.init)) {
|
|
16343
17197
|
for (const property of current.id.properties) {
|
|
16344
|
-
if (property.type ===
|
|
17198
|
+
if (property.type === AST_NODE_TYPES71.RestElement) {
|
|
16345
17199
|
for (const name of privateNames) pinned.add(name);
|
|
16346
17200
|
continue;
|
|
16347
17201
|
}
|
|
16348
|
-
if (property.type ===
|
|
17202
|
+
if (property.type === AST_NODE_TYPES71.Property && property.key.type === AST_NODE_TYPES71.Identifier && privateNames.has(property.key.name)) pinned.add(property.key.name);
|
|
16349
17203
|
}
|
|
16350
17204
|
}
|
|
16351
|
-
if (current.type !==
|
|
17205
|
+
if (current.type !== AST_NODE_TYPES71.MemberExpression) return;
|
|
16352
17206
|
const target = referencedMethod(context, current, methodClassVariables);
|
|
16353
17207
|
if (target === null) {
|
|
16354
17208
|
const possibleTarget = referencedPropertyName(current);
|
|
@@ -16356,12 +17210,12 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16356
17210
|
return;
|
|
16357
17211
|
}
|
|
16358
17212
|
if (!privateNames.has(target)) return;
|
|
16359
|
-
const objectVariable = current.object.type ===
|
|
17213
|
+
const objectVariable = current.object.type === AST_NODE_TYPES71.Identifier ? ASTUtils23.findVariable(context.sourceCode.getScope(current.object), current.object.name) : null;
|
|
16360
17214
|
if (objectVariable !== null && methodAliases.has(objectVariable)) {
|
|
16361
17215
|
pinned.add(target);
|
|
16362
17216
|
return;
|
|
16363
17217
|
}
|
|
16364
|
-
if (current.computed || nestedFunction || parameterDecoratorNodes.has(current) || current.parent.type !==
|
|
17218
|
+
if (current.computed || nestedFunction || parameterDecoratorNodes.has(current) || current.parent.type !== AST_NODE_TYPES71.CallExpression || current.parent.callee !== current) {
|
|
16365
17219
|
pinned.add(target);
|
|
16366
17220
|
return;
|
|
16367
17221
|
}
|
|
@@ -16381,9 +17235,9 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16381
17235
|
}
|
|
16382
17236
|
}
|
|
16383
17237
|
for (const member of node.body.body) {
|
|
16384
|
-
if (member.type ===
|
|
17238
|
+
if (member.type === AST_NODE_TYPES71.MethodDefinition || member.type === AST_NODE_TYPES71.TSAbstractMethodDefinition) continue;
|
|
16385
17239
|
walk2(member, context.sourceCode.visitorKeys, (current) => {
|
|
16386
|
-
if (current.type !==
|
|
17240
|
+
if (current.type !== AST_NODE_TYPES71.MemberExpression) return;
|
|
16387
17241
|
const target = referencedMethod(context, current, classVariables);
|
|
16388
17242
|
const possibleTarget = target ?? referencedPropertyName(current);
|
|
16389
17243
|
if (possibleTarget !== null && privateNames.has(possibleTarget)) pinned.add(possibleTarget);
|
|
@@ -16435,12 +17289,12 @@ function classScope(context, node, computedReferenceNames) {
|
|
|
16435
17289
|
}
|
|
16436
17290
|
function isClassRuntimeBarrier(member) {
|
|
16437
17291
|
switch (member.type) {
|
|
16438
|
-
case
|
|
17292
|
+
case AST_NODE_TYPES71.StaticBlock:
|
|
16439
17293
|
return true;
|
|
16440
|
-
case
|
|
16441
|
-
case
|
|
17294
|
+
case AST_NODE_TYPES71.PropertyDefinition:
|
|
17295
|
+
case AST_NODE_TYPES71.AccessorProperty:
|
|
16442
17296
|
return member.static || member.computed || member.decorators.length > 0 || member.value !== null;
|
|
16443
|
-
case
|
|
17297
|
+
case AST_NODE_TYPES71.MethodDefinition:
|
|
16444
17298
|
return member.computed || member.decorators.length > 0;
|
|
16445
17299
|
default:
|
|
16446
17300
|
return false;
|
|
@@ -16473,7 +17327,7 @@ var stepdown_default = createRule({
|
|
|
16473
17327
|
moduleScope(context, program);
|
|
16474
17328
|
const computedReferenceNames = /* @__PURE__ */ new Set();
|
|
16475
17329
|
walk2(program, context.sourceCode.visitorKeys, (node) => {
|
|
16476
|
-
if (node.type ===
|
|
17330
|
+
if (node.type === AST_NODE_TYPES71.MemberExpression && node.computed && node.property.type === AST_NODE_TYPES71.Literal && typeof node.property.value === "string") computedReferenceNames.add(node.property.value);
|
|
16477
17331
|
});
|
|
16478
17332
|
for (const node of classes) classScope(context, node, computedReferenceNames);
|
|
16479
17333
|
}
|
|
@@ -16482,7 +17336,7 @@ var stepdown_default = createRule({
|
|
|
16482
17336
|
});
|
|
16483
17337
|
|
|
16484
17338
|
// src/rules/source-coupled-test.ts
|
|
16485
|
-
import { AST_NODE_TYPES as
|
|
17339
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES72 } from "@typescript-eslint/utils";
|
|
16486
17340
|
var GENERAL_SOURCE_SUFFIX_RE = /\.(?:bash|sh|ya?ml|jsonc|py|[cm]?[jt]s)$/iu;
|
|
16487
17341
|
var FS_MODULES = /* @__PURE__ */ new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
|
|
16488
17342
|
var FS_READERS = /* @__PURE__ */ new Set(["readFile", "readFileSync"]);
|
|
@@ -16551,28 +17405,28 @@ var SOURCE_COUPLED_TEST_DOCUMENTATION = {
|
|
|
16551
17405
|
]
|
|
16552
17406
|
};
|
|
16553
17407
|
function staticMemberName7(node) {
|
|
16554
|
-
if (!node.computed && node.property.type ===
|
|
16555
|
-
if (node.computed && node.property.type ===
|
|
17408
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES72.Identifier) return node.property.name;
|
|
17409
|
+
if (node.computed && node.property.type === AST_NODE_TYPES72.Literal && typeof node.property.value === "string") return node.property.value;
|
|
16556
17410
|
return null;
|
|
16557
17411
|
}
|
|
16558
|
-
function
|
|
16559
|
-
if (node.type ===
|
|
16560
|
-
if (node.type ===
|
|
16561
|
-
if (node.type ===
|
|
17412
|
+
function unwrap6(node) {
|
|
17413
|
+
if (node.type === AST_NODE_TYPES72.AwaitExpression) return unwrap6(node.argument);
|
|
17414
|
+
if (node.type === AST_NODE_TYPES72.ChainExpression) return unwrap6(node.expression);
|
|
17415
|
+
if (node.type === AST_NODE_TYPES72.TSAsExpression || node.type === AST_NODE_TYPES72.TSNonNullExpression || node.type === AST_NODE_TYPES72.TSTypeAssertion) return unwrap6(node.expression);
|
|
16562
17416
|
return node;
|
|
16563
17417
|
}
|
|
16564
17418
|
function stringValue(node) {
|
|
16565
|
-
const current =
|
|
16566
|
-
if (current.type ===
|
|
16567
|
-
if (current.type ===
|
|
17419
|
+
const current = unwrap6(node);
|
|
17420
|
+
if (current.type === AST_NODE_TYPES72.Literal && typeof current.value === "string") return current.value;
|
|
17421
|
+
if (current.type === AST_NODE_TYPES72.TemplateLiteral && current.expressions.length === 0) return current.quasis[0]?.value.cooked ?? null;
|
|
16568
17422
|
return null;
|
|
16569
17423
|
}
|
|
16570
17424
|
function importSource(node) {
|
|
16571
17425
|
return typeof node.source.value === "string" ? node.source.value : null;
|
|
16572
17426
|
}
|
|
16573
17427
|
function requireSource(node) {
|
|
16574
|
-
const current =
|
|
16575
|
-
if (current.type !==
|
|
17428
|
+
const current = unwrap6(node);
|
|
17429
|
+
if (current.type !== AST_NODE_TYPES72.CallExpression || current.callee.type !== AST_NODE_TYPES72.Identifier || current.callee.name !== "require" || current.arguments.length !== 1 || current.arguments[0]?.type === AST_NODE_TYPES72.SpreadElement) return null;
|
|
16576
17430
|
return stringValue(current.arguments[0]);
|
|
16577
17431
|
}
|
|
16578
17432
|
function newScope() {
|
|
@@ -16609,80 +17463,80 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
|
16609
17463
|
return /* @__PURE__ */ new Set();
|
|
16610
17464
|
};
|
|
16611
17465
|
const sourcePath = (node) => {
|
|
16612
|
-
const current =
|
|
17466
|
+
const current = unwrap6(node);
|
|
16613
17467
|
const value = stringValue(current);
|
|
16614
17468
|
if (value !== null) return sourceSuffixRe.test(value);
|
|
16615
|
-
if (current.type ===
|
|
16616
|
-
if (current.type ===
|
|
17469
|
+
if (current.type === AST_NODE_TYPES72.Identifier) return visible("paths", current.name);
|
|
17470
|
+
if (current.type === AST_NODE_TYPES72.BinaryExpression && current.operator === "+") {
|
|
16617
17471
|
return sourcePath(current.left) || sourcePath(current.right);
|
|
16618
17472
|
}
|
|
16619
|
-
if (current.type ===
|
|
16620
|
-
if (current.type ===
|
|
16621
|
-
return current.arguments.some((argument) => argument.type !==
|
|
17473
|
+
if (current.type === AST_NODE_TYPES72.TemplateLiteral) return current.expressions.some(sourcePath);
|
|
17474
|
+
if (current.type === AST_NODE_TYPES72.CallExpression || current.type === AST_NODE_TYPES72.NewExpression) {
|
|
17475
|
+
return current.arguments.some((argument) => argument.type !== AST_NODE_TYPES72.SpreadElement && sourcePath(argument));
|
|
16622
17476
|
}
|
|
16623
|
-
if (current.type ===
|
|
17477
|
+
if (current.type === AST_NODE_TYPES72.MemberExpression) return sourcePath(current.object);
|
|
16624
17478
|
return false;
|
|
16625
17479
|
};
|
|
16626
17480
|
const rawRead = (node) => {
|
|
16627
|
-
const current =
|
|
16628
|
-
if (current.type !==
|
|
16629
|
-
const callee =
|
|
16630
|
-
if (callee.type ===
|
|
17481
|
+
const current = unwrap6(node);
|
|
17482
|
+
if (current.type !== AST_NODE_TYPES72.CallExpression || current.arguments.length === 0) return false;
|
|
17483
|
+
const callee = unwrap6(current.callee);
|
|
17484
|
+
if (callee.type === AST_NODE_TYPES72.Identifier) {
|
|
16631
17485
|
return visible("fsReaders", callee.name) && sourcePath(current.arguments[0]);
|
|
16632
17486
|
}
|
|
16633
|
-
if (callee.type !==
|
|
17487
|
+
if (callee.type !== AST_NODE_TYPES72.MemberExpression) return false;
|
|
16634
17488
|
const name2 = staticMemberName7(callee);
|
|
16635
|
-
const object =
|
|
16636
|
-
return name2 !== null && FS_READERS.has(name2) && object.type ===
|
|
17489
|
+
const object = unwrap6(callee.object);
|
|
17490
|
+
return name2 !== null && FS_READERS.has(name2) && object.type === AST_NODE_TYPES72.Identifier && visible("fsObjects", object.name) && sourcePath(current.arguments[0]);
|
|
16637
17491
|
};
|
|
16638
17492
|
const rawOrigins = (node) => {
|
|
16639
|
-
const current =
|
|
16640
|
-
if (current.type ===
|
|
17493
|
+
const current = unwrap6(node);
|
|
17494
|
+
if (current.type === AST_NODE_TYPES72.Identifier) return visibleRawOrigins(current.name);
|
|
16641
17495
|
if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
|
|
16642
|
-
if (current.type ===
|
|
16643
|
-
if (current.type ===
|
|
16644
|
-
if (current.type !==
|
|
16645
|
-
const callee =
|
|
16646
|
-
if (callee.type !==
|
|
17496
|
+
if (current.type === AST_NODE_TYPES72.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
|
|
17497
|
+
if (current.type === AST_NODE_TYPES72.MemberExpression && staticMemberName7(current) === "length") return rawOrigins(current.object);
|
|
17498
|
+
if (current.type !== AST_NODE_TYPES72.CallExpression) return /* @__PURE__ */ new Set();
|
|
17499
|
+
const callee = unwrap6(current.callee);
|
|
17500
|
+
if (callee.type !== AST_NODE_TYPES72.MemberExpression) return /* @__PURE__ */ new Set();
|
|
16647
17501
|
const name2 = staticMemberName7(callee);
|
|
16648
17502
|
return name2 !== null && TEXT_TRANSFORMS.has(name2) ? rawOrigins(callee.object) : /* @__PURE__ */ new Set();
|
|
16649
17503
|
};
|
|
16650
17504
|
const evidenceOrigins = (node) => {
|
|
16651
|
-
const current =
|
|
17505
|
+
const current = unwrap6(node);
|
|
16652
17506
|
const direct = rawOrigins(current);
|
|
16653
17507
|
if (direct.size > 0) return direct;
|
|
16654
|
-
if (current.type ===
|
|
16655
|
-
if (current.type ===
|
|
16656
|
-
if (current.type !==
|
|
16657
|
-
const callee =
|
|
16658
|
-
if (callee.type !==
|
|
17508
|
+
if (current.type === AST_NODE_TYPES72.BinaryExpression || current.type === AST_NODE_TYPES72.LogicalExpression) return /* @__PURE__ */ new Set([...evidenceOrigins(current.left), ...evidenceOrigins(current.right)]);
|
|
17509
|
+
if (current.type === AST_NODE_TYPES72.UnaryExpression) return evidenceOrigins(current.argument);
|
|
17510
|
+
if (current.type !== AST_NODE_TYPES72.CallExpression) return /* @__PURE__ */ new Set();
|
|
17511
|
+
const callee = unwrap6(current.callee);
|
|
17512
|
+
if (callee.type !== AST_NODE_TYPES72.MemberExpression) return /* @__PURE__ */ new Set();
|
|
16659
17513
|
const name2 = staticMemberName7(callee);
|
|
16660
17514
|
if (name2 !== null && TEXT_PREDICATES.has(name2)) return rawOrigins(callee.object);
|
|
16661
|
-
if (name2 !== null && REGEXP_PREDICATES.has(name2)) return new Set(current.arguments.flatMap((argument) => argument.type ===
|
|
17515
|
+
if (name2 !== null && REGEXP_PREDICATES.has(name2)) return new Set(current.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES72.SpreadElement ? [] : [...rawOrigins(argument)]));
|
|
16662
17516
|
return /* @__PURE__ */ new Set();
|
|
16663
17517
|
};
|
|
16664
17518
|
const rawAssertionOrigins = (node) => {
|
|
16665
|
-
const callee =
|
|
16666
|
-
if (callee.type ===
|
|
16667
|
-
return new Set(node.arguments.flatMap((argument) => argument.type ===
|
|
17519
|
+
const callee = unwrap6(node.callee);
|
|
17520
|
+
if (callee.type === AST_NODE_TYPES72.Identifier && callee.name === "assert") {
|
|
17521
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES72.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
16668
17522
|
}
|
|
16669
|
-
if (callee.type !==
|
|
17523
|
+
if (callee.type !== AST_NODE_TYPES72.MemberExpression) return /* @__PURE__ */ new Set();
|
|
16670
17524
|
const matcher = staticMemberName7(callee);
|
|
16671
17525
|
if (matcher === null) return /* @__PURE__ */ new Set();
|
|
16672
|
-
let receiver =
|
|
16673
|
-
while (receiver.type ===
|
|
16674
|
-
if (receiver.type ===
|
|
17526
|
+
let receiver = unwrap6(callee.object);
|
|
17527
|
+
while (receiver.type === AST_NODE_TYPES72.MemberExpression && EXPECT_MODIFIERS2.has(staticMemberName7(receiver) ?? "")) receiver = unwrap6(receiver.object);
|
|
17528
|
+
if (receiver.type === AST_NODE_TYPES72.CallExpression && receiver.callee.type === AST_NODE_TYPES72.Identifier && receiver.callee.name === "expect") {
|
|
16675
17529
|
if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
16676
|
-
return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type ===
|
|
17530
|
+
return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === AST_NODE_TYPES72.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
16677
17531
|
}
|
|
16678
|
-
if (receiver.type !==
|
|
16679
|
-
return new Set(node.arguments.flatMap((argument) => argument.type ===
|
|
17532
|
+
if (receiver.type !== AST_NODE_TYPES72.Identifier || receiver.name !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
17533
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES72.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
16680
17534
|
};
|
|
16681
17535
|
const rawRegexExtractionOrigins = (node) => {
|
|
16682
|
-
const callee =
|
|
16683
|
-
if (callee.type !==
|
|
17536
|
+
const callee = unwrap6(node.callee);
|
|
17537
|
+
if (callee.type !== AST_NODE_TYPES72.MemberExpression || staticMemberName7(callee) !== "matchAll" || node.arguments.length !== 1) return /* @__PURE__ */ new Set();
|
|
16684
17538
|
const argument = node.arguments[0];
|
|
16685
|
-
if (argument?.type !==
|
|
17539
|
+
if (argument?.type !== AST_NODE_TYPES72.Literal || !(argument.value instanceof RegExp)) return /* @__PURE__ */ new Set();
|
|
16686
17540
|
return rawOrigins(callee.object);
|
|
16687
17541
|
};
|
|
16688
17542
|
const declare = (name2, state) => {
|
|
@@ -16702,16 +17556,16 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
|
16702
17556
|
}
|
|
16703
17557
|
};
|
|
16704
17558
|
const sourceCollection = (node) => {
|
|
16705
|
-
const current =
|
|
16706
|
-
return current.type ===
|
|
17559
|
+
const current = unwrap6(node);
|
|
17560
|
+
return current.type === AST_NODE_TYPES72.ArrayExpression && current.elements.length > 0 && current.elements.every((element) => element !== null && element.type !== AST_NODE_TYPES72.SpreadElement && sourcePath(element));
|
|
16707
17561
|
};
|
|
16708
17562
|
const declaredNames2 = (node) => {
|
|
16709
|
-
const current =
|
|
16710
|
-
if (current.type ===
|
|
16711
|
-
if (current.type ===
|
|
16712
|
-
if (current.type ===
|
|
16713
|
-
if (current.type ===
|
|
16714
|
-
if (current.type ===
|
|
17563
|
+
const current = unwrap6(node);
|
|
17564
|
+
if (current.type === AST_NODE_TYPES72.Identifier) return [current.name];
|
|
17565
|
+
if (current.type === AST_NODE_TYPES72.AssignmentPattern) return declaredNames2(current.left);
|
|
17566
|
+
if (current.type === AST_NODE_TYPES72.RestElement) return declaredNames2(current.argument);
|
|
17567
|
+
if (current.type === AST_NODE_TYPES72.ArrayPattern) return current.elements.flatMap((element) => element === null ? [] : declaredNames2(element));
|
|
17568
|
+
if (current.type === AST_NODE_TYPES72.ObjectPattern) return current.properties.flatMap((property) => property.type === AST_NODE_TYPES72.RestElement ? declaredNames2(property.argument) : declaredNames2(property.value));
|
|
16715
17569
|
return [];
|
|
16716
17570
|
};
|
|
16717
17571
|
const enterFunction = (node) => {
|
|
@@ -16726,8 +17580,8 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
|
16726
17580
|
const source = importSource(node);
|
|
16727
17581
|
if (source === null || !FS_MODULES.has(source)) return;
|
|
16728
17582
|
for (const specifier of node.specifiers) {
|
|
16729
|
-
if (specifier.type ===
|
|
16730
|
-
const imported = specifier.imported.type ===
|
|
17583
|
+
if (specifier.type === AST_NODE_TYPES72.ImportSpecifier) {
|
|
17584
|
+
const imported = specifier.imported.type === AST_NODE_TYPES72.Identifier ? specifier.imported.name : String(specifier.imported.value);
|
|
16731
17585
|
if (FS_READERS.has(imported)) declare(specifier.local.name, { fsReader: true });
|
|
16732
17586
|
} else {
|
|
16733
17587
|
declare(specifier.local.name, { fsObject: true });
|
|
@@ -16739,29 +17593,29 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
|
16739
17593
|
VariableDeclarator(node) {
|
|
16740
17594
|
if (node.init === null) return;
|
|
16741
17595
|
const required = requireSource(node.init);
|
|
16742
|
-
if (required !== null && FS_MODULES.has(required) && node.id.type ===
|
|
17596
|
+
if (required !== null && FS_MODULES.has(required) && node.id.type === AST_NODE_TYPES72.Identifier) {
|
|
16743
17597
|
declare(node.id.name, { fsObject: true });
|
|
16744
17598
|
return;
|
|
16745
17599
|
}
|
|
16746
|
-
if (node.id.type ===
|
|
17600
|
+
if (node.id.type === AST_NODE_TYPES72.ObjectPattern && required !== null && FS_MODULES.has(required)) {
|
|
16747
17601
|
for (const property of node.id.properties) {
|
|
16748
|
-
if (property.type !==
|
|
16749
|
-
const key = property.key.type ===
|
|
17602
|
+
if (property.type !== AST_NODE_TYPES72.Property || property.value.type !== AST_NODE_TYPES72.Identifier) continue;
|
|
17603
|
+
const key = property.key.type === AST_NODE_TYPES72.Identifier ? property.key.name : property.key.type === AST_NODE_TYPES72.Literal ? String(property.key.value) : "";
|
|
16750
17604
|
if (FS_READERS.has(key)) declare(property.value.name, { fsReader: true });
|
|
16751
17605
|
}
|
|
16752
17606
|
return;
|
|
16753
17607
|
}
|
|
16754
|
-
if (node.id.type !==
|
|
17608
|
+
if (node.id.type !== AST_NODE_TYPES72.Identifier) return;
|
|
16755
17609
|
declare(node.id.name, { collection: sourceCollection(node.init), path: sourcePath(node.init), rawOrigins: rawOrigins(node.init) });
|
|
16756
17610
|
},
|
|
16757
17611
|
AssignmentExpression(node) {
|
|
16758
|
-
if (node.left.type ===
|
|
17612
|
+
if (node.left.type === AST_NODE_TYPES72.Identifier) declare(node.left.name, { path: sourcePath(node.right), rawOrigins: rawOrigins(node.right) });
|
|
16759
17613
|
},
|
|
16760
17614
|
ForOfStatement(node) {
|
|
16761
|
-
const right =
|
|
16762
|
-
const collection = right.type ===
|
|
16763
|
-
const left = node.left.type ===
|
|
16764
|
-
if (collection && left?.type ===
|
|
17615
|
+
const right = unwrap6(node.right);
|
|
17616
|
+
const collection = right.type === AST_NODE_TYPES72.Identifier && visible("collections", right.name);
|
|
17617
|
+
const left = node.left.type === AST_NODE_TYPES72.VariableDeclaration ? node.left.declarations[0]?.id : node.left;
|
|
17618
|
+
if (collection && left?.type === AST_NODE_TYPES72.Identifier) declare(left.name, { path: true });
|
|
16765
17619
|
},
|
|
16766
17620
|
CallExpression(node) {
|
|
16767
17621
|
const origins = /* @__PURE__ */ new Set([
|
|
@@ -16782,6 +17636,120 @@ var source_coupled_test_default = createSourceCoupledRule(
|
|
|
16782
17636
|
GENERAL_SOURCE_SUFFIX_RE
|
|
16783
17637
|
);
|
|
16784
17638
|
|
|
17639
|
+
// src/rules/sole-export-matches-filename.ts
|
|
17640
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES73 } from "@typescript-eslint/utils";
|
|
17641
|
+
var SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION = {
|
|
17642
|
+
summary: "Match a module filename to its sole named public runtime export.",
|
|
17643
|
+
rationale: "When a module owns one runtime responsibility, matching names make that responsibility directly discoverable.",
|
|
17644
|
+
remediation: "Rename the module stem to the kebab-case export name, or colocate genuinely related exports.",
|
|
17645
|
+
category: "maintainability",
|
|
17646
|
+
limitations: [
|
|
17647
|
+
"Framework entrypoints, generic stems covered by no-generic-single-export-module, tests, generated files, anonymous defaults, CommonJS, and re-exports are excluded.",
|
|
17648
|
+
"The rule compares the primary filename stem and preserves conventional suffixes such as .server or .worker."
|
|
17649
|
+
],
|
|
17650
|
+
examples: [
|
|
17651
|
+
{ id: "matching-class", title: "Match a class and module", outcome: "no-match", files: [{ path: "src/artifact-store.ts", source: "export class ArtifactStore {}" }], focusPath: "src/artifact-store.ts", expectedCount: 0, public: true },
|
|
17652
|
+
{ id: "mismatched-class", title: "Do not hide a sole class behind another filename", outcome: "match", files: [{ path: "src/artifacts.ts", source: "export class ArtifactStore {}" }], focusPath: "src/artifacts.ts", expectedCount: 1, public: true }
|
|
17653
|
+
]
|
|
17654
|
+
};
|
|
17655
|
+
var EXCLUDED_STEMS = /* @__PURE__ */ new Set([
|
|
17656
|
+
"common",
|
|
17657
|
+
"global",
|
|
17658
|
+
"helpers",
|
|
17659
|
+
"index",
|
|
17660
|
+
"layout",
|
|
17661
|
+
"loading",
|
|
17662
|
+
"middleware",
|
|
17663
|
+
"misc",
|
|
17664
|
+
"not-found",
|
|
17665
|
+
"page",
|
|
17666
|
+
"route",
|
|
17667
|
+
"shared",
|
|
17668
|
+
"template",
|
|
17669
|
+
"types",
|
|
17670
|
+
"util",
|
|
17671
|
+
"utils"
|
|
17672
|
+
]);
|
|
17673
|
+
function stem3(filename) {
|
|
17674
|
+
const base = filename.replaceAll("\\", "/").split("/").at(-1) ?? "";
|
|
17675
|
+
return base.replace(/\.[cm]?[jt]sx?$/u, "").split(".")[0] ?? "";
|
|
17676
|
+
}
|
|
17677
|
+
function kebabCase(name) {
|
|
17678
|
+
return name.replace(/([A-Z]{2,})([A-Z][a-z])/gu, "$1-$2").replace(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[^a-z0-9]+/giu, "-").replaceAll(/^-+|-+$/gu, "").toLowerCase();
|
|
17679
|
+
}
|
|
17680
|
+
function declarationExport(statement) {
|
|
17681
|
+
const declaration = statement.declaration;
|
|
17682
|
+
if (declaration === null || declaration.declare === true) return [];
|
|
17683
|
+
if (declaration.type === AST_NODE_TYPES73.ClassDeclaration || declaration.type === AST_NODE_TYPES73.FunctionDeclaration || declaration.type === AST_NODE_TYPES73.TSEnumDeclaration) return declaration.id === null ? [] : [{ name: declaration.id.name, node: declaration }];
|
|
17684
|
+
if (declaration.type !== AST_NODE_TYPES73.VariableDeclaration) return [];
|
|
17685
|
+
return declaration.declarations.flatMap(
|
|
17686
|
+
(item) => item.id.type === AST_NODE_TYPES73.Identifier ? [{ name: item.id.name, node: item }] : []
|
|
17687
|
+
);
|
|
17688
|
+
}
|
|
17689
|
+
var sole_export_matches_filename_default = createRule({
|
|
17690
|
+
name: "sole-export-matches-filename",
|
|
17691
|
+
documentation: SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION,
|
|
17692
|
+
meta: {
|
|
17693
|
+
type: "suggestion",
|
|
17694
|
+
docs: { description: "Match a module filename to its sole named public runtime export." },
|
|
17695
|
+
schema: [],
|
|
17696
|
+
messages: {
|
|
17697
|
+
matchSoleExport: "This module's sole runtime export is `{{exported}}`; rename the file stem to `{{expected}}`."
|
|
17698
|
+
}
|
|
17699
|
+
},
|
|
17700
|
+
defaultOptions: [],
|
|
17701
|
+
create(context) {
|
|
17702
|
+
const fileStem = stem3(context.filename);
|
|
17703
|
+
const normalizedFilename = context.filename.replaceAll("\\", "/");
|
|
17704
|
+
if (EXCLUDED_STEMS.has(fileStem) || normalizedFilename.includes("/pages/") || context.filename.endsWith(".d.ts") || isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
17705
|
+
return {
|
|
17706
|
+
"Program:exit"(program) {
|
|
17707
|
+
const exports = [];
|
|
17708
|
+
const publicExports = /* @__PURE__ */ new Set();
|
|
17709
|
+
for (const statement of program.body) {
|
|
17710
|
+
if (statement.type === AST_NODE_TYPES73.ExportAllDeclaration || statement.type === AST_NODE_TYPES73.ExportNamedDeclaration && statement.source !== null) return;
|
|
17711
|
+
if (statement.type === AST_NODE_TYPES73.ExportDefaultDeclaration) {
|
|
17712
|
+
publicExports.add("default");
|
|
17713
|
+
const declaration2 = statement.declaration;
|
|
17714
|
+
if ((declaration2.type === AST_NODE_TYPES73.ClassDeclaration || declaration2.type === AST_NODE_TYPES73.FunctionDeclaration) && declaration2.id !== null) exports.push({ name: declaration2.id.name, node: declaration2 });
|
|
17715
|
+
else return;
|
|
17716
|
+
}
|
|
17717
|
+
if (statement.type !== AST_NODE_TYPES73.ExportNamedDeclaration) continue;
|
|
17718
|
+
const declaration = statement.declaration;
|
|
17719
|
+
if (declaration !== null && "id" in declaration && declaration.id?.type === AST_NODE_TYPES73.Identifier) {
|
|
17720
|
+
publicExports.add(declaration.id.name);
|
|
17721
|
+
}
|
|
17722
|
+
if (declaration?.type === AST_NODE_TYPES73.VariableDeclaration) {
|
|
17723
|
+
for (const item of declaration.declarations) {
|
|
17724
|
+
if (item.id.type === AST_NODE_TYPES73.Identifier) publicExports.add(item.id.name);
|
|
17725
|
+
}
|
|
17726
|
+
}
|
|
17727
|
+
for (const specifier of statement.specifiers) {
|
|
17728
|
+
const exported = specifier.exported.type === AST_NODE_TYPES73.Identifier ? specifier.exported.name : specifier.exported.value;
|
|
17729
|
+
publicExports.add(String(exported));
|
|
17730
|
+
}
|
|
17731
|
+
if (statement.exportKind === "type") continue;
|
|
17732
|
+
exports.push(...declarationExport(statement));
|
|
17733
|
+
for (const specifier of statement.specifiers) {
|
|
17734
|
+
const exported = specifier.exported.type === AST_NODE_TYPES73.Identifier ? specifier.exported.name : specifier.exported.value;
|
|
17735
|
+
publicExports.add(String(exported));
|
|
17736
|
+
if (specifier.exportKind === "type") continue;
|
|
17737
|
+
if (exported === "default") exports.push({ name: specifier.local.name, node: specifier });
|
|
17738
|
+
else exports.push({ name: String(exported), node: specifier });
|
|
17739
|
+
}
|
|
17740
|
+
}
|
|
17741
|
+
const unique = new Map(exports.map((item) => [item.name, item]));
|
|
17742
|
+
if (unique.size !== 1 || publicExports.size !== 1) return;
|
|
17743
|
+
const only = [...unique.values()][0];
|
|
17744
|
+
if (only === void 0) return;
|
|
17745
|
+
const expected = kebabCase(only.name);
|
|
17746
|
+
if (expected === "" || expected === fileStem.toLowerCase()) return;
|
|
17747
|
+
context.report({ node: only.node, messageId: "matchSoleExport", data: { exported: only.name, expected } });
|
|
17748
|
+
}
|
|
17749
|
+
};
|
|
17750
|
+
}
|
|
17751
|
+
});
|
|
17752
|
+
|
|
16785
17753
|
// src/rules/iac-source-coupled-test.ts
|
|
16786
17754
|
var IAC_SOURCE_SUFFIX_RE = /(?:\.tf\.json|\.tftest\.(?:hcl|json)|\.(?:hcl|tf|tfvars))$/iu;
|
|
16787
17755
|
var IAC_SOURCE_COUPLED_TEST_DOCUMENTATION = {
|
|
@@ -16822,8 +17790,8 @@ var iac_source_coupled_test_default = createSourceCoupledRule(
|
|
|
16822
17790
|
|
|
16823
17791
|
// src/rules/require-pascal-case-zod-schema-name.ts
|
|
16824
17792
|
import {
|
|
16825
|
-
AST_NODE_TYPES as
|
|
16826
|
-
ASTUtils as
|
|
17793
|
+
AST_NODE_TYPES as AST_NODE_TYPES74,
|
|
17794
|
+
ASTUtils as ASTUtils24
|
|
16827
17795
|
} from "@typescript-eslint/utils";
|
|
16828
17796
|
var REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION = {
|
|
16829
17797
|
summary: "Require confirmed module-level Zod schema contracts to use PascalCase with a `Schema` suffix.",
|
|
@@ -16956,18 +17924,18 @@ var SCHEMA_RETURNING_METHODS = /* @__PURE__ */ new Set([
|
|
|
16956
17924
|
"superRefine",
|
|
16957
17925
|
"transform"
|
|
16958
17926
|
]);
|
|
16959
|
-
var terminalMethodName = (callee) => !callee.computed && callee.property.type ===
|
|
17927
|
+
var terminalMethodName = (callee) => !callee.computed && callee.property.type === AST_NODE_TYPES74.Identifier ? callee.property.name : null;
|
|
16960
17928
|
var calleeChainRoot = (node) => {
|
|
16961
17929
|
let current = node;
|
|
16962
17930
|
for (; ; ) {
|
|
16963
|
-
if (current.type ===
|
|
17931
|
+
if (current.type === AST_NODE_TYPES74.Identifier) {
|
|
16964
17932
|
return current;
|
|
16965
17933
|
}
|
|
16966
|
-
if (current.type ===
|
|
17934
|
+
if (current.type === AST_NODE_TYPES74.MemberExpression) {
|
|
16967
17935
|
current = current.object;
|
|
16968
17936
|
continue;
|
|
16969
17937
|
}
|
|
16970
|
-
if (current.type ===
|
|
17938
|
+
if (current.type === AST_NODE_TYPES74.CallExpression) {
|
|
16971
17939
|
current = current.callee;
|
|
16972
17940
|
continue;
|
|
16973
17941
|
}
|
|
@@ -16978,13 +17946,13 @@ var chainMemberNames = (node) => {
|
|
|
16978
17946
|
const names = [];
|
|
16979
17947
|
let current = node;
|
|
16980
17948
|
for (; ; ) {
|
|
16981
|
-
if (current.type ===
|
|
16982
|
-
if (current.computed || current.property.type !==
|
|
17949
|
+
if (current.type === AST_NODE_TYPES74.MemberExpression) {
|
|
17950
|
+
if (current.computed || current.property.type !== AST_NODE_TYPES74.Identifier) return [];
|
|
16983
17951
|
names.push(current.property.name);
|
|
16984
17952
|
current = current.object;
|
|
16985
17953
|
continue;
|
|
16986
17954
|
}
|
|
16987
|
-
if (current.type ===
|
|
17955
|
+
if (current.type === AST_NODE_TYPES74.CallExpression) {
|
|
16988
17956
|
current = current.callee;
|
|
16989
17957
|
continue;
|
|
16990
17958
|
}
|
|
@@ -16995,16 +17963,16 @@ var chainMemberNames = (node) => {
|
|
|
16995
17963
|
};
|
|
16996
17964
|
var unwrapExpression4 = (node) => {
|
|
16997
17965
|
let current = node;
|
|
16998
|
-
while (current.type ===
|
|
17966
|
+
while (current.type === AST_NODE_TYPES74.TSAsExpression || current.type === AST_NODE_TYPES74.TSSatisfiesExpression || current.type === AST_NODE_TYPES74.TSNonNullExpression || current.type === AST_NODE_TYPES74.TSTypeAssertion) {
|
|
16999
17967
|
current = current.expression;
|
|
17000
17968
|
}
|
|
17001
17969
|
return current;
|
|
17002
17970
|
};
|
|
17003
17971
|
var isModuleDeclarator = (node) => {
|
|
17004
17972
|
const declaration = node.parent;
|
|
17005
|
-
if (declaration.type !==
|
|
17973
|
+
if (declaration.type !== AST_NODE_TYPES74.VariableDeclaration) return false;
|
|
17006
17974
|
const owner = declaration.parent;
|
|
17007
|
-
return owner.type ===
|
|
17975
|
+
return owner.type === AST_NODE_TYPES74.Program || owner.type === AST_NODE_TYPES74.ExportNamedDeclaration && owner.parent.type === AST_NODE_TYPES74.Program;
|
|
17008
17976
|
};
|
|
17009
17977
|
var require_pascal_case_zod_schema_name_default = createRule({
|
|
17010
17978
|
name: "require-pascal-case-zod-schema-name",
|
|
@@ -17024,7 +17992,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
|
|
|
17024
17992
|
const zodBindings = /* @__PURE__ */ new Set();
|
|
17025
17993
|
const schemaBindings = /* @__PURE__ */ new Set();
|
|
17026
17994
|
function resolvedBinding(identifier) {
|
|
17027
|
-
return
|
|
17995
|
+
return ASTUtils24.findVariable(
|
|
17028
17996
|
context.sourceCode.getScope(identifier),
|
|
17029
17997
|
identifier.name
|
|
17030
17998
|
);
|
|
@@ -17045,8 +18013,8 @@ var require_pascal_case_zod_schema_name_default = createRule({
|
|
|
17045
18013
|
}
|
|
17046
18014
|
function isConfirmedSchema(expression) {
|
|
17047
18015
|
const init = unwrapExpression4(expression);
|
|
17048
|
-
if (init.type ===
|
|
17049
|
-
if (init.type !==
|
|
18016
|
+
if (init.type === AST_NODE_TYPES74.Identifier) return isSchemaBinding(init);
|
|
18017
|
+
if (init.type !== AST_NODE_TYPES74.CallExpression || init.callee.type !== AST_NODE_TYPES74.MemberExpression) {
|
|
17050
18018
|
return false;
|
|
17051
18019
|
}
|
|
17052
18020
|
const terminal = terminalMethodName(init.callee);
|
|
@@ -17066,7 +18034,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
|
|
|
17066
18034
|
ImportDeclaration(node) {
|
|
17067
18035
|
if (!isZodModule(node.source.value)) return;
|
|
17068
18036
|
for (const specifier of node.specifiers) {
|
|
17069
|
-
if (specifier.type ===
|
|
18037
|
+
if (specifier.type === AST_NODE_TYPES74.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES74.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES74.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES74.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
|
|
17070
18038
|
recordZodBinding(specifier.local);
|
|
17071
18039
|
}
|
|
17072
18040
|
}
|
|
@@ -17075,7 +18043,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
|
|
|
17075
18043
|
if (!isModuleDeclarator(node)) return;
|
|
17076
18044
|
const init = node.init;
|
|
17077
18045
|
if (init === null || init === void 0) return;
|
|
17078
|
-
if (node.id.type !==
|
|
18046
|
+
if (node.id.type !== AST_NODE_TYPES74.Identifier) return;
|
|
17079
18047
|
if (!isConfirmedSchema(init)) return;
|
|
17080
18048
|
const binding = resolvedBinding(node.id);
|
|
17081
18049
|
if (binding !== null) schemaBindings.add(binding);
|
|
@@ -17233,11 +18201,16 @@ var RULES = {
|
|
|
17233
18201
|
"prefer-shadcn-primitives": prefer_shadcn_primitives_default,
|
|
17234
18202
|
"prefer-module-level-constant": prefer_module_level_constant_default,
|
|
17235
18203
|
"prefer-module-level-schema": prefer_module_level_schema_default,
|
|
18204
|
+
"prefer-named-complex-return-type": prefer_named_complex_return_type_default,
|
|
17236
18205
|
"prefer-native-random-uuid": prefer_native_random_uuid_default,
|
|
18206
|
+
"prefer-node-crypto-hash": prefer_node_crypto_hash_default,
|
|
18207
|
+
"prefer-node-fs-promises": prefer_node_fs_promises_default,
|
|
17237
18208
|
"prefer-non-nullable-collection": prefer_non_nullable_collection_default,
|
|
17238
18209
|
"prefer-nullish-filter-predicate": prefer_nullish_filter_predicate_default,
|
|
17239
18210
|
"prefer-await-in-async-return": prefer_await_in_async_return_default,
|
|
17240
18211
|
"prefer-schema-for-api-payload": prefer_schema_for_api_payload_default,
|
|
18212
|
+
"prefer-shared-zod-enum": prefer_shared_zod_enum_default,
|
|
18213
|
+
"prefer-switch-for-repeated-equality": prefer_switch_for_repeated_equality_default,
|
|
17241
18214
|
"prefer-semantic-colors": prefer_semantic_colors_default,
|
|
17242
18215
|
"prefer-server-actions": prefer_server_actions_default,
|
|
17243
18216
|
"prefer-whole-object-assertion": prefer_whole_object_assertion_default,
|
|
@@ -17245,24 +18218,37 @@ var RULES = {
|
|
|
17245
18218
|
"prefer-zod-infer": prefer_zod_infer_default,
|
|
17246
18219
|
"require-assert-never": require_assert_never_default,
|
|
17247
18220
|
"require-fetch-timeout": require_fetch_timeout_default,
|
|
18221
|
+
"require-interface-for-exported-class": require_interface_for_exported_class_default,
|
|
17248
18222
|
"require-port-for-service": require_port_for_service_default,
|
|
18223
|
+
"require-sql-access-class": require_sql_access_class_default,
|
|
17249
18224
|
"require-static-next-matcher": require_static_next_matcher_default,
|
|
17250
18225
|
"require-zod-form-validation": require_zod_form_validation_default,
|
|
17251
18226
|
"store-insert-requires-on-conflict": store_insert_requires_on_conflict_default,
|
|
17252
18227
|
"stepdown": stepdown_default,
|
|
17253
18228
|
"source-coupled-test": source_coupled_test_default,
|
|
18229
|
+
"sole-export-matches-filename": sole_export_matches_filename_default,
|
|
17254
18230
|
"require-pascal-case-zod-schema-name": require_pascal_case_zod_schema_name_default
|
|
17255
18231
|
};
|
|
17256
18232
|
var meta = {
|
|
17257
18233
|
name: "@sarj/eslint-plugin",
|
|
17258
|
-
version: "15.
|
|
18234
|
+
version: "15.16.0"
|
|
17259
18235
|
};
|
|
17260
18236
|
var APPLICATION_ONLY_RULES = [
|
|
17261
18237
|
"no-restricted-library-load",
|
|
17262
18238
|
"prefer-native-random-uuid",
|
|
17263
18239
|
"prefer-shadcn-primitives"
|
|
17264
18240
|
];
|
|
17265
|
-
var ADVISORY_RULES = [
|
|
18241
|
+
var ADVISORY_RULES = [
|
|
18242
|
+
"@sarj/prefer-named-complex-return-type",
|
|
18243
|
+
"@sarj/prefer-node-crypto-hash",
|
|
18244
|
+
"@sarj/prefer-node-fs-promises",
|
|
18245
|
+
"@sarj/prefer-shared-zod-enum",
|
|
18246
|
+
"@sarj/prefer-switch-for-repeated-equality",
|
|
18247
|
+
"@sarj/require-interface-for-exported-class",
|
|
18248
|
+
"@sarj/require-pascal-case-zod-schema-name",
|
|
18249
|
+
"@sarj/require-sql-access-class",
|
|
18250
|
+
"@sarj/sole-export-matches-filename"
|
|
18251
|
+
];
|
|
17266
18252
|
var RECOMMENDED_RULES = {
|
|
17267
18253
|
"@sarj/interface-contract-members-private": "error",
|
|
17268
18254
|
"@sarj/iac-source-coupled-test": "error",
|
|
@@ -17316,10 +18302,15 @@ var RECOMMENDED_RULES = {
|
|
|
17316
18302
|
"@sarj/prefer-immutable-module-constant": "error",
|
|
17317
18303
|
"@sarj/prefer-module-level-constant": "error",
|
|
17318
18304
|
"@sarj/prefer-module-level-schema": "error",
|
|
18305
|
+
"@sarj/prefer-named-complex-return-type": "warn",
|
|
18306
|
+
"@sarj/prefer-node-crypto-hash": "warn",
|
|
18307
|
+
"@sarj/prefer-node-fs-promises": "warn",
|
|
17319
18308
|
"@sarj/prefer-non-nullable-collection": "error",
|
|
17320
18309
|
"@sarj/prefer-nullish-filter-predicate": "error",
|
|
17321
18310
|
"@sarj/prefer-await-in-async-return": "error",
|
|
17322
18311
|
"@sarj/prefer-schema-for-api-payload": "error",
|
|
18312
|
+
"@sarj/prefer-shared-zod-enum": "warn",
|
|
18313
|
+
"@sarj/prefer-switch-for-repeated-equality": "warn",
|
|
17323
18314
|
"@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
|
|
17324
18315
|
"@sarj/prefer-server-actions": "error",
|
|
17325
18316
|
"@sarj/prefer-whole-object-assertion": "error",
|
|
@@ -17327,7 +18318,9 @@ var RECOMMENDED_RULES = {
|
|
|
17327
18318
|
"@sarj/prefer-zod-infer": "error",
|
|
17328
18319
|
"@sarj/require-assert-never": "error",
|
|
17329
18320
|
"@sarj/require-fetch-timeout": "error",
|
|
18321
|
+
"@sarj/require-interface-for-exported-class": "warn",
|
|
17330
18322
|
"@sarj/require-port-for-service": "error",
|
|
18323
|
+
"@sarj/require-sql-access-class": "warn",
|
|
17331
18324
|
"@sarj/require-static-next-matcher": "error",
|
|
17332
18325
|
"@sarj/require-use-form-default-values": "error",
|
|
17333
18326
|
"@sarj/require-use-server-in-actions-file": "error",
|
|
@@ -17335,6 +18328,7 @@ var RECOMMENDED_RULES = {
|
|
|
17335
18328
|
"@sarj/store-insert-requires-on-conflict": "error",
|
|
17336
18329
|
"@sarj/stepdown": "error",
|
|
17337
18330
|
"@sarj/source-coupled-test": "error",
|
|
18331
|
+
"@sarj/sole-export-matches-filename": "warn",
|
|
17338
18332
|
"@sarj/test-phase-label-comment": "error",
|
|
17339
18333
|
"@sarj/require-pascal-case-zod-schema-name": "warn"
|
|
17340
18334
|
};
|
|
@@ -17395,10 +18389,15 @@ var STRICT_RULES = {
|
|
|
17395
18389
|
"@sarj/prefer-immutable-module-constant": "error",
|
|
17396
18390
|
"@sarj/prefer-module-level-constant": "error",
|
|
17397
18391
|
"@sarj/prefer-module-level-schema": "error",
|
|
18392
|
+
"@sarj/prefer-named-complex-return-type": "warn",
|
|
18393
|
+
"@sarj/prefer-node-crypto-hash": "warn",
|
|
18394
|
+
"@sarj/prefer-node-fs-promises": "warn",
|
|
17398
18395
|
"@sarj/prefer-non-nullable-collection": "error",
|
|
17399
18396
|
"@sarj/prefer-nullish-filter-predicate": "error",
|
|
17400
18397
|
"@sarj/prefer-await-in-async-return": "error",
|
|
17401
18398
|
"@sarj/prefer-schema-for-api-payload": "error",
|
|
18399
|
+
"@sarj/prefer-shared-zod-enum": "warn",
|
|
18400
|
+
"@sarj/prefer-switch-for-repeated-equality": "warn",
|
|
17402
18401
|
"@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
|
|
17403
18402
|
"@sarj/prefer-server-actions": "error",
|
|
17404
18403
|
"@sarj/prefer-whole-object-assertion": "error",
|
|
@@ -17406,7 +18405,9 @@ var STRICT_RULES = {
|
|
|
17406
18405
|
"@sarj/prefer-zod-infer": "error",
|
|
17407
18406
|
"@sarj/require-assert-never": "error",
|
|
17408
18407
|
"@sarj/require-fetch-timeout": "error",
|
|
18408
|
+
"@sarj/require-interface-for-exported-class": "warn",
|
|
17409
18409
|
"@sarj/require-port-for-service": "error",
|
|
18410
|
+
"@sarj/require-sql-access-class": "warn",
|
|
17410
18411
|
"@sarj/require-static-next-matcher": "error",
|
|
17411
18412
|
"@sarj/require-use-form-default-values": "error",
|
|
17412
18413
|
"@sarj/require-use-server-in-actions-file": "error",
|
|
@@ -17414,6 +18415,7 @@ var STRICT_RULES = {
|
|
|
17414
18415
|
"@sarj/store-insert-requires-on-conflict": "error",
|
|
17415
18416
|
"@sarj/stepdown": "error",
|
|
17416
18417
|
"@sarj/source-coupled-test": "error",
|
|
18418
|
+
"@sarj/sole-export-matches-filename": "warn",
|
|
17417
18419
|
"@sarj/test-phase-label-comment": "error",
|
|
17418
18420
|
"@sarj/require-pascal-case-zod-schema-name": "warn"
|
|
17419
18421
|
};
|