@suss/adapter-typescript 0.33.1 → 0.34.1

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.d.ts CHANGED
@@ -1,22 +1,64 @@
1
- import { SourceFile, Node, Project, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, Symbol, CallExpression, PropertyAccessExpression, TaggedTemplateExpression, ImportDeclaration, ArrayLiteralExpression, ObjectLiteralExpression, ObjectLiteralElementLike, Expression, NewExpression, Identifier } from 'ts-morph';
2
- import { TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, EffectArg, CallOps, LanguageAdapter, PatternPack, ExtractorOptions, TimingReport, CacheDiagnostic, ExtractionReport, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, configuredCallOption, RawDeclaredContract, ContractPattern, AstCapableOps, ResponsePropertyMapping } from '@suss/extractor';
1
+ import { SourceFile, Node, Project, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, Symbol, CallExpression, NewExpression, TaggedTemplateExpression, PropertyAccessExpression, Expression, ImportDeclaration, ArrayLiteralExpression, ObjectLiteralExpression, ObjectLiteralElementLike, Identifier } from 'ts-morph';
2
+ import { PatternPack, TransparentWrapper, ParameterSupplier, VersionPlacement, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, ArgumentParser, StatedSlot, AstCapableOps, CallOps, EffectArg, LanguageAdapter, ExtractorOptions, TimingReport, CacheDiagnostic, ExtractionReport, DeclaredModule, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, ResponsePropertyMapping, RawBranch, KeepsArms, configuredCallOption, RawDeclaredContract, ContractPattern } from '@suss/extractor';
3
3
  export { EmptyStage, ExtractionReport, PackFunnel, Timer, TimingReport, computeContentHash } from '@suss/extractor';
