@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
@@ -5,11 +5,9 @@
5
5
  * call's value is what the read reads, whatever member of the constraint the name resolves
6
6
  * to. A class's members a constraint requires are interface satisfaction's.
7
7
  */
8
- import { isBinaryExpression, isCallExpression, isIdentifier, isNewExpression, isPropertyAccessExpression, isTypeParameterDeclaration, SyntaxKind, } from "@typescript/native/ast";
8
+ import { isBinaryExpression, isCallExpression, isIdentifier, isNewExpression, isPropertyAccessExpression, isSourceFile, isTypeParameterDeclaration, SyntaxKind, } from "@typescript/native/ast";
9
9
  import { SymbolFlags } from "@typescript/native/sync";
10
- import { nodeKey } from "./inventory.js";
11
- import { renderPosition } from "./position.js";
12
- import { isAnswered } from "./query.js";
10
+ import { isAnswered, UNANSWERED } from "./query.js";
13
11
  /** How deep a parameter's type is matched against the type a call passes: `readonly T[]` is one level. */
14
12
  const MATCH_DEPTH = 3;
15
13
  /** The name a call reaches one generic by: its own, or that of what holds it. */
@@ -26,147 +24,188 @@ function assignedTo(access) {
26
24
  parent.operatorToken.kind === SyntaxKind.EqualsToken &&
27
25
  parent.left === access);
28
26
  }
29
- /**
30
- * The references the reads through type-parameter-typed values of one project's own files
31
- * make to the members of the types its calls pass, each made by the declaration holding
32
- * the read.
33
- */
34
- export function typeParameterReads(project, held, chains, root, testFiles) {
35
- const queries = project.queries;
36
- const reads = [];
37
- const calls = [];
38
- for (const file of project.ownSourceFiles()) {
39
- const fileId = held.declarations.get(nodeKey(file, file));
40
- if (fileId === undefined) {
41
- continue;
27
+ /** Whether one node is written inside a declaration that declares type parameters, itself included. */
28
+ function inGeneric(node) {
29
+ for (let at = node; !isSourceFile(at); at = at.parent) {
30
+ if (at.typeParameters !== undefined) {
31
+ return true;
42
32
  }
43
- const visit = (node, from, generic) => {
44
- const holder = held.declarations.get(nodeKey(file, node)) ?? from;
45
- const inside = generic ||
46
- node.typeParameters !== undefined;
47
- if (inside &&
48
- isPropertyAccessExpression(node) &&
49
- isIdentifier(node.name) &&
50
- !assignedTo(node)) {
51
- reads.push({ file, from: holder, access: node });
52
- }
53
- if (isCallExpression(node) || isNewExpression(node)) {
54
- calls.push(node);
55
- }
56
- node.forEachChild((child) => {
57
- visit(child, holder, inside);
58
- });
59
- };
60
- file.forEachChild((child) => {
61
- visit(child, fileId, false);
62
- });
63
33
  }
64
- if (reads.length === 0) {
65
- return [];
66
- }
67
- // The reads whose receiver the checker types as a type parameter, by the generic declaring it.
68
- const receivers = queries.typesAt(reads.map((read) => read.access.expression));
69
- const byGeneric = new Map();
70
- reads.forEach((read, at) => {
71
- const type = receivers[at];
72
- if (type === undefined || !isAnswered(type) || !type.isTypeParameter()) {
73
- return;
74
- }
75
- const symbol = queries.symbolOfType(type);
76
- const declaration = symbol === undefined || !isAnswered(symbol)
77
- ? undefined
78
- : symbol.declarations
79
- .map((handle) => project.declarationAt(handle)?.node)
80
- .find((node) => node !== undefined && isTypeParameterDeclaration(node));
81
- const generic = declaration?.parent;
82
- if (generic !== undefined) {
83
- byGeneric.set(generic, [...(byGeneric.get(generic) ?? []), { read, parameter: type }]);
84
- }
85
- });
86
- if (byGeneric.size === 0) {
87
- return [];
88
- }
89
- /** The types `instantiated` holds where `declared` holds `parameter`, matched part for part. */
90
- const passedFor = (parameter, declared, instantiated, depth) => {
91
- if (declared.id === parameter.id) {
92
- return [instantiated];
93
- }
94
- if (depth >= MATCH_DEPTH) {
95
- return [];
96
- }
97
- const a = queries.typeArguments(declared);
98
- const b = queries.typeArguments(instantiated);
99
- if (!isAnswered(a) || !isAnswered(b) || a.length !== b.length) {
100
- return [];
101
- }
102
- return a.flatMap((one, at) => {
103
- const other = b[at];
104
- return other === undefined ? [] : passedFor(parameter, one, other, depth + 1);
105
- });
106
- };
107
- // Only a call spelling a generic's name is resolved: one request each.
108
- const spelled = new Set([...byGeneric.keys()].flatMap((generic) => nameOf(generic) ?? []));
109
- const found = new Map();
110
- for (const call of calls) {
111
- const callee = call.expression;
112
- const written = isIdentifier(callee)
113
- ? callee.text
114
- : isPropertyAccessExpression(callee) && isIdentifier(callee.name)
115
- ? callee.name.text
116
- : undefined;
117
- if (written === undefined || !spelled.has(written)) {
118
- continue;
119
- }
120
- const resolved = queries.resolvedSignature(call);
121
- if (resolved === undefined || !isAnswered(resolved) || resolved.declaration === undefined) {
122
- continue;
123
- }
124
- const generic = project.declarationAt(resolved.declaration)?.node;
125
- const pending = generic === undefined ? undefined : byGeneric.get(generic);
126
- const declared = pending === undefined ? undefined : queries.genericOf(resolved);
127
- if (pending === undefined || declared === undefined || !isAnswered(declared)) {
128
- continue;
129
- }
130
- const count = (generic?.parameters ?? []).length;
131
- for (const { read, parameter } of pending) {
132
- const passed = [];
133
- for (let at = 0; at < count; at += 1) {
134
- const own = queries.parameterType(declared, at);
135
- const given = queries.typeAtPosition(resolved, at);
136
- if (own !== undefined && isAnswered(own) && isAnswered(given)) {
137
- passed.push(...passedFor(parameter, own, given, 0));
34
+ return false;
35
+ }
36
+ /**
37
+ * The reads the reads through type-parameter-typed values of a side's files make of the
38
+ * members of the types its calls pass, each made by the declaration holding the read. A
39
+ * question the checker leaves unanswered holds every member the read's name spells.
40
+ */
41
+ export const typeParameterReads = {
42
+ start() {
43
+ const reads = [];
44
+ const calls = [];
45
+ return {
46
+ visit(node, { file, from }) {
47
+ if (isPropertyAccessExpression(node) &&
48
+ isIdentifier(node.name) &&
49
+ !assignedTo(node) &&
50
+ inGeneric(node)) {
51
+ reads.push({ file, from, access: node });
138
52
  }
139
- }
140
- const name = read.access.name.text;
141
- const position = renderPosition(read.file, root, read.access.name.getStart());
142
- for (const type of passed) {
143
- const parts = type.isUnionType() ? queries.constituents(type) : [type];
144
- for (const part of isAnswered(parts) ? parts : []) {
145
- const owner = queries.symbolOfType(part);
146
- if (!isAnswered(owner) ||
147
- owner === undefined ||
148
- (owner.flags & SymbolFlags.Class) !== 0) {
53
+ if (isCallExpression(node) || isNewExpression(node)) {
54
+ calls.push(node);
55
+ }
56
+ },
57
+ reads({ project, chains }) {
58
+ const out = [];
59
+ if (reads.length === 0) {
60
+ return out;
61
+ }
62
+ const queries = project.queries;
63
+ const hold = (read) => {
64
+ out.push({ kind: "held", from: read.from, names: [read.access.name.text] });
65
+ };
66
+ // The reads whose receiver the checker types as a type parameter, by the generic declaring it.
67
+ const receivers = queries.typesAt(reads.map((read) => read.access.expression));
68
+ const byGeneric = new Map();
69
+ reads.forEach((read, at) => {
70
+ const type = receivers[at];
71
+ if (type === UNANSWERED) {
72
+ hold(read);
73
+ return;
74
+ }
75
+ if (type?.isTypeParameter() !== true) {
76
+ return;
77
+ }
78
+ const symbol = queries.symbolOfType(type);
79
+ if (symbol === UNANSWERED) {
80
+ hold(read);
81
+ return;
82
+ }
83
+ const declaration = symbol === undefined
84
+ ? undefined
85
+ : symbol.declarations
86
+ .map((handle) => project.declarationAt(handle)?.node)
87
+ .find((node) => node !== undefined && isTypeParameterDeclaration(node));
88
+ const generic = declaration?.parent;
89
+ if (generic !== undefined) {
90
+ byGeneric.set(generic, [...(byGeneric.get(generic) ?? []), { read, parameter: type }]);
91
+ }
92
+ });
93
+ if (byGeneric.size === 0) {
94
+ return out;
95
+ }
96
+ /** The types `instantiated` holds where `declared` holds `parameter`, matched part for part. */
97
+ const passedFor = (read, parameter, declared, instantiated, depth) => {
98
+ if (declared.id === parameter.id) {
99
+ return [instantiated];
100
+ }
101
+ if (depth >= MATCH_DEPTH) {
102
+ return [];
103
+ }
104
+ const a = queries.typeArguments(declared);
105
+ const b = queries.typeArguments(instantiated);
106
+ if (!isAnswered(a) || !isAnswered(b)) {
107
+ hold(read);
108
+ return [];
109
+ }
110
+ if (a.length !== b.length) {
111
+ return [];
112
+ }
113
+ return a.flatMap((one, at) => {
114
+ const other = b[at];
115
+ return other === undefined ? [] : passedFor(read, parameter, one, other, depth + 1);
116
+ });
117
+ };
118
+ // Only a call spelling a generic's name is resolved: one request each.
119
+ const bySpelling = new Map();
120
+ for (const [generic, pending] of byGeneric) {
121
+ const name = nameOf(generic);
122
+ if (name !== undefined) {
123
+ bySpelling.set(name, [
124
+ ...(bySpelling.get(name) ?? []),
125
+ ...pending.map((one) => one.read),
126
+ ]);
127
+ }
128
+ }
129
+ const found = new Map();
130
+ for (const call of calls) {
131
+ const callee = call.expression;
132
+ const written = isIdentifier(callee)
133
+ ? callee.text
134
+ : isPropertyAccessExpression(callee) && isIdentifier(callee.name)
135
+ ? callee.name.text
136
+ : undefined;
137
+ const spelledBy = written === undefined ? undefined : bySpelling.get(written);
138
+ if (spelledBy === undefined) {
139
+ continue;
140
+ }
141
+ const resolved = queries.resolvedSignature(call);
142
+ if (resolved === UNANSWERED) {
143
+ spelledBy.forEach(hold);
149
144
  continue;
150
145
  }
151
- const properties = queries.propertiesOf(part);
152
- for (const property of isAnswered(properties) ? properties : []) {
153
- if (property.name !== name) {
154
- continue;
146
+ if (resolved?.declaration === undefined) {
147
+ continue;
148
+ }
149
+ const generic = project.declarationAt(resolved.declaration)?.node;
150
+ const pending = generic === undefined ? undefined : byGeneric.get(generic);
151
+ const declared = pending === undefined ? undefined : queries.genericOf(resolved);
152
+ if (declared === UNANSWERED) {
153
+ pending?.forEach((one) => {
154
+ hold(one.read);
155
+ });
156
+ continue;
157
+ }
158
+ if (pending === undefined || declared === undefined) {
159
+ continue;
160
+ }
161
+ const count = (generic?.parameters ?? []).length;
162
+ for (const { read, parameter } of pending) {
163
+ const passed = [];
164
+ for (let at = 0; at < count; at += 1) {
165
+ const own = queries.parameterType(declared, at);
166
+ const given = queries.typeAtPosition(resolved, at);
167
+ if (own === UNANSWERED || given === UNANSWERED) {
168
+ hold(read);
169
+ }
170
+ else if (own !== undefined) {
171
+ passed.push(...passedFor(read, parameter, own, given, 0));
172
+ }
155
173
  }
156
- for (const to of chains.declarationsOf(property)) {
157
- found.set(`${read.from}\u0000${to}\u0000${String(read.access.name.pos)}`, {
158
- from: read.from,
159
- to,
160
- position,
161
- use: "read",
162
- resolution: "batch",
163
- test: testFiles.has(position.path),
164
- });
174
+ const name = read.access.name.text;
175
+ for (const type of passed) {
176
+ const parts = type.isUnionType() ? queries.constituents(type) : [type];
177
+ for (const part of isAnswered(parts) ? parts : [type]) {
178
+ const owner = queries.symbolOfType(part);
179
+ const properties = queries.propertiesOf(part);
180
+ if (owner === UNANSWERED || properties === UNANSWERED) {
181
+ hold(read);
182
+ continue;
183
+ }
184
+ if (owner === undefined || (owner.flags & SymbolFlags.Class) !== 0) {
185
+ continue;
186
+ }
187
+ for (const property of properties) {
188
+ if (property.name !== name) {
189
+ continue;
190
+ }
191
+ for (const to of chains.declarationsOf(property)) {
192
+ found.set(`${read.from}\u0000${to}\u0000${String(read.access.name.pos)}`, {
193
+ kind: "named",
194
+ from: read.from,
195
+ to,
196
+ file: read.file,
197
+ at: read.access.name,
198
+ use: "read",
199
+ via: "batch",
200
+ });
201
+ }
202
+ }
203
+ }
165
204
  }
166
205
  }
167
206
  }
168
- }
169
- }
170
- }
171
- return [...found.values()];
172
- }
207
+ return [...out, ...found.values()];
208
+ },
209
+ };
210
+ },
211
+ };