@suss/adapter-typescript 0.33.0 → 0.34.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.d.ts CHANGED
@@ -1,22 +1,64 @@
1
- import { SourceFile, Node, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, Symbol, CallExpression, PropertyAccessExpression, TaggedTemplateExpression, Project, 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, ImportDeclaration, ArrayLiteralExpression, ObjectLiteralExpression, ObjectLiteralElementLike, Expression, Identifier } from 'ts-morph';
2
+ import { PatternPack, TransparentWrapper, ParameterSupplier, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, ArgumentParser, StatedSlot, AstCapableOps, CallOps, EffectArg, LanguageAdapter, ExtractorOptions, TimingReport, CacheDiagnostic, ExtractionReport, DeclaredModule, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, configuredCallOption, RawDeclaredContract, ContractPattern, ResponsePropertyMapping } 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
- private envNamersAnswer;
90
- private envNamersExtractedAt;
143
+ /** See `environmentAnswers`; null until the first env question. */
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
@@ -171,10 +267,8 @@ declare class ResolutionStore {
171
267
  * a pack spells it, a name declared as that, or a parameter some
172
268
  * caller hands one to, however many calls deep.
173
269
  *
174
- * A parameter is the only shape whose answer can change once its
175
- * callers are in, and reading those means reading every file that
176
- * imports this one, so a value that is not one is answered from what
177
- * the store already has.
270
+ * A parameter's answer depends on its callers, so it comes from the
271
+ * parameters the environment reaches, worked out once per run.
178
272
  */
179
273
  isEnvironmentValue(value: Node): boolean;
180
274
  private hasAnswer;
@@ -183,24 +277,31 @@ declare class ResolutionStore {
183
277
  * from, for a reader standing at a call. One question covers the
184
278
  * whole project: a project has a handful of environment reads and
185
279
  * thousands of parameters, and with the read bound the rules run from
186
- * each callee to its callers.
187
- *
188
- * `definedIn` is the callee's own file, read into the store before
189
- * the question so a helper nothing had extracted yet is among the
190
- * facts the rules run over.
280
+ * each callee to its callers. The facts README says which files that
281
+ * reads and why it is asked once.
191
282
  */
192
- envNamers(definedIn: SourceFile): EnvironmentNamers;
283
+ envNamers(project: Project): EnvironmentNamers;
284
+ private environmentAnswers;
285
+ /**
286
+ * Ask until every call handing the environment on has had its callee
287
+ * read, one hop a round, so the answer covers each parameter it lands in.
288
+ */
289
+ private followEnvironment;
290
+ private readCalleeOf;
291
+ /** The files the parameters an answer is keyed by are declared in. */
292
+ private filesOf;
193
293
  private sitesNamedBy;
194
294
  /**
195
295
  * Seed every expression that spells the environment, derive, and take
196
- * the sites back per parameter. The question is dropped afterwards, so
197
- * a later ask over a larger fact set derives it again.
296
+ * back the read sites per parameter and the parameters the object is
297
+ * handed to. The question is dropped afterwards, so a later ask over a
298
+ * larger fact set derives it again.
198
299
  *
199
300
  * The reads themselves cannot be the seed: one written through a
200
301
  * parameter is off an object a scan of the source has no way to pick
201
302
  * out, and the whole point of asking is to find those.
202
303
  */
203
- private askEnvNamers;
304
+ private askEnvironment;
204
305
  /**
205
306
  * The project's files that hand the environment object somewhere,
206
307
  * read into the store. Which files those are cannot depend on what a
@@ -208,6 +309,36 @@ declare class ResolutionStore {
208
309
  * project's own sources and it happens once.
209
310
  */
210
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;
211
342
  /**
212
343
  * Whether running this function hands back that call: returned
213
344
  * outright, written into a name and returned, or a shorthand body.
@@ -215,6 +346,13 @@ declare class ResolutionStore {
215
346
  * what keeps a wrapper's own result apart from the library's.
216
347
  */
217
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;
218
356
  /**
219
357
  * Files a later question about a parameter may find a caller in.
220
358
  * Without this the search falls back to every file the project has
@@ -250,7 +388,8 @@ declare class ResolutionStore {
250
388
  * declared name.
251
389
  */
252
390
  private constructionComesFrom;
253
- private calleeNameOf;
391
+ /** The callee of a call, as written. */
392
+ private calleeTextOf;
254
393
  /**
255
394
  * Which names from `modules` this value comes down to, either by being
256
395
  * one of them under a local name or by calling into one. Getting
@@ -290,6 +429,12 @@ declare class ResolutionStore {
290
429
  private lookupImportOrigins;
291
430
  private lookupImportedNames;
292
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;
293
438
  /**
294
439
  * Extract the seed files, then every module the rules ask for, until
295
440
  * they ask for nothing new. The files a question reads are then fixed
@@ -326,7 +471,12 @@ declare class ResolutionStore {
326
471
  */
327
472
  private seedValue;
328
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
+ */
329
478
  private lookupReturned;
479
+ private singleFunctionIn;
330
480
  /**
331
481
  * Two candidates give null, since ambiguity is nothing. The value
332
482
  * itself is never a result either, or an identifier whose chain went
@@ -336,6 +486,8 @@ declare class ResolutionStore {
336
486
  * construction makes an instance of. The README says why.
337
487
  */
338
488
  private lookupWritten;
489
+ /** The one class among what a value is written as, under the same policy. */
490
+ private lookupWrittenClass;
339
491
  /**
340
492
  * Read these files' facts now, before anything asks a question.
341
493
  *
@@ -383,6 +535,27 @@ declare class ResolutionStore {
383
535
  private extractFile;
384
536
  }
385
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
+
386
559
  type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration;
387
560
  /**
388
561
  * Public API: returns RawCondition[] with structured: null.
@@ -559,6 +732,13 @@ interface DiscoveredUnit {
559
732
  method: string | null;
560
733
  path: string | null;
561
734
  };
735
+ /**
736
+ * The status the framework sends for a response this unit's body
737
+ * states none for, when the route declares one: `@HttpCode(204)`, or
738
+ * the 201 NestJS sends for `@Post`. It replaces the default on the
739
+ * pack's response terminals for this unit alone.
740
+ */
741
+ defaultStatusCode?: number;
562
742
  /**
563
743
  * Populated by a pack's `discoverUnits` callback for a message-bus
564
744
  * consumer whose channel the code gives (a handler factory whose
@@ -646,6 +826,11 @@ interface MountPrefixIndex {
646
826
  * re-checks a stored prefix against a rebuilt index this way).
647
827
  */
648
828
  prefixForId?(childId: string): string;
829
+ /**
830
+ * The prefix the calls keyed by `globalPrefixKey` agree an application
831
+ * puts in front of its routes. A key with no entry has none.
832
+ */
833
+ globalPrefixes?: ReadonlyMap<string, GlobalPrefix>;
649
834
  }
650
835
  /**
651
836
  * What the project helper index says it has already expanded, which the
@@ -661,6 +846,18 @@ interface ExpandedRegistrations {
661
846
  */
662
847
  declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore, mountPrefixes?: MountPrefixIndex, expandedElsewhere?: ExpandedRegistrations): DiscoveredUnit[];
