@suss/adapter-typescript 0.20.0 → 0.21.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/README.md +3 -1
- package/dist/index.cjs +1912 -878
- package/dist/index.d.cts +161 -51
- package/dist/index.d.ts +161 -51
- package/dist/index.js +1875 -840
- package/package.json +7 -6
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SourceFile, Node, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, CallExpression, PropertyAccessExpression, TaggedTemplateExpression, Project, ImportDeclaration, Symbol, Expression, NewExpression, Identifier } from 'ts-morph';
|
|
2
|
-
import { PackDeclarations, TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, EffectArg, CallOps, LanguageAdapter, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, RawDeclaredContract, ContractPattern, AstCapableOps, ResponsePropertyMapping } from '@suss/extractor';
|
|
2
|
+
import { PackDeclarations, TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, EffectArg, CallOps, LanguageAdapter, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, configuredCallOption, RawDeclaredContract, ContractPattern, AstCapableOps, ResponsePropertyMapping } from '@suss/extractor';
|
|
3
3
|
import { BehavioralSummary, MessageBusSemantics, DeployableUnit, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
|
|
4
|
+
import { z } from 'zod';
|
|
4
5
|
import { Proof, Atom } from '@suss/datalog';
|
|
5
6
|
import { ResolutionExplanation } from '@suss/resolution';
|
|
6
7
|
|
|
@@ -140,6 +141,14 @@ interface PackFunnel {
|
|
|
140
141
|
* while this is non-empty.
|
|
141
142
|
*/
|
|
142
143
|
failures: PackFailure[];
|
|
144
|
+
/**
|
|
145
|
+
* Registration helpers this pack's config asked for that no call in
|
|
146
|
+
* the run matched. The helper belongs to the project, so a spelling
|
|
147
|
+
* that matches nothing is a config mistake with no other symptom: the
|
|
148
|
+
* routes go missing and every count reads the same as a project
|
|
149
|
+
* without them.
|
|
150
|
+
*/
|
|
151
|
+
helpersUnmatched: string[];
|
|
143
152
|
/**
|
|
144
153
|
* What the pack wrote as data rather than as code, or null for a pack
|
|
145
154
|
* written as a hand-rolled walk. This is the one thing in the funnel
|
|
@@ -247,6 +256,7 @@ declare class ResolutionStore {
|
|
|
247
256
|
private readonly importedNames;
|
|
248
257
|
private readonly writtenValues;
|
|
249
258
|
private readonly importOrigins;
|
|
259
|
+
private readonly subjectConstructions;
|
|
250
260
|
/**
|
|
251
261
|
* A file's table depends only on its re-export closure, which
|
|
252
262
|
* `collectExports` extracts whole before answering, so later
|
|
@@ -288,6 +298,36 @@ declare class ResolutionStore {
|
|
|
288
298
|
* GraphQL document kept in a constant in another file.
|
|
289
299
|
*/
|
|
290
300
|
resolveWrittenValue(value: Node): Node | null;
|
|
301
|
+
/**
|
|
302
|
+
* The construction behind a registration subject: the call or `new`
|
|
303
|
+
* this value is written as, kept only when its callee comes from
|
|
304
|
+
* `importModule` under `importName`. A value written as two
|
|
305
|
+
* different things comes back null, since keying a route on the
|
|
306
|
+
* wrong app is worse than not keying it.
|
|
307
|
+
*/
|
|
308
|
+
subjectConstructionOf(value: Node, importModule: string, importName: string): Node | null;
|
|
309
|
+
/**
|
|
310
|
+
* How many constructions this value was written as, which is what
|
|
311
|
+
* `subjectConstructionOf` weighed before it declined. Ask it after
|
|
312
|
+
* that call, so the walk it needs has already been paid for.
|
|
313
|
+
*/
|
|
314
|
+
subjectCandidateCountOf(value: Node, importModule: string, importName: string): number;
|
|
315
|
+
/**
|
|
316
|
+
* The single-answer policy over the written-value walk, then the
|
|
317
|
+
* origin check on the one candidate. A candidate failing the check
|
|
318
|
+
* is settled refusal rather than a reason to widen: its own file's
|
|
319
|
+
* import facts are already in, and more files only add candidates.
|
|
320
|
+
*/
|
|
321
|
+
private lookupSubjectConstruction;
|
|
322
|
+
/**
|
|
323
|
+
* Whether the construction's callee was imported from this module
|
|
324
|
+
* under this name. A default import records its name as "default",
|
|
325
|
+
* and a pack declares a default export by the local name people
|
|
326
|
+
* give it, so "default" counts when the callee is spelled with the
|
|
327
|
+
* declared name.
|
|
328
|
+
*/
|
|
329
|
+
private constructionComesFrom;
|
|
330
|
+
private calleeNameOf;
|
|
291
331
|
/**
|
|
292
332
|
* Which names from `modules` this value comes down to, either by being
|
|
293
333
|
* one of them under a local name or by calling into one. Getting
|
|
@@ -355,6 +395,15 @@ declare class ResolutionStore {
|
|
|
355
395
|
* construction makes an instance of. The README says why.
|
|
356
396
|
*/
|
|
357
397
|
private lookupWritten;
|
|
398
|
+
/**
|
|
399
|
+
* Read these files' facts now, before anything asks a question.
|
|
400
|
+
*
|
|
401
|
+
* A query widens along the imports of the file it starts in, which
|
|
402
|
+
* is where a value's definition is. What a caller passed is the other
|
|
403
|
+
* direction, so a question about a parameter is answered only by
|
|
404
|
+
* files the walk never reaches on its own.
|
|
405
|
+
*/
|
|
406
|
+
extractFiles(sourceFiles: Iterable<SourceFile>): void;
|
|
358
407
|
/**
|
|
359
408
|
* Which of these files reach any of these packages, following
|
|
360
409
|
* project-local re-export chains. A barrel package that re-exports an
|
|
@@ -405,6 +454,44 @@ type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | M
|
|
|
405
454
|
*/
|
|
406
455
|
declare function collectAncestorBranches(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
|
|
407
456
|
|
|
457
|
+
/**
|
|
458
|
+
* unfollowedCall.ts: naming the calls the reachable closure stops at.
|
|
459
|
+
*
|
|
460
|
+
* The closure follows a call by resolving its callee to a function with a
|
|
461
|
+
* body. When that fails the edge is dropped, and a unit whose body is full
|
|
462
|
+
* of dropped edges produces the same empty summary as a unit that does
|
|
463
|
+
* nothing. This module says which kind of stop a call site is, and which
|
|
464
|
+
* kinds are worth leaving a gap for.
|
|
465
|
+
*
|
|
466
|
+
* The README beside this file explains where that line is drawn, and why
|
|
467
|
+
* a call into a dependency stays on the other side of it.
|
|
468
|
+
*/
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Why the walk stopped.
|
|
472
|
+
*
|
|
473
|
+
* `noBody` states a shape and nothing else: a method on an interface, an
|
|
474
|
+
* abstract method, an ambient declaration. `unsettledValue` is declared
|
|
475
|
+
* as something other than a function, with something in it that could
|
|
476
|
+
* not be read. `multipleSources` reaches two different functions, so no
|
|
477
|
+
* single body can be followed. `outsideRun` is a declaration in a
|
|
478
|
+
* dependency, whose source this run never read. `noDeclaration` is a
|
|
479
|
+
* callee nothing declares, which is what a call on an untyped value
|
|
480
|
+
* comes to. `callerSupplied` is a parameter of the function being
|
|
481
|
+
* scanned, so the call runs whatever its caller handed in.
|
|
482
|
+
* `multipleReceivers` is a registration whose receiver comes down to
|
|
483
|
+
* more than one thing, so nothing says which one it registers on.
|
|
484
|
+
*/
|
|
485
|
+
type UnfollowedReason = "noBody" | "unsettledValue" | "multipleSources" | "outsideRun" | "noDeclaration" | "callerSupplied" | "multipleReceivers";
|
|
486
|
+
/** One call the walk met and could not follow. */
|
|
487
|
+
interface UnfollowedCall {
|
|
488
|
+
/** The callee as the source writes it, `this.dao.getEditions` say. */
|
|
489
|
+
readonly callee: string;
|
|
490
|
+
readonly reason: UnfollowedReason;
|
|
491
|
+
/** How many things the walk reached where it needed one. */
|
|
492
|
+
readonly candidates?: number;
|
|
493
|
+
}
|
|
494
|
+
|
|
408
495
|
interface ClientCallSite {
|
|
409
496
|
callExpression: CallExpression;
|
|
410
497
|
/** Method name on the client object (e.g. "getUser"), null for bare calls like fetch() */
|
|
@@ -556,6 +643,19 @@ interface DiscoveredUnit {
|
|
|
556
643
|
/** Null when the pack knows the wire but not the channel on it. */
|
|
557
644
|
channel: string | null;
|
|
558
645
|
};
|
|
646
|
+
/**
|
|
647
|
+
* Populated by a pack's `discoverUnits` callback for a deployed unit
|
|
648
|
+
* nothing else routes to, which is reached by being invoked by name.
|
|
649
|
+
* The adapter builds a `unit-invocation` binding from it, which pairs
|
|
650
|
+
* with the calls that name the same unit.
|
|
651
|
+
*/
|
|
652
|
+
invocationInfo?: DeployableUnit;
|
|
653
|
+
/**
|
|
654
|
+
* Identity of the routable this unit was registered on, when a
|
|
655
|
+
* registration call put it there. What the wrapper index is keyed on,
|
|
656
|
+
* since a wrapper is registered on the routable and not on the unit.
|
|
657
|
+
*/
|
|
658
|
+
registrationSubjectId?: string;
|
|
559
659
|
/** The thing that gets deployed and runs this unit, when known. */
|
|
560
660
|
deployableUnit?: DeployableUnit;
|
|
561
661
|
/**
|
|
@@ -573,6 +673,12 @@ interface DiscoveredUnit {
|
|
|
573
673
|
* summary as an `unreadOutcome` gap.
|
|
574
674
|
*/
|
|
575
675
|
unreadBinding?: string;
|
|
676
|
+
/**
|
|
677
|
+
* A call the handler met and could not follow, which reaches the
|
|
678
|
+
* summary as an `unfollowedCall` gap beside the ones the closure
|
|
679
|
+
* walk records.
|
|
680
|
+
*/
|
|
681
|
+
unfollowed?: UnfollowedCall;
|
|
576
682
|
}
|
|
577
683
|
|
|
578
684
|
/**
|
|
@@ -597,12 +703,19 @@ interface MountPrefixIndex {
|
|
|
597
703
|
*/
|
|
598
704
|
prefixForId?(childId: string): string;
|
|
599
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* What the project helper index says it has already expanded, which the
|
|
708
|
+
* walk consults so one registration does not become two summaries.
|
|
709
|
+
*/
|
|
710
|
+
interface ExpandedRegistrations {
|
|
711
|
+
expandedAtCallSites(helper: Node, method: string): boolean;
|
|
712
|
+
}
|
|
600
713
|
|
|
601
714
|
/**
|
|
602
715
|
* Discover code units in `sourceFile` by running all patterns.
|
|
603
716
|
* Deduplicates entries with the same function node and kind.
|
|
604
717
|
*/
|
|
605
|
-
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore, mountPrefixes?: MountPrefixIndex): DiscoveredUnit[];
|
|
718
|
+
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore, mountPrefixes?: MountPrefixIndex, expandedElsewhere?: ExpandedRegistrations): DiscoveredUnit[];
|
|
606
719
|
|
|
607
720
|
interface TimingReport {
|
|
608
721
|
totalMs: number;
|
|
@@ -887,28 +1000,12 @@ declare function findNearestTsconfig(startDir: string): string | null;
|
|
|
887
1000
|
*/
|
|
888
1001
|
|
|
889
1002
|
/**
|
|
890
|
-
* A call the project has declared to be its own dispatcher.
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
894
|
-
* the type is the only thing stable across all three.
|
|
1003
|
+
* A call the project has declared to be its own dispatcher. The
|
|
1004
|
+
* declaration a project config is parsed against lives with the other
|
|
1005
|
+
* shared pack options, so this reader and the packs that take it under
|
|
1006
|
+
* `producers` describe one shape.
|
|
895
1007
|
*/
|
|
896
|
-
|
|
897
|
-
/** Module that declares the receiver's type. */
|
|
898
|
-
module: string;
|
|
899
|
-
/** Type name of the receiver, as exported from that module. */
|
|
900
|
-
receiver: string;
|
|
901
|
-
/** Method that performs the send. */
|
|
902
|
-
method: string;
|
|
903
|
-
/** Argument index carrying the subject. */
|
|
904
|
-
subjectArg: number;
|
|
905
|
-
/**
|
|
906
|
-
* Which argument the message body is. Left out when the method has no
|
|
907
|
-
* single body argument, as a batch method taking a list of entries
|
|
908
|
-
* does, and then no body is reported.
|
|
909
|
-
*/
|
|
910
|
-
bodyArg?: number;
|
|
911
|
-
}
|
|
1008
|
+
type ConfiguredCallSpec = z.infer<typeof configuredCallOption>;
|
|
912
1009
|
interface ConfiguredCallRead {
|
|
913
1010
|
/** The subject the call sends to, always a literal string. */
|
|
914
1011
|
subject: string;
|
|
@@ -962,6 +1059,45 @@ declare function readContract(unit: DiscoveredUnit, pattern: ContractPattern, fr
|
|
|
962
1059
|
*/
|
|
963
1060
|
declare function readContractForClientCall(callExpression: Node, methodName: string, pattern: ContractPattern, framework: string, resolution?: ResolutionStore): ContractReadResult | null;
|
|
964
1061
|
|
|
1062
|
+
/**
|
|
1063
|
+
* helperIndex.ts: reading the project's own helpers once, before any
|
|
1064
|
+
* file is walked.
|
|
1065
|
+
*
|
|
1066
|
+
* A pack that declares `projectHelpers` gets every helper the project
|
|
1067
|
+
* wrote in front of its library, each read in terms of its own
|
|
1068
|
+
* parameters, and gives back the patterns and recognizers it would
|
|
1069
|
+
* otherwise have taken as config. Those join the pack for the rest of
|
|
1070
|
+
* the run, so the match happens at the call site, where the arguments
|
|
1071
|
+
* are literal.
|
|
1072
|
+
*
|
|
1073
|
+
* Built alongside the mount and wrapper indexes, over the same files.
|
|
1074
|
+
* The discovery README has the ordering and the cost.
|
|
1075
|
+
*/
|
|
1076
|
+
|
|
1077
|
+
interface ProjectHelperIndex {
|
|
1078
|
+
/** Discovery patterns `packName` contributed after reading the project. */
|
|
1079
|
+
patternsFor(packName: string): readonly DiscoveryPattern[];
|
|
1080
|
+
/**
|
|
1081
|
+
* Recognizers the packs contributed. They match calls to functions
|
|
1082
|
+
* this project declares, so they run wherever a call can appear
|
|
1083
|
+
* rather than only where the pack's own import gate reaches.
|
|
1084
|
+
*/
|
|
1085
|
+
contributedRecognizers(): readonly InvocationRecognizer[];
|
|
1086
|
+
/**
|
|
1087
|
+
* The helper files that shaped what `file` extracts to, so the
|
|
1088
|
+
* per-file cache invalidates `file` when one of them is edited.
|
|
1089
|
+
*/
|
|
1090
|
+
helperFilesFor(file: SourceFile): readonly string[];
|
|
1091
|
+
/**
|
|
1092
|
+
* Whether a registration written inside `helper` with `method` is one
|
|
1093
|
+
* the call sites already expand. Reading it here as well would give
|
|
1094
|
+
* one registration two summaries, and which of the two a run kept
|
|
1095
|
+
* would come down to the order the files were walked in.
|
|
1096
|
+
*/
|
|
1097
|
+
expandedAtCallSites(helper: Node, method: string): boolean;
|
|
1098
|
+
}
|
|
1099
|
+
declare function buildProjectHelperIndex(sourceFiles: ReadonlyArray<SourceFile>, packs: ReadonlyArray<PatternPack>, packsByFile: ReadonlyMap<SourceFile, readonly PatternPack[]>, resolution: ResolutionStore): ProjectHelperIndex;
|
|
1100
|
+
|
|
965
1101
|
/**
|
|
966
1102
|
* The one import scan.
|
|
967
1103
|
*
|
|
@@ -1027,32 +1163,6 @@ interface TsDiscoveryContext {
|
|
|
1027
1163
|
func: FunctionRoot;
|
|
1028
1164
|
isDefault: boolean;
|
|
1029
1165
|
}>;
|
|
1030
|
-
/**
|
|
1031
|
-
* For an export the project builds by calling a factory, the string
|
|
1032
|
-
* under a property of that call's config object:
|
|
1033
|
-
* `export const handler = makeWidgetHandler({ subject: "a.b" }, ...)`
|
|
1034
|
-
* with `{ property: "subject" }` gives back `"a.b"`.
|
|
1035
|
-
*
|
|
1036
|
-
* The caller does not have to say which function was called or which
|
|
1037
|
-
* argument the config was in. Every object argument is read. Giving the
|
|
1038
|
-
* callee or fixing the argument position narrows that down, for a
|
|
1039
|
-
* project whose factories would otherwise collide.
|
|
1040
|
-
*
|
|
1041
|
-
* Two arguments with the property set to different values give back
|
|
1042
|
-
* null, since nothing says which one was meant.
|
|
1043
|
-
*
|
|
1044
|
-
* The config argument is usually an object literal at the call site;
|
|
1045
|
-
* a variable or import is followed to the literal it resolves to.
|
|
1046
|
-
* `as const` and parentheses around the property value are peeled.
|
|
1047
|
-
* Anything but a string literal underneath (a computed subject, a
|
|
1048
|
-
* template, a call) gives back null, and the caller attaches nothing
|
|
1049
|
-
* rather than guessing.
|
|
1050
|
-
*/
|
|
1051
|
-
exportedCallConfigString(sourceFile: SourceFile, exportName: string, spec: {
|
|
1052
|
-
callees?: string[];
|
|
1053
|
-
argIndex?: number;
|
|
1054
|
-
property: string;
|
|
1055
|
-
}): string | null;
|
|
1056
1166
|
/**
|
|
1057
1167
|
* Walk a function's body for return statements whose value is a
|
|
1058
1168
|
* JSX element / fragment / self-closing tag. Returns true on the
|
|
@@ -1339,7 +1449,7 @@ declare function collectClientFieldAccesses(callExpr: CallExpression, func: Node
|
|
|
1339
1449
|
/**
|
|
1340
1450
|
* Evidence for drafting a dependency stub: every call the project
|
|
1341
1451
|
* makes into a named package, grouped by the export it reaches, with
|
|
1342
|
-
* the argument shapes observed at each call site. `suss stub
|
|
1452
|
+
* the argument shapes observed at each call site. `suss infer stub`
|
|
1343
1453
|
* turns this into a stub skeleton for an author to fill in. The
|
|
1344
1454
|
* package's own code is never read, only the project's calls into it,
|
|
1345
1455
|
* so this works for packages whose source no adapter can parse.
|
|
@@ -1501,4 +1611,4 @@ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
|
|
|
1501
1611
|
version?: string;
|
|
1502
1612
|
}>): string;
|
|
1503
1613
|
|
|
1504
|
-
export { ADAPTER_VERSION, type Accessed, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExplainCallableOptions, type ExplainStats, type ExplainedResolution, type ExtractionReport, type FoundTerminal, type FunctionRoot, type HealthCheck, type HealthViolation, type ImportScanOptions, type ObservedStubCall, type PackFunnel, type PackGradient, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, type Timer, type TimingReport, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, type ValueLocation, type WhyExplained, WhySession, type WhySessionOptions, accessContextFor, callOpsFor, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, computeContentHash, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, evaluatePackHealth, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, formatPackHealth, functionTargetOf, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isImportedFrom, methodDeclaredIn, namedImportsOf, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, stubEvidence, stubEvidenceIn, workspaceRootFor };
|
|
1614
|
+
export { ADAPTER_VERSION, type Accessed, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExplainCallableOptions, type ExplainStats, type ExplainedResolution, type ExtractionReport, type FoundTerminal, type FunctionRoot, type HealthCheck, type HealthViolation, type ImportScanOptions, type ObservedStubCall, type PackFunnel, type PackGradient, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, type Timer, type TimingReport, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, type ValueLocation, type WhyExplained, WhySession, type WhySessionOptions, accessContextFor, buildProjectHelperIndex, callOpsFor, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, computeContentHash, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, evaluatePackHealth, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, formatPackHealth, functionTargetOf, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isImportedFrom, methodDeclaredIn, namedImportsOf, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, stubEvidence, stubEvidenceIn, workspaceRootFor };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SourceFile, Node, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, CallExpression, PropertyAccessExpression, TaggedTemplateExpression, Project, ImportDeclaration, Symbol, Expression, NewExpression, Identifier } from 'ts-morph';
|
|
2
|
-
import { PackDeclarations, TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, EffectArg, CallOps, LanguageAdapter, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, RawDeclaredContract, ContractPattern, AstCapableOps, ResponsePropertyMapping } from '@suss/extractor';
|
|
2
|
+
import { PackDeclarations, TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, EffectArg, CallOps, LanguageAdapter, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, configuredCallOption, RawDeclaredContract, ContractPattern, AstCapableOps, ResponsePropertyMapping } from '@suss/extractor';
|
|
3
3
|
import { BehavioralSummary, MessageBusSemantics, DeployableUnit, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
|
|
4
|
+
import { z } from 'zod';
|
|
4
5
|
import { Proof, Atom } from '@suss/datalog';
|
|
5
6
|
import { ResolutionExplanation } from '@suss/resolution';
|
|
6
7
|
|
|
@@ -140,6 +141,14 @@ interface PackFunnel {
|
|
|
140
141
|
* while this is non-empty.
|
|
141
142
|
*/
|
|
142
143
|
failures: PackFailure[];
|
|
144
|
+
/**
|
|
145
|
+
* Registration helpers this pack's config asked for that no call in
|
|
146
|
+
* the run matched. The helper belongs to the project, so a spelling
|
|
147
|
+
* that matches nothing is a config mistake with no other symptom: the
|
|
148
|
+
* routes go missing and every count reads the same as a project
|
|
149
|
+
* without them.
|
|
150
|
+
*/
|
|
151
|
+
helpersUnmatched: string[];
|
|
143
152
|
/**
|
|
144
153
|
* What the pack wrote as data rather than as code, or null for a pack
|
|
145
154
|
* written as a hand-rolled walk. This is the one thing in the funnel
|
|
@@ -247,6 +256,7 @@ declare class ResolutionStore {
|
|
|
247
256
|
private readonly importedNames;
|
|
248
257
|
private readonly writtenValues;
|
|
249
258
|
private readonly importOrigins;
|
|
259
|
+
private readonly subjectConstructions;
|
|
250
260
|
/**
|
|
251
261
|
* A file's table depends only on its re-export closure, which
|
|
252
262
|
* `collectExports` extracts whole before answering, so later
|
|
@@ -288,6 +298,36 @@ declare class ResolutionStore {
|
|
|
288
298
|
* GraphQL document kept in a constant in another file.
|
|
289
299
|
*/
|
|
290
300
|
resolveWrittenValue(value: Node): Node | null;
|
|
301
|
+
/**
|
|
302
|
+
* The construction behind a registration subject: the call or `new`
|
|
303
|
+
* this value is written as, kept only when its callee comes from
|
|
304
|
+
* `importModule` under `importName`. A value written as two
|
|
305
|
+
* different things comes back null, since keying a route on the
|
|
306
|
+
* wrong app is worse than not keying it.
|
|
307
|
+
*/
|
|
308
|
+
subjectConstructionOf(value: Node, importModule: string, importName: string): Node | null;
|
|
309
|
+
/**
|
|
310
|
+
* How many constructions this value was written as, which is what
|
|
311
|
+
* `subjectConstructionOf` weighed before it declined. Ask it after
|
|
312
|
+
* that call, so the walk it needs has already been paid for.
|
|
313
|
+
*/
|
|
314
|
+
subjectCandidateCountOf(value: Node, importModule: string, importName: string): number;
|
|
315
|
+
/**
|
|
316
|
+
* The single-answer policy over the written-value walk, then the
|
|
317
|
+
* origin check on the one candidate. A candidate failing the check
|
|
318
|
+
* is settled refusal rather than a reason to widen: its own file's
|
|
319
|
+
* import facts are already in, and more files only add candidates.
|
|
320
|
+
*/
|
|
321
|
+
private lookupSubjectConstruction;
|
|
322
|
+
/**
|
|
323
|
+
* Whether the construction's callee was imported from this module
|
|
324
|
+
* under this name. A default import records its name as "default",
|
|
325
|
+
* and a pack declares a default export by the local name people
|
|
326
|
+
* give it, so "default" counts when the callee is spelled with the
|
|
327
|
+
* declared name.
|
|
328
|
+
*/
|
|
329
|
+
private constructionComesFrom;
|
|
330
|
+
private calleeNameOf;
|
|
291
331
|
/**
|
|
292
332
|
* Which names from `modules` this value comes down to, either by being
|
|
293
333
|
* one of them under a local name or by calling into one. Getting
|
|
@@ -355,6 +395,15 @@ declare class ResolutionStore {
|
|
|
355
395
|
* construction makes an instance of. The README says why.
|
|
356
396
|
*/
|
|
357
397
|
private lookupWritten;
|
|
398
|
+
/**
|
|
399
|
+
* Read these files' facts now, before anything asks a question.
|
|
400
|
+
*
|
|
401
|
+
* A query widens along the imports of the file it starts in, which
|
|
402
|
+
* is where a value's definition is. What a caller passed is the other
|
|
403
|
+
* direction, so a question about a parameter is answered only by
|
|
404
|
+
* files the walk never reaches on its own.
|
|
405
|
+
*/
|
|
406
|
+
extractFiles(sourceFiles: Iterable<SourceFile>): void;
|
|
358
407
|
/**
|
|
359
408
|
* Which of these files reach any of these packages, following
|
|
360
409
|
* project-local re-export chains. A barrel package that re-exports an
|
|
@@ -405,6 +454,44 @@ type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | M
|
|
|
405
454
|
*/
|
|
406
455
|
declare function collectAncestorBranches(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
|
|
407
456
|
|
|
457
|
+
/**
|
|
458
|
+
* unfollowedCall.ts: naming the calls the reachable closure stops at.
|
|
459
|
+
*
|
|
460
|
+
* The closure follows a call by resolving its callee to a function with a
|
|
461
|
+
* body. When that fails the edge is dropped, and a unit whose body is full
|
|
462
|
+
* of dropped edges produces the same empty summary as a unit that does
|
|
463
|
+
* nothing. This module says which kind of stop a call site is, and which
|
|
464
|
+
* kinds are worth leaving a gap for.
|
|
465
|
+
*
|
|
466
|
+
* The README beside this file explains where that line is drawn, and why
|
|
467
|
+
* a call into a dependency stays on the other side of it.
|
|
468
|
+
*/
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Why the walk stopped.
|
|
472
|
+
*
|
|
473
|
+
* `noBody` states a shape and nothing else: a method on an interface, an
|
|
474
|
+
* abstract method, an ambient declaration. `unsettledValue` is declared
|
|
475
|
+
* as something other than a function, with something in it that could
|
|
476
|
+
* not be read. `multipleSources` reaches two different functions, so no
|
|
477
|
+
* single body can be followed. `outsideRun` is a declaration in a
|
|
478
|
+
* dependency, whose source this run never read. `noDeclaration` is a
|
|
479
|
+
* callee nothing declares, which is what a call on an untyped value
|
|
480
|
+
* comes to. `callerSupplied` is a parameter of the function being
|
|
481
|
+
* scanned, so the call runs whatever its caller handed in.
|
|
482
|
+
* `multipleReceivers` is a registration whose receiver comes down to
|
|
483
|
+
* more than one thing, so nothing says which one it registers on.
|
|
484
|
+
*/
|
|
485
|
+
type UnfollowedReason = "noBody" | "unsettledValue" | "multipleSources" | "outsideRun" | "noDeclaration" | "callerSupplied" | "multipleReceivers";
|
|
486
|
+
/** One call the walk met and could not follow. */
|
|
487
|
+
interface UnfollowedCall {
|
|
488
|
+
/** The callee as the source writes it, `this.dao.getEditions` say. */
|
|
489
|
+
readonly callee: string;
|
|
490
|
+
readonly reason: UnfollowedReason;
|
|
491
|
+
/** How many things the walk reached where it needed one. */
|
|
492
|
+
readonly candidates?: number;
|
|
493
|
+
}
|
|
494
|
+
|
|
408
495
|
interface ClientCallSite {
|
|
409
496
|
callExpression: CallExpression;
|
|
410
497
|
/** Method name on the client object (e.g. "getUser"), null for bare calls like fetch() */
|
|
@@ -556,6 +643,19 @@ interface DiscoveredUnit {
|
|
|
556
643
|
/** Null when the pack knows the wire but not the channel on it. */
|
|
557
644
|
channel: string | null;
|
|
558
645
|
};
|
|
646
|
+
/**
|
|
647
|
+
* Populated by a pack's `discoverUnits` callback for a deployed unit
|
|
648
|
+
* nothing else routes to, which is reached by being invoked by name.
|
|
649
|
+
* The adapter builds a `unit-invocation` binding from it, which pairs
|
|
650
|
+
* with the calls that name the same unit.
|
|
651
|
+
*/
|
|
652
|
+
invocationInfo?: DeployableUnit;
|
|
653
|
+
/**
|
|
654
|
+
* Identity of the routable this unit was registered on, when a
|
|
655
|
+
* registration call put it there. What the wrapper index is keyed on,
|
|
656
|
+
* since a wrapper is registered on the routable and not on the unit.
|
|
657
|
+
*/
|
|
658
|
+
registrationSubjectId?: string;
|
|
559
659
|
/** The thing that gets deployed and runs this unit, when known. */
|
|
560
660
|
deployableUnit?: DeployableUnit;
|
|
561
661
|
/**
|
|
@@ -573,6 +673,12 @@ interface DiscoveredUnit {
|
|
|
573
673
|
* summary as an `unreadOutcome` gap.
|
|
574
674
|
*/
|
|
575
675
|
unreadBinding?: string;
|
|
676
|
+
/**
|
|
677
|
+
* A call the handler met and could not follow, which reaches the
|
|
678
|
+
* summary as an `unfollowedCall` gap beside the ones the closure
|
|
679
|
+
* walk records.
|
|
680
|
+
*/
|
|
681
|
+
unfollowed?: UnfollowedCall;
|
|
576
682
|
}
|
|
577
683
|
|
|
578
684
|
/**
|
|
@@ -597,12 +703,19 @@ interface MountPrefixIndex {
|
|
|
597
703
|
*/
|
|
598
704
|
prefixForId?(childId: string): string;
|
|
599
705
|
}
|
|
706
|
+
/**
|
|
707
|
+
* What the project helper index says it has already expanded, which the
|
|
708
|
+
* walk consults so one registration does not become two summaries.
|
|
709
|
+
*/
|
|
710
|
+
interface ExpandedRegistrations {
|
|
711
|
+
expandedAtCallSites(helper: Node, method: string): boolean;
|
|
712
|
+
}
|
|
600
713
|
|
|
601
714
|
/**
|
|
602
715
|
* Discover code units in `sourceFile` by running all patterns.
|
|
603
716
|
* Deduplicates entries with the same function node and kind.
|
|
604
717
|
*/
|
|
605
|
-
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore, mountPrefixes?: MountPrefixIndex): DiscoveredUnit[];
|
|
718
|
+
declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[], resolution?: ResolutionStore, mountPrefixes?: MountPrefixIndex, expandedElsewhere?: ExpandedRegistrations): DiscoveredUnit[];
|
|
606
719
|
|
|
607
720
|
interface TimingReport {
|
|
608
721
|
totalMs: number;
|
|
@@ -887,28 +1000,12 @@ declare function findNearestTsconfig(startDir: string): string | null;
|
|
|
887
1000
|
*/
|
|
888
1001
|
|
|
889
1002
|
/**
|
|
890
|
-
* A call the project has declared to be its own dispatcher.
|
|
891
|
-
*
|
|
892
|
-
*
|
|
893
|
-
*
|
|
894
|
-
* the type is the only thing stable across all three.
|
|
1003
|
+
* A call the project has declared to be its own dispatcher. The
|
|
1004
|
+
* declaration a project config is parsed against lives with the other
|
|
1005
|
+
* shared pack options, so this reader and the packs that take it under
|
|
1006
|
+
* `producers` describe one shape.
|
|
895
1007
|
*/
|
|
896
|
-
|
|
897
|
-
/** Module that declares the receiver's type. */
|
|
898
|
-
module: string;
|
|
899
|
-
/** Type name of the receiver, as exported from that module. */
|
|
900
|
-
receiver: string;
|
|
901
|
-
/** Method that performs the send. */
|
|
902
|
-
method: string;
|
|
903
|
-
/** Argument index carrying the subject. */
|
|
904
|
-
subjectArg: number;
|
|
905
|
-
/**
|
|
906
|
-
* Which argument the message body is. Left out when the method has no
|
|
907
|
-
* single body argument, as a batch method taking a list of entries
|
|
908
|
-
* does, and then no body is reported.
|
|
909
|
-
*/
|
|
910
|
-
bodyArg?: number;
|
|
911
|
-
}
|
|
1008
|
+
type ConfiguredCallSpec = z.infer<typeof configuredCallOption>;
|
|
912
1009
|
interface ConfiguredCallRead {
|
|
913
1010
|
/** The subject the call sends to, always a literal string. */
|
|
914
1011
|
subject: string;
|
|
@@ -962,6 +1059,45 @@ declare function readContract(unit: DiscoveredUnit, pattern: ContractPattern, fr
|
|
|
962
1059
|
*/
|
|
963
1060
|
declare function readContractForClientCall(callExpression: Node, methodName: string, pattern: ContractPattern, framework: string, resolution?: ResolutionStore): ContractReadResult | null;
|
|
964
1061
|
|
|
1062
|
+
/**
|
|
1063
|
+
* helperIndex.ts: reading the project's own helpers once, before any
|
|
1064
|
+
* file is walked.
|
|
1065
|
+
*
|
|
1066
|
+
* A pack that declares `projectHelpers` gets every helper the project
|
|
1067
|
+
* wrote in front of its library, each read in terms of its own
|
|
1068
|
+
* parameters, and gives back the patterns and recognizers it would
|
|
1069
|
+
* otherwise have taken as config. Those join the pack for the rest of
|
|
1070
|
+
* the run, so the match happens at the call site, where the arguments
|
|
1071
|
+
* are literal.
|
|
1072
|
+
*
|
|
1073
|
+
* Built alongside the mount and wrapper indexes, over the same files.
|
|
1074
|
+
* The discovery README has the ordering and the cost.
|
|
1075
|
+
*/
|
|
1076
|
+
|
|
1077
|
+
interface ProjectHelperIndex {
|
|
1078
|
+
/** Discovery patterns `packName` contributed after reading the project. */
|
|
1079
|
+
patternsFor(packName: string): readonly DiscoveryPattern[];
|
|
1080
|
+
/**
|
|
1081
|
+
* Recognizers the packs contributed. They match calls to functions
|
|
1082
|
+
* this project declares, so they run wherever a call can appear
|
|
1083
|
+
* rather than only where the pack's own import gate reaches.
|
|
1084
|
+
*/
|
|
1085
|
+
contributedRecognizers(): readonly InvocationRecognizer[];
|
|
1086
|
+
/**
|
|
1087
|
+
* The helper files that shaped what `file` extracts to, so the
|
|
1088
|
+
* per-file cache invalidates `file` when one of them is edited.
|
|
1089
|
+
*/
|
|
1090
|
+
helperFilesFor(file: SourceFile): readonly string[];
|
|
1091
|
+
/**
|
|
1092
|
+
* Whether a registration written inside `helper` with `method` is one
|
|
1093
|
+
* the call sites already expand. Reading it here as well would give
|
|
1094
|
+
* one registration two summaries, and which of the two a run kept
|
|
1095
|
+
* would come down to the order the files were walked in.
|
|
1096
|
+
*/
|
|
1097
|
+
expandedAtCallSites(helper: Node, method: string): boolean;
|
|
1098
|
+
}
|
|
1099
|
+
declare function buildProjectHelperIndex(sourceFiles: ReadonlyArray<SourceFile>, packs: ReadonlyArray<PatternPack>, packsByFile: ReadonlyMap<SourceFile, readonly PatternPack[]>, resolution: ResolutionStore): ProjectHelperIndex;
|
|
1100
|
+
|
|
965
1101
|
/**
|
|
966
1102
|
* The one import scan.
|
|
967
1103
|
*
|
|
@@ -1027,32 +1163,6 @@ interface TsDiscoveryContext {
|
|
|
1027
1163
|
func: FunctionRoot;
|
|
1028
1164
|
isDefault: boolean;
|
|
1029
1165
|
}>;
|
|
1030
|
-
/**
|
|
1031
|
-
* For an export the project builds by calling a factory, the string
|
|
1032
|
-
* under a property of that call's config object:
|
|
1033
|
-
* `export const handler = makeWidgetHandler({ subject: "a.b" }, ...)`
|
|
1034
|
-
* with `{ property: "subject" }` gives back `"a.b"`.
|
|
1035
|
-
*
|
|
1036
|
-
* The caller does not have to say which function was called or which
|
|
1037
|
-
* argument the config was in. Every object argument is read. Giving the
|
|
1038
|
-
* callee or fixing the argument position narrows that down, for a
|
|
1039
|
-
* project whose factories would otherwise collide.
|
|
1040
|
-
*
|
|
1041
|
-
* Two arguments with the property set to different values give back
|
|
1042
|
-
* null, since nothing says which one was meant.
|
|
1043
|
-
*
|
|
1044
|
-
* The config argument is usually an object literal at the call site;
|
|
1045
|
-
* a variable or import is followed to the literal it resolves to.
|
|
1046
|
-
* `as const` and parentheses around the property value are peeled.
|
|
1047
|
-
* Anything but a string literal underneath (a computed subject, a
|
|
1048
|
-
* template, a call) gives back null, and the caller attaches nothing
|
|
1049
|
-
* rather than guessing.
|
|
1050
|
-
*/
|
|
1051
|
-
exportedCallConfigString(sourceFile: SourceFile, exportName: string, spec: {
|
|
1052
|
-
callees?: string[];
|
|
1053
|
-
argIndex?: number;
|
|
1054
|
-
property: string;
|
|
1055
|
-
}): string | null;
|
|
1056
1166
|
/**
|
|
1057
1167
|
* Walk a function's body for return statements whose value is a
|
|
1058
1168
|
* JSX element / fragment / self-closing tag. Returns true on the
|
|
@@ -1339,7 +1449,7 @@ declare function collectClientFieldAccesses(callExpr: CallExpression, func: Node
|
|
|
1339
1449
|
/**
|
|
1340
1450
|
* Evidence for drafting a dependency stub: every call the project
|
|
1341
1451
|
* makes into a named package, grouped by the export it reaches, with
|
|
1342
|
-
* the argument shapes observed at each call site. `suss stub
|
|
1452
|
+
* the argument shapes observed at each call site. `suss infer stub`
|
|
1343
1453
|
* turns this into a stub skeleton for an author to fill in. The
|
|
1344
1454
|
* package's own code is never read, only the project's calls into it,
|
|
1345
1455
|
* so this works for packages whose source no adapter can parse.
|
|
@@ -1501,4 +1611,4 @@ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
|
|
|
1501
1611
|
version?: string;
|
|
1502
1612
|
}>): string;
|
|
1503
1613
|
|
|
1504
|
-
export { ADAPTER_VERSION, type Accessed, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExplainCallableOptions, type ExplainStats, type ExplainedResolution, type ExtractionReport, type FoundTerminal, type FunctionRoot, type HealthCheck, type HealthViolation, type ImportScanOptions, type ObservedStubCall, type PackFunnel, type PackGradient, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, type Timer, type TimingReport, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, type ValueLocation, type WhyExplained, WhySession, type WhySessionOptions, accessContextFor, callOpsFor, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, computeContentHash, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, evaluatePackHealth, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, formatPackHealth, functionTargetOf, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isImportedFrom, methodDeclaredIn, namedImportsOf, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, stubEvidence, stubEvidenceIn, workspaceRootFor };
|
|
1614
|
+
export { ADAPTER_VERSION, type Accessed, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExplainCallableOptions, type ExplainStats, type ExplainedResolution, type ExtractionReport, type FoundTerminal, type FunctionRoot, type HealthCheck, type HealthViolation, type ImportScanOptions, type ObservedStubCall, type PackFunnel, type PackGradient, type ReadNameOptions, ResolutionStore, type StubCallEvidence, type StubEvidenceOptions, type Timer, type TimingReport, type TsDiscoveryContext, type TsInvocationRecognizerContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, type ValueLocation, type WhyExplained, WhySession, type WhySessionOptions, accessContextFor, buildProjectHelperIndex, callOpsFor, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, computeContentHash, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, evaluatePackHealth, exportedDeclarationsOf, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, formatPackHealth, functionTargetOf, importDeclarationsOf, importedNamesOf, importedRootsOf, invocationContextFor, isImportedFrom, methodDeclaredIn, namedImportsOf, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, readName, resolveAliasedSymbol, resolveSubject, rootIdentifier, stubEvidence, stubEvidenceIn, workspaceRootFor };
|