lint-suite 2.0.1 → 2.1.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.
Files changed (44) hide show
  1. package/README.md +27 -7
  2. package/eslint.js +221 -85
  3. package/eslint.js.map +4 -4
  4. package/lib/rules/file-cache.d.ts +1 -1
  5. package/lib/rules/file-cache.d.ts.map +1 -1
  6. package/lib/rules/no-unstyled-classes/styles/stylesheet-classes.d.ts.map +1 -1
  7. package/lib/rules/no-unstyled-classes/styles/stylesheet-collection.d.ts +1 -1
  8. package/lib/rules/no-unstyled-classes/styles/stylesheet-collection.d.ts.map +1 -1
  9. package/lib/rules/no-unstyled-classes/styles/stylesheet-imports.d.ts +8 -1
  10. package/lib/rules/no-unstyled-classes/styles/stylesheet-imports.d.ts.map +1 -1
  11. package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts.map +1 -1
  12. package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts +1 -0
  13. package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts.map +1 -1
  14. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts.map +1 -1
  15. package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts.map +1 -1
  16. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-dangling-imports.d.ts +8 -0
  17. package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-dangling-imports.d.ts.map +1 -0
  18. package/lib/rules/no-unused-classes/no-unused-classes.d.ts.map +1 -1
  19. package/lib/rules/no-unused-classes/template/template-usage.d.ts.map +1 -1
  20. package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts +9 -1
  21. package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts.map +1 -1
  22. package/lib/rules/no-unused-exports/disk-resolver.d.ts +9 -0
  23. package/lib/rules/no-unused-exports/disk-resolver.d.ts.map +1 -0
  24. package/lib/rules/no-unused-exports/export-index.d.ts.map +1 -1
  25. package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts +3 -3
  26. package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts.map +1 -1
  27. package/lib/rules/no-unused-exports/utils/module-resolver.util.d.ts +8 -0
  28. package/lib/rules/no-unused-exports/utils/module-resolver.util.d.ts.map +1 -0
  29. package/lib/rules/package-version.d.ts +2 -0
  30. package/lib/rules/package-version.d.ts.map +1 -0
  31. package/lib/rules/utils/template-classes.util.d.ts +2 -0
  32. package/lib/rules/utils/template-classes.util.d.ts.map +1 -1
  33. package/lib/typescript-safety.d.ts.map +1 -1
  34. package/package.json +4 -7
  35. package/stylelint.js +96 -28
  36. package/stylelint.js.map +4 -4
  37. package/eslint.cjs +0 -7363
  38. package/eslint.cjs.map +0 -7
  39. package/lib/rules/no-unused-exports/utils/module-target.util.d.ts +0 -4
  40. package/lib/rules/no-unused-exports/utils/module-target.util.d.ts.map +0 -1
  41. package/prettier.cjs +0 -50
  42. package/prettier.cjs.map +0 -7
  43. package/stylelint.cjs +0 -947
  44. package/stylelint.cjs.map +0 -7