663
848
 
849
+ /**
850
+ * What every unit is read with beyond its own pack's patterns, whichever
851
+ * pack discovered it: the terminals a runtime ends the process with, and
852
+ * the command-line parsers it provides. A pack's recognizers reach every
853
+ * unit the same way, and are collected on their own.
854
+ */
855
+
856
+ interface EveryUnitDeclarations {
857
+ terminals: readonly TerminalPattern[];
858
+ argumentParsers: readonly ArgumentParser[];
859
+ }
860
+
664
861
  /**
665
862
  * Nested function nodes a pack claimed as sub-units. The unit-body
666
863
  * walkers stop at these so the sub-unit's behavior isn't double-counted
@@ -675,6 +872,71 @@ declare const NO_BARRIERS: DescentBarriers;
675
872
  */
676
873
  declare function startsItsOwnScope(node: Node): boolean;
677
874
 
875
+ /**
876
+ * What this adapter can tell a declared pack about a call.
877
+ *
878
+ * Every question here was already worked out somewhere in this adapter,
879
+ * once per pack that needed it. Collecting them behind the one
880
+ * interface `@suss/extractor` declares is what lets a pack stop being a
881
+ * walk over ts-morph and start being data.
882
+ *
883
+ * Two of the receiver origins are implemented. The migration plan for
884
+ * #542 lists four more, and each one adds an entry to `ORIGIN` beside
885
+ * the union member it matches.
886
+ */
887
+
888
+ /**
889
+ * A call, a construction, or a tagged template, which all ask the same
890
+ * questions. A tagged template is a call the source wrote without
891
+ * parentheses: the tag is the callee and the template is the one
892
+ * argument, which is how a pack reaches a statement written that way
893
+ * without a second grammar for it.
894
+ */
895
+ type Called = CallExpression | NewExpression | TaggedTemplateExpression;
896
+ /** One-hop lookup from a written name to the value it was bound to. */
897
+ type Resolve = (value: Node) => Node | null;
898
+ /**
899
+ * What the ops read a call through. A reading left out reads only what
900
+ * the source spells at the call.
901
+ */
902
+ interface CallReading {
903
+ /** One-hop lookup from a written name to the value it was bound to. */
904
+ readonly resolve?: Resolve;
905
+ readonly originatesFrom?: OriginatesFrom | undefined;
906
+ readonly anchorCallsOf?: AnchorCallsOf | undefined;
907
+ /** The run's store, which the value evaluator follows names through. */
908
+ readonly resolution?: ResolutionStore | undefined;
909
+ /**
910
+ * The arguments of the walk this call was visited by. A value is read
911
+ * through it in place of `resolve`, and it asks the store about any
912
+ * value it has no answer for.
913
+ */
914
+ readonly walk?: WalkArguments | undefined;
915
+ /** Where a recognizer's `statesSlots` goes, when somebody listens. */
916
+ readonly statesSlots?: ((effect: Effect, slots: readonly StatedSlot[]) => void) | undefined;
917
+ }
918
+ /**
919
+ * The arguments of every call one walk visits. A chain that steps to
920
+ * every argument would otherwise ask the store about each one at each
921
+ * call, and each question runs and clears the rules once.
922
+ */
923
+ interface WalkArguments {
924
+ /** Ask about these positions of every call in the walk, in one question. */
925
+ settle(first: number, last?: number): void;
926
+ /**
927
+ * Ask about the receiver of every call in the walk whose method is one
928
+ * of these, in one question.
929
+ */
930
+ settleReceivers(methods: ReadonlySet<string>): void;
931
+ /**
932
+ * What a value was written as: the walk's own answer for an argument
933
+ * a `settle` covered, and the store's for anything else.
934
+ */
935
+ writtenValueOf(value: Node): Node | null;
936
+ }
937
+ /** What a declared pack can ask about one TypeScript call. */
938
+ declare function callOpsFor(call: Called, reading?: CallReading): AstCapableOps;
939
+
678
940
  /**
679
941
  * invocationEffects.ts: capture every call in a unit's body as an
680
942
  * `invocation` RawEffect, wherever the call is written: a statement of
@@ -690,6 +952,24 @@ declare function startsItsOwnScope(node: Node): boolean;
690
952
  * ordered and what `async` means.
691
953
  */
