@suss/adapter-typescript 0.22.3 → 0.22.4

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
@@ -3716,6 +3716,18 @@ var ResolutionStore = class {
3716
3716
  const target = factKeyOf(value);
3717
3717
  return this.askAbout(target, "wanted", () => this.lookupObject(target));
3718
3718
  }
3719
+ /**
3720
+ * The function a call returns: `app.use(requireCaller(config))`
3721
+ * registers what the factory gives back. A separate question from
3722
+ * `resolveCallable`, which keeps a call unresolved on purpose so an
3723
+ * unwrapping answer wins; this one is asked only after that has
3724
+ * declined. Two returned functions give null, like every other
3725
+ * single-answer question here.
3726
+ */
3727
+ resolveReturnedCallable(call) {
3728
+ const target = factKeyOf(call);
3729
+ return this.askAbout(target, "wanted", () => this.lookupReturned(target));
3730
+ }
3719
3731
  /**
3720
3732
  * For a value that is neither a function nor an object, such as a
3721
3733
  * GraphQL document kept in a constant in another file.
@@ -4159,6 +4171,21 @@ var ResolutionStore = class {
4159
4171
  }
4160
4172
  return [...candidates][0];
4161
4173
  }
4174
+ lookupReturned(call) {
4175
+ this.derive();
4176
+ const candidates = /* @__PURE__ */ new Set();
4177
+ for (const target of this.answersFor("wantedGivesBack", nodeId(call))) {
4178
+ const node = this.table.byId.get(target);
4179
+ if (node === void 0 || !isFunctionRoot(node)) {
4180
+ continue;
4181
+ }
4182
+ candidates.add(node);
4183
+ }
4184
+ if (candidates.size !== 1) {
4185
+ return null;
4186
+ }
4187
+ return [...candidates][0];
4188
+ }
4162
4189
  /**
4163
4190
  * Two candidates give null, since ambiguity is nothing. The value
4164
4191
  * itself is never a result either, or an identifier whose chain went
@@ -5286,7 +5313,27 @@ function functionValueOf(value, resolution) {
5286
5313
  return null;
5287
5314
  }
5288
5315
  const resolved = resolution.resolveCallable(written);
5289
- return resolved === null ? null : toFunctionRoot(resolved);
5316
+ if (resolved !== null) {
5317
+ return toFunctionRoot(resolved);
5318
+ }
5319
+ if (!Node17.isCallExpression(written)) {
5320
+ return null;
5321
+ }
5322
+ const returned = resolution.resolveReturnedCallable(written);
5323
+ return returned === null ? null : toFunctionRoot(returned);
5324
+ }
5325
+ function propertyNameOf(property) {
5326
+ if (Node17.isPropertyAssignment(property) || Node17.isShorthandPropertyAssignment(property) || Node17.isMethodDeclaration(property)) {
5327
+ return property.getName();
5328
+ }
5329
+ return null;
5330
+ }
5331
+ function propertyFunctionOf(property, resolution) {
5332
+ if (Node17.isMethodDeclaration(property)) {
5333
+ return property;
5334
+ }
5335
+ const held = propertyValueOf(property);
5336
+ return held === null ? null : functionValueOf(held, resolution);
5290
5337
  }
5291
5338
  function objectLiteralOf(value, resolution) {
5292
5339
  return literalValueOf(
@@ -8760,7 +8807,7 @@ function discoverResolverMaps(sourceFile, match, kind, resolution) {
8760
8807
  }
8761
8808
  const schemaSdl = extractTypeDefsSdl(config, store);
8762
8809
  for (const typeProp of propertiesOf(resolversObj, store)) {
8763
- const typeName = resolverPropertyName(typeProp);
8810
+ const typeName = propertyNameOf(typeProp);
8764
8811
  if (typeName === null || excludeTypes.has(typeName)) {
8765
8812
  continue;
8766
8813
  }
@@ -8769,11 +8816,11 @@ function discoverResolverMaps(sourceFile, match, kind, resolution) {
8769
8816
  continue;
8770
8817
  }
8771
8818
  for (const fieldProp of propertiesOf(typeObj, store)) {
8772
- const fieldName = resolverPropertyName(fieldProp);
8819
+ const fieldName = propertyNameOf(fieldProp);
8773
8820
  if (fieldName === null) {
8774
8821
  continue;
8775
8822
  }
8776
- const fn = resolverPropertyFunction(fieldProp, store);
8823
+ const fn = propertyFunctionOf(fieldProp, store);
8777
8824
  if (fn === null) {
8778
8825
  continue;
8779
8826
  }
@@ -8837,22 +8884,6 @@ function writtenSdl(expr) {
8837
8884
  }
8838
8885
  return null;
8839
8886
  }
8840
- function resolverPropertyName(prop) {
8841
- if (Node36.isPropertyAssignment(prop) || Node36.isMethodDeclaration(prop)) {
8842
- return prop.getName();
8843
- }
8844
- if (Node36.isShorthandPropertyAssignment(prop)) {
8845
- return prop.getName();
8846
- }
8847
- return null;
8848
- }
8849
- function resolverPropertyFunction(prop, resolution) {
8850
- if (Node36.isMethodDeclaration(prop)) {
8851
- return prop;
8852
- }
8853
- const held = propertyValueOf(prop);
8854
- return held === null ? null : functionValueOf(held, resolution);
8855
- }
8856
8887
 
8857
8888
  // src/discovery/index.ts
8858
8889
  function runPattern(sourceFile, pattern, resolution, mountPrefixes, expandedElsewhere) {
@@ -12265,7 +12296,7 @@ function countUnmatchedReturns(func, terminals, barriers = NO_BARRIERS) {
12265
12296
  });
12266
12297
  return unmatched;
12267
12298
  }
12268
- function extractRawBranches(func, terminalPatterns, invocationRecognizers = [], accessRecognizers = [], barriers = NO_BARRIERS, resolution, originatesFrom, anchorCallsOf, resolveCallee2) {
12299
+ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [], accessRecognizers = [], barriers = NO_BARRIERS, resolution, originatesFrom, anchorCallsOf, resolveCallee2, collectCallAccounting = false) {
12269
12300
  const terminals = findTerminals(
12270
12301
  func,
12271
12302
  terminalPatterns,
@@ -12353,8 +12384,8 @@ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [],
12353
12384
  seenBranches.add(key);
12354
12385
  return true;
12355
12386
  });
12387
+ const terminalNodes = new Set(terminals.map(({ node }) => node));
12356
12388
  if (invocations.length > 0) {
12357
- const terminalNodes = new Set(terminals.map(({ node }) => node));
12358
12389
  const sideEffects = invocations.filter(
12359
12390
  (i) => !writesTerminal(i.node, terminalNodes)
12360
12391
  );
@@ -12370,7 +12401,39 @@ function extractRawBranches(func, terminalPatterns, invocationRecognizers = [],
12370
12401
  branch.extraEffects = [...branch.extraEffects ?? [], ...extra];
12371
12402
  }
12372
12403
  }
12373
- return { branches: distinctBranches, terminals };
12404
+ return {
12405
+ branches: distinctBranches,
12406
+ terminals,
12407
+ ...collectCallAccounting ? {
12408
+ callAccounting: invocations.map(
12409
+ (site) => accountFor(site, terminalNodes, distinctBranches)
12410
+ )
12411
+ } : {}
12412
+ };
12413
+ }
12414
+ function accountFor(site, terminalNodes, branches) {
12415
+ const { node, line } = site;
12416
+ const callee = node.getExpression().getText();
12417
+ if (writesTerminal(node, terminalNodes)) {
12418
+ return { node, callee, line, outcome: "terminal" };
12419
+ }
12420
+ const call = {
12421
+ line,
12422
+ alwaysRuns: site.alwaysRuns,
12423
+ preconditions: preconditionsOf(site.effect)
12424
+ };
12425
+ if (branches.some((branch) => firesOn(call, branch))) {
12426
+ return { node, callee, line, outcome: "invocation" };
12427
+ }
12428
+ const reachable = branches.some(
12429
+ (branch) => site.alwaysRuns || runsBefore(line, branch.terminal.location.end)
12430
+ );
12431
+ return {
12432
+ node,
12433
+ callee,
12434
+ line,
12435
+ outcome: reachable ? "unrecorded" : "unreachable"
12436
+ };
12374
12437
  }
12375
12438
 
12376
12439
  // src/bootstrap/sourceFileLookup.ts
@@ -12585,7 +12648,7 @@ function unwrapContractInit(init) {
12585
12648
  }
12586
12649
  return null;
12587
12650
  }
12588
- function extractEndpointContract(endpointNode, pattern, framework) {
12651
+ function extractEndpointContract(endpointNode, pattern, framework, resolution) {
12589
12652
  if (!Node54.isObjectLiteralExpression(endpointNode)) {
12590
12653
  return null;
12591
12654
  }
@@ -12610,9 +12673,10 @@ function extractEndpointContract(endpointNode, pattern, framework) {
12610
12673
  }
12611
12674
  }
12612
12675
  if (propName === pattern.responseExtraction.property) {
12613
- const val = prop.getInitializer();
12614
- if (val !== void 0 && Node54.isObjectLiteralExpression(val)) {
12615
- for (const respProp of val.getProperties()) {
12676
+ const written = prop.getInitializer();
12677
+ const val = written === void 0 ? null : objectLiteralOf(written, resolution);
12678
+ if (val !== null) {
12679
+ for (const respProp of propertiesOf(val, resolution)) {
12616
12680
  if (!Node54.isPropertyAssignment(respProp)) {
12617
12681
  continue;
12618
12682
  }
@@ -12651,7 +12715,12 @@ function readContract(unit, pattern, framework, resolution) {
12651
12715
  if (endpointNode === null) {
12652
12716
  return null;
12653
12717
  }
12654
- return extractEndpointContract(endpointNode, pattern, framework);
12718
+ return extractEndpointContract(
12719
+ endpointNode,
12720
+ pattern,
12721
+ framework,
12722
+ resolution
12723
+ );
12655
12724
  }
12656
12725
  const routerInfo = findRouterCall(unit);
12657
12726
  if (routerInfo === null) {
@@ -12672,7 +12741,12 @@ function readContract(unit, pattern, framework, resolution) {
12672
12741
  if (endpointInit === void 0) {
12673
12742
  continue;
12674
12743
  }
12675
- return extractEndpointContract(endpointInit, pattern, framework);
12744
+ return extractEndpointContract(
12745
+ endpointInit,
12746
+ pattern,
12747
+ framework,
12748
+ resolution
12749
+ );
12676
12750
  }
12677
12751
  return null;
12678
12752
  }
@@ -12749,7 +12823,12 @@ function readContractForClientCall(callExpression, methodName, pattern, framewor
12749
12823
  if (endpointInit === void 0) {
12750
12824
  continue;
12751
12825
  }
12752
- return extractEndpointContract(endpointInit, pattern, framework);
12826
+ return extractEndpointContract(
12827
+ endpointInit,
12828
+ pattern,
12829
+ framework,
12830
+ resolution
12831
+ );
12753
12832
  }
12754
12833
  return null;
12755
12834
  }
@@ -13509,7 +13588,11 @@ function recordEdge(edgesByChild, candidate) {
13509
13588
  // src/discovery/wrapperIndex.ts
13510
13589
  import { Node as Node58 } from "ts-morph";
13511
13590
  import { joinMountedPath as joinMountedPath3 } from "@suss/resolution";
13512
- var NO_WRAPPERS = { wrappersFor: () => [], unitsIn: () => [] };
13591
+ var NO_WRAPPERS = {
13592
+ wrappersFor: () => [],
13593
+ unfollowedFor: () => [],
13594
+ unitsIn: () => []
13595
+ };
13513
13596
  var ANONYMOUS = "<anon>";
13514
13597
  function buildWrapperIndex(packsByFile, resolution, mountPrefixes) {
13515
13598
  const workByPack = /* @__PURE__ */ new Map();
@@ -13535,21 +13618,32 @@ function buildWrapperIndex(packsByFile, resolution, mountPrefixes) {
13535
13618
  }
13536
13619
  }
13537
13620
  const bySubject = /* @__PURE__ */ new Map();
13621
+ const unfollowedBySubject = /* @__PURE__ */ new Map();
13538
13622
  const unitsByFile = /* @__PURE__ */ new Map();
13623
+ const stopsSeen = /* @__PURE__ */ new Set();
13539
13624
  let found = false;
13540
13625
  for (const [packName, work] of workByPack) {
13541
13626
  const candidates = [];
13542
13627
  for (const { sourceFile, pattern, match, wraps } of work) {
13543
- candidates.push(
13544
- ...discoverWrapperRegistrations(
13545
- sourceFile,
13546
- pattern,
13547
- match,
13548
- wraps,
13549
- resolution,
13550
- mountPrefixes
13551
- )
13628
+ const scan = discoverWrapperRegistrations(
13629
+ sourceFile,
13630
+ pattern,
13631
+ match,
13632
+ wraps,
13633
+ resolution,
13634
+ mountPrefixes
13552
13635
  );
13636
+ candidates.push(...scan.candidates);
13637
+ for (const { subjectId, callId, stop } of scan.unresolved) {
13638
+ if (stopsSeen.has(callId)) {
13639
+ continue;
13640
+ }
13641
+ stopsSeen.add(callId);
13642
+ found = true;
13643
+ const stops = unfollowedBySubject.get(subjectId) ?? [];
13644
+ stops.push(stop);
13645
+ unfollowedBySubject.set(subjectId, stops);
13646
+ }
13553
13647
  }
13554
13648
  for (const candidate of mostSpecific(candidates)) {
13555
13649
  found = true;
@@ -13567,6 +13661,7 @@ function buildWrapperIndex(packsByFile, resolution, mountPrefixes) {
13567
13661
  }
13568
13662
  return {
13569
13663
  wrappersFor: (subjectId) => bySubject.get(subjectId) ?? [],
13664
+ unfollowedFor: (subjectId) => unfollowedBySubject.get(subjectId) ?? [],
13570
13665
  unitsIn: (file, pack) => unitsByFile.get(unitKey(file, pack)) ?? []
13571
13666
  };
13572
13667
  }
@@ -13600,10 +13695,20 @@ function discoverWrapperRegistrations(sourceFile, pattern, match, wraps, resolut
13600
13695
  match.importName,
13601
13696
  resolution
13602
13697
  );
13698
+ if ("constructorOption" in wraps) {
13699
+ return discoverConstructorOptions(
13700
+ sourceFile,
13701
+ pattern,
13702
+ wraps,
13703
+ subjects,
13704
+ resolution
13705
+ );
13706
+ }
13603
13707
  if (subjects.size === 0 && !storeCanFindSubjects(sourceFile, match, resolution)) {
13604
- return [];
13708
+ return { candidates: [], unresolved: [] };
13605
13709
  }
13606
13710
  const candidates = [];
13711
+ const unresolved = [];
13607
13712
  sourceFile.forEachDescendant((node) => {
13608
13713
  if (!Node58.isCallExpression(node)) {
13609
13714
  return;
@@ -13626,8 +13731,13 @@ function discoverWrapperRegistrations(sourceFile, pattern, match, wraps, resolut
13626
13731
  if (targetArg === void 0) {
13627
13732
  return;
13628
13733
  }
13734
+ const subjectId = nodeId(subjectNode);
13629
13735
  const target = functionValueOf(targetArg, resolution);
13630
13736
  if (target === null) {
13737
+ const stop = factoryStopOf(targetArg);
13738
+ if (stop !== null) {
13739
+ unresolved.push({ subjectId, callId: nodeId(node), stop });
13740
+ }
13631
13741
  return;
13632
13742
  }
13633
13743
  if (wraps.arity !== void 0 && target.getParameters().length !== wraps.arity) {
@@ -13637,29 +13747,136 @@ function discoverWrapperRegistrations(sourceFile, pattern, match, wraps, resolut
13637
13747
  if (scope === null) {
13638
13748
  return;
13639
13749
  }
13640
- const subjectId = nodeId(subjectNode);
13641
13750
  const mountedScope = scope === void 0 ? void 0 : mountedAt(subjectId, mountPrefixes, scope);
13642
- const named2 = functionNameOrAnon(target) !== ANONYMOUS;
13643
- candidates.push({
13644
- subjectId,
13645
- callId: nodeId(node),
13646
- targetId: nodeId(target),
13647
- byArity: wraps.arity !== void 0,
13648
- target,
13649
- pattern,
13650
- registeredIn: sourceFile.getFilePath(),
13651
- named: named2,
13652
- reference: {
13653
- file: target.getSourceFile().getFilePath(),
13654
- // A function written out at the registration call has no name
13655
- // of its own, so it goes by the method that registered it.
13656
- name: named2 ? functionNameOrAnon(target) : wraps.method,
13657
- ...wraps.throwParam === void 0 ? {} : { onThrow: true },
13658
- ...mountedScope === void 0 ? {} : { scope: mountedScope }
13659
- }
13660
- });
13751
+ candidates.push(
13752
+ candidateOf(
13753
+ {
13754
+ subjectId,
13755
+ callId: nodeId(node),
13756
+ target,
13757
+ label: labelFor(targetArg, wraps),
13758
+ byArity: wraps.arity !== void 0,
13759
+ onThrow: wraps.throwParam !== void 0,
13760
+ scope: mountedScope
13761
+ },
13762
+ pattern,
13763
+ sourceFile
13764
+ )
13765
+ );
13661
13766
  });
13662
- return candidates;
13767
+ return { candidates, unresolved };
13768
+ }
13769
+ function discoverConstructorOptions(sourceFile, pattern, wraps, subjects, resolution) {
13770
+ const candidates = [];
13771
+ const unresolved = [];
13772
+ const seen = /* @__PURE__ */ new Set();
13773
+ for (const construction of subjects.values()) {
13774
+ const subjectId = nodeId(construction);
13775
+ if (seen.has(subjectId) || construction.getSourceFile() !== sourceFile) {
13776
+ continue;
13777
+ }
13778
+ seen.add(subjectId);
13779
+ const option = constructorOptionOf(construction, wraps, resolution);
13780
+ if (option === void 0) {
13781
+ continue;
13782
+ }
13783
+ const callId = nodeId(option);
13784
+ const written = propertyValueOf(option);
13785
+ const target = propertyFunctionOf(option, resolution);
13786
+ if (target === null) {
13787
+ const stop = written === null ? null : factoryStopOf(written);
13788
+ if (stop !== null) {
13789
+ unresolved.push({ subjectId, callId, stop });
13790
+ }
13791
+ continue;
13792
+ }
13793
+ candidates.push(
13794
+ candidateOf(
13795
+ {
13796
+ subjectId,
13797
+ callId,
13798
+ target,
13799
+ label: (written === null ? void 0 : factoryNameOf(written)) ?? wraps.constructorOption,
13800
+ byArity: false,
13801
+ onThrow: wraps.throwParam !== void 0,
13802
+ scope: void 0
13803
+ },
13804
+ pattern,
13805
+ sourceFile
13806
+ )
13807
+ );
13808
+ }
13809
+ return { candidates, unresolved };
13810
+ }
13811
+ function constructorOptionOf(construction, wraps, resolution) {
13812
+ if (!(Node58.isNewExpression(construction) || Node58.isCallExpression(construction))) {
13813
+ return void 0;
13814
+ }
13815
+ const optionsArg = construction.getArguments()[wraps.targetPosition];
13816
+ if (optionsArg === void 0) {
13817
+ return void 0;
13818
+ }
13819
+ const options = objectLiteralOf(optionsArg, resolution);
13820
+ if (options === null) {
13821
+ return void 0;
13822
+ }
13823
+ return propertiesOf(options, resolution).find(
13824
+ (property) => propertyNameOf(property) === wraps.constructorOption
13825
+ );
13826
+ }
13827
+ function candidateOf(registration, pattern, sourceFile) {
13828
+ const { target, label, onThrow, scope } = registration;
13829
+ const named2 = functionNameOrAnon(target) !== ANONYMOUS;
13830
+ return {
13831
+ subjectId: registration.subjectId,
13832
+ callId: registration.callId,
13833
+ targetId: nodeId(target),
13834
+ byArity: registration.byArity,
13835
+ target,
13836
+ pattern,
13837
+ registeredIn: sourceFile.getFilePath(),
13838
+ named: named2,
13839
+ reference: {
13840
+ file: target.getSourceFile().getFilePath(),
13841
+ name: named2 ? functionNameOrAnon(target) : label,
13842
+ ...onThrow ? { onThrow: true } : {},
13843
+ ...scope === void 0 ? {} : { scope }
13844
+ }
13845
+ };
13846
+ }
13847
+ function labelFor(targetArg, wraps) {
13848
+ return factoryNameOf(targetArg) ?? wraps.method;
13849
+ }
13850
+ function factoryNameOf(targetArg) {
13851
+ const written = factKeyOf(targetArg);
13852
+ if (!Node58.isCallExpression(written)) {
13853
+ return void 0;
13854
+ }
13855
+ const callee = written.getExpression();
13856
+ if (Node58.isIdentifier(callee)) {
13857
+ return callee.getText();
13858
+ }
13859
+ if (Node58.isPropertyAccessExpression(callee)) {
13860
+ return callee.getName();
13861
+ }
13862
+ return void 0;
13863
+ }
13864
+ function factoryStopOf(targetArg) {
13865
+ const written = factKeyOf(targetArg);
13866
+ if (!Node58.isCallExpression(written)) {
13867
+ return null;
13868
+ }
13869
+ const callee = factoryNameOf(targetArg);
13870
+ if (callee === void 0) {
13871
+ return null;
13872
+ }
13873
+ const reason = classifyStop(
13874
+ declarationsBehind(written.getExpression().getSymbol())
13875
+ );
13876
+ if (!worthRecording(reason)) {
13877
+ return null;
13878
+ }
13879
+ return { callee, reason: "unresolvedWrapper" };
13663
13880
  }
13664
13881
  function mountedAt(subjectId, mountPrefixes, scope) {
13665
13882
  const prefix = mountPrefixes?.prefixForId?.(subjectId) ?? "";
@@ -14034,22 +14251,23 @@ import { Node as Node60 } from "ts-morph";
14034
14251
  import { functionCallBinding, TargetPlacements } from "@suss/behavioral-ir";
14035
14252
  import { Database as Database3, evaluate as evaluate4, lit as lit4, rule as rule4, variable as variable2 } from "@suss/datalog";
14036
14253
  import { assembleSummary as assembleSummary2 } from "@suss/extractor";
14254
+ var GENERIC_TERMINALS = [
14255
+ { kind: "return", match: { type: "returnStatement" }, extraction: {} },
14256
+ { kind: "throw", match: { type: "throwExpression" }, extraction: {} },
14257
+ {
14258
+ // Implicit fall-through at the end of a function body: covers
14259
+ // void-returning orchestrators that never write `return`.
14260
+ kind: "return",
14261
+ match: { type: "functionFallthrough" },
14262
+ extraction: {}
14263
+ }
14264
+ ];
14037
14265
  var reachablePack = {
14038
14266
  name: "reachable",
14039
14267
  languages: ["typescript"],
14040
14268
  protocol: "in-process",
14041
14269
  discovery: [],
14042
- terminals: [
14043
- { kind: "return", match: { type: "returnStatement" }, extraction: {} },
14044
- { kind: "throw", match: { type: "throwExpression" }, extraction: {} },
14045
- {
14046
- // Implicit fall-through at the end of a function body: covers
14047
- // void-returning orchestrators that never write `return`.
14048
- kind: "return",
14049
- match: { type: "functionFallthrough" },
14050
- extraction: {}
14051
- }
14052
- ],
14270
+ terminals: GENERIC_TERMINALS,
14053
14271
  inputMapping: { type: "allPositional" }
14054
14272
  };
14055
14273
  function nodeKey(func) {
@@ -15854,10 +16072,10 @@ var FUNCTION_FALLTHROUGH_TERMINAL = {
15854
16072
  match: { type: "functionFallthrough" },
15855
16073
  extraction: {}
15856
16074
  };
15857
- function thrownValueAt(unit) {
15858
- return unit.pattern?.wraps?.throwParam;
16075
+ function frameworkValueAt(unit) {
16076
+ return unit.pattern?.wraps?.throwParam ?? unit.pattern?.wraps?.resultParam;
15859
16077
  }
15860
- function pastThrownValue(terminals, at) {
16078
+ function pastFrameworkValue(terminals, at) {
15861
16079
  if (at === void 0) {
15862
16080
  return terminals;
15863
16081
  }
@@ -15871,7 +16089,7 @@ function pastThrownValue(terminals, at) {
15871
16089
  } : pattern
15872
16090
  );
15873
16091
  }
15874
- function rolesPastThrownValue(mapping, at) {
16092
+ function rolesPastFrameworkValue(mapping, at) {
15875
16093
  if (at === void 0 || mapping.type !== "positionalParams") {
15876
16094
  return mapping;
15877
16095
  }
@@ -15897,7 +16115,7 @@ function continuationTerminal(unit) {
15897
16115
  }
15898
16116
  function terminalsFor(unit, pack) {
15899
16117
  const declared = [
15900
- ...unit.terminals ?? pastThrownValue(pack.terminals, thrownValueAt(unit)),
16118
+ ...unit.terminals ?? pastFrameworkValue(pack.terminals, frameworkValueAt(unit)),
15901
16119
  ...continuationTerminal(unit)
15902
16120
  ];
15903
16121
  if (unit.callSite === void 0) {
@@ -15915,7 +16133,7 @@ function readCodeStructure(unit, pack, invocationRecognizers, accessRecognizers,
15915
16133
  }
15916
16134
  const params = extractParameters(
15917
16135
  func,
15918
- unit.inputMapping ?? rolesPastThrownValue(pack.inputMapping, thrownValueAt(unit))
16136
+ unit.inputMapping ?? rolesPastFrameworkValue(pack.inputMapping, frameworkValueAt(unit))
15919
16137
  );
15920
16138
  const extracted = extractRawBranches(
15921
16139
  func,
@@ -16417,8 +16635,10 @@ function extractFromSourceFile(sourceFile, frameworks, claimedUnits, options, ta
16417
16635
  }
16418
16636
  }
16419
16637
  const summary = assembleSummary3(raw, options);
16420
- if (unit.unfollowed !== void 0 && options?.gapHandling !== "silent") {
16421
- summary.gaps.push(unfollowedCallGap(unit.unfollowed));
16638
+ if (options?.gapHandling !== "silent") {
16639
+ for (const stop of unfollowedStopsOf(unit, wrappers)) {
16640
+ summary.gaps.push(unfollowedCallGap(stop));
16641
+ }
16422
16642
  }
16423
16643
  if (unit.metadata !== void 0 && Object.keys(unit.metadata).length > 0) {
16424
16644
  summary.metadata = {
@@ -16471,6 +16691,13 @@ function stampWrappers(raw, unit, wrappers) {
16471
16691
  recordFileDependency(wrapper.file);
16472
16692
  }
16473
16693
  }
16694
+ function unfollowedStopsOf(unit, wrappers) {
16695
+ const stops = unit.unfollowed === void 0 ? [] : [unit.unfollowed];
16696
+ if (wrappers === void 0 || unit.registrationSubjectId === void 0) {
16697
+ return stops;
16698
+ }
16699
+ return [...stops, ...wrappers.unfollowedFor(unit.registrationSubjectId)];
16700
+ }
16474
16701
  function emitLibraryEnvReadMarkers(summaries, project, frameworks) {
16475
16702
  for (const pack of frameworks) {
16476
16703
  for (const declared of pack.libraryEnvVars ?? []) {
@@ -17185,7 +17412,7 @@ function createTypeScriptAdapter(suppliedConfig) {
17185
17412
  });
17186
17413
  const composed = timer.time(
17187
17414
  "composeWrappers",
17188
- () => composeWrappers(enriched)
17415
+ () => composeWrappers(enriched, config.extractorOptions ?? {})
17189
17416
  );
17190
17417
  if (config.onTiming !== void 0) {
17191
17418
  config.onTiming(timer.report());
@@ -17809,6 +18036,8 @@ function stubEvidence(options) {
17809
18036
  }
17810
18037
  export {
17811
18038
  ADAPTER_VERSION,
18039
+ GENERIC_TERMINALS,
18040
+ NO_BARRIERS,
17812
18041
  ResolutionStore,
17813
18042
  TypeScriptWhySession,
17814
18043
  accessContextFor,
@@ -17829,6 +18058,7 @@ export {
17829
18058
  findNearestTsconfig,
17830
18059
  findTerminals,
17831
18060
  functionTargetOf,
18061
+ hasBody,
17832
18062
  importDeclarationsOf,
17833
18063
  importedNamesOf,
17834
18064
  importedRootsOf,
@@ -17844,6 +18074,7 @@ export {
17844
18074
  resolveAliasedSymbol,
17845
18075
  resolveSubject,
17846
18076
  rootIdentifier,
18077
+ startsItsOwnScope,
17847
18078
  stubEvidence,
17848
18079
  stubEvidenceIn,
17849
18080
  workspaceRootFor
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "@suss/adapter-typescript",
3
- "version": "0.22.3",
3
+ "version": "0.22.4",
4
4
  "type": "module",
5
- "description": "TypeScript adapter for suss — walks source files with ts-morph and emits raw extractions for the suss pipeline.",
5
+ "description": "Read a TypeScript or JavaScript codebase with suss and check what each handler returns against every caller, spec and template it can see.",
6
6
  "keywords": [
7
7
  "suss",
8
- "behavioral-summary",
9
8
  "static-analysis",
10
9
  "typescript",
10
+ "javascript",
11
11
  "ts-morph",
12
- "ast"
12
+ "api-contract",
13
+ "api-drift",
14
+ "code-review"
13
15
  ],
14
16
  "license": "Apache-2.0",
15
17
  "author": "Nimbus Cloud AI LLC",
@@ -46,11 +48,11 @@
46
48
  "typecheck": "tsc --noEmit"
47
49
  },
48
50
  "dependencies": {
49
- "@suss/behavioral-ir": "0.22.3",
50
- "@suss/datalog": "0.22.3",
51
- "@suss/extractor": "0.22.3",
52
- "@suss/resolution": "0.22.3",
53
- "@suss/values": "0.22.3",
51
+ "@suss/behavioral-ir": "0.22.4",
52
+ "@suss/datalog": "0.22.4",
53
+ "@suss/extractor": "0.22.4",
54
+ "@suss/resolution": "0.22.4",
55
+ "@suss/values": "0.22.4",
54
56
  "graphql": "^16.8.0",
55
57
  "picomatch": "^4.0.4",
56
58
  "ts-morph": "^23.0.0",