@suss/adapter-typescript 0.37.0 → 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.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import path15 from "path";
3
3
  import {
4
4
  Node as Node82,
5
- Project as Project2
5
+ Project as Project2,
6
+ SyntaxKind as SyntaxKind31
6
7
  } from "ts-morph";
7
8
  import {
8
9
  BOUNDARY_ROLE,
@@ -37,21 +38,412 @@ import { force as force8, hostOf as hostOf2, literalOf as literalOf6, pathOf as
37
38
 
38
39
  // src/assembly.ts
39
40
  import {
40
- Node as Node67
41
+ Node as Node67,
42
+ SyntaxKind as SyntaxKind27
41
43
  } from "ts-morph";
42
44
  import { firesOn, runsBefore, splitAtHandOffs } from "@suss/extractor";
43
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
+
44
436
  // src/conditions.ts
45
437
  import {
46
438
  Node as Node46
47
439
  } from "ts-morph";
48
440
 
49
441
  // src/predicates.ts
50
- import { Node as Node45, SyntaxKind as SyntaxKind12 } from "ts-morph";
442
+ import { Node as Node45, SyntaxKind as SyntaxKind19 } from "ts-morph";
51
443
  import { replacePredicateRefs } from "@suss/behavioral-ir";
52
444
 
53
445
  // src/resolve/astResolve.ts
54
- import { Node as Node42, SyntaxKind as SyntaxKind11 } from "ts-morph";
446
+ import { Node as Node42, SyntaxKind as SyntaxKind18 } from "ts-morph";
55
447
 
56
448
  // src/walk/nodeKeys.ts
57
449
  import { declarationKey } from "@suss/behavioral-ir";
@@ -138,12 +530,11 @@ function passesValueThrough(node) {
138
530
  }
139
531
 
140
532
  // src/resolve/functionBehind.ts
141
- import { Node as Node41, SyntaxKind as SyntaxKind10 } from "ts-morph";
533
+ import { Node as Node41, SyntaxKind as SyntaxKind17 } from "ts-morph";
142
534
  import { normalizeCalleeText } from "@suss/behavioral-ir";
143
535
 
144
536
  // src/facts/store.ts
145
537
  import { Node as Node9 } from "ts-morph";
146
- import { isTestFile } from "@suss/behavioral-ir";
147
538
  import {
148
539
  clearRelations,
149
540
  Database as Database2,
@@ -179,7 +570,8 @@ import path from "path";
179
570
 
180
571
  // src/discovery/shared.ts
181
572
  import {
182
- Node as Node2
573
+ Node as Node2,
574
+ SyntaxKind
183
575
  } from "ts-morph";
184
576
  function unitNode(unit) {
185
577
  return unit.func ?? unit.announcedAt ?? null;
@@ -218,8 +610,15 @@ function exportIdentityOf(unit) {
218
610
  return "";
219
611
  }
220
612
  function isFunctionRoot(node) {
221
- return Node2.isFunctionDeclaration(node) || Node2.isFunctionExpression(node) || Node2.isArrowFunction(node) || Node2.isMethodDeclaration(node) || Node2.isConstructorDeclaration(node);
222
- }
613
+ return FUNCTION_ROOT_KINDS.has(node.getKind());
614
+ }
615
+ var FUNCTION_ROOT_KINDS = /* @__PURE__ */ new Set([
616
+ SyntaxKind.FunctionDeclaration,
617
+ SyntaxKind.FunctionExpression,
618
+ SyntaxKind.ArrowFunction,
619
+ SyntaxKind.MethodDeclaration,
620
+ SyntaxKind.Constructor
621
+ ]);
223
622
  function declarationCarryingTheBody(declaration) {
224
623
  if (!Node2.isFunctionDeclaration(declaration) && !Node2.isMethodDeclaration(declaration) && !Node2.isConstructorDeclaration(declaration)) {
225
624
  return declaration;
@@ -300,6 +699,61 @@ function createPerFileCache() {
300
699
  };
301
700
  }
302
701
 
702
+ // src/walk/rawDescent.ts
703
+ import {
704
+ ts as ts2
705
+ } from "ts-morph";
706
+ function statementsOfKind(file, kind) {
707
+ const found = [];
708
+ for (const raw of file.compilerNode.statements) {
709
+ if (raw.kind === kind) {
710
+ found.push(wrapperOf(file, raw));
711
+ }
712
+ }
713
+ return found;
714
+ }
715
+ function forEachDescendantOfKinds(root, kinds, visit, skips = runsNothing) {
716
+ forEachDescendantWhere(root, (raw) => kinds.has(raw.kind), visit, skips);
717
+ }
718
+ function forEachDescendantWhere(root, accepts, visit, skips = runsNothing) {
719
+ const walk = (raw) => {
720
+ if (skips(raw)) {
721
+ return void 0;
722
+ }
723
+ if (accepts(raw) && visit(wrapperOf(root, raw)) === true) {
724
+ return void 0;
725
+ }
726
+ ts2.forEachChild(raw, walk);
727
+ return void 0;
728
+ };
729
+ ts2.forEachChild(root.compilerNode, walk);
730
+ }
731
+ function runsNothing(raw) {
732
+ return isTypeOnlySyntax(raw) || isAmbient(raw);
733
+ }
734
+ function skipsNothing() {
735
+ return false;
736
+ }
737
+ function isTypeOnlySyntax(raw) {
738
+ return raw.kind >= ts2.SyntaxKind.FirstTypeNode && raw.kind <= ts2.SyntaxKind.LastTypeNode || TYPE_DECLARATIONS.has(raw.kind);
739
+ }
740
+ var TYPE_DECLARATIONS = /* @__PURE__ */ new Set([
741
+ ts2.SyntaxKind.TypeAliasDeclaration,
742
+ ts2.SyntaxKind.InterfaceDeclaration,
743
+ ts2.SyntaxKind.TypeParameter
744
+ ]);
745
+ function isAmbient(raw) {
746
+ if (!ts2.canHaveModifiers(raw)) {
747
+ return false;
748
+ }
749
+ return ts2.getModifiers(raw)?.some((modifier) => modifier.kind === ts2.SyntaxKind.DeclareKeyword) ?? false;
750
+ }
751
+ function wrapperOf(anchor, raw) {
752
+ return anchor._getNodeFromCompilerNode(
753
+ raw
754
+ );
755
+ }
756
+
303
757
  // src/bootstrap/sourceFileLookup.ts
304
758
  function sourceFileFor(project, moduleKey) {
305
759
  if (!isPathKey(moduleKey)) {
@@ -403,54 +857,43 @@ function spanKey(span) {
403
857
  var functionIndexes = createPerFileCache();
404
858
  function indexFunctions(sf) {
405
859
  const index = /* @__PURE__ */ new Map();
406
- sf.forEachDescendant((node) => {
407
- if (!isFunctionRoot(node)) {
408
- return;
409
- }
410
- const bySpan = spanKey({ start: node.getStart(), end: node.getEnd() });
411
- index.set(bySpan, node);
412
- const key = rangeKey({ start: startLineOf(node), end: endLineOf(node) });
413
- if (!index.has(key)) {
414
- index.set(key, node);
415
- }
416
- });
860
+ forEachDescendantOfKinds(
861
+ sf,
862
+ FUNCTION_ROOT_KINDS,
863
+ (found) => {
864
+ const node = found;
865
+ const bySpan = spanKey({ start: node.getStart(), end: node.getEnd() });
866
+ index.set(bySpan, node);
867
+ const key = rangeKey({ start: startLineOf(node), end: endLineOf(node) });
868
+ if (!index.has(key)) {
869
+ index.set(key, node);
870
+ }
871
+ return false;
872
+ },
873
+ isTypeOnlySyntax
874
+ );
417
875
  return index;
418
876
  }
419
877
 
420
- // src/depTracking.ts
421
- function createDependencySink() {
422
- return { files: /* @__PURE__ */ new Set(), mountPrefixes: /* @__PURE__ */ new Map(), claims: [] };
423
- }
424
- var activeSink = null;
425
- function withDependencySink(sink, fn) {
426
- const previous = activeSink;
427
- activeSink = sink;
428
- try {
429
- return fn();
430
- } finally {
431
- activeSink = previous;
432
- }
433
- }
434
- function recordFileDependency(filePath) {
435
- activeSink?.files.add(filePath);
436
- }
437
- function recordMountPrefix(childId, prefix) {
438
- activeSink?.mountPrefixes.set(childId, prefix);
878
+ // src/testCode.ts
879
+ import { isTestFile } from "@suss/behavioral-ir";
880
+ function inTestFile(node) {
881
+ return isTestFile(node.getSourceFile().getFilePath());
439
882
  }
440
- function recordUnitClaim(key, pack) {
441
- activeSink?.claims.push({ key, pack });
883
+ function testCallingProduction(call, callee) {
884
+ return inTestFile(call) && !inTestFile(callee);
442
885
  }
443
886
 
444
887
  // src/facts/containerWrites.ts
445
- import { Node as Node8, SyntaxKind as SyntaxKind4 } from "ts-morph";
888
+ import { Node as Node8, SyntaxKind as SyntaxKind8 } from "ts-morph";
446
889
 
447
890
  // src/facts/extract.ts
448
891
  import { posix } from "path";
449
892
  import {
450
893
  ModuleDeclarationKind,
451
894
  Node as Node6,
452
- SyntaxKind as SyntaxKind2,
453
- ts as ts2
895
+ SyntaxKind as SyntaxKind6,
896
+ ts as ts5
454
897
  } from "ts-morph";
455
898
  import {
456
899
  addEntryRows,
@@ -467,12 +910,12 @@ import {
467
910
  } from "@suss/resolution";
468
911
 
469
912
  // src/moduleExports.ts
470
- import { Node as Node3 } from "ts-morph";
913
+ import { Node as Node3, SyntaxKind as SyntaxKind4 } from "ts-morph";
471
914
 
472
915
  // src/bootstrap/lazyProjectInit.ts
473
916
  import fs2 from "fs/promises";
474
917
  import path3 from "path";
475
- import { ts } from "ts-morph";
918
+ import { ts as ts3 } from "ts-morph";
476
919
 
477
920
  // src/facts/generatedModules.ts
478
921
  import fs from "fs";
@@ -558,6 +1001,7 @@ function generatedModulesOf(packs) {
558
1001
  }
559
1002
 
560
1003
  // src/facts/moduleGraph.ts
1004
+ import { SyntaxKind as SyntaxKind2 } from "ts-morph";
561
1005
  import { Database, evaluate, lit, rule, variable as v } from "@suss/datalog";
562
1006
  var NO_GENERATOR = new GeneratedModules([]);
563
1007
  var REACH_RULES = [
@@ -762,10 +1206,16 @@ var ModuleGraph = class {
762
1206
  };
763
1207
  function readModuleSpecifiers(sourceFile) {
764
1208
  const specifiers = [];
765
- for (const importDecl of sourceFile.getImportDeclarations()) {
1209
+ for (const importDecl of statementsOfKind(
1210
+ sourceFile,
1211
+ SyntaxKind2.ImportDeclaration
1212
+ )) {
766
1213
  specifiers.push(importDecl.getModuleSpecifierValue());
767
1214
  }
768
- for (const exportDecl of sourceFile.getExportDeclarations()) {
1215
+ for (const exportDecl of statementsOfKind(
1216
+ sourceFile,
1217
+ SyntaxKind2.ExportDeclaration
1218
+ )) {
769
1219
  const specifier = exportDecl.getModuleSpecifierValue();
770
1220
  if (specifier !== void 0) {
771
1221
  specifiers.push(specifier);
@@ -785,13 +1235,19 @@ function resolveModuleSpecifiers(sourceFile) {
785
1235
  }
786
1236
  function resolveModuleSpecifiersOf(sourceFile) {
787
1237
  const resolved = [];
788
- for (const importDecl of sourceFile.getImportDeclarations()) {
1238
+ for (const importDecl of statementsOfKind(
1239
+ sourceFile,
1240
+ SyntaxKind2.ImportDeclaration
1241
+ )) {
789
1242
  const target = importDecl.getModuleSpecifierSourceFile();
790
1243
  if (target !== void 0) {
791
1244
  resolved.push(target);
792
1245
  }
793
1246
  }
794
- for (const exportDecl of sourceFile.getExportDeclarations()) {
1247
+ for (const exportDecl of statementsOfKind(
1248
+ sourceFile,
1249
+ SyntaxKind2.ExportDeclaration
1250
+ )) {
795
1251
  const target = exportDecl.getModuleSpecifierSourceFile();
796
1252
  if (target !== void 0) {
797
1253
  resolved.push(target);
@@ -809,6 +1265,7 @@ function namesAnyPackage(specifiers, names) {
809
1265
  }
810
1266
 
811
1267
  // src/bootstrap/preFilter.ts
1268
+ import { SyntaxKind as SyntaxKind3 } from "ts-morph";
812
1269
  function computePackApplicability(sourceFiles, packs, resolution) {
813
1270
  const ungatedPacks = [];
814
1271
  const gatedPacks = [];
@@ -828,7 +1285,9 @@ function computePackApplicability(sourceFiles, packs, resolution) {
828
1285
  for (const sf of sourceFiles) {
829
1286
  importsByFile.set(
830
1287
  sf,
831
- sf.getImportDeclarations().map((d) => d.getModuleSpecifierValue())
1288
+ statementsOfKind(sf, SyntaxKind3.ImportDeclaration).map(
1289
+ (d) => d.getModuleSpecifierValue()
1290
+ )
832
1291
  );
833
1292
  }
834
1293
  }
@@ -1088,7 +1547,7 @@ function resolutionCacheFor(project, options) {
1088
1547
  if (existing !== void 0) {
1089
1548
  return existing;
1090
1549
  }
1091
- const fresh = ts.createModuleResolutionCache(
1550
+ const fresh = ts3.createModuleResolutionCache(
1092
1551
  project.getFileSystem().getCurrentDirectory(),
1093
1552
  (name) => name,
1094
1553
  options
@@ -1122,11 +1581,11 @@ function readSpecifierPaths(project, filePath, options, host) {
1122
1581
  if (text3 === null) {
1123
1582
  return [];
1124
1583
  }
1125
- const scanned = ts.preProcessFile(text3, true, true);
1584
+ const scanned = ts3.preProcessFile(text3, true, true);
1126
1585
  const cache = resolutionCacheFor(project, options);
1127
1586
  const paths = [];
1128
1587
  for (const imported of scanned.importedFiles) {
1129
- const resolved = ts.resolveModuleName(
1588
+ const resolved = ts3.resolveModuleName(
1130
1589
  imported.fileName,
1131
1590
  filePath,
1132
1591
  options,
@@ -1152,13 +1611,13 @@ function readFileText(project, filePath) {
1152
1611
  }
1153
1612
  function parseTsconfig(tsConfigFilePath, seen = /* @__PURE__ */ new Set()) {
1154
1613
  seen.add(tsConfigFilePath);
1155
- const configFile = ts.readConfigFile(tsConfigFilePath, ts.sys.readFile);
1614
+ const configFile = ts3.readConfigFile(tsConfigFilePath, ts3.sys.readFile);
1156
1615
  if (configFile.error !== void 0) {
1157
1616
  return { fileNames: [], options: {} };
1158
1617
  }
1159
- const parsed = ts.parseJsonConfigFileContent(
1618
+ const parsed = ts3.parseJsonConfigFileContent(
1160
1619
  configFile.config,
1161
- ts.sys,
1620
+ ts3.sys,
1162
1621
  path3.dirname(tsConfigFilePath),
1163
1622
  /*existingOptions*/
1164
1623
  void 0,
@@ -1167,7 +1626,7 @@ function parseTsconfig(tsConfigFilePath, seen = /* @__PURE__ */ new Set()) {
1167
1626
  if (parsed.fileNames.length > 0) {
1168
1627
  return { fileNames: parsed.fileNames, options: parsed.options };
1169
1628
  }
1170
- const referenced = (parsed.projectReferences ?? []).map((reference) => ts.resolveProjectReferencePath(reference)).filter((referencePath) => !seen.has(referencePath)).map((referencePath) => parseTsconfig(referencePath, seen));
1629
+ const referenced = (parsed.projectReferences ?? []).map((reference) => ts3.resolveProjectReferencePath(reference)).filter((referencePath) => !seen.has(referencePath)).map((referencePath) => parseTsconfig(referencePath, seen));
1171
1630
  const fileNames = [
1172
1631
  ...new Set(referenced.flatMap((reference) => reference.fileNames))
1173
1632
  ];
@@ -1241,17 +1700,17 @@ function addImportersOfMatches(fileImports, matched, options) {
1241
1700
  }
1242
1701
  function internalSpecifierResolver(files, options) {
1243
1702
  const fileSet = new Set(files);
1244
- const cache = ts.createModuleResolutionCache(
1245
- ts.sys.getCurrentDirectory(),
1703
+ const cache = ts3.createModuleResolutionCache(
1704
+ ts3.sys.getCurrentDirectory(),
1246
1705
  (name) => name,
1247
1706
  options
1248
1707
  );
1249
1708
  return (fromFile, spec) => {
1250
- const resolved = ts.resolveModuleName(
1709
+ const resolved = ts3.resolveModuleName(
1251
1710
  spec,
1252
1711
  fromFile,
1253
1712
  options,
1254
- ts.sys,
1713
+ ts3.sys,
1255
1714
  cache
1256
1715
  ).resolvedModule?.resolvedFileName;
1257
1716
  if (resolved === void 0) {
@@ -1260,7 +1719,7 @@ function internalSpecifierResolver(files, options) {
1260
1719
  if (fileSet.has(resolved)) {
1261
1720
  return resolved;
1262
1721
  }
1263
- const real = ts.sys.realpath?.(resolved) ?? resolved;
1722
+ const real = ts3.sys.realpath?.(resolved) ?? resolved;
1264
1723
  return fileSet.has(real) ? real : null;
1265
1724
  };
1266
1725
  }
@@ -1295,7 +1754,7 @@ async function readImportsConcurrently(paths, marks) {
1295
1754
  const p = paths[i];
1296
1755
  try {
1297
1756
  const text3 = await fs2.readFile(p, "utf-8");
1298
- const pre = ts.preProcessFile(text3, true, false);
1757
+ const pre = ts3.preProcessFile(text3, true, false);
1299
1758
  results[i] = {
1300
1759
  path: p,
1301
1760
  importedModules: pre.importedFiles.map((f) => f.fileName),
@@ -1418,7 +1877,7 @@ function reExportShapeOf(file, reach) {
1418
1877
  const targets = [];
1419
1878
  const exportNodes = [];
1420
1879
  const localNames = /* @__PURE__ */ new Set();
1421
- for (const decl of file.getExportDeclarations()) {
1880
+ for (const decl of statementsOfKind(file, SyntaxKind4.ExportDeclaration)) {
1422
1881
  const target = decl.getModuleSpecifierSourceFile();
1423
1882
  if (target !== void 0) {
1424
1883
  targets.push(target);
@@ -1430,7 +1889,10 @@ function reExportShapeOf(file, reach) {
1430
1889
  }
1431
1890
  }
1432
1891
  }
1433
- for (const assignment of file.getExportAssignments()) {
1892
+ for (const assignment of statementsOfKind(
1893
+ file,
1894
+ SyntaxKind4.ExportAssignment
1895
+ )) {
1434
1896
  exportNodes.push(assignment);
1435
1897
  const expression = assignment.getExpression();
1436
1898
  if (Node3.isIdentifier(expression)) {
@@ -1438,7 +1900,7 @@ function reExportShapeOf(file, reach) {
1438
1900
  }
1439
1901
  }
1440
1902
  const importNodes = [];
1441
- for (const decl of file.getImportDeclarations()) {
1903
+ for (const decl of statementsOfKind(file, SyntaxKind4.ImportDeclaration)) {
1442
1904
  const all = importBindingsOf(decl);
1443
1905
  const bindings = reach === "every import" ? all : all.filter((binding) => localNames.has(binding.name));
1444
1906
  if (bindings.length === 0) {
@@ -1528,7 +1990,7 @@ function keyNameOf(name) {
1528
1990
  }
1529
1991
 
1530
1992
  // src/facts/assignments.ts
1531
- import { Node as Node5, SyntaxKind, VariableDeclarationKind } from "ts-morph";
1993
+ import { Node as Node5, SyntaxKind as SyntaxKind5, ts as ts4, VariableDeclarationKind } from "ts-morph";
1532
1994
  import { valueLeftByWrites } from "@suss/resolution";
1533
1995
  var byFile = createPerFileCache();
1534
1996
  var byDeclaration = /* @__PURE__ */ new WeakMap();
@@ -1576,7 +2038,7 @@ function describeWrites(values) {
1576
2038
  }));
1577
2039
  }
1578
2040
  function isNotYetPlaceholder(value) {
1579
- return value.getKind() === SyntaxKind.NullKeyword || Node5.isIdentifier(value) && value.getText() === "undefined";
2041
+ return value.getKind() === SyntaxKind5.NullKeyword || Node5.isIdentifier(value) && value.getText() === "undefined";
1580
2042
  }
1581
2043
  function isConstruction(value) {
1582
2044
  return Node5.isCallExpression(value) || Node5.isNewExpression(value) || Node5.isObjectLiteralExpression(value) || Node5.isArrayLiteralExpression(value);
@@ -1711,11 +2173,8 @@ function assignmentsInFile(sourceFile) {
1711
2173
  }
1712
2174
  const found = /* @__PURE__ */ new Map();
1713
2175
  byFile.set(sourceFile, found);
1714
- sourceFile.forEachDescendant((node) => {
2176
+ forEachDescendantWhere(sourceFile, mayWrite, (node) => {
1715
2177
  const written = writeAt(node);
1716
- if (written === null) {
1717
- return;
1718
- }
1719
2178
  for (const declaration of declarationsOf(written.target)) {
1720
2179
  const writes = found.get(declaration);
1721
2180
  if (writes === void 0) {
@@ -1724,34 +2183,33 @@ function assignmentsInFile(sourceFile) {
1724
2183
  writes.push(written.write);
1725
2184
  }
1726
2185
  }
2186
+ return false;
1727
2187
  });
1728
2188
  return found;
1729
2189
  }
2190
+ function mayWrite(raw) {
2191
+ if (ts4.isBinaryExpression(raw)) {
2192
+ return isAssignmentOperator(raw.operatorToken.kind) && (ts4.isIdentifier(raw.left) || ts4.isPropertyAccessExpression(raw.left));
2193
+ }
2194
+ if (ts4.isPrefixUnaryExpression(raw) || ts4.isPostfixUnaryExpression(raw)) {
2195
+ return (raw.operator === SyntaxKind5.PlusPlusToken || raw.operator === SyntaxKind5.MinusMinusToken) && ts4.isIdentifier(raw.operand);
2196
+ }
2197
+ return false;
2198
+ }
1730
2199
  function isAssignmentOperator(kind) {
1731
- return kind >= SyntaxKind.FirstAssignment && kind <= SyntaxKind.LastAssignment;
2200
+ return kind >= SyntaxKind5.FirstAssignment && kind <= SyntaxKind5.LastAssignment;
1732
2201
  }
1733
2202
  function writesItsWholeValue(kind) {
1734
- return kind === SyntaxKind.EqualsToken || kind === SyntaxKind.QuestionQuestionEqualsToken || kind === SyntaxKind.BarBarEqualsToken;
2203
+ return kind === SyntaxKind5.EqualsToken || kind === SyntaxKind5.QuestionQuestionEqualsToken || kind === SyntaxKind5.BarBarEqualsToken;
1735
2204
  }
1736
2205
  function writeAt(node) {
1737
2206
  if (Node5.isBinaryExpression(node)) {
1738
2207
  const operator = node.getOperatorToken().getKind();
1739
- const target = node.getLeft();
1740
- if (!isAssignmentOperator(operator) || !(Node5.isIdentifier(target) || Node5.isPropertyAccessExpression(target))) {
1741
- return null;
1742
- }
1743
2208
  const value = writesItsWholeValue(operator) ? node.getRight() : null;
1744
- return { target, write: { value, node } };
1745
- }
1746
- if (Node5.isPrefixUnaryExpression(node) || Node5.isPostfixUnaryExpression(node)) {
1747
- const operator = node.getOperatorToken();
1748
- if (operator !== SyntaxKind.PlusPlusToken && operator !== SyntaxKind.MinusMinusToken) {
1749
- return null;
1750
- }
1751
- const target = node.getOperand();
1752
- return Node5.isIdentifier(target) ? { target, write: { value: null, node } } : null;
2209
+ return { target: node.getLeft(), write: { value, node } };
1753
2210
  }
1754
- return null;
2211
+ const update = node;
2212
+ return { target: update.getOperand(), write: { value: null, node } };
1755
2213
  }
1756
2214
  function declarationsOf(name) {
1757
2215
  const nameNode = Node5.isPropertyAccessExpression(name) ? name.getNameNode() : name;
@@ -1793,35 +2251,39 @@ function statementOf(node) {
1793
2251
  function isReadBefore(declaration, position) {
1794
2252
  const name = declaration.getName();
1795
2253
  const sourceFile = declaration.getSourceFile();
1796
- let read2 = false;
1797
- sourceFile.forEachDescendant((node, traversal) => {
1798
- if (read2) {
1799
- traversal.stop();
1800
- return;
1801
- }
1802
- if (node.getStart() >= position) {
1803
- traversal.skip();
1804
- return;
1805
- }
1806
- if (startsItsOwnBody(node)) {
1807
- traversal.skip();
1808
- return;
1809
- }
1810
- if (!Node5.isIdentifier(node) || node.getText() !== name) {
1811
- return;
2254
+ const file = sourceFile.compilerNode;
2255
+ const readsHere = (raw) => {
2256
+ if (!ts4.isIdentifier(raw) || raw.getText(file) !== name) {
2257
+ return false;
1812
2258
  }
2259
+ const node = wrapperOf(sourceFile, raw);
1813
2260
  if (node === declaration.getNameNode() || isWriteTarget(node)) {
1814
- return;
1815
- }
1816
- if (declarationsOf(node).includes(declaration)) {
1817
- read2 = true;
2261
+ return false;
1818
2262
  }
1819
- });
1820
- return read2;
1821
- }
1822
- function startsItsOwnBody(node) {
1823
- return Node5.isFunctionDeclaration(node) || Node5.isFunctionExpression(node) || Node5.isArrowFunction(node) || Node5.isMethodDeclaration(node) || Node5.isClassDeclaration(node);
2263
+ return declarationsOf(node).includes(declaration);
2264
+ };
2265
+ return someBefore(file, position, readsHere);
1824
2266
  }
2267
+ function someBefore(root, position, test) {
2268
+ const file = root.getSourceFile();
2269
+ const visit = (raw) => {
2270
+ if (raw.getStart(file) >= position || OWN_BODY_KINDS.has(raw.kind)) {
2271
+ return void 0;
2272
+ }
2273
+ if (test(raw)) {
2274
+ return true;
2275
+ }
2276
+ return ts4.forEachChild(raw, visit);
2277
+ };
2278
+ return ts4.forEachChild(root, visit) === true;
2279
+ }
2280
+ var OWN_BODY_KINDS = /* @__PURE__ */ new Set([
2281
+ SyntaxKind5.FunctionDeclaration,
2282
+ SyntaxKind5.FunctionExpression,
2283
+ SyntaxKind5.ArrowFunction,
2284
+ SyntaxKind5.MethodDeclaration,
2285
+ SyntaxKind5.ClassDeclaration
2286
+ ]);
1825
2287
  function isWriteTarget(name) {
1826
2288
  const parent = name.getParent();
1827
2289
  if (parent === void 0) {
@@ -1911,21 +2373,12 @@ function runsAsItsOwnBody(node) {
1911
2373
  return Node5.isFunctionDeclaration(node) || Node5.isFunctionExpression(node) || Node5.isArrowFunction(node) || Node5.isMethodDeclaration(node) || Node5.isConstructorDeclaration(node) || Node5.isGetAccessorDeclaration(node) || Node5.isSetAccessorDeclaration(node);
1912
2374
  }
1913
2375
  function isPropertyReadBefore(statements, name, property, position) {
1914
- let read2 = false;
1915
- statements.forEachDescendant((node, traversal) => {
1916
- if (read2) {
1917
- traversal.stop();
1918
- return;
1919
- }
1920
- if (node.getStart() >= position || startsItsOwnBody(node)) {
1921
- traversal.skip();
1922
- return;
1923
- }
1924
- if (Node5.isPropertyAccessExpression(node) && node.getName() === property && node.getExpression().getText() === name && !isWriteTarget(node)) {
1925
- read2 = true;
1926
- }
1927
- });
1928
- return read2;
2376
+ const file = statements.getSourceFile().compilerNode;
2377
+ return someBefore(
2378
+ statements.compilerNode,
2379
+ position,
2380
+ (raw) => ts4.isPropertyAccessExpression(raw) && raw.name.getText(file) === property && raw.expression.getText(file) === name && !isWriteTarget(wrapperOf(statements, raw))
2381
+ );
1929
2382
  }
1930
2383
 
1931
2384
  // src/facts/languageWords.ts
@@ -1974,8 +2427,15 @@ function createNodeTable(environmentObjects = [], runtime = NO_RUNTIME_SPELLINGS
1974
2427
  };
1975
2428
  }
1976
2429
  function nodeId(node) {
1977
- return `${node.getSourceFile().getFilePath()}:${node.getStart()}-${node.getEnd()}`;
2430
+ const known = idByNode.get(node.compilerNode);
2431
+ if (known !== void 0) {
2432
+ return known;
2433
+ }
2434
+ const id = `${node.getSourceFile().getFilePath()}:${node.getStart()}-${node.getEnd()}`;
2435
+ idByNode.set(node.compilerNode, id);
2436
+ return id;
1978
2437
  }
2438
+ var idByNode = /* @__PURE__ */ new WeakMap();
1979
2439
  function moduleKeyOf(declaration) {
1980
2440
  const resolved = declaration.getModuleSpecifierSourceFile();
1981
2441
  if (resolved !== void 0) {
@@ -1989,7 +2449,7 @@ function moduleKeyOf(declaration) {
1989
2449
  }
1990
2450
  function compilerResolvedPathOf(declaration, specifier) {
1991
2451
  const project = declaration.getProject();
1992
- const result = ts2.resolveModuleName(
2452
+ const result = ts5.resolveModuleName(
1993
2453
  specifier,
1994
2454
  declaration.getSourceFile().getFilePath(),
1995
2455
  project.getCompilerOptions(),
@@ -2031,7 +2491,7 @@ function moduleKeysOf(moduleKey, specifier) {
2031
2491
  }
2032
2492
  function dynamicImportKeysOf(expression) {
2033
2493
  const call = unwrapExpression(expression);
2034
- if (!Node6.isCallExpression(call) || call.getExpression().getKind() !== SyntaxKind2.ImportKeyword) {
2494
+ if (!Node6.isCallExpression(call) || call.getExpression().getKind() !== SyntaxKind6.ImportKeyword) {
2035
2495
  return null;
2036
2496
  }
2037
2497
  const [argument] = call.getArguments();
@@ -2296,7 +2756,33 @@ function spellingsHandedOn(paths, sourceFile) {
2296
2756
  if (!paths.some((path18) => text3.includes(path18))) {
2297
2757
  return [];
2298
2758
  }
2299
- return sourceFile.getDescendantsOfKind(SyntaxKind2.PropertyAccessExpression).filter((node) => spellsOneOf(paths, node) && flowsOnward(node));
2759
+ const file = sourceFile.compilerNode;
2760
+ const found = [];
2761
+ forEachDescendantWhere(
2762
+ sourceFile,
2763
+ (raw) => ts5.isPropertyAccessExpression(raw) && paths.includes(compilerDottedPathOf(raw, file) ?? ""),
2764
+ (node) => {
2765
+ if (flowsOnward(node)) {
2766
+ found.push(node);
2767
+ }
2768
+ return false;
2769
+ }
2770
+ );
2771
+ return found;
2772
+ }
2773
+ function compilerDottedPathOf(raw, file) {
2774
+ if (ts5.isIdentifier(raw)) {
2775
+ return raw.getText(file);
2776
+ }
2777
+ if (ts5.isMetaProperty(raw)) {
2778
+ const keyword = ts5.tokenToString(raw.keywordToken);
2779
+ return `${keyword}.${raw.name.getText(file)}`;
2780
+ }
2781
+ if (!ts5.isPropertyAccessExpression(raw)) {
2782
+ return null;
2783
+ }
2784
+ const object = compilerDottedPathOf(raw.expression, file);
2785
+ return object === null ? null : `${object}.${raw.name.getText(file)}`;
2300
2786
  }
2301
2787
  function flowsOnward(node) {
2302
2788
  const parent = node.getParent();
@@ -2313,7 +2799,7 @@ function dottedPathOf(expression) {
2313
2799
  return expression.getText();
2314
2800
  }
2315
2801
  if (Node6.isMetaProperty(expression)) {
2316
- const keyword = ts2.tokenToString(expression.getKeywordToken());
2802
+ const keyword = ts5.tokenToString(expression.getKeywordToken());
2317
2803
  return `${keyword}.${expression.getName()}`;
2318
2804
  }
2319
2805
  if (!Node6.isPropertyAccessExpression(expression)) {
@@ -2327,7 +2813,7 @@ function asFallbackExpression(expression) {
2327
2813
  return null;
2328
2814
  }
2329
2815
  const operator = expression.getOperatorToken().getKind();
2330
- return operator === SyntaxKind2.BarBarToken || operator === SyntaxKind2.QuestionQuestionToken ? expression : null;
2816
+ return operator === SyntaxKind6.BarBarToken || operator === SyntaxKind6.QuestionQuestionToken ? expression : null;
2331
2817
  }
2332
2818
  function unwrapExpression(expression) {
2333
2819
  let current2 = expression;
@@ -2349,7 +2835,7 @@ function unwrapExpression(expression) {
2349
2835
  }
2350
2836
  function emitValue(db, table, value) {
2351
2837
  const expression = unwrapExpression(value);
2352
- if (expression.getKind() === SyntaxKind2.ThisKeyword) {
2838
+ if (expression.getKind() === SyntaxKind6.ThisKeyword) {
2353
2839
  const receiver = receiverKeyOf(db, table, expression);
2354
2840
  if (receiver !== null) {
2355
2841
  return receiver;
@@ -2503,7 +2989,7 @@ function memberReadName(read2) {
2503
2989
  }
2504
2990
  function readsOffClassItself(receiver) {
2505
2991
  const written = unwrapExpression(receiver);
2506
- if (written.getKind() === SyntaxKind2.ThisKeyword) {
2992
+ if (written.getKind() === SyntaxKind6.ThisKeyword) {
2507
2993
  return thisIsTheClass(written);
2508
2994
  }
2509
2995
  return isClassReference(written, /* @__PURE__ */ new Set());
@@ -2648,7 +3134,7 @@ function emitReferenceFacts(db, table, reference) {
2648
3134
  }
2649
3135
  if (Node6.isImportClause(declaration)) {
2650
3136
  const importDecl = declaration.getParentIfKind(
2651
- SyntaxKind2.ImportDeclaration
3137
+ SyntaxKind6.ImportDeclaration
2652
3138
  );
2653
3139
  if (importDecl !== void 0) {
2654
3140
  emitImportFacts(
@@ -2664,7 +3150,7 @@ function emitReferenceFacts(db, table, reference) {
2664
3150
  }
2665
3151
  if (Node6.isNamespaceImport(declaration)) {
2666
3152
  const importDecl = declaration.getFirstAncestorByKind(
2667
- SyntaxKind2.ImportDeclaration
3153
+ SyntaxKind6.ImportDeclaration
2668
3154
  );
2669
3155
  if (importDecl !== void 0) {
2670
3156
  emitImportFacts(
@@ -2978,11 +3464,11 @@ function emitConstructorFacts(db, table, declaration, classId) {
2978
3464
  return;
2979
3465
  }
2980
3466
  const writes = propertyWritesOf(implementation, body);
2981
- body.forEachDescendant((descendant, traversal) => {
2982
- if (recordBodyCalls(db, table, classId, descendant, writes)) {
2983
- traversal.skip();
2984
- }
2985
- });
3467
+ forEachDescendantOfKinds(
3468
+ body,
3469
+ BODY_FACT_KINDS,
3470
+ (descendant) => recordBodyCalls(db, table, classId, descendant, writes)
3471
+ );
2986
3472
  emitNamedStores(db, table, writes);
2987
3473
  }
2988
3474
  function emitParameters(db, table, ownerId, parameters) {
@@ -3034,11 +3520,11 @@ function emitFunctionFacts(db, table, fn) {
3034
3520
  returns.stated = true;
3035
3521
  recordBodyNode(db, table, fnId, body, returns, writes);
3036
3522
  }
3037
- body.forEachDescendant((descendant, traversal) => {
3038
- if (recordBodyNode(db, table, fnId, descendant, returns, writes)) {
3039
- traversal.skip();
3040
- }
3041
- });
3523
+ forEachDescendantOfKinds(
3524
+ body,
3525
+ BODY_FACT_KINDS,
3526
+ (descendant) => recordBodyNode(db, table, fnId, descendant, returns, writes)
3527
+ );
3042
3528
  emitNamedStores(db, table, writes);
3043
3529
  }
3044
3530
  if (!returns.stated) {
@@ -3096,6 +3582,18 @@ function recordBodyNode(db, table, fnId, node, returns, writes) {
3096
3582
  }
3097
3583
  return recordBodyCalls(db, table, fnId, node, writes);
3098
3584
  }
3585
+ var BODY_FACT_KINDS = /* @__PURE__ */ new Set([
3586
+ ...FUNCTION_ROOT_KINDS,
3587
+ SyntaxKind6.ReturnStatement,
3588
+ SyntaxKind6.ElementAccessExpression,
3589
+ SyntaxKind6.BinaryExpression,
3590
+ SyntaxKind6.CallExpression,
3591
+ SyntaxKind6.NewExpression,
3592
+ SyntaxKind6.AwaitExpression,
3593
+ SyntaxKind6.ParenthesizedExpression,
3594
+ SyntaxKind6.AsExpression,
3595
+ SyntaxKind6.SatisfiesExpression
3596
+ ]);
3099
3597
  function recordBodyCalls(db, table, fnId, node, writes) {
3100
3598
  if (isFunctionRoot(node)) {
3101
3599
  emitValue(db, table, node);
@@ -3122,7 +3620,7 @@ function recordBodyCalls(db, table, fnId, node, writes) {
3122
3620
  return false;
3123
3621
  }
3124
3622
  function emitExitCodeWrite(db, table, node) {
3125
- if (table.exitCodeWrites.length === 0 || !Node6.isBinaryExpression(node) || node.getOperatorToken().getKind() !== SyntaxKind2.EqualsToken || !spellsOneOf(table.exitCodeWrites, node.getLeft())) {
3623
+ if (table.exitCodeWrites.length === 0 || !Node6.isBinaryExpression(node) || node.getOperatorToken().getKind() !== SyntaxKind6.EqualsToken || !spellsOneOf(table.exitCodeWrites, node.getLeft())) {
3126
3624
  return;
3127
3625
  }
3128
3626
  fact(db, "exitCodeWrite", emitValue(db, table, node.getRight()));
@@ -3146,12 +3644,12 @@ function emitTopLevelStatements(db, table, sourceFile) {
3146
3644
  continue;
3147
3645
  }
3148
3646
  if (TOP_LEVEL_BLOCKS.has(statement.getKind())) {
3149
- statement.forEachDescendant((node, traversal) => {
3647
+ forEachDescendantOfKinds(statement, TOP_LEVEL_WRITE_KINDS, (node) => {
3150
3648
  if (isFunctionRoot(node) || Node6.isClassDeclaration(node)) {
3151
- traversal.skip();
3152
- return;
3649
+ return true;
3153
3650
  }
3154
3651
  notePropertyWrite(writes, node);
3652
+ return false;
3155
3653
  });
3156
3654
  }
3157
3655
  }
@@ -3162,16 +3660,21 @@ function statementExpressionOf(statement) {
3162
3660
  return Node6.isVoidExpression(expression) ? unwrapExpression(expression.getExpression()) : expression;
3163
3661
  }
3164
3662
  var TOP_LEVEL_BLOCKS = /* @__PURE__ */ new Set([
3165
- SyntaxKind2.Block,
3166
- SyntaxKind2.IfStatement,
3167
- SyntaxKind2.TryStatement,
3168
- SyntaxKind2.SwitchStatement,
3169
- SyntaxKind2.LabeledStatement,
3170
- SyntaxKind2.ForStatement,
3171
- SyntaxKind2.ForOfStatement,
3172
- SyntaxKind2.ForInStatement,
3173
- SyntaxKind2.WhileStatement,
3174
- SyntaxKind2.DoStatement
3663
+ SyntaxKind6.Block,
3664
+ SyntaxKind6.IfStatement,
3665
+ SyntaxKind6.TryStatement,
3666
+ SyntaxKind6.SwitchStatement,
3667
+ SyntaxKind6.LabeledStatement,
3668
+ SyntaxKind6.ForStatement,
3669
+ SyntaxKind6.ForOfStatement,
3670
+ SyntaxKind6.ForInStatement,
3671
+ SyntaxKind6.WhileStatement,
3672
+ SyntaxKind6.DoStatement
3673
+ ]);
3674
+ var TOP_LEVEL_WRITE_KINDS = /* @__PURE__ */ new Set([
3675
+ ...FUNCTION_ROOT_KINDS,
3676
+ SyntaxKind6.BinaryExpression,
3677
+ SyntaxKind6.ClassDeclaration
3175
3678
  ]);
3176
3679
  function descendantIsReturned(fn) {
3177
3680
  const consumer = climbSyntax(fn).getParent();
@@ -3180,8 +3683,8 @@ function descendantIsReturned(fn) {
3180
3683
  function importedModuleKeys(sourceFile) {
3181
3684
  const keys = [];
3182
3685
  for (const declaration of [
3183
- ...sourceFile.getImportDeclarations(),
3184
- ...sourceFile.getExportDeclarations()
3686
+ ...statementsOfKind(sourceFile, SyntaxKind6.ImportDeclaration),
3687
+ ...statementsOfKind(sourceFile, SyntaxKind6.ExportDeclaration)
3185
3688
  ]) {
3186
3689
  const moduleKey = moduleKeyOf(declaration);
3187
3690
  if (moduleKey !== null) {
@@ -3192,7 +3695,10 @@ function importedModuleKeys(sourceFile) {
3192
3695
  }
3193
3696
  function extractReExportFacts(db, sourceFile) {
3194
3697
  const filePath = sourceFile.getFilePath();
3195
- for (const exportDecl of sourceFile.getExportDeclarations()) {
3698
+ for (const exportDecl of statementsOfKind(
3699
+ sourceFile,
3700
+ SyntaxKind6.ExportDeclaration
3701
+ )) {
3196
3702
  const moduleKey = moduleKeyOf(exportDecl);
3197
3703
  if (moduleKey === null) {
3198
3704
  continue;
@@ -3249,7 +3755,7 @@ function collectDirectExports(statements, found) {
3249
3755
  continue;
3250
3756
  }
3251
3757
  for (const element of nameNode.getDescendantsOfKind(
3252
- SyntaxKind2.BindingElement
3758
+ SyntaxKind6.BindingElement
3253
3759
  )) {
3254
3760
  const bound = element.getNameNode();
3255
3761
  if (Node6.isIdentifier(bound)) {
@@ -3268,7 +3774,10 @@ function collectDirectExports(statements, found) {
3268
3774
  }
3269
3775
  }
3270
3776
  function emitLocalExportLists(db, table, sourceFile, filePath) {
3271
- for (const exportDecl of sourceFile.getExportDeclarations()) {
3777
+ for (const exportDecl of statementsOfKind(
3778
+ sourceFile,
3779
+ SyntaxKind6.ExportDeclaration
3780
+ )) {
3272
3781
  if (exportDecl.getModuleSpecifier() !== void 0) {
3273
3782
  continue;
3274
3783
  }
@@ -3279,7 +3788,10 @@ function emitLocalExportLists(db, table, sourceFile, filePath) {
3279
3788
  }
3280
3789
  }
3281
3790
  }
3282
- for (const assignment of sourceFile.getExportAssignments()) {
3791
+ for (const assignment of statementsOfKind(
3792
+ sourceFile,
3793
+ SyntaxKind6.ExportAssignment
3794
+ )) {
3283
3795
  if (assignment.isExportEquals()) {
3284
3796
  continue;
3285
3797
  }
@@ -3303,7 +3815,7 @@ function emitExportedDeclaration(db, table, filePath, alias, declaration) {
3303
3815
  const specifier = importSpecifierOf(declaration);
3304
3816
  if (specifier !== null) {
3305
3817
  const importDecl = declaration.getFirstAncestorByKind(
3306
- SyntaxKind2.ImportDeclaration
3818
+ SyntaxKind6.ImportDeclaration
3307
3819
  );
3308
3820
  const moduleKey = importDecl === void 0 ? null : moduleKeyOf(importDecl);
3309
3821
  if (moduleKey !== null) {
@@ -3358,7 +3870,7 @@ function emitExportedValue(db, table, filePath, name, spelling) {
3358
3870
  }
3359
3871
 
3360
3872
  // src/facts/localUses.ts
3361
- import { Node as Node7, SyntaxKind as SyntaxKind3 } from "ts-morph";
3873
+ import { Node as Node7, SyntaxKind as SyntaxKind7 } from "ts-morph";
3362
3874
  import { UNPLACED_STORE_NAME } from "@suss/resolution";
3363
3875
  function fact2(db, relation, ...tuple) {
3364
3876
  db.add(relation, tuple);
@@ -3420,25 +3932,25 @@ function emitUse(db, table, operand2) {
3420
3932
  return key;
3421
3933
  }
3422
3934
  var CONSUMERS = {
3423
- [SyntaxKind3.PropertyAccessExpression]: emitPartRead,
3424
- [SyntaxKind3.ElementAccessExpression]: emitPartRead,
3425
- [SyntaxKind3.CallExpression]: emitWhole,
3426
- [SyntaxKind3.NewExpression]: emitWhole,
3427
- [SyntaxKind3.ArrayLiteralExpression]: emitWhole,
3428
- [SyntaxKind3.PropertyAssignment]: emitHolder,
3429
- [SyntaxKind3.ShorthandPropertyAssignment]: emitHolder,
3430
- [SyntaxKind3.ReturnStatement]: emitEnclosingFunction,
3431
- [SyntaxKind3.ArrowFunction]: emitEnclosingFunction,
3432
- [SyntaxKind3.Parameter]: emitEnclosingFunction,
3433
- [SyntaxKind3.YieldExpression]: emitYield,
3434
- [SyntaxKind3.VariableDeclaration]: emitNameWrite,
3435
- [SyntaxKind3.BinaryExpression]: emitBinary,
3436
- [SyntaxKind3.ConditionalExpression]: emitConditionalBranch,
3437
- [SyntaxKind3.SpreadElement]: emitGivenTo,
3438
- [SyntaxKind3.SpreadAssignment]: emitGivenTo,
3439
- [SyntaxKind3.JsxSpreadAttribute]: emitGivenToElement,
3440
- [SyntaxKind3.JsxExpression]: emitGivenToElement,
3441
- [SyntaxKind3.PropertyDeclaration]: emitFieldInitializer
3935
+ [SyntaxKind7.PropertyAccessExpression]: emitPartRead,
3936
+ [SyntaxKind7.ElementAccessExpression]: emitPartRead,
3937
+ [SyntaxKind7.CallExpression]: emitWhole,
3938
+ [SyntaxKind7.NewExpression]: emitWhole,
3939
+ [SyntaxKind7.ArrayLiteralExpression]: emitWhole,
3940
+ [SyntaxKind7.PropertyAssignment]: emitHolder,
3941
+ [SyntaxKind7.ShorthandPropertyAssignment]: emitHolder,
3942
+ [SyntaxKind7.ReturnStatement]: emitEnclosingFunction,
3943
+ [SyntaxKind7.ArrowFunction]: emitEnclosingFunction,
3944
+ [SyntaxKind7.Parameter]: emitEnclosingFunction,
3945
+ [SyntaxKind7.YieldExpression]: emitYield,
3946
+ [SyntaxKind7.VariableDeclaration]: emitNameWrite,
3947
+ [SyntaxKind7.BinaryExpression]: emitBinary,
3948
+ [SyntaxKind7.ConditionalExpression]: emitConditionalBranch,
3949
+ [SyntaxKind7.SpreadElement]: emitGivenTo,
3950
+ [SyntaxKind7.SpreadAssignment]: emitGivenTo,
3951
+ [SyntaxKind7.JsxSpreadAttribute]: emitGivenToElement,
3952
+ [SyntaxKind7.JsxExpression]: emitGivenToElement,
3953
+ [SyntaxKind7.PropertyDeclaration]: emitFieldInitializer
3442
3954
  };
3443
3955
  function emitGivenTo(db, _table, _operand, key, parent) {
3444
3956
  const container = parent.getParent();
@@ -3526,16 +4038,16 @@ function emitNameWrite(db, _table, _operand, key, parent) {
3526
4038
  fact2(db, "mayHold", nodeId(name), key);
3527
4039
  }
3528
4040
  var WHOLE_VALUE_WRITES = /* @__PURE__ */ new Set([
3529
- SyntaxKind3.EqualsToken,
3530
- SyntaxKind3.BarBarEqualsToken,
3531
- SyntaxKind3.QuestionQuestionEqualsToken
4041
+ SyntaxKind7.EqualsToken,
4042
+ SyntaxKind7.BarBarEqualsToken,
4043
+ SyntaxKind7.QuestionQuestionEqualsToken
3532
4044
  ]);
3533
4045
  function emitBinary(db, table, operand2, key, parent) {
3534
4046
  if (!Node7.isBinaryExpression(parent)) {
3535
4047
  return;
3536
4048
  }
3537
4049
  const operator = parent.getOperatorToken().getKind();
3538
- if (operator === SyntaxKind3.AmpersandAmpersandToken && parent.getRight() === operand2) {
4050
+ if (operator === SyntaxKind7.AmpersandAmpersandToken && parent.getRight() === operand2) {
3539
4051
  fact2(db, "conditionalBranch", nodeId(parent), key);
3540
4052
  return;
3541
4053
  }
@@ -3611,7 +4123,7 @@ function valueWrittenThrough(name) {
3611
4123
  const parent = name.getParent();
3612
4124
  if (Node8.isElementAccessExpression(parent) && parent.getExpression() === name) {
3613
4125
  const assignment = parent.getParent();
3614
- return Node8.isBinaryExpression(assignment) && assignment.getLeft() === parent && assignment.getOperatorToken().getKind() === SyntaxKind4.EqualsToken ? assignment.getRight() : null;
4126
+ return Node8.isBinaryExpression(assignment) && assignment.getLeft() === parent && assignment.getOperatorToken().getKind() === SyntaxKind8.EqualsToken ? assignment.getRight() : null;
3615
4127
  }
3616
4128
  if (Node8.isPropertyAccessExpression(parent) && parent.getExpression() === name && parent.getName() === MAP_ENTRY_WRITE) {
3617
4129
  const call = parent.getParent();
@@ -3629,6 +4141,10 @@ var NOT_BASE_FACTS = /* @__PURE__ */ new Set([
3629
4141
  ...RESOLUTION_PROGRAM.rules.map((r) => r.head.relation),
3630
4142
  ...ASKING_RELATIONS
3631
4143
  ]);
4144
+ var DERIVED_RELATIONS = /* @__PURE__ */ new Set([
4145
+ ...NOT_BASE_FACTS,
4146
+ ...resolutionUnderProgram().rules.map((r) => r.head.relation)
4147
+ ]);
3632
4148
  var QUERY_FACTS = queryFacts(RESOLUTION_PROGRAM);
3633
4149
  var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
3634
4150
  (one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
@@ -3665,6 +4181,8 @@ var ResolutionStore = class _ResolutionStore {
3665
4181
  constructionSites = /* @__PURE__ */ new Map();
3666
4182
  /** What each local's reads do with it, by its declaration. A local's function is walked whole, so an answer stays true. */
3667
4183
  localUses = /* @__PURE__ */ new Map();
4184
+ /** See `remembered`. */
4185
+ answers = /* @__PURE__ */ new Map();
3668
4186
  /** Files the most recent query read, for the memo to keep. */
3669
4187
  lastQueryWalked = [];
3670
4188
  /** See `environmentSiteFiles`; null until the first env question. */
@@ -3716,12 +4234,18 @@ var ResolutionStore = class _ResolutionStore {
3716
4234
  */
3717
4235
  resolveCallableSources(value, alsoFrom) {
3718
4236
  const target = factKeyOf(value);
3719
- return this.askAbout(
3720
- target,
3721
- "wanted",
3722
- () => this.lookupSources(target),
3723
- alsoFrom
3724
- );
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
+ ];
3725
4249
  }
3726
4250
  /**
3727
4251
  * `resolveCallable` for several values, asked as one question. A file
@@ -3783,7 +4307,45 @@ var ResolutionStore = class _ResolutionStore {
3783
4307
  }
3784
4308
  resolveObject(value) {
3785
4309
  const target = factKeyOf(value);
3786
- return this.askAbout(target, "wanted", () => this.lookupObject(target));
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;
3787
4349
  }
3788
4350
  /**
3789
4351
  * The function a call returns: `app.use(requireCaller(config))`
@@ -3883,7 +4445,7 @@ var ResolutionStore = class _ResolutionStore {
3883
4445
  writtenAnswers(values, wanted) {
3884
4446
  const found = /* @__PURE__ */ new Map();
3885
4447
  const asked = /* @__PURE__ */ new Map();
3886
- const keyOf = /* @__PURE__ */ new Map();
4448
+ const keyOf2 = /* @__PURE__ */ new Map();
3887
4449
  for (const value of values) {
3888
4450
  const target = factKeyOf(value);
3889
4451
  const key = nodeId(this.sharedDeclarationFor(target));
@@ -3898,7 +4460,7 @@ var ResolutionStore = class _ResolutionStore {
3898
4460
  if (!asked.has(key)) {
3899
4461
  asked.set(key, target);
3900
4462
  }
3901
- keyOf.set(value, key);
4463
+ keyOf2.set(value, key);
3902
4464
  }
3903
4465
  if (asked.size === 0) {
3904
4466
  return found;
@@ -3913,7 +4475,7 @@ var ResolutionStore = class _ResolutionStore {
3913
4475
  });
3914
4476
  }
3915
4477
  });
3916
- for (const [value, key] of keyOf) {
4478
+ for (const [value, key] of keyOf2) {
3917
4479
  found.set(value, this.writtenValues.get(key)?.[wanted] ?? null);
3918
4480
  }
3919
4481
  return found;
@@ -5196,9 +5758,6 @@ function namesPackage2(moduleKey, packages) {
5196
5758
  packages
5197
5759
  );
5198
5760
  }
5199
- function inTestFile(node) {
5200
- return isTestFile(node.getSourceFile().getFilePath());
5201
- }
5202
5761
  function declarationOf(value) {
5203
5762
  const nameNode = Node9.isPropertyAccessExpression(value) ? value.getNameNode() : value;
5204
5763
  return nameNode.getSymbol()?.getDeclarations()[0] ?? value;
@@ -5246,12 +5805,12 @@ function forgetProgramMemos(project) {
5246
5805
  }
5247
5806
 
5248
5807
  // src/values/lowering.ts
5249
- import { Node as Node11, SyntaxKind as SyntaxKind6 } from "ts-morph";
5808
+ import { Node as Node11, SyntaxKind as SyntaxKind10 } from "ts-morph";
5250
5809
 
5251
5810
  // src/resolve/unfollowedCall.ts
5252
5811
  import {
5253
5812
  Node as Node10,
5254
- SyntaxKind as SyntaxKind5
5813
+ SyntaxKind as SyntaxKind9
5255
5814
  } from "ts-morph";
5256
5815
  import {
5257
5816
  unfollowedCallGap,
@@ -5274,14 +5833,14 @@ function isExternalDeclaration(declaration) {
5274
5833
  return true;
5275
5834
  }
5276
5835
  if (Node10.isImportSpecifier(declaration) || Node10.isImportClause(declaration) || Node10.isNamespaceImport(declaration)) {
5277
- const target = declaration.getFirstAncestorByKind(SyntaxKind5.ImportDeclaration)?.getModuleSpecifierSourceFile();
5836
+ const target = declaration.getFirstAncestorByKind(SyntaxKind9.ImportDeclaration)?.getModuleSpecifierSourceFile();
5278
5837
  return target === void 0 || isInExternalCode(target);
5279
5838
  }
5280
5839
  return declaresAnotherModule(declaration);
5281
5840
  }
5282
5841
  function declaresAnotherModule(declaration) {
5283
5842
  const module = declaration.getFirstAncestorByKind(
5284
- SyntaxKind5.ModuleDeclaration
5843
+ SyntaxKind9.ModuleDeclaration
5285
5844
  );
5286
5845
  return module !== void 0 && Node10.isStringLiteral(module.getNameNode());
5287
5846
  }
@@ -5534,7 +6093,7 @@ function expressionOf(node, originOf2) {
5534
6093
  }
5535
6094
  if (Node11.isPrefixUnaryExpression(node)) {
5536
6095
  const operator = node.getOperatorToken();
5537
- return operator === SyntaxKind6.ExclamationToken ? { kind: "operator", operator: "!", operands: [node.getOperand()] } : { kind: "opaque" };
6096
+ return operator === SyntaxKind10.ExclamationToken ? { kind: "operator", operator: "!", operands: [node.getOperand()] } : { kind: "opaque" };
5538
6097
  }
5539
6098
  if (Node11.isConditionalExpression(node)) {
5540
6099
  return {
@@ -6295,7 +6854,7 @@ function settledChannel(argument, resolution) {
6295
6854
  }
6296
6855
 
6297
6856
  // src/discovery/importedCalls.ts
6298
- import { Node as Node14 } from "ts-morph";
6857
+ import { Node as Node14, ts as ts6 } from "ts-morph";
6299
6858
  function callsResolvingTo(sourceFile, resolution, spec) {
6300
6859
  return [
6301
6860
  ...callsByOriginName(
@@ -6307,26 +6866,30 @@ function callsResolvingTo(sourceFile, resolution, spec) {
6307
6866
  ];
6308
6867
  }
6309
6868
  function callsByOriginName(sourceFile, resolution, module, names) {
6869
+ return callsNamed(importedCallOrigins(sourceFile, resolution, module), names);
6870
+ }
6871
+ function importedCallOrigins(sourceFile, resolution, module) {
6310
6872
  const candidates = [];
6311
- sourceFile.forEachDescendant((node) => {
6312
- if (!Node14.isCallExpression(node) && !Node14.isNewExpression(node)) {
6313
- return;
6314
- }
6315
- const callee = node.getExpression();
6316
- if (Node14.isIdentifier(callee) && !declaredLocally(callee)) {
6317
- candidates.push(node);
6873
+ forEachDescendantWhere(sourceFile, callsANamedCallee, (node) => {
6874
+ const call = node;
6875
+ if (!declaredLocally(call.getExpression())) {
6876
+ candidates.push(call);
6318
6877
  }
6878
+ return false;
6319
6879
  });
6320
- const matched = /* @__PURE__ */ new Map();
6321
6880
  if (candidates.length === 0) {
6322
- return matched;
6881
+ return { candidates, origins: /* @__PURE__ */ new Map() };
6323
6882
  }
6324
6883
  const origins = resolution.importOriginsOfMany(
6325
6884
  candidates.map((call) => call.getExpression()),
6326
6885
  [module]
6327
6886
  );
6328
- for (const call of candidates) {
6329
- const origin = (origins.get(call.getExpression()) ?? []).find(
6887
+ return { candidates, origins };
6888
+ }
6889
+ function callsNamed(found, names) {
6890
+ const matched = /* @__PURE__ */ new Map();
6891
+ for (const call of found.candidates) {
6892
+ const origin = (found.origins.get(call.getExpression()) ?? []).find(
6330
6893
  (one) => one.path.length === 1 && names.has(one.path[0] ?? "")
6331
6894
  );
6332
6895
  const name = origin?.path[0];
@@ -6336,6 +6899,9 @@ function callsByOriginName(sourceFile, resolution, module, names) {
6336
6899
  }
6337
6900
  return matched;
6338
6901
  }
6902
+ function callsANamedCallee(raw) {
6903
+ return (ts6.isCallExpression(raw) || ts6.isNewExpression(raw)) && ts6.isIdentifier(raw.expression);
6904
+ }
6339
6905
  function declaredLocally(callee) {
6340
6906
  const declarations = callee.getSymbol()?.getDeclarations() ?? [];
6341
6907
  return declarations.length > 0 && declarations.every(
@@ -6384,7 +6950,7 @@ function unitFor(call, func, match, kind, store, binding) {
6384
6950
  }
6385
6951
 
6386
6952
  // src/discovery/clientCall.ts
6387
- import { Node as Node15, SyntaxKind as SyntaxKind7 } from "ts-morph";
6953
+ import { Node as Node15, SyntaxKind as SyntaxKind12 } from "ts-morph";
6388
6954
  import { hasNameHole } from "@suss/behavioral-ir";
6389
6955
 
6390
6956
  // src/resolve/routePath.ts
@@ -6424,6 +6990,9 @@ function propertyValueAt(arg, property, resolution, site) {
6424
6990
 
6425
6991
  // src/discovery/importScan.ts
6426
6992
  import path4 from "path";
6993
+ import {
6994
+ SyntaxKind as SyntaxKind11
6995
+ } from "ts-morph";
6427
6996
  import { commonDirectoryOf } from "@suss/extractor";
6428
6997
  function specifierMatches(specifier, moduleName, subpaths) {
6429
6998
  if (specifier === moduleName) {
@@ -6468,7 +7037,10 @@ function importedRootsOf(sourceFile, modules, options = {}) {
6468
7037
  return roots;
6469
7038
  }
6470
7039
  function moduleImportedWholeAs(sourceFile, local) {
6471
- for (const decl of sourceFile.getImportDeclarations()) {
7040
+ for (const decl of statementsOfKind(
7041
+ sourceFile,
7042
+ SyntaxKind11.ImportDeclaration
7043
+ )) {
6472
7044
  const bound = decl.getNamespaceImport()?.getText() ?? decl.getDefaultImport()?.getText();
6473
7045
  if (bound !== local) {
6474
7046
  continue;
@@ -6479,7 +7051,10 @@ function moduleImportedWholeAs(sourceFile, local) {
6479
7051
  return null;
6480
7052
  }
6481
7053
  function specifierImportedAs(sourceFile, local) {
6482
- for (const decl of sourceFile.getImportDeclarations()) {
7054
+ for (const decl of statementsOfKind(
7055
+ sourceFile,
7056
+ SyntaxKind11.ImportDeclaration
7057
+ )) {
6483
7058
  const bound = [
6484
7059
  decl.getDefaultImport()?.getText(),
6485
7060
  decl.getNamespaceImport()?.getText(),
@@ -6510,9 +7085,11 @@ function importDeclarationsOf(sourceFile, modules, options = {}) {
6510
7085
  function matchingImportDeclarations(sourceFile, importModule, resolution, subpaths = false) {
6511
7086
  const target = isPathShapedSpecifier(importModule) ? resolvedModuleFile(sourceFile.getProject(), importModule, resolution) : null;
6512
7087
  if (target !== null) {
6513
- return sourceFile.getImportDeclarations().filter((decl) => decl.getModuleSpecifierSourceFile() === target);
7088
+ return statementsOfKind(sourceFile, SyntaxKind11.ImportDeclaration).filter(
7089
+ (decl) => decl.getModuleSpecifierSourceFile() === target
7090
+ );
6514
7091
  }
6515
- return sourceFile.getImportDeclarations().filter(
7092
+ return statementsOfKind(sourceFile, SyntaxKind11.ImportDeclaration).filter(
6516
7093
  (decl) => specifierMatches(decl.getModuleSpecifierValue(), importModule, subpaths)
6517
7094
  );
6518
7095
  }
@@ -6588,14 +7165,18 @@ function importedReferenceSpellings(sourceFile, importModule, importName) {
6588
7165
  }
6589
7166
 
6590
7167
  // src/discovery/clientCall.ts
7168
+ var CALL_KIND = /* @__PURE__ */ new Set([SyntaxKind12.CallExpression]);
7169
+ var BINDING_KINDS = /* @__PURE__ */ new Set([
7170
+ SyntaxKind12.VariableDeclaration,
7171
+ SyntaxKind12.Parameter
7172
+ ]);
6591
7173
  var GLOBAL_OBJECTS = /* @__PURE__ */ new Set(["globalThis", "window", "self", "global"]);
6592
7174
  function discoverClientCalls(sourceFile, match, kind, resolution, binding) {
6593
7175
  const results = [];
6594
7176
  const calls = [];
6595
- sourceFile.forEachDescendant((node) => {
6596
- if (Node15.isCallExpression(node)) {
6597
- calls.push(node);
6598
- }
7177
+ forEachDescendantOfKinds(sourceFile, CALL_KIND, (node) => {
7178
+ calls.push(node);
7179
+ return false;
6599
7180
  });
6600
7181
  const matched = match.importModule === "global" ? globalCallsAmong(calls, match) : clientCallsAmong(calls, match, sourceFile, resolution);
6601
7182
  for (const call of calls) {
@@ -6709,7 +7290,7 @@ function clientsBuiltAtTopLevel(sourceFile, match, resolution) {
6709
7290
  );
6710
7291
  }
6711
7292
  function sitesToReadUnder(call, binding, resolution) {
6712
- const cls = call.getFirstAncestorByKind(SyntaxKind7.ClassDeclaration);
7293
+ const cls = call.getFirstAncestorByKind(SyntaxKind12.ClassDeclaration);
6713
7294
  if (binding === void 0 || resolution === void 0 || cls === void 0) {
6714
7295
  return [void 0];
6715
7296
  }
@@ -6797,7 +7378,7 @@ function clientReceiverCheckFor(sourceFile, match, resolution) {
6797
7378
  );
6798
7379
  const constructedHere = /* @__PURE__ */ new Set();
6799
7380
  const initializedBy = /* @__PURE__ */ new Map();
6800
- sourceFile.forEachDescendant((node) => {
7381
+ const visit = (node) => {
6801
7382
  if (Node15.isVariableDeclaration(node)) {
6802
7383
  const init = node.getInitializer();
6803
7384
  if (init !== void 0 && (Node15.isCallExpression(init) || Node15.isNewExpression(init))) {
@@ -6806,7 +7387,7 @@ function clientReceiverCheckFor(sourceFile, match, resolution) {
6806
7387
  if (localName !== null && typedAsClient(node.getTypeNode(), localName)) {
6807
7388
  constructedHere.add(node.getName());
6808
7389
  }
6809
- return;
7390
+ return false;
6810
7391
  }
6811
7392
  if (Node15.isParameterDeclaration(node) && localName !== null && typedAsClient(node.getTypeNode(), localName)) {
6812
7393
  const written = node.getNameNode();
@@ -6814,7 +7395,9 @@ function clientReceiverCheckFor(sourceFile, match, resolution) {
6814
7395
  constructedHere.add(written.getText());
6815
7396
  }
6816
7397
  }
6817
- });
7398
+ return false;
7399
+ };
7400
+ forEachDescendantOfKinds(sourceFile, BINDING_KINDS, visit, skipsNothing);
6818
7401
  const creating = creationCallsAmong(
6819
7402
  [...initializedBy.keys()],
6820
7403
  match,
@@ -7011,7 +7594,7 @@ function callableOf(member) {
7011
7594
  }
7012
7595
 
7013
7596
  // src/discovery/decoratorComposition.ts
7014
- import { Node as Node17, SyntaxKind as SyntaxKind8 } from "ts-morph";
7597
+ import { Node as Node17, SyntaxKind as SyntaxKind13 } from "ts-morph";
7015
7598
  function classDecoratorStandingFor(cls, names, modules, resolution) {
7016
7599
  for (const candidate of names) {
7017
7600
  const decorator = cls.getDecorator(candidate);
@@ -7049,7 +7632,7 @@ function frameworkArgs(decorator, standsFor, modules, resolution) {
7049
7632
  if (wrapper === null) {
7050
7633
  return atClass;
7051
7634
  }
7052
- for (const call of wrapper.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
7635
+ for (const call of wrapper.getDescendantsOfKind(SyntaxKind13.CallExpression)) {
7053
7636
  const names = resolution.importedNamesOf(call.getExpression(), modules);
7054
7637
  if (!names.includes(standsFor)) {
7055
7638
  continue;
@@ -7060,7 +7643,7 @@ function frameworkArgs(decorator, standsFor, modules, resolution) {
7060
7643
  return atClass;
7061
7644
  }
7062
7645
  function statesAValue(arg, wrapper) {
7063
- const identifiers = Node17.isIdentifier(arg) ? [arg] : arg.getDescendantsOfKind(SyntaxKind8.Identifier);
7646
+ const identifiers = Node17.isIdentifier(arg) ? [arg] : arg.getDescendantsOfKind(SyntaxKind13.Identifier);
7064
7647
  return !identifiers.some(
7065
7648
  (identifier) => identifier.getSymbol()?.getDeclarations().some(
7066
7649
  (declaration) => Node17.isParameterDeclaration(declaration) && isWithin(declaration, wrapper)
@@ -7798,7 +8381,8 @@ import picomatch from "picomatch";
7798
8381
 
7799
8382
  // src/discovery/namedExport.ts
7800
8383
  import {
7801
- Node as Node27
8384
+ Node as Node27,
8385
+ SyntaxKind as SyntaxKind15
7802
8386
  } from "ts-morph";
7803
8387
 
7804
8388
  // src/discovery/wrappedExport.ts
@@ -7808,7 +8392,7 @@ import { Node as Node26 } from "ts-morph";
7808
8392
  import { Node as Node23 } from "ts-morph";
7809
8393
 
7810
8394
  // src/walk/descent.ts
7811
- import { Node as Node22 } from "ts-morph";
8395
+ import { Node as Node22, SyntaxKind as SyntaxKind14 } from "ts-morph";
7812
8396
  var NO_BARRIERS = /* @__PURE__ */ new Set();
7813
8397
  function isDescentStop(node, func, barriers = NO_BARRIERS) {
7814
8398
  if (node === func) {
@@ -7822,24 +8406,16 @@ function isDescentStop(node, func, barriers = NO_BARRIERS) {
7822
8406
  }
7823
8407
  return false;
7824
8408
  }
7825
- function forEachInUnitBody(root, visit) {
7826
- root.forEachDescendant(visit);
8409
+ function forEachInUnitBodyOfKinds(root, kinds, visit) {
8410
+ forEachInUnitBodyWhere(root, (raw) => kinds.has(raw.kind), visit);
8411
+ }
8412
+ function forEachInUnitBodyWhere(root, accepts, visit) {
8413
+ forEachDescendantWhere(root, accepts, visit);
7827
8414
  for (const initializer of fieldInitializersRunBy(root)) {
7828
- let skipped = false;
7829
- visit(initializer, {
7830
- stop: () => {
7831
- skipped = true;
7832
- },
7833
- skip: () => {
7834
- skipped = true;
7835
- },
7836
- up: () => {
7837
- skipped = true;
7838
- }
7839
- });
7840
- if (!skipped) {
7841
- initializer.forEachDescendant(visit);
8415
+ if (accepts(initializer.compilerNode) && visit(initializer)) {
8416
+ continue;
7842
8417
  }
8418
+ forEachDescendantWhere(initializer, accepts, visit);
7843
8419
  }
7844
8420
  }
7845
8421
  function fieldInitializersRunBy(root) {
@@ -7868,6 +8444,19 @@ function isInlineCallback(node, func, barriers = NO_BARRIERS) {
7868
8444
  }
7869
8445
  return !barriers.has(node);
7870
8446
  }
8447
+ var DESCENT_STOP_KINDS = /* @__PURE__ */ new Set([
8448
+ SyntaxKind14.FunctionDeclaration,
8449
+ SyntaxKind14.MethodDeclaration,
8450
+ SyntaxKind14.Constructor,
8451
+ SyntaxKind14.ArrowFunction,
8452
+ SyntaxKind14.FunctionExpression,
8453
+ SyntaxKind14.ClassDeclaration,
8454
+ SyntaxKind14.ClassExpression,
8455
+ SyntaxKind14.Decorator
8456
+ ]);
8457
+ function withDescentStops(...kinds) {
8458
+ return /* @__PURE__ */ new Set([...DESCENT_STOP_KINDS, ...kinds]);
8459
+ }
7871
8460
  function isModuleScopeStop(node) {
7872
8461
  if (isImmediatelyInvoked(node)) {
7873
8462
  return false;
@@ -7896,11 +8485,17 @@ function crossesNestedFunctionScope(node, func) {
7896
8485
  return false;
7897
8486
  }
7898
8487
  function startsItsOwnScope(node) {
7899
- return Node22.isArrowFunction(node) || Node22.isFunctionExpression(node) || Node22.isFunctionDeclaration(node) || Node22.isMethodDeclaration(node) || Node22.isGetAccessorDeclaration(node) || Node22.isSetAccessorDeclaration(node) || Node22.isConstructorDeclaration(node);
7900
- }
7901
- function containsNoCode(node) {
7902
- return Node22.isTypeNode(node) && !Node22.isExpressionWithTypeArguments(node);
7903
- }
8488
+ return OWN_SCOPE_KINDS.has(node.getKind());
8489
+ }
8490
+ var OWN_SCOPE_KINDS = /* @__PURE__ */ new Set([
8491
+ SyntaxKind14.ArrowFunction,
8492
+ SyntaxKind14.FunctionExpression,
8493
+ SyntaxKind14.FunctionDeclaration,
8494
+ SyntaxKind14.MethodDeclaration,
8495
+ SyntaxKind14.GetAccessor,
8496
+ SyntaxKind14.SetAccessor,
8497
+ SyntaxKind14.Constructor
8498
+ ]);
7904
8499
 
7905
8500
  // src/parameterReads.ts
7906
8501
  function pathAbove(reference) {
@@ -8710,7 +9305,7 @@ function evaluateObjectLiteralAsJson(node) {
8710
9305
  return node.getLiteralValue();
8711
9306
  }
8712
9307
  if (Node25.isNumericLiteral(node)) {
8713
- return Number(node.getText());
9308
+ return node.getLiteralValue();
8714
9309
  }
8715
9310
  const kind = node.getText();
8716
9311
  if (kind === "true") {
@@ -9101,7 +9696,10 @@ function discoverNamedExports(sourceFile, match, kind, resolution, options = {})
9101
9696
  return results;
9102
9697
  }
9103
9698
  function defaultExportUnits(sourceFile, kind, resolution, options) {
9104
- for (const assignment of sourceFile.getExportAssignments()) {
9699
+ for (const assignment of statementsOfKind(
9700
+ sourceFile,
9701
+ SyntaxKind15.ExportAssignment
9702
+ )) {
9105
9703
  if (assignment.isExportEquals()) {
9106
9704
  continue;
9107
9705
  }
@@ -9215,6 +9813,9 @@ function expandParameter(parameter, forwardsResult, depth, expanded, context, ch
9215
9813
  const units = [];
9216
9814
  let unfollowed = 0;
9217
9815
  for (const { call, argument } of passed) {
9816
+ if (testCallingProduction(call, parameter)) {
9817
+ continue;
9818
+ }
9218
9819
  const caller = enclosingFunctionRoot(call);
9219
9820
  if (caller === null || !Node28.isCallExpression(call)) {
9220
9821
  unfollowed++;
@@ -10022,7 +10623,7 @@ function sameDeclaration(a, b) {
10022
10623
  }
10023
10624
 
10024
10625
  // src/discovery/factorySurface.ts
10025
- import { Node as Node32, SyntaxKind as SyntaxKind9 } from "ts-morph";
10626
+ import { Node as Node32, SyntaxKind as SyntaxKind16 } from "ts-morph";
10026
10627
  var MAX_BUILDER_HOPS = 2;
10027
10628
  function surfaceMethods(decl, resolution) {
10028
10629
  if (Node32.isClassDeclaration(decl)) {
@@ -10037,7 +10638,7 @@ function surfaceClassMethods(cls) {
10037
10638
  const out = [];
10038
10639
  const seen = /* @__PURE__ */ new Set();
10039
10640
  for (const method of cls.getInstanceMethods()) {
10040
- if (method.hasModifier(SyntaxKind9.PrivateKeyword)) {
10641
+ if (method.hasModifier(SyntaxKind16.PrivateKeyword)) {
10041
10642
  continue;
10042
10643
  }
10043
10644
  const name = method.getName();
@@ -10048,7 +10649,7 @@ function surfaceClassMethods(cls) {
10048
10649
  out.push({ func: method, name });
10049
10650
  }
10050
10651
  for (const method of cls.getStaticMethods()) {
10051
- if (method.hasModifier(SyntaxKind9.PrivateKeyword)) {
10652
+ if (method.hasModifier(SyntaxKind16.PrivateKeyword)) {
10052
10653
  continue;
10053
10654
  }
10054
10655
  const name = method.getName();
@@ -10831,7 +11432,7 @@ function creationSiteBehind(parameter, resolution) {
10831
11432
  }
10832
11433
  function registrationSubjectIdsOf(sourceFile, matches, resolution) {
10833
11434
  const seenImports = /* @__PURE__ */ new Set();
10834
- const ids = /* @__PURE__ */ new Set();
11435
+ const ids2 = /* @__PURE__ */ new Set();
10835
11436
  for (const match of matches) {
10836
11437
  const importKey = `${match.importModule}::${match.importName}`;
10837
11438
  if (seenImports.has(importKey)) {
@@ -10844,17 +11445,17 @@ function registrationSubjectIdsOf(sourceFile, matches, resolution) {
10844
11445
  match.importName,
10845
11446
  resolution
10846
11447
  ).values()) {
10847
- ids.add(nodeId(node));
11448
+ ids2.add(nodeId(node));
10848
11449
  }
10849
11450
  for (const node of unboundConstructionsOf(
10850
11451
  sourceFile,
10851
11452
  match.importModule,
10852
11453
  match.importName
10853
11454
  )) {
10854
- ids.add(nodeId(node));
11455
+ ids2.add(nodeId(node));
10855
11456
  }
10856
11457
  }
10857
- return ids;
11458
+ return ids2;
10858
11459
  }
10859
11460
  function unboundConstructionsOf(sourceFile, importModule, importName) {
10860
11461
  const spellings = importedReferenceSpellings(
@@ -11882,7 +12483,7 @@ function constructorCalledAt(construction) {
11882
12483
  }
11883
12484
  function baseConstructorCalledAt(superKeyword) {
11884
12485
  const owner = superKeyword.getFirstAncestorByKind(
11885
- SyntaxKind10.ClassDeclaration
12486
+ SyntaxKind17.ClassDeclaration
11886
12487
  );
11887
12488
  const base = owner?.getBaseClass();
11888
12489
  return base === void 0 ? null : constructorOf(base);
@@ -12088,7 +12689,7 @@ function shapeFromDeclaration(decl, extractShape2, ctx) {
12088
12689
  return enterShape(init, extractShape2, ctx);
12089
12690
  }
12090
12691
  if (Node42.isBindingElement(decl)) {
12091
- const varDecl = decl.getFirstAncestorByKind(SyntaxKind11.VariableDeclaration);
12692
+ const varDecl = decl.getFirstAncestorByKind(SyntaxKind18.VariableDeclaration);
12092
12693
  if (!varDecl) {
12093
12694
  return null;
12094
12695
  }
@@ -12174,7 +12775,7 @@ function isInformativeInitializer(node) {
12174
12775
  return isInformativeInitializer(unwrapped2.getOperand());
12175
12776
  }
12176
12777
  const kind = unwrapped2.getKind();
12177
- return kind === SyntaxKind11.TrueKeyword || kind === SyntaxKind11.FalseKeyword || kind === SyntaxKind11.NullKeyword;
12778
+ return kind === SyntaxKind18.TrueKeyword || kind === SyntaxKind18.FalseKeyword || kind === SyntaxKind18.NullKeyword;
12178
12779
  }
12179
12780
  function resolveCallableBody(callee) {
12180
12781
  if (!Node42.isIdentifier(callee)) {
@@ -12523,7 +13124,7 @@ function parseConditionExpression(expr, depth = 0) {
12523
13124
  }
12524
13125
  }
12525
13126
  if (Node45.isPrefixUnaryExpression(expr)) {
12526
- if (expr.getOperatorToken() !== SyntaxKind12.ExclamationToken) {
13127
+ if (expr.getOperatorToken() !== SyntaxKind19.ExclamationToken) {
12527
13128
  return null;
12528
13129
  }
12529
13130
  const operand2 = expr.getOperand();
@@ -12551,7 +13152,7 @@ function parseConditionExpression(expr, depth = 0) {
12551
13152
  const right = expr.getRight();
12552
13153
  const opToken = expr.getOperatorToken();
12553
13154
  const opText = opToken.getText();
12554
- if (opToken.getKind() === SyntaxKind12.AmpersandAmpersandToken) {
13155
+ if (opToken.getKind() === SyntaxKind19.AmpersandAmpersandToken) {
12555
13156
  const leftPred = parseConditionExpression(left, depth);
12556
13157
  const rightPred = parseConditionExpression(right, depth);
12557
13158
  return {
@@ -12563,7 +13164,7 @@ function parseConditionExpression(expr, depth = 0) {
12563
13164
  ]
12564
13165
  };
12565
13166
  }
12566
- if (opToken.getKind() === SyntaxKind12.BarBarToken) {
13167
+ if (opToken.getKind() === SyntaxKind19.BarBarToken) {
12567
13168
  const leftPred = parseConditionExpression(left, depth);
12568
13169
  const rightPred = parseConditionExpression(right, depth);
12569
13170
  return {
@@ -12575,11 +13176,11 @@ function parseConditionExpression(expr, depth = 0) {
12575
13176
  ]
12576
13177
  };
12577
13178
  }
12578
- if (opToken.getKind() === SyntaxKind12.InstanceOfKeyword) {
13179
+ if (opToken.getKind() === SyntaxKind19.InstanceOfKeyword) {
12579
13180
  const subject = resolveSubject(left);
12580
13181
  return { type: "typeCheck", subject, expectedType: right.getText() };
12581
13182
  }
12582
- if (opToken.getKind() === SyntaxKind12.InKeyword) {
13183
+ if (opToken.getKind() === SyntaxKind19.InKeyword) {
12583
13184
  if (Node45.isStringLiteral(left)) {
12584
13185
  const subject = resolveSubject(right);
12585
13186
  return {
@@ -12896,7 +13497,7 @@ function collectFallthroughCaseLabels(caseClause) {
12896
13497
  }
12897
13498
 
12898
13499
  // src/paths/pathConditions.ts
12899
- import { Node as Node48 } from "ts-morph";
13500
+ import { Node as Node48, SyntaxKind as SyntaxKind21 } from "ts-morph";
12900
13501
  import {
12901
13502
  enumerateStructuredPaths,
12902
13503
  PathBudgetExceeded,
@@ -12906,7 +13507,9 @@ import {
12906
13507
 
12907
13508
  // src/paths/lowering.ts
12908
13509
  import {
12909
- Node as Node47
13510
+ Node as Node47,
13511
+ SyntaxKind as SyntaxKind20,
13512
+ ts as ts7
12910
13513
  } from "ts-morph";
12911
13514
  import {
12912
13515
  UnmodeledFlow
@@ -12915,24 +13518,25 @@ var NO_ENDINGS = /* @__PURE__ */ new Set();
12915
13518
  function exitKindOf(stmt, endings) {
12916
13519
  let sawReturn = false;
12917
13520
  let sawThrow = false;
12918
- const visit = (node) => {
12919
- if (node !== stmt && startsItsOwnScope(node)) {
12920
- return;
13521
+ const ending = new Set([...endings].map((node) => node.compilerNode));
13522
+ const root = stmt.compilerNode;
13523
+ const visit = (raw) => {
13524
+ if (raw !== root && OWN_SCOPE_KINDS.has(raw.kind)) {
13525
+ return void 0;
12921
13526
  }
12922
- if (containsNoCode(node)) {
12923
- return;
13527
+ if (runsNothing(raw)) {
13528
+ return void 0;
12924
13529
  }
12925
- if (Node47.isReturnStatement(node) || endings.has(node)) {
13530
+ if (raw.kind === SyntaxKind20.ReturnStatement || ending.has(raw)) {
12926
13531
  sawReturn = true;
12927
13532
  }
12928
- if (Node47.isThrowStatement(node)) {
13533
+ if (raw.kind === SyntaxKind20.ThrowStatement) {
12929
13534
  sawThrow = true;
12930
13535
  }
12931
- for (const child of node.getChildren()) {
12932
- visit(child);
12933
- }
13536
+ ts7.forEachChild(raw, visit);
13537
+ return void 0;
12934
13538
  };
12935
- visit(stmt);
13539
+ visit(root);
12936
13540
  if (sawThrow) {
12937
13541
  return "throw";
12938
13542
  }
@@ -12947,7 +13551,20 @@ var statementsOf = (stmt) => {
12947
13551
  }
12948
13552
  return [stmt];
12949
13553
  };
12950
- var isLoop = (stmt) => Node47.isForOfStatement(stmt) || Node47.isForInStatement(stmt) || Node47.isForStatement(stmt) || Node47.isWhileStatement(stmt) || Node47.isDoStatement(stmt);
13554
+ var LOOP_KINDS = /* @__PURE__ */ new Set([
13555
+ SyntaxKind20.ForOfStatement,
13556
+ SyntaxKind20.ForInStatement,
13557
+ SyntaxKind20.ForStatement,
13558
+ SyntaxKind20.WhileStatement,
13559
+ SyntaxKind20.DoStatement
13560
+ ]);
13561
+ var isLoop = (stmt) => LOOP_KINDS.has(stmt.getKind());
13562
+ var CLAUSE_BREAK_KINDS = /* @__PURE__ */ new Set([
13563
+ ...OWN_SCOPE_KINDS,
13564
+ ...LOOP_KINDS,
13565
+ SyntaxKind20.SwitchStatement,
13566
+ SyntaxKind20.BreakStatement
13567
+ ]);
12951
13568
  function getLoopBody(stmt) {
12952
13569
  if (Node47.isForOfStatement(stmt) || Node47.isForInStatement(stmt) || Node47.isForStatement(stmt) || Node47.isWhileStatement(stmt) || Node47.isDoStatement(stmt)) {
12953
13570
  return stmt.getStatement();
@@ -13006,28 +13623,33 @@ function ownExpressionsOf(stmt) {
13006
13623
  }
13007
13624
  function lowerCallbacksIn(parts, ctx) {
13008
13625
  const bodies = [];
13009
- const visit = (node, root) => {
13010
- if (node !== root && isDescentStop(node, ctx.func, ctx.barriers)) {
13011
- return;
13012
- }
13013
- if (node !== root && (Node47.isArrowFunction(node) || Node47.isFunctionExpression(node)) && isInlineCallback(node, ctx.func, ctx.barriers)) {
13014
- const body = node.getBody();
13015
- if (body !== void 0 && Node47.isBlock(body)) {
13016
- bodies.push(lowerList(body.getStatements(), ctx));
13017
- return;
13018
- }
13019
- } else if (node !== root && startsItsOwnScope(node)) {
13020
- return;
13626
+ const entersScope = (node) => {
13627
+ if (isDescentStop(node, ctx.func, ctx.barriers)) {
13628
+ return false;
13021
13629
  }
13022
- if (containsNoCode(node)) {
13023
- return;
13630
+ if (!(Node47.isArrowFunction(node) || Node47.isFunctionExpression(node)) || !isInlineCallback(node, ctx.func, ctx.barriers)) {
13631
+ return !startsItsOwnScope(node);
13024
13632
  }
13025
- for (const child of node.getChildren()) {
13026
- visit(child, root);
13633
+ const body = node.getBody();
13634
+ if (body !== void 0 && Node47.isBlock(body)) {
13635
+ bodies.push(lowerList(body.getStatements(), ctx));
13636
+ return false;
13027
13637
  }
13638
+ return true;
13028
13639
  };
13029
13640
  for (const part of parts) {
13030
- visit(part, part);
13641
+ const root = part.compilerNode;
13642
+ const visit = (raw) => {
13643
+ if (raw !== root && OWN_SCOPE_KINDS.has(raw.kind) && !entersScope(wrapperOf(part, raw))) {
13644
+ return void 0;
13645
+ }
13646
+ if (runsNothing(raw)) {
13647
+ return void 0;
13648
+ }
13649
+ ts7.forEachChild(raw, visit);
13650
+ return void 0;
13651
+ };
13652
+ visit(root);
13031
13653
  }
13032
13654
  return bodies;
13033
13655
  }
@@ -13149,14 +13771,11 @@ function validateClauseBreaks(stmts) {
13149
13771
  if (Node47.isSwitchStatement(stmt) || isLoop(stmt)) {
13150
13772
  continue;
13151
13773
  }
13152
- stmt.forEachDescendant((node, traversal) => {
13153
- if (startsItsOwnScope(node) || Node47.isSwitchStatement(node) || isLoop(node)) {
13154
- traversal.skip();
13155
- return;
13156
- }
13774
+ forEachDescendantOfKinds(stmt, CLAUSE_BREAK_KINDS, (node) => {
13157
13775
  if (Node47.isBreakStatement(node)) {
13158
13776
  throw new UnmodeledFlow("non-trailing break in switch clause");
13159
13777
  }
13778
+ return true;
13160
13779
  });
13161
13780
  if (Node47.isBreakStatement(stmt)) {
13162
13781
  throw new UnmodeledFlow("non-trailing break in switch clause");
@@ -13211,18 +13830,20 @@ function enclosingLoweredStatement(terminal, body, rawToStructured) {
13211
13830
  // src/paths/pathConditions.ts
13212
13831
  function containsUnmodeledFlow(body, func, barriers) {
13213
13832
  let found = false;
13214
- body.forEachDescendant((node, traversal) => {
13215
- if (isDescentStop(node, func, barriers)) {
13216
- traversal.skip();
13217
- return;
13218
- }
13219
- if (Node48.isLabeledStatement(node)) {
13220
- found = true;
13221
- traversal.stop();
13833
+ forEachDescendantWhere(
13834
+ body,
13835
+ (raw) => !found && LABELS_AND_STOPS.has(raw.kind),
13836
+ (node) => {
13837
+ if (isDescentStop(node, func, barriers)) {
13838
+ return true;
13839
+ }
13840
+ found = Node48.isLabeledStatement(node);
13841
+ return found;
13222
13842
  }
13223
- });
13843
+ );
13224
13844
  return found;
13225
13845
  }
13846
+ var LABELS_AND_STOPS = withDescentStops(SyntaxKind21.LabeledStatement);
13226
13847
  function loweredExpressionBody(body, terminalNodes, func, barriers) {
13227
13848
  const statement = {
13228
13849
  kind: "opaque",
@@ -13359,151 +13980,49 @@ function refsOf(found, func, resolution) {
13359
13980
  textAt: (key) => nodes.get(key)?.getText() ?? null
13360
13981
  };
13361
13982
  return sourceRefsOf(
13362
- found.map((one) => one.leaf),
13363
- spelling
13364
- );
13365
- }
13366
- function inputOf(found, func) {
13367
- const { leaf, node, parameterOf } = found;
13368
- if (node !== null && Node49.isBindingElement(node)) {
13369
- return boundByParameterOf(node, func) ? { type: "input", inputRef: node.getName(), path: leaf.path } : null;
13370
- }
13371
- if (parameterOf !== func || node === null || !Node49.isParameterDeclaration(node)) {
13372
- return null;
13373
- }
13374
- const name = node.getNameNode();
13375
- return Node49.isIdentifier(name) ? { type: "input", inputRef: name.getText(), path: leaf.path } : null;
13376
- }
13377
- function boundByParameterOf(element, func) {
13378
- const parameter = element.getParent().getParent();
13379
- return Node49.isParameterDeclaration(parameter) && parameter.getParent() === func;
13380
- }
13381
- function literalAt(node, resolution) {
13382
- return node === void 0 ? void 0 : constantOf4(evaluatedValue(node, resolution));
13383
- }
13384
-
13385
- // src/resolve/invocationEffects.ts
13386
- import {
13387
- Node as Node54,
13388
- VariableDeclarationKind as VariableDeclarationKind2
13389
- } from "ts-morph";
13390
- import {
13391
- numberRepeatedCallSites,
13392
- rawConditionToPredicate
13393
- } from "@suss/extractor";
13394
-
13395
- // src/resolve/callOps.ts
13396
- import { Node as Node53 } from "ts-morph";
13397
-
13398
- // src/configuredCall.ts
13399
- import { Node as Node51 } from "ts-morph";
13400
-
13401
- // src/values/receiverType.ts
13402
- import { Node as Node50 } from "ts-morph";
13403
-
13404
- // src/shapes/typeText.ts
13405
- import { ts as ts3 } from "ts-morph";
13406
- var PRINTER = ts3.createPrinter({
13407
- removeComments: true,
13408
- newLine: ts3.NewLineKind.LineFeed
13409
- });
13410
- var NO_FILE = ts3.createSourceFile("", "", ts3.ScriptTarget.Latest);
13411
- function defaultFlags(enclosing) {
13412
- const flags = ts3.TypeFormatFlags.UseTypeOfFunction | ts3.TypeFormatFlags.NoTruncation | ts3.TypeFormatFlags.UseFullyQualifiedType | ts3.TypeFormatFlags.WriteTypeArgumentsOfSignature;
13413
- if (enclosing?.getKind() === ts3.SyntaxKind.TypeAliasDeclaration) {
13414
- return flags | ts3.TypeFormatFlags.InTypeAlias;
13415
- }
13416
- return flags;
13417
- }
13418
- function stableTypeText(type, reader, enclosing, flags) {
13419
- const checker = reader.getProject().getTypeChecker().compilerObject;
13420
- const format = flags ?? defaultFlags(enclosing);
13421
- const enclosingNode = enclosing?.compilerNode;
13422
- const typeNode = checker.typeToTypeNode(
13423
- type.compilerType,
13424
- enclosingNode,
13425
- format & ts3.TypeFormatFlags.NodeBuilderFlagsMask | ts3.NodeBuilderFlags.IgnoreErrors
13426
- );
13427
- if (typeNode === void 0) {
13428
- return withoutImportQualifiers(
13429
- checker.typeToString(type.compilerType, enclosingNode, format)
13430
- );
13431
- }
13432
- const file = enclosing?.getSourceFile().compilerNode ?? NO_FILE;
13433
- const ordered = containsUnion(typeNode) ? withUnionMembersOrdered(typeNode, file) : typeNode;
13434
- return withoutImportQualifiers(printed(ordered, file));
13435
- }
13436
- var IMPORT_QUALIFIER = /import\("[^"]*"\)\./g;
13437
- var withoutImportQualifiers = (text3) => text3.replace(IMPORT_QUALIFIER, "");
13438
- function printed(node, file) {
13439
- return PRINTER.printNode(ts3.EmitHint.Unspecified, node, file).replace(
13440
- /\n/g,
13441
- ""
13442
- );
13443
- }
13444
- function containsUnion(node) {
13445
- if (ts3.isUnionTypeNode(node)) {
13446
- return true;
13447
- }
13448
- return ts3.forEachChild(node, (child) => containsUnion(child) || void 0) === true;
13449
- }
13450
- function withUnionMembersOrdered(root, file) {
13451
- const result = ts3.transform(root, [
13452
- (context) => {
13453
- const visit = (node) => {
13454
- const visited = ts3.visitEachChild(node, visit, context);
13455
- if (!ts3.isUnionTypeNode(visited)) {
13456
- return visited;
13457
- }
13458
- return context.factory.updateUnionTypeNode(
13459
- visited,
13460
- context.factory.createNodeArray(inStableOrder(visited.types, file))
13461
- );
13462
- };
13463
- return (node) => visit(node);
13464
- }
13465
- ]);
13466
- const [ordered] = result.transformed;
13467
- result.dispose();
13468
- return ordered;
13469
- }
13470
- function inStableOrder(members, file) {
13471
- return members.map((member) => ({
13472
- member,
13473
- text: withoutImportQualifiers(printed(member, file))
13474
- })).sort((a, b) => compareMembers(a.text, b.text)).map(({ member }) => member);
13475
- }
13476
- function compareMembers(a, b) {
13477
- return nullishRank(a) - nullishRank(b) || compareText(a, b);
13983
+ found.map((one) => one.leaf),
13984
+ spelling
13985
+ );
13478
13986
  }
13479
- function nullishRank(text3) {
13480
- if (text3 === "null") {
13481
- return 1;
13987
+ function inputOf(found, func) {
13988
+ const { leaf, node, parameterOf } = found;
13989
+ if (node !== null && Node49.isBindingElement(node)) {
13990
+ return boundByParameterOf(node, func) ? { type: "input", inputRef: node.getName(), path: leaf.path } : null;
13482
13991
  }
13483
- if (text3 === "undefined") {
13484
- return 2;
13992
+ if (parameterOf !== func || node === null || !Node49.isParameterDeclaration(node)) {
13993
+ return null;
13485
13994
  }
13486
- return 0;
13995
+ const name = node.getNameNode();
13996
+ return Node49.isIdentifier(name) ? { type: "input", inputRef: name.getText(), path: leaf.path } : null;
13487
13997
  }
13488
- function compareText(a, b) {
13489
- if (a < b) {
13490
- return -1;
13491
- }
13492
- if (a > b) {
13493
- return 1;
13494
- }
13495
- return 0;
13998
+ function boundByParameterOf(element, func) {
13999
+ const parameter = element.getParent().getParent();
14000
+ return Node49.isParameterDeclaration(parameter) && parameter.getParent() === func;
13496
14001
  }
13497
- function stablePropertyName(symbol, reader) {
13498
- const name = symbol.getName();
13499
- if (!name.startsWith("__@")) {
13500
- return name;
13501
- }
13502
- const checker = reader.getProject().getTypeChecker().compilerObject;
13503
- return checker.symbolToString(symbol.compilerSymbol);
14002
+ function literalAt(node, resolution) {
14003
+ return node === void 0 ? void 0 : constantOf4(evaluatedValue(node, resolution));
13504
14004
  }
13505
14005
 
14006
+ // src/resolve/invocationEffects.ts
14007
+ import {
14008
+ Node as Node54,
14009
+ SyntaxKind as SyntaxKind23,
14010
+ ts as ts8,
14011
+ VariableDeclarationKind as VariableDeclarationKind2
14012
+ } from "ts-morph";
14013
+ import {
14014
+ numberRepeatedCallSites,
14015
+ rawConditionToPredicate
14016
+ } from "@suss/extractor";
14017
+
14018
+ // src/resolve/callOps.ts
14019
+ import { Node as Node53 } from "ts-morph";
14020
+
14021
+ // src/configuredCall.ts
14022
+ import { Node as Node51 } from "ts-morph";
14023
+
13506
14024
  // src/values/receiverType.ts
14025
+ import { Node as Node50 } from "ts-morph";
13507
14026
  function receiverTypesOf(node) {
13508
14027
  const type = node.getType();
13509
14028
  if (type.isAny()) {
@@ -13650,7 +14169,7 @@ function rootIdentifier(node) {
13650
14169
  }
13651
14170
 
13652
14171
  // src/resolve/readName.ts
13653
- import { Node as Node52, SyntaxKind as SyntaxKind13 } from "ts-morph";
14172
+ import { Node as Node52, SyntaxKind as SyntaxKind22 } from "ts-morph";
13654
14173
  import { patternHole, referenceName } from "@suss/behavioral-ir";
13655
14174
  var MAX_HELPER_HOPS = 2;
13656
14175
  var UNNAMED_HOLE = "param";
@@ -13748,7 +14267,7 @@ function isFallbackBranch(node) {
13748
14267
  return false;
13749
14268
  }
13750
14269
  const operator = step.getOperatorToken().getKind();
13751
- return operator === SyntaxKind13.BarBarToken || operator === SyntaxKind13.QuestionQuestionToken;
14270
+ return operator === SyntaxKind22.BarBarToken || operator === SyntaxKind22.QuestionQuestionToken;
13752
14271
  }
13753
14272
  function fromTemplate(expr, ctx) {
13754
14273
  if (!Node52.isTemplateExpression(expr)) {
@@ -13766,10 +14285,10 @@ function fromBinary(expr, ctx) {
13766
14285
  return null;
13767
14286
  }
13768
14287
  const operator = expr.getOperatorToken().getKind();
13769
- if (operator === SyntaxKind13.BarBarToken || operator === SyntaxKind13.QuestionQuestionToken) {
14288
+ if (operator === SyntaxKind22.BarBarToken || operator === SyntaxKind22.QuestionQuestionToken) {
13770
14289
  return ctx.insideHole ? null : read(expr.getRight(), ctx);
13771
14290
  }
13772
- if (operator !== SyntaxKind13.PlusToken) {
14291
+ if (operator !== SyntaxKind22.PlusToken) {
13773
14292
  return null;
13774
14293
  }
13775
14294
  const parts = { ...ctx, insideHole: true };
@@ -14483,16 +15002,32 @@ function extractInvocationEffectsAtModuleScope(sourceFile) {
14483
15002
  (call) => !invokesFunctionInPlace(call.node)
14484
15003
  );
14485
15004
  }
15005
+ var CALLS_AND_STOPS = withDescentStops(SyntaxKind23.CallExpression);
15006
+ var ACCESSES_CONSTRUCTIONS_AND_STOPS = withDescentStops(
15007
+ SyntaxKind23.PropertyAccessExpression,
15008
+ SyntaxKind23.CallExpression,
15009
+ SyntaxKind23.TaggedTemplateExpression,
15010
+ SyntaxKind23.NewExpression
15011
+ );
15012
+ var INVOCATIONS_AND_STOPS = withDescentStops(
15013
+ SyntaxKind23.CallExpression,
15014
+ SyntaxKind23.NewExpression
15015
+ );
15016
+ var ACCESSES_AND_STOPS = withDescentStops(
15017
+ SyntaxKind23.PropertyAccessExpression,
15018
+ SyntaxKind23.CallExpression,
15019
+ SyntaxKind23.TaggedTemplateExpression
15020
+ );
14486
15021
  function invocationsUnder(root, isStop) {
14487
15022
  const calls = [];
14488
- forEachInUnitBody(root, (node, traversal) => {
15023
+ forEachInUnitBodyOfKinds(root, INVOCATIONS_AND_STOPS, (node) => {
14489
15024
  if (isStop(node)) {
14490
- traversal.skip();
14491
- return;
15025
+ return true;
14492
15026
  }
14493
15027
  if (Node54.isCallExpression(node) || runsProjectConstructor(node)) {
14494
15028
  calls.push(node);
14495
15029
  }
15030
+ return false;
14496
15031
  });
14497
15032
  calls.sort((a, b) => a.getEnd() - b.getEnd());
14498
15033
  return calls.map((call) => invocationAt(call, root));
@@ -14530,14 +15065,14 @@ function runInvocationRecognizers(func, recognizers, barriers = NO_BARRIERS, res
14530
15065
  const sites = [];
14531
15066
  const sourceFile = func.getSourceFile();
14532
15067
  const calls = [];
14533
- forEachInUnitBody(func, (node, traversal) => {
15068
+ forEachInUnitBodyOfKinds(func, CALLS_AND_STOPS, (node) => {
14534
15069
  if (isDescentStop(node, func, barriers)) {
14535
- traversal.skip();
14536
- return;
15070
+ return true;
14537
15071
  }
14538
15072
  if (Node54.isCallExpression(node)) {
14539
15073
  calls.push(node);
14540
15074
  }
15075
+ return false;
14541
15076
  });
14542
15077
  const walk = walkArguments(calls, resolution);
14543
15078
  for (const node of calls) {
@@ -14697,10 +15232,11 @@ function dispatchAccessRecognizers(root, recognizers, isStop, resolution, origin
14697
15232
  function accessedIn(root, isStop) {
14698
15233
  const sites = [];
14699
15234
  const calls = [];
14700
- forEachInUnitBody(root, (node, traversal) => {
15235
+ const own = root.compilerNode;
15236
+ const accepts = (raw) => ACCESSES_CONSTRUCTIONS_AND_STOPS.has(raw.kind) || ts8.isParameter(raw.parent) && raw.parent.initializer === raw && raw.parent.parent === own;
15237
+ forEachInUnitBodyWhere(root, accepts, (node) => {
14701
15238
  if (isStop(node) || isOwnParameterDefault(node, root)) {
14702
- traversal.skip();
14703
- return;
15239
+ return true;
14704
15240
  }
14705
15241
  if (isAccessed(node)) {
14706
15242
  sites.push({ node, at: node });
@@ -14708,17 +15244,18 @@ function accessedIn(root, isStop) {
14708
15244
  if (Node54.isCallExpression(node) || Node54.isNewExpression(node)) {
14709
15245
  calls.push(node);
14710
15246
  }
15247
+ return false;
14711
15248
  });
14712
15249
  for (const call of calls) {
14713
15250
  for (const initializer of defaultsRunBy(call)) {
14714
- forEachInUnitBody(initializer, (node, traversal) => {
15251
+ forEachInUnitBodyOfKinds(initializer, ACCESSES_AND_STOPS, (node) => {
14715
15252
  if (isStop(node)) {
14716
- traversal.skip();
14717
- return;
15253
+ return true;
14718
15254
  }
14719
15255
  if (isAccessed(node)) {
14720
15256
  sites.push({ node, at: call });
14721
15257
  }
15258
+ return false;
14722
15259
  });
14723
15260
  if (isAccessed(initializer)) {
14724
15261
  sites.push({ node: initializer, at: call });
@@ -15455,7 +15992,7 @@ function rootOf(ref) {
15455
15992
  }
15456
15993
 
15457
15994
  // src/terminals/index.ts
15458
- import { Node as Node66 } from "ts-morph";
15995
+ import { Node as Node66, SyntaxKind as SyntaxKind26 } from "ts-morph";
15459
15996
 
15460
15997
  // src/terminals/continuation.ts
15461
15998
  import { Node as Node57 } from "ts-morph";
@@ -15493,55 +16030,12 @@ import { constantOf as constantOf5 } from "@suss/values";
15493
16030
  // src/shapes/shapes.ts
15494
16031
  import {
15495
16032
  Node as Node59,
15496
- SyntaxKind as SyntaxKind14
16033
+ SyntaxKind as SyntaxKind24
15497
16034
  } from "ts-morph";
15498
16035
 
15499
16036
  // src/shapes/typeShapes.ts
15500
16037
  import { createHash } from "crypto";
15501
16038
  import { Node as Node58, TypeFormatFlags } from "ts-morph";
15502
-
15503
- // src/shapes/definitions.ts
15504
- var current = null;
15505
- var definitionsInProgress = () => current;
15506
- function createDefinitionTable() {
15507
- const shapes = /* @__PURE__ */ new Map();
15508
- return {
15509
- has: (key) => shapes.has(key),
15510
- reserve: (key) => {
15511
- shapes.set(key, null);
15512
- },
15513
- define: (key, shape) => {
15514
- shapes.set(key, shape);
15515
- },
15516
- // Sorted because the walk meets types in the checker's union order,
15517
- // which changes between runs.
15518
- collected: () => {
15519
- const out = {};
15520
- let any = false;
15521
- const keys = [...shapes.keys()].sort(compareText);
15522
- for (const key of keys) {
15523
- const shape = shapes.get(key) ?? null;
15524
- if (shape !== null) {
15525
- out[key] = shape;
15526
- any = true;
15527
- }
15528
- }
15529
- return any ? out : null;
15530
- }
15531
- };
15532
- }
15533
- function withDefinitions(read2) {
15534
- const table = createDefinitionTable();
15535
- const outer = current;
15536
- current = table;
15537
- try {
15538
- return { value: read2(), definitions: table.collected() };
15539
- } finally {
15540
- current = outer;
15541
- }
15542
- }
15543
-
15544
- // src/shapes/typeShapes.ts
15545
16039
  var MAX_DEPTH = 6;
15546
16040
  var OPAQUE_NAMED_TYPES = /* @__PURE__ */ new Set([
15547
16041
  "Date",
@@ -15579,16 +16073,17 @@ function overloadIsAGuess(node) {
15579
16073
  if (signatures.length < 2) {
15580
16074
  return false;
15581
16075
  }
15582
- const returns = new Set(
15583
- signatures.map((signature) => signature.getReturnType().getText(node))
15584
- );
15585
- if (returns.size < 2) {
15586
- return false;
15587
- }
15588
- return node.getArguments().some((argument) => {
16076
+ const untypedArgument = node.getArguments().some((argument) => {
15589
16077
  const type = argument.getType();
15590
16078
  return type.isAny() || type.isNever();
15591
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;
15592
16087
  }
15593
16088
  function typeToShape(type, ctx) {
15594
16089
  if (type.isAny()) {
@@ -15882,16 +16377,16 @@ function namedOnce(type, ctx) {
15882
16377
  const filed = { ...named2, def: key };
15883
16378
  if (!table.has(key)) {
15884
16379
  table.reserve(key);
15885
- const expanded = objectToShape(type, {
15886
- enclosing: ctx.enclosing,
15887
- depth: 0,
15888
- seen: /* @__PURE__ */ new Set()
15889
- });
15890
- if (expanded === null) {
15891
- return null;
15892
- }
15893
- table.define(key, expanded);
16380
+ table.defer(
16381
+ key,
16382
+ () => objectToShape(type, {
16383
+ enclosing: ctx.enclosing,
16384
+ depth: 0,
16385
+ seen: /* @__PURE__ */ new Set()
16386
+ })
16387
+ );
15894
16388
  }
16389
+ table.settle();
15895
16390
  return filed;
15896
16391
  }
15897
16392
  function definitionKeyFor(type, name, reader) {
@@ -16055,13 +16550,13 @@ function extractShapeInner(node) {
16055
16550
  }
16056
16551
  if (Node59.isPrefixUnaryExpression(unwrapped2)) {
16057
16552
  const op = unwrapped2.getOperatorToken();
16058
- if (op === SyntaxKind14.MinusToken || op === SyntaxKind14.PlusToken) {
16553
+ if (op === SyntaxKind24.MinusToken || op === SyntaxKind24.PlusToken) {
16059
16554
  const inner = unwrapped2.getOperand();
16060
16555
  if (Node59.isNumericLiteral(inner)) {
16061
16556
  const v2 = inner.getLiteralValue();
16062
- const signed = op === SyntaxKind14.MinusToken ? -v2 : v2;
16557
+ const signed = op === SyntaxKind24.MinusToken ? -v2 : v2;
16063
16558
  const rawBody = inner.getText();
16064
- const raw = op === SyntaxKind14.MinusToken ? `-${rawBody}` : rawBody;
16559
+ const raw = op === SyntaxKind24.MinusToken ? `-${rawBody}` : rawBody;
16065
16560
  return numericLiteralShape(signed, raw);
16066
16561
  }
16067
16562
  }
@@ -16070,13 +16565,13 @@ function extractShapeInner(node) {
16070
16565
  return { type: "ref", name: "bigint" };
16071
16566
  }
16072
16567
  const kind = unwrapped2.getKind();
16073
- if (kind === SyntaxKind14.TrueKeyword) {
16568
+ if (kind === SyntaxKind24.TrueKeyword) {
16074
16569
  return { type: "literal", value: true };
16075
16570
  }
16076
- if (kind === SyntaxKind14.FalseKeyword) {
16571
+ if (kind === SyntaxKind24.FalseKeyword) {
16077
16572
  return { type: "literal", value: false };
16078
16573
  }
16079
- if (kind === SyntaxKind14.NullKeyword) {
16574
+ if (kind === SyntaxKind24.NullKeyword) {
16080
16575
  return { type: "null" };
16081
16576
  }
16082
16577
  if (Node59.isIdentifier(unwrapped2) && unwrapped2.getText() === "undefined") {
@@ -16664,7 +17159,7 @@ import {
16664
17159
  } from "ts-morph";
16665
17160
 
16666
17161
  // src/terminals/helperResolution.ts
16667
- import { Node as Node62, SyntaxKind as SyntaxKind15 } from "ts-morph";
17162
+ import { Node as Node62, SyntaxKind as SyntaxKind25 } from "ts-morph";
16668
17163
  function resolveHelperReturn(call, resolveCallee2) {
16669
17164
  const callee = call.getExpression();
16670
17165
  if (!Node62.isIdentifier(callee)) {
@@ -16767,7 +17262,7 @@ function evaluateComparison(condition, substitutions) {
16767
17262
  }
16768
17263
  function numberFor(node, substitutions) {
16769
17264
  const resolved = Node62.isIdentifier(node) && substitutions.has(node.getText()) ? substitutions.get(node.getText()) : node;
16770
- return Node62.isNumericLiteral(resolved) ? Number(resolved.getText()) : null;
17265
+ return Node62.isNumericLiteral(resolved) ? resolved.getLiteralValue() : null;
16771
17266
  }
16772
17267
  var helperBySymbol = createProgramMemo();
16773
17268
  function memoizedLocalHelper(callee, resolveCallee2) {
@@ -16877,7 +17372,7 @@ function returnedObjects(fn) {
16877
17372
  }
16878
17373
  const found = [];
16879
17374
  for (const statement of body.getDescendantsOfKind(
16880
- SyntaxKind15.ReturnStatement
17375
+ SyntaxKind25.ReturnStatement
16881
17376
  )) {
16882
17377
  if (enclosingFunctionOf2(statement) !== body) {
16883
17378
  continue;
@@ -17437,12 +17932,23 @@ function classifyThrownExpression(thrown, constructorPattern) {
17437
17932
 
17438
17933
  // src/terminals/index.ts
17439
17934
  var NESTED_ESCAPING_MATCH_TYPES = /* @__PURE__ */ new Set(["parameterMethodCall"]);
17935
+ var TERMINAL_KINDS = /* @__PURE__ */ new Set([
17936
+ SyntaxKind26.ObjectLiteralExpression,
17937
+ SyntaxKind26.ReturnStatement,
17938
+ SyntaxKind26.ThrowStatement,
17939
+ SyntaxKind26.CallExpression,
17940
+ SyntaxKind26.NewExpression,
17941
+ SyntaxKind26.ArrowFunction,
17942
+ SyntaxKind26.FunctionExpression,
17943
+ SyntaxKind26.FunctionDeclaration,
17944
+ SyntaxKind26.MethodDeclaration,
17945
+ SyntaxKind26.Constructor
17946
+ ]);
17440
17947
  function findTerminals(func, patterns, barriers = NO_BARRIERS, resolution, originatesFrom, resolveCallee2) {
17441
17948
  const results = [];
17442
- func.forEachDescendant((node, traversal) => {
17949
+ forEachDescendantOfKinds(func, TERMINAL_KINDS, (node) => {
17443
17950
  if (isDescentStop(node, func, barriers)) {
17444
- traversal.skip();
17445
- return;
17951
+ return true;
17446
17952
  }
17447
17953
  const nested = crossesNestedFunctionScope(node, func);
17448
17954
  for (const pattern of patterns) {
@@ -17510,6 +18016,7 @@ function findTerminals(func, patterns, barriers = NO_BARRIERS, resolution, origi
17510
18016
  break;
17511
18017
  }
17512
18018
  }
18019
+ return false;
17513
18020
  });
17514
18021
  if (results.length === 0 && Node66.isArrowFunction(func)) {
17515
18022
  const body = func.getBody();
@@ -17635,55 +18142,72 @@ function countUnmatchedReturns(func, terminals, barriers = NO_BARRIERS) {
17635
18142
  return claimed.has(body) ? 0 : 1;
17636
18143
  }
17637
18144
  let unmatched = 0;
17638
- body.forEachDescendant((node, traversal) => {
18145
+ forEachDescendantOfKinds(body, RETURNS_AND_SCOPES, (node) => {
17639
18146
  if (isDescentStop(node, func, barriers)) {
17640
- traversal.skip();
17641
- return;
18147
+ return true;
17642
18148
  }
17643
18149
  if (startsItsOwnScope(node)) {
17644
- traversal.skip();
17645
- return;
17646
- }
17647
- if (!Node67.isReturnStatement(node)) {
17648
- return;
18150
+ return true;
17649
18151
  }
17650
18152
  if (node.getExpression() === void 0) {
17651
- return;
18153
+ return false;
17652
18154
  }
17653
18155
  if (!claimed.has(node)) {
17654
18156
  unmatched++;
17655
18157
  }
18158
+ return false;
17656
18159
  });
17657
18160
  return unmatched;
17658
18161
  }
18162
+ var RETURNS_AND_SCOPES = /* @__PURE__ */ new Set([
18163
+ ...OWN_SCOPE_KINDS,
18164
+ SyntaxKind27.ReturnStatement
18165
+ ]);
17659
18166
  function extractRawBranches(func, terminalPatterns, invocationRecognizers = [], accessRecognizers = [], barriers = NO_BARRIERS, resolution, originatesFrom, anchorCallsOf, resolveCallee2, collectCallAccounting = false, keepsArms, handOff) {
17660
- const terminals = findTerminals(
18167
+ const { terminals, invocations, recognized } = walkBodyOnce(
17661
18168
  func,
17662
- terminalPatterns,
17663
- barriers,
17664
- resolution,
17665
- originatesFrom,
17666
- resolveCallee2
17667
- );
17668
- const invocations = extractInvocationEffects(func, barriers);
17669
- const recognized = [
17670
- ...runInvocationRecognizers(
17671
- func,
18169
+ {
18170
+ terminalPatterns,
17672
18171
  invocationRecognizers,
17673
- barriers,
17674
- resolution,
17675
- originatesFrom,
17676
- anchorCallsOf
17677
- ),
17678
- ...runAccessRecognizers(
17679
- func,
17680
18172
  accessRecognizers,
17681
18173
  barriers,
17682
18174
  resolution,
17683
- originatesFrom,
17684
- anchorCallsOf
17685
- )
17686
- ];
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
+ );
17687
18211
  const endings = new Set(
17688
18212
  terminals.filter(({ terminal }) => terminal.kind === "exit").map(({ node }) => node)
17689
18213
  );
@@ -17847,14 +18371,14 @@ function accountFor(site, terminalNodes, branches) {
17847
18371
  }
17848
18372
 
17849
18373
  // src/bootstrap/automaticTypes.ts
17850
- import { ts as ts4 } from "ts-morph";
18374
+ import { ts as ts9 } from "ts-morph";
17851
18375
  function pinAutomaticTypes(project) {
17852
18376
  const options = project.getCompilerOptions();
17853
18377
  if (options.types !== void 0) {
17854
18378
  return;
17855
18379
  }
17856
18380
  project.compilerOptions.set({
17857
- types: ts4.getAutomaticTypeDirectiveNames(options, ts4.sys)
18381
+ types: ts9.getAutomaticTypeDirectiveNames(options, ts9.sys)
17858
18382
  });
17859
18383
  }
17860
18384
 
@@ -18297,7 +18821,7 @@ function readContractForClientCall(callExpression, methodName, pattern, framewor
18297
18821
 
18298
18822
  // src/diagnostics.ts
18299
18823
  import path10 from "path";
18300
- import { ts as ts5 } from "ts-morph";
18824
+ import { ts as ts10 } from "ts-morph";
18301
18825
  import {
18302
18826
  createPackTallies,
18303
18827
  emptyTally,
@@ -18305,23 +18829,23 @@ import {
18305
18829
  summaryCountsByPack
18306
18830
  } from "@suss/extractor";
18307
18831
  var DEFAULT_RESOLUTION = {
18308
- moduleResolution: ts5.ModuleResolutionKind.Bundler,
18309
- target: ts5.ScriptTarget.ESNext,
18310
- module: ts5.ModuleKind.ESNext
18832
+ moduleResolution: ts10.ModuleResolutionKind.Bundler,
18833
+ target: ts10.ScriptTarget.ESNext,
18834
+ module: ts10.ModuleKind.ESNext
18311
18835
  };
18312
18836
  function resolutionContext(args) {
18313
18837
  if (args.tsConfigFilePath !== void 0) {
18314
- const configFile = ts5.readConfigFile(
18838
+ const configFile = ts10.readConfigFile(
18315
18839
  args.tsConfigFilePath,
18316
- ts5.sys.readFile
18840
+ ts10.sys.readFile
18317
18841
  );
18318
18842
  if (configFile.error !== void 0) {
18319
18843
  return null;
18320
18844
  }
18321
18845
  const dir = path10.dirname(args.tsConfigFilePath);
18322
- const parsed = ts5.parseJsonConfigFileContent(
18846
+ const parsed = ts10.parseJsonConfigFileContent(
18323
18847
  configFile.config,
18324
- ts5.sys,
18848
+ ts10.sys,
18325
18849
  dir,
18326
18850
  /*existingOptions*/
18327
18851
  void 0,
@@ -18350,11 +18874,11 @@ function unresolvedGatesFor(gates, args) {
18350
18874
  }
18351
18875
  const unresolved = [];
18352
18876
  for (const gate of gates) {
18353
- const resolved = ts5.resolveModuleName(
18877
+ const resolved = ts10.resolveModuleName(
18354
18878
  gate,
18355
18879
  context.containingFile,
18356
18880
  context.options,
18357
- ts5.sys
18881
+ ts10.sys
18358
18882
  );
18359
18883
  if (resolved.resolvedModule === void 0) {
18360
18884
  unresolved.push(gate);
@@ -18706,14 +19230,14 @@ function graphqlClientConstructions(sourceFiles, specs, resolution) {
18706
19230
  const store = resolution ?? new ResolutionStore();
18707
19231
  const found = [];
18708
19232
  for (const sourceFile of sourceFiles) {
19233
+ const byModule = /* @__PURE__ */ new Map();
18709
19234
  for (const spec of specs) {
18710
- const constructions = callsByOriginName(
18711
- sourceFile,
18712
- store,
18713
- spec.importModule,
19235
+ const origins = byModule.get(spec.importModule) ?? importedCallOrigins(sourceFile, store, spec.importModule);
19236
+ byModule.set(spec.importModule, origins);
19237
+ for (const node of callsNamed(
19238
+ origins,
18714
19239
  /* @__PURE__ */ new Set([spec.importName])
18715
- );
18716
- for (const node of constructions.keys()) {
19240
+ ).keys()) {
18717
19241
  found.push({ node, spec });
18718
19242
  }
18719
19243
  }
@@ -19550,6 +20074,9 @@ function callSitesOf(func, store) {
19550
20074
  if (!Node73.isCallExpression(passed.call)) {
19551
20075
  continue;
19552
20076
  }
20077
+ if (testCallingProduction(passed.call, func)) {
20078
+ continue;
20079
+ }
19553
20080
  const key = siteKey(passed.call);
19554
20081
  const site = byCall.get(key) ?? {
19555
20082
  call: passed.call,
@@ -19851,7 +20378,17 @@ function scopeOf(args, wraps, resolution) {
19851
20378
  }
19852
20379
 
19853
20380
  // src/discoveryContext.ts
19854
- import { Node as Node75 } from "ts-morph";
20381
+ import { Node as Node75, SyntaxKind as SyntaxKind28 } from "ts-morph";
20382
+ var NESTED_FUNCTION_KINDS = /* @__PURE__ */ new Set([
20383
+ SyntaxKind28.FunctionDeclaration,
20384
+ SyntaxKind28.FunctionExpression,
20385
+ SyntaxKind28.ArrowFunction,
20386
+ SyntaxKind28.MethodDeclaration
20387
+ ]);
20388
+ var RETURNS_AND_FUNCTIONS = /* @__PURE__ */ new Set([
20389
+ ...NESTED_FUNCTION_KINDS,
20390
+ SyntaxKind28.ReturnStatement
20391
+ ]);
19855
20392
  function createTsDiscoveryContext(resolution) {
19856
20393
  const store = resolution ?? new ResolutionStore();
19857
20394
  return {
@@ -19936,22 +20473,20 @@ function hasJsxReturn(func) {
19936
20473
  return false;
19937
20474
  }
19938
20475
  let found = false;
19939
- body.forEachDescendant((node, traversal) => {
19940
- if (found) {
19941
- traversal.stop();
19942
- return;
19943
- }
19944
- if (node !== func && (Node75.isFunctionDeclaration(node) || Node75.isFunctionExpression(node) || Node75.isArrowFunction(node) || Node75.isMethodDeclaration(node))) {
19945
- traversal.skip();
19946
- return;
19947
- }
19948
- if (Node75.isReturnStatement(node)) {
19949
- const expr = node.getExpression();
19950
- if (expr !== void 0 && isJsxOrFragment(expr)) {
19951
- found = true;
20476
+ forEachDescendantWhere(
20477
+ body,
20478
+ (raw) => !found && RETURNS_AND_FUNCTIONS.has(raw.kind),
20479
+ (node) => {
20480
+ if (node !== func && NESTED_FUNCTION_KINDS.has(node.getKind())) {
20481
+ return true;
19952
20482
  }
20483
+ if (Node75.isReturnStatement(node)) {
20484
+ const expr = node.getExpression();
20485
+ found = expr !== void 0 && isJsxOrFragment(expr);
20486
+ }
20487
+ return found;
19953
20488
  }
19954
- });
20489
+ );
19955
20490
  return found;
19956
20491
  }
19957
20492
  function isJsxOrFragment(node) {
@@ -20505,7 +21040,8 @@ function placeOfKey(key) {
20505
21040
 
20506
21041
  // src/resolve/reachableClosure.ts
20507
21042
  import {
20508
- Node as Node79
21043
+ Node as Node79,
21044
+ SyntaxKind as SyntaxKind29
20509
21045
  } from "ts-morph";
20510
21046
  import {
20511
21047
  functionCallBinding,
@@ -20912,6 +21448,21 @@ function resolveJsxReference(node, scan) {
20912
21448
  )
20913
21449
  };
20914
21450
  }
21451
+ var BODY_SCAN_KINDS = /* @__PURE__ */ new Set([
21452
+ SyntaxKind29.CallExpression,
21453
+ SyntaxKind29.NewExpression,
21454
+ SyntaxKind29.JsxOpeningElement,
21455
+ SyntaxKind29.JsxSelfClosingElement
21456
+ ]);
21457
+ var MODULE_SCAN_KINDS = /* @__PURE__ */ new Set([
21458
+ ...BODY_SCAN_KINDS,
21459
+ SyntaxKind29.FunctionDeclaration,
21460
+ SyntaxKind29.MethodDeclaration,
21461
+ SyntaxKind29.ArrowFunction,
21462
+ SyntaxKind29.FunctionExpression,
21463
+ SyntaxKind29.ClassDeclaration,
21464
+ SyntaxKind29.ClassExpression
21465
+ ]);
20915
21466
  function collectReachable(root, scan) {
20916
21467
  const atModuleScope = Node79.isSourceFile(root);
20917
21468
  const inFunc = atModuleScope ? { ...scan } : { ...scan, scanning: root };
@@ -20978,31 +21529,32 @@ function collectReachable(root, scan) {
20978
21529
  });
20979
21530
  };
20980
21531
  const found = [];
20981
- forEachInUnitBody(root, (node, traversal) => {
21532
+ const kinds = atModuleScope ? MODULE_SCAN_KINDS : BODY_SCAN_KINDS;
21533
+ forEachInUnitBodyOfKinds(root, kinds, (node) => {
20982
21534
  if (atModuleScope && isModuleScopeStop(node)) {
20983
- traversal.skip();
20984
- return;
21535
+ return true;
20985
21536
  }
20986
21537
  const jsx = resolveJsxReference(node, inFunc);
20987
21538
  if (jsx !== null) {
20988
21539
  found.push({ node, outcome: jsx.outcome });
20989
- return;
21540
+ return false;
20990
21541
  }
20991
21542
  if (Node79.isNewExpression(node)) {
20992
21543
  const outcome2 = resolveConstruction(node, inFunc);
20993
21544
  if (outcome2 !== null) {
20994
21545
  found.push({ node, calleeText: constructionCallee(node), outcome: outcome2 });
20995
21546
  }
20996
- return;
21547
+ return false;
20997
21548
  }
20998
21549
  if (!Node79.isCallExpression(node)) {
20999
- return;
21550
+ return false;
21000
21551
  }
21001
21552
  const calleeText = normalizeCalleeText2(node.getExpression().getText());
21002
21553
  const outcome = resolveCallee(node, calleeText, inFunc);
21003
21554
  if (outcome !== null) {
21004
21555
  found.push({ node, calleeText, outcome });
21005
21556
  }
21557
+ return false;
21006
21558
  });
21007
21559
  const settle = settleThroughStore(
21008
21560
  found.map((one) => one.outcome),
@@ -21775,7 +22327,8 @@ function resolveCalleeSummary(call, index) {
21775
22327
 
21776
22328
  // src/subUnitContext.ts
21777
22329
  import {
21778
- Node as Node81
22330
+ Node as Node81,
22331
+ SyntaxKind as SyntaxKind30
21779
22332
  } from "ts-morph";
21780
22333
  function createTsSubUnitContext() {
21781
22334
  return {
@@ -21787,24 +22340,19 @@ function createTsSubUnitContext() {
21787
22340
  readArrayLiteralText
21788
22341
  };
21789
22342
  }
21790
- function skipNestedFunctions(parent) {
21791
- return (node, traversal) => {
21792
- if (isDescentStop(node, parent)) {
21793
- traversal.skip();
21794
- return true;
21795
- }
21796
- return false;
21797
- };
21798
- }
22343
+ var JSX_ELEMENTS_AND_STOPS = withDescentStops(
22344
+ SyntaxKind30.JsxOpeningElement,
22345
+ SyntaxKind30.JsxSelfClosingElement
22346
+ );
22347
+ var CALLS_AND_STOPS2 = withDescentStops(SyntaxKind30.CallExpression);
21799
22348
  function findJsxAttributes(parent) {
21800
22349
  const out = [];
21801
- const skip = skipNestedFunctions(parent);
21802
- parent.forEachDescendant((node, traversal) => {
21803
- if (skip(node, traversal)) {
21804
- return;
22350
+ forEachDescendantOfKinds(parent, JSX_ELEMENTS_AND_STOPS, (node) => {
22351
+ if (isDescentStop(node, parent)) {
22352
+ return true;
21805
22353
  }
21806
22354
  if (!Node81.isJsxOpeningElement(node) && !Node81.isJsxSelfClosingElement(node)) {
21807
- return;
22355
+ return false;
21808
22356
  }
21809
22357
  const tag = node.getTagNameNode().getText();
21810
22358
  for (const attr of node.getAttributes()) {
@@ -21827,23 +22375,24 @@ function findJsxAttributes(parent) {
21827
22375
  valueExpression
21828
22376
  });
21829
22377
  }
22378
+ return false;
21830
22379
  });
21831
22380
  return out;
21832
22381
  }
21833
22382
  function findCallExpressionsByName(parent, name) {
21834
22383
  const out = [];
21835
- const skip = skipNestedFunctions(parent);
21836
- parent.forEachDescendant((node, traversal) => {
21837
- if (skip(node, traversal)) {
21838
- return;
22384
+ forEachDescendantOfKinds(parent, CALLS_AND_STOPS2, (node) => {
22385
+ if (isDescentStop(node, parent)) {
22386
+ return true;
21839
22387
  }
21840
22388
  if (!Node81.isCallExpression(node)) {
21841
- return;
22389
+ return false;
21842
22390
  }
21843
22391
  const callee = node.getExpression();
21844
22392
  if (Node81.isIdentifier(callee) && callee.getText() === name) {
21845
22393
  out.push(node);
21846
22394
  }
22395
+ return false;
21847
22396
  });
21848
22397
  return out;
21849
22398
  }
@@ -22494,17 +23043,16 @@ function extractParameters(func, inputMapping) {
22494
23043
  }
22495
23044
  function extractDependencyCalls(func, barriers = NO_BARRIERS) {
22496
23045
  const results = [];
22497
- func.forEachDescendant((node, traversal) => {
23046
+ forEachDescendantOfKinds(func, DECLARATIONS_AND_STOPS, (node) => {
22498
23047
  if (isDescentStop(node, func, barriers)) {
22499
- traversal.skip();
22500
- return;
23048
+ return true;
22501
23049
  }
22502
23050
  if (!Node82.isVariableDeclaration(node)) {
22503
- return;
23051
+ return false;
22504
23052
  }
22505
23053
  const init = node.getInitializer();
22506
23054
  if (init === void 0) {
22507
- return;
23055
+ return false;
22508
23056
  }
22509
23057
  let isAsync = false;
22510
23058
  let callExpr = init;
@@ -22513,7 +23061,7 @@ function extractDependencyCalls(func, barriers = NO_BARRIERS) {
22513
23061
  callExpr = init.getExpression();
22514
23062
  }
22515
23063
  if (!Node82.isCallExpression(callExpr)) {
22516
- return;
23064
+ return false;
22517
23065
  }
22518
23066
  const calleeName = callExpr.getExpression().getText();
22519
23067
  const nameNode = node.getNameNode();
@@ -22531,9 +23079,11 @@ function extractDependencyCalls(func, barriers = NO_BARRIERS) {
22531
23079
  end: endLineOf(locationNode)
22532
23080
  }
22533
23081
  });
23082
+ return false;
22534
23083
  });
22535
23084
  return results;
22536
23085
  }
23086
+ var DECLARATIONS_AND_STOPS = withDescentStops(SyntaxKind31.VariableDeclaration);
22537
23087
  function resolveResponseProperties(branches, calleeText, semantics) {
22538
23088
  return branches.map((branch) => ({
22539
23089
  ...branch,
@@ -22994,13 +23544,15 @@ function resolveContractField(callSite, pack, field, resolution) {
22994
23544
  return value ?? void 0;
22995
23545
  }
22996
23546
  function reportingTo(recognize, tally) {
22997
- return (node, ctx) => {
23547
+ const reporting = (node, ctx) => {
22998
23548
  const effects = recognize(node, ctx);
22999
23549
  if (effects !== null) {
23000
23550
  tally.effectsRecognized += effects.length;
23001
23551
  }
23002
23552
  return effects;
23003
23553
  };
23554
+ noteRecognizerTally(reporting, tally);
23555
+ return reporting;
23004
23556
  }
23005
23557
  function collectInvocationRecognizers(frameworks, tallies) {
23006
23558
  const out = [];
@@ -23480,7 +24032,10 @@ function fileImporting(project, modulePrefix) {
23480
24032
  if (sourceFile.isInNodeModules() || sourceFile.isDeclarationFile()) {
23481
24033
  continue;
23482
24034
  }
23483
- for (const imp of sourceFile.getImportDeclarations()) {
24035
+ for (const imp of statementsOfKind(
24036
+ sourceFile,
24037
+ SyntaxKind31.ImportDeclaration
24038
+ )) {
23484
24039
  if (imp.getModuleSpecifierValue().startsWith(modulePrefix)) {
23485
24040
  return sourceFile.getFilePath();
23486
24041
  }
@@ -23530,10 +24085,16 @@ function internalImportsOf(project, file) {
23530
24085
  targets.add(target.getFilePath());
23531
24086
  }
23532
24087
  };
23533
- for (const imp of sourceFile.getImportDeclarations()) {
24088
+ for (const imp of statementsOfKind(
24089
+ sourceFile,
24090
+ SyntaxKind31.ImportDeclaration
24091
+ )) {
23534
24092
  record2(imp.getModuleSpecifierSourceFile());
23535
24093
  }
23536
- for (const exp of sourceFile.getExportDeclarations()) {
24094
+ for (const exp of statementsOfKind(
24095
+ sourceFile,
24096
+ SyntaxKind31.ExportDeclaration
24097
+ )) {
23537
24098
  record2(exp.getModuleSpecifierSourceFile());
23538
24099
  }
23539
24100
  return [...targets].sort();
@@ -24751,7 +25312,7 @@ function buildSubUnitSummary(subUnit, parent, parentFunc, recognizers, everyUnit
24751
25312
 
24752
25313
  // src/facts/why.ts
24753
25314
  import path16 from "path";
24754
- import { Node as Node83, Project as Project3, SyntaxKind as SyntaxKind16 } from "ts-morph";
25315
+ import { Node as Node83, Project as Project3, SyntaxKind as SyntaxKind32 } from "ts-morph";
24755
25316
  import { explainResolutionProof, renderExplanation } from "@suss/resolution";
24756
25317
  var TypeScriptWhySession = class {
24757
25318
  project;
@@ -24793,7 +25354,7 @@ var TypeScriptWhySession = class {
24793
25354
  return null;
24794
25355
  }
24795
25356
  for (const call of sourceFile.getDescendantsOfKind(
24796
- SyntaxKind16.CallExpression
25357
+ SyntaxKind32.CallExpression
24797
25358
  )) {
24798
25359
  const line = call.getStartLineNumber();
24799
25360
  if (line < startLine || line > endLine) {
@@ -24929,7 +25490,7 @@ function stubEvidence(options) {
24929
25490
  }
24930
25491
 
24931
25492
  // src/walk/defaulted.ts
24932
- import { Node as Node84, SyntaxKind as SyntaxKind17 } from "ts-morph";
25493
+ import { Node as Node84, SyntaxKind as SyntaxKind33, ts as ts11 } from "ts-morph";
24933
25494
  function isDefaultedAt(node) {
24934
25495
  if (!Node84.isBindingElement(node)) {
24935
25496
  const read2 = climbSyntax(node);
@@ -25219,7 +25780,7 @@ function comparedValue(operand2, other, loose) {
25219
25780
  return missing ? operand2 : null;
25220
25781
  }
25221
25782
  function negatedOperand(node) {
25222
- if (Node84.isPrefixUnaryExpression(node) && node.getOperatorToken() === SyntaxKind17.ExclamationToken) {
25783
+ if (Node84.isPrefixUnaryExpression(node) && node.getOperatorToken() === SyntaxKind33.ExclamationToken) {
25223
25784
  return node.getOperand();
25224
25785
  }
25225
25786
  return null;
@@ -25261,9 +25822,20 @@ function declarationInitializedBy(node) {
25261
25822
  return null;
25262
25823
  }
25263
25824
  function usesOf(local) {
25264
- return local.scope.getDescendantsOfKind(SyntaxKind17.Identifier).filter(
25265
- (identifier) => identifier !== local.name && refersTo(identifier, local)
25266
- );
25825
+ const name = local.name.getText();
25826
+ const file = local.scope.getSourceFile();
25827
+ const uses = [];
25828
+ const visit = (node) => {
25829
+ if (ts11.isIdentifier(node) && node.text === name) {
25830
+ const found = file.getDescendantAtPos(node.getStart(file.compilerNode));
25831
+ if (found !== void 0 && Node84.isIdentifier(found) && found !== local.name && refersTo(found, local)) {
25832
+ uses.push(found);
25833
+ }
25834
+ }
25835
+ ts11.forEachChild(node, visit);
25836
+ };
25837
+ ts11.forEachChild(local.scope.compilerNode, visit);
25838
+ return uses;
25267
25839
  }
25268
25840
  export {
25269
25841
  ADAPTER_VERSION,