692
954
 
955
+ /** A column a recognized effect writes or picks rows by, and its value. */
956
+ interface SlotValue {
957
+ slot: StatedSlot["slot"];
958
+ name: string;
959
+ value: Node;
960
+ }
961
+ /**
962
+ * What a recognizer says about each effect it built at one call, kept
963
+ * until the dispatch loop knows which effects the recognizer returned.
964
+ */
965
+ declare class SlotsStated {
966
+ private readonly byEffect;
967
+ readonly listen: (effect: Effect, slots: readonly StatedSlot[]) => void;
968
+ /** The slots stated for an effect, ready to spread onto its location. */
969
+ of(effect: Effect): {
970
+ slots?: SlotValue[];
971
+ };
972
+ }
693
973
  /**
694
974
  * Context handed to TypeScript-adapter access recognizers: sister
695
975
  * to TsInvocationRecognizerContext but for property-access nodes.
@@ -785,7 +1065,7 @@ interface TsInvocationRecognizerContext {
785
1065
  * A pack's tests build it here too, so a pack that passes them has run
786
1066
  * against the context extraction gives it.
787
1067
  */
788
- declare function invocationContextFor(call: CallExpression, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf): TsInvocationRecognizerContext;
1068
+ declare function invocationContextFor(call: CallExpression, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, walk?: WalkArguments, stated?: SlotsStated): TsInvocationRecognizerContext;
789
1069
  /**
790
1070
  * Whether a value's chain reaches the module, asked of the store. The
791
1071
  * adapter binds it; a context built bare falls back to the checker's
@@ -818,7 +1098,7 @@ type Accessed = PropertyAccessExpression | CallExpression | TaggedTemplateExpres
818
1098
  * A pack's tests build it here too, so a pack that passes them has run
819
1099
  * against the context extraction gives it.
820
1100
  */
