@suss/adapter-typescript 0.10.0 → 0.11.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
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ADAPTER_VERSION: () => ADAPTER_VERSION,
34
34
  ResolutionStore: () => ResolutionStore,
35
+ WhySession: () => WhySession,
35
36
  collectAncestorBranches: () => collectAncestorBranches,
36
37
  collectClientFieldAccesses: () => collectClientFieldAccesses,
37
38
  computeAdapterPacksDigest: () => computeAdapterPacksDigest,
@@ -57,7 +58,8 @@ __export(index_exports, {
57
58
  readName: () => readName,
58
59
  resolveAliasedSymbol: () => resolveAliasedSymbol,
59
60
  resolveSubject: () => resolveSubject,
60
- rootIdentifier: () => rootIdentifier
61
+ rootIdentifier: () => rootIdentifier2,
62
+ workspaceRootFor: () => workspaceRootFor
61
63
  });
62
64
  module.exports = __toCommonJS(index_exports);
63
65
 
@@ -1642,7 +1644,7 @@ var ModuleGraph = class {
1642
1644
  return created;
1643
1645
  }
1644
1646
  assert(relation, tuple) {
1645
- if (this.db.add(relation, tuple)) {
1647
+ if (this.db.add(relation, tuple) === "added") {
1646
1648
  this.stale = true;
1647
1649
  }
1648
1650
  }
@@ -1859,8 +1861,8 @@ function loadImportGraphsDepthFirstFromPaths(project, rootPaths) {
1859
1861
  stack.pop();
1860
1862
  loadOrder.push(top.path);
1861
1863
  let deepest = 0;
1862
- for (const path11 of top.deps) {
1863
- deepest = Math.max(deepest, chainDepth.get(path11) ?? 0);
1864
+ for (const path12 of top.deps) {
1865
+ deepest = Math.max(deepest, chainDepth.get(path12) ?? 0);
1864
1866
  }
1865
1867
  chainDepth.set(top.path, deepest + 1);
1866
1868
  }
@@ -2205,11 +2207,11 @@ function walkAndWarm(root, reach) {
2205
2207
  if (warmedFiles.get(target) !== void 0) {
2206
2208
  continue;
2207
2209
  }
2208
- const path11 = target.getFilePath();
2209
- if (visited.has(path11)) {
2210
+ const path12 = target.getFilePath();
2211
+ if (visited.has(path12)) {
2210
2212
  continue;
2211
2213
  }
2212
- visited.add(path11);
2214
+ visited.add(path12);
2213
2215
  stack.push(frameOf(target, reach));
2214
2216
  continue;
2215
2217
  }
@@ -2226,7 +2228,7 @@ function sitsOnWarmChains(file) {
2226
2228
  return false;
2227
2229
  }
2228
2230
  const imported = importedFilePathsOf(project, file.getFilePath());
2229
- return imported.length > 0 && imported.every((path11) => warmed.has(path11));
2231
+ return imported.length > 0 && imported.every((path12) => warmed.has(path12));
2230
2232
  }
2231
2233
  function markWarmed(file) {
2232
2234
  warmedFiles.set(file, true);
@@ -2359,14 +2361,38 @@ function isImportedFrom(identifier, expectedModule) {
2359
2361
  (decl) => decl.getSourceFile().getFilePath().includes(`/node_modules/${expectedModule}/`)
2360
2362
  );
2361
2363
  }
2362
- function methodDeclaredIn(callee, expectedModule) {
2364
+ function methodDeclaredIn(callee, expectedModule, resolve2) {
2363
2365
  if (!import_ts_morph12.Node.isPropertyAccessExpression(callee)) {
2364
2366
  return false;
2365
2367
  }
2366
2368
  const declarations = callee.getNameNode().getSymbol()?.getDeclarations();
2367
- return declarations !== void 0 && declarations.some(
2369
+ if (declarations !== void 0 && declarations.some(
2368
2370
  (declaration) => declaration.getSourceFile().getFilePath().includes(`/node_modules/${expectedModule}/`)
2369
- );
2371
+ )) {
2372
+ return true;
2373
+ }
2374
+ if (resolve2 === void 0) {
2375
+ return false;
2376
+ }
2377
+ const written = resolve2(callee.getExpression());
2378
+ const made = maker(written);
2379
+ return made !== null && isImportedFrom(rootIdentifier(made), expectedModule);
2380
+ }
2381
+ function maker(written) {
2382
+ if (written === null) {
2383
+ return null;
2384
+ }
2385
+ if (import_ts_morph12.Node.isNewExpression(written) || import_ts_morph12.Node.isCallExpression(written)) {
2386
+ return written.getExpression();
2387
+ }
2388
+ return null;
2389
+ }
2390
+ function rootIdentifier(expression) {
2391
+ let root = expression;
2392
+ while (import_ts_morph12.Node.isPropertyAccessExpression(root)) {
2393
+ root = root.getExpression();
2394
+ }
2395
+ return root;
2370
2396
  }
2371
2397
  function importSpecifierMatches(decl, expectedModule) {
2372
2398
  if (import_ts_morph12.Node.isImportSpecifier(decl)) {
@@ -2446,6 +2472,26 @@ function extractInvocationEffects(func, barriers = NO_BARRIERS) {
2446
2472
  }
2447
2473
  return;
2448
2474
  }
2475
+ if (import_ts_morph12.Node.isReturnStatement(node)) {
2476
+ const returned = node.getExpression();
2477
+ const { call, async } = returned === void 0 ? { call: null, async: false } : unwrapCall(returned);
2478
+ if (call !== null) {
2479
+ const preconditions = collectPreconditions(node, func);
2480
+ results.push({
2481
+ effect: {
2482
+ type: "invocation",
2483
+ callee: call.getExpression().getText(),
2484
+ args: extractArgs(call),
2485
+ async,
2486
+ ...preconditions.length > 0 ? { preconditions } : {}
2487
+ },
2488
+ line: startLineOf(node),
2489
+ neverTerminal: false,
2490
+ node: call
2491
+ });
2492
+ }
2493
+ return;
2494
+ }
2449
2495
  if (import_ts_morph12.Node.isCallExpression(node)) {
2450
2496
  const parent = node.getParent();
2451
2497
  if (parent === void 0) {
@@ -5107,7 +5153,10 @@ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [],
5107
5153
  const terminalLines = new Set(
5108
5154
  distinctBranches.map((b) => b.terminal.location.start)
5109
5155
  );
5110
- defaultBranch.effects = invocations.filter((i) => i.neverTerminal || !terminalLines.has(i.line)).map((i) => i.effect);
5156
+ const terminalNodes = new Set(terminals.map(({ node }) => node));
5157
+ defaultBranch.effects = invocations.filter(
5158
+ (i) => i.node !== void 0 ? !terminalNodes.has(i.node) : i.neverTerminal || !terminalLines.has(i.line)
5159
+ ).map((i) => i.effect);
5111
5160
  }
5112
5161
  }
5113
5162
  if (recognized.length > 0) {
@@ -5152,9 +5201,9 @@ function createSourceFileLookup(project) {
5152
5201
  if (sf === null) {
5153
5202
  return null;
5154
5203
  }
5155
- const path11 = sf.getFilePath();
5156
- const index = functionsByFile.get(path11) ?? indexFunctions(sf);
5157
- functionsByFile.set(path11, index);
5204
+ const path12 = sf.getFilePath();
5205
+ const index = functionsByFile.get(path12) ?? indexFunctions(sf);
5206
+ functionsByFile.set(path12, index);
5158
5207
  return index.get(rangeKey(location.range)) ?? null;
5159
5208
  }
5160
5209
  };
@@ -5232,7 +5281,6 @@ function createCacheLayer(cacheDir) {
5232
5281
  return {
5233
5282
  kind: "hit",
5234
5283
  summaries: manifest.summaries,
5235
- ...manifest.projectRoot === void 0 ? {} : { projectRoot: manifest.projectRoot },
5236
5284
  diagnostic: { kind: "hit" }
5237
5285
  };
5238
5286
  },
@@ -5346,7 +5394,6 @@ async function buildPlan(manifest, currentStamps) {
5346
5394
  roots,
5347
5395
  validRoots,
5348
5396
  rootsDeclined,
5349
- storedProjectRoot: manifest.projectRoot ?? null,
5350
5397
  reuse(valid) {
5351
5398
  const summaries = [];
5352
5399
  const reusedOwners = [];
@@ -5373,8 +5420,7 @@ async function buildPlan(manifest, currentStamps) {
5373
5420
  const p = rootNames[o];
5374
5421
  return p === void 0 ? [] : [p];
5375
5422
  })
5376
- ),
5377
- ...manifest.projectRoot === void 0 ? {} : { projectRoot: manifest.projectRoot }
5423
+ )
5378
5424
  };
5379
5425
  }
5380
5426
  };
@@ -5407,13 +5453,7 @@ function encodeAttribution(attribution) {
5407
5453
  return i === void 0 ? [] : [i];
5408
5454
  })
5409
5455
  );
5410
- return {
5411
- roots,
5412
- rootMeta,
5413
- depPaths,
5414
- owners,
5415
- ...attribution.projectRoot === void 0 ? {} : { projectRoot: attribution.projectRoot }
5416
- };
5456
+ return { roots, rootMeta, depPaths, owners };
5417
5457
  }
5418
5458
  async function hashStamps(stamps, previous) {
5419
5459
  const before = new Map((previous?.files ?? []).map((f) => [f.path, f]));
@@ -5690,7 +5730,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
5690
5730
  }
5691
5731
  const responses = [];
5692
5732
  let method;