4
- import { MessageBusSemantics, DeployableUnit, UnfollowedCall, WrapperReference, BehavioralSummary, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
5
- import { ExplainStats, WhyExplained, ValueLocation } from '@suss/resolution';
4
+ import { MessageBusSemantics, DeployableUnit, UnfollowedCall, WrapperReference, Effect, BehavioralSummary, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
5
+ import { ExplainStats, SourceLeaf, ValueUses, WhyExplained, ValueLocation } from '@suss/resolution';
6
6
  export { ExplainStats, ValueLocation, WhyExplained } from '@suss/resolution';
7
7
  import { Proof, Atom } from '@suss/datalog';
8
8
  import { z } from 'zod';
9
9
 
10
+ /** How the packs in a run spell the parts of the process nothing declares. */
11
+ interface RuntimeSpellings {
12
+ streamObjects: readonly string[];
13
+ exitCalls: readonly string[];
14
+ exitCodeWrites: readonly string[];
15
+ }
16
+
17
+ /**
18
+ * A library's own module, written into the project by that library's
19
+ * code generator.
20
+ *
21
+ * A pack says which file its generator leaves beside the module it
22
+ * wrote, and a directory containing that file counts as the package. A
23
+ * pack whose generator leaves no such file says instead where the
24
+ * project's configuration tells the generator to write. The README says
25
+ * why the import gate needs this.
26
+ */
27
+
28
+ type DirFinder = NonNullable<PatternPack["generatedModuleDirs"]>;
29
+ declare class GeneratedModules {
30
+ private readonly markers;
31
+ private readonly finders;
32
+ private readonly generatedDirs;
33
+ private readonly declaredDirs;
34
+ constructor(markers: ReadonlyArray<string>, finders?: ReadonlyArray<{
35
+ pack: string;
36
+ find: DirFinder;
37
+ }>);
38
+ /** Whether any pack asked for a generated module to be looked for. */
39
+ get declared(): boolean;
40
+ /** Distinguishes two asks about one package that declare different markers. */
41
+ get key(): string;
42
+ /**
43
+ * Whether any of this file's specifiers points into a directory the
44
+ * generator wrote. A specifier can name the directory itself or a
45
+ * file in it, so both are checked.
46
+ */
47
+ reachedFrom(fromFile: string, specifiers: ReadonlyArray<string>): boolean;
48
+ private isGenerated;
49
+ private isDeclaredOutput;
50
+ }
51
+
10
52
  /** One question: do these files reach any of these packages. */
11
53
  interface FileSetQuery {
12
54
  sourceFiles: ReadonlyArray<SourceFile>;
13
55
  packages: ReadonlyArray<string>;
14
56
  /**
15
- * Files the asking pack's code generator leaves beside a module it
16
- * wrote into the project. A relative import into such a directory
17
- * counts as an import of the package.
57
+ * Where the asking pack's code generator writes a module into the
58
+ * project. A relative import into such a directory counts as an
59
+ * import of the package.
18
60
  */
19
- generatedMarkers?: ReadonlyArray<string>;
61
+ generated?: GeneratedModules;
20
62
  }
21
63
 
22
64
  /**
@@ -33,6 +75,16 @@ interface FileSetQuery {
33
75
  * local barrel re-exports the SDK.
34
76
  */
35
77
 
78
+ /** One place a value's walk ended, with the nodes the store keyed it by. */
79
+ interface SourceFound {
80
+ leaf: SourceLeaf;
81
+ /** The node the walk ended at, or null when the store keyed none. */
82
+ node: Node | null;
83
+ /** The read at a computed key on the way, when there was one. */
84
+ computedAt: Node | null;
85
+ /** The function a parameter the walk ended at belongs to. */
86
+ parameterOf: Node | null;
87
+ }
36
88
  interface ExplainCallableOptions {
37
89
  /** A second file to walk out from; see `resolveCallable`. */
38
90
  alsoFrom?: SourceFile;
@@ -82,19 +134,25 @@ declare class ResolutionStore {
82
134
  /** Keyed by value and site both, since one value differs per site. */
83
135
  private readonly writtenUnderSite;
84
136
  private readonly constructionSites;
137
+ /** What each local's reads do with it, by its declaration. A local's function is walked whole, so an answer stays true. */
138
+ private readonly localUses;
85
139
  /** Files the most recent query read, for the memo to keep. */
86
140
  private lastQueryWalked;
87
141
  /** See `environmentSiteFiles`; null until the first env question. */
88
142
  private envSiteFiles;
89
143
  /** See `environmentAnswers`; null until the first env question. */
90
144
  private envAnswers;
145
+ /** See `streamAnswers`: the declared streams each expression reaches. */
146
+ private streamsReached;
91
147
  private readonly declarations;
92
148
  private readonly graph;
93
149
  /** See `notePossibleCallers`. */
94
150
  private readonly possibleCallers;
95
151
  private readonly callerFilesRead;
96
152
  private stale;
97
- constructor(wrappers?: TransparentWrapper[], environmentObjects?: readonly string[]);
153
+ constructor(wrappers?: TransparentWrapper[], environmentObjects?: readonly string[], runtime?: RuntimeSpellings, parameterSuppliers?: readonly ParameterSupplier[]);
154
+ /** A store with the wrappers and runtime objects these packs declare, as an extraction over them starts from. */
155
+ static forPacks(packs: readonly PatternPack[]): ResolutionStore;
98
156
  /**
99
157
  * `alsoFrom` is a second file to walk out from, for a caller that
100
158
  * knows where the value it is asking about was set up. The walk
@@ -110,6 +168,12 @@ declare class ResolutionStore {
110
168
  * folding into the same nothing as a chain that went nowhere.
111
169
  */
112
170
  resolveCallableSources(value: Node, alsoFrom?: SourceFile): Node[];
171
+ /**
172
+ * `resolveCallable` for several values, asked as one question. A file
173
+ * with a receiver at every call would otherwise derive and clear the
174
+ * rules once per receiver.
175
+ */
176
+ resolveCallables(values: readonly Node[]): Map<Node, Node | null>;
113
177
  /**
114
178
  * The witness proof behind `resolveCallable`'s answer. Resolves the
115
179
  * value first, which extracts the files the question demands, then
@@ -128,11 +192,43 @@ declare class ResolutionStore {
128
192
  * single-answer question here.
129
193
  */
130
194
  resolveReturnedCallable(call: Node): Node | null;
195
+ /**
196
+ * The function a call through this value runs: the one it comes down
197
+ * to, and failing that the one it gives back, so a name written as
198
+ * `useNavigator()` runs what that factory returned. Both answers come
199
+ * from the same derivation, so asking them together costs one query.
200
+ */
201
+ resolveCalledFunction(value: Node): Node | null;
202
+ /**
203
+ * The batched form, for a caller with a body's worth of callees: one
204
+ * demand set and one derivation shared by all of them, where asking
205
+ * each alone re-derives once per value.
206
+ */
207
+ resolveCalledFunctions(values: readonly Node[]): Map<Node, Node | null>;
208
+ private calledFunctionOf;
131
209
  /**
132
210
  * For a value that is neither a function nor an object, such as a
133
211
  * GraphQL document kept in a constant in another file.
134
212
  */
135
213
  resolveWrittenValue(value: Node): Node | null;
214
+ /**
215
+ * Where each value came from, asked as one question: every place the
216
+ * walk from it ended, with the node there and, for a parameter, the
217
+ * function it belongs to.
218
+ */
219
+ sourcesOf(values: readonly Node[]): Map<Node, SourceFound[]>;
220
+ /**
221
+ * `resolveWrittenValue` for several values, asked as one question.
222
+ * Values that share a declaration share one answer, as they do when
223
+ * asked one at a time.
224
+ */
225
+ resolveWrittenValues(values: readonly Node[]): Map<Node, Node | null>;
226
+ /**
227
+ * The class a name refers to, asked the same narrow way. A class is
228
+ * not an expression, so `resolveWrittenValue` never gives one back.
229
+ */
230
+ resolveWrittenClass(value: Node): Node | null;
231
+ private writtenAnswers;
136
232
  /**
137
233
  * The same question under one construction site: what the value is
138
234
  * when the receiver behind it is the instance that site made. A field
@@ -213,6 +309,36 @@ declare class ResolutionStore {
213
309
  * project's own sources and it happens once.
214
310
  */
215
311
  private environmentSiteFiles;
312
+ /**
313
+ * Which output stream a receiver is, for a writer standing at
314
+ * `out.write(...)`: the path a pack declared, such as
315
+ * `process.stdout`. Null when it is a stream and the source does not
316
+ * settle which one, and undefined when nothing says it is a stream.
317
+ *
318
+ * A receiver the source does not spell as a stream is looked up in
319
+ * one answer worked out for the whole run, so a question is never
320
+ * asked per call. A parameter nothing in the run passes a stream to
321
+ * is still a stream when it is annotated as one of `streamTypes`.
322
+ */
323
+ streamPathOf(receiver: Node, streamTypes: readonly string[]): string | null | undefined;
324
+ private streamAnswers;
325
+ /**
326
+ * The environment's loop for the streams: ask, read the callee of every
327
+ * call that hands a stream on, and ask again until no new call turns up.
328
+ */
329
+ private followStreams;
330
+ private askStreams;
331
+ /**
332
+ * The functions whose return becomes the process's exit code, asked
333
+ * once from the files that end the process or set its exit code. Each
334
+ * value that ends up as the code seeds the walk; DESIGN.md in the
335
+ * resolution package says how it gets from there to a function.
336
+ */
337
+ exitCodeFunctions(project: Project): readonly Node[];
338
+ /** The values that end up as the exit code: an exit call's first argument, or what is assigned to the code. */
339
+ private exitSinks;
340
+ /** Whether the parameter a name refers to is annotated as one of these types. */
341
+ private annotatedAsOneOf;
216
342
  /**
217
343
  * Whether running this function hands back that call: returned
218
344
  * outright, written into a name and returned, or a shorthand body.
@@ -220,6 +346,13 @@ declare class ResolutionStore {
220
346
  * what keeps a wrapper's own result apart from the library's.
221
347
  */
222
348
  returnsCall(func: Node, call: Node): boolean;
349
+ /**
350
+ * What the reads of a local do with it, when `receiver` is a local a
351
+ * function declares once as `construction`. Null for anything else,
352
+ * such as a module-level value, which some other file may serve.
353
+ */
354
+ usesOfLocal(receiver: Node, construction: Node): ValueUses | null;
355
+ private askLocalUses;
223
356
  /**
224
357
  * Files a later question about a parameter may find a caller in.
225
358
  * Without this the search falls back to every file the project has
@@ -255,7 +388,8 @@ declare class ResolutionStore {
255
388
  * declared name.
256
389
  */
257
390
  private constructionComesFrom;
258
- private calleeNameOf;
391
+ /** The callee of a call, as written. */
392
+ private calleeTextOf;
259
393
  /**
260
394
  * Which names from `modules` this value comes down to, either by being
261
395
  * one of them under a local name or by calling into one. Getting
@@ -295,6 +429,12 @@ declare class ResolutionStore {
295
429
  private lookupImportOrigins;
296
430
  private lookupImportedNames;
297
431
  private askAbout;
432
+ /**
433
+ * One question about several values: one demand set, one round of
434
+ * extraction and one derivation shared by all of them. Asking each
435
+ * alone pays the rounds, the clear and the allocation once per value.
436
+ */
437
+ private askAboutAll;
298
438
  /**
299
439
  * Extract the seed files, then every module the rules ask for, until
300
440
  * they ask for nothing new. The files a question reads are then fixed
@@ -331,7 +471,12 @@ declare class ResolutionStore {
331
471
  */
332
472
  private seedValue;
333
473
  private lookupObject;
474
+ /**
475
+ * A factory returning a wrapper's call gives back the wrapper's own
476
+ * closure and the function it unwraps. The unwrapped one wins.
477
+ */
334
478
  private lookupReturned;
479
+ private singleFunctionIn;
335
480
  /**
336
481
  * Two candidates give null, since ambiguity is nothing. The value
337
482
  * itself is never a result either, or an identifier whose chain went
@@ -341,6 +486,8 @@ declare class ResolutionStore {
341
486
  * construction makes an instance of. The README says why.
342
487
  */
343
488
  private lookupWritten;
489
+ /** The one class among what a value is written as, under the same policy. */
490
+ private lookupWrittenClass;
344
491
  /**
345
492
  * Read these files' facts now, before anything asks a question.
346
493
  *
@@ -388,6 +535,66 @@ declare class ResolutionStore {
388
535
  private extractFile;
389
536
  }
390
537
 
538
+ /**
539
+ * The path an application puts in front of every route it serves.
540
+ *
541
+ * NestJS serves each decorated route under whatever the bootstrap's
542
+ * `app.setGlobalPrefix("api")` says, in a file with no controller in it.
543
+ * A call counts when the store says its receiver is the app the
544
+ * framework's factory made, following a parameter to every caller. The
545
+ * prefix and its exclusions are read through the value evaluator, and
546
+ * every call in the run has to agree, or no prefix is applied.
547
+ */
548
+
549
+ /** A route the prefix leaves out. A null method leaves out every verb. */
550
+ interface ExcludedRoute {
551
+ path: string;
552
+ method: string | null;
553
+ }
554
+ interface GlobalPrefix {
555
+ prefix: string;
556
+ excluded: ExcludedRoute[];
557
+ }
558
+
559
+ /**
560
+ * The API versions a decorated route serves, and the paths they put it at.
561
+ *
562
+ * NestJS reads `@Controller({ version })` and `@Version()` only after the
563
+ * bootstrap calls `app.enableVersioning()`, usually in a file with no
564
+ * controller in it. URI versioning puts `v1` in the path after the global
565
+ * prefix and before the controller's path. Header, media type and custom
566
+ * versioning leave the path alone, so every version of a route shares it.
567
+ *
568
+ * When the run cannot read how the application serves versions, a route
569
+ * that states a version claims no path. Any path it claimed could pair it
570
+ * with a client or a document for another version.
571
+ */
572
+
573
+ /** The versions a route or an application states. Null in the list means every version. */
574
+ type StatedVersion = {
575
+ kind: "unstated";
576
+ } | {
577
+ kind: "unread";
578
+ } | {
579
+ kind: "listed";
580
+ versions: ReadonlyArray<string | null>;
581
+ };
582
+ /**
583
+ * How an application serves versions. `off` means the run read the
584
+ * application and nothing turns versioning on, so Nest ignores every
585
+ * version a route states.
586
+ */
587
+ type AppVersioning = {
588
+ kind: "off";
589
+ } | {
590
+ kind: "unread";
591
+ } | {
592
+ kind: "on";
593
+ placement: VersionPlacement;
594
+ pathPrefix: string;
595
+ defaultVersion: StatedVersion;
596
+ };
597
+
391
598
  type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration;
392
599
  /**
393
600
  * Public API: returns RawCondition[] with structured: null.
@@ -564,6 +771,21 @@ interface DiscoveredUnit {
564
771
  method: string | null;
565
772
  path: string | null;
566
773
  };
774
+ /**
775
+ * The file a file convention found this unit in. Its path and export
776
+ * name decide the route, even when the function it exports was written
777
+ * in another module or returned by a factory.
778
+ */
779
+ routeFile?: SourceFile;
780
+ /**
781
+ * The status the framework sends for a response this unit's body
782
+ * states none for, when the route declares one: `@HttpCode(204)`, or
783
+ * the 201 NestJS sends for `@Post`. It replaces the default on the
784
+ * pack's response terminals for this unit alone.
785
+ */
786
+ defaultStatusCode?: number;
787
+ /** Statuses the route's own decorators list as possible responses. */
788
+ declaredStatuses?: number[];
567
789
  /**
568
790
  * Populated by a pack's `discoverUnits` callback for a message-bus
569
791
  * consumer whose channel the code gives (a handler factory whose
@@ -651,6 +873,13 @@ interface MountPrefixIndex {
651
873
  * re-checks a stored prefix against a rebuilt index this way).
652
874
  */
653
875
  prefixForId?(childId: string): string;
876
+ /**
877
+ * The prefix the calls keyed by `globalPrefixKey` agree an application
878
+ * puts in front of its routes. A key with no entry has none.
879
+ */
880
+ globalPrefixes?: ReadonlyMap<string, GlobalPrefix>;
881
+ /** How the run's applications serve API versions, keyed by `routeVersioningKey`. */
882
+ versionings?: ReadonlyMap<string, AppVersioning>;
654
883
  }
655
884
  /**
656
885
  * What the project helper index says it has already expanded, which the
@@ -666,6 +895,18 @@ interface ExpandedRegistrations {
666
895
  */
667
896
  declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore, mountPrefixes?: MountPrefixIndex, expandedElsewhere?: ExpandedRegistrations): DiscoveredUnit[];
668
897
 
898
+ /**
899
+ * What every unit is read with beyond its own pack's patterns, whichever
900
+ * pack discovered it: the terminals a runtime ends the process with, and
901
+ * the command-line parsers it provides. A pack's recognizers reach every
902
+ * unit the same way, and are collected on their own.
903
+ */
904
+
905
+ interface EveryUnitDeclarations {
906
+ terminals: readonly TerminalPattern[];
907
+ argumentParsers: readonly ArgumentParser[];
908
+ }
909
+
669
910
  /**
670
911
  * Nested function nodes a pack claimed as sub-units. The unit-body
671
912
  * walkers stop at these so the sub-unit's behavior isn't double-counted
@@ -680,6 +921,71 @@ declare const NO_BARRIERS: DescentBarriers;
680
921
  */
681
922
  declare function startsItsOwnScope(node: Node): boolean;
682
923
 
924
+ /**
925
+ * What this adapter can tell a declared pack about a call.
926
+ *
927
+ * Every question here was already worked out somewhere in this adapter,
928
+ * once per pack that needed it. Collecting them behind the one
929
+ * interface `@suss/extractor` declares is what lets a pack stop being a
930
+ * walk over ts-morph and start being data.
931
+ *
932
+ * Two of the receiver origins are implemented. The migration plan for
933
+ * #542 lists four more, and each one adds an entry to `ORIGIN` beside
934
+ * the union member it matches.
935
+ */
936
+
937
+ /**
938
+ * A call, a construction, or a tagged template, which all ask the same
939
+ * questions. A tagged template is a call the source wrote without
940
+ * parentheses: the tag is the callee and the template is the one
941
+ * argument, which is how a pack reaches a statement written that way
942
+ * without a second grammar for it.
943
+ */
944
+ type Called = CallExpression | NewExpression | TaggedTemplateExpression;
945
+ /** One-hop lookup from a written name to the value it was bound to. */
946
+ type Resolve = (value: Node) => Node | null;
947
+ /**
948
+ * What the ops read a call through. A reading left out reads only what
949
+ * the source spells at the call.
950
+ */
951
+ interface CallReading {
952
+ /** One-hop lookup from a written name to the value it was bound to. */
953
+ readonly resolve?: Resolve;
954
+ readonly originatesFrom?: OriginatesFrom | undefined;
955
+ readonly anchorCallsOf?: AnchorCallsOf | undefined;
956
+ /** The run's store, which the value evaluator follows names through. */
957
+ readonly resolution?: ResolutionStore | undefined;
958
+ /**
959
+ * The arguments of the walk this call was visited by. A value is read
960
+ * through it in place of `resolve`, and it asks the store about any
961
+ * value it has no answer for.
962
+ */
963
+ readonly walk?: WalkArguments | undefined;
964
+ /** Where a recognizer's `statesSlots` goes, when somebody listens. */
965
+ readonly statesSlots?: ((effect: Effect, slots: readonly StatedSlot[]) => void) | undefined;
966
+ }
967
+ /**
968
+ * The arguments of every call one walk visits. A chain that steps to
969
+ * every argument would otherwise ask the store about each one at each
970
+ * call, and each question runs and clears the rules once.
971
+ */
972
+ interface WalkArguments {
973
+ /** Ask about these positions of every call in the walk, in one question. */
974
+ settle(first: number, last?: number): void;
975
+ /**
976
+ * Ask about the receiver of every call in the walk whose method is one
977
+ * of these, in one question.
978
+ */
979
+ settleReceivers(methods: ReadonlySet<string>): void;
980
+ /**
981
+ * What a value was written as: the walk's own answer for an argument
982
+ * a `settle` covered, and the store's for anything else.
983
+ */
984
+ writtenValueOf(value: Node): Node | null;
985
+ }
986
+ /** What a declared pack can ask about one TypeScript call. */
987
+ declare function callOpsFor(call: Called, reading?: CallReading): AstCapableOps;
988
+
683
989
  /**
684
990
  * invocationEffects.ts: capture every call in a unit's body as an
685
991
  * `invocation` RawEffect, wherever the call is written: a statement of
@@ -695,6 +1001,24 @@ declare function startsItsOwnScope(node: Node): boolean;
695
1001
  * ordered and what `async` means.
696
1002
  */
697
1003
 
1004
+ /** A column a recognized effect writes or picks rows by, and its value. */
1005
+ interface SlotValue {
1006
+ slot: StatedSlot["slot"];
1007
+ name: string;
1008
+ value: Node;
1009
+ }
1010
+ /**
1011
+ * What a recognizer says about each effect it built at one call, kept
1012
+ * until the dispatch loop knows which effects the recognizer returned.
1013
+ */
1014
+ declare class SlotsStated {
1015
+ private readonly byEffect;
1016
+ readonly listen: (effect: Effect, slots: readonly StatedSlot[]) => void;
1017
+ /** The slots stated for an effect, ready to spread onto its location. */
1018
+ of(effect: Effect): {
1019
+ slots?: SlotValue[];
1020
+ };
1021
+ }
698
1022
  /**
699
1023
  * Context handed to TypeScript-adapter access recognizers: sister
700
1024
  * to TsInvocationRecognizerContext but for property-access nodes.
@@ -790,7 +1114,7 @@ interface TsInvocationRecognizerContext {
790
1114
  * A pack's tests build it here too, so a pack that passes them has run
791
1115
  * against the context extraction gives it.
792
1116
  */
793
- declare function invocationContextFor(call: CallExpression, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf): TsInvocationRecognizerContext;
1117
+ declare function invocationContextFor(call: CallExpression, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, walk?: WalkArguments, stated?: SlotsStated): TsInvocationRecognizerContext;
794
1118
  /**
795
1119
  * Whether a value's chain reaches the module, asked of the store. The
796
1120
  * adapter binds it; a context built bare falls back to the checker's
@@ -823,7 +1147,7 @@ type Accessed = PropertyAccessExpression | CallExpression | TaggedTemplateExpres
823
1147
  * A pack's tests build it here too, so a pack that passes them has run
824
1148
  * against the context extraction gives it.
825
1149
  */
826
- declare function accessContextFor(node: Accessed, sourceFile: SourceFile, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf): TsAccessRecognizerContext;
1150
+ declare function accessContextFor(node: Accessed, sourceFile: SourceFile, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, walk?: WalkArguments, stated?: SlotsStated): TsAccessRecognizerContext;
827
1151
 
828
1152
  /** Resolves a helper callee to its declaration; the adapter binds the store's ask. */
829
1153
  type ResolveCallee = (callee: Node) => Node | null;
@@ -843,7 +1167,7 @@ type ResolveCallee = (callee: Node) => Node | null;
843
1167
  * framework or a runtime belongs to a pack.
844
1168
  */
845
1169
 
846
- declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, resolveCallee?: ResolveCallee): RawCodeStructure;
1170
+ declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, resolveCallee?: ResolveCallee, everyUnit?: EveryUnitDeclarations): RawCodeStructure;
847
1171
  interface TypeScriptAdapterConfig {
848
1172
  tsConfigFilePath?: string;
849
1173
  /**
@@ -862,14 +1186,46 @@ interface TypeScriptAdapterConfig {
862
1186
  onCacheDiagnostic?: (diagnostic: CacheDiagnostic) => void;
863
1187
  /** Not called on a cache hit, where no stage ran. */
864
1188
  onExtractionReport?: (report: ExtractionReport) => void;
865
- /** Absolute. `.suss/cache/` beside the tsconfig; `null` turns it off. */
1189
+ /**
1190
+ * Absolute. `.suss/cache/` in `walkedDirectory` when set, otherwise
1191
+ * beside the tsconfig; `null` turns it off.
1192
+ */
866
1193
  cacheDir?: string | null;
1194
+ /** The modules the project lists in `suss.json`, with absolute paths. */
1195
+ modules?: readonly DeclaredModule[];
1196
+ /**
1197
+ * Absolute. Walks only the tsconfig's files under this directory, for a
1198
+ * tsconfig found above the directory a run was pointed at.
1199
+ */
1200
+ walkedDirectory?: string;
867
1201
  }
