eslint-plugin-zod 3.5.1 → 3.5.2
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/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/index.cjs +94 -83
- package/dist/index.d.cts +17 -16
- package/dist/index.d.mts +24 -0
- package/dist/index.mjs +98 -0
- package/dist/meta.cjs +11 -11
- package/dist/meta.mjs +10 -0
- package/dist/rules/array-style.cjs +88 -101
- package/dist/rules/array-style.mjs +89 -0
- package/dist/rules/consistent-import-source.cjs +59 -66
- package/dist/rules/consistent-import-source.mjs +60 -0
- package/dist/rules/consistent-import.cjs +146 -172
- package/dist/rules/consistent-import.mjs +152 -0
- package/dist/rules/consistent-object-schema-type.cjs +81 -84
- package/dist/rules/consistent-object-schema-type.mjs +81 -0
- package/dist/rules/no-any-schema.cjs +62 -67
- package/dist/rules/no-any-schema.mjs +62 -0
- package/dist/rules/no-empty-custom-schema.cjs +32 -40
- package/dist/rules/no-empty-custom-schema.mjs +34 -0
- package/dist/rules/no-number-schema-with-int.cjs +56 -62
- package/dist/rules/no-number-schema-with-int.mjs +57 -0
- package/dist/rules/no-optional-and-default-together.cjs +69 -80
- package/dist/rules/no-optional-and-default-together.mjs +71 -0
- package/dist/rules/no-string-schema-with-uuid.cjs +57 -63
- package/dist/rules/no-string-schema-with-uuid.mjs +58 -0
- package/dist/rules/no-throw-in-refine.cjs +69 -87
- package/dist/rules/no-throw-in-refine.mjs +69 -0
- package/dist/rules/no-unknown-schema.cjs +29 -35
- package/dist/rules/no-unknown-schema.mjs +31 -0
- package/dist/rules/prefer-enum-over-literal-union.cjs +63 -79
- package/dist/rules/prefer-enum-over-literal-union.mjs +63 -0
- package/dist/rules/prefer-meta-last.cjs +47 -63
- package/dist/rules/prefer-meta-last.mjs +49 -0
- package/dist/rules/prefer-meta.cjs +38 -48
- package/dist/rules/prefer-meta.mjs +40 -0
- package/dist/rules/prefer-namespace-import.cjs +110 -142
- package/dist/rules/prefer-namespace-import.mjs +116 -0
- package/dist/rules/prefer-string-schema-with-trim.cjs +45 -52
- package/dist/rules/prefer-string-schema-with-trim.mjs +47 -0
- package/dist/rules/require-brand-type-parameter.cjs +47 -60
- package/dist/rules/require-brand-type-parameter.mjs +49 -0
- package/dist/rules/require-error-message.cjs +83 -102
- package/dist/rules/require-error-message.mjs +83 -0
- package/dist/rules/require-schema-suffix.cjs +67 -78
- package/dist/rules/require-schema-suffix.mjs +67 -0
- package/dist/rules/schema-error-property-style.cjs +95 -107
- package/dist/rules/schema-error-property-style.mjs +94 -0
- package/dist/utils/build-zod-chain-replacement-fix.cjs +28 -29
- package/dist/utils/build-zod-chain-replacement-fix.mjs +30 -0
- package/dist/utils/create-plugin-rule.cjs +6 -6
- package/dist/utils/create-plugin-rule.mjs +6 -0
- package/dist/utils/detect-zod-schema-root-node.cjs +94 -96
- package/dist/utils/detect-zod-schema-root-node.mjs +101 -0
- package/dist/utils/is-zod-import-source.cjs +14 -18
- package/dist/utils/is-zod-import-source.mjs +16 -0
- package/dist/utils/track-zod-schema-imports.cjs +61 -63
- package/dist/utils/track-zod-schema-imports.mjs +64 -0
- package/package.json +14 -17
- package/dist/index.d.ts +0 -22
- package/dist/index.js +0 -84
- package/dist/meta.d.cts +0 -3
- package/dist/meta.d.ts +0 -3
- package/dist/meta.js +0 -8
- package/dist/rules/array-style.d.cts +0 -11
- package/dist/rules/array-style.d.ts +0 -11
- package/dist/rules/array-style.js +0 -99
- package/dist/rules/consistent-import-source.d.cts +0 -11
- package/dist/rules/consistent-import-source.d.ts +0 -11
- package/dist/rules/consistent-import-source.js +0 -64
- package/dist/rules/consistent-import.d.cts +0 -12
- package/dist/rules/consistent-import.d.ts +0 -12
- package/dist/rules/consistent-import.js +0 -176
- package/dist/rules/consistent-object-schema-type.d.cts +0 -13
- package/dist/rules/consistent-object-schema-type.d.ts +0 -13
- package/dist/rules/consistent-object-schema-type.js +0 -82
- package/dist/rules/no-any-schema.d.cts +0 -6
- package/dist/rules/no-any-schema.d.ts +0 -6
- package/dist/rules/no-any-schema.js +0 -65
- package/dist/rules/no-empty-custom-schema.d.cts +0 -5
- package/dist/rules/no-empty-custom-schema.d.ts +0 -5
- package/dist/rules/no-empty-custom-schema.js +0 -38
- package/dist/rules/no-number-schema-with-int.d.cts +0 -5
- package/dist/rules/no-number-schema-with-int.d.ts +0 -5
- package/dist/rules/no-number-schema-with-int.js +0 -60
- package/dist/rules/no-optional-and-default-together.d.cts +0 -12
- package/dist/rules/no-optional-and-default-together.d.ts +0 -12
- package/dist/rules/no-optional-and-default-together.js +0 -78
- package/dist/rules/no-string-schema-with-uuid.d.cts +0 -5
- package/dist/rules/no-string-schema-with-uuid.d.ts +0 -5
- package/dist/rules/no-string-schema-with-uuid.js +0 -61
- package/dist/rules/no-throw-in-refine.d.cts +0 -5
- package/dist/rules/no-throw-in-refine.d.ts +0 -5
- package/dist/rules/no-throw-in-refine.js +0 -85
- package/dist/rules/no-unknown-schema.d.cts +0 -5
- package/dist/rules/no-unknown-schema.d.ts +0 -5
- package/dist/rules/no-unknown-schema.js +0 -33
- package/dist/rules/prefer-enum-over-literal-union.d.cts +0 -5
- package/dist/rules/prefer-enum-over-literal-union.d.ts +0 -5
- package/dist/rules/prefer-enum-over-literal-union.js +0 -77
- package/dist/rules/prefer-meta-last.d.cts +0 -5
- package/dist/rules/prefer-meta-last.d.ts +0 -5
- package/dist/rules/prefer-meta-last.js +0 -61
- package/dist/rules/prefer-meta.d.cts +0 -5
- package/dist/rules/prefer-meta.d.ts +0 -5
- package/dist/rules/prefer-meta.js +0 -46
- package/dist/rules/prefer-namespace-import.d.cts +0 -5
- package/dist/rules/prefer-namespace-import.d.ts +0 -5
- package/dist/rules/prefer-namespace-import.js +0 -146
- package/dist/rules/prefer-string-schema-with-trim.d.cts +0 -5
- package/dist/rules/prefer-string-schema-with-trim.d.ts +0 -5
- package/dist/rules/prefer-string-schema-with-trim.js +0 -50
- package/dist/rules/require-brand-type-parameter.d.cts +0 -6
- package/dist/rules/require-brand-type-parameter.d.ts +0 -6
- package/dist/rules/require-brand-type-parameter.js +0 -58
- package/dist/rules/require-error-message.d.cts +0 -5
- package/dist/rules/require-error-message.d.ts +0 -5
- package/dist/rules/require-error-message.js +0 -100
- package/dist/rules/require-schema-suffix.d.cts +0 -9
- package/dist/rules/require-schema-suffix.d.ts +0 -9
- package/dist/rules/require-schema-suffix.js +0 -76
- package/dist/rules/schema-error-property-style.d.cts +0 -10
- package/dist/rules/schema-error-property-style.d.ts +0 -10
- package/dist/rules/schema-error-property-style.js +0 -102
- package/dist/utils/build-zod-chain-replacement-fix.d.cts +0 -12
- package/dist/utils/build-zod-chain-replacement-fix.d.ts +0 -12
- package/dist/utils/build-zod-chain-replacement-fix.js +0 -28
- package/dist/utils/create-plugin-rule.d.cts +0 -13
- package/dist/utils/create-plugin-rule.d.ts +0 -13
- package/dist/utils/create-plugin-rule.js +0 -3
- package/dist/utils/detect-zod-schema-root-node.d.cts +0 -10
- package/dist/utils/detect-zod-schema-root-node.d.ts +0 -10
- package/dist/utils/detect-zod-schema-root-node.js +0 -101
- package/dist/utils/is-zod-import-source.d.cts +0 -4
- package/dist/utils/is-zod-import-source.d.ts +0 -4
- package/dist/utils/is-zod-import-source.js +0 -17
- package/dist/utils/track-zod-schema-imports.d.cts +0 -18
- package/dist/utils/track-zod-schema-imports.d.ts +0 -18
- package/dist/utils/track-zod-schema-imports.js +0 -64
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { isZodImportSource } from "../utils/is-zod-import-source.mjs";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
//#region src/rules/consistent-import.ts
|
|
5
|
+
const IMPORT_SYNTAXES = ["namespace", "named"];
|
|
6
|
+
/**
|
|
7
|
+
* Determines whether the first import in a group is valid for a given import
|
|
8
|
+
* syntax (`named` or `namespace`), taking into account whether the group
|
|
9
|
+
* contains only type imports.
|
|
10
|
+
*
|
|
11
|
+
* Rules enforced:
|
|
12
|
+
* - For `named` syntax:
|
|
13
|
+
* - The first import must have exactly one specifier
|
|
14
|
+
* - That specifier must be a named import of identifier `z`
|
|
15
|
+
* - For `namespace` syntax:
|
|
16
|
+
* - The first import must have exactly one namespace specifier
|
|
17
|
+
* - If the group contains only type imports, the first import must explicitly
|
|
18
|
+
* be declared as `import type`
|
|
19
|
+
*
|
|
20
|
+
* @param group - Metadata describing the import group
|
|
21
|
+
* @param syntax - Expected import syntax for the group
|
|
22
|
+
* @returns `true` if the first import matches the expected syntax and type rules
|
|
23
|
+
*/
|
|
24
|
+
function isGroupFirstImportKindValidForSyntax(group, syntax) {
|
|
25
|
+
const { hasOnlyTypeImports, nodes } = group;
|
|
26
|
+
const [firstImportNode] = nodes;
|
|
27
|
+
const { specifiers, importKind } = firstImportNode;
|
|
28
|
+
if (specifiers.length !== 1) return false;
|
|
29
|
+
const [specifier] = specifiers;
|
|
30
|
+
if (!(syntax === "named" ? specifier.type === AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES.Identifier && specifier.imported.name === "z" : specifier.type === AST_NODE_TYPES.ImportNamespaceSpecifier)) return false;
|
|
31
|
+
if (hasOnlyTypeImports) return importKind === "type";
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
function shouldIdentifierBeRenamed(node) {
|
|
35
|
+
if (node.parent.type === AST_NODE_TYPES.ImportSpecifier) return false;
|
|
36
|
+
if (node.parent.type === AST_NODE_TYPES.MemberExpression && node.parent.object.type === AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* From a given specifiers retrieve the most significant to use when creating an alias import
|
|
41
|
+
*/
|
|
42
|
+
function getNamespaceAliasNameFrom(node) {
|
|
43
|
+
if (node.type === AST_NODE_TYPES.ImportDefaultSpecifier || node.type === AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
|
|
44
|
+
if (node.imported.type === AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const consistentImport = createZodPluginRule({
|
|
48
|
+
name: "consistent-import",
|
|
49
|
+
meta: {
|
|
50
|
+
type: "problem",
|
|
51
|
+
docs: {
|
|
52
|
+
zodImportAllowedSource: "all",
|
|
53
|
+
description: "Enforce a consistent import style for Zod"
|
|
54
|
+
},
|
|
55
|
+
fixable: "code",
|
|
56
|
+
messages: {
|
|
57
|
+
changeImportSyntax: "Use a {{syntax}} import for Zod.",
|
|
58
|
+
removeDuplicate: "Remove duplicate Zod import; Zod is already imported.",
|
|
59
|
+
convertUsage: "Update Zod usage to match the {{syntax}} import syntax."
|
|
60
|
+
},
|
|
61
|
+
schema: [{
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: { syntax: {
|
|
64
|
+
description: "Specifies the import syntax to use for Zod.",
|
|
65
|
+
type: "string",
|
|
66
|
+
enum: IMPORT_SYNTAXES
|
|
67
|
+
} },
|
|
68
|
+
additionalProperties: false
|
|
69
|
+
}]
|
|
70
|
+
},
|
|
71
|
+
defaultOptions: [{ syntax: "namespace" }],
|
|
72
|
+
create(context, [options]) {
|
|
73
|
+
const { syntax } = options;
|
|
74
|
+
const { sourceCode } = context;
|
|
75
|
+
const importGroups = {};
|
|
76
|
+
return {
|
|
77
|
+
ImportDeclaration(node) {
|
|
78
|
+
const { source, importKind } = node;
|
|
79
|
+
if (!isZodImportSource(source.value, "all")) return;
|
|
80
|
+
if (!importGroups[source.value]) importGroups[source.value] = {
|
|
81
|
+
hasOnlyTypeImports: true,
|
|
82
|
+
nodes: []
|
|
83
|
+
};
|
|
84
|
+
if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
|
|
85
|
+
importGroups[source.value].nodes.push(node);
|
|
86
|
+
},
|
|
87
|
+
"Program:exit": function() {
|
|
88
|
+
let namespaceAliasNameIndex = 0;
|
|
89
|
+
for (const importGroup of Object.values(importGroups)) {
|
|
90
|
+
const { hasOnlyTypeImports, nodes } = importGroup;
|
|
91
|
+
const [firstImportNode, ...othersImportNodes] = nodes;
|
|
92
|
+
/**
|
|
93
|
+
* Variable to track all specifiers that later are used by {@link getDeclaredVariables}
|
|
94
|
+
* to add the namespace prefix
|
|
95
|
+
*/
|
|
96
|
+
const nodesWithVariablesToUpdate = [];
|
|
97
|
+
let namespaceAliasName = null;
|
|
98
|
+
for (const specifier of nodes.flatMap((it) => it.specifiers)) {
|
|
99
|
+
if (!namespaceAliasName) {
|
|
100
|
+
namespaceAliasName = getNamespaceAliasNameFrom(specifier);
|
|
101
|
+
if (namespaceAliasName) continue;
|
|
102
|
+
}
|
|
103
|
+
nodesWithVariablesToUpdate.push(specifier);
|
|
104
|
+
}
|
|
105
|
+
if (!namespaceAliasName) {
|
|
106
|
+
namespaceAliasName = "z";
|
|
107
|
+
if (namespaceAliasNameIndex > 0) {
|
|
108
|
+
namespaceAliasName = `z${namespaceAliasNameIndex}`;
|
|
109
|
+
namespaceAliasNameIndex += 1;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!isGroupFirstImportKindValidForSyntax(importGroup, syntax)) context.report({
|
|
113
|
+
node: firstImportNode,
|
|
114
|
+
messageId: "changeImportSyntax",
|
|
115
|
+
data: { syntax },
|
|
116
|
+
fix(fixer) {
|
|
117
|
+
const importTypeKeyword = hasOnlyTypeImports ? "type " : "";
|
|
118
|
+
let importSpecifier;
|
|
119
|
+
if (syntax === "named") if (namespaceAliasName === "z") importSpecifier = "{ z }";
|
|
120
|
+
else importSpecifier = `{ z as ${namespaceAliasName} }`;
|
|
121
|
+
else importSpecifier = `* as ${namespaceAliasName}`;
|
|
122
|
+
const newImportText = `import ${importTypeKeyword}${importSpecifier} from ${firstImportNode.source.raw};`;
|
|
123
|
+
return fixer.replaceText(firstImportNode, newImportText);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
|
|
127
|
+
for (const ref of allReferences) {
|
|
128
|
+
const { identifier } = ref;
|
|
129
|
+
if (shouldIdentifierBeRenamed(identifier)) context.report({
|
|
130
|
+
node: identifier,
|
|
131
|
+
messageId: "convertUsage",
|
|
132
|
+
data: { syntax },
|
|
133
|
+
fix(fixer) {
|
|
134
|
+
const newId = `${namespaceAliasName}.${identifier.name}`;
|
|
135
|
+
return fixer.replaceText(identifier, newId);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
for (const extraImport of othersImportNodes) context.report({
|
|
140
|
+
node: extraImport,
|
|
141
|
+
messageId: "removeDuplicate",
|
|
142
|
+
fix(fixer) {
|
|
143
|
+
return fixer.removeRange(extraImport.range);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
//#endregion
|
|
152
|
+
export { consistentImport };
|
|
@@ -1,85 +1,82 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
},
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
const require_track_zod_schema_imports = require("../utils/track-zod-schema-imports.cjs");
|
|
4
|
+
let _typescript_eslint_utils = require("@typescript-eslint/utils");
|
|
5
|
+
//#region src/rules/consistent-object-schema-type.ts
|
|
6
|
+
const ZOD_OBJECT_METHODS = [
|
|
7
|
+
"object",
|
|
8
|
+
"looseObject",
|
|
9
|
+
"strictObject"
|
|
10
|
+
];
|
|
11
|
+
const defaultOptions = { allow: ["object"] };
|
|
12
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = require_track_zod_schema_imports.createZodSchemaImportTrack("all");
|
|
13
|
+
const consistentObjectSchemaType = require_create_plugin_rule.createZodPluginRule({
|
|
14
|
+
name: "consistent-object-schema-type",
|
|
15
|
+
meta: {
|
|
16
|
+
hasSuggestions: true,
|
|
17
|
+
type: "suggestion",
|
|
18
|
+
docs: {
|
|
19
|
+
zodImportAllowedSource,
|
|
20
|
+
description: "Enforce consistent usage of Zod schema methods"
|
|
21
|
+
},
|
|
22
|
+
messages: {
|
|
23
|
+
consistentMethod: "Inconsistent Zod object schema method '{{actual}}'. Allowed: {{allowedList}}.",
|
|
24
|
+
useMethod: "Replace with '{{expected}}'."
|
|
25
|
+
},
|
|
26
|
+
schema: [{
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: { allow: {
|
|
29
|
+
type: "array",
|
|
30
|
+
description: "Decides which object methods are allowed",
|
|
31
|
+
items: {
|
|
32
|
+
type: "string",
|
|
33
|
+
enum: [...ZOD_OBJECT_METHODS]
|
|
34
|
+
},
|
|
35
|
+
minItems: 1,
|
|
36
|
+
uniqueItems: true
|
|
37
|
+
} },
|
|
38
|
+
additionalProperties: false
|
|
39
|
+
}]
|
|
40
|
+
},
|
|
41
|
+
defaultOptions: [defaultOptions],
|
|
42
|
+
create(context, [{ allow: allowedList }]) {
|
|
43
|
+
const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
|
|
44
|
+
return {
|
|
45
|
+
ImportDeclaration: importDeclarationListener,
|
|
46
|
+
CallExpression(node) {
|
|
47
|
+
const schemaType = detectZodSchemaRootNode(node)?.schemaType;
|
|
48
|
+
if (!schemaType || !ZOD_OBJECT_METHODS.includes(schemaType)) return;
|
|
49
|
+
if (allowedList.includes(schemaType)) return;
|
|
50
|
+
const { callee } = node;
|
|
51
|
+
if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
|
|
52
|
+
context.report({
|
|
53
|
+
node,
|
|
54
|
+
messageId: "consistentMethod",
|
|
55
|
+
data: {
|
|
56
|
+
actual: schemaType,
|
|
57
|
+
allowedList: allowedList.join(",")
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) context.report({
|
|
63
|
+
node,
|
|
64
|
+
messageId: "consistentMethod",
|
|
65
|
+
data: {
|
|
66
|
+
actual: schemaType,
|
|
67
|
+
allowedList: allowedList.join(",")
|
|
68
|
+
},
|
|
69
|
+
suggest: allowedList.map((it) => ({
|
|
70
|
+
messageId: "useMethod",
|
|
71
|
+
data: { expected: it },
|
|
72
|
+
fix(fixer) {
|
|
73
|
+
return fixer.replaceText(callee.property, it);
|
|
74
|
+
}
|
|
75
|
+
}))
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
85
80
|
});
|
|
81
|
+
//#endregion
|
|
82
|
+
exports.consistentObjectSchemaType = consistentObjectSchemaType;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "../utils/track-zod-schema-imports.mjs";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
//#region src/rules/consistent-object-schema-type.ts
|
|
5
|
+
const ZOD_OBJECT_METHODS = [
|
|
6
|
+
"object",
|
|
7
|
+
"looseObject",
|
|
8
|
+
"strictObject"
|
|
9
|
+
];
|
|
10
|
+
const defaultOptions = { allow: ["object"] };
|
|
11
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("all");
|
|
12
|
+
const consistentObjectSchemaType = createZodPluginRule({
|
|
13
|
+
name: "consistent-object-schema-type",
|
|
14
|
+
meta: {
|
|
15
|
+
hasSuggestions: true,
|
|
16
|
+
type: "suggestion",
|
|
17
|
+
docs: {
|
|
18
|
+
zodImportAllowedSource,
|
|
19
|
+
description: "Enforce consistent usage of Zod schema methods"
|
|
20
|
+
},
|
|
21
|
+
messages: {
|
|
22
|
+
consistentMethod: "Inconsistent Zod object schema method '{{actual}}'. Allowed: {{allowedList}}.",
|
|
23
|
+
useMethod: "Replace with '{{expected}}'."
|
|
24
|
+
},
|
|
25
|
+
schema: [{
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: { allow: {
|
|
28
|
+
type: "array",
|
|
29
|
+
description: "Decides which object methods are allowed",
|
|
30
|
+
items: {
|
|
31
|
+
type: "string",
|
|
32
|
+
enum: [...ZOD_OBJECT_METHODS]
|
|
33
|
+
},
|
|
34
|
+
minItems: 1,
|
|
35
|
+
uniqueItems: true
|
|
36
|
+
} },
|
|
37
|
+
additionalProperties: false
|
|
38
|
+
}]
|
|
39
|
+
},
|
|
40
|
+
defaultOptions: [defaultOptions],
|
|
41
|
+
create(context, [{ allow: allowedList }]) {
|
|
42
|
+
const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
|
|
43
|
+
return {
|
|
44
|
+
ImportDeclaration: importDeclarationListener,
|
|
45
|
+
CallExpression(node) {
|
|
46
|
+
const schemaType = detectZodSchemaRootNode(node)?.schemaType;
|
|
47
|
+
if (!schemaType || !ZOD_OBJECT_METHODS.includes(schemaType)) return;
|
|
48
|
+
if (allowedList.includes(schemaType)) return;
|
|
49
|
+
const { callee } = node;
|
|
50
|
+
if (callee.type === AST_NODE_TYPES.Identifier) {
|
|
51
|
+
context.report({
|
|
52
|
+
node,
|
|
53
|
+
messageId: "consistentMethod",
|
|
54
|
+
data: {
|
|
55
|
+
actual: schemaType,
|
|
56
|
+
allowedList: allowedList.join(",")
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (callee.type === AST_NODE_TYPES.MemberExpression) context.report({
|
|
62
|
+
node,
|
|
63
|
+
messageId: "consistentMethod",
|
|
64
|
+
data: {
|
|
65
|
+
actual: schemaType,
|
|
66
|
+
allowedList: allowedList.join(",")
|
|
67
|
+
},
|
|
68
|
+
suggest: allowedList.map((it) => ({
|
|
69
|
+
messageId: "useMethod",
|
|
70
|
+
data: { expected: it },
|
|
71
|
+
fix(fixer) {
|
|
72
|
+
return fixer.replaceText(callee.property, it);
|
|
73
|
+
}
|
|
74
|
+
}))
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
//#endregion
|
|
81
|
+
export { consistentObjectSchemaType };
|
|
@@ -1,68 +1,63 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
node,
|
|
62
|
-
messageId: 'noZAny',
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
};
|
|
67
|
-
},
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
const require_track_zod_schema_imports = require("../utils/track-zod-schema-imports.cjs");
|
|
4
|
+
let _typescript_eslint_utils = require("@typescript-eslint/utils");
|
|
5
|
+
//#region src/rules/no-any-schema.ts
|
|
6
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = require_track_zod_schema_imports.createZodSchemaImportTrack("all");
|
|
7
|
+
const noAnySchema = require_create_plugin_rule.createZodPluginRule({
|
|
8
|
+
name: "no-any-schema",
|
|
9
|
+
meta: {
|
|
10
|
+
hasSuggestions: true,
|
|
11
|
+
type: "suggestion",
|
|
12
|
+
docs: {
|
|
13
|
+
zodImportAllowedSource,
|
|
14
|
+
description: "Disallow usage of `z.any()` in Zod schemas"
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
noZAny: "Using `z.any()` is not allowed. Please use a more specific schema.",
|
|
18
|
+
useUnknown: "Replace `z.any()` with `z.unknown()`"
|
|
19
|
+
},
|
|
20
|
+
schema: []
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create(context) {
|
|
24
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
25
|
+
return {
|
|
26
|
+
ImportDeclaration: importDeclarationListener,
|
|
27
|
+
CallExpression(node) {
|
|
28
|
+
if (detectZodSchemaRootNode(node)?.schemaType !== "any") return;
|
|
29
|
+
const { callee } = node;
|
|
30
|
+
if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
|
|
31
|
+
context.report({
|
|
32
|
+
node,
|
|
33
|
+
messageId: "noZAny"
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression) {
|
|
38
|
+
const [{ node: schemaMethod }] = collectZodChainMethods(node);
|
|
39
|
+
const schemaMethodCallee = schemaMethod.callee;
|
|
40
|
+
if (schemaMethodCallee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && schemaMethodCallee.property.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) {
|
|
41
|
+
context.report({
|
|
42
|
+
node,
|
|
43
|
+
messageId: "noZAny",
|
|
44
|
+
suggest: [{
|
|
45
|
+
messageId: "useUnknown",
|
|
46
|
+
fix(fixer) {
|
|
47
|
+
return fixer.replaceText(schemaMethodCallee.property, "unknown");
|
|
48
|
+
}
|
|
49
|
+
}]
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
context.report({
|
|
54
|
+
node,
|
|
55
|
+
messageId: "noZAny"
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
68
61
|
});
|
|
62
|
+
//#endregion
|
|
63
|
+
exports.noAnySchema = noAnySchema;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "../utils/track-zod-schema-imports.mjs";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
//#region src/rules/no-any-schema.ts
|
|
5
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("all");
|
|
6
|
+
const noAnySchema = createZodPluginRule({
|
|
7
|
+
name: "no-any-schema",
|
|
8
|
+
meta: {
|
|
9
|
+
hasSuggestions: true,
|
|
10
|
+
type: "suggestion",
|
|
11
|
+
docs: {
|
|
12
|
+
zodImportAllowedSource,
|
|
13
|
+
description: "Disallow usage of `z.any()` in Zod schemas"
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
noZAny: "Using `z.any()` is not allowed. Please use a more specific schema.",
|
|
17
|
+
useUnknown: "Replace `z.any()` with `z.unknown()`"
|
|
18
|
+
},
|
|
19
|
+
schema: []
|
|
20
|
+
},
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
23
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
24
|
+
return {
|
|
25
|
+
ImportDeclaration: importDeclarationListener,
|
|
26
|
+
CallExpression(node) {
|
|
27
|
+
if (detectZodSchemaRootNode(node)?.schemaType !== "any") return;
|
|
28
|
+
const { callee } = node;
|
|
29
|
+
if (callee.type === AST_NODE_TYPES.Identifier) {
|
|
30
|
+
context.report({
|
|
31
|
+
node,
|
|
32
|
+
messageId: "noZAny"
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (callee.type === AST_NODE_TYPES.MemberExpression) {
|
|
37
|
+
const [{ node: schemaMethod }] = collectZodChainMethods(node);
|
|
38
|
+
const schemaMethodCallee = schemaMethod.callee;
|
|
39
|
+
if (schemaMethodCallee.type === AST_NODE_TYPES.MemberExpression && schemaMethodCallee.property.type === AST_NODE_TYPES.Identifier) {
|
|
40
|
+
context.report({
|
|
41
|
+
node,
|
|
42
|
+
messageId: "noZAny",
|
|
43
|
+
suggest: [{
|
|
44
|
+
messageId: "useUnknown",
|
|
45
|
+
fix(fixer) {
|
|
46
|
+
return fixer.replaceText(schemaMethodCallee.property, "unknown");
|
|
47
|
+
}
|
|
48
|
+
}]
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
context.report({
|
|
53
|
+
node,
|
|
54
|
+
messageId: "noZAny"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
//#endregion
|
|
62
|
+
export { noAnySchema };
|