@suss/adapter-typescript 0.37.1 → 0.38.0
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.
- package/dist/index.cjs +1350 -1084
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +572 -306
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -43,6 +43,396 @@ import {
|
|
|
43
43
|
} from "ts-morph";
|
|
44
44
|
import { firesOn, runsBefore, splitAtHandOffs } from "@suss/extractor";
|
|
45
45
|
|
|
46
|
+
// src/depTracking.ts
|
|
47
|
+
function createDependencySink() {
|
|
48
|
+
return { files: /* @__PURE__ */ new Set(), mountPrefixes: /* @__PURE__ */ new Map(), claims: [] };
|
|
49
|
+
}
|
|
50
|
+
var activeSink = null;
|
|
51
|
+
function withDependencySink(sink, fn) {
|
|
52
|
+
const previous = activeSink;
|
|
53
|
+
activeSink = sink;
|
|
54
|
+
try {
|
|
55
|
+
return fn();
|
|
56
|
+
} finally {
|
|
57
|
+
activeSink = previous;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function withFilesNoted(fn) {
|
|
61
|
+
const outer = activeSink;
|
|
62
|
+
const noted = createDependencySink();
|
|
63
|
+
activeSink = noted;
|
|
64
|
+
let value;
|
|
65
|
+
try {
|
|
66
|
+
value = fn();
|
|
67
|
+
} finally {
|
|
68
|
+
activeSink = outer;
|
|
69
|
+
}
|
|
70
|
+
if (outer !== null) {
|
|
71
|
+
for (const filePath of noted.files) {
|
|
72
|
+
outer.files.add(filePath);
|
|
73
|
+
}
|
|
74
|
+
for (const [childId, prefix] of noted.mountPrefixes) {
|
|
75
|
+
outer.mountPrefixes.set(childId, prefix);
|
|
76
|
+
}
|
|
77
|
+
outer.claims.push(...noted.claims);
|
|
78
|
+
}
|
|
79
|
+
return { value, files: [...noted.files] };
|
|
80
|
+
}
|
|
81
|
+
function recordFileDependency(filePath) {
|
|
82
|
+
activeSink?.files.add(filePath);
|
|
83
|
+
}
|
|
84
|
+
function recordMountPrefix(childId, prefix) {
|
|
85
|
+
activeSink?.mountPrefixes.set(childId, prefix);
|
|
86
|
+
}
|
|
87
|
+
function recordUnitClaim(key, pack) {
|
|
88
|
+
activeSink?.claims.push({ key, pack });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/shapes/typeText.ts
|
|
92
|
+
import { ts } from "ts-morph";
|
|
93
|
+
var PRINTER = ts.createPrinter({
|
|
94
|
+
removeComments: true,
|
|
95
|
+
newLine: ts.NewLineKind.LineFeed
|
|
96
|
+
});
|
|
97
|
+
var NO_FILE = ts.createSourceFile("", "", ts.ScriptTarget.Latest);
|
|
98
|
+
function defaultFlags(enclosing) {
|
|
99
|
+
const flags = ts.TypeFormatFlags.UseTypeOfFunction | ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType | ts.TypeFormatFlags.WriteTypeArgumentsOfSignature;
|
|
100
|
+
if (enclosing?.getKind() === ts.SyntaxKind.TypeAliasDeclaration) {
|
|
101
|
+
return flags | ts.TypeFormatFlags.InTypeAlias;
|
|
102
|
+
}
|
|
103
|
+
return flags;
|
|
104
|
+
}
|
|
105
|
+
function stableTypeText(type, reader, enclosing, flags) {
|
|
106
|
+
const format = flags ?? defaultFlags(enclosing);
|
|
107
|
+
const place = enclosing?.compilerNode ?? NOWHERE;
|
|
108
|
+
const atPlace = printedAt.get(place) ?? /* @__PURE__ */ new WeakMap();
|
|
109
|
+
printedAt.set(place, atPlace);
|
|
110
|
+
const byFormat = atPlace.get(type.compilerType) ?? /* @__PURE__ */ new Map();
|
|
111
|
+
atPlace.set(type.compilerType, byFormat);
|
|
112
|
+
const kept = byFormat.get(format);
|
|
113
|
+
if (kept !== void 0) {
|
|
114
|
+
return kept;
|
|
115
|
+
}
|
|
116
|
+
const text3 = printedType(type, reader, enclosing, format);
|
|
117
|
+
byFormat.set(format, text3);
|
|
118
|
+
return text3;
|
|
119
|
+
}
|
|
120
|
+
var NOWHERE = {};
|
|
121
|
+
var printedAt = /* @__PURE__ */ new WeakMap();
|
|
122
|
+
function printedType(type, reader, enclosing, format) {
|
|
123
|
+
const checker = reader.getProject().getTypeChecker().compilerObject;
|
|
124
|
+
const enclosingNode = enclosing?.compilerNode;
|
|
125
|
+
const typeNode = checker.typeToTypeNode(
|
|
126
|
+
type.compilerType,
|
|
127
|
+
enclosingNode,
|
|
128
|
+
format & ts.TypeFormatFlags.NodeBuilderFlagsMask | ts.NodeBuilderFlags.IgnoreErrors
|
|
129
|
+
);
|
|
130
|
+
if (typeNode === void 0) {
|
|
131
|
+
return withoutImportQualifiers(
|
|
132
|
+
checker.typeToString(type.compilerType, enclosingNode, format)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const file = enclosing?.getSourceFile().compilerNode ?? NO_FILE;
|
|
136
|
+
const ordered = containsUnion(typeNode) ? withUnionMembersOrdered(typeNode, file) : typeNode;
|
|
137
|
+
return withoutImportQualifiers(printed(ordered, file));
|
|
138
|
+
}
|
|
139
|
+
var IMPORT_QUALIFIER = /import\("[^"]*"\)\./g;
|
|
140
|
+
var withoutImportQualifiers = (text3) => text3.replace(IMPORT_QUALIFIER, "");
|
|
141
|
+
function printed(node, file) {
|
|
142
|
+
return PRINTER.printNode(ts.EmitHint.Unspecified, node, file).replace(
|
|
143
|
+
/\n/g,
|
|
144
|
+
""
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
function containsUnion(node) {
|
|
148
|
+
if (ts.isUnionTypeNode(node)) {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
return ts.forEachChild(node, (child) => containsUnion(child) || void 0) === true;
|
|
152
|
+
}
|
|
153
|
+
function withUnionMembersOrdered(root, file) {
|
|
154
|
+
const result = ts.transform(root, [
|
|
155
|
+
(context) => {
|
|
156
|
+
const visit = (node) => {
|
|
157
|
+
const visited = ts.visitEachChild(node, visit, context);
|
|
158
|
+
if (!ts.isUnionTypeNode(visited)) {
|
|
159
|
+
return visited;
|
|
160
|
+
}
|
|
161
|
+
return context.factory.updateUnionTypeNode(
|
|
162
|
+
visited,
|
|
163
|
+
context.factory.createNodeArray(inStableOrder(visited.types, file))
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
return (node) => visit(node);
|
|
167
|
+
}
|
|
168
|
+
]);
|
|
169
|
+
const [ordered] = result.transformed;
|
|
170
|
+
result.dispose();
|
|
171
|
+
return ordered;
|
|
172
|
+
}
|
|
173
|
+
function inStableOrder(members, file) {
|
|
174
|
+
return members.map((member) => ({
|
|
175
|
+
member,
|
|
176
|
+
text: withoutImportQualifiers(printed(member, file))
|
|
177
|
+
})).sort((a, b) => compareMembers(a.text, b.text)).map(({ member }) => member);
|
|
178
|
+
}
|
|
179
|
+
function compareMembers(a, b) {
|
|
180
|
+
return nullishRank(a) - nullishRank(b) || compareText(a, b);
|
|
181
|
+
}
|
|
182
|
+
function nullishRank(text3) {
|
|
183
|
+
if (text3 === "null") {
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
if (text3 === "undefined") {
|
|
187
|
+
return 2;
|
|
188
|
+
}
|
|
189
|
+
return 0;
|
|
190
|
+
}
|
|
191
|
+
function compareText(a, b) {
|
|
192
|
+
if (a < b) {
|
|
193
|
+
return -1;
|
|
194
|
+
}
|
|
195
|
+
if (a > b) {
|
|
196
|
+
return 1;
|
|
197
|
+
}
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
function stablePropertyName(symbol, reader) {
|
|
201
|
+
const name = symbol.getName();
|
|
202
|
+
if (!name.startsWith("__@")) {
|
|
203
|
+
return name;
|
|
204
|
+
}
|
|
205
|
+
const checker = reader.getProject().getTypeChecker().compilerObject;
|
|
206
|
+
return checker.symbolToString(symbol.compilerSymbol);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/shapes/definitions.ts
|
|
210
|
+
var current = null;
|
|
211
|
+
var definitionsInProgress = () => current;
|
|
212
|
+
function createDefinitionTable() {
|
|
213
|
+
const shapes = /* @__PURE__ */ new Map();
|
|
214
|
+
const deferred = [];
|
|
215
|
+
let settling = false;
|
|
216
|
+
return {
|
|
217
|
+
has: (key) => shapes.has(key),
|
|
218
|
+
reserve: (key) => {
|
|
219
|
+
shapes.set(key, null);
|
|
220
|
+
},
|
|
221
|
+
define: (key, shape) => {
|
|
222
|
+
shapes.set(key, shape);
|
|
223
|
+
},
|
|
224
|
+
defer: (key, expand) => {
|
|
225
|
+
deferred.push({ key, expand });
|
|
226
|
+
},
|
|
227
|
+
settle: () => {
|
|
228
|
+
if (settling) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
settling = true;
|
|
232
|
+
try {
|
|
233
|
+
for (let next = deferred.shift(); next; next = deferred.shift()) {
|
|
234
|
+
shapes.set(next.key, next.expand());
|
|
235
|
+
}
|
|
236
|
+
} finally {
|
|
237
|
+
settling = false;
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
// Sorted because the walk meets types in the checker's union order,
|
|
241
|
+
// which changes between runs.
|
|
242
|
+
collected: () => {
|
|
243
|
+
const out = {};
|
|
244
|
+
let any = false;
|
|
245
|
+
const keys = [...shapes.keys()].sort(compareText);
|
|
246
|
+
for (const key of keys) {
|
|
247
|
+
const shape = shapes.get(key) ?? null;
|
|
248
|
+
if (shape !== null) {
|
|
249
|
+
out[key] = shape;
|
|
250
|
+
any = true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return any ? out : null;
|
|
254
|
+
},
|
|
255
|
+
shapeOf: (key) => shapes.get(key)
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function withDefinitionsNoted(read2) {
|
|
259
|
+
const table = current;
|
|
260
|
+
if (table === null) {
|
|
261
|
+
return { value: read2(), noted: [] };
|
|
262
|
+
}
|
|
263
|
+
const keys = /* @__PURE__ */ new Set();
|
|
264
|
+
current = {
|
|
265
|
+
has: (key) => {
|
|
266
|
+
keys.add(key);
|
|
267
|
+
return table.has(key);
|
|
268
|
+
},
|
|
269
|
+
reserve: (key) => {
|
|
270
|
+
keys.add(key);
|
|
271
|
+
table.reserve(key);
|
|
272
|
+
},
|
|
273
|
+
define: (key, shape) => {
|
|
274
|
+
keys.add(key);
|
|
275
|
+
table.define(key, shape);
|
|
276
|
+
},
|
|
277
|
+
defer: (key, expand) => {
|
|
278
|
+
keys.add(key);
|
|
279
|
+
table.defer(key, expand);
|
|
280
|
+
},
|
|
281
|
+
settle: () => table.settle(),
|
|
282
|
+
collected: () => table.collected(),
|
|
283
|
+
shapeOf: (key) => table.shapeOf(key)
|
|
284
|
+
};
|
|
285
|
+
let value;
|
|
286
|
+
try {
|
|
287
|
+
value = read2();
|
|
288
|
+
} finally {
|
|
289
|
+
current = table;
|
|
290
|
+
}
|
|
291
|
+
const noted = [];
|
|
292
|
+
for (const key of keys) {
|
|
293
|
+
const shape = table.shapeOf(key);
|
|
294
|
+
if (shape === null || shape === void 0) {
|
|
295
|
+
return { value, noted: null };
|
|
296
|
+
}
|
|
297
|
+
noted.push([key, shape]);
|
|
298
|
+
}
|
|
299
|
+
return { value, noted };
|
|
300
|
+
}
|
|
301
|
+
function writeNotedDefinitions(noted) {
|
|
302
|
+
const table = current;
|
|
303
|
+
if (table === null) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
for (const [key, shape] of noted) {
|
|
307
|
+
if (!table.has(key)) {
|
|
308
|
+
table.define(key, structuredClone(shape));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function withDefinitions(read2) {
|
|
313
|
+
const table = createDefinitionTable();
|
|
314
|
+
const outer = current;
|
|
315
|
+
current = table;
|
|
316
|
+
try {
|
|
317
|
+
return { value: read2(), definitions: table.collected() };
|
|
318
|
+
} finally {
|
|
319
|
+
current = outer;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// src/bodyWalks.ts
|
|
324
|
+
var keptByBody = /* @__PURE__ */ new WeakMap();
|
|
325
|
+
var talliesByRecognizer = /* @__PURE__ */ new WeakMap();
|
|
326
|
+
var ids = /* @__PURE__ */ new WeakMap();
|
|
327
|
+
var nextId = 1;
|
|
328
|
+
function noteRecognizerTally(recognizer, tally) {
|
|
329
|
+
talliesByRecognizer.set(recognizer, tally);
|
|
330
|
+
}
|
|
331
|
+
function walkBodyOnce(body, inputs, walk) {
|
|
332
|
+
const key = keyOf(inputs);
|
|
333
|
+
const facts = inputs.resolution?.sourceFactCount() ?? -1;
|
|
334
|
+
const kept = keptByBody.get(body)?.find((one) => one.key === key && one.facts === facts);
|
|
335
|
+
if (kept !== void 0) {
|
|
336
|
+
return replay(kept);
|
|
337
|
+
}
|
|
338
|
+
const before = new Map(
|
|
339
|
+
[...talliesOf(inputs)].map((tally) => [tally, tally.effectsRecognized])
|
|
340
|
+
);
|
|
341
|
+
const read2 = withFilesNoted(() => withDefinitionsNoted(walk));
|
|
342
|
+
const { value, noted } = read2.value;
|
|
343
|
+
const factsAfter = inputs.resolution?.sourceFactCount() ?? -1;
|
|
344
|
+
if (noted === null || factsAfter !== facts) {
|
|
345
|
+
return value;
|
|
346
|
+
}
|
|
347
|
+
const effectsByTally = /* @__PURE__ */ new Map();
|
|
348
|
+
for (const [tally, count] of before) {
|
|
349
|
+
effectsByTally.set(tally, tally.effectsRecognized - count);
|
|
350
|
+
}
|
|
351
|
+
const entry = {
|
|
352
|
+
key,
|
|
353
|
+
facts,
|
|
354
|
+
walk: copyWalk(value),
|
|
355
|
+
definitions: noted.map(([name, shape]) => [name, structuredClone(shape)]),
|
|
356
|
+
files: read2.files,
|
|
357
|
+
effectsByTally
|
|
358
|
+
};
|
|
359
|
+
const forBody = keptByBody.get(body);
|
|
360
|
+
if (forBody === void 0) {
|
|
361
|
+
keptByBody.set(body, [entry]);
|
|
362
|
+
} else {
|
|
363
|
+
forBody.push(entry);
|
|
364
|
+
}
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
367
|
+
function replay(kept) {
|
|
368
|
+
writeNotedDefinitions(kept.definitions);
|
|
369
|
+
for (const filePath of kept.files) {
|
|
370
|
+
recordFileDependency(filePath);
|
|
371
|
+
}
|
|
372
|
+
for (const [tally, count] of kept.effectsByTally) {
|
|
373
|
+
tally.effectsRecognized += count;
|
|
374
|
+
}
|
|
375
|
+
return copyWalk(kept.walk);
|
|
376
|
+
}
|
|
377
|
+
function keyOf(inputs) {
|
|
378
|
+
const barrierIds = [...inputs.barriers].map(idOf).sort((a, b) => a - b);
|
|
379
|
+
return [
|
|
380
|
+
inputs.terminalPatterns.map(idOf).join(","),
|
|
381
|
+
idOf(inputs.invocationRecognizers),
|
|
382
|
+
idOf(inputs.accessRecognizers),
|
|
383
|
+
barrierIds.join(","),
|
|
384
|
+
inputs.resolution === void 0 ? 0 : idOf(inputs.resolution),
|
|
385
|
+
inputs.callbacks.map((present) => present ? 1 : 0).join(""),
|
|
386
|
+
// A walk with no table to write named types into notes none, so it
|
|
387
|
+
// cannot stand in for one that has a table.
|
|
388
|
+
definitionsInProgress() === null ? 0 : 1
|
|
389
|
+
].join("|");
|
|
390
|
+
}
|
|
391
|
+
function idOf(value) {
|
|
392
|
+
const known = ids.get(value);
|
|
393
|
+
if (known !== void 0) {
|
|
394
|
+
return known;
|
|
395
|
+
}
|
|
396
|
+
const id = nextId++;
|
|
397
|
+
ids.set(value, id);
|
|
398
|
+
return id;
|
|
399
|
+
}
|
|
400
|
+
function talliesOf(inputs) {
|
|
401
|
+
const tallies = /* @__PURE__ */ new Set();
|
|
402
|
+
for (const recognizer of [
|
|
403
|
+
...inputs.invocationRecognizers,
|
|
404
|
+
...inputs.accessRecognizers
|
|
405
|
+
]) {
|
|
406
|
+
const tally = talliesByRecognizer.get(recognizer);
|
|
407
|
+
if (tally !== void 0) {
|
|
408
|
+
tallies.add(tally);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return tallies;
|
|
412
|
+
}
|
|
413
|
+
function copyWalk(walk) {
|
|
414
|
+
return {
|
|
415
|
+
terminals: walk.terminals.map((found) => ({
|
|
416
|
+
...found,
|
|
417
|
+
terminal: structuredClone(found.terminal),
|
|
418
|
+
...found.whenAlso === void 0 ? {} : { whenAlso: copyCondition(found.whenAlso) }
|
|
419
|
+
})),
|
|
420
|
+
invocations: walk.invocations.map((site) => ({
|
|
421
|
+
...site,
|
|
422
|
+
effect: structuredClone(site.effect)
|
|
423
|
+
})),
|
|
424
|
+
recognized: walk.recognized.map((site) => ({
|
|
425
|
+
...site,
|
|
426
|
+
effect: structuredClone(site.effect),
|
|
427
|
+
preconditions: site.preconditions.map(copyCondition),
|
|
428
|
+
...site.slots === void 0 ? {} : { slots: site.slots.map((slot) => ({ ...slot })) }
|
|
429
|
+
}))
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function copyCondition(condition) {
|
|
433
|
+
return structuredClone(condition);
|
|
434
|
+
}
|
|
435
|
+
|
|
46
436
|
// src/conditions.ts
|
|
47
437
|
import {
|
|
48
438
|
Node as Node46
|
|
@@ -145,7 +535,6 @@ import { normalizeCalleeText } from "@suss/behavioral-ir";
|
|
|
145
535
|
|
|
146
536
|
// src/facts/store.ts
|
|
147
537
|
import { Node as Node9 } from "ts-morph";
|
|
148
|
-
import { isTestFile } from "@suss/behavioral-ir";
|
|
149
538
|
import {
|
|
150
539
|
clearRelations,
|
|
151
540
|
Database as Database2,
|
|
@@ -312,7 +701,7 @@ function createPerFileCache() {
|
|
|
312
701
|
|
|
313
702
|
// src/walk/rawDescent.ts
|
|
314
703
|
import {
|
|
315
|
-
ts
|
|
704
|
+
ts as ts2
|
|
316
705
|
} from "ts-morph";
|
|
317
706
|
function statementsOfKind(file, kind) {
|
|
318
707
|
const found = [];
|
|
@@ -334,10 +723,10 @@ function forEachDescendantWhere(root, accepts, visit, skips = runsNothing) {
|
|
|
334
723
|
if (accepts(raw) && visit(wrapperOf(root, raw)) === true) {
|
|
335
724
|
return void 0;
|
|
336
725
|
}
|
|
337
|
-
|
|
726
|
+
ts2.forEachChild(raw, walk);
|
|
338
727
|
return void 0;
|
|
339
728
|
};
|
|
340
|
-
|
|
729
|
+
ts2.forEachChild(root.compilerNode, walk);
|
|
341
730
|
}
|
|
342
731
|
function runsNothing(raw) {
|
|
343
732
|
return isTypeOnlySyntax(raw) || isAmbient(raw);
|
|
@@ -346,18 +735,18 @@ function skipsNothing() {
|
|
|
346
735
|
return false;
|
|
347
736
|
}
|
|
348
737
|
function isTypeOnlySyntax(raw) {
|
|
349
|
-
return raw.kind >=
|
|
738
|
+
return raw.kind >= ts2.SyntaxKind.FirstTypeNode && raw.kind <= ts2.SyntaxKind.LastTypeNode || TYPE_DECLARATIONS.has(raw.kind);
|
|
350
739
|
}
|
|
351
740
|
var TYPE_DECLARATIONS = /* @__PURE__ */ new Set([
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
741
|
+
ts2.SyntaxKind.TypeAliasDeclaration,
|
|
742
|
+
ts2.SyntaxKind.InterfaceDeclaration,
|
|
743
|
+
ts2.SyntaxKind.TypeParameter
|
|
355
744
|
]);
|
|
356
745
|
function isAmbient(raw) {
|
|
357
|
-
if (!
|
|
746
|
+
if (!ts2.canHaveModifiers(raw)) {
|
|
358
747
|
return false;
|
|
359
748
|
}
|
|
360
|
-
return
|
|
749
|
+
return ts2.getModifiers(raw)?.some((modifier) => modifier.kind === ts2.SyntaxKind.DeclareKeyword) ?? false;
|
|
361
750
|
}
|
|
362
751
|
function wrapperOf(anchor, raw) {
|
|
363
752
|
return anchor._getNodeFromCompilerNode(
|
|
@@ -476,38 +865,23 @@ function indexFunctions(sf) {
|
|
|
476
865
|
const bySpan = spanKey({ start: node.getStart(), end: node.getEnd() });
|
|
477
866
|
index.set(bySpan, node);
|
|
478
867
|
const key = rangeKey({ start: startLineOf(node), end: endLineOf(node) });
|
|
479
|
-
if (!index.has(key)) {
|
|
480
|
-
index.set(key, node);
|
|
481
|
-
}
|
|
482
|
-
return false;
|
|
483
|
-
},
|
|
484
|
-
isTypeOnlySyntax
|
|
485
|
-
);
|
|
486
|
-
return index;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// src/depTracking.ts
|
|
490
|
-
function createDependencySink() {
|
|
491
|
-
return { files: /* @__PURE__ */ new Set(), mountPrefixes: /* @__PURE__ */ new Map(), claims: [] };
|
|
492
|
-
}
|
|
493
|
-
var activeSink = null;
|
|
494
|
-
function withDependencySink(sink, fn) {
|
|
495
|
-
const previous = activeSink;
|
|
496
|
-
activeSink = sink;
|
|
497
|
-
try {
|
|
498
|
-
return fn();
|
|
499
|
-
} finally {
|
|
500
|
-
activeSink = previous;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
function recordFileDependency(filePath) {
|
|
504
|
-
activeSink?.files.add(filePath);
|
|
868
|
+
if (!index.has(key)) {
|
|
869
|
+
index.set(key, node);
|
|
870
|
+
}
|
|
871
|
+
return false;
|
|
872
|
+
},
|
|
873
|
+
isTypeOnlySyntax
|
|
874
|
+
);
|
|
875
|
+
return index;
|
|
505
876
|
}
|
|
506
|
-
|
|
507
|
-
|
|
877
|
+
|
|
878
|
+
// src/testCode.ts
|
|
879
|
+
import { isTestFile } from "@suss/behavioral-ir";
|
|
880
|
+
function inTestFile(node) {
|
|
881
|
+
return isTestFile(node.getSourceFile().getFilePath());
|
|
508
882
|
}
|
|
509
|
-
function
|
|
510
|
-
|
|
883
|
+
function testCallingProduction(call, callee) {
|
|
884
|
+
return inTestFile(call) && !inTestFile(callee);
|
|
511
885
|
}
|
|
512
886
|
|
|
513
887
|
// src/facts/containerWrites.ts
|
|
@@ -519,7 +893,7 @@ import {
|
|
|
519
893
|
ModuleDeclarationKind,
|
|
520
894
|
Node as Node6,
|
|
521
895
|
SyntaxKind as SyntaxKind6,
|
|
522
|
-
ts as
|
|
896
|
+
ts as ts5
|
|
523
897
|
} from "ts-morph";
|
|
524
898
|
import {
|
|
525
899
|
addEntryRows,
|
|
@@ -541,7 +915,7 @@ import { Node as Node3, SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
|
541
915
|
// src/bootstrap/lazyProjectInit.ts
|
|
542
916
|
import fs2 from "fs/promises";
|
|
543
917
|
import path3 from "path";
|
|
544
|
-
import { ts as
|
|
918
|
+
import { ts as ts3 } from "ts-morph";
|
|
545
919
|
|
|
546
920
|
// src/facts/generatedModules.ts
|
|
547
921
|
import fs from "fs";
|
|
@@ -1173,7 +1547,7 @@ function resolutionCacheFor(project, options) {
|
|
|
1173
1547
|
if (existing !== void 0) {
|
|
1174
1548
|
return existing;
|
|
1175
1549
|
}
|
|
1176
|
-
const fresh =
|
|
1550
|
+
const fresh = ts3.createModuleResolutionCache(
|
|
1177
1551
|
project.getFileSystem().getCurrentDirectory(),
|
|
1178
1552
|
(name) => name,
|
|
1179
1553
|
options
|
|
@@ -1207,11 +1581,11 @@ function readSpecifierPaths(project, filePath, options, host) {
|
|
|
1207
1581
|
if (text3 === null) {
|
|
1208
1582
|
return [];
|
|
1209
1583
|
}
|
|
1210
|
-
const scanned =
|
|
1584
|
+
const scanned = ts3.preProcessFile(text3, true, true);
|
|
1211
1585
|
const cache = resolutionCacheFor(project, options);
|
|
1212
1586
|
const paths = [];
|
|
1213
1587
|
for (const imported of scanned.importedFiles) {
|
|
1214
|
-
const resolved =
|
|
1588
|
+
const resolved = ts3.resolveModuleName(
|
|
1215
1589
|
imported.fileName,
|
|
1216
1590
|
filePath,
|
|
1217
1591
|
options,
|
|
@@ -1237,13 +1611,13 @@ function readFileText(project, filePath) {
|
|
|
1237
1611
|
}
|
|
1238
1612
|
function parseTsconfig(tsConfigFilePath, seen = /* @__PURE__ */ new Set()) {
|
|
1239
1613
|
seen.add(tsConfigFilePath);
|
|
1240
|
-
const configFile =
|
|
1614
|
+
const configFile = ts3.readConfigFile(tsConfigFilePath, ts3.sys.readFile);
|
|
1241
1615
|
if (configFile.error !== void 0) {
|
|
1242
1616
|
return { fileNames: [], options: {} };
|
|
1243
1617
|
}
|
|
1244
|
-
const parsed =
|
|
1618
|
+
const parsed = ts3.parseJsonConfigFileContent(
|
|
1245
1619
|
configFile.config,
|
|
1246
|
-
|
|
1620
|
+
ts3.sys,
|
|
1247
1621
|
path3.dirname(tsConfigFilePath),
|
|
1248
1622
|
/*existingOptions*/
|
|
1249
1623
|
void 0,
|
|
@@ -1252,7 +1626,7 @@ function parseTsconfig(tsConfigFilePath, seen = /* @__PURE__ */ new Set()) {
|
|
|
1252
1626
|
if (parsed.fileNames.length > 0) {
|
|
1253
1627
|
return { fileNames: parsed.fileNames, options: parsed.options };
|
|
1254
1628
|
}
|
|
1255
|
-
const referenced = (parsed.projectReferences ?? []).map((reference) =>
|
|
1629
|
+
const referenced = (parsed.projectReferences ?? []).map((reference) => ts3.resolveProjectReferencePath(reference)).filter((referencePath) => !seen.has(referencePath)).map((referencePath) => parseTsconfig(referencePath, seen));
|
|
1256
1630
|
const fileNames = [
|
|
1257
1631
|
...new Set(referenced.flatMap((reference) => reference.fileNames))
|
|
1258
1632
|
];
|
|
@@ -1326,17 +1700,17 @@ function addImportersOfMatches(fileImports, matched, options) {
|
|
|
1326
1700
|
}
|
|
1327
1701
|
function internalSpecifierResolver(files, options) {
|
|
1328
1702
|
const fileSet = new Set(files);
|
|
1329
|
-
const cache =
|
|
1330
|
-
|
|
1703
|
+
const cache = ts3.createModuleResolutionCache(
|
|
1704
|
+
ts3.sys.getCurrentDirectory(),
|
|
1331
1705
|
(name) => name,
|
|
1332
1706
|
options
|
|
1333
1707
|
);
|
|
1334
1708
|
return (fromFile, spec) => {
|
|
1335
|
-
const resolved =
|
|
1709
|
+
const resolved = ts3.resolveModuleName(
|
|
1336
1710
|
spec,
|
|
1337
1711
|
fromFile,
|
|
1338
1712
|
options,
|
|
1339
|
-
|
|
1713
|
+
ts3.sys,
|
|
1340
1714
|
cache
|
|
1341
1715
|
).resolvedModule?.resolvedFileName;
|
|
1342
1716
|
if (resolved === void 0) {
|
|
@@ -1345,7 +1719,7 @@ function internalSpecifierResolver(files, options) {
|
|
|
1345
1719
|
if (fileSet.has(resolved)) {
|
|
1346
1720
|
return resolved;
|
|
1347
1721
|
}
|
|
1348
|
-
const real =
|
|
1722
|
+
const real = ts3.sys.realpath?.(resolved) ?? resolved;
|
|
1349
1723
|
return fileSet.has(real) ? real : null;
|
|
1350
1724
|
};
|
|
1351
1725
|
}
|
|
@@ -1380,7 +1754,7 @@ async function readImportsConcurrently(paths, marks) {
|
|
|
1380
1754
|
const p = paths[i];
|
|
1381
1755
|
try {
|
|
1382
1756
|
const text3 = await fs2.readFile(p, "utf-8");
|
|
1383
|
-
const pre =
|
|
1757
|
+
const pre = ts3.preProcessFile(text3, true, false);
|
|
1384
1758
|
results[i] = {
|
|
1385
1759
|
path: p,
|
|
1386
1760
|
importedModules: pre.importedFiles.map((f) => f.fileName),
|
|
@@ -1616,7 +1990,7 @@ function keyNameOf(name) {
|
|
|
1616
1990
|
}
|
|
1617
1991
|
|
|
1618
1992
|
// src/facts/assignments.ts
|
|
1619
|
-
import { Node as Node5, SyntaxKind as SyntaxKind5, ts as
|
|
1993
|
+
import { Node as Node5, SyntaxKind as SyntaxKind5, ts as ts4, VariableDeclarationKind } from "ts-morph";
|
|
1620
1994
|
import { valueLeftByWrites } from "@suss/resolution";
|
|
1621
1995
|
var byFile = createPerFileCache();
|
|
1622
1996
|
var byDeclaration = /* @__PURE__ */ new WeakMap();
|
|
@@ -1814,11 +2188,11 @@ function assignmentsInFile(sourceFile) {
|
|
|
1814
2188
|
return found;
|
|
1815
2189
|
}
|
|
1816
2190
|
function mayWrite(raw) {
|
|
1817
|
-
if (
|
|
1818
|
-
return isAssignmentOperator(raw.operatorToken.kind) && (
|
|
2191
|
+
if (ts4.isBinaryExpression(raw)) {
|
|
2192
|
+
return isAssignmentOperator(raw.operatorToken.kind) && (ts4.isIdentifier(raw.left) || ts4.isPropertyAccessExpression(raw.left));
|
|
1819
2193
|
}
|
|
1820
|
-
if (
|
|
1821
|
-
return (raw.operator === SyntaxKind5.PlusPlusToken || raw.operator === SyntaxKind5.MinusMinusToken) &&
|
|
2194
|
+
if (ts4.isPrefixUnaryExpression(raw) || ts4.isPostfixUnaryExpression(raw)) {
|
|
2195
|
+
return (raw.operator === SyntaxKind5.PlusPlusToken || raw.operator === SyntaxKind5.MinusMinusToken) && ts4.isIdentifier(raw.operand);
|
|
1822
2196
|
}
|
|
1823
2197
|
return false;
|
|
1824
2198
|
}
|
|
@@ -1879,7 +2253,7 @@ function isReadBefore(declaration, position) {
|
|
|
1879
2253
|
const sourceFile = declaration.getSourceFile();
|
|
1880
2254
|
const file = sourceFile.compilerNode;
|
|
1881
2255
|
const readsHere = (raw) => {
|
|
1882
|
-
if (!
|
|
2256
|
+
if (!ts4.isIdentifier(raw) || raw.getText(file) !== name) {
|
|
1883
2257
|
return false;
|
|
1884
2258
|
}
|
|
1885
2259
|
const node = wrapperOf(sourceFile, raw);
|
|
@@ -1899,9 +2273,9 @@ function someBefore(root, position, test) {
|
|
|
1899
2273
|
if (test(raw)) {
|
|
1900
2274
|
return true;
|
|
1901
2275
|
}
|
|
1902
|
-
return
|
|
2276
|
+
return ts4.forEachChild(raw, visit);
|
|
1903
2277
|
};
|
|
1904
|
-
return
|
|
2278
|
+
return ts4.forEachChild(root, visit) === true;
|
|
1905
2279
|
}
|
|
1906
2280
|
var OWN_BODY_KINDS = /* @__PURE__ */ new Set([
|
|
1907
2281
|
SyntaxKind5.FunctionDeclaration,
|
|
@@ -2003,7 +2377,7 @@ function isPropertyReadBefore(statements, name, property, position) {
|
|
|
2003
2377
|
return someBefore(
|
|
2004
2378
|
statements.compilerNode,
|
|
2005
2379
|
position,
|
|
2006
|
-
(raw) =>
|
|
2380
|
+
(raw) => ts4.isPropertyAccessExpression(raw) && raw.name.getText(file) === property && raw.expression.getText(file) === name && !isWriteTarget(wrapperOf(statements, raw))
|
|
2007
2381
|
);
|
|
2008
2382
|
}
|
|
2009
2383
|
|
|
@@ -2075,7 +2449,7 @@ function moduleKeyOf(declaration) {
|
|
|
2075
2449
|
}
|
|
2076
2450
|
function compilerResolvedPathOf(declaration, specifier) {
|
|
2077
2451
|
const project = declaration.getProject();
|
|
2078
|
-
const result =
|
|
2452
|
+
const result = ts5.resolveModuleName(
|
|
2079
2453
|
specifier,
|
|
2080
2454
|
declaration.getSourceFile().getFilePath(),
|
|
2081
2455
|
project.getCompilerOptions(),
|
|
@@ -2386,7 +2760,7 @@ function spellingsHandedOn(paths, sourceFile) {
|
|
|
2386
2760
|
const found = [];
|
|
2387
2761
|
forEachDescendantWhere(
|
|
2388
2762
|
sourceFile,
|
|
2389
|
-
(raw) =>
|
|
2763
|
+
(raw) => ts5.isPropertyAccessExpression(raw) && paths.includes(compilerDottedPathOf(raw, file) ?? ""),
|
|
2390
2764
|
(node) => {
|
|
2391
2765
|
if (flowsOnward(node)) {
|
|
2392
2766
|
found.push(node);
|
|
@@ -2397,14 +2771,14 @@ function spellingsHandedOn(paths, sourceFile) {
|
|
|
2397
2771
|
return found;
|
|
2398
2772
|
}
|
|
2399
2773
|
function compilerDottedPathOf(raw, file) {
|
|
2400
|
-
if (
|
|
2774
|
+
if (ts5.isIdentifier(raw)) {
|
|
2401
2775
|
return raw.getText(file);
|
|
2402
2776
|
}
|
|
2403
|
-
if (
|
|
2404
|
-
const keyword =
|
|
2777
|
+
if (ts5.isMetaProperty(raw)) {
|
|
2778
|
+
const keyword = ts5.tokenToString(raw.keywordToken);
|
|
2405
2779
|
return `${keyword}.${raw.name.getText(file)}`;
|
|
2406
2780
|
}
|
|
2407
|
-
if (!
|
|
2781
|
+
if (!ts5.isPropertyAccessExpression(raw)) {
|
|
2408
2782
|
return null;
|
|
2409
2783
|
}
|
|
2410
2784
|
const object = compilerDottedPathOf(raw.expression, file);
|
|
@@ -2425,7 +2799,7 @@ function dottedPathOf(expression) {
|
|
|
2425
2799
|
return expression.getText();
|
|
2426
2800
|
}
|
|
2427
2801
|
if (Node6.isMetaProperty(expression)) {
|
|
2428
|
-
const keyword =
|
|
2802
|
+
const keyword = ts5.tokenToString(expression.getKeywordToken());
|
|
2429
2803
|
return `${keyword}.${expression.getName()}`;
|
|
2430
2804
|
}
|
|
2431
2805
|
if (!Node6.isPropertyAccessExpression(expression)) {
|
|
@@ -3767,6 +4141,10 @@ var NOT_BASE_FACTS = /* @__PURE__ */ new Set([
|
|
|
3767
4141
|
...RESOLUTION_PROGRAM.rules.map((r) => r.head.relation),
|
|
3768
4142
|
...ASKING_RELATIONS
|
|
3769
4143
|
]);
|
|
4144
|
+
var DERIVED_RELATIONS = /* @__PURE__ */ new Set([
|
|
4145
|
+
...NOT_BASE_FACTS,
|
|
4146
|
+
...resolutionUnderProgram().rules.map((r) => r.head.relation)
|
|
4147
|
+
]);
|
|
3770
4148
|
var QUERY_FACTS = queryFacts(RESOLUTION_PROGRAM);
|
|
3771
4149
|
var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
|
|
3772
4150
|
(one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
|
|
@@ -3803,6 +4181,8 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
3803
4181
|
constructionSites = /* @__PURE__ */ new Map();
|
|
3804
4182
|
/** What each local's reads do with it, by its declaration. A local's function is walked whole, so an answer stays true. */
|
|
3805
4183
|
localUses = /* @__PURE__ */ new Map();
|
|
4184
|
+
/** See `remembered`. */
|
|
4185
|
+
answers = /* @__PURE__ */ new Map();
|
|
3806
4186
|
/** Files the most recent query read, for the memo to keep. */
|
|
3807
4187
|
lastQueryWalked = [];
|
|
3808
4188
|
/** See `environmentSiteFiles`; null until the first env question. */
|
|
@@ -3854,12 +4234,18 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
3854
4234
|
*/
|
|
3855
4235
|
resolveCallableSources(value, alsoFrom) {
|
|
3856
4236
|
const target = factKeyOf(value);
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
4237
|
+
const key = `sources|${nodeId(target)}|${alsoFrom?.getFilePath() ?? ""}`;
|
|
4238
|
+
return [
|
|
4239
|
+
...this.remembered(
|
|
4240
|
+
key,
|
|
4241
|
+
() => this.askAbout(
|
|
4242
|
+
target,
|
|
4243
|
+
"wanted",
|
|
4244
|
+
() => this.lookupSources(target),
|
|
4245
|
+
alsoFrom
|
|
4246
|
+
)
|
|
4247
|
+
)
|
|
4248
|
+
];
|
|
3863
4249
|
}
|
|
3864
4250
|
/**
|
|
3865
4251
|
* `resolveCallable` for several values, asked as one question. A file
|
|
@@ -3921,7 +4307,45 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
3921
4307
|
}
|
|
3922
4308
|
resolveObject(value) {
|
|
3923
4309
|
const target = factKeyOf(value);
|
|
3924
|
-
return this.
|
|
4310
|
+
return this.remembered(
|
|
4311
|
+
`object|${nodeId(target)}`,
|
|
4312
|
+
() => this.askAbout(target, "wanted", () => this.lookupObject(target))
|
|
4313
|
+
);
|
|
4314
|
+
}
|
|
4315
|
+
/**
|
|
4316
|
+
* A question asked again over the same facts reads the same files and
|
|
4317
|
+
* derives the same answer, so the store gives back the one it found
|
|
4318
|
+
* before. The files that answer read still count as read.
|
|
4319
|
+
*/
|
|
4320
|
+
remembered(key, ask) {
|
|
4321
|
+
const known = this.answers.get(key);
|
|
4322
|
+
if (known !== void 0 && known.facts === this.sourceFactCount()) {
|
|
4323
|
+
for (const walkedPath of known.walked) {
|
|
4324
|
+
recordFileDependency(walkedPath);
|
|
4325
|
+
}
|
|
4326
|
+
return known.answer;
|
|
4327
|
+
}
|
|
4328
|
+
const answer = ask();
|
|
4329
|
+
this.answers.set(key, {
|
|
4330
|
+
answer,
|
|
4331
|
+
walked: [...this.lastQueryWalked],
|
|
4332
|
+
facts: this.sourceFactCount()
|
|
4333
|
+
});
|
|
4334
|
+
return answer;
|
|
4335
|
+
}
|
|
4336
|
+
/**
|
|
4337
|
+
* How many facts the store has read from source. They are only ever
|
|
4338
|
+
* added, so work that asked the store questions and found this number
|
|
4339
|
+
* unchanged afterwards would get the same answers asking again.
|
|
4340
|
+
*/
|
|
4341
|
+
sourceFactCount() {
|
|
4342
|
+
let count = 0;
|
|
4343
|
+
for (const relation of this.db.relationNames()) {
|
|
4344
|
+
if (!DERIVED_RELATIONS.has(relation)) {
|
|
4345
|
+
count += this.db.size(relation);
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
return count;
|
|
3925
4349
|
}
|
|
3926
4350
|
/**
|
|
3927
4351
|
* The function a call returns: `app.use(requireCaller(config))`
|
|
@@ -4021,7 +4445,7 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
4021
4445
|
writtenAnswers(values, wanted) {
|
|
4022
4446
|
const found = /* @__PURE__ */ new Map();
|
|
4023
4447
|
const asked = /* @__PURE__ */ new Map();
|
|
4024
|
-
const
|
|
4448
|
+
const keyOf2 = /* @__PURE__ */ new Map();
|
|
4025
4449
|
for (const value of values) {
|
|
4026
4450
|
const target = factKeyOf(value);
|
|
4027
4451
|
const key = nodeId(this.sharedDeclarationFor(target));
|
|
@@ -4036,7 +4460,7 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
4036
4460
|
if (!asked.has(key)) {
|
|
4037
4461
|
asked.set(key, target);
|
|
4038
4462
|
}
|
|
4039
|
-
|
|
4463
|
+
keyOf2.set(value, key);
|
|
4040
4464
|
}
|
|
4041
4465
|
if (asked.size === 0) {
|
|
4042
4466
|
return found;
|
|
@@ -4051,7 +4475,7 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
4051
4475
|
});
|
|
4052
4476
|
}
|
|
4053
4477
|
});
|
|
4054
|
-
for (const [value, key] of
|
|
4478
|
+
for (const [value, key] of keyOf2) {
|
|
4055
4479
|
found.set(value, this.writtenValues.get(key)?.[wanted] ?? null);
|
|
4056
4480
|
}
|
|
4057
4481
|
return found;
|
|
@@ -5334,9 +5758,6 @@ function namesPackage2(moduleKey, packages) {
|
|
|
5334
5758
|
packages
|
|
5335
5759
|
);
|
|
5336
5760
|
}
|
|
5337
|
-
function inTestFile(node) {
|
|
5338
|
-
return isTestFile(node.getSourceFile().getFilePath());
|
|
5339
|
-
}
|
|
5340
5761
|
function declarationOf(value) {
|
|
5341
5762
|
const nameNode = Node9.isPropertyAccessExpression(value) ? value.getNameNode() : value;
|
|
5342
5763
|
return nameNode.getSymbol()?.getDeclarations()[0] ?? value;
|
|
@@ -6433,7 +6854,7 @@ function settledChannel(argument, resolution) {
|
|
|
6433
6854
|
}
|
|
6434
6855
|
|
|
6435
6856
|
// src/discovery/importedCalls.ts
|
|
6436
|
-
import { Node as Node14, ts as
|
|
6857
|
+
import { Node as Node14, ts as ts6 } from "ts-morph";
|
|
6437
6858
|
function callsResolvingTo(sourceFile, resolution, spec) {
|
|
6438
6859
|
return [
|
|
6439
6860
|
...callsByOriginName(
|
|
@@ -6479,7 +6900,7 @@ function callsNamed(found, names) {
|
|
|
6479
6900
|
return matched;
|
|
6480
6901
|
}
|
|
6481
6902
|
function callsANamedCallee(raw) {
|
|
6482
|
-
return (
|
|
6903
|
+
return (ts6.isCallExpression(raw) || ts6.isNewExpression(raw)) && ts6.isIdentifier(raw.expression);
|
|
6483
6904
|
}
|
|
6484
6905
|
function declaredLocally(callee) {
|
|
6485
6906
|
const declarations = callee.getSymbol()?.getDeclarations() ?? [];
|
|
@@ -8884,7 +9305,7 @@ function evaluateObjectLiteralAsJson(node) {
|
|
|
8884
9305
|
return node.getLiteralValue();
|
|
8885
9306
|
}
|
|
8886
9307
|
if (Node25.isNumericLiteral(node)) {
|
|
8887
|
-
return
|
|
9308
|
+
return node.getLiteralValue();
|
|
8888
9309
|
}
|
|
8889
9310
|
const kind = node.getText();
|
|
8890
9311
|
if (kind === "true") {
|
|
@@ -9392,6 +9813,9 @@ function expandParameter(parameter, forwardsResult, depth, expanded, context, ch
|
|
|
9392
9813
|
const units = [];
|
|
9393
9814
|
let unfollowed = 0;
|
|
9394
9815
|
for (const { call, argument } of passed) {
|
|
9816
|
+
if (testCallingProduction(call, parameter)) {
|
|
9817
|
+
continue;
|
|
9818
|
+
}
|
|
9395
9819
|
const caller = enclosingFunctionRoot(call);
|
|
9396
9820
|
if (caller === null || !Node28.isCallExpression(call)) {
|
|
9397
9821
|
unfollowed++;
|
|
@@ -11008,7 +11432,7 @@ function creationSiteBehind(parameter, resolution) {
|
|
|
11008
11432
|
}
|
|
11009
11433
|
function registrationSubjectIdsOf(sourceFile, matches, resolution) {
|
|
11010
11434
|
const seenImports = /* @__PURE__ */ new Set();
|
|
11011
|
-
const
|
|
11435
|
+
const ids2 = /* @__PURE__ */ new Set();
|
|
11012
11436
|
for (const match of matches) {
|
|
11013
11437
|
const importKey = `${match.importModule}::${match.importName}`;
|
|
11014
11438
|
if (seenImports.has(importKey)) {
|
|
@@ -11021,17 +11445,17 @@ function registrationSubjectIdsOf(sourceFile, matches, resolution) {
|
|
|
11021
11445
|
match.importName,
|
|
11022
11446
|
resolution
|
|
11023
11447
|
).values()) {
|
|
11024
|
-
|
|
11448
|
+
ids2.add(nodeId(node));
|
|
11025
11449
|
}
|
|
11026
11450
|
for (const node of unboundConstructionsOf(
|
|
11027
11451
|
sourceFile,
|
|
11028
11452
|
match.importModule,
|
|
11029
11453
|
match.importName
|
|
11030
11454
|
)) {
|
|
11031
|
-
|
|
11455
|
+
ids2.add(nodeId(node));
|
|
11032
11456
|
}
|
|
11033
11457
|
}
|
|
11034
|
-
return
|
|
11458
|
+
return ids2;
|
|
11035
11459
|
}
|
|
11036
11460
|
function unboundConstructionsOf(sourceFile, importModule, importName) {
|
|
11037
11461
|
const spellings = importedReferenceSpellings(
|
|
@@ -13085,7 +13509,7 @@ import {
|
|
|
13085
13509
|
import {
|
|
13086
13510
|
Node as Node47,
|
|
13087
13511
|
SyntaxKind as SyntaxKind20,
|
|
13088
|
-
ts as
|
|
13512
|
+
ts as ts7
|
|
13089
13513
|
} from "ts-morph";
|
|
13090
13514
|
import {
|
|
13091
13515
|
UnmodeledFlow
|
|
@@ -13109,7 +13533,7 @@ function exitKindOf(stmt, endings) {
|
|
|
13109
13533
|
if (raw.kind === SyntaxKind20.ThrowStatement) {
|
|
13110
13534
|
sawThrow = true;
|
|
13111
13535
|
}
|
|
13112
|
-
|
|
13536
|
+
ts7.forEachChild(raw, visit);
|
|
13113
13537
|
return void 0;
|
|
13114
13538
|
};
|
|
13115
13539
|
visit(root);
|
|
@@ -13222,7 +13646,7 @@ function lowerCallbacksIn(parts, ctx) {
|
|
|
13222
13646
|
if (runsNothing(raw)) {
|
|
13223
13647
|
return void 0;
|
|
13224
13648
|
}
|
|
13225
|
-
|
|
13649
|
+
ts7.forEachChild(raw, visit);
|
|
13226
13650
|
return void 0;
|
|
13227
13651
|
};
|
|
13228
13652
|
visit(root);
|
|
@@ -13599,126 +14023,6 @@ import { Node as Node51 } from "ts-morph";
|
|
|
13599
14023
|
|
|
13600
14024
|
// src/values/receiverType.ts
|
|
13601
14025
|
import { Node as Node50 } from "ts-morph";
|
|
13602
|
-
|
|
13603
|
-
// src/shapes/typeText.ts
|
|
13604
|
-
import { ts as ts7 } from "ts-morph";
|
|
13605
|
-
var PRINTER = ts7.createPrinter({
|
|
13606
|
-
removeComments: true,
|
|
13607
|
-
newLine: ts7.NewLineKind.LineFeed
|
|
13608
|
-
});
|
|
13609
|
-
var NO_FILE = ts7.createSourceFile("", "", ts7.ScriptTarget.Latest);
|
|
13610
|
-
function defaultFlags(enclosing) {
|
|
13611
|
-
const flags = ts7.TypeFormatFlags.UseTypeOfFunction | ts7.TypeFormatFlags.NoTruncation | ts7.TypeFormatFlags.UseFullyQualifiedType | ts7.TypeFormatFlags.WriteTypeArgumentsOfSignature;
|
|
13612
|
-
if (enclosing?.getKind() === ts7.SyntaxKind.TypeAliasDeclaration) {
|
|
13613
|
-
return flags | ts7.TypeFormatFlags.InTypeAlias;
|
|
13614
|
-
}
|
|
13615
|
-
return flags;
|
|
13616
|
-
}
|
|
13617
|
-
function stableTypeText(type, reader, enclosing, flags) {
|
|
13618
|
-
const format = flags ?? defaultFlags(enclosing);
|
|
13619
|
-
const place = enclosing?.compilerNode ?? NOWHERE;
|
|
13620
|
-
const atPlace = printedAt.get(place) ?? /* @__PURE__ */ new WeakMap();
|
|
13621
|
-
printedAt.set(place, atPlace);
|
|
13622
|
-
const byFormat = atPlace.get(type.compilerType) ?? /* @__PURE__ */ new Map();
|
|
13623
|
-
atPlace.set(type.compilerType, byFormat);
|
|
13624
|
-
const kept = byFormat.get(format);
|
|
13625
|
-
if (kept !== void 0) {
|
|
13626
|
-
return kept;
|
|
13627
|
-
}
|
|
13628
|
-
const text3 = printedType(type, reader, enclosing, format);
|
|
13629
|
-
byFormat.set(format, text3);
|
|
13630
|
-
return text3;
|
|
13631
|
-
}
|
|
13632
|
-
var NOWHERE = {};
|
|
13633
|
-
var printedAt = /* @__PURE__ */ new WeakMap();
|
|
13634
|
-
function printedType(type, reader, enclosing, format) {
|
|
13635
|
-
const checker = reader.getProject().getTypeChecker().compilerObject;
|
|
13636
|
-
const enclosingNode = enclosing?.compilerNode;
|
|
13637
|
-
const typeNode = checker.typeToTypeNode(
|
|
13638
|
-
type.compilerType,
|
|
13639
|
-
enclosingNode,
|
|
13640
|
-
format & ts7.TypeFormatFlags.NodeBuilderFlagsMask | ts7.NodeBuilderFlags.IgnoreErrors
|
|
13641
|
-
);
|
|
13642
|
-
if (typeNode === void 0) {
|
|
13643
|
-
return withoutImportQualifiers(
|
|
13644
|
-
checker.typeToString(type.compilerType, enclosingNode, format)
|
|
13645
|
-
);
|
|
13646
|
-
}
|
|
13647
|
-
const file = enclosing?.getSourceFile().compilerNode ?? NO_FILE;
|
|
13648
|
-
const ordered = containsUnion(typeNode) ? withUnionMembersOrdered(typeNode, file) : typeNode;
|
|
13649
|
-
return withoutImportQualifiers(printed(ordered, file));
|
|
13650
|
-
}
|
|
13651
|
-
var IMPORT_QUALIFIER = /import\("[^"]*"\)\./g;
|
|
13652
|
-
var withoutImportQualifiers = (text3) => text3.replace(IMPORT_QUALIFIER, "");
|
|
13653
|
-
function printed(node, file) {
|
|
13654
|
-
return PRINTER.printNode(ts7.EmitHint.Unspecified, node, file).replace(
|
|
13655
|
-
/\n/g,
|
|
13656
|
-
""
|
|
13657
|
-
);
|
|
13658
|
-
}
|
|
13659
|
-
function containsUnion(node) {
|
|
13660
|
-
if (ts7.isUnionTypeNode(node)) {
|
|
13661
|
-
return true;
|
|
13662
|
-
}
|
|
13663
|
-
return ts7.forEachChild(node, (child) => containsUnion(child) || void 0) === true;
|
|
13664
|
-
}
|
|
13665
|
-
function withUnionMembersOrdered(root, file) {
|
|
13666
|
-
const result = ts7.transform(root, [
|
|
13667
|
-
(context) => {
|
|
13668
|
-
const visit = (node) => {
|
|
13669
|
-
const visited = ts7.visitEachChild(node, visit, context);
|
|
13670
|
-
if (!ts7.isUnionTypeNode(visited)) {
|
|
13671
|
-
return visited;
|
|
13672
|
-
}
|
|
13673
|
-
return context.factory.updateUnionTypeNode(
|
|
13674
|
-
visited,
|
|
13675
|
-
context.factory.createNodeArray(inStableOrder(visited.types, file))
|
|
13676
|
-
);
|
|
13677
|
-
};
|
|
13678
|
-
return (node) => visit(node);
|
|
13679
|
-
}
|
|
13680
|
-
]);
|
|
13681
|
-
const [ordered] = result.transformed;
|
|
13682
|
-
result.dispose();
|
|
13683
|
-
return ordered;
|
|
13684
|
-
}
|
|
13685
|
-
function inStableOrder(members, file) {
|
|
13686
|
-
return members.map((member) => ({
|
|
13687
|
-
member,
|
|
13688
|
-
text: withoutImportQualifiers(printed(member, file))
|
|
13689
|
-
})).sort((a, b) => compareMembers(a.text, b.text)).map(({ member }) => member);
|
|
13690
|
-
}
|
|
13691
|
-
function compareMembers(a, b) {
|
|
13692
|
-
return nullishRank(a) - nullishRank(b) || compareText(a, b);
|
|
13693
|
-
}
|
|
13694
|
-
function nullishRank(text3) {
|
|
13695
|
-
if (text3 === "null") {
|
|
13696
|
-
return 1;
|
|
13697
|
-
}
|
|
13698
|
-
if (text3 === "undefined") {
|
|
13699
|
-
return 2;
|
|
13700
|
-
}
|
|
13701
|
-
return 0;
|
|
13702
|
-
}
|
|
13703
|
-
function compareText(a, b) {
|
|
13704
|
-
if (a < b) {
|
|
13705
|
-
return -1;
|
|
13706
|
-
}
|
|
13707
|
-
if (a > b) {
|
|
13708
|
-
return 1;
|
|
13709
|
-
}
|
|
13710
|
-
return 0;
|
|
13711
|
-
}
|
|
13712
|
-
function stablePropertyName(symbol, reader) {
|
|
13713
|
-
const name = symbol.getName();
|
|
13714
|
-
if (!name.startsWith("__@")) {
|
|
13715
|
-
return name;
|
|
13716
|
-
}
|
|
13717
|
-
const checker = reader.getProject().getTypeChecker().compilerObject;
|
|
13718
|
-
return checker.symbolToString(symbol.compilerSymbol);
|
|
13719
|
-
}
|
|
13720
|
-
|
|
13721
|
-
// src/values/receiverType.ts
|
|
13722
14026
|
function receiverTypesOf(node) {
|
|
13723
14027
|
const type = node.getType();
|
|
13724
14028
|
if (type.isAny()) {
|
|
@@ -15732,67 +16036,6 @@ import {
|
|
|
15732
16036
|
// src/shapes/typeShapes.ts
|
|
15733
16037
|
import { createHash } from "crypto";
|
|
15734
16038
|
import { Node as Node58, TypeFormatFlags } from "ts-morph";
|
|
15735
|
-
|
|
15736
|
-
// src/shapes/definitions.ts
|
|
15737
|
-
var current = null;
|
|
15738
|
-
var definitionsInProgress = () => current;
|
|
15739
|
-
function createDefinitionTable() {
|
|
15740
|
-
const shapes = /* @__PURE__ */ new Map();
|
|
15741
|
-
const deferred = [];
|
|
15742
|
-
let settling = false;
|
|
15743
|
-
return {
|
|
15744
|
-
has: (key) => shapes.has(key),
|
|
15745
|
-
reserve: (key) => {
|
|
15746
|
-
shapes.set(key, null);
|
|
15747
|
-
},
|
|
15748
|
-
define: (key, shape) => {
|
|
15749
|
-
shapes.set(key, shape);
|
|
15750
|
-
},
|
|
15751
|
-
defer: (key, expand) => {
|
|
15752
|
-
deferred.push({ key, expand });
|
|
15753
|
-
},
|
|
15754
|
-
settle: () => {
|
|
15755
|
-
if (settling) {
|
|
15756
|
-
return;
|
|
15757
|
-
}
|
|
15758
|
-
settling = true;
|
|
15759
|
-
try {
|
|
15760
|
-
for (let next = deferred.shift(); next; next = deferred.shift()) {
|
|
15761
|
-
shapes.set(next.key, next.expand());
|
|
15762
|
-
}
|
|
15763
|
-
} finally {
|
|
15764
|
-
settling = false;
|
|
15765
|
-
}
|
|
15766
|
-
},
|
|
15767
|
-
// Sorted because the walk meets types in the checker's union order,
|
|
15768
|
-
// which changes between runs.
|
|
15769
|
-
collected: () => {
|
|
15770
|
-
const out = {};
|
|
15771
|
-
let any = false;
|
|
15772
|
-
const keys = [...shapes.keys()].sort(compareText);
|
|
15773
|
-
for (const key of keys) {
|
|
15774
|
-
const shape = shapes.get(key) ?? null;
|
|
15775
|
-
if (shape !== null) {
|
|
15776
|
-
out[key] = shape;
|
|
15777
|
-
any = true;
|
|
15778
|
-
}
|
|
15779
|
-
}
|
|
15780
|
-
return any ? out : null;
|
|
15781
|
-
}
|
|
15782
|
-
};
|
|
15783
|
-
}
|
|
15784
|
-
function withDefinitions(read2) {
|
|
15785
|
-
const table = createDefinitionTable();
|
|
15786
|
-
const outer = current;
|
|
15787
|
-
current = table;
|
|
15788
|
-
try {
|
|
15789
|
-
return { value: read2(), definitions: table.collected() };
|
|
15790
|
-
} finally {
|
|
15791
|
-
current = outer;
|
|
15792
|
-
}
|
|
15793
|
-
}
|
|
15794
|
-
|
|
15795
|
-
// src/shapes/typeShapes.ts
|
|
15796
16039
|
var MAX_DEPTH = 6;
|
|
15797
16040
|
var OPAQUE_NAMED_TYPES = /* @__PURE__ */ new Set([
|
|
15798
16041
|
"Date",
|
|
@@ -15830,16 +16073,17 @@ function overloadIsAGuess(node) {
|
|
|
15830
16073
|
if (signatures.length < 2) {
|
|
15831
16074
|
return false;
|
|
15832
16075
|
}
|
|
15833
|
-
const
|
|
15834
|
-
signatures.map((signature) => signature.getReturnType().getText(node))
|
|
15835
|
-
);
|
|
15836
|
-
if (returns.size < 2) {
|
|
15837
|
-
return false;
|
|
15838
|
-
}
|
|
15839
|
-
return node.getArguments().some((argument) => {
|
|
16076
|
+
const untypedArgument = node.getArguments().some((argument) => {
|
|
15840
16077
|
const type = argument.getType();
|
|
15841
16078
|
return type.isAny() || type.isNever();
|
|
15842
16079
|
});
|
|
16080
|
+
if (!untypedArgument) {
|
|
16081
|
+
return false;
|
|
16082
|
+
}
|
|
16083
|
+
const returns = new Set(
|
|
16084
|
+
signatures.map((signature) => signature.getReturnType().getText(node))
|
|
16085
|
+
);
|
|
16086
|
+
return returns.size >= 2;
|
|
15843
16087
|
}
|
|
15844
16088
|
function typeToShape(type, ctx) {
|
|
15845
16089
|
if (type.isAny()) {
|
|
@@ -17018,7 +17262,7 @@ function evaluateComparison(condition, substitutions) {
|
|
|
17018
17262
|
}
|
|
17019
17263
|
function numberFor(node, substitutions) {
|
|
17020
17264
|
const resolved = Node62.isIdentifier(node) && substitutions.has(node.getText()) ? substitutions.get(node.getText()) : node;
|
|
17021
|
-
return Node62.isNumericLiteral(resolved) ?
|
|
17265
|
+
return Node62.isNumericLiteral(resolved) ? resolved.getLiteralValue() : null;
|
|
17022
17266
|
}
|
|
17023
17267
|
var helperBySymbol = createProgramMemo();
|
|
17024
17268
|
function memoizedLocalHelper(callee, resolveCallee2) {
|
|
@@ -17920,33 +18164,50 @@ var RETURNS_AND_SCOPES = /* @__PURE__ */ new Set([
|
|
|
17920
18164
|
SyntaxKind27.ReturnStatement
|
|
17921
18165
|
]);
|
|
17922
18166
|
function extractRawBranches(func, terminalPatterns, invocationRecognizers = [], accessRecognizers = [], barriers = NO_BARRIERS, resolution, originatesFrom, anchorCallsOf, resolveCallee2, collectCallAccounting = false, keepsArms, handOff) {
|
|
17923
|
-
const terminals =
|
|
18167
|
+
const { terminals, invocations, recognized } = walkBodyOnce(
|
|
17924
18168
|
func,
|
|
17925
|
-
|
|
17926
|
-
|
|
17927
|
-
resolution,
|
|
17928
|
-
originatesFrom,
|
|
17929
|
-
resolveCallee2
|
|
17930
|
-
);
|
|
17931
|
-
const invocations = extractInvocationEffects(func, barriers);
|
|
17932
|
-
const recognized = [
|
|
17933
|
-
...runInvocationRecognizers(
|
|
17934
|
-
func,
|
|
18169
|
+
{
|
|
18170
|
+
terminalPatterns,
|
|
17935
18171
|
invocationRecognizers,
|
|
17936
|
-
barriers,
|
|
17937
|
-
resolution,
|
|
17938
|
-
originatesFrom,
|
|
17939
|
-
anchorCallsOf
|
|
17940
|
-
),
|
|
17941
|
-
...runAccessRecognizers(
|
|
17942
|
-
func,
|
|
17943
18172
|
accessRecognizers,
|
|
17944
18173
|
barriers,
|
|
17945
18174
|
resolution,
|
|
17946
|
-
|
|
17947
|
-
|
|
17948
|
-
|
|
17949
|
-
|
|
18175
|
+
callbacks: [
|
|
18176
|
+
originatesFrom !== void 0,
|
|
18177
|
+
anchorCallsOf !== void 0,
|
|
18178
|
+
resolveCallee2 !== void 0
|
|
18179
|
+
]
|
|
18180
|
+
},
|
|
18181
|
+
() => ({
|
|
18182
|
+
terminals: findTerminals(
|
|
18183
|
+
func,
|
|
18184
|
+
terminalPatterns,
|
|
18185
|
+
barriers,
|
|
18186
|
+
resolution,
|
|
18187
|
+
originatesFrom,
|
|
18188
|
+
resolveCallee2
|
|
18189
|
+
),
|
|
18190
|
+
invocations: extractInvocationEffects(func, barriers),
|
|
18191
|
+
recognized: [
|
|
18192
|
+
...runInvocationRecognizers(
|
|
18193
|
+
func,
|
|
18194
|
+
invocationRecognizers,
|
|
18195
|
+
barriers,
|
|
18196
|
+
resolution,
|
|
18197
|
+
originatesFrom,
|
|
18198
|
+
anchorCallsOf
|
|
18199
|
+
),
|
|
18200
|
+
...runAccessRecognizers(
|
|
18201
|
+
func,
|
|
18202
|
+
accessRecognizers,
|
|
18203
|
+
barriers,
|
|
18204
|
+
resolution,
|
|
18205
|
+
originatesFrom,
|
|
18206
|
+
anchorCallsOf
|
|
18207
|
+
)
|
|
18208
|
+
]
|
|
18209
|
+
})
|
|
18210
|
+
);
|
|
17950
18211
|
const endings = new Set(
|
|
17951
18212
|
terminals.filter(({ terminal }) => terminal.kind === "exit").map(({ node }) => node)
|
|
17952
18213
|
);
|
|
@@ -19813,6 +20074,9 @@ function callSitesOf(func, store) {
|
|
|
19813
20074
|
if (!Node73.isCallExpression(passed.call)) {
|
|
19814
20075
|
continue;
|
|
19815
20076
|
}
|
|
20077
|
+
if (testCallingProduction(passed.call, func)) {
|
|
20078
|
+
continue;
|
|
20079
|
+
}
|
|
19816
20080
|
const key = siteKey(passed.call);
|
|
19817
20081
|
const site = byCall.get(key) ?? {
|
|
19818
20082
|
call: passed.call,
|
|
@@ -23280,13 +23544,15 @@ function resolveContractField(callSite, pack, field, resolution) {
|
|
|
23280
23544
|
return value ?? void 0;
|
|
23281
23545
|
}
|
|
23282
23546
|
function reportingTo(recognize, tally) {
|
|
23283
|
-
|
|
23547
|
+
const reporting = (node, ctx) => {
|
|
23284
23548
|
const effects = recognize(node, ctx);
|
|
23285
23549
|
if (effects !== null) {
|
|
23286
23550
|
tally.effectsRecognized += effects.length;
|
|
23287
23551
|
}
|
|
23288
23552
|
return effects;
|
|
23289
23553
|
};
|
|
23554
|
+
noteRecognizerTally(reporting, tally);
|
|
23555
|
+
return reporting;
|
|
23290
23556
|
}
|
|
23291
23557
|
function collectInvocationRecognizers(frameworks, tallies) {
|
|
23292
23558
|
const out = [];
|