package/eslint.js CHANGED
@@ -13,8 +13,8 @@ var definePlugin = (name, rules) => {
13
13
  import { ESLintUtils } from "@typescript-eslint/utils";
14
14
 
15
15
  // packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/component-stylesheets.ts
16
- import { existsSync } from "node:fs";
17
- import { dirname as dirname2, resolve } from "node:path";
16
+ import { existsSync as existsSync2 } from "node:fs";
17
+ import { dirname as dirname3, resolve } from "node:path";
18
18
 
19
19
  // packages/lint-suite/src/lib/rules/component-metadata.ts
20
20
  import {
@@ -34,12 +34,59 @@ import {
34
34
  // packages/lint-suite/src/lib/rules/file-cache.ts
35
35
  import {
36
36
  mkdirSync,
37
- readFileSync,
37
+ readFileSync as readFileSync2,
38
38
  renameSync,
39
39
  statSync,
40
40
  writeFileSync
41
41
  } from "node:fs";
42
+ import { dirname as dirname2, join as join2 } from "node:path";
43
+
44
+ // packages/lint-suite/src/lib/rules/package-version.ts
45
+ import { existsSync, readFileSync } from "node:fs";
42
46
  import { dirname, join } from "node:path";
47
+ import { fileURLToPath } from "node:url";
48
+ var PACKAGE_NAME = "lint-suite";
49
+ var DEV_VERSION = "dev";
50
+ var MAX_MANIFEST_DEPTH = 6;
51
+ var moduleDirectory = () => {
52
+ const url = import.meta.url;
53
+ if (typeof url !== "string") return null;
54
+ return dirname(fileURLToPath(url));
55
+ };
56
+ var manifestVersion = (file) => {
57
+ const isPresent = existsSync(file);
58
+ if (!isPresent) return null;
59
+ try {
60
+ const manifest = JSON.parse(readFileSync(file, "utf8"));
61
+ const isRecord = typeof manifest === "object" && manifest !== null;
62
+ if (!isRecord) return null;
63
+ if (!("name" in manifest)) return null;
64
+ if (manifest.name !== PACKAGE_NAME) return null;
65
+ if (!("version" in manifest)) return null;
66
+ if (typeof manifest.version !== "string") return null;
67
+ return manifest.version;
68
+ } catch {
69
+ return null;
70
+ }
71
+ };
72
+ var parentOf = (directory) => {
73
+ const parent = dirname(directory);
74
+ if (parent === directory) return null;
75
+ return parent;
76
+ };
77
+ var packageVersion = () => {
78
+ let directory = moduleDirectory();
79
+ for (let depth = 0; depth < MAX_MANIFEST_DEPTH; depth += 1) {
80
+ if (directory === null) break;
81
+ const version = manifestVersion(join(directory, "package.json"));
82
+ if (version !== null) return version;
83
+ directory = parentOf(directory);
84
+ }
85
+ return DEV_VERSION;
86
+ };
87
+ var PACKAGE_VERSION = packageVersion();
88
+
89
+ // packages/lint-suite/src/lib/rules/file-cache.ts
43
90
  var CACHE_FORMAT_VERSION = 1;
44
91
  var caches = /* @__PURE__ */ new Set();
45
92
  var isFlushRegistered = false;
@@ -48,12 +95,12 @@ var cacheDirectory = () => {
48
95
  const isDisabled = LINT_SUITE_CACHE === "0";
49
96
  if (isDisabled) return null;
50
97
  if (LINT_SUITE_CACHE_DIR) return LINT_SUITE_CACHE_DIR;
51
- return join(process.cwd(), "node_modules", ".cache", "lint-suite");
98
+ return join2(process.cwd(), "node_modules", ".cache", "lint-suite");
52
99
  };
53
100
  var cacheFile = (name) => {
54
101
  const directory = cacheDirectory();
55
102
  if (directory === null) return null;
56
- return join(directory, `${name}.v${CACHE_FORMAT_VERSION}.json`);
103
+ return join2(directory, `${name}.v${CACHE_FORMAT_VERSION}.json`);
57
104
  };
58
105
  var isCachedFile = (value) => {
59
106
  const isObject = typeof value === "object" && value !== null;
@@ -76,7 +123,7 @@ var load = (cache2) => {
76
123
  const file = cacheFile(cache2.name);
77
124
  if (file === null) return;
78
125
  try {
79
- const stored = storedEntries(readFileSync(file, "utf8"));
126
+ const stored = storedEntries(readFileSync2(file, "utf8"));
80
127
  for (const [path, entry] of stored) cache2.entries.set(path, entry);
81
128
  } catch {
82
129
  return;
@@ -86,7 +133,7 @@ var write = (cache2) => {
86
133
  const file = cacheFile(cache2.name);
87
134
  if (file === null) return;
88
135
  try {
89
- mkdirSync(dirname(file), { recursive: true });
136
+ mkdirSync(dirname2(file), { recursive: true });
90
137
  const temporary = `${file}.${process.pid}.tmp`;
91
138
  const stored = Object.fromEntries(cache2.entries);
92
139
  writeFileSync(temporary, JSON.stringify(stored));
@@ -122,10 +169,10 @@ var readCached = (cache2, path, parse2) => {
122
169
  if (!cache2.loaded) load(cache2);
123
170
  try {
124
171
  const stats = statSync(path, { bigint: true });
125
- const version = `${stats.mtimeNs}:${stats.size}`;
172
+ const version = `${PACKAGE_VERSION}:${stats.mtimeNs}:${stats.size}`;
126
173
  const cached = cache2.entries.get(path);
127
174
  if (cached?.version === version) return cached.value;
128
- const value = parse2(readFileSync(path, "utf8"), path);
175
+ const value = parse2(readFileSync2(path, "utf8"), path);
129
176
  const fresh = { value, version };
130
177
  cache2.entries.set(path, fresh);
131
178
  cache2.dirty = true;
@@ -231,7 +278,7 @@ var matchesTemplate = (metadata, directory, templateFilename) => {
231
278
  };
232
279
  var templateMetadata = (componentPath, templateFilename) => {
233
280
  const components = componentMetadata(componentPath);
234
- const directory = dirname2(componentPath);
281
+ const directory = dirname3(componentPath);
235
282
  const matches = (metadata) => {
236
283
  return matchesTemplate(metadata, directory, templateFilename);
237
284
  };
@@ -246,7 +293,7 @@ var stylesheetFiles = (paths, directory) => {
246
293
  const sources = [];
247
294
  for (const path of paths) {
248
295
  const resolved = resolve(directory, path);
249
- const isPresent = existsSync(resolved);
296
+ const isPresent = existsSync2(resolved);
250
297
  if (!isPresent) continue;
251
298
  const source = { kind: "file", path: resolved };
252
299
  sources.push(source);
@@ -267,7 +314,7 @@ var inlineSources = (styles, componentPath) => {
267
314
  var metadataSources = (componentPath, templateFilename) => {
268
315
  const metadata = templateMetadata(componentPath, templateFilename);
269
316
  if (metadata === null) return [];
270
- const directory = dirname2(componentPath);
317
+ const directory = dirname3(componentPath);
271
318
  const files = stylesheetFiles(metadata.styleUrls, directory);
272
319
  const inline = inlineSources(metadata.styles, componentPath);
273
320
  return [...files, ...inline];
@@ -276,7 +323,7 @@ var siblingSources = (templateFilename) => {
276
323
  const base2 = templateFilename.replace(HTML_EXTENSION, "");
277
324
  const candidateOf = (extension) => `${base2}${extension}`;
278
325
  const candidates = SIBLING_EXTENSIONS.map(candidateOf);
279
- return stylesheetFiles(candidates, dirname2(templateFilename));
326
+ return stylesheetFiles(candidates, dirname3(templateFilename));
280
327
  };
281
328
  var componentStylesheets = (templateFilename) => {
282
329
  const componentPath = templateFilename.replace(HTML_EXTENSION, ".ts");
@@ -286,7 +333,7 @@ var componentStylesheets = (templateFilename) => {
286
333
  };
287
334
 
288
335
  // packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/linked-stylesheets.ts
289
- import { dirname as dirname3 } from "node:path";
336
+ import { dirname as dirname4 } from "node:path";
290
337
 
291
338
  // packages/lint-suite/src/lib/rules/utils/template-links.util.ts
292
339
  var LINK_TAG = /<link\b[^>]*>/giu;
@@ -309,16 +356,16 @@ var linkedStylesheetHrefs = (template) => {
309
356
  // packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/linked-stylesheets.ts
310
357
  var linkedStylesheets = (template, templateFilename) => {
311
358
  const hrefs = linkedStylesheetHrefs(template);
312
- return stylesheetFiles(hrefs, dirname3(templateFilename));
359
+ return stylesheetFiles(hrefs, dirname4(templateFilename));
313
360
  };
314
361
 
315
362
  // packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/stylesheet-classes.ts
316
- import { dirname as dirname5 } from "node:path";
363
+ import { dirname as dirname6 } from "node:path";
317
364
  import { parse } from "postcss-scss";
318
365
 
319
366
  // packages/lint-suite/src/lib/rules/no-unstyled-classes/styles/stylesheet-imports.ts
320
- import { existsSync as existsSync2 } from "node:fs";
321
- import { basename, dirname as dirname4, join as join2, resolve as resolve2 } from "node:path";
367
+ import { existsSync as existsSync3 } from "node:fs";
368
+ import { basename, dirname as dirname5, join as join3, resolve as resolve2 } from "node:path";
322
369
  var QUOTED = /'([^']*)'|"([^"]*)"/u;
323
370
  var SKIPPED_PREFIXES = ["sass:", "http", "url("];
324
371
  var specifierOf = (params) => {
@@ -335,25 +382,28 @@ var isResolvable = (specifier) => {
335
382
  if (isSkipped) return false;
336
383
  return !specifier.endsWith(".css");
337
384
  };
385
+ var importSpecifier = (params) => {
386
+ const specifier = specifierOf(params);
387
+ if (specifier === null) return null;
388
+ const isCandidate = isResolvable(specifier);
389
+ if (!isCandidate) return null;
390
+ return specifier;
391
+ };
338
392
  var candidatesOf = (path) => {
339
393
  const isStylesheet = path.endsWith(".scss");
340
- if (isStylesheet) return [path, join2(dirname4(path), `_${basename(path)}`)];
341
- const partial = join2(dirname4(path), `_${basename(path)}.scss`);
394
+ if (isStylesheet) return [path, join3(dirname5(path), `_${basename(path)}`)];
395
+ const partial = join3(dirname5(path), `_${basename(path)}.scss`);
342
396
  return [
343
397
  `${path}.scss`,
344
398
  partial,
345
- join2(path, "index.scss"),
346
- join2(path, "_index.scss")
399
+ join3(path, "index.scss"),
400
+ join3(path, "_index.scss")
347
401
  ];
348
402
  };
349
- var resolveStylesheetImport = (params, directory) => {
350
- const specifier = specifierOf(params);
351
- if (specifier === null) return null;
352
- const isCandidate = isResolvable(specifier);
353
- if (!isCandidate) return null;
403
+ var resolveStylesheetImport = (specifier, directory) => {
354
404
  const path = resolve2(directory, specifier);
355
405
  const candidates = candidatesOf(path);
356
- const existing = candidates.find((candidate) => existsSync2(candidate));
406
+ const existing = candidates.find((candidate) => existsSync3(candidate));
357
407
  return existing ?? null;
358
408
  };
359
409
 
@@ -456,19 +506,19 @@ var addSelectors = (selectors, entry) => {
456
506
  entry.patterns.push(...patterns);
457
507
  }
458
508
  };
459
- var addImport = (node, entry, directory) => {
509
+ var addImport = (node, entry) => {
460
510
  const isImport = IMPORT_AT_RULES.has(node.name);
461
511
  if (!isImport) return;
462
- const imported = resolveStylesheetImport(node.params, directory);
463
- if (imported !== null) entry.imports.push(imported);
512
+ const specifier = importSpecifier(node.params);
513
+ if (specifier !== null) entry.imports.push(specifier);
464
514
  };
465
- var collectStylesheet = (root, directory) => {
515
+ var collectStylesheet = (root) => {
466
516
  const entry = { classes: [], patterns: [], imports: [] };
467
517
  const onRule = (_rule, resolved) => {
468
518
  addSelectors(resolved, entry);
469
519
  };
470
520
  const onAtRule = (node) => {
471
- addImport(node, entry, directory);
521
+ addImport(node, entry);
472
522
  };
473
523
  walkResolvedRules(root, onRule);
474
524
  root.walkAtRules(onAtRule);
@@ -485,8 +535,7 @@ var inlineStylesheets = /* @__PURE__ */ new Map();
485
535
  var merged = /* @__PURE__ */ new Map();
486
536
  var parseStylesheet = (source, path) => {
487
537
  try {
488
- const root = parse(source, { from: path });
489
- return collectStylesheet(root, dirname5(path));
538
+ return collectStylesheet(parse(source, { from: path }));
490
539
  } catch {
491
540
  return EMPTY_ENTRY;
492
541
  }
@@ -502,14 +551,16 @@ var inlineEntry = (source, path) => {
502
551
  inlineStylesheets.set(key2, entry);
503
552
  return entry;
504
553
  };
505
- var collectImports = (entry, chain, visited) => {
506
- for (const imported of entry.imports) {
554
+ var collectImports = (entry, directory, chain, visited) => {
555
+ for (const specifier of entry.imports) {
556
+ const imported = resolveStylesheetImport(specifier, directory);
557
+ if (imported === null) continue;
507
558
  const isVisited = visited.has(imported);
508
559
  if (isVisited) continue;
509
560
  visited.add(imported);
510
561
  const importedEntry = fileEntry(imported);
511
562
  chain.push(importedEntry);
512
- collectImports(importedEntry, chain, visited);
563
+ collectImports(importedEntry, dirname6(imported), chain, visited);
513
564
  }
514
565
  };
515
566
  var entryOf = (source) => {
@@ -524,7 +575,7 @@ var collectChain = (source, chain, visited) => {
524
575
  }
525
576
  const entry = entryOf(source);
526
577
  chain.push(entry);
527
- collectImports(entry, chain, visited);
578
+ collectImports(entry, dirname6(source.path), chain, visited);
528
579
  };
529
580
  var mergeChain = (chain) => {
530
581
  const exact = /* @__PURE__ */ new Set();
@@ -668,7 +719,12 @@ var classExpressionLiterals = (source) => {
668
719
  };
669
720
 
670
721
  // packages/lint-suite/src/lib/rules/utils/template-classes.util.ts
671
- var CLASS_ATTRIBUTE = "class";
722
+ var CLASS_ATTRIBUTES = [
723
+ "class",
724
+ "routerLinkActive",
725
+ "animate.enter",
726
+ "animate.leave"
727
+ ];
672
728
  var CLASS_BINDING_PREFIX = "class.";
673
729
  var TOKEN = /\S+/gu;
674
730
  var expressionSource = (value) => {
@@ -697,11 +753,11 @@ var boundClassName = (input) => {
697
753
  return input.name;
698
754
  };
699
755
  var isClassExpression = (input) => {
700
- const isClassName = input.name === CLASS_ATTRIBUTE;
756
+ const isClassName = CLASS_ATTRIBUTES.includes(input.name);
701
757
  if (!isClassName) return false;
702
758
  const { details } = input.keySpan;
703
759
  if (details === null) return true;
704
- return details === CLASS_ATTRIBUTE;
760
+ return details === input.name;
705
761
  };
706
762
  var expressionClasses = (input) => {
707
763
  const source = expressionSource(input.value);
@@ -726,7 +782,7 @@ var inputClasses = (input) => {
726
782
  var templateClasses = (node) => {
727
783
  const classes = [];
728
784
  for (const attribute of node.attributes) {
729
- const isClassName = attribute.name === CLASS_ATTRIBUTE;
785
+ const isClassName = CLASS_ATTRIBUTES.includes(attribute.name);
730
786
  if (isClassName) {
731
787
  const found = staticClasses(attribute);
732
788
  classes.push(...found);
@@ -1177,7 +1233,7 @@ var methodCandidate = (node, localPrivateOnly, implementedMethods) => {
1177
1233
  };
1178
1234
 
1179
1235
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
1180
- import { dirname as dirname6, resolve as resolve3 } from "node:path";
1236
+ import { dirname as dirname7, resolve as resolve3 } from "node:path";
1181
1237
  import { TSESTree as TSESTree5 } from "@typescript-eslint/utils";
1182
1238
 
1183
1239
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.ts
@@ -1221,7 +1277,7 @@ import {
1221
1277
  R3TargetBinder,
1222
1278
  parseTemplate
1223
1279
  } from "@angular/compiler";
1224
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
1280
+ import { readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
1225
1281
 
1226
1282
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.ts
1227
1283
  import {
@@ -1320,7 +1376,7 @@ var externalTemplateReads = (filename) => {
1320
1376
  const version = `${stats.mtimeNs}:${stats.size}`;
1321
1377
  const cached = externalTemplates.get(filename);
1322
1378
  if (cached?.version === version) return cached.reads;
1323
- const reads = templateReads(readFileSync2(filename, "utf8"), filename);
1379
+ const reads = templateReads(readFileSync3(filename, "utf8"), filename);
1324
1380
  externalTemplates.set(filename, { reads, version });
1325
1381
  return reads;
1326
1382
  } catch {
@@ -1388,7 +1444,7 @@ var inlineTemplateReads = (template, reads, filename) => {
1388
1444
  var externalTemplatePropertyReads = (templateUrl, reads, filename) => {
1389
1445
  if (!templateUrl) return true;
1390
1446
  const url = text(templateUrl);
1391
- return url !== null && addReads(reads, externalTemplateReads(resolve3(dirname6(filename), url)));
1447
+ return url !== null && addReads(reads, externalTemplateReads(resolve3(dirname7(filename), url)));
1392
1448
  };
1393
1449
  var componentTemplateReads = (metadata, reads, filename) => {
1394
1450
  const template = metadataValue2(metadata, "template");
@@ -1617,7 +1673,7 @@ var lexicalThisVisitor = (thisStack) => {
1617
1673
 
1618
1674
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.ts
1619
1675
  import { TSESTree as TSESTree8 } from "@typescript-eslint/utils";
1620
- var parentOf = (node) => {
1676
+ var parentOf2 = (node) => {
1621
1677
  if (node.type === TSESTree8.AST_NODE_TYPES.Program) return void 0;
1622
1678
  return node.parent;
1623
1679
  };
@@ -1661,10 +1717,10 @@ var isWrapping = (parent, child) => {
1661
1717
  };
1662
1718
  var isDirectWrite = (node) => {
1663
1719
  let current = node;
1664
- let parent = parentOf(node);
1720
+ let parent = parentOf2(node);
1665
1721
  while (parent && isTypeScriptExpressionWrapper(parent) && parent.expression === current) {
1666
1722
  current = parent;
1667
- parent = parentOf(parent);
1723
+ parent = parentOf2(parent);
1668
1724
  }
1669
1725
  const isDeleteExpression2 = parent?.type === TSESTree8.AST_NODE_TYPES.UnaryExpression && parent.operator === "delete";
1670
1726
  const isAssignment = isSimpleAssignmentTarget(parent, current);
@@ -1672,7 +1728,7 @@ var isDirectWrite = (node) => {
1672
1728
  };
1673
1729
  var isDestructuringOrLoopTarget = (node) => {
1674
1730
  let current = node;
1675
- let parent = parentOf(node);
1731
+ let parent = parentOf2(node);
1676
1732
  let patternTarget = false;
1677
1733
  while (parent) {
1678
1734
  const wrapper = isWrapping(parent, current);
@@ -1682,7 +1738,7 @@ var isDestructuringOrLoopTarget = (node) => {
1682
1738
  patternTarget = true;
1683
1739
  }
1684
1740
  current = parent;
1685
- parent = parentOf(parent);
1741
+ parent = parentOf2(parent);
1686
1742
  }
1687
1743
  const isSimpleTarget = isSimpleAssignmentTarget(parent, current);
1688
1744
  const isAssignedPattern = patternTarget && isSimpleTarget;
@@ -1865,11 +1921,11 @@ var replaceDeclarations = (index, previous, next) => {
1865
1921
  };
1866
1922
 
1867
1923
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.ts
1868
- import { dirname as dirname9, normalize as normalize2 } from "node:path";
1924
+ import { dirname as dirname10, normalize as normalize2 } from "node:path";
1869
1925
 
1870
1926
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
1871
- import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
1872
- import { dirname as dirname7, normalize } from "node:path";
1927
+ import { readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
1928
+ import { dirname as dirname8, normalize } from "node:path";
1873
1929
  import { isIdentifier as isIdentifier3, isStringLiteralLike as isStringLiteralLike3 } from "typescript";
1874
1930
 
1875
1931
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
@@ -2308,6 +2364,7 @@ var addTemplateReads = ({
2308
2364
  };
2309
2365
 
2310
2366
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
2367
+ var MISSING = -1n;
2311
2368
  var memberNameOf2 = (member) => {
2312
2369
  const name = member.name;
2313
2370
  if (!name) return [];
@@ -2333,17 +2390,27 @@ var addTemplateMentions = (source, sink) => {
2333
2390
  for (const [name] of source.matchAll(IDENTIFIER)) sink.addMention(name);
2334
2391
  };
2335
2392
  var templateFileVersion = (fileName) => {
2336
- const { mtimeNs, size } = statSync3(fileName, { bigint: true });
2337
- const directory = dirname7(normalize(fileName));
2338
- const version = { directory, fileName, mtimeNs, size };
2339
- return version;
2393
+ const directory = dirname8(normalize(fileName));
2394
+ try {
2395
+ const { mtimeNs, size } = statSync3(fileName, { bigint: true });
2396
+ const version = { directory, fileName, mtimeNs, size };
2397
+ return version;
2398
+ } catch {
2399
+ const missing = {
2400
+ directory,
2401
+ fileName,
2402
+ mtimeNs: MISSING,
2403
+ size: MISSING
2404
+ };
2405
+ return missing;
2406
+ }
2340
2407
  };
2341
2408
  var templateFileIsCurrent = (version) => {
2342
2409
  try {
2343
2410
  const current = statSync3(version.fileName, { bigint: true });
2344
2411
  return current.mtimeNs === version.mtimeNs && current.size === version.size;
2345
2412
  } catch {
2346
- return false;
2413
+ return version.mtimeNs === MISSING;
2347
2414
  }
2348
2415
  };
2349
2416
  var templateSourceOf = (angularClass2, allNames, sink, versions) => {
@@ -2362,9 +2429,9 @@ var templateSourceOf = (angularClass2, allNames, sink, versions) => {
2362
2429
  return inlineSource;
2363
2430
  }
2364
2431
  const templateFileName = template.fileName;
2432
+ versions.push(templateFileVersion(templateFileName));
2365
2433
  try {
2366
- versions.push(templateFileVersion(templateFileName));
2367
- const source = readFileSync3(templateFileName, "utf8");
2434
+ const source = readFileSync4(templateFileName, "utf8");
2368
2435
  const externalSource = {
2369
2436
  fileName: templateFileName,
2370
2437
  source
@@ -2412,6 +2479,18 @@ var collectAngularTemplateReads = ({
2412
2479
  return templateReads2;
2413
2480
  };
2414
2481
 
2482
+ // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-dangling-imports.ts
2483
+ import { isImportDeclaration } from "typescript";
2484
+ var hasDanglingImport = (sourceFile, checker) => {
2485
+ for (const statement of sourceFile.statements) {
2486
+ if (!isImportDeclaration(statement)) continue;
2487
+ if (!statement.importClause) continue;
2488
+ const symbol = checker.getSymbolAtLocation(statement.moduleSpecifier);
2489
+ if (!symbol) return true;
2490
+ }
2491
+ return false;
2492
+ };
2493
+
2415
2494
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
2416
2495
  import {
2417
2496
  forEachChild as forEachChild2,
@@ -2969,6 +3048,13 @@ var collectFileReads = (index, sourceFile, checker, sink) => {
2969
3048
  return noTemplateReads;
2970
3049
  }
2971
3050
  };
3051
+ var addDanglingFallback = (index, sourceFile, mentionedNames, sink) => {
3052
+ const isCandidate = (name) => index.candidateNames.has(name);
3053
+ const mentioned = [...mentionedNames];
3054
+ const names = mentioned.filter(isCandidate);
3055
+ const reason = `${sourceFile.fileName}: an import resolves to no module`;
3056
+ sink.addFallbackNames(names, reason);
3057
+ };
2972
3058
  var computeEntry = (index, sourceFile, checker) => {
2973
3059
  const declarations = /* @__PURE__ */ new Set();
2974
3060
  const dependencies = /* @__PURE__ */ new Set();
@@ -2993,9 +3079,12 @@ var computeEntry = (index, sourceFile, checker) => {
2993
3079
  }
2994
3080
  };
2995
3081
  const reads = collectFileReads(index, sourceFile, checker, sink);
3082
+ const dangling = hasDanglingImport(sourceFile, checker);
3083
+ if (dangling) addDanglingFallback(index, sourceFile, mentionedNames, sink);
2996
3084
  dependencies.delete(sourceFile);
2997
3085
  const fileEntry2 = {
2998
3086
  ...reads,
3087
+ dangling,
2999
3088
  declarations,
3000
3089
  dependencies,
3001
3090
  fallbackNames,
@@ -3030,7 +3119,7 @@ import {
3030
3119
  canHaveDecorators as canHaveDecorators2,
3031
3120
  getDecorators as getDecorators2,
3032
3121
  isCallExpression as isCallExpression2,
3033
- isImportDeclaration,
3122
+ isImportDeclaration as isImportDeclaration2,
3034
3123
  isStringLiteralLike as isStringLiteralLike5
3035
3124
  } from "typescript";
3036
3125
  var decoratorKinds = [
@@ -3046,16 +3135,16 @@ var isAngularCoreFile = (declaration) => {
3046
3135
  const fileName = declaration.getSourceFile().fileName.replaceAll("\\", "/");
3047
3136
  return fileName.includes("/node_modules/@angular/core/");
3048
3137
  };
3049
- var parentOf2 = (node) => {
3138
+ var parentOf3 = (node) => {
3050
3139
  return node.parent;
3051
3140
  };
3052
3141
  var importedFromAngularCore = (declaration) => {
3053
- let current = parentOf2(declaration);
3142
+ let current = parentOf3(declaration);
3054
3143
  while (current) {
3055
- if (isImportDeclaration(current)) {
3144
+ if (isImportDeclaration2(current)) {
3056
3145
  return isStringLiteralLike5(current.moduleSpecifier) && current.moduleSpecifier.text === "@angular/core";
3057
3146
  }
3058
- current = parentOf2(current);
3147
+ current = parentOf3(current);
3059
3148
  }
3060
3149
  return false;
3061
3150
  };
@@ -3103,7 +3192,7 @@ var classDecoratorKind = (declaration, discovery) => {
3103
3192
  };
3104
3193
 
3105
3194
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.ts
3106
- import { dirname as dirname8, resolve as resolve4 } from "node:path";
3195
+ import { dirname as dirname9, resolve as resolve4 } from "node:path";
3107
3196
  import {
3108
3197
  isIdentifier as isIdentifier6,
3109
3198
  isNumericLiteral as isNumericLiteral2,
@@ -3153,7 +3242,7 @@ var templateOf = (metadata, fileName, discovery) => {
3153
3242
  if (url) {
3154
3243
  const text2 = stringValue(url, discovery);
3155
3244
  if (text2 === null) return void 0;
3156
- const externalFileName = resolve4(dirname8(fileName), text2);
3245
+ const externalFileName = resolve4(dirname9(fileName), text2);
3157
3246
  const externalTemplate = {
3158
3247
  fileName: externalFileName,
3159
3248
  kind: "external"
@@ -3536,6 +3625,7 @@ var lazyChecker = (program) => {
3536
3625
  let typeChecker;
3537
3626
  return () => typeChecker ??= program.getTypeChecker();
3538
3627
  };
3628
+ var isDangling = (entry) => entry.dangling;
3539
3629
  var indexMissingEntries = (index, sourceFiles, checker) => {
3540
3630
  for (const sourceFile of sourceFiles) {
3541
3631
  const isEntryIndexed = index.entries.has(sourceFile.fileName);
@@ -3547,6 +3637,7 @@ var reindexProgram = (index, program, checker) => {
3547
3637
  const indexable = indexableSourceFiles(program);
3548
3638
  const current = currentSourceFiles(program);
3549
3639
  dropReplacedEntries(index, current);
3640
+ dropEntries(index, isDangling);
3550
3641
  const newNames = reconcileClasses(index, indexable, current, checker);
3551
3642
  dropEntriesMentioning(index, newNames);
3552
3643
  index.program = program;
@@ -3571,7 +3662,7 @@ var isLocalEntry = (entry, sourceFile, directory) => {
3571
3662
  var refreshLocalEntries = (index, program, fileName, checker) => {
3572
3663
  const sourceFile = program.getSourceFile(fileName);
3573
3664
  if (!sourceFile) return;
3574
- const directory = dirname9(normalize2(sourceFile.fileName));
3665
+ const directory = dirname10(normalize2(sourceFile.fileName));
3575
3666
  const stale = [];
3576
3667
  for (const entry of index.entries.values()) {
3577
3668
  if (entry.templateVersions.length === 0) continue;
@@ -5760,7 +5851,24 @@ var ruleDefaults4 = { entryPoints: [...entryPointDefaults] };
5760
5851
  var defaultOptions7 = [ruleDefaults4];
5761
5852
 
5762
5853
  // packages/lint-suite/src/lib/rules/no-unused-exports/export-index.ts
5763
- import { dirname as dirname10 } from "node:path";
5854
+ import { dirname as dirname11 } from "node:path";
5855
+
5856
+ // packages/lint-suite/src/lib/rules/no-unused-exports/disk-resolver.ts
5857
+ import { resolveModuleName, sys } from "typescript";
5858
+ var diskResolver = (program) => {
5859
+ const options = program.getCompilerOptions();
5860
+ return (specifier) => {
5861
+ const containingFile = specifier.getSourceFile().fileName;
5862
+ const { resolvedModule } = resolveModuleName(
5863
+ specifier.text,
5864
+ containingFile,
5865
+ options,
5866
+ sys
5867
+ );
5868
+ if (!resolvedModule) return void 0;
5869
+ return program.getSourceFile(resolvedModule.resolvedFileName);
5870
+ };
5871
+ };
5764
5872
 
5765
5873
  // packages/lint-suite/src/lib/rules/no-unused-exports/utils/export-usage.util.ts
5766
5874
  var MAX_DEPTH = 50;
@@ -5991,7 +6099,7 @@ import {
5991
6099
  isCallExpression as isCallExpression4,
5992
6100
  isExportAssignment,
5993
6101
  isExportDeclaration,
5994
- isImportDeclaration as isImportDeclaration2,
6102
+ isImportDeclaration as isImportDeclaration3,
5995
6103
  isModuleDeclaration,
5996
6104
  isNamespaceImport
5997
6105
  } from "typescript";
@@ -6083,22 +6191,37 @@ var exportedNames = (statement) => {
6083
6191
  return [name];
6084
6192
  };
6085
6193
 
6086
- // packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-target.util.ts
6194
+ // packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-resolver.util.ts
6195
+ import { isStringLiteralLike as isStringLiteralLike9 } from "typescript";
6087
6196
  var declarationOf = (specifier, checker) => {
6088
6197
  const symbol = checker.getSymbolAtLocation(specifier);
6089
6198
  if (!symbol) return void 0;
6090
6199
  return symbol.valueDeclaration ?? symbol.declarations?.[0];
6091
6200
  };
6092
- var moduleTarget = (specifier, checker, isExternal) => {
6093
- if (!specifier) return void 0;
6201
+ var declaredSourceFile = (specifier, checker) => {
6094
6202
  const declaration = declarationOf(specifier, checker);
6095
6203
  if (!declaration) return void 0;
6096
- const sourceFile = declaration.getSourceFile();
6204
+ return declaration.getSourceFile();
6205
+ };
6206
+ var moduleTarget = (sourceFile, isExternal) => {
6097
6207
  if (sourceFile.isDeclarationFile) return void 0;
6098
6208
  const isSourceExternal = isExternal(sourceFile);
6099
6209
  if (isSourceExternal) return void 0;
6100
6210
  return sourceFile.fileName;
6101
6211
  };
6212
+ var moduleResolver = (resolution, dangling) => {
6213
+ const { checker, isExternal, onDisk } = resolution;
6214
+ return (specifier) => {
6215
+ if (!specifier) return void 0;
6216
+ const declared = declaredSourceFile(specifier, checker);
6217
+ if (declared) return moduleTarget(declared, isExternal);
6218
+ if (!isStringLiteralLike9(specifier)) return void 0;
6219
+ const found = onDisk(specifier);
6220
+ if (found) return moduleTarget(found, isExternal);
6221
+ dangling.push(specifier.text);
6222
+ return void 0;
6223
+ };
6224
+ };
6102
6225
 
6103
6226
  // packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-edges.util.ts
6104
6227
  var importNames = (clause) => {
@@ -6164,16 +6287,17 @@ var emptyEdges = () => {
6164
6287
  declared: /* @__PURE__ */ new Set(),
6165
6288
  imports: [],
6166
6289
  reExports: [],
6167
- starTargets: []
6290
+ starTargets: [],
6291
+ dangling: []
6168
6292
  };
6169
6293
  return edges;
6170
6294
  };
6171
- var moduleEdges = (sourceFile, checker, isExternal) => {
6172
- const resolve5 = (specifier) => moduleTarget(specifier, checker, isExternal);
6295
+ var moduleEdges = (sourceFile, resolution) => {
6173
6296
  const edges = emptyEdges();
6297
+ const resolve5 = moduleResolver(resolution, edges.dangling);
6174
6298
  let skipped = false;
6175
6299
  for (const statement of sourceFile.statements) {
6176
- if (isImportDeclaration2(statement)) {
6300
+ if (isImportDeclaration3(statement)) {
6177
6301
  addImport2(statement, edges, resolve5);
6178
6302
  } else if (isExportDeclaration(statement)) {
6179
6303
  if (statement.moduleSpecifier) addExportFrom(statement, edges, resolve5);
@@ -6218,28 +6342,32 @@ var LAST_AGGREGATE = /* @__PURE__ */ new Map();
6218
6342
  var projectKey = (program) => {
6219
6343
  const configFilePath = program.getCompilerOptions()["configFilePath"];
6220
6344
  if (typeof configFilePath === "string") return configFilePath;
6221
- const directories = program.getRootFileNames().map(dirname10);
6345
+ const directories = program.getRootFileNames().map(dirname11);
6222
6346
  const uniqueDirectorySet = new Set(directories);
6223
6347
  const uniqueDirectories = [...uniqueDirectorySet];
6224
6348
  const sortedDirectories = uniqueDirectories.sort();
6225
6349
  return sortedDirectories.join("|");
6226
6350
  };
6227
- var fileEdges = (sourceFile, checker, isExternal) => {
6351
+ var fileEdges = (sourceFile, resolution) => {
6228
6352
  const cached = FILE_EDGES.get(sourceFile);
6229
- if (cached) return cached;
6230
- const edges = moduleEdges(sourceFile, checker, isExternal);
6353
+ const isCached = cached !== void 0;
6354
+ const isSettled = isCached && cached.dangling.length === 0;
6355
+ if (isSettled) return cached;
6356
+ const edges = moduleEdges(sourceFile, resolution);
6231
6357
  FILE_EDGES.set(sourceFile, edges);
6232
6358
  return edges;
6233
6359
  };
6234
6360
  var programEdges = (program) => {
6235
6361
  const checker = program.getTypeChecker();
6236
6362
  const isExternal = (sourceFile) => program.isSourceFileFromExternalLibrary(sourceFile);
6363
+ const onDisk = diskResolver(program);
6364
+ const resolution = { checker, isExternal, onDisk };
6237
6365
  const byFile = /* @__PURE__ */ new Map();
6238
6366
  for (const sourceFile of program.getSourceFiles()) {
6239
6367
  if (sourceFile.isDeclarationFile) continue;
6240
6368
  const isSourceExternal = isExternal(sourceFile);
6241
6369
  if (isSourceExternal) continue;
6242
- byFile.set(sourceFile.fileName, fileEdges(sourceFile, checker, isExternal));
6370
+ byFile.set(sourceFile.fileName, fileEdges(sourceFile, resolution));
6243
6371
  }
6244
6372
  return byFile;
6245
6373
  };
@@ -7418,6 +7546,14 @@ var typescriptSafety = defineConfig18([
7418
7546
  // Class actions carry their payload as constructor parameter properties.
7419
7547
  "@typescript-eslint/parameter-properties": "off"
7420
7548
  }
7549
+ },
7550
+ {
7551
+ files: ["**/*.stub.ts"],
7552
+ rules: {
7553
+ // local/test-file-shape requires STUB: Type; a literal stub would trip
7554
+ // no-inferrable-types.
7555
+ "@typescript-eslint/no-inferrable-types": "off"
7556
+ }
7421
7557
  }
7422
7558
  ]);
7423
7559