821
- declare function accessContextFor(node: Accessed, sourceFile: SourceFile, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf): TsAccessRecognizerContext;
1101
+ declare function accessContextFor(node: Accessed, sourceFile: SourceFile, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, walk?: WalkArguments, stated?: SlotsStated): TsAccessRecognizerContext;
822
1102
 
823
1103
  /** Resolves a helper callee to its declaration; the adapter binds the store's ask. */
824
1104
  type ResolveCallee = (callee: Node) => Node | null;
@@ -838,7 +1118,7 @@ type ResolveCallee = (callee: Node) => Node | null;
838
1118
  * framework or a runtime belongs to a pack.
839
1119
  */
840
1120
 
841
- declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, resolveCallee?: ResolveCallee): RawCodeStructure;
1121
+ declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers, resolution?: ResolutionStore, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf, resolveCallee?: ResolveCallee, everyUnit?: EveryUnitDeclarations): RawCodeStructure;
842
1122
  interface TypeScriptAdapterConfig {
843
1123
  tsConfigFilePath?: string;
844
1124
  /**
@@ -859,12 +1139,36 @@ interface TypeScriptAdapterConfig {
859
1139
  onExtractionReport?: (report: ExtractionReport) => void;
860
1140
  /** Absolute. `.suss/cache/` beside the tsconfig; `null` turns it off. */
861
1141
  cacheDir?: string | null;
1142
+ /** The modules the project lists in `suss.json`, with absolute paths. */
1143
+ modules?: readonly DeclaredModule[];
862
1144
  }
863
1145
  interface TypeScriptAdapter extends LanguageAdapter {
864
1146
  /** Kept off `LanguageAdapter`, so a caller needing ts-morph asks for it. */
865
1147
  readonly tsProject: Project;
866
1148
  extractFromFiles(filePaths: string[]): Promise<BehavioralSummary[]>;
867
1149
  extractAll(): Promise<BehavioralSummary[]>;
1150
+ /**
1151
+ * Re-reads the files that changed on disk since the last `extractAll`,
1152
+ * so the next one describes the tree as it is now and keeps the parse
1153
+ * of every other file. A process that keeps the adapter between runs
1154
+ * calls this before each one. `changedPaths` are files the caller knows
1155
+ * were written; the rest are found by their stamps.
1156
+ */
1157
+ refresh(changedPaths?: readonly string[]): RefreshReport;
1158
+ /**
1159
+ * Loads the files a run walks and everything they import, and builds
1160
+ * the compiler's program, without extracting. A run served whole from
1161
+ * the cache loads nothing, so a process that keeps the adapter calls
1162
+ * this once while nobody is waiting, and the first edit after that
1163
+ * finds the program built.
1164
+ */
1165
+ loadProgram(): Promise<void>;
1166
+ }
1167
+ interface RefreshReport {
1168
+ /** Files parsed again because their text changed. */
1169
+ changed: string[];
1170
+ /** Why the adapter started over with a new project, or null. */
1171
+ startedOver: string | null;
868
1172
  }
