@sarj/eslint-plugin 16.14.2 → 16.14.4

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.
Files changed (3) hide show
  1. package/dist/index.cjs +45 -54
  2. package/dist/index.js +146 -155
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -52,7 +52,7 @@ module.exports = __toCommonJS(src_exports);
52
52
  // package.json
53
53
  var package_default = {
54
54
  name: "@sarj/eslint-plugin",
55
- version: "16.14.2",
55
+ version: "16.14.4",
56
56
  packageManager: "npm@12.2.0",
57
57
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
58
58
  type: "module",
@@ -382,6 +382,7 @@ function deepFreeze(value) {
382
382
  }
383
383
 
384
384
  // src/rules/_paths.ts
385
+ var import_node_path = require("path");
385
386
  var LINE_TERMINATOR_RE = /[\n\r\u2028\u2029]/u;
386
387
  var SCRIPT_FILE_RE = /(?:^|[\\/])scripts[\\/]|\.mjs$/;
387
388
  var STORY_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
@@ -465,6 +466,10 @@ function leadingCommentBodies(sourceText) {
465
466
  function isScriptFile(filename) {
466
467
  return SCRIPT_FILE_RE.test(filename);
467
468
  }
469
+ function matchesAnyPattern(filename, patterns) {
470
+ const normalized = filename.replaceAll("\\", "/");
471
+ return patterns.some((pattern) => import_node_path.posix.matchesGlob(normalized, pattern.replaceAll("\\", "/")));
472
+ }
468
473
  function commentLineEnd(sourceText, start) {
469
474
  const end = sourceText.slice(start).search(LINE_TERMINATOR_RE);
470
475
  return end === -1 ? sourceText.length : start + end;
@@ -5842,15 +5847,6 @@ var NO_ENUM_DOCUMENTATION = {
5842
5847
  { id: "generated-header", scenarioId: "native-header-boundary", title: "Respect a native generated banner", outcome: "no-match", files: [{ path: "src/status.ts", source: '// auto-generated file\u2028const marker="auto-generated file"; enum Mode {Start} console.log(Mode.Start, marker);' }], focusPath: "src/status.ts", expectedCount: 0, public: true }
5843
5848
  ]
5844
5849
  };
5845
- function matchesAnyPattern(filename, patterns) {
5846
- for (const pattern of patterns) {
5847
- const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
5848
- if (new RegExp(`^${regexSource}$`).test(filename)) {
5849
- return true;
5850
- }
5851
- }
5852
- return false;
5853
- }
5854
5850
  var no_enum_default = createRule({
5855
5851
  name: "no-enum",
5856
5852
  documentation: NO_ENUM_DOCUMENTATION,
@@ -6515,15 +6511,6 @@ var GLOBAL_OBJECTS = /* @__PURE__ */ new Set([
6515
6511
  ]);
6516
6512
  var CLIENT_ONLY_MODULES = /^(react|react-dom|react-native|svelte|vue|preact|solid-js)(\/|$)|^next\/(navigation|router|link|image)$/;
6517
6513
  var RACE_METHODS = /* @__PURE__ */ new Set(["race", "any"]);
6518
- function matchesAnyPattern2(filename, patterns) {
6519
- for (const pattern of patterns) {
6520
- const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
6521
- if (new RegExp(`^${regexSource}$`).test(filename)) {
6522
- return true;
6523
- }
6524
- }
6525
- return false;
6526
- }
6527
6514
  function isSetTimeoutCallee(callee) {
6528
6515
  callee = unwrapExpression(callee);
6529
6516
  if (callee.type === import_utils37.AST_NODE_TYPES.Identifier) {
@@ -6629,7 +6616,7 @@ var no_hand_rolled_sleep_default = createRule({
6629
6616
  return {};
6630
6617
  }
6631
6618
  const allowIn = optionsArg?.allowIn ?? [];
6632
- if (allowIn.length > 0 && matchesAnyPattern2(filename, allowIn)) {
6619
+ if (allowIn.length > 0 && matchesAnyPattern(filename, allowIn)) {
6633
6620
  return {};
6634
6621
  }
6635
6622
  const checkClientModules = optionsArg?.checkClientModules ?? false;
@@ -16398,7 +16385,7 @@ function unwrapTransparentExport(node) {
16398
16385
  var import_utils95 = require("@typescript-eslint/utils");
16399
16386
  var import_typescript_estree = require("@typescript-eslint/typescript-estree");
16400
16387
  var import_node_fs = require("fs");
16401
- var import_node_path = require("path");
16388
+ var import_node_path2 = require("path");
16402
16389
  var import_jsonc_parser = require("jsonc-parser");
16403
16390
  var PREFER_SHADCN_PRIMITIVES_DOCUMENTATION = {
16404
16391
  summary: "Require visible raw JSX controls to use the corresponding shared shadcn primitive.",
@@ -16460,9 +16447,9 @@ var AMBIGUOUS_INPUT_TYPES = /* @__PURE__ */ new Set([
16460
16447
  var MAX_PROJECT_FILE_BYTES = 1048576;
16461
16448
  var PROJECT_PRIMITIVES_CACHE = /* @__PURE__ */ new Map();
16462
16449
  function detectProjectPrimitives(filename, requested) {
16463
- const packageRoot = findPackageRoot((0, import_node_path.dirname)(filename));
16450
+ const packageRoot = findPackageRoot((0, import_node_path2.dirname)(filename));
16464
16451
  if (packageRoot === null) return { available: /* @__PURE__ */ new Set(), uiRoot: null };
16465
- const manifest = readJsonc((0, import_node_path.join)(packageRoot, "components.json"));
16452
+ const manifest = readJsonc((0, import_node_path2.join)(packageRoot, "components.json"));
16466
16453
  const alias = stringProperty(manifest, "aliases", "ui");
16467
16454
  const unresolvedUiRoot = alias === null ? null : resolveAlias(packageRoot, alias);
16468
16455
  if (unresolvedUiRoot === null) return { available: /* @__PURE__ */ new Set(), uiRoot: null };
@@ -16474,14 +16461,14 @@ function detectProjectPrimitives(filename, requested) {
16474
16461
  for (const [capability, moduleName] of Object.entries(CAPABILITIES)) {
16475
16462
  if (!requested.has(capability)) continue;
16476
16463
  moduleCandidates.set(capability, ["tsx", "ts", "jsx", "js"].flatMap((extension) => [
16477
- (0, import_node_path.join)(uiRoot, `${moduleName}.${extension}`),
16478
- (0, import_node_path.join)(uiRoot, moduleName, `index.${extension}`)
16464
+ (0, import_node_path2.join)(uiRoot, `${moduleName}.${extension}`),
16465
+ (0, import_node_path2.join)(uiRoot, moduleName, `index.${extension}`)
16479
16466
  ]));
16480
16467
  }
16481
16468
  const fingerprint = [
16482
- (0, import_node_path.join)(packageRoot, "components.json"),
16483
- (0, import_node_path.join)(packageRoot, "tsconfig.json"),
16484
- (0, import_node_path.join)(packageRoot, "jsconfig.json"),
16469
+ (0, import_node_path2.join)(packageRoot, "components.json"),
16470
+ (0, import_node_path2.join)(packageRoot, "tsconfig.json"),
16471
+ (0, import_node_path2.join)(packageRoot, "jsconfig.json"),
16485
16472
  ...[...moduleCandidates.values()].flat()
16486
16473
  ].map(fileFingerprint).join("|");
16487
16474
  const cacheKey = `${packageRoot}:${[...requested].sort().join(",")}`;
@@ -16508,8 +16495,8 @@ function fileFingerprint(path) {
16508
16495
  }
16509
16496
  }
16510
16497
  function isWithin2(root, candidate2) {
16511
- const path = (0, import_node_path.relative)(root, candidate2);
16512
- return path === "" || !path.startsWith(`..${import_node_path.sep}`) && path !== ".." && !(0, import_node_path.isAbsolute)(path);
16498
+ const path = (0, import_node_path2.relative)(root, candidate2);
16499
+ return path === "" || !path.startsWith(`..${import_node_path2.sep}`) && path !== ".." && !(0, import_node_path2.isAbsolute)(path);
16513
16500
  }
16514
16501
  function safeContainedDirectory(root, candidate2) {
16515
16502
  try {
@@ -16523,10 +16510,10 @@ function safeContainedDirectory(root, candidate2) {
16523
16510
  }
16524
16511
  function findPackageRoot(startDir) {
16525
16512
  let dir = startDir;
16526
- const filesystemRoot = (0, import_node_path.parse)(dir).root;
16513
+ const filesystemRoot = (0, import_node_path2.parse)(dir).root;
16527
16514
  for (; ; ) {
16528
- if ((0, import_node_fs.existsSync)((0, import_node_path.join)(dir, "package.json"))) return dir;
16529
- const parent = (0, import_node_path.dirname)(dir);
16515
+ if ((0, import_node_fs.existsSync)((0, import_node_path2.join)(dir, "package.json"))) return dir;
16516
+ const parent = (0, import_node_path2.dirname)(dir);
16530
16517
  if (dir === filesystemRoot || parent === dir) return null;
16531
16518
  dir = parent;
16532
16519
  }
@@ -16563,9 +16550,9 @@ function stringProperty(value, ...keys) {
16563
16550
  return typeof current === "string" && current.trim() !== "" ? current : null;
16564
16551
  }
16565
16552
  function resolveAlias(packageRoot, alias) {
16566
- if ((0, import_node_path.isAbsolute)(alias)) return null;
16567
- if (alias.startsWith(".")) return (0, import_node_path.resolve)(packageRoot, alias);
16568
- const configPath = ["tsconfig.json", "jsconfig.json"].map((name) => (0, import_node_path.join)(packageRoot, name)).find(import_node_fs.existsSync);
16553
+ if ((0, import_node_path2.isAbsolute)(alias)) return null;
16554
+ if (alias.startsWith(".")) return (0, import_node_path2.resolve)(packageRoot, alias);
16555
+ const configPath = ["tsconfig.json", "jsconfig.json"].map((name) => (0, import_node_path2.join)(packageRoot, name)).find(import_node_fs.existsSync);
16569
16556
  if (configPath === void 0) return null;
16570
16557
  const config = readJsonc(configPath);
16571
16558
  if (typeof config !== "object" || config === null) return null;
@@ -16578,7 +16565,7 @@ function resolveAlias(packageRoot, alias) {
16578
16565
  const matches = matchingAliasTargets(paths, alias);
16579
16566
  const [match] = matches;
16580
16567
  if (matches.length !== 1 || match === void 0) return null;
16581
- return (0, import_node_path.resolve)(packageRoot, baseUrl, match);
16568
+ return (0, import_node_path2.resolve)(packageRoot, baseUrl, match);
16582
16569
  }
16583
16570
  function exportsPrimitive(path, exportName) {
16584
16571
  try {
@@ -18119,8 +18106,7 @@ function isNullish(node) {
18119
18106
  }
18120
18107
  function referenceCarrier(node, context, depth) {
18121
18108
  if (node.typeName.type !== import_utils100.AST_NODE_TYPES.Identifier) return void 0;
18122
- const variable = import_utils100.ASTUtils.findVariable(context.sourceCode.getScope(node), node.typeName.name);
18123
- const definitions = variable?.defs ?? [];
18109
+ const definitions = typeDefinitions(node, context);
18124
18110
  const args = node.typeArguments?.params;
18125
18111
  if (definitions.length === 0 && ["Array", "ReadonlyArray"].includes(node.typeName.name) && args?.length === 1) {
18126
18112
  return arrayCarrier(rawCarrier(args[0], context, depth + 1));
@@ -18130,6 +18116,17 @@ function referenceCarrier(node, context, depth) {
18130
18116
  if (declaration?.type !== import_utils100.AST_NODE_TYPES.TSTypeAliasDeclaration || declaration.typeParameters !== void 0) return void 0;
18131
18117
  return rawCarrier(declaration.typeAnnotation, context, depth + 1);
18132
18118
  }
18119
+ function typeDefinitions(node, context) {
18120
+ if (node.typeName.type !== import_utils100.AST_NODE_TYPES.Identifier) return [];
18121
+ let scope = context.sourceCode.getScope(node);
18122
+ while (scope !== null) {
18123
+ const variable = scope.set.get(node.typeName.name);
18124
+ const definitions = variable?.defs.filter((definition) => definition.isTypeDefinition) ?? [];
18125
+ if (definitions.length > 0 || variable?.isTypeVariable === true) return definitions;
18126
+ scope = scope.upper;
18127
+ }
18128
+ return [];
18129
+ }
18133
18130
  function rawCarrier(node, context, depth = 0) {
18134
18131
  if (node === void 0 || depth >= MAX_ALIAS_DEPTH) return void 0;
18135
18132
  switch (node.type) {
@@ -18200,6 +18197,9 @@ var prefer_nominal_id_types_default = createRule({
18200
18197
  FunctionExpression: (node) => checkBoundary(node, context),
18201
18198
  TSDeclareFunction: (node) => checkBoundary(node, context),
18202
18199
  TSEmptyBodyFunctionExpression: (node) => checkBoundary(node, context),
18200
+ TSCallSignatureDeclaration: (node) => checkBoundary(node, context),
18201
+ TSConstructSignatureDeclaration: (node) => checkBoundary(node, context),
18202
+ TSConstructorType: (node) => checkBoundary(node, context),
18203
18203
  TSFunctionType: (node) => checkBoundary(node, context),
18204
18204
  TSMethodSignature: (node) => checkBoundary(node, context)
18205
18205
  };
@@ -22666,15 +22666,6 @@ var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
22666
22666
  }
22667
22667
  ]
22668
22668
  };
22669
- function matchesAnyPattern3(filename, patterns) {
22670
- for (const pattern of patterns) {
22671
- const regexSource = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "::DOUBLESTAR::").replace(/\*/g, "[^/\\\\]*").replace(/::DOUBLESTAR::/g, ".*");
22672
- if (new RegExp(`^${regexSource}$`).test(filename)) {
22673
- return true;
22674
- }
22675
- }
22676
- return false;
22677
- }
22678
22669
  function emptySignal(expression, resolvesToGlobal) {
22679
22670
  const value = unwrapExpression(expression);
22680
22671
  if (value.type === import_utils121.AST_NODE_TYPES.Literal && value.value === null)
@@ -22755,7 +22746,7 @@ var require_fetch_timeout_default = createRule({
22755
22746
  return {};
22756
22747
  }
22757
22748
  const allowIn = optionsArg?.allowIn ?? [];
22758
- if (allowIn.length > 0 && matchesAnyPattern3(context.filename, allowIn)) {
22749
+ if (allowIn.length > 0 && matchesAnyPattern(context.filename, allowIn)) {
22759
22750
  return {};
22760
22751
  }
22761
22752
  function resolvesToGlobal(identifier) {
@@ -24871,7 +24862,7 @@ var import_utils131 = require("@typescript-eslint/utils");
24871
24862
 
24872
24863
  // src/rules/_is-framework-entrypoint.ts
24873
24864
  var import_node_fs2 = require("fs");
24874
- var import_node_path2 = require("path");
24865
+ var import_node_path3 = require("path");
24875
24866
  var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]);
24876
24867
  var NEXT_COMPONENT = /^(?:src\/)?app\/(?:.*\/)?(?:page|layout|loading|not-found|template|error|global-error|default|forbidden|unauthorized)\.[jt]sx?$/u;
24877
24868
  var NEXT_METADATA = /^(?:src\/)?app\/(?:.*\/)?(?:(?:opengraph-image|twitter-image|icon|apple-icon)\.[jt]sx?|(?:robots|sitemap|manifest)\.[jt]s)$/u;
@@ -24881,7 +24872,7 @@ function isFrameworkEntrypoint(filename, exportKey) {
24881
24872
  if (!/(?:^|\/)(?:app|pages)\/|(?:^|\/)(?:middleware|proxy|instrumentation)\.[jt]s$/u.test(normalized)) return false;
24882
24873
  const owner = packageOwner(normalized);
24883
24874
  if (owner === null) return false;
24884
- const path = (0, import_node_path2.relative)(owner.root, normalized).replaceAll("\\", "/");
24875
+ const path = (0, import_node_path3.relative)(owner.root, normalized).replaceAll("\\", "/");
24885
24876
  if (declaresFramework(owner.metadata, "next") && isNextEntrypoint(path, exportKey)) return true;
24886
24877
  return declaresFramework(owner.metadata, "astro") && isAstroEntrypoint(path, exportKey);
24887
24878
  }
@@ -24903,14 +24894,14 @@ function isAstroEntrypoint(path, exportKey) {
24903
24894
  );
24904
24895
  }
24905
24896
  function packageOwner(filename) {
24906
- let root = (0, import_node_path2.dirname)(filename);
24897
+ let root = (0, import_node_path3.dirname)(filename);
24907
24898
  while (true) {
24908
24899
  try {
24909
- return { root, metadata: JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(root, "package.json"), "utf8")) };
24900
+ return { root, metadata: JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path3.join)(root, "package.json"), "utf8")) };
24910
24901
  } catch (error) {
24911
24902
  if (typeof error !== "object" || error === null || !("code" in error) || error.code !== "ENOENT") return null;
24912
24903
  }
24913
- const parent = (0, import_node_path2.dirname)(root);
24904
+ const parent = (0, import_node_path3.dirname)(root);
24914
24905
  if (parent === root) return null;
24915
24906
  root = parent;
24916
24907
  }