eslint-plugin-zod-mini 0.1.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 +21 -0
- package/README.md +149 -0
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/index.cjs +62 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.mjs +62 -0
- package/dist/meta.cjs +12 -0
- package/dist/meta.mjs +9 -0
- package/dist/rules/consistent-import-source.cjs +61 -0
- package/dist/rules/consistent-import-source.mjs +60 -0
- package/dist/rules/consistent-import.cjs +153 -0
- package/dist/rules/consistent-import.mjs +152 -0
- package/dist/rules/consistent-object-schema-type.cjs +82 -0
- package/dist/rules/consistent-object-schema-type.mjs +81 -0
- package/dist/rules/consistent-schema-output-type-style.cjs +70 -0
- package/dist/rules/consistent-schema-output-type-style.mjs +69 -0
- package/dist/rules/consistent-schema-var-name.cjs +76 -0
- package/dist/rules/consistent-schema-var-name.mjs +75 -0
- package/dist/rules/no-any-schema.cjs +63 -0
- package/dist/rules/no-any-schema.mjs +62 -0
- package/dist/rules/no-empty-custom-schema.cjs +36 -0
- package/dist/rules/no-empty-custom-schema.mjs +36 -0
- package/dist/rules/no-unknown-schema.cjs +31 -0
- package/dist/rules/no-unknown-schema.mjs +31 -0
- package/dist/rules/prefer-meta.cjs +46 -0
- package/dist/rules/prefer-meta.mjs +45 -0
- package/dist/rules/prefer-namespace-import.cjs +117 -0
- package/dist/rules/prefer-namespace-import.mjs +116 -0
- package/dist/rules/require-brand-type-parameter.cjs +49 -0
- package/dist/rules/require-brand-type-parameter.mjs +49 -0
- package/dist/rules/require-error-message.cjs +85 -0
- package/dist/rules/require-error-message.mjs +84 -0
- package/dist/rules/require-schema-suffix.cjs +69 -0
- package/dist/rules/require-schema-suffix.mjs +68 -0
- package/dist/rules/schema-error-property-style.cjs +96 -0
- package/dist/rules/schema-error-property-style.mjs +94 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.js +56 -0
- package/dist/src/meta.d.ts +3 -0
- package/dist/src/meta.js +8 -0
- package/dist/src/rules/consistent-import-source.d.ts +11 -0
- package/dist/src/rules/consistent-import-source.js +64 -0
- package/dist/src/rules/consistent-import-source.spec.d.ts +1 -0
- package/dist/src/rules/consistent-import-source.spec.js +103 -0
- package/dist/src/rules/consistent-import.d.ts +12 -0
- package/dist/src/rules/consistent-import.js +176 -0
- package/dist/src/rules/consistent-import.spec.d.ts +1 -0
- package/dist/src/rules/consistent-import.spec.js +194 -0
- package/dist/src/rules/consistent-object-schema-type.d.ts +13 -0
- package/dist/src/rules/consistent-object-schema-type.js +82 -0
- package/dist/src/rules/consistent-object-schema-type.spec.d.ts +1 -0
- package/dist/src/rules/consistent-object-schema-type.spec.js +138 -0
- package/dist/src/rules/consistent-schema-output-type-style.d.ts +12 -0
- package/dist/src/rules/consistent-schema-output-type-style.js +81 -0
- package/dist/src/rules/consistent-schema-output-type-style.spec.d.ts +1 -0
- package/dist/src/rules/consistent-schema-output-type-style.spec.js +128 -0
- package/dist/src/rules/consistent-schema-var-name.d.ts +10 -0
- package/dist/src/rules/consistent-schema-var-name.js +86 -0
- package/dist/src/rules/consistent-schema-var-name.spec.d.ts +1 -0
- package/dist/src/rules/consistent-schema-var-name.spec.js +130 -0
- package/dist/src/rules/no-any-schema.d.ts +6 -0
- package/dist/src/rules/no-any-schema.js +65 -0
- package/dist/src/rules/no-any-schema.spec.d.ts +1 -0
- package/dist/src/rules/no-any-schema.spec.js +155 -0
- package/dist/src/rules/no-empty-custom-schema.d.ts +5 -0
- package/dist/src/rules/no-empty-custom-schema.js +43 -0
- package/dist/src/rules/no-empty-custom-schema.spec.d.ts +1 -0
- package/dist/src/rules/no-empty-custom-schema.spec.js +97 -0
- package/dist/src/rules/no-unknown-schema.d.ts +5 -0
- package/dist/src/rules/no-unknown-schema.js +33 -0
- package/dist/src/rules/no-unknown-schema.spec.d.ts +1 -0
- package/dist/src/rules/no-unknown-schema.spec.js +75 -0
- package/dist/src/rules/prefer-meta.d.ts +5 -0
- package/dist/src/rules/prefer-meta.js +51 -0
- package/dist/src/rules/prefer-meta.spec.d.ts +1 -0
- package/dist/src/rules/prefer-meta.spec.js +118 -0
- package/dist/src/rules/prefer-namespace-import.d.ts +5 -0
- package/dist/src/rules/prefer-namespace-import.js +146 -0
- package/dist/src/rules/prefer-namespace-import.spec.d.ts +1 -0
- package/dist/src/rules/prefer-namespace-import.spec.js +100 -0
- package/dist/src/rules/require-brand-type-parameter.d.ts +6 -0
- package/dist/src/rules/require-brand-type-parameter.js +58 -0
- package/dist/src/rules/require-brand-type-parameter.spec.d.ts +1 -0
- package/dist/src/rules/require-brand-type-parameter.spec.js +157 -0
- package/dist/src/rules/require-error-message.d.ts +5 -0
- package/dist/src/rules/require-error-message.js +103 -0
- package/dist/src/rules/require-error-message.spec.d.ts +1 -0
- package/dist/src/rules/require-error-message.spec.js +161 -0
- package/dist/src/rules/require-schema-suffix.d.ts +9 -0
- package/dist/src/rules/require-schema-suffix.js +79 -0
- package/dist/src/rules/require-schema-suffix.spec.d.ts +1 -0
- package/dist/src/rules/require-schema-suffix.spec.js +131 -0
- package/dist/src/rules/schema-error-property-style.d.ts +10 -0
- package/dist/src/rules/schema-error-property-style.js +102 -0
- package/dist/src/rules/schema-error-property-style.spec.d.ts +1 -0
- package/dist/src/rules/schema-error-property-style.spec.js +134 -0
- package/dist/src/utils/create-plugin-rule.d.ts +8 -0
- package/dist/src/utils/create-plugin-rule.js +3 -0
- package/dist/tests/setup.d.ts +1 -0
- package/dist/tests/setup.js +12 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/tsdown.config.d.ts +2 -0
- package/dist/tsdown.config.js +11 -0
- package/dist/utils/create-plugin-rule.cjs +6 -0
- package/dist/utils/create-plugin-rule.mjs +6 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +7 -0
- package/package.json +80 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "@eslint-zod/utils";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
//#region src/rules/no-any-schema.ts
|
|
5
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
|
|
6
|
+
const noAnySchema = createZodMiniPluginRule({
|
|
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 Mini 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 };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
//#region src/rules/no-empty-custom-schema.ts
|
|
4
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = (0, require("@eslint-zod/utils").createZodSchemaImportTrack)("zod-mini");
|
|
5
|
+
const noEmptyCustomSchema = require_create_plugin_rule.createZodMiniPluginRule({
|
|
6
|
+
name: "no-empty-custom-schema",
|
|
7
|
+
meta: {
|
|
8
|
+
hasSuggestions: false,
|
|
9
|
+
type: "suggestion",
|
|
10
|
+
docs: {
|
|
11
|
+
zodImportAllowedSource,
|
|
12
|
+
description: "Disallow usage of `z.custom()` without arguments"
|
|
13
|
+
},
|
|
14
|
+
messages: { noEmptyCustomSchema: "You should provide a validate function within `z.custom()`" },
|
|
15
|
+
schema: []
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create(context) {
|
|
19
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
20
|
+
return {
|
|
21
|
+
ImportDeclaration: importDeclarationListener,
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
24
|
+
if (!zodSchemaMeta) return;
|
|
25
|
+
if (zodSchemaMeta.schemaType !== "custom") return;
|
|
26
|
+
const customCallNode = collectZodChainMethods(node).find((method) => method.name === "custom")?.node;
|
|
27
|
+
if (customCallNode?.arguments.length === 0) context.report({
|
|
28
|
+
node: customCallNode,
|
|
29
|
+
messageId: "noEmptyCustomSchema"
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.noEmptyCustomSchema = noEmptyCustomSchema;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "@eslint-zod/utils";
|
|
3
|
+
//#region src/rules/no-empty-custom-schema.ts
|
|
4
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
|
|
5
|
+
const noEmptyCustomSchema = createZodMiniPluginRule({
|
|
6
|
+
name: "no-empty-custom-schema",
|
|
7
|
+
meta: {
|
|
8
|
+
hasSuggestions: false,
|
|
9
|
+
type: "suggestion",
|
|
10
|
+
docs: {
|
|
11
|
+
zodImportAllowedSource,
|
|
12
|
+
description: "Disallow usage of `z.custom()` without arguments"
|
|
13
|
+
},
|
|
14
|
+
messages: { noEmptyCustomSchema: "You should provide a validate function within `z.custom()`" },
|
|
15
|
+
schema: []
|
|
16
|
+
},
|
|
17
|
+
defaultOptions: [],
|
|
18
|
+
create(context) {
|
|
19
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
20
|
+
return {
|
|
21
|
+
ImportDeclaration: importDeclarationListener,
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
24
|
+
if (!zodSchemaMeta) return;
|
|
25
|
+
if (zodSchemaMeta.schemaType !== "custom") return;
|
|
26
|
+
const customCallNode = collectZodChainMethods(node).find((method) => method.name === "custom")?.node;
|
|
27
|
+
if (customCallNode?.arguments.length === 0) context.report({
|
|
28
|
+
node: customCallNode,
|
|
29
|
+
messageId: "noEmptyCustomSchema"
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
//#endregion
|
|
36
|
+
export { noEmptyCustomSchema };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
//#region src/rules/no-unknown-schema.ts
|
|
4
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = (0, require("@eslint-zod/utils").createZodSchemaImportTrack)("zod-mini");
|
|
5
|
+
const noUnknownSchema = require_create_plugin_rule.createZodMiniPluginRule({
|
|
6
|
+
name: "no-unknown-schema",
|
|
7
|
+
meta: {
|
|
8
|
+
type: "suggestion",
|
|
9
|
+
docs: {
|
|
10
|
+
zodImportAllowedSource,
|
|
11
|
+
description: "Disallow usage of `z.unknown()` in Zod Mini schemas"
|
|
12
|
+
},
|
|
13
|
+
messages: { noZUnknown: "Using `z.unknown()` is not allowed. Please use a more specific schema." },
|
|
14
|
+
schema: []
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
|
|
19
|
+
return {
|
|
20
|
+
ImportDeclaration: importDeclarationListener,
|
|
21
|
+
CallExpression(node) {
|
|
22
|
+
if (detectZodSchemaRootNode(node)?.schemaType === "unknown") context.report({
|
|
23
|
+
node,
|
|
24
|
+
messageId: "noZUnknown"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
//#endregion
|
|
31
|
+
exports.noUnknownSchema = noUnknownSchema;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "@eslint-zod/utils";
|
|
3
|
+
//#region src/rules/no-unknown-schema.ts
|
|
4
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
|
|
5
|
+
const noUnknownSchema = createZodMiniPluginRule({
|
|
6
|
+
name: "no-unknown-schema",
|
|
7
|
+
meta: {
|
|
8
|
+
type: "suggestion",
|
|
9
|
+
docs: {
|
|
10
|
+
zodImportAllowedSource,
|
|
11
|
+
description: "Disallow usage of `z.unknown()` in Zod Mini schemas"
|
|
12
|
+
},
|
|
13
|
+
messages: { noZUnknown: "Using `z.unknown()` is not allowed. Please use a more specific schema." },
|
|
14
|
+
schema: []
|
|
15
|
+
},
|
|
16
|
+
defaultOptions: [],
|
|
17
|
+
create(context) {
|
|
18
|
+
const { importDeclarationListener, detectZodSchemaRootNode } = trackZodSchemaImports();
|
|
19
|
+
return {
|
|
20
|
+
ImportDeclaration: importDeclarationListener,
|
|
21
|
+
CallExpression(node) {
|
|
22
|
+
if (detectZodSchemaRootNode(node)?.schemaType === "unknown") context.report({
|
|
23
|
+
node,
|
|
24
|
+
messageId: "noZUnknown"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
//#endregion
|
|
31
|
+
export { noUnknownSchema };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
let _eslint_zod_utils = require("@eslint-zod/utils");
|
|
4
|
+
let _typescript_eslint_utils = require("@typescript-eslint/utils");
|
|
5
|
+
//#region src/rules/prefer-meta.ts
|
|
6
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = (0, _eslint_zod_utils.createZodSchemaImportTrack)("zod-mini");
|
|
7
|
+
const preferMeta = require_create_plugin_rule.createZodMiniPluginRule({
|
|
8
|
+
name: "prefer-meta",
|
|
9
|
+
meta: {
|
|
10
|
+
type: "suggestion",
|
|
11
|
+
fixable: "code",
|
|
12
|
+
docs: {
|
|
13
|
+
zodImportAllowedSource,
|
|
14
|
+
description: "Enforce usage of `z.meta()` over `z.describe()`"
|
|
15
|
+
},
|
|
16
|
+
messages: { preferMeta: "The `z.describe()` function still exists for compatibility with Zod 3, but `z.meta()` is now the recommended approach." },
|
|
17
|
+
schema: []
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create(context) {
|
|
21
|
+
const { importDeclarationListener, isZodNamespace, getNamedImportOriginal } = trackZodSchemaImports();
|
|
22
|
+
return {
|
|
23
|
+
ImportDeclaration: importDeclarationListener,
|
|
24
|
+
CallExpression(node) {
|
|
25
|
+
const { callee } = node;
|
|
26
|
+
if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && callee.property.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && callee.property.name === "describe" && callee.object.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && isZodNamespace(callee.object.name)) {
|
|
27
|
+
const [describeArg] = node.arguments;
|
|
28
|
+
context.report({
|
|
29
|
+
node,
|
|
30
|
+
messageId: "preferMeta",
|
|
31
|
+
fix(fixer) {
|
|
32
|
+
return [fixer.replaceText(callee.property, "meta"), fixer.replaceText(describeArg, `{ description: ${context.sourceCode.getText(describeArg)} }`)];
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && getNamedImportOriginal(callee.name) === "describe") context.report({
|
|
38
|
+
node,
|
|
39
|
+
messageId: "preferMeta"
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
//#endregion
|
|
46
|
+
exports.preferMeta = preferMeta;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "@eslint-zod/utils";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
//#region src/rules/prefer-meta.ts
|
|
5
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
|
|
6
|
+
const preferMeta = createZodMiniPluginRule({
|
|
7
|
+
name: "prefer-meta",
|
|
8
|
+
meta: {
|
|
9
|
+
type: "suggestion",
|
|
10
|
+
fixable: "code",
|
|
11
|
+
docs: {
|
|
12
|
+
zodImportAllowedSource,
|
|
13
|
+
description: "Enforce usage of `z.meta()` over `z.describe()`"
|
|
14
|
+
},
|
|
15
|
+
messages: { preferMeta: "The `z.describe()` function still exists for compatibility with Zod 3, but `z.meta()` is now the recommended approach." },
|
|
16
|
+
schema: []
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
const { importDeclarationListener, isZodNamespace, getNamedImportOriginal } = trackZodSchemaImports();
|
|
21
|
+
return {
|
|
22
|
+
ImportDeclaration: importDeclarationListener,
|
|
23
|
+
CallExpression(node) {
|
|
24
|
+
const { callee } = node;
|
|
25
|
+
if (callee.type === AST_NODE_TYPES.MemberExpression && callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === "describe" && callee.object.type === AST_NODE_TYPES.Identifier && isZodNamespace(callee.object.name)) {
|
|
26
|
+
const [describeArg] = node.arguments;
|
|
27
|
+
context.report({
|
|
28
|
+
node,
|
|
29
|
+
messageId: "preferMeta",
|
|
30
|
+
fix(fixer) {
|
|
31
|
+
return [fixer.replaceText(callee.property, "meta"), fixer.replaceText(describeArg, `{ description: ${context.sourceCode.getText(describeArg)} }`)];
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (callee.type === AST_NODE_TYPES.Identifier && getNamedImportOriginal(callee.name) === "describe") context.report({
|
|
37
|
+
node,
|
|
38
|
+
messageId: "preferMeta"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
export { preferMeta };
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
let _eslint_zod_utils = require("@eslint-zod/utils");
|
|
4
|
+
let _typescript_eslint_utils = require("@typescript-eslint/utils");
|
|
5
|
+
//#region src/rules/prefer-namespace-import.ts
|
|
6
|
+
function isGroupFirstImportTypeNamespace(group) {
|
|
7
|
+
const { hasOnlyTypeImports, nodes: [firstImportNode] } = group;
|
|
8
|
+
const { specifiers } = firstImportNode;
|
|
9
|
+
if (specifiers.length === 1 && specifiers[0].type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier) if (hasOnlyTypeImports) {
|
|
10
|
+
if (firstImportNode.importKind === "type") return true;
|
|
11
|
+
} else return true;
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
function shouldIdentifierBeRenamed(node) {
|
|
15
|
+
if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier) return false;
|
|
16
|
+
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;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* From a given specifiers retrieve the most significant to use when creating an alias import
|
|
21
|
+
*/
|
|
22
|
+
function getNamespaceAliasNameFrom(node) {
|
|
23
|
+
if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportDefaultSpecifier || node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
|
|
24
|
+
if (node.imported.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const preferNamespaceImport = require_create_plugin_rule.createZodMiniPluginRule({
|
|
28
|
+
name: "prefer-namespace-import",
|
|
29
|
+
meta: {
|
|
30
|
+
type: "suggestion",
|
|
31
|
+
deprecated: { message: "Use `zod-mini/consistent-import` with `{ syntax: 'namespace' }`" },
|
|
32
|
+
docs: {
|
|
33
|
+
zodImportAllowedSource: "zod-mini",
|
|
34
|
+
description: "Enforce importing zod/mini as a namespace import (`import * as z from 'zod/mini'`)"
|
|
35
|
+
},
|
|
36
|
+
fixable: "code",
|
|
37
|
+
messages: {
|
|
38
|
+
useNamespace: "Import Zod Mini with a namespace import",
|
|
39
|
+
removeDuplicate: "Zod Mini is already imported via namespace import",
|
|
40
|
+
convertUsage: "Convert to namespace usage"
|
|
41
|
+
},
|
|
42
|
+
schema: []
|
|
43
|
+
},
|
|
44
|
+
defaultOptions: [],
|
|
45
|
+
create(context) {
|
|
46
|
+
const { sourceCode } = context;
|
|
47
|
+
const importGroups = {};
|
|
48
|
+
return {
|
|
49
|
+
ImportDeclaration(node) {
|
|
50
|
+
const { source, importKind } = node;
|
|
51
|
+
if (!(0, _eslint_zod_utils.isZodImportSource)(source.value, "zod-mini")) return;
|
|
52
|
+
if (!importGroups[source.value]) importGroups[source.value] = {
|
|
53
|
+
hasOnlyTypeImports: true,
|
|
54
|
+
nodes: []
|
|
55
|
+
};
|
|
56
|
+
if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
|
|
57
|
+
importGroups[source.value].nodes.push(node);
|
|
58
|
+
},
|
|
59
|
+
"Program:exit": function() {
|
|
60
|
+
let namespaceAliasNameIndex = 0;
|
|
61
|
+
for (const importGroup of Object.values(importGroups)) {
|
|
62
|
+
const { hasOnlyTypeImports, nodes } = importGroup;
|
|
63
|
+
const [firstImportNode, ...othersImportNodes] = nodes;
|
|
64
|
+
/**
|
|
65
|
+
* Variable to track all specifiers that later are used by {@link getDeclaredVariables}
|
|
66
|
+
* to add the namespace prefix
|
|
67
|
+
*/
|
|
68
|
+
const nodesWithVariablesToUpdate = [];
|
|
69
|
+
let namespaceAliasName = null;
|
|
70
|
+
for (const specifier of nodes.flatMap((it) => it.specifiers)) {
|
|
71
|
+
if (!namespaceAliasName) {
|
|
72
|
+
namespaceAliasName = getNamespaceAliasNameFrom(specifier);
|
|
73
|
+
if (namespaceAliasName) continue;
|
|
74
|
+
}
|
|
75
|
+
nodesWithVariablesToUpdate.push(specifier);
|
|
76
|
+
}
|
|
77
|
+
if (!namespaceAliasName) {
|
|
78
|
+
namespaceAliasName = "z";
|
|
79
|
+
if (namespaceAliasNameIndex > 0) {
|
|
80
|
+
namespaceAliasName = `z${namespaceAliasNameIndex}`;
|
|
81
|
+
namespaceAliasNameIndex += 1;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!isGroupFirstImportTypeNamespace(importGroup)) context.report({
|
|
85
|
+
node: firstImportNode,
|
|
86
|
+
messageId: "useNamespace",
|
|
87
|
+
fix(fixer) {
|
|
88
|
+
const newImportText = `import ${hasOnlyTypeImports ? "type " : ""}* as ${namespaceAliasName} from ${firstImportNode.source.raw};`;
|
|
89
|
+
return fixer.replaceText(firstImportNode, newImportText);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
|
|
93
|
+
for (const ref of allReferences) {
|
|
94
|
+
const { identifier } = ref;
|
|
95
|
+
if (shouldIdentifierBeRenamed(identifier)) context.report({
|
|
96
|
+
node: identifier,
|
|
97
|
+
messageId: "convertUsage",
|
|
98
|
+
fix(fixer) {
|
|
99
|
+
const newId = `${namespaceAliasName}.${identifier.name}`;
|
|
100
|
+
return fixer.replaceText(identifier, newId);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
for (const extraImport of othersImportNodes) context.report({
|
|
105
|
+
node: extraImport,
|
|
106
|
+
messageId: "removeDuplicate",
|
|
107
|
+
fix(fixer) {
|
|
108
|
+
return fixer.removeRange(extraImport.range);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
//#endregion
|
|
117
|
+
exports.preferNamespaceImport = preferNamespaceImport;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { isZodImportSource } from "@eslint-zod/utils";
|
|
3
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
4
|
+
//#region src/rules/prefer-namespace-import.ts
|
|
5
|
+
function isGroupFirstImportTypeNamespace(group) {
|
|
6
|
+
const { hasOnlyTypeImports, nodes: [firstImportNode] } = group;
|
|
7
|
+
const { specifiers } = firstImportNode;
|
|
8
|
+
if (specifiers.length === 1 && specifiers[0].type === AST_NODE_TYPES.ImportNamespaceSpecifier) if (hasOnlyTypeImports) {
|
|
9
|
+
if (firstImportNode.importKind === "type") return true;
|
|
10
|
+
} else return true;
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
function shouldIdentifierBeRenamed(node) {
|
|
14
|
+
if (node.parent.type === AST_NODE_TYPES.ImportSpecifier) return false;
|
|
15
|
+
if (node.parent.type === AST_NODE_TYPES.MemberExpression && node.parent.object.type === AST_NODE_TYPES.Identifier && node.parent.object.name !== node.name) return false;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* From a given specifiers retrieve the most significant to use when creating an alias import
|
|
20
|
+
*/
|
|
21
|
+
function getNamespaceAliasNameFrom(node) {
|
|
22
|
+
if (node.type === AST_NODE_TYPES.ImportDefaultSpecifier || node.type === AST_NODE_TYPES.ImportNamespaceSpecifier) return node.local.name;
|
|
23
|
+
if (node.imported.type === AST_NODE_TYPES.Identifier && node.imported.name === "z") return node.local.name;
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const preferNamespaceImport = createZodMiniPluginRule({
|
|
27
|
+
name: "prefer-namespace-import",
|
|
28
|
+
meta: {
|
|
29
|
+
type: "suggestion",
|
|
30
|
+
deprecated: { message: "Use `zod-mini/consistent-import` with `{ syntax: 'namespace' }`" },
|
|
31
|
+
docs: {
|
|
32
|
+
zodImportAllowedSource: "zod-mini",
|
|
33
|
+
description: "Enforce importing zod/mini as a namespace import (`import * as z from 'zod/mini'`)"
|
|
34
|
+
},
|
|
35
|
+
fixable: "code",
|
|
36
|
+
messages: {
|
|
37
|
+
useNamespace: "Import Zod Mini with a namespace import",
|
|
38
|
+
removeDuplicate: "Zod Mini is already imported via namespace import",
|
|
39
|
+
convertUsage: "Convert to namespace usage"
|
|
40
|
+
},
|
|
41
|
+
schema: []
|
|
42
|
+
},
|
|
43
|
+
defaultOptions: [],
|
|
44
|
+
create(context) {
|
|
45
|
+
const { sourceCode } = context;
|
|
46
|
+
const importGroups = {};
|
|
47
|
+
return {
|
|
48
|
+
ImportDeclaration(node) {
|
|
49
|
+
const { source, importKind } = node;
|
|
50
|
+
if (!isZodImportSource(source.value, "zod-mini")) return;
|
|
51
|
+
if (!importGroups[source.value]) importGroups[source.value] = {
|
|
52
|
+
hasOnlyTypeImports: true,
|
|
53
|
+
nodes: []
|
|
54
|
+
};
|
|
55
|
+
if (importGroups[source.value].hasOnlyTypeImports && importKind === "value") importGroups[source.value].hasOnlyTypeImports = false;
|
|
56
|
+
importGroups[source.value].nodes.push(node);
|
|
57
|
+
},
|
|
58
|
+
"Program:exit": function() {
|
|
59
|
+
let namespaceAliasNameIndex = 0;
|
|
60
|
+
for (const importGroup of Object.values(importGroups)) {
|
|
61
|
+
const { hasOnlyTypeImports, nodes } = importGroup;
|
|
62
|
+
const [firstImportNode, ...othersImportNodes] = nodes;
|
|
63
|
+
/**
|
|
64
|
+
* Variable to track all specifiers that later are used by {@link getDeclaredVariables}
|
|
65
|
+
* to add the namespace prefix
|
|
66
|
+
*/
|
|
67
|
+
const nodesWithVariablesToUpdate = [];
|
|
68
|
+
let namespaceAliasName = null;
|
|
69
|
+
for (const specifier of nodes.flatMap((it) => it.specifiers)) {
|
|
70
|
+
if (!namespaceAliasName) {
|
|
71
|
+
namespaceAliasName = getNamespaceAliasNameFrom(specifier);
|
|
72
|
+
if (namespaceAliasName) continue;
|
|
73
|
+
}
|
|
74
|
+
nodesWithVariablesToUpdate.push(specifier);
|
|
75
|
+
}
|
|
76
|
+
if (!namespaceAliasName) {
|
|
77
|
+
namespaceAliasName = "z";
|
|
78
|
+
if (namespaceAliasNameIndex > 0) {
|
|
79
|
+
namespaceAliasName = `z${namespaceAliasNameIndex}`;
|
|
80
|
+
namespaceAliasNameIndex += 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!isGroupFirstImportTypeNamespace(importGroup)) context.report({
|
|
84
|
+
node: firstImportNode,
|
|
85
|
+
messageId: "useNamespace",
|
|
86
|
+
fix(fixer) {
|
|
87
|
+
const newImportText = `import ${hasOnlyTypeImports ? "type " : ""}* as ${namespaceAliasName} from ${firstImportNode.source.raw};`;
|
|
88
|
+
return fixer.replaceText(firstImportNode, newImportText);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const allReferences = nodesWithVariablesToUpdate.flatMap((it) => sourceCode.getDeclaredVariables(it)).flatMap((it) => it.references);
|
|
92
|
+
for (const ref of allReferences) {
|
|
93
|
+
const { identifier } = ref;
|
|
94
|
+
if (shouldIdentifierBeRenamed(identifier)) context.report({
|
|
95
|
+
node: identifier,
|
|
96
|
+
messageId: "convertUsage",
|
|
97
|
+
fix(fixer) {
|
|
98
|
+
const newId = `${namespaceAliasName}.${identifier.name}`;
|
|
99
|
+
return fixer.replaceText(identifier, newId);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
for (const extraImport of othersImportNodes) context.report({
|
|
104
|
+
node: extraImport,
|
|
105
|
+
messageId: "removeDuplicate",
|
|
106
|
+
fix(fixer) {
|
|
107
|
+
return fixer.removeRange(extraImport.range);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
//#endregion
|
|
116
|
+
export { preferNamespaceImport };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_create_plugin_rule = require("../utils/create-plugin-rule.cjs");
|
|
3
|
+
//#region src/rules/require-brand-type-parameter.ts
|
|
4
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = (0, require("@eslint-zod/utils").createZodSchemaImportTrack)("zod-mini");
|
|
5
|
+
const requireBrandTypeParameter = require_create_plugin_rule.createZodMiniPluginRule({
|
|
6
|
+
name: "require-brand-type-parameter",
|
|
7
|
+
meta: {
|
|
8
|
+
hasSuggestions: true,
|
|
9
|
+
type: "problem",
|
|
10
|
+
docs: {
|
|
11
|
+
zodImportAllowedSource,
|
|
12
|
+
description: "Require type parameter on `.brand()` functions"
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
missingTypeParameter: "Type parameter is required when using `.brand()`",
|
|
16
|
+
removeBrandFunction: "Brand is a static-only construct. If not parameter is required consider removal"
|
|
17
|
+
},
|
|
18
|
+
schema: []
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
23
|
+
return {
|
|
24
|
+
ImportDeclaration: importDeclarationListener,
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
27
|
+
if (!zodSchemaMeta) return;
|
|
28
|
+
const brandMethod = collectZodChainMethods(zodSchemaMeta.node).find((it) => it.name === "brand");
|
|
29
|
+
if (!brandMethod) return;
|
|
30
|
+
const brandNode = brandMethod.node;
|
|
31
|
+
const { typeArguments } = brandNode;
|
|
32
|
+
if (typeArguments && typeArguments.params.length > 0) return;
|
|
33
|
+
const brandCalleeNode = brandNode.callee;
|
|
34
|
+
context.report({
|
|
35
|
+
messageId: "missingTypeParameter",
|
|
36
|
+
node: brandCalleeNode.property,
|
|
37
|
+
suggest: [{
|
|
38
|
+
messageId: "removeBrandFunction",
|
|
39
|
+
fix(fixer) {
|
|
40
|
+
return fixer.removeRange([brandCalleeNode.object.range[1], brandNode.range[1]]);
|
|
41
|
+
}
|
|
42
|
+
}]
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
//#endregion
|
|
49
|
+
exports.requireBrandTypeParameter = requireBrandTypeParameter;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createZodMiniPluginRule } from "../utils/create-plugin-rule.mjs";
|
|
2
|
+
import { createZodSchemaImportTrack } from "@eslint-zod/utils";
|
|
3
|
+
//#region src/rules/require-brand-type-parameter.ts
|
|
4
|
+
const { zodImportAllowedSource, trackZodSchemaImports } = createZodSchemaImportTrack("zod-mini");
|
|
5
|
+
const requireBrandTypeParameter = createZodMiniPluginRule({
|
|
6
|
+
name: "require-brand-type-parameter",
|
|
7
|
+
meta: {
|
|
8
|
+
hasSuggestions: true,
|
|
9
|
+
type: "problem",
|
|
10
|
+
docs: {
|
|
11
|
+
zodImportAllowedSource,
|
|
12
|
+
description: "Require type parameter on `.brand()` functions"
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
missingTypeParameter: "Type parameter is required when using `.brand()`",
|
|
16
|
+
removeBrandFunction: "Brand is a static-only construct. If not parameter is required consider removal"
|
|
17
|
+
},
|
|
18
|
+
schema: []
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
const { importDeclarationListener, detectZodSchemaRootNode, collectZodChainMethods } = trackZodSchemaImports();
|
|
23
|
+
return {
|
|
24
|
+
ImportDeclaration: importDeclarationListener,
|
|
25
|
+
CallExpression(node) {
|
|
26
|
+
const zodSchemaMeta = detectZodSchemaRootNode(node);
|
|
27
|
+
if (!zodSchemaMeta) return;
|
|
28
|
+
const brandMethod = collectZodChainMethods(zodSchemaMeta.node).find((it) => it.name === "brand");
|
|
29
|
+
if (!brandMethod) return;
|
|
30
|
+
const brandNode = brandMethod.node;
|
|
31
|
+
const { typeArguments } = brandNode;
|
|
32
|
+
if (typeArguments && typeArguments.params.length > 0) return;
|
|
33
|
+
const brandCalleeNode = brandNode.callee;
|
|
34
|
+
context.report({
|
|
35
|
+
messageId: "missingTypeParameter",
|
|
36
|
+
node: brandCalleeNode.property,
|
|
37
|
+
suggest: [{
|
|
38
|
+
messageId: "removeBrandFunction",
|
|
39
|
+
fix(fixer) {
|
|
40
|
+
return fixer.removeRange([brandCalleeNode.object.range[1], brandNode.range[1]]);
|
|
41
|
+
}
|
|
42
|
+
}]
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
//#endregion
|
|
49
|
+
export { requireBrandTypeParameter };
|