@cplieger/deadset-ts 8.0.0-dev.15 → 8.0.0-dev.17

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 (207) hide show
  1. package/dist/src/alias-chain.js +0 -5
  2. package/dist/src/amd.js +81 -0
  3. package/dist/src/analysis.js +94 -54
  4. package/dist/src/augmentations.js +23 -24
  5. package/dist/src/bindings.js +382 -0
  6. package/dist/src/calls.js +25 -8
  7. package/dist/src/commands/read.js +6 -7
  8. package/dist/src/commands/tools.js +5 -9
  9. package/dist/src/component-files.js +3 -2
  10. package/dist/src/conformance-record.js +1 -1
  11. package/dist/src/consumers.js +9 -10
  12. package/dist/src/contextual-uses.js +1 -17
  13. package/dist/src/contract/config.generated.js +5 -2
  14. package/dist/src/contract/contract.generated.js +119 -2
  15. package/dist/src/contract/report.generated.js +6 -2
  16. package/dist/src/dependencies.js +98 -71
  17. package/dist/src/destructuring.js +1 -19
  18. package/dist/src/element-access.js +179 -164
  19. package/dist/src/entries/build-scripts.js +222 -0
  20. package/dist/src/{configuration-files.js → entries/configuration-files.js} +22 -64
  21. package/dist/src/{convention-rows.js → entries/convention-rows.js} +120 -27
  22. package/dist/src/entries/conventions.js +739 -0
  23. package/dist/src/{html-entries.js → entries/html-entries.js} +9 -12
  24. package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +3 -3
  25. package/dist/src/entries/run-directories.js +77 -0
  26. package/dist/src/entries/sources.js +144 -0
  27. package/dist/src/entries/static-module.js +670 -0
  28. package/dist/src/entries/test-runners.js +684 -0
  29. package/dist/src/{workflow-steps.js → entries/workflow-steps.js} +18 -8
  30. package/dist/src/extensions.js +37 -0
  31. package/dist/src/facts.js +38 -0
  32. package/dist/src/findings/completion.js +40 -4
  33. package/dist/src/findings/emitters.js +5 -8
  34. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  35. package/dist/src/{in-operands.js → findings/in-operands.js} +2 -2
  36. package/dist/src/findings/self-check.js +36 -20
  37. package/dist/src/findings-pass.js +5 -6
  38. package/dist/src/framework-lifecycle.js +42 -15
  39. package/dist/src/fs/manifest.js +15 -20
  40. package/dist/src/generated-file.js +172 -29
  41. package/dist/src/graph.js +14 -8
  42. package/dist/src/import-bindings.js +73 -28
  43. package/dist/src/index/sites.js +557 -0
  44. package/dist/src/index.js +1 -1
  45. package/dist/src/indexed-access.js +523 -478
  46. package/dist/src/injection-container.js +1 -1
  47. package/dist/src/interface-satisfaction.js +1 -1
  48. package/dist/src/inventory/commonjs.js +62 -17
  49. package/dist/src/inventory/enumerate.js +2 -1
  50. package/dist/src/javascript-file.js +26 -11
  51. package/dist/src/keyof-comparisons.js +124 -103
  52. package/dist/src/load/classify.js +28 -9
  53. package/dist/src/load/diagnostics.js +8 -1
  54. package/dist/src/load/discover.js +15 -7
  55. package/dist/src/load/expected-module.js +2 -2
  56. package/dist/src/load/plan.js +2 -2
  57. package/dist/src/load/specifiers.js +2 -4
  58. package/dist/src/load/synthesize.js +10 -5
  59. package/dist/src/load/workspace-manifests.js +1 -1
  60. package/dist/src/load/workspace-resolution.js +2 -2
  61. package/dist/src/matrix.js +12 -17
  62. package/dist/src/module-declarations.js +70 -85
  63. package/dist/src/overrides.js +134 -112
  64. package/dist/src/paths.js +56 -1
  65. package/dist/src/platform-calls.js +78 -0
  66. package/dist/src/platform-symbols.js +134 -0
  67. package/dist/src/references/read-rule.js +1 -0
  68. package/dist/src/references/read-rules.js +48 -0
  69. package/dist/src/references/sink.js +151 -0
  70. package/dist/src/references/sources.js +450 -0
  71. package/dist/src/references.js +111 -1116
  72. package/dist/src/resolve.js +1 -1
  73. package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +7 -4
  74. package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +5 -8
  75. package/dist/src/{manifest.js → roots/manifest.js} +4 -4
  76. package/dist/src/roots/published-reach.js +412 -0
  77. package/dist/src/roots/root-set.js +489 -0
  78. package/dist/src/roots/unseen-loads.js +236 -0
  79. package/dist/src/serialization-contract.js +9 -4
  80. package/dist/src/source-files.js +5 -9
  81. package/dist/src/stores.js +4 -2
  82. package/dist/src/suppress.js +30 -32
  83. package/dist/src/sweep.js +25 -13
  84. package/dist/src/symbol-keys.js +89 -83
  85. package/dist/src/tests/file-class.js +76 -0
  86. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  87. package/dist/src/{test-support.js → tests/support.js} +5 -12
  88. package/dist/src/type-parameter-reads.js +178 -139
  89. package/dist/src/unimplemented-callees.js +262 -242
  90. package/dist/src/verbs/analyze.js +15 -3
  91. package/dist/src/verbs/describe.js +5 -3
  92. package/dist/src/verbs/explain.js +50 -28
  93. package/dist/src/verbs/print-retained.js +2 -2
  94. package/jsr.json +1 -1
  95. package/package.json +3 -3
  96. package/src/alias-chain.ts +0 -7
  97. package/src/amd.ts +130 -0
  98. package/src/analysis.ts +156 -70
  99. package/src/augmentations.ts +41 -27
  100. package/src/automatic-types.ts +1 -1
  101. package/src/bindings.ts +460 -0
  102. package/src/calls.ts +25 -7
  103. package/src/commands/read.ts +6 -8
  104. package/src/commands/tools.ts +5 -11
  105. package/src/component-files.ts +4 -2
  106. package/src/conformance-record.ts +1 -1
  107. package/src/consumers.ts +12 -11
  108. package/src/contextual-uses.ts +2 -22
  109. package/src/contract/config.generated.ts +5 -2
  110. package/src/contract/contract.generated.ts +138 -2
  111. package/src/contract/report.generated.ts +6 -2
  112. package/src/dependencies.ts +117 -71
  113. package/src/destructuring.ts +1 -31
  114. package/src/element-access.ts +188 -182
  115. package/src/entries/build-scripts.ts +292 -0
  116. package/src/{configuration-files.ts → entries/configuration-files.ts} +33 -82
  117. package/src/{convention-rows.ts → entries/convention-rows.ts} +167 -28
  118. package/src/{conventions.ts → entries/conventions.ts} +349 -523
  119. package/src/{html-entries.ts → entries/html-entries.ts} +19 -18
  120. package/src/{mdx-entries.ts → entries/mdx-entries.ts} +5 -5
  121. package/src/entries/run-directories.ts +108 -0
  122. package/src/entries/sources.ts +266 -0
  123. package/src/entries/static-module.ts +858 -0
  124. package/src/entries/test-runners.ts +868 -0
  125. package/src/{workflow-steps.ts → entries/workflow-steps.ts} +29 -11
  126. package/src/exempt.ts +3 -2
  127. package/src/extensions.ts +45 -0
  128. package/src/facts.ts +46 -0
  129. package/src/file-facts.ts +1 -1
  130. package/src/findings/boundary.ts +2 -0
  131. package/src/findings/completion.ts +43 -4
  132. package/src/findings/emitter.ts +1 -1
  133. package/src/findings/emitters.ts +14 -10
  134. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  135. package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
  136. package/src/findings/self-check.ts +41 -22
  137. package/src/findings/visibility-narrowing.ts +1 -1
  138. package/src/findings-pass.ts +5 -12
  139. package/src/framework-lifecycle.ts +43 -15
  140. package/src/fs/manifest.ts +25 -21
  141. package/src/generated-file.ts +240 -36
  142. package/src/graph.ts +27 -11
  143. package/src/import-bindings.ts +98 -29
  144. package/src/index/sites.ts +781 -0
  145. package/src/index.ts +1 -1
  146. package/src/indexed-access.ts +570 -527
  147. package/src/injection-container.ts +1 -1
  148. package/src/interface-satisfaction.ts +1 -1
  149. package/src/inventory/commonjs.ts +102 -17
  150. package/src/inventory/enumerate.ts +2 -1
  151. package/src/javascript-file.ts +29 -12
  152. package/src/keyof-comparisons.ts +131 -116
  153. package/src/load/classify.ts +49 -13
  154. package/src/load/diagnostics.ts +11 -1
  155. package/src/load/discover.ts +27 -11
  156. package/src/load/expected-module.ts +8 -2
  157. package/src/load/plan.ts +11 -2
  158. package/src/load/specifiers.ts +8 -5
  159. package/src/load/synthesize.ts +12 -6
  160. package/src/load/test-globals.ts +1 -1
  161. package/src/load/workspace-manifests.ts +1 -1
  162. package/src/load/workspace-resolution.ts +9 -2
  163. package/src/load/workspace-run.ts +1 -1
  164. package/src/matrix.ts +13 -17
  165. package/src/module-declarations.ts +74 -98
  166. package/src/overrides.ts +162 -134
  167. package/src/paths.ts +65 -1
  168. package/src/platform-calls.ts +119 -0
  169. package/src/platform-symbols.ts +189 -0
  170. package/src/references/read-rule.ts +60 -0
  171. package/src/references/read-rules.ts +55 -0
  172. package/src/references/sink.ts +213 -0
  173. package/src/references/sources.ts +632 -0
  174. package/src/references.ts +174 -1492
  175. package/src/report.ts +2 -2
  176. package/src/resolve.ts +1 -1
  177. package/src/{configured-declarations.ts → roots/configured-declarations.ts} +10 -7
  178. package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +5 -8
  179. package/src/{manifest.ts → roots/manifest.ts} +5 -5
  180. package/src/roots/published-reach.ts +481 -0
  181. package/src/{roots.ts → roots/root-set.ts} +203 -630
  182. package/src/roots/unseen-loads.ts +345 -0
  183. package/src/serialization-contract.ts +9 -4
  184. package/src/source-files.ts +5 -10
  185. package/src/stores.ts +13 -2
  186. package/src/suppress.ts +48 -33
  187. package/src/sweep.ts +37 -14
  188. package/src/symbol-keys.ts +102 -102
  189. package/src/tests/file-class.ts +118 -0
  190. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  191. package/src/{test-support.ts → tests/support.ts} +15 -21
  192. package/src/type-parameter-reads.ts +187 -158
  193. package/src/unimplemented-callees.ts +297 -280
  194. package/src/verbs/analyze.ts +19 -5
  195. package/src/verbs/describe.ts +5 -2
  196. package/src/verbs/explain.ts +75 -32
  197. package/src/verbs/print-retained.ts +2 -2
  198. package/dist/src/build-scripts.js +0 -418
  199. package/dist/src/conventions.js +0 -907
  200. package/dist/src/entry-points.js +0 -444
  201. package/dist/src/own-body.js +0 -28
  202. package/dist/src/roots.js +0 -865
  203. package/dist/src/unseen-loads.js +0 -189
  204. package/src/build-scripts.ts +0 -536
  205. package/src/entry-points.ts +0 -584
  206. package/src/own-body.ts +0 -42
  207. package/src/unseen-loads.ts +0 -282
@@ -66,11 +66,9 @@ function readConfiguration(engine, configFile) {
66
66
  try {
67
67
  const parsed = engine.parseConfigFile(configFile);
68
68
  const circular = parsed.errors.find(({ code }) => code === CIRCULAR_EXTENDS);
69
- // The compiler leaves the message's `{0}` unfilled:
70
- // https://github.com/microsoft/TypeScript/pull/64755
71
69
  return circular === undefined
72
70
  ? { parsed }
73
- : { reason: `TS${String(circular.code)}: ${circular.text.replace("{0}", () => configFile)}` };
71
+ : { reason: `TS${String(circular.code)}: ${circular.text}` };
74
72
  }
75
73
  catch (error) {
76
74
  return { reason: message(error) };
@@ -137,8 +135,12 @@ export function targetWithoutSources(target) {
137
135
  return failureExit("no-program", `${target} holds no compiler configuration, no file named ${MARKERS.join(", ")}, and no JavaScript file: run from the directory that holds one, or name the languages to analyze`);
138
136
  }
139
137
  /** A target configuration a matrix or the invocation names that cannot be built, ending the run. */
140
- function unbuilt(named, reason) {
141
- throw failureExit("no-program", `${named} ${reason}: correct the configuration, or name the configurations to analyze`);
138
+ function unbuilt(named, reason, failureClass = "no-program") {
139
+ throw failureExit(failureClass, unreadableDetail(named, reason));
140
+ }
141
+ /** What fails and the fix, for a configuration `named` that `reason` keeps from being built. */
142
+ export function unreadableDetail(named, reason) {
143
+ return `${named} ${reason}: correct the configuration, or name the configurations to analyze`;
142
144
  }
143
145
  /**
144
146
  * The projects a build matrix declares, in its order, each a file below the target root, a
@@ -172,7 +174,7 @@ function declaredProjects(engine, host, targetRoot, entries) {
172
174
  }
173
175
  const read = readConfiguration(engine, configFile);
174
176
  if ("reason" in read) {
175
- unbuilt(named, `cannot be read as a compiler configuration: ${read.reason}`);
177
+ unbuilt(named, `cannot be read as a compiler configuration: ${read.reason}`, "unreadable-configuration");
176
178
  }
177
179
  references.set(configFile, referencesOf(read.parsed));
178
180
  const configuration = {
@@ -212,13 +214,19 @@ function derivedProjects(engine, host, scope) {
212
214
  const idOf = (configFile) => relativePath(targetRoot, configFile) ?? configFile;
213
215
  const notBuilt = [];
214
216
  const found = derivedFrom(engine, host, [...fromScope, ...configFilesUnder(host, targetRoot)], (reference) => relativePath(rootDir, reference) !== undefined, (configFile, reason) => {
217
+ const why = `cannot be read as a compiler configuration: ${reason}`;
215
218
  if (fromScope.includes(configFile)) {
216
- unbuilt(configFile, `cannot be read as a compiler configuration: ${reason}`);
219
+ unbuilt(configFile, why, "unreadable-configuration");
217
220
  }
221
+ const failure = {
222
+ failureClass: "unreadable-configuration",
223
+ detail: targetRelative(unreadableDetail(idOf(configFile), why), absoluteRoot),
224
+ };
218
225
  notBuilt.push({
219
226
  id: idOf(configFile),
220
227
  configFile,
221
228
  error: targetRelative(reason, absoluteRoot),
229
+ failures: [failure],
222
230
  });
223
231
  });
224
232
  const configurations = found.map(({ configFile, parsed }) => ({
@@ -2,7 +2,7 @@ import { isNoSubstitutionTemplateLiteral, isStringLiteral, } from "@typescript/n
2
2
  import { packageOfSpecifier } from "../dependencies.js";
3
3
  import { MANIFEST } from "../fs/manifest.js";
4
4
  import { entriesOf } from "../fs/tree.js";
5
- import { dirnamePath, isAbsolutePath, joinPath, relativePath, resolvePath } from "../paths.js";
5
+ import { cannotStartPackageName, dirnamePath, joinPath, relativePath, resolvePath, } from "../paths.js";
6
6
  import { dependencySpecifiers, installedPackage, manifestsAbove } from "./module-lookup.js";
7
7
  /** The string literal holding one offset, innermost first, a doc comment's included. */
8
8
  function literalAt(file, offset) {
@@ -77,7 +77,7 @@ function declaringManifest(host, dir, targetRoot, name) {
77
77
  function expectedModule(context, importer, specifier) {
78
78
  const { host, targetRoot } = context;
79
79
  const fix = "run the generator or the build that writes it";
80
- if (specifier.startsWith(".") || isAbsolutePath(specifier)) {
80
+ if (cannotStartPackageName(specifier)) {
81
81
  return provided(host, resolvePath(dirnamePath(importer), specifier), false)
82
82
  ? undefined
83
83
  : `which names no file of the target: ${fix}`;
@@ -1,7 +1,7 @@
1
- import { readConventions } from "../conventions.js";
1
+ import { readConventions, } from "../entries/conventions.js";
2
2
  import { holdsManifest, inInstalledPackages, MANIFEST, readManifestAt } from "../fs/manifest.js";
3
3
  import { gitIgnored } from "../git-ignore.js";
4
- import { packageEntries, readManifest } from "../manifest.js";
4
+ import { packageEntries, readManifest, } from "../roots/manifest.js";
5
5
  import { ancestors, dirnamePath, joinPath, normalizePath, relativePath, resolvePath, } from "../paths.js";
6
6
  import { bytewise } from "../text/compare.js";
7
7
  import { globExpression } from "../text/glob.js";
@@ -9,12 +9,10 @@ import { isBinaryExpression, isCallExpression, isParenthesizedExpression, isStri
9
9
  import { packageOfSpecifier } from "../dependencies.js";
10
10
  import { readManifestAt } from "../fs/manifest.js";
11
11
  import { JAVASCRIPT_FILE } from "../javascript-file.js";
12
- import { ancestors, dirnamePath, relativePath, resolvePath } from "../paths.js";
12
+ import { ancestors, dirnamePath, isRelativeSpecifier, relativePath, resolvePath, } from "../paths.js";
13
13
  import { renderPosition } from "../position.js";
14
14
  import { batched } from "../session.js";
15
15
  import { dependencySpecifiers } from "./module-lookup.js";
16
- /** A relative specifier: `.`, `..`, or one starting `./` or `../`. */
17
- const RELATIVE = /^\.\.?(?:\/|$)/u;
18
16
  /**
19
17
  * Whether one specifier is loaded optionally: written inside a `try` block, or as a call whose
20
18
  * result an `||` or a `??` falls back from, so the program is written for its absence.
@@ -87,7 +85,7 @@ export function readSpecifiers(engine, host, project, { checked, root, outputs }
87
85
  const resolved = (answers[at]?.resolvedFileName ?? "") !== "";
88
86
  const specifier = usage.node.text;
89
87
  const name = packageOfSpecifier(specifier);
90
- if (RELATIVE.test(specifier)) {
88
+ if (isRelativeSpecifier(specifier)) {
91
89
  const named = resolvePath(dirnamePath(usage.file.fileName), specifier);
92
90
  if (!resolved && !outputs.some((dir) => relativePath(dir, named) !== undefined)) {
93
91
  unresolved.push({
@@ -5,12 +5,12 @@
5
5
  * is written for.
6
6
  */
7
7
  import { readCommands } from "../commands/read.js";
8
- import { CONVENTION_ROWS } from "../convention-rows.js";
8
+ import { CONVENTION_ROWS } from "../entries/convention-rows.js";
9
9
  import { holdsManifest, MANIFEST, readManifestAt } from "../fs/manifest.js";
10
10
  import { filesBelow } from "../fs/tree.js";
11
- import { JAVASCRIPT_FILE, minified, minifiedByName } from "../javascript-file.js";
11
+ import { JAVASCRIPT_FILE, minifiedBy, minifiedByName } from "../javascript-file.js";
12
12
  import { isRecord } from "../json-document.js";
13
- import { manifestCommands } from "../manifest.js";
13
+ import { manifestCommands } from "../roots/manifest.js";
14
14
  import { ancestors, dirnamePath, joinPath, relativePath } from "../paths.js";
15
15
  import { bytewise } from "../text/compare.js";
16
16
  import { writtenPath } from "./workspace-programs.js";
@@ -33,11 +33,11 @@ const FORMED_OPTIONS = {
33
33
  };
34
34
  /** Whether one file is minified build output; one that cannot be read is left to the compiler. */
35
35
  function minifiedFile(host, file) {
36
- if (minifiedByName(file)) {
36
+ if (minifiedByName(file) !== undefined) {
37
37
  return true;
38
38
  }
39
39
  try {
40
- return minified(file, host.readFile(file));
40
+ return minifiedBy(file, host.readFile(file)) !== undefined;
41
41
  }
42
42
  catch {
43
43
  return false;
@@ -89,6 +89,11 @@ const RUNTIME_OPTIONS = {
89
89
  bundler: { module: "preserve", moduleResolution: "bundler" },
90
90
  node: { module: "nodenext", moduleResolution: "nodenext" },
91
91
  };
92
+ /** Whether one configuration is a program the run formed to resolve its modules as Node does. */
93
+ export function formedForNode(configuration) {
94
+ const options = configuration.written?.["compilerOptions"];
95
+ return isRecord(options) && options["moduleResolution"] === RUNTIME_OPTIONS.node.moduleResolution;
96
+ }
92
97
  /** The manifest members that say a package is written for Node. */
93
98
  const NODE_MEMBERS = ["main", "exports", "bin", "type"];
94
99
  /**
@@ -6,7 +6,7 @@
6
6
  * workspace imports, so only its commands are entry points.
7
7
  */
8
8
  import { emittedFrom } from "./emit-map.js";
9
- import { readManifest } from "../manifest.js";
9
+ import { readManifest } from "../roots/manifest.js";
10
10
  import { joinPath, relativePath } from "../paths.js";
11
11
  import { MANIFEST } from "../fs/manifest.js";
12
12
  /** The one character a subpath pattern of a manifest's `exports` holds. */
@@ -8,7 +8,7 @@
8
8
  import { emittedFrom } from "./emit-map.js";
9
9
  import { packageOfSpecifier } from "../dependencies.js";
10
10
  import { gitIgnored } from "../git-ignore.js";
11
- import { ancestors, dirnamePath, joinPath, relativePath, resolvePath } from "../paths.js";
11
+ import { ancestors, cannotStartPackageName, dirnamePath, joinPath, relativePath, resolvePath, } from "../paths.js";
12
12
  import { satisfies } from "../version-range.js";
13
13
  import { isRecord } from "../json-document.js";
14
14
  import { MANIFEST } from "../fs/manifest.js";
@@ -99,7 +99,7 @@ function dependsOn(specifier, member, fromDir) {
99
99
  const inRange = (range) => member.version !== undefined && satisfies(member.version, range);
100
100
  if (specifier.startsWith("workspace:")) {
101
101
  const rest = specifier.slice("workspace:".length);
102
- if (rest.startsWith(".") || rest.startsWith("/")) {
102
+ if (cannotStartPackageName(rest)) {
103
103
  return atPath(rest);
104
104
  }
105
105
  const alias = /^((?:@[^/@]+\/)?[^/@]+)@(.*)$/u.exec(rest);
@@ -6,7 +6,8 @@
6
6
  import { componentsOf } from "./components.js";
7
7
  import { graphOf, OUTSIDE } from "./graph.js";
8
8
  import { byPosition } from "./position.js";
9
- import { reachedWithTheTests, sweep, } from "./sweep.js";
9
+ import { edgeWithheldBy } from "./tests/file-class.js";
10
+ import { reachedWithTheTests, splitRefs, sweep, } from "./sweep.js";
10
11
  /**
11
12
  * What makes one reference one reference, whichever configuration made it. A consumer's
12
13
  * position is rendered against its own root, so the consumer is part of what it names.
@@ -81,19 +82,12 @@ export function matrixOf(per) {
81
82
  };
82
83
  }
83
84
  /**
84
- * Answers which declarations of the run are dead in every configuration that holds them.
85
- *
86
- * Liveness is a question about one configuration, because a file another configuration
87
- * does not compile makes no reference there and a root it does not hold seeds nothing
88
- * there, so each configuration is swept on its own graph under the run's input. A
89
- * declaration is a candidate when every configuration holding it judged it one: a
90
- * reference under one configuration is a reference, so what one project uses is never
91
- * reported, and a configuration that does not hold a declaration says nothing about it.
92
- * The candidate's relation is reference counting where every configuration found it so,
93
- * and reachability otherwise; its counts are the union's, one per reference.
94
- *
95
- * The components are computed once, over the union and the intersected dead set, so one
96
- * dead component is one entry of the run with one identifier.
85
+ * Which declarations of the run are dead in every configuration that holds them. Each
86
+ * configuration is swept on its own graph, since a file it does not compile references nothing
87
+ * there and a root it does not hold seeds nothing. A declaration is a candidate when every
88
+ * configuration holding it judged it one; its relation is reference counting where every one
89
+ * found it so, else reachability, and its counts are the union's. Components are computed once,
90
+ * over the union and the intersected dead set, so one dead component has one identifier.
97
91
  */
98
92
  export function sweepMatrix(matrix, input) {
99
93
  const per = matrix.graphs.map((graph) => sweep(graph, input));
@@ -140,12 +134,13 @@ export function sweepMatrix(matrix, input) {
140
134
  }
141
135
  const held = matrix.heldIn[at] ?? [];
142
136
  const admitted = admittedAt(at);
143
- const testRefs = union.made[at]?.test ?? 0;
137
+ const split = splitRefs(union.made[at], input.mode);
138
+ const testRefs = split.test;
144
139
  const heldByTests = heldBy[union.parent[at] ?? OUTSIDE] ??
145
140
  (union.support[at] === true && testRefs > 0 && !admitted ? symbol.id : undefined);
146
141
  const unreferenced = union.test[at] === true && !admitted && testReached[at] !== true;
147
142
  heldBy[at] = heldByTests;
148
- const productionRefs = union.made[at]?.production ?? 0;
143
+ const productionRefs = split.production;
149
144
  const counted = all.every((candidate) => candidate.relation === "reference-counting");
150
145
  candidates.push({
151
146
  id: symbol.id,
@@ -188,7 +183,7 @@ function compiledReferences(matrix, dead, mode) {
188
183
  }
189
184
  for (const edge of edges) {
190
185
  const to = graph.symbols[edge.to]?.id ?? "";
191
- if ((!mode.production || !edge.test) && dead.has(to) && !kept.has(to)) {
186
+ if (!edgeWithheldBy(mode, edge) && dead.has(to) && !kept.has(to)) {
192
187
  kept.add(to);
193
188
  changed = true;
194
189
  }
@@ -5,11 +5,12 @@
5
5
  * to the same module. One that names it by name or pattern also reads the members it
6
6
  * imports, whatever file the specifier resolves to, as a compiler reading no such file does.
7
7
  */
8
- import { isCallExpression, isExportDeclaration, isExternalModuleReference, isImportDeclaration, isImportEqualsDeclaration, isImportTypeNode, isLiteralTypeNode, isModuleDeclaration, isNamespaceExport, isNamespaceImport, isNoSubstitutionTemplateLiteral, isStringLiteral, SyntaxKind, } from "@typescript/native/ast";
8
+ import { isCallExpression, isExportDeclaration, isExternalModuleReference, isImportDeclaration, isImportEqualsDeclaration, isImportTypeNode, isLiteralTypeNode, isModuleDeclaration, isNoSubstitutionTemplateLiteral, isStringLiteral, SyntaxKind, } from "@typescript/native/ast";
9
+ import { namesImported } from "./import-bindings.js";
9
10
  import { nodeKey } from "./inventory.js";
10
- import { renderPosition } from "./position.js";
11
11
  import { UNANSWERED } from "./query.js";
12
12
  import { aliasFragment, nameComponent } from "./ref.js";
13
+ import { isPathSpecifier } from "./paths.js";
13
14
  /** Whether a node is a specifier's text: a string literal or a template with no substitution. */
14
15
  function literalText(node) {
15
16
  return node !== undefined && (isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node));
@@ -36,32 +37,12 @@ function specifierOf(node) {
36
37
  }
37
38
  return undefined;
38
39
  }
39
- /**
40
- * The export names an import or a re-export reads from the module it names: none for a
41
- * namespace, a star or a bare form.
42
- */
43
- export function namesImported(node) {
44
- if (isImportDeclaration(node)) {
45
- const clause = node.importClause;
46
- const bindings = clause?.namedBindings;
47
- return [
48
- ...(clause?.name === undefined ? [] : ["default"]),
49
- ...(bindings === undefined || isNamespaceImport(bindings)
50
- ? []
51
- : bindings.elements.map((one) => (one.propertyName ?? one.name).text)),
52
- ];
53
- }
54
- const clause = isExportDeclaration(node) ? node.exportClause : undefined;
55
- return clause === undefined || isNamespaceExport(clause)
56
- ? []
57
- : clause.elements.map((one) => (one.propertyName ?? one.name).text);
58
- }
59
40
  /**
60
41
  * Whether a specifier matches a declaration's name, the name's one `*` standing for any run.
61
42
  * A relative name is resolved against its own file, so no specifier names it by its text.
62
43
  */
63
44
  function namesModule(specifier, name) {
64
- if (/^(?:\.{1,2}(?:\/|$)|\/)/u.test(name)) {
45
+ if (isPathSpecifier(name)) {
65
46
  return false;
66
47
  }
67
48
  const star = name.indexOf("*");
@@ -107,67 +88,71 @@ function namedBy(held) {
107
88
  });
108
89
  }
109
90
  /**
110
- * The references the imports of one project's own files make to the module declarations
111
- * they name, each at the import's specifier.
91
+ * The reads the imports of a side's files make of the module declarations of the target they
92
+ * name, each at the import's specifier. A specifier the checker leaves unanswered still names
93
+ * a declaration by its name or pattern.
112
94
  */
113
- export function moduleDeclarationReferences(project, held, root, testFiles) {
114
- const imports = [];
115
- const declared = [];
116
- for (const file of project.ownSourceFiles()) {
117
- const fileId = held.declarations.get(nodeKey(file, file));
118
- if (fileId === undefined) {
119
- continue;
120
- }
121
- const visit = (node, from) => {
122
- const own = held.declarations.get(nodeKey(file, node));
123
- if (isModuleDeclaration(node) && literalText(node.name) && own !== undefined) {
124
- declared.push({ id: own, name: node.name });
125
- }
126
- const specifier = specifierOf(node);
127
- if (specifier !== undefined) {
128
- imports.push({ file, from, specifier, names: namesImported(node) });
129
- }
130
- node.forEachChild((child) => {
131
- visit(child, own ?? from);
132
- });
133
- };
134
- file.forEachChild((child) => {
135
- visit(child, fileId);
136
- });
137
- }
138
- if (declared.length === 0 || imports.length === 0) {
139
- return [];
140
- }
141
- const asked = [...declared.map((one) => one.name), ...imports.map((one) => one.specifier)];
142
- const answers = project.symbolsAt(asked.map((node) => project.handle(node)));
143
- const moduleOf = (at) => {
144
- const symbol = answers[at];
145
- return symbol === undefined || symbol === UNANSWERED ? undefined : symbol.id;
146
- };
147
- const named = namedBy(held);
148
- const found = [];
149
- imports.forEach((one, index) => {
150
- const resolved = moduleOf(declared.length + index);
151
- const position = renderPosition(one.file, root, one.specifier.getStart());
152
- const read = (to, resolution, test) => {
153
- found.push({ from: one.from, to, position, use: "read", resolution, test });
154
- };
155
- const test = testFiles.has(position.path);
156
- const same = new Set(declared
157
- .filter((_, at) => resolved !== undefined && resolved === moduleOf(at))
158
- .map((declaration) => declaration.id));
159
- for (const id of same) {
160
- read(id, "batch", test);
161
- }
162
- for (const declaration of named(one.specifier.text, one.names)) {
163
- // A wildcard declaration is how the compiler types the file a matching specifier
164
- // names, so the import uses it whoever writes it, a test included.
165
- if (declaration.wildcard || !same.has(declaration.id)) {
166
- for (const to of [declaration.id, ...declaration.members]) {
167
- read(to, "syntax", test && !declaration.wildcard);
95
+ export const moduleDeclarations = {
96
+ start() {
97
+ const imports = [];
98
+ return {
99
+ visit(node, { file, from }) {
100
+ const specifier = specifierOf(node);
101
+ if (specifier !== undefined) {
102
+ imports.push({ file, from, specifier, names: namesImported(node) });
168
103
  }
169
- }
170
- }
171
- });
172
- return found;
173
- }
104
+ },
105
+ reads({ project, held }) {
106
+ const found = [];
107
+ // A module declaration whose name is a string is written at a file's top level.
108
+ const declared = project.ownSourceFiles().flatMap((file) => file.statements.flatMap((statement) => {
109
+ const id = held.declarations.get(nodeKey(file, statement));
110
+ return isModuleDeclaration(statement) && literalText(statement.name) && id !== undefined
111
+ ? [{ id, name: statement.name }]
112
+ : [];
113
+ }));
114
+ if (declared.length === 0 || imports.length === 0) {
115
+ return found;
116
+ }
117
+ const asked = [...declared.map((one) => one.name), ...imports.map((one) => one.specifier)];
118
+ const answers = project.symbolsAt(asked.map((node) => project.handle(node)));
119
+ const moduleOf = (at) => {
120
+ const symbol = answers[at];
121
+ return symbol === undefined || symbol === UNANSWERED ? undefined : symbol.id;
122
+ };
123
+ const named = namedBy(held);
124
+ imports.forEach((one, index) => {
125
+ const resolved = moduleOf(declared.length + index);
126
+ const read = (to, via, production) => {
127
+ found.push({
128
+ kind: "named",
129
+ from: one.from,
130
+ to,
131
+ file: one.file,
132
+ at: one.specifier,
133
+ use: "read",
134
+ via,
135
+ ...(production ? { production: true } : {}),
136
+ });
137
+ };
138
+ const same = new Set(declared
139
+ .filter((_, at) => resolved !== undefined && resolved === moduleOf(at))
140
+ .map((declaration) => declaration.id));
141
+ for (const id of same) {
142
+ read(id, "batch", false);
143
+ }
144
+ for (const declaration of named(one.specifier.text, one.names)) {
145
+ // A wildcard declaration is how the compiler types the file a matching specifier
146
+ // names, so the import uses it whoever writes it, a test included.
147
+ if (declaration.wildcard || !same.has(declaration.id)) {
148
+ for (const to of [declaration.id, ...declaration.members]) {
149
+ read(to, "syntax", declaration.wildcard);
150
+ }
151
+ }
152
+ }
153
+ });
154
+ return found;
155
+ },
156
+ };
157
+ },
158
+ };