lint-suite 2.0.2 → 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 (39) hide show
  1. package/README.md +18 -4
  2. package/eslint.js +204 -81
  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-exports/common/no-unused-exports.type.d.ts +9 -1
  19. package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts.map +1 -1
  20. package/lib/rules/no-unused-exports/disk-resolver.d.ts +9 -0
  21. package/lib/rules/no-unused-exports/disk-resolver.d.ts.map +1 -0
  22. package/lib/rules/no-unused-exports/export-index.d.ts.map +1 -1
  23. package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts +3 -3
  24. package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts.map +1 -1
  25. package/lib/rules/no-unused-exports/utils/module-resolver.util.d.ts +8 -0
  26. package/lib/rules/no-unused-exports/utils/module-resolver.util.d.ts.map +1 -0
  27. package/lib/rules/package-version.d.ts +2 -0
  28. package/lib/rules/package-version.d.ts.map +1 -0
  29. package/package.json +4 -7
  30. package/stylelint.js +65 -18
  31. package/stylelint.js.map +4 -4
  32. package/eslint.cjs +0 -7376
  33. package/eslint.cjs.map +0 -7
  34. package/lib/rules/no-unused-exports/utils/module-target.util.d.ts +0 -4
  35. package/lib/rules/no-unused-exports/utils/module-target.util.d.ts.map +0 -1
  36. package/prettier.cjs +0 -50
  37. package/prettier.cjs.map +0 -7
  38. package/stylelint.cjs +0 -968
  39. 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();
@@ -1182,7 +1233,7 @@ var methodCandidate = (node, localPrivateOnly, implementedMethods) => {
1182
1233
  };
1183
1234
 
1184
1235
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-reads.ts
1185
- import { dirname as dirname6, resolve as resolve3 } from "node:path";
1236
+ import { dirname as dirname7, resolve as resolve3 } from "node:path";
1186
1237
  import { TSESTree as TSESTree5 } from "@typescript-eslint/utils";
1187
1238
 
1188
1239
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.ts
@@ -1226,7 +1277,7 @@ import {
1226
1277
  R3TargetBinder,
1227
1278
  parseTemplate
1228
1279
  } from "@angular/compiler";