5693
- let path11;
5733
+ let path12;
5694
5734
  for (const prop of endpointNode.getProperties()) {
5695
5735
  if (!import_ts_morph25.Node.isPropertyAssignment(prop)) {
5696
5736
  continue;
@@ -5705,7 +5745,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
5705
5745
  if (propName === pattern.pathProperty) {
5706
5746
  const val = prop.getInitializer();
5707
5747
  if (val !== void 0 && import_ts_morph25.Node.isStringLiteral(val)) {
5708
- path11 = val.getLiteralValue();
5748
+ path12 = val.getLiteralValue();
5709
5749
  }
5710
5750
  }
5711
5751
  if (propName === pattern.responseExtraction.property) {
@@ -5729,10 +5769,10 @@ function extractEndpointContract(endpointNode, pattern, framework) {
5729
5769
  if (responses.length === 0) {
5730
5770
  return null;
5731
5771
  }
5732
- const boundaryBinding = method !== void 0 || path11 !== void 0 ? (0, import_behavioral_ir.restBinding)({
5772
+ const boundaryBinding = method !== void 0 || path12 !== void 0 ? (0, import_behavioral_ir.restBinding)({
5733
5773
  transport: "http",
5734
5774
  method: method ?? null,
5735
- path: path11 ?? null,
5775
+ path: path12 ?? null,
5736
5776
  recognition: framework
5737
5777
  }) : null;
5738
5778
  return {
@@ -6316,6 +6356,13 @@ function literalIndexOf(index) {
6316
6356
  }
6317
6357
  return null;
6318
6358
  }
6359
+ function asFallbackExpression(expression) {
6360
+ if (!import_ts_morph28.Node.isBinaryExpression(expression)) {
6361
+ return null;
6362
+ }
6363
+ const operator = expression.getOperatorToken().getKind();
6364
+ return operator === import_ts_morph28.SyntaxKind.BarBarToken || operator === import_ts_morph28.SyntaxKind.QuestionQuestionToken ? expression : null;
6365
+ }
6319
6366
  function unwrapExpression(expression) {
6320
6367
  let current2 = expression;
6321
6368
  for (; ; ) {
@@ -6427,6 +6474,12 @@ function emitValue(db, table, value) {
6427
6474
  }
6428
6475
  return id;
6429
6476
  }
6477
+ const fallback = asFallbackExpression(expression);
6478
+ if (fallback !== null) {
6479
+ fact(db, "fallbackBranch", id, emitValue(db, table, fallback.getLeft()));
6480
+ fact(db, "fallbackBranch", id, emitValue(db, table, fallback.getRight()));
6481
+ return id;
6482
+ }
6430
6483
  if (import_ts_morph28.Node.isCallExpression(expression) || import_ts_morph28.Node.isNewExpression(expression)) {
6431
6484
  emitCallFacts(db, table, expression);
6432
6485
  fact(db, "writtenValue", id);
@@ -6891,24 +6944,27 @@ function stampGraphqlClientRefs(summaries, sourceFiles, packs, resolution) {
6891
6944
  const sole = soleGraphqlClientRef(
6892
6945
  collectGraphqlClientRefs(sourceFiles, packs, resolution)
6893
6946
  );
6894
- if (sole === null && scopes.length === 0) {
6895
- return;
6896
- }
6897
6947
  const workspace = sole !== null ? boundWorkspaceFor(sole, packs) : null;
6898
6948
  const soleClient = sole !== null ? workspace !== null ? { ...sole, workspace } : sole : null;
6949
+ let registry = null;
6899
6950
  for (const summary of summaries) {
6900
6951
  if (!(0, import_behavioral_ir3.isGraphqlOperationBinding)(summary.identity.boundaryBinding)) {
6901
6952
  continue;
6902
6953
  }
6954
+ const existing = (0, import_behavioral_ir3.readGraphqlMetadata)(summary) ?? {};
6903
6955
  const scoped = scopedWorkspaceFor(summary.location.file, scopes);
6904
6956
  const client = scoped !== null ? { uri: null, uriRef: null, workspace: scoped } : soleClient;
6905
- if (client === null) {
6957
+ const dangling = (existing.unresolvedFragments?.length ?? 0) > 0;
6958
+ if (client === null && !dangling) {
6906
6959
  continue;
6907
6960
  }
6908
- const existing = (0, import_behavioral_ir3.readGraphqlMetadata)(summary) ?? {};
6961
+ if (dangling && registry === null) {
6962
+ registry = fragmentRegistryStatus(sourceFiles, packs);
6963
+ }
6909
6964
  summary.metadata = (0, import_behavioral_ir3.withGraphqlMetadata)(summary.metadata, {
6910
6965
  ...existing,
6911
- client
6966
+ ...client !== null ? { client } : {},
6967
+ ...dangling && registry !== null ? { fragmentRegistry: registry } : {}
6912
6968
  });
6913
6969
  }
6914
6970
  }
@@ -6974,6 +7030,156 @@ function soleGraphqlClientRef(refs) {
6974
7030
  }
6975
7031
  return [...distinct.values()][0] ?? null;
6976
7032
  }
7033
+ function fragmentRegistryStatus(sourceFiles, packs) {
7034
+ const statuses = [];
7035
+ for (const spec of packs.flatMap((pack) => pack.graphqlClients ?? [])) {
7036
+ const registrySpec = spec.fragmentRegistry;
7037
+ if (registrySpec === void 0) {
7038
+ continue;
7039
+ }
7040
+ for (const sourceFile of sourceFiles) {
7041
+ const local = localImportName(
7042
+ sourceFile,
7043
+ spec.importModule,
7044
+ spec.importName
7045
+ );
7046
+ if (local === null) {
7047
+ continue;
7048
+ }
7049
+ sourceFile.forEachDescendant((node) => {
7050
+ if (isConstructionNamed(node, local)) {
7051
+ statuses.push(constructionRegistryStatus(node, registrySpec));
7052
+ }
7053
+ });
7054
+ }
7055
+ }
7056
+ return combineRegistryStatuses(statuses);
7057
+ }
7058
+ function combineRegistryStatuses(statuses) {
7059
+ if (statuses.includes("configured")) {
7060
+ return "configured";
7061
+ }
7062
+ if (statuses.length === 0 || statuses.includes("unknown")) {
7063
+ return "unknown";
7064
+ }
7065
+ return "absent";
7066
+ }
7067
+ function constructionRegistryStatus(construction, spec) {
7068
+ const options = firstArgumentObjectLiteral(construction);
7069
+ if (options === null) {
7070
+ return "unknown";
7071
+ }
7072
+ const cacheExpr = propertyValueOf2(options, spec.cacheProperty);
7073
+ if (cacheExpr === null) {
7074
+ return "unknown";
7075
+ }
7076
+ const cacheConstruction = resolveToConstructionOf(
7077
+ cacheExpr,
7078
+ spec.cacheConstructor
7079
+ );
7080
+ if (cacheConstruction === null) {
7081
+ return "unknown";
7082
+ }
7083
+ if (!import_ts_morph30.Node.isNewExpression(cacheConstruction) && !import_ts_morph30.Node.isCallExpression(cacheConstruction)) {
7084
+ return "unknown";
7085
+ }
7086
+ const args = cacheConstruction.getArguments();
7087
+ if (args.length === 0) {
7088
+ return "absent";
7089
+ }
7090
+ const cacheOptions = firstArgumentObjectLiteral(cacheConstruction);
7091
+ if (cacheOptions === null) {
7092
+ return "unknown";
7093
+ }
7094
+ if (cacheOptions.getProperty(spec.registryProperty) !== void 0) {
7095
+ return "configured";
7096
+ }
7097
+ const hasSpread = cacheOptions.getProperties().some((property) => import_ts_morph30.Node.isSpreadAssignment(property));
7098
+ return hasSpread ? "unknown" : "absent";
7099
+ }
7100
+ function firstArgumentObjectLiteral(construction) {
7101
+ if (!import_ts_morph30.Node.isNewExpression(construction) && !import_ts_morph30.Node.isCallExpression(construction)) {
7102
+ return null;
7103
+ }
7104
+ const arg = construction.getArguments()[0];
7105
+ if (arg === void 0 || !import_ts_morph30.Node.isObjectLiteralExpression(arg)) {
7106
+ return null;
7107
+ }
7108
+ return arg;
7109
+ }
7110
+ function propertyValueOf2(options, name) {
7111
+ const property = options.getProperty(name);
7112
+ if (property === void 0) {
7113
+ return null;
7114
+ }
7115
+ if (import_ts_morph30.Node.isPropertyAssignment(property)) {
7116
+ return property.getInitializer() ?? null;
7117
+ }
7118
+ if (import_ts_morph30.Node.isShorthandPropertyAssignment(property)) {
7119
+ const symbol = property.getProject().getTypeChecker().getShorthandAssignmentValueSymbol(property);
7120
+ return symbol?.getValueDeclaration() ?? null;
7121
+ }
7122
+ return null;
7123
+ }
7124
+ function resolveToConstructionOf(expression, cacheClass) {
7125
+ let current2 = expression;
7126
+ for (let hop = 0; hop < 4 && current2 !== void 0; hop += 1) {
7127
+ current2 = unwrapExpression2(current2);
7128
+ if (import_ts_morph30.Node.isVariableDeclaration(current2)) {
7129
+ current2 = current2.getInitializer();
7130
+ continue;
7131
+ }
7132
+ if (import_ts_morph30.Node.isNewExpression(current2) || import_ts_morph30.Node.isCallExpression(current2)) {
7133
+ const callee = current2.getExpression();
7134
+ if (callee === void 0 || !import_ts_morph30.Node.isIdentifier(callee)) {
7135
+ return null;
7136
+ }
7137
+ const local = localImportName(
7138
+ current2.getSourceFile(),
7139
+ cacheClass.importModule,
7140
+ cacheClass.importName
7141
+ );
7142
+ return local !== null && callee.getText() === local ? current2 : null;
7143
+ }
7144
+ if (!import_ts_morph30.Node.isIdentifier(current2)) {
7145
+ return null;
7146
+ }
7147
+ const declaration = current2.getSymbol()?.getValueDeclaration();
7148
+ if (declaration === void 0 || !import_ts_morph30.Node.isVariableDeclaration(declaration)) {
7149
+ return null;
7150
+ }
7151
+ current2 = declaration.getInitializer();
7152
+ }
7153
+ return null;
7154
+ }
7155
+ function unwrapExpression2(node) {
7156
+ let current2 = node;
7157
+ while (import_ts_morph30.Node.isParenthesizedExpression(current2) || import_ts_morph30.Node.isAsExpression(current2) || import_ts_morph30.Node.isNonNullExpression(current2)) {
7158
+ current2 = current2.getExpression();
7159
+ }
7160
+ return current2;
7161
+ }
7162
+ function isConstructionNamed(node, localName) {
7163
+ if (!import_ts_morph30.Node.isNewExpression(node) && !import_ts_morph30.Node.isCallExpression(node)) {
7164
+ return false;
7165
+ }
7166
+ const callee = node.getExpression();
7167
+ return callee !== void 0 && import_ts_morph30.Node.isIdentifier(callee) && callee.getText() === localName;
7168
+ }
7169
+ function localImportName(sourceFile, importModule, importName) {
7170
+ for (const importDecl of sourceFile.getImportDeclarations()) {
7171
+ const module2 = importDecl.getModuleSpecifierValue();
7172
+ if (module2 !== importModule && !module2.startsWith(`${importModule}/`)) {
7173
+ continue;
7174
+ }
7175
+ for (const named2 of importDecl.getNamedImports()) {
7176
+ if (named2.getName() === importName) {
7177
+ return named2.getAliasNode()?.getText() ?? named2.getName();
7178
+ }
7179
+ }
7180
+ }
7181
+ return null;
7182
+ }
6977
7183
  function localNamesFor(sourceFile, specs) {
6978
7184
  const names = /* @__PURE__ */ new Map();
6979
7185
  for (const importDecl of sourceFile.getImportDeclarations()) {
@@ -7715,32 +7921,163 @@ function innerTemplateText(template) {
7715
7921
  }
7716
7922
  return raw;
7717
7923
  }
7718
- function resolveGraphqlDocument(arg, resolution) {
7719
- const stripped = stripDocumentNodeCasts(arg);
7720
- const inline = documentTextFromExpression(stripped);
7924
+ function startAssembly(resolution) {
7925
+ return {
7926
+ resolution,
7927
+ seen: /* @__PURE__ */ new Set(),
7928
+ unresolvedInterpolations: [],
7929
+ unresolvedInsideSelection: false
7930
+ };
7931
+ }
7932
+ function assembledTemplateText(template, assembly) {
7933
+ if (import_ts_morph37.Node.isNoSubstitutionTemplateLiteral(template)) {
7934
+ return innerTemplateText(template);
7935
+ }
7936
+ if (!import_ts_morph37.Node.isTemplateExpression(template)) {
7937
+ return null;
7938
+ }
7939
+ let text = template.getHead().getLiteralText();
7940
+ for (const span of template.getTemplateSpans()) {
7941
+ const spliced = interpolatedDocumentText(span.getExpression(), assembly);
7942
+ if (spliced === null) {
7943
+ assembly.unresolvedInterpolations.push(
7944
+ singleLine(span.getExpression().getText())
7945
+ );
7946
+ if (openBraceDepth(text) > 0) {
7947
+ assembly.unresolvedInsideSelection = true;
7948
+ }
7949
+ } else {
7950
+ text += `
7951
+ ${spliced}
7952
+ `;
7953
+ }
7954
+ text += span.getLiteral().getLiteralText();
7955
+ }
7956
+ return text;
7957
+ }
7958
+ function openBraceDepth(text) {
7959
+ let depth = 0;
7960
+ for (const char of text) {
7961
+ if (char === "{") {
7962
+ depth += 1;
7963
+ } else if (char === "}") {
7964
+ depth -= 1;
7965
+ }
7966
+ }
7967
+ return depth;
7968
+ }
7969
+ function interpolatedDocumentText(expr, assembly) {
7970
+ const stripped = stripDocumentNodeCasts(expr);
7971
+ const inline = documentTextFromExpression(stripped, assembly);
7721
7972
  if (inline !== null) {
7722
- return { document: inline };
7973
+ return inline;
7723
7974
  }
7724
- const templateText = resolveGqlTemplateText(stripped);
7725
- if (templateText !== null) {
7726
- return { document: templateText };
7975
+ const named2 = resolveGqlTemplateText(stripped, assembly);
7976
+ if (named2 !== null) {
7977
+ return named2;
7727
7978
  }
7728
7979
  const objectDoc = resolveTypedDocumentSource(stripped);
7729
7980
  if (objectDoc !== null) {
7730
- return { document: objectDoc };
7981
+ return objectDoc;
7731
7982
  }
7732
- const throughFacts = resolveThroughFacts(stripped, resolution);
7733
- if (throughFacts !== null) {
7734
- return { document: throughFacts };
7983
+ return resolveThroughFacts(stripped, assembly);
7984
+ }
7985
+ function resolveGraphqlDocument(arg, resolution) {
7986
+ const assembly = startAssembly(resolution);
7987
+ const stripped = stripDocumentNodeCasts(arg);
7988
+ const text = documentTextFromExpression(stripped, assembly) ?? resolveGqlTemplateText(stripped, assembly) ?? resolveTypedDocumentSource(stripped) ?? resolveThroughFacts(stripped, assembly);
7989
+ if (text !== null) {
7990
+ return assembledDocumentResolution(text, stripped, assembly);
7735
7991
  }
7736
7992
  return resolveTypedDocumentHeader(stripped);
7737
7993
  }
7738
- function documentTextFromExpression(node) {
7994
+ function assembledDocumentResolution(text, arg, assembly) {
7995
+ const interpolations = assembly.unresolvedInterpolations;
7996
+ if (assembly.unresolvedInsideSelection) {
7997
+ const header = parseGraphqlOperation(text);
7998
+ return {
7999
+ ...header !== null ? { operationType: header.operationType } : {},
8000
+ ...header?.operationName !== void 0 ? { operationName: header.operationName } : {},
8001
+ unresolved: {
8002
+ reference: singleLine(arg.getText()),
8003
+ reason: `interpolated ${describeInterpolations(interpolations)} inside a selection set did not resolve to a GraphQL document, so what the operation selects is not statically written`
8004
+ }
8005
+ };
8006
+ }
8007
+ const dangling = danglingFragmentSpreads(text);
8008
+ if (dangling === null) {
8009
+ if (interpolations.length === 0) {
8010
+ return { document: text };
8011
+ }
8012
+ return {
8013
+ unresolved: {
8014
+ reference: singleLine(arg.getText()),
8015
+ reason: `the document did not parse after dropping interpolated ${describeInterpolations(interpolations)} that resolved to no GraphQL document`
8016
+ }
8017
+ };
8018
+ }
8019
+ if (dangling.length > 0) {
8020
+ return { document: text, unresolvedFragments: dangling };
8021
+ }
8022
+ if (interpolations.length > 0) {
8023
+ return {
8024
+ document: text,
8025
+ unresolved: {
8026
+ reference: singleLine(arg.getText()),
8027
+ reason: `interpolated ${describeInterpolations(interpolations)} did not resolve to a GraphQL document, so whatever it contributes is not part of the stored document`
8028
+ }
8029
+ };
8030
+ }
8031
+ return { document: text };
8032
+ }
8033
+ function describeInterpolations(interpolations) {
8034
+ const quoted = interpolations.map((text) => `\`${text}\``).join(", ");
8035
+ return interpolations.length === 1 ? `expression ${quoted}` : `expressions ${quoted}`;
8036
+ }
8037
+ function danglingFragmentSpreads(text) {
8038
+ let doc;
8039
+ try {
8040
+ doc = (0, import_graphql.parse)(text);
8041
+ } catch {
8042
+ return null;
8043
+ }
8044
+ const defined = /* @__PURE__ */ new Set();
8045
+ for (const def of doc.definitions) {
8046
+ if (def.kind === import_graphql.Kind.FRAGMENT_DEFINITION) {
8047
+ defined.add(def.name.value);
8048
+ }
8049
+ }
8050
+ const dangling = /* @__PURE__ */ new Set();
8051
+ for (const def of doc.definitions) {
8052
+ if (def.kind === import_graphql.Kind.OPERATION_DEFINITION || def.kind === import_graphql.Kind.FRAGMENT_DEFINITION) {
8053
+ collectDanglingSpreads(def.selectionSet, defined, dangling);
8054
+ }
8055
+ }
8056
+ return [...dangling].sort();
8057
+ }
8058
+ function collectDanglingSpreads(selectionSet, defined, dangling) {
8059
+ for (const selection of selectionSet.selections) {
8060
+ if (selection.kind === import_graphql.Kind.FRAGMENT_SPREAD) {
8061
+ if (!defined.has(selection.name.value)) {
8062
+ dangling.add(selection.name.value);
8063
+ }
8064
+ continue;
8065
+ }
8066
+ if (selection.selectionSet !== void 0) {
8067
+ collectDanglingSpreads(selection.selectionSet, defined, dangling);
8068
+ }
8069
+ }
8070
+ }
8071
+ function documentTextFromExpression(node, assembly) {
7739
8072
  if (import_ts_morph37.Node.isTaggedTemplateExpression(node)) {
7740
8073
  if (!isDocumentTag(node.getTag())) {
7741
8074
  return null;
7742
8075
  }
7743
- return innerTemplateText(node.getTemplate());
8076
+ if (assembly.seen.has(node)) {
8077
+ return "";
8078
+ }
8079
+ assembly.seen.add(node);
8080
+ return assembledTemplateText(node.getTemplate(), assembly);
7744
8081
  }
7745
8082
  if (!import_ts_morph37.Node.isCallExpression(node)) {
7746
8083
  return null;
@@ -7756,7 +8093,11 @@ function documentTextFromExpression(node) {
7756
8093
  if (!import_ts_morph37.Node.isNoSubstitutionTemplateLiteral(template) && !import_ts_morph37.Node.isTemplateExpression(template)) {
7757
8094
  return null;
7758
8095
  }
7759
- return innerTemplateText(template);
8096
+ if (assembly.seen.has(node)) {
8097
+ return "";
8098
+ }
8099
+ assembly.seen.add(node);
8100
+ return assembledTemplateText(template, assembly);
7760
8101
  }
7761
8102
  function isDocumentTag(tag) {
7762
8103
  if (!import_ts_morph37.Node.isIdentifier(tag)) {
@@ -7776,15 +8117,15 @@ function isDocumentTag(tag) {
7776
8117
  }
7777
8118
  return false;
7778
8119
  }
7779
- function resolveThroughFacts(arg, resolution) {
7780
- if (resolution === void 0 || !import_ts_morph37.Node.isIdentifier(arg)) {
8120
+ function resolveThroughFacts(arg, assembly) {
8121
+ if (assembly.resolution === void 0 || !import_ts_morph37.Node.isIdentifier(arg)) {
7781
8122
  return null;
7782
8123
  }
7783
- const written = resolution.resolveWrittenValue(arg);
8124
+ const written = assembly.resolution.resolveWrittenValue(arg);
7784
8125
  if (written === null) {
7785
8126
  return null;
7786
8127
  }
7787
- const text = documentTextFromExpression(written);
8128
+ const text = documentTextFromExpression(written, assembly);
7788
8129
  if (text !== null) {
7789
8130
  return text;
7790
8131
  }
@@ -7797,7 +8138,13 @@ function operationInfoFromResolution(resolution, callOperationType) {
7797
8138
  return null;
7798
8139
  }
7799
8140
  const operationType = operation.operationName !== void 0 ? operation.operationType : callOperationType;
7800
- return { ...operation, operationType, document: resolution.document };
8141
+ return {
8142
+ ...operation,
8143
+ operationType,
8144
+ document: resolution.document,
8145
+ ...resolution.unresolvedFragments !== void 0 ? { unresolvedFragments: resolution.unresolvedFragments } : {},
8146
+ ...resolution.unresolved !== void 0 ? { unresolved: resolution.unresolved } : {}
8147
+ };
7801
8148
  }
7802
8149
  return {
7803
8150
  operationType: resolution.operationType ?? callOperationType,
@@ -7839,8 +8186,8 @@ function importedVariableInitializers(identifier) {
7839
8186
  }
7840
8187
  return inits;
7841
8188
  }
7842
- function resolveGqlTemplateText(arg) {
7843
- const direct = documentTextFromExpression(arg);
8189
+ function resolveGqlTemplateText(arg, assembly) {
8190
+ const direct = documentTextFromExpression(arg, assembly);
7844
8191
  if (direct !== null) {
7845
8192
  return direct;
7846
8193
  }
@@ -7860,7 +8207,10 @@ function resolveGqlTemplateText(arg) {
7860
8207
  }
7861
8208
  }
7862
8209
  for (const init of importedVariableInitializers(arg)) {
7863
- const text = documentTextFromExpression(stripDocumentNodeCasts(init));
8210
+ const text = documentTextFromExpression(
8211
+ stripDocumentNodeCasts(init),
8212
+ assembly
8213
+ );
7864
8214
  if (text !== null) {
7865
8215
  return text;
7866
8216
  }
@@ -8448,14 +8798,14 @@ function unitForJsxRoute(node, match, routeNames, kind, resolution) {
8448
8798
  }
8449
8799
  return routeUnit(node, kind, match.method, resolved.path, target, resolution);
8450
8800
  }
8451
- function routeUnit(at, kind, method, path11, target, resolution) {
8452
- const routeInfo = { method, path: path11 };
8801
+ function routeUnit(at, kind, method, path12, target, resolution) {
8802
+ const routeInfo = { method, path: path12 };
8453
8803
  if (target.kind === "unreadable") {
8454
8804
  return {
8455
8805
  func: null,
8456
8806
  announcedAt: at,
8457
8807
  kind,
8458
- name: path11,
8808
+ name: path12,
8459
8809
  nameKind: "label",
8460
8810
  routeInfo
8461
8811
  };
@@ -9343,9 +9693,9 @@ function withMountPrefix(routeInfo, subjectNode, mountPrefixes) {
9343
9693
  const prefix = mountPrefixes.effectivePrefixFor(subjectNode);
9344
9694
  return prefix === "" ? routeInfo : { ...routeInfo, path: joinMountedPath(prefix, routeInfo.path) };
9345
9695
  }
9346
- function joinMountedPath(prefix, path11) {
9696
+ function joinMountedPath(prefix, path12) {
9347
9697
  const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
9348
- return trimmed === "" ? path11 : trimmed + path11;
9698
+ return trimmed === "" ? path12 : trimmed + path12;
9349
9699
  }
9350
9700
  function registrationSubjectsOf(sourceFile, importModule, importName) {
9351
9701
  let importedLocalName = null;
@@ -9509,11 +9859,11 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
9509
9859
  return null;
9510
9860
  }
9511
9861
  const method2 = stringProperty(routeObject, binding.method.property);
9512
- const path11 = stringProperty(routeObject, binding.path.property);
9513
- if (method2 === null || path11 === null) {
9862
+ const path12 = stringProperty(routeObject, binding.path.property);
9863
+ if (method2 === null || path12 === null) {
9514
9864
  return null;
9515
9865
  }
9516
- return { method: method2.toUpperCase(), path: path11 };
9866
+ return { method: method2.toUpperCase(), path: path12 };
9517
9867
  }
9518
9868
  if (binding.method.type !== "fromRegistration" || binding.path.type !== "fromRegistration") {
9519
9869
  return null;
@@ -9620,7 +9970,7 @@ function bodyReferencesLoopVar(loop, name) {
9620
9970
  }
9621
9971
  function readRouteSpec(element, shape, resolution) {
9622
9972
  let method = null;
9623
- let path11 = null;
9973
+ let path12 = null;
9624
9974
  let handler = null;
9625
9975
  for (const prop of element.getProperties()) {
9626
9976
  if (import_ts_morph46.Node.isMethodDeclaration(prop) && prop.getName() === shape.handlerKey) {
@@ -9638,16 +9988,16 @@ function readRouteSpec(element, shape, resolution) {
9638
9988
  if (name === shape.methodKey) {
9639
9989
  method = readStringLiteralValue(init);
9640
9990
  } else if (name === shape.pathKey) {
9641
- path11 = readStringLiteralValue(init);
9991
+ path12 = readStringLiteralValue(init);
9642
9992
  } else if (name === shape.handlerKey) {
9643
9993
  const func = functionValueOf(init, resolution);
9644
9994
  handler = func === null ? null : { func, name: handlerName(init) };
9645
9995
  }
9646
9996
  }
9647
- if (method === null || path11 === null || handler === null) {
9997
+ if (method === null || path12 === null || handler === null) {
9648
9998
  return null;
9649
9999
  }
9650
- return { method, path: path11, handler: handler.func, handlerName: handler.name };
10000
+ return { method, path: path12, handler: handler.func, handlerName: handler.name };
9651
10001
  }
9652
10002
  function readStringLiteralValue(node) {
9653
10003
  if (import_ts_morph46.Node.isStringLiteral(node) || import_ts_morph46.Node.isNoSubstitutionTemplateLiteral(node)) {
@@ -9676,8 +10026,8 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
9676
10026
  }
9677
10027
  const args = node.getArguments();
9678
10028
  for (const reg of match.registrations) {
9679
- const path11 = substitutePath(reg.pathTemplate, args);
9680
- if (path11 === null) {
10029
+ const path12 = substitutePath(reg.pathTemplate, args);
10030
+ if (path12 === null) {
9681
10031
  continue;
9682
10032
  }
9683
10033
  const handler = resolveHandler(reg.handlerArg, args, resolution);
@@ -9690,7 +10040,7 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
9690
10040
  name: handler.name,
9691
10041
  routeInfo: {
9692
10042
  method: reg.method.toUpperCase(),
9693
- path: path11
10043
+ path: path12
9694
10044
  }
9695
10045
  });
9696
10046
  }
@@ -10378,7 +10728,8 @@ var JS_RULES = [
10378
10728
  (0, import_datalog2.rule)(
10379
10729
  "stepsTo",
10380
10730
  [(0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("t"), import_resolution.VALUE_STEP],
10381
- [(0, import_datalog2.lit)("bindCall", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("t"))]
10731
+ [(0, import_datalog2.lit)("bindCall", (0, import_datalog2.variable)("r"), (0, import_datalog2.variable)("t"))],
10732
+ "bind"
10382
10733
  )
10383
10734
  ];
10384
10735
  var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
@@ -10388,6 +10739,15 @@ var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
10388
10739
  [...import_resolution.RESOLUTION_RULES, ...JS_RULES, ...import_resolution.RESOLUTION_QUESTIONS],
10389
10740
  import_resolution.ANSWER_RELATIONS
10390
10741
  );
10742
+ var WITNESS_RULES = [...import_resolution.RESOLUTION_RULES, ...JS_RULES];
10743
+ var NOT_BASE_FACTS = /* @__PURE__ */ new Set([
10744
+ ...[...import_resolution.RESOLUTION_RULES, ...JS_RULES, ...import_resolution.RESOLUTION_QUESTIONS].map(
10745
+ (r) => r.head.relation
10746
+ ),
10747
+ ...RESOLUTION_PROGRAM.rules.map((r) => r.head.relation),
10748
+ "wanted",
10749
+ "wantedOrigin"
10750
+ ]);
10391
10751
  var QUERY_FACTS = RESOLUTION_PROGRAM.demandDriven.length === 0 ? [] : [...RESOLUTION_PROGRAM.demandDriven, "wanted", "wantedOrigin"];
10392
10752
  var MAX_MODULE_HOPS = 6;
10393
10753
  var ResolutionStore = class {
@@ -10415,13 +10775,64 @@ var ResolutionStore = class {
10415
10775
  * the walk never reaches on its own.
10416
10776
  */
10417
10777
  resolveCallable(value, alsoFrom) {
10778
+ const sources = this.resolveCallableSources(value, alsoFrom);
10779
+ const only = sources[0];
10780
+ return sources.length === 1 && only !== void 0 ? only : null;
10781
+ }
10782
+ /**
10783
+ * Every function the value comes down to. One is the answer
10784
+ * `resolveCallable` gives; several is a value with more than one
10785
+ * possible source, which a caller says at the site rather than
10786
+ * folding into the same nothing as a chain that went nowhere.
10787
+ */
10788
+ resolveCallableSources(value, alsoFrom) {
10418
10789
  const target = factKeyOf(value);
10419
10790
  return this.resolveByWaves(
10420
10791
  target,
10421
10792
  "wanted",
10422
- () => this.lookup(target),
10793
+ () => this.lookupSources(target),
10423
10794
  alsoFrom
10795
+ ) ?? [];
10796
+ }
10797
+ /**
10798
+ * The witness proof behind `resolveCallable`'s answer. Resolves the
10799
+ * value first, which walks files and extracts facts in the usual
10800
+ * waves, then re-evaluates the rules over those base facts under the
10801
+ * witness algebra and rebuilds the proof of the answer. Null when
10802
+ * the value does not resolve at all.
10803
+ */
10804
+ explainCallable(value, options = {}) {
10805
+ const resolved = this.resolveCallable(value, options.alsoFrom);
10806
+ if (resolved === null) {
10807
+ return null;
10808
+ }
10809
+ const proofDb = new import_datalog2.Database();
10810
+ let baseFacts = 0;
10811
+ for (const relation of this.db.relationNames()) {
10812
+ if (NOT_BASE_FACTS.has(relation)) {
10813
+ continue;
10814
+ }
10815
+ for (const tuple of this.db.facts(relation)) {
10816
+ proofDb.add(relation, tuple);
10817
+ baseFacts++;
10818
+ }
10819
+ }
10820
+ const started = performance.now();
10821
+ (0, import_datalog2.evaluate)(proofDb, WITNESS_RULES, import_datalog2.witnesses);
10822
+ const evaluateMs = performance.now() - started;
10823
+ const derivedFacts = proofDb.relationNames().reduce((count, relation) => count + proofDb.size(relation), 0) - baseFacts;
10824
+ const proof = (0, import_datalog2.proofOf)(
10825
+ proofDb,
10826
+ "resolves",
10827
+ [nodeId(factKeyOf(value)), nodeId(resolved)],
10828
+ options.maxDepth === void 0 ? {} : { maxDepth: options.maxDepth }
10424
10829
  );
10830
+ return {
10831
+ target: resolved,
10832
+ proof,
10833
+ nodeFor: (atom) => this.table.byId.get(String(atom)),
10834
+ stats: { baseFacts, derivedFacts, evaluateMs }
10835
+ };
10425
10836
  }
10426
10837
  resolveObject(value) {
10427
10838
  const target = factKeyOf(value);
@@ -10544,7 +10955,7 @@ var ResolutionStore = class {
10544
10955
  this.stale = false;
10545
10956
  }
10546
10957
  wantValue(question, value) {
10547
- if (this.db.add(question, [nodeId(value)])) {
10958
+ if (this.db.add(question, [nodeId(value)]) === "added") {
10548
10959
  this.stale = true;
10549
10960
  }
10550
10961
  }
@@ -10608,10 +11019,12 @@ var ResolutionStore = class {
10608
11019
  return this.graph.filesReachingAnyPackage(fileSets);
10609
11020
  }
10610
11021
  /**
10611
- * Two candidates give null. Picking whichever arrived first would make
10612
- * the result depend on the order the facts came in.
11022
+ * Null keeps the wave walk widening; any candidate at all ends it,
11023
+ * since more files can only add candidates, never take one away. The
11024
+ * single-answer policy stays with the callers: picking one of two
11025
+ * would make the result depend on the order the facts came in.
10613
11026
  */
10614
- lookup(value) {
11027
+ lookupSources(value) {
10615
11028
  this.derive();
10616
11029
  const candidates = /* @__PURE__ */ new Set();
10617
11030
  for (const target of this.answersFor("wantedResolves", nodeId(value))) {
@@ -10623,10 +11036,7 @@ var ResolutionStore = class {
10623
11036
  candidates.add(resolved);
10624
11037
  }
10625
11038
  }
10626
- if (candidates.size !== 1) {
10627
- return null;
10628
- }
10629
- return [...candidates][0];
11039
+ return candidates.size === 0 ? null : [...candidates];
10630
11040
  }
10631
11041
  derive() {
10632
11042
  if (!this.stale) {
@@ -11031,6 +11441,7 @@ function classifyStop(declarations) {
11031
11441
  var RECORDED = {
11032
11442
  noBody: true,
11033
11443
  unsettledValue: true,
11444
+ multipleSources: true,
11034
11445
  outsideRun: false,
11035
11446
  noDeclaration: false
11036
11447
  };
@@ -11040,6 +11451,7 @@ function worthRecording(reason) {
11040
11451
  var STOP_SENTENCE = {
11041
11452
  noBody: (callee) => `The call to ${callee} lands on a declaration with no body, so whatever runs there is missing from this summary`,
11042
11453
  unsettledValue: (callee) => `The call to ${callee} goes through a value this run could not settle, so whatever runs there is missing from this summary`,
11454
+ multipleSources: (callee) => `The call to ${callee} reaches a value with more than one possible source, so whatever runs there is missing from this summary`,
11043
11455
  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`,
11044
11456
  noDeclaration: (callee) => `The call to ${callee} has no declaration this run could find, so whatever runs there is missing from this summary`
11045
11457
  };
@@ -11093,24 +11505,6 @@ function resolveDecl(decl, calleeName) {
11093
11505
  }
11094
11506
  return null;
11095
11507
  }
11096
- if (import_ts_morph52.Node.isImportSpecifier(decl)) {
11097
- const importDecl = decl.getImportDeclaration();
11098
- const sf = importDecl.getModuleSpecifierSourceFile();
11099
- if (sf === void 0 || isInExternalCode(sf)) {
11100
- return null;
11101
- }
11102
- const exported = exportedDeclarationsOf(sf).get(decl.getName());
11103
- if (exported === void 0) {
11104
- return null;
11105
- }
11106
- for (const ed of exported) {
11107
- const resolved = resolveDecl(ed, calleeName);
11108
- if (resolved !== null) {
11109
- return resolved;
11110
- }
11111
- }
11112
- return null;
11113
- }
11114
11508
  return null;
11115
11509
  }
11116
11510
  function declName(decl) {
@@ -11138,20 +11532,27 @@ function resolveCallee(call, calleeName, scan) {
11138
11532
  }
11139
11533
  const callee = call.getExpression();
11140
11534
  const symbol = callee.getSymbol();
11141
- const declarations = symbol?.getDeclarations() ?? [];
11535
+ const declarations = declarationsBehind(symbol);
11142
11536
  for (const decl of declarations) {
11143
11537
  const resolved = resolveDecl(decl, calleeName);
11144
11538
  if (resolved !== null) {
11145
11539
  return { kind: "followed", candidate: resolved };
11146
11540
  }
11147
11541
  }
11148
- const resolveCallable = scan.resolveCallable;
11149
- if (resolveCallable !== void 0 && import_ts_morph52.Node.isPropertyAccessExpression(callee) && declarations.some(isDeclaredShape)) {
11150
- const value = resolveCallable(callee, scan.reachedFrom);
11151
- const resolved = value === null ? null : resolveDecl(value, calleeName);
11542
+ const resolveSources = scan.resolveCallableSources;
11543
+ if (resolveSources !== void 0 && import_ts_morph52.Node.isPropertyAccessExpression(callee) && declarations.some(isDeclaredShape)) {
11544
+ const sources = resolveSources(callee, scan.reachedFrom);
11545
+ const only = sources.length === 1 ? sources[0] : void 0;
11546
+ const resolved = only === void 0 ? null : resolveDecl(only, calleeName);
11152
11547
  if (resolved !== null) {
11153
11548
  return { kind: "followed", candidate: resolved };
11154
11549
  }
11550
+ if (sources.length > 1) {
11551
+ return {
11552
+ kind: "stopped",
11553
+ stop: { callee: calleeName, reason: "multipleSources" }
11554
+ };
11555
+ }
11155
11556
  }
11156
11557
  return {
11157
11558
  kind: "stopped",
@@ -11269,7 +11670,7 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
11269
11670
  }
11270
11671
  const cameFrom = reachedFrom.get(key);
11271
11672
  const scan = {
11272
- ...recognizers.resolveCallable === void 0 ? {} : { resolveCallable: recognizers.resolveCallable },
11673
+ ...recognizers.resolveCallableSources === void 0 ? {} : { resolveCallableSources: recognizers.resolveCallableSources },
11273
11674
  ...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
11274
11675
  };
11275
11676
  const { candidates, stops } = scanWithRecording(
@@ -12083,20 +12484,25 @@ function readArrayLiteralText(node) {
12083
12484
  var import_node_fs4 = __toESM(require("fs"), 1);
12084
12485
  var import_node_path7 = __toESM(require("path"), 1);
12085
12486
  var import_behavioral_ir5 = require("@suss/behavioral-ir");
12487
+ function workspaceRootFor(anchor) {
12488
+ return namedPackageDirAbove(anchor) ?? import_node_path7.default.resolve(anchor);
12489
+ }
12086
12490
  function workspaceNameFor(root) {
12087
12491
  if (root === void 0) {
12088
12492
  return null;
12089
12493
  }
12090
- let at = import_node_path7.default.resolve(root);
12494
+ const dir = namedPackageDirAbove(root);
12495
+ if (dir !== null) {
12496
+ return packageNameAt(dir);
12497
+ }
12498
+ const folder = import_node_path7.default.basename(import_node_path7.default.resolve(root));
12499
+ return folder.length > 0 ? folder : null;
12500
+ }
12501
+ function namedPackageDirAbove(start) {
12502
+ let at = import_node_path7.default.resolve(start);
12091
12503
  for (let up = 0; up < 12; up += 1) {
12092
- try {
12093
- const manifest = JSON.parse(
12094
- import_node_fs4.default.readFileSync(import_node_path7.default.join(at, "package.json"), "utf8")
12095
- );
12096
- if (typeof manifest.name === "string" && manifest.name.length > 0) {
12097
- return manifest.name;
12098
- }
12099
- } catch {
12504
+ if (packageNameAt(at) !== null) {
12505
+ return at;
12100
12506
  }
12101
12507
  const parent = import_node_path7.default.dirname(at);
12102
12508
  if (parent === at) {
@@ -12104,8 +12510,19 @@ function workspaceNameFor(root) {
12104
12510
  }
12105
12511
  at = parent;
12106
12512
  }
12107
- const folder = import_node_path7.default.basename(import_node_path7.default.resolve(root));
12108
- return folder.length > 0 ? folder : null;
12513
+ return null;
12514
+ }
12515
+ function packageNameAt(dir) {
12516
+ try {
12517
+ const manifest = JSON.parse(
12518
+ import_node_fs4.default.readFileSync(import_node_path7.default.join(dir, "package.json"), "utf8")
12519
+ );
12520
+ if (typeof manifest.name === "string" && manifest.name.length > 0) {
12521
+ return manifest.name;
12522
+ }
12523
+ } catch {
12524
+ }
12525
+ return null;
12109
12526
  }
12110
12527
  function nameSummaries(summaries, args) {
12111
12528
  for (const summary of summaries) {
@@ -12705,11 +13122,11 @@ function extractConsumerBinding(unit, pattern, pack, resolution) {
12705
13122
  return null;
12706
13123
  }
12707
13124
  const method = extractBindingMethod(binding, callSite, pack, resolution);
12708
- const path11 = extractBindingPath(binding, callSite, pack, resolution);
13125
+ const path12 = extractBindingPath(binding, callSite, pack, resolution);
12709
13126
  return (0, import_behavioral_ir6.restBinding)({
12710
13127
  transport: pack.protocol,
12711
13128
  method: method ?? null,
12712
- path: path11 ?? null,
13129
+ path: path12 ?? null,
12713
13130
  recognition: pack.name
12714
13131
  });
12715
13132
  }
@@ -12798,12 +13215,12 @@ function originEndOf(flattened) {
12798
13215
  const slash = flattened.indexOf("/", opener[0].length);
12799
13216
  return slash === -1 ? flattened.length : slash;
12800
13217
  }
12801
- function appendPathText(path11, text) {
13218
+ function appendPathText(path12, text) {
12802
13219
  const idx = text.search(/[?#]/);
12803
13220
  if (idx === -1) {
12804
- return { path: path11 + text, stop: false };
13221
+ return { path: path12 + text, stop: false };
12805
13222
  }
12806
- return { path: path11 + text.slice(0, idx), stop: true };
13223
+ return { path: path12 + text.slice(0, idx), stop: true };
12807
13224
  }
12808
13225
  function parseAbsoluteUrl(text) {
12809
13226
  try {
@@ -12827,8 +13244,8 @@ function pathnameOfAbsoluteLiteral(text) {
12827
13244
  return stripQueryAndFragment(stripOriginManually(text));
12828
13245
  }
12829
13246
  function pathFromLiteralUrl(text) {
12830
- const path11 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
12831
- return path11 === "" ? void 0 : path11;
13247
+ const path12 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
13248
+ return path12 === "" ? void 0 : path12;
12832
13249
  }
12833
13250
  function pathFromTemplateUrl(arg) {
12834
13251
  const headText = arg.getHead().getLiteralText();
@@ -12836,7 +13253,7 @@ function pathFromTemplateUrl(arg) {
12836
13253
  const tails = spans.map((span) => span.getLiteral().getLiteralText());
12837
13254
  const originEnd = originEndOf([headText, ...tails].join(SUBSTITUTION));
12838
13255
  const head = appendPathText("", headText.slice(originEnd));
12839
- let path11 = head.path;
13256
+ let path12 = head.path;
12840
13257
  let stop = head.stop;
12841
13258
  let at = headText.length;
12842
13259
  for (let i = 0; i < spans.length && !stop; i++) {
@@ -12846,18 +13263,18 @@ function pathFromTemplateUrl(arg) {
12846
13263
  continue;
12847
13264
  }
12848
13265
  if (at >= originEnd) {
12849
- path11 += `{${placeholderName(span.getExpression())}}`;
13266
+ path12 += `{${placeholderName(span.getExpression())}}`;
12850
13267
  }
12851
13268
  at += SUBSTITUTION.length;
12852
13269
  const appended = appendPathText(
12853
- path11,
13270
+ path12,
12854
13271
  tailText.slice(Math.max(0, originEnd - at))
12855
13272
  );
12856
- path11 = appended.path;
13273
+ path12 = appended.path;
12857
13274
  stop = appended.stop;
12858
13275
  at += tailText.length;
12859
13276
  }
12860
- return path11 === "" ? void 0 : path11;
13277
+ return path12 === "" ? void 0 : path12;
12861
13278
  }
12862
13279
  function extractBindingPath(binding, callSite, pack, resolution) {
12863
13280
  const p = binding.path;
@@ -13136,6 +13553,9 @@ function extractFromSourceFile(sourceFile, frameworks, claimedUnits, options, ta
13136
13553
  if (unit.operationInfo.document !== void 0) {
13137
13554
  raw.graphqlDocument = unit.operationInfo.document;
13138
13555
  }
13556
+ if (unit.operationInfo.unresolvedFragments !== void 0) {
13557
+ raw.graphqlUnresolvedFragments = unit.operationInfo.unresolvedFragments;
13558
+ }
13139
13559
  if (unit.operationInfo.unresolved !== void 0) {
13140
13560
  raw.graphqlUnresolvedDocument = unit.operationInfo.unresolved;
13141
13561
  }
@@ -13437,8 +13857,8 @@ function synthesizeCallerSummaries(wrapper, _project, options) {
13437
13857
  if (pathArg === void 0) {
13438
13858
  continue;
13439
13859
  }
13440
- const path11 = literalOrTemplate(pathArg);
13441
- if (path11 === void 0) {
13860
+ const path12 = literalOrTemplate(pathArg);
13861
+ if (path12 === void 0) {
13442
13862
  continue;
13443
13863
  }
13444
13864
  const callerFunc = enclosingFunction(callExpr);
@@ -13450,7 +13870,7 @@ function synthesizeCallerSummaries(wrapper, _project, options) {
13450
13870
  continue;
13451
13871
  }
13452
13872
  seen.add(dedupKey);
13453
- out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path11, options));
13873
+ out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path12, options));
13454
13874
  }
13455
13875
  return out;
13456
13876
  }
@@ -13502,12 +13922,12 @@ function literalOrTemplate(arg) {
13502
13922
  return arg.getLiteralValue();
13503
13923
  }
13504
13924
  if (import_ts_morph56.Node.isTemplateExpression(arg)) {
13505
- let path11 = arg.getHead().getLiteralText();
13925
+ let path12 = arg.getHead().getLiteralText();
13506
13926
  for (const span of arg.getTemplateSpans()) {
13507
- path11 += `{${placeholderName(span.getExpression())}}`;
13508
- path11 += span.getLiteral().getLiteralText();
13927
+ path12 += `{${placeholderName(span.getExpression())}}`;
13928
+ path12 += span.getLiteral().getLiteralText();
13509
13929
  }
13510
- return path11;
13930
+ return path12;
13511
13931
  }
13512
13932
  return void 0;
13513
13933
  }
@@ -13524,7 +13944,7 @@ function callerName(func) {
13524
13944
  }
13525
13945
  return "anonymous";
13526
13946
  }
13527
- function buildCallerSummary(wrapper, callerFunc, callExpr, path11, options) {
13947
+ function buildCallerSummary(wrapper, callerFunc, callExpr, path12, options) {
13528
13948
  const wrapperBinding = wrapper.summary.identity.boundaryBinding;
13529
13949
  const wrapperRest = wrapperBinding?.semantics.name === "rest" ? wrapperBinding.semantics : null;
13530
13950
  const syntheticPack = {
@@ -13556,7 +13976,7 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path11, options) {
13556
13976
  raw.boundaryBinding = (0, import_behavioral_ir6.restBinding)({
13557
13977
  transport: wrapperBinding?.transport ?? "http",
13558
13978
  method: wrapperRest?.method ?? null,
13559
- path: path11,
13979
+ path: path12,
13560
13980
  recognition: wrapperBinding?.recognition ?? "unknown"
13561
13981
  });
13562
13982
  const summary = (0, import_extractor5.assembleSummary)(raw, options);
@@ -13570,8 +13990,8 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path11, options) {
13570
13990
  summary.confidence = { source: "inferred_static", level: "low" };
13571
13991
  return summary;
13572
13992
  }
13573
- function named(summaries, workspace, storedProjectRoot) {
13574
- const projectRoot = storedProjectRoot ?? commonDirectoryOf(summaries.map((s) => s.location.file));
13993
+ function named(summaries, workspace, runRoot) {
13994
+ const projectRoot = runRoot ?? commonDirectoryOf(summaries.map((s) => s.location.file));
13575
13995
  nameSummaries(summaries, {
13576
13996
  workspace: workspace ?? workspaceNameFor(projectRoot),
13577
13997
  projectRoot
@@ -13629,6 +14049,7 @@ function createTypeScriptAdapter(config) {
13629
14049
  skipAddingFilesFromTsConfig: true
13630
14050
  } : { skipAddingFilesFromTsConfig: true }
13631
14051
  );
14052
+ const runRoot = config.projectRoot ?? (config.tsConfigFilePath !== void 0 ? workspaceRootFor(import_node_path9.default.dirname(config.tsConfigFilePath)) : void 0);
13632
14053
  let lazyBootstrapped = false;
13633
14054
  let projectFileSet;
13634
14055
  const cacheDir = declineWhenRunFromSource(
@@ -13669,7 +14090,7 @@ function createTypeScriptAdapter(config) {
13669
14090
  )
13670
14091
  );
13671
14092
  }
13672
- return named(summaries, config.workspace);
14093
+ return named(summaries, config.workspace, runRoot);
13673
14094
  },
13674
14095
  async extractAll() {
13675
14096
  const timer = createTimer();
@@ -13702,7 +14123,7 @@ function createTypeScriptAdapter(config) {
13702
14123
  if (config.onTiming !== void 0) {
13703
14124
  config.onTiming(timer.report());
13704
14125
  }
13705
- return named(lookup.summaries, config.workspace, lookup.projectRoot);
14126
+ return named(lookup.summaries, config.workspace, runRoot);
13706
14127
  }
13707
14128
  const plan = lookup.diagnostic.missReason === "files-changed" ? await timer.timeAsync("cache.plan", () => cache.plan(cacheInput)) : null;
13708
14129
  if (plan !== null && plan.changed.size === 0 && plan.removed.size === 0) {
@@ -13720,11 +14141,7 @@ function createTypeScriptAdapter(config) {
13720
14141
  if (config.onTiming !== void 0) {
13721
14142
  config.onTiming(timer.report());
13722
14143
  }
13723
- return named(
13724
- plan.allSummaries(),
13725
- config.workspace,
13726
- plan.storedProjectRoot ?? void 0
13727
- );
14144
+ return named(plan.allSummaries(), config.workspace, runRoot);
13728
14145
  }
13729
14146
  let candidatePaths = null;
13730
14147
  if (lazyEligible) {
@@ -13870,7 +14287,7 @@ function createTypeScriptAdapter(config) {
13870
14287
  ),
13871
14288
  access: collectAccessRecognizers(config.frameworks, tallies),
13872
14289
  resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
13873
- resolveCallable: (value, alsoFrom) => resolution.resolveCallable(value, alsoFrom)
14290
+ resolveCallableSources: (value, alsoFrom) => resolution.resolveCallableSources(value, alsoFrom)
13874
14291
  },
13875
14292
  // Reached units the cache already serves emit nothing,
13876
14293
  // the way a cold run's seeds do not.
@@ -13934,9 +14351,6 @@ function createTypeScriptAdapter(config) {
13934
14351
  }
13935
14352
  });
13936
14353
  }
13937
- const runProjectRoot = commonDirectoryOf(
13938
- sourceFiles.map((f) => f.getFilePath())
13939
- );
13940
14354
  await timer.timeAsync("cache.write", async () => {
13941
14355
  if (!caching || enriched.length === 0) {
13942
14356
  return;
@@ -13956,8 +14370,7 @@ function createTypeScriptAdapter(config) {
13956
14370
  reusedOwners: merged.reusedOwners,
13957
14371
  // Everything after the reused prefix, the passes' own
13958
14372
  // additions (markers, schema documents) included.
13959
- fresh: enriched.slice(merged.reusedKept.length),
13960
- projectRoot: runProjectRoot
14373
+ fresh: enriched.slice(merged.reusedKept.length)
13961
14374
  });
13962
14375
  await cache.write(cacheInput, enriched, attribution);
13963
14376
  } catch {
@@ -13982,13 +14395,11 @@ function createTypeScriptAdapter(config) {
13982
14395
  })
13983
14396
  );
13984
14397
  }
13985
- nameSummaries(enriched, {
13986
- workspace: config.workspace ?? workspaceNameFor(
13987
- commonDirectoryOf(sourceFiles.map((f) => f.getFilePath()))
13988
- ),
13989
- projectRoot: commonDirectoryOf(sourceFiles.map((f) => f.getFilePath()))
13990
- });
13991
- return enriched;
14398
+ return named(
14399
+ enriched,
14400
+ config.workspace,
14401
+ runRoot ?? commonDirectoryOf(sourceFiles.map((f) => f.getFilePath()))
14402
+ );
13992
14403
  }
13993
14404
  };
13994
14405
  }
@@ -14179,11 +14590,7 @@ function buildCacheAttribution(args) {
14179
14590
  ...reusedOwners,
14180
14591
  ...args.fresh.map((s) => [...args.ownersBySummary.get(s) ?? []])
14181
14592
  ];
14182
- return {
14183
- roots,
14184
- owners,
14185
- ...args.projectRoot === void 0 ? {} : { projectRoot: args.projectRoot }
14186
- };
14593
+ return { roots, owners };
14187
14594
  }
14188
14595
  function synthesizeSubUnits(summaries, project, frameworks, options, tallies, onCreated) {
14189
14596
  const packByRecognition = /* @__PURE__ */ new Map();
@@ -14422,7 +14829,7 @@ function readStringArg(arg) {
14422
14829
  }
14423
14830
  return candidate.value;
14424
14831
  }
14425
- function rootIdentifier(node) {
14832
+ function rootIdentifier2(node) {
14426
14833
  let current2 = node;
14427
14834
  while (import_ts_morph58.Node.isPropertyAccessExpression(current2)) {
14428
14835
  current2 = current2.getExpression();
@@ -14430,10 +14837,165 @@ function rootIdentifier(node) {
14430
14837
  return import_ts_morph58.Node.isIdentifier(current2) ? current2 : null;
14431
14838
  }
14432
14839
 
14840
+ // src/facts/why.ts
14841
+ var import_node_path11 = __toESM(require("path"), 1);
14842
+ var import_ts_morph59 = require("ts-morph");
14843
+ var import_resolution2 = require("@suss/resolution");
14844
+ var JS_PHRASES = {
14845
+ bind: ({ tuple, describe }) => ({
14846
+ reason: `${describe(tuple[0])} is a .bind of ${describe(tuple[1])}, which runs the same function`
14847
+ })
14848
+ };
14849
+ var WhySession = class {
14850
+ project;
14851
+ store;
14852
+ root;
14853
+ constructor(options) {
14854
+ this.root = import_node_path11.default.resolve(options.dir);
14855
+ const tsconfig = findNearestTsconfig(this.root);
14856
+ this.project = tsconfig === null ? createProjectWithoutTsconfig(this.root).project : new import_ts_morph59.Project({ tsConfigFilePath: tsconfig });
14857
+ this.store = new ResolutionStore();
14858
+ }
14859
+ /**
14860
+ * The smallest expression on `line` of `file` whose text is exactly
14861
+ * `text`, or null. Spelled from the person's side: the name as
14862
+ * written, not a node id.
14863
+ */
14864
+ findExpression(file, line, text) {
14865
+ const sourceFile = this.sourceFileAt(file);
14866
+ if (sourceFile === null) {
14867
+ return null;
14868
+ }
14869
+ let found = null;
14870
+ sourceFile.forEachDescendant((node) => {
14871
+ if (import_ts_morph59.Node.isExpression(node) && node.getStartLineNumber() === line && node.getText() === text && (found === null || node.getWidth() <= found.getWidth())) {
14872
+ found = node;
14873
+ }
14874
+ });
14875
+ return found;
14876
+ }
14877
+ /**
14878
+ * The callee of the call written as `calleeText` between `startLine`
14879
+ * and `endLine` of `file`, or null. This is how a summary's recorded
14880
+ * callee gets back to its node: the summary keeps source text and a
14881
+ * range, not ids.
14882
+ */
14883
+ findCallee(file, startLine, endLine, calleeText) {
14884
+ const sourceFile = this.sourceFileAt(file);
14885
+ if (sourceFile === null) {
14886
+ return null;
14887
+ }
14888
+ for (const call of sourceFile.getDescendantsOfKind(
14889
+ import_ts_morph59.SyntaxKind.CallExpression
14890
+ )) {
14891
+ const line = call.getStartLineNumber();
14892
+ if (line < startLine || line > endLine) {
14893
+ continue;
14894
+ }
14895
+ if (call.getExpression().getText() === calleeText) {
14896
+ return call.getExpression();
14897
+ }
14898
+ }
14899
+ return null;
14900
+ }
14901
+ /**
14902
+ * Why `value` resolves to what it does: the witness proof, flattened
14903
+ * to the chain and rendered. Null when the value does not resolve,
14904
+ * which the caller says in its own words.
14905
+ */
14906
+ explain(value, options = {}) {
14907
+ const explained = this.store.explainCallable(value, options);
14908
+ if (explained === null) {
14909
+ return null;
14910
+ }
14911
+ const describe = (atom) => {
14912
+ const node = explained.nodeFor(atom);
14913
+ if (node === void 0) {
14914
+ return this.displayPath(String(atom));
14915
+ }
14916
+ const at = this.locate(node);
14917
+ return `${at.name} (${at.file}:${at.line})`;
14918
+ };
14919
+ const explanation = (0, import_resolution2.explainResolutionProof)(explained.proof, {
14920
+ describe,
14921
+ phrases: JS_PHRASES
14922
+ });
14923
+ if (explanation === null) {
14924
+ return null;
14925
+ }
14926
+ return {
14927
+ explanation,
14928
+ chain: explanation.atoms.map((atom) => describe(atom)),
14929
+ lines: (0, import_resolution2.renderExplanation)(explanation, describe),
14930
+ target: this.locate(explained.target),
14931
+ stats: explained.stats
14932
+ };
14933
+ }
14934
+ /** Where a found node is, in the terms an answer prints. */
14935
+ locate(node) {
14936
+ return {
14937
+ name: displayNameOf(node),
14938
+ file: this.displayPath(node.getSourceFile().getFilePath()),
14939
+ line: node.getStartLineNumber()
14940
+ };
14941
+ }
14942
+ sourceFileAt(file) {
14943
+ const absolute = import_node_path11.default.resolve(this.root, file);
14944
+ const loaded = this.project.getSourceFile(absolute);
14945
+ if (loaded !== void 0) {
14946
+ return loaded;
14947
+ }
14948
+ try {
14949
+ return this.project.addSourceFileAtPath(absolute);
14950
+ } catch {
14951
+ return null;
14952
+ }
14953
+ }
14954
+ /** A module key: a file path said relative to the root, or a package name. */
14955
+ displayPath(key) {
14956
+ if (key.startsWith(this.root)) {
14957
+ return import_node_path11.default.relative(this.root, key);
14958
+ }
14959
+ return key;
14960
+ }
14961
+ };
14962
+ function displayNameOf(node) {
14963
+ if (import_ts_morph59.Node.isIdentifier(node) || import_ts_morph59.Node.isPropertyAccessExpression(node)) {
14964
+ return node.getText();
14965
+ }
14966
+ if (import_ts_morph59.Node.isCallExpression(node) || import_ts_morph59.Node.isNewExpression(node)) {
14967
+ return `${node.getExpression()?.getText() ?? "call"}(...)`;
14968
+ }
14969
+ if (import_ts_morph59.Node.isFunctionDeclaration(node) || import_ts_morph59.Node.isClassDeclaration(node) || import_ts_morph59.Node.isMethodDeclaration(node) || import_ts_morph59.Node.isVariableDeclaration(node)) {
14970
+ const name = node.getName();
14971
+ if (name !== void 0) {
14972
+ return name;
14973
+ }
14974
+ }
14975
+ if (import_ts_morph59.Node.isArrowFunction(node) || import_ts_morph59.Node.isFunctionExpression(node)) {
14976
+ const parent = node.getParent();
14977
+ if (parent !== void 0 && import_ts_morph59.Node.isVariableDeclaration(parent)) {
14978
+ return parent.getName();
14979
+ }
14980
+ }
14981
+ const text = node.getText().split("\n")[0].trim();
14982
+ return text.length > 40 ? `${text.slice(0, 40)}...` : text;
14983
+ }
14984
+
14433
14985
  // src/packHealth.ts
14434
14986
  function stagesOf(funnel) {
14435
14987
  const stages = [];
14436
14988
  const gateSaysSomething = funnel.gates.length > 0 && funnel.unresolvedGates.length === 0;
14989
+ if (funnel.recognizes && !funnel.discovers && gateSaysSomething) {
14990
+ stages.push({
14991
+ from: {
14992
+ name: "unit bodies to look inside",
14993
+ count: funnel.unitsInGatedFiles
14994
+ },
14995
+ to: { name: "effects recognized", count: funnel.effectsRecognized },
14996
+ meaning: "its import gate found the library and it matched nothing in the bodies it saw"
14997
+ });
14998
+ }
14437
14999
  if (funnel.discovers && gateSaysSomething) {
14438
15000
  stages.push({
14439
15001
  from: { name: "candidate files", count: funnel.candidateFiles },
@@ -14543,7 +15105,7 @@ function formatPackHealth(checks, audiences) {
14543
15105
  }
14544
15106
 
14545
15107
  // src/resolve/readName.ts
14546
- var import_ts_morph59 = require("ts-morph");
15108
+ var import_ts_morph60 = require("ts-morph");
14547
15109
  var import_behavioral_ir7 = require("@suss/behavioral-ir");
14548
15110
  var MAX_HELPER_HOPS = 2;
14549
15111
  var UNNAMED_HOLE = "param";
@@ -14578,11 +15140,11 @@ function referenceIn(expr) {
14578
15140
  function parameterPath(expr) {
14579
15141
  const fields = [];
14580
15142
  let step = expr;
14581
- while (import_ts_morph59.Node.isPropertyAccessExpression(step)) {
15143
+ while (import_ts_morph60.Node.isPropertyAccessExpression(step)) {
14582
15144
  fields.unshift(step.getName());
14583
15145
  step = step.getExpression();
14584
15146
  }
14585
- if (!import_ts_morph59.Node.isIdentifier(step) || !isParameter(step)) {
15147
+ if (!import_ts_morph60.Node.isIdentifier(step) || !isParameter(step)) {
14586
15148
  return null;
14587
15149
  }
14588
15150
  return { root: step.getText(), fields };
@@ -14590,7 +15152,7 @@ function parameterPath(expr) {
14590
15152
  function isParameter(identifier) {
14591
15153
  const declarations = identifier.getSymbol()?.getDeclarations() ?? [];
14592
15154
  return declarations.some(
14593
- (declaration) => import_ts_morph59.Node.isParameterDeclaration(declaration)
15155
+ (declaration) => import_ts_morph60.Node.isParameterDeclaration(declaration)
14594
15156
  );
14595
15157
  }
14596
15158
  function read(expr, ctx) {
@@ -14599,35 +15161,52 @@ function read(expr, ctx) {
14599
15161
  }
14600
15162
  const seen = new Set(ctx.seen).add(expr);
14601
15163
  const inner = { ...ctx, seen };
14602
- if (import_ts_morph59.Node.isStringLiteral(expr) || import_ts_morph59.Node.isNoSubstitutionTemplateLiteral(expr)) {
15164
+ if (import_ts_morph60.Node.isStringLiteral(expr) || import_ts_morph60.Node.isNoSubstitutionTemplateLiteral(expr)) {
14603
15165
  return expr.getLiteralValue();
14604
15166
  }
14605
- if (import_ts_morph59.Node.isNumericLiteral(expr)) {
15167
+ if (import_ts_morph60.Node.isNumericLiteral(expr)) {
14606
15168
  return expr.getLiteralText();
14607
15169
  }
14608
- if (import_ts_morph59.Node.isTemplateExpression(expr)) {
15170
+ if (import_ts_morph60.Node.isTemplateExpression(expr)) {
14609
15171
  return fromTemplate(expr, inner);
14610
15172
  }
14611
- if (import_ts_morph59.Node.isParenthesizedExpression(expr)) {
15173
+ if (import_ts_morph60.Node.isParenthesizedExpression(expr)) {
14612
15174
  return read(expr.getExpression(), inner);
14613
15175
  }
14614
- if (import_ts_morph59.Node.isBinaryExpression(expr)) {
15176
+ if (import_ts_morph60.Node.isBinaryExpression(expr)) {
14615
15177
  return fromBinary(expr, inner);
14616
15178
  }
14617
- if (import_ts_morph59.Node.isCallExpression(expr)) {
15179
+ if (import_ts_morph60.Node.isCallExpression(expr)) {
14618
15180
  return fromCall(expr, inner);
14619
15181
  }
14620
- if (import_ts_morph59.Node.isIdentifier(expr)) {
15182
+ if (import_ts_morph60.Node.isIdentifier(expr)) {
14621
15183
  const only = boundOnce(expr, ctx);
14622
15184
  if (only !== null) {
14623
15185
  return read(only.node, { ...inner, bindings: only.scope });
14624
15186
  }
14625
15187
  }
14626
15188
  const written = ctx.resolve(expr);
14627
- return written === null || written === expr ? null : read(written, inner);
15189
+ if (written === null || written === expr) {
15190
+ return null;
15191
+ }
15192
+ if (ctx.insideHole && isFallbackBranch(written)) {
15193
+ return null;
15194
+ }
15195
+ return read(written, inner);
15196
+ }
15197
+ function isFallbackBranch(node) {
15198
+ let step = node.getParent();
15199
+ while (step !== void 0 && import_ts_morph60.Node.isParenthesizedExpression(step)) {
15200
+ step = step.getParent();
15201
+ }
15202
+ if (step === void 0 || !import_ts_morph60.Node.isBinaryExpression(step)) {
15203
+ return false;
15204
+ }
15205
+ const operator = step.getOperatorToken().getKind();
15206
+ return operator === import_ts_morph60.SyntaxKind.BarBarToken || operator === import_ts_morph60.SyntaxKind.QuestionQuestionToken;
14628
15207
  }
14629
15208
  function fromTemplate(expr, ctx) {
14630
- if (!import_ts_morph59.Node.isTemplateExpression(expr)) {
15209
+ if (!import_ts_morph60.Node.isTemplateExpression(expr)) {
14631
15210
  return null;
14632
15211
  }
14633
15212
  let name = expr.getHead().getLiteralText();
@@ -14638,28 +15217,28 @@ function fromTemplate(expr, ctx) {
14638
15217
  return name;
14639
15218
  }
14640
15219
  function fromBinary(expr, ctx) {
14641
- if (!import_ts_morph59.Node.isBinaryExpression(expr)) {
15220
+ if (!import_ts_morph60.Node.isBinaryExpression(expr)) {
14642
15221
  return null;
14643
15222
  }
14644
15223
  const operator = expr.getOperatorToken().getKind();
14645
- if (operator === import_ts_morph59.SyntaxKind.BarBarToken || operator === import_ts_morph59.SyntaxKind.QuestionQuestionToken) {
15224
+ if (operator === import_ts_morph60.SyntaxKind.BarBarToken || operator === import_ts_morph60.SyntaxKind.QuestionQuestionToken) {
14646
15225
  return ctx.insideHole ? null : read(expr.getRight(), ctx);
14647
15226
  }
14648
- if (operator !== import_ts_morph59.SyntaxKind.PlusToken) {
15227
+ if (operator !== import_ts_morph60.SyntaxKind.PlusToken) {
14649
15228
  return null;
14650
15229
  }
14651
15230
  const parts = { ...ctx, insideHole: true };
14652
15231
  return readOrHole(expr.getLeft(), parts) + readOrHole(expr.getRight(), parts);
14653
15232
  }
14654
15233
  function fromCall(expr, ctx) {
14655
- if (!import_ts_morph59.Node.isCallExpression(expr)) {
15234
+ if (!import_ts_morph60.Node.isCallExpression(expr)) {
14656
15235
  return null;
14657
15236
  }
14658
15237
  const callee = expr.getExpression();
14659
- if (import_ts_morph59.Node.isPropertyAccessExpression(callee) && callee.getName() === "join") {
15238
+ if (import_ts_morph60.Node.isPropertyAccessExpression(callee) && callee.getName() === "join") {
14660
15239
  return fromJoin(callee.getExpression(), expr.getArguments(), ctx);
14661
15240
  }
14662
- if (import_ts_morph59.Node.isIdentifier(callee) && callee.getText() === "String") {
15241
+ if (import_ts_morph60.Node.isIdentifier(callee) && callee.getText() === "String") {
14663
15242
  const only = expr.getArguments()[0];
14664
15243
  return only === void 0 ? null : readOrHole(only, ctx);
14665
15244
  }
@@ -14678,7 +15257,7 @@ function fromCall(expr, ctx) {
14678
15257
  }
14679
15258
  function fromJoin(subject, args, ctx) {
14680
15259
  const separator = args[0];
14681
- if (separator === void 0 || !import_ts_morph59.Node.isStringLiteral(separator)) {
15260
+ if (separator === void 0 || !import_ts_morph60.Node.isStringLiteral(separator)) {
14682
15261
  return null;
14683
15262
  }
14684
15263
  const parts = elementsOf(subject, ctx);
@@ -14694,17 +15273,17 @@ function fromJoin(subject, args, ctx) {
14694
15273
  ).join(separator.getLiteralValue());
14695
15274
  }
14696
15275
  function elementsOf(subject, ctx) {
14697
- if (import_ts_morph59.Node.isArrayLiteralExpression(subject)) {
15276
+ if (import_ts_morph60.Node.isArrayLiteralExpression(subject)) {
14698
15277
  return subject.getElements().map((element) => here(element, ctx));
14699
15278
  }
14700
- if (import_ts_morph59.Node.isCallExpression(subject)) {
15279
+ if (import_ts_morph60.Node.isCallExpression(subject)) {
14701
15280
  const callee = subject.getExpression();
14702
- if (import_ts_morph59.Node.isPropertyAccessExpression(callee) && callee.getName() === "map") {
15281
+ if (import_ts_morph60.Node.isPropertyAccessExpression(callee) && callee.getName() === "map") {
14703
15282
  return elementsOf(callee.getExpression(), ctx);
14704
15283
  }
14705
15284
  return null;
14706
15285
  }
14707
- if (!import_ts_morph59.Node.isIdentifier(subject)) {
15286
+ if (!import_ts_morph60.Node.isIdentifier(subject)) {
14708
15287
  return null;
14709
15288
  }
14710
15289
  const bound = ctx.bindings.get(subject.getText());
@@ -14712,7 +15291,7 @@ function elementsOf(subject, ctx) {
14712
15291
  return null;
14713
15292
  }
14714
15293
  const only = bound.length === 1 ? bound[0] : void 0;
14715
- return only !== void 0 && import_ts_morph59.Node.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
15294
+ return only !== void 0 && import_ts_morph60.Node.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
14716
15295
  }
14717
15296
  function singleReturnBody(callee, ctx) {
14718
15297
  const declaration = declarationOf2(callee, ctx);
@@ -14727,22 +15306,22 @@ function singleReturnBody(callee, ctx) {
14727
15306
  if (body === void 0) {
14728
15307
  return null;
14729
15308
  }
14730
- if (import_ts_morph59.Node.isExpression(body)) {
15309
+ if (import_ts_morph60.Node.isExpression(body)) {
14731
15310
  return { parameters, returned: body };
14732
15311
  }
14733
- if (!import_ts_morph59.Node.isBlock(body)) {
15312
+ if (!import_ts_morph60.Node.isBlock(body)) {
14734
15313
  return null;
14735
15314
  }
14736
15315
  const statements = body.getStatements();
14737
15316
  const only = statements[0];
14738
- if (statements.length !== 1 || only === void 0 || !import_ts_morph59.Node.isReturnStatement(only)) {
15317
+ if (statements.length !== 1 || only === void 0 || !import_ts_morph60.Node.isReturnStatement(only)) {
14739
15318
  return null;
14740
15319
  }
14741
15320
  const returned = only.getExpression();
14742
15321
  return returned === void 0 ? null : { parameters, returned };
14743
15322
  }
14744
15323
  function declarationOf2(callee, ctx) {
14745
- const symbol = import_ts_morph59.Node.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
15324
+ const symbol = import_ts_morph60.Node.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
14746
15325
  const declarations = symbol?.getAliasedSymbol()?.getDeclarations() ?? symbol?.getDeclarations() ?? [];
14747
15326
  for (const declaration of declarations) {
14748
15327
  const callable = asCallable(declaration);
@@ -14754,14 +15333,14 @@ function declarationOf2(callee, ctx) {
14754
15333
  return written === null || written === callee ? null : declarationOf2(written, { ...ctx, resolve: () => null });
14755
15334
  }
14756
15335
  function asCallable(declaration) {
14757
- 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)) {
15336
+ if (import_ts_morph60.Node.isFunctionDeclaration(declaration) || import_ts_morph60.Node.isMethodDeclaration(declaration) || import_ts_morph60.Node.isArrowFunction(declaration) || import_ts_morph60.Node.isFunctionExpression(declaration)) {
14758
15337
  return declaration;
14759
15338
  }
14760
- if (!import_ts_morph59.Node.isVariableDeclaration(declaration)) {
15339
+ if (!import_ts_morph60.Node.isVariableDeclaration(declaration)) {
14761
15340
  return null;
14762
15341
  }
14763
15342
  const initializer = declaration.getInitializer();
14764
- if (initializer !== void 0 && (import_ts_morph59.Node.isArrowFunction(initializer) || import_ts_morph59.Node.isFunctionExpression(initializer))) {
15343
+ if (initializer !== void 0 && (import_ts_morph60.Node.isArrowFunction(initializer) || import_ts_morph60.Node.isFunctionExpression(initializer))) {
14765
15344
  return initializer;
14766
15345
  }
14767
15346
  return null;
@@ -14783,7 +15362,7 @@ function here(node, ctx) {
14783
15362
  return { node, scope: ctx.bindings };
14784
15363
  }
14785
15364
  function boundOnce(expr, ctx) {
14786
- const bound = import_ts_morph59.Node.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
15365
+ const bound = import_ts_morph60.Node.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
14787
15366
  return bound !== void 0 && bound.length === 1 ? bound[0] : null;
14788
15367
  }
14789
15368
  function readOrHole(expr, ctx) {
@@ -14795,10 +15374,10 @@ function holeName(expr, ctx) {
14795
15374
  if (bound !== null) {
14796
15375
  return holeName(bound.node, { ...ctx, bindings: bound.scope });
14797
15376
  }
14798
- if (import_ts_morph59.Node.isIdentifier(expr)) {
15377
+ if (import_ts_morph60.Node.isIdentifier(expr)) {
14799
15378
  return expr.getText();
14800
15379
  }
14801
- if (import_ts_morph59.Node.isPropertyAccessExpression(expr)) {
15380
+ if (import_ts_morph60.Node.isPropertyAccessExpression(expr)) {
14802
15381
  return expr.getName();
14803
15382
  }
14804
15383
  return UNNAMED_HOLE;
@@ -14807,6 +15386,7 @@ function holeName(expr, ctx) {
14807
15386
  0 && (module.exports = {
14808
15387
  ADAPTER_VERSION,
14809
15388
  ResolutionStore,
15389
+ WhySession,
14810
15390
  collectAncestorBranches,
14811
15391
  collectClientFieldAccesses,
14812
15392
  computeAdapterPacksDigest,
@@ -14832,5 +15412,6 @@ function holeName(expr, ctx) {
14832
15412
  readName,
14833
15413
  resolveAliasedSymbol,
14834
15414
  resolveSubject,
14835
- rootIdentifier
15415
+ rootIdentifier,
15416
+ workspaceRootFor
14836
15417
  });