@cplieger/deadset-ts 8.0.0-dev.1 → 8.0.0-dev.11

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 (276) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/mapper-connection.js +2 -1
  3. package/dist/bin/node-host.js +24 -5
  4. package/dist/src/analysis.js +181 -341
  5. package/dist/src/augmentations.js +106 -13
  6. package/dist/src/automatic-types.js +10 -29
  7. package/dist/src/build-scripts.js +425 -0
  8. package/dist/src/component-layer.js +4 -2
  9. package/dist/src/components.js +2 -3
  10. package/dist/src/config.js +6 -82
  11. package/dist/src/configuration-files.js +28 -176
  12. package/dist/src/configured-declarations.js +15 -20
  13. package/dist/src/conformance-record.js +1 -1
  14. package/dist/src/consumers.js +3 -30
  15. package/dist/src/contextual-uses.js +56 -9
  16. package/dist/src/contract/config.generated.js +558 -0
  17. package/dist/src/contract/contract.generated.js +1244 -0
  18. package/dist/src/contract/report.generated.js +862 -0
  19. package/dist/src/convention-rows.js +73 -3
  20. package/dist/src/conventions.js +36 -66
  21. package/dist/src/dependencies.js +103 -40
  22. package/dist/src/edges.js +38 -122
  23. package/dist/src/element-access.js +4 -6
  24. package/dist/src/entry-point-gaps.js +2 -8
  25. package/dist/src/entry-points.js +11 -27
  26. package/dist/src/enum-group.js +3 -10
  27. package/dist/src/erased-stores.js +4 -6
  28. package/dist/src/exempt-classes.js +1 -63
  29. package/dist/src/exempt.js +21 -40
  30. package/dist/src/failure.js +36 -0
  31. package/dist/src/file-facts.js +2 -25
  32. package/dist/src/findings/completion.js +139 -72
  33. package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
  34. package/dist/src/findings/emitters.js +5 -5
  35. package/dist/src/findings/interfaces.js +4 -5
  36. package/dist/src/findings/intra-function.js +13 -10
  37. package/dist/src/findings/non-code-artifacts.js +7 -8
  38. package/dist/src/findings/reads-and-writes.js +16 -13
  39. package/dist/src/findings/self-check.js +10 -12
  40. package/dist/src/findings/unused-declarations.js +41 -32
  41. package/dist/src/findings/visibility-narrowing.js +19 -16
  42. package/dist/src/findings-pass.js +8 -15
  43. package/dist/src/framework-lifecycle.js +7 -7
  44. package/dist/src/fs/document.js +52 -0
  45. package/dist/src/fs/manifest.js +72 -0
  46. package/dist/src/fs/tree.js +88 -0
  47. package/dist/src/generated-file.js +7 -4
  48. package/dist/src/git-ignore.js +39 -26
  49. package/dist/src/graph.js +5 -3
  50. package/dist/src/html-entries.js +6 -33
  51. package/dist/src/in-operands.js +2 -1
  52. package/dist/src/index.js +1 -1
  53. package/dist/src/injection-container.js +1 -1
  54. package/dist/src/intra-function-parts.js +63 -43
  55. package/dist/src/inventory.js +2 -21
  56. package/dist/src/javascript-file.js +33 -0
  57. package/dist/src/json-document.js +198 -67
  58. package/dist/src/keyof-comparisons.js +4 -6
  59. package/dist/src/kinds.js +3 -366
  60. package/dist/src/load/classify.js +270 -0
  61. package/dist/src/load/diagnostics.js +80 -0
  62. package/dist/src/load/discover.js +277 -0
  63. package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
  64. package/dist/src/load/expected-module.js +136 -0
  65. package/dist/src/load/load.js +27 -0
  66. package/dist/src/load/module-lookup.js +37 -0
  67. package/dist/src/load/plan.js +313 -0
  68. package/dist/src/load/specifiers.js +115 -0
  69. package/dist/src/load/synthesize.js +140 -0
  70. package/dist/src/load/test-globals.js +207 -0
  71. package/dist/src/load/test-joins.js +82 -0
  72. package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
  73. package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
  74. package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +23 -65
  75. package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
  76. package/dist/src/{workspace.js → load/workspace.js} +62 -124
  77. package/dist/src/manifest.js +49 -54
  78. package/dist/src/matrix.js +76 -4
  79. package/dist/src/mdx-entries.js +3 -26
  80. package/dist/src/outside-tests.js +1 -1
  81. package/dist/src/partial.js +2 -1
  82. package/dist/src/paths.js +26 -15
  83. package/dist/src/position.js +2 -1
  84. package/dist/src/print.js +11 -79
  85. package/dist/src/product.js +13 -0
  86. package/dist/src/query.js +1 -0
  87. package/dist/src/ref.js +1 -0
  88. package/dist/src/references.js +48 -30
  89. package/dist/src/report-schema.js +51 -0
  90. package/dist/src/report.js +57 -41
  91. package/dist/src/reporters/annotations.js +15 -8
  92. package/dist/src/reporters/sarif.js +16 -10
  93. package/dist/src/reporters/template.js +4 -19
  94. package/dist/src/resolve.js +245 -729
  95. package/dist/src/roots.js +273 -87
  96. package/dist/src/run.js +66 -77
  97. package/dist/src/schema.js +320 -343
  98. package/dist/src/scope.js +38 -115
  99. package/dist/src/serialization-contract.js +595 -21
  100. package/dist/src/session.js +34 -29
  101. package/dist/src/source-files.js +1 -1
  102. package/dist/src/suppress-file.js +25 -28
  103. package/dist/src/suppress-inline.js +3 -2
  104. package/dist/src/suppress.js +33 -51
  105. package/dist/src/sweep.js +7 -9
  106. package/dist/src/symbol-keys.js +3 -5
  107. package/dist/src/template-field.js +9 -19
  108. package/dist/src/test-support.js +8 -11
  109. package/dist/src/text/compare.js +26 -0
  110. package/dist/src/text/glob.js +194 -0
  111. package/dist/src/text/named-files.js +54 -0
  112. package/dist/src/text/shell.js +159 -0
  113. package/dist/src/text/yaml.js +393 -0
  114. package/dist/src/type-errors.js +11 -232
  115. package/dist/src/unseen-loads.js +100 -0
  116. package/dist/src/unwrap.js +23 -0
  117. package/dist/src/usage.js +10 -0
  118. package/dist/src/verbs/analyze.js +166 -126
  119. package/dist/src/verbs/describe.js +9 -16
  120. package/dist/src/verbs/explain.js +10 -7
  121. package/dist/src/verbs/print-config.js +2 -1
  122. package/dist/src/verbs/print-projects.js +6 -4
  123. package/dist/src/verbs/print-retained.js +4 -2
  124. package/dist/src/verbs/print-roots.js +4 -2
  125. package/dist/src/verbs/verb.js +1 -5
  126. package/dist/src/verbs/version.js +14 -3
  127. package/dist/src/workflow-steps.js +62 -64
  128. package/jsr.json +1 -1
  129. package/package.json +5 -4
  130. package/src/analysis.ts +245 -502
  131. package/src/augmentations.ts +135 -17
  132. package/src/automatic-types.ts +11 -29
  133. package/src/build-scripts.ts +543 -0
  134. package/src/component-layer.ts +4 -2
  135. package/src/components.ts +2 -4
  136. package/src/config.ts +31 -302
  137. package/src/configuration-files.ts +34 -179
  138. package/src/configured-declarations.ts +18 -23
  139. package/src/conformance-record.ts +1 -1
  140. package/src/consumers.ts +6 -57
  141. package/src/contextual-uses.ts +64 -12
  142. package/src/contract/config.generated.ts +818 -0
  143. package/src/contract/contract.generated.ts +1308 -0
  144. package/src/contract/report.generated.ts +1237 -0
  145. package/src/convention-rows.ts +85 -3
  146. package/src/conventions.ts +46 -84
  147. package/src/dependencies.ts +118 -46
  148. package/src/edges.ts +41 -140
  149. package/src/element-access.ts +4 -7
  150. package/src/entry-point-gaps.ts +3 -9
  151. package/src/entry-points.ts +12 -38
  152. package/src/enum-group.ts +2 -11
  153. package/src/erased-stores.ts +3 -7
  154. package/src/exempt-classes.ts +1 -75
  155. package/src/exempt.ts +36 -50
  156. package/src/failure.ts +63 -0
  157. package/src/file-facts.ts +9 -24
  158. package/src/finding.ts +14 -9
  159. package/src/findings/boundary.ts +2 -0
  160. package/src/findings/completion.ts +181 -84
  161. package/src/findings/dependencies-and-module-machinery.ts +4 -7
  162. package/src/findings/emitter.ts +8 -9
  163. package/src/findings/emitters.ts +7 -7
  164. package/src/findings/interfaces.ts +4 -6
  165. package/src/findings/intra-function.ts +13 -11
  166. package/src/findings/non-code-artifacts.ts +9 -11
  167. package/src/findings/reads-and-writes.ts +20 -16
  168. package/src/findings/self-check.ts +11 -17
  169. package/src/findings/unused-declarations.ts +45 -32
  170. package/src/findings/visibility-narrowing.ts +20 -17
  171. package/src/findings-pass.ts +10 -19
  172. package/src/framework-lifecycle.ts +7 -7
  173. package/src/fs/document.ts +70 -0
  174. package/src/fs/manifest.ts +92 -0
  175. package/src/fs/tree.ts +110 -0
  176. package/src/generated-file.ts +7 -4
  177. package/src/git-ignore.ts +50 -26
  178. package/src/graph.ts +5 -3
  179. package/src/host.ts +12 -5
  180. package/src/html-entries.ts +6 -33
  181. package/src/in-operands.ts +2 -1
  182. package/src/index.ts +1 -1
  183. package/src/injection-container.ts +1 -1
  184. package/src/intra-function-parts.ts +73 -44
  185. package/src/inventory.ts +2 -20
  186. package/src/javascript-file.ts +37 -0
  187. package/src/json-document.ts +241 -76
  188. package/src/keyof-comparisons.ts +3 -7
  189. package/src/kinds.ts +5 -413
  190. package/src/load/classify.ts +397 -0
  191. package/src/load/diagnostics.ts +144 -0
  192. package/src/load/discover.ts +455 -0
  193. package/src/{emit-map.ts → load/emit-map.ts} +1 -1
  194. package/src/load/expected-module.ts +188 -0
  195. package/src/load/load.ts +73 -0
  196. package/src/load/module-lookup.ts +50 -0
  197. package/src/load/plan.ts +504 -0
  198. package/src/load/specifiers.ts +168 -0
  199. package/src/load/synthesize.ts +211 -0
  200. package/src/load/test-globals.ts +251 -0
  201. package/src/load/test-joins.ts +98 -0
  202. package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
  203. package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
  204. package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +33 -76
  205. package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
  206. package/src/{workspace.ts → load/workspace.ts} +90 -134
  207. package/src/manifest.ts +81 -75
  208. package/src/matrix.ts +122 -4
  209. package/src/mdx-entries.ts +3 -26
  210. package/src/outside-tests.ts +1 -1
  211. package/src/partial.ts +3 -2
  212. package/src/paths.ts +27 -15
  213. package/src/position.ts +2 -1
  214. package/src/print.ts +12 -92
  215. package/src/product.ts +18 -0
  216. package/src/query.ts +11 -0
  217. package/src/ref.ts +1 -0
  218. package/src/references.ts +52 -31
  219. package/src/report-schema.ts +68 -0
  220. package/src/report.ts +101 -224
  221. package/src/reporters/annotations.ts +22 -11
  222. package/src/reporters/json.ts +1 -1
  223. package/src/reporters/reporter.ts +2 -4
  224. package/src/reporters/reporters.ts +1 -1
  225. package/src/reporters/sarif.ts +29 -16
  226. package/src/reporters/template.ts +4 -20
  227. package/src/reporters/text.ts +3 -3
  228. package/src/resolve.ts +283 -1114
  229. package/src/roots.ts +339 -104
  230. package/src/run.ts +75 -91
  231. package/src/schema.ts +391 -388
  232. package/src/scope.ts +46 -138
  233. package/src/serialization-contract.ts +763 -22
  234. package/src/session.ts +70 -54
  235. package/src/source-files.ts +1 -1
  236. package/src/suppress-file.ts +24 -33
  237. package/src/suppress-inline.ts +2 -2
  238. package/src/suppress.ts +43 -58
  239. package/src/sweep.ts +23 -9
  240. package/src/symbol-keys.ts +2 -5
  241. package/src/template-field.ts +15 -25
  242. package/src/test-support.ts +17 -13
  243. package/src/text/compare.ts +27 -0
  244. package/src/text/glob.ts +210 -0
  245. package/src/text/named-files.inputs.json +1522 -0
  246. package/src/text/named-files.ts +68 -0
  247. package/src/text/shell.ts +161 -0
  248. package/src/text/yaml.ts +423 -0
  249. package/src/type-errors.ts +18 -288
  250. package/src/unseen-loads.ts +134 -0
  251. package/src/unwrap.ts +34 -0
  252. package/src/usage.ts +10 -0
  253. package/src/verbs/analyze.ts +224 -162
  254. package/src/verbs/describe.ts +14 -15
  255. package/src/verbs/explain.ts +10 -11
  256. package/src/verbs/print-config.ts +2 -1
  257. package/src/verbs/print-projects.ts +6 -4
  258. package/src/verbs/print-retained.ts +4 -2
  259. package/src/verbs/print-roots.ts +4 -2
  260. package/src/verbs/verb.ts +2 -8
  261. package/src/verbs/version.ts +15 -3
  262. package/src/workflow-steps.ts +74 -64
  263. package/dist/src/base-url.js +0 -18
  264. package/dist/src/discover.js +0 -468
  265. package/dist/src/glob.js +0 -65
  266. package/dist/src/pnpm-workspace.js +0 -120
  267. package/dist/src/setup-failure.js +0 -23
  268. package/dist/src/test-joins.js +0 -101
  269. package/dist/src/version.js +0 -7
  270. package/src/base-url.ts +0 -24
  271. package/src/discover.ts +0 -653
  272. package/src/glob.ts +0 -67
  273. package/src/pnpm-workspace.ts +0 -135
  274. package/src/setup-failure.ts +0 -39
  275. package/src/test-joins.ts +0 -120
  276. package/src/version.ts +0 -7
