@suss/adapter-typescript 0.7.2 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -63,7 +63,7 @@ module.exports = __toCommonJS(index_exports);
63
63
 
64
64
  // src/adapter.ts
65
65
  var import_node_path9 = __toESM(require("path"), 1);
66
- var import_ts_morph55 = require("ts-morph");
66
+ var import_ts_morph56 = require("ts-morph");
67
67
  var import_behavioral_ir6 = require("@suss/behavioral-ir");
68
68
  var import_datalog6 = require("@suss/datalog");
69
69
  var import_extractor5 = require("@suss/extractor");
@@ -3985,6 +3985,7 @@ var import_ts_morph19 = require("ts-morph");
3985
3985
  var import_ts_morph18 = require("ts-morph");
3986
3986
  var byFile = createPerFileCache();
3987
3987
  var byDeclaration = /* @__PURE__ */ new WeakMap();
3988
+ var byField = /* @__PURE__ */ new WeakMap();
3988
3989
  function writesToBinding(declaration) {
3989
3990
  const remembered = byDeclaration.get(declaration);
3990
3991
  if (remembered !== void 0) {
@@ -4017,22 +4018,19 @@ function writesToBindingUncached(declaration) {
4017
4018
  return { values, inOrder: writesRunInOrder(declaration, writes) };
4018
4019
  }
4019
4020
  function writesToField(declaration) {
4020
- const remembered = byDeclaration.get(declaration);
4021
+ const remembered = byField.get(declaration);
4021
4022
  if (remembered !== void 0) {
4022
4023
  return remembered;
4023
4024
  }
4024
4025
  const answer = writesToFieldUncached(declaration);
4025
- byDeclaration.set(declaration, answer);
4026
+ byField.set(declaration, answer);
4026
4027
  return answer;
4027
4028
  }
4028
4029
  function writesToFieldUncached(declaration) {
4029
- const initializer = declaration.getInitializer();
4030
+ const first = startingValueOf(declaration);
4030
4031
  const assignments = assignmentsTo(declaration);
4031
4032
  if (assignments.length === 0) {
4032
- return {
4033
- values: initializer === void 0 ? [] : [initializer],
4034
- inOrder: true
4035
- };
4033
+ return { values: first === void 0 ? [] : [first], inOrder: true };
4036
4034
  }
4037
4035
  const values = [];
4038
4036
  for (const write of assignments) {
@@ -4041,14 +4039,16 @@ function writesToFieldUncached(declaration) {
4041
4039
  }
4042
4040
  values.push(write.value);
4043
4041
  }
4044
- const withInitializer = initializer === void 0 ? values : [initializer, ...values];
4045
4042
  return {
4046
- values: withInitializer,
4043
+ values: first === void 0 ? values : [first, ...values],
4047
4044
  inOrder: assignments.every(
4048
4045
  (write) => writeRunsInConstructor(declaration, write)
4049
4046
  )
4050
4047
  };
4051
4048
  }
4049
+ function startingValueOf(declaration) {
4050
+ return import_ts_morph18.Node.isParameterDeclaration(declaration) ? declaration : declaration.getInitializer();
4051
+ }
4052
4052
  function writeRunsInConstructor(declaration, write) {
4053
4053
  const statement = statementOf(write.node);
4054
4054
  if (statement === null) {
@@ -4059,13 +4059,16 @@ function writeRunsInConstructor(declaration, write) {
4059
4059
  return false;
4060
4060
  }
4061
4061
  const owner = body.getParent();
4062
- return owner !== void 0 && import_ts_morph18.Node.isConstructorDeclaration(owner) && owner.getParent() === declaration.getParent();
4062
+ return owner !== void 0 && import_ts_morph18.Node.isConstructorDeclaration(owner) && owner.getParent() === classHolding(declaration);
4063
+ }
4064
+ function classHolding(declaration) {
4065
+ return import_ts_morph18.Node.isParameterDeclaration(declaration) ? declaration.getParent().getParent() : declaration.getParent();
4063
4066
  }
4064
4067
  function isWrittenAgain(declaration) {
4065
4068
  return assignmentsTo(declaration).length > 0;
4066
4069
  }
4067
4070
  function assignmentsTo(declaration) {
4068
- if (import_ts_morph18.Node.isPropertyDeclaration(declaration)) {
4071
+ if (import_ts_morph18.Node.isPropertyDeclaration(declaration) || import_ts_morph18.Node.isParameterDeclaration(declaration)) {
4069
4072
  const sourceFile2 = declaration.getSourceFile();
4070
4073
  return sourceFile2.isDeclarationFile() ? [] : assignmentsInFile(sourceFile2).get(declaration) ?? [];
4071
4074
  }
@@ -4132,7 +4135,9 @@ function declarationsOf(name) {
4132
4135
  }
4133
4136
  const declarations = [];
4134
4137
  for (const declaration of symbol.getDeclarations()) {
4135
- if (import_ts_morph18.Node.isVariableDeclaration(declaration) || import_ts_morph18.Node.isPropertyDeclaration(declaration)) {
4138
+ if (import_ts_morph18.Node.isVariableDeclaration(declaration) || import_ts_morph18.Node.isPropertyDeclaration(declaration) || // A parameter property is the field's only declaration, so
4139
+ // `this.dao = other` in the constructor writes to it.
4140
+ import_ts_morph18.Node.isParameterDeclaration(declaration) && declaration.isParameterProperty()) {
4136
4141
  declarations.push(declaration);
4137
4142
  }
4138
4143
  }
@@ -5909,7 +5914,8 @@ function createNodeTable() {
5909
5914
  byId: /* @__PURE__ */ new Map(),
5910
5915
  seenFunctions: /* @__PURE__ */ new Set(),
5911
5916
  seenBindings: /* @__PURE__ */ new Set(),
5912
- seenValues: /* @__PURE__ */ new Set()
5917
+ seenValues: /* @__PURE__ */ new Set(),
5918
+ seenClasses: /* @__PURE__ */ new Set()
5913
5919
  };
5914
5920
  }
5915
5921
  function nodeId(node) {
@@ -6130,7 +6136,7 @@ function emitValue(db, table, value) {
6130
6136
  }
6131
6137
  return id;
6132
6138
  }
6133
- if (import_ts_morph28.Node.isCallExpression(expression)) {
6139
+ if (import_ts_morph28.Node.isCallExpression(expression) || import_ts_morph28.Node.isNewExpression(expression)) {
6134
6140
  emitCallFacts(db, table, expression);
6135
6141
  fact(db, "writtenValue", id);
6136
6142
  return id;
@@ -6157,11 +6163,24 @@ function emitBindingValues(db, table, declaration) {
6157
6163
  function emitFieldValues(db, table, declaration) {
6158
6164
  const { values, inOrder } = writesToField(declaration);
6159
6165
  const last = values[values.length - 1];
6160
- if (!inOrder || last === void 0) {
6166
+ if (!inOrder || last === void 0 || !import_ts_morph28.Node.isExpression(last)) {
6161
6167
  return;
6162
6168
  }
6163
6169
  fact(db, "binds", nodeId(declaration), emitValue(db, table, last));
6164
6170
  }
6171
+ function emitParameterPropertyRead(db, table, referenceId, declaration) {
6172
+ const { values, inOrder } = writesToField(declaration);
6173
+ const last = values[values.length - 1];
6174
+ if (!inOrder || last === void 0) {
6175
+ return;
6176
+ }
6177
+ if (!import_ts_morph28.Node.isExpression(last)) {
6178
+ table.byId.set(nodeId(last), last);
6179
+ fact(db, "binds", referenceId, nodeId(last));
6180
+ return;
6181
+ }
6182
+ fact(db, "binds", referenceId, emitValue(db, table, last));
6183
+ }
6165
6184
  function emitBindingElementFacts(db, table, element) {
6166
6185
  const id = nodeId(element);
6167
6186
  table.byId.set(id, element);
@@ -6243,7 +6262,16 @@ function emitReferenceFacts(db, table, reference) {
6243
6262
  continue;
6244
6263
  }
6245
6264
  if (import_ts_morph28.Node.isParameterDeclaration(declaration)) {
6265
+ if (declaration.isParameterProperty() && import_ts_morph28.Node.isPropertyAccessExpression(reference)) {
6266
+ emitParameterPropertyRead(db, table, referenceId, declaration);
6267
+ } else {
6268
+ fact(db, "binds", referenceId, declarationId);
6269
+ }
6270
+ continue;
6271
+ }
6272
+ if (import_ts_morph28.Node.isClassDeclaration(declaration)) {
6246
6273
  fact(db, "binds", referenceId, declarationId);
6274
+ emitClassFacts(db, table, declaration);
6247
6275
  continue;
6248
6276
  }
6249
6277
  if (import_ts_morph28.Node.isBindingElement(declaration)) {
@@ -6288,9 +6316,14 @@ function emitCallFacts(db, table, call) {
6288
6316
  }
6289
6317
  }
6290
6318
  function emitClassFacts(db, table, declaration) {
6319
+ if (table.seenClasses.has(declaration)) {
6320
+ return;
6321
+ }
6322
+ table.seenClasses.add(declaration);
6291
6323
  const id = nodeId(declaration);
6292
6324
  table.byId.set(id, declaration);
6293
6325
  fact(db, "objectValue", id);
6326
+ emitConstructorParameters(db, table, declaration, id);
6294
6327
  for (const method of declaration.getMethods()) {
6295
6328
  const methodId = nodeId(method);
6296
6329
  table.byId.set(methodId, method);
@@ -6311,6 +6344,25 @@ function emitClassFacts(db, table, declaration) {
6311
6344
  }
6312
6345
  }
6313
6346
  }
6347
+ function emitConstructorParameters(db, table, declaration, classId) {
6348
+ const implementation = declaration.getConstructors().find((candidate) => candidate.getBody() !== void 0);
6349
+ if (implementation === void 0) {
6350
+ return;
6351
+ }
6352
+ emitParameters(db, table, classId, implementation.getParameters());
6353
+ }
6354
+ function emitParameters(db, table, ownerId, parameters) {
6355
+ for (let position = 0; position < parameters.length; position++) {
6356
+ const parameter = parameters[position];
6357
+ if (parameter === void 0) {
6358
+ continue;
6359
+ }
6360
+ const parameterId = nodeId(parameter);
6361
+ table.byId.set(parameterId, parameter);
6362
+ fact(db, "paramOf", ownerId, String(position), parameterId);
6363
+ fact(db, "paramNamed", ownerId, parameter.getName(), parameterId);
6364
+ }
6365
+ }
6314
6366
  function emitFunctionFacts(db, table, fn) {
6315
6367
  if (table.seenFunctions.has(fn)) {
6316
6368
  return;
@@ -6319,17 +6371,7 @@ function emitFunctionFacts(db, table, fn) {
6319
6371
  const fnId = nodeId(fn);
6320
6372
  table.byId.set(fnId, fn);
6321
6373
  if (import_ts_morph28.Node.isFunctionDeclaration(fn) || import_ts_morph28.Node.isFunctionExpression(fn) || import_ts_morph28.Node.isArrowFunction(fn) || import_ts_morph28.Node.isMethodDeclaration(fn)) {
6322
- const parameters = fn.getParameters();
6323
- for (let position = 0; position < parameters.length; position++) {
6324
- const parameter = parameters[position];
6325
- if (parameter === void 0) {
6326
- continue;
6327
- }
6328
- const parameterId = nodeId(parameter);
6329
- table.byId.set(parameterId, parameter);
6330
- fact(db, "paramOf", fnId, String(position), parameterId);
6331
- fact(db, "paramNamed", fnId, parameter.getName(), parameterId);
6332
- }
6374
+ emitParameters(db, table, fnId, fn.getParameters());
6333
6375
  const body = fn.getBody?.();
6334
6376
  if (body !== void 0) {
6335
6377
  if (import_ts_morph28.Node.isExpression(body)) {
@@ -10024,11 +10066,12 @@ var import_ts_morph50 = require("ts-morph");
10024
10066
  var import_datalog2 = require("@suss/datalog");
10025
10067
  var import_resolution = require("@suss/resolution");
10026
10068
  var JS_RULES = [
10027
- // f.bind(...) resolves to whatever f resolves to.
10069
+ // f.bind(...) leads wherever f leads. Stated as a step, so the
10070
+ // questions other than `comesTo` follow it too.
10028
10071
  (0, import_datalog2.rule)(
10029
- "comesTo",
10030
- [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("h")],
10031
- [(0, import_datalog2.lit)("bindCall", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("t")), (0, import_datalog2.lit)("comesTo", (0, import_datalog2.variable)("t"), (0, import_datalog2.variable)("h"))]
10072
+ "stepsTo",
10073
+ [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("t"), import_resolution.VALUE_STEP],
10074
+ [(0, import_datalog2.lit)("bindCall", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("t"))]
10032
10075
  )
10033
10076
  ];
10034
10077
  var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
@@ -10055,9 +10098,21 @@ var ResolutionStore = class {
10055
10098
  this.db.add("wrapperModule", [wrapper.callee, wrapper.module]);
10056
10099
  }
10057
10100
  }
10058
- resolveCallable(value) {
10101
+ /**
10102
+ * `alsoFrom` is a second file to walk out from, for a caller that
10103
+ * knows where the value it is asking about was set up. The walk
10104
+ * follows imports outward from the value's own file, so a file that
10105
+ * imports it, and passed something to the constructor, is somewhere
10106
+ * the walk never reaches on its own.
10107
+ */
10108
+ resolveCallable(value, alsoFrom) {
10059
10109
  const target = factKeyOf(value);
10060
- return this.resolveByWaves(target, "wanted", () => this.lookup(target));
10110
+ return this.resolveByWaves(
10111
+ target,
10112
+ "wanted",
10113
+ () => this.lookup(target),
10114
+ alsoFrom
10115
+ );
10061
10116
  }
10062
10117
  resolveObject(value) {
10063
10118
  const target = factKeyOf(value);
@@ -10125,18 +10180,18 @@ var ResolutionStore = class {
10125
10180
  }
10126
10181
  return origins.some((pair) => namesAPackage(pairHalves(pair).module)) ? [] : null;
10127
10182
  }
10128
- resolveByWaves(value, question, ask) {
10183
+ resolveByWaves(value, question, ask, alsoFrom) {
10129
10184
  try {
10130
- return this.walkForAnswer(value, question, ask);
10185
+ return this.walkForAnswer(value, question, ask, alsoFrom);
10131
10186
  } finally {
10132
10187
  this.forgetQuery();
10133
10188
  }
10134
10189
  }
10135
- walkForAnswer(value, question, ask) {
10190
+ walkForAnswer(value, question, ask, alsoFrom) {
10136
10191
  this.wantValue(question, value);
10137
10192
  this.seedValue(value);
10138
10193
  const walked = /* @__PURE__ */ new Set();
10139
- let frontier = [value.getSourceFile()];
10194
+ let frontier = alsoFrom === void 0 ? [value.getSourceFile()] : [value.getSourceFile(), alsoFrom];
10140
10195
  for (let hop = 0; hop <= MAX_MODULE_HOPS; hop++) {
10141
10196
  const next = [];
10142
10197
  for (const sourceFile of frontier) {
@@ -10485,7 +10540,10 @@ function bindingLabel(binding) {
10485
10540
  if (semantics.name === "graphql-operation") {
10486
10541
  return `${semantics.operationType} ${semantics.operationName ?? ""}`.trim();
10487
10542
  }
10488
- return semantics.exportName ?? semantics.module ?? binding.recognition;
10543
+ if ("exportName" in semantics || "module" in semantics) {
10544
+ return semantics.exportName ?? semantics.module ?? binding.recognition;
10545
+ }
10546
+ return binding.recognition;
10489
10547
  }
10490
10548
  function effectFact(effect) {
10491
10549
  if (effect.type === "invocation") {
@@ -10557,10 +10615,100 @@ function deriveBoundaryEffects(summaries, facts) {
10557
10615
  }
10558
10616
 
10559
10617
  // src/resolve/reachableClosure.ts
10560
- var import_ts_morph51 = require("ts-morph");
10618
+ var import_ts_morph52 = require("ts-morph");
10561
10619
  var import_behavioral_ir4 = require("@suss/behavioral-ir");
10562
10620
  var import_datalog4 = require("@suss/datalog");
10563
10621
  var import_extractor4 = require("@suss/extractor");
10622
+
10623
+ // src/resolve/unfollowedCall.ts
10624
+ var import_ts_morph51 = require("ts-morph");
10625
+ function isInExternalCode(sourceFile) {
10626
+ if (sourceFile.isDeclarationFile()) {
10627
+ return true;
10628
+ }
10629
+ return sourceFile.getFilePath().includes("/node_modules/");
10630
+ }
10631
+ function hasBody(fn) {
10632
+ if (import_ts_morph51.Node.isFunctionDeclaration(fn) || import_ts_morph51.Node.isMethodDeclaration(fn) || import_ts_morph51.Node.isFunctionExpression(fn)) {
10633
+ return fn.getBody?.() !== void 0;
10634
+ }
10635
+ return true;
10636
+ }
10637
+ function isDeclaredShape(declaration) {
10638
+ return (import_ts_morph51.Node.isMethodSignature(declaration) || import_ts_morph51.Node.isPropertySignature(declaration)) && !isInExternalCode(declaration.getSourceFile());
10639
+ }
10640
+ function isExternalDeclaration(declaration) {
10641
+ if (isInExternalCode(declaration.getSourceFile())) {
10642
+ return true;
10643
+ }
10644
+ if (import_ts_morph51.Node.isImportSpecifier(declaration) || import_ts_morph51.Node.isImportClause(declaration) || import_ts_morph51.Node.isNamespaceImport(declaration)) {
10645
+ const target = declaration.getFirstAncestorByKind(import_ts_morph51.SyntaxKind.ImportDeclaration)?.getModuleSpecifierSourceFile();
10646
+ return target === void 0 || isInExternalCode(target);
10647
+ }
10648
+ return declaresAnotherModule(declaration);
10649
+ }
10650
+ function declaresAnotherModule(declaration) {
10651
+ const module2 = declaration.getFirstAncestorByKind(
10652
+ import_ts_morph51.SyntaxKind.ModuleDeclaration
10653
+ );
10654
+ return module2 !== void 0 && import_ts_morph51.Node.isStringLiteral(module2.getNameNode());
10655
+ }
10656
+ function statesShapeOnly(declaration) {
10657
+ if (isExternalDeclaration(declaration)) {
10658
+ return false;
10659
+ }
10660
+ if (import_ts_morph51.Node.isMethodSignature(declaration) || import_ts_morph51.Node.isPropertySignature(declaration)) {
10661
+ return true;
10662
+ }
10663
+ if (import_ts_morph51.Node.isFunctionDeclaration(declaration) || import_ts_morph51.Node.isMethodDeclaration(declaration)) {
10664
+ return declaration.getBody() === void 0;
10665
+ }
10666
+ return false;
10667
+ }
10668
+ function declarationsBehind(symbol) {
10669
+ if (symbol === void 0) {
10670
+ return [];
10671
+ }
10672
+ const behind = symbol.getAliasedSymbol()?.getDeclarations() ?? [];
10673
+ return behind.length > 0 ? behind : symbol.getDeclarations();
10674
+ }
10675
+ function classifyStop(declarations) {
10676
+ if (declarations.length === 0) {
10677
+ return "noDeclaration";
10678
+ }
10679
+ if (declarations.every(isExternalDeclaration)) {
10680
+ return "outsideRun";
10681
+ }
10682
+ if (declarations.some(statesShapeOnly)) {
10683
+ return "noBody";
10684
+ }
10685
+ return "unsettledValue";
10686
+ }
10687
+ var RECORDED = {
10688
+ noBody: true,
10689
+ unsettledValue: true,
10690
+ outsideRun: false,
10691
+ noDeclaration: false
10692
+ };
10693
+ function worthRecording(reason) {
10694
+ return RECORDED[reason];
10695
+ }
10696
+ var STOP_SENTENCE = {
10697
+ noBody: (callee) => `The call to ${callee} lands on a declaration with no body, so whatever runs there is missing from this summary`,
10698
+ unsettledValue: (callee) => `The call to ${callee} goes through a value this run could not settle, so whatever runs there is missing from this summary`,
10699
+ outsideRun: (callee) => `The call to ${callee} lands in a package whose source is not in this run, so whatever runs there is missing from this summary`,
10700
+ noDeclaration: (callee) => `The call to ${callee} has no declaration this run could find, so whatever runs there is missing from this summary`
10701
+ };
10702
+ function unfollowedCallGap(stop) {
10703
+ return {
10704
+ type: "unfollowedCall",
10705
+ conditions: [],
10706
+ consequence: "unknown",
10707
+ description: STOP_SENTENCE[stop.reason](stop.callee)
10708
+ };
10709
+ }
10710
+
10711
+ // src/resolve/reachableClosure.ts
10564
10712
  var reachablePack = {
10565
10713
  name: "reachable",
10566
10714
  languages: ["typescript"],
@@ -10583,23 +10731,6 @@ function nodeKey2(func) {
10583
10731
  const sf = func.getSourceFile();
10584
10732
  return `${sf.getFilePath()}:${func.getStart()}-${func.getEnd()}`;
10585
10733
  }
10586
- function isInExternalCode(sourceFile) {
10587
- if (sourceFile.isDeclarationFile()) {
10588
- return true;
10589
- }
10590
- const filePath = sourceFile.getFilePath();
10591
- if (filePath.includes("/node_modules/")) {
10592
- return true;
10593
- }
10594
- return false;
10595
- }
10596
- function hasBody(fn) {
10597
- if (import_ts_morph51.Node.isFunctionDeclaration(fn) || import_ts_morph51.Node.isMethodDeclaration(fn) || import_ts_morph51.Node.isFunctionExpression(fn)) {
10598
- const body = fn.getBody?.();
10599
- return body !== void 0;
10600
- }
10601
- return true;
10602
- }
10603
10734
  function resolveDecl(decl, calleeName) {
10604
10735
  if (isInExternalCode(decl.getSourceFile())) {
10605
10736
  return null;
@@ -10611,14 +10742,14 @@ function resolveDecl(decl, calleeName) {
10611
10742
  }
10612
10743
  return { func: fn, name: declName(decl) ?? calleeName };
10613
10744
  }
10614
- if (import_ts_morph51.Node.isVariableDeclaration(decl)) {
10745
+ if (import_ts_morph52.Node.isVariableDeclaration(decl)) {
10615
10746
  const init = decl.getInitializer();
10616
- if (init !== void 0 && (import_ts_morph51.Node.isArrowFunction(init) || import_ts_morph51.Node.isFunctionExpression(init))) {
10747
+ if (init !== void 0 && (import_ts_morph52.Node.isArrowFunction(init) || import_ts_morph52.Node.isFunctionExpression(init))) {
10617
10748
  return { func: init, name: decl.getName() };
10618
10749
  }
10619
10750
  return null;
10620
10751
  }
10621
- if (import_ts_morph51.Node.isImportSpecifier(decl)) {
10752
+ if (import_ts_morph52.Node.isImportSpecifier(decl)) {
10622
10753
  const importDecl = decl.getImportDeclaration();
10623
10754
  const sf = importDecl.getModuleSpecifierSourceFile();
10624
10755
  if (sf === void 0 || isInExternalCode(sf)) {
@@ -10639,61 +10770,85 @@ function resolveDecl(decl, calleeName) {
10639
10770
  return null;
10640
10771
  }
10641
10772
  function declName(decl) {
10642
- if (import_ts_morph51.Node.isFunctionDeclaration(decl) || import_ts_morph51.Node.isMethodDeclaration(decl)) {
10773
+ if (import_ts_morph52.Node.isFunctionDeclaration(decl) || import_ts_morph52.Node.isMethodDeclaration(decl)) {
10643
10774
  const n = decl.getName?.();
10644
10775
  if (typeof n === "string" && n.length > 0) {
10645
10776
  return n;
10646
10777
  }
10647
10778
  }
10648
- if (import_ts_morph51.Node.isFunctionExpression(decl)) {
10779
+ if (import_ts_morph52.Node.isFunctionExpression(decl)) {
10649
10780
  const n = decl.getName();
10650
10781
  if (typeof n === "string" && n.length > 0) {
10651
10782
  return n;
10652
10783
  }
10653
10784
  }
10654
10785
  const parent = decl.getParent();
10655
- if (parent !== void 0 && import_ts_morph51.Node.isVariableDeclaration(parent)) {
10786
+ if (parent !== void 0 && import_ts_morph52.Node.isVariableDeclaration(parent)) {
10656
10787
  return parent.getName();
10657
10788
  }
10658
10789
  return null;
10659
10790
  }
10660
- function resolveCallee(call, calleeName) {
10661
- if (!import_ts_morph51.Node.isCallExpression(call)) {
10791
+ function resolveCallee(call, calleeName, scan) {
10792
+ if (!import_ts_morph52.Node.isCallExpression(call)) {
10662
10793
  return null;
10663
10794
  }
10664
10795
  const callee = call.getExpression();
10665
10796
  const symbol = callee.getSymbol();
10666
- if (symbol === void 0) {
10667
- return null;
10668
- }
10669
- for (const decl of symbol.getDeclarations()) {
10797
+ const declarations = symbol?.getDeclarations() ?? [];
10798
+ for (const decl of declarations) {
10670
10799
  const resolved = resolveDecl(decl, calleeName);
10671
10800
  if (resolved !== null) {
10672
- return resolved;
10801
+ return { kind: "followed", candidate: resolved };
10673
10802
  }
10674
10803
  }
10675
- return null;
10804
+ const resolveCallable = scan.resolveCallable;
10805
+ if (resolveCallable !== void 0 && import_ts_morph52.Node.isPropertyAccessExpression(callee) && declarations.some(isDeclaredShape)) {
10806
+ const value = resolveCallable(callee, scan.reachedFrom);
10807
+ const resolved = value === null ? null : resolveDecl(value, calleeName);
10808
+ if (resolved !== null) {
10809
+ return { kind: "followed", candidate: resolved };
10810
+ }
10811
+ }
10812
+ return {
10813
+ kind: "stopped",
10814
+ stop: {
10815
+ callee: calleeName,
10816
+ reason: classifyStop(declarationsBehind(symbol))
10817
+ }
10818
+ };
10676
10819
  }
10677
- function collectReachable(func) {
10678
- const found = [];
10820
+ function collectReachable(func, scan) {
10821
+ const candidates = [];
10822
+ const stops = [];
10679
10823
  const seen = /* @__PURE__ */ new Set();
10680
10824
  func.forEachDescendant((node) => {
10681
- if (!import_ts_morph51.Node.isCallExpression(node)) {
10825
+ if (!import_ts_morph52.Node.isCallExpression(node)) {
10682
10826
  return;
10683
10827
  }
10684
- const calleeText = node.getExpression().getText();
10685
- const resolved = resolveCallee(node, calleeText);
10686
- if (resolved === null) {
10828
+ const calleeText = normalizeCallee(node.getExpression().getText());
10829
+ const outcome = resolveCallee(node, calleeText, scan);
10830
+ if (outcome === null) {
10831
+ return;
10832
+ }
10833
+ if (outcome.kind === "stopped") {
10834
+ const stopKey = `${outcome.stop.reason}:${outcome.stop.callee}`;
10835
+ if (!seen.has(stopKey) && worthRecording(outcome.stop.reason)) {
10836
+ seen.add(stopKey);
10837
+ stops.push(outcome.stop);
10838
+ }
10687
10839
  return;
10688
10840
  }
10689
- const key = nodeKey2(resolved.func);
10841
+ const key = nodeKey2(outcome.candidate.func);
10690
10842
  if (seen.has(key)) {
10691
10843
  return;
10692
10844
  }
10693
10845
  seen.add(key);
10694
- found.push(resolved);
10846
+ candidates.push(outcome.candidate);
10695
10847
  });
10696
- return found;
10848
+ return { candidates, stops };
10849
+ }
10850
+ function normalizeCallee(text) {
10851
+ return text.replace(/\s+/g, " ").trim();
10697
10852
  }
10698
10853
  function extractReachableSummary(candidate, options, recognizers) {
10699
10854
  const unit = {
@@ -10733,6 +10888,9 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10733
10888
  const functionByKey = /* @__PURE__ */ new Map();
10734
10889
  const seedKeys = /* @__PURE__ */ new Set();
10735
10890
  const scanned = /* @__PURE__ */ new Set();
10891
+ const stopsByKey = /* @__PURE__ */ new Map();
10892
+ const summariesByKey = /* @__PURE__ */ new Map();
10893
+ const reachedFrom = /* @__PURE__ */ new Map();
10736
10894
  for (const seed of seeds) {
10737
10895
  const func = lookup.functionAt(seed.location);
10738
10896
  if (func !== null) {
@@ -10740,6 +10898,7 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10740
10898
  seedKeys.add(key);
10741
10899
  functionByKey.set(key, { func, name: seed.identity.name });
10742
10900
  facts?.unitKeyBySummary.set(seed, key);
10901
+ rememberSummary(summariesByKey, key, seed);
10743
10902
  db.add("entry", [key]);
10744
10903
  }
10745
10904
  }
@@ -10755,11 +10914,23 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10755
10914
  if (source === void 0) {
10756
10915
  continue;
10757
10916
  }
10758
- for (const candidate of collectReachable(source.func)) {
10917
+ const cameFrom = reachedFrom.get(key);
10918
+ const scan = {
10919
+ ...recognizers.resolveCallable === void 0 ? {} : { resolveCallable: recognizers.resolveCallable },
10920
+ ...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
10921
+ };
10922
+ const { candidates, stops } = collectReachable(source.func, scan);
10923
+ if (stops.length > 0) {
10924
+ stopsByKey.set(key, stops);
10925
+ }
10926
+ for (const candidate of candidates) {
10759
10927
  const calleeKey = nodeKey2(candidate.func);
10760
10928
  if (!functionByKey.has(calleeKey)) {
10761
10929
  functionByKey.set(calleeKey, candidate);
10762
10930
  }
10931
+ if (!reachedFrom.has(calleeKey)) {
10932
+ reachedFrom.set(calleeKey, source.func.getSourceFile());
10933
+ }
10763
10934
  db.add("calls", [key, calleeKey]);
10764
10935
  }
10765
10936
  }
@@ -10783,13 +10954,30 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10783
10954
  }
10784
10955
  const summary = extractReachableSummary(candidate, options, recognizers);
10785
10956
  facts?.unitKeyBySummary.set(summary, key);
10957
+ rememberSummary(summariesByKey, key, summary);
10786
10958
  reached.push(summary);
10787
10959
  }
10960
+ recordStops(stopsByKey, summariesByKey, options);
10788
10961
  return [...seeds, ...reached];
10789
10962
  }
10963
+ function rememberSummary(summariesByKey, key, summary) {
10964
+ const bucket = summariesByKey.get(key) ?? [];
10965
+ bucket.push(summary);
10966
+ summariesByKey.set(key, bucket);
10967
+ }
10968
+ function recordStops(stopsByKey, summariesByKey, options) {
10969
+ if (options?.gapHandling === "silent") {
10970
+ return;
10971
+ }
10972
+ for (const [key, stops] of stopsByKey) {
10973
+ for (const summary of summariesByKey.get(key) ?? []) {
10974
+ summary.gaps.push(...stops.map(unfollowedCallGap));
10975
+ }
10976
+ }
10977
+ }
10790
10978
 
10791
10979
  // src/resolve/rethrowEnrichment.ts
10792
- var import_ts_morph52 = require("ts-morph");
10980
+ var import_ts_morph53 = require("ts-morph");
10793
10981
  var import_datalog5 = require("@suss/datalog");
10794
10982
  var RETHROW_RULES = [
10795
10983
  (0, import_datalog5.rule)(
@@ -10929,7 +11117,7 @@ function findBareRethrow(func, location) {
10929
11117
  traversal.stop();
10930
11118
  return;
10931
11119
  }
10932
- if (!import_ts_morph52.Node.isThrowStatement(node)) {
11120
+ if (!import_ts_morph53.Node.isThrowStatement(node)) {
10933
11121
  return;
10934
11122
  }
10935
11123
  if (startLineOf(node) !== location.start) {
@@ -10939,7 +11127,7 @@ function findBareRethrow(func, location) {
10939
11127
  return;
10940
11128
  }
10941
11129
  const thrown = node.getExpression();
10942
- if (thrown !== void 0 && import_ts_morph52.Node.isIdentifier(thrown)) {
11130
+ if (thrown !== void 0 && import_ts_morph53.Node.isIdentifier(thrown)) {
10943
11131
  found = node;
10944
11132
  }
10945
11133
  });
@@ -10949,13 +11137,13 @@ function enclosingTry(throwStmt) {
10949
11137
  let current2 = throwStmt.getParent();
10950
11138
  let sawCatchClause = false;
10951
11139
  while (current2 !== void 0) {
10952
- if (import_ts_morph52.Node.isCatchClause(current2)) {
11140
+ if (import_ts_morph53.Node.isCatchClause(current2)) {
10953
11141
  sawCatchClause = true;
10954
11142
  }
10955
- if (import_ts_morph52.Node.isTryStatement(current2)) {
11143
+ if (import_ts_morph53.Node.isTryStatement(current2)) {
10956
11144
  return sawCatchClause ? current2 : null;
10957
11145
  }
10958
- if (import_ts_morph52.Node.isFunctionDeclaration(current2) || import_ts_morph52.Node.isFunctionExpression(current2) || import_ts_morph52.Node.isArrowFunction(current2) || import_ts_morph52.Node.isMethodDeclaration(current2)) {
11146
+ if (import_ts_morph53.Node.isFunctionDeclaration(current2) || import_ts_morph53.Node.isFunctionExpression(current2) || import_ts_morph53.Node.isArrowFunction(current2) || import_ts_morph53.Node.isMethodDeclaration(current2)) {
10959
11147
  return null;
10960
11148
  }
10961
11149
  current2 = current2.getParent();
@@ -10963,14 +11151,14 @@ function enclosingTry(throwStmt) {
10963
11151
  return null;
10964
11152
  }
10965
11153
  function collectTryBodyCallees(tryStmt, index, keyFor) {
10966
- if (!import_ts_morph52.Node.isTryStatement(tryStmt)) {
11154
+ if (!import_ts_morph53.Node.isTryStatement(tryStmt)) {
10967
11155
  return [];
10968
11156
  }
10969
11157
  const tryBlock = tryStmt.getTryBlock();
10970
11158
  const callees = [];
10971
11159
  const seen = /* @__PURE__ */ new Set();
10972
11160
  tryBlock.forEachDescendant((node) => {
10973
- if (!import_ts_morph52.Node.isCallExpression(node)) {
11161
+ if (!import_ts_morph53.Node.isCallExpression(node)) {
10974
11162
  return;
10975
11163
  }
10976
11164
  const calleeSummary = resolveCalleeSummary(node, index);
@@ -10987,7 +11175,7 @@ function collectTryBodyCallees(tryStmt, index, keyFor) {
10987
11175
  return callees;
10988
11176
  }
10989
11177
  function resolveCalleeSummary(call, index) {
10990
- if (!import_ts_morph52.Node.isCallExpression(call)) {
11178
+ if (!import_ts_morph53.Node.isCallExpression(call)) {
10991
11179
  return null;
10992
11180
  }
10993
11181
  const callee = call.getExpression();
@@ -11013,12 +11201,12 @@ function resolveCalleeSummary(call, index) {
11013
11201
  return null;
11014
11202
  }
11015
11203
  function functionFromDecl(decl) {
11016
- if (import_ts_morph52.Node.isFunctionDeclaration(decl) || import_ts_morph52.Node.isFunctionExpression(decl) || import_ts_morph52.Node.isArrowFunction(decl) || import_ts_morph52.Node.isMethodDeclaration(decl)) {
11204
+ if (import_ts_morph53.Node.isFunctionDeclaration(decl) || import_ts_morph53.Node.isFunctionExpression(decl) || import_ts_morph53.Node.isArrowFunction(decl) || import_ts_morph53.Node.isMethodDeclaration(decl)) {
11017
11205
  return decl;
11018
11206
  }
11019
- if (import_ts_morph52.Node.isVariableDeclaration(decl)) {
11207
+ if (import_ts_morph53.Node.isVariableDeclaration(decl)) {
11020
11208
  const init = decl.getInitializer();
11021
- if (init !== void 0 && (import_ts_morph52.Node.isArrowFunction(init) || import_ts_morph52.Node.isFunctionExpression(init))) {
11209
+ if (init !== void 0 && (import_ts_morph53.Node.isArrowFunction(init) || import_ts_morph53.Node.isFunctionExpression(init))) {
11022
11210
  return init;
11023
11211
  }
11024
11212
  }
@@ -11026,22 +11214,22 @@ function functionFromDecl(decl) {
11026
11214
  }
11027
11215
 
11028
11216
  // src/shapes/fieldAccesses.ts
11029
- var import_ts_morph53 = require("ts-morph");
11217
+ var import_ts_morph54 = require("ts-morph");
11030
11218
  function findResponseAccessor(callExpr) {
11031
11219
  let current2 = callExpr;
11032
11220
  const parent1 = current2.getParent();
11033
- if (parent1 !== void 0 && import_ts_morph53.Node.isAwaitExpression(parent1)) {
11221
+ if (parent1 !== void 0 && import_ts_morph54.Node.isAwaitExpression(parent1)) {
11034
11222
  current2 = parent1;
11035
11223
  }
11036
11224
  const parent2 = current2.getParent();
11037
- if (parent2 === void 0 || !import_ts_morph53.Node.isVariableDeclaration(parent2)) {
11225
+ if (parent2 === void 0 || !import_ts_morph54.Node.isVariableDeclaration(parent2)) {
11038
11226
  return null;
11039
11227
  }
11040
11228
  const nameNode = parent2.getNameNode();
11041
- if (import_ts_morph53.Node.isIdentifier(nameNode)) {
11229
+ if (import_ts_morph54.Node.isIdentifier(nameNode)) {
11042
11230
  return { kind: "identifier", name: nameNode.getText() };
11043
11231
  }
11044
- if (import_ts_morph53.Node.isObjectBindingPattern(nameNode)) {
11232
+ if (import_ts_morph54.Node.isObjectBindingPattern(nameNode)) {
11045
11233
  const bindings = /* @__PURE__ */ new Map();
11046
11234
  for (const element of nameNode.getElements()) {
11047
11235
  if (element.getDotDotDotToken() !== void 0) {
@@ -11062,11 +11250,11 @@ function findResponseAccessor(callExpr) {
11062
11250
  function buildThenChainAccessor(callExpr, func) {
11063
11251
  const bindings = /* @__PURE__ */ new Map();
11064
11252
  func.forEachDescendant((node) => {
11065
- if (!import_ts_morph53.Node.isParameterDeclaration(node)) {
11253
+ if (!import_ts_morph54.Node.isParameterDeclaration(node)) {
11066
11254
  return;
11067
11255
  }
11068
11256
  const nameNode = node.getNameNode();
11069
- if (!import_ts_morph53.Node.isIdentifier(nameNode)) {
11257
+ if (!import_ts_morph54.Node.isIdentifier(nameNode)) {
11070
11258
  return;
11071
11259
  }
11072
11260
  const prefix = prefixOfThenParam(node, callExpr, 0);
@@ -11098,7 +11286,7 @@ function prefixOfExpr(expr, responseCall, depth) {
11098
11286
  if (node === responseCall) {
11099
11287
  return [];
11100
11288
  }
11101
- if (import_ts_morph53.Node.isCallExpression(node)) {
11289
+ if (import_ts_morph54.Node.isCallExpression(node)) {
11102
11290
  const hop = thenLikeCall(node);
11103
11291
  if (hop !== null) {
11104
11292
  if (hop.method === "catch") {
@@ -11130,14 +11318,14 @@ function prefixOfMemberExpr(expr, responseCall, depth) {
11130
11318
  return null;
11131
11319
  }
11132
11320
  const decl = chain.root.getSymbol()?.getDeclarations()?.[0];
11133
- if (decl === void 0 || !import_ts_morph53.Node.isParameterDeclaration(decl)) {
11321
+ if (decl === void 0 || !import_ts_morph54.Node.isParameterDeclaration(decl)) {
11134
11322
  return null;
11135
11323
  }
11136
11324
  const base = prefixOfThenParam(decl, responseCall, depth + 1);
11137
11325
  return base === null ? null : [...base, ...chain.segments];
11138
11326
  }
11139
11327
  function firstCallbackParamName(callback) {
11140
- if (callback === void 0 || !(import_ts_morph53.Node.isArrowFunction(callback) || import_ts_morph53.Node.isFunctionExpression(callback))) {
11328
+ if (callback === void 0 || !(import_ts_morph54.Node.isArrowFunction(callback) || import_ts_morph54.Node.isFunctionExpression(callback))) {
11141
11329
  return null;
11142
11330
  }
11143
11331
  const param = callback.getParameters()[0];
@@ -11145,11 +11333,11 @@ function firstCallbackParamName(callback) {
11145
11333
  return null;
11146
11334
  }
11147
11335
  const nameNode = param.getNameNode();
11148
- return import_ts_morph53.Node.isIdentifier(nameNode) ? nameNode.getText() : null;
11336
+ return import_ts_morph54.Node.isIdentifier(nameNode) ? nameNode.getText() : null;
11149
11337
  }
11150
11338
  function unwrap2(expr) {
11151
11339
  let node = expr;
11152
- while (import_ts_morph53.Node.isAwaitExpression(node) || import_ts_morph53.Node.isParenthesizedExpression(node) || import_ts_morph53.Node.isAsExpression(node)) {
11340
+ while (import_ts_morph54.Node.isAwaitExpression(node) || import_ts_morph54.Node.isParenthesizedExpression(node) || import_ts_morph54.Node.isAsExpression(node)) {
11153
11341
  node = node.getExpression();
11154
11342
  }
11155
11343
  return node;
@@ -11159,15 +11347,15 @@ function chainRootedAt(expr, rootName) {
11159
11347
  if (chain === null) {
11160
11348
  return null;
11161
11349
  }
11162
- return import_ts_morph53.Node.isIdentifier(chain.root) && chain.root.getText() === rootName ? chain.segments : null;
11350
+ return import_ts_morph54.Node.isIdentifier(chain.root) && chain.root.getText() === rootName ? chain.segments : null;
11163
11351
  }
11164
11352
  function memberChain(expr) {
11165
- let node = import_ts_morph53.Node.isExpression(expr) ? unwrap2(expr) : expr;
11166
- if (import_ts_morph53.Node.isCallExpression(node)) {
11353
+ let node = import_ts_morph54.Node.isExpression(expr) ? unwrap2(expr) : expr;
11354
+ if (import_ts_morph54.Node.isCallExpression(node)) {
11167
11355
  node = node.getExpression();
11168
11356
  }
11169
11357
  const segments = [];
11170
- while (import_ts_morph53.Node.isPropertyAccessExpression(node)) {
11358
+ while (import_ts_morph54.Node.isPropertyAccessExpression(node)) {
11171
11359
  segments.unshift(node.getName());
11172
11360
  node = node.getExpression();
11173
11361
  }
@@ -11186,16 +11374,16 @@ function collectPropertyAccesses(subtree, accessor) {
11186
11374
  if (accessor.kind === "identifier") {
11187
11375
  const varName = accessor.name;
11188
11376
  subtree.forEachDescendant((node) => {
11189
- if (!import_ts_morph53.Node.isPropertyAccessExpression(node)) {
11377
+ if (!import_ts_morph54.Node.isPropertyAccessExpression(node)) {
11190
11378
  return;
11191
11379
  }
11192
11380
  const chain = [];
11193
11381
  let current2 = node;
11194
- while (import_ts_morph53.Node.isPropertyAccessExpression(current2)) {
11382
+ while (import_ts_morph54.Node.isPropertyAccessExpression(current2)) {
11195
11383
  chain.unshift(current2.getName());
11196
11384
  current2 = current2.getExpression();
11197
11385
  }
11198
- if (import_ts_morph53.Node.isIdentifier(current2) && current2.getText() === varName) {
11386
+ if (import_ts_morph54.Node.isIdentifier(current2) && current2.getText() === varName) {
11199
11387
  pushChain(chain);
11200
11388
  }
11201
11389
  });
@@ -11206,7 +11394,7 @@ function collectPropertyAccesses(subtree, accessor) {
11206
11394
  return source === void 0 ? void 0 : [source];
11207
11395
  } : (name) => accessor.bindings.get(name);
11208
11396
  subtree.forEachDescendant((node) => {
11209
- if (!import_ts_morph53.Node.isIdentifier(node)) {
11397
+ if (!import_ts_morph54.Node.isIdentifier(node)) {
11210
11398
  return;
11211
11399
  }
11212
11400
  const prefix = prefixOf(node.getText());
@@ -11218,13 +11406,13 @@ function collectPropertyAccesses(subtree, accessor) {
11218
11406
  }
11219
11407
  let chainTop = node;
11220
11408
  let parent = chainTop.getParent();
11221
- while (parent !== void 0 && import_ts_morph53.Node.isPropertyAccessExpression(parent) && parent.getExpression() === chainTop) {
11409
+ while (parent !== void 0 && import_ts_morph54.Node.isPropertyAccessExpression(parent) && parent.getExpression() === chainTop) {
11222
11410
  chainTop = parent;
11223
11411
  parent = chainTop.getParent();
11224
11412
  }
11225
11413
  const segments = [];
11226
11414
  let current2 = chainTop;
11227
- while (import_ts_morph53.Node.isPropertyAccessExpression(current2)) {
11415
+ while (import_ts_morph54.Node.isPropertyAccessExpression(current2)) {
11228
11416
  segments.push(current2.getName());
11229
11417
  current2 = current2.getExpression();
11230
11418
  }
@@ -11238,15 +11426,15 @@ function isBindingDeclarationSite(node) {
11238
11426
  return true;
11239
11427
  }
11240
11428
  const parent = node.getParent();
11241
- return parent !== void 0 && import_ts_morph53.Node.isParameterDeclaration(parent) && parent.getNameNode() === node;
11429
+ return parent !== void 0 && import_ts_morph54.Node.isParameterDeclaration(parent) && parent.getNameNode() === node;
11242
11430
  }
11243
11431
  function isInsideObjectBindingPattern(node) {
11244
11432
  let current2 = node.getParent();
11245
11433
  while (current2 !== void 0) {
11246
- if (import_ts_morph53.Node.isObjectBindingPattern(current2)) {
11434
+ if (import_ts_morph54.Node.isObjectBindingPattern(current2)) {
11247
11435
  return true;
11248
11436
  }
11249
- if (import_ts_morph53.Node.isFunctionLikeDeclaration(current2) || import_ts_morph53.Node.isVariableStatement(current2)) {
11437
+ if (import_ts_morph54.Node.isFunctionLikeDeclaration(current2) || import_ts_morph54.Node.isVariableStatement(current2)) {
11250
11438
  break;
11251
11439
  }
11252
11440
  current2 = current2.getParent();
@@ -11309,7 +11497,7 @@ function findBranchSubtree(func, byLineRange, terminalStartLine, terminalEndLine
11309
11497
  if (parent === void 0) {
11310
11498
  break;
11311
11499
  }
11312
- if (import_ts_morph53.Node.isIfStatement(parent)) {
11500
+ if (import_ts_morph54.Node.isIfStatement(parent)) {
11313
11501
  const ifStmt = parent;
11314
11502
  const thenBlock = ifStmt.getThenStatement();
11315
11503
  const elseBlock = ifStmt.getElseStatement();
@@ -11371,7 +11559,7 @@ function buildNonBodyPropertySet(semantics) {
11371
11559
  }
11372
11560
 
11373
11561
  // src/subUnitContext.ts
11374
- var import_ts_morph54 = require("ts-morph");
11562
+ var import_ts_morph55 = require("ts-morph");
11375
11563
  function createTsSubUnitContext() {
11376
11564
  return {
11377
11565
  findJsxAttributes,
@@ -11384,7 +11572,7 @@ function createTsSubUnitContext() {
11384
11572
  }
11385
11573
  function skipNestedFunctions(parent) {
11386
11574
  return (node, traversal) => {
11387
- if (node !== parent && (import_ts_morph54.Node.isFunctionDeclaration(node) || import_ts_morph54.Node.isFunctionExpression(node) || import_ts_morph54.Node.isArrowFunction(node) || import_ts_morph54.Node.isMethodDeclaration(node))) {
11575
+ if (node !== parent && (import_ts_morph55.Node.isFunctionDeclaration(node) || import_ts_morph55.Node.isFunctionExpression(node) || import_ts_morph55.Node.isArrowFunction(node) || import_ts_morph55.Node.isMethodDeclaration(node))) {
11388
11576
  traversal.skip();
11389
11577
  return true;
11390
11578
  }
@@ -11398,18 +11586,18 @@ function findJsxAttributes(parent) {
11398
11586
  if (skip(node, traversal)) {
11399
11587
  return;
11400
11588
  }
11401
- if (!import_ts_morph54.Node.isJsxOpeningElement(node) && !import_ts_morph54.Node.isJsxSelfClosingElement(node)) {
11589
+ if (!import_ts_morph55.Node.isJsxOpeningElement(node) && !import_ts_morph55.Node.isJsxSelfClosingElement(node)) {
11402
11590
  return;
11403
11591
  }
11404
11592
  const tag = node.getTagNameNode().getText();
11405
11593
  for (const attr of node.getAttributes()) {
11406
- if (!import_ts_morph54.Node.isJsxAttribute(attr)) {
11594
+ if (!import_ts_morph55.Node.isJsxAttribute(attr)) {
11407
11595
  continue;
11408
11596
  }
11409
11597
  const initializer = attr.getInitializer();
11410
11598
  let valueExpression = null;
11411
11599
  if (initializer !== void 0) {
11412
- if (import_ts_morph54.Node.isJsxExpression(initializer)) {
11600
+ if (import_ts_morph55.Node.isJsxExpression(initializer)) {
11413
11601
  const inner = initializer.getExpression();
11414
11602
  valueExpression = inner ?? null;
11415
11603
  } else {
@@ -11432,11 +11620,11 @@ function findCallExpressionsByName(parent, name) {
11432
11620
  if (skip(node, traversal)) {
11433
11621
  return;
11434
11622
  }
11435
- if (!import_ts_morph54.Node.isCallExpression(node)) {
11623
+ if (!import_ts_morph55.Node.isCallExpression(node)) {
11436
11624
  return;
11437
11625
  }
11438
11626
  const callee = node.getExpression();
11439
- if (import_ts_morph54.Node.isIdentifier(callee) && callee.getText() === name) {
11627
+ if (import_ts_morph55.Node.isIdentifier(callee) && callee.getText() === name) {
11440
11628
  out.push(node);
11441
11629
  }
11442
11630
  });
@@ -11447,10 +11635,10 @@ function resolveAttributeValueFunction(attr, parent) {
11447
11635
  if (expr === null) {
11448
11636
  return null;
11449
11637
  }
11450
- if (import_ts_morph54.Node.isArrowFunction(expr) || import_ts_morph54.Node.isFunctionExpression(expr)) {
11638
+ if (import_ts_morph55.Node.isArrowFunction(expr) || import_ts_morph55.Node.isFunctionExpression(expr)) {
11451
11639
  return { func: expr, localName: null };
11452
11640
  }
11453
- if (import_ts_morph54.Node.isIdentifier(expr)) {
11641
+ if (import_ts_morph55.Node.isIdentifier(expr)) {
11454
11642
  const symbol = expr.getSymbol();
11455
11643
  if (symbol === void 0) {
11456
11644
  return null;
@@ -11469,15 +11657,15 @@ function resolveAttributeValueFunction(attr, parent) {
11469
11657
  return null;
11470
11658
  }
11471
11659
  function tryExtractFunction(decl) {
11472
- if (import_ts_morph54.Node.isFunctionDeclaration(decl)) {
11660
+ if (import_ts_morph55.Node.isFunctionDeclaration(decl)) {
11473
11661
  return decl;
11474
11662
  }
11475
- if (import_ts_morph54.Node.isVariableDeclaration(decl)) {
11663
+ if (import_ts_morph55.Node.isVariableDeclaration(decl)) {
11476
11664
  const init = decl.getInitializer();
11477
11665
  if (init === void 0) {
11478
11666
  return null;
11479
11667
  }
11480
- if (import_ts_morph54.Node.isArrowFunction(init) || import_ts_morph54.Node.isFunctionExpression(init)) {
11668
+ if (import_ts_morph55.Node.isArrowFunction(init) || import_ts_morph55.Node.isFunctionExpression(init)) {
11481
11669
  return init;
11482
11670
  }
11483
11671
  }
@@ -11498,7 +11686,7 @@ function getCallArgumentFunction(call, position) {
11498
11686
  if (arg === void 0) {
11499
11687
  return null;
11500
11688
  }
11501
- if (import_ts_morph54.Node.isArrowFunction(arg) || import_ts_morph54.Node.isFunctionExpression(arg)) {
11689
+ if (import_ts_morph55.Node.isArrowFunction(arg) || import_ts_morph55.Node.isFunctionExpression(arg)) {
11502
11690
  return arg;
11503
11691
  }
11504
11692
  return null;
@@ -11510,7 +11698,7 @@ function readArrayLiteralText(node) {
11510
11698
  if (node === null) {
11511
11699
  return null;
11512
11700
  }
11513
- if (import_ts_morph54.Node.isArrayLiteralExpression(node)) {
11701
+ if (import_ts_morph55.Node.isArrayLiteralExpression(node)) {
11514
11702
  return node.getElements().map((e) => e.getText());
11515
11703
  }
11516
11704
  return [node.getText()];
@@ -11733,13 +11921,13 @@ var raise = (msg) => {
11733
11921
  throw new Error(msg);
11734
11922
  };
11735
11923
  function bindingPatternNames(nameNode) {
11736
- if (import_ts_morph55.Node.isObjectBindingPattern(nameNode)) {
11924
+ if (import_ts_morph56.Node.isObjectBindingPattern(nameNode)) {
11737
11925
  return nameNode.getElements().map((e) => e.getName());
11738
11926
  }
11739
- if (import_ts_morph55.Node.isArrayBindingPattern(nameNode)) {
11927
+ if (import_ts_morph56.Node.isArrayBindingPattern(nameNode)) {
11740
11928
  const names = [];
11741
11929
  for (const element of nameNode.getElements()) {
11742
- if (import_ts_morph55.Node.isOmittedExpression(element)) {
11930
+ if (import_ts_morph56.Node.isOmittedExpression(element)) {
11743
11931
  continue;
11744
11932
  }
11745
11933
  names.push(element.getName());
@@ -11750,7 +11938,7 @@ function bindingPatternNames(nameNode) {
11750
11938
  }
11751
11939
  function componentPropsParameters(param, mapping) {
11752
11940
  const nameNode = param.getNameNode();
11753
- if (!import_ts_morph55.Node.isObjectBindingPattern(nameNode)) {
11941
+ if (!import_ts_morph56.Node.isObjectBindingPattern(nameNode)) {
11754
11942
  const type = param.getType();
11755
11943
  return [
11756
11944
  {
@@ -11876,11 +12064,11 @@ function extractParameters(func, inputMapping) {
11876
12064
  function extractDependencyCalls(func) {
11877
12065
  const results = [];
11878
12066
  func.forEachDescendant((node, traversal) => {
11879
- if (node !== func && (import_ts_morph55.Node.isFunctionDeclaration(node) || import_ts_morph55.Node.isFunctionExpression(node) || import_ts_morph55.Node.isArrowFunction(node) || import_ts_morph55.Node.isMethodDeclaration(node))) {
12067
+ if (node !== func && (import_ts_morph56.Node.isFunctionDeclaration(node) || import_ts_morph56.Node.isFunctionExpression(node) || import_ts_morph56.Node.isArrowFunction(node) || import_ts_morph56.Node.isMethodDeclaration(node))) {
11880
12068
  traversal.skip();
11881
12069
  return;
11882
12070
  }
11883
- if (!import_ts_morph55.Node.isVariableDeclaration(node)) {
12071
+ if (!import_ts_morph56.Node.isVariableDeclaration(node)) {
11884
12072
  return;
11885
12073
  }
11886
12074
  const init = node.getInitializer();
@@ -11889,19 +12077,19 @@ function extractDependencyCalls(func) {
11889
12077
  }
11890
12078
  let isAsync = false;
11891
12079
  let callExpr = init;
11892
- if (import_ts_morph55.Node.isAwaitExpression(init)) {
12080
+ if (import_ts_morph56.Node.isAwaitExpression(init)) {
11893
12081
  isAsync = true;
11894
12082
  callExpr = init.getExpression();
11895
12083
  }
11896
- if (!import_ts_morph55.Node.isCallExpression(callExpr)) {
12084
+ if (!import_ts_morph56.Node.isCallExpression(callExpr)) {
11897
12085
  return;
11898
12086
  }
11899
12087
  const calleeName = callExpr.getExpression().getText();
11900
12088
  const nameNode = node.getNameNode();
11901
- const assignedTo = import_ts_morph55.Node.isIdentifier(nameNode) ? nameNode.getText() : null;
12089
+ const assignedTo = import_ts_morph56.Node.isIdentifier(nameNode) ? nameNode.getText() : null;
11902
12090
  const declList = node.getParent();
11903
12091
  const varStmt = declList?.getParent();
11904
- const locationNode = varStmt !== void 0 && import_ts_morph55.Node.isVariableStatement(varStmt) ? varStmt : node;
12092
+ const locationNode = varStmt !== void 0 && import_ts_morph56.Node.isVariableStatement(varStmt) ? varStmt : node;
11905
12093
  results.push({
11906
12094
  name: calleeName,
11907
12095
  assignedTo,
@@ -12157,9 +12345,9 @@ function extractBindingMethod(binding, callSite, pack, resolution) {
12157
12345
  if (m.type === "fromArgumentProperty") {
12158
12346
  const args = callSite.callExpression.getArguments();
12159
12347
  const arg = args[m.position];
12160
- if (arg !== void 0 && import_ts_morph55.Node.isObjectLiteralExpression(arg)) {
12348
+ if (arg !== void 0 && import_ts_morph56.Node.isObjectLiteralExpression(arg)) {
12161
12349
  const prop = arg.getProperty(m.property);
12162
- if (prop !== void 0 && import_ts_morph55.Node.isPropertyAssignment(prop)) {
12350
+ if (prop !== void 0 && import_ts_morph56.Node.isPropertyAssignment(prop)) {
12163
12351
  const init = prop.getInitializer();
12164
12352
  if (init !== void 0) {
12165
12353
  const value = stringValueOf(init, resolution);
@@ -12288,22 +12476,22 @@ function extractBindingPath(binding, callSite, pack, resolution) {
12288
12476
  return void 0;
12289
12477
  }
12290
12478
  function pathFromUrlNode(node) {
12291
- if (import_ts_morph55.Node.isStringLiteral(node)) {
12479
+ if (import_ts_morph56.Node.isStringLiteral(node)) {
12292
12480
  return pathFromLiteralUrl(node.getLiteralValue());
12293
12481
  }
12294
- if (import_ts_morph55.Node.isNoSubstitutionTemplateLiteral(node)) {
12482
+ if (import_ts_morph56.Node.isNoSubstitutionTemplateLiteral(node)) {
12295
12483
  return pathFromLiteralUrl(node.getLiteralValue());
12296
12484
  }
12297
- if (import_ts_morph55.Node.isTemplateExpression(node)) {
12485
+ if (import_ts_morph56.Node.isTemplateExpression(node)) {
12298
12486
  return pathFromTemplateUrl(node);
12299
12487
  }
12300
12488
  return void 0;
12301
12489
  }
12302
12490
  function placeholderName(expr) {
12303
- if (import_ts_morph55.Node.isIdentifier(expr)) {
12491
+ if (import_ts_morph56.Node.isIdentifier(expr)) {
12304
12492
  return expr.getText();
12305
12493
  }
12306
- if (import_ts_morph55.Node.isPropertyAccessExpression(expr)) {
12494
+ if (import_ts_morph56.Node.isPropertyAccessExpression(expr)) {
12307
12495
  return expr.getName();
12308
12496
  }
12309
12497
  return "param";
@@ -12738,7 +12926,7 @@ function expandWrapperCallers(summaries, project, options) {
12738
12926
  continue;
12739
12927
  }
12740
12928
  const binding = s.identity.boundaryBinding;
12741
- if (binding === null || binding.semantics.name !== "rest" || binding.semantics.method === null || binding.semantics.path !== null) {
12929
+ if (binding === null || binding.semantics.name !== "rest" || binding.semantics.method === null) {
12742
12930
  continue;
12743
12931
  }
12744
12932
  lookup ??= createSourceFileLookup(project);
@@ -12766,11 +12954,21 @@ function findWrapperPathParam(summary, lookup) {
12766
12954
  if (func === null) {
12767
12955
  return null;
12768
12956
  }
12769
- const params = func.getParameters();
12770
- if (params.length === 0) {
12957
+ const names = func.getParameters().map((p) => p.getName());
12958
+ if (names.length === 0) {
12771
12959
  return null;
12772
12960
  }
12773
- return { func, pathParamPosition: 0 };
12961
+ for (const call of func.getDescendantsOfKind(import_ts_morph56.SyntaxKind.CallExpression)) {
12962
+ const first = call.getArguments()[0];
12963
+ if (first === void 0 || !import_ts_morph56.Node.isIdentifier(first)) {
12964
+ continue;
12965
+ }
12966
+ const at = names.indexOf(first.getText());
12967
+ if (at !== -1) {
12968
+ return { func, pathParamPosition: at };
12969
+ }
12970
+ }
12971
+ return null;
12774
12972
  }
12775
12973
  function synthesizeCallerSummaries(wrapper, _project, options) {
12776
12974
  const nameNode = wrapperNameNode(wrapper.func);
@@ -12811,16 +13009,16 @@ function synthesizeCallerSummaries(wrapper, _project, options) {
12811
13009
  return out;
12812
13010
  }
12813
13011
  function wrapperNameNode(func) {
12814
- if (import_ts_morph55.Node.isFunctionDeclaration(func) || import_ts_morph55.Node.isMethodDeclaration(func)) {
13012
+ if (import_ts_morph56.Node.isFunctionDeclaration(func) || import_ts_morph56.Node.isMethodDeclaration(func)) {
12815
13013
  const name = func.getNameNode();
12816
- if (name !== void 0 && import_ts_morph55.Node.isIdentifier(name)) {
13014
+ if (name !== void 0 && import_ts_morph56.Node.isIdentifier(name)) {
12817
13015
  return name;
12818
13016
  }
12819
13017
  }
12820
13018
  const parent = func.getParent();
12821
- if (parent !== void 0 && import_ts_morph55.Node.isVariableDeclaration(parent)) {
13019
+ if (parent !== void 0 && import_ts_morph56.Node.isVariableDeclaration(parent)) {
12822
13020
  const nameNode = parent.getNameNode();
12823
- if (import_ts_morph55.Node.isIdentifier(nameNode)) {
13021
+ if (import_ts_morph56.Node.isIdentifier(nameNode)) {
12824
13022
  return nameNode;
12825
13023
  }
12826
13024
  }
@@ -12829,10 +13027,10 @@ function wrapperNameNode(func) {
12829
13027
  function enclosingCall(node) {
12830
13028
  let current2 = node.getParent();
12831
13029
  while (current2 !== void 0) {
12832
- if (import_ts_morph55.Node.isCallExpression(current2)) {
13030
+ if (import_ts_morph56.Node.isCallExpression(current2)) {
12833
13031
  return current2;
12834
13032
  }
12835
- if (import_ts_morph55.Node.isPropertyAccessExpression(current2)) {
13033
+ if (import_ts_morph56.Node.isPropertyAccessExpression(current2)) {
12836
13034
  current2 = current2.getParent();
12837
13035
  continue;
12838
13036
  }
@@ -12843,7 +13041,7 @@ function enclosingCall(node) {
12843
13041
  function enclosingFunction(node) {
12844
13042
  let current2 = node.getParent();
12845
13043
  while (current2 !== void 0) {
12846
- if (import_ts_morph55.Node.isFunctionDeclaration(current2) || import_ts_morph55.Node.isFunctionExpression(current2) || import_ts_morph55.Node.isArrowFunction(current2) || import_ts_morph55.Node.isMethodDeclaration(current2)) {
13044
+ if (import_ts_morph56.Node.isFunctionDeclaration(current2) || import_ts_morph56.Node.isFunctionExpression(current2) || import_ts_morph56.Node.isArrowFunction(current2) || import_ts_morph56.Node.isMethodDeclaration(current2)) {
12847
13045
  return current2;
12848
13046
  }
12849
13047
  current2 = current2.getParent();
@@ -12851,13 +13049,13 @@ function enclosingFunction(node) {
12851
13049
  return null;
12852
13050
  }
12853
13051
  function literalOrTemplate(arg) {
12854
- if (import_ts_morph55.Node.isStringLiteral(arg)) {
13052
+ if (import_ts_morph56.Node.isStringLiteral(arg)) {
12855
13053
  return arg.getLiteralValue();
12856
13054
  }
12857
- if (import_ts_morph55.Node.isNoSubstitutionTemplateLiteral(arg)) {
13055
+ if (import_ts_morph56.Node.isNoSubstitutionTemplateLiteral(arg)) {
12858
13056
  return arg.getLiteralValue();
12859
13057
  }
12860
- if (import_ts_morph55.Node.isTemplateExpression(arg)) {
13058
+ if (import_ts_morph56.Node.isTemplateExpression(arg)) {
12861
13059
  let path11 = arg.getHead().getLiteralText();
12862
13060
  for (const span of arg.getTemplateSpans()) {
12863
13061
  path11 += `{${placeholderName(span.getExpression())}}`;
@@ -12868,13 +13066,13 @@ function literalOrTemplate(arg) {
12868
13066
  return void 0;
12869
13067
  }
12870
13068
  function callerName(func) {
12871
- if (import_ts_morph55.Node.isFunctionDeclaration(func) || import_ts_morph55.Node.isMethodDeclaration(func)) {
13069
+ if (import_ts_morph56.Node.isFunctionDeclaration(func) || import_ts_morph56.Node.isMethodDeclaration(func)) {
12872
13070
  return func.getName() ?? "anonymous";
12873
13071
  }
12874
13072
  const parent = func.getParent();
12875
- if (parent !== void 0 && import_ts_morph55.Node.isVariableDeclaration(parent)) {
13073
+ if (parent !== void 0 && import_ts_morph56.Node.isVariableDeclaration(parent)) {
12876
13074
  const nameNode = parent.getNameNode();
12877
- if (import_ts_morph55.Node.isIdentifier(nameNode)) {
13075
+ if (import_ts_morph56.Node.isIdentifier(nameNode)) {
12878
13076
  return nameNode.getText();
12879
13077
  }
12880
13078
  }
@@ -12979,7 +13177,7 @@ function loadRunFiles(project, candidatePaths, timer) {
12979
13177
  return { sourceFiles, deep };
12980
13178
  }
12981
13179
  function createTypeScriptAdapter(config) {
12982
- const project = config.project ?? new import_ts_morph55.Project(
13180
+ const project = config.project ?? new import_ts_morph56.Project(
12983
13181
  config.tsConfigFilePath !== void 0 ? {
12984
13182
  tsConfigFilePath: config.tsConfigFilePath,
12985
13183
  skipAddingFilesFromTsConfig: true
@@ -13148,7 +13346,8 @@ function createTypeScriptAdapter(config) {
13148
13346
  tallies
13149
13347
  ),
13150
13348
  access: collectAccessRecognizers(config.frameworks, tallies),
13151
- resolveWrittenValue: (value) => resolution.resolveWrittenValue(value)
13349
+ resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
13350
+ resolveCallable: (value, alsoFrom) => resolution.resolveCallable(value, alsoFrom)
13152
13351
  }
13153
13352
  )
13154
13353
  ) : withSubUnits;
@@ -13321,7 +13520,7 @@ function buildSubUnitSummary(subUnit, parent, invocationRecognizers, accessRecog
13321
13520
  // src/bootstrap/noTsconfigProject.ts
13322
13521
  var import_node_fs6 = __toESM(require("fs"), 1);
13323
13522
  var import_node_path10 = __toESM(require("path"), 1);
13324
- var import_ts_morph56 = require("ts-morph");
13523
+ var import_ts_morph57 = require("ts-morph");
13325
13524
  var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
13326
13525
  ".ts",
13327
13526
  ".tsx",
@@ -13369,12 +13568,12 @@ function findSourceFiles(rootDir, depth = 0) {
13369
13568
  return found;
13370
13569
  }
13371
13570
  function createProjectWithoutTsconfig(rootDir) {
13372
- const project = new import_ts_morph56.Project({
13571
+ const project = new import_ts_morph57.Project({
13373
13572
  skipAddingFilesFromTsConfig: true,
13374
13573
  compilerOptions: {
13375
- target: import_ts_morph56.ScriptTarget.ES2022,
13376
- module: import_ts_morph56.ModuleKind.ESNext,
13377
- moduleResolution: import_ts_morph56.ModuleResolutionKind.Bundler,
13574
+ target: import_ts_morph57.ScriptTarget.ES2022,
13575
+ module: import_ts_morph57.ModuleKind.ESNext,
13576
+ moduleResolution: import_ts_morph57.ModuleResolutionKind.Bundler,
13378
13577
  allowJs: true,
13379
13578
  checkJs: false,
13380
13579
  noEmit: true,
@@ -13414,10 +13613,10 @@ function findNearestTsconfig(startDir) {
13414
13613
  }
13415
13614
 
13416
13615
  // src/configuredCall.ts
13417
- var import_ts_morph57 = require("ts-morph");
13616
+ var import_ts_morph58 = require("ts-morph");
13418
13617
  function readConfiguredCall(call, ctx, spec) {
13419
13618
  const callee = call.getExpression();
13420
- if (!import_ts_morph57.Node.isPropertyAccessExpression(callee)) {
13619
+ if (!import_ts_morph58.Node.isPropertyAccessExpression(callee)) {
13421
13620
  return null;
13422
13621
  }
13423
13622
  if (callee.getName() !== spec.method) {
@@ -13462,10 +13661,10 @@ function readStringArg(arg) {
13462
13661
  }
13463
13662
  function rootIdentifier(node) {
13464
13663
  let current2 = node;
13465
- while (import_ts_morph57.Node.isPropertyAccessExpression(current2)) {
13664
+ while (import_ts_morph58.Node.isPropertyAccessExpression(current2)) {
13466
13665
  current2 = current2.getExpression();
13467
13666
  }
13468
- return import_ts_morph57.Node.isIdentifier(current2) ? current2 : null;
13667
+ return import_ts_morph58.Node.isIdentifier(current2) ? current2 : null;
13469
13668
  }
13470
13669
 
13471
13670
  // src/packHealth.ts
@@ -13581,7 +13780,7 @@ function formatPackHealth(checks, audiences) {
13581
13780
  }
13582
13781
 
13583
13782
  // src/resolve/readName.ts
13584
- var import_ts_morph58 = require("ts-morph");
13783
+ var import_ts_morph59 = require("ts-morph");
13585
13784
  var MAX_HELPER_HOPS = 2;
13586
13785
  var UNNAMED_HOLE = "param";
13587
13786
  function readName(expr, options = {}) {
@@ -13610,25 +13809,25 @@ function read(expr, ctx) {
13610
13809
  }
13611
13810
  const seen = new Set(ctx.seen).add(expr);
13612
13811
  const inner = { ...ctx, seen };
13613
- if (import_ts_morph58.Node.isStringLiteral(expr) || import_ts_morph58.Node.isNoSubstitutionTemplateLiteral(expr)) {
13812
+ if (import_ts_morph59.Node.isStringLiteral(expr) || import_ts_morph59.Node.isNoSubstitutionTemplateLiteral(expr)) {
13614
13813
  return expr.getLiteralValue();
13615
13814
  }
13616
- if (import_ts_morph58.Node.isNumericLiteral(expr)) {
13815
+ if (import_ts_morph59.Node.isNumericLiteral(expr)) {
13617
13816
  return expr.getLiteralText();
13618
13817
  }
13619
- if (import_ts_morph58.Node.isTemplateExpression(expr)) {
13818
+ if (import_ts_morph59.Node.isTemplateExpression(expr)) {
13620
13819
  return fromTemplate(expr, inner);
13621
13820
  }
13622
- if (import_ts_morph58.Node.isParenthesizedExpression(expr)) {
13821
+ if (import_ts_morph59.Node.isParenthesizedExpression(expr)) {
13623
13822
  return read(expr.getExpression(), inner);
13624
13823
  }
13625
- if (import_ts_morph58.Node.isBinaryExpression(expr)) {
13824
+ if (import_ts_morph59.Node.isBinaryExpression(expr)) {
13626
13825
  return fromBinary(expr, inner);
13627
13826
  }
13628
- if (import_ts_morph58.Node.isCallExpression(expr)) {
13827
+ if (import_ts_morph59.Node.isCallExpression(expr)) {
13629
13828
  return fromCall(expr, inner);
13630
13829
  }
13631
- if (import_ts_morph58.Node.isIdentifier(expr)) {
13830
+ if (import_ts_morph59.Node.isIdentifier(expr)) {
13632
13831
  const only = boundOnce(expr, ctx);
13633
13832
  if (only !== null) {
13634
13833
  return read(only.node, { ...inner, bindings: only.scope });
@@ -13638,7 +13837,7 @@ function read(expr, ctx) {
13638
13837
  return written === null || written === expr ? null : read(written, inner);
13639
13838
  }
13640
13839
  function fromTemplate(expr, ctx) {
13641
- if (!import_ts_morph58.Node.isTemplateExpression(expr)) {
13840
+ if (!import_ts_morph59.Node.isTemplateExpression(expr)) {
13642
13841
  return null;
13643
13842
  }
13644
13843
  let name = expr.getHead().getLiteralText();
@@ -13649,28 +13848,28 @@ function fromTemplate(expr, ctx) {
13649
13848
  return name;
13650
13849
  }
13651
13850
  function fromBinary(expr, ctx) {
13652
- if (!import_ts_morph58.Node.isBinaryExpression(expr)) {
13851
+ if (!import_ts_morph59.Node.isBinaryExpression(expr)) {
13653
13852
  return null;
13654
13853
  }
13655
13854
  const operator = expr.getOperatorToken().getKind();
13656
- if (operator === import_ts_morph58.SyntaxKind.BarBarToken || operator === import_ts_morph58.SyntaxKind.QuestionQuestionToken) {
13855
+ if (operator === import_ts_morph59.SyntaxKind.BarBarToken || operator === import_ts_morph59.SyntaxKind.QuestionQuestionToken) {
13657
13856
  return ctx.insideHole ? null : read(expr.getRight(), ctx);
13658
13857
  }
13659
- if (operator !== import_ts_morph58.SyntaxKind.PlusToken) {
13858
+ if (operator !== import_ts_morph59.SyntaxKind.PlusToken) {
13660
13859
  return null;
13661
13860
  }
13662
13861
  const parts = { ...ctx, insideHole: true };
13663
13862
  return readOrHole(expr.getLeft(), parts) + readOrHole(expr.getRight(), parts);
13664
13863
  }
13665
13864
  function fromCall(expr, ctx) {
13666
- if (!import_ts_morph58.Node.isCallExpression(expr)) {
13865
+ if (!import_ts_morph59.Node.isCallExpression(expr)) {
13667
13866
  return null;
13668
13867
  }
13669
13868
  const callee = expr.getExpression();
13670
- if (import_ts_morph58.Node.isPropertyAccessExpression(callee) && callee.getName() === "join") {
13869
+ if (import_ts_morph59.Node.isPropertyAccessExpression(callee) && callee.getName() === "join") {
13671
13870
  return fromJoin(callee.getExpression(), expr.getArguments(), ctx);
13672
13871
  }
13673
- if (import_ts_morph58.Node.isIdentifier(callee) && callee.getText() === "String") {
13872
+ if (import_ts_morph59.Node.isIdentifier(callee) && callee.getText() === "String") {
13674
13873
  const only = expr.getArguments()[0];
13675
13874
  return only === void 0 ? null : readOrHole(only, ctx);
13676
13875
  }
@@ -13689,7 +13888,7 @@ function fromCall(expr, ctx) {
13689
13888
  }
13690
13889
  function fromJoin(subject, args, ctx) {
13691
13890
  const separator = args[0];
13692
- if (separator === void 0 || !import_ts_morph58.Node.isStringLiteral(separator)) {
13891
+ if (separator === void 0 || !import_ts_morph59.Node.isStringLiteral(separator)) {
13693
13892
  return null;
13694
13893
  }
13695
13894
  const parts = elementsOf(subject, ctx);
@@ -13705,17 +13904,17 @@ function fromJoin(subject, args, ctx) {
13705
13904
  ).join(separator.getLiteralValue());
13706
13905
  }
13707
13906
  function elementsOf(subject, ctx) {
13708
- if (import_ts_morph58.Node.isArrayLiteralExpression(subject)) {
13907
+ if (import_ts_morph59.Node.isArrayLiteralExpression(subject)) {
13709
13908
  return subject.getElements().map((element) => here(element, ctx));
13710
13909
  }
13711
- if (import_ts_morph58.Node.isCallExpression(subject)) {
13910
+ if (import_ts_morph59.Node.isCallExpression(subject)) {
13712
13911
  const callee = subject.getExpression();
13713
- if (import_ts_morph58.Node.isPropertyAccessExpression(callee) && callee.getName() === "map") {
13912
+ if (import_ts_morph59.Node.isPropertyAccessExpression(callee) && callee.getName() === "map") {
13714
13913
  return elementsOf(callee.getExpression(), ctx);
13715
13914
  }
13716
13915
  return null;
13717
13916
  }
13718
- if (!import_ts_morph58.Node.isIdentifier(subject)) {
13917
+ if (!import_ts_morph59.Node.isIdentifier(subject)) {
13719
13918
  return null;
13720
13919
  }
13721
13920
  const bound = ctx.bindings.get(subject.getText());
@@ -13723,7 +13922,7 @@ function elementsOf(subject, ctx) {
13723
13922
  return null;
13724
13923
  }
13725
13924
  const only = bound.length === 1 ? bound[0] : void 0;
13726
- return only !== void 0 && import_ts_morph58.Node.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
13925
+ return only !== void 0 && import_ts_morph59.Node.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
13727
13926
  }
13728
13927
  function singleReturnBody(callee, ctx) {
13729
13928
  const declaration = declarationOf2(callee, ctx);
@@ -13738,22 +13937,22 @@ function singleReturnBody(callee, ctx) {
13738
13937
  if (body === void 0) {
13739
13938
  return null;
13740
13939
  }
13741
- if (import_ts_morph58.Node.isExpression(body)) {
13940
+ if (import_ts_morph59.Node.isExpression(body)) {
13742
13941
  return { parameters, returned: body };
13743
13942
  }
13744
- if (!import_ts_morph58.Node.isBlock(body)) {
13943
+ if (!import_ts_morph59.Node.isBlock(body)) {
13745
13944
  return null;
13746
13945
  }
13747
13946
  const statements = body.getStatements();
13748
13947
  const only = statements[0];
13749
- if (statements.length !== 1 || only === void 0 || !import_ts_morph58.Node.isReturnStatement(only)) {
13948
+ if (statements.length !== 1 || only === void 0 || !import_ts_morph59.Node.isReturnStatement(only)) {
13750
13949
  return null;
13751
13950
  }
13752
13951
  const returned = only.getExpression();
13753
13952
  return returned === void 0 ? null : { parameters, returned };
13754
13953
  }
13755
13954
  function declarationOf2(callee, ctx) {
13756
- const symbol = import_ts_morph58.Node.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
13955
+ const symbol = import_ts_morph59.Node.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
13757
13956
  const declarations = symbol?.getAliasedSymbol()?.getDeclarations() ?? symbol?.getDeclarations() ?? [];
13758
13957
  for (const declaration of declarations) {
13759
13958
  const callable = asCallable(declaration);
@@ -13765,14 +13964,14 @@ function declarationOf2(callee, ctx) {
13765
13964
  return written === null || written === callee ? null : declarationOf2(written, { ...ctx, resolve: () => null });
13766
13965
  }
13767
13966
  function asCallable(declaration) {
13768
- if (import_ts_morph58.Node.isFunctionDeclaration(declaration) || import_ts_morph58.Node.isMethodDeclaration(declaration) || import_ts_morph58.Node.isArrowFunction(declaration) || import_ts_morph58.Node.isFunctionExpression(declaration)) {
13967
+ if (import_ts_morph59.Node.isFunctionDeclaration(declaration) || import_ts_morph59.Node.isMethodDeclaration(declaration) || import_ts_morph59.Node.isArrowFunction(declaration) || import_ts_morph59.Node.isFunctionExpression(declaration)) {
13769
13968
  return declaration;
13770
13969
  }
13771
- if (!import_ts_morph58.Node.isVariableDeclaration(declaration)) {
13970
+ if (!import_ts_morph59.Node.isVariableDeclaration(declaration)) {
13772
13971
  return null;
13773
13972
  }
13774
13973
  const initializer = declaration.getInitializer();
13775
- if (initializer !== void 0 && (import_ts_morph58.Node.isArrowFunction(initializer) || import_ts_morph58.Node.isFunctionExpression(initializer))) {
13974
+ if (initializer !== void 0 && (import_ts_morph59.Node.isArrowFunction(initializer) || import_ts_morph59.Node.isFunctionExpression(initializer))) {
13776
13975
  return initializer;
13777
13976
  }
13778
13977
  return null;
@@ -13794,7 +13993,7 @@ function here(node, ctx) {
13794
13993
  return { node, scope: ctx.bindings };
13795
13994
  }
13796
13995
  function boundOnce(expr, ctx) {
13797
- const bound = import_ts_morph58.Node.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
13996
+ const bound = import_ts_morph59.Node.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
13798
13997
  return bound !== void 0 && bound.length === 1 ? bound[0] : null;
13799
13998
  }
13800
13999
  function readOrHole(expr, ctx) {
@@ -13806,10 +14005,10 @@ function holeName(expr, ctx) {
13806
14005
  if (bound !== null) {
13807
14006
  return holeName(bound.node, { ...ctx, bindings: bound.scope });
13808
14007
  }
13809
- if (import_ts_morph58.Node.isIdentifier(expr)) {
14008
+ if (import_ts_morph59.Node.isIdentifier(expr)) {
13810
14009
  return expr.getText();
13811
14010
  }
13812
- if (import_ts_morph58.Node.isPropertyAccessExpression(expr)) {
14011
+ if (import_ts_morph59.Node.isPropertyAccessExpression(expr)) {
13813
14012
  return expr.getName();
13814
14013
  }
13815
14014
  return UNNAMED_HOLE;