@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.js CHANGED
@@ -1608,7 +1608,7 @@ var ModuleGraph = class {
1608
1608
  return created;
1609
1609
  }
1610
1610
  assert(relation, tuple) {
1611
- if (this.db.add(relation, tuple)) {
1611
+ if (this.db.add(relation, tuple) === "added") {
1612
1612
  this.stale = true;
1613
1613
  }
1614
1614
  }
@@ -1825,8 +1825,8 @@ function loadImportGraphsDepthFirstFromPaths(project, rootPaths) {
1825
1825
  stack.pop();
1826
1826
  loadOrder.push(top.path);
1827
1827
  let deepest = 0;
1828
- for (const path11 of top.deps) {
1829
- deepest = Math.max(deepest, chainDepth.get(path11) ?? 0);
1828
+ for (const path12 of top.deps) {
1829
+ deepest = Math.max(deepest, chainDepth.get(path12) ?? 0);
1830
1830
  }
1831
1831
  chainDepth.set(top.path, deepest + 1);
1832
1832
  }
@@ -2171,11 +2171,11 @@ function walkAndWarm(root, reach) {
2171
2171
  if (warmedFiles.get(target) !== void 0) {
2172
2172
  continue;
2173
2173
  }
2174
- const path11 = target.getFilePath();
2175
- if (visited.has(path11)) {
2174
+ const path12 = target.getFilePath();
2175
+ if (visited.has(path12)) {
2176
2176
  continue;
2177
2177
  }
2178
- visited.add(path11);
2178
+ visited.add(path12);
2179
2179
  stack.push(frameOf(target, reach));
2180
2180
  continue;
2181
2181
  }
@@ -2192,7 +2192,7 @@ function sitsOnWarmChains(file) {
2192
2192
  return false;
2193
2193
  }
2194
2194
  const imported = importedFilePathsOf(project, file.getFilePath());
2195
- return imported.length > 0 && imported.every((path11) => warmed.has(path11));
2195
+ return imported.length > 0 && imported.every((path12) => warmed.has(path12));
2196
2196
  }
2197
2197
  function markWarmed(file) {
2198
2198
  warmedFiles.set(file, true);
@@ -2325,14 +2325,38 @@ function isImportedFrom(identifier, expectedModule) {
2325
2325
  (decl) => decl.getSourceFile().getFilePath().includes(`/node_modules/${expectedModule}/`)
2326
2326
  );
2327
2327
  }
2328
- function methodDeclaredIn(callee, expectedModule) {
2328
+ function methodDeclaredIn(callee, expectedModule, resolve2) {
2329
2329
  if (!Node11.isPropertyAccessExpression(callee)) {
2330
2330
  return false;
2331
2331
  }
2332
2332
  const declarations = callee.getNameNode().getSymbol()?.getDeclarations();
2333
- return declarations !== void 0 && declarations.some(
2333
+ if (declarations !== void 0 && declarations.some(
2334
2334
  (declaration) => declaration.getSourceFile().getFilePath().includes(`/node_modules/${expectedModule}/`)
2335
- );
2335
+ )) {
2336
+ return true;
2337
+ }
2338
+ if (resolve2 === void 0) {
2339
+ return false;
2340
+ }
2341
+ const written = resolve2(callee.getExpression());
2342
+ const made = maker(written);
2343
+ return made !== null && isImportedFrom(rootIdentifier(made), expectedModule);
2344
+ }
2345
+ function maker(written) {
2346
+ if (written === null) {
2347
+ return null;
2348
+ }
2349
+ if (Node11.isNewExpression(written) || Node11.isCallExpression(written)) {
2350
+ return written.getExpression();
2351
+ }
2352
+ return null;
2353
+ }
2354
+ function rootIdentifier(expression) {
2355
+ let root = expression;
2356
+ while (Node11.isPropertyAccessExpression(root)) {
2357
+ root = root.getExpression();
2358
+ }
2359
+ return root;
2336
2360
  }
2337
2361
  function importSpecifierMatches(decl, expectedModule) {
2338
2362
  if (Node11.isImportSpecifier(decl)) {
@@ -2412,6 +2436,26 @@ function extractInvocationEffects(func, barriers = NO_BARRIERS) {
2412
2436
  }
2413
2437
  return;
2414
2438
  }
2439
+ if (Node11.isReturnStatement(node)) {
2440
+ const returned = node.getExpression();
2441
+ const { call, async } = returned === void 0 ? { call: null, async: false } : unwrapCall(returned);
2442
+ if (call !== null) {
2443
+ const preconditions = collectPreconditions(node, func);
2444
+ results.push({
2445
+ effect: {
2446
+ type: "invocation",
2447
+ callee: call.getExpression().getText(),
2448
+ args: extractArgs(call),
2449
+ async,
2450
+ ...preconditions.length > 0 ? { preconditions } : {}
2451
+ },
2452
+ line: startLineOf(node),
2453
+ neverTerminal: false,
2454
+ node: call
2455
+ });
2456
+ }
2457
+ return;
2458
+ }
2415
2459
  if (Node11.isCallExpression(node)) {
2416
2460
  const parent = node.getParent();
2417
2461
  if (parent === void 0) {
@@ -5080,7 +5124,10 @@ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [],
5080
5124
  const terminalLines = new Set(
5081
5125
  distinctBranches.map((b) => b.terminal.location.start)
5082
5126
  );
5083
- defaultBranch.effects = invocations.filter((i) => i.neverTerminal || !terminalLines.has(i.line)).map((i) => i.effect);
5127
+ const terminalNodes = new Set(terminals.map(({ node }) => node));
5128
+ defaultBranch.effects = invocations.filter(
5129
+ (i) => i.node !== void 0 ? !terminalNodes.has(i.node) : i.neverTerminal || !terminalLines.has(i.line)
5130
+ ).map((i) => i.effect);
5084
5131
  }
5085
5132
  }
5086
5133
  if (recognized.length > 0) {
@@ -5125,9 +5172,9 @@ function createSourceFileLookup(project) {
5125
5172
  if (sf === null) {
5126
5173
  return null;
5127
5174
  }
5128
- const path11 = sf.getFilePath();
5129
- const index = functionsByFile.get(path11) ?? indexFunctions(sf);
5130
- functionsByFile.set(path11, index);
5175
+ const path12 = sf.getFilePath();
5176
+ const index = functionsByFile.get(path12) ?? indexFunctions(sf);
5177
+ functionsByFile.set(path12, index);
5131
5178
  return index.get(rangeKey(location.range)) ?? null;
5132
5179
  }
5133
5180
  };
@@ -5205,7 +5252,6 @@ function createCacheLayer(cacheDir) {
5205
5252
  return {
5206
5253
  kind: "hit",
5207
5254
  summaries: manifest.summaries,
5208
- ...manifest.projectRoot === void 0 ? {} : { projectRoot: manifest.projectRoot },
5209
5255
  diagnostic: { kind: "hit" }
5210
5256
  };
5211
5257
  },
@@ -5319,7 +5365,6 @@ async function buildPlan(manifest, currentStamps) {
5319
5365
  roots,
5320
5366
  validRoots,
5321
5367
  rootsDeclined,
5322
- storedProjectRoot: manifest.projectRoot ?? null,
5323
5368
  reuse(valid) {
5324
5369
  const summaries = [];
5325
5370
  const reusedOwners = [];
@@ -5346,8 +5391,7 @@ async function buildPlan(manifest, currentStamps) {
5346
5391
  const p = rootNames[o];
5347
5392
  return p === void 0 ? [] : [p];
5348
5393
  })
5349
- ),
5350
- ...manifest.projectRoot === void 0 ? {} : { projectRoot: manifest.projectRoot }
5394
+ )
5351
5395
  };
5352
5396
  }
5353
5397
  };
@@ -5380,13 +5424,7 @@ function encodeAttribution(attribution) {
5380
5424
  return i === void 0 ? [] : [i];
5381
5425
  })
5382
5426
  );
5383
- return {
5384
- roots,
5385
- rootMeta,
5386
- depPaths,
5387
- owners,
5388
- ...attribution.projectRoot === void 0 ? {} : { projectRoot: attribution.projectRoot }
5389
- };
5427
+ return { roots, rootMeta, depPaths, owners };
5390
5428
  }
5391
5429
  async function hashStamps(stamps, previous) {
5392
5430
  const before = new Map((previous?.files ?? []).map((f) => [f.path, f]));
@@ -5663,7 +5701,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
5663
5701
  }
5664
5702
  const responses = [];
5665
5703
  let method;
5666
- let path11;
5704
+ let path12;
5667
5705
  for (const prop of endpointNode.getProperties()) {
5668
5706
  if (!Node24.isPropertyAssignment(prop)) {
5669
5707
  continue;
@@ -5678,7 +5716,7 @@ function extractEndpointContract(endpointNode, pattern, framework) {
5678
5716
  if (propName === pattern.pathProperty) {
5679
5717
  const val = prop.getInitializer();
5680
5718
  if (val !== void 0 && Node24.isStringLiteral(val)) {
5681
- path11 = val.getLiteralValue();
5719
+ path12 = val.getLiteralValue();
5682
5720
  }
5683
5721
  }
5684
5722
  if (propName === pattern.responseExtraction.property) {
@@ -5702,10 +5740,10 @@ function extractEndpointContract(endpointNode, pattern, framework) {
5702
5740
  if (responses.length === 0) {
5703
5741
  return null;
5704
5742
  }
5705
- const boundaryBinding = method !== void 0 || path11 !== void 0 ? restBinding({
5743
+ const boundaryBinding = method !== void 0 || path12 !== void 0 ? restBinding({
5706
5744
  transport: "http",
5707
5745
  method: method ?? null,
5708
- path: path11 ?? null,
5746
+ path: path12 ?? null,
5709
5747
  recognition: framework
5710
5748
  }) : null;
5711
5749
  return {
@@ -6296,6 +6334,13 @@ function literalIndexOf(index) {
6296
6334
  }
6297
6335
  return null;
6298
6336
  }
6337
+ function asFallbackExpression(expression) {
6338
+ if (!Node26.isBinaryExpression(expression)) {
6339
+ return null;
6340
+ }
6341
+ const operator = expression.getOperatorToken().getKind();
6342
+ return operator === SyntaxKind6.BarBarToken || operator === SyntaxKind6.QuestionQuestionToken ? expression : null;
6343
+ }
6299
6344
  function unwrapExpression(expression) {
6300
6345
  let current2 = expression;
6301
6346
  for (; ; ) {
@@ -6407,6 +6452,12 @@ function emitValue(db, table, value) {
6407
6452
  }
6408
6453
  return id;
6409
6454
  }
6455
+ const fallback = asFallbackExpression(expression);
6456
+ if (fallback !== null) {
6457
+ fact(db, "fallbackBranch", id, emitValue(db, table, fallback.getLeft()));
6458
+ fact(db, "fallbackBranch", id, emitValue(db, table, fallback.getRight()));
6459
+ return id;
6460
+ }
6410
6461
  if (Node26.isCallExpression(expression) || Node26.isNewExpression(expression)) {
6411
6462
  emitCallFacts(db, table, expression);
6412
6463
  fact(db, "writtenValue", id);
@@ -6871,24 +6922,27 @@ function stampGraphqlClientRefs(summaries, sourceFiles, packs, resolution) {
6871
6922
  const sole = soleGraphqlClientRef(
6872
6923
  collectGraphqlClientRefs(sourceFiles, packs, resolution)
6873
6924
  );
6874
- if (sole === null && scopes.length === 0) {
6875
- return;
6876
- }
6877
6925
  const workspace = sole !== null ? boundWorkspaceFor(sole, packs) : null;
6878
6926
  const soleClient = sole !== null ? workspace !== null ? { ...sole, workspace } : sole : null;
6927
+ let registry = null;
6879
6928
  for (const summary of summaries) {
6880
6929
  if (!isGraphqlOperationBinding(summary.identity.boundaryBinding)) {
6881
6930
  continue;
6882
6931
  }
6932
+ const existing = readGraphqlMetadata(summary) ?? {};
6883
6933
  const scoped = scopedWorkspaceFor(summary.location.file, scopes);
6884
6934
  const client = scoped !== null ? { uri: null, uriRef: null, workspace: scoped } : soleClient;
6885
- if (client === null) {
6935
+ const dangling = (existing.unresolvedFragments?.length ?? 0) > 0;
6936
+ if (client === null && !dangling) {
6886
6937
  continue;
6887
6938
  }
6888
- const existing = readGraphqlMetadata(summary) ?? {};
6939
+ if (dangling && registry === null) {
6940
+ registry = fragmentRegistryStatus(sourceFiles, packs);
6941
+ }
6889
6942
  summary.metadata = withGraphqlMetadata(summary.metadata, {
6890
6943
  ...existing,
6891
- client
6944
+ ...client !== null ? { client } : {},
6945
+ ...dangling && registry !== null ? { fragmentRegistry: registry } : {}
6892
6946
  });
6893
6947
  }
6894
6948
  }
@@ -6954,6 +7008,156 @@ function soleGraphqlClientRef(refs) {
6954
7008
  }
6955
7009
  return [...distinct.values()][0] ?? null;
6956
7010
  }
7011
+ function fragmentRegistryStatus(sourceFiles, packs) {
7012
+ const statuses = [];
7013
+ for (const spec of packs.flatMap((pack) => pack.graphqlClients ?? [])) {
7014
+ const registrySpec = spec.fragmentRegistry;
7015
+ if (registrySpec === void 0) {
7016
+ continue;
7017
+ }
7018
+ for (const sourceFile of sourceFiles) {
7019
+ const local = localImportName(
7020
+ sourceFile,
7021
+ spec.importModule,
7022
+ spec.importName
7023
+ );
7024
+ if (local === null) {
7025
+ continue;
7026
+ }
7027
+ sourceFile.forEachDescendant((node) => {
7028
+ if (isConstructionNamed(node, local)) {
7029
+ statuses.push(constructionRegistryStatus(node, registrySpec));
7030
+ }
7031
+ });
7032
+ }
7033
+ }
7034
+ return combineRegistryStatuses(statuses);
7035
+ }
7036
+ function combineRegistryStatuses(statuses) {
7037
+ if (statuses.includes("configured")) {
7038
+ return "configured";
7039
+ }
7040
+ if (statuses.length === 0 || statuses.includes("unknown")) {
7041
+ return "unknown";
7042
+ }
7043
+ return "absent";
7044
+ }
7045
+ function constructionRegistryStatus(construction, spec) {
7046
+ const options = firstArgumentObjectLiteral(construction);
7047
+ if (options === null) {
7048
+ return "unknown";
7049
+ }
7050
+ const cacheExpr = propertyValueOf2(options, spec.cacheProperty);
7051
+ if (cacheExpr === null) {
7052
+ return "unknown";
7053
+ }
7054
+ const cacheConstruction = resolveToConstructionOf(
7055
+ cacheExpr,
7056
+ spec.cacheConstructor
7057
+ );
7058
+ if (cacheConstruction === null) {
7059
+ return "unknown";
7060
+ }
7061
+ if (!Node28.isNewExpression(cacheConstruction) && !Node28.isCallExpression(cacheConstruction)) {
7062
+ return "unknown";
7063
+ }
7064
+ const args = cacheConstruction.getArguments();
7065
+ if (args.length === 0) {
7066
+ return "absent";
7067
+ }
7068
+ const cacheOptions = firstArgumentObjectLiteral(cacheConstruction);
7069
+ if (cacheOptions === null) {
7070
+ return "unknown";
7071
+ }
7072
+ if (cacheOptions.getProperty(spec.registryProperty) !== void 0) {
7073
+ return "configured";
7074
+ }
7075
+ const hasSpread = cacheOptions.getProperties().some((property) => Node28.isSpreadAssignment(property));
7076
+ return hasSpread ? "unknown" : "absent";
7077
+ }
7078
+ function firstArgumentObjectLiteral(construction) {
7079
+ if (!Node28.isNewExpression(construction) && !Node28.isCallExpression(construction)) {
7080
+ return null;
7081
+ }
7082
+ const arg = construction.getArguments()[0];
7083
+ if (arg === void 0 || !Node28.isObjectLiteralExpression(arg)) {
7084
+ return null;
7085
+ }
7086
+ return arg;
7087
+ }
7088
+ function propertyValueOf2(options, name) {
7089
+ const property = options.getProperty(name);
7090
+ if (property === void 0) {
7091
+ return null;
7092
+ }
7093
+ if (Node28.isPropertyAssignment(property)) {
7094
+ return property.getInitializer() ?? null;
7095
+ }
7096
+ if (Node28.isShorthandPropertyAssignment(property)) {
7097
+ const symbol = property.getProject().getTypeChecker().getShorthandAssignmentValueSymbol(property);
7098
+ return symbol?.getValueDeclaration() ?? null;
7099
+ }
7100
+ return null;
7101
+ }
7102
+ function resolveToConstructionOf(expression, cacheClass) {
7103
+ let current2 = expression;
7104
+ for (let hop = 0; hop < 4 && current2 !== void 0; hop += 1) {
7105
+ current2 = unwrapExpression2(current2);
7106
+ if (Node28.isVariableDeclaration(current2)) {
7107
+ current2 = current2.getInitializer();
7108
+ continue;
7109
+ }
7110
+ if (Node28.isNewExpression(current2) || Node28.isCallExpression(current2)) {
7111
+ const callee = current2.getExpression();
7112
+ if (callee === void 0 || !Node28.isIdentifier(callee)) {
7113
+ return null;
7114
+ }
7115
+ const local = localImportName(
7116
+ current2.getSourceFile(),
7117
+ cacheClass.importModule,
7118
+ cacheClass.importName
7119
+ );
7120
+ return local !== null && callee.getText() === local ? current2 : null;
7121
+ }
7122
+ if (!Node28.isIdentifier(current2)) {
7123
+ return null;
7124
+ }
7125
+ const declaration = current2.getSymbol()?.getValueDeclaration();
7126
+ if (declaration === void 0 || !Node28.isVariableDeclaration(declaration)) {
7127
+ return null;
7128
+ }
7129
+ current2 = declaration.getInitializer();
7130
+ }
7131
+ return null;
7132
+ }
7133
+ function unwrapExpression2(node) {
7134
+ let current2 = node;
7135
+ while (Node28.isParenthesizedExpression(current2) || Node28.isAsExpression(current2) || Node28.isNonNullExpression(current2)) {
7136
+ current2 = current2.getExpression();
7137
+ }
7138
+ return current2;
7139
+ }
7140
+ function isConstructionNamed(node, localName) {
7141
+ if (!Node28.isNewExpression(node) && !Node28.isCallExpression(node)) {
7142
+ return false;
7143
+ }
7144
+ const callee = node.getExpression();
7145
+ return callee !== void 0 && Node28.isIdentifier(callee) && callee.getText() === localName;
7146
+ }
7147
+ function localImportName(sourceFile, importModule, importName) {
7148
+ for (const importDecl of sourceFile.getImportDeclarations()) {
7149
+ const module = importDecl.getModuleSpecifierValue();
7150
+ if (module !== importModule && !module.startsWith(`${importModule}/`)) {
7151
+ continue;
7152
+ }
7153
+ for (const named2 of importDecl.getNamedImports()) {
7154
+ if (named2.getName() === importName) {
7155
+ return named2.getAliasNode()?.getText() ?? named2.getName();
7156
+ }
7157
+ }
7158
+ }
7159
+ return null;
7160
+ }
6957
7161
  function localNamesFor(sourceFile, specs) {
6958
7162
  const names = /* @__PURE__ */ new Map();
6959
7163
  for (const importDecl of sourceFile.getImportDeclarations()) {
@@ -7701,32 +7905,163 @@ function innerTemplateText(template) {
7701
7905
  }
7702
7906
  return raw;
7703
7907
  }
7704
- function resolveGraphqlDocument(arg, resolution) {
7705
- const stripped = stripDocumentNodeCasts(arg);
7706
- const inline = documentTextFromExpression(stripped);
7908
+ function startAssembly(resolution) {
7909
+ return {
7910
+ resolution,
7911
+ seen: /* @__PURE__ */ new Set(),
7912
+ unresolvedInterpolations: [],
7913
+ unresolvedInsideSelection: false
7914
+ };
7915
+ }
7916
+ function assembledTemplateText(template, assembly) {
7917
+ if (Node35.isNoSubstitutionTemplateLiteral(template)) {
7918
+ return innerTemplateText(template);
7919
+ }
7920
+ if (!Node35.isTemplateExpression(template)) {
7921
+ return null;
7922
+ }
7923
+ let text = template.getHead().getLiteralText();
7924
+ for (const span of template.getTemplateSpans()) {
7925
+ const spliced = interpolatedDocumentText(span.getExpression(), assembly);
7926
+ if (spliced === null) {
7927
+ assembly.unresolvedInterpolations.push(
7928
+ singleLine(span.getExpression().getText())
7929
+ );
7930
+ if (openBraceDepth(text) > 0) {
7931
+ assembly.unresolvedInsideSelection = true;
7932
+ }
7933
+ } else {
7934
+ text += `
7935
+ ${spliced}
7936
+ `;
7937
+ }
7938
+ text += span.getLiteral().getLiteralText();
7939
+ }
7940
+ return text;
7941
+ }
7942
+ function openBraceDepth(text) {
7943
+ let depth = 0;
7944
+ for (const char of text) {
7945
+ if (char === "{") {
7946
+ depth += 1;
7947
+ } else if (char === "}") {
7948
+ depth -= 1;
7949
+ }
7950
+ }
7951
+ return depth;
7952
+ }
7953
+ function interpolatedDocumentText(expr, assembly) {
7954
+ const stripped = stripDocumentNodeCasts(expr);
7955
+ const inline = documentTextFromExpression(stripped, assembly);
7707
7956
  if (inline !== null) {
7708
- return { document: inline };
7957
+ return inline;
7709
7958
  }
7710
- const templateText = resolveGqlTemplateText(stripped);
7711
- if (templateText !== null) {
7712
- return { document: templateText };
7959
+ const named2 = resolveGqlTemplateText(stripped, assembly);
7960
+ if (named2 !== null) {
7961
+ return named2;
7713
7962
  }
7714
7963
  const objectDoc = resolveTypedDocumentSource(stripped);
7715
7964
  if (objectDoc !== null) {
7716
- return { document: objectDoc };
7965
+ return objectDoc;
7717
7966
  }
7718
- const throughFacts = resolveThroughFacts(stripped, resolution);
7719
- if (throughFacts !== null) {
7720
- return { document: throughFacts };
7967
+ return resolveThroughFacts(stripped, assembly);
7968
+ }
7969
+ function resolveGraphqlDocument(arg, resolution) {
7970
+ const assembly = startAssembly(resolution);
7971
+ const stripped = stripDocumentNodeCasts(arg);
7972
+ const text = documentTextFromExpression(stripped, assembly) ?? resolveGqlTemplateText(stripped, assembly) ?? resolveTypedDocumentSource(stripped) ?? resolveThroughFacts(stripped, assembly);
7973
+ if (text !== null) {
7974
+ return assembledDocumentResolution(text, stripped, assembly);
7721
7975
  }
7722
7976
  return resolveTypedDocumentHeader(stripped);
7723
7977
  }
7724
- function documentTextFromExpression(node) {
7978
+ function assembledDocumentResolution(text, arg, assembly) {
7979
+ const interpolations = assembly.unresolvedInterpolations;
7980
+ if (assembly.unresolvedInsideSelection) {
7981
+ const header = parseGraphqlOperation(text);
7982
+ return {
7983
+ ...header !== null ? { operationType: header.operationType } : {},
7984
+ ...header?.operationName !== void 0 ? { operationName: header.operationName } : {},
7985
+ unresolved: {
7986
+ reference: singleLine(arg.getText()),
7987
+ reason: `interpolated ${describeInterpolations(interpolations)} inside a selection set did not resolve to a GraphQL document, so what the operation selects is not statically written`
7988
+ }
7989
+ };
7990
+ }
7991
+ const dangling = danglingFragmentSpreads(text);
7992
+ if (dangling === null) {
7993
+ if (interpolations.length === 0) {
7994
+ return { document: text };
7995
+ }
7996
+ return {
7997
+ unresolved: {
7998
+ reference: singleLine(arg.getText()),
7999
+ reason: `the document did not parse after dropping interpolated ${describeInterpolations(interpolations)} that resolved to no GraphQL document`
8000
+ }
8001
+ };
8002
+ }
8003
+ if (dangling.length > 0) {
8004
+ return { document: text, unresolvedFragments: dangling };
8005
+ }
8006
+ if (interpolations.length > 0) {
8007
+ return {
8008
+ document: text,
8009
+ unresolved: {
8010
+ reference: singleLine(arg.getText()),
8011
+ reason: `interpolated ${describeInterpolations(interpolations)} did not resolve to a GraphQL document, so whatever it contributes is not part of the stored document`
8012
+ }
8013
+ };
8014
+ }
8015
+ return { document: text };
8016
+ }
8017
+ function describeInterpolations(interpolations) {
8018
+ const quoted = interpolations.map((text) => `\`${text}\``).join(", ");
8019
+ return interpolations.length === 1 ? `expression ${quoted}` : `expressions ${quoted}`;
8020
+ }
8021
+ function danglingFragmentSpreads(text) {
8022
+ let doc;
8023
+ try {
8024
+ doc = graphqlParse(text);
8025
+ } catch {
8026
+ return null;
8027
+ }
8028
+ const defined = /* @__PURE__ */ new Set();
8029
+ for (const def of doc.definitions) {
8030
+ if (def.kind === GraphqlKind.FRAGMENT_DEFINITION) {
8031
+ defined.add(def.name.value);
8032
+ }
8033
+ }
8034
+ const dangling = /* @__PURE__ */ new Set();
8035
+ for (const def of doc.definitions) {
8036
+ if (def.kind === GraphqlKind.OPERATION_DEFINITION || def.kind === GraphqlKind.FRAGMENT_DEFINITION) {
8037
+ collectDanglingSpreads(def.selectionSet, defined, dangling);
8038
+ }
8039
+ }
8040
+ return [...dangling].sort();
8041
+ }
8042
+ function collectDanglingSpreads(selectionSet, defined, dangling) {
8043
+ for (const selection of selectionSet.selections) {
8044
+ if (selection.kind === GraphqlKind.FRAGMENT_SPREAD) {
8045
+ if (!defined.has(selection.name.value)) {
8046
+ dangling.add(selection.name.value);
8047
+ }
8048
+ continue;
8049
+ }
8050
+ if (selection.selectionSet !== void 0) {
8051
+ collectDanglingSpreads(selection.selectionSet, defined, dangling);
8052
+ }
8053
+ }
8054
+ }
8055
+ function documentTextFromExpression(node, assembly) {
7725
8056
  if (Node35.isTaggedTemplateExpression(node)) {
7726
8057
  if (!isDocumentTag(node.getTag())) {
7727
8058
  return null;
7728
8059
  }
7729
- return innerTemplateText(node.getTemplate());
8060
+ if (assembly.seen.has(node)) {
8061
+ return "";
8062
+ }
8063
+ assembly.seen.add(node);
8064
+ return assembledTemplateText(node.getTemplate(), assembly);
7730
8065
  }
7731
8066
  if (!Node35.isCallExpression(node)) {
7732
8067
  return null;
@@ -7742,7 +8077,11 @@ function documentTextFromExpression(node) {
7742
8077
  if (!Node35.isNoSubstitutionTemplateLiteral(template) && !Node35.isTemplateExpression(template)) {
7743
8078
  return null;
7744
8079
  }
7745
- return innerTemplateText(template);
8080
+ if (assembly.seen.has(node)) {
8081
+ return "";
8082
+ }
8083
+ assembly.seen.add(node);
8084
+ return assembledTemplateText(template, assembly);
7746
8085
  }
7747
8086
  function isDocumentTag(tag) {
7748
8087
  if (!Node35.isIdentifier(tag)) {
@@ -7762,15 +8101,15 @@ function isDocumentTag(tag) {
7762
8101
  }
7763
8102
  return false;
7764
8103
  }
7765
- function resolveThroughFacts(arg, resolution) {
7766
- if (resolution === void 0 || !Node35.isIdentifier(arg)) {
8104
+ function resolveThroughFacts(arg, assembly) {
8105
+ if (assembly.resolution === void 0 || !Node35.isIdentifier(arg)) {
7767
8106
  return null;
7768
8107
  }
7769
- const written = resolution.resolveWrittenValue(arg);
8108
+ const written = assembly.resolution.resolveWrittenValue(arg);
7770
8109
  if (written === null) {
7771
8110
  return null;
7772
8111
  }
7773
- const text = documentTextFromExpression(written);
8112
+ const text = documentTextFromExpression(written, assembly);
7774
8113
  if (text !== null) {
7775
8114
  return text;
7776
8115
  }
@@ -7783,7 +8122,13 @@ function operationInfoFromResolution(resolution, callOperationType) {
7783
8122
  return null;
7784
8123
  }
7785
8124
  const operationType = operation.operationName !== void 0 ? operation.operationType : callOperationType;
7786
- return { ...operation, operationType, document: resolution.document };
8125
+ return {
8126
+ ...operation,
8127
+ operationType,
8128
+ document: resolution.document,
8129
+ ...resolution.unresolvedFragments !== void 0 ? { unresolvedFragments: resolution.unresolvedFragments } : {},
8130
+ ...resolution.unresolved !== void 0 ? { unresolved: resolution.unresolved } : {}
8131
+ };
7787
8132
  }
7788
8133
  return {
7789
8134
  operationType: resolution.operationType ?? callOperationType,
@@ -7825,8 +8170,8 @@ function importedVariableInitializers(identifier) {
7825
8170
  }
7826
8171
  return inits;
7827
8172
  }
7828
- function resolveGqlTemplateText(arg) {
7829
- const direct = documentTextFromExpression(arg);
8173
+ function resolveGqlTemplateText(arg, assembly) {
8174
+ const direct = documentTextFromExpression(arg, assembly);
7830
8175
  if (direct !== null) {
7831
8176
  return direct;
7832
8177
  }
@@ -7846,7 +8191,10 @@ function resolveGqlTemplateText(arg) {
7846
8191
  }
7847
8192
  }
7848
8193
  for (const init of importedVariableInitializers(arg)) {
7849
- const text = documentTextFromExpression(stripDocumentNodeCasts(init));
8194
+ const text = documentTextFromExpression(
8195
+ stripDocumentNodeCasts(init),
8196
+ assembly
8197
+ );
7850
8198
  if (text !== null) {
7851
8199
  return text;
7852
8200
  }
@@ -8434,14 +8782,14 @@ function unitForJsxRoute(node, match, routeNames, kind, resolution) {
8434
8782
  }
8435
8783
  return routeUnit(node, kind, match.method, resolved.path, target, resolution);
8436
8784
  }
8437
- function routeUnit(at, kind, method, path11, target, resolution) {
8438
- const routeInfo = { method, path: path11 };
8785
+ function routeUnit(at, kind, method, path12, target, resolution) {
8786
+ const routeInfo = { method, path: path12 };
8439
8787
  if (target.kind === "unreadable") {
8440
8788
  return {
8441
8789
  func: null,
8442
8790
  announcedAt: at,
8443
8791
  kind,
8444
- name: path11,
8792
+ name: path12,
8445
8793
  nameKind: "label",
8446
8794
  routeInfo
8447
8795
  };
@@ -9329,9 +9677,9 @@ function withMountPrefix(routeInfo, subjectNode, mountPrefixes) {
9329
9677
  const prefix = mountPrefixes.effectivePrefixFor(subjectNode);
9330
9678
  return prefix === "" ? routeInfo : { ...routeInfo, path: joinMountedPath(prefix, routeInfo.path) };
9331
9679
  }
9332
- function joinMountedPath(prefix, path11) {
9680
+ function joinMountedPath(prefix, path12) {
9333
9681
  const trimmed = prefix.endsWith("/") ? prefix.slice(0, -1) : prefix;
9334
- return trimmed === "" ? path11 : trimmed + path11;
9682
+ return trimmed === "" ? path12 : trimmed + path12;
9335
9683
  }
9336
9684
  function registrationSubjectsOf(sourceFile, importModule, importName) {
9337
9685
  let importedLocalName = null;
@@ -9495,11 +9843,11 @@ function extractRouteInfoFromBinding(call, methodName, binding, resolution) {
9495
9843
  return null;
9496
9844
  }
9497
9845
  const method2 = stringProperty(routeObject, binding.method.property);
9498
- const path11 = stringProperty(routeObject, binding.path.property);
9499
- if (method2 === null || path11 === null) {
9846
+ const path12 = stringProperty(routeObject, binding.path.property);
9847
+ if (method2 === null || path12 === null) {
9500
9848
  return null;
9501
9849
  }
9502
- return { method: method2.toUpperCase(), path: path11 };
9850
+ return { method: method2.toUpperCase(), path: path12 };
9503
9851
  }
9504
9852
  if (binding.method.type !== "fromRegistration" || binding.path.type !== "fromRegistration") {
9505
9853
  return null;
@@ -9606,7 +9954,7 @@ function bodyReferencesLoopVar(loop, name) {
9606
9954
  }
9607
9955
  function readRouteSpec(element, shape, resolution) {
9608
9956
  let method = null;
9609
- let path11 = null;
9957
+ let path12 = null;
9610
9958
  let handler = null;
9611
9959
  for (const prop of element.getProperties()) {
9612
9960
  if (Node44.isMethodDeclaration(prop) && prop.getName() === shape.handlerKey) {
@@ -9624,16 +9972,16 @@ function readRouteSpec(element, shape, resolution) {
9624
9972
  if (name === shape.methodKey) {
9625
9973
  method = readStringLiteralValue(init);
9626
9974
  } else if (name === shape.pathKey) {
9627
- path11 = readStringLiteralValue(init);
9975
+ path12 = readStringLiteralValue(init);
9628
9976
  } else if (name === shape.handlerKey) {
9629
9977
  const func = functionValueOf(init, resolution);
9630
9978
  handler = func === null ? null : { func, name: handlerName(init) };
9631
9979
  }
9632
9980
  }
9633
- if (method === null || path11 === null || handler === null) {
9981
+ if (method === null || path12 === null || handler === null) {
9634
9982
  return null;
9635
9983
  }
9636
- return { method, path: path11, handler: handler.func, handlerName: handler.name };
9984
+ return { method, path: path12, handler: handler.func, handlerName: handler.name };
9637
9985
  }
9638
9986
  function readStringLiteralValue(node) {
9639
9987
  if (Node44.isStringLiteral(node) || Node44.isNoSubstitutionTemplateLiteral(node)) {
@@ -9662,8 +10010,8 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
9662
10010
  }
9663
10011
  const args = node.getArguments();
9664
10012
  for (const reg of match.registrations) {
9665
- const path11 = substitutePath(reg.pathTemplate, args);
9666
- if (path11 === null) {
10013
+ const path12 = substitutePath(reg.pathTemplate, args);
10014
+ if (path12 === null) {
9667
10015
  continue;
9668
10016
  }
9669
10017
  const handler = resolveHandler(reg.handlerArg, args, resolution);
@@ -9676,7 +10024,7 @@ function discoverRegistrationTemplates(sourceFile, match, kind, resolution) {
9676
10024
  name: handler.name,
9677
10025
  routeInfo: {
9678
10026
  method: reg.method.toUpperCase(),
9679
- path: path11
10027
+ path: path12
9680
10028
  }
9681
10029
  });
9682
10030
  }
@@ -10362,10 +10710,12 @@ import {
10362
10710
  deriveOnDemand,
10363
10711
  evaluate as evaluate2,
10364
10712
  lit as lit2,
10713
+ proofOf,
10365
10714
  rule as rule2,
10366
10715
  tupleKey,
10367
10716
  tupleKeyParts,
10368
- variable as v2
10717
+ variable as v2,
10718
+ witnesses
10369
10719
  } from "@suss/datalog";
10370
10720
  import {
10371
10721
  ANSWER_RELATIONS,
@@ -10379,7 +10729,8 @@ var JS_RULES = [
10379
10729
  rule2(
10380
10730
  "stepsTo",
10381
10731
  [v2("r"), v2("t"), VALUE_STEP],
10382
- [lit2("bindCall", v2("r"), v2("t"))]
10732
+ [lit2("bindCall", v2("r"), v2("t"))],
10733
+ "bind"
10383
10734
  )
10384
10735
  ];
10385
10736
  var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
@@ -10389,6 +10740,15 @@ var RESOLUTION_PROGRAM = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? {
10389
10740
  [...SHARED_RULES, ...JS_RULES, ...RESOLUTION_QUESTIONS],
10390
10741
  ANSWER_RELATIONS
10391
10742
  );
10743
+ var WITNESS_RULES = [...SHARED_RULES, ...JS_RULES];
10744
+ var NOT_BASE_FACTS = /* @__PURE__ */ new Set([
10745
+ ...[...SHARED_RULES, ...JS_RULES, ...RESOLUTION_QUESTIONS].map(
10746
+ (r) => r.head.relation
10747
+ ),
10748
+ ...RESOLUTION_PROGRAM.rules.map((r) => r.head.relation),
10749
+ "wanted",
10750
+ "wantedOrigin"
10751
+ ]);
10392
10752
  var QUERY_FACTS = RESOLUTION_PROGRAM.demandDriven.length === 0 ? [] : [...RESOLUTION_PROGRAM.demandDriven, "wanted", "wantedOrigin"];
10393
10753
  var MAX_MODULE_HOPS = 6;
10394
10754
  var ResolutionStore = class {
@@ -10416,13 +10776,64 @@ var ResolutionStore = class {
10416
10776
  * the walk never reaches on its own.
10417
10777
  */
10418
10778
  resolveCallable(value, alsoFrom) {
10779
+ const sources = this.resolveCallableSources(value, alsoFrom);
10780
+ const only = sources[0];
10781
+ return sources.length === 1 && only !== void 0 ? only : null;
10782
+ }
10783
+ /**
10784
+ * Every function the value comes down to. One is the answer
10785
+ * `resolveCallable` gives; several is a value with more than one
10786
+ * possible source, which a caller says at the site rather than
10787
+ * folding into the same nothing as a chain that went nowhere.
10788
+ */
10789
+ resolveCallableSources(value, alsoFrom) {
10419
10790
  const target = factKeyOf(value);
10420
10791
  return this.resolveByWaves(
10421
10792
  target,
10422
10793
  "wanted",
10423
- () => this.lookup(target),
10794
+ () => this.lookupSources(target),
10424
10795
  alsoFrom
10796
+ ) ?? [];
10797
+ }
10798
+ /**
10799
+ * The witness proof behind `resolveCallable`'s answer. Resolves the
10800
+ * value first, which walks files and extracts facts in the usual
10801
+ * waves, then re-evaluates the rules over those base facts under the
10802
+ * witness algebra and rebuilds the proof of the answer. Null when
10803
+ * the value does not resolve at all.
10804
+ */
10805
+ explainCallable(value, options = {}) {
10806
+ const resolved = this.resolveCallable(value, options.alsoFrom);
10807
+ if (resolved === null) {
10808
+ return null;
10809
+ }
10810
+ const proofDb = new Database2();
10811
+ let baseFacts = 0;
10812
+ for (const relation of this.db.relationNames()) {
10813
+ if (NOT_BASE_FACTS.has(relation)) {
10814
+ continue;
10815
+ }
10816
+ for (const tuple of this.db.facts(relation)) {
10817
+ proofDb.add(relation, tuple);
10818
+ baseFacts++;
10819
+ }
10820
+ }
10821
+ const started = performance.now();
10822
+ evaluate2(proofDb, WITNESS_RULES, witnesses);
10823
+ const evaluateMs = performance.now() - started;
10824
+ const derivedFacts = proofDb.relationNames().reduce((count, relation) => count + proofDb.size(relation), 0) - baseFacts;
10825
+ const proof = proofOf(
10826
+ proofDb,
10827
+ "resolves",
10828
+ [nodeId(factKeyOf(value)), nodeId(resolved)],
10829
+ options.maxDepth === void 0 ? {} : { maxDepth: options.maxDepth }
10425
10830
  );
10831
+ return {
10832
+ target: resolved,
10833
+ proof,
10834
+ nodeFor: (atom) => this.table.byId.get(String(atom)),
10835
+ stats: { baseFacts, derivedFacts, evaluateMs }
10836
+ };
10426
10837
  }
10427
10838
  resolveObject(value) {
10428
10839
  const target = factKeyOf(value);
@@ -10545,7 +10956,7 @@ var ResolutionStore = class {
10545
10956
  this.stale = false;
10546
10957
  }
10547
10958
  wantValue(question, value) {
10548
- if (this.db.add(question, [nodeId(value)])) {
10959
+ if (this.db.add(question, [nodeId(value)]) === "added") {
10549
10960
  this.stale = true;
10550
10961
  }
10551
10962
  }
@@ -10609,10 +11020,12 @@ var ResolutionStore = class {
10609
11020
  return this.graph.filesReachingAnyPackage(fileSets);
10610
11021
  }
10611
11022
  /**
10612
- * Two candidates give null. Picking whichever arrived first would make
10613
- * the result depend on the order the facts came in.
11023
+ * Null keeps the wave walk widening; any candidate at all ends it,
11024
+ * since more files can only add candidates, never take one away. The
11025
+ * single-answer policy stays with the callers: picking one of two
11026
+ * would make the result depend on the order the facts came in.
10614
11027
  */
10615
- lookup(value) {
11028
+ lookupSources(value) {
10616
11029
  this.derive();
10617
11030
  const candidates = /* @__PURE__ */ new Set();
10618
11031
  for (const target of this.answersFor("wantedResolves", nodeId(value))) {
@@ -10624,10 +11037,7 @@ var ResolutionStore = class {
10624
11037
  candidates.add(resolved);
10625
11038
  }
10626
11039
  }
10627
- if (candidates.size !== 1) {
10628
- return null;
10629
- }
10630
- return [...candidates][0];
11040
+ return candidates.size === 0 ? null : [...candidates];
10631
11041
  }
10632
11042
  derive() {
10633
11043
  if (!this.stale) {
@@ -11038,6 +11448,7 @@ function classifyStop(declarations) {
11038
11448
  var RECORDED = {
11039
11449
  noBody: true,
11040
11450
  unsettledValue: true,
11451
+ multipleSources: true,
11041
11452
  outsideRun: false,
11042
11453
  noDeclaration: false
11043
11454
  };
@@ -11047,6 +11458,7 @@ function worthRecording(reason) {
11047
11458
  var STOP_SENTENCE = {
11048
11459
  noBody: (callee) => `The call to ${callee} lands on a declaration with no body, so whatever runs there is missing from this summary`,
11049
11460
  unsettledValue: (callee) => `The call to ${callee} goes through a value this run could not settle, so whatever runs there is missing from this summary`,
11461
+ multipleSources: (callee) => `The call to ${callee} reaches a value with more than one possible source, so whatever runs there is missing from this summary`,
11050
11462
  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`,
11051
11463
  noDeclaration: (callee) => `The call to ${callee} has no declaration this run could find, so whatever runs there is missing from this summary`
11052
11464
  };
@@ -11100,24 +11512,6 @@ function resolveDecl(decl, calleeName) {
11100
11512
  }
11101
11513
  return null;
11102
11514
  }
11103
- if (Node50.isImportSpecifier(decl)) {
11104
- const importDecl = decl.getImportDeclaration();
11105
- const sf = importDecl.getModuleSpecifierSourceFile();
11106
- if (sf === void 0 || isInExternalCode(sf)) {
11107
- return null;
11108
- }
11109
- const exported = exportedDeclarationsOf(sf).get(decl.getName());
11110
- if (exported === void 0) {
11111
- return null;
11112
- }
11113
- for (const ed of exported) {
11114
- const resolved = resolveDecl(ed, calleeName);
11115
- if (resolved !== null) {
11116
- return resolved;
11117
- }
11118
- }
11119
- return null;
11120
- }
11121
11515
  return null;
11122
11516
  }
11123
11517
  function declName(decl) {
@@ -11145,20 +11539,27 @@ function resolveCallee(call, calleeName, scan) {
11145
11539
  }
11146
11540
  const callee = call.getExpression();
11147
11541
  const symbol = callee.getSymbol();
11148
- const declarations = symbol?.getDeclarations() ?? [];
11542
+ const declarations = declarationsBehind(symbol);
11149
11543
  for (const decl of declarations) {
11150
11544
  const resolved = resolveDecl(decl, calleeName);
11151
11545
  if (resolved !== null) {
11152
11546
  return { kind: "followed", candidate: resolved };
11153
11547
  }
11154
11548
  }
11155
- const resolveCallable = scan.resolveCallable;
11156
- if (resolveCallable !== void 0 && Node50.isPropertyAccessExpression(callee) && declarations.some(isDeclaredShape)) {
11157
- const value = resolveCallable(callee, scan.reachedFrom);
11158
- const resolved = value === null ? null : resolveDecl(value, calleeName);
11549
+ const resolveSources = scan.resolveCallableSources;
11550
+ if (resolveSources !== void 0 && Node50.isPropertyAccessExpression(callee) && declarations.some(isDeclaredShape)) {
11551
+ const sources = resolveSources(callee, scan.reachedFrom);
11552
+ const only = sources.length === 1 ? sources[0] : void 0;
11553
+ const resolved = only === void 0 ? null : resolveDecl(only, calleeName);
11159
11554
  if (resolved !== null) {
11160
11555
  return { kind: "followed", candidate: resolved };
11161
11556
  }
11557
+ if (sources.length > 1) {
11558
+ return {
11559
+ kind: "stopped",
11560
+ stop: { callee: calleeName, reason: "multipleSources" }
11561
+ };
11562
+ }
11162
11563
  }
11163
11564
  return {
11164
11565
  kind: "stopped",
@@ -11276,7 +11677,7 @@ function expandReachableClosure(seeds, project, options, projectFileSet, facts,
11276
11677
  }
11277
11678
  const cameFrom = reachedFrom.get(key);
11278
11679
  const scan = {
11279
- ...recognizers.resolveCallable === void 0 ? {} : { resolveCallable: recognizers.resolveCallable },
11680
+ ...recognizers.resolveCallableSources === void 0 ? {} : { resolveCallableSources: recognizers.resolveCallableSources },
11280
11681
  ...cameFrom === void 0 ? {} : { reachedFrom: cameFrom }
11281
11682
  };
11282
11683
  const { candidates, stops } = scanWithRecording(
@@ -12097,20 +12498,25 @@ import {
12097
12498
  disambiguateSummaryIds,
12098
12499
  summaryIdFromParts
12099
12500
  } from "@suss/behavioral-ir";
12501
+ function workspaceRootFor(anchor) {
12502
+ return namedPackageDirAbove(anchor) ?? path7.resolve(anchor);
12503
+ }
12100
12504
  function workspaceNameFor(root) {
12101
12505
  if (root === void 0) {
12102
12506
  return null;
12103
12507
  }
12104
- let at = path7.resolve(root);
12508
+ const dir = namedPackageDirAbove(root);
12509
+ if (dir !== null) {
12510
+ return packageNameAt(dir);
12511
+ }
12512
+ const folder = path7.basename(path7.resolve(root));
12513
+ return folder.length > 0 ? folder : null;
12514
+ }
12515
+ function namedPackageDirAbove(start) {
12516
+ let at = path7.resolve(start);
12105
12517
  for (let up = 0; up < 12; up += 1) {
12106
- try {
12107
- const manifest = JSON.parse(
12108
- fs6.readFileSync(path7.join(at, "package.json"), "utf8")
12109
- );
12110
- if (typeof manifest.name === "string" && manifest.name.length > 0) {
12111
- return manifest.name;
12112
- }
12113
- } catch {
12518
+ if (packageNameAt(at) !== null) {
12519
+ return at;
12114
12520
  }
12115
12521
  const parent = path7.dirname(at);
12116
12522
  if (parent === at) {
@@ -12118,8 +12524,19 @@ function workspaceNameFor(root) {
12118
12524
  }
12119
12525
  at = parent;
12120
12526
  }
12121
- const folder = path7.basename(path7.resolve(root));
12122
- return folder.length > 0 ? folder : null;
12527
+ return null;
12528
+ }
12529
+ function packageNameAt(dir) {
12530
+ try {
12531
+ const manifest = JSON.parse(
12532
+ fs6.readFileSync(path7.join(dir, "package.json"), "utf8")
12533
+ );
12534
+ if (typeof manifest.name === "string" && manifest.name.length > 0) {
12535
+ return manifest.name;
12536
+ }
12537
+ } catch {
12538
+ }
12539
+ return null;
12123
12540
  }
12124
12541
  function nameSummaries(summaries, args) {
12125
12542
  for (const summary of summaries) {
@@ -12718,11 +13135,11 @@ function extractConsumerBinding(unit, pattern, pack, resolution) {
12718
13135
  return null;
12719
13136
  }
12720
13137
  const method = extractBindingMethod(binding, callSite, pack, resolution);
12721
- const path11 = extractBindingPath(binding, callSite, pack, resolution);
13138
+ const path12 = extractBindingPath(binding, callSite, pack, resolution);
12722
13139
  return restBinding2({
12723
13140
  transport: pack.protocol,
12724
13141
  method: method ?? null,
12725
- path: path11 ?? null,
13142
+ path: path12 ?? null,
12726
13143
  recognition: pack.name
12727
13144
  });
12728
13145
  }
@@ -12811,12 +13228,12 @@ function originEndOf(flattened) {
12811
13228
  const slash = flattened.indexOf("/", opener[0].length);
12812
13229
  return slash === -1 ? flattened.length : slash;
12813
13230
  }
12814
- function appendPathText(path11, text) {
13231
+ function appendPathText(path12, text) {
12815
13232
  const idx = text.search(/[?#]/);
12816
13233
  if (idx === -1) {
12817
- return { path: path11 + text, stop: false };
13234
+ return { path: path12 + text, stop: false };
12818
13235
  }
12819
- return { path: path11 + text.slice(0, idx), stop: true };
13236
+ return { path: path12 + text.slice(0, idx), stop: true };
12820
13237
  }
12821
13238
  function parseAbsoluteUrl(text) {
12822
13239
  try {
@@ -12840,8 +13257,8 @@ function pathnameOfAbsoluteLiteral(text) {
12840
13257
  return stripQueryAndFragment(stripOriginManually(text));
12841
13258
  }
12842
13259
  function pathFromLiteralUrl(text) {
12843
- const path11 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
12844
- return path11 === "" ? void 0 : path11;
13260
+ const path12 = isAbsoluteUrlLiteral(text) ? pathnameOfAbsoluteLiteral(text) : stripQueryAndFragment(text);
13261
+ return path12 === "" ? void 0 : path12;
12845
13262
  }
12846
13263
  function pathFromTemplateUrl(arg) {
12847
13264
  const headText = arg.getHead().getLiteralText();
@@ -12849,7 +13266,7 @@ function pathFromTemplateUrl(arg) {
12849
13266
  const tails = spans.map((span) => span.getLiteral().getLiteralText());
12850
13267
  const originEnd = originEndOf([headText, ...tails].join(SUBSTITUTION));
12851
13268
  const head = appendPathText("", headText.slice(originEnd));
12852
- let path11 = head.path;
13269
+ let path12 = head.path;
12853
13270
  let stop = head.stop;
12854
13271
  let at = headText.length;
12855
13272
  for (let i = 0; i < spans.length && !stop; i++) {
@@ -12859,18 +13276,18 @@ function pathFromTemplateUrl(arg) {
12859
13276
  continue;
12860
13277
  }
12861
13278
  if (at >= originEnd) {
12862
- path11 += `{${placeholderName(span.getExpression())}}`;
13279
+ path12 += `{${placeholderName(span.getExpression())}}`;
12863
13280
  }
12864
13281
  at += SUBSTITUTION.length;
12865
13282
  const appended = appendPathText(
12866
- path11,
13283
+ path12,
12867
13284
  tailText.slice(Math.max(0, originEnd - at))
12868
13285
  );
12869
- path11 = appended.path;
13286
+ path12 = appended.path;
12870
13287
  stop = appended.stop;
12871
13288
  at += tailText.length;
12872
13289
  }
12873
- return path11 === "" ? void 0 : path11;
13290
+ return path12 === "" ? void 0 : path12;
12874
13291
  }
12875
13292
  function extractBindingPath(binding, callSite, pack, resolution) {
12876
13293
  const p = binding.path;
@@ -13149,6 +13566,9 @@ function extractFromSourceFile(sourceFile, frameworks, claimedUnits, options, ta
13149
13566
  if (unit.operationInfo.document !== void 0) {
13150
13567
  raw.graphqlDocument = unit.operationInfo.document;
13151
13568
  }
13569
+ if (unit.operationInfo.unresolvedFragments !== void 0) {
13570
+ raw.graphqlUnresolvedFragments = unit.operationInfo.unresolvedFragments;
13571
+ }
13152
13572
  if (unit.operationInfo.unresolved !== void 0) {
13153
13573
  raw.graphqlUnresolvedDocument = unit.operationInfo.unresolved;
13154
13574
  }
@@ -13450,8 +13870,8 @@ function synthesizeCallerSummaries(wrapper, _project, options) {
13450
13870
  if (pathArg === void 0) {
13451
13871
  continue;
13452
13872
  }
13453
- const path11 = literalOrTemplate(pathArg);
13454
- if (path11 === void 0) {
13873
+ const path12 = literalOrTemplate(pathArg);
13874
+ if (path12 === void 0) {
13455
13875
  continue;
13456
13876
  }
13457
13877
  const callerFunc = enclosingFunction(callExpr);
@@ -13463,7 +13883,7 @@ function synthesizeCallerSummaries(wrapper, _project, options) {
13463
13883
  continue;
13464
13884
  }
13465
13885
  seen.add(dedupKey);
13466
- out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path11, options));
13886
+ out.push(buildCallerSummary(wrapper, callerFunc, callExpr, path12, options));
13467
13887
  }
13468
13888
  return out;
13469
13889
  }
@@ -13515,12 +13935,12 @@ function literalOrTemplate(arg) {
13515
13935
  return arg.getLiteralValue();
13516
13936
  }
13517
13937
  if (Node54.isTemplateExpression(arg)) {
13518
- let path11 = arg.getHead().getLiteralText();
13938
+ let path12 = arg.getHead().getLiteralText();
13519
13939
  for (const span of arg.getTemplateSpans()) {
13520
- path11 += `{${placeholderName(span.getExpression())}}`;
13521
- path11 += span.getLiteral().getLiteralText();
13940
+ path12 += `{${placeholderName(span.getExpression())}}`;
13941
+ path12 += span.getLiteral().getLiteralText();
13522
13942
  }
13523
- return path11;
13943
+ return path12;
13524
13944
  }
13525
13945
  return void 0;
13526
13946
  }
@@ -13537,7 +13957,7 @@ function callerName(func) {
13537
13957
  }
13538
13958
  return "anonymous";
13539
13959
  }
13540
- function buildCallerSummary(wrapper, callerFunc, callExpr, path11, options) {
13960
+ function buildCallerSummary(wrapper, callerFunc, callExpr, path12, options) {
13541
13961
  const wrapperBinding = wrapper.summary.identity.boundaryBinding;
13542
13962
  const wrapperRest = wrapperBinding?.semantics.name === "rest" ? wrapperBinding.semantics : null;
13543
13963
  const syntheticPack = {
@@ -13569,7 +13989,7 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path11, options) {
13569
13989
  raw.boundaryBinding = restBinding2({
13570
13990
  transport: wrapperBinding?.transport ?? "http",
13571
13991
  method: wrapperRest?.method ?? null,
13572
- path: path11,
13992
+ path: path12,
13573
13993
  recognition: wrapperBinding?.recognition ?? "unknown"
13574
13994
  });
13575
13995
  const summary = assembleSummary3(raw, options);
@@ -13583,8 +14003,8 @@ function buildCallerSummary(wrapper, callerFunc, callExpr, path11, options) {
13583
14003
  summary.confidence = { source: "inferred_static", level: "low" };
13584
14004
  return summary;
13585
14005
  }
13586
- function named(summaries, workspace, storedProjectRoot) {
13587
- const projectRoot = storedProjectRoot ?? commonDirectoryOf(summaries.map((s) => s.location.file));
14006
+ function named(summaries, workspace, runRoot) {
14007
+ const projectRoot = runRoot ?? commonDirectoryOf(summaries.map((s) => s.location.file));
13588
14008
  nameSummaries(summaries, {
13589
14009
  workspace: workspace ?? workspaceNameFor(projectRoot),
13590
14010
  projectRoot
@@ -13642,6 +14062,7 @@ function createTypeScriptAdapter(config) {
13642
14062
  skipAddingFilesFromTsConfig: true
13643
14063
  } : { skipAddingFilesFromTsConfig: true }
13644
14064
  );
14065
+ const runRoot = config.projectRoot ?? (config.tsConfigFilePath !== void 0 ? workspaceRootFor(path9.dirname(config.tsConfigFilePath)) : void 0);
13645
14066
  let lazyBootstrapped = false;
13646
14067
  let projectFileSet;
13647
14068
  const cacheDir = declineWhenRunFromSource(
@@ -13682,7 +14103,7 @@ function createTypeScriptAdapter(config) {
13682
14103
  )
13683
14104
  );
13684
14105
  }
13685
- return named(summaries, config.workspace);
14106
+ return named(summaries, config.workspace, runRoot);
13686
14107
  },
13687
14108
  async extractAll() {
13688
14109
  const timer = createTimer();
@@ -13715,7 +14136,7 @@ function createTypeScriptAdapter(config) {
13715
14136
  if (config.onTiming !== void 0) {
13716
14137
  config.onTiming(timer.report());
13717
14138
  }
13718
- return named(lookup.summaries, config.workspace, lookup.projectRoot);
14139
+ return named(lookup.summaries, config.workspace, runRoot);
13719
14140
  }
13720
14141
  const plan = lookup.diagnostic.missReason === "files-changed" ? await timer.timeAsync("cache.plan", () => cache.plan(cacheInput)) : null;
13721
14142
  if (plan !== null && plan.changed.size === 0 && plan.removed.size === 0) {
@@ -13733,11 +14154,7 @@ function createTypeScriptAdapter(config) {
13733
14154
  if (config.onTiming !== void 0) {
13734
14155
  config.onTiming(timer.report());
13735
14156
  }
13736
- return named(
13737
- plan.allSummaries(),
13738
- config.workspace,
13739
- plan.storedProjectRoot ?? void 0
13740
- );
14157
+ return named(plan.allSummaries(), config.workspace, runRoot);
13741
14158
  }
13742
14159
  let candidatePaths = null;
13743
14160
  if (lazyEligible) {
@@ -13883,7 +14300,7 @@ function createTypeScriptAdapter(config) {
13883
14300
  ),
13884
14301
  access: collectAccessRecognizers(config.frameworks, tallies),
13885
14302
  resolveWrittenValue: (value) => resolution.resolveWrittenValue(value),
13886
- resolveCallable: (value, alsoFrom) => resolution.resolveCallable(value, alsoFrom)
14303
+ resolveCallableSources: (value, alsoFrom) => resolution.resolveCallableSources(value, alsoFrom)
13887
14304
  },
13888
14305
  // Reached units the cache already serves emit nothing,
13889
14306
  // the way a cold run's seeds do not.
@@ -13947,9 +14364,6 @@ function createTypeScriptAdapter(config) {
13947
14364
  }
13948
14365
  });
13949
14366
  }
13950
- const runProjectRoot = commonDirectoryOf(
13951
- sourceFiles.map((f) => f.getFilePath())
13952
- );
13953
14367
  await timer.timeAsync("cache.write", async () => {
13954
14368
  if (!caching || enriched.length === 0) {
13955
14369
  return;
@@ -13969,8 +14383,7 @@ function createTypeScriptAdapter(config) {
13969
14383
  reusedOwners: merged.reusedOwners,
13970
14384
  // Everything after the reused prefix, the passes' own
13971
14385
  // additions (markers, schema documents) included.
13972
- fresh: enriched.slice(merged.reusedKept.length),
13973
- projectRoot: runProjectRoot
14386
+ fresh: enriched.slice(merged.reusedKept.length)
13974
14387
  });
13975
14388
  await cache.write(cacheInput, enriched, attribution);
13976
14389
  } catch {
@@ -13995,13 +14408,11 @@ function createTypeScriptAdapter(config) {
13995
14408
  })
13996
14409
  );
13997
14410
  }
13998
- nameSummaries(enriched, {
13999
- workspace: config.workspace ?? workspaceNameFor(
14000
- commonDirectoryOf(sourceFiles.map((f) => f.getFilePath()))
14001
- ),
14002
- projectRoot: commonDirectoryOf(sourceFiles.map((f) => f.getFilePath()))
14003
- });
14004
- return enriched;
14411
+ return named(
14412
+ enriched,
14413
+ config.workspace,
14414
+ runRoot ?? commonDirectoryOf(sourceFiles.map((f) => f.getFilePath()))
14415
+ );
14005
14416
  }
14006
14417
  };
14007
14418
  }
@@ -14192,11 +14603,7 @@ function buildCacheAttribution(args) {
14192
14603
  ...reusedOwners,
14193
14604
  ...args.fresh.map((s) => [...args.ownersBySummary.get(s) ?? []])
14194
14605
  ];
14195
- return {
14196
- roots,
14197
- owners,
14198
- ...args.projectRoot === void 0 ? {} : { projectRoot: args.projectRoot }
14199
- };
14606
+ return { roots, owners };
14200
14607
  }
14201
14608
  function synthesizeSubUnits(summaries, project, frameworks, options, tallies, onCreated) {
14202
14609
  const packByRecognition = /* @__PURE__ */ new Map();
@@ -14440,7 +14847,7 @@ function readStringArg(arg) {
14440
14847
  }
14441
14848
  return candidate.value;
14442
14849
  }
14443
- function rootIdentifier(node) {
14850
+ function rootIdentifier2(node) {
14444
14851
  let current2 = node;
14445
14852
  while (Node55.isPropertyAccessExpression(current2)) {
14446
14853
  current2 = current2.getExpression();
@@ -14448,10 +14855,165 @@ function rootIdentifier(node) {
14448
14855
  return Node55.isIdentifier(current2) ? current2 : null;
14449
14856
  }
14450
14857
 
14858
+ // src/facts/why.ts
14859
+ import path11 from "path";
14860
+ import { Node as Node56, Project as Project3, SyntaxKind as SyntaxKind12 } from "ts-morph";
14861
+ import { explainResolutionProof, renderExplanation } from "@suss/resolution";
14862
+ var JS_PHRASES = {
14863
+ bind: ({ tuple, describe }) => ({
14864
+ reason: `${describe(tuple[0])} is a .bind of ${describe(tuple[1])}, which runs the same function`
14865
+ })
14866
+ };
14867
+ var WhySession = class {
14868
+ project;
14869
+ store;
14870
+ root;
14871
+ constructor(options) {
14872
+ this.root = path11.resolve(options.dir);
14873
+ const tsconfig = findNearestTsconfig(this.root);
14874
+ this.project = tsconfig === null ? createProjectWithoutTsconfig(this.root).project : new Project3({ tsConfigFilePath: tsconfig });
14875
+ this.store = new ResolutionStore();
14876
+ }
14877
+ /**
14878
+ * The smallest expression on `line` of `file` whose text is exactly
14879
+ * `text`, or null. Spelled from the person's side: the name as
14880
+ * written, not a node id.
14881
+ */
14882
+ findExpression(file, line, text) {
14883
+ const sourceFile = this.sourceFileAt(file);
14884
+ if (sourceFile === null) {
14885
+ return null;
14886
+ }
14887
+ let found = null;
14888
+ sourceFile.forEachDescendant((node) => {
14889
+ if (Node56.isExpression(node) && node.getStartLineNumber() === line && node.getText() === text && (found === null || node.getWidth() <= found.getWidth())) {
14890
+ found = node;
14891
+ }
14892
+ });
14893
+ return found;
14894
+ }
14895
+ /**
14896
+ * The callee of the call written as `calleeText` between `startLine`
14897
+ * and `endLine` of `file`, or null. This is how a summary's recorded
14898
+ * callee gets back to its node: the summary keeps source text and a
14899
+ * range, not ids.
14900
+ */
14901
+ findCallee(file, startLine, endLine, calleeText) {
14902
+ const sourceFile = this.sourceFileAt(file);
14903
+ if (sourceFile === null) {
14904
+ return null;
14905
+ }
14906
+ for (const call of sourceFile.getDescendantsOfKind(
14907
+ SyntaxKind12.CallExpression
14908
+ )) {
14909
+ const line = call.getStartLineNumber();
14910
+ if (line < startLine || line > endLine) {
14911
+ continue;
14912
+ }
14913
+ if (call.getExpression().getText() === calleeText) {
14914
+ return call.getExpression();
14915
+ }
14916
+ }
14917
+ return null;
14918
+ }
14919
+ /**
14920
+ * Why `value` resolves to what it does: the witness proof, flattened
14921
+ * to the chain and rendered. Null when the value does not resolve,
14922
+ * which the caller says in its own words.
14923
+ */
14924
+ explain(value, options = {}) {
14925
+ const explained = this.store.explainCallable(value, options);
14926
+ if (explained === null) {
14927
+ return null;
14928
+ }
14929
+ const describe = (atom) => {
14930
+ const node = explained.nodeFor(atom);
14931
+ if (node === void 0) {
14932
+ return this.displayPath(String(atom));
14933
+ }
14934
+ const at = this.locate(node);
14935
+ return `${at.name} (${at.file}:${at.line})`;
14936
+ };
14937
+ const explanation = explainResolutionProof(explained.proof, {
14938
+ describe,
14939
+ phrases: JS_PHRASES
14940
+ });
14941
+ if (explanation === null) {
14942
+ return null;
14943
+ }
14944
+ return {
14945
+ explanation,
14946
+ chain: explanation.atoms.map((atom) => describe(atom)),
14947
+ lines: renderExplanation(explanation, describe),
14948
+ target: this.locate(explained.target),
14949
+ stats: explained.stats
14950
+ };
14951
+ }
14952
+ /** Where a found node is, in the terms an answer prints. */
14953
+ locate(node) {
14954
+ return {
14955
+ name: displayNameOf(node),
14956
+ file: this.displayPath(node.getSourceFile().getFilePath()),
14957
+ line: node.getStartLineNumber()
14958
+ };
14959
+ }
14960
+ sourceFileAt(file) {
14961
+ const absolute = path11.resolve(this.root, file);
14962
+ const loaded = this.project.getSourceFile(absolute);
14963
+ if (loaded !== void 0) {
14964
+ return loaded;
14965
+ }
14966
+ try {
14967
+ return this.project.addSourceFileAtPath(absolute);
14968
+ } catch {
14969
+ return null;
14970
+ }
14971
+ }
14972
+ /** A module key: a file path said relative to the root, or a package name. */
14973
+ displayPath(key) {
14974
+ if (key.startsWith(this.root)) {
14975
+ return path11.relative(this.root, key);
14976
+ }
14977
+ return key;
14978
+ }
14979
+ };
14980
+ function displayNameOf(node) {
14981
+ if (Node56.isIdentifier(node) || Node56.isPropertyAccessExpression(node)) {
14982
+ return node.getText();
14983
+ }
14984
+ if (Node56.isCallExpression(node) || Node56.isNewExpression(node)) {
14985
+ return `${node.getExpression()?.getText() ?? "call"}(...)`;
14986
+ }
14987
+ if (Node56.isFunctionDeclaration(node) || Node56.isClassDeclaration(node) || Node56.isMethodDeclaration(node) || Node56.isVariableDeclaration(node)) {
14988
+ const name = node.getName();
14989
+ if (name !== void 0) {
14990
+ return name;
14991
+ }
14992
+ }
14993
+ if (Node56.isArrowFunction(node) || Node56.isFunctionExpression(node)) {
14994
+ const parent = node.getParent();
14995
+ if (parent !== void 0 && Node56.isVariableDeclaration(parent)) {
14996
+ return parent.getName();
14997
+ }
14998
+ }
14999
+ const text = node.getText().split("\n")[0].trim();
15000
+ return text.length > 40 ? `${text.slice(0, 40)}...` : text;
15001
+ }
15002
+
14451
15003
  // src/packHealth.ts
14452
15004
  function stagesOf(funnel) {
14453
15005
  const stages = [];
14454
15006
  const gateSaysSomething = funnel.gates.length > 0 && funnel.unresolvedGates.length === 0;
15007
+ if (funnel.recognizes && !funnel.discovers && gateSaysSomething) {
15008
+ stages.push({
15009
+ from: {
15010
+ name: "unit bodies to look inside",
15011
+ count: funnel.unitsInGatedFiles
15012
+ },
15013
+ to: { name: "effects recognized", count: funnel.effectsRecognized },
15014
+ meaning: "its import gate found the library and it matched nothing in the bodies it saw"
15015
+ });
15016
+ }
14455
15017
  if (funnel.discovers && gateSaysSomething) {
14456
15018
  stages.push({
14457
15019
  from: { name: "candidate files", count: funnel.candidateFiles },
@@ -14561,7 +15123,7 @@ function formatPackHealth(checks, audiences) {
14561
15123
  }
14562
15124
 
14563
15125
  // src/resolve/readName.ts
14564
- import { Node as Node56, SyntaxKind as SyntaxKind12 } from "ts-morph";
15126
+ import { Node as Node57, SyntaxKind as SyntaxKind13 } from "ts-morph";
14565
15127
  import { patternHole, referenceName } from "@suss/behavioral-ir";
14566
15128
  var MAX_HELPER_HOPS = 2;
14567
15129
  var UNNAMED_HOLE = "param";
@@ -14596,11 +15158,11 @@ function referenceIn(expr) {
14596
15158
  function parameterPath(expr) {
14597
15159
  const fields = [];
14598
15160
  let step = expr;
14599
- while (Node56.isPropertyAccessExpression(step)) {
15161
+ while (Node57.isPropertyAccessExpression(step)) {
14600
15162
  fields.unshift(step.getName());
14601
15163
  step = step.getExpression();
14602
15164
  }
14603
- if (!Node56.isIdentifier(step) || !isParameter(step)) {
15165
+ if (!Node57.isIdentifier(step) || !isParameter(step)) {
14604
15166
  return null;
14605
15167
  }
14606
15168
  return { root: step.getText(), fields };
@@ -14608,7 +15170,7 @@ function parameterPath(expr) {
14608
15170
  function isParameter(identifier) {
14609
15171
  const declarations = identifier.getSymbol()?.getDeclarations() ?? [];
14610
15172
  return declarations.some(
14611
- (declaration) => Node56.isParameterDeclaration(declaration)
15173
+ (declaration) => Node57.isParameterDeclaration(declaration)
14612
15174
  );
14613
15175
  }
14614
15176
  function read(expr, ctx) {
@@ -14617,35 +15179,52 @@ function read(expr, ctx) {
14617
15179
  }
14618
15180
  const seen = new Set(ctx.seen).add(expr);
14619
15181
  const inner = { ...ctx, seen };
14620
- if (Node56.isStringLiteral(expr) || Node56.isNoSubstitutionTemplateLiteral(expr)) {
15182
+ if (Node57.isStringLiteral(expr) || Node57.isNoSubstitutionTemplateLiteral(expr)) {
14621
15183
  return expr.getLiteralValue();
14622
15184
  }
14623
- if (Node56.isNumericLiteral(expr)) {
15185
+ if (Node57.isNumericLiteral(expr)) {
14624
15186
  return expr.getLiteralText();
14625
15187
  }
14626
- if (Node56.isTemplateExpression(expr)) {
15188
+ if (Node57.isTemplateExpression(expr)) {
14627
15189
  return fromTemplate(expr, inner);
14628
15190
  }
14629
- if (Node56.isParenthesizedExpression(expr)) {
15191
+ if (Node57.isParenthesizedExpression(expr)) {
14630
15192
  return read(expr.getExpression(), inner);
14631
15193
  }
14632
- if (Node56.isBinaryExpression(expr)) {
15194
+ if (Node57.isBinaryExpression(expr)) {
14633
15195
  return fromBinary(expr, inner);
14634
15196
  }
14635
- if (Node56.isCallExpression(expr)) {
15197
+ if (Node57.isCallExpression(expr)) {
14636
15198
  return fromCall(expr, inner);
14637
15199
  }
14638
- if (Node56.isIdentifier(expr)) {
15200
+ if (Node57.isIdentifier(expr)) {
14639
15201
  const only = boundOnce(expr, ctx);
14640
15202
  if (only !== null) {
14641
15203
  return read(only.node, { ...inner, bindings: only.scope });
14642
15204
  }
14643
15205
  }
14644
15206
  const written = ctx.resolve(expr);
14645
- return written === null || written === expr ? null : read(written, inner);
15207
+ if (written === null || written === expr) {
15208
+ return null;
15209
+ }
15210
+ if (ctx.insideHole && isFallbackBranch(written)) {
15211
+ return null;
15212
+ }
15213
+ return read(written, inner);
15214
+ }
15215
+ function isFallbackBranch(node) {
15216
+ let step = node.getParent();
15217
+ while (step !== void 0 && Node57.isParenthesizedExpression(step)) {
15218
+ step = step.getParent();
15219
+ }
15220
+ if (step === void 0 || !Node57.isBinaryExpression(step)) {
15221
+ return false;
15222
+ }
15223
+ const operator = step.getOperatorToken().getKind();
15224
+ return operator === SyntaxKind13.BarBarToken || operator === SyntaxKind13.QuestionQuestionToken;
14646
15225
  }
14647
15226
  function fromTemplate(expr, ctx) {
14648
- if (!Node56.isTemplateExpression(expr)) {
15227
+ if (!Node57.isTemplateExpression(expr)) {
14649
15228
  return null;
14650
15229
  }
14651
15230
  let name = expr.getHead().getLiteralText();
@@ -14656,28 +15235,28 @@ function fromTemplate(expr, ctx) {
14656
15235
  return name;
14657
15236
  }
14658
15237
  function fromBinary(expr, ctx) {
14659
- if (!Node56.isBinaryExpression(expr)) {
15238
+ if (!Node57.isBinaryExpression(expr)) {
14660
15239
  return null;
14661
15240
  }
14662
15241
  const operator = expr.getOperatorToken().getKind();
14663
- if (operator === SyntaxKind12.BarBarToken || operator === SyntaxKind12.QuestionQuestionToken) {
15242
+ if (operator === SyntaxKind13.BarBarToken || operator === SyntaxKind13.QuestionQuestionToken) {
14664
15243
  return ctx.insideHole ? null : read(expr.getRight(), ctx);
14665
15244
  }
14666
- if (operator !== SyntaxKind12.PlusToken) {
15245
+ if (operator !== SyntaxKind13.PlusToken) {
14667
15246
  return null;
14668
15247
  }
14669
15248
  const parts = { ...ctx, insideHole: true };
14670
15249
  return readOrHole(expr.getLeft(), parts) + readOrHole(expr.getRight(), parts);
14671
15250
  }
14672
15251
  function fromCall(expr, ctx) {
14673
- if (!Node56.isCallExpression(expr)) {
15252
+ if (!Node57.isCallExpression(expr)) {
14674
15253
  return null;
14675
15254
  }
14676
15255
  const callee = expr.getExpression();
14677
- if (Node56.isPropertyAccessExpression(callee) && callee.getName() === "join") {
15256
+ if (Node57.isPropertyAccessExpression(callee) && callee.getName() === "join") {
14678
15257
  return fromJoin(callee.getExpression(), expr.getArguments(), ctx);
14679
15258
  }
14680
- if (Node56.isIdentifier(callee) && callee.getText() === "String") {
15259
+ if (Node57.isIdentifier(callee) && callee.getText() === "String") {
14681
15260
  const only = expr.getArguments()[0];
14682
15261
  return only === void 0 ? null : readOrHole(only, ctx);
14683
15262
  }
@@ -14696,7 +15275,7 @@ function fromCall(expr, ctx) {
14696
15275
  }
14697
15276
  function fromJoin(subject, args, ctx) {
14698
15277
  const separator = args[0];
14699
- if (separator === void 0 || !Node56.isStringLiteral(separator)) {
15278
+ if (separator === void 0 || !Node57.isStringLiteral(separator)) {
14700
15279
  return null;
14701
15280
  }
14702
15281
  const parts = elementsOf(subject, ctx);
@@ -14712,17 +15291,17 @@ function fromJoin(subject, args, ctx) {
14712
15291
  ).join(separator.getLiteralValue());
14713
15292
  }
14714
15293
  function elementsOf(subject, ctx) {
14715
- if (Node56.isArrayLiteralExpression(subject)) {
15294
+ if (Node57.isArrayLiteralExpression(subject)) {
14716
15295
  return subject.getElements().map((element) => here(element, ctx));
14717
15296
  }
14718
- if (Node56.isCallExpression(subject)) {
15297
+ if (Node57.isCallExpression(subject)) {
14719
15298
  const callee = subject.getExpression();
14720
- if (Node56.isPropertyAccessExpression(callee) && callee.getName() === "map") {
15299
+ if (Node57.isPropertyAccessExpression(callee) && callee.getName() === "map") {
14721
15300
  return elementsOf(callee.getExpression(), ctx);
14722
15301
  }
14723
15302
  return null;
14724
15303
  }
14725
- if (!Node56.isIdentifier(subject)) {
15304
+ if (!Node57.isIdentifier(subject)) {
14726
15305
  return null;
14727
15306
  }
14728
15307
  const bound = ctx.bindings.get(subject.getText());
@@ -14730,7 +15309,7 @@ function elementsOf(subject, ctx) {
14730
15309
  return null;
14731
15310
  }
14732
15311
  const only = bound.length === 1 ? bound[0] : void 0;
14733
- return only !== void 0 && Node56.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
15312
+ return only !== void 0 && Node57.isArrayLiteralExpression(only.node) ? only.node.getElements().map((element) => here(element, ctx)) : bound;
14734
15313
  }
14735
15314
  function singleReturnBody(callee, ctx) {
14736
15315
  const declaration = declarationOf2(callee, ctx);
@@ -14745,22 +15324,22 @@ function singleReturnBody(callee, ctx) {
14745
15324
  if (body === void 0) {
14746
15325
  return null;
14747
15326
  }
14748
- if (Node56.isExpression(body)) {
15327
+ if (Node57.isExpression(body)) {
14749
15328
  return { parameters, returned: body };
14750
15329
  }
14751
- if (!Node56.isBlock(body)) {
15330
+ if (!Node57.isBlock(body)) {
14752
15331
  return null;
14753
15332
  }
14754
15333
  const statements = body.getStatements();
14755
15334
  const only = statements[0];
14756
- if (statements.length !== 1 || only === void 0 || !Node56.isReturnStatement(only)) {
15335
+ if (statements.length !== 1 || only === void 0 || !Node57.isReturnStatement(only)) {
14757
15336
  return null;
14758
15337
  }
14759
15338
  const returned = only.getExpression();
14760
15339
  return returned === void 0 ? null : { parameters, returned };
14761
15340
  }
14762
15341
  function declarationOf2(callee, ctx) {
14763
- const symbol = Node56.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
15342
+ const symbol = Node57.isPropertyAccessExpression(callee) ? callee.getNameNode().getSymbol() : callee.getSymbol();
14764
15343
  const declarations = symbol?.getAliasedSymbol()?.getDeclarations() ?? symbol?.getDeclarations() ?? [];
14765
15344
  for (const declaration of declarations) {
14766
15345
  const callable = asCallable(declaration);
@@ -14772,14 +15351,14 @@ function declarationOf2(callee, ctx) {
14772
15351
  return written === null || written === callee ? null : declarationOf2(written, { ...ctx, resolve: () => null });
14773
15352
  }
14774
15353
  function asCallable(declaration) {
14775
- if (Node56.isFunctionDeclaration(declaration) || Node56.isMethodDeclaration(declaration) || Node56.isArrowFunction(declaration) || Node56.isFunctionExpression(declaration)) {
15354
+ if (Node57.isFunctionDeclaration(declaration) || Node57.isMethodDeclaration(declaration) || Node57.isArrowFunction(declaration) || Node57.isFunctionExpression(declaration)) {
14776
15355
  return declaration;
14777
15356
  }
14778
- if (!Node56.isVariableDeclaration(declaration)) {
15357
+ if (!Node57.isVariableDeclaration(declaration)) {
14779
15358
  return null;
14780
15359
  }
14781
15360
  const initializer = declaration.getInitializer();
14782
- if (initializer !== void 0 && (Node56.isArrowFunction(initializer) || Node56.isFunctionExpression(initializer))) {
15361
+ if (initializer !== void 0 && (Node57.isArrowFunction(initializer) || Node57.isFunctionExpression(initializer))) {
14783
15362
  return initializer;
14784
15363
  }
14785
15364
  return null;
@@ -14801,7 +15380,7 @@ function here(node, ctx) {
14801
15380
  return { node, scope: ctx.bindings };
14802
15381
  }
14803
15382
  function boundOnce(expr, ctx) {
14804
- const bound = Node56.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
15383
+ const bound = Node57.isIdentifier(expr) ? ctx.bindings.get(expr.getText()) : void 0;
14805
15384
  return bound !== void 0 && bound.length === 1 ? bound[0] : null;
14806
15385
  }
14807
15386
  function readOrHole(expr, ctx) {
@@ -14813,10 +15392,10 @@ function holeName(expr, ctx) {
14813
15392
  if (bound !== null) {
14814
15393
  return holeName(bound.node, { ...ctx, bindings: bound.scope });
14815
15394
  }
14816
- if (Node56.isIdentifier(expr)) {
15395
+ if (Node57.isIdentifier(expr)) {
14817
15396
  return expr.getText();
14818
15397
  }
14819
- if (Node56.isPropertyAccessExpression(expr)) {
15398
+ if (Node57.isPropertyAccessExpression(expr)) {
14820
15399
  return expr.getName();
14821
15400
  }
14822
15401
  return UNNAMED_HOLE;
@@ -14824,6 +15403,7 @@ function holeName(expr, ctx) {
14824
15403
  export {
14825
15404
  ADAPTER_VERSION,
14826
15405
  ResolutionStore,
15406
+ WhySession,
14827
15407
  collectAncestorBranches,
14828
15408
  collectClientFieldAccesses,
14829
15409
  computeAdapterPacksDigest,
@@ -14849,5 +15429,6 @@ export {
14849
15429
  readName,
14850
15430
  resolveAliasedSymbol,
14851
15431
  resolveSubject,
14852
- rootIdentifier
15432
+ rootIdentifier2 as rootIdentifier,
15433
+ workspaceRootFor
14853
15434
  };