eslint-plugin-zod 3.5.0 → 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 -74
- 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 -64
- package/dist/utils/track-zod-schema-imports.mjs +64 -0
- package/package.json +16 -19
- 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 -72
- 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,89 @@
|
|
|
1
|
+
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "../utils/track-zod-schema-imports.mjs";
|
|
3
|
+
//#region src/rules/array-style.ts
|
|
4
|
+
const ZOD_ARRAY_STYLES = ["function", "method"];
|
|
5
|
+
const defaultOptions = { style: "function" };
|
|
6
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod");
|
|
7
|
+
const arrayStyle = createZodPluginRule({
|
|
8
|
+
name: "array-style",
|
|
9
|
+
meta: {
|
|
10
|
+
type: "suggestion",
|
|
11
|
+
fixable: "code",
|
|
12
|
+
docs: {
|
|
13
|
+
zodImportAllowedSource,
|
|
14
|
+
description: "Enforce consistent Zod array style"
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
useFunction: "Use z.array(schema) instead of schema.array().",
|
|
18
|
+
useMethod: "Use schema.array() instead of z.array(schema)."
|
|
19
|
+
},
|
|
20
|
+
schema: [{
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: { style: {
|
|
23
|
+
description: "Decides which style for zod array function",
|
|
24
|
+
type: "string",
|
|
25
|
+
enum: ZOD_ARRAY_STYLES
|
|
26
|
+
} },
|
|
27
|
+
additionalProperties: false
|
|
28
|
+
}]
|
|
29
|
+
},
|
|
30
|
+
defaultOptions: [defaultOptions],
|
|
31
|
+
create(context, [{ style }]) {
|
|
32
|
+
const { sourceCode } = context;
|
|
33
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
34
|
+
return {
|
|
35
|
+
ImportDeclaration: importDeclarationListener,
|
|
36
|
+
CallExpression(node) {
|
|
37
|
+
const zodSchema = detectZodSchemaRootNode(node);
|
|
38
|
+
if (!zodSchema) return;
|
|
39
|
+
const { schemaDecl, schemaType } = zodSchema;
|
|
40
|
+
if (style === "method") {
|
|
41
|
+
if (schemaType === "array") {
|
|
42
|
+
if (schemaDecl === "namespace") {
|
|
43
|
+
context.report({
|
|
44
|
+
node,
|
|
45
|
+
messageId: "useMethod",
|
|
46
|
+
fix(fixer) {
|
|
47
|
+
const arrayCall = collectZodChainMethods(node).find((c) => c.name === "array");
|
|
48
|
+
if (!arrayCall) return null;
|
|
49
|
+
const arg = arrayCall.node.arguments.at(0);
|
|
50
|
+
if (!arg) return null;
|
|
51
|
+
const argText = sourceCode.getText(arg);
|
|
52
|
+
return fixer.replaceText(arrayCall.node, `${argText}.array()`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
context.report({
|
|
58
|
+
node,
|
|
59
|
+
messageId: "useMethod"
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const arrayMethod = collectZodChainMethods(node).find((it) => it.name === "array" && it.node.arguments.length === 0);
|
|
65
|
+
if (arrayMethod) {
|
|
66
|
+
const arrayNode = arrayMethod.node;
|
|
67
|
+
if (schemaDecl === "namespace") {
|
|
68
|
+
context.report({
|
|
69
|
+
node,
|
|
70
|
+
messageId: "useFunction",
|
|
71
|
+
fix(fixer) {
|
|
72
|
+
const callee = arrayNode.callee;
|
|
73
|
+
const objText = sourceCode.getText(callee.object);
|
|
74
|
+
return fixer.replaceText(arrayNode, `z.array(${objText})`);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
context.report({
|
|
80
|
+
node,
|
|
81
|
+
messageId: "useFunction"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
//#endregion
|
|
89
|
+
export { arrayStyle };
|
|
@@ -1,67 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
data: { valid: it, invalid: sourceValue },
|
|
59
|
-
fix(fixer) {
|
|
60
|
-
return fixer.replaceText(node.source, node.source.raw.replace(sourceValue, it));
|
|
61
|
-
},
|
|
62
|
-
})),
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
},
|
|
1
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
2
|
+
const require_is_zod_import_source = require("../utils/is-zod-import-source.cjs");
|
|
3
|
+
//#region src/rules/consistent-import-source.ts
|
|
4
|
+
const consistentImportSource = require_create_plugin_rule.createZodPluginRule({
|
|
5
|
+
name: "consistent-import-source",
|
|
6
|
+
meta: {
|
|
7
|
+
hasSuggestions: true,
|
|
8
|
+
type: "suggestion",
|
|
9
|
+
docs: {
|
|
10
|
+
zodImportAllowedSource: "all",
|
|
11
|
+
description: "Enforce consistent source from Zod imports"
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
sourceNotAllowed: "\"{{source}}\" is not allowed. Available values are: {{sources}}",
|
|
15
|
+
replaceSource: "Replace \"{{invalid}}\" with \"{{valid}}\""
|
|
16
|
+
},
|
|
17
|
+
schema: [{
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: { sources: {
|
|
20
|
+
type: "array",
|
|
21
|
+
description: "An array of allowed Zod import sources.",
|
|
22
|
+
items: {
|
|
23
|
+
type: "string",
|
|
24
|
+
enum: [...require_is_zod_import_source.ZOD_IMPORT_SOURCES]
|
|
25
|
+
},
|
|
26
|
+
minItems: 1,
|
|
27
|
+
uniqueItems: true
|
|
28
|
+
} },
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
}]
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [{ sources: ["zod"] }],
|
|
33
|
+
create(context, [{ sources }]) {
|
|
34
|
+
return { ImportDeclaration(node) {
|
|
35
|
+
const sourceValue = node.source.value;
|
|
36
|
+
if (!sourceValue.startsWith("zod")) return;
|
|
37
|
+
if (sources.includes(sourceValue)) return;
|
|
38
|
+
context.report({
|
|
39
|
+
node,
|
|
40
|
+
messageId: "sourceNotAllowed",
|
|
41
|
+
data: {
|
|
42
|
+
source: sourceValue,
|
|
43
|
+
sources: sources.map((s) => `"${s}"`).join(", ")
|
|
44
|
+
},
|
|
45
|
+
suggest: sources.map((it) => ({
|
|
46
|
+
messageId: "replaceSource",
|
|
47
|
+
data: {
|
|
48
|
+
valid: it,
|
|
49
|
+
invalid: sourceValue
|
|
50
|
+
},
|
|
51
|
+
fix(fixer) {
|
|
52
|
+
return fixer.replaceText(node.source, node.source.raw.replace(sourceValue, it));
|
|
53
|
+
}
|
|
54
|
+
}))
|
|
55
|
+
});
|
|
56
|
+
} };
|
|
57
|
+
}
|
|
67
58
|
});
|
|
59
|
+
//#endregion
|
|
60
|
+
exports.consistentImportSource = consistentImportSource;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createZodPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { ZOD_IMPORT_SOURCES } from "../utils/is-zod-import-source.mjs";
|
|
3
|
+
//#region src/rules/consistent-import-source.ts
|
|
4
|
+
const consistentImportSource = createZodPluginRule({
|
|
5
|
+
name: "consistent-import-source",
|
|
6
|
+
meta: {
|
|
7
|
+
hasSuggestions: true,
|
|
8
|
+
type: "suggestion",
|
|
9
|
+
docs: {
|
|
10
|
+
zodImportAllowedSource: "all",
|
|
11
|
+
description: "Enforce consistent source from Zod imports"
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
sourceNotAllowed: "\"{{source}}\" is not allowed. Available values are: {{sources}}",
|
|
15
|
+
replaceSource: "Replace \"{{invalid}}\" with \"{{valid}}\""
|
|
16
|
+
},
|
|
17
|
+
schema: [{
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: { sources: {
|
|
20
|
+
type: "array",
|
|
21
|
+
description: "An array of allowed Zod import sources.",
|
|
22
|
+
items: {
|
|
23
|
+
type: "string",
|
|
24
|
+
enum: [...ZOD_IMPORT_SOURCES]
|
|
25
|
+
},
|
|
26
|
+
minItems: 1,
|
|
27
|
+
uniqueItems: true
|
|
28
|
+
} },
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
}]
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [{ sources: ["zod"] }],
|
|
33
|
+
create(context, [{ sources }]) {
|
|
34
|
+
return { ImportDeclaration(node) {
|
|
35
|
+
const sourceValue = node.source.value;
|
|
36
|
+
if (!sourceValue.startsWith("zod")) return;
|
|
37
|
+
if (sources.includes(sourceValue)) return;
|
|
38
|
+
context.report({
|
|
39
|
+
node,
|
|
40
|
+
messageId: "sourceNotAllowed",
|
|
41
|
+
data: {
|
|
42
|
+
source: sourceValue,
|
|
43
|
+
sources: sources.map((s) => `"${s}"`).join(", ")
|
|
44
|
+
},
|
|
45
|
+
suggest: sources.map((it) => ({
|
|
46
|
+
messageId: "replaceSource",
|
|
47
|
+
data: {
|
|
48
|
+
valid: it,
|
|
49
|
+
invalid: sourceValue
|
|
50
|
+
},
|
|
51
|
+
fix(fixer) {
|
|
52
|
+
return fixer.replaceText(node.source, node.source.raw.replace(sourceValue, it));
|
|
53
|
+
}
|
|
54
|
+
}))
|
|
55
|
+
});
|
|
56
|
+
} };
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
//#endregion
|
|
60
|
+
export { consistentImportSource };
|
|
@@ -1,179 +1,153 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
const require_is_zod_import_source = require("../utils/is-zod-import-source.cjs");
|
|
4
|
+
let _typescript_eslint_utils = require("@typescript-eslint/utils");
|
|
5
|
+
//#region src/rules/consistent-import.ts
|
|
6
|
+
const IMPORT_SYNTAXES = ["namespace", "named"];
|
|
7
|
+
/**
|
|
8
|
+
* Determines whether the first import in a group is valid for a given import
|
|
9
|
+
* syntax (`named` or `namespace`), taking into account whether the group
|
|
10
|
+
* contains only type imports.
|
|
11
|
+
*
|
|
12
|
+
* Rules enforced:
|
|
13
|
+
* - For `named` syntax:
|
|
14
|
+
* - The first import must have exactly one specifier
|
|
15
|
+
* - That specifier must be a named import of identifier `z`
|
|
16
|
+
* - For `namespace` syntax:
|
|
17
|
+
* - The first import must have exactly one namespace specifier
|
|
18
|
+
* - If the group contains only type imports, the first import must explicitly
|
|
19
|
+
* be declared as `import type`
|
|
20
|
+
*
|
|
21
|
+
* @param group - Metadata describing the import group
|
|
22
|
+
* @param syntax - Expected import syntax for the group
|
|
23
|
+
* @returns `true` if the first import matches the expected syntax and type rules
|
|
24
|
+
*/
|
|
8
25
|
function isGroupFirstImportKindValidForSyntax(group, syntax) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
? specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
|
18
|
-
specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
19
|
-
specifier.imported.name === 'z'
|
|
20
|
-
: specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier;
|
|
21
|
-
if (!isValidForSyntax) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
if (hasOnlyTypeImports) {
|
|
25
|
-
return importKind === 'type';
|
|
26
|
-
}
|
|
27
|
-
return true;
|
|
26
|
+
const { hasOnlyTypeImports, nodes } = group;
|
|
27
|
+
const [firstImportNode] = nodes;
|
|
28
|
+
const { specifiers, importKind } = firstImportNode;
|
|
29
|
+
if (specifiers.length !== 1) return false;
|
|
30
|
+
const [specifier] = specifiers;
|
|
31
|
+
if (!(syntax === "named" ? specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && specifier.imported.name === "z" : specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier)) return false;
|
|
32
|
+
if (hasOnlyTypeImports) return importKind === "type";
|
|
33
|
+
return true;
|
|
28
34
|
}
|
|
29
35
|
function shouldIdentifierBeRenamed(node) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (node.parent.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
34
|
-
node.parent.object.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
35
|
-
node.parent.object.name !== node.name) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
return true;
|
|
36
|
+
if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier) return false;
|
|
37
|
+
if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && node.parent.object.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
|
|
38
|
+
return true;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* From a given specifiers retrieve the most significant to use when creating an alias import
|
|
42
|
+
*/
|
|
40
43
|
function getNamespaceAliasNameFrom(node) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
if (node.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
46
|
-
node.imported.name === 'z') {
|
|
47
|
-
return node.local.name;
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
44
|
+
if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportDefaultSpecifier || node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
|
|
45
|
+
if (node.imported.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
|
|
46
|
+
return null;
|
|
50
47
|
}
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (shouldIdentifierBeRenamed(identifier)) {
|
|
155
|
-
context.report({
|
|
156
|
-
node: identifier,
|
|
157
|
-
messageId: 'convertUsage',
|
|
158
|
-
data: { syntax },
|
|
159
|
-
fix(fixer) {
|
|
160
|
-
const newId = `${namespaceAliasName}.${identifier.name}`;
|
|
161
|
-
return fixer.replaceText(identifier, newId);
|
|
162
|
-
},
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
for (const extraImport of othersImportNodes) {
|
|
167
|
-
context.report({
|
|
168
|
-
node: extraImport,
|
|
169
|
-
messageId: 'removeDuplicate',
|
|
170
|
-
fix(fixer) {
|
|
171
|
-
return fixer.removeRange(extraImport.range);
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
},
|
|
48
|
+
const consistentImport = require_create_plugin_rule.createZodPluginRule({
|
|
49
|
+
name: "consistent-import",
|
|
50
|
+
meta: {
|
|
51
|
+
type: "problem",
|
|
52
|
+
docs: {
|
|
53
|
+
zodImportAllowedSource: "all",
|
|
54
|
+
description: "Enforce a consistent import style for Zod"
|
|
55
|
+
},
|
|
56
|
+
fixable: "code",
|
|
57
|
+
messages: {
|
|
58
|
+
changeImportSyntax: "Use a {{syntax}} import for Zod.",
|
|
59
|
+
removeDuplicate: "Remove duplicate Zod import; Zod is already imported.",
|
|
60
|
+
convertUsage: "Update Zod usage to match the {{syntax}} import syntax."
|
|
61
|
+
},
|
|
62
|
+
schema: [{
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: { syntax: {
|
|
65
|
+
description: "Specifies the import syntax to use for Zod.",
|
|
66
|
+
type: "string",
|
|
67
|
+
enum: IMPORT_SYNTAXES
|
|
68
|
+
} },
|
|
69
|
+
additionalProperties: false
|
|
70
|
+
}]
|
|
71
|
+
},
|
|
72
|
+
defaultOptions: [{ syntax: "namespace" }],
|
|
73
|
+
create(context, [options]) {
|
|
74
|
+
const { syntax } = options;
|
|
75
|
+
const { sourceCode } = context;
|
|
76
|
+
const importGroups = {};
|
|
77
|
+
return {
|
|
78
|
+
ImportDeclaration(node) {
|
|
79
|
+
const { source, importKind } = node;
|
|
80
|
+
if (!require_is_zod_import_source.isZodImportSource(source.value, "all")) return;
|
|
81
|
+
if (!importGroups[source.value]) importGroups[source.value] = {
|
|
82
|
+
hasOnlyTypeImports: true,
|
|
83
|
+
nodes: []
|
|
84
|
+
};
|
|
85
|
+
if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
|
|
86
|
+
importGroups[source.value].nodes.push(node);
|
|
87
|
+
},
|
|
88
|
+
"Program:exit": function() {
|
|
89
|
+
let namespaceAliasNameIndex = 0;
|
|
90
|
+
for (const importGroup of Object.values(importGroups)) {
|
|
91
|
+
const { hasOnlyTypeImports, nodes } = importGroup;
|
|
92
|
+
const [firstImportNode, ...othersImportNodes] = nodes;
|
|
93
|
+
/**
|
|
94
|
+
* Variable to track all specifiers that later are used by {@link getDeclaredVariables}
|
|
95
|
+
* to add the namespace prefix
|
|
96
|
+
*/
|
|
97
|
+
const nodesWithVariablesToUpdate = [];
|
|
98
|
+
let namespaceAliasName = null;
|
|
99
|
+
for (const specifier of nodes.flatMap((it) => it.specifiers)) {
|
|
100
|
+
if (!namespaceAliasName) {
|
|
101
|
+
namespaceAliasName = getNamespaceAliasNameFrom(specifier);
|
|
102
|
+
if (namespaceAliasName) continue;
|
|
103
|
+
}
|
|
104
|
+
nodesWithVariablesToUpdate.push(specifier);
|
|
105
|
+
}
|
|
106
|
+
if (!namespaceAliasName) {
|
|
107
|
+
namespaceAliasName = "z";
|
|
108
|
+
if (namespaceAliasNameIndex > 0) {
|
|
109
|
+
namespaceAliasName = `z${namespaceAliasNameIndex}`;
|
|
110
|
+
namespaceAliasNameIndex += 1;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (!isGroupFirstImportKindValidForSyntax(importGroup, syntax)) context.report({
|
|
114
|
+
node: firstImportNode,
|
|
115
|
+
messageId: "changeImportSyntax",
|
|
116
|
+
data: { syntax },
|
|
117
|
+
fix(fixer) {
|
|
118
|
+
const importTypeKeyword = hasOnlyTypeImports ? "type " : "";
|
|
119
|
+
let importSpecifier;
|
|
120
|
+
if (syntax === "named") if (namespaceAliasName === "z") importSpecifier = "{ z }";
|
|
121
|
+
else importSpecifier = `{ z as ${namespaceAliasName} }`;
|
|
122
|
+
else importSpecifier = `* as ${namespaceAliasName}`;
|
|
123
|
+
const newImportText = `import ${importTypeKeyword}${importSpecifier} from ${firstImportNode.source.raw};`;
|
|
124
|
+
return fixer.replaceText(firstImportNode, newImportText);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
|
|
128
|
+
for (const ref of allReferences) {
|
|
129
|
+
const { identifier } = ref;
|
|
130
|
+
if (shouldIdentifierBeRenamed(identifier)) context.report({
|
|
131
|
+
node: identifier,
|
|
132
|
+
messageId: "convertUsage",
|
|
133
|
+
data: { syntax },
|
|
134
|
+
fix(fixer) {
|
|
135
|
+
const newId = `${namespaceAliasName}.${identifier.name}`;
|
|
136
|
+
return fixer.replaceText(identifier, newId);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
for (const extraImport of othersImportNodes) context.report({
|
|
141
|
+
node: extraImport,
|
|
142
|
+
messageId: "removeDuplicate",
|
|
143
|
+
fix(fixer) {
|
|
144
|
+
return fixer.removeRange(extraImport.range);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
179
151
|
});
|
|
152
|
+
//#endregion
|
|
153
|
+
exports.consistentImport = consistentImport;
|