pasika 0.10.45 → 0.10.47
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/eslint/pasika/index.js +72 -18
- package/package.json +1 -1
|
@@ -3485,14 +3485,11 @@ function relativeSpecifier(filename, resolvedPath) {
|
|
|
3485
3485
|
function aliasSpecifier(sourceRoot, resolvedPath) {
|
|
3486
3486
|
return `@/${(sourceSegments(sourceRoot, resolvedPath) ?? []).join("/")}`;
|
|
3487
3487
|
}
|
|
3488
|
-
function
|
|
3489
|
-
return specifier.
|
|
3488
|
+
function parentTraversalCount(specifier) {
|
|
3489
|
+
return specifier.split("/").filter((segment) => segment === "..").length;
|
|
3490
3490
|
}
|
|
3491
|
-
function
|
|
3492
|
-
return
|
|
3493
|
-
}
|
|
3494
|
-
function prefersRelative(sourceRoot, filename, resolvedPath) {
|
|
3495
|
-
return segmentCount(relativeSpecifier(filename, resolvedPath)) <= segmentCount(aliasSpecifier(sourceRoot, resolvedPath));
|
|
3491
|
+
function prefersRelative(filename, resolvedPath) {
|
|
3492
|
+
return parentTraversalCount(relativeSpecifier(filename, resolvedPath)) <= 1;
|
|
3496
3493
|
}
|
|
3497
3494
|
var importBoundariesRule = {
|
|
3498
3495
|
meta: {
|
|
@@ -3536,23 +3533,17 @@ var importBoundariesRule = {
|
|
|
3536
3533
|
}
|
|
3537
3534
|
const relativeForm = relativeSpecifier(filename, resolvedPath);
|
|
3538
3535
|
const aliasForm = aliasSpecifier(sourceRoot, resolvedPath);
|
|
3539
|
-
|
|
3540
|
-
const aliasSegments = segmentCount(aliasForm);
|
|
3541
|
-
function describeChoice(preferred, preferredSegments, other, otherSegments) {
|
|
3542
|
-
const tie = preferredSegments === otherSegments ? ", and a tie goes to the relative path" : "";
|
|
3543
|
-
return `Use "${preferred}" (${describeSegments(preferredSegments)}) instead of "${other}" (${describeSegments(otherSegments)})${tie}.`;
|
|
3544
|
-
}
|
|
3545
|
-
if (prefersRelative(sourceRoot, filename, resolvedPath) && importPath.startsWith("@/")) {
|
|
3536
|
+
if (prefersRelative(filename, resolvedPath) && importPath.startsWith("@/")) {
|
|
3546
3537
|
context.report({
|
|
3547
3538
|
node: source,
|
|
3548
|
-
message:
|
|
3539
|
+
message: `Use "${relativeForm}" instead of "${aliasForm}".`
|
|
3549
3540
|
});
|
|
3550
3541
|
return;
|
|
3551
3542
|
}
|
|
3552
|
-
if (!prefersRelative(
|
|
3543
|
+
if (!prefersRelative(filename, resolvedPath) && importPath.startsWith(".")) {
|
|
3553
3544
|
context.report({
|
|
3554
3545
|
node: source,
|
|
3555
|
-
message:
|
|
3546
|
+
message: `Use "${aliasForm}" instead of "${relativeForm}".`
|
|
3556
3547
|
});
|
|
3557
3548
|
}
|
|
3558
3549
|
}
|
|
@@ -5184,19 +5175,82 @@ function isEnumLiteralType(node) {
|
|
|
5184
5175
|
function isEnumLiteralUnion(node) {
|
|
5185
5176
|
return node?.type === "TSUnionType" && (node.types?.length ?? 0) >= 2 && (node.types ?? []).every(isEnumLiteralType);
|
|
5186
5177
|
}
|
|
5178
|
+
function isZodCall(node, method) {
|
|
5179
|
+
const { callee } = node;
|
|
5180
|
+
return callee?.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "z" && callee.property.type === "Identifier" && callee.property.name === method;
|
|
5181
|
+
}
|
|
5182
|
+
function propertyName2(property) {
|
|
5183
|
+
if (property.computed) return void 0;
|
|
5184
|
+
if (property.key.type === "Identifier") return property.key.name;
|
|
5185
|
+
if (property.key.type === "Literal" && typeof property.key.value === "string") return property.key.value;
|
|
5186
|
+
return void 0;
|
|
5187
|
+
}
|
|
5188
|
+
function rawZodDiscriminantLiteral(schemaCall, discriminator) {
|
|
5189
|
+
if (!isZodCall(schemaCall, "object")) return void 0;
|
|
5190
|
+
const shape = schemaCall.arguments[0];
|
|
5191
|
+
if (shape?.type !== "ObjectExpression") return void 0;
|
|
5192
|
+
for (const property of shape.properties) {
|
|
5193
|
+
if (property.type !== "Property" || propertyName2(property) !== discriminator) continue;
|
|
5194
|
+
if (property.value.type !== "CallExpression" || !isZodCall(property.value, "literal")) return void 0;
|
|
5195
|
+
const literal = property.value.arguments[0];
|
|
5196
|
+
if (literal?.type === "Literal" && (typeof literal.value === "string" || typeof literal.value === "number")) {
|
|
5197
|
+
return literal;
|
|
5198
|
+
}
|
|
5199
|
+
return void 0;
|
|
5200
|
+
}
|
|
5201
|
+
return void 0;
|
|
5202
|
+
}
|
|
5187
5203
|
var preferEnumRule = {
|
|
5188
5204
|
meta: {
|
|
5189
5205
|
schema: [],
|
|
5190
5206
|
type: "problem",
|
|
5191
5207
|
docs: {
|
|
5192
|
-
description: "Require fixed sets of named string/number values to be TypeScript enums
|
|
5208
|
+
description: "Require fixed sets of named string/number values to be TypeScript enums, including Zod discriminated-union discriminator values."
|
|
5193
5209
|
}
|
|
5194
5210
|
},
|
|
5195
5211
|
create(context) {
|
|
5196
5212
|
const filename = path40.resolve(context.filename);
|
|
5197
5213
|
const sourceRoot = sourceRootOf(context);
|
|
5198
5214
|
if (!filename.startsWith(sourceRoot + path40.sep)) return {};
|
|
5215
|
+
const objectSchemas = /* @__PURE__ */ new Map();
|
|
5216
|
+
const discriminatedUnions = [];
|
|
5217
|
+
const reportedDiscriminants = /* @__PURE__ */ new Set();
|
|
5199
5218
|
return {
|
|
5219
|
+
VariableDeclarator(node) {
|
|
5220
|
+
const { id, init } = node;
|
|
5221
|
+
if (id?.type !== "Identifier" || init?.type !== "CallExpression" || !isZodCall(init, "object")) return;
|
|
5222
|
+
objectSchemas.set(id.name, init);
|
|
5223
|
+
},
|
|
5224
|
+
CallExpression(node) {
|
|
5225
|
+
if (isZodCall(node, "discriminatedUnion")) {
|
|
5226
|
+
discriminatedUnions.push(node);
|
|
5227
|
+
}
|
|
5228
|
+
},
|
|
5229
|
+
"Program:exit"() {
|
|
5230
|
+
for (const unionCall of discriminatedUnions) {
|
|
5231
|
+
const [discriminatorArg, optionsArg] = unionCall.arguments ?? [];
|
|
5232
|
+
if (discriminatorArg?.type !== "Literal" || typeof discriminatorArg.value !== "string" || optionsArg?.type !== "ArrayExpression") {
|
|
5233
|
+
continue;
|
|
5234
|
+
}
|
|
5235
|
+
for (const option of optionsArg.elements) {
|
|
5236
|
+
if (!option || option.type === "SpreadElement") continue;
|
|
5237
|
+
let schemaCall;
|
|
5238
|
+
if (option.type === "Identifier") {
|
|
5239
|
+
schemaCall = objectSchemas.get(option.name);
|
|
5240
|
+
} else if (option.type === "CallExpression" && isZodCall(option, "object")) {
|
|
5241
|
+
schemaCall = option;
|
|
5242
|
+
}
|
|
5243
|
+
if (!schemaCall) continue;
|
|
5244
|
+
const literal = rawZodDiscriminantLiteral(schemaCall, discriminatorArg.value);
|
|
5245
|
+
if (!literal || reportedDiscriminants.has(literal)) continue;
|
|
5246
|
+
reportedDiscriminants.add(literal);
|
|
5247
|
+
context.report({
|
|
5248
|
+
node: literal,
|
|
5249
|
+
message: "A Zod discriminated-union discriminator literal must use a TypeScript enum member. See docs/next-codebase-guide/rules/constants-rule.md"
|
|
5250
|
+
});
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
},
|
|
5200
5254
|
TSAsExpression(node) {
|
|
5201
5255
|
if (!isConstAssertion(node)) return;
|
|
5202
5256
|
const expression = node.expression;
|