@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 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.22.2",
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: "eslint . ../../.github/scripts ../standards/src ../standards/eslint.config.mts --max-warnings 0",
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
- "Generated files and 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."
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)) continue;
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 === import_utils143.AST_NODE_TYPES.CallExpression || current.type === import_utils143.AST_NODE_TYPES.NewExpression) {
27295
- const callee = unwrapExpression(current.callee);
27296
- const first = current.arguments[0];
27297
- if (first === void 0 || first.type === import_utils143.AST_NODE_TYPES.SpreadElement) return false;
27298
- const pathBuilder = callee.type === import_utils143.AST_NODE_TYPES.Identifier ? nativePathBuilder(callee) : null;
27299
- if (current.type === import_utils143.AST_NODE_TYPES.CallExpression && pathBuilder !== null) {
27300
- if (temporaryDescendant(current, pathBuilder)) return false;
27301
- const trailing = [];
27302
- for (const argument of current.arguments.toReversed()) {
27303
- if (argument.type === import_utils143.AST_NODE_TYPES.SpreadElement) return false;
27304
- const segment = stringValue(argument);
27305
- if (segment === null) break;
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.22.2",
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: "eslint . ../../.github/scripts ../standards/src ../standards/eslint.config.mts --max-warnings 0",
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
- "Generated files and 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."
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)) continue;
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 === AST_NODE_TYPES122.CallExpression || current.type === AST_NODE_TYPES122.NewExpression) {
27319
- const callee = unwrapExpression(current.callee);
27320
- const first = current.arguments[0];
27321
- if (first === void 0 || first.type === AST_NODE_TYPES122.SpreadElement) return false;
27322
- const pathBuilder = callee.type === AST_NODE_TYPES122.Identifier ? nativePathBuilder(callee) : null;
27323
- if (current.type === AST_NODE_TYPES122.CallExpression && pathBuilder !== null) {
27324
- if (temporaryDescendant(current, pathBuilder)) return false;
27325
- const trailing = [];
27326
- for (const argument of current.arguments.toReversed()) {
27327
- if (argument.type === AST_NODE_TYPES122.SpreadElement) return false;
27328
- const segment = stringValue(argument);
27329
- if (segment === null) break;
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.22.2",
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 --max-warnings 0",
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",