869
1173
  declare function createTypeScriptAdapter(suppliedConfig: TypeScriptAdapterConfig): TypeScriptAdapter;
870
1174
 
@@ -1215,6 +1519,8 @@ declare function writtenNodeOf(value: Node, resolution: ResolutionStore | undefi
1215
1519
  * empty" from "could not read" (#123).
1216
1520
  */
1217
1521
  declare function stringValueOf(value: Node, resolution: ResolutionStore | undefined): string | null;
1522
+ /** The number this value comes to, or null when it does not settle to one. */
1523
+ declare function numberValueOf(value: Node, resolution: ResolutionStore | undefined): number | null;
1218
1524
  /**
1219
1525
  * The string a named property of an object is set to, with the object
1220
1526
  * and the value each read through whatever name they were given.
@@ -1280,6 +1586,8 @@ declare function createTsDiscoveryContext(resolution?: ResolutionStore): TsDisco
1280
1586
  interface WhySessionOptions {
1281
1587
  /** The project root, which paths in every answer come out relative to. */
1282
1588
  dir: string;
1589
+ /** The packs the extraction ran with, for the wrappers and environment objects they declare. */
1590
+ packs?: readonly PatternPack[];
1283
1591
  }
1284
1592
  declare class TypeScriptWhySession {
1285
1593
  private readonly project;
@@ -1338,32 +1646,6 @@ declare function resolveAliasedSymbol(symbol: Symbol): Symbol | undefined;
1338
1646
  */
1339
1647
  declare function parseConditionExpression(expr: Expression, depth?: number): Predicate | null;
1340
1648
 
1341
- /**
1342
- * What this adapter can tell a declared pack about a call.
1343
- *
1344
- * Every question here was already worked out somewhere in this adapter,
1345
- * once per pack that needed it. Collecting them behind the one
1346
- * interface `@suss/extractor` declares is what lets a pack stop being a
1347
- * walk over ts-morph and start being data.
1348
- *
1349
- * Two of the receiver origins are implemented. The migration plan for
1350
- * #542 lists four more, and each one adds an entry to `ORIGIN` beside
1351
- * the union member it matches.
1352
- */
1353
-
1354
- /**
1355
- * A call, a construction, or a tagged template, which all ask the same
1356
- * questions. A tagged template is a call the source wrote without
1357
- * parentheses: the tag is the callee and the template is the one
1358
- * argument, which is how a pack reaches a statement written that way
1359
- * without a second grammar for it.
1360
- */
1361
- type Called = CallExpression | NewExpression | TaggedTemplateExpression;
1362
- /** One-hop lookup from a written name to the value it was bound to. */
1363
- type Resolve = (value: Node) => Node | null;
1364
- /** What a declared pack can ask about one TypeScript call. */
1365
- declare function callOpsFor(call: Called, resolveWrittenValue?: Resolve, originatesFrom?: OriginatesFrom, anchorCallsOf?: AnchorCallsOf): AstCapableOps;
1366
-
1367
1649
  /**
1368
1650
  * The one resolver from a reference to the function behind it.
1369
1651
  *
@@ -1585,6 +1867,49 @@ declare function createTsSubUnitContext(): TsSubUnitContext;
1585
1867
  */
1586
1868
  declare function workspaceRootFor(anchor: string): string;
1587
1869
 
1870
+ /** What a call writes out, and whether it was serialized as JSON first. */
1871
+ interface WrittenPayload {
1872
+ shape: TypeShape | null;
1873
+ serialized: "json" | "text";
1874
+ }
1875
+ /**
1876
+ * What a call writes, for a pack recording a write to a stream.
1877
+ * `JSON.stringify(report)` writes the report as JSON, and so does a
1878
+ * template that puts nothing but whitespace around one such call, the
1879
+ * way a command ends its report with a newline. Several arguments are
1880
+ * written one after another, so their shapes come back keyed by position.
1881
+ */
1882
+ declare function writtenPayloadOf(args: readonly Node[]): WrittenPayload;
1883
+
1884
+ /**
1885
+ * The named types behind a node's type, for a pack that recognizes a
1886
+ * call by what its receiver is rather than by what it is called.
1887
+ *
1888
+ * A library rarely hands back its type bare. A client factory can return
1889
+ * the library's class joined with an extra field (`Db & { $client: Pool }`),
1890
+ * and a project can declare the client as optional (`Db | undefined`), alias
1891
+ * it, subclass it, or pass it through a type parameter. A union or an
1892
+ * intersection has no symbol of its own, so this looks through each of
1893
+ * those to the named types underneath, and the pack tests each one.
1894
+ *
1895
+ * When the checker cannot resolve the type because the library is not
1896
+ * installed, the names come from the written type, with no declaring file.
1897
+ */
1898
+
1899
+ /** One named type a receiver is, and the files that declare it. */
1900
+ interface ReceiverType {
1901
+ name: string;
1902
+ declaredIn: readonly string[];
1903
+ /**
1904
+ * The base each declaring class is written as extending. When the
1905
+ * library is not installed the checker cannot see past a project's
1906
+ * `class Db extends Client`, and a pack asks where the base came from.
1907
+ */
1908
+ extendsWritten: readonly Node[];
1909
+ }
1910
+ /** Every named type the node's type is, nearest first. */
1911
+ declare function receiverTypesOf(node: Node): ReceiverType[];
1912
+
1588
1913
  /**
1589
1914
  * version.ts: this adapter's own half of the cache key.
1590
1915
  *
@@ -1614,19 +1939,23 @@ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
1614
1939
  /**
1615
1940
  * defaulted.ts: whether a read has something behind it.
1616
1941
  *
1617
- * `??` and `||` are ECMAScript, not anything a pack defines, so the
1618
- * packs that record a read ask here instead of each spelling the
1619
- * operators out. This is a separate file from unwrap.ts because that
1620
- * one is about wrappers, and a fallback is not one.
1942
+ * A read is defaulted when the program still works where the value is
1943
+ * missing. Either a `??` or `||` supplies a fallback value, or the
1944
+ * program tests the value for presence, only uses it where the test
1945
+ * passed, and the path a missing value takes does not end in a throw.
1946
+ * The test can be on the read itself or on a local the read
1947
+ * initializes: a truthiness check, a comparison with `undefined` or
1948
+ * `null`, or an `in` membership test.
1949
+ *
1950
+ * All of this is ECMAScript, so the packs that record a read ask here
1951
+ * instead of each spelling the forms out. The Python and Ruby adapters
1952
+ * define the same rule for their own syntax.
1621
1953
  */
1622
1954
 
1623
1955
  /**
1624
- * Whether something else supplies a value when this read comes back
1625
- * empty. `env.X ?? "default"` and `env.X || other` both do, and so does
1626
- * the middle of a chain: in `env.A || env.B || undefined`, B's fallback
1627
- * is the chain's tail. The climb stops when the read is the final
1628
- * operand (`getDefault() ?? env.X`), where the read is itself the
1629
- * fallback and its absence propagates.
1956
+ * Whether the program copes with this read coming back empty: something
1957
+ * falls back from it, or every use of its value runs only after a
1958
+ * presence test has passed.
1630
1959
  */
1631
1960
  declare function isDefaultedAt(node: Node): boolean;
1632
1961
 
@@ -1653,4 +1982,4 @@ declare function climbSyntax(node: Node): Node;
1653
1982
  */
1654
1983
  declare function peelValue(node: Node): Node;
1655
1984
 
1656
- 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 };
1985
+ 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, 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, receiverTypesOf, resolveAliasedSymbol, resolveSubject, rootIdentifier, startsItsOwnScope, stringPropertyOf, stringValueOf, stubEvidence, stubEvidenceIn, symbolBehind, toFunctionRoot, workspaceRootFor, writtenNodeOf, writtenPayloadOf };