@suss/adapter-typescript 0.0.1 → 0.1.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/README.md +1 -1
- package/dist/index.cjs +2810 -947
- package/dist/index.d.cts +210 -38
- package/dist/index.d.ts +210 -38
- package/dist/index.js +2771 -908
- package/package.json +9 -5
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration,
|
|
2
|
-
import { RawCondition, DiscoveryPattern, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure,
|
|
3
|
-
import { BehavioralSummary, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
|
|
1
|
+
import { Node, SourceFile, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, CallExpression, Project, Expression } from 'ts-morph';
|
|
2
|
+
import { TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, EffectArg, RawDeclaredContract, ContractPattern, ResponsePropertyMapping } from '@suss/extractor';
|
|
3
|
+
import { BehavioralSummary, MessageBusSemantics, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Reported by `lookup`. Surfaces what the cache decided and, for
|
|
@@ -92,17 +92,74 @@ interface ExtractionReport {
|
|
|
92
92
|
}
|
|
93
93
|
type EmptyStage = "tsconfig" | "gateResolution" | "candidateFiles" | "discovery" | "assembly";
|
|
94
94
|
|
|
95
|
+
declare class ResolutionStore {
|
|
96
|
+
private readonly db;
|
|
97
|
+
private readonly table;
|
|
98
|
+
private readonly fullyExtracted;
|
|
99
|
+
private readonly seededValues;
|
|
100
|
+
private readonly gateAnswers;
|
|
101
|
+
private resolvedBySource;
|
|
102
|
+
private comesToBySource;
|
|
103
|
+
private stale;
|
|
104
|
+
constructor(wrappers?: TransparentWrapper[]);
|
|
105
|
+
/**
|
|
106
|
+
* The function `value` resolves to, or null when no chain reaches
|
|
107
|
+
* one. The result is a ts-morph node in whatever file the function
|
|
108
|
+
* actually lives.
|
|
109
|
+
*
|
|
110
|
+
* Facts come in waves: extract the file the value lives in, ask, and
|
|
111
|
+
* only widen to the files it imports when the answer is still
|
|
112
|
+
* missing. A value that resolves without leaving its own file costs
|
|
113
|
+
* one file of extraction, not the whole import closure.
|
|
114
|
+
*/
|
|
115
|
+
resolveCallable(value: Node): Node | null;
|
|
116
|
+
/**
|
|
117
|
+
* The object literal `value` ends up being, or null. The route a
|
|
118
|
+
* registration call names often lives on a shared object built in
|
|
119
|
+
* another file, and this is how discovery reads it back.
|
|
120
|
+
*/
|
|
121
|
+
resolveObject(value: Node): Node | null;
|
|
122
|
+
private resolveByWaves;
|
|
123
|
+
/**
|
|
124
|
+
* Facts for the queried value itself. File extraction only reaches
|
|
125
|
+
* values that hang off exports, and a query can be rooted anywhere:
|
|
126
|
+
* a registration call passes `routes.provision` as an argument, and
|
|
127
|
+
* nothing else ever emits facts for that expression.
|
|
128
|
+
*/
|
|
129
|
+
private seedValue;
|
|
130
|
+
private lookupObject;
|
|
131
|
+
/**
|
|
132
|
+
* Whether `file` reaches any of `packages` through its imports,
|
|
133
|
+
* following project-local re-export chains.
|
|
134
|
+
*
|
|
135
|
+
* A walk rather than a rule: the answer is one boolean per file, and
|
|
136
|
+
* deriving the full reachable-module relation for every file in a
|
|
137
|
+
* large repo costs far more than the question is worth.
|
|
138
|
+
*/
|
|
139
|
+
importsTransitively(sourceFile: SourceFile, packages: string[]): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* The one function this value resolves to. Several rules can reach
|
|
142
|
+
* the same answer, which is fine, but reaching two different
|
|
143
|
+
* functions means the rules cannot tell which one the value is, and
|
|
144
|
+
* picking whichever landed in the relation first would make the
|
|
145
|
+
* answer depend on the order facts arrived in. Ambiguity is nothing.
|
|
146
|
+
*/
|
|
147
|
+
private lookup;
|
|
148
|
+
/**
|
|
149
|
+
* Run the rules to fixpoint and index `resolves` by its source, so
|
|
150
|
+
* a lookup is a map hit rather than a scan of every derived tuple.
|
|
151
|
+
*/
|
|
152
|
+
private derive;
|
|
153
|
+
/** Emit a file's facts, unless some earlier query already did. */
|
|
154
|
+
private extractFile;
|
|
155
|
+
}
|
|
156
|
+
|
|
95
157
|
type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration;
|
|
96
158
|
/**
|
|
97
159
|
* Public API — returns RawCondition[] with structured: null.
|
|
98
160
|
* Use collectAncestorConditionInfos when you need the Expression nodes.
|
|
99
161
|
*/
|
|
100
162
|
declare function collectAncestorBranches(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
|
|
101
|
-
/**
|
|
102
|
-
* Public API — returns RawCondition[] with structured: null.
|
|
103
|
-
* Use collectEarlyReturnConditionInfos when you need the Expression nodes.
|
|
104
|
-
*/
|
|
105
|
-
declare function collectEarlyReturns(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
|
|
106
163
|
|
|
107
164
|
interface ClientCallSite {
|
|
108
165
|
callExpression: CallExpression;
|
|
@@ -116,6 +173,21 @@ interface DiscoveredUnit {
|
|
|
116
173
|
callSite?: ClientCallSite;
|
|
117
174
|
/** The discovery pattern that produced this unit. Set by discoverUnits. */
|
|
118
175
|
pattern?: DiscoveryPattern;
|
|
176
|
+
/**
|
|
177
|
+
* Terminal patterns for this unit's body, when a discoverUnits
|
|
178
|
+
* callback attached them (`DiscoveredCustomUnit.terminals`). A pack
|
|
179
|
+
* whose units follow more than one output convention declares the
|
|
180
|
+
* common one at pack level and attaches the other per unit.
|
|
181
|
+
* `extractCodeStructure` falls back to the pack-level `terminals`
|
|
182
|
+
* when unset.
|
|
183
|
+
*/
|
|
184
|
+
terminals?: TerminalPattern[];
|
|
185
|
+
/**
|
|
186
|
+
* Input mapping for this unit, when a discoverUnits callback attached
|
|
187
|
+
* one (`DiscoveredCustomUnit.inputMapping`). Falls back to the
|
|
188
|
+
* pack-level `inputMapping` when unset.
|
|
189
|
+
*/
|
|
190
|
+
inputMapping?: InputMappingPattern;
|
|
119
191
|
/**
|
|
120
192
|
* Populated by `resolverMap`-style discovery (GraphQL code-first).
|
|
121
193
|
* The adapter uses it to build a `graphql-resolver` binding directly,
|
|
@@ -201,6 +273,17 @@ interface DiscoveredUnit {
|
|
|
201
273
|
method: string;
|
|
202
274
|
path: string;
|
|
203
275
|
};
|
|
276
|
+
/**
|
|
277
|
+
* Populated by a pack's `discoverUnits` callback for a message-bus
|
|
278
|
+
* consumer whose channel the code names (a handler factory whose
|
|
279
|
+
* config carries the expected subject). The adapter uses it to build
|
|
280
|
+
* a `message-bus` binding directly, which pairs with producers
|
|
281
|
+
* sending on the same channel.
|
|
282
|
+
*/
|
|
283
|
+
channelInfo?: {
|
|
284
|
+
messageBus: MessageBusSemantics["messageBus"];
|
|
285
|
+
channel: string;
|
|
286
|
+
};
|
|
204
287
|
/**
|
|
205
288
|
* Metadata merged onto the assembled summary's `metadata` field.
|
|
206
289
|
* Populated when a pack's `discoverUnits` callback stamps provenance
|
|
@@ -214,7 +297,7 @@ interface DiscoveredUnit {
|
|
|
214
297
|
* Discover code units in `sourceFile` by running all patterns.
|
|
215
298
|
* Deduplicates entries with the same function node and kind.
|
|
216
299
|
*/
|
|
217
|
-
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[]): DiscoveredUnit[];
|
|
300
|
+
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore): DiscoveredUnit[];
|
|
218
301
|
|
|
219
302
|
interface TimingReport {
|
|
220
303
|
totalMs: number;
|
|
@@ -308,20 +391,58 @@ interface TypeScriptAdapter {
|
|
|
308
391
|
}
|
|
309
392
|
declare function createTypeScriptAdapter(config: TypeScriptAdapterConfig): TypeScriptAdapter;
|
|
310
393
|
|
|
394
|
+
interface FoundTerminal {
|
|
395
|
+
node: Node;
|
|
396
|
+
terminal: RawTerminal;
|
|
397
|
+
/**
|
|
398
|
+
* The return this terminal came from: a ReturnStatement, or the body
|
|
399
|
+
* of an arrow that returns without writing `return`. Absent when the
|
|
400
|
+
* terminal is not a return at all, as a throw is not.
|
|
401
|
+
*
|
|
402
|
+
* The matcher is the only thing that knows, because `node` is
|
|
403
|
+
* wherever the matcher stopped looking, which differs by matcher.
|
|
404
|
+
* Anything downstream that guessed instead got it wrong.
|
|
405
|
+
*/
|
|
406
|
+
source?: Node;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Walk every descendant of `func` and try each pattern in order (first match
|
|
411
|
+
* wins per node). Returns all matched terminals across the whole function.
|
|
412
|
+
*
|
|
413
|
+
* Descends into nested function expressions / arrows so a unit whose
|
|
414
|
+
* terminal output is produced inside a Promise executor or `.then`
|
|
415
|
+
* callback (`res.json(data)` on the unit's own `res` parameter) is still
|
|
416
|
+
* discovered. Inside a nested function only escaping terminals are
|
|
417
|
+
* matched — see `NESTED_ESCAPING_MATCH_TYPES`.
|
|
418
|
+
*/
|
|
419
|
+
declare function findTerminals(func: FunctionRoot, patterns: TerminalPattern[], barriers?: DescentBarriers): FoundTerminal[];
|
|
420
|
+
|
|
311
421
|
/**
|
|
312
422
|
* Extract all raw branches from a function, composing:
|
|
313
|
-
* 1. findTerminals
|
|
314
|
-
* 2.
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
423
|
+
* 1. findTerminals, to locate terminal nodes
|
|
424
|
+
* 2. computePathConditions, for the conditions on each path (CFG
|
|
425
|
+
* enumeration; declined shapes degrade to sound
|
|
426
|
+
* under-specification)
|
|
427
|
+
* 3. parseConditionExpression, turning an Expression into a Predicate
|
|
428
|
+
* 4. extractInvocationEffects, for bare expression-statement calls,
|
|
429
|
+
* attached to the default branch so handler and useEffect bodies
|
|
430
|
+
* carry their side-effect set
|
|
320
431
|
*
|
|
321
432
|
* `isDefault` is true when the branch has no conditions, or all
|
|
322
|
-
* conditions come from early returns
|
|
433
|
+
* conditions come from early returns or throws.
|
|
323
434
|
*/
|
|
324
|
-
|
|
435
|
+
/**
|
|
436
|
+
* The branches a function produces, alongside the terminals they came
|
|
437
|
+
* from. A caller that wants to know which returns went unclaimed needs
|
|
438
|
+
* the terminals, and searching for them a second time costs about as
|
|
439
|
+
* much as this whole pass.
|
|
440
|
+
*/
|
|
441
|
+
interface RawBranchResult {
|
|
442
|
+
branches: RawBranch[];
|
|
443
|
+
terminals: FoundTerminal[];
|
|
444
|
+
}
|
|
445
|
+
declare function extractRawBranches(func: FunctionRoot, terminalPatterns: TerminalPattern[], invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers): RawBranchResult;
|
|
325
446
|
|
|
326
447
|
/**
|
|
327
448
|
* A Project covering `rootDir`, for a codebase with no tsconfig to read.
|
|
@@ -334,6 +455,53 @@ declare function createProjectWithoutTsconfig(rootDir: string): {
|
|
|
334
455
|
/** The nearest tsconfig or jsconfig at or above `startDir`, or null. */
|
|
335
456
|
declare function findNearestTsconfig(startDir: string): string | null;
|
|
336
457
|
|
|
458
|
+
/**
|
|
459
|
+
* A call a project names as its own dispatcher.
|
|
460
|
+
*
|
|
461
|
+
* `receiver` is the type name, not the variable: a service holds its
|
|
462
|
+
* dispatcher in a field, a closure, or a constructor parameter, and
|
|
463
|
+
* only the type is stable across those.
|
|
464
|
+
*/
|
|
465
|
+
interface ConfiguredCallSpec {
|
|
466
|
+
/** Module the receiver's type is declared in. */
|
|
467
|
+
module: string;
|
|
468
|
+
/** Type name of the receiver, as exported from that module. */
|
|
469
|
+
receiver: string;
|
|
470
|
+
/** Method that performs the send. */
|
|
471
|
+
method: string;
|
|
472
|
+
/** Argument index carrying the subject. */
|
|
473
|
+
subjectArg: number;
|
|
474
|
+
/**
|
|
475
|
+
* Argument index carrying the message body. Left out when the
|
|
476
|
+
* method takes no single body argument (a batch method takes a
|
|
477
|
+
* list of entries), and then the read carries no body.
|
|
478
|
+
*/
|
|
479
|
+
bodyArg?: number;
|
|
480
|
+
}
|
|
481
|
+
interface ConfiguredCallRead {
|
|
482
|
+
/** The subject the call names, always a string the source states. */
|
|
483
|
+
subject: string;
|
|
484
|
+
/** The body argument's extracted shape, or null when none applies. */
|
|
485
|
+
body: EffectArg | null;
|
|
486
|
+
/** Source text of the callee, for the effect's `callee` field. */
|
|
487
|
+
callee: string;
|
|
488
|
+
}
|
|
489
|
+
/** The parts of a recognizer context this helper needs. */
|
|
490
|
+
interface ConfiguredCallContext {
|
|
491
|
+
sourceFile: SourceFile;
|
|
492
|
+
extractArgs(): EffectArg[];
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Read `call` as the configured send, or answer null.
|
|
496
|
+
*
|
|
497
|
+
* A subject that is not a string the source states (a variable built
|
|
498
|
+
* at runtime, a template with substitutions, a computed key) answers
|
|
499
|
+
* null, and the pack emits nothing. Naming a channel we cannot read
|
|
500
|
+
* would pair a producer against the wrong consumer, which is worse
|
|
501
|
+
* than not seeing the producer at all.
|
|
502
|
+
*/
|
|
503
|
+
declare function readConfiguredCall(call: CallExpression, ctx: ConfiguredCallContext, spec: ConfiguredCallSpec): ConfiguredCallRead | null;
|
|
504
|
+
|
|
337
505
|
interface ContractReadResult {
|
|
338
506
|
declaredContract: RawDeclaredContract;
|
|
339
507
|
boundaryBinding: BoundaryBinding | null;
|
|
@@ -379,6 +547,25 @@ interface TsDiscoveryContext {
|
|
|
379
547
|
func: FunctionRoot;
|
|
380
548
|
isDefault: boolean;
|
|
381
549
|
}>;
|
|
550
|
+
/**
|
|
551
|
+
* For an export whose declaration is a call to one of `callees`,
|
|
552
|
+
* read the string a property of the call's config object holds:
|
|
553
|
+
* `export const handler = createEventHandler({ expected: "a.b" }, ...)`
|
|
554
|
+
* with `{ callees: ["createEventHandler"], argIndex: 0, property:
|
|
555
|
+
* "expected" }` answers `"a.b"`.
|
|
556
|
+
*
|
|
557
|
+
* The config argument is usually an object literal at the call site;
|
|
558
|
+
* a variable or import is followed to the literal it resolves to.
|
|
559
|
+
* `as const` and parentheses around the property value are peeled.
|
|
560
|
+
* Anything but a string literal underneath (a computed subject, a
|
|
561
|
+
* template, a call) answers null — the caller attaches nothing
|
|
562
|
+
* rather than guessing.
|
|
563
|
+
*/
|
|
564
|
+
exportedCallConfigString(sourceFile: SourceFile, exportName: string, spec: {
|
|
565
|
+
callees: string[];
|
|
566
|
+
argIndex: number;
|
|
567
|
+
property: string;
|
|
568
|
+
}): string | null;
|
|
382
569
|
/**
|
|
383
570
|
* Walk a function's body for return statements whose value is a
|
|
384
571
|
* JSX element / fragment / self-closing tag. Returns true on the
|
|
@@ -391,7 +578,7 @@ interface TsDiscoveryContext {
|
|
|
391
578
|
*/
|
|
392
579
|
hasJsxReturn(func: FunctionRoot): boolean;
|
|
393
580
|
}
|
|
394
|
-
declare function createTsDiscoveryContext(): TsDiscoveryContext;
|
|
581
|
+
declare function createTsDiscoveryContext(resolution?: ResolutionStore): TsDiscoveryContext;
|
|
395
582
|
|
|
396
583
|
/**
|
|
397
584
|
* Parse a ts-morph Expression into a structured Predicate.
|
|
@@ -405,6 +592,8 @@ declare function createTsDiscoveryContext(): TsDiscoveryContext;
|
|
|
405
592
|
*/
|
|
406
593
|
declare function parseConditionExpression(expr: Expression, depth?: number): Predicate | null;
|
|
407
594
|
|
|
595
|
+
declare function isImportedFrom(identifier: Node, expectedModule: string): boolean;
|
|
596
|
+
|
|
408
597
|
interface BranchFieldAccesses {
|
|
409
598
|
/** Terminal location (start, end lines) — used to match back to transitions */
|
|
410
599
|
terminalLocation: {
|
|
@@ -505,24 +694,7 @@ interface TsJsxAttributeLocation {
|
|
|
505
694
|
}
|
|
506
695
|
declare function createTsSubUnitContext(): TsSubUnitContext;
|
|
507
696
|
|
|
508
|
-
|
|
509
|
-
node: Node;
|
|
510
|
-
terminal: RawTerminal;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* Walk every descendant of `func` and try each pattern in order (first match
|
|
515
|
-
* wins per node). Returns all matched terminals across the whole function.
|
|
516
|
-
*
|
|
517
|
-
* Descends into nested function expressions / arrows so a unit whose
|
|
518
|
-
* terminal output is produced inside a Promise executor or `.then`
|
|
519
|
-
* callback (`res.json(data)` on the unit's own `res` parameter) is still
|
|
520
|
-
* discovered. Inside a nested function only escaping terminals are
|
|
521
|
-
* matched — see `NESTED_ESCAPING_MATCH_TYPES`.
|
|
522
|
-
*/
|
|
523
|
-
declare function findTerminals(func: FunctionRoot, patterns: TerminalPattern[], barriers?: DescentBarriers): FoundTerminal[];
|
|
524
|
-
|
|
525
|
-
declare const ADAPTER_VERSION = "0.1.0";
|
|
697
|
+
declare const ADAPTER_VERSION = "0.2.0";
|
|
526
698
|
/**
|
|
527
699
|
* Compute a cache-friendly identity for an adapter+packs combination.
|
|
528
700
|
* Stable across processes given the same inputs; bumps when any pack
|
|
@@ -534,4 +706,4 @@ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
|
|
|
534
706
|
version?: string;
|
|
535
707
|
}>): string;
|
|
536
708
|
|
|
537
|
-
export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExtractionReport, type FoundTerminal, type FunctionRoot, type PackFunnel, type Timer, type TimingReport, type TsDiscoveryContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, collectAncestorBranches, collectClientFieldAccesses,
|
|
709
|
+
export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExtractionReport, type FoundTerminal, type FunctionRoot, type PackFunnel, type Timer, type TimingReport, type TsDiscoveryContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, isImportedFrom, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, resolveSubject };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration,
|
|
2
|
-
import { RawCondition, DiscoveryPattern, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure,
|
|
3
|
-
import { BehavioralSummary, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
|
|
1
|
+
import { Node, SourceFile, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, CallExpression, Project, Expression } from 'ts-morph';
|
|
2
|
+
import { TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, EffectArg, RawDeclaredContract, ContractPattern, ResponsePropertyMapping } from '@suss/extractor';
|
|
3
|
+
import { BehavioralSummary, MessageBusSemantics, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Reported by `lookup`. Surfaces what the cache decided and, for
|
|
@@ -92,17 +92,74 @@ interface ExtractionReport {
|
|
|
92
92
|
}
|
|
93
93
|
type EmptyStage = "tsconfig" | "gateResolution" | "candidateFiles" | "discovery" | "assembly";
|
|
94
94
|
|
|
95
|
+
declare class ResolutionStore {
|
|
96
|
+
private readonly db;
|
|
97
|
+
private readonly table;
|
|
98
|
+
private readonly fullyExtracted;
|
|
99
|
+
private readonly seededValues;
|
|
100
|
+
private readonly gateAnswers;
|
|
101
|
+
private resolvedBySource;
|
|
102
|
+
private comesToBySource;
|
|
103
|
+
private stale;
|
|
104
|
+
constructor(wrappers?: TransparentWrapper[]);
|
|
105
|
+
/**
|
|
106
|
+
* The function `value` resolves to, or null when no chain reaches
|
|
107
|
+
* one. The result is a ts-morph node in whatever file the function
|
|
108
|
+
* actually lives.
|
|
109
|
+
*
|
|
110
|
+
* Facts come in waves: extract the file the value lives in, ask, and
|
|
111
|
+
* only widen to the files it imports when the answer is still
|
|
112
|
+
* missing. A value that resolves without leaving its own file costs
|
|
113
|
+
* one file of extraction, not the whole import closure.
|
|
114
|
+
*/
|
|
115
|
+
resolveCallable(value: Node): Node | null;
|
|
116
|
+
/**
|
|
117
|
+
* The object literal `value` ends up being, or null. The route a
|
|
118
|
+
* registration call names often lives on a shared object built in
|
|
119
|
+
* another file, and this is how discovery reads it back.
|
|
120
|
+
*/
|
|
121
|
+
resolveObject(value: Node): Node | null;
|
|
122
|
+
private resolveByWaves;
|
|
123
|
+
/**
|
|
124
|
+
* Facts for the queried value itself. File extraction only reaches
|
|
125
|
+
* values that hang off exports, and a query can be rooted anywhere:
|
|
126
|
+
* a registration call passes `routes.provision` as an argument, and
|
|
127
|
+
* nothing else ever emits facts for that expression.
|
|
128
|
+
*/
|
|
129
|
+
private seedValue;
|
|
130
|
+
private lookupObject;
|
|
131
|
+
/**
|
|
132
|
+
* Whether `file` reaches any of `packages` through its imports,
|
|
133
|
+
* following project-local re-export chains.
|
|
134
|
+
*
|
|
135
|
+
* A walk rather than a rule: the answer is one boolean per file, and
|
|
136
|
+
* deriving the full reachable-module relation for every file in a
|
|
137
|
+
* large repo costs far more than the question is worth.
|
|
138
|
+
*/
|
|
139
|
+
importsTransitively(sourceFile: SourceFile, packages: string[]): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* The one function this value resolves to. Several rules can reach
|
|
142
|
+
* the same answer, which is fine, but reaching two different
|
|
143
|
+
* functions means the rules cannot tell which one the value is, and
|
|
144
|
+
* picking whichever landed in the relation first would make the
|
|
145
|
+
* answer depend on the order facts arrived in. Ambiguity is nothing.
|
|
146
|
+
*/
|
|
147
|
+
private lookup;
|
|
148
|
+
/**
|
|
149
|
+
* Run the rules to fixpoint and index `resolves` by its source, so
|
|
150
|
+
* a lookup is a map hit rather than a scan of every derived tuple.
|
|
151
|
+
*/
|
|
152
|
+
private derive;
|
|
153
|
+
/** Emit a file's facts, unless some earlier query already did. */
|
|
154
|
+
private extractFile;
|
|
155
|
+
}
|
|
156
|
+
|
|
95
157
|
type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration;
|
|
96
158
|
/**
|
|
97
159
|
* Public API — returns RawCondition[] with structured: null.
|
|
98
160
|
* Use collectAncestorConditionInfos when you need the Expression nodes.
|
|
99
161
|
*/
|
|
100
162
|
declare function collectAncestorBranches(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
|
|
101
|
-
/**
|
|
102
|
-
* Public API — returns RawCondition[] with structured: null.
|
|
103
|
-
* Use collectEarlyReturnConditionInfos when you need the Expression nodes.
|
|
104
|
-
*/
|
|
105
|
-
declare function collectEarlyReturns(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
|
|
106
163
|
|
|
107
164
|
interface ClientCallSite {
|
|
108
165
|
callExpression: CallExpression;
|
|
@@ -116,6 +173,21 @@ interface DiscoveredUnit {
|
|
|
116
173
|
callSite?: ClientCallSite;
|
|
117
174
|
/** The discovery pattern that produced this unit. Set by discoverUnits. */
|
|
118
175
|
pattern?: DiscoveryPattern;
|
|
176
|
+
/**
|
|
177
|
+
* Terminal patterns for this unit's body, when a discoverUnits
|
|
178
|
+
* callback attached them (`DiscoveredCustomUnit.terminals`). A pack
|
|
179
|
+
* whose units follow more than one output convention declares the
|
|
180
|
+
* common one at pack level and attaches the other per unit.
|
|
181
|
+
* `extractCodeStructure` falls back to the pack-level `terminals`
|
|
182
|
+
* when unset.
|
|
183
|
+
*/
|
|
184
|
+
terminals?: TerminalPattern[];
|
|
185
|
+
/**
|
|
186
|
+
* Input mapping for this unit, when a discoverUnits callback attached
|
|
187
|
+
* one (`DiscoveredCustomUnit.inputMapping`). Falls back to the
|
|
188
|
+
* pack-level `inputMapping` when unset.
|
|
189
|
+
*/
|
|
190
|
+
inputMapping?: InputMappingPattern;
|
|
119
191
|
/**
|
|
120
192
|
* Populated by `resolverMap`-style discovery (GraphQL code-first).
|
|
121
193
|
* The adapter uses it to build a `graphql-resolver` binding directly,
|
|
@@ -201,6 +273,17 @@ interface DiscoveredUnit {
|
|
|
201
273
|
method: string;
|
|
202
274
|
path: string;
|
|
203
275
|
};
|
|
276
|
+
/**
|
|
277
|
+
* Populated by a pack's `discoverUnits` callback for a message-bus
|
|
278
|
+
* consumer whose channel the code names (a handler factory whose
|
|
279
|
+
* config carries the expected subject). The adapter uses it to build
|
|
280
|
+
* a `message-bus` binding directly, which pairs with producers
|
|
281
|
+
* sending on the same channel.
|
|
282
|
+
*/
|
|
283
|
+
channelInfo?: {
|
|
284
|
+
messageBus: MessageBusSemantics["messageBus"];
|
|
285
|
+
channel: string;
|
|
286
|
+
};
|
|
204
287
|
/**
|
|
205
288
|
* Metadata merged onto the assembled summary's `metadata` field.
|
|
206
289
|
* Populated when a pack's `discoverUnits` callback stamps provenance
|
|
@@ -214,7 +297,7 @@ interface DiscoveredUnit {
|
|
|
214
297
|
* Discover code units in `sourceFile` by running all patterns.
|
|
215
298
|
* Deduplicates entries with the same function node and kind.
|
|
216
299
|
*/
|
|
217
|
-
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[]): DiscoveredUnit[];
|
|
300
|
+
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore): DiscoveredUnit[];
|
|
218
301
|
|
|
219
302
|
interface TimingReport {
|
|
220
303
|
totalMs: number;
|
|
@@ -308,20 +391,58 @@ interface TypeScriptAdapter {
|
|
|
308
391
|
}
|
|
309
392
|
declare function createTypeScriptAdapter(config: TypeScriptAdapterConfig): TypeScriptAdapter;
|
|
310
393
|
|
|
394
|
+
interface FoundTerminal {
|
|
395
|
+
node: Node;
|
|
396
|
+
terminal: RawTerminal;
|
|
397
|
+
/**
|
|
398
|
+
* The return this terminal came from: a ReturnStatement, or the body
|
|
399
|
+
* of an arrow that returns without writing `return`. Absent when the
|
|
400
|
+
* terminal is not a return at all, as a throw is not.
|
|
401
|
+
*
|
|
402
|
+
* The matcher is the only thing that knows, because `node` is
|
|
403
|
+
* wherever the matcher stopped looking, which differs by matcher.
|
|
404
|
+
* Anything downstream that guessed instead got it wrong.
|
|
405
|
+
*/
|
|
406
|
+
source?: Node;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Walk every descendant of `func` and try each pattern in order (first match
|
|
411
|
+
* wins per node). Returns all matched terminals across the whole function.
|
|
412
|
+
*
|
|
413
|
+
* Descends into nested function expressions / arrows so a unit whose
|
|
414
|
+
* terminal output is produced inside a Promise executor or `.then`
|
|
415
|
+
* callback (`res.json(data)` on the unit's own `res` parameter) is still
|
|
416
|
+
* discovered. Inside a nested function only escaping terminals are
|
|
417
|
+
* matched — see `NESTED_ESCAPING_MATCH_TYPES`.
|
|
418
|
+
*/
|
|
419
|
+
declare function findTerminals(func: FunctionRoot, patterns: TerminalPattern[], barriers?: DescentBarriers): FoundTerminal[];
|
|
420
|
+
|
|
311
421
|
/**
|
|
312
422
|
* Extract all raw branches from a function, composing:
|
|
313
|
-
* 1. findTerminals
|
|
314
|
-
* 2.
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
423
|
+
* 1. findTerminals, to locate terminal nodes
|
|
424
|
+
* 2. computePathConditions, for the conditions on each path (CFG
|
|
425
|
+
* enumeration; declined shapes degrade to sound
|
|
426
|
+
* under-specification)
|
|
427
|
+
* 3. parseConditionExpression, turning an Expression into a Predicate
|
|
428
|
+
* 4. extractInvocationEffects, for bare expression-statement calls,
|
|
429
|
+
* attached to the default branch so handler and useEffect bodies
|
|
430
|
+
* carry their side-effect set
|
|
320
431
|
*
|
|
321
432
|
* `isDefault` is true when the branch has no conditions, or all
|
|
322
|
-
* conditions come from early returns
|
|
433
|
+
* conditions come from early returns or throws.
|
|
323
434
|
*/
|
|
324
|
-
|
|
435
|
+
/**
|
|
436
|
+
* The branches a function produces, alongside the terminals they came
|
|
437
|
+
* from. A caller that wants to know which returns went unclaimed needs
|
|
438
|
+
* the terminals, and searching for them a second time costs about as
|
|
439
|
+
* much as this whole pass.
|
|
440
|
+
*/
|
|
441
|
+
interface RawBranchResult {
|
|
442
|
+
branches: RawBranch[];
|
|
443
|
+
terminals: FoundTerminal[];
|
|
444
|
+
}
|
|
445
|
+
declare function extractRawBranches(func: FunctionRoot, terminalPatterns: TerminalPattern[], invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers): RawBranchResult;
|
|
325
446
|
|
|
326
447
|
/**
|
|
327
448
|
* A Project covering `rootDir`, for a codebase with no tsconfig to read.
|
|
@@ -334,6 +455,53 @@ declare function createProjectWithoutTsconfig(rootDir: string): {
|
|
|
334
455
|
/** The nearest tsconfig or jsconfig at or above `startDir`, or null. */
|
|
335
456
|
declare function findNearestTsconfig(startDir: string): string | null;
|
|
336
457
|
|
|
458
|
+
/**
|
|
459
|
+
* A call a project names as its own dispatcher.
|
|
460
|
+
*
|
|
461
|
+
* `receiver` is the type name, not the variable: a service holds its
|
|
462
|
+
* dispatcher in a field, a closure, or a constructor parameter, and
|
|
463
|
+
* only the type is stable across those.
|
|
464
|
+
*/
|
|
465
|
+
interface ConfiguredCallSpec {
|
|
466
|
+
/** Module the receiver's type is declared in. */
|
|
467
|
+
module: string;
|
|
468
|
+
/** Type name of the receiver, as exported from that module. */
|
|
469
|
+
receiver: string;
|
|
470
|
+
/** Method that performs the send. */
|
|
471
|
+
method: string;
|
|
472
|
+
/** Argument index carrying the subject. */
|
|
473
|
+
subjectArg: number;
|
|
474
|
+
/**
|
|
475
|
+
* Argument index carrying the message body. Left out when the
|
|
476
|
+
* method takes no single body argument (a batch method takes a
|
|
477
|
+
* list of entries), and then the read carries no body.
|
|
478
|
+
*/
|
|
479
|
+
bodyArg?: number;
|
|
480
|
+
}
|
|
481
|
+
interface ConfiguredCallRead {
|
|
482
|
+
/** The subject the call names, always a string the source states. */
|
|
483
|
+
subject: string;
|
|
484
|
+
/** The body argument's extracted shape, or null when none applies. */
|
|
485
|
+
body: EffectArg | null;
|
|
486
|
+
/** Source text of the callee, for the effect's `callee` field. */
|
|
487
|
+
callee: string;
|
|
488
|
+
}
|
|
489
|
+
/** The parts of a recognizer context this helper needs. */
|
|
490
|
+
interface ConfiguredCallContext {
|
|
491
|
+
sourceFile: SourceFile;
|
|
492
|
+
extractArgs(): EffectArg[];
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Read `call` as the configured send, or answer null.
|
|
496
|
+
*
|
|
497
|
+
* A subject that is not a string the source states (a variable built
|
|
498
|
+
* at runtime, a template with substitutions, a computed key) answers
|
|
499
|
+
* null, and the pack emits nothing. Naming a channel we cannot read
|
|
500
|
+
* would pair a producer against the wrong consumer, which is worse
|
|
501
|
+
* than not seeing the producer at all.
|
|
502
|
+
*/
|
|
503
|
+
declare function readConfiguredCall(call: CallExpression, ctx: ConfiguredCallContext, spec: ConfiguredCallSpec): ConfiguredCallRead | null;
|
|
504
|
+
|
|
337
505
|
interface ContractReadResult {
|
|
338
506
|
declaredContract: RawDeclaredContract;
|
|
339
507
|
boundaryBinding: BoundaryBinding | null;
|
|
@@ -379,6 +547,25 @@ interface TsDiscoveryContext {
|
|
|
379
547
|
func: FunctionRoot;
|
|
380
548
|
isDefault: boolean;
|
|
381
549
|
}>;
|
|
550
|
+
/**
|
|
551
|
+
* For an export whose declaration is a call to one of `callees`,
|
|
552
|
+
* read the string a property of the call's config object holds:
|
|
553
|
+
* `export const handler = createEventHandler({ expected: "a.b" }, ...)`
|
|
554
|
+
* with `{ callees: ["createEventHandler"], argIndex: 0, property:
|
|
555
|
+
* "expected" }` answers `"a.b"`.
|
|
556
|
+
*
|
|
557
|
+
* The config argument is usually an object literal at the call site;
|
|
558
|
+
* a variable or import is followed to the literal it resolves to.
|
|
559
|
+
* `as const` and parentheses around the property value are peeled.
|
|
560
|
+
* Anything but a string literal underneath (a computed subject, a
|
|
561
|
+
* template, a call) answers null — the caller attaches nothing
|
|
562
|
+
* rather than guessing.
|
|
563
|
+
*/
|
|
564
|
+
exportedCallConfigString(sourceFile: SourceFile, exportName: string, spec: {
|
|
565
|
+
callees: string[];
|
|
566
|
+
argIndex: number;
|
|
567
|
+
property: string;
|
|
568
|
+
}): string | null;
|
|
382
569
|
/**
|
|
383
570
|
* Walk a function's body for return statements whose value is a
|
|
384
571
|
* JSX element / fragment / self-closing tag. Returns true on the
|
|
@@ -391,7 +578,7 @@ interface TsDiscoveryContext {
|
|
|
391
578
|
*/
|
|
392
579
|
hasJsxReturn(func: FunctionRoot): boolean;
|
|
393
580
|
}
|
|
394
|
-
declare function createTsDiscoveryContext(): TsDiscoveryContext;
|
|
581
|
+
declare function createTsDiscoveryContext(resolution?: ResolutionStore): TsDiscoveryContext;
|
|
395
582
|
|
|
396
583
|
/**
|
|
397
584
|
* Parse a ts-morph Expression into a structured Predicate.
|
|
@@ -405,6 +592,8 @@ declare function createTsDiscoveryContext(): TsDiscoveryContext;
|
|
|
405
592
|
*/
|
|
406
593
|
declare function parseConditionExpression(expr: Expression, depth?: number): Predicate | null;
|
|
407
594
|
|
|
595
|
+
declare function isImportedFrom(identifier: Node, expectedModule: string): boolean;
|
|
596
|
+
|
|
408
597
|
interface BranchFieldAccesses {
|
|
409
598
|
/** Terminal location (start, end lines) — used to match back to transitions */
|
|
410
599
|
terminalLocation: {
|
|
@@ -505,24 +694,7 @@ interface TsJsxAttributeLocation {
|
|
|
505
694
|
}
|
|
506
695
|
declare function createTsSubUnitContext(): TsSubUnitContext;
|
|
507
696
|
|
|
508
|
-
|
|
509
|
-
node: Node;
|
|
510
|
-
terminal: RawTerminal;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/**
|
|
514
|
-
* Walk every descendant of `func` and try each pattern in order (first match
|
|
515
|
-
* wins per node). Returns all matched terminals across the whole function.
|
|
516
|
-
*
|
|
517
|
-
* Descends into nested function expressions / arrows so a unit whose
|
|
518
|
-
* terminal output is produced inside a Promise executor or `.then`
|
|
519
|
-
* callback (`res.json(data)` on the unit's own `res` parameter) is still
|
|
520
|
-
* discovered. Inside a nested function only escaping terminals are
|
|
521
|
-
* matched — see `NESTED_ESCAPING_MATCH_TYPES`.
|
|
522
|
-
*/
|
|
523
|
-
declare function findTerminals(func: FunctionRoot, patterns: TerminalPattern[], barriers?: DescentBarriers): FoundTerminal[];
|
|
524
|
-
|
|
525
|
-
declare const ADAPTER_VERSION = "0.1.0";
|
|
697
|
+
declare const ADAPTER_VERSION = "0.2.0";
|
|
526
698
|
/**
|
|
527
699
|
* Compute a cache-friendly identity for an adapter+packs combination.
|
|
528
700
|
* Stable across processes given the same inputs; bumps when any pack
|
|
@@ -534,4 +706,4 @@ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
|
|
|
534
706
|
version?: string;
|
|
535
707
|
}>): string;
|
|
536
708
|
|
|
537
|
-
export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExtractionReport, type FoundTerminal, type FunctionRoot, type PackFunnel, type Timer, type TimingReport, type TsDiscoveryContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, collectAncestorBranches, collectClientFieldAccesses,
|
|
709
|
+
export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExtractionReport, type FoundTerminal, type FunctionRoot, type PackFunnel, type Timer, type TimingReport, type TsDiscoveryContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, isImportedFrom, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, resolveSubject };
|