1229
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
1280
+ import { readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
1230
1281
 
1231
1282
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-expression-reads.ts
1232
1283
  import {
@@ -1325,7 +1376,7 @@ var externalTemplateReads = (filename) => {
1325
1376
  const version = `${stats.mtimeNs}:${stats.size}`;
1326
1377
  const cached = externalTemplates.get(filename);
1327
1378
  if (cached?.version === version) return cached.reads;
1328
- const reads = templateReads(readFileSync2(filename, "utf8"), filename);
1379
+ const reads = templateReads(readFileSync3(filename, "utf8"), filename);
1329
1380
  externalTemplates.set(filename, { reads, version });
1330
1381
  return reads;
1331
1382
  } catch {
@@ -1393,7 +1444,7 @@ var inlineTemplateReads = (template, reads, filename) => {
1393
1444
  var externalTemplatePropertyReads = (templateUrl, reads, filename) => {
1394
1445
  if (!templateUrl) return true;
1395
1446
  const url = text(templateUrl);
1396
- return url !== null && addReads(reads, externalTemplateReads(resolve3(dirname6(filename), url)));
1447
+ return url !== null && addReads(reads, externalTemplateReads(resolve3(dirname7(filename), url)));
1397
1448
  };
1398
1449
  var componentTemplateReads = (metadata, reads, filename) => {
1399
1450
  const template = metadataValue2(metadata, "template");
@@ -1622,7 +1673,7 @@ var lexicalThisVisitor = (thisStack) => {
1622
1673
 
1623
1674
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-write-targets.ts
1624
1675
  import { TSESTree as TSESTree8 } from "@typescript-eslint/utils";
1625
- var parentOf = (node) => {
1676
+ var parentOf2 = (node) => {
1626
1677
  if (node.type === TSESTree8.AST_NODE_TYPES.Program) return void 0;
1627
1678
  return node.parent;
1628
1679
  };
@@ -1666,10 +1717,10 @@ var isWrapping = (parent, child) => {
1666
1717
  };
1667
1718
  var isDirectWrite = (node) => {
1668
1719
  let current = node;
1669
- let parent = parentOf(node);
1720
+ let parent = parentOf2(node);
1670
1721
  while (parent && isTypeScriptExpressionWrapper(parent) && parent.expression === current) {
1671
1722
  current = parent;
1672
- parent = parentOf(parent);
1723
+ parent = parentOf2(parent);
1673
1724
  }
1674
1725
  const isDeleteExpression2 = parent?.type === TSESTree8.AST_NODE_TYPES.UnaryExpression && parent.operator === "delete";
1675
1726
  const isAssignment = isSimpleAssignmentTarget(parent, current);
@@ -1677,7 +1728,7 @@ var isDirectWrite = (node) => {
1677
1728
  };
1678
1729
  var isDestructuringOrLoopTarget = (node) => {
1679
1730
  let current = node;
1680
- let parent = parentOf(node);
1731
+ let parent = parentOf2(node);
1681
1732
  let patternTarget = false;
1682
1733
  while (parent) {
1683
1734
  const wrapper = isWrapping(parent, current);
@@ -1687,7 +1738,7 @@ var isDestructuringOrLoopTarget = (node) => {
1687
1738
  patternTarget = true;
1688
1739
  }
1689
1740
  current = parent;
1690
- parent = parentOf(parent);
1741
+ parent = parentOf2(parent);
1691
1742
  }
1692
1743
  const isSimpleTarget = isSimpleAssignmentTarget(parent, current);
1693
1744
  const isAssignedPattern = patternTarget && isSimpleTarget;
@@ -1870,11 +1921,11 @@ var replaceDeclarations = (index, previous, next) => {
1870
1921
  };
1871
1922
 
1872
1923
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.ts
1873
- import { dirname as dirname9, normalize as normalize2 } from "node:path";
1924
+ import { dirname as dirname10, normalize as normalize2 } from "node:path";
1874
1925
 
1875
1926
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
1876
- import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
1877
- 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";
1878
1929
  import { isIdentifier as isIdentifier3, isStringLiteralLike as isStringLiteralLike3 } from "typescript";
1879
1930
 
1880
1931
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.ts
@@ -2313,6 +2364,7 @@ var addTemplateReads = ({
2313
2364
  };
2314
2365
 
2315
2366
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.ts
2367
+ var MISSING = -1n;
2316
2368
  var memberNameOf2 = (member) => {
2317
2369
  const name = member.name;
2318
2370
  if (!name) return [];
@@ -2338,17 +2390,27 @@ var addTemplateMentions = (source, sink) => {
2338
2390
  for (const [name] of source.matchAll(IDENTIFIER)) sink.addMention(name);
2339
2391
  };
2340
2392
  var templateFileVersion = (fileName) => {
2341
- const { mtimeNs, size } = statSync3(fileName, { bigint: true });
2342
- const directory = dirname7(normalize(fileName));
2343
- const version = { directory, fileName, mtimeNs, size };
2344
- 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
+ }
2345
2407
  };
2346
2408
  var templateFileIsCurrent = (version) => {
2347
2409
  try {
2348
2410
  const current = statSync3(version.fileName, { bigint: true });
2349
2411
  return current.mtimeNs === version.mtimeNs && current.size === version.size;
2350
2412
  } catch {
2351
- return false;
2413
+ return version.mtimeNs === MISSING;
2352
2414
  }
2353
2415
  };
2354
2416
  var templateSourceOf = (angularClass2, allNames, sink, versions) => {
@@ -2367,9 +2429,9 @@ var templateSourceOf = (angularClass2, allNames, sink, versions) => {
2367
2429
  return inlineSource;
2368
2430
  }
2369
2431
  const templateFileName = template.fileName;
2432
+ versions.push(templateFileVersion(templateFileName));
2370
2433
  try {
2371
- versions.push(templateFileVersion(templateFileName));
2372
- const source = readFileSync3(templateFileName, "utf8");
2434
+ const source = readFileSync4(templateFileName, "utf8");
2373
2435
  const externalSource = {
2374
2436
  fileName: templateFileName,
2375
2437
  source
@@ -2417,6 +2479,18 @@ var collectAngularTemplateReads = ({
2417
2479
  return templateReads2;
2418
2480
  };
2419
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
+
2420
2494
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.ts
2421
2495
  import {
2422
2496
  forEachChild as forEachChild2,
@@ -2974,6 +3048,13 @@ var collectFileReads = (index, sourceFile, checker, sink) => {
2974
3048
  return noTemplateReads;
2975
3049
  }
2976
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
+ };
2977
3058
  var computeEntry = (index, sourceFile, checker) => {
2978
3059
  const declarations = /* @__PURE__ */ new Set();
2979
3060
  const dependencies = /* @__PURE__ */ new Set();
@@ -2998,9 +3079,12 @@ var computeEntry = (index, sourceFile, checker) => {
2998
3079
  }
2999
3080
  };
3000
3081
  const reads = collectFileReads(index, sourceFile, checker, sink);
3082
+ const dangling = hasDanglingImport(sourceFile, checker);
3083
+ if (dangling) addDanglingFallback(index, sourceFile, mentionedNames, sink);
3001
3084
  dependencies.delete(sourceFile);
3002
3085
  const fileEntry2 = {
3003
3086
  ...reads,
3087
+ dangling,
3004
3088
  declarations,
3005
3089
  dependencies,
3006
3090
  fallbackNames,
@@ -3035,7 +3119,7 @@ import {
3035
3119
  canHaveDecorators as canHaveDecorators2,
3036
3120
  getDecorators as getDecorators2,
3037
3121
  isCallExpression as isCallExpression2,
3038
- isImportDeclaration,
3122
+ isImportDeclaration as isImportDeclaration2,
3039
3123
  isStringLiteralLike as isStringLiteralLike5
3040
3124
  } from "typescript";
3041
3125
  var decoratorKinds = [
@@ -3051,16 +3135,16 @@ var isAngularCoreFile = (declaration) => {
3051
3135
  const fileName = declaration.getSourceFile().fileName.replaceAll("\\", "/");
3052
3136
  return fileName.includes("/node_modules/@angular/core/");
3053
3137
  };
3054
- var parentOf2 = (node) => {
3138
+ var parentOf3 = (node) => {
3055
3139
  return node.parent;
3056
3140
  };
3057
3141
  var importedFromAngularCore = (declaration) => {
3058
- let current = parentOf2(declaration);
3142
+ let current = parentOf3(declaration);
3059
3143
  while (current) {
3060
- if (isImportDeclaration(current)) {
3144
+ if (isImportDeclaration2(current)) {
3061
3145
  return isStringLiteralLike5(current.moduleSpecifier) && current.moduleSpecifier.text === "@angular/core";
3062
3146
  }
3063
- current = parentOf2(current);
3147
+ current = parentOf3(current);
3064
3148
  }
3065
3149
  return false;
3066
3150
  };
@@ -3108,7 +3192,7 @@ var classDecoratorKind = (declaration, discovery) => {
3108
3192
  };
3109
3193
 
3110
3194
  // packages/lint-suite/src/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-metadata-values.ts
3111
- import { dirname as dirname8, resolve as resolve4 } from "node:path";
3195
+ import { dirname as dirname9, resolve as resolve4 } from "node:path";
3112
3196
  import {
3113
3197
  isIdentifier as isIdentifier6,
3114
3198
  isNumericLiteral as isNumericLiteral2,
@@ -3158,7 +3242,7 @@ var templateOf = (metadata, fileName, discovery) => {
3158
3242
  if (url) {
3159
3243
  const text2 = stringValue(url, discovery);
3160
3244
  if (text2 === null) return void 0;
3161
- const externalFileName = resolve4(dirname8(fileName), text2);
3245
+ const externalFileName = resolve4(dirname9(fileName), text2);
3162
3246
  const externalTemplate = {
3163
3247
  fileName: externalFileName,
3164
3248
  kind: "external"
@@ -3541,6 +3625,7 @@ var lazyChecker = (program) => {
3541
3625
  let typeChecker;
3542
3626
  return () => typeChecker ??= program.getTypeChecker();
3543
3627
  };
3628
+ var isDangling = (entry) => entry.dangling;
3544
3629
  var indexMissingEntries = (index, sourceFiles, checker) => {
3545
3630
  for (const sourceFile of sourceFiles) {
3546
3631
  const isEntryIndexed = index.entries.has(sourceFile.fileName);
@@ -3552,6 +3637,7 @@ var reindexProgram = (index, program, checker) => {
3552
3637
  const indexable = indexableSourceFiles(program);
3553
3638
  const current = currentSourceFiles(program);
3554
3639
  dropReplacedEntries(index, current);
3640
+ dropEntries(index, isDangling);
3555
3641
  const newNames = reconcileClasses(index, indexable, current, checker);
3556
3642
  dropEntriesMentioning(index, newNames);
3557
3643
  index.program = program;
@@ -3576,7 +3662,7 @@ var isLocalEntry = (entry, sourceFile, directory) => {
3576
3662
  var refreshLocalEntries = (index, program, fileName, checker) => {
3577
3663
  const sourceFile = program.getSourceFile(fileName);
3578
3664
  if (!sourceFile) return;
3579
- const directory = dirname9(normalize2(sourceFile.fileName));
3665
+ const directory = dirname10(normalize2(sourceFile.fileName));
3580
3666
  const stale = [];
3581
3667
  for (const entry of index.entries.values()) {
3582
3668
  if (entry.templateVersions.length === 0) continue;
@@ -5765,7 +5851,24 @@ var ruleDefaults4 = { entryPoints: [...entryPointDefaults] };
5765
5851
  var defaultOptions7 = [ruleDefaults4];
5766
5852
 
5767
5853
  // packages/lint-suite/src/lib/rules/no-unused-exports/export-index.ts
5768
- 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
+ };
5769
5872
 
5770
5873
  // packages/lint-suite/src/lib/rules/no-unused-exports/utils/export-usage.util.ts
5771
5874
  var MAX_DEPTH = 50;
@@ -5996,7 +6099,7 @@ import {
5996
6099
  isCallExpression as isCallExpression4,
5997
6100
  isExportAssignment,
5998
6101
  isExportDeclaration,
5999
- isImportDeclaration as isImportDeclaration2,
6102
+ isImportDeclaration as isImportDeclaration3,
6000
6103
  isModuleDeclaration,
6001
6104
  isNamespaceImport
6002
6105
  } from "typescript";
@@ -6088,22 +6191,37 @@ var exportedNames = (statement) => {
6088
6191
  return [name];
6089
6192
  };
6090
6193
 
6091
- // 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";
6092
6196
  var declarationOf = (specifier, checker) => {
6093
6197
  const symbol = checker.getSymbolAtLocation(specifier);
6094
6198
  if (!symbol) return void 0;
6095
6199
  return symbol.valueDeclaration ?? symbol.declarations?.[0];
6096
6200
  };
6097
- var moduleTarget = (specifier, checker, isExternal) => {
6098
- if (!specifier) return void 0;
6201
+ var declaredSourceFile = (specifier, checker) => {
6099
6202
  const declaration = declarationOf(specifier, checker);
6100
6203
  if (!declaration) return void 0;
6101
- const sourceFile = declaration.getSourceFile();
6204
+ return declaration.getSourceFile();
6205
+ };
6206
+ var moduleTarget = (sourceFile, isExternal) => {
6102
6207
  if (sourceFile.isDeclarationFile) return void 0;
6103
6208
  const isSourceExternal = isExternal(sourceFile);
6104
6209
  if (isSourceExternal) return void 0;
6105
6210
  return sourceFile.fileName;
6106
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
+ };
6107
6225
 
6108
6226
  // packages/lint-suite/src/lib/rules/no-unused-exports/utils/module-edges.util.ts
6109
6227
  var importNames = (clause) => {
@@ -6169,16 +6287,17 @@ var emptyEdges = () => {
6169
6287
  declared: /* @__PURE__ */ new Set(),
6170
6288
  imports: [],
6171
6289
  reExports: [],
6172
- starTargets: []
6290
+ starTargets: [],
6291
+ dangling: []
6173
6292
  };
6174
6293
  return edges;
6175
6294
  };
6176
- var moduleEdges = (sourceFile, checker, isExternal) => {
6177
- const resolve5 = (specifier) => moduleTarget(specifier, checker, isExternal);
6295
+ var moduleEdges = (sourceFile, resolution) => {
6178
6296
  const edges = emptyEdges();
6297
+ const resolve5 = moduleResolver(resolution, edges.dangling);
6179
6298
  let skipped = false;
6180
6299
  for (const statement of sourceFile.statements) {
6181
- if (isImportDeclaration2(statement)) {
6300
+ if (isImportDeclaration3(statement)) {
6182
6301
  addImport2(statement, edges, resolve5);
6183
6302
  } else if (isExportDeclaration(statement)) {
6184
6303
  if (statement.moduleSpecifier) addExportFrom(statement, edges, resolve5);
@@ -6223,28 +6342,32 @@ var LAST_AGGREGATE = /* @__PURE__ */ new Map();
6223
6342
  var projectKey = (program) => {
6224
6343
  const configFilePath = program.getCompilerOptions()["configFilePath"];
6225
6344
  if (typeof configFilePath === "string") return configFilePath;
6226
- const directories = program.getRootFileNames().map(dirname10);
6345
+ const directories = program.getRootFileNames().map(dirname11);
6227
6346
  const uniqueDirectorySet = new Set(directories);
6228
6347
  const uniqueDirectories = [...uniqueDirectorySet];
6229
6348
  const sortedDirectories = uniqueDirectories.sort();
6230
6349
  return sortedDirectories.join("|");
6231
6350
  };
6232
- var fileEdges = (sourceFile, checker, isExternal) => {
6351
+ var fileEdges = (sourceFile, resolution) => {
6233
6352
  const cached = FILE_EDGES.get(sourceFile);
6234
- if (cached) return cached;
6235
- 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);
6236
6357
  FILE_EDGES.set(sourceFile, edges);
6237
6358
  return edges;
6238
6359
  };
6239
6360
  var programEdges = (program) => {
6240
6361
  const checker = program.getTypeChecker();
6241
6362
  const isExternal = (sourceFile) => program.isSourceFileFromExternalLibrary(sourceFile);
6363
+ const onDisk = diskResolver(program);
6364
+ const resolution = { checker, isExternal, onDisk };
6242
6365
  const byFile = /* @__PURE__ */ new Map();
6243
6366
  for (const sourceFile of program.getSourceFiles()) {
6244
6367
  if (sourceFile.isDeclarationFile) continue;
6245
6368
  const isSourceExternal = isExternal(sourceFile);
6246
6369
  if (isSourceExternal) continue;
6247
- byFile.set(sourceFile.fileName, fileEdges(sourceFile, checker, isExternal));
6370
+ byFile.set(sourceFile.fileName, fileEdges(sourceFile, resolution));
6248
6371
  }
6249
6372
  return byFile;
6250
6373
  };