868
1202
  interface TypeScriptAdapter extends LanguageAdapter {
869
1203
  /** Kept off `LanguageAdapter`, so a caller needing ts-morph asks for it. */
870
1204
  readonly tsProject: Project;
871
1205
  extractFromFiles(filePaths: string[]): Promise<BehavioralSummary[]>;
872
1206
  extractAll(): Promise<BehavioralSummary[]>;
1207
+ /**
1208
+ * Re-reads the files that changed on disk since the last `extractAll`,
1209
+ * so the next one describes the tree as it is now and keeps the parse
1210
+ * of every other file. A process that keeps the adapter between runs
1211
+ * calls this before each one. `changedPaths` are files the caller knows
1212
+ * were written; the rest are found by their stamps.
1213
+ */
1214
+ refresh(changedPaths?: readonly string[]): RefreshReport;
1215
+ /**
1216
+ * Loads the files a run walks and everything they import, and builds
1217
+ * the compiler's program, without extracting. A run served whole from
1218
+ * the cache loads nothing, so a process that keeps the adapter calls
1219
+ * this once while nobody is waiting, and the first edit after that
1220
+ * finds the program built.
1221
+ */
1222
+ loadProgram(): Promise<void>;
1223
+ }
1224
+ interface RefreshReport {
1225
+ /** Files parsed again because their text changed. */
1226
+ changed: string[];
1227
+ /** Why the adapter started over with a new project, or null. */
1228
+ startedOver: string | null;
873
1229
  }