@@ -3,10 +3,10 @@
3
3
  * file below the target root, whether or not a project includes it, and the files a
4
4
  * program holds by inclusion rather than by an import.
5
5
  */
6
- import { IGNORED_DIRECTORIES } from "./discover.js";
7
6
  import { packageScope } from "./inventory.js";
8
7
  import { dirnamePath, joinPath, relativePath, resolvePath } from "./paths.js";
9
8
  import { renderRef } from "./ref.js";
9
+ import { filesBelow } from "./fs/tree.js";
10
10
  /** A file name the compiler reads as a source file. */
11
11
  const SOURCE_FILE = /\.(?:ts|tsx|mts|cts)$/u;
12
12
  /** A file name the compiler reads as a declaration file, which no build emits code from. */
@@ -30,30 +30,7 @@ function lastLine(text) {
30
30
  * that cannot be read is skipped, as discovery skips it.
31
31
  */
32
32
  export function sourcePaths(host, targetRoot) {
33
- const found = [];
34
- const pending = [""];
35
- for (let dir = pending.pop(); dir !== undefined; dir = pending.pop()) {
36
- let entries;
37
- try {
38
- entries = host.readDirectory(joinPath(targetRoot, dir));
39
- }
40
- catch {
41
- continue;
42
- }
43
- for (const entry of entries) {
44
- const path = dir === "" ? entry.name : `${dir}/${entry.name}`;
45
- if (entry.directory) {
46
- if (!IGNORED_DIRECTORIES.has(entry.name)) {
47
- pending.push(path);
48
- }
49
- continue;
50
- }
51
- if (SOURCE_FILE.test(entry.name) && !DECLARATION_FILE.test(entry.name)) {
52
- found.push(path);
53
- }
54
- }
55
- }
56
- return found.sort((a, b) => (a < b ? -1 : 1));
33
+ return filesBelow(host, targetRoot, (name) => SOURCE_FILE.test(name) && !DECLARATION_FILE.test(name));
57
34
  }
58
35
  /**
59
36
  * Every source file below the target root, in path order. A file that cannot be read is
@@ -3,29 +3,20 @@
3
3
  * the code's row of the issue-kind vocabulary, and the dials that withhold a finding
4
4
  * together with every finding that falls with a root they withhold.
5
5
  */
6
+ import { CODE, FAMILY_KEY_LENGTH, KIND_ROWS, } from "../contract/contract.generated.js";
6
7
  import { componentId } from "../components.js";
7
8
  import { deadComponents } from "../matrix.js";
8
9
  import { OUTSIDE } from "../graph.js";
9
10
  import { KINDS } from "../kinds.js";
10
11
  import { byPosition, positionKey } from "../position.js";
11
12
  import { declarationKey } from "../ref.js";
12
- import { FAMILY_KEY_LENGTH } from "../resolve.js";
13
13
  import { isPartSubject, isRowSubject } from "../suppress.js";
14
- /** The unused-file code, whose deletion removes every use its file writes. */
15
- const FILE_NEVER_IMPORTED = "DS1502";
16
14
  /**
17
- * The codes whose subject the run that counts test references holds live, as
18
- * finding.schema.json lists them, so a test file's candidate reported under one carries
19
- * none of a dead declaration's sweep facts.
15
+ * The codes whose subject the run that counts test references holds live, so a test
16
+ * file's candidate reported under one carries none of a dead declaration's sweep facts.
20
17
  */
21
- const LIVE_SUBJECT = new Set([
22
- "DS1101",
23
- "DS1102",
24
- "DS1104",
25
- "DS1204",
26
- "DS1301",
27
- ]);
28
- /** The fixability grammar/analysis.md "Fixability" gives a finding about a held declaration. */
18
+ const LIVE_SUBJECT = new Set(KIND_ROWS.filter((row) => row.holdsLive).map((row) => row.code));
19
+ /** The fixability grammar/analysis/fixability.md gives a finding about a held declaration. */
29
20
  const MANUAL = "manual";
30
21
  /** The member kinds an object property can declare, which an `in` expression tests by name. */
31
22
  const IN_TESTED = new Set([
@@ -50,8 +41,9 @@ function everyDeclaredLoaded(boundary) {
50
41
  * naming its family, else the code's default.
51
42
  */
52
43
  function severityOf(input, code, fallback) {
53
- const { config } = input;
54
- return (config.severity.get(code) ?? config.severity.get(code.slice(0, FAMILY_KEY_LENGTH)) ?? fallback);
44
+ const { severity } = input.config;
45
+ const key = [code, code.slice(0, FAMILY_KEY_LENGTH)].find((one) => Object.hasOwn(severity, one));
46
+ return key === undefined ? fallback : (severity[key] ?? fallback);
55
47
  }
56
48
  /**
57
49
  * The declarations the roots name as a library's published API, each public member of a
@@ -87,10 +79,12 @@ function testedByIn(input) {
87
79
  * published API, a public member of a published type included, is `certain` where the
88
80
  * run loaded every consumer the scope declared and declared one, `probable` where one did
89
81
  * not load, and `possible` where it declared none, whatever the configuration says of the
90
- * consumer set. A member an `in` expression tests by name is `possible`.
82
+ * consumer set. A member an `in` expression tests by name, and one a function outside the
83
+ * analysis fills, is `possible`.
91
84
  */
92
85
  function reachabilityClasses(input) {
93
86
  const tested = testedByIn(input);
87
+ const filled = input.boundary.filledOutside ?? new Set();
94
88
  const published = publishedIds(input.swept.matrix.union);
95
89
  const { declared } = input.boundary.consumers;
96
90
  const outside = declared.length === 0
@@ -99,12 +93,38 @@ function reachabilityClasses(input) {
99
93
  ? "certain"
100
94
  : "probable";
101
95
  return (id) => {
102
- if (tested.has(id)) {
96
+ if (tested.has(id) || filled.has(id)) {
103
97
  return "possible";
104
98
  }
105
99
  return published.has(id) ? outside : "certain";
106
100
  };
107
101
  }
102
+ /**
103
+ * Whether one test of dead code references a target symbol that is published API of a run
104
+ * that declares no consumer, which outside programs the run cannot see may use, so the
105
+ * target counts as live for the test and the test is no test of dead code.
106
+ */
107
+ export function testsUnseenAPI(input) {
108
+ if (input.boundary.consumers.declared.length > 0) {
109
+ return () => false;
110
+ }
111
+ const union = input.swept.matrix.union;
112
+ const published = publishedIds(union);
113
+ return (id) => testTargets(union, id).some((target) => published.has(target));
114
+ }
115
+ /** The target symbols one test of dead code references, by id: production declarations the sweep judges. */
116
+ function testTargets(union, id) {
117
+ return (union.out[union.at(id)] ?? []).flatMap((edge) => {
118
+ const target = union.symbols[edge.to];
119
+ const testCode = union.test[edge.to] === true || union.support[edge.to] === true;
120
+ return target !== undefined &&
121
+ !testCode &&
122
+ union.ambient[edge.to] !== true &&
123
+ union.subject[edge.to] === true
124
+ ? [target.id]
125
+ : [];
126
+ });
127
+ }
108
128
  /**
109
129
  * The confidence ceiling of a test of dead code: the lowest reachability class among the
110
130
  * target symbols it references, because its deadness is theirs, whether or not they share
@@ -113,33 +133,41 @@ function reachabilityClasses(input) {
113
133
  function testCeilings(input, classOf) {
114
134
  const union = input.swept.matrix.union;
115
135
  const tests = new Set(input.swept.sweep.candidates.filter((one) => one.testOfDeadCode).map((one) => one.id));
116
- return (id) => {
117
- let lowest = "certain";
118
- if (!tests.has(id)) {
119
- return lowest;
120
- }
121
- for (const edge of union.out[union.at(id)] ?? []) {
122
- const target = union.symbols[edge.to];
123
- const testCode = union.test[edge.to] === true || union.support[edge.to] === true;
124
- if (target !== undefined &&
125
- !testCode &&
126
- union.ambient[edge.to] !== true &&
127
- union.subject[edge.to] === true) {
128
- lowest = capped(lowest, classOf(target.id));
129
- }
136
+ return (id) => tests.has(id)
137
+ ? testTargets(union, id).reduce((lowest, target) => capped(lowest, classOf(target)), "certain")
138
+ : "certain";
139
+ }
140
+ /**
141
+ * The subjects dead only because production code only tests use is: each declaration the
142
+ * sweep marks test-used, each `DS1602` file of such code, and each test of dead code every
143
+ * target of which is one. Nothing they hold references a dead declaration outside them, so
144
+ * the rest of a component they share is reported without them.
145
+ */
146
+ function testUsedSubjects(input) {
147
+ const { matrix, sweep } = input.swept;
148
+ const union = matrix.union;
149
+ const used = new Set(sweep.candidates.filter((one) => one.testUsed).map((one) => one.id));
150
+ for (const test of sweep.candidates.filter((one) => one.testOfDeadCode)) {
151
+ const targets = testTargets(union, test.id);
152
+ if (targets.length > 0 && targets.every((target) => used.has(target))) {
153
+ used.add(test.id);
130
154
  }
131
- return lowest;
132
- };
155
+ }
156
+ const files = new Set(union.symbols.flatMap((symbol, at) => matrix.testUsed[at] === true ? [symbol.position.path] : []));
157
+ return { declarations: used, files };
133
158
  }
134
159
  /**
135
160
  * The ceiling the roots the run found put on one dead subject: a subject other declarations
136
- * reference, found dead only because no root reaches them, is `probable` unless
137
- * the configuration declares the roots complete, because a root the analysis cannot see
138
- * would make it live; every other declaration has none below `certain`.
161
+ * reference, found dead only because no root reaches them, is `probable` unless the
162
+ * configuration declares the roots complete and no configuration holding the subject loads
163
+ * a module the analysis cannot resolve, because a root the analysis cannot see would make
164
+ * it live; every other declaration has none below `certain`.
139
165
  */
140
- function rootsCeiling(input, finding, candidate) {
166
+ function rootsCeiling(input, finding, candidate, configurations) {
141
167
  const unreachable = candidate?.relation === "reachability" || finding.unreachableOnly === true;
142
- return unreachable && !input.config.ts.rootsComplete ? "probable" : "certain";
168
+ const unseen = new Set((input.files.unseenLoads ?? []).map((load) => load.configuration));
169
+ const complete = input.config.ts.roots_complete && !configurations.some((one) => unseen.has(one));
170
+ return unreachable && !complete ? "probable" : "certain";
143
171
  }
144
172
  /**
145
173
  * The component each dead declaration of the run falls in, and none for a live one, with
@@ -152,8 +180,24 @@ function findingComponents(swept, components, cascade) {
152
180
  held.set(member, component);
153
181
  }
154
182
  }
183
+ const listed = membersListed(swept);
184
+ return (id) => {
185
+ const component = held.get(id);
186
+ return component === undefined
187
+ ? undefined
188
+ : {
189
+ id: component.id,
190
+ root: component.roots.includes(id),
191
+ symbolCount: component.members.length,
192
+ deletableLines: component.deletableLines,
193
+ ...(cascade === "full" ? { members: listed(component.members) } : {}),
194
+ };
195
+ };
196
+ }
197
+ /** The members of a component as the run lists them, positioned and in the canonical order. */
198
+ function membersListed(swept) {
155
199
  const symbols = new Map(swept.matrix.union.symbols.map((symbol) => [symbol.id, symbol]));
156
- const listed = (component) => component.members
200
+ return (members) => members
157
201
  .flatMap((member) => {
158
202
  const symbol = symbols.get(member);
159
203
  return symbol === undefined
@@ -170,27 +214,15 @@ function findingComponents(swept, components, cascade) {
170
214
  ];
171
215
  })
172
216
  .sort((a, b) => byPosition(a.position, b.position));
173
- return (id) => {
174
- const component = held.get(id);
175
- return component === undefined
176
- ? undefined
177
- : {
178
- id: component.id,
179
- root: component.roots.includes(id),
180
- symbolCount: component.members.length,
181
- deletableLines: component.deletableLines,
182
- ...(cascade === "full" ? { members: listed(component) } : {}),
183
- };
184
- };
185
217
  }
186
218
  /**
187
- * The run's dead components with each file a `DS1502` finding reports dead among them, so
219
+ * The run's dead components with each file a `DS1602` finding reports dead among them, so
188
220
  * the file's declarations fall with it, and with the components each subject that is no
189
221
  * declaration falls with joined into one.
190
222
  */
191
223
  function runComponents(swept, findings) {
192
224
  const union = swept.matrix.union;
193
- const reported = new Set(findings.filter((one) => one.code === FILE_NEVER_IMPORTED).map((one) => one.position.path));
225
+ const reported = new Set(findings.filter((one) => one.code === CODE.fileNeverImported).map((one) => one.position.path));
194
226
  const files = new Map(union.symbols.flatMap((symbol, at) => symbol.kind === "file" && reported.has(symbol.position.path) ? [[at, symbol]] : []));
195
227
  const computed = files.size === 0
196
228
  ? swept.sweep.components
@@ -251,6 +283,7 @@ export function completed(input, findings, kinds = KINDS) {
251
283
  const candidates = new Map(swept.sweep.candidates.map((candidate) => [candidate.id, candidate]));
252
284
  const classOf = reachabilityClasses(input);
253
285
  const ceilingOf = testCeilings(input, classOf);
286
+ const testUsed = testUsedSubjects(input);
254
287
  const { components, computed, files } = runComponents(swept, findings);
255
288
  const componentOf = findingComponents(swept, components, input.config.reporters.cascade);
256
289
  const held = new Set(components.filter((one) => one.held).flatMap((one) => one.members));
@@ -258,11 +291,12 @@ export function completed(input, findings, kinds = KINDS) {
258
291
  let minted = computed;
259
292
  const dead = new Set(components.map((component) => component.id));
260
293
  const fallingWith = new Map();
261
- for (const { heldByTests } of swept.sweep.candidates) {
294
+ for (const { id, heldByTests } of swept.sweep.candidates) {
262
295
  if (heldByTests !== undefined) {
263
- fallingWith.set(heldByTests, (fallingWith.get(heldByTests) ?? 0) + 1);
296
+ fallingWith.set(heldByTests, [...(fallingWith.get(heldByTests) ?? []), id]);
264
297
  }
265
298
  }
299
+ const listed = membersListed(swept);
266
300
  const done = findings.map((finding) => {
267
301
  const row = kinds.get(finding.code);
268
302
  if (row === undefined) {
@@ -288,7 +322,7 @@ export function completed(input, findings, kinds = KINDS) {
288
322
  : candidates.get(judged.id);
289
323
  const fallsWith = finding.fallsWith?.[0];
290
324
  const joined = fallsWith === undefined ? undefined : componentOf(fallsWith);
291
- const file = finding.code === FILE_NEVER_IMPORTED ? files.get(finding.position.path) : undefined;
325
+ const file = finding.code === CODE.fileNeverImported ? files.get(finding.position.path) : undefined;
292
326
  const found = joined !== undefined
293
327
  ? { ...joined, root: false }
294
328
  : file !== undefined
@@ -307,17 +341,40 @@ export function completed(input, findings, kinds = KINDS) {
307
341
  let component = found;
308
342
  if (component === undefined) {
309
343
  minted += 1;
344
+ const falling = symbol?.kind === "interface" ? fallingWith.get(symbol.id) : undefined;
310
345
  component = {
311
346
  id: componentId(minted),
312
347
  root: true,
313
- symbolCount: symbol?.kind === "interface" ? (fallingWith.get(symbol.id) ?? 1) : 1,
348
+ symbolCount: falling?.length ?? 1,
314
349
  deletableLines: 0,
350
+ ...(input.config.reporters.cascade !== "full"
351
+ ? {}
352
+ : falling === undefined
353
+ ? {
354
+ members: [
355
+ {
356
+ ref: finding.symbol.ref,
357
+ name: finding.symbol.name,
358
+ position: finding.position,
359
+ },
360
+ ],
361
+ }
362
+ : { members: listed(falling) }),
315
363
  };
316
364
  }
317
365
  const counts = candidate === undefined
318
366
  ? union.made[at]
319
367
  : { production: candidate.productionRefs, test: candidate.testRefs };
320
- const reachabilityClass = judged === undefined ? (finding.reachabilityClass ?? "certain") : classOf(judged.id);
368
+ const ownClass = judged === undefined ? (finding.reachabilityClass ?? "certain") : classOf(judged.id);
369
+ const used = judged !== undefined
370
+ ? candidate !== undefined && testUsed.declarations.has(judged.id)
371
+ : finding.code === CODE.fileNeverImported && testUsed.files.has(finding.position.path);
372
+ const reachabilityClass = used && candidate?.testOfDeadCode !== true ? "possible" : ownClass;
373
+ const configurations = candidate?.configurations ??
374
+ (judged === undefined && !part
375
+ ? swept.matrix.configurations
376
+ : (swept.matrix.heldIn[at] ?? swept.matrix.configurations));
377
+ const untested = capped(capped(capped(ownClass, row.maxClass), rootsCeiling(input, finding, candidate, configurations)), judged === undefined ? "certain" : ceilingOf(judged.id));
321
378
  const generated = input.files.generated?.has(finding.position.path) === true;
322
379
  const fixability = generated
323
380
  ? "none"
@@ -331,7 +388,7 @@ export function completed(input, findings, kinds = KINDS) {
331
388
  ? undefined
332
389
  : candidate !== undefined
333
390
  ? input.dependencies.lastUses.get(candidate.id)
334
- : finding.code === FILE_NEVER_IMPORTED
391
+ : finding.code === CODE.fileNeverImported
335
392
  ? input.dependencies.fileLastUses.get(finding.position.path)
336
393
  : undefined;
337
394
  return {
@@ -341,16 +398,14 @@ export function completed(input, findings, kinds = KINDS) {
341
398
  position: finding.position,
342
399
  symbol: finding.symbol,
343
400
  reachabilityClass,
344
- confidence: capped(capped(capped(reachabilityClass, row.maxClass), rootsCeiling(input, finding, candidate)), judged === undefined ? "certain" : ceilingOf(judged.id)),
401
+ confidence: used ? "possible" : untested,
402
+ ...(used ? { componentConfidence: untested } : {}),
345
403
  ...(candidate === undefined ? {} : { livenessRelation: candidate.relation }),
346
404
  testOnly: judged !== undefined && counts?.production === 0 && counts.test > 0,
347
405
  generated,
348
406
  component,
349
407
  retainedBy: [],
350
- configurations: candidate?.configurations ??
351
- (judged === undefined && !part
352
- ? swept.matrix.configurations
353
- : (swept.matrix.heldIn[at] ?? swept.matrix.configurations)),
408
+ configurations,
354
409
  consumersLoaded: input.boundary.consumers.loaded,
355
410
  fixability,
356
411
  severity: severityOf(input, finding.code, row.defaultSeverity),
@@ -365,7 +420,7 @@ export function completed(input, findings, kinds = KINDS) {
365
420
  /**
366
421
  * The findings with every finding of a dead component capped by the lowest confidence
367
422
  * among the component's root members, so the minimum confidence reports or withholds a
368
- * component whole.
423
+ * component whole but for the findings test-used code lowers on their own.
369
424
  */
370
425
  function componentCapped(findings, dead) {
371
426
  const lowest = new Map();
@@ -373,16 +428,27 @@ function componentCapped(findings, dead) {
373
428
  const { id, root } = finding.component;
374
429
  if (root && dead.has(id)) {
375
430
  const held = lowest.get(id);
376
- lowest.set(id, held === undefined ? finding.confidence : capped(held, finding.confidence));
431
+ const own = componentConfidenceOf(finding);
432
+ lowest.set(id, held === undefined ? own : capped(held, own));
377
433
  }
378
434
  }
379
435
  return findings.map((finding) => {
380
436
  const cap = lowest.get(finding.component.id);
381
- return cap === undefined || RANK[cap] >= RANK[finding.confidence]
382
- ? finding
383
- : { ...finding, confidence: cap };
437
+ if (cap === undefined) {
438
+ return finding;
439
+ }
440
+ const own = finding.componentConfidence;
441
+ return {
442
+ ...finding,
443
+ confidence: capped(finding.confidence, cap),
444
+ ...(own === undefined ? {} : { componentConfidence: capped(own, cap) }),
445
+ };
384
446
  });
385
447
  }
448
+ /** The confidence a finding gives its component's cap and the dials. */
449
+ function componentConfidenceOf(finding) {
450
+ return finding.componentConfidence ?? finding.confidence;
451
+ }
386
452
  /** Whether the dials withhold a finding by its own severity or confidence. */
387
453
  function dialed(finding, minConfidence) {
388
454
  return finding.severity === "allow" || RANK[finding.confidence] < RANK[minConfidence];
@@ -395,9 +461,10 @@ function dialed(finding, minConfidence) {
395
461
  * root withholds itself alone.
396
462
  */
397
463
  export function dialsOf(input, findings) {
398
- const minConfidence = input.config.analysis.minConfidence;
464
+ const minConfidence = input.config.analysis.min_confidence;
399
465
  const components = new Set(findings
400
- .filter((finding) => finding.component.root && dialed(finding, minConfidence))
466
+ .filter((finding) => finding.component.root &&
467
+ dialed({ ...finding, confidence: componentConfidenceOf(finding) }, minConfidence))
401
468
  .map((finding) => finding.component.id));
402
469
  return {
403
470
  allows: (code) => {
@@ -1,8 +1,7 @@
1
+ import { CODE } from "../contract/contract.generated.js";
1
2
  import { declarationKey } from "../dependencies.js";
2
3
  import { renderRef } from "../ref.js";
3
4
  import { nonCodeArtifacts } from "./non-code-artifacts.js";
4
- const UNUSED_DEPENDENCY = "DS1601";
5
- const FILE_NEVER_IMPORTED = "DS1502";
6
5
  const MESSAGES = {
7
6
  dependency: "no import in the target needs the declared dependency",
8
7
  "dev-dependency": "no import in the target needs the declared development dependency",
@@ -25,7 +24,7 @@ function deadCode(input) {
25
24
  const reachedOnly = new Set(swept.sweep.candidates.filter((one) => one.relation === "reachability").map((one) => one.id));
26
25
  for (const finding of nonCodeArtifacts(input)) {
27
26
  const id = files.get(finding.position.path);
28
- if (finding.code === FILE_NEVER_IMPORTED && id !== undefined) {
27
+ if (finding.code === CODE.fileNeverImported && id !== undefined) {
29
28
  dead.add(id);
30
29
  if (finding.unreachableOnly === true) {
31
30
  reachedOnly.add(id);
@@ -57,7 +56,7 @@ function unusedDependencies(input, dependencies) {
57
56
  const atPossible = unbuilt || users?.some((id) => published.has(id)) === true;
58
57
  return [
59
58
  {
60
- code: UNUSED_DEPENDENCY,
59
+ code: CODE.unusedDependency,
61
60
  position: dependency.position,
62
61
  symbol: {
63
62
  ref: renderRef(dependency.manifest, {
@@ -80,5 +79,5 @@ function unusedDependencies(input, dependencies) {
80
79
  ];
81
80
  });
82
81
  }
83
- /** The findings of the dependencies-and-module-machinery family, `DS1600` to `DS1699`. */
82
+ /** The findings of the dependencies family, `DS1700` to `DS1799`. */
84
83
  export const dependenciesAndModuleMachinery = (input) => unusedDependencies(input, input.dependencies);
@@ -12,7 +12,7 @@ import { readsAndWrites } from "./reads-and-writes.js";
12
12
  import { selfCheck } from "./self-check.js";
13
13
  import { fallenMembers, unusedDeclarations } from "./unused-declarations.js";
14
14
  import { visibilityNarrowing } from "./visibility-narrowing.js";
15
- /** Every kind family this analyzer reports, each by its emitter, in code order. */
15
+ /** Every emitter this analyzer runs, by the name its tests select it by. */
16
16
  export const EMITTERS = new Map([
17
17
  ["unused-declarations", unusedDeclarations],
18
18
  ["visibility-narrowing", visibilityNarrowing],
@@ -51,7 +51,7 @@ function markupKeys(input) {
51
51
  .filter((symbol) => live.has(symbol.parent))
52
52
  .map((symbol) => declarationKey(symbol.ref, symbol.position.path)));
53
53
  }
54
- /** Every family's findings over one sweep, and those of any further emitter, completed by one step. */
54
+ /** Every emitter's findings over one sweep, and those of any further emitter, completed by one step. */
55
55
  function completedOver(input, ...more) {
56
56
  return completed(input, [...EMITTERS.values(), ...more].flatMap((emit) => emit(input)));
57
57
  }
@@ -70,8 +70,8 @@ function dialsOver(input, found, suppressed, unmarked) {
70
70
  }
71
71
  /**
72
72
  * Every finding of one run swept under its suppressions' marks, decided in one pass: each
73
- * family's findings completed by one step, so every component number is minted once, the
74
- * finding each record claims withheld, the rest withheld by the dials, so a root one family
73
+ * emitter's findings completed by one step, so every component number is minted once, the
74
+ * finding each record claims withheld, the rest withheld by the dials, so a root one emitter
75
75
  * reports withholds what another reports in its component, and every declared edge
76
76
  * evaluated over what remains, so a pending finding is in its evaluation alone.
77
77
  */
@@ -86,7 +86,7 @@ function atPossible(input) {
86
86
  const { config } = input;
87
87
  return {
88
88
  ...input,
89
- config: { ...config, analysis: { ...config.analysis, minConfidence: "possible" } },
89
+ config: { ...config, analysis: { ...config.analysis, min_confidence: "possible" } },
90
90
  };
91
91
  }
92
92
  /**
@@ -1,6 +1,5 @@
1
+ import { CODE } from "../contract/contract.generated.js";
1
2
  import { byPosition } from "../position.js";
2
- const UNUSED_INTERFACE = "DS1201";
3
- const UNCALLED_INTERFACE_METHOD = "DS1203";
4
3
  /** What each finding says, by what the sweep found about the subject's references. */
5
4
  const UNUSED_MESSAGE = "nothing in the target names the interface as a type";
6
5
  const UNUSED_DEAD_MESSAGE = "the interface is named as a type only from declarations that are themselves dead";
@@ -45,7 +44,7 @@ function findingOf(code, symbol, message, implementations) {
45
44
  }
46
45
  /**
47
46
  * The findings of the interfaces family, `DS1200` to `DS1299`: `DS1201`, a dead
48
- * interface, whose members fall with it unreported; and `DS1203`, a method of a live
47
+ * interface, whose members fall with it unreported; and `DS1202`, a method of a live
49
48
  * interface no reference names, unless it is a marker, a method whose every
50
49
  * implementation has an empty body. A test file's declaration is neither kind's subject,
51
50
  * because a production sweep counts none of the references it can have, save an interface
@@ -60,7 +59,7 @@ export const interfaces = (input) => {
60
59
  continue;
61
60
  }
62
61
  if (symbol.kind === "interface") {
63
- found.push(findingOf(UNUSED_INTERFACE, symbol, unusedMessage(candidate), run.implementationsOf(candidate.id)));
62
+ found.push(findingOf(CODE.unusedInterface, symbol, unusedMessage(candidate), run.implementationsOf(candidate.id)));
64
63
  continue;
65
64
  }
66
65
  if (symbol.kind !== "interface-method" ||
@@ -69,7 +68,7 @@ export const interfaces = (input) => {
69
68
  marker(input, candidate.id)) {
70
69
  continue;
71
70
  }
72
- found.push(findingOf(UNCALLED_INTERFACE_METHOD, symbol, UNCALLED_MESSAGE, run.implementationsOf(symbol.parent)));
71
+ found.push(findingOf(CODE.uncalledInterfaceMethod, symbol, UNCALLED_MESSAGE, run.implementationsOf(symbol.parent)));
73
72
  }
74
73
  return found;
75
74
  };
@@ -1,6 +1,7 @@
1
+ import { CODE } from "../contract/contract.generated.js";
1
2
  import { KINDS } from "../kinds.js";
2
3
  import { parameterRef } from "../ref.js";
3
- import { UNUSED_PARAMETER, UNUSED_RESULT } from "../intra-function-parts.js";
4
+ import {} from "../intra-function-parts.js";
4
5
  import { reachedWithTheTests } from "../sweep.js";
5
6
  /** A list of rules as a sentence names them. */
6
7
  function spelled(rules) {
@@ -28,7 +29,8 @@ function overlapClause(overlap, part) {
28
29
  * caller may pass a function used as a value more arguments than it declares, so there one
29
30
  * a read parameter follows is renamed to an underscore name, which the compilers read as
30
31
  * declared unread, and one no read parameter follows is deleted: kept where the call's
31
- * inference may read its annotation, at `probable` where nothing reads the annotation.
32
+ * inference may read its annotation, at `probable` where nothing reads the annotation or
33
+ * where it is a name a contextually typed object pattern binds.
32
34
  */
33
35
  function parameterVerdict(part, free, freeButValued) {
34
36
  const place = part.parameter;
@@ -45,7 +47,8 @@ function parameterVerdict(part, free, freeButValued) {
45
47
  if (place?.annotated === "steers") {
46
48
  return undefined;
47
49
  }
48
- return { fix: "delete", confidence: place?.annotated === "free" ? "probable" : "certain" };
50
+ const unseen = place?.annotated === "free" || place?.contextualPattern === true;
51
+ return { fix: "delete", confidence: unseen ? "probable" : "certain" };
49
52
  }
50
53
  /**
51
54
  * Whether one part is reported. A parameter needs its function's signature free to
@@ -60,9 +63,9 @@ function reported(input, part, callersUnknown) {
60
63
  }
61
64
  const { free, freeButValued, discardedEverywhere } = input.intraFunction;
62
65
  switch (part.code) {
63
- case UNUSED_PARAMETER:
66
+ case CODE.unusedParameter:
64
67
  return parameterVerdict(part, free, freeButValued) !== undefined;
65
- case UNUSED_RESULT:
68
+ case CODE.unusedResult:
66
69
  return (free.has(part.declaration) &&
67
70
  discardedEverywhere.has(part.declaration) &&
68
71
  !callersUnknown.has(part.declaration));
@@ -71,7 +74,7 @@ function reported(input, part, callersUnknown) {
71
74
  }
72
75
  }
73
76
  /**
74
- * The findings of the intra-function family, `DS1800` to `DS1899`, each about a part of
77
+ * The findings of the inside-functions family, `DS1401` to `DS1406`, each about a part of
75
78
  * the declaration its reference names, at the part's own position, whatever the sweep
76
79
  * decided about a production declaration. A part of test code is reported only where the
77
80
  * run that counts test references reaches its declaration and that is no test of dead
@@ -95,7 +98,7 @@ export const intraFunction = (input) => {
95
98
  return symbol === undefined ? [] : [symbol.id];
96
99
  }));
97
100
  const { declared, loaded } = input.boundary.consumers;
98
- const closed = input.config.consumersComplete && declared.every((id) => loaded.includes(id));
101
+ const closed = input.config.consumers.complete && declared.every((id) => loaded.includes(id));
99
102
  const published = (id) => {
100
103
  const symbol = byId.get(id);
101
104
  return (symbol !== undefined &&
@@ -112,11 +115,11 @@ export const intraFunction = (input) => {
112
115
  const found = [];
113
116
  for (const part of input.intraFunction.parts) {
114
117
  const declaration = byId.get(part.declaration);
115
- const overlap = KINDS.get(part.code)?.overlap ?? [];
118
+ const overlap = KINDS.get(part.code)?.overlap?.ts ?? [];
116
119
  if (declaration === undefined || !judged(declaration.id) || !reported(input, part, unknown)) {
117
120
  continue;
118
121
  }
119
- const verdict = part.code === UNUSED_PARAMETER
122
+ const verdict = part.code === CODE.unusedParameter
120
123
  ? parameterVerdict(part, input.intraFunction.free, input.intraFunction.freeButValued)
121
124
  : undefined;
122
125
  const message = verdict?.fix === "rename"
@@ -126,7 +129,7 @@ export const intraFunction = (input) => {
126
129
  code: part.code,
127
130
  position: part.position,
128
131
  symbol: {
129
- ...(part.code === UNUSED_PARAMETER
132
+ ...(part.code === CODE.unusedParameter
130
133
  ? { ref: parameterRef(declaration.ref, part.name), holder: declaration.ref }
131
134
  : { ref: declaration.ref }),
132
135
  kind: part.kind,
@@ -1,5 +1,4 @@
1
- const FILE_NEVER_BUILT = "DS1501";
2
- const FILE_NEVER_IMPORTED = "DS1502";
1
+ import { CODE } from "../contract/contract.generated.js";
3
2
  /** The subject kind of a finding about a source file, from the finding schema's vocabulary. */
4
3
  const FILE_SUBJECT = "file";
5
4
  /** A file's subject starts at its first character. */
@@ -11,8 +10,8 @@ const FILE_START = 1;
11
10
  * derived matrix is never complete.
12
11
  */
13
12
  function completeMatrix(config) {
14
- return (config.analysis.matrixComplete &&
15
- config.analysis.configurations.some((entry) => entry.shape === "project"));
13
+ return (config.analysis.matrix.complete &&
14
+ config.analysis.configurations.some((entry) => "project" in entry));
16
15
  }
17
16
  /** One finding about a whole file. */
18
17
  function fileFinding(code, file, message) {
@@ -40,7 +39,7 @@ function fileNeverBuilt({ config, swept, files }) {
40
39
  const message = `no project of the build matrix includes this file (${swept.matrix.configurations.join(", ")})`;
41
40
  return files.tree
42
41
  .filter((file) => !built.has(file.path))
43
- .map((file) => fileFinding(FILE_NEVER_BUILT, file, message));
42
+ .map((file) => fileFinding(CODE.fileNeverBuilt, file, message));
44
43
  }
45
44
  /**
46
45
  * The paths of the files a reference from a live declaration of another file reaches, a
@@ -125,13 +124,13 @@ function fileNeverImported(input) {
125
124
  const file = { path: symbol.position.path, ref: symbol.ref, endLine: symbol.endLine };
126
125
  return referenced.has(symbol.position.path)
127
126
  ? {
128
- ...fileFinding(FILE_NEVER_IMPORTED, file, "only code that is itself dead imports this file, and no root names it or a declaration in it"),
127
+ ...fileFinding(CODE.fileNeverImported, file, "only code that is itself dead imports this file, and no root names it or a declaration in it"),
129
128
  unreachableOnly: true,
130
129
  }
131
- : fileFinding(FILE_NEVER_IMPORTED, file, "no import reaches this file and no root names it or a declaration in it");
130
+ : fileFinding(CODE.fileNeverImported, file, "no import reaches this file and no root names it or a declaration in it");
132
131
  });
133
132
  }
134
- /** The findings of the non-code-artifacts family, `DS1500` to `DS1599`. */
133
+ /** The findings of the files family, `DS1600` to `DS1699`. */
135
134
  export const nonCodeArtifacts = (input) => [
136
135
  ...fileNeverBuilt(input),
137
136
  ...fileNeverImported(input),