eslint-plugin-zod 1.3.0 → 3.0.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/LICENSE +19 -22
- package/README.md +84 -56
- package/dist/index.cjs +71 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +68 -0
- package/dist/meta.cjs +13 -0
- package/dist/meta.d.cts +3 -0
- package/dist/meta.d.ts +3 -0
- package/dist/meta.js +8 -0
- package/dist/rules/array-style.cjs +99 -0
- package/dist/rules/array-style.d.cts +10 -0
- package/dist/rules/array-style.d.ts +10 -0
- package/dist/rules/array-style.js +96 -0
- package/dist/rules/consistent-import-source.cjs +73 -0
- package/dist/rules/consistent-import-source.d.cts +10 -0
- package/dist/rules/consistent-import-source.d.ts +10 -0
- package/dist/rules/consistent-import-source.js +70 -0
- package/dist/rules/consistent-object-schema-type.cjs +83 -0
- package/dist/rules/consistent-object-schema-type.d.cts +11 -0
- package/dist/rules/consistent-object-schema-type.d.ts +11 -0
- package/dist/rules/consistent-object-schema-type.js +80 -0
- package/dist/rules/no-any-schema.cjs +66 -0
- package/dist/rules/no-any-schema.d.cts +4 -0
- package/dist/rules/no-any-schema.d.ts +4 -0
- package/dist/rules/no-any-schema.js +63 -0
- package/dist/rules/no-empty-custom-schema.cjs +40 -0
- package/dist/rules/no-empty-custom-schema.d.cts +4 -0
- package/dist/rules/no-empty-custom-schema.d.ts +4 -0
- package/dist/rules/no-empty-custom-schema.js +37 -0
- package/dist/rules/no-number-schema-with-int.cjs +78 -0
- package/dist/rules/no-number-schema-with-int.d.cts +4 -0
- package/dist/rules/no-number-schema-with-int.d.ts +4 -0
- package/dist/rules/no-number-schema-with-int.js +75 -0
- package/dist/rules/no-optional-and-default-together.cjs +80 -0
- package/dist/rules/no-optional-and-default-together.d.cts +11 -0
- package/dist/rules/no-optional-and-default-together.d.ts +11 -0
- package/dist/rules/no-optional-and-default-together.js +77 -0
- package/dist/rules/no-throw-in-refine.cjs +84 -0
- package/dist/rules/no-throw-in-refine.d.cts +4 -0
- package/dist/rules/no-throw-in-refine.d.ts +4 -0
- package/dist/rules/no-throw-in-refine.js +81 -0
- package/dist/rules/no-unknown-schema.cjs +35 -0
- package/dist/rules/no-unknown-schema.d.cts +4 -0
- package/dist/rules/no-unknown-schema.d.ts +4 -0
- package/dist/rules/no-unknown-schema.js +32 -0
- package/dist/rules/prefer-enum-over-literal-union.cjs +72 -0
- package/dist/rules/prefer-enum-over-literal-union.d.cts +4 -0
- package/dist/rules/prefer-enum-over-literal-union.d.ts +4 -0
- package/dist/rules/prefer-enum-over-literal-union.js +69 -0
- package/dist/rules/prefer-meta-last.cjs +71 -0
- package/dist/rules/prefer-meta-last.d.cts +4 -0
- package/dist/rules/prefer-meta-last.d.ts +4 -0
- package/dist/rules/prefer-meta-last.js +68 -0
- package/dist/rules/prefer-meta.cjs +48 -0
- package/dist/rules/prefer-meta.d.cts +4 -0
- package/dist/rules/prefer-meta.d.ts +4 -0
- package/dist/rules/prefer-meta.js +45 -0
- package/dist/rules/prefer-namespace-import.cjs +145 -0
- package/dist/rules/prefer-namespace-import.d.cts +4 -0
- package/dist/rules/prefer-namespace-import.d.ts +4 -0
- package/dist/rules/prefer-namespace-import.js +142 -0
- package/dist/rules/require-brand-type-parameter.cjs +60 -0
- package/dist/rules/require-brand-type-parameter.d.cts +4 -0
- package/dist/rules/require-brand-type-parameter.d.ts +4 -0
- package/dist/rules/require-brand-type-parameter.js +57 -0
- package/dist/rules/require-error-message.cjs +101 -0
- package/dist/rules/require-error-message.d.cts +4 -0
- package/dist/rules/require-error-message.d.ts +4 -0
- package/dist/rules/require-error-message.js +98 -0
- package/dist/rules/require-schema-suffix.cjs +73 -0
- package/dist/rules/require-schema-suffix.d.cts +8 -0
- package/dist/rules/require-schema-suffix.d.ts +8 -0
- package/dist/rules/require-schema-suffix.js +70 -0
- package/dist/rules/schema-error-property-style.cjs +106 -0
- package/dist/rules/schema-error-property-style.d.cts +9 -0
- package/dist/rules/schema-error-property-style.d.ts +9 -0
- package/dist/rules/schema-error-property-style.js +100 -0
- package/dist/utils/detect-zod-schema-root-node.cjs +104 -0
- package/dist/utils/detect-zod-schema-root-node.d.cts +10 -0
- package/dist/utils/detect-zod-schema-root-node.d.ts +10 -0
- package/dist/utils/detect-zod-schema-root-node.js +101 -0
- package/dist/utils/get-outermost-call.cjs +14 -0
- package/dist/utils/get-outermost-call.d.cts +2 -0
- package/dist/utils/get-outermost-call.d.ts +2 -0
- package/dist/utils/get-outermost-call.js +11 -0
- package/dist/utils/is-zod-expression.cjs +14 -0
- package/dist/utils/is-zod-expression.d.cts +2 -0
- package/dist/utils/is-zod-expression.d.ts +2 -0
- package/dist/utils/is-zod-expression.js +11 -0
- package/dist/utils/is-zod-import-source.cjs +6 -0
- package/dist/utils/is-zod-import-source.d.cts +1 -0
- package/dist/utils/is-zod-import-source.d.ts +1 -0
- package/dist/utils/is-zod-import-source.js +3 -0
- package/dist/utils/track-zod-schema-imports.cjs +61 -0
- package/dist/utils/track-zod-schema-imports.d.cts +13 -0
- package/dist/utils/track-zod-schema-imports.d.ts +13 -0
- package/dist/utils/track-zod-schema-imports.js +58 -0
- package/package.json +82 -38
- package/dist/src/index.d.ts +0 -31
- package/dist/src/index.js +0 -14
- package/dist/src/rules/requireStrict.d.ts +0 -24
- package/dist/src/rules/requireStrict.js +0 -69
- package/tsconfig.json +0 -28
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { getRuleURL } from "../meta.js";
|
|
3
|
+
import { getOutermostCall } from "../utils/get-outermost-call.js";
|
|
4
|
+
import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
|
|
5
|
+
export const noNumberSchemaWithInt = ESLintUtils.RuleCreator(getRuleURL)({
|
|
6
|
+
name: 'no-number-schema-with-int',
|
|
7
|
+
meta: {
|
|
8
|
+
fixable: 'code',
|
|
9
|
+
type: 'problem',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Disallow usage of `z.number().int()` as it is considered legacy',
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
removeNumber: '`z.number().int()` is considered legacy. Use `z.int()` instead.',
|
|
15
|
+
},
|
|
16
|
+
schema: [],
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
const { sourceCode } = context;
|
|
21
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods, } = trackZodSchemaImports();
|
|
22
|
+
return {
|
|
23
|
+
ImportDeclaration: importDeclarationListener,
|
|
24
|
+
CallExpression(node) {
|
|
25
|
+
var _a;
|
|
26
|
+
const outer = (_a = getOutermostCall(node)) !== null && _a !== void 0 ? _a : node;
|
|
27
|
+
const zodSchemaMeta = detectZodSchemaRootNode(outer);
|
|
28
|
+
if (!zodSchemaMeta) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (zodSchemaMeta.schemaType !== 'number') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const methods = collectZodChainMethods(outer);
|
|
35
|
+
const numberIndex = methods.findIndex((m) => m.name === 'number');
|
|
36
|
+
const intIndex = methods.findIndex((m) => m.name === 'int');
|
|
37
|
+
if (numberIndex === -1 || intIndex === -1) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const numberMethod = methods[numberIndex];
|
|
41
|
+
const intMethod = methods[intIndex];
|
|
42
|
+
if (node !== intMethod.node) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (zodSchemaMeta.schemaDecl === 'named') {
|
|
46
|
+
context.report({
|
|
47
|
+
node,
|
|
48
|
+
messageId: 'removeNumber',
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
context.report({
|
|
53
|
+
node,
|
|
54
|
+
messageId: 'removeNumber',
|
|
55
|
+
fix(fixer) {
|
|
56
|
+
const numberNode = numberMethod.node;
|
|
57
|
+
const intNode = intMethod.node;
|
|
58
|
+
const numberCallee = numberNode.callee;
|
|
59
|
+
const prefixObj = numberCallee.object;
|
|
60
|
+
const prefixText = sourceCode.getText(prefixObj);
|
|
61
|
+
const methodsBetween = methods.slice(numberIndex + 1, intIndex);
|
|
62
|
+
const betweenSuffixes = methodsBetween.map((m) => {
|
|
63
|
+
const callee = m.node.callee;
|
|
64
|
+
const objText = sourceCode.getText(callee.object);
|
|
65
|
+
const fullText = sourceCode.getText(m.node);
|
|
66
|
+
return fullText.slice(objText.length);
|
|
67
|
+
});
|
|
68
|
+
const replacement = `${prefixText}.int()${betweenSuffixes.join('')}`;
|
|
69
|
+
return fixer.replaceTextRange([numberNode.range[0], intNode.range[1]], replacement);
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noOptionalAndDefaultTogether = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const meta_js_1 = require("../meta.cjs");
|
|
6
|
+
const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
|
|
7
|
+
const preferredMethods = ['none', 'default', 'optional'];
|
|
8
|
+
const defaultOptions = { preferredMethod: 'none' };
|
|
9
|
+
exports.noOptionalAndDefaultTogether = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
|
|
10
|
+
name: 'no-optional-and-default-together',
|
|
11
|
+
meta: {
|
|
12
|
+
type: 'problem',
|
|
13
|
+
fixable: 'code',
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Disallow using both `.optional()` and `.default()` on the same Zod schema',
|
|
16
|
+
},
|
|
17
|
+
messages: {
|
|
18
|
+
noOptionalAndDefaultTogether: 'Using both `.optional()` and `.default()` is redundant. A schema with a default value is already optional.',
|
|
19
|
+
noOptionalAndDefaultTogetherRemoveMethod: 'Using both `.optional()` and `.default()` is redundant. Remove the `.{{method}}()` method to avoid redundancy.',
|
|
20
|
+
},
|
|
21
|
+
schema: [
|
|
22
|
+
{
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
preferredMethod: {
|
|
26
|
+
description: 'Determines which method to keep when both are present',
|
|
27
|
+
type: 'string',
|
|
28
|
+
enum: [...preferredMethods],
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
additionalProperties: false,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
defaultOptions: [defaultOptions],
|
|
36
|
+
create(context, [{ preferredMethod }]) {
|
|
37
|
+
const { sourceCode } = context;
|
|
38
|
+
const { importDeclarationListener, detectZodSchemaRootNode: isZodSchema, collectZodChainMethods, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
|
|
39
|
+
return {
|
|
40
|
+
ImportDeclaration: importDeclarationListener,
|
|
41
|
+
CallExpression(node) {
|
|
42
|
+
if (!isZodSchema(node)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const methods = collectZodChainMethods(node);
|
|
46
|
+
if (methods.length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const optionalMethod = methods.find((m) => m.name === 'optional');
|
|
50
|
+
const defaultMethod = methods.find((m) => m.name === 'default');
|
|
51
|
+
if (!optionalMethod || !defaultMethod) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const reportNode = methods.indexOf(optionalMethod) > methods.indexOf(defaultMethod)
|
|
55
|
+
? optionalMethod.node
|
|
56
|
+
: defaultMethod.node;
|
|
57
|
+
if (preferredMethod === 'none') {
|
|
58
|
+
context.report({
|
|
59
|
+
node: reportNode,
|
|
60
|
+
messageId: 'noOptionalAndDefaultTogether',
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const methodToRemoveName = preferredMethod === 'default' ? 'optional' : 'default';
|
|
65
|
+
context.report({
|
|
66
|
+
node: reportNode,
|
|
67
|
+
messageId: 'noOptionalAndDefaultTogetherRemoveMethod',
|
|
68
|
+
data: { method: methodToRemoveName },
|
|
69
|
+
fix(fixer) {
|
|
70
|
+
const nodeToRemove = preferredMethod === 'default'
|
|
71
|
+
? optionalMethod.node
|
|
72
|
+
: defaultMethod.node;
|
|
73
|
+
const calleeToRemove = nodeToRemove.callee;
|
|
74
|
+
return fixer.replaceText(nodeToRemove, sourceCode.getText(calleeToRemove.object));
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
declare const preferredMethods: readonly ["none", "default", "optional"];
|
|
3
|
+
type PreferredMethod = (typeof preferredMethods)[number];
|
|
4
|
+
interface Options {
|
|
5
|
+
preferredMethod: PreferredMethod;
|
|
6
|
+
}
|
|
7
|
+
type MessageIds = 'noOptionalAndDefaultTogether' | 'noOptionalAndDefaultTogetherRemoveMethod';
|
|
8
|
+
export declare const noOptionalAndDefaultTogether: ESLintUtils.RuleModule<MessageIds, [Options], unknown, ESLintUtils.RuleListener> & {
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
declare const preferredMethods: readonly ["none", "default", "optional"];
|
|
3
|
+
type PreferredMethod = (typeof preferredMethods)[number];
|
|
4
|
+
interface Options {
|
|
5
|
+
preferredMethod: PreferredMethod;
|
|
6
|
+
}
|
|
7
|
+
type MessageIds = 'noOptionalAndDefaultTogether' | 'noOptionalAndDefaultTogetherRemoveMethod';
|
|
8
|
+
export declare const noOptionalAndDefaultTogether: ESLintUtils.RuleModule<MessageIds, [Options], unknown, ESLintUtils.RuleListener> & {
|
|
9
|
+
name: string;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { getRuleURL } from "../meta.js";
|
|
3
|
+
import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
|
|
4
|
+
const preferredMethods = ['none', 'default', 'optional'];
|
|
5
|
+
const defaultOptions = { preferredMethod: 'none' };
|
|
6
|
+
export const noOptionalAndDefaultTogether = ESLintUtils.RuleCreator(getRuleURL)({
|
|
7
|
+
name: 'no-optional-and-default-together',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'problem',
|
|
10
|
+
fixable: 'code',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Disallow using both `.optional()` and `.default()` on the same Zod schema',
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
noOptionalAndDefaultTogether: 'Using both `.optional()` and `.default()` is redundant. A schema with a default value is already optional.',
|
|
16
|
+
noOptionalAndDefaultTogetherRemoveMethod: 'Using both `.optional()` and `.default()` is redundant. Remove the `.{{method}}()` method to avoid redundancy.',
|
|
17
|
+
},
|
|
18
|
+
schema: [
|
|
19
|
+
{
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
preferredMethod: {
|
|
23
|
+
description: 'Determines which method to keep when both are present',
|
|
24
|
+
type: 'string',
|
|
25
|
+
enum: [...preferredMethods],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [defaultOptions],
|
|
33
|
+
create(context, [{ preferredMethod }]) {
|
|
34
|
+
const { sourceCode } = context;
|
|
35
|
+
const { importDeclarationListener, detectZodSchemaRootNode: isZodSchema, collectZodChainMethods, } = trackZodSchemaImports();
|
|
36
|
+
return {
|
|
37
|
+
ImportDeclaration: importDeclarationListener,
|
|
38
|
+
CallExpression(node) {
|
|
39
|
+
if (!isZodSchema(node)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const methods = collectZodChainMethods(node);
|
|
43
|
+
if (methods.length === 0) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const optionalMethod = methods.find((m) => m.name === 'optional');
|
|
47
|
+
const defaultMethod = methods.find((m) => m.name === 'default');
|
|
48
|
+
if (!optionalMethod || !defaultMethod) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const reportNode = methods.indexOf(optionalMethod) > methods.indexOf(defaultMethod)
|
|
52
|
+
? optionalMethod.node
|
|
53
|
+
: defaultMethod.node;
|
|
54
|
+
if (preferredMethod === 'none') {
|
|
55
|
+
context.report({
|
|
56
|
+
node: reportNode,
|
|
57
|
+
messageId: 'noOptionalAndDefaultTogether',
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const methodToRemoveName = preferredMethod === 'default' ? 'optional' : 'default';
|
|
62
|
+
context.report({
|
|
63
|
+
node: reportNode,
|
|
64
|
+
messageId: 'noOptionalAndDefaultTogetherRemoveMethod',
|
|
65
|
+
data: { method: methodToRemoveName },
|
|
66
|
+
fix(fixer) {
|
|
67
|
+
const nodeToRemove = preferredMethod === 'default'
|
|
68
|
+
? optionalMethod.node
|
|
69
|
+
: defaultMethod.node;
|
|
70
|
+
const calleeToRemove = nodeToRemove.callee;
|
|
71
|
+
return fixer.replaceText(nodeToRemove, sourceCode.getText(calleeToRemove.object));
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noThrowInRefine = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const meta_js_1 = require("../meta.cjs");
|
|
6
|
+
const is_zod_expression_js_1 = require("../utils/is-zod-expression.cjs");
|
|
7
|
+
const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
|
|
8
|
+
exports.noThrowInRefine = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
|
|
9
|
+
name: 'no-throw-in-refine',
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Disallow throwing errors directly inside Zod refine callbacks',
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
noThrowInRefine: 'Do not throw errors directly inside a z.refine callback.',
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const { importDeclarationListener, detectZodSchemaRootNode, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
|
|
23
|
+
function checkNode(node) {
|
|
24
|
+
if (!node) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
switch (node.type) {
|
|
28
|
+
case utils_1.AST_NODE_TYPES.ThrowStatement:
|
|
29
|
+
context.report({ node, messageId: 'noThrowInRefine' });
|
|
30
|
+
break;
|
|
31
|
+
case utils_1.AST_NODE_TYPES.BlockStatement:
|
|
32
|
+
node.body.forEach(checkNode);
|
|
33
|
+
break;
|
|
34
|
+
case utils_1.AST_NODE_TYPES.IfStatement:
|
|
35
|
+
checkNode(node.consequent);
|
|
36
|
+
if (node.alternate) {
|
|
37
|
+
checkNode(node.alternate);
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
case utils_1.AST_NODE_TYPES.ForStatement:
|
|
41
|
+
case utils_1.AST_NODE_TYPES.ForInStatement:
|
|
42
|
+
case utils_1.AST_NODE_TYPES.ForOfStatement:
|
|
43
|
+
case utils_1.AST_NODE_TYPES.WhileStatement:
|
|
44
|
+
case utils_1.AST_NODE_TYPES.DoWhileStatement:
|
|
45
|
+
checkNode(node.body);
|
|
46
|
+
break;
|
|
47
|
+
case utils_1.AST_NODE_TYPES.TryStatement:
|
|
48
|
+
checkNode(node.block);
|
|
49
|
+
if (node.handler) {
|
|
50
|
+
checkNode(node.handler.body);
|
|
51
|
+
}
|
|
52
|
+
if (node.finalizer) {
|
|
53
|
+
checkNode(node.finalizer);
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
case utils_1.AST_NODE_TYPES.FunctionExpression:
|
|
57
|
+
case utils_1.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
58
|
+
case utils_1.AST_NODE_TYPES.FunctionDeclaration:
|
|
59
|
+
return;
|
|
60
|
+
default:
|
|
61
|
+
if ('body' in node && Array.isArray(node.body)) {
|
|
62
|
+
node.body.forEach(checkNode);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
ImportDeclaration: importDeclarationListener,
|
|
69
|
+
CallExpression(node) {
|
|
70
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
71
|
+
if (!zodSchemaMeta) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if ((0, is_zod_expression_js_1.isZodExpressionEndingWithMethod)(node.callee, 'refine')) {
|
|
75
|
+
const [callback] = node.arguments;
|
|
76
|
+
if (callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
77
|
+
callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
78
|
+
checkNode(callback.body);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { getRuleURL } from "../meta.js";
|
|
3
|
+
import { isZodExpressionEndingWithMethod } from "../utils/is-zod-expression.js";
|
|
4
|
+
import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
|
|
5
|
+
export const noThrowInRefine = ESLintUtils.RuleCreator(getRuleURL)({
|
|
6
|
+
name: 'no-throw-in-refine',
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'problem',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Disallow throwing errors directly inside Zod refine callbacks',
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
noThrowInRefine: 'Do not throw errors directly inside a z.refine callback.',
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create(context) {
|
|
19
|
+
const { importDeclarationListener, detectZodSchemaRootNode, } = trackZodSchemaImports();
|
|
20
|
+
function checkNode(node) {
|
|
21
|
+
if (!node) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
switch (node.type) {
|
|
25
|
+
case AST_NODE_TYPES.ThrowStatement:
|
|
26
|
+
context.report({ node, messageId: 'noThrowInRefine' });
|
|
27
|
+
break;
|
|
28
|
+
case AST_NODE_TYPES.BlockStatement:
|
|
29
|
+
node.body.forEach(checkNode);
|
|
30
|
+
break;
|
|
31
|
+
case AST_NODE_TYPES.IfStatement:
|
|
32
|
+
checkNode(node.consequent);
|
|
33
|
+
if (node.alternate) {
|
|
34
|
+
checkNode(node.alternate);
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
case AST_NODE_TYPES.ForStatement:
|
|
38
|
+
case AST_NODE_TYPES.ForInStatement:
|
|
39
|
+
case AST_NODE_TYPES.ForOfStatement:
|
|
40
|
+
case AST_NODE_TYPES.WhileStatement:
|
|
41
|
+
case AST_NODE_TYPES.DoWhileStatement:
|
|
42
|
+
checkNode(node.body);
|
|
43
|
+
break;
|
|
44
|
+
case AST_NODE_TYPES.TryStatement:
|
|
45
|
+
checkNode(node.block);
|
|
46
|
+
if (node.handler) {
|
|
47
|
+
checkNode(node.handler.body);
|
|
48
|
+
}
|
|
49
|
+
if (node.finalizer) {
|
|
50
|
+
checkNode(node.finalizer);
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
case AST_NODE_TYPES.FunctionExpression:
|
|
54
|
+
case AST_NODE_TYPES.ArrowFunctionExpression:
|
|
55
|
+
case AST_NODE_TYPES.FunctionDeclaration:
|
|
56
|
+
return;
|
|
57
|
+
default:
|
|
58
|
+
if ('body' in node && Array.isArray(node.body)) {
|
|
59
|
+
node.body.forEach(checkNode);
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
ImportDeclaration: importDeclarationListener,
|
|
66
|
+
CallExpression(node) {
|
|
67
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
68
|
+
if (!zodSchemaMeta) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (isZodExpressionEndingWithMethod(node.callee, 'refine')) {
|
|
72
|
+
const [callback] = node.arguments;
|
|
73
|
+
if (callback.type === AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
74
|
+
callback.type === AST_NODE_TYPES.FunctionExpression) {
|
|
75
|
+
checkNode(callback.body);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noUnknownSchema = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const meta_js_1 = require("../meta.cjs");
|
|
6
|
+
const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
|
|
7
|
+
exports.noUnknownSchema = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
|
|
8
|
+
name: 'no-unknown-schema',
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'suggestion',
|
|
11
|
+
docs: {
|
|
12
|
+
description: 'Disallow usage of `z.unknown()` in Zod schemas',
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
noZUnknown: 'Using `z.unknown()` is not allowed. Please use a more specific schema.',
|
|
16
|
+
},
|
|
17
|
+
schema: [],
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create(context) {
|
|
21
|
+
const { importDeclarationListener, detectZodSchemaRootNode, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
|
|
22
|
+
return {
|
|
23
|
+
ImportDeclaration: importDeclarationListener,
|
|
24
|
+
CallExpression(node) {
|
|
25
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
26
|
+
if ((zodSchemaMeta === null || zodSchemaMeta === void 0 ? void 0 : zodSchemaMeta.schemaType) === 'unknown') {
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId: 'noZUnknown',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { getRuleURL } from "../meta.js";
|
|
3
|
+
import { trackZodSchemaImports } from "../utils/track-zod-schema-imports.js";
|
|
4
|
+
export const noUnknownSchema = ESLintUtils.RuleCreator(getRuleURL)({
|
|
5
|
+
name: 'no-unknown-schema',
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'suggestion',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Disallow usage of `z.unknown()` in Zod schemas',
|
|
10
|
+
},
|
|
11
|
+
messages: {
|
|
12
|
+
noZUnknown: 'Using `z.unknown()` is not allowed. Please use a more specific schema.',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
const { importDeclarationListener, detectZodSchemaRootNode, } = trackZodSchemaImports();
|
|
19
|
+
return {
|
|
20
|
+
ImportDeclaration: importDeclarationListener,
|
|
21
|
+
CallExpression(node) {
|
|
22
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
23
|
+
if ((zodSchemaMeta === null || zodSchemaMeta === void 0 ? void 0 : zodSchemaMeta.schemaType) === 'unknown') {
|
|
24
|
+
context.report({
|
|
25
|
+
node,
|
|
26
|
+
messageId: 'noZUnknown',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferEnumOverLiteralUnion = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const meta_js_1 = require("../meta.cjs");
|
|
6
|
+
const track_zod_schema_imports_js_1 = require("../utils/track-zod-schema-imports.cjs");
|
|
7
|
+
exports.preferEnumOverLiteralUnion = utils_1.ESLintUtils.RuleCreator(meta_js_1.getRuleURL)({
|
|
8
|
+
name: 'prefer-enum-over-literal-union',
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'suggestion',
|
|
11
|
+
fixable: 'code',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Prefer `z.enum()` over `z.union()` when all members are string literals.',
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
useEnum: 'Replace this union of string literals with `z.enum()`.',
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const { importDeclarationListener, detectZodSchemaRootNode, } = (0, track_zod_schema_imports_js_1.trackZodSchemaImports)();
|
|
23
|
+
return {
|
|
24
|
+
ImportDeclaration: importDeclarationListener,
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
const zodSchema = detectZodSchemaRootNode(node);
|
|
27
|
+
if ((zodSchema === null || zodSchema === void 0 ? void 0 : zodSchema.schemaType) !== 'union') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const [unionArgument] = node.arguments;
|
|
31
|
+
if (unionArgument.type !== utils_1.AST_NODE_TYPES.ArrayExpression) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const zodLiteralStrings = unionArgument.elements.map((s) => {
|
|
35
|
+
if (!s) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const maybeLiteralSchema = detectZodSchemaRootNode(s);
|
|
39
|
+
if ((maybeLiteralSchema === null || maybeLiteralSchema === void 0 ? void 0 : maybeLiteralSchema.schemaType) !== 'literal') {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const [literalArgument] = maybeLiteralSchema.node.arguments;
|
|
43
|
+
if (literalArgument.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
44
|
+
typeof literalArgument.value === 'string') {
|
|
45
|
+
return literalArgument.raw;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
});
|
|
49
|
+
if (zodLiteralStrings.some((it) => it === null)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (zodSchema.schemaDecl === 'named') {
|
|
53
|
+
context.report({
|
|
54
|
+
node,
|
|
55
|
+
messageId: 'useEnum',
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
context.report({
|
|
60
|
+
node,
|
|
61
|
+
messageId: 'useEnum',
|
|
62
|
+
fix(fixer) {
|
|
63
|
+
return [
|
|
64
|
+
fixer.replaceText(node.callee.property, 'enum'),
|
|
65
|
+
fixer.replaceText(node.arguments[0], `[${zodLiteralStrings.join(', ')}]`),
|
|
66
|
+
];
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
});
|