874
1230
  declare function createTypeScriptAdapter(suppliedConfig: TypeScriptAdapterConfig): TypeScriptAdapter;
875
1231
 
@@ -909,6 +1265,31 @@ interface FoundTerminal {
909
1265
  */
910
1266
  declare function findTerminals(func: FunctionRoot, patterns: TerminalPattern[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, resolveCallee?: ResolveCallee): FoundTerminal[];
911
1267
 
1268
+ /**
1269
+ * Reads a project function a client caller hands its response to as part
1270
+ * of the caller.
1271
+ *
1272
+ * const response = await fetch(`/api/orders/${id}`);
1273
+ * return readOrder(response);
1274
+ *
1275
+ * `readOrder` throws on `!response.ok`. Read alone, the caller tests
1276
+ * nothing, so every failure looks unhandled. The helper's paths are read
1277
+ * the way the caller's were, with each parameter replaced by what the
1278
+ * caller passed, and each becomes a path of the caller. A helper is
1279
+ * followed only when one of its paths tests the response or its parsed
1280
+ * body, so a call that logs the response leaves the caller as it was.
1281
+ */
1282
+
1283
+ interface ResponseHandOffOptions {
1284
+ /** The callee text the caller's own conditions use for the response. */
1285
+ responseCallee: string;
1286
+ /** The callee texts they use for its parsed body, such as `res.json`. */
1287
+ bodyCallees: readonly string[];
1288
+ /** The pack's response members, to tell a body field from a status read. */
1289
+ responseSemantics: ResponsePropertyMapping[] | undefined;
1290
+ resolution: ResolutionStore;
1291
+ }
1292
+
912
1293
  /**
913
1294
  * Turns one function into the list of branches a summary is built from.
914
1295
  *
@@ -958,8 +1339,29 @@ interface RawBranchResult {
958
1339
  * or when every condition on it came from an early return or throw,
959
1340
  * since those are the paths that run when no guard fired.
960
1341
  */
961
- declare function extractRawBranches(func: FunctionRoot, terminalPatterns: TerminalPattern[], invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, resolveCallee?: ResolveCallee, collectCallAccounting?: boolean): RawBranchResult;
1342
+ declare function extractRawBranches(func: FunctionRoot, terminalPatterns: TerminalPattern[], invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, resolveCallee?: ResolveCallee, collectCallAccounting?: boolean, keepsArms?: KeepsArms<Expression>, handOff?: ResponseHandOffOptions): RawBranchResult;
1343
+
1344
+ /**
1345
+ * Picks the files a run walks, and gets the compiler ahead of the
1346
+ * import graph before anything asks it a question.
1347
+ *
1348
+ * `createLazyProject` reads the tsconfig's file list and keeps the
1349
+ * files whose imports match some active pack's `requiresImport` gate.
1350
+ * Those candidates are what the run walks; everything else is loaded
1351
+ * later, one file at a time, by `lazyAddSourceFile` when symbol
1352
+ * resolution points at it.
1353
+ *
1354
+ * The rest of the module is about load order. TypeScript follows a
1355
+ * re-export chain by recursing, so a barrel chain a few hundred files
1356
+ * deep runs the call stack out. `loadImportGraphsDepthFirst` loads each
1357
+ * file after everything it imports. The README says why that matters.
1358
+ */
1359
+
1360
+ /** Reads no source, so a cache hit never pays for the bootstrap. */
1361
+ declare function readTsconfigFileList(tsConfigFilePath: string): string[];
962
1362
 
1363
+ /** The suffixes this adapter reads, JavaScript included. */
1364
+ declare const SOURCE_SUFFIXES: readonly [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
963
1365
  /**
964
1366
  * A Project covering `rootDir`, for a codebase with no tsconfig to read.
965
1367
  * Returns the project and the files it loaded.
@@ -1135,6 +1537,12 @@ declare function namedImportsOf(sourceFile: SourceFile, modules: readonly string
1135
1537
  declare function importedNamesOf(sourceFile: SourceFile, modules: readonly string[], options?: ImportScanOptions): Map<string, string>;
1136
1538
  /** The local spellings of default and namespace imports of these modules. */
1137
1539
  declare function importedRootsOf(sourceFile: SourceFile, modules: readonly string[], options?: ImportScanOptions): Set<string>;
1540
+ /**
1541
+ * The specifier, as written, of the import that binds this local name,
1542
+ * whether as a named, default or namespace import. Null when no import
1543
+ * in the file binds it.
1544
+ */
1545
+ declare function specifierImportedAs(sourceFile: SourceFile, local: string): string | null;
1138
1546
  /** Every import declaration in the file that names one of `modules`. */
1139
1547
  declare function importDeclarationsOf(sourceFile: SourceFile, modules: readonly string[], options?: ImportScanOptions): ImportDeclaration[];
1140
1548
 
@@ -1220,6 +1628,8 @@ declare function writtenNodeOf(value: Node, resolution: ResolutionStore | undefi
1220
1628
  * empty" from "could not read" (#123).
1221
1629
  */
1222
1630
  declare function stringValueOf(value: Node, resolution: ResolutionStore | undefined): string | null;
1631
+ /** The number this value comes to, or null when it does not settle to one. */
1632
+ declare function numberValueOf(value: Node, resolution: ResolutionStore | undefined): number | null;
1223
1633
  /**
1224
1634
  * The string a named property of an object is set to, with the object
1225
1635
  * and the value each read through whatever name they were given.
@@ -1285,6 +1695,8 @@ declare function createTsDiscoveryContext(resolution?: ResolutionStore): TsDisco
1285
1695
  interface WhySessionOptions {
1286
1696
  /** The project root, which paths in every answer come out relative to. */
1287
1697
  dir: string;
1698
+ /** The packs the extraction ran with, for the wrappers and environment objects they declare. */
1699
+ packs?: readonly PatternPack[];
1288
1700
  }
1289
1701
  declare class TypeScriptWhySession {
1290
1702
  private readonly project;
@@ -1343,32 +1755,6 @@ declare function resolveAliasedSymbol(symbol: Symbol): Symbol | undefined;
1343
1755
  */
1344
1756
  declare function parseConditionExpression(expr: Expression, depth?: number): Predicate | null;
1345
1757
 
1346
- /**
1347
- * What this adapter can tell a declared pack about a call.
1348
- *
1349
- * Every question here was already worked out somewhere in this adapter,
1350
- * once per pack that needed it. Collecting them behind the one
1351
- * interface `@suss/extractor` declares is what lets a pack stop being a
1352
- * walk over ts-morph and start being data.
1353
- *
1354
- * Two of the receiver origins are implemented. The migration plan for
1355
- * #542 lists four more, and each one adds an entry to `ORIGIN` beside
1356
- * the union member it matches.
1357
- */
1358
-
1359
- /**
1360
- * A call, a construction, or a tagged template, which all ask the same
1361
- * questions. A tagged template is a call the source wrote without
1362
- * parentheses: the tag is the callee and the template is the one
1363
- * argument, which is how a pack reaches a statement written that way
1364
- * without a second grammar for it.
1365
- */
1366
- type Called = CallExpression | NewExpression | TaggedTemplateExpression;
1367
- /** One-hop lookup from a written name to the value it was bound to. */
1368
- type Resolve = (value: Node) => Node | null;
1369
- /** What a declared pack can ask about one TypeScript call. */
1370
- declare function callOpsFor(call: Called, resolveWrittenValue?: Resolve, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf): AstCapableOps;
1371
-
1372
1758
  /**
1373
1759
  * The one resolver from a reference to the function behind it.
1374
1760
  *
@@ -1589,6 +1975,57 @@ declare function createTsSubUnitContext(): TsSubUnitContext;
1589
1975
  * way twice.
1590
1976
  */
1591
1977
  declare function workspaceRootFor(anchor: string): string;
1978
+ /**
1979
+ * What a project calls itself.
1980
+ *
1981
+ * Its package.json name is what a person would say and what a sibling
1982
+ * package already imports it by. A project without one falls back to
1983
+ * the folder, which is at least what somebody typed.
1984
+ */
1985
+ declare function workspaceNameFor(root: string | undefined): string | null;
1986
+
1987
+ /** What a call writes out, and whether it was serialized as JSON first. */
1988
+ interface WrittenPayload {
1989
+ shape: TypeShape | null;
1990
+ serialized: "json" | "text";
1991
+ }
1992
+ /**
1993
+ * What a call writes, for a pack recording a write to a stream.
1994
+ * `JSON.stringify(report)` writes the report as JSON, and so does a
1995
+ * template that puts nothing but whitespace around one such call, the
1996
+ * way a command ends its report with a newline. Several arguments are
1997
+ * written one after another, so their shapes come back keyed by position.
1998
+ */
1999
+ declare function writtenPayloadOf(args: readonly Node[]): WrittenPayload;
2000
+
2001
+ /**
2002
+ * The named types behind a node's type, for a pack that recognizes a
2003
+ * call by what its receiver is rather than by what it is called.
2004
+ *
2005
+ * A library rarely hands back its type bare. A client factory can return
2006
+ * the library's class joined with an extra field (`Db & { $client: Pool }`),
2007
+ * and a project can declare the client as optional (`Db | undefined`), alias
2008
+ * it, subclass it, or pass it through a type parameter. A union or an
2009
+ * intersection has no symbol of its own, so this looks through each of
2010
+ * those to the named types underneath, and the pack tests each one.
2011
+ *
2012
+ * When the checker cannot resolve the type because the library is not
2013
+ * installed, the names come from the written type, with no declaring file.
2014
+ */
2015
+
2016
+ /** One named type a receiver is, and the files that declare it. */
2017
+ interface ReceiverType {
2018
+ name: string;
2019
+ declaredIn: readonly string[];
2020
+ /**
2021
+ * The base each declaring class is written as extending. When the
2022
+ * library is not installed the checker cannot see past a project's
2023
+ * `class Db extends Client`, and a pack asks where the base came from.
2024
+ */
2025
+ extendsWritten: readonly Node[];
2026
+ }
2027
+ /** Every named type the node's type is, nearest first. */
2028
+ declare function receiverTypesOf(node: Node): ReceiverType[];
1592
2029
 
1593
2030
  /**
1594
2031
  * version.ts: this adapter's own half of the cache key.
@@ -1619,19 +2056,23 @@ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
1619
2056
  /**
1620
2057
  * defaulted.ts: whether a read has something behind it.
1621
2058
  *
1622
- * `??` and `||` are ECMAScript, not anything a pack defines, so the
1623
- * packs that record a read ask here instead of each spelling the
1624
- * operators out. This is a separate file from unwrap.ts because that
1625
- * one is about wrappers, and a fallback is not one.
2059
+ * A read is defaulted when the program still works where the value is
2060
+ * missing. Either a `??` or `||` supplies a fallback value, or the
2061
+ * program tests the value for presence, only uses it where the test
2062
+ * passed, and the path a missing value takes does not end in a throw.
2063
+ * The test can be on the read itself or on a local the read
2064
+ * initializes: a truthiness check, a comparison with `undefined` or
2065
+ * `null`, or an `in` membership test.
2066
+ *
2067
+ * All of this is ECMAScript, so the packs that record a read ask here
2068
+ * instead of each spelling the forms out. The Python and Ruby adapters
2069
+ * define the same rule for their own syntax.
1626
2070
  */
1627
2071
 
1628
2072
  /**
1629
- * Whether something else supplies a value when this read comes back
1630
- * empty. `env.X ?? "default"` and `env.X || other` both do, and so does
1631
- * the middle of a chain: in `env.A || env.B || undefined`, B's fallback
1632
- * is the chain's tail. The climb stops when the read is the final
1633
- * operand (`getDefault() ?? env.X`), where the read is itself the
1634
- * fallback and its absence propagates.
2073
+ * Whether the program copes with this read coming back empty: something
2074
+ * falls back from it, or every use of its value runs only after a
2075
+ * presence test has passed.
1635
2076
  */
1636
2077
  declare function isDefaultedAt(node: Node): boolean;
1637
2078
 
@@ -1658,4 +2099,4 @@ declare function climbSyntax(node: Node): Node;
1658
2099
  */
1659
2100
  declare function peelValue(node: Node): Node;
1660
2101
 
1661
- export { ADAPTER_VERSION, type Accessed, type CallAccountingEntry, type CallAccountingOutcome, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DescentBarriers, type DiscoveredUnit, type EnvironmentNamers, type ExplainCallableOptions, type ExplainedResolution, type FoundTerminal, type FunctionRoot, GENERIC_TERMINALS, type ImportScanOptions, NO_BARRIERS, type ObservedStubCall, type RawBranchResult, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, TSCONFIG_NAMES, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, TypeScriptWhySession, type WhySessionOptions, accessContextFor, arrayLiteralOf, buildProjectHelperIndex, callOpsFor, climbSyntax, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, couldNameAValue, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, declarationsBehind, discoverUnits, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findEnclosingFunction, findNearestTsconfig, findTerminals, functionTargetOf, functionValueOf, hasBody, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isDefaultedAt, isImportedFrom, methodDeclaredIn, namedImportsOf, objectLiteralOf, parseConditionExpression, peelSyntax, peelValue, propertiesOf, propertyFunctionOf, propertyNameOf, propertyOf, propertyValueOf, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, toFunctionRoot, workspaceRootFor, writtenNodeOf };
2102
+ export { ADAPTER_VERSION, type Accessed, type CallAccountingEntry, type CallAccountingOutcome, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DescentBarriers, type DiscoveredUnit, type EnvironmentNamers, type ExplainCallableOptions, type ExplainedResolution, type FoundTerminal, type FunctionRoot, GENERIC_TERMINALS, type ImportScanOptions, NO_BARRIERS, type ObservedStubCall, type RawBranchResult, type ReadNameOptions, type ReceiverType, type RefreshReport, ResolutionStore, SOURCE_SUFFIXES, type StubCallEvidence, type StubEvidenceOptions, TSCONFIG_NAMES, type TsAccessRecognizerContext, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, TypeScriptWhySession, type WhySessionOptions, type WrittenPayload, accessContextFor, arrayLiteralOf, buildProjectHelperIndex, callOpsFor, climbSyntax, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, couldNameAValue, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, declarationsBehind, discoverUnits, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findEnclosingFunction, findNearestTsconfig, findTerminals, functionTargetOf, functionValueOf, hasBody, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isDefaultedAt, isImportedFrom, methodDeclaredIn, namedImportsOf, numberValueOf, objectLiteralOf, parseConditionExpression, peelSyntax, peelValue, propertiesOf, propertyFunctionOf, propertyNameOf, propertyOf, propertyValueOf, readConfiguredCall, readContract, readContractForClientCall, readName, readTsconfigFileList, receiverTypesOf, resolveAliasedSymbol, resolveSubject, rootIdentifier, specifierImportedAs, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, toFunctionRoot, workspaceNameFor, workspaceRootFor, writtenNodeOf, writtenPayloadOf };