@cplieger/deadset-ts 8.0.0-dev.16 → 8.0.0-dev.18

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 (161) 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 +82 -91
  4. package/dist/src/augmentations.js +24 -25
  5. package/dist/src/bindings.js +382 -0
  6. package/dist/src/calls.js +279 -43
  7. package/dist/src/commands/tools.js +5 -9
  8. package/dist/src/component-files.js +3 -2
  9. package/dist/src/conformance-record.js +1 -1
  10. package/dist/src/consumers.js +6 -9
  11. package/dist/src/contextual-uses.js +1 -17
  12. package/dist/src/contract/config.generated.js +4 -1
  13. package/dist/src/contract/contract.generated.js +2 -2
  14. package/dist/src/contract/report.generated.js +6 -2
  15. package/dist/src/dependencies.js +25 -29
  16. package/dist/src/destructuring.js +1 -19
  17. package/dist/src/element-access.js +179 -164
  18. package/dist/src/entries/build-scripts.js +2 -2
  19. package/dist/src/entries/configuration-files.js +3 -7
  20. package/dist/src/entries/conventions.js +2 -2
  21. package/dist/src/entries/html-entries.js +7 -10
  22. package/dist/src/entries/mdx-entries.js +2 -2
  23. package/dist/src/entries/static-module.js +2 -1
  24. package/dist/src/exempt.js +0 -26
  25. package/dist/src/exposure.js +400 -0
  26. package/dist/src/facts.js +4 -4
  27. package/dist/src/findings/completion.js +44 -21
  28. package/dist/src/findings/emitters.js +22 -33
  29. package/dist/src/{implementations.js → findings/implementations.js} +3 -3
  30. package/dist/src/{in-operands.js → findings/in-operands.js} +2 -2
  31. package/dist/src/findings/intra-function.js +3 -3
  32. package/dist/src/findings/reads-and-writes.js +71 -15
  33. package/dist/src/findings/unused-declarations.js +2 -22
  34. package/dist/src/findings/visibility-narrowing.js +14 -20
  35. package/dist/src/framework-lifecycle.js +41 -14
  36. package/dist/src/import-bindings.js +73 -28
  37. package/dist/src/index/sites.js +557 -0
  38. package/dist/src/indexed-access.js +523 -478
  39. package/dist/src/interface-satisfaction.js +1 -1
  40. package/dist/src/inventory.js +18 -0
  41. package/dist/src/keyof-comparisons.js +124 -103
  42. package/dist/src/{components.js → liveness/components.js} +1 -1
  43. package/dist/src/{graph.js → liveness/graph.js} +45 -20
  44. package/dist/src/liveness/matrix.js +99 -0
  45. package/dist/src/liveness/sweep.js +558 -0
  46. package/dist/src/load/expected-module.js +2 -2
  47. package/dist/src/load/specifiers.js +2 -4
  48. package/dist/src/load/synthesize.js +5 -0
  49. package/dist/src/load/workspace-resolution.js +2 -2
  50. package/dist/src/module-declarations.js +70 -85
  51. package/dist/src/overrides.js +134 -112
  52. package/dist/src/paths.js +46 -7
  53. package/dist/src/platform-calls.js +2 -2
  54. package/dist/src/platform-symbols.js +13 -19
  55. package/dist/src/query.js +46 -0
  56. package/dist/src/references/read-rule.js +1 -0
  57. package/dist/src/references/read-rules.js +48 -0
  58. package/dist/src/references/sink.js +237 -0
  59. package/dist/src/references/sources.js +450 -0
  60. package/dist/src/references.js +110 -1285
  61. package/dist/src/roots/configured-declarations.js +3 -0
  62. package/dist/src/roots/published-reach.js +4 -4
  63. package/dist/src/roots/root-set.js +1 -1
  64. package/dist/src/roots/unseen-loads.js +38 -10
  65. package/dist/src/serialization-contract.js +8 -3
  66. package/dist/src/stores.js +4 -2
  67. package/dist/src/symbol-keys.js +89 -83
  68. package/dist/src/tests/file-class.js +76 -0
  69. package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
  70. package/dist/src/{test-support.js → tests/support.js} +2 -11
  71. package/dist/src/type-parameter-reads.js +178 -139
  72. package/dist/src/unimplemented-callees.js +262 -242
  73. package/dist/src/verbs/analyze.js +3 -3
  74. package/dist/src/verbs/explain.js +75 -132
  75. package/dist/src/verbs/print-retained.js +3 -3
  76. package/jsr.json +1 -1
  77. package/package.json +2 -2
  78. package/src/alias-chain.ts +0 -7
  79. package/src/amd.ts +130 -0
  80. package/src/analysis.ts +125 -128
  81. package/src/augmentations.ts +42 -28
  82. package/src/bindings.ts +460 -0
  83. package/src/calls.ts +338 -46
  84. package/src/commands/tools.ts +5 -11
  85. package/src/component-files.ts +4 -2
  86. package/src/conformance-record.ts +1 -1
  87. package/src/consumers.ts +8 -11
  88. package/src/contextual-uses.ts +2 -22
  89. package/src/contract/config.generated.ts +4 -1
  90. package/src/contract/contract.generated.ts +2 -2
  91. package/src/contract/report.generated.ts +6 -2
  92. package/src/dependencies.ts +27 -28
  93. package/src/destructuring.ts +1 -31
  94. package/src/element-access.ts +188 -182
  95. package/src/entries/build-scripts.ts +2 -2
  96. package/src/entries/configuration-files.ts +11 -8
  97. package/src/entries/conventions.ts +2 -1
  98. package/src/entries/html-entries.ts +15 -14
  99. package/src/entries/mdx-entries.ts +2 -2
  100. package/src/entries/static-module.ts +2 -1
  101. package/src/exempt.ts +31 -46
  102. package/src/exposure.ts +492 -0
  103. package/src/facts.ts +5 -3
  104. package/src/finding.ts +1 -1
  105. package/src/findings/boundary.ts +9 -0
  106. package/src/findings/completion.ts +48 -23
  107. package/src/findings/emitter.ts +1 -1
  108. package/src/findings/emitters.ts +23 -41
  109. package/src/{implementations.ts → findings/implementations.ts} +4 -4
  110. package/src/{in-operands.ts → findings/in-operands.ts} +3 -3
  111. package/src/findings/interfaces.ts +3 -3
  112. package/src/findings/intra-function.ts +3 -3
  113. package/src/findings/reads-and-writes.ts +99 -26
  114. package/src/findings/unused-declarations.ts +4 -28
  115. package/src/findings/visibility-narrowing.ts +25 -26
  116. package/src/framework-lifecycle.ts +42 -14
  117. package/src/import-bindings.ts +98 -29
  118. package/src/index/sites.ts +781 -0
  119. package/src/indexed-access.ts +570 -527
  120. package/src/interface-satisfaction.ts +2 -2
  121. package/src/inventory.ts +19 -0
  122. package/src/keyof-comparisons.ts +131 -116
  123. package/src/{components.ts → liveness/components.ts} +3 -3
  124. package/src/{graph.ts → liveness/graph.ts} +93 -27
  125. package/src/liveness/matrix.ts +162 -0
  126. package/src/liveness/sweep.ts +855 -0
  127. package/src/load/expected-module.ts +8 -2
  128. package/src/load/specifiers.ts +8 -5
  129. package/src/load/synthesize.ts +6 -0
  130. package/src/load/workspace-resolution.ts +9 -2
  131. package/src/module-declarations.ts +74 -98
  132. package/src/overrides.ts +162 -134
  133. package/src/paths.ts +54 -8
  134. package/src/platform-calls.ts +3 -3
  135. package/src/platform-symbols.ts +11 -27
  136. package/src/query.ts +81 -0
  137. package/src/references/read-rule.ts +60 -0
  138. package/src/references/read-rules.ts +55 -0
  139. package/src/references/sink.ts +314 -0
  140. package/src/references/sources.ts +632 -0
  141. package/src/references.ts +175 -1733
  142. package/src/report.ts +1 -1
  143. package/src/roots/configured-declarations.ts +3 -0
  144. package/src/roots/published-reach.ts +9 -4
  145. package/src/roots/root-set.ts +1 -1
  146. package/src/roots/unseen-loads.ts +49 -11
  147. package/src/serialization-contract.ts +8 -3
  148. package/src/stores.ts +15 -3
  149. package/src/symbol-keys.ts +102 -102
  150. package/src/tests/file-class.ts +135 -0
  151. package/src/{outside-tests.ts → tests/outside.ts} +16 -10
  152. package/src/{test-support.ts → tests/support.ts} +9 -20
  153. package/src/type-parameter-reads.ts +187 -158
  154. package/src/unimplemented-callees.ts +297 -280
  155. package/src/verbs/analyze.ts +3 -2
  156. package/src/verbs/explain.ts +83 -158
  157. package/src/verbs/print-retained.ts +3 -3
  158. package/dist/src/matrix.js +0 -273
  159. package/dist/src/sweep.js +0 -222
  160. package/src/matrix.ts +0 -463
  161. package/src/sweep.ts +0 -361
package/src/paths.ts CHANGED
@@ -11,6 +11,58 @@ export function isAbsolutePath(path: string): boolean {
11
11
  return path.startsWith(SEPARATOR);
12
12
  }
13
13
 
14
+ /** Whether a specifier starts a path relative to the file that writes it: `./` or `../`. */
15
+ export function startsRelativePath(specifier: string): boolean {
16
+ return specifier.startsWith("./") || specifier.startsWith("../");
17
+ }
18
+
19
+ /** Whether a specifier names a path relative to the file that writes it: `.`, `..`, `./` or `../` first. */
20
+ export function isRelativeSpecifier(specifier: string): boolean {
21
+ return specifier === "." || specifier === ".." || startsRelativePath(specifier);
22
+ }
23
+
24
+ /**
25
+ * Whether a module specifier names a path rather than a package, as the compiler reads one:
26
+ * a relative specifier or an absolute path.
27
+ */
28
+ export function isPathSpecifier(specifier: string): boolean {
29
+ return isRelativeSpecifier(specifier) || isAbsolutePath(specifier);
30
+ }
31
+
32
+ /**
33
+ * Whether a string starts with `./`, `../` or `/`, the specifiers a browser reads as a URL
34
+ * rather than a bare name, so a bare `.` or `..` stays a request:
35
+ * https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-url-like-module-specifier
36
+ */
37
+ export function isExplicitPath(text: string): boolean {
38
+ return startsRelativePath(text) || isAbsolutePath(text);
39
+ }
40
+
41
+ /**
42
+ * Whether a string starts with `.` or `/`, which no npm package name does, so a reader that
43
+ * takes any other string as a package's takes it as a path:
44
+ * https://docs.npmjs.com/cli/v11/configuring-npm/package-json#name
45
+ */
46
+ export function cannotStartPackageName(text: string): boolean {
47
+ return text.startsWith(".") || isAbsolutePath(text);
48
+ }
49
+
50
+ /** A URL scheme, `file:` and `node:` among them: https://url.spec.whatwg.org/#url-scheme-string */
51
+ const URL_SCHEME = /^[a-z][a-z\d+.-]*:/iu;
52
+
53
+ /** Whether a string starts with a URL scheme. */
54
+ export function hasURLScheme(text: string): boolean {
55
+ return URL_SCHEME.test(text);
56
+ }
57
+
58
+ /**
59
+ * Whether a URL reference is a relative one that does not start with a solidus, the bare
60
+ * name included: https://url.spec.whatwg.org/#relative-url-string
61
+ */
62
+ export function isPathRelativeURL(reference: string): boolean {
63
+ return reference !== "" && !reference.startsWith(SEPARATOR) && !hasURLScheme(reference);
64
+ }
65
+
14
66
  /**
15
67
  * One path with `.` removed, `..` applied to the segment before it, and repeated
16
68
  * separators collapsed. A `..` that walks past the root of an absolute path is
@@ -97,18 +149,12 @@ export function resolvePath(against: string, path: string): string {
97
149
  return isAbsolutePath(path) ? normalizePath(path) : joinPath(against, path);
98
150
  }
99
151
 
100
- /**
101
- * A URL reference's scheme. A reference with none that does not start with a solidus is
102
- * relative, the bare name included: https://url.spec.whatwg.org/#relative-url-string
103
- */
104
- const URL_SCHEME = /^[a-z][a-z\d+.-]*:/iu;
105
-
106
152
  /**
107
153
  * The path a relative URL reference names against `dir`, its query and its fragment
108
154
  * removed, which name no part of the file; undefined where the reference is not relative.
109
155
  */
110
156
  export function relativeURLPath(dir: string, reference: string): string | undefined {
111
- if (reference === "" || reference.startsWith("/") || URL_SCHEME.test(reference)) {
157
+ if (!isPathRelativeURL(reference)) {
112
158
  return undefined;
113
159
  }
114
160
  const cut = reference.search(/[?#]/u);
@@ -123,7 +169,7 @@ export function relativeURLPath(dir: string, reference: string): string | undefi
123
169
  */
124
170
  export function queriedModulePath(specifier: string): string | undefined {
125
171
  const query = specifier.indexOf("?");
126
- if (query < 0 || !(specifier.startsWith("./") || specifier.startsWith("../"))) {
172
+ if (query < 0 || !startsRelativePath(specifier)) {
127
173
  return undefined;
128
174
  }
129
175
  const raw = specifier
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Which calls are the platform's `require` and which constructions its `URL` (roots.23,
3
- * references-ts.1), decided once over the bindings of the names a callee is written with: the
2
+ * Which calls are the platform's `require` or AMD's `define` and which constructions its `URL`
3
+ * (roots.23, references-ts.37, references-ts.1), decided once over the bindings of the names a callee is written with: the
4
4
  * checker's in a program, the file's own scopes in a module read outside every program.
5
5
  */
6
6
 
@@ -19,7 +19,7 @@ import {
19
19
  import { parenthesesRemoved, unwrapped } from "./unwrap.ts";
20
20
 
21
21
  /** A name of the platform the analysis reads calls of. */
22
- type PlatformName = "require" | "createRequire" | "URL";
22
+ type PlatformName = "require" | "createRequire" | "define" | "URL";
23
23
 
24
24
  /** What one written name is bound to, as far as its reader can tell. */
25
25
  export interface Bound {
@@ -28,19 +28,11 @@ import { isAmbient } from "./inventory.ts";
28
28
  import { callsPlatformBy, carriedNames, type BindingOf, type Bound } from "./platform-calls.ts";
29
29
  import { unwrapped } from "./unwrap.ts";
30
30
 
31
- /** Counts one request a platform decision puts to the checker. */
32
- type Asked = () => void;
33
-
34
31
  /** The symbol one symbol names through its aliases, or the symbol itself where it is none. */
35
- function dealiased<Brand>(
36
- project: ProjectView<Brand>,
37
- symbol: TSSymbol,
38
- asked: Asked,
39
- ): Answer<TSSymbol> {
32
+ function dealiased<Brand>(project: ProjectView<Brand>, symbol: TSSymbol): Answer<TSSymbol> {
40
33
  if ((symbol.flags & SymbolFlags.Alias) === 0) {
41
34
  return symbol;
42
35
  }
43
- asked();
44
36
  return project.queries.aliased(symbol);
45
37
  }
46
38
 
@@ -84,7 +76,6 @@ function writesBody(node: Node): boolean {
84
76
  function boundBy<Brand>(
85
77
  project: ProjectView<Brand>,
86
78
  symbol: Answer<TSSymbol> | undefined,
87
- asked: Asked,
88
79
  ): Bound | undefined {
89
80
  if (typeof symbol !== "object") {
90
81
  return undefined;
@@ -101,7 +92,6 @@ function boundBy<Brand>(
101
92
  if ((at.flags & SymbolFlags.Alias) === 0) {
102
93
  return { names, own, provenOwn: own.some(writesBody) };
103
94
  }
104
- asked();
105
95
  const next = project.aliasStepOf(at);
106
96
  at = typeof next === "object" ? next : undefined;
107
97
  }
@@ -109,29 +99,24 @@ function boundBy<Brand>(
109
99
  }
110
100
 
111
101
  /** Each written name's binding, as this project's checker answers it. */
112
- function checkerBinding<Brand>(project: ProjectView<Brand>, asked: Asked): BindingOf {
113
- return (written) => {
114
- asked();
115
- return boundBy(project, project.symbolsAt([project.handle(written)])[0], asked);
116
- };
102
+ function checkerBinding<Brand>(project: ProjectView<Brand>): BindingOf {
103
+ return (written) => boundBy(project, project.symbolsAt([project.handle(written)])[0]);
117
104
  }
118
105
 
119
106
  /**
120
107
  * Whether a call or construction through `callee`, the batch's answer for which is `symbol`,
121
- * is one of the platform's `require` or `URL` (roots.23, references-ts.1), as
122
- * {@link callsPlatformBy} decides it over this project's checker, each request it puts
123
- * counted by `asked`.
108
+ * is one of the platform's `require`, AMD's `define` or `URL` (roots.23, references-ts.37,
109
+ * references-ts.1), as {@link callsPlatformBy} decides it over this project's checker.
124
110
  */
125
111
  export function callsPlatform<Brand>(
126
112
  project: ProjectView<Brand>,
127
- name: "require" | "URL",
113
+ name: "require" | "define" | "URL",
128
114
  callee: Identifier,
129
115
  symbol: Answer<TSSymbol> | undefined,
130
- asked: Asked,
131
116
  ): boolean {
132
- const others = checkerBinding(project, asked);
117
+ const others = checkerBinding(project);
133
118
  return callsPlatformBy(name, callee, (written) =>
134
- written === callee ? boundBy(project, symbol, asked) : others(written),
119
+ written === callee ? boundBy(project, symbol) : others(written),
135
120
  );
136
121
  }
137
122
 
@@ -177,15 +162,14 @@ function inThreadsModule(node: Node): boolean {
177
162
  * (references-ts.2): its symbol resolves to a declaration of `worker_threads`, or one of its
178
163
  * own declarations binds the module's `Worker`, or `holder`, the namespace it is read
179
164
  * through, binds the module, each binding read as {@link boundExports} reads one, which
180
- * decides where the module has no declaration. Each request it puts is counted by `asked`.
165
+ * decides where the module has no declaration.
181
166
  */
182
167
  export function startsThread<Brand>(
183
168
  project: ProjectView<Brand>,
184
169
  symbol: Answer<TSSymbol> | undefined,
185
170
  holder: Answer<TSSymbol> | undefined,
186
- asked: Asked,
187
171
  ): boolean {
188
- const bindingOf = checkerBinding(project, asked);
172
+ const bindingOf = checkerBinding(project);
189
173
  const declared = (one: Answer<TSSymbol> | undefined, member: string): boolean =>
190
174
  typeof one === "object" &&
191
175
  ownDeclarations(project, one).some((node) =>
@@ -194,7 +178,7 @@ export function startsThread<Brand>(
194
178
  if (declared(symbol, "Worker") || declared(holder, NAMESPACE)) {
195
179
  return true;
196
180
  }
197
- const named = typeof symbol === "object" ? dealiased(project, symbol, asked) : undefined;
181
+ const named = typeof symbol === "object" ? dealiased(project, symbol) : undefined;
198
182
  return (
199
183
  typeof named === "object" &&
200
184
  named.declarations.some((handle) => {
package/src/query.ts CHANGED
@@ -207,8 +207,22 @@ export interface Queries {
207
207
  constraintOf(type: Type): Answer<Type | undefined>;
208
208
  /** The object and the index of an indexed-access type; none for another type. */
209
209
  indexedAccessOf(type: Type): Answer<{ readonly object: Type; readonly index: Type } | undefined>;
210
+ /**
211
+ * The types one type is spelled from besides its constituents, type arguments and members:
212
+ * a type parameter's constraint and default, a conditional's check, extends, true
213
+ * and false types, a mapped type's constraint, name and template, an indexed access's
214
+ * object and index, the operand of `keyof` or of a string mapping, a template literal's
215
+ * spans and a substitution's base and constraint. None for another type.
216
+ */
217
+ partsOf(type: Type): Answer<readonly Type[]>;
218
+ /** The type parameters of a signature, its `this` parameter's type and its predicate's type. */
219
+ signaturePartsOf(signature: Signature): Answer<readonly Type[]>;
210
220
  /** The symbol a type is declared by. */
211
221
  symbolOfType(type: Type): Answer<TSSymbol | undefined>;
222
+ /** The type alias a type was instantiated from, where it was. */
223
+ aliasSymbolOf(type: Type): Answer<TSSymbol | undefined>;
224
+ /** The type arguments the alias a type was instantiated from was given. */
225
+ aliasArgumentsOf(type: Type): Answer<readonly Type[]>;
212
226
  signaturesOf(type: Type, kind: SignatureKind): Answer<readonly Signature[]>;
213
227
  resolvedSignature(node: Node): Answer<Signature | undefined>;
214
228
  /** The signature each call-like node resolves to. */
@@ -223,6 +237,37 @@ export interface Queries {
223
237
  typeToString(type: Type): Answer<string>;
224
238
  }
225
239
 
240
+ /** How to read the types one type is spelled from, as {@link Queries.partsOf} names them. */
241
+ function partQuestion(type: Type): (() => readonly (Type | undefined)[]) | undefined {
242
+ if (type.isTypeParameter()) {
243
+ return () => [type.getConstraint(), type.getDefault()];
244
+ }
245
+ if (type.isConditionalType()) {
246
+ return () => [
247
+ type.getCheckType(),
248
+ type.getExtendsType(),
249
+ type.getTrueType(),
250
+ type.getFalseType(),
251
+ ];
252
+ }
253
+ if (type.isMappedType()) {
254
+ return () => [type.getConstraintType(), type.getNameType(), type.getTemplateType()];
255
+ }
256
+ if (type.isIndexedAccessType()) {
257
+ return () => [type.getObjectType(), type.getIndexType()];
258
+ }
259
+ if (type.isIndexType() || type.isStringMappingType()) {
260
+ return () => [type.getTarget()];
261
+ }
262
+ if (type.isTemplateLiteralType()) {
263
+ return () => type.getTypes();
264
+ }
265
+ if (type.isSubstitutionType()) {
266
+ return () => [type.getBaseType(), type.getConstraint()];
267
+ }
268
+ return undefined;
269
+ }
270
+
226
271
  /**
227
272
  * The guarded questions over one project's checker. `configFile` names the project
228
273
  * in the log, `batch` sends many questions in one round trip, `log` is the run's,
@@ -528,12 +573,48 @@ export function queriesOf(
528
573
  () => ({ object: type.getObjectType(), index: type.getIndexType() }),
529
574
  )
530
575
  : undefined,
576
+ partsOf: (type) => {
577
+ const parts = partQuestion(type);
578
+ return parts === undefined
579
+ ? []
580
+ : one(
581
+ "getParts",
582
+ () => typeLocation(type),
583
+ () => parts().filter((part) => part !== undefined),
584
+ );
585
+ },
586
+ signaturePartsOf: (signature) =>
587
+ one(
588
+ "getSignatureParts",
589
+ () => `signature ${String(signature.id)}`,
590
+ () => {
591
+ const self =
592
+ signature.thisParameter === undefined ? undefined : signature.getThisParameter();
593
+ return [
594
+ ...((signature.typeParameters ?? []).length === 0 ? [] : signature.getTypeParameters()),
595
+ self === undefined ? undefined : checker.getTypeOfSymbol(self),
596
+ checker.getTypePredicateOfSignature(signature)?.type,
597
+ ].filter((part) => part !== undefined);
598
+ },
599
+ ),
531
600
  symbolOfType: (type) =>
532
601
  one(
533
602
  "getSymbol",
534
603
  () => typeLocation(type),
535
604
  () => type.getSymbol(),
536
605
  ),
606
+ aliasSymbolOf: (type) =>
607
+ one(
608
+ "getAliasSymbol",
609
+ () => typeLocation(type),
610
+ () => type.getAliasSymbol(),
611
+ ),
612
+ aliasArgumentsOf: (type) =>
613
+ one(
614
+ "getAliasTypeArguments",
615
+ () => typeLocation(type),
616
+ () => type.getAliasTypeArguments(),
617
+ ),
537
618
  signaturesOf: (type, kind) =>
538
619
  one(
539
620
  "getSignaturesOfType",
@@ -0,0 +1,60 @@
1
+ import type { Node, SourceFile } from "@typescript/native/ast";
2
+ import type { Type } from "@typescript/native/sync";
3
+ import type { AliasChains } from "../alias-chain.ts";
4
+ import type { Inventory } from "../inventory.ts";
5
+ import type { Position } from "../position.ts";
6
+ import type { Resolution } from "../references.ts";
7
+ import type { ProjectView } from "../session.ts";
8
+
9
+ /** Where the walk offered a read rule one node: the file, and the declaration enclosing the node. */
10
+ interface ReadSite {
11
+ readonly file: SourceFile;
12
+ readonly from: string;
13
+ }
14
+
15
+ /** What a read rule reads its answers through, after the walk of every file of the side. */
16
+ export interface ReadContext<Brand> {
17
+ readonly project: ProjectView<Brand>;
18
+ readonly held: Inventory;
19
+ readonly chains: AliasChains;
20
+ }
21
+
22
+ /**
23
+ * One read a rule makes: a use of the declaration `to` by `from` at a node of a walked file,
24
+ * or, where a question the read needed went unanswered, a hold. A hold names what the answer
25
+ * could have made live (program.33): the declarations `ids`, each declaration bearing one of
26
+ * `names`, each member of one of `types`, or with `members` every member the inventory holds;
27
+ * the declaration making the read is held as well. A named read sits at a node of `file`, or
28
+ * at a declaration's own position in it.
29
+ */
30
+ export type Read =
31
+ | {
32
+ readonly kind: "named";
33
+ readonly from: string;
34
+ readonly to: string;
35
+ readonly file: SourceFile;
36
+ readonly at: Node | Position;
37
+ readonly use: "read" | "write";
38
+ readonly via: Resolution;
39
+ /** A read a rule counts as production code's whoever writes it. */
40
+ readonly production?: true;
41
+ }
42
+ | {
43
+ readonly kind: "held";
44
+ readonly from: string;
45
+ readonly ids?: readonly string[];
46
+ readonly names?: readonly string[];
47
+ readonly types?: readonly Type[];
48
+ readonly members?: true;
49
+ };
50
+
51
+ /** One pass of one read rule over the files of one side: it collects while the walk offers nodes, then reads. */
52
+ interface ReadRuleRun {
53
+ visit(node: Node, site: ReadSite): void;
54
+ reads<Brand>(context: ReadContext<Brand>): readonly Read[];
55
+ }
56
+
57
+ /** One rule of the references pages that reads declarations no name node names. */
58
+ export interface ReadRule {
59
+ start(): ReadRuleRun;
60
+ }
@@ -0,0 +1,55 @@
1
+ import { elementAccess } from "../element-access.ts";
2
+ import { indexedAccess } from "../indexed-access.ts";
3
+ import { keyofComparisons } from "../keyof-comparisons.ts";
4
+ import { moduleDeclarations } from "../module-declarations.ts";
5
+ import { overrides } from "../overrides.ts";
6
+ import { isAnswered } from "../query.ts";
7
+ import { iteration } from "../symbol-keys.ts";
8
+ import { typeParameterReads } from "../type-parameter-reads.ts";
9
+ import { unimplementedCallees } from "../unimplemented-callees.ts";
10
+ import type { Read, ReadContext, ReadRule } from "./read-rule.ts";
11
+
12
+ /** The member kinds a hold of every member names. */
13
+ const MEMBER_KINDS: ReadonlySet<string> = new Set([
14
+ "method",
15
+ "class-member",
16
+ "interface-method",
17
+ "type-member",
18
+ "enum-member",
19
+ ]);
20
+
21
+ /**
22
+ * Every read rule, each run over every side's walked files with the reference sources:
23
+ * a consumer's read of a target member is a reference as the target's own is.
24
+ */
25
+ export const READ_RULES: readonly ReadRule[] = [
26
+ overrides,
27
+ indexedAccess,
28
+ elementAccess,
29
+ keyofComparisons,
30
+ iteration,
31
+ typeParameterReads,
32
+ unimplementedCallees,
33
+ moduleDeclarations,
34
+ ];
35
+
36
+ /** The declarations one hold names, with the declaration whose read it is. */
37
+ export function heldBy<Brand>(
38
+ read: Extract<Read, { kind: "held" }>,
39
+ { project, held, chains }: ReadContext<Brand>,
40
+ ): readonly string[] {
41
+ const ids = [...(read.from === "" ? [] : [read.from]), ...(read.ids ?? [])];
42
+ for (const name of read.names ?? []) {
43
+ ids.push(...(held.byName.get(name) ?? []));
44
+ }
45
+ for (const type of read.types ?? []) {
46
+ const properties = project.queries.propertiesOf(type);
47
+ for (const property of isAnswered(properties) ? properties : []) {
48
+ ids.push(...chains.declarationsOf(property));
49
+ }
50
+ }
51
+ if (read.members === true) {
52
+ ids.push(...held.symbols.filter((one) => MEMBER_KINDS.has(one.kind)).map((one) => one.id));
53
+ }
54
+ return ids;
55
+ }