@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.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // src/adapter.ts
2
2
  import path9 from "path";
3
3
  import {
4
- Node as Node53,
5
- Project
4
+ Node as Node54,
5
+ Project,
6
+ SyntaxKind as SyntaxKind11
6
7
  } from "ts-morph";
7
8
  import {
8
9
  functionCallBinding as functionCallBinding2,
@@ -3953,6 +3954,7 @@ import { Node as Node18 } from "ts-morph";
3953
3954
  import { Node as Node17, SyntaxKind as SyntaxKind5, VariableDeclarationKind } from "ts-morph";
3954
3955
  var byFile = createPerFileCache();
3955
3956
  var byDeclaration = /* @__PURE__ */ new WeakMap();
3957
+ var byField = /* @__PURE__ */ new WeakMap();
3956
3958
  function writesToBinding(declaration) {
3957
3959
  const remembered = byDeclaration.get(declaration);
3958
3960
  if (remembered !== void 0) {
@@ -3985,22 +3987,19 @@ function writesToBindingUncached(declaration) {
3985
3987
  return { values, inOrder: writesRunInOrder(declaration, writes) };
3986
3988
  }
3987
3989
  function writesToField(declaration) {
3988
- const remembered = byDeclaration.get(declaration);
3990
+ const remembered = byField.get(declaration);
3989
3991
  if (remembered !== void 0) {
3990
3992
  return remembered;
3991
3993
  }
3992
3994
  const answer = writesToFieldUncached(declaration);
3993
- byDeclaration.set(declaration, answer);
3995
+ byField.set(declaration, answer);
3994
3996
  return answer;
3995
3997
  }
3996
3998
  function writesToFieldUncached(declaration) {
3997
- const initializer = declaration.getInitializer();
3999
+ const first = startingValueOf(declaration);
3998
4000
  const assignments = assignmentsTo(declaration);
3999
4001
  if (assignments.length === 0) {
4000
- return {
4001
- values: initializer === void 0 ? [] : [initializer],
4002
- inOrder: true
4003
- };
4002
+ return { values: first === void 0 ? [] : [first], inOrder: true };
4004
4003
  }
4005
4004
  const values = [];
4006
4005
  for (const write of assignments) {
@@ -4009,14 +4008,16 @@ function writesToFieldUncached(declaration) {
4009
4008
  }
4010
4009
  values.push(write.value);
4011
4010
  }
4012
- const withInitializer = initializer === void 0 ? values : [initializer, ...values];
4013
4011
  return {
4014
- values: withInitializer,
4012
+ values: first === void 0 ? values : [first, ...values],
4015
4013
  inOrder: assignments.every(
4016
4014
  (write) => writeRunsInConstructor(declaration, write)
4017
4015
  )
4018
4016
  };
4019
4017
  }
4018
+ function startingValueOf(declaration) {
4019
+ return Node17.isParameterDeclaration(declaration) ? declaration : declaration.getInitializer();
4020
+ }
4020
4021
  function writeRunsInConstructor(declaration, write) {
4021
4022
  const statement = statementOf(write.node);
4022
4023
  if (statement === null) {
@@ -4027,13 +4028,16 @@ function writeRunsInConstructor(declaration, write) {
4027
4028
  return false;
4028
4029
  }
4029
4030
  const owner = body.getParent();
4030
- return owner !== void 0 && Node17.isConstructorDeclaration(owner) && owner.getParent() === declaration.getParent();
4031
+ return owner !== void 0 && Node17.isConstructorDeclaration(owner) && owner.getParent() === classHolding(declaration);
4032
+ }
4033
+ function classHolding(declaration) {
4034
+ return Node17.isParameterDeclaration(declaration) ? declaration.getParent().getParent() : declaration.getParent();
4031
4035
  }
4032
4036
  function isWrittenAgain(declaration) {
4033
4037
  return assignmentsTo(declaration).length > 0;
4034
4038
  }
4035
4039
  function assignmentsTo(declaration) {
4036
- if (Node17.isPropertyDeclaration(declaration)) {
4040
+ if (Node17.isPropertyDeclaration(declaration) || Node17.isParameterDeclaration(declaration)) {
4037
4041
  const sourceFile2 = declaration.getSourceFile();
4038
4042
  return sourceFile2.isDeclarationFile() ? [] : assignmentsInFile(sourceFile2).get(declaration) ?? [];
4039
4043
  }
@@ -4100,7 +4104,9 @@ function declarationsOf(name) {
4100
4104
  }
4101
4105
  const declarations = [];
4102
4106
  for (const declaration of symbol.getDeclarations()) {
4103
- if (Node17.isVariableDeclaration(declaration) || Node17.isPropertyDeclaration(declaration)) {
4107
+ if (Node17.isVariableDeclaration(declaration) || Node17.isPropertyDeclaration(declaration) || // A parameter property is the field's only declaration, so
4108
+ // `this.dao = other` in the constructor writes to it.
4109
+ Node17.isParameterDeclaration(declaration) && declaration.isParameterProperty()) {
4104
4110
  declarations.push(declaration);
4105
4111
  }
4106
4112
  }
@@ -5884,7 +5890,8 @@ function createNodeTable() {
5884
5890
  byId: /* @__PURE__ */ new Map(),
5885
5891
  seenFunctions: /* @__PURE__ */ new Set(),
5886
5892
  seenBindings: /* @__PURE__ */ new Set(),
5887
- seenValues: /* @__PURE__ */ new Set()
5893
+ seenValues: /* @__PURE__ */ new Set(),
5894
+ seenClasses: /* @__PURE__ */ new Set()
5888
5895
  };
5889
5896
  }
5890
5897
  function nodeId(node) {
@@ -6105,7 +6112,7 @@ function emitValue(db, table, value) {
6105
6112
  }
6106
6113
  return id;
6107
6114
  }
6108
- if (Node26.isCallExpression(expression)) {
6115
+ if (Node26.isCallExpression(expression) || Node26.isNewExpression(expression)) {
6109
6116
  emitCallFacts(db, table, expression);
6110
6117
  fact(db, "writtenValue", id);
6111
6118
  return id;
@@ -6132,11 +6139,24 @@ function emitBindingValues(db, table, declaration) {
6132
6139
  function emitFieldValues(db, table, declaration) {
6133
6140
  const { values, inOrder } = writesToField(declaration);
6134
6141
  const last = values[values.length - 1];
6135
- if (!inOrder || last === void 0) {
6142
+ if (!inOrder || last === void 0 || !Node26.isExpression(last)) {
6136
6143
  return;
6137
6144
  }
6138
6145
  fact(db, "binds", nodeId(declaration), emitValue(db, table, last));
6139
6146
  }
6147
+ function emitParameterPropertyRead(db, table, referenceId, declaration) {
6148
+ const { values, inOrder } = writesToField(declaration);
6149
+ const last = values[values.length - 1];
6150
+ if (!inOrder || last === void 0) {
6151
+ return;
6152
+ }
6153
+ if (!Node26.isExpression(last)) {
6154
+ table.byId.set(nodeId(last), last);
6155
+ fact(db, "binds", referenceId, nodeId(last));
6156
+ return;
6157
+ }
6158
+ fact(db, "binds", referenceId, emitValue(db, table, last));
6159
+ }
6140
6160
  function emitBindingElementFacts(db, table, element) {
6141
6161
  const id = nodeId(element);
6142
6162
  table.byId.set(id, element);
@@ -6218,7 +6238,16 @@ function emitReferenceFacts(db, table, reference) {
6218
6238
  continue;
6219
6239
  }
6220
6240
  if (Node26.isParameterDeclaration(declaration)) {
6241
+ if (declaration.isParameterProperty() && Node26.isPropertyAccessExpression(reference)) {
6242
+ emitParameterPropertyRead(db, table, referenceId, declaration);
6243
+ } else {
6244
+ fact(db, "binds", referenceId, declarationId);
6245
+ }
6246
+ continue;
6247
+ }
6248
+ if (Node26.isClassDeclaration(declaration)) {
6221
6249
  fact(db, "binds", referenceId, declarationId);
6250
+ emitClassFacts(db, table, declaration);
6222
6251
  continue;
6223
6252
  }
6224
6253
  if (Node26.isBindingElement(declaration)) {
@@ -6263,9 +6292,14 @@ function emitCallFacts(db, table, call) {
6263
6292
  }
6264
6293
  }
6265
6294
  function emitClassFacts(db, table, declaration) {
6295
+ if (table.seenClasses.has(declaration)) {
6296
+ return;
6297
+ }
6298
+ table.seenClasses.add(declaration);
6266
6299
  const id = nodeId(declaration);
6267
6300
  table.byId.set(id, declaration);
6268
6301
  fact(db, "objectValue", id);
6302
+ emitConstructorParameters(db, table, declaration, id);
6269
6303
  for (const method of declaration.getMethods()) {
6270
6304
  const methodId = nodeId(method);
6271
6305
  table.byId.set(methodId, method);
@@ -6286,6 +6320,25 @@ function emitClassFacts(db, table, declaration) {
6286
6320
  }
6287
6321
  }
6288
6322
  }
6323
+ function emitConstructorParameters(db, table, declaration, classId) {
6324
+ const implementation = declaration.getConstructors().find((candidate) => candidate.getBody() !== void 0);
6325
+ if (implementation === void 0) {
6326
+ return;
6327
+ }
6328
+ emitParameters(db, table, classId, implementation.getParameters());
6329
+ }
6330
+ function emitParameters(db, table, ownerId, parameters) {
6331
+ for (let position = 0; position < parameters.length; position++) {
6332
+ const parameter = parameters[position];
6333
+ if (parameter === void 0) {
6334
+ continue;
6335
+ }
6336
+ const parameterId = nodeId(parameter);
6337
+ table.byId.set(parameterId, parameter);
6338
+ fact(db, "paramOf", ownerId, String(position), parameterId);
6339
+ fact(db, "paramNamed", ownerId, parameter.getName(), parameterId);
6340
+ }
6341
+ }
6289
6342
  function emitFunctionFacts(db, table, fn) {
6290
6343
  if (table.seenFunctions.has(fn)) {
6291
6344
  return;
@@ -6294,17 +6347,7 @@ function emitFunctionFacts(db, table, fn) {
6294
6347
  const fnId = nodeId(fn);
6295
6348
  table.byId.set(fnId, fn);
6296
6349
  if (Node26.isFunctionDeclaration(fn) || Node26.isFunctionExpression(fn) || Node26.isArrowFunction(fn) || Node26.isMethodDeclaration(fn)) {
6297
- const parameters = fn.getParameters();
6298
- for (let position = 0; position < parameters.length; position++) {
6299
- const parameter = parameters[position];
6300
- if (parameter === void 0) {
6301
- continue;
6302
- }
6303
- const parameterId = nodeId(parameter);
6304
- table.byId.set(parameterId, parameter);
6305
- fact(db, "paramOf", fnId, String(position), parameterId);
6306
- fact(db, "paramNamed", fnId, parameter.getName(), parameterId);
6307
- }
6350
+ emitParameters(db, table, fnId, fn.getParameters());
6308
6351
  const body = fn.getBody?.();
6309
6352
  if (body !== void 0) {
6310
6353
  if (Node26.isExpression(body)) {
@@ -10016,14 +10059,16 @@ import {
10016
10059
  import {
10017
10060
  ANSWER_RELATIONS,
10018
10061
  RESOLUTION_QUESTIONS,
10019
- RESOLUTION_RULES as SHARED_RULES
10062
+ RESOLUTION_RULES as SHARED_RULES,
10063
+ VALUE_STEP
10020
10064
  } from "@suss/resolution";
10021
10065
  var JS_RULES = [
10022
- // f.bind(...) resolves to whatever f resolves to.
10066
+ // f.bind(...) leads wherever f leads. Stated as a step, so the
10067
+ // questions other than `comesTo` follow it too.
10023
10068
  rule2(
10024
- "comesTo",
10025
- [v2("r"), v2("h")],
10026
- [lit2("bindCall", v2("r"), v2("t")), lit2("comesTo", v2("t"), v2("h"))]
10069
+ "stepsTo",
10070
+ [v2("r"), v2("t"), VALUE_STEP],
10071
+ [lit2("bindCall", v2("r"), v2("t"))]
10027
10072
  )
10028
10073
  ];
10029
10074
  var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
@@ -10050,9 +10095,21 @@ var ResolutionStore = class {
10050
10095
  this.db.add("wrapperModule", [wrapper.callee, wrapper.module]);
10051
10096
  }
10052
10097
  }
10053
- resolveCallable(value) {
10098
+ /**
10099
+ * `alsoFrom` is a second file to walk out from, for a caller that
10100
+ * knows where the value it is asking about was set up. The walk
10101
+ * follows imports outward from the value's own file, so a file that
10102
+ * imports it, and passed something to the constructor, is somewhere
10103
+ * the walk never reaches on its own.
10104
+ */
10105
+ resolveCallable(value, alsoFrom) {
10054
10106
  const target = factKeyOf(value);
10055
- return this.resolveByWaves(target, "wanted", () => this.lookup(target));
10107
+ return this.resolveByWaves(
10108
+ target,
10109
+ "wanted",
10110
+ () => this.lookup(target),
10111
+ alsoFrom
10112
+ );
10056
10113
  }
10057
10114
  resolveObject(value) {
10058
10115
  const target = factKeyOf(value);
@@ -10120,18 +10177,18 @@ var ResolutionStore = class {
10120
10177
  }
10121
10178
  return origins.some((pair) => namesAPackage(pairHalves(pair).module)) ? [] : null;
10122
10179
  }
10123
- resolveByWaves(value, question, ask) {
10180
+ resolveByWaves(value, question, ask, alsoFrom) {
10124
10181
  try {
10125
- return this.walkForAnswer(value, question, ask);
10182
+ return this.walkForAnswer(value, question, ask, alsoFrom);
10126
10183
  } finally {
10127
10184
  this.forgetQuery();
10128
10185
  }
10129
10186
  }
10130
- walkForAnswer(value, question, ask) {
10187
+ walkForAnswer(value, question, ask, alsoFrom) {
10131
10188
  this.wantValue(question, value);
10132
10189
  this.seedValue(value);
10133
10190
  const walked = /* @__PURE__ */ new Set();
10134
- let frontier = [value.getSourceFile()];
10191
+ let frontier = alsoFrom === void 0 ? [value.getSourceFile()] : [value.getSourceFile(), alsoFrom];
10135
10192
  for (let hop = 0; hop <= MAX_MODULE_HOPS; hop++) {
10136
10193
  const next = [];
10137
10194
  for (const sourceFile of frontier) {
@@ -10483,7 +10540,10 @@ function bindingLabel(binding) {
10483
10540
  if (semantics.name === "graphql-operation") {
10484
10541
  return `${semantics.operationType} ${semantics.operationName ?? ""}`.trim();
10485
10542
  }
10486
- 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;
10487
10547
  }
10488
10548
  function effectFact(effect) {
10489
10549
  if (effect.type === "invocation") {
@@ -10555,10 +10615,103 @@ function deriveBoundaryEffects(summaries, facts) {
10555
10615
  }
10556
10616
 
10557
10617
  // src/resolve/reachableClosure.ts
10558
- import { Node as Node49 } from "ts-morph";
10618
+ import { Node as Node50 } from "ts-morph";
10559
10619
  import { functionCallBinding } from "@suss/behavioral-ir";
10560
10620
  import { Database as Database3, evaluate as evaluate4, lit as lit4, rule as rule4, variable as variable2 } from "@suss/datalog";
10561
10621
  import { assembleSummary as assembleSummary2 } from "@suss/extractor";
10622
+
10623
+ // src/resolve/unfollowedCall.ts
10624
+ import {
10625
+ Node as Node49,
10626
+ SyntaxKind as SyntaxKind10
10627
+ } from "ts-morph";
10628
+ function isInExternalCode(sourceFile) {
10629
+ if (sourceFile.isDeclarationFile()) {
10630
+ return true;
10631
+ }
10632
+ return sourceFile.getFilePath().includes("/node_modules/");
10633
+ }
10634
+ function hasBody(fn) {
10635
+ if (Node49.isFunctionDeclaration(fn) || Node49.isMethodDeclaration(fn) || Node49.isFunctionExpression(fn)) {
10636
+ return fn.getBody?.() !== void 0;
10637
+ }
10638
+ return true;
10639
+ }
10640
+ function isDeclaredShape(declaration) {
10641
+ return (Node49.isMethodSignature(declaration) || Node49.isPropertySignature(declaration)) && !isInExternalCode(declaration.getSourceFile());
10642
+ }
10643
+ function isExternalDeclaration(declaration) {
10644
+ if (isInExternalCode(declaration.getSourceFile())) {
10645
+ return true;
10646
+ }
10647
+ if (Node49.isImportSpecifier(declaration) || Node49.isImportClause(declaration) || Node49.isNamespaceImport(declaration)) {
10648
+ const target = declaration.getFirstAncestorByKind(SyntaxKind10.ImportDeclaration)?.getModuleSpecifierSourceFile();
10649
+ return target === void 0 || isInExternalCode(target);
10650
+ }
10651
+ return declaresAnotherModule(declaration);
10652
+ }
10653
+ function declaresAnotherModule(declaration) {
10654
+ const module = declaration.getFirstAncestorByKind(
10655
+ SyntaxKind10.ModuleDeclaration
10656
+ );
10657
+ return module !== void 0 && Node49.isStringLiteral(module.getNameNode());
10658
+ }
10659
+ function statesShapeOnly(declaration) {
10660
+ if (isExternalDeclaration(declaration)) {
10661
+ return false;
10662
+ }
10663
+ if (Node49.isMethodSignature(declaration) || Node49.isPropertySignature(declaration)) {
10664
+ return true;
10665
+ }
10666
+ if (Node49.isFunctionDeclaration(declaration) || Node49.isMethodDeclaration(declaration)) {
10667
+ return declaration.getBody() === void 0;
10668
+ }
10669
+ return false;
10670
+ }
10671
+ function declarationsBehind(symbol) {
10672
+ if (symbol === void 0) {
10673
+ return [];
10674
+ }
10675
+ const behind = symbol.getAliasedSymbol()?.getDeclarations() ?? [];
10676
+ return behind.length > 0 ? behind : symbol.getDeclarations();
10677
+ }
10678
+ function classifyStop(declarations) {
10679
+ if (declarations.length === 0) {
10680
+ return "noDeclaration";
10681
+ }
10682
+ if (declarations.every(isExternalDeclaration)) {
10683
+ return "outsideRun";
10684
+ }
10685
+ if (declarations.some(statesShapeOnly)) {
10686
+ return "noBody";
10687
+ }
10688
+ return "unsettledValue";
10689
+ }
10690
+ var RECORDED = {
10691
+ noBody: true,
10692
+ unsettledValue: true,
10693
+ outsideRun: false,
10694
+ noDeclaration: false
10695
+ };
10696
+ function worthRecording(reason) {
10697
+ return RECORDED[reason];
10698
+ }
10699
+ var STOP_SENTENCE = {
10700
+ noBody: (callee) => `The call to ${callee} lands on a declaration with no body, so whatever runs there is missing from this summary`,
10701
+ unsettledValue: (callee) => `The call to ${callee} goes through a value this run could not settle, so whatever runs there is missing from this summary`,
10702
+ 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`,
10703
+ noDeclaration: (callee) => `The call to ${callee} has no declaration this run could find, so whatever runs there is missing from this summary`
10704
+ };
10705
+ function unfollowedCallGap(stop) {
10706
+ return {
10707
+ type: "unfollowedCall",
10708
+ conditions: [],
10709
+ consequence: "unknown",
10710
+ description: STOP_SENTENCE[stop.reason](stop.callee)
10711
+ };
10712
+ }
10713
+
10714
+ // src/resolve/reachableClosure.ts
10562
10715
  var reachablePack = {
10563
10716
  name: "reachable",
10564
10717
  languages: ["typescript"],
@@ -10581,23 +10734,6 @@ function nodeKey2(func) {
10581
10734
  const sf = func.getSourceFile();
10582
10735
  return `${sf.getFilePath()}:${func.getStart()}-${func.getEnd()}`;
10583
10736
  }
10584
- function isInExternalCode(sourceFile) {
10585
- if (sourceFile.isDeclarationFile()) {
10586
- return true;
10587
- }
10588
- const filePath = sourceFile.getFilePath();
10589
- if (filePath.includes("/node_modules/")) {
10590
- return true;
10591
- }
10592
- return false;
10593
- }
10594
- function hasBody(fn) {
10595
- if (Node49.isFunctionDeclaration(fn) || Node49.isMethodDeclaration(fn) || Node49.isFunctionExpression(fn)) {
10596
- const body = fn.getBody?.();
10597
- return body !== void 0;
10598
- }
10599
- return true;
10600
- }
10601
10737
  function resolveDecl(decl, calleeName) {
10602
10738
  if (isInExternalCode(decl.getSourceFile())) {
10603
10739
  return null;
@@ -10609,14 +10745,14 @@ function resolveDecl(decl, calleeName) {
10609
10745
  }
10610
10746
  return { func: fn, name: declName(decl) ?? calleeName };
10611
10747
  }
10612
- if (Node49.isVariableDeclaration(decl)) {
10748
+ if (Node50.isVariableDeclaration(decl)) {
10613
10749
  const init = decl.getInitializer();
10614
- if (init !== void 0 && (Node49.isArrowFunction(init) || Node49.isFunctionExpression(init))) {
10750
+ if (init !== void 0 && (Node50.isArrowFunction(init) || Node50.isFunctionExpression(init))) {
10615
10751
  return { func: init, name: decl.getName() };
10616
10752
  }
10617
10753
  return null;
10618
10754
  }
10619
- if (Node49.isImportSpecifier(decl)) {
10755
+ if (Node50.isImportSpecifier(decl)) {
10620
10756
  const importDecl = decl.getImportDeclaration();
10621
10757
  const sf = importDecl.getModuleSpecifierSourceFile();
10622
10758
  if (sf === void 0 || isInExternalCode(sf)) {
@@ -10637,61 +10773,85 @@ function resolveDecl(decl, calleeName) {
10637
10773
  return null;
10638
10774
  }
10639
10775
  function declName(decl) {
10640
- if (Node49.isFunctionDeclaration(decl) || Node49.isMethodDeclaration(decl)) {
10776
+ if (Node50.isFunctionDeclaration(decl) || Node50.isMethodDeclaration(decl)) {
10641
10777
  const n = decl.getName?.();
10642
10778
  if (typeof n === "string" && n.length > 0) {
10643
10779
  return n;
10644
10780
  }
10645
10781
  }
10646
- if (Node49.isFunctionExpression(decl)) {
10782
+ if (Node50.isFunctionExpression(decl)) {
10647
10783
  const n = decl.getName();
10648
10784
  if (typeof n === "string" && n.length > 0) {
10649
10785
  return n;
10650
10786
  }
10651
10787
  }
10652
10788
  const parent = decl.getParent();
10653
- if (parent !== void 0 && Node49.isVariableDeclaration(parent)) {
10789
+ if (parent !== void 0 && Node50.isVariableDeclaration(parent)) {
10654
10790
  return parent.getName();
10655
10791
  }
10656
10792
  return null;
10657
10793
  }
10658
- function resolveCallee(call, calleeName) {
10659
- if (!Node49.isCallExpression(call)) {
10794
+ function resolveCallee(call, calleeName, scan) {
10795
+ if (!Node50.isCallExpression(call)) {
10660
10796
  return null;
10661
10797
  }
10662
10798
  const callee = call.getExpression();
10663
10799
  const symbol = callee.getSymbol();
10664
- if (symbol === void 0) {
10665
- return null;
10666
- }
10667
- for (const decl of symbol.getDeclarations()) {
10800
+ const declarations = symbol?.getDeclarations() ?? [];
10801
+ for (const decl of declarations) {
10668
10802
  const resolved = resolveDecl(decl, calleeName);
10669
10803
  if (resolved !== null) {
10670
- return resolved;
10804
+ return { kind: "followed", candidate: resolved };
10671
10805
  }
10672
10806
  }
10673
- return null;
10807
+ const resolveCallable = scan.resolveCallable;
10808
+ if (resolveCallable !== void 0 && Node50.isPropertyAccessExpression(callee) && declarations.some(isDeclaredShape)) {
10809
+ const value = resolveCallable(callee, scan.reachedFrom);
10810
+ const resolved = value === null ? null : resolveDecl(value, calleeName);
10811
+ if (resolved !== null) {
10812
+ return { kind: "followed", candidate: resolved };
10813
+ }
10814
+ }
10815
+ return {
10816
+ kind: "stopped",
10817
+ stop: {
10818
+ callee: calleeName,
10819
+ reason: classifyStop(declarationsBehind(symbol))
10820
+ }
10821
+ };
10674
10822
  }
10675
- function collectReachable(func) {
10676
- const found = [];
10823
+ function collectReachable(func, scan) {
10824
+ const candidates = [];
10825
+ const stops = [];
10677
10826
  const seen = /* @__PURE__ */ new Set();
10678
10827
  func.forEachDescendant((node) => {
10679
- if (!Node49.isCallExpression(node)) {
10828
+ if (!Node50.isCallExpression(node)) {
10680
10829
  return;
10681
10830
  }
10682
- const calleeText = node.getExpression().getText();
10683
- const resolved = resolveCallee(node, calleeText);
10684
- if (resolved === null) {
10831
+ const calleeText = normalizeCallee(node.getExpression().getText());
10832
+ const outcome = resolveCallee(node, calleeText, scan);
10833
+ if (outcome === null) {
10685
10834
  return;
10686
10835
  }
10687
- const key = nodeKey2(resolved.func);
10836
+ if (outcome.kind === "stopped") {
10837
+ const stopKey = `${outcome.stop.reason}:${outcome.stop.callee}`;
10838
+ if (!seen.has(stopKey) && worthRecording(outcome.stop.reason)) {
10839
+ seen.add(stopKey);
10840
+ stops.push(outcome.stop);
10841
+ }
10842
+ return;
10843
+ }
10844
+ const key = nodeKey2(outcome.candidate.func);
10688
10845
  if (seen.has(key)) {
10689
10846
  return;
10690
10847
  }
10691
10848
  seen.add(key);
10692
- found.push(resolved);
10849
+ candidates.push(outcome.candidate);
10693
10850
  });
10694
- return found;
10851
+ return { candidates, stops };
10852
+ }
10853
+ function normalizeCallee(text) {
10854
+ return text.replace(/\s+/g, " ").trim();
10695
10855
  }
10696
10856
  function extractReachableSummary(candidate, options, recognizers) {
10697
10857
  const unit = {
@@ -10731,6 +10891,9 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10731
10891
  const functionByKey = /* @__PURE__ */ new Map();
10732
10892
  const seedKeys = /* @__PURE__ */ new Set();
10733
10893
  const scanned = /* @__PURE__ */ new Set();
10894
+ const stopsByKey = /* @__PURE__ */ new Map();
10895
+ const summariesByKey = /* @__PURE__ */ new Map();
10896
+ const reachedFrom = /* @__PURE__ */ new Map();
10734
10897
  for (const seed of seeds) {
10735
10898
  const func = lookup.functionAt(seed.location);
10736
10899
  if (func !== null) {
@@ -10738,6 +10901,7 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10738
10901
  seedKeys.add(key);
10739
10902
  functionByKey.set(key, { func, name: seed.identity.name });
10740
10903
  facts?.unitKeyBySummary.set(seed, key);
10904
+ rememberSummary(summariesByKey, key, seed);
10741
10905
  db.add("entry", [key]);
10742
10906
  }
10743
10907
  }
@@ -10753,11 +10917,23 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10753
10917
  if (source === void 0) {
10754
10918
  continue;
10755
10919
  }
10756
- for (const candidate of collectReachable(source.func)) {
10920
+ const cameFrom = reachedFrom.get(key);
10921
+ const scan = {
10922
+ ...recognizers.resolveCallable === void 0 ? {} : { resolveCallable: recognizers.resolveCallable },
10923
+ ...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
10924
+ };
10925
+ const { candidates, stops } = collectReachable(source.func, scan);
10926
+ if (stops.length > 0) {
10927
+ stopsByKey.set(key, stops);
10928
+ }
10929
+ for (const candidate of candidates) {
10757
10930
  const calleeKey = nodeKey2(candidate.func);
10758
10931
  if (!functionByKey.has(calleeKey)) {
10759
10932
  functionByKey.set(calleeKey, candidate);
10760
10933
  }
10934
+ if (!reachedFrom.has(calleeKey)) {
10935
+ reachedFrom.set(calleeKey, source.func.getSourceFile());
10936
+ }
10761
10937
  db.add("calls", [key, calleeKey]);
10762
10938
  }
10763
10939
  }
@@ -10781,13 +10957,30 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
10781
10957
  }
10782
10958
  const summary = extractReachableSummary(candidate, options, recognizers);
10783
10959
  facts?.unitKeyBySummary.set(summary, key);
10960
+ rememberSummary(summariesByKey, key, summary);
10784
10961
  reached.push(summary);
10785
10962
  }
10963
+ recordStops(stopsByKey, summariesByKey, options);
10786
10964
  return [...seeds, ...reached];
10787
10965
  }
10966
+ function rememberSummary(summariesByKey, key, summary) {
10967
+ const bucket = summariesByKey.get(key) ?? [];
10968
+ bucket.push(summary);
10969
+ summariesByKey.set(key, bucket);
10970
+ }
10971
+ function recordStops(stopsByKey, summariesByKey, options) {
10972
+ if (options?.gapHandling === "silent") {
10973
+ return;
10974
+ }
10975
+ for (const [key, stops] of stopsByKey) {
10976
+ for (const summary of summariesByKey.get(key) ?? []) {
10977
+ summary.gaps.push(...stops.map(unfollowedCallGap));
10978
+ }
10979
+ }
10980
+ }
10788
10981
 
10789
10982
  // src/resolve/rethrowEnrichment.ts
10790
- import { Node as Node50 } from "ts-morph";
10983
+ import { Node as Node51 } from "ts-morph";
10791
10984
  import { Database as Database4, evaluate as evaluate5, lit as lit5, rule as rule5, variable as variable3 } from "@suss/datalog";
10792
10985
  var RETHROW_RULES = [
10793
10986
  rule5(
@@ -10927,7 +11120,7 @@ function findBareRethrow(func, location) {
10927
11120
  traversal.stop();
10928
11121
  return;
10929
11122
  }
10930
- if (!Node50.isThrowStatement(node)) {
11123
+ if (!Node51.isThrowStatement(node)) {
10931
11124
  return;
10932
11125
  }
10933
11126
  if (startLineOf(node) !== location.start) {
@@ -10937,7 +11130,7 @@ function findBareRethrow(func, location) {
10937
11130
  return;
10938
11131
  }
10939
11132
  const thrown = node.getExpression();
10940
- if (thrown !== void 0 && Node50.isIdentifier(thrown)) {
11133
+ if (thrown !== void 0 && Node51.isIdentifier(thrown)) {
10941
11134
  found = node;
10942
11135
  }
10943
11136
  });
@@ -10947,13 +11140,13 @@ function enclosingTry(throwStmt) {
10947
11140
  let current2 = throwStmt.getParent();
10948
11141
  let sawCatchClause = false;
10949
11142
  while (current2 !== void 0) {
10950
- if (Node50.isCatchClause(current2)) {
11143
+ if (Node51.isCatchClause(current2)) {
10951
11144
  sawCatchClause = true;
10952
11145
  }
10953
- if (Node50.isTryStatement(current2)) {
11146
+ if (Node51.isTryStatement(current2)) {
10954
11147
  return sawCatchClause ? current2 : null;
10955
11148
  }
10956
- if (Node50.isFunctionDeclaration(current2) || Node50.isFunctionExpression(current2) || Node50.isArrowFunction(current2) || Node50.isMethodDeclaration(current2)) {
11149
+ if (Node51.isFunctionDeclaration(current2) || Node51.isFunctionExpression(current2) || Node51.isArrowFunction(current2) || Node51.isMethodDeclaration(current2)) {
10957
11150
  return null;
10958
11151
  }
10959
11152
  current2 = current2.getParent();
@@ -10961,14 +11154,14 @@ function enclosingTry(throwStmt) {
10961
11154
  return null;
10962
11155
  }
10963
11156
  function collectTryBodyCallees(tryStmt, index, keyFor) {
10964
- if (!Node50.isTryStatement(tryStmt)) {
11157
+ if (!Node51.isTryStatement(tryStmt)) {
10965
11158
  return [];
10966
11159
  }
10967
11160
  const tryBlock = tryStmt.getTryBlock();
10968
11161
  const callees = [];
10969
11162
  const seen = /* @__PURE__ */ new Set();
10970
11163
  tryBlock.forEachDescendant((node) => {
10971
- if (!Node50.isCallExpression(node)) {
11164
+ if (!Node51.isCallExpression(node)) {
10972
11165
  return;
10973
11166
  }
10974
11167
  const calleeSummary = resolveCalleeSummary(node, index);
@@ -10985,7 +11178,7 @@ function collectTryBodyCallees(tryStmt, index, keyFor) {
10985
11178
  return callees;
10986
11179
  }
10987
11180
  function resolveCalleeSummary(call, index) {
10988
- if (!Node50.isCallExpression(call)) {
11181
+ if (!Node51.isCallExpression(call)) {
10989
11182
  return null;
10990
11183
  }
10991
11184
  const callee = call.getExpression();
@@ -11011,12 +11204,12 @@ function resolveCalleeSummary(call, index) {
11011
11204
  return null;
11012
11205
  }
11013
11206
  function functionFromDecl(decl) {
11014
- if (Node50.isFunctionDeclaration(decl) || Node50.isFunctionExpression(decl) || Node50.isArrowFunction(decl) || Node50.isMethodDeclaration(decl)) {
11207
+ if (Node51.isFunctionDeclaration(decl) || Node51.isFunctionExpression(decl) || Node51.isArrowFunction(decl) || Node51.isMethodDeclaration(decl)) {
11015
11208
  return decl;
11016
11209
  }
11017
- if (Node50.isVariableDeclaration(decl)) {
11210
+ if (Node51.isVariableDeclaration(decl)) {
11018
11211
  const init = decl.getInitializer();
11019
- if (init !== void 0 && (Node50.isArrowFunction(init) || Node50.isFunctionExpression(init))) {
11212
+ if (init !== void 0 && (Node51.isArrowFunction(init) || Node51.isFunctionExpression(init))) {
11020
11213
  return init;
11021
11214
  }
11022
11215
  }
@@ -11025,23 +11218,23 @@ function functionFromDecl(decl) {
11025
11218
 
11026
11219
  // src/shapes/fieldAccesses.ts
11027
11220
  import {
11028
- Node as Node51
11221
+ Node as Node52
11029
11222
  } from "ts-morph";
11030
11223
  function findResponseAccessor(callExpr) {
11031
11224
  let current2 = callExpr;
11032
11225
  const parent1 = current2.getParent();
11033
- if (parent1 !== void 0 && Node51.isAwaitExpression(parent1)) {
11226
+ if (parent1 !== void 0 && Node52.isAwaitExpression(parent1)) {
11034
11227
  current2 = parent1;
11035
11228
  }
11036
11229
  const parent2 = current2.getParent();
11037
- if (parent2 === void 0 || !Node51.isVariableDeclaration(parent2)) {
11230
+ if (parent2 === void 0 || !Node52.isVariableDeclaration(parent2)) {
11038
11231
  return null;
11039
11232
  }
11040
11233
  const nameNode = parent2.getNameNode();
11041
- if (Node51.isIdentifier(nameNode)) {
11234
+ if (Node52.isIdentifier(nameNode)) {
11042
11235
  return { kind: "identifier", name: nameNode.getText() };
11043
11236
  }
11044
- if (Node51.isObjectBindingPattern(nameNode)) {
11237
+ if (Node52.isObjectBindingPattern(nameNode)) {
11045
11238
  const bindings = /* @__PURE__ */ new Map();
11046
11239
  for (const element of nameNode.getElements()) {
11047
11240
  if (element.getDotDotDotToken() !== void 0) {
@@ -11062,11 +11255,11 @@ function findResponseAccessor(callExpr) {
11062
11255
  function buildThenChainAccessor(callExpr, func) {
11063
11256
  const bindings = /* @__PURE__ */ new Map();
11064
11257
  func.forEachDescendant((node) => {
11065
- if (!Node51.isParameterDeclaration(node)) {
11258
+ if (!Node52.isParameterDeclaration(node)) {
11066
11259
  return;
11067
11260
  }
11068
11261
  const nameNode = node.getNameNode();
11069
- if (!Node51.isIdentifier(nameNode)) {
11262
+ if (!Node52.isIdentifier(nameNode)) {
11070
11263
  return;
11071
11264
  }
11072
11265
  const prefix = prefixOfThenParam(node, callExpr, 0);
@@ -11098,7 +11291,7 @@ function prefixOfExpr(expr, responseCall, depth) {
11098
11291
  if (node === responseCall) {
11099
11292
  return [];
11100
11293
  }
11101
- if (Node51.isCallExpression(node)) {
11294
+ if (Node52.isCallExpression(node)) {
11102
11295
  const hop = thenLikeCall(node);
11103
11296
  if (hop !== null) {
11104
11297
  if (hop.method === "catch") {
@@ -11130,14 +11323,14 @@ function prefixOfMemberExpr(expr, responseCall, depth) {
11130
11323
  return null;
11131
11324
  }
11132
11325
  const decl = chain.root.getSymbol()?.getDeclarations()?.[0];
11133
- if (decl === void 0 || !Node51.isParameterDeclaration(decl)) {
11326
+ if (decl === void 0 || !Node52.isParameterDeclaration(decl)) {
11134
11327
  return null;
11135
11328
  }
11136
11329
  const base = prefixOfThenParam(decl, responseCall, depth + 1);
11137
11330
  return base === null ? null : [...base, ...chain.segments];
11138
11331
  }
11139
11332
  function firstCallbackParamName(callback) {
11140
- if (callback === void 0 || !(Node51.isArrowFunction(callback) || Node51.isFunctionExpression(callback))) {
11333
+ if (callback === void 0 || !(Node52.isArrowFunction(callback) || Node52.isFunctionExpression(callback))) {
11141
11334
  return null;
11142
11335
  }
11143
11336
  const param = callback.getParameters()[0];
@@ -11145,11 +11338,11 @@ function firstCallbackParamName(callback) {
11145
11338
  return null;
11146
11339
  }
11147
11340
  const nameNode = param.getNameNode();
11148
- return Node51.isIdentifier(nameNode) ? nameNode.getText() : null;
11341
+ return Node52.isIdentifier(nameNode) ? nameNode.getText() : null;
11149
11342
  }
11150
11343
  function unwrap2(expr) {
11151
11344
  let node = expr;
11152
- while (Node51.isAwaitExpression(node) || Node51.isParenthesizedExpression(node) || Node51.isAsExpression(node)) {
11345
+ while (Node52.isAwaitExpression(node) || Node52.isParenthesizedExpression(node) || Node52.isAsExpression(node)) {
11153
11346
  node = node.getExpression();
11154
11347
  }
11155
11348
  return node;
@@ -11159,15 +11352,15 @@ function chainRootedAt(expr, rootName) {
11159
11352
  if (chain === null) {
11160
11353
  return null;
11161
11354
  }
11162
- return Node51.isIdentifier(chain.root) && chain.root.getText() === rootName ? chain.segments : null;
11355
+ return Node52.isIdentifier(chain.root) && chain.root.getText() === rootName ? chain.segments : null;
11163
11356
  }
11164
11357
  function memberChain(expr) {
11165
- let node = Node51.isExpression(expr) ? unwrap2(expr) : expr;
11166
- if (Node51.isCallExpression(node)) {
11358
+ let node = Node52.isExpression(expr) ? unwrap2(expr) : expr;
11359
+ if (Node52.isCallExpression(node)) {
11167
11360
  node = node.getExpression();
11168
11361
  }
11169
11362
  const segments = [];
11170
- while (Node51.isPropertyAccessExpression(node)) {
11363
+ while (Node52.isPropertyAccessExpression(node)) {
11171
11364
  segments.unshift(node.getName());
11172
11365
  node = node.getExpression();
11173
11366
  }
@@ -11186,16 +11379,16 @@ function collectPropertyAccesses(subtree, accessor) {
11186
11379
  if (accessor.kind === "identifier") {
11187
11380
  const varName = accessor.name;
11188
11381
  subtree.forEachDescendant((node) => {
11189
- if (!Node51.isPropertyAccessExpression(node)) {
11382
+ if (!Node52.isPropertyAccessExpression(node)) {
11190
11383
  return;
11191
11384
  }
11192
11385
  const chain = [];
11193
11386
  let current2 = node;
11194
- while (Node51.isPropertyAccessExpression(current2)) {
11387
+ while (Node52.isPropertyAccessExpression(current2)) {
11195
11388
  chain.unshift(current2.getName());
11196
11389
  current2 = current2.getExpression();
11197
11390
  }
11198
- if (Node51.isIdentifier(current2) && current2.getText() === varName) {
11391
+ if (Node52.isIdentifier(current2) && current2.getText() === varName) {
11199
11392
  pushChain(chain);
11200
11393
  }
11201
11394
  });
@@ -11206,7 +11399,7 @@ function collectPropertyAccesses(subtree, accessor) {
11206
11399
  return source === void 0 ? void 0 : [source];
11207
11400
  } : (name) => accessor.bindings.get(name);
11208
11401
  subtree.forEachDescendant((node) => {
11209
- if (!Node51.isIdentifier(node)) {
11402
+ if (!Node52.isIdentifier(node)) {
11210
11403
  return;
11211
11404
  }
11212
11405
  const prefix = prefixOf(node.getText());
@@ -11218,13 +11411,13 @@ function collectPropertyAccesses(subtree, accessor) {
11218
11411
  }
11219
11412
  let chainTop = node;
11220
11413
  let parent = chainTop.getParent();
11221
- while (parent !== void 0 && Node51.isPropertyAccessExpression(parent) && parent.getExpression() === chainTop) {
11414
+ while (parent !== void 0 && Node52.isPropertyAccessExpression(parent) && parent.getExpression() === chainTop) {
11222
11415
  chainTop = parent;
11223
11416
  parent = chainTop.getParent();
11224
11417
  }
11225
11418
  const segments = [];
11226
11419
  let current2 = chainTop;
11227
- while (Node51.isPropertyAccessExpression(current2)) {
11420
+ while (Node52.isPropertyAccessExpression(current2)) {
11228
11421
  segments.push(current2.getName());
11229
11422
  current2 = current2.getExpression();
11230
11423
  }
@@ -11238,15 +11431,15 @@ function isBindingDeclarationSite(node) {
11238
11431
  return true;
11239
11432
  }
11240
11433
  const parent = node.getParent();
11241
- return parent !== void 0 && Node51.isParameterDeclaration(parent) && parent.getNameNode() === node;
11434
+ return parent !== void 0 && Node52.isParameterDeclaration(parent) && parent.getNameNode() === node;
11242
11435
  }
11243
11436
  function isInsideObjectBindingPattern(node) {
11244
11437
  let current2 = node.getParent();
11245
11438
  while (current2 !== void 0) {
11246
- if (Node51.isObjectBindingPattern(current2)) {
11439
+ if (Node52.isObjectBindingPattern(current2)) {
11247
11440
  return true;
11248
11441
  }
11249
- if (Node51.isFunctionLikeDeclaration(current2) || Node51.isVariableStatement(current2)) {
11442
+ if (Node52.isFunctionLikeDeclaration(current2) || Node52.isVariableStatement(current2)) {
11250
11443
  break;
11251
11444
  }
11252
11445
  current2 = current2.getParent();
@@ -11309,7 +11502,7 @@ function findBranchSubtree(func, byLineRange, terminalStartLine, terminalEndLine
11309
11502
  if (parent === void 0) {
11310
11503
  break;
11311
11504
  }
11312
- if (Node51.isIfStatement(parent)) {
11505
+ if (Node52.isIfStatement(parent)) {
11313
11506
  const ifStmt = parent;
11314
11507
  const thenBlock = ifStmt.getThenStatement();
11315
11508
  const elseBlock = ifStmt.getElseStatement();
@@ -11372,7 +11565,7 @@ function buildNonBodyPropertySet(semantics) {
11372
11565
 
11373
11566
  // src/subUnitContext.ts
11374
11567
  import {
11375
- Node as Node52
11568
+ Node as Node53
11376
11569
  } from "ts-morph";
11377
11570
  function createTsSubUnitContext() {
11378
11571
  return {
@@ -11386,7 +11579,7 @@ function createTsSubUnitContext() {
11386
11579
  }
11387
11580
  function skipNestedFunctions(parent) {
11388
11581
  return (node, traversal) => {
11389
- if (node !== parent && (Node52.isFunctionDeclaration(node) || Node52.isFunctionExpression(node) || Node52.isArrowFunction(node) || Node52.isMethodDeclaration(node))) {
11582
+ if (node !== parent && (Node53.isFunctionDeclaration(node) || Node53.isFunctionExpression(node) || Node53.isArrowFunction(node) || Node53.isMethodDeclaration(node))) {
11390
11583
  traversal.skip();
11391
11584
  return true;
11392
11585
  }
@@ -11400,18 +11593,18 @@ function findJsxAttributes(parent) {
11400
11593
  if (skip(node, traversal)) {
11401
11594
  return;
11402
11595
  }
11403
- if (!Node52.isJsxOpeningElement(node) && !Node52.isJsxSelfClosingElement(node)) {
11596
+ if (!Node53.isJsxOpeningElement(node) && !Node53.isJsxSelfClosingElement(node)) {
11404
11597
  return;
11405
11598
  }
11406
11599
  const tag = node.getTagNameNode().getText();
11407
11600
  for (const attr of node.getAttributes()) {
11408
- if (!Node52.isJsxAttribute(attr)) {
11601
+ if (!Node53.isJsxAttribute(attr)) {
11409
11602
  continue;
11410
11603
  }
11411
11604
  const initializer = attr.getInitializer();
11412
11605
  let valueExpression = null;
11413
11606
  if (initializer !== void 0) {
11414
- if (Node52.isJsxExpression(initializer)) {
11607
+ if (Node53.isJsxExpression(initializer)) {
11415
11608
  const inner = initializer.getExpression();
11416
11609
  valueExpression = inner ?? null;
11417
11610
  } else {
@@ -11434,11 +11627,11 @@ function findCallExpressionsByName(parent, name) {
11434
11627
  if (skip(node, traversal)) {
11435
11628
  return;
11436
11629
  }
11437
- if (!Node52.isCallExpression(node)) {
11630
+ if (!Node53.isCallExpression(node)) {
11438
11631
  return;
11439
11632
  }
11440
11633
  const callee = node.getExpression();
11441
- if (Node52.isIdentifier(callee) && callee.getText() === name) {
11634
+ if (Node53.isIdentifier(callee) && callee.getText() === name) {
11442
11635
  out.push(node);
11443
11636
  }
11444
11637
  });
@@ -11449,10 +11642,10 @@ function resolveAttributeValueFunction(attr, parent) {
11449
11642
  if (expr === null) {
11450
11643
  return null;
11451
11644
  }
11452
- if (Node52.isArrowFunction(expr) || Node52.isFunctionExpression(expr)) {
11645
+ if (Node53.isArrowFunction(expr) || Node53.isFunctionExpression(expr)) {
11453
11646
  return { func: expr, localName: null };
11454
11647
  }
11455
- if (Node52.isIdentifier(expr)) {
11648
+ if (Node53.isIdentifier(expr)) {
11456
11649
  const symbol = expr.getSymbol();
11457
11650
  if (symbol === void 0) {
11458
11651
  return null;
@@ -11471,15 +11664,15 @@ function resolveAttributeValueFunction(attr, parent) {
11471
11664
  return null;
11472
11665
  }
11473
11666
  function tryExtractFunction(decl) {
11474
- if (Node52.isFunctionDeclaration(decl)) {
11667
+ if (Node53.isFunctionDeclaration(decl)) {
11475
11668
  return decl;
11476
11669
  }
11477
- if (Node52.isVariableDeclaration(decl)) {
11670
+ if (Node53.isVariableDeclaration(decl)) {
11478
11671
  const init = decl.getInitializer();
11479
11672
  if (init === void 0) {
11480
11673
  return null;
11481
11674
  }
11482
- if (Node52.isArrowFunction(init) || Node52.isFunctionExpression(init)) {
11675
+ if (Node53.isArrowFunction(init) || Node53.isFunctionExpression(init)) {
11483
11676
  return init;
11484
11677
  }
11485
11678
  }
@@ -11500,7 +11693,7 @@ function getCallArgumentFunction(call, position) {
11500
11693
  if (arg === void 0) {
11501
11694
  return null;
11502
11695
  }
11503
- if (Node52.isArrowFunction(arg) || Node52.isFunctionExpression(arg)) {
11696
+ if (Node53.isArrowFunction(arg) || Node53.isFunctionExpression(arg)) {
11504
11697
  return arg;
11505
11698
  }
11506
11699
  return null;
@@ -11512,7 +11705,7 @@ function readArrayLiteralText(node) {
11512
11705
  if (node === null) {
11513
11706
  return null;
11514
11707
  }
11515
- if (Node52.isArrayLiteralExpression(node)) {
11708
+ if (Node53.isArrayLiteralExpression(node)) {
11516
11709
  return node.getElements().map((e) => e.getText());
11517
11710
  }
11518
11711
  return [node.getText()];
@@ -11737,13 +11930,13 @@ var raise = (msg) => {
11737
11930
  throw new Error(msg);
11738
11931
  };
11739
11932
  function bindingPatternNames(nameNode) {
11740
- if (Node53.isObjectBindingPattern(nameNode)) {
11933
+ if (Node54.isObjectBindingPattern(nameNode)) {
11741
11934
  return nameNode.getElements().map((e) => e.getName());
11742
11935
  }
11743
- if (Node53.isArrayBindingPattern(nameNode)) {
11936
+ if (Node54.isArrayBindingPattern(nameNode)) {
11744
11937
  const names = [];
11745
11938
  for (const element of nameNode.getElements()) {
11746
- if (Node53.isOmittedExpression(element)) {
11939
+ if (Node54.isOmittedExpression(element)) {
11747
11940
  continue;
11748
11941
  }
11749
11942
  names.push(element.getName());
@@ -11754,7 +11947,7 @@ function bindingPatternNames(nameNode) {
11754
11947
  }
11755
11948
  function componentPropsParameters(param, mapping) {
11756
11949
  const nameNode = param.getNameNode();
11757
- if (!Node53.isObjectBindingPattern(nameNode)) {
11950
+ if (!Node54.isObjectBindingPattern(nameNode)) {
11758
11951
  const type = param.getType();
11759
11952
  return [
11760
11953
  {
@@ -11880,11 +12073,11 @@ function extractParameters(func, inputMapping) {
11880
12073
  function extractDependencyCalls(func) {
11881
12074
  const results = [];
11882
12075
  func.forEachDescendant((node, traversal) => {
11883
- if (node !== func && (Node53.isFunctionDeclaration(node) || Node53.isFunctionExpression(node) || Node53.isArrowFunction(node) || Node53.isMethodDeclaration(node))) {
12076
+ if (node !== func && (Node54.isFunctionDeclaration(node) || Node54.isFunctionExpression(node) || Node54.isArrowFunction(node) || Node54.isMethodDeclaration(node))) {
11884
12077
  traversal.skip();
11885
12078
  return;
11886
12079
  }
11887
- if (!Node53.isVariableDeclaration(node)) {
12080
+ if (!Node54.isVariableDeclaration(node)) {
11888
12081
  return;
11889
12082
  }
11890
12083
  const init = node.getInitializer();
@@ -11893,19 +12086,19 @@ function extractDependencyCalls(func) {
11893
12086
  }
11894
12087
  let isAsync = false;
11895
12088
  let callExpr = init;
11896
- if (Node53.isAwaitExpression(init)) {
12089
+ if (Node54.isAwaitExpression(init)) {
11897
12090
  isAsync = true;
11898
12091
  callExpr = init.getExpression();
11899
12092
  }
11900
- if (!Node53.isCallExpression(callExpr)) {
12093
+ if (!Node54.isCallExpression(callExpr)) {
11901
12094
  return;
11902
12095
  }
11903
12096
  const calleeName = callExpr.getExpression().getText();
11904
12097
  const nameNode = node.getNameNode();
11905
- const assignedTo = Node53.isIdentifier(nameNode) ? nameNode.getText() : null;
12098
+ const assignedTo = Node54.isIdentifier(nameNode) ? nameNode.getText() : null;
11906
12099
  const declList = node.getParent();
11907
12100
  const varStmt = declList?.getParent();
11908
- const locationNode = varStmt !== void 0 && Node53.isVariableStatement(varStmt) ? varStmt : node;
12101
+ const locationNode = varStmt !== void 0 && Node54.isVariableStatement(varStmt) ? varStmt : node;
11909
12102
  results.push({
11910
12103
  name: calleeName,
11911
12104
  assignedTo,
@@ -12161,9 +12354,9 @@ function extractBindingMethod(binding, callSite, pack, resolution) {
12161
12354
  if (m.type === "fromArgumentProperty") {
12162
12355
  const args = callSite.callExpression.getArguments();
12163
12356
  const arg = args[m.position];
12164
- if (arg !== void 0 && Node53.isObjectLiteralExpression(arg)) {
12357
+ if (arg !== void 0 && Node54.isObjectLiteralExpression(arg)) {
12165
12358
  const prop = arg.getProperty(m.property);
12166
- if (prop !== void 0 && Node53.isPropertyAssignment(prop)) {
12359
+ if (prop !== void 0 && Node54.isPropertyAssignment(prop)) {
12167
12360
  const init = prop.getInitializer();
12168
12361
  if (init !== void 0) {
12169
12362
  const value = stringValueOf(init, resolution);
@@ -12292,22 +12485,22 @@ function extractBindingPath(binding, callSite, pack, resolution) {
12292
12485
  return void 0;
12293
12486
  }
12294
12487
  function pathFromUrlNode(node) {
12295
- if (Node53.isStringLiteral(node)) {
12488
+ if (Node54.isStringLiteral(node)) {
12296
12489
  return pathFromLiteralUrl(node.getLiteralValue());
12297
12490
  }
12298
- if (Node53.isNoSubstitutionTemplateLiteral(node)) {
12491
+ if (Node54.isNoSubstitutionTemplateLiteral(node)) {
12299
12492
  return pathFromLiteralUrl(node.getLiteralValue());
12300
12493
  }
12301
- if (Node53.isTemplateExpression(node)) {
12494
+ if (Node54.isTemplateExpression(node)) {
12302
12495
  return pathFromTemplateUrl(node);
12303
12496
  }
12304
12497
  return void 0;
12305
12498
  }
12306
12499
  function placeholderName(expr) {
12307
- if (Node53.isIdentifier(expr)) {
12500
+ if (Node54.isIdentifier(expr)) {
12308
12501
  return expr.getText();
12309
12502
  }
12310
- if (Node53.isPropertyAccessExpression(expr)) {
12503
+ if (Node54.isPropertyAccessExpression(expr)) {
12311
12504
  return expr.getName();
12312
12505
  }
12313
12506
  return "param";
@@ -12742,7 +12935,7 @@ function expandWrapperCallers(summaries, project, options) {
12742
12935
  continue;
12743
12936
  }
12744
12937
  const binding = s.identity.boundaryBinding;
12745
- if (binding === null || binding.semantics.name !== "rest" || binding.semantics.method === null || binding.semantics.path !== null) {
12938
+ if (binding === null || binding.semantics.name !== "rest" || binding.semantics.method === null) {
12746
12939
  continue;
12747
12940
  }
12748
12941
  lookup ??= createSourceFileLookup(project);
@@ -12770,11 +12963,21 @@ function findWrapperPathParam(summary, lookup) {
12770
12963
  if (func === null) {
12771
12964
  return null;
12772
12965
  }
12773
- const params = func.getParameters();
12774
- if (params.length === 0) {
12966
+ const names = func.getParameters().map((p) => p.getName());
12967
+ if (names.length === 0) {
12775
12968
  return null;
12776
12969
  }
12777
- return { func, pathParamPosition: 0 };
12970
+ for (const call of func.getDescendantsOfKind(SyntaxKind11.CallExpression)) {
12971
+ const first = call.getArguments()[0];
12972
+ if (first === void 0 || !Node54.isIdentifier(first)) {
12973
+ continue;
12974
+ }
12975
+ const at = names.indexOf(first.getText());
12976
+ if (at !== -1) {
12977
+ return { func, pathParamPosition: at };
12978
+ }
12979
+ }
12980
+ return null;
12778
12981
  }
12779
12982
  function synthesizeCallerSummaries(wrapper, _project, options) {
12780
12983
  const nameNode = wrapperNameNode(wrapper.func);
@@ -12815,16 +13018,16 @@ function synthesizeCallerSummaries(wrapper, _project, options) {
12815
13018
  return out;
12816
13019
  }
12817
13020
  function wrapperNameNode(func) {
12818
- if (Node53.isFunctionDeclaration(func) || Node53.isMethodDeclaration(func)) {
13021
+ if (Node54.isFunctionDeclaration(func) || Node54.isMethodDeclaration(func)) {
12819
13022
  const name = func.getNameNode();
12820
- if (name !== void 0 && Node53.isIdentifier(name)) {
13023
+ if (name !== void 0 && Node54.isIdentifier(name)) {
12821
13024
  return name;
12822
13025
  }
12823
13026
  }
12824
13027
  const parent = func.getParent();
12825
- if (parent !== void 0 && Node53.isVariableDeclaration(parent)) {
13028
+ if (parent !== void 0 && Node54.isVariableDeclaration(parent)) {
12826
13029
  const nameNode = parent.getNameNode();
12827
- if (Node53.isIdentifier(nameNode)) {
13030
+ if (Node54.isIdentifier(nameNode)) {
12828
13031
  return nameNode;
12829
13032
  }
12830
13033
  }
@@ -12833,10 +13036,10 @@ function wrapperNameNode(func) {
12833
13036
  function enclosingCall(node) {
12834
13037
  let current2 = node.getParent();
12835
13038
  while (current2 !== void 0) {
12836
- if (Node53.isCallExpression(current2)) {
13039
+ if (Node54.isCallExpression(current2)) {
12837
13040
  return current2;
12838
13041
  }
12839
- if (Node53.isPropertyAccessExpression(current2)) {
13042
+ if (Node54.isPropertyAccessExpression(current2)) {
12840
13043
  current2 = current2.getParent();
12841
13044
  continue;
12842
13045
  }
@@ -12847,7 +13050,7 @@ function enclosingCall(node) {
12847
13050
  function enclosingFunction(node) {
12848
13051
  let current2 = node.getParent();
12849
13052
  while (current2 !== void 0) {
12850
- if (Node53.isFunctionDeclaration(current2) || Node53.isFunctionExpression(current2) || Node53.isArrowFunction(current2) || Node53.isMethodDeclaration(current2)) {
13053
+ if (Node54.isFunctionDeclaration(current2) || Node54.isFunctionExpression(current2) || Node54.isArrowFunction(current2) || Node54.isMethodDeclaration(current2)) {
12851
13054
  return current2;
12852
13055
  }
12853
13056
  current2 = current2.getParent();
@@ -12855,13 +13058,13 @@ function enclosingFunction(node) {
12855
13058
  return null;
12856
13059
  }
12857
13060
  function literalOrTemplate(arg) {
12858
- if (Node53.isStringLiteral(arg)) {
13061
+ if (Node54.isStringLiteral(arg)) {
12859
13062
  return arg.getLiteralValue();
12860
13063
  }
12861
- if (Node53.isNoSubstitutionTemplateLiteral(arg)) {
13064
+ if (Node54.isNoSubstitutionTemplateLiteral(arg)) {
12862
13065
  return arg.getLiteralValue();
12863
13066
  }
12864
- if (Node53.isTemplateExpression(arg)) {
13067
+ if (Node54.isTemplateExpression(arg)) {
12865
13068
  let path11 = arg.getHead().getLiteralText();
12866
13069
  for (const span of arg.getTemplateSpans()) {
12867
13070
  path11 += `{${placeholderName(span.getExpression())}}`;
@@ -12872,13 +13075,13 @@ function literalOrTemplate(arg) {
12872
13075
  return void 0;
12873
13076
  }
12874
13077
  function callerName(func) {
12875
- if (Node53.isFunctionDeclaration(func) || Node53.isMethodDeclaration(func)) {
13078
+ if (Node54.isFunctionDeclaration(func) || Node54.isMethodDeclaration(func)) {
12876
13079
  return func.getName() ?? "anonymous";
12877
13080
  }
12878
13081
  const parent = func.getParent();
12879
- if (parent !== void 0 && Node53.isVariableDeclaration(parent)) {
13082
+ if (parent !== void 0 && Node54.isVariableDeclaration(parent)) {
12880
13083
  const nameNode = parent.getNameNode();
12881
- if (Node53.isIdentifier(nameNode)) {
13084
+ if (Node54.isIdentifier(nameNode)) {
12882
13085
  return nameNode.getText();
12883
13086
  }
12884
13087
  }
@@ -13152,7 +13355,8 @@ function createTypeScriptAdapter(config) {
13152
13355
  tallies
13153
13356
  ),
13154
13357
  access: collectAccessRecognizers(config.frameworks, tallies),
13155
- resolveWrittenValue: (value) => resolution.resolveWrittenValue(value)
13358
+ resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
13359
+ resolveCallable: (value, alsoFrom) => resolution.resolveCallable(value, alsoFrom)
13156
13360
  }
13157
13361
  )
13158
13362
  ) : withSubUnits;
@@ -13423,10 +13627,10 @@ function findNearestTsconfig(startDir) {
13423
13627
  }
13424
13628
 
13425
13629
  // src/configuredCall.ts
13426
- import { Node as Node54 } from "ts-morph";
13630
+ import { Node as Node55 } from "ts-morph";
13427
13631
  function readConfiguredCall(call, ctx, spec) {
13428
13632
  const callee = call.getExpression();
13429
- if (!Node54.isPropertyAccessExpression(callee)) {
13633
+ if (!Node55.isPropertyAccessExpression(callee)) {
13430
13634
  return null;
13431
13635
  }
13432
13636
  if (callee.getName() !== spec.method) {
@@ -13471,10 +13675,10 @@ function readStringArg(arg) {
13471
13675
  }
13472
13676
  function rootIdentifier(node) {
13473
13677
  let current2 = node;
13474
- while (Node54.isPropertyAccessExpression(current2)) {
13678
+ while (Node55.isPropertyAccessExpression(current2)) {
13475
13679
  current2 = current2.getExpression();
13476
13680
  }
13477
- return Node54.isIdentifier(current2) ? current2 : null;
13681
+ return Node55.isIdentifier(current2) ? current2 : null;
13478
13682
  }
13479
13683
 
13480
13684
  // src/packHealth.ts
@@ -13590,7 +13794,7 @@ function formatPackHealth(checks, audiences) {
13590
13794
  }
13591
13795
 
13592
13796
  // src/resolve/readName.ts
13593
- import { Node as Node55, SyntaxKind as SyntaxKind10 } from "ts-morph";
13797
+ import { Node as Node56, SyntaxKind as SyntaxKind12 } from "ts-morph";
13594
13798
  var MAX_HELPER_HOPS = 2;
13595
13799
  var UNNAMED_HOLE = "param";
13596
13800
  function readName(expr, options = {}) {
@@ -13619,25 +13823,25 @@ function read(expr, ctx) {
13619
13823
  }
13620
13824
  const seen = new Set(ctx.seen).add(expr);
13621
13825
  const inner = { ...ctx, seen };
13622
- if (Node55.isStringLiteral(expr) || Node55.isNoSubstitutionTemplateLiteral(expr)) {
13826
+ if (Node56.isStringLiteral(expr) || Node56.isNoSubstitutionTemplateLiteral(expr)) {
13623
13827
  return expr.getLiteralValue();
13624
13828
  }
13625
- if (Node55.isNumericLiteral(expr)) {
13829
+ if (Node56.isNumericLiteral(expr)) {
13626
13830
  return expr.getLiteralText();
13627
13831
  }
13628
- if (Node55.isTemplateExpression(expr)) {
13832
+ if (Node56.isTemplateExpression(expr)) {
13629
13833
  return fromTemplate(expr, inner);
13630
13834
  }
13631
- if (Node55.isParenthesizedExpression(expr)) {
13835
+ if (Node56.isParenthesizedExpression(expr)) {
13632
13836
  return read(expr.getExpression(), inner);
13633
13837
  }
13634
- if (Node55.isBinaryExpression(expr)) {
13838
+ if (Node56.isBinaryExpression(expr)) {
13635
13839
  return fromBinary(expr, inner);
13636
13840
  }
13637
- if (Node55.isCallExpression(expr)) {
13841
+ if (Node56.isCallExpression(expr)) {
13638
13842
  return fromCall(expr, inner);
13639
13843
  }
13640
- if (Node55.isIdentifier(expr)) {
13844
+ if (Node56.isIdentifier(expr)) {
13641
13845
  const only = boundOnce(expr, ctx);
13642
13846
  if (only !== null) {
13643
13847
  return read(only.node, { ...inner, bindings: only.scope });
@@ -13647,7 +13851,7 @@ function read(expr, ctx) {
13647
13851
  return written === null || written === expr ? null : read(written, inner);
13648
13852
  }
13649
13853
  function fromTemplate(expr, ctx) {
13650
- if (!Node55.isTemplateExpression(expr)) {
13854
+ if (!Node56.isTemplateExpression(expr)) {
13651
13855
  return null;
13652
13856
  }
13653
13857
  let name = expr.getHead().getLiteralText();
@@ -13658,28 +13862,28 @@ function fromTemplate(expr, ctx) {
13658
13862
  return name;
13659
13863
  }
13660
13864
  function fromBinary(expr, ctx) {
13661
- if (!Node55.isBinaryExpression(expr)) {
13865
+ if (!Node56.isBinaryExpression(expr)) {
13662
13866
  return null;
13663
13867
  }
13664
13868
  const operator = expr.getOperatorToken().getKind();
13665
- if (operator === SyntaxKind10.BarBarToken || operator === SyntaxKind10.QuestionQuestionToken) {
13869
+ if (operator === SyntaxKind12.BarBarToken || operator === SyntaxKind12.QuestionQuestionToken) {
13666
13870
  return ctx.insideHole ? null : read(expr.getRight(), ctx);
13667
13871
  }
13668
- if (operator !== SyntaxKind10.PlusToken) {
13872
+ if (operator !== SyntaxKind12.PlusToken) {
13669
13873
  return null;
13670
13874
  }
13671
13875
  const parts = { ...ctx, insideHole: true };
13672
13876
  return readOrHole(expr.getLeft(), parts) + readOrHole(expr.getRight(), parts);
13673
13877
  }
13674
13878
  function fromCall(expr, ctx) {
13675
- if (!Node55.isCallExpression(expr)) {
13879
+ if (!Node56.isCallExpression(expr)) {
13676
13880
  return null;
13677
13881
  }
13678
13882
  const callee = expr.getExpression();
13679
- if (Node55.isPropertyAccessExpression(callee) && callee.getName() === "join") {
13883
+ if (Node56.isPropertyAccessExpression(callee) && callee.getName() === "join") {
13680
13884
  return fromJoin(callee.getExpression(), expr.getArguments(), ctx);
13681
13885
  }
13682
- if (Node55.isIdentifier(callee) && callee.getText() === "String") {
13886
+ if (Node56.isIdentifier(callee) && callee.getText() === "String") {
13683
13887
  const only = expr.getArguments()[0];
13684
13888
  return only === void 0 ? null : readOrHole(only, ctx);
13685
13889
  }
@@ -13698,7 +13902,7 @@ function fromCall(expr, ctx) {
13698
13902
  }
13699
13903
  function fromJoin(subject, args, ctx) {
13700
13904
  const separator = args[0];
13701
- if (separator === void 0 || !Node55.isStringLiteral(separator)) {
13905
+ if (separator === void 0 || !Node56.isStringLiteral(separator)) {
13702
13906
  return null;
13703
13907
  }
13704
13908
  const parts = elementsOf(subject, ctx);
@@ -13714,17 +13918,17 @@ function fromJoin(subject, args, ctx) {
13714
13918
  ).join(separator.getLiteralValue());
13715
13919
  }
13716
13920
  function elementsOf(subject, ctx) {
13717
- if (Node55.isArrayLiteralExpression(subject)) {
13921
+ if (Node56.isArrayLiteralExpression(subject)) {
13718
13922
  return subject.getElements().map((element) => here(element, ctx));
13719
13923
  }
13720
- if (Node55.isCallExpression(subject)) {
13924
+ if (Node56.isCallExpression(subject)) {
13721
13925
  const callee = subject.getExpression();
13722
- if (Node55.isPropertyAccessExpression(callee) && callee.getName() === "map") {
13926
+ if (Node56.isPropertyAccessExpression(callee) && callee.getName() === "map") {
13723
13927
  return elementsOf(callee.getExpression(), ctx);
13724
13928
  }
13725
13929
  return null;
13726
13930
  }
13727
- if (!Node55.isIdentifier(subject)) {
13931
+ if (!Node56.isIdentifier(subject)) {
13728
13932
  return null;
13729
13933
  }
13730
13934
  const bound = ctx.bindings.get(subject.getText());
@@ -13732,7 +13936,7 @@ function elementsOf(subject, ctx) {
13732
13936
  return null;
13733
13937
  }
13734
13938
  const only = bound.length === 1 ? bound[0] : void 0;
13735
- return only !== void 0 && Node55.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
13939
+ return only !== void 0 && Node56.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
13736
13940
  }
13737
13941
  function singleReturnBody(callee, ctx) {
13738
13942
  const declaration = declarationOf2(callee, ctx);
@@ -13747,22 +13951,22 @@ function singleReturnBody(callee, ctx) {
13747
13951
  if (body === void 0) {
13748
13952
  return null;
13749
13953
  }
13750
- if (Node55.isExpression(body)) {
13954
+ if (Node56.isExpression(body)) {
13751
13955
  return { parameters, returned: body };
13752
13956
  }
13753
- if (!Node55.isBlock(body)) {
13957
+ if (!Node56.isBlock(body)) {
13754
13958
  return null;
13755
13959
  }
13756
13960
  const statements = body.getStatements();
13757
13961
  const only = statements[0];
13758
- if (statements.length !== 1 || only === void 0 || !Node55.isReturnStatement(only)) {
13962
+ if (statements.length !== 1 || only === void 0 || !Node56.isReturnStatement(only)) {
13759
13963
  return null;
13760
13964
  }
13761
13965
  const returned = only.getExpression();
13762
13966
  return returned === void 0 ? null : { parameters, returned };
13763
13967
  }
13764
13968
  function declarationOf2(callee, ctx) {
13765
- const symbol = Node55.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
13969
+ const symbol = Node56.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
13766
13970
  const declarations = symbol?.getAliasedSymbol()?.getDeclarations() ?? symbol?.getDeclarations() ?? [];
13767
13971
  for (const declaration of declarations) {
13768
13972
  const callable = asCallable(declaration);
@@ -13774,14 +13978,14 @@ function declarationOf2(callee, ctx) {
13774
13978
  return written === null || written === callee ? null : declarationOf2(written, { ...ctx, resolve: () => null });
13775
13979
  }
13776
13980
  function asCallable(declaration) {
13777
- if (Node55.isFunctionDeclaration(declaration) || Node55.isMethodDeclaration(declaration) || Node55.isArrowFunction(declaration) || Node55.isFunctionExpression(declaration)) {
13981
+ if (Node56.isFunctionDeclaration(declaration) || Node56.isMethodDeclaration(declaration) || Node56.isArrowFunction(declaration) || Node56.isFunctionExpression(declaration)) {
13778
13982
  return declaration;
13779
13983
  }
13780
- if (!Node55.isVariableDeclaration(declaration)) {
13984
+ if (!Node56.isVariableDeclaration(declaration)) {
13781
13985
  return null;
13782
13986
  }
13783
13987
  const initializer = declaration.getInitializer();
13784
- if (initializer !== void 0 && (Node55.isArrowFunction(initializer) || Node55.isFunctionExpression(initializer))) {
13988
+ if (initializer !== void 0 && (Node56.isArrowFunction(initializer) || Node56.isFunctionExpression(initializer))) {
13785
13989
  return initializer;
13786
13990
  }
13787
13991
  return null;
@@ -13803,7 +14007,7 @@ function here(node, ctx) {
13803
14007
  return { node, scope: ctx.bindings };
13804
14008
  }
13805
14009
  function boundOnce(expr, ctx) {
13806
- const bound = Node55.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
14010
+ const bound = Node56.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
13807
14011
  return bound !== void 0 && bound.length === 1 ? bound[0] : null;
13808
14012
  }
13809
14013
  function readOrHole(expr, ctx) {
@@ -13815,10 +14019,10 @@ function holeName(expr, ctx) {
13815
14019
  if (bound !== null) {
13816
14020
  return holeName(bound.node, { ...ctx, bindings: bound.scope });
13817
14021
  }
13818
- if (Node55.isIdentifier(expr)) {
14022
+ if (Node56.isIdentifier(expr)) {
13819
14023
  return expr.getText();
13820
14024
  }
13821
- if (Node55.isPropertyAccessExpression(expr)) {
14025
+ if (Node56.isPropertyAccessExpression(expr)) {
13822
14026
  return expr.getName();
13823
14027
  }
13824
14028
  return UNNAMED_HOLE;