@suss/adapter-typescript 0.37.1 → 0.38.1
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 +1406 -1085
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +622 -300
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -43,6 +43,409 @@ 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 = containsReordered(typeNode) ? withMembersOrdered(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
|
+
var isReordered = (node) => ts.isUnionTypeNode(node) || ts.isTypeLiteralNode(node);
|
|
148
|
+
function containsReordered(node) {
|
|
149
|
+
if (isReordered(node)) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
return ts.forEachChild(node, (child) => containsReordered(child) || void 0) === true;
|
|
153
|
+
}
|
|
154
|
+
function withMembersOrdered(root, file) {
|
|
155
|
+
const result = ts.transform(root, [
|
|
156
|
+
(context) => {
|
|
157
|
+
const visit = (node) => {
|
|
158
|
+
const visited = ts.visitEachChild(node, visit, context);
|
|
159
|
+
if (ts.isUnionTypeNode(visited)) {
|
|
160
|
+
return context.factory.updateUnionTypeNode(
|
|
161
|
+
visited,
|
|
162
|
+
context.factory.createNodeArray(inStableOrder(visited.types, file))
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
if (ts.isTypeLiteralNode(visited)) {
|
|
166
|
+
return context.factory.updateTypeLiteralNode(
|
|
167
|
+
visited,
|
|
168
|
+
context.factory.createNodeArray(inNameOrder(visited.members, file))
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
return visited;
|
|
172
|
+
};
|
|
173
|
+
return (node) => visit(node);
|
|
174
|
+
}
|
|
175
|
+
]);
|
|
176
|
+
const [ordered] = result.transformed;
|
|
177
|
+
result.dispose();
|
|
178
|
+
return ordered;
|
|
179
|
+
}
|
|
180
|
+
function inNameOrder(members, file) {
|
|
181
|
+
return members.map((member) => ({
|
|
182
|
+
member,
|
|
183
|
+
name: member.name === void 0 ? "" : printed(member.name, file)
|
|
184
|
+
})).sort((a, b) => compareText(a.name, b.name)).map(({ member }) => member);
|
|
185
|
+
}
|
|
186
|
+
function inStableOrder(members, file) {
|
|
187
|
+
return members.map((member) => ({
|
|
188
|
+
member,
|
|
189
|
+
text: withoutImportQualifiers(printed(member, file))
|
|
190
|
+
})).sort((a, b) => compareMembers(a.text, b.text)).map(({ member }) => member);
|
|
191
|
+
}
|
|
192
|
+
function compareMembers(a, b) {
|
|
193
|
+
return nullishRank(a) - nullishRank(b) || compareText(a, b);
|
|
194
|
+
}
|
|
195
|
+
function nullishRank(text3) {
|
|
196
|
+
if (text3 === "null") {
|
|
197
|
+
return 1;
|
|
198
|
+
}
|
|
199
|
+
if (text3 === "undefined") {
|
|
200
|
+
return 2;
|
|
201
|
+
}
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
function compareText(a, b) {
|
|
205
|
+
if (a < b) {
|
|
206
|
+
return -1;
|
|
207
|
+
}
|
|
208
|
+
if (a > b) {
|
|
209
|
+
return 1;
|
|
210
|
+
}
|
|
211
|
+
return 0;
|
|
212
|
+
}
|
|
213
|
+
function stablePropertyName(symbol, reader) {
|
|
214
|
+
const name = symbol.getName();
|
|
215
|
+
if (!name.startsWith("__@")) {
|
|
216
|
+
return name;
|
|
217
|
+
}
|
|
218
|
+
const checker = reader.getProject().getTypeChecker().compilerObject;
|
|
219
|
+
return checker.symbolToString(symbol.compilerSymbol);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/shapes/definitions.ts
|
|
223
|
+
var current = null;
|
|
224
|
+
var definitionsInProgress = () => current;
|
|
225
|
+
function createDefinitionTable() {
|
|
226
|
+
const shapes = /* @__PURE__ */ new Map();
|
|
227
|
+
const deferred = [];
|
|
228
|
+
let settling = false;
|
|
229
|
+
return {
|
|
230
|
+
has: (key) => shapes.has(key),
|
|
231
|
+
reserve: (key) => {
|
|
232
|
+
shapes.set(key, null);
|
|
233
|
+
},
|
|
234
|
+
define: (key, shape) => {
|
|
235
|
+
shapes.set(key, shape);
|
|
236
|
+
},
|
|
237
|
+
defer: (key, expand) => {
|
|
238
|
+
deferred.push({ key, expand });
|
|
239
|
+
},
|
|
240
|
+
settle: () => {
|
|
241
|
+
if (settling) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
settling = true;
|
|
245
|
+
try {
|
|
246
|
+
for (let next = deferred.shift(); next; next = deferred.shift()) {
|
|
247
|
+
shapes.set(next.key, next.expand());
|
|
248
|
+
}
|
|
249
|
+
} finally {
|
|
250
|
+
settling = false;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
// Sorted because the walk meets types in the checker's union order,
|
|
254
|
+
// which changes between runs.
|
|
255
|
+
collected: () => {
|
|
256
|
+
const out = {};
|
|
257
|
+
let any = false;
|
|
258
|
+
const keys = [...shapes.keys()].sort(compareText);
|
|
259
|
+
for (const key of keys) {
|
|
260
|
+
const shape = shapes.get(key) ?? null;
|
|
261
|
+
if (shape !== null) {
|
|
262
|
+
out[key] = shape;
|
|
263
|
+
any = true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return any ? out : null;
|
|
267
|
+
},
|
|
268
|
+
shapeOf: (key) => shapes.get(key)
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
function withDefinitionsNoted(read2) {
|
|
272
|
+
const table = current;
|
|
273
|
+
if (table === null) {
|
|
274
|
+
return { value: read2(), noted: [] };
|
|
275
|
+
}
|
|
276
|
+
const keys = /* @__PURE__ */ new Set();
|
|
277
|
+
current = {
|
|
278
|
+
has: (key) => {
|
|
279
|
+
keys.add(key);
|
|
280
|
+
return table.has(key);
|
|
281
|
+
},
|
|
282
|
+
reserve: (key) => {
|
|
283
|
+
keys.add(key);
|
|
284
|
+
table.reserve(key);
|
|
285
|
+
},
|
|
286
|
+
define: (key, shape) => {
|
|
287
|
+
keys.add(key);
|
|
288
|
+
table.define(key, shape);
|
|
289
|
+
},
|
|
290
|
+
defer: (key, expand) => {
|
|
291
|
+
keys.add(key);
|
|
292
|
+
table.defer(key, expand);
|
|
293
|
+
},
|
|
294
|
+
settle: () => table.settle(),
|
|
295
|
+
collected: () => table.collected(),
|
|
296
|
+
shapeOf: (key) => table.shapeOf(key)
|
|
297
|
+
};
|
|
298
|
+
let value;
|
|
299
|
+
try {
|
|
300
|
+
value = read2();
|
|
301
|
+
} finally {
|
|
302
|
+
current = table;
|
|
303
|
+
}
|
|
304
|
+
const noted = [];
|
|
305
|
+
for (const key of keys) {
|
|
306
|
+
const shape = table.shapeOf(key);
|
|
307
|
+
if (shape === null || shape === void 0) {
|
|
308
|
+
return { value, noted: null };
|
|
309
|
+
}
|
|
310
|
+
noted.push([key, shape]);
|
|
311
|
+
}
|
|
312
|
+
return { value, noted };
|
|
313
|
+
}
|
|
314
|
+
function writeNotedDefinitions(noted) {
|
|
315
|
+
const table = current;
|
|
316
|
+
if (table === null) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
for (const [key, shape] of noted) {
|
|
320
|
+
if (!table.has(key)) {
|
|
321
|
+
table.define(key, structuredClone(shape));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function withDefinitions(read2) {
|
|
326
|
+
const table = createDefinitionTable();
|
|
327
|
+
const outer = current;
|
|
328
|
+
current = table;
|
|
329
|
+
try {
|
|
330
|
+
return { value: read2(), definitions: table.collected() };
|
|
331
|
+
} finally {
|
|
332
|
+
current = outer;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/bodyWalks.ts
|
|
337
|
+
var keptByBody = /* @__PURE__ */ new WeakMap();
|
|
338
|
+
var talliesByRecognizer = /* @__PURE__ */ new WeakMap();
|
|
339
|
+
var ids = /* @__PURE__ */ new WeakMap();
|
|
340
|
+
var nextId = 1;
|
|
341
|
+
function noteRecognizerTally(recognizer, tally) {
|
|
342
|
+
talliesByRecognizer.set(recognizer, tally);
|
|
343
|
+
}
|
|
344
|
+
function walkBodyOnce(body, inputs, walk) {
|
|
345
|
+
const key = keyOf(inputs);
|
|
346
|
+
const facts = inputs.resolution?.sourceFactCount() ?? -1;
|
|
347
|
+
const kept = keptByBody.get(body)?.find((one) => one.key === key && one.facts === facts);
|
|
348
|
+
if (kept !== void 0) {
|
|
349
|
+
return replay(kept);
|
|
350
|
+
}
|
|
351
|
+
const before = new Map(
|
|
352
|
+
[...talliesOf(inputs)].map((tally) => [tally, tally.effectsRecognized])
|
|
353
|
+
);
|
|
354
|
+
const read2 = withFilesNoted(() => withDefinitionsNoted(walk));
|
|
355
|
+
const { value, noted } = read2.value;
|
|
356
|
+
const factsAfter = inputs.resolution?.sourceFactCount() ?? -1;
|
|
357
|
+
if (noted === null || factsAfter !== facts) {
|
|
358
|
+
return value;
|
|
359
|
+
}
|
|
360
|
+
const effectsByTally = /* @__PURE__ */ new Map();
|
|
361
|
+
for (const [tally, count] of before) {
|
|
362
|
+
effectsByTally.set(tally, tally.effectsRecognized - count);
|
|
363
|
+
}
|
|
364
|
+
const entry = {
|
|
365
|
+
key,
|
|
366
|
+
facts,
|
|
367
|
+
walk: copyWalk(value),
|
|
368
|
+
definitions: noted.map(([name, shape]) => [name, structuredClone(shape)]),
|
|
369
|
+
files: read2.files,
|
|
370
|
+
effectsByTally
|
|
371
|
+
};
|
|
372
|
+
const forBody = keptByBody.get(body);
|
|
373
|
+
if (forBody === void 0) {
|
|
374
|
+
keptByBody.set(body, [entry]);
|
|
375
|
+
} else {
|
|
376
|
+
forBody.push(entry);
|
|
377
|
+
}
|
|
378
|
+
return value;
|
|
379
|
+
}
|
|
380
|
+
function replay(kept) {
|
|
381
|
+
writeNotedDefinitions(kept.definitions);
|
|
382
|
+
for (const filePath of kept.files) {
|
|
383
|
+
recordFileDependency(filePath);
|
|
384
|
+
}
|
|
385
|
+
for (const [tally, count] of kept.effectsByTally) {
|
|
386
|
+
tally.effectsRecognized += count;
|
|
387
|
+
}
|
|
388
|
+
return copyWalk(kept.walk);
|
|
389
|
+
}
|
|
390
|
+
function keyOf(inputs) {
|
|
391
|
+
const barrierIds = [...inputs.barriers].map(idOf).sort((a, b) => a - b);
|
|
392
|
+
return [
|
|
393
|
+
inputs.terminalPatterns.map(idOf).join(","),
|
|
394
|
+
idOf(inputs.invocationRecognizers),
|
|
395
|
+
idOf(inputs.accessRecognizers),
|
|
396
|
+
barrierIds.join(","),
|
|
397
|
+
inputs.resolution === void 0 ? 0 : idOf(inputs.resolution),
|
|
398
|
+
inputs.callbacks.map((present) => present ? 1 : 0).join(""),
|
|
399
|
+
// A walk with no table to write named types into notes none, so it
|
|
400
|
+
// cannot stand in for one that has a table.
|
|
401
|
+
definitionsInProgress() === null ? 0 : 1
|
|
402
|
+
].join("|");
|
|
403
|
+
}
|
|
404
|
+
function idOf(value) {
|
|
405
|
+
const known = ids.get(value);
|
|
406
|
+
if (known !== void 0) {
|
|
407
|
+
return known;
|
|
408
|
+
}
|
|
409
|
+
const id = nextId++;
|
|
410
|
+
ids.set(value, id);
|
|
411
|
+
return id;
|
|
412
|
+
}
|
|
413
|
+
function talliesOf(inputs) {
|
|
414
|
+
const tallies = /* @__PURE__ */ new Set();
|
|
415
|
+
for (const recognizer of [
|
|
416
|
+
...inputs.invocationRecognizers,
|
|
417
|
+
...inputs.accessRecognizers
|
|
418
|
+
]) {
|
|
419
|
+
const tally = talliesByRecognizer.get(recognizer);
|
|
420
|
+
if (tally !== void 0) {
|
|
421
|
+
tallies.add(tally);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return tallies;
|
|
425
|
+
}
|
|
426
|
+
function copyWalk(walk) {
|
|
427
|
+
return {
|
|
428
|
+
terminals: walk.terminals.map((found) => ({
|
|
429
|
+
...found,
|
|
430
|
+
terminal: structuredClone(found.terminal),
|
|
431
|
+
...found.whenAlso === void 0 ? {} : { whenAlso: copyCondition(found.whenAlso) }
|
|
432
|
+
})),
|
|
433
|
+
invocations: walk.invocations.map((site) => ({
|
|
434
|
+
...site,
|
|
435
|
+
effect: structuredClone(site.effect)
|
|
436
|
+
})),
|
|
437
|
+
recognized: walk.recognized.map((site) => ({
|
|
438
|
+
...site,
|
|
439
|
+
effect: structuredClone(site.effect),
|
|
440
|
+
preconditions: site.preconditions.map(copyCondition),
|
|
441
|
+
...site.slots === void 0 ? {} : { slots: site.slots.map((slot) => ({ ...slot })) }
|
|
442
|
+
}))
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function copyCondition(condition) {
|
|
446
|
+
return structuredClone(condition);
|
|
447
|
+
}
|
|
448
|
+
|
|
46
449
|
// src/conditions.ts
|
|
47
450
|
import {
|
|
48
451
|
Node as Node46
|
|
@@ -145,11 +548,11 @@ import { normalizeCalleeText } from "@suss/behavioral-ir";
|
|
|
145
548
|
|
|
146
549
|
// src/facts/store.ts
|
|
147
550
|
import { Node as Node9 } from "ts-morph";
|
|
148
|
-
import { isTestFile } from "@suss/behavioral-ir";
|
|
149
551
|
import {
|
|
150
552
|
clearRelations,
|
|
151
553
|
Database as Database2,
|
|
152
554
|
evaluate as evaluate2,
|
|
555
|
+
noteReads,
|
|
153
556
|
proofOf,
|
|
154
557
|
tupleKey,
|
|
155
558
|
tupleKeyParts,
|
|
@@ -312,7 +715,7 @@ function createPerFileCache() {
|
|
|
312
715
|
|
|
313
716
|
// src/walk/rawDescent.ts
|
|
314
717
|
import {
|
|
315
|
-
ts
|
|
718
|
+
ts as ts2
|
|
316
719
|
} from "ts-morph";
|
|
317
720
|
function statementsOfKind(file, kind) {
|
|
318
721
|
const found = [];
|
|
@@ -334,10 +737,10 @@ function forEachDescendantWhere(root, accepts, visit, skips = runsNothing) {
|
|
|
334
737
|
if (accepts(raw) && visit(wrapperOf(root, raw)) === true) {
|
|
335
738
|
return void 0;
|
|
336
739
|
}
|
|
337
|
-
|
|
740
|
+
ts2.forEachChild(raw, walk);
|
|
338
741
|
return void 0;
|
|
339
742
|
};
|
|
340
|
-
|
|
743
|
+
ts2.forEachChild(root.compilerNode, walk);
|
|
341
744
|
}
|
|
342
745
|
function runsNothing(raw) {
|
|
343
746
|
return isTypeOnlySyntax(raw) || isAmbient(raw);
|
|
@@ -346,18 +749,18 @@ function skipsNothing() {
|
|
|
346
749
|
return false;
|
|
347
750
|
}
|
|
348
751
|
function isTypeOnlySyntax(raw) {
|
|
349
|
-
return raw.kind >=
|
|
752
|
+
return raw.kind >= ts2.SyntaxKind.FirstTypeNode && raw.kind <= ts2.SyntaxKind.LastTypeNode || TYPE_DECLARATIONS.has(raw.kind);
|
|
350
753
|
}
|
|
351
754
|
var TYPE_DECLARATIONS = /* @__PURE__ */ new Set([
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
755
|
+
ts2.SyntaxKind.TypeAliasDeclaration,
|
|
756
|
+
ts2.SyntaxKind.InterfaceDeclaration,
|
|
757
|
+
ts2.SyntaxKind.TypeParameter
|
|
355
758
|
]);
|
|
356
759
|
function isAmbient(raw) {
|
|
357
|
-
if (!
|
|
760
|
+
if (!ts2.canHaveModifiers(raw)) {
|
|
358
761
|
return false;
|
|
359
762
|
}
|
|
360
|
-
return
|
|
763
|
+
return ts2.getModifiers(raw)?.some((modifier) => modifier.kind === ts2.SyntaxKind.DeclareKeyword) ?? false;
|
|
361
764
|
}
|
|
362
765
|
function wrapperOf(anchor, raw) {
|
|
363
766
|
return anchor._getNodeFromCompilerNode(
|
|
@@ -483,31 +886,16 @@ function indexFunctions(sf) {
|
|
|
483
886
|
},
|
|
484
887
|
isTypeOnlySyntax
|
|
485
888
|
);
|
|
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);
|
|
889
|
+
return index;
|
|
505
890
|
}
|
|
506
|
-
|
|
507
|
-
|
|
891
|
+
|
|
892
|
+
// src/testCode.ts
|
|
893
|
+
import { isTestFile } from "@suss/behavioral-ir";
|
|
894
|
+
function inTestFile(node) {
|
|
895
|
+
return isTestFile(node.getSourceFile().getFilePath());
|
|
508
896
|
}
|
|
509
|
-
function
|
|
510
|
-
|
|
897
|
+
function testCallingProduction(call, callee) {
|
|
898
|
+
return inTestFile(call) && !inTestFile(callee);
|
|
511
899
|
}
|
|
512
900
|
|
|
513
901
|
// src/facts/containerWrites.ts
|
|
@@ -519,7 +907,7 @@ import {
|
|
|
519
907
|
ModuleDeclarationKind,
|
|
520
908
|
Node as Node6,
|
|
521
909
|
SyntaxKind as SyntaxKind6,
|
|
522
|
-
ts as
|
|
910
|
+
ts as ts5
|
|
523
911
|
} from "ts-morph";
|
|
524
912
|
import {
|
|
525
913
|
addEntryRows,
|
|
@@ -541,7 +929,7 @@ import { Node as Node3, SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
|
541
929
|
// src/bootstrap/lazyProjectInit.ts
|
|
542
930
|
import fs2 from "fs/promises";
|
|
543
931
|
import path3 from "path";
|
|
544
|
-
import { ts as
|
|
932
|
+
import { ts as ts3 } from "ts-morph";
|
|
545
933
|
|
|
546
934
|
// src/facts/generatedModules.ts
|
|
547
935
|
import fs from "fs";
|
|
@@ -1173,7 +1561,7 @@ function resolutionCacheFor(project, options) {
|
|
|
1173
1561
|
if (existing !== void 0) {
|
|
1174
1562
|
return existing;
|
|
1175
1563
|
}
|
|
1176
|
-
const fresh =
|
|
1564
|
+
const fresh = ts3.createModuleResolutionCache(
|
|
1177
1565
|
project.getFileSystem().getCurrentDirectory(),
|
|
1178
1566
|
(name) => name,
|
|
1179
1567
|
options
|
|
@@ -1207,11 +1595,11 @@ function readSpecifierPaths(project, filePath, options, host) {
|
|
|
1207
1595
|
if (text3 === null) {
|
|
1208
1596
|
return [];
|
|
1209
1597
|
}
|
|
1210
|
-
const scanned =
|
|
1598
|
+
const scanned = ts3.preProcessFile(text3, true, true);
|
|
1211
1599
|
const cache = resolutionCacheFor(project, options);
|
|
1212
1600
|
const paths = [];
|
|
1213
1601
|
for (const imported of scanned.importedFiles) {
|
|
1214
|
-
const resolved =
|
|
1602
|
+
const resolved = ts3.resolveModuleName(
|
|
1215
1603
|
imported.fileName,
|
|
1216
1604
|
filePath,
|
|
1217
1605
|
options,
|
|
@@ -1237,13 +1625,13 @@ function readFileText(project, filePath) {
|
|
|
1237
1625
|
}
|
|
1238
1626
|
function parseTsconfig(tsConfigFilePath, seen = /* @__PURE__ */ new Set()) {
|
|
1239
1627
|
seen.add(tsConfigFilePath);
|
|
1240
|
-
const configFile =
|
|
1628
|
+
const configFile = ts3.readConfigFile(tsConfigFilePath, ts3.sys.readFile);
|
|
1241
1629
|
if (configFile.error !== void 0) {
|
|
1242
1630
|
return { fileNames: [], options: {} };
|
|
1243
1631
|
}
|
|
1244
|
-
const parsed =
|
|
1632
|
+
const parsed = ts3.parseJsonConfigFileContent(
|
|
1245
1633
|
configFile.config,
|
|
1246
|
-
|
|
1634
|
+
ts3.sys,
|
|
1247
1635
|
path3.dirname(tsConfigFilePath),
|
|
1248
1636
|
/*existingOptions*/
|
|
1249
1637
|
void 0,
|
|
@@ -1252,7 +1640,7 @@ function parseTsconfig(tsConfigFilePath, seen = /* @__PURE__ */ new Set()) {
|
|
|
1252
1640
|
if (parsed.fileNames.length > 0) {
|
|
1253
1641
|
return { fileNames: parsed.fileNames, options: parsed.options };
|
|
1254
1642
|
}
|
|
1255
|
-
const referenced = (parsed.projectReferences ?? []).map((reference) =>
|
|
1643
|
+
const referenced = (parsed.projectReferences ?? []).map((reference) => ts3.resolveProjectReferencePath(reference)).filter((referencePath) => !seen.has(referencePath)).map((referencePath) => parseTsconfig(referencePath, seen));
|
|
1256
1644
|
const fileNames = [
|
|
1257
1645
|
...new Set(referenced.flatMap((reference) => reference.fileNames))
|
|
1258
1646
|
];
|
|
@@ -1326,17 +1714,17 @@ function addImportersOfMatches(fileImports, matched, options) {
|
|
|
1326
1714
|
}
|
|
1327
1715
|
function internalSpecifierResolver(files, options) {
|
|
1328
1716
|
const fileSet = new Set(files);
|
|
1329
|
-
const cache =
|
|
1330
|
-
|
|
1717
|
+
const cache = ts3.createModuleResolutionCache(
|
|
1718
|
+
ts3.sys.getCurrentDirectory(),
|
|
1331
1719
|
(name) => name,
|
|
1332
1720
|
options
|
|
1333
1721
|
);
|
|
1334
1722
|
return (fromFile, spec) => {
|
|
1335
|
-
const resolved =
|
|
1723
|
+
const resolved = ts3.resolveModuleName(
|
|
1336
1724
|
spec,
|
|
1337
1725
|
fromFile,
|
|
1338
1726
|
options,
|
|
1339
|
-
|
|
1727
|
+
ts3.sys,
|
|
1340
1728
|
cache
|
|
1341
1729
|
).resolvedModule?.resolvedFileName;
|
|
1342
1730
|
if (resolved === void 0) {
|
|
@@ -1345,7 +1733,7 @@ function internalSpecifierResolver(files, options) {
|
|
|
1345
1733
|
if (fileSet.has(resolved)) {
|
|
1346
1734
|
return resolved;
|
|
1347
1735
|
}
|
|
1348
|
-
const real =
|
|
1736
|
+
const real = ts3.sys.realpath?.(resolved) ?? resolved;
|
|
1349
1737
|
return fileSet.has(real) ? real : null;
|
|
1350
1738
|
};
|
|
1351
1739
|
}
|
|
@@ -1380,7 +1768,7 @@ async function readImportsConcurrently(paths, marks) {
|
|
|
1380
1768
|
const p = paths[i];
|
|
1381
1769
|
try {
|
|
1382
1770
|
const text3 = await fs2.readFile(p, "utf-8");
|
|
1383
|
-
const pre =
|
|
1771
|
+
const pre = ts3.preProcessFile(text3, true, false);
|
|
1384
1772
|
results[i] = {
|
|
1385
1773
|
path: p,
|
|
1386
1774
|
importedModules: pre.importedFiles.map((f) => f.fileName),
|
|
@@ -1616,7 +2004,7 @@ function keyNameOf(name) {
|
|
|
1616
2004
|
}
|
|
1617
2005
|
|
|
1618
2006
|
// src/facts/assignments.ts
|
|
1619
|
-
import { Node as Node5, SyntaxKind as SyntaxKind5, ts as
|
|
2007
|
+
import { Node as Node5, SyntaxKind as SyntaxKind5, ts as ts4, VariableDeclarationKind } from "ts-morph";
|
|
1620
2008
|
import { valueLeftByWrites } from "@suss/resolution";
|
|
1621
2009
|
var byFile = createPerFileCache();
|
|
1622
2010
|
var byDeclaration = /* @__PURE__ */ new WeakMap();
|
|
@@ -1814,11 +2202,11 @@ function assignmentsInFile(sourceFile) {
|
|
|
1814
2202
|
return found;
|
|
1815
2203
|
}
|
|
1816
2204
|
function mayWrite(raw) {
|
|
1817
|
-
if (
|
|
1818
|
-
return isAssignmentOperator(raw.operatorToken.kind) && (
|
|
2205
|
+
if (ts4.isBinaryExpression(raw)) {
|
|
2206
|
+
return isAssignmentOperator(raw.operatorToken.kind) && (ts4.isIdentifier(raw.left) || ts4.isPropertyAccessExpression(raw.left));
|
|
1819
2207
|
}
|
|
1820
|
-
if (
|
|
1821
|
-
return (raw.operator === SyntaxKind5.PlusPlusToken || raw.operator === SyntaxKind5.MinusMinusToken) &&
|
|
2208
|
+
if (ts4.isPrefixUnaryExpression(raw) || ts4.isPostfixUnaryExpression(raw)) {
|
|
2209
|
+
return (raw.operator === SyntaxKind5.PlusPlusToken || raw.operator === SyntaxKind5.MinusMinusToken) && ts4.isIdentifier(raw.operand);
|
|
1822
2210
|
}
|
|
1823
2211
|
return false;
|
|
1824
2212
|
}
|
|
@@ -1879,7 +2267,7 @@ function isReadBefore(declaration, position) {
|
|
|
1879
2267
|
const sourceFile = declaration.getSourceFile();
|
|
1880
2268
|
const file = sourceFile.compilerNode;
|
|
1881
2269
|
const readsHere = (raw) => {
|
|
1882
|
-
if (!
|
|
2270
|
+
if (!ts4.isIdentifier(raw) || raw.getText(file) !== name) {
|
|
1883
2271
|
return false;
|
|
1884
2272
|
}
|
|
1885
2273
|
const node = wrapperOf(sourceFile, raw);
|
|
@@ -1899,9 +2287,9 @@ function someBefore(root, position, test) {
|
|
|
1899
2287
|
if (test(raw)) {
|
|
1900
2288
|
return true;
|
|
1901
2289
|
}
|
|
1902
|
-
return
|
|
2290
|
+
return ts4.forEachChild(raw, visit);
|
|
1903
2291
|
};
|
|
1904
|
-
return
|
|
2292
|
+
return ts4.forEachChild(root, visit) === true;
|
|
1905
2293
|
}
|
|
1906
2294
|
var OWN_BODY_KINDS = /* @__PURE__ */ new Set([
|
|
1907
2295
|
SyntaxKind5.FunctionDeclaration,
|
|
@@ -2003,7 +2391,7 @@ function isPropertyReadBefore(statements, name, property, position) {
|
|
|
2003
2391
|
return someBefore(
|
|
2004
2392
|
statements.compilerNode,
|
|
2005
2393
|
position,
|
|
2006
|
-
(raw) =>
|
|
2394
|
+
(raw) => ts4.isPropertyAccessExpression(raw) && raw.name.getText(file) === property && raw.expression.getText(file) === name && !isWriteTarget(wrapperOf(statements, raw))
|
|
2007
2395
|
);
|
|
2008
2396
|
}
|
|
2009
2397
|
|
|
@@ -2075,7 +2463,7 @@ function moduleKeyOf(declaration) {
|
|
|
2075
2463
|
}
|
|
2076
2464
|
function compilerResolvedPathOf(declaration, specifier) {
|
|
2077
2465
|
const project = declaration.getProject();
|
|
2078
|
-
const result =
|
|
2466
|
+
const result = ts5.resolveModuleName(
|
|
2079
2467
|
specifier,
|
|
2080
2468
|
declaration.getSourceFile().getFilePath(),
|
|
2081
2469
|
project.getCompilerOptions(),
|
|
@@ -2386,7 +2774,7 @@ function spellingsHandedOn(paths, sourceFile) {
|
|
|
2386
2774
|
const found = [];
|
|
2387
2775
|
forEachDescendantWhere(
|
|
2388
2776
|
sourceFile,
|
|
2389
|
-
(raw) =>
|
|
2777
|
+
(raw) => ts5.isPropertyAccessExpression(raw) && paths.includes(compilerDottedPathOf(raw, file) ?? ""),
|
|
2390
2778
|
(node) => {
|
|
2391
2779
|
if (flowsOnward(node)) {
|
|
2392
2780
|
found.push(node);
|
|
@@ -2397,14 +2785,14 @@ function spellingsHandedOn(paths, sourceFile) {
|
|
|
2397
2785
|
return found;
|
|
2398
2786
|
}
|
|
2399
2787
|
function compilerDottedPathOf(raw, file) {
|
|
2400
|
-
if (
|
|
2788
|
+
if (ts5.isIdentifier(raw)) {
|
|
2401
2789
|
return raw.getText(file);
|
|
2402
2790
|
}
|
|
2403
|
-
if (
|
|
2404
|
-
const keyword =
|
|
2791
|
+
if (ts5.isMetaProperty(raw)) {
|
|
2792
|
+
const keyword = ts5.tokenToString(raw.keywordToken);
|
|
2405
2793
|
return `${keyword}.${raw.name.getText(file)}`;
|
|
2406
2794
|
}
|
|
2407
|
-
if (!
|
|
2795
|
+
if (!ts5.isPropertyAccessExpression(raw)) {
|
|
2408
2796
|
return null;
|
|
2409
2797
|
}
|
|
2410
2798
|
const object = compilerDottedPathOf(raw.expression, file);
|
|
@@ -2425,7 +2813,7 @@ function dottedPathOf(expression) {
|
|
|
2425
2813
|
return expression.getText();
|
|
2426
2814
|
}
|
|
2427
2815
|
if (Node6.isMetaProperty(expression)) {
|
|
2428
|
-
const keyword =
|
|
2816
|
+
const keyword = ts5.tokenToString(expression.getKeywordToken());
|
|
2429
2817
|
return `${keyword}.${expression.getName()}`;
|
|
2430
2818
|
}
|
|
2431
2819
|
if (!Node6.isPropertyAccessExpression(expression)) {
|
|
@@ -3767,7 +4155,12 @@ var NOT_BASE_FACTS = /* @__PURE__ */ new Set([
|
|
|
3767
4155
|
...RESOLUTION_PROGRAM.rules.map((r) => r.head.relation),
|
|
3768
4156
|
...ASKING_RELATIONS
|
|
3769
4157
|
]);
|
|
4158
|
+
var DERIVED_RELATIONS = /* @__PURE__ */ new Set([
|
|
4159
|
+
...NOT_BASE_FACTS,
|
|
4160
|
+
...resolutionUnderProgram().rules.map((r) => r.head.relation)
|
|
4161
|
+
]);
|
|
3770
4162
|
var QUERY_FACTS = queryFacts(RESOLUTION_PROGRAM);
|
|
4163
|
+
var DERIVED_AGAIN = new Set(QUERY_FACTS);
|
|
3771
4164
|
var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
|
|
3772
4165
|
(one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
|
|
3773
4166
|
).map((one) => one.demand);
|
|
@@ -3803,6 +4196,8 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
3803
4196
|
constructionSites = /* @__PURE__ */ new Map();
|
|
3804
4197
|
/** What each local's reads do with it, by its declaration. A local's function is walked whole, so an answer stays true. */
|
|
3805
4198
|
localUses = /* @__PURE__ */ new Map();
|
|
4199
|
+
/** See `remembered`. */
|
|
4200
|
+
answers = /* @__PURE__ */ new Map();
|
|
3806
4201
|
/** Files the most recent query read, for the memo to keep. */
|
|
3807
4202
|
lastQueryWalked = [];
|
|
3808
4203
|
/** See `environmentSiteFiles`; null until the first env question. */
|
|
@@ -3854,12 +4249,18 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
3854
4249
|
*/
|
|
3855
4250
|
resolveCallableSources(value, alsoFrom) {
|
|
3856
4251
|
const target = factKeyOf(value);
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
4252
|
+
const key = `sources|${nodeId(target)}|${alsoFrom?.getFilePath() ?? ""}`;
|
|
4253
|
+
return [
|
|
4254
|
+
...this.remembered(
|
|
4255
|
+
key,
|
|
4256
|
+
() => this.askAbout(
|
|
4257
|
+
target,
|
|
4258
|
+
"wanted",
|
|
4259
|
+
() => this.lookupSources(target),
|
|
4260
|
+
alsoFrom
|
|
4261
|
+
)
|
|
4262
|
+
)
|
|
4263
|
+
];
|
|
3863
4264
|
}
|
|
3864
4265
|
/**
|
|
3865
4266
|
* `resolveCallable` for several values, asked as one question. A file
|
|
@@ -3921,7 +4322,65 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
3921
4322
|
}
|
|
3922
4323
|
resolveObject(value) {
|
|
3923
4324
|
const target = factKeyOf(value);
|
|
3924
|
-
return this.
|
|
4325
|
+
return this.remembered(
|
|
4326
|
+
`object|${nodeId(target)}`,
|
|
4327
|
+
() => this.askAbout(target, "wanted", () => this.lookupObject(target))
|
|
4328
|
+
);
|
|
4329
|
+
}
|
|
4330
|
+
/**
|
|
4331
|
+
* A question asked again, when no fact its derivation looked up has
|
|
4332
|
+
* arrived since, reads the same files and derives the same answer, so
|
|
4333
|
+
* the store gives back the one it found before. The files that answer
|
|
4334
|
+
* read still count as read.
|
|
4335
|
+
*
|
|
4336
|
+
* Noting the lookups costs the question a share of its time, and most
|
|
4337
|
+
* questions are asked once, so a question notes them only once it has
|
|
4338
|
+
* had to be asked again. Until then, as without demand, only an
|
|
4339
|
+
* unchanged fact count says the answer is the same. Without demand the
|
|
4340
|
+
* rules keep every conclusion between questions, so a question's own
|
|
4341
|
+
* lookups miss what earlier questions derived for it. A question that
|
|
4342
|
+
* started on another question's leftovers gets the count too.
|
|
4343
|
+
*/
|
|
4344
|
+
remembered(key, ask) {
|
|
4345
|
+
const known = this.answers.get(key);
|
|
4346
|
+
if (known !== void 0 && this.stillDerives(known.check)) {
|
|
4347
|
+
for (const walkedPath of known.walked) {
|
|
4348
|
+
recordFileDependency(walkedPath);
|
|
4349
|
+
}
|
|
4350
|
+
return known.answer;
|
|
4351
|
+
}
|
|
4352
|
+
const { value, reads } = known === void 0 || QUERY_FACTS.length === 0 ? { value: ask(), reads: null } : noteReads(this.db, DERIVED_AGAIN, ask);
|
|
4353
|
+
this.answers.set(key, {
|
|
4354
|
+
answer: value,
|
|
4355
|
+
walked: [...this.lastQueryWalked],
|
|
4356
|
+
check: reads ?? this.sourceFactCount()
|
|
4357
|
+
});
|
|
4358
|
+
return value;
|
|
4359
|
+
}
|
|
4360
|
+
/**
|
|
4361
|
+
* Facts added since the last derivation have not reached the relations
|
|
4362
|
+
* the rules keep between questions, so the reads cannot say yet what
|
|
4363
|
+
* those facts change.
|
|
4364
|
+
*/
|
|
4365
|
+
stillDerives(check) {
|
|
4366
|
+
if (typeof check === "number") {
|
|
4367
|
+
return check === this.sourceFactCount();
|
|
4368
|
+
}
|
|
4369
|
+
return !this.stale && check.unchangedIn(this.db);
|
|
4370
|
+
}
|
|
4371
|
+
/**
|
|
4372
|
+
* How many facts the store has read from source. They are only ever
|
|
4373
|
+
* added, so work that asked the store questions and found this number
|
|
4374
|
+
* unchanged afterwards would get the same answers asking again.
|
|
4375
|
+
*/
|
|
4376
|
+
sourceFactCount() {
|
|
4377
|
+
let count = 0;
|
|
4378
|
+
for (const relation of this.db.relationNames()) {
|
|
4379
|
+
if (!DERIVED_RELATIONS.has(relation)) {
|
|
4380
|
+
count += this.db.size(relation);
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
return count;
|
|
3925
4384
|
}
|
|
3926
4385
|
/**
|
|
3927
4386
|
* The function a call returns: `app.use(requireCaller(config))`
|
|
@@ -4021,7 +4480,7 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
4021
4480
|
writtenAnswers(values, wanted) {
|
|
4022
4481
|
const found = /* @__PURE__ */ new Map();
|
|
4023
4482
|
const asked = /* @__PURE__ */ new Map();
|
|
4024
|
-
const
|
|
4483
|
+
const keyOf2 = /* @__PURE__ */ new Map();
|
|
4025
4484
|
for (const value of values) {
|
|
4026
4485
|
const target = factKeyOf(value);
|
|
4027
4486
|
const key = nodeId(this.sharedDeclarationFor(target));
|
|
@@ -4036,7 +4495,7 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
4036
4495
|
if (!asked.has(key)) {
|
|
4037
4496
|
asked.set(key, target);
|
|
4038
4497
|
}
|
|
4039
|
-
|
|
4498
|
+
keyOf2.set(value, key);
|
|
4040
4499
|
}
|
|
4041
4500
|
if (asked.size === 0) {
|
|
4042
4501
|
return found;
|
|
@@ -4051,7 +4510,7 @@ var ResolutionStore = class _ResolutionStore {
|
|
|
4051
4510
|
});
|
|
4052
4511
|
}
|
|
4053
4512
|
});
|
|
4054
|
-
for (const [value, key] of
|
|
4513
|
+
for (const [value, key] of keyOf2) {
|
|
4055
4514
|
found.set(value, this.writtenValues.get(key)?.[wanted] ?? null);
|
|
4056
4515
|
}
|
|
4057
4516
|
return found;
|
|
@@ -5334,9 +5793,6 @@ function namesPackage2(moduleKey, packages) {
|
|
|
5334
5793
|
packages
|
|
5335
5794
|
);
|
|
5336
5795
|
}
|
|
5337
|
-
function inTestFile(node) {
|
|
5338
|
-
return isTestFile(node.getSourceFile().getFilePath());
|
|
5339
|
-
}
|
|
5340
5796
|
function declarationOf(value) {
|
|
5341
5797
|
const nameNode = Node9.isPropertyAccessExpression(value) ? value.getNameNode() : value;
|
|
5342
5798
|
return nameNode.getSymbol()?.getDeclarations()[0] ?? value;
|
|
@@ -6433,7 +6889,7 @@ function settledChannel(argument, resolution) {
|
|
|
6433
6889
|
}
|
|
6434
6890
|
|
|
6435
6891
|
// src/discovery/importedCalls.ts
|
|
6436
|
-
import { Node as Node14, ts as
|
|
6892
|
+
import { Node as Node14, ts as ts6 } from "ts-morph";
|
|
6437
6893
|
function callsResolvingTo(sourceFile, resolution, spec) {
|
|
6438
6894
|
return [
|
|
6439
6895
|
...callsByOriginName(
|
|
@@ -6451,7 +6907,8 @@ function importedCallOrigins(sourceFile, resolution, module) {
|
|
|
6451
6907
|
const candidates = [];
|
|
6452
6908
|
forEachDescendantWhere(sourceFile, callsANamedCallee, (node) => {
|
|
6453
6909
|
const call = node;
|
|
6454
|
-
|
|
6910
|
+
const callee = call.getExpression();
|
|
6911
|
+
if (!declaredLocally(callee) && !importedFromAnotherPackage(callee, module)) {
|
|
6455
6912
|
candidates.push(call);
|
|
6456
6913
|
}
|
|
6457
6914
|
return false;
|
|
@@ -6479,7 +6936,27 @@ function callsNamed(found, names) {
|
|
|
6479
6936
|
return matched;
|
|
6480
6937
|
}
|
|
6481
6938
|
function callsANamedCallee(raw) {
|
|
6482
|
-
return (
|
|
6939
|
+
return (ts6.isCallExpression(raw) || ts6.isNewExpression(raw)) && ts6.isIdentifier(raw.expression);
|
|
6940
|
+
}
|
|
6941
|
+
var samePackage = (specifier, module) => specifier === module || specifier.startsWith(`${module}/`) || module.startsWith(`${specifier}/`);
|
|
6942
|
+
function importOf(declaration) {
|
|
6943
|
+
if (Node14.isImportSpecifier(declaration)) {
|
|
6944
|
+
return declaration.getImportDeclaration();
|
|
6945
|
+
}
|
|
6946
|
+
const parent = Node14.isImportClause(declaration) ? declaration.getParent() : void 0;
|
|
6947
|
+
return parent !== void 0 && Node14.isImportDeclaration(parent) ? parent : void 0;
|
|
6948
|
+
}
|
|
6949
|
+
function importedFromAnotherPackage(callee, module) {
|
|
6950
|
+
const declarations = callee.getSymbol()?.getDeclarations() ?? [];
|
|
6951
|
+
return declarations.length > 0 && declarations.every((declaration) => {
|
|
6952
|
+
const from = importOf(declaration);
|
|
6953
|
+
if (from === void 0) {
|
|
6954
|
+
return false;
|
|
6955
|
+
}
|
|
6956
|
+
const resolved = from.getModuleSpecifierSourceFile();
|
|
6957
|
+
const specifier = from.getModuleSpecifierValue();
|
|
6958
|
+
return (resolved === void 0 || resolved.isInNodeModules()) && !specifier.startsWith(".") && !samePackage(specifier, module);
|
|
6959
|
+
});
|
|
6483
6960
|
}
|
|
6484
6961
|
function declaredLocally(callee) {
|
|
6485
6962
|
const declarations = callee.getSymbol()?.getDeclarations() ?? [];
|
|
@@ -8884,7 +9361,7 @@ function evaluateObjectLiteralAsJson(node) {
|
|
|
8884
9361
|
return node.getLiteralValue();
|
|
8885
9362
|
}
|
|
8886
9363
|
if (Node25.isNumericLiteral(node)) {
|
|
8887
|
-
return
|
|
9364
|
+
return node.getLiteralValue();
|
|
8888
9365
|
}
|
|
8889
9366
|
const kind = node.getText();
|
|
8890
9367
|
if (kind === "true") {
|
|
@@ -9392,6 +9869,9 @@ function expandParameter(parameter, forwardsResult, depth, expanded, context, ch
|
|
|
9392
9869
|
const units = [];
|
|
9393
9870
|
let unfollowed = 0;
|
|
9394
9871
|
for (const { call, argument } of passed) {
|
|
9872
|
+
if (testCallingProduction(call, parameter)) {
|
|
9873
|
+
continue;
|
|
9874
|
+
}
|
|
9395
9875
|
const caller = enclosingFunctionRoot(call);
|
|
9396
9876
|
if (caller === null || !Node28.isCallExpression(call)) {
|
|
9397
9877
|
unfollowed++;
|
|
@@ -11008,7 +11488,7 @@ function creationSiteBehind(parameter, resolution) {
|
|
|
11008
11488
|
}
|
|
11009
11489
|
function registrationSubjectIdsOf(sourceFile, matches, resolution) {
|
|
11010
11490
|
const seenImports = /* @__PURE__ */ new Set();
|
|
11011
|
-
const
|
|
11491
|
+
const ids2 = /* @__PURE__ */ new Set();
|
|
11012
11492
|
for (const match of matches) {
|
|
11013
11493
|
const importKey = `${match.importModule}::${match.importName}`;
|
|
11014
11494
|
if (seenImports.has(importKey)) {
|
|
@@ -11021,17 +11501,17 @@ function registrationSubjectIdsOf(sourceFile, matches, resolution) {
|
|
|
11021
11501
|
match.importName,
|
|
11022
11502
|
resolution
|
|
11023
11503
|
).values()) {
|
|
11024
|
-
|
|
11504
|
+
ids2.add(nodeId(node));
|
|
11025
11505
|
}
|
|
11026
11506
|
for (const node of unboundConstructionsOf(
|
|
11027
11507
|
sourceFile,
|
|
11028
11508
|
match.importModule,
|
|
11029
11509
|
match.importName
|
|
11030
11510
|
)) {
|
|
11031
|
-
|
|
11511
|
+
ids2.add(nodeId(node));
|
|
11032
11512
|
}
|
|
11033
11513
|
}
|
|
11034
|
-
return
|
|
11514
|
+
return ids2;
|
|
11035
11515
|
}
|
|
11036
11516
|
function unboundConstructionsOf(sourceFile, importModule, importName) {
|
|
11037
11517
|
const spellings = importedReferenceSpellings(
|
|
@@ -13085,7 +13565,7 @@ import {
|
|
|
13085
13565
|
import {
|
|
13086
13566
|
Node as Node47,
|
|
13087
13567
|
SyntaxKind as SyntaxKind20,
|
|
13088
|
-
ts as
|
|
13568
|
+
ts as ts7
|
|
13089
13569
|
} from "ts-morph";
|
|
13090
13570
|
import {
|
|
13091
13571
|
UnmodeledFlow
|
|
@@ -13109,7 +13589,7 @@ function exitKindOf(stmt, endings) {
|
|
|
13109
13589
|
if (raw.kind === SyntaxKind20.ThrowStatement) {
|
|
13110
13590
|
sawThrow = true;
|
|
13111
13591
|
}
|
|
13112
|
-
|
|
13592
|
+
ts7.forEachChild(raw, visit);
|
|
13113
13593
|
return void 0;
|
|
13114
13594
|
};
|
|
13115
13595
|
visit(root);
|
|
@@ -13222,7 +13702,7 @@ function lowerCallbacksIn(parts, ctx) {
|
|
|
13222
13702
|
if (runsNothing(raw)) {
|
|
13223
13703
|
return void 0;
|
|
13224
13704
|
}
|
|
13225
|
-
|
|
13705
|
+
ts7.forEachChild(raw, visit);
|
|
13226
13706
|
return void 0;
|
|
13227
13707
|
};
|
|
13228
13708
|
visit(root);
|
|
@@ -13599,126 +14079,6 @@ import { Node as Node51 } from "ts-morph";
|
|
|
13599
14079
|
|
|
13600
14080
|
// src/values/receiverType.ts
|
|
13601
14081
|
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
14082
|
function receiverTypesOf(node) {
|
|
13723
14083
|
const type = node.getType();
|
|
13724
14084
|
if (type.isAny()) {
|
|
@@ -15732,67 +16092,6 @@ import {
|
|
|
15732
16092
|
// src/shapes/typeShapes.ts
|
|
15733
16093
|
import { createHash } from "crypto";
|
|
15734
16094
|
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
16095
|
var MAX_DEPTH = 6;
|
|
15797
16096
|
var OPAQUE_NAMED_TYPES = /* @__PURE__ */ new Set([
|
|
15798
16097
|
"Date",
|
|
@@ -15830,16 +16129,17 @@ function overloadIsAGuess(node) {
|
|
|
15830
16129
|
if (signatures.length < 2) {
|
|
15831
16130
|
return false;
|
|
15832
16131
|
}
|
|
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) => {
|
|
16132
|
+
const untypedArgument = node.getArguments().some((argument) => {
|
|
15840
16133
|
const type = argument.getType();
|
|
15841
16134
|
return type.isAny() || type.isNever();
|
|
15842
16135
|
});
|
|
16136
|
+
if (!untypedArgument) {
|
|
16137
|
+
return false;
|
|
16138
|
+
}
|
|
16139
|
+
const returns = new Set(
|
|
16140
|
+
signatures.map((signature) => signature.getReturnType().getText(node))
|
|
16141
|
+
);
|
|
16142
|
+
return returns.size >= 2;
|
|
15843
16143
|
}
|
|
15844
16144
|
function typeToShape(type, ctx) {
|
|
15845
16145
|
if (type.isAny()) {
|
|
@@ -17018,7 +17318,7 @@ function evaluateComparison(condition, substitutions) {
|
|
|
17018
17318
|
}
|
|
17019
17319
|
function numberFor(node, substitutions) {
|
|
17020
17320
|
const resolved = Node62.isIdentifier(node) && substitutions.has(node.getText()) ? substitutions.get(node.getText()) : node;
|
|
17021
|
-
return Node62.isNumericLiteral(resolved) ?
|
|
17321
|
+
return Node62.isNumericLiteral(resolved) ? resolved.getLiteralValue() : null;
|
|
17022
17322
|
}
|
|
17023
17323
|
var helperBySymbol = createProgramMemo();
|
|
17024
17324
|
function memoizedLocalHelper(callee, resolveCallee2) {
|
|
@@ -17920,33 +18220,50 @@ var RETURNS_AND_SCOPES = /* @__PURE__ */ new Set([
|
|
|
17920
18220
|
SyntaxKind27.ReturnStatement
|
|
17921
18221
|
]);
|
|
17922
18222
|
function extractRawBranches(func, terminalPatterns, invocationRecognizers = [], accessRecognizers = [], barriers = NO_BARRIERS, resolution, originatesFrom, anchorCallsOf, resolveCallee2, collectCallAccounting = false, keepsArms, handOff) {
|
|
17923
|
-
const terminals =
|
|
18223
|
+
const { terminals, invocations, recognized } = walkBodyOnce(
|
|
17924
18224
|
func,
|
|
17925
|
-
|
|
17926
|
-
|
|
17927
|
-
resolution,
|
|
17928
|
-
originatesFrom,
|
|
17929
|
-
resolveCallee2
|
|
17930
|
-
);
|
|
17931
|
-
const invocations = extractInvocationEffects(func, barriers);
|
|
17932
|
-
const recognized = [
|
|
17933
|
-
...runInvocationRecognizers(
|
|
17934
|
-
func,
|
|
18225
|
+
{
|
|
18226
|
+
terminalPatterns,
|
|
17935
18227
|
invocationRecognizers,
|
|
17936
|
-
barriers,
|
|
17937
|
-
resolution,
|
|
17938
|
-
originatesFrom,
|
|
17939
|
-
anchorCallsOf
|
|
17940
|
-
),
|
|
17941
|
-
...runAccessRecognizers(
|
|
17942
|
-
func,
|
|
17943
18228
|
accessRecognizers,
|
|
17944
18229
|
barriers,
|
|
17945
18230
|
resolution,
|
|
17946
|
-
|
|
17947
|
-
|
|
17948
|
-
|
|
17949
|
-
|
|
18231
|
+
callbacks: [
|
|
18232
|
+
originatesFrom !== void 0,
|
|
18233
|
+
anchorCallsOf !== void 0,
|
|
18234
|
+
resolveCallee2 !== void 0
|
|
18235
|
+
]
|
|
18236
|
+
},
|
|
18237
|
+
() => ({
|
|
18238
|
+
terminals: findTerminals(
|
|
18239
|
+
func,
|
|
18240
|
+
terminalPatterns,
|
|
18241
|
+
barriers,
|
|
18242
|
+
resolution,
|
|
18243
|
+
originatesFrom,
|
|
18244
|
+
resolveCallee2
|
|
18245
|
+
),
|
|
18246
|
+
invocations: extractInvocationEffects(func, barriers),
|
|
18247
|
+
recognized: [
|
|
18248
|
+
...runInvocationRecognizers(
|
|
18249
|
+
func,
|
|
18250
|
+
invocationRecognizers,
|
|
18251
|
+
barriers,
|
|
18252
|
+
resolution,
|
|
18253
|
+
originatesFrom,
|
|
18254
|
+
anchorCallsOf
|
|
18255
|
+
),
|
|
18256
|
+
...runAccessRecognizers(
|
|
18257
|
+
func,
|
|
18258
|
+
accessRecognizers,
|
|
18259
|
+
barriers,
|
|
18260
|
+
resolution,
|
|
18261
|
+
originatesFrom,
|
|
18262
|
+
anchorCallsOf
|
|
18263
|
+
)
|
|
18264
|
+
]
|
|
18265
|
+
})
|
|
18266
|
+
);
|
|
17950
18267
|
const endings = new Set(
|
|
17951
18268
|
terminals.filter(({ terminal }) => terminal.kind === "exit").map(({ node }) => node)
|
|
17952
18269
|
);
|
|
@@ -19813,6 +20130,9 @@ function callSitesOf(func, store) {
|
|
|
19813
20130
|
if (!Node73.isCallExpression(passed.call)) {
|
|
19814
20131
|
continue;
|
|
19815
20132
|
}
|
|
20133
|
+
if (testCallingProduction(passed.call, func)) {
|
|
20134
|
+
continue;
|
|
20135
|
+
}
|
|
19816
20136
|
const key = siteKey(passed.call);
|
|
19817
20137
|
const site = byCall.get(key) ?? {
|
|
19818
20138
|
call: passed.call,
|
|
@@ -23280,13 +23600,15 @@ function resolveContractField(callSite, pack, field, resolution) {
|
|
|
23280
23600
|
return value ?? void 0;
|
|
23281
23601
|
}
|
|
23282
23602
|
function reportingTo(recognize, tally) {
|
|
23283
|
-
|
|
23603
|
+
const reporting = (node, ctx) => {
|
|
23284
23604
|
const effects = recognize(node, ctx);
|
|
23285
23605
|
if (effects !== null) {
|
|
23286
23606
|
tally.effectsRecognized += effects.length;
|
|
23287
23607
|
}
|
|
23288
23608
|
return effects;
|
|
23289
23609
|
};
|
|
23610
|
+
noteRecognizerTally(reporting, tally);
|
|
23611
|
+
return reporting;
|
|
23290
23612
|
}
|
|
23291
23613
|
function collectInvocationRecognizers(frameworks, tallies) {
|
|
23292
23614
|
const out = [];
|