@sarj/eslint-plugin 16.22.2 → 16.23.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/dist/index.cjs +29 -28
- package/dist/index.js +29 -28
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -866,7 +866,7 @@ function isSearchParamReceiver(call, services) {
|
|
|
866
866
|
// package.json
|
|
867
867
|
var package_default = {
|
|
868
868
|
name: "@sarj/eslint-plugin",
|
|
869
|
-
version: "16.
|
|
869
|
+
version: "16.23.0",
|
|
870
870
|
packageManager: "npm@12.2.0",
|
|
871
871
|
description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
|
|
872
872
|
type: "module",
|
|
@@ -901,7 +901,7 @@ var package_default = {
|
|
|
901
901
|
scripts: {
|
|
902
902
|
build: "tsup",
|
|
903
903
|
dogfood: "npm run build && npm run dogfood:built",
|
|
904
|
-
lint:
|
|
904
|
+
lint: 'node ../standards/src/sarj_standards/configs/eslint-selected-rules.mts "{\\"full\\":true,\\"config\\":null,\\"rules\\":[],\\"consoleOutput\\":true,\\"failOnWarnings\\":true}" -- . ../../.github/scripts ../standards/src ../standards/eslint.config.mts',
|
|
905
905
|
prepack: "npm run build && npm run verify-package",
|
|
906
906
|
test: "vitest run",
|
|
907
907
|
typecheck: "tsc --noEmit && tsc --project tsconfig.tools.json",
|
|
@@ -11273,7 +11273,7 @@ var no_long_comment_default = createRule({
|
|
|
11273
11273
|
// src/rules/no-vague-suppression-description.ts
|
|
11274
11274
|
var ESLINT_DIRECTIVE_WITH_DESCRIPTION_RE = /^eslint-(?:disable|disable-next-line|disable-line)\b[^:\n]*?\s*(?::|--)\s*(.+?)\s*$/iu;
|
|
11275
11275
|
var TS_EXPECT_ERROR_WITH_DESCRIPTION_RE = /^@ts-expect-error\b(?:(?:\s*(?::|--)\s*)|\s+)(.+?)\s*$/iu;
|
|
11276
|
-
var VAGUE_RE = /^(?:needed|required|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
|
|
11276
|
+
var VAGUE_RE = /^(?:needed|required|same|n\/a|legacy|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
|
|
11277
11277
|
var NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION = {
|
|
11278
11278
|
summary: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason.",
|
|
11279
11279
|
rationale: "Generic phrases satisfy require-description mechanically while leaving reviewers unable to audit the risk or remove stale debt.",
|
|
@@ -11282,7 +11282,7 @@ var NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION = {
|
|
|
11282
11282
|
limitations: [
|
|
11283
11283
|
"Only ESLint disable comments and TypeScript expect-error directives are checked.",
|
|
11284
11284
|
"The rule uses a small anchored vocabulary and does not score prose quality generally.",
|
|
11285
|
-
"
|
|
11285
|
+
"Descriptions outside that exact vocabulary are excluded; an unflagged reason is not proof of a justified suppression. Missing descriptions remain owned by the upstream description requirement. Explicit path exclusions own generated-source boundaries; a source marker does not waive suppression accountability."
|
|
11286
11286
|
],
|
|
11287
11287
|
examples: [
|
|
11288
11288
|
{
|
|
@@ -11333,15 +11333,13 @@ var no_vague_suppression_description_default = createRule({
|
|
|
11333
11333
|
},
|
|
11334
11334
|
defaultOptions: [],
|
|
11335
11335
|
create(context) {
|
|
11336
|
-
if (isGeneratedFile(context.filename, context.sourceCode.text)) {
|
|
11337
|
-
return {};
|
|
11338
|
-
}
|
|
11339
11336
|
return {
|
|
11340
11337
|
Program() {
|
|
11341
11338
|
for (const comment of context.sourceCode.getAllComments()) {
|
|
11342
11339
|
const text = comment.value.trim();
|
|
11343
11340
|
const description = suppressionDescription(text);
|
|
11344
|
-
if (description === void 0 || !VAGUE_RE.test(description))
|
|
11341
|
+
if (description === void 0 || !VAGUE_RE.test(description))
|
|
11342
|
+
continue;
|
|
11345
11343
|
context.report({
|
|
11346
11344
|
loc: comment.loc,
|
|
11347
11345
|
messageId: "vagueDescription",
|
|
@@ -27229,6 +27227,17 @@ function stringValue(node) {
|
|
|
27229
27227
|
}
|
|
27230
27228
|
return null;
|
|
27231
27229
|
}
|
|
27230
|
+
function staticPathSuffix(pathArguments, builder) {
|
|
27231
|
+
const trailing = [];
|
|
27232
|
+
for (const argument of pathArguments.toReversed()) {
|
|
27233
|
+
if (argument.type === import_utils143.AST_NODE_TYPES.SpreadElement) return null;
|
|
27234
|
+
const segment = stringValue(argument);
|
|
27235
|
+
if (segment === null) break;
|
|
27236
|
+
trailing.unshift(segment);
|
|
27237
|
+
if (builder === "resolve" && import_node_path3.posix.isAbsolute(segment.replaceAll("\\", "/"))) break;
|
|
27238
|
+
}
|
|
27239
|
+
return trailing.length > 0 ? trailing.join("/") : null;
|
|
27240
|
+
}
|
|
27232
27241
|
function importSource(node) {
|
|
27233
27242
|
return typeof node.source.value === "string" ? node.source.value : null;
|
|
27234
27243
|
}
|
|
@@ -27291,26 +27300,18 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
|
27291
27300
|
const value = stringValue(current);
|
|
27292
27301
|
if (value !== null) return sourcePathValue(value);
|
|
27293
27302
|
if (current.type === import_utils143.AST_NODE_TYPES.Identifier) return visible("paths", current);
|
|
27294
|
-
if (current.type
|
|
27295
|
-
|
|
27296
|
-
|
|
27297
|
-
|
|
27298
|
-
|
|
27299
|
-
|
|
27300
|
-
|
|
27301
|
-
|
|
27302
|
-
|
|
27303
|
-
|
|
27304
|
-
|
|
27305
|
-
|
|
27306
|
-
trailing.unshift(segment);
|
|
27307
|
-
if (pathBuilder === "resolve" && import_node_path3.posix.isAbsolute(segment.replaceAll("\\", "/"))) break;
|
|
27308
|
-
}
|
|
27309
|
-
return trailing.length > 0 && sourcePathValue(trailing.join("/"));
|
|
27310
|
-
}
|
|
27311
|
-
if (current.type === import_utils143.AST_NODE_TYPES.NewExpression && callee.type === import_utils143.AST_NODE_TYPES.Identifier && callee.name === "URL" && (bindingOf(callee)?.defs.length ?? 0) === 0) return sourcePath(first);
|
|
27312
|
-
if (callee.type === import_utils143.AST_NODE_TYPES.Identifier && bindingOf(callee)?.defs.some((definition) => definition.node.type === import_utils143.AST_NODE_TYPES.ImportSpecifier && definition.node.imported.type === import_utils143.AST_NODE_TYPES.Identifier && definition.node.imported.name === "fileURLToPath" && definition.node.parent.type === import_utils143.AST_NODE_TYPES.ImportDeclaration && ["node:url", "url"].includes(String(definition.node.parent.source.value)))) return sourcePath(first);
|
|
27313
|
-
}
|
|
27303
|
+
if (current.type !== import_utils143.AST_NODE_TYPES.CallExpression && current.type !== import_utils143.AST_NODE_TYPES.NewExpression) return false;
|
|
27304
|
+
const callee = unwrapExpression(current.callee);
|
|
27305
|
+
const first = current.arguments[0];
|
|
27306
|
+
if (first === void 0 || first.type === import_utils143.AST_NODE_TYPES.SpreadElement) return false;
|
|
27307
|
+
const pathBuilder = callee.type === import_utils143.AST_NODE_TYPES.Identifier ? nativePathBuilder(callee) : null;
|
|
27308
|
+
if (current.type === import_utils143.AST_NODE_TYPES.CallExpression && pathBuilder !== null) {
|
|
27309
|
+
if (temporaryDescendant(current, pathBuilder)) return false;
|
|
27310
|
+
const suffix = staticPathSuffix(current.arguments, pathBuilder);
|
|
27311
|
+
return suffix !== null && sourcePathValue(suffix);
|
|
27312
|
+
}
|
|
27313
|
+
if (current.type === import_utils143.AST_NODE_TYPES.NewExpression && callee.type === import_utils143.AST_NODE_TYPES.Identifier && callee.name === "URL" && (bindingOf(callee)?.defs.length ?? 0) === 0) return sourcePath(first);
|
|
27314
|
+
if (callee.type === import_utils143.AST_NODE_TYPES.Identifier && bindingOf(callee)?.defs.some((definition) => definition.node.type === import_utils143.AST_NODE_TYPES.ImportSpecifier && definition.node.imported.type === import_utils143.AST_NODE_TYPES.Identifier && definition.node.imported.name === "fileURLToPath" && definition.node.parent.type === import_utils143.AST_NODE_TYPES.ImportDeclaration && ["node:url", "url"].includes(String(definition.node.parent.source.value)))) return sourcePath(first);
|
|
27314
27315
|
return false;
|
|
27315
27316
|
};
|
|
27316
27317
|
const nativePathBuilder = (node) => {
|
package/dist/index.js
CHANGED
|
@@ -819,7 +819,7 @@ function isSearchParamReceiver(call, services) {
|
|
|
819
819
|
// package.json
|
|
820
820
|
var package_default = {
|
|
821
821
|
name: "@sarj/eslint-plugin",
|
|
822
|
-
version: "16.
|
|
822
|
+
version: "16.23.0",
|
|
823
823
|
packageManager: "npm@12.2.0",
|
|
824
824
|
description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
|
|
825
825
|
type: "module",
|
|
@@ -854,7 +854,7 @@ var package_default = {
|
|
|
854
854
|
scripts: {
|
|
855
855
|
build: "tsup",
|
|
856
856
|
dogfood: "npm run build && npm run dogfood:built",
|
|
857
|
-
lint:
|
|
857
|
+
lint: 'node ../standards/src/sarj_standards/configs/eslint-selected-rules.mts "{\\"full\\":true,\\"config\\":null,\\"rules\\":[],\\"consoleOutput\\":true,\\"failOnWarnings\\":true}" -- . ../../.github/scripts ../standards/src ../standards/eslint.config.mts',
|
|
858
858
|
prepack: "npm run build && npm run verify-package",
|
|
859
859
|
test: "vitest run",
|
|
860
860
|
typecheck: "tsc --noEmit && tsc --project tsconfig.tools.json",
|
|
@@ -11258,7 +11258,7 @@ var no_long_comment_default = createRule({
|
|
|
11258
11258
|
// src/rules/no-vague-suppression-description.ts
|
|
11259
11259
|
var ESLINT_DIRECTIVE_WITH_DESCRIPTION_RE = /^eslint-(?:disable|disable-next-line|disable-line)\b[^:\n]*?\s*(?::|--)\s*(.+?)\s*$/iu;
|
|
11260
11260
|
var TS_EXPECT_ERROR_WITH_DESCRIPTION_RE = /^@ts-expect-error\b(?:(?:\s*(?::|--)\s*)|\s+)(.+?)\s*$/iu;
|
|
11261
|
-
var VAGUE_RE = /^(?:needed|required|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
|
|
11261
|
+
var VAGUE_RE = /^(?:needed|required|same|n\/a|legacy|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
|
|
11262
11262
|
var NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION = {
|
|
11263
11263
|
summary: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason.",
|
|
11264
11264
|
rationale: "Generic phrases satisfy require-description mechanically while leaving reviewers unable to audit the risk or remove stale debt.",
|
|
@@ -11267,7 +11267,7 @@ var NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION = {
|
|
|
11267
11267
|
limitations: [
|
|
11268
11268
|
"Only ESLint disable comments and TypeScript expect-error directives are checked.",
|
|
11269
11269
|
"The rule uses a small anchored vocabulary and does not score prose quality generally.",
|
|
11270
|
-
"
|
|
11270
|
+
"Descriptions outside that exact vocabulary are excluded; an unflagged reason is not proof of a justified suppression. Missing descriptions remain owned by the upstream description requirement. Explicit path exclusions own generated-source boundaries; a source marker does not waive suppression accountability."
|
|
11271
11271
|
],
|
|
11272
11272
|
examples: [
|
|
11273
11273
|
{
|
|
@@ -11318,15 +11318,13 @@ var no_vague_suppression_description_default = createRule({
|
|
|
11318
11318
|
},
|
|
11319
11319
|
defaultOptions: [],
|
|
11320
11320
|
create(context) {
|
|
11321
|
-
if (isGeneratedFile(context.filename, context.sourceCode.text)) {
|
|
11322
|
-
return {};
|
|
11323
|
-
}
|
|
11324
11321
|
return {
|
|
11325
11322
|
Program() {
|
|
11326
11323
|
for (const comment of context.sourceCode.getAllComments()) {
|
|
11327
11324
|
const text = comment.value.trim();
|
|
11328
11325
|
const description = suppressionDescription(text);
|
|
11329
|
-
if (description === void 0 || !VAGUE_RE.test(description))
|
|
11326
|
+
if (description === void 0 || !VAGUE_RE.test(description))
|
|
11327
|
+
continue;
|
|
11330
11328
|
context.report({
|
|
11331
11329
|
loc: comment.loc,
|
|
11332
11330
|
messageId: "vagueDescription",
|
|
@@ -27253,6 +27251,17 @@ function stringValue(node) {
|
|
|
27253
27251
|
}
|
|
27254
27252
|
return null;
|
|
27255
27253
|
}
|
|
27254
|
+
function staticPathSuffix(pathArguments, builder) {
|
|
27255
|
+
const trailing = [];
|
|
27256
|
+
for (const argument of pathArguments.toReversed()) {
|
|
27257
|
+
if (argument.type === AST_NODE_TYPES122.SpreadElement) return null;
|
|
27258
|
+
const segment = stringValue(argument);
|
|
27259
|
+
if (segment === null) break;
|
|
27260
|
+
trailing.unshift(segment);
|
|
27261
|
+
if (builder === "resolve" && posix2.isAbsolute(segment.replaceAll("\\", "/"))) break;
|
|
27262
|
+
}
|
|
27263
|
+
return trailing.length > 0 ? trailing.join("/") : null;
|
|
27264
|
+
}
|
|
27256
27265
|
function importSource(node) {
|
|
27257
27266
|
return typeof node.source.value === "string" ? node.source.value : null;
|
|
27258
27267
|
}
|
|
@@ -27315,26 +27324,18 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
|
27315
27324
|
const value = stringValue(current);
|
|
27316
27325
|
if (value !== null) return sourcePathValue(value);
|
|
27317
27326
|
if (current.type === AST_NODE_TYPES122.Identifier) return visible("paths", current);
|
|
27318
|
-
if (current.type
|
|
27319
|
-
|
|
27320
|
-
|
|
27321
|
-
|
|
27322
|
-
|
|
27323
|
-
|
|
27324
|
-
|
|
27325
|
-
|
|
27326
|
-
|
|
27327
|
-
|
|
27328
|
-
|
|
27329
|
-
|
|
27330
|
-
trailing.unshift(segment);
|
|
27331
|
-
if (pathBuilder === "resolve" && posix2.isAbsolute(segment.replaceAll("\\", "/"))) break;
|
|
27332
|
-
}
|
|
27333
|
-
return trailing.length > 0 && sourcePathValue(trailing.join("/"));
|
|
27334
|
-
}
|
|
27335
|
-
if (current.type === AST_NODE_TYPES122.NewExpression && callee.type === AST_NODE_TYPES122.Identifier && callee.name === "URL" && (bindingOf(callee)?.defs.length ?? 0) === 0) return sourcePath(first);
|
|
27336
|
-
if (callee.type === AST_NODE_TYPES122.Identifier && bindingOf(callee)?.defs.some((definition) => definition.node.type === AST_NODE_TYPES122.ImportSpecifier && definition.node.imported.type === AST_NODE_TYPES122.Identifier && definition.node.imported.name === "fileURLToPath" && definition.node.parent.type === AST_NODE_TYPES122.ImportDeclaration && ["node:url", "url"].includes(String(definition.node.parent.source.value)))) return sourcePath(first);
|
|
27337
|
-
}
|
|
27327
|
+
if (current.type !== AST_NODE_TYPES122.CallExpression && current.type !== AST_NODE_TYPES122.NewExpression) return false;
|
|
27328
|
+
const callee = unwrapExpression(current.callee);
|
|
27329
|
+
const first = current.arguments[0];
|
|
27330
|
+
if (first === void 0 || first.type === AST_NODE_TYPES122.SpreadElement) return false;
|
|
27331
|
+
const pathBuilder = callee.type === AST_NODE_TYPES122.Identifier ? nativePathBuilder(callee) : null;
|
|
27332
|
+
if (current.type === AST_NODE_TYPES122.CallExpression && pathBuilder !== null) {
|
|
27333
|
+
if (temporaryDescendant(current, pathBuilder)) return false;
|
|
27334
|
+
const suffix = staticPathSuffix(current.arguments, pathBuilder);
|
|
27335
|
+
return suffix !== null && sourcePathValue(suffix);
|
|
27336
|
+
}
|
|
27337
|
+
if (current.type === AST_NODE_TYPES122.NewExpression && callee.type === AST_NODE_TYPES122.Identifier && callee.name === "URL" && (bindingOf(callee)?.defs.length ?? 0) === 0) return sourcePath(first);
|
|
27338
|
+
if (callee.type === AST_NODE_TYPES122.Identifier && bindingOf(callee)?.defs.some((definition) => definition.node.type === AST_NODE_TYPES122.ImportSpecifier && definition.node.imported.type === AST_NODE_TYPES122.Identifier && definition.node.imported.name === "fileURLToPath" && definition.node.parent.type === AST_NODE_TYPES122.ImportDeclaration && ["node:url", "url"].includes(String(definition.node.parent.source.value)))) return sourcePath(first);
|
|
27338
27339
|
return false;
|
|
27339
27340
|
};
|
|
27340
27341
|
const nativePathBuilder = (node) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sarj/eslint-plugin",
|
|
3
|
-
"version": "16.
|
|
3
|
+
"version": "16.23.0",
|
|
4
4
|
"packageManager": "npm@12.2.0",
|
|
5
5
|
"description": "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup",
|
|
37
37
|
"dogfood": "npm run build && npm run dogfood:built",
|
|
38
|
-
"lint": "eslint . ../../.github/scripts ../standards/src ../standards/eslint.config.mts
|
|
38
|
+
"lint": "node ../standards/src/sarj_standards/configs/eslint-selected-rules.mts \"{\\\"full\\\":true,\\\"config\\\":null,\\\"rules\\\":[],\\\"consoleOutput\\\":true,\\\"failOnWarnings\\\":true}\" -- . ../../.github/scripts ../standards/src ../standards/eslint.config.mts",
|
|
39
39
|
"prepack": "npm run build && npm run verify-package",
|
|
40
40
|
"test": "vitest run",
|
|
41
41
|
"typecheck": "tsc --noEmit && tsc --project tsconfig.tools.json",
|