@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
@@ -19,7 +19,6 @@ export function aliasChains(project, held) {
19
19
  const ownFiles = project.ownPaths();
20
20
  const steps = new Map();
21
21
  const chains = new Map();
22
- let asked = 0;
23
22
  const declarationsOf = (symbol) => {
24
23
  const ids = [];
25
24
  for (const handle of symbol.declarations) {
@@ -52,7 +51,6 @@ export function aliasChains(project, held) {
52
51
  return steps.get(symbol.id);
53
52
  }
54
53
  const next = project.aliasStepOf(symbol);
55
- asked += 1;
56
54
  steps.set(symbol.id, next);
57
55
  return next;
58
56
  };
@@ -145,8 +143,5 @@ export function aliasChains(project, held) {
145
143
  declarationsOf,
146
144
  chainOf,
147
145
  nextDeclared,
148
- get steps() {
149
- return asked;
150
- },
151
146
  };
152
147
  }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * AMD's module forms (references-ts.37), read from the syntax because the binder declares
3
+ * none of them: `define([<ids>], factory)`, `define("<name>", [<ids>], factory)` and
4
+ * `require([<ids>], callback)` (https://github.com/amdjs/amdjs-api/blob/master/AMD.md).
5
+ */
6
+ import { isArrayLiteralExpression, isArrowFunction, isFunctionExpression, isCallExpression, isIdentifier, isNoSubstitutionTemplateLiteral, isStringLiteral, } from "@typescript/native/ast";
7
+ import { hasURLScheme, isAbsolutePath, resolvePath, startsRelativePath } from "./paths.js";
8
+ import { parenthesesRemoved } from "./unwrap.js";
9
+ /** The ids AMD binds to the factory's CommonJS parameters, which load no module. */
10
+ const FREE_VARIABLES = new Set(["require", "exports", "module"]);
11
+ /** The platform function `callee` is written as. */
12
+ export function amdPlatform(callee) {
13
+ return callee.text === "define" ? "define" : "require";
14
+ }
15
+ /**
16
+ * The dependency list one call writes, where it is a call of a bare `define` or `require` in
17
+ * one of AMD's forms. A `define` with no list, of a factory or a value alone, loads nothing;
18
+ * a `require` whose first argument is no array literal is CommonJS's.
19
+ */
20
+ export function amdLoadOf(node) {
21
+ if (!isCallExpression(node)) {
22
+ return undefined;
23
+ }
24
+ const callee = parenthesesRemoved(node.expression);
25
+ if (!isIdentifier(callee) || (callee.text !== "define" && callee.text !== "require")) {
26
+ return undefined;
27
+ }
28
+ const written = node.arguments.map((one) => parenthesesRemoved(one));
29
+ const [first] = written;
30
+ if (first === undefined) {
31
+ return undefined;
32
+ }
33
+ const define = callee.text === "define";
34
+ const named = define && isLiteralText(first);
35
+ const list = written[named ? 1 : 0];
36
+ if (list !== undefined && isArrayLiteralExpression(list)) {
37
+ const elements = list.elements.map((one) => parenthesesRemoved(one));
38
+ const factory = written[named ? 2 : 1];
39
+ const ids = elements.flatMap((one, at) => isLiteralText(one) && !FREE_VARIABLES.has(one.text)
40
+ ? [{ id: one, received: receives(factory, at) }]
41
+ : []);
42
+ return { callee, ids, computed: elements.some((one) => !isLiteralText(one)) };
43
+ }
44
+ if (!define) {
45
+ return undefined;
46
+ }
47
+ // A factory after the list's place makes what stands there a list, here a computed one.
48
+ return { callee, ids: [], computed: written.length > (named ? 2 : 1) };
49
+ }
50
+ function isLiteralText(node) {
51
+ return isStringLiteral(node) || isNoSubstitutionTemplateLiteral(node);
52
+ }
53
+ /** Whether a factory may receive the dependency at place `at` of its list. */
54
+ function receives(factory, at) {
55
+ if (factory === undefined) {
56
+ return false;
57
+ }
58
+ if (!isFunctionExpression(factory) && !isArrowFunction(factory)) {
59
+ return true;
60
+ }
61
+ const { parameters } = factory;
62
+ return at < parameters.length || parameters.some((one) => one.dotDotDotToken !== undefined);
63
+ }
64
+ /**
65
+ * The path a dependency id names against the calling file's directory: a relative module id,
66
+ * `./` or `../` with no `.js` ending, with `.js` appended. RequireJS reads any other id
67
+ * through its configuration or as a URL against the page, which the analysis does not know.
68
+ */
69
+ export function amdPath(dir, id) {
70
+ return startsRelativePath(id) && !id.endsWith(".js") ? resolvePath(dir, `${id}.js`) : undefined;
71
+ }
72
+ /**
73
+ * Whether one call may load a file the analysis cannot name: a computed list, or an id that
74
+ * RequireJS reads as a URL, one ending in `.js`, starting with `/` or carrying a scheme. Any
75
+ * other id {@link amdPath} reads no path from is a package's.
76
+ */
77
+ export function amdUnresolved(load) {
78
+ return (load.computed ||
79
+ load.ids.some(({ id }) => amdPath("/", id.text) === undefined &&
80
+ (id.text.endsWith(".js") || isAbsolutePath(id.text) || hasURLScheme(id.text))));
81
+ }
@@ -9,43 +9,45 @@ import { isStringLiteralLikeNode } from "@typescript/native/ast";
9
9
  import { lineOf, readComponent } from "./component-files.js";
10
10
  import { kindOf } from "./config.js";
11
11
  import { consumerReferences } from "./consumers.js";
12
- import { configuredDeclarations, configuredRef, declarationsNamed, } from "./configured-declarations.js";
12
+ import { configuredDeclarations, configuredRef, declarationsNamed, } from "./roots/configured-declarations.js";
13
13
  import { decorator } from "./decorator.js";
14
14
  import { configurationNeeds, dependenciesOf, projectNeeds } from "./dependencies.js";
15
15
  import { deprecatedDeclarations } from "./deprecation.js";
16
16
  import { moduleIdentity } from "./load/discover.js";
17
17
  import { loadRun } from "./load/load.js";
18
- import { generatedFiles } from "./conventions.js";
18
+ import { readSources } from "./entries/sources.js";
19
+ import { readWorkflows } from "./entries/workflow-steps.js";
19
20
  import { readEdgeSides } from "./edges.js";
20
21
  import { enumGroup } from "./enum-group.js";
22
+ import { bindingsOf, distinctBindings } from "./bindings.js";
21
23
  import { generatedFile, generatedFilesOf } from "./generated-file.js";
22
- import { inOperandNames } from "./in-operands.js";
24
+ import { inOperandNames } from "./findings/in-operands.js";
23
25
  import { sourceFilesOf } from "./source-files.js";
24
26
  import { evidenceRecords, heldRecords, disabledClasses, exemptionsOf, holdingWhile, isUnansweredRecord, retainedIn, writtenRecords, } from "./exempt.js";
25
27
  import { heldByInclusion, sourcePaths, sourceTree } from "./file-facts.js";
26
28
  import { findingsPass, recordedFindings, rowKey } from "./findings-pass.js";
27
29
  import { unmatchedRootFindings } from "./findings/self-check.js";
28
30
  import { frameworkLifecycle } from "./framework-lifecycle.js";
29
- import { implementations, mergeImplementations } from "./implementations.js";
31
+ import { implementations, mergeImplementations } from "./findings/implementations.js";
30
32
  import { injectionContainer } from "./injection-container.js";
31
33
  import { interfaceSatisfaction, settledSatisfaction } from "./interface-satisfaction.js";
32
34
  import { intraFunctionFacts, projectParts } from "./intra-function-parts.js";
33
35
  import {} from "./inventory.js";
34
36
  import { inventory } from "./inventory/enumerate.js";
35
- import { readManifest } from "./manifest.js";
37
+ import { readManifest } from "./roots/manifest.js";
36
38
  import { liveFilesAt, matrixOf, referenceKey, sweepMatrix, } from "./matrix.js";
37
39
  import { ancestors, dirnamePath, extensionOf, joinPath, relativePath, resolvePath, } from "./paths.js";
38
40
  import { byPosition, isComponentFile } from "./position.js";
39
- import { skippedRoots, skippedUnits } from "./type-errors.js";
41
+ import { skippedUnits } from "./type-errors.js";
40
42
  import { reflectiveLookup } from "./reflective-lookup.js";
41
- import { references, testFileRulesOf } from "./references.js";
42
- import { roots, unmatchedEverywhere, } from "./roots.js";
43
+ import { references } from "./references.js";
44
+ import { rootSet, unmatchedEverywhere, } from "./roots/root-set.js";
43
45
  import { decodedMembers, serializationContract } from "./serialization-contract.js";
44
- import { outsideTestReferences, testFilesAt } from "./outside-tests.js";
45
- import { mergedGlobalInterfaces } from "./augmentations.js";
46
- import { unseenLoadsOf } from "./unseen-loads.js";
46
+ import { outsideTestReferences, testFilesAt } from "./tests/outside.js";
47
+ import { formedForNode } from "./load/synthesize.js";
47
48
  import { GLOBALS_RUNNER, namesTestGlobals } from "./load/test-globals.js";
48
- import { supportReferences, testSupportFiles } from "./test-support.js";
49
+ import { targetTestFile, testFilePaths, testFileRulesOf, withheldBy, } from "./tests/file-class.js";
50
+ import { testSupportFiles } from "./tests/support.js";
49
51
  import { accessorsOf, storesOf } from "./stores.js";
50
52
  import { isPartKind } from "./suppress.js";
51
53
  import { bindRows, readBaseline, readIgnoreFile } from "./suppress-file.js";
@@ -53,6 +55,7 @@ import { inlineDirectives, inlineSuppressions } from "./suppress-inline.js";
53
55
  import { readTemplates, templateField } from "./template-field.js";
54
56
  import { bytewise } from "./text/compare.js";
55
57
  import { holdsManifest, manifestAt } from "./fs/manifest.js";
58
+ import { runDirectories } from "./entries/run-directories.js";
56
59
  import { globExpression } from "./text/glob.js";
57
60
  /** The setting whose source decides where a finding about a configured root sits. */
58
61
  const ROOTS_SETTING = "roots.patterns";
@@ -82,14 +85,13 @@ function readProjects(engine, host, scope, config, stage) {
82
85
  const parse = (fileName, text) => engine.parseSourceFile(fileName, text);
83
86
  return loadRun(engine, host, scope, config, ({ plan, classified, runFiles }) => {
84
87
  const { packages, conventions } = plan;
88
+ const workflows = readWorkflows(host, targetRoot);
85
89
  const options = {
86
90
  host,
87
91
  manifest: packages.manifest,
88
92
  otherPackages: packages.entries,
89
93
  patterns: config.roots.patterns,
90
94
  entryFiles: config.ts.entry_files,
91
- conventions,
92
- testFiles: config.ts.test_files,
93
95
  parse,
94
96
  publishedAPI: config.target.kind !== undefined && kindOf(config.target.kind) === "library",
95
97
  publishedMembers: packages.published,
@@ -99,18 +101,18 @@ function readProjects(engine, host, scope, config, stage) {
99
101
  const answers = classified.analyzed.map(({ plan: planned, project, skips, referenceOnly }) => {
100
102
  const read = () => {
101
103
  const held = inventory(project, host, targetRoot);
102
- const found = roots(project, held, targetRoot, options);
103
- const kept = skippedRoots(project, held, skips);
104
- const rooted = kept.length === 0
105
- ? found
106
- : {
107
- ...found,
108
- liveUnderReachability: [
109
- ...found.liveUnderReachability,
110
- ...kept.map((id) => ({ id, kind: "type-error", source: "" })),
111
- ],
112
- };
113
104
  const own = sourceFilesOf(project, targetRoot);
105
+ const sources = readSources({
106
+ host,
107
+ targetRoot,
108
+ files: own,
109
+ parse,
110
+ testFiles: config.ts.test_files,
111
+ conventions,
112
+ workflows,
113
+ });
114
+ const rooted = rootSet(project, held, targetRoot, { ...options, sources, skips });
115
+ const generated = generatedFilesOf(own, sources.generated);
114
116
  return {
115
117
  configuration: planned.id,
116
118
  configFile: project.configFile,
@@ -122,8 +124,12 @@ function readProjects(engine, host, scope, config, stage) {
122
124
  .ownSourceFiles()
123
125
  .filter((file) => referenceOnly(file.fileName))
124
126
  .flatMap((file) => relativePath(absoluteRoot, file.fileName) ?? []),
125
- generated: generatedFilesOf(own, generatedFiles(conventions, own)),
126
- testFileNames: conventions.testFiles,
127
+ generated,
128
+ bindings: bindingsOf(own.byPath, generated, new Map(held.symbols
129
+ .filter((one) => one.kind === "file")
130
+ .map((one) => [one.position.path, one.ref]))),
131
+ sources,
132
+ formedForNode: formedForNode(planned),
127
133
  };
128
134
  };
129
135
  for (const file of project.ownSourceFiles()) {
@@ -132,14 +138,25 @@ function readProjects(engine, host, scope, config, stage) {
132
138
  return stage(project, { configuration: planned.id, read });
133
139
  });
134
140
  const consumed = new Map();
141
+ const consumerHeld = new Set();
135
142
  for (const { project, consumer } of classified.consumed) {
136
143
  const side = { id: consumer.id, root: consumer.path };
137
- for (const reference of consumerReferences(project, host, targetRoot, side, config)) {
144
+ const read = consumerReferences(project, host, targetRoot, side, config, parse);
145
+ for (const reference of read.references) {
138
146
  consumed.set(referenceKey(reference), reference);
139
147
  }
148
+ for (const id of read.held) {
149
+ consumerHeld.add(id);
150
+ }
140
151
  }
141
152
  const outsideTests = testFilesAt(host, targetRoot, sourcePaths(host, targetRoot).filter((path) => !heldFiles.has(path) && testPatterns.some((pattern) => pattern.test(path))), parse);
142
- return { answers, references: [...consumed.values()], outsideTests };
153
+ return {
154
+ answers,
155
+ references: [...consumed.values()],
156
+ consumerHeld: [...consumerHeld],
157
+ outsideTests,
158
+ workflows,
159
+ };
143
160
  });
144
161
  }
145
162
  /**
@@ -204,6 +221,13 @@ export function runRoots(engine, host, scope, config, provenance) {
204
221
  unanswered: read.unanswered,
205
222
  };
206
223
  }
224
+ /** The production mode a configuration sets: a consumer's test reference is classed as `analysis.consumer_tests` says. */
225
+ export function productionMode(config) {
226
+ return {
227
+ production: true,
228
+ consumerTestsProduction: config.analysis.consumer_tests === "production",
229
+ };
230
+ }
207
231
  /** The exemption classes this analyzer detects, each by its detector; any other retains nothing. */
208
232
  export const DETECTORS = new Map([
209
233
  ["interface-satisfaction", interfaceSatisfaction],
@@ -267,12 +291,16 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
267
291
  ? { delimiters: config.analysis.template_delimiters, files: [] }
268
292
  : readTemplates(host, targetRoot, config.analysis);
269
293
  const consumers = scope.consumers.map((consumer) => consumer.path);
294
+ const directories = runDirectories(host, targetRoot, (fileName, text) => engine.parseSourceFile(fileName, text));
270
295
  const read = readProjects(engine, host, scope, config, (project, opened) => {
271
296
  const projectRead = opened.read();
297
+ const testFile = targetTestFile(projectRead.sources.testFiles);
272
298
  const resolved = references(project, projectRead.held, targetRoot, {
273
- testFiles: config.ts.test_files,
274
- testFileNames: projectRead.testFileNames,
299
+ testFile,
300
+ directories,
301
+ formedForNode: projectRead.formedForNode,
275
302
  });
303
+ const testFiles = testFilePaths(project, targetRoot, testFile);
276
304
  const evidence = evidenceRecords({
277
305
  project,
278
306
  held: projectRead.held,
@@ -292,10 +320,11 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
292
320
  return {
293
321
  projectRead,
294
322
  references: resolved.references,
295
- testFiles: resolved.testFilePaths,
323
+ held: resolved.held,
324
+ possiblyLoaded: resolved.possiblyLoaded,
325
+ testFiles,
296
326
  evidence,
297
327
  componentFiles: components.map(pathOf),
298
- augmented: mergedGlobalInterfaces(project, projectRead.held, sourceFilesOf(project, targetRoot)).map((id) => ({ id, kind: "global-augmentation", source: "" })),
299
328
  imports: new Map(project.ownSourceFiles().flatMap((file) => {
300
329
  const path = relativePath(targetRoot, file.fileName);
301
330
  if (path === undefined) {
@@ -317,8 +346,11 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
317
346
  line: lineOf(file.originalText, warning.offset),
318
347
  reason: warning.reason,
319
348
  }))),
320
- decoded: decodedMembers(project, projectRead.held, productionFiles(project, targetRoot, resolved.testFilePaths), consumers),
321
- extra: extra(project, projectRead, resolved.references, resolved.testFilePaths),
349
+ decoded: decodedMembers(project, projectRead.held, productionFiles(project, targetRoot, testFiles), consumers),
350
+ extra: extra(project, projectRead, resolved.references, testFiles, resolved.unseenLoads.map((position) => ({
351
+ configuration: projectRead.configuration,
352
+ position,
353
+ }))),
322
354
  };
323
355
  });
324
356
  const outsidePaths = read.result.outsideTests.map((one) => one.path);
@@ -332,7 +364,9 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
332
364
  }));
333
365
  // Test-support code is code only test code imports in any configuration of the run: a
334
366
  // configuration that holds no test file says nothing about what the tests import.
335
- const { support, testUsed } = testSupportFiles(withOutside.flatMap((one) => one.projectRead.held.symbols), withOutside.flatMap((one) => one.references), withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability), withOutside.flatMap((one) => one.testFiles), testEvidence(host, targetRoot, withOutside));
367
+ const { support, testUsed } = testSupportFiles(withOutside.flatMap((one) => one.projectRead.held.symbols), withOutside.flatMap((one) => one.references),
368
+ // An outside declaration naming a global augmentation calls nothing of its file.
369
+ withOutside.flatMap((one) => one.projectRead.rooted.liveUnderReachability.filter((root) => root.kind !== "global-augmentation")), withOutside.flatMap((one) => one.testFiles), testEvidence(host, targetRoot, withOutside));
336
370
  // A member a decode fills or a copy carries is written: a value decoded and sent again carries it on.
337
371
  const written = new Set([
338
372
  ...countedWrites([...withOutside.flatMap((one) => one.references), ...read.result.references], support, mode),
@@ -355,7 +389,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
355
389
  testFiles: new Set([...one.testFiles, ...support]),
356
390
  });
357
391
  const exempt = detected.records;
358
- const made = supportReferences([...one.references, ...(satisfied?.references ?? [])], support);
392
+ const made = [...one.references, ...(satisfied?.references ?? [])];
359
393
  const held = new Set(projectRead.held.symbols.map((symbol) => symbol.position.path));
360
394
  const supportFiles = [...support].filter((path) => held.has(path)).sort(bytewise);
361
395
  const testUsedFiles = [...testUsed].filter((path) => held.has(path)).sort(bytewise);
@@ -363,9 +397,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
363
397
  configuration: projectRead.configuration,
364
398
  symbols: projectRead.held.symbols,
365
399
  references: [...made, ...evidenceReferences(projectRead.held.symbols, detected.inTestFiles)],
366
- // The augmentations are rooted after test support is read: an outside declaration
367
- // naming one calls nothing of its file.
368
- roots: [...projectRead.rooted.liveUnderReachability, ...one.augmented],
400
+ roots: projectRead.rooted.liveUnderReachability,
369
401
  testFiles: [...one.testFiles, ...supportFiles],
370
402
  ...(supportFiles.length === 0 ? {} : { supportFiles }),
371
403
  ...(testUsedFiles.length === 0 ? {} : { testUsedFiles }),
@@ -384,13 +416,13 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
384
416
  unanswered: [
385
417
  ...projectRead.held.unanswered,
386
418
  ...projectRead.rooted.unanswered,
387
- ...made
388
- .filter((reference) => reference.resolution === "by-name")
389
- .map((reference) => reference.to),
419
+ ...made.filter((reference) => reference.guessed === true).map((reference) => reference.to),
420
+ ...one.held,
390
421
  ...exempt.filter(isUnansweredRecord).map((record) => record.id),
391
422
  ...one.decoded.unanswered,
392
423
  ],
393
424
  filledOutside: one.decoded.filled,
425
+ possiblyLoaded: one.possiblyLoaded,
394
426
  typeErrorSkips: projectRead.typeErrorSkips,
395
427
  unmappedEntries: projectRead.rooted.unmappedEntries,
396
428
  heldScripts: projectRead.rooted.heldScripts,
@@ -416,7 +448,8 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
416
448
  unansweredHeld: [
417
449
  ...new Set([
418
450
  ...answers.flatMap((one) => one.unanswered),
419
- ...consumed.filter((one) => one.resolution === "by-name").map((one) => one.to),
451
+ ...consumed.filter((one) => one.guessed === true).map((one) => one.to),
452
+ ...read.result.consumerHeld,
420
453
  ]),
421
454
  ],
422
455
  projects,
@@ -431,6 +464,7 @@ function readRun(engine, host, scope, config, mode, detectors, extra) {
431
464
  conventionUses: read.plan.conventions.uses,
432
465
  memberDirs: read.plan.packages.members,
433
466
  nestedDirs: read.plan.packages.nested,
467
+ workflows: read.result.workflows,
434
468
  };
435
469
  }
436
470
  /**
@@ -488,7 +522,7 @@ function evidenceReferences(symbols, inTestFiles) {
488
522
  * makes being a test's.
489
523
  */
490
524
  function countedWrites(references, support, mode) {
491
- return new Set(supportReferences(references, support).flatMap((reference) => reference.use === "write" && !(mode.production && reference.test) ? [reference.to] : []));
525
+ return new Set(references.flatMap((reference) => reference.use === "write" && !withheldBy(mode, reference, support) ? [reference.to] : []));
492
526
  }
493
527
  /**
494
528
  * The declarations every reference the mode counts stores into, a loaded consumer's
@@ -498,8 +532,9 @@ function writtenOnly(read, mode) {
498
532
  const written = new Set();
499
533
  const readSome = new Set();
500
534
  for (const { configured } of read.projects) {
535
+ const support = new Set(configured.supportFiles ?? []);
501
536
  for (const reference of configured.references) {
502
- if (mode.production && reference.test) {
537
+ if (withheldBy(mode, reference, support)) {
503
538
  continue;
504
539
  }
505
540
  if (reference.use === "write" && reference.consumer === undefined) {
@@ -528,7 +563,7 @@ function sweptOf(read, input) {
528
563
  // over what it reads, the test of dead code among them, cannot judge it.
529
564
  for (const { configured } of read.projects) {
530
565
  for (const reference of configured.references) {
531
- if (reference.resolution === "by-name") {
566
+ if (reference.guessed === true) {
532
567
  held.add(reference.from);
533
568
  }
534
569
  }
@@ -536,7 +571,7 @@ function sweptOf(read, input) {
536
571
  const dead = new Map(result.candidates.map((candidate) => [candidate.id, candidate]));
537
572
  const answered = matrixOf(read.projects.map(({ configured }) => ({
538
573
  ...configured,
539
- references: configured.references.filter((one) => one.resolution !== "by-name"),
574
+ references: configured.references.filter((one) => one.guessed !== true),
540
575
  })));
541
576
  const bare = {
542
577
  ...swept,
@@ -582,19 +617,20 @@ function productionFiles(project, targetRoot, testFiles) {
582
617
  /** Reads a run's projects with every per-project fact an emitter reads. */
583
618
  export function readEmitterRun(engine, host, scope, config, mode, detectors) {
584
619
  const targetRoot = scope.target.path;
585
- const run = readRun(engine, host, scope, config, mode, detectors, (project, read, references, testFiles) => ({
620
+ const run = readRun(engine, host, scope, config, mode, detectors, (project, read, references, testFiles, unseenLoads) => ({
586
621
  deprecation: deprecatedDeclarations(project, read.held),
587
622
  accessors: accessorsOf(project, read.held),
588
- needs: projectNeeds(project, read.held, host, targetRoot, (fileName, text) => engine.parseSourceFile(fileName, text)),
623
+ needs: projectNeeds(project, read.held, host, targetRoot, (fileName, text) => engine.parseSourceFile(fileName, text), read.sources.configuration, read.sources.workflows),
589
624
  implementations: implementations(project, read.held),
590
625
  heldByInclusion: heldByInclusion(project, targetRoot),
591
- generated: [...read.generated.keys()],
626
+ generated: read.generated,
627
+ bindings: read.bindings,
592
628
  inOperands: inOperandNames(project, targetRoot, testFiles),
593
629
  rooted: read.rooted,
594
630
  directives: inlineDirectives(project, read.held, targetRoot).filter((directive) => !read.referenceOnly.includes(directive.site.path)),
595
631
  declarationsNamed: declarationsNamed(project, read.held, configuredDeclarations(config)),
596
632
  parts: projectParts(project, read.held, references, targetRoot),
597
- unseenLoads: unseenLoadsOf(project, read.configuration, targetRoot, testFiles),
633
+ unseenLoads,
598
634
  }));
599
635
  // Whether a declaration carries the marker decides its code, so one whose answer went
600
636
  // unread is reported by nothing.
@@ -656,14 +692,15 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
656
692
  deprecated: new Set(projects.flatMap((one) => one.extra.deprecation.deprecated)),
657
693
  stores: storesOf(projects.map((one) => ({
658
694
  references: one.configured.references,
695
+ support: new Set(one.configured.supportFiles ?? []),
659
696
  accessors: one.extra.accessors,
660
697
  })), swept.exempt, input.mode),
661
- dependencies: dependenciesOf(host, targetRoot, [...projects.map((one) => one.extra.needs), configurationNeeds(read.conventionUses)], swept.sweep.candidates.map((candidate) => candidate.id), members.read, members.unbuilt, read.nestedDirs),
698
+ dependencies: dependenciesOf(host, targetRoot, read.workflows, [...projects.map((one) => one.extra.needs), configurationNeeds(read.conventionUses)], swept.sweep.candidates.map((candidate) => candidate.id), members.read, members.unbuilt, read.nestedDirs),
662
699
  implementations: mergeImplementations(projects.map((one) => one.extra.implementations)),
663
700
  files: {
664
701
  tree: sourceTree(host, targetRoot),
665
702
  heldByInclusion: new Set(projects.flatMap((one) => one.extra.heldByInclusion)),
666
- generated: new Set(projects.flatMap((one) => one.extra.generated)),
703
+ generated: new Set(projects.flatMap((one) => [...one.extra.generated.keys()])),
667
704
  inOperands: new Set(projects.flatMap((one) => one.extra.inOperands)),
668
705
  unseenLoads: projects.flatMap((one) => one.extra.unseenLoads),
669
706
  },
@@ -675,6 +712,7 @@ export function emitterInputOver(host, scope, config, read, input, selfCheck) {
675
712
  encapsulated: readManifest(host, targetRoot).declaresExports,
676
713
  edges: readEdgeSides(host, targetRoot),
677
714
  filledOutside: new Set(projects.flatMap((one) => one.filledOutside)),
715
+ possiblyLoaded: new Set(projects.flatMap((one) => one.possiblyLoaded)),
678
716
  },
679
717
  selfCheck,
680
718
  intraFunction: intraFunctionFacts(projects.map((one) => one.extra.parts), projects.flatMap((one) => one.configured.references), new Set([...swept.exempt.map((one) => one.id), ...swept.heldByUnanswered])),
@@ -721,6 +759,8 @@ function readAnalysis(engine, host, scope, config, provenance, mode, detectors)
721
759
  unmappedEntries: unmappedEverywhere(read.projects),
722
760
  heldScripts: read.projects.flatMap((one) => one.heldScripts.map((held) => ({ ...held, configFile: one.configFile }))),
723
761
  unseenLoads: read.projects.flatMap((one) => one.extra.unseenLoads),
762
+ generated: new Map(read.projects.flatMap((one) => [...one.extra.generated])),
763
+ bindings: distinctBindings(read.projects.flatMap((one) => one.extra.bindings)),
724
764
  },
725
765
  configured: read.projects.map((one) => one.configured),
726
766
  symbols,
@@ -50,19 +50,15 @@ function holdersOf(held, scripts) {
50
50
  * file or a `declare` holds that a `declare global` block, or the top level of a file in
51
51
  * `scripts`, declares, directly or inside a namespace there.
52
52
  */
53
- export function ambientGlobalInterfaces(held, interfaces, scripts) {
53
+ function ambientGlobalInterfaces(held, interfaces, scripts) {
54
54
  const holders = holdersOf(held, scripts);
55
55
  return holders === undefined
56
56
  ? []
57
57
  : interfaces.filter((id) => held.ambient.has(id) && holders(id).global);
58
58
  }
59
59
  /**
60
- * Each ambient global interface of the project's own files that merges into an interface
61
- * declared outside them, with every interface, namespace and block between it and the
62
- * global scope: the outside declaration names it wherever a value is typed by it. Where
63
- * every outside declaration is a package's, not the compiler's library, and declares no
64
- * member, each member it declares as well: such an interface is a slot the package reads
65
- * by type, as `keyof` does, in declarations the analysis does not walk.
60
+ * Which ambient global interfaces of the project's own files, `files`, merge into an interface
61
+ * declared outside them, and what each merge keeps.
66
62
  */
67
63
  export function mergedGlobalInterfaces(project, held, files) {
68
64
  const scripts = new Set();
@@ -88,7 +84,7 @@ export function mergedGlobalInterfaces(project, held, files) {
88
84
  const global = new Set(ambientGlobalInterfaces(held, [...names.keys()], scripts));
89
85
  const asked = [...names].filter(([id]) => global.has(id));
90
86
  if (asked.length === 0) {
91
- return [];
87
+ return { scripts, interfaces: new Set(), kept: [] };
92
88
  }
93
89
  const answers = project.symbolsAt(asked.map(([, name]) => project.handle(name)));
94
90
  const holders = holdersOf(held, scripts);
@@ -99,22 +95,25 @@ export function mergedGlobalInterfaces(project, held, files) {
99
95
  const node = project.declarationAt(handle)?.node;
100
96
  return node !== undefined && isInterfaceDeclaration(node) && node.members.length === 0;
101
97
  };
102
- return [
103
- ...new Set(asked.flatMap(([id], at) => {
104
- const symbol = answers[at];
105
- if (typeof symbol !== "object") {
106
- return [];
107
- }
108
- const outside = symbol.declarations.filter((handle) => !files.byName.has(handle.path));
109
- if (outside.length === 0) {
110
- return [];
111
- }
112
- const members = outside.every(empty)
113
- ? held.symbols.filter((one) => one.parent === id).map((one) => one.id)
114
- : [];
115
- return [id, ...(holders?.(id).ids ?? []), ...members];
116
- })),
117
- ];
98
+ const interfaces = new Set();
99
+ const kept = new Set();
100
+ asked.forEach(([id], at) => {
101
+ const symbol = answers[at];
102
+ const outside = typeof symbol === "object"
103
+ ? symbol.declarations.filter((handle) => !files.byName.has(handle.path))
104
+ : [];
105
+ if (outside.length === 0) {
106
+ return;
107
+ }
108
+ interfaces.add(id);
109
+ const members = outside.every(empty)
110
+ ? held.symbols.filter((one) => one.parent === id).map((one) => one.id)
111
+ : [];
112
+ for (const one of [id, ...(holders?.(id).ids ?? []), ...members]) {
113
+ kept.add(one);
114
+ }
115
+ });
116
+ return { scripts, interfaces, kept: [...kept] };
118
117
  }
119
118
  /**
120
119
  * For each reference to a declaration an augmentation block, or the global scope of a