@sarj/eslint-plugin 15.17.1 → 15.17.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/index.cjs +420 -115
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +459 -148
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -12048,99 +12048,367 @@ var prefer_module_level_schema_default = createRule({
|
|
|
12048
12048
|
|
|
12049
12049
|
// src/rules/prefer-module-level-refined-schema.ts
|
|
12050
12050
|
var import_utils69 = require("@typescript-eslint/utils");
|
|
12051
|
+
var BENCHMARK_PATH_RE = /(^|[/\\])(?:benchmarks?|bench)[/\\]/;
|
|
12051
12052
|
var FACTORIES = /* @__PURE__ */ new Set([
|
|
12052
12053
|
"array",
|
|
12054
|
+
"base64",
|
|
12055
|
+
"base64url",
|
|
12053
12056
|
"bigint",
|
|
12054
12057
|
"boolean",
|
|
12058
|
+
"cidrv4",
|
|
12059
|
+
"cidrv6",
|
|
12060
|
+
"codec",
|
|
12061
|
+
"custom",
|
|
12055
12062
|
"date",
|
|
12056
|
-
"
|
|
12057
|
-
"
|
|
12058
|
-
]);
|
|
12059
|
-
var REFINEMENTS = /* @__PURE__ */ new Set([
|
|
12060
|
-
"brand",
|
|
12061
|
-
"check",
|
|
12063
|
+
"datetime",
|
|
12064
|
+
"duration",
|
|
12062
12065
|
"email",
|
|
12063
|
-
"
|
|
12064
|
-
"
|
|
12065
|
-
"
|
|
12066
|
-
"
|
|
12067
|
-
"
|
|
12068
|
-
"
|
|
12069
|
-
"
|
|
12070
|
-
"
|
|
12071
|
-
"
|
|
12072
|
-
"
|
|
12073
|
-
"
|
|
12074
|
-
"
|
|
12075
|
-
"
|
|
12076
|
-
"
|
|
12066
|
+
"emoji",
|
|
12067
|
+
"enum",
|
|
12068
|
+
"file",
|
|
12069
|
+
"function",
|
|
12070
|
+
"hash",
|
|
12071
|
+
"hex",
|
|
12072
|
+
"hostname",
|
|
12073
|
+
"instanceof",
|
|
12074
|
+
"ipv4",
|
|
12075
|
+
"ipv6",
|
|
12076
|
+
"json",
|
|
12077
|
+
"jwt",
|
|
12078
|
+
"literal",
|
|
12079
|
+
"map",
|
|
12080
|
+
"nan",
|
|
12081
|
+
"nativeEnum",
|
|
12082
|
+
"never",
|
|
12083
|
+
"null",
|
|
12084
|
+
"nullable",
|
|
12085
|
+
"nullish",
|
|
12086
|
+
"number",
|
|
12087
|
+
"optional",
|
|
12088
|
+
"partialRecord",
|
|
12089
|
+
"preprocess",
|
|
12090
|
+
"promise",
|
|
12091
|
+
"set",
|
|
12092
|
+
"string",
|
|
12093
|
+
"stringbool",
|
|
12094
|
+
"symbol",
|
|
12095
|
+
"templateLiteral",
|
|
12096
|
+
"time",
|
|
12097
|
+
"undefined",
|
|
12077
12098
|
"url",
|
|
12078
|
-
"uuid"
|
|
12099
|
+
"uuid",
|
|
12100
|
+
"void"
|
|
12101
|
+
]);
|
|
12102
|
+
var COMPOSITE_FACTORIES = /* @__PURE__ */ new Set([
|
|
12103
|
+
"discriminatedUnion",
|
|
12104
|
+
"intersection",
|
|
12105
|
+
"looseObject",
|
|
12106
|
+
"object",
|
|
12107
|
+
"record",
|
|
12108
|
+
"strictObject",
|
|
12109
|
+
"tuple",
|
|
12110
|
+
"union"
|
|
12111
|
+
]);
|
|
12112
|
+
var FACTORY_NAMESPACES = /* @__PURE__ */ new Set(["coerce", "iso"]);
|
|
12113
|
+
var NON_SCHEMA_TERMINALS = /* @__PURE__ */ new Set([
|
|
12114
|
+
"decode",
|
|
12115
|
+
"decodeAsync",
|
|
12116
|
+
"encode",
|
|
12117
|
+
"encodeAsync",
|
|
12118
|
+
"flattenError",
|
|
12119
|
+
"formatError",
|
|
12120
|
+
"implement",
|
|
12121
|
+
"isNullable",
|
|
12122
|
+
"isOptional",
|
|
12123
|
+
"parse",
|
|
12124
|
+
"parseAsync",
|
|
12125
|
+
"prettifyError",
|
|
12126
|
+
"registry",
|
|
12127
|
+
"safeDecode",
|
|
12128
|
+
"safeDecodeAsync",
|
|
12129
|
+
"safeEncode",
|
|
12130
|
+
"safeEncodeAsync",
|
|
12131
|
+
"safeParse",
|
|
12132
|
+
"safeParseAsync",
|
|
12133
|
+
"spa",
|
|
12134
|
+
"toJSONSchema",
|
|
12135
|
+
"treeifyError"
|
|
12136
|
+
]);
|
|
12137
|
+
var MEMO_CALLEES2 = /* @__PURE__ */ new Set([
|
|
12138
|
+
"lazy",
|
|
12139
|
+
"memo",
|
|
12140
|
+
"once",
|
|
12141
|
+
"useMemo"
|
|
12142
|
+
]);
|
|
12143
|
+
var I18N_CALLEE_NAMES2 = /* @__PURE__ */ new Set([
|
|
12144
|
+
"$t",
|
|
12145
|
+
"defineMessage",
|
|
12146
|
+
"gettext",
|
|
12147
|
+
"msg",
|
|
12148
|
+
"ngettext",
|
|
12149
|
+
"t",
|
|
12150
|
+
"translate"
|
|
12151
|
+
]);
|
|
12152
|
+
var I18N_RECEIVER_NAMES2 = /* @__PURE__ */ new Set([
|
|
12153
|
+
"$i18n",
|
|
12154
|
+
"i18n",
|
|
12155
|
+
"intl"
|
|
12156
|
+
]);
|
|
12157
|
+
var FUNCTION_TYPES9 = /* @__PURE__ */ new Set([
|
|
12158
|
+
import_utils69.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
12159
|
+
import_utils69.AST_NODE_TYPES.FunctionDeclaration,
|
|
12160
|
+
import_utils69.AST_NODE_TYPES.FunctionExpression
|
|
12079
12161
|
]);
|
|
12080
12162
|
var PREFER_MODULE_LEVEL_REFINED_SCHEMA_DOCUMENTATION = {
|
|
12081
|
-
summary: "Declare closed
|
|
12163
|
+
summary: "Declare closed Zod scalar, format, and wrapper schemas at module scope.",
|
|
12082
12164
|
rationale: "A closed validation pipeline created inside a function is rebuilt on every invocation and obscures a reusable constraint.",
|
|
12083
|
-
remediation: "Move the validation schema to module scope and call parse on the shared schema.",
|
|
12165
|
+
remediation: "Move the validation schema to module scope, name it with a PascalCase Schema suffix, and call parse on the shared schema.",
|
|
12084
12166
|
category: "performance",
|
|
12085
|
-
limitations: [
|
|
12167
|
+
limitations: [
|
|
12168
|
+
"Composite object/record/tuple/union schemas are owned by prefer-module-level-schema.",
|
|
12169
|
+
"Schemas that depend on function-local or mutable state, localized text, receiver state, lazy construction, or recognized memoization are excluded.",
|
|
12170
|
+
"Literal string z.enum domains are owned by prefer-shared-zod-enum."
|
|
12171
|
+
],
|
|
12086
12172
|
examples: [
|
|
12087
|
-
{
|
|
12088
|
-
|
|
12173
|
+
{
|
|
12174
|
+
id: "module-refinement",
|
|
12175
|
+
title: "Share the validation schema",
|
|
12176
|
+
outcome: "no-match",
|
|
12177
|
+
files: [{
|
|
12178
|
+
path: "src/options.ts",
|
|
12179
|
+
source: "import { z } from 'zod'; const BatchSizeSchema = z.number().int().min(1).max(1000); export function parse(value: unknown) { return BatchSizeSchema.parse(value); }"
|
|
12180
|
+
}],
|
|
12181
|
+
focusPath: "src/options.ts",
|
|
12182
|
+
expectedCount: 0,
|
|
12183
|
+
public: true
|
|
12184
|
+
},
|
|
12185
|
+
{
|
|
12186
|
+
id: "local-refinement",
|
|
12187
|
+
title: "Do not rebuild a closed validation chain",
|
|
12188
|
+
outcome: "match",
|
|
12189
|
+
files: [{
|
|
12190
|
+
path: "src/options.ts",
|
|
12191
|
+
source: "import { z } from 'zod'; export function parse(value: unknown) { return z.string().trim().min(1).max(128).parse(value); }"
|
|
12192
|
+
}],
|
|
12193
|
+
focusPath: "src/options.ts",
|
|
12194
|
+
expectedCount: 1,
|
|
12195
|
+
public: true
|
|
12196
|
+
}
|
|
12089
12197
|
]
|
|
12090
12198
|
};
|
|
12091
|
-
function
|
|
12199
|
+
function outermostEnclosingFunction2(node) {
|
|
12200
|
+
let outermost;
|
|
12092
12201
|
let current = node.parent ?? void 0;
|
|
12093
12202
|
while (current !== void 0) {
|
|
12094
|
-
if (
|
|
12203
|
+
if (FUNCTION_TYPES9.has(current.type)) outermost = current;
|
|
12095
12204
|
current = current.parent ?? void 0;
|
|
12096
12205
|
}
|
|
12097
|
-
return
|
|
12206
|
+
return outermost;
|
|
12098
12207
|
}
|
|
12099
12208
|
function collectReferences2(scope, output) {
|
|
12100
12209
|
output.push(...scope.references);
|
|
12101
12210
|
for (const child of scope.childScopes) collectReferences2(child, output);
|
|
12102
12211
|
}
|
|
12212
|
+
function subtreeSome2(root, predicate) {
|
|
12213
|
+
let found = false;
|
|
12214
|
+
const visit = (value) => {
|
|
12215
|
+
if (found || value === null || typeof value !== "object") return;
|
|
12216
|
+
if (Array.isArray(value)) {
|
|
12217
|
+
for (const item of value) visit(item);
|
|
12218
|
+
return;
|
|
12219
|
+
}
|
|
12220
|
+
const candidate2 = value;
|
|
12221
|
+
if (typeof candidate2.type !== "string") return;
|
|
12222
|
+
if (predicate(candidate2)) {
|
|
12223
|
+
found = true;
|
|
12224
|
+
return;
|
|
12225
|
+
}
|
|
12226
|
+
for (const key of Object.keys(candidate2)) {
|
|
12227
|
+
if (key === "parent" || key === "loc" || key === "range") continue;
|
|
12228
|
+
visit(candidate2[key]);
|
|
12229
|
+
}
|
|
12230
|
+
};
|
|
12231
|
+
visit(root);
|
|
12232
|
+
return found;
|
|
12233
|
+
}
|
|
12234
|
+
function readsReceiver2(node) {
|
|
12235
|
+
return subtreeSome2(
|
|
12236
|
+
node,
|
|
12237
|
+
(inner) => inner.type === import_utils69.AST_NODE_TYPES.ThisExpression || inner.type === import_utils69.AST_NODE_TYPES.Super || inner.type === import_utils69.AST_NODE_TYPES.Identifier && inner.name === "arguments"
|
|
12238
|
+
);
|
|
12239
|
+
}
|
|
12240
|
+
function buildsLocalizedText2(node) {
|
|
12241
|
+
return subtreeSome2(node, (inner) => {
|
|
12242
|
+
if (inner.type === import_utils69.AST_NODE_TYPES.TaggedTemplateExpression) return true;
|
|
12243
|
+
if (inner.type !== import_utils69.AST_NODE_TYPES.CallExpression) return false;
|
|
12244
|
+
const { callee } = inner;
|
|
12245
|
+
if (callee.type === import_utils69.AST_NODE_TYPES.Identifier)
|
|
12246
|
+
return I18N_CALLEE_NAMES2.has(callee.name);
|
|
12247
|
+
return callee.type === import_utils69.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.object.type === import_utils69.AST_NODE_TYPES.Identifier && I18N_RECEIVER_NAMES2.has(callee.object.name);
|
|
12248
|
+
});
|
|
12249
|
+
}
|
|
12250
|
+
function calleeChainRoot(node) {
|
|
12251
|
+
let current = node;
|
|
12252
|
+
for (; ; ) {
|
|
12253
|
+
if (current.type === import_utils69.AST_NODE_TYPES.Identifier) return current;
|
|
12254
|
+
if (current.type === import_utils69.AST_NODE_TYPES.MemberExpression) {
|
|
12255
|
+
current = current.object;
|
|
12256
|
+
continue;
|
|
12257
|
+
}
|
|
12258
|
+
if (current.type === import_utils69.AST_NODE_TYPES.CallExpression) {
|
|
12259
|
+
current = current.callee;
|
|
12260
|
+
continue;
|
|
12261
|
+
}
|
|
12262
|
+
return null;
|
|
12263
|
+
}
|
|
12264
|
+
}
|
|
12265
|
+
function chainMemberNames(node) {
|
|
12266
|
+
const names = [];
|
|
12267
|
+
let current = node;
|
|
12268
|
+
for (; ; ) {
|
|
12269
|
+
if (current.type === import_utils69.AST_NODE_TYPES.MemberExpression) {
|
|
12270
|
+
if (current.computed || current.property.type !== import_utils69.AST_NODE_TYPES.Identifier)
|
|
12271
|
+
return [];
|
|
12272
|
+
names.push(current.property.name);
|
|
12273
|
+
current = current.object;
|
|
12274
|
+
continue;
|
|
12275
|
+
}
|
|
12276
|
+
if (current.type === import_utils69.AST_NODE_TYPES.CallExpression) {
|
|
12277
|
+
current = current.callee;
|
|
12278
|
+
continue;
|
|
12279
|
+
}
|
|
12280
|
+
break;
|
|
12281
|
+
}
|
|
12282
|
+
names.reverse();
|
|
12283
|
+
return names;
|
|
12284
|
+
}
|
|
12285
|
+
function schemaExpression2(node) {
|
|
12286
|
+
let current = node;
|
|
12287
|
+
for (; ; ) {
|
|
12288
|
+
const parent = current.parent ?? void 0;
|
|
12289
|
+
if (parent?.type === import_utils69.AST_NODE_TYPES.MemberExpression && parent.object === current && !parent.computed && parent.property.type === import_utils69.AST_NODE_TYPES.Identifier && parent.parent?.type === import_utils69.AST_NODE_TYPES.CallExpression && parent.parent.callee === parent) {
|
|
12290
|
+
if (NON_SCHEMA_TERMINALS.has(parent.property.name)) return current;
|
|
12291
|
+
current = parent.parent;
|
|
12292
|
+
continue;
|
|
12293
|
+
}
|
|
12294
|
+
if (parent?.type === import_utils69.AST_NODE_TYPES.TSAsExpression || parent?.type === import_utils69.AST_NODE_TYPES.TSNonNullExpression || parent?.type === import_utils69.AST_NODE_TYPES.TSSatisfiesExpression || parent?.type === import_utils69.AST_NODE_TYPES.TSTypeAssertion) {
|
|
12295
|
+
current = parent;
|
|
12296
|
+
continue;
|
|
12297
|
+
}
|
|
12298
|
+
return current;
|
|
12299
|
+
}
|
|
12300
|
+
}
|
|
12103
12301
|
var prefer_module_level_refined_schema_default = createRule({
|
|
12104
12302
|
name: "prefer-module-level-refined-schema",
|
|
12105
12303
|
documentation: PREFER_MODULE_LEVEL_REFINED_SCHEMA_DOCUMENTATION,
|
|
12106
|
-
meta: {
|
|
12304
|
+
meta: {
|
|
12305
|
+
type: "suggestion",
|
|
12306
|
+
docs: {
|
|
12307
|
+
description: "Declare closed Zod scalar, format, and wrapper schemas at module scope."
|
|
12308
|
+
},
|
|
12309
|
+
schema: [],
|
|
12310
|
+
messages: {
|
|
12311
|
+
hoistRefinedSchema: "Move this closed Zod schema to module scope, give it a PascalCase Schema name, and reuse it for parsing."
|
|
12312
|
+
}
|
|
12313
|
+
},
|
|
12107
12314
|
defaultOptions: [],
|
|
12108
12315
|
create(context) {
|
|
12109
|
-
if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text))
|
|
12110
|
-
|
|
12316
|
+
if (isTestFile(context.filename) || BENCHMARK_PATH_RE.test(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text))
|
|
12317
|
+
return {};
|
|
12318
|
+
const zodBindings = /* @__PURE__ */ new Set();
|
|
12319
|
+
function resolvedBinding(identifier) {
|
|
12320
|
+
return import_utils69.ASTUtils.findVariable(
|
|
12321
|
+
context.sourceCode.getScope(identifier),
|
|
12322
|
+
identifier.name
|
|
12323
|
+
);
|
|
12324
|
+
}
|
|
12325
|
+
function recordZodBinding(identifier) {
|
|
12326
|
+
const binding = resolvedBinding(identifier);
|
|
12327
|
+
if (binding !== null) zodBindings.add(binding);
|
|
12328
|
+
}
|
|
12329
|
+
function factoryName(node, allowed) {
|
|
12330
|
+
if (node.callee.type !== import_utils69.AST_NODE_TYPES.MemberExpression) return null;
|
|
12331
|
+
const root = calleeChainRoot(node.callee);
|
|
12332
|
+
if (root === null) return null;
|
|
12333
|
+
const binding = resolvedBinding(root);
|
|
12334
|
+
if (binding === null || !zodBindings.has(binding)) return null;
|
|
12335
|
+
const names = chainMemberNames(node.callee);
|
|
12336
|
+
if (names.length === 1 && allowed.has(names[0] ?? ""))
|
|
12337
|
+
return names[0] ?? null;
|
|
12338
|
+
if (names.length === 2 && FACTORY_NAMESPACES.has(names[0] ?? "") && allowed.has(names[1] ?? ""))
|
|
12339
|
+
return names[1] ?? null;
|
|
12340
|
+
return null;
|
|
12341
|
+
}
|
|
12342
|
+
function isSharedEnumDomain(node, factory) {
|
|
12343
|
+
if (factory !== "enum") return false;
|
|
12344
|
+
const [argument] = node.arguments;
|
|
12345
|
+
return argument?.type === import_utils69.AST_NODE_TYPES.ArrayExpression && argument.elements.length >= 2 && argument.elements.every(
|
|
12346
|
+
(element) => element?.type === import_utils69.AST_NODE_TYPES.Literal && typeof element.value === "string"
|
|
12347
|
+
);
|
|
12348
|
+
}
|
|
12349
|
+
function isNestedInOwnedFactory(node) {
|
|
12350
|
+
let current = node;
|
|
12351
|
+
while (current.parent != null) {
|
|
12352
|
+
current = current.parent;
|
|
12353
|
+
if (FUNCTION_TYPES9.has(current.type)) return false;
|
|
12354
|
+
if (current.type === import_utils69.AST_NODE_TYPES.CallExpression && (factoryName(current, FACTORIES) !== null || factoryName(current, COMPOSITE_FACTORIES) !== null))
|
|
12355
|
+
return true;
|
|
12356
|
+
}
|
|
12357
|
+
return false;
|
|
12358
|
+
}
|
|
12359
|
+
function isMemoized(node) {
|
|
12360
|
+
let current = node.parent ?? void 0;
|
|
12361
|
+
while (current !== void 0) {
|
|
12362
|
+
if (current.type === import_utils69.AST_NODE_TYPES.CallExpression && (current.callee.type === import_utils69.AST_NODE_TYPES.Identifier && MEMO_CALLEES2.has(current.callee.name) || current.callee.type === import_utils69.AST_NODE_TYPES.MemberExpression && !current.callee.computed && current.callee.property.type === import_utils69.AST_NODE_TYPES.Identifier && MEMO_CALLEES2.has(current.callee.property.name)))
|
|
12363
|
+
return true;
|
|
12364
|
+
current = current.parent ?? void 0;
|
|
12365
|
+
}
|
|
12366
|
+
return false;
|
|
12367
|
+
}
|
|
12368
|
+
function closesOverNothing(node, enclosing) {
|
|
12369
|
+
const references = [];
|
|
12370
|
+
collectReferences2(context.sourceCode.getScope(node), references);
|
|
12371
|
+
const [start, end] = node.range;
|
|
12372
|
+
const [functionStart, functionEnd] = enclosing.range;
|
|
12373
|
+
for (const reference of references) {
|
|
12374
|
+
const [referenceStart] = reference.identifier.range;
|
|
12375
|
+
if (referenceStart < start || referenceStart >= end) continue;
|
|
12376
|
+
const resolved = reference.resolved;
|
|
12377
|
+
if (resolved === null) continue;
|
|
12378
|
+
for (const definition of resolved.defs) {
|
|
12379
|
+
if (definition.type === "ImportBinding") {
|
|
12380
|
+
const parent = reference.identifier.parent;
|
|
12381
|
+
if (parent?.type === import_utils69.AST_NODE_TYPES.CallExpression && parent.callee === reference.identifier && !zodBindings.has(resolved))
|
|
12382
|
+
return false;
|
|
12383
|
+
continue;
|
|
12384
|
+
}
|
|
12385
|
+
if (definition.node.type === import_utils69.AST_NODE_TYPES.VariableDeclarator && definition.node.parent.type === import_utils69.AST_NODE_TYPES.VariableDeclaration && definition.node.parent.kind !== "const")
|
|
12386
|
+
return false;
|
|
12387
|
+
const [definitionStart, definitionEnd] = definition.node.range;
|
|
12388
|
+
if (definitionStart >= start && definitionEnd <= end) continue;
|
|
12389
|
+
if (definitionStart >= functionStart && definitionEnd <= functionEnd)
|
|
12390
|
+
return false;
|
|
12391
|
+
}
|
|
12392
|
+
}
|
|
12393
|
+
return true;
|
|
12394
|
+
}
|
|
12111
12395
|
return {
|
|
12112
12396
|
ImportDeclaration(node) {
|
|
12113
12397
|
if (!isZodModule(node.source.value)) return;
|
|
12114
|
-
for (const specifier of node.specifiers)
|
|
12398
|
+
for (const specifier of node.specifiers) {
|
|
12399
|
+
if (specifier.type === import_utils69.AST_NODE_TYPES.ImportDefaultSpecifier || specifier.type === import_utils69.AST_NODE_TYPES.ImportNamespaceSpecifier || specifier.type === import_utils69.AST_NODE_TYPES.ImportSpecifier && (specifier.imported.type === import_utils69.AST_NODE_TYPES.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z"))
|
|
12400
|
+
recordZodBinding(specifier.local);
|
|
12401
|
+
}
|
|
12115
12402
|
},
|
|
12116
12403
|
CallExpression(node) {
|
|
12117
|
-
const
|
|
12118
|
-
if (
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
if (REFINEMENTS.has(current.parent.property.name)) refinements += 1;
|
|
12126
|
-
current = call;
|
|
12127
|
-
}
|
|
12128
|
-
if (refinements < 2) return;
|
|
12129
|
-
const references = [];
|
|
12130
|
-
collectReferences2(context.sourceCode.getScope(current), references);
|
|
12131
|
-
const [start, end] = current.range;
|
|
12132
|
-
const [functionStart, functionEnd] = enclosing.range;
|
|
12133
|
-
for (const reference of references) {
|
|
12134
|
-
const [referenceStart] = reference.identifier.range;
|
|
12135
|
-
if (referenceStart < start || referenceStart >= end || reference.resolved === null) continue;
|
|
12136
|
-
for (const definition of reference.resolved.defs) {
|
|
12137
|
-
if (definition.type === "ImportBinding") continue;
|
|
12138
|
-
if (definition.node.type === import_utils69.AST_NODE_TYPES.VariableDeclarator && definition.node.parent.type === import_utils69.AST_NODE_TYPES.VariableDeclaration && definition.node.parent.kind !== "const") return;
|
|
12139
|
-
const [definitionStart, definitionEnd] = definition.node.range;
|
|
12140
|
-
if (definitionStart >= start && definitionEnd <= end) continue;
|
|
12141
|
-
if (definitionStart >= functionStart && definitionEnd <= functionEnd) return;
|
|
12142
|
-
}
|
|
12143
|
-
}
|
|
12404
|
+
const factory = factoryName(node, FACTORIES);
|
|
12405
|
+
if (factory === null || isSharedEnumDomain(node, factory) || isNestedInOwnedFactory(node) || isMemoized(node))
|
|
12406
|
+
return;
|
|
12407
|
+
const enclosing = outermostEnclosingFunction2(node);
|
|
12408
|
+
if (enclosing === void 0) return;
|
|
12409
|
+
const expression = schemaExpression2(node);
|
|
12410
|
+
if (readsReceiver2(expression) || buildsLocalizedText2(expression) || !closesOverNothing(expression, enclosing))
|
|
12411
|
+
return;
|
|
12144
12412
|
context.report({ node, messageId: "hoistRefinedSchema" });
|
|
12145
12413
|
}
|
|
12146
12414
|
};
|
|
@@ -12154,20 +12422,21 @@ var PREFER_MULTI_VALUE_ZOD_LITERAL_DOCUMENTATION = {
|
|
|
12154
12422
|
rationale: "One multi-value literal expresses the same closed value domain without repeated schema wrappers.",
|
|
12155
12423
|
remediation: "Replace the union with z.literal([value1, value2, ...]).",
|
|
12156
12424
|
category: "maintainability",
|
|
12425
|
+
autofix: "safe",
|
|
12157
12426
|
limitations: [
|
|
12158
|
-
"Bare
|
|
12427
|
+
"Bare zod imports are analyzed only when the rule option explicitly declares zodMajorVersion: 4; explicit zod/v4 entrypoints are self-declaring.",
|
|
12428
|
+
"All-string domains are left to zod/prefer-enum-over-literal-union.",
|
|
12429
|
+
"A finding containing comments is not autofixed because moving its trivia is ambiguous."
|
|
12159
12430
|
],
|
|
12160
12431
|
examples: [
|
|
12161
12432
|
{
|
|
12162
12433
|
id: "multi-value",
|
|
12163
12434
|
title: "Use one multi-value literal",
|
|
12164
12435
|
outcome: "no-match",
|
|
12165
|
-
files: [
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
}
|
|
12170
|
-
],
|
|
12436
|
+
files: [{
|
|
12437
|
+
path: "src/schema.ts",
|
|
12438
|
+
source: "import { z } from 'zod'; export const Version = z.literal([1, 2, 3]);"
|
|
12439
|
+
}],
|
|
12171
12440
|
focusPath: "src/schema.ts",
|
|
12172
12441
|
expectedCount: 0,
|
|
12173
12442
|
public: true
|
|
@@ -12176,80 +12445,116 @@ var PREFER_MULTI_VALUE_ZOD_LITERAL_DOCUMENTATION = {
|
|
|
12176
12445
|
id: "literal-union",
|
|
12177
12446
|
title: "Avoid repeated literal wrappers",
|
|
12178
12447
|
outcome: "match",
|
|
12179
|
-
files: [
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12448
|
+
files: [{
|
|
12449
|
+
path: "src/schema.ts",
|
|
12450
|
+
source: "import { z } from 'zod'; export const Version = z.union([z.literal(1), z.literal(2), z.literal(3)]);"
|
|
12451
|
+
}],
|
|
12452
|
+
fixedFiles: [{
|
|
12453
|
+
path: "src/schema.ts",
|
|
12454
|
+
source: "import { z } from 'zod'; export const Version = z.literal([1, 2, 3]);"
|
|
12455
|
+
}],
|
|
12185
12456
|
focusPath: "src/schema.ts",
|
|
12186
12457
|
expectedCount: 1,
|
|
12187
12458
|
public: true
|
|
12188
12459
|
}
|
|
12189
12460
|
]
|
|
12190
12461
|
};
|
|
12191
|
-
function
|
|
12192
|
-
|
|
12462
|
+
function isStaticPrimitive(node, context) {
|
|
12463
|
+
if (node.type === import_utils70.AST_NODE_TYPES.Literal) {
|
|
12464
|
+
return node.value === null || ["bigint", "boolean", "number", "string"].includes(typeof node.value);
|
|
12465
|
+
}
|
|
12466
|
+
if (node.type === import_utils70.AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0)
|
|
12467
|
+
return true;
|
|
12468
|
+
if (node.type === import_utils70.AST_NODE_TYPES.Identifier && node.name === "undefined") {
|
|
12469
|
+
const binding = import_utils70.ASTUtils.findVariable(
|
|
12470
|
+
context.sourceCode.getScope(node),
|
|
12471
|
+
node.name
|
|
12472
|
+
);
|
|
12473
|
+
return binding === null || binding.defs.length === 0;
|
|
12474
|
+
}
|
|
12475
|
+
return node.type === import_utils70.AST_NODE_TYPES.UnaryExpression && node.operator === "-" && node.argument.type === import_utils70.AST_NODE_TYPES.Literal && ["bigint", "number"].includes(typeof node.argument.value);
|
|
12476
|
+
}
|
|
12477
|
+
function isStaticString(node) {
|
|
12478
|
+
return node.type === import_utils70.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils70.AST_NODE_TYPES.TemplateLiteral && node.expressions.length === 0;
|
|
12193
12479
|
}
|
|
12194
12480
|
var prefer_multi_value_zod_literal_default = createRule({
|
|
12195
12481
|
name: "prefer-multi-value-zod-literal",
|
|
12196
12482
|
documentation: PREFER_MULTI_VALUE_ZOD_LITERAL_DOCUMENTATION,
|
|
12197
12483
|
meta: {
|
|
12198
12484
|
type: "suggestion",
|
|
12485
|
+
fixable: "code",
|
|
12199
12486
|
docs: {
|
|
12200
12487
|
description: "Use the Zod 4 multi-value literal API instead of a union of literal schemas."
|
|
12201
12488
|
},
|
|
12202
|
-
schema: [
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
zodMajorVersion: { type: "integer", minimum: 4, maximum: 4 }
|
|
12208
|
-
}
|
|
12489
|
+
schema: [{
|
|
12490
|
+
type: "object",
|
|
12491
|
+
additionalProperties: false,
|
|
12492
|
+
properties: {
|
|
12493
|
+
zodMajorVersion: { type: "integer", minimum: 4, maximum: 4 }
|
|
12209
12494
|
}
|
|
12210
|
-
],
|
|
12495
|
+
}],
|
|
12211
12496
|
messages: {
|
|
12212
|
-
useMultiValueLiteral: "Replace this literal-schema union with
|
|
12497
|
+
useMultiValueLiteral: "Replace this literal-schema union with {{zod}}.literal([\u2026])."
|
|
12213
12498
|
}
|
|
12214
12499
|
},
|
|
12215
12500
|
defaultOptions: [{}],
|
|
12216
12501
|
create(context, [options]) {
|
|
12217
12502
|
if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text))
|
|
12218
12503
|
return {};
|
|
12219
|
-
const
|
|
12220
|
-
const
|
|
12504
|
+
const zodBindings = /* @__PURE__ */ new Set();
|
|
12505
|
+
const zod4Bindings = /* @__PURE__ */ new Set();
|
|
12506
|
+
function resolvedBinding(identifier) {
|
|
12507
|
+
return import_utils70.ASTUtils.findVariable(
|
|
12508
|
+
context.sourceCode.getScope(identifier),
|
|
12509
|
+
identifier.name
|
|
12510
|
+
);
|
|
12511
|
+
}
|
|
12512
|
+
function directMemberCall(node, binding, method) {
|
|
12513
|
+
if (node.callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression || node.callee.computed || node.callee.object.type !== import_utils70.AST_NODE_TYPES.Identifier || node.callee.property.type !== import_utils70.AST_NODE_TYPES.Identifier || node.callee.property.name !== method)
|
|
12514
|
+
return false;
|
|
12515
|
+
return resolvedBinding(node.callee.object) === binding;
|
|
12516
|
+
}
|
|
12221
12517
|
return {
|
|
12222
12518
|
ImportDeclaration(node) {
|
|
12223
12519
|
if (!isZodModule(node.source.value)) return;
|
|
12520
|
+
const isExplicitV4 = /^zod\/v4(?:$|[-/])/.test(node.source.value);
|
|
12224
12521
|
for (const specifier of node.specifiers) {
|
|
12225
|
-
if (specifier.type === import_utils70.AST_NODE_TYPES.ImportDefaultSpecifier || specifier.type === import_utils70.AST_NODE_TYPES.ImportNamespaceSpecifier || specifier.type === import_utils70.AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === import_utils70.AST_NODE_TYPES.Identifier
|
|
12226
|
-
|
|
12227
|
-
if (
|
|
12228
|
-
|
|
12522
|
+
if (specifier.type === import_utils70.AST_NODE_TYPES.ImportDefaultSpecifier || specifier.type === import_utils70.AST_NODE_TYPES.ImportNamespaceSpecifier || specifier.type === import_utils70.AST_NODE_TYPES.ImportSpecifier && (specifier.imported.type === import_utils70.AST_NODE_TYPES.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
|
|
12523
|
+
const binding = resolvedBinding(specifier.local);
|
|
12524
|
+
if (binding === null) continue;
|
|
12525
|
+
zodBindings.add(binding);
|
|
12526
|
+
if (isExplicitV4) zod4Bindings.add(binding);
|
|
12229
12527
|
}
|
|
12230
12528
|
}
|
|
12231
12529
|
},
|
|
12232
12530
|
CallExpression(node) {
|
|
12233
|
-
|
|
12234
|
-
|
|
12235
|
-
);
|
|
12236
|
-
if (
|
|
12531
|
+
if (node.callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression || node.callee.object.type !== import_utils70.AST_NODE_TYPES.Identifier)
|
|
12532
|
+
return;
|
|
12533
|
+
const binding = resolvedBinding(node.callee.object);
|
|
12534
|
+
if (binding === null || !zodBindings.has(binding) || !directMemberCall(node, binding, "union") || options?.zodMajorVersion !== 4 && !zod4Bindings.has(binding) || node.arguments.length !== 1)
|
|
12237
12535
|
return;
|
|
12238
12536
|
const [argument] = node.arguments;
|
|
12239
|
-
if (argument?.type !== import_utils70.AST_NODE_TYPES.ArrayExpression || argument.elements.length <
|
|
12240
|
-
if (element === null || element.type !== import_utils70.AST_NODE_TYPES.CallExpression || !memberCall(element, namespace, "literal") || element.arguments.length !== 1)
|
|
12241
|
-
return true;
|
|
12242
|
-
const [value] = element.arguments;
|
|
12243
|
-
return value === void 0 || value.type === import_utils70.AST_NODE_TYPES.SpreadElement || ![
|
|
12244
|
-
import_utils70.AST_NODE_TYPES.Literal,
|
|
12245
|
-
import_utils70.AST_NODE_TYPES.TemplateLiteral
|
|
12246
|
-
].includes(value.type);
|
|
12247
|
-
}))
|
|
12537
|
+
if (argument?.type !== import_utils70.AST_NODE_TYPES.ArrayExpression || argument.elements.length < 2)
|
|
12248
12538
|
return;
|
|
12539
|
+
const values = [];
|
|
12540
|
+
for (const element of argument.elements) {
|
|
12541
|
+
if (element === null || element.type !== import_utils70.AST_NODE_TYPES.CallExpression || !directMemberCall(element, binding, "literal") || element.arguments.length !== 1)
|
|
12542
|
+
return;
|
|
12543
|
+
const [value] = element.arguments;
|
|
12544
|
+
if (value === void 0 || !isStaticPrimitive(value, context)) return;
|
|
12545
|
+
values.push(value);
|
|
12546
|
+
}
|
|
12547
|
+
if (values.every(isStaticString)) return;
|
|
12548
|
+
const namespace = node.callee.object.name;
|
|
12549
|
+
const hasComments = context.sourceCode.getCommentsInside(node).length > 0;
|
|
12249
12550
|
context.report({
|
|
12250
12551
|
node,
|
|
12251
12552
|
messageId: "useMultiValueLiteral",
|
|
12252
|
-
data: { zod: namespace }
|
|
12553
|
+
data: { zod: namespace },
|
|
12554
|
+
fix: hasComments ? null : (fixer) => fixer.replaceText(
|
|
12555
|
+
node,
|
|
12556
|
+
`${namespace}.literal([${values.map((value) => context.sourceCode.getText(value)).join(", ")}])`
|
|
12557
|
+
)
|
|
12253
12558
|
});
|
|
12254
12559
|
}
|
|
12255
12560
|
};
|
|
@@ -18436,8 +18741,8 @@ var REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION = {
|
|
|
18436
18741
|
]
|
|
18437
18742
|
};
|
|
18438
18743
|
var PASCAL_SCHEMA_NAME_RE = /^[A-Z][A-Za-z0-9]*Schema$/;
|
|
18439
|
-
var
|
|
18440
|
-
var
|
|
18744
|
+
var BENCHMARK_PATH_RE2 = /(^|[\\/])(?:benchmarks?|bench)[\\/]/;
|
|
18745
|
+
var NON_SCHEMA_TERMINALS2 = /* @__PURE__ */ new Set([
|
|
18441
18746
|
"parse",
|
|
18442
18747
|
"parseAsync",
|
|
18443
18748
|
"safeParse",
|
|
@@ -18550,7 +18855,7 @@ var SCHEMA_RETURNING_METHODS = /* @__PURE__ */ new Set([
|
|
|
18550
18855
|
"transform"
|
|
18551
18856
|
]);
|
|
18552
18857
|
var terminalMethodName = (callee) => !callee.computed && callee.property.type === import_utils100.AST_NODE_TYPES.Identifier ? callee.property.name : null;
|
|
18553
|
-
var
|
|
18858
|
+
var calleeChainRoot2 = (node) => {
|
|
18554
18859
|
let current = node;
|
|
18555
18860
|
for (; ; ) {
|
|
18556
18861
|
if (current.type === import_utils100.AST_NODE_TYPES.Identifier) {
|
|
@@ -18567,7 +18872,7 @@ var calleeChainRoot = (node) => {
|
|
|
18567
18872
|
return null;
|
|
18568
18873
|
}
|
|
18569
18874
|
};
|
|
18570
|
-
var
|
|
18875
|
+
var chainMemberNames2 = (node) => {
|
|
18571
18876
|
const names = [];
|
|
18572
18877
|
let current = node;
|
|
18573
18878
|
for (; ; ) {
|
|
@@ -18627,7 +18932,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
|
|
|
18627
18932
|
if (binding !== null) zodBindings.add(binding);
|
|
18628
18933
|
}
|
|
18629
18934
|
function isZodChain(node) {
|
|
18630
|
-
const root =
|
|
18935
|
+
const root = calleeChainRoot2(node);
|
|
18631
18936
|
if (root === null) return false;
|
|
18632
18937
|
const binding = resolvedBinding(root);
|
|
18633
18938
|
return binding !== null && zodBindings.has(binding);
|
|
@@ -18643,16 +18948,16 @@ var require_pascal_case_zod_schema_name_default = createRule({
|
|
|
18643
18948
|
return false;
|
|
18644
18949
|
}
|
|
18645
18950
|
const terminal = terminalMethodName(init.callee);
|
|
18646
|
-
if (terminal === null ||
|
|
18647
|
-
const names =
|
|
18951
|
+
if (terminal === null || NON_SCHEMA_TERMINALS2.has(terminal)) return false;
|
|
18952
|
+
const names = chainMemberNames2(init.callee);
|
|
18648
18953
|
if (names.length === 0) return false;
|
|
18649
18954
|
if (isZodChain(init.callee)) {
|
|
18650
18955
|
return ZOD_SCHEMA_FACTORIES.has(names[0] ?? "") || ZOD_FACTORY_NAMESPACES.has(names[0] ?? "") && ZOD_SCHEMA_FACTORIES.has(names[1] ?? "");
|
|
18651
18956
|
}
|
|
18652
|
-
const root =
|
|
18957
|
+
const root = calleeChainRoot2(init.callee);
|
|
18653
18958
|
return root !== null && isSchemaBinding(root) && SCHEMA_RETURNING_METHODS.has(terminal);
|
|
18654
18959
|
}
|
|
18655
|
-
if (isTestFile(context.filename) ||
|
|
18960
|
+
if (isTestFile(context.filename) || BENCHMARK_PATH_RE2.test(context.filename.replaceAll("\\", "/")) || isGeneratedFile(context.filename, context.sourceCode.text)) {
|
|
18656
18961
|
return {};
|
|
18657
18962
|
}
|
|
18658
18963
|
return {
|
|
@@ -18855,14 +19160,14 @@ var RULES = {
|
|
|
18855
19160
|
"require-static-next-matcher": require_static_next_matcher_default,
|
|
18856
19161
|
"require-zod-form-validation": require_zod_form_validation_default,
|
|
18857
19162
|
"store-insert-requires-on-conflict": store_insert_requires_on_conflict_default,
|
|
18858
|
-
stepdown: stepdown_default,
|
|
19163
|
+
"stepdown": stepdown_default,
|
|
18859
19164
|
"source-coupled-test": source_coupled_test_default,
|
|
18860
19165
|
"sole-export-matches-filename": sole_export_matches_filename_default,
|
|
18861
19166
|
"require-pascal-case-zod-schema-name": require_pascal_case_zod_schema_name_default
|
|
18862
19167
|
};
|
|
18863
19168
|
var meta = {
|
|
18864
19169
|
name: "@sarj/eslint-plugin",
|
|
18865
|
-
version: "15.17.
|
|
19170
|
+
version: "15.17.2"
|
|
18866
19171
|
};
|
|
18867
19172
|
var APPLICATION_ONLY_RULES = [
|
|
18868
19173
|
"no-restricted-library-load",
|