@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
@@ -0,0 +1,151 @@
1
+ import { isBinaryExpression, isParenthesizedExpression, isPropertyAccessExpression, SyntaxKind, } from "@typescript/native/ast";
2
+ import { bindingsOf } from "../import-bindings.js";
3
+ import { byPosition, renderPosition } from "../position.js";
4
+ import { bytewise } from "../text/compare.js";
5
+ /**
6
+ * Where every reference of one pass is made: it renders the position against the side's
7
+ * root, takes the writing file's test class from the file classes, marks a use only a
8
+ * declaration's name answered `guessed` and an alias step's `alias`, tags a consumer's
9
+ * reference with the consumer, and orders the records.
10
+ */
11
+ export class Sink {
12
+ #root;
13
+ #testFile;
14
+ #consumer;
15
+ #found = [];
16
+ #valued = new Map();
17
+ #held = new Set();
18
+ constructor(root, testFile, consumer) {
19
+ this.#root = root;
20
+ this.#testFile = testFile;
21
+ this.#consumer = consumer;
22
+ }
23
+ /** Whether a test file wrote one walked file's uses. */
24
+ isTest(file) {
25
+ return this.#testFile(file);
26
+ }
27
+ /** The position one node of a walked file renders at. */
28
+ position(file, at) {
29
+ return renderPosition(file, this.#root, at.getStart());
30
+ }
31
+ /**
32
+ * Records one use of each target, made by `from` at `at` in `file`. A write that stores
33
+ * `value` is remembered for the import bindings only its values use. A `production` use is
34
+ * production code's whoever writes it.
35
+ */
36
+ add(file, at, from, targets, use, via, value, production = false) {
37
+ const position = "column" in at ? at : this.position(file, at);
38
+ const test = !production && this.#testFile(file);
39
+ for (const one of targets) {
40
+ const target = typeof one === "string" ? { id: one } : one;
41
+ this.#found.push({
42
+ from,
43
+ to: target.id,
44
+ position,
45
+ use,
46
+ resolution: target.guessed === true ? "by-name" : target.stepped === true ? "alias" : via,
47
+ test,
48
+ ...(target.guessed === true ? { guessed: true } : {}),
49
+ });
50
+ if (use === "write" && value !== undefined) {
51
+ const valued = this.#valued.get(file) ?? [];
52
+ valued.push({ index: this.#found.length - 1, value });
53
+ this.#valued.set(file, valued);
54
+ }
55
+ }
56
+ }
57
+ /** Holds declarations an unanswered question could have made live, and the one whose read asked it. */
58
+ hold(ids) {
59
+ for (const id of ids) {
60
+ this.#held.add(id);
61
+ }
62
+ }
63
+ /** The records made so far, before {@link finish} orders them. */
64
+ get made() {
65
+ return this.#found;
66
+ }
67
+ /** Appends records another stage derived from these, rendered already. */
68
+ extend(references) {
69
+ this.#found.push(...references);
70
+ }
71
+ /**
72
+ * The records in position order, then the declaration named, the referencing declaration
73
+ * and the use, each write marked with the import bindings only its values use, and the
74
+ * held declarations. `usesOf` gives each walked file's name sites.
75
+ */
76
+ finish(usesOf) {
77
+ const found = this.#found;
78
+ for (const [file, writes] of this.#valued) {
79
+ for (const { index, names } of aloneIn(file, usesOf.get(file) ?? [], writes, found)) {
80
+ const reference = found[index];
81
+ if (reference !== undefined) {
82
+ found[index] = { ...reference, alone: names };
83
+ }
84
+ }
85
+ }
86
+ found.sort((a, b) => byPosition(a.position, b.position) ||
87
+ bytewise(a.to, b.to) ||
88
+ bytewise(a.from, b.from) ||
89
+ bytewise(a.use, b.use));
90
+ const consumer = this.#consumer;
91
+ return {
92
+ references: consumer === undefined
93
+ ? found
94
+ : found.map((reference) => ({ ...reference, consumer: consumer.id })),
95
+ held: [...this.#held].sort(bytewise),
96
+ };
97
+ }
98
+ }
99
+ /** The value one assignment stores through the name it writes, where it is a plain assignment. */
100
+ export function storedValue(name) {
101
+ let target = name;
102
+ if (isPropertyAccessExpression(name.parent) && name.parent.name === name) {
103
+ target = name.parent;
104
+ }
105
+ while (isParenthesizedExpression(target.parent)) {
106
+ target = target.parent;
107
+ }
108
+ const parent = target.parent;
109
+ return isBinaryExpression(parent) &&
110
+ parent.operatorToken.kind === SyntaxKind.EqualsToken &&
111
+ parent.left === target
112
+ ? parent.right
113
+ : undefined;
114
+ }
115
+ /**
116
+ * The import bindings of one file that only the values written into one declaration
117
+ * use, for each write into it. A binding is named by an identifier that spells its
118
+ * local name and is not the member a property access names.
119
+ */
120
+ function aloneIn(file, uses, writes, found) {
121
+ const bindings = new Set(bindingsOf(file).map((binding) => binding.name.text));
122
+ if (bindings.size === 0) {
123
+ return [];
124
+ }
125
+ const occurrences = new Map();
126
+ for (const site of uses) {
127
+ const text = site.node.getText();
128
+ const parent = site.node.parent;
129
+ if (!bindings.has(text) || (isPropertyAccessExpression(parent) && parent.name === site.node)) {
130
+ continue;
131
+ }
132
+ if (!occurrences.get(text)?.includes(site.node)) {
133
+ occurrences.set(text, [...(occurrences.get(text) ?? []), site.node]);
134
+ }
135
+ }
136
+ const inside = (node, value) => node.pos >= value.pos && node.end <= value.end;
137
+ const result = [];
138
+ for (const write of writes) {
139
+ const to = found[write.index]?.to;
140
+ const sameTarget = writes.filter((one) => found[one.index]?.to === to);
141
+ const names = [...occurrences]
142
+ .filter(([, nodes]) => nodes.some((node) => inside(node, write.value)) &&
143
+ nodes.every((node) => sameTarget.some((one) => inside(node, one.value))))
144
+ .map(([name]) => name)
145
+ .sort(bytewise);
146
+ if (names.length > 0) {
147
+ result.push({ index: write.index, names });
148
+ }
149
+ }
150
+ return result;
151
+ }
@@ -0,0 +1,450 @@
1
+ /**
2
+ * The reference sources of the reference pass: each turns one form of site the walk found in a
3
+ * file into uses, through the file's one batch, into the pass's one sink. A source names the
4
+ * nodes it needs the batch to answer, and the pass asks them all in capped runs.
5
+ */
6
+ import { isExportDeclaration, isIdentifier, isImportDeclaration, isStringLiteralLikeNode, } from "@typescript/native/ast";
7
+ import { amdPath, amdPlatform } from "../amd.js";
8
+ import { specifierCandidates } from "../entries/configuration-files.js";
9
+ import { bindingsOf, importedNames } from "../import-bindings.js";
10
+ import { isLiteralText, WORKER_CONSTRUCTORS, } from "../index/sites.js";
11
+ import { nodeKey } from "../inventory.js";
12
+ import { JAVASCRIPT_FILE } from "../javascript-file.js";
13
+ import { dirnamePath, isRelativeSpecifier, queriedModulePath, relativeURLPath, resolvePath, startsRelativePath, } from "../paths.js";
14
+ import { callsPlatform, isPlatformGlobal, startsThread } from "../platform-symbols.js";
15
+ import { isComponentFile } from "../position.js";
16
+ import { UNANSWERED } from "../query.js";
17
+ import { computedLoadsOf } from "../roots/unseen-loads.js";
18
+ import { computedKeyNames, keyedUses } from "../symbol-keys.js";
19
+ import { storedValue } from "./sink.js";
20
+ /** The file of the target a relative specifier written in `file` names, by its source or output name. */
21
+ function fileNamed(file, specifier, fileIdByName) {
22
+ return specifierCandidates(dirnamePath(file.fileName), specifier)
23
+ .map((path) => fileIdByName.get(path))
24
+ .find((id) => id !== undefined);
25
+ }
26
+ /**
27
+ * The own file a module specifier with a query evaluates ({@link queriedModulePath}): the
28
+ * checker resolves the whole specifier to whatever module declaration matches it.
29
+ */
30
+ function queriedFile(file, specifier, fileIdByName) {
31
+ if (!isLiteralText(specifier)) {
32
+ return undefined;
33
+ }
34
+ const path = queriedModulePath(specifier.text);
35
+ return path === undefined
36
+ ? undefined
37
+ : fileIdByName.get(resolvePath(dirnamePath(file.fileName), path));
38
+ }
39
+ /**
40
+ * A decorator is written inside the declaration it is attached to and receives it, so the
41
+ * declaration is used where the decorator is written, whatever the decorator does with it.
42
+ */
43
+ const decorators = {
44
+ emit({ file, decorated }, _answered, { sink }) {
45
+ for (const { decorator, declaration } of decorated) {
46
+ sink.add(file, decorator, declaration, [declaration], "decorator", "syntax");
47
+ }
48
+ },
49
+ };
50
+ /** The constructor stores its argument in the member a parameter property declares. */
51
+ const parameterWrites = {
52
+ emit({ file, parameterWrites: writes }, _answered, { sink }) {
53
+ for (const { name, from, member } of writes) {
54
+ sink.add(file, name, from, [member], "write", "syntax");
55
+ }
56
+ },
57
+ };
58
+ /**
59
+ * A re-export references the first declaration its alias chain carries forward that the
60
+ * inventory declares, one link per re-export, or for a bare star the module it names.
61
+ */
62
+ const links = {
63
+ batched: ({ links: found }) => found.map((link) => link.node),
64
+ emit({ file, links: found }, answered, { sink, chains, named }) {
65
+ for (const link of found) {
66
+ const symbol = answered.get(link.node);
67
+ if (symbol === undefined) {
68
+ continue;
69
+ }
70
+ const carried = symbol === UNANSWERED ? named(link.at) : carriedBy(chains, link, symbol);
71
+ sink.add(file, link.at, link.from, carried, "read", link.alias ? "alias" : "batch");
72
+ }
73
+ },
74
+ };
75
+ /**
76
+ * The declarations one re-export carries forward: for an alias, the first link along its chain
77
+ * that the inventory declares, stepping over the links it does not, such as an import the
78
+ * re-export is written against; for a bare star, the module it names.
79
+ */
80
+ function carriedBy(chains, link, symbol) {
81
+ return link.alias
82
+ ? chains.nextDeclared(symbol).map((target) => ({ ...target, stepped: false }))
83
+ : chains.declarationsOf(symbol).map((id) => ({ id, stepped: false, guessed: false }));
84
+ }
85
+ /**
86
+ * Whether one evaluation loads its module: an import form, or a `require`, or an AMD `define`
87
+ * or `require`, that {@link callsPlatform} names.
88
+ */
89
+ function loading(evaluation, answered, project) {
90
+ const { require } = evaluation;
91
+ return (require === undefined ||
92
+ callsPlatform(project, evaluation.amd === true ? amdPlatform(require) : "require", require, answered.get(require)));
93
+ }
94
+ /**
95
+ * Every import of one of the target's modules evaluates that module's file. A required
96
+ * file the checker names no module for is read whole where the call's value is used: the
97
+ * value is the file's exports object, which this pass does not follow.
98
+ */
99
+ const evaluations = {
100
+ batched: ({ evaluations: found }) => found.flatMap((evaluation) => evaluation.require === undefined
101
+ ? [evaluation.node]
102
+ : [
103
+ evaluation.require,
104
+ ...(evaluation.require.text === "require" && evaluation.amd !== true
105
+ ? [evaluation.node]
106
+ : []),
107
+ ]),
108
+ emit({ file, evaluations: found }, answered, pass) {
109
+ const { project, sink, fileIds, fileIdByName, chains, loadableById, cap, exportsRead } = pass;
110
+ const loaded = found.filter((one) => loading(one, answered, project));
111
+ // A script declares no module, so the checker names nothing for a specifier of one;
112
+ // the compiler's module resolution still names its file.
113
+ const unnamed = loaded.flatMap(({ node, amd }) => amd !== true &&
114
+ answered.get(node) === undefined &&
115
+ isStringLiteralLikeNode(node) &&
116
+ queriedFile(file, node, fileIdByName) === undefined
117
+ ? [node]
118
+ : []);
119
+ const resolved = project.resolvedFileNames(unnamed);
120
+ const scripts = new Map(unnamed.map((node, at) => {
121
+ const name = resolved[at];
122
+ return [node, name === undefined ? undefined : fileIdByName.get(name)];
123
+ }));
124
+ const wholeReads = [];
125
+ for (const evaluation of loaded) {
126
+ const queried = queriedFile(file, evaluation.node, fileIdByName);
127
+ if (queried !== undefined) {
128
+ sink.add(file, evaluation.node, evaluation.from, [queried], "evaluation", "syntax");
129
+ }
130
+ const module = answered.get(evaluation.node);
131
+ const amd = evaluation.amd === true && isLiteralText(evaluation.node);
132
+ const amdFile = amd
133
+ ? fileIdByName.get(amdPath(dirnamePath(file.fileName), evaluation.node.text) ?? "")
134
+ : undefined;
135
+ // Node's require resolves a relative specifier the program records no resolution for,
136
+ // as in a TypeScript file, by its own extension search.
137
+ const script = amdFile ??
138
+ scripts.get(evaluation.node) ??
139
+ (!amd &&
140
+ evaluation.require !== undefined &&
141
+ module === undefined &&
142
+ isLiteralText(evaluation.node) &&
143
+ startsRelativePath(evaluation.node.text)
144
+ ? fileNamed(file, evaluation.node.text, fileIdByName)
145
+ : undefined);
146
+ if (script === undefined && module === undefined) {
147
+ possibleLoad(file, evaluation, pass);
148
+ }
149
+ if (script !== undefined) {
150
+ const whole = loadableById.get(script);
151
+ if (evaluation.whole === true && module === undefined && whole !== undefined) {
152
+ wholeReads.push({ evaluation, loaded: whole });
153
+ }
154
+ sink.add(file, evaluation.node, evaluation.from, [script], "evaluation", "syntax");
155
+ }
156
+ if (module === undefined) {
157
+ continue;
158
+ }
159
+ // A module the checker could not resolve may be any file of the target.
160
+ const evaluated = module === UNANSWERED
161
+ ? [...fileIds].map((id) => ({ id, guessed: true }))
162
+ : chains
163
+ .declarationsOf(module)
164
+ .flatMap((id) => (fileIds.has(id) ? [id] : []))
165
+ .map((id) => ({ id }));
166
+ sink.add(file, evaluation.node, evaluation.from, evaluated, "evaluation", "batch");
167
+ }
168
+ const modules = project.symbolsAt(wholeReads.map((one) => project.handle(one.loaded)), cap);
169
+ wholeReads.forEach(({ evaluation }, at) => {
170
+ const module = modules[at];
171
+ const targets = module === undefined ? [] : exportsRead(module);
172
+ sink.add(file, evaluation.node, evaluation.from, targets, "read", "batch");
173
+ });
174
+ },
175
+ };
176
+ /**
177
+ * An import of a JavaScript file that a program formed for Node leaves unresolved, asked again
178
+ * as a bundler resolves it (program.38): the file it names, and each export there the import
179
+ * binds, a namespace import binding every one, are only possibly loaded.
180
+ */
181
+ function possibleLoad(file, evaluation, pass) {
182
+ const { node } = evaluation;
183
+ const declaration = node.parent;
184
+ if (!pass.formedForNode ||
185
+ evaluation.require !== undefined ||
186
+ !JAVASCRIPT_FILE.test(file.fileName) ||
187
+ !isLiteralText(node) ||
188
+ !isRelativeSpecifier(node.text) ||
189
+ !(isImportDeclaration(declaration) || isExportDeclaration(declaration))) {
190
+ return;
191
+ }
192
+ const loaded = fileNamed(file, node.text, pass.fileIdByName);
193
+ if (loaded === undefined) {
194
+ return;
195
+ }
196
+ pass.possiblyLoaded.add(loaded);
197
+ const exported = pass.declaredIn(loaded).filter((one) => one.exported);
198
+ for (const name of importedNames(declaration)) {
199
+ for (const one of exported) {
200
+ if (name === undefined || one.name === name) {
201
+ pass.possiblyLoaded.add(one.id);
202
+ }
203
+ }
204
+ }
205
+ }
206
+ /** A module URL the platform's `URL` builds names the file a runtime starts as a module. */
207
+ const urls = {
208
+ batched: ({ urls: found }) => found.flatMap((url) => url.constructor ?? []),
209
+ emit({ file, urls: found }, answered, { project, sink, fileIdByName }) {
210
+ for (const url of found) {
211
+ if (url.constructor !== undefined &&
212
+ !callsPlatform(project, "URL", url.constructor, answered.get(url.constructor))) {
213
+ continue;
214
+ }
215
+ const path = relativeURLPath(dirnamePath(file.fileName), url.specifier);
216
+ const loaded = path === undefined ? undefined : fileNamed(file, path, fileIdByName);
217
+ if (loaded !== undefined) {
218
+ sink.add(file, url.at, url.from, [loaded], "evaluation", "syntax");
219
+ }
220
+ }
221
+ },
222
+ };
223
+ /**
224
+ * A worker address names the file a runtime starts (references-ts.2): Node's `Worker` reads
225
+ * a relative path against the working directory and a path of the module's own directory
226
+ * against that directory, a browser's an address against the module's URL.
227
+ */
228
+ const workers = {
229
+ batched: ({ workers: found }) => found.flatMap((worker) => worker.holder === undefined ? [worker.constructor] : [worker.constructor, worker.holder]),
230
+ emit({ file, workers: found }, answered, pass) {
231
+ const { project, sink, fileIds, directories, held } = pass;
232
+ for (const worker of found) {
233
+ const symbol = answered.get(worker.constructor);
234
+ const text = worker.address;
235
+ let path;
236
+ if (startsThread(project, symbol, worker.holder && answered.get(worker.holder))) {
237
+ path = worker.evaluated
238
+ ? undefined
239
+ : worker.ownDirectory
240
+ ? resolvePath(dirnamePath(file.fileName), text)
241
+ : startsRelativePath(text)
242
+ ? resolvePath(directories.workingDirectoryOf(file.fileName), text)
243
+ : undefined;
244
+ }
245
+ else if (!worker.ownDirectory &&
246
+ (WORKER_CONSTRUCTORS.has(worker.constructor.text) ||
247
+ worker.constructor.text === "navigator") &&
248
+ isPlatformGlobal(project, symbol)) {
249
+ path = relativeURLPath(dirnamePath(file.fileName), text);
250
+ }
251
+ const started = (path === undefined ? [] : pass.ownFiles().named(path)).flatMap((one) => {
252
+ const id = held.declarations.get(nodeKey(one, one));
253
+ return id !== undefined && fileIds.has(id) ? [id] : [];
254
+ });
255
+ sink.add(file, worker.at, worker.from, started, "evaluation", "syntax");
256
+ }
257
+ },
258
+ };
259
+ /**
260
+ * A computed load imports each file it loads where the call is written, reading what the file
261
+ * exports unless it reads the file as text or a URL; callsPlatform owns which call is a `require`.
262
+ */
263
+ const loads = {
264
+ batched: ({ loads: found }) => found.flatMap((load) => [
265
+ ...(load.require === undefined ? [] : [load.require]),
266
+ ...(load.asset ? [] : load.files.map((loaded) => loaded.file)),
267
+ ]),
268
+ emit({ file, fileId, loads: found }, answered, pass) {
269
+ const { project, sink, consumer, exportsRead, unseenLoads } = pass;
270
+ for (const load of found) {
271
+ if (load.require !== undefined &&
272
+ !callsPlatform(project, load.amd ? amdPlatform(load.require) : "require", load.require, answered.get(load.require))) {
273
+ continue;
274
+ }
275
+ const position = sink.position(file, load.call);
276
+ if (!load.resolved && !consumer && !file.isDeclarationFile && !sink.isTest(file)) {
277
+ unseenLoads.push(position);
278
+ }
279
+ for (const loaded of load.files) {
280
+ sink.add(file, position, load.eager ? fileId : load.from, [loaded.fileId], "evaluation", "syntax");
281
+ const module = load.asset ? undefined : answered.get(loaded.file);
282
+ sink.add(file, position, load.from, module === undefined ? [] : exportsRead(module), "read", "batch");
283
+ }
284
+ }
285
+ },
286
+ };
287
+ /** A use of a module namespace object that may read every export of the module reads them all. */
288
+ const wholes = {
289
+ batched: ({ wholes: found }) => found.map((whole) => whole.specifier),
290
+ emit({ file, wholes: found }, answered, { sink, exportsRead }) {
291
+ for (const whole of found) {
292
+ const module = answered.get(whole.specifier);
293
+ if (module !== undefined) {
294
+ sink.add(file, whole.at, whole.from, exportsRead(module), "read", "batch");
295
+ }
296
+ }
297
+ },
298
+ };
299
+ /**
300
+ * A component file's markup may use any binding its blocks declare at the top level, and any
301
+ * export of a module a binding's chain reaches, whether a namespace import binds it or a named
302
+ * or default import of a namespace re-export.
303
+ */
304
+ const markup = {
305
+ batched: ({ bindings }) => bindings,
306
+ emit({ file, fileId, markup: written, bindings }, answered, pass) {
307
+ if (!written) {
308
+ return;
309
+ }
310
+ const { sink, chains, named, declaredIn } = pass;
311
+ for (const symbol of declaredIn(fileId)) {
312
+ sink.add(file, symbol.position, fileId, [symbol.id], "read", "syntax");
313
+ }
314
+ for (const binding of bindings) {
315
+ const symbol = answered.get(binding);
316
+ if (symbol === undefined) {
317
+ continue;
318
+ }
319
+ const chained = symbol === UNANSWERED ? named(binding) : chains.chainOf(symbol);
320
+ const targets = chained.flatMap((target) => [
321
+ target,
322
+ ...declaredIn(target.id)
323
+ .filter((one) => one.exported)
324
+ .map((one) => ({ ...target, id: one.id })),
325
+ ]);
326
+ sink.add(file, binding, fileId, targets, "read", "batch");
327
+ }
328
+ },
329
+ };
330
+ /**
331
+ * A pattern names a property of the value it destructures, which no name node of the pattern
332
+ * resolves to: a shorthand's name is the local it binds.
333
+ */
334
+ const patterns = {
335
+ emit({ file, reads }, _answered, { sink, held, destructured, targetsOf }) {
336
+ destructured.resolve(reads).forEach((symbol, index) => {
337
+ const read = reads[index];
338
+ if (symbol === undefined || read === undefined) {
339
+ return;
340
+ }
341
+ const targets = symbol === UNANSWERED
342
+ ? (held.byName.get(read.name) ?? []).map((id) => ({ id, guessed: true }))
343
+ : targetsOf(symbol).map((target) => ({ ...target, stepped: false }));
344
+ sink.add(file, read.key, read.from, targets, "read", "destructured");
345
+ });
346
+ },
347
+ };
348
+ /** A key a unique symbol types selects the member declared under that symbol. */
349
+ const keyed = {
350
+ emit({ file, keyed: found }, answered, { project, sink, chains, tables, cap, held }) {
351
+ const keyNames = computedKeyNames(held.symbols);
352
+ const resolvedKeys = found.flatMap((access) => {
353
+ const symbol = isIdentifier(access.key) && keyNames.has(access.key.text)
354
+ ? answered.get(access.key)
355
+ : undefined;
356
+ return typeof symbol === "object" ? [{ access, symbol }] : [];
357
+ });
358
+ for (const { access, ids } of keyedUses(project, chains, resolvedKeys, tables, cap)) {
359
+ for (const use of access.use === "both" ? ["read", "write"] : [access.use]) {
360
+ sink.add(file, access.access.argumentExpression, access.from, ids, use, "keyed");
361
+ }
362
+ }
363
+ },
364
+ };
365
+ /**
366
+ * A name a use writes resolves to what it names; a re-export something imports is used and so
367
+ * is the declaration behind it, so the use names every link of the chain its name stands at the
368
+ * head of. A shorthand is left out of the batch: its name resolves to the property the literal
369
+ * declares, which this project's inventory never holds, so its value is asked on its own.
370
+ */
371
+ const names = {
372
+ batched: ({ uses }) => uses.filter((site) => site.shorthand === undefined).map((site) => site.node),
373
+ emit({ file, uses }, answered, pass) {
374
+ const { project, sink, named, targetsOf, throughAliases } = pass;
375
+ for (const site of uses) {
376
+ const symbol = symbolFor(project, site, answered);
377
+ if (symbol === undefined) {
378
+ continue;
379
+ }
380
+ const direct = site.shorthand !== undefined
381
+ ? "shorthand"
382
+ : typeof answered.get(site.node) === "object"
383
+ ? "batch"
384
+ : "resolved-symbol";
385
+ const targets = throughAliases(symbol === UNANSWERED ? named(site.node) : targetsOf(symbol));
386
+ const value = site.use === "write" ? storedValue(site.node) : undefined;
387
+ sink.add(file, site.node, site.from, targets, site.use, direct, value);
388
+ }
389
+ },
390
+ };
391
+ /** The symbol one site resolves to, asking only the accessor the site's form names. */
392
+ function symbolFor(project, site, answered) {
393
+ if (site.shorthand !== undefined) {
394
+ return project.shorthandValueAt(project.handle(site.shorthand));
395
+ }
396
+ const batched = answered.get(site.node);
397
+ if (batched === UNANSWERED || typeof batched === "object") {
398
+ return batched;
399
+ }
400
+ return project.resolvedSymbolAt(project.handle(site.node));
401
+ }
402
+ /** Every per-file source, in the order the pass asks their nodes. */
403
+ const REFERENCE_SOURCES = [
404
+ names,
405
+ links,
406
+ evaluations,
407
+ wholes,
408
+ urls,
409
+ workers,
410
+ markup,
411
+ loads,
412
+ decorators,
413
+ parameterWrites,
414
+ patterns,
415
+ keyed,
416
+ ];
417
+ /** What the pass reads of one walked file before its batch: its computed loads and its markup bindings. */
418
+ export function prepared(sites, pass, loadable) {
419
+ const markupFile = isComponentFile(sites.file);
420
+ return {
421
+ ...sites,
422
+ loads: computedLoadsOf(sites.file, sites.loadCalls, loadable, (fileName) => pass.directories.bundlerRootOf(fileName)),
423
+ markup: markupFile,
424
+ bindings: markupFile ? bindingsOf(sites.file).map((binding) => binding.name) : [],
425
+ };
426
+ }
427
+ /**
428
+ * Runs every source over one walked file: one batch per capped run of the nodes the sources
429
+ * name, each node once, then each source's uses.
430
+ */
431
+ export function emitFile(walked, pass) {
432
+ const { project, cap } = pass;
433
+ const batching = [
434
+ ...new Set(REFERENCE_SOURCES.flatMap((source) => [...(source.batched?.(walked, pass) ?? [])])),
435
+ ];
436
+ const answered = new Map();
437
+ for (let from = 0; from < batching.length; from += cap) {
438
+ const run = batching.slice(from, from + cap);
439
+ const answers = project.symbolsAt(run.map((node) => project.handle(node)), cap);
440
+ run.forEach((node, index) => {
441
+ const symbol = answers[index];
442
+ if (symbol !== undefined) {
443
+ answered.set(node, symbol);
444
+ }
445
+ });
446
+ }
447
+ for (const source of REFERENCE_SOURCES) {
448
+ source.emit(walked, answered, pass);
449
+ }
450
+ }