@ttsc/graph 0.30.3 → 0.31.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 +122 -30
- package/lib/CapturedProcessOutput.d.ts +47 -0
- package/lib/CapturedProcessOutput.js +3 -0
- package/lib/CapturedProcessOutput.js.map +1 -0
- package/lib/ILauncherOption.d.ts +22 -0
- package/lib/ILauncherOption.js +3 -0
- package/lib/ILauncherOption.js.map +1 -0
- package/lib/IProjectOptions.d.ts +18 -0
- package/lib/IProjectOptions.js +3 -0
- package/lib/IProjectOptions.js.map +1 -0
- package/lib/ParsedLauncherOptions.d.ts +13 -0
- package/lib/ParsedLauncherOptions.js +3 -0
- package/lib/ParsedLauncherOptions.js.map +1 -0
- package/lib/TtscGraphApplication.d.ts +38 -1
- package/lib/TtscGraphApplication.js +26 -1
- package/lib/TtscGraphApplication.js.map +1 -1
- package/lib/TtscGraphLauncherArguments.d.ts +115 -0
- package/lib/TtscGraphLauncherArguments.js +181 -0
- package/lib/TtscGraphLauncherArguments.js.map +1 -0
- package/lib/TtscGraphViewSnapshot.d.ts +35 -0
- package/lib/TtscGraphViewSnapshot.js +48 -0
- package/lib/TtscGraphViewSnapshot.js.map +1 -0
- package/lib/index.d.ts +9 -24
- package/lib/index.js +6 -128
- package/lib/index.js.map +1 -1
- package/lib/internal/GraphProcessTrace.d.ts +1 -0
- package/lib/internal/GraphProcessTrace.js +235 -0
- package/lib/internal/GraphProcessTrace.js.map +1 -0
- package/lib/launcherArgs.d.ts +75 -16
- package/lib/launcherArgs.js +77 -8
- package/lib/launcherArgs.js.map +1 -1
- package/lib/model/IArtifactDirectory.d.ts +26 -0
- package/lib/model/IArtifactDirectory.js +3 -0
- package/lib/model/IArtifactDirectory.js.map +1 -0
- package/lib/model/IArtifactInputs.d.ts +19 -0
- package/lib/model/IArtifactInputs.js +3 -0
- package/lib/model/IArtifactInputs.js.map +1 -0
- package/lib/model/IPublishedArtifacts.d.ts +76 -0
- package/lib/model/IPublishedArtifacts.js +3 -0
- package/lib/model/IPublishedArtifacts.js.map +1 -0
- package/lib/model/IPublishedArtifactsResident.d.ts +19 -0
- package/lib/model/IPublishedArtifactsResident.js +3 -0
- package/lib/model/IPublishedArtifactsResident.js.map +1 -0
- package/lib/model/ITtscLintDaemonTarget.d.ts +20 -0
- package/lib/model/ITtscLintDaemonTarget.js +3 -0
- package/lib/model/ITtscLintDaemonTarget.js.map +1 -0
- package/lib/model/TtscGraphLinePeer.d.ts +146 -0
- package/lib/model/TtscGraphLinePeer.js +213 -0
- package/lib/model/TtscGraphLinePeer.js.map +1 -0
- package/lib/model/TtscGraphMemory.d.ts +156 -16
- package/lib/model/TtscGraphMemory.js +228 -222
- package/lib/model/TtscGraphMemory.js.map +1 -1
- package/lib/model/TtscGraphNativeArguments.d.ts +40 -0
- package/lib/model/TtscGraphNativeArguments.js +64 -0
- package/lib/model/TtscGraphNativeArguments.js.map +1 -0
- package/lib/model/TtscGraphNodeId.d.ts +55 -3
- package/lib/model/TtscGraphNodeId.js +40 -2
- package/lib/model/TtscGraphNodeId.js.map +1 -1
- package/lib/model/TtscGraphProjection.d.ts +156 -0
- package/lib/model/TtscGraphProjection.js +390 -0
- package/lib/model/TtscGraphProjection.js.map +1 -0
- package/lib/model/TtscGraphProtocol.d.ts +28 -0
- package/lib/model/TtscGraphProtocol.js +928 -0
- package/lib/model/TtscGraphProtocol.js.map +1 -0
- package/lib/model/TtscGraphReadonly.d.ts +15 -0
- package/lib/model/TtscGraphReadonly.js +3 -0
- package/lib/model/TtscGraphReadonly.js.map +1 -0
- package/lib/model/TtscGraphRequestOptions.d.ts +16 -0
- package/lib/model/TtscGraphRequestOptions.js +3 -0
- package/lib/model/TtscGraphRequestOptions.js.map +1 -0
- package/lib/model/TtscGraphSession.d.ts +82 -36
- package/lib/model/TtscGraphSession.js +164 -1238
- package/lib/model/TtscGraphSession.js.map +1 -1
- package/lib/model/TtscGraphSessionOptions.d.ts +20 -0
- package/lib/model/TtscGraphSessionOptions.js +3 -0
- package/lib/model/TtscGraphSessionOptions.js.map +1 -0
- package/lib/model/TtscGraphSessionState.d.ts +187 -0
- package/lib/model/TtscGraphSessionState.js +417 -0
- package/lib/model/TtscGraphSessionState.js.map +1 -0
- package/lib/model/TtscGraphShardStore.d.ts +64 -3
- package/lib/model/TtscGraphShardStore.js +85 -15
- package/lib/model/TtscGraphShardStore.js.map +1 -1
- package/lib/model/TtscGraphSourceReader.d.ts +31 -8
- package/lib/model/TtscGraphSourceReader.js +37 -13
- package/lib/model/TtscGraphSourceReader.js.map +1 -1
- package/lib/model/TtscLintDaemon.d.ts +35 -17
- package/lib/model/TtscLintDaemon.js +39 -117
- package/lib/model/TtscLintDaemon.js.map +1 -1
- package/lib/model/TtscLintDaemonState.d.ts +69 -0
- package/lib/model/TtscLintDaemonState.js +166 -0
- package/lib/model/TtscLintDaemonState.js.map +1 -0
- package/lib/model/copyGraphRecords.d.ts +14 -0
- package/lib/model/copyGraphRecords.js +19 -0
- package/lib/model/copyGraphRecords.js.map +1 -0
- package/lib/model/copyGraphSnapshot.d.ts +17 -0
- package/lib/model/copyGraphSnapshot.js +33 -0
- package/lib/model/copyGraphSnapshot.js.map +1 -0
- package/lib/model/loadGraph.d.ts +19 -10
- package/lib/model/loadGraph.js +21 -12
- package/lib/model/loadGraph.js.map +1 -1
- package/lib/model/publishedArtifacts.d.ts +78 -97
- package/lib/model/publishedArtifacts.js +271 -85
- package/lib/model/publishedArtifacts.js.map +1 -1
- package/lib/nativeExecutable.d.ts +19 -8
- package/lib/nativeExecutable.js +75 -15
- package/lib/nativeExecutable.js.map +1 -1
- package/lib/reduce.d.ts +19 -45
- package/lib/reduce.js +19 -3
- package/lib/reduce.js.map +1 -1
- package/lib/resolveGraphBinary.d.ts +9 -0
- package/lib/resolveGraphBinary.js +11 -3
- package/lib/resolveGraphBinary.js.map +1 -1
- package/lib/runGraph.d.ts +21 -0
- package/lib/runGraph.js +83 -0
- package/lib/runGraph.js.map +1 -0
- package/lib/server/IResolvedGraphHandle.d.ts +22 -0
- package/lib/server/IResolvedGraphHandle.js +3 -0
- package/lib/server/IResolvedGraphHandle.js.map +1 -0
- package/lib/server/createServer.d.ts +14 -10
- package/lib/server/createServer.js +42 -39
- package/lib/server/createServer.js.map +1 -1
- package/lib/server/exportSurface.d.ts +23 -1
- package/lib/server/exportSurface.js +23 -1
- package/lib/server/exportSurface.js.map +1 -1
- package/lib/server/formatGraphFailure.d.ts +20 -0
- package/lib/server/formatGraphFailure.js +35 -0
- package/lib/server/formatGraphFailure.js.map +1 -0
- package/lib/server/pathPolicy.d.ts +70 -5
- package/lib/server/pathPolicy.js +66 -4
- package/lib/server/pathPolicy.js.map +1 -1
- package/lib/server/resolveHandle.d.ts +10 -5
- package/lib/server/resolveHandle.js +39 -7
- package/lib/server/resolveHandle.js.map +1 -1
- package/lib/server/resultAudit.d.ts +17 -14
- package/lib/server/resultAudit.js +56 -27
- package/lib/server/resultAudit.js.map +1 -1
- package/lib/server/resultNext.d.ts +26 -1
- package/lib/server/resultNext.js +14 -0
- package/lib/server/resultNext.js.map +1 -1
- package/lib/server/runDetails.d.ts +72 -15
- package/lib/server/runDetails.js +104 -69
- package/lib/server/runDetails.js.map +1 -1
- package/lib/server/runEntrypoints.d.ts +9 -0
- package/lib/server/runEntrypoints.js +9 -0
- package/lib/server/runEntrypoints.js.map +1 -1
- package/lib/server/runLookup.d.ts +13 -3
- package/lib/server/runLookup.js +19 -6
- package/lib/server/runLookup.js.map +1 -1
- package/lib/server/runOverview.d.ts +13 -4
- package/lib/server/runOverview.js +13 -4
- package/lib/server/runOverview.js.map +1 -1
- package/lib/server/runTour.d.ts +9 -0
- package/lib/server/runTour.js +33 -65
- package/lib/server/runTour.js.map +1 -1
- package/lib/server/runTrace.d.ts +25 -1
- package/lib/server/runTrace.js +133 -88
- package/lib/server/runTrace.js.map +1 -1
- package/lib/server/startServer.d.ts +16 -0
- package/lib/server/startServer.js +24 -1
- package/lib/server/startServer.js.map +1 -1
- package/lib/structures/ITtscGraphApplication.d.ts +95 -41
- package/lib/structures/ITtscGraphDecorator.d.ts +18 -0
- package/lib/structures/ITtscGraphDetails.d.ts +81 -6
- package/lib/structures/ITtscGraphDocTag.d.ts +17 -8
- package/lib/structures/ITtscGraphDump.d.ts +106 -8
- package/lib/structures/ITtscGraphEdge.d.ts +14 -2
- package/lib/structures/ITtscGraphEntrypoints.d.ts +81 -6
- package/lib/structures/ITtscGraphEscape.d.ts +24 -2
- package/lib/structures/ITtscGraphEvidence.d.ts +9 -0
- package/lib/structures/ITtscGraphLookup.d.ts +42 -9
- package/lib/structures/ITtscGraphNext.d.ts +12 -1
- package/lib/structures/ITtscGraphNode.d.ts +38 -11
- package/lib/structures/ITtscGraphOverview.d.ts +81 -6
- package/lib/structures/ITtscGraphSnapshot.d.ts +97 -2
- package/lib/structures/ITtscGraphSpan.d.ts +9 -0
- package/lib/structures/ITtscGraphTour.d.ts +83 -9
- package/lib/structures/ITtscGraphTrace.d.ts +99 -14
- package/lib/structures/RawDump.d.ts +22 -0
- package/lib/structures/RawDump.js +3 -0
- package/lib/structures/RawDump.js.map +1 -0
- package/lib/structures/RawEdge.d.ts +20 -0
- package/lib/structures/RawEdge.js +3 -0
- package/lib/structures/RawEdge.js.map +1 -0
- package/lib/structures/RawNode.d.ts +26 -0
- package/lib/structures/RawNode.js +3 -0
- package/lib/structures/RawNode.js.map +1 -0
- package/lib/structures/TtscGraphArtifactNodeKind.d.ts +9 -0
- package/lib/structures/TtscGraphArtifactNodeKind.js +9 -0
- package/lib/structures/TtscGraphArtifactNodeKind.js.map +1 -1
- package/lib/structures/TtscGraphDumpEdgeKind.d.ts +15 -1
- package/lib/structures/TtscGraphDumpNodeKind.d.ts +9 -0
- package/lib/structures/TtscGraphEdgeKind.d.ts +13 -4
- package/lib/structures/TtscGraphNodeKind.d.ts +9 -0
- package/lib/structures/TtscGraphNodeModifier.d.ts +9 -0
- package/lib/structures/ViewerLink.d.ts +20 -0
- package/lib/structures/ViewerLink.js +3 -0
- package/lib/structures/ViewerLink.js.map +1 -0
- package/lib/structures/ViewerNode.d.ts +24 -0
- package/lib/structures/ViewerNode.js +3 -0
- package/lib/structures/ViewerNode.js.map +1 -0
- package/lib/structures/ViewerPayload.d.ts +42 -0
- package/lib/structures/ViewerPayload.js +3 -0
- package/lib/structures/ViewerPayload.js.map +1 -0
- package/lib/view.d.ts +9 -0
- package/lib/view.js +203 -91
- package/lib/view.js.map +1 -1
- package/lib/viewer/viewer.js +1 -1
- package/package.json +8 -6
- package/src/CapturedProcessOutput.ts +50 -0
- package/src/ILauncherOption.ts +24 -0
- package/src/IProjectOptions.ts +19 -0
- package/src/ParsedLauncherOptions.ts +13 -0
- package/src/TtscGraphApplication.ts +38 -1
- package/src/TtscGraphLauncherArguments.ts +207 -0
- package/src/TtscGraphViewSnapshot.ts +46 -0
- package/src/index.ts +9 -160
- package/src/internal/GraphProcessTrace.ts +242 -0
- package/src/launcherArgs.ts +89 -23
- package/src/model/IArtifactDirectory.ts +27 -0
- package/src/model/IArtifactInputs.ts +21 -0
- package/src/model/IPublishedArtifacts.ts +81 -0
- package/src/model/IPublishedArtifactsResident.ts +24 -0
- package/src/model/ITtscLintDaemonTarget.ts +22 -0
- package/src/model/TtscGraphLinePeer.ts +318 -0
- package/src/model/TtscGraphMemory.ts +284 -246
- package/src/model/TtscGraphNativeArguments.ts +67 -0
- package/src/model/TtscGraphNodeId.ts +57 -3
- package/src/model/TtscGraphProjection.ts +473 -0
- package/src/model/TtscGraphProtocol.ts +90 -0
- package/src/model/TtscGraphReadonly.ts +17 -0
- package/src/model/TtscGraphRequestOptions.ts +16 -0
- package/src/model/TtscGraphSession.ts +196 -475
- package/src/model/TtscGraphSessionOptions.ts +22 -0
- package/src/model/TtscGraphSessionState.ts +558 -0
- package/src/model/TtscGraphShardStore.ts +99 -23
- package/src/model/TtscGraphSourceReader.ts +37 -15
- package/src/model/TtscLintDaemon.ts +55 -136
- package/src/model/TtscLintDaemonState.ts +174 -0
- package/src/model/copyGraphRecords.ts +17 -0
- package/src/model/copyGraphSnapshot.ts +30 -0
- package/src/model/loadGraph.ts +23 -12
- package/src/model/publishedArtifacts.ts +361 -182
- package/src/nativeExecutable.ts +93 -26
- package/src/reduce.ts +24 -51
- package/src/resolveGraphBinary.ts +13 -3
- package/src/runGraph.ts +90 -0
- package/src/server/IResolvedGraphHandle.ts +24 -0
- package/src/server/createServer.ts +16 -22
- package/src/server/exportSurface.ts +23 -1
- package/src/server/formatGraphFailure.ts +32 -0
- package/src/server/pathPolicy.ts +70 -5
- package/src/server/resolveHandle.ts +45 -14
- package/src/server/resultAudit.ts +58 -27
- package/src/server/resultNext.ts +26 -1
- package/src/server/runDetails.ts +138 -73
- package/src/server/runEntrypoints.ts +13 -1
- package/src/server/runLookup.ts +23 -7
- package/src/server/runOverview.ts +17 -5
- package/src/server/runTour.ts +44 -82
- package/src/server/runTrace.ts +175 -102
- package/src/server/startServer.ts +29 -1
- package/src/structures/ITtscGraphApplication.ts +95 -41
- package/src/structures/ITtscGraphDecorator.ts +18 -0
- package/src/structures/ITtscGraphDetails.ts +81 -6
- package/src/structures/ITtscGraphDocTag.ts +17 -8
- package/src/structures/ITtscGraphDump.ts +106 -8
- package/src/structures/ITtscGraphEdge.ts +14 -2
- package/src/structures/ITtscGraphEntrypoints.ts +81 -6
- package/src/structures/ITtscGraphEscape.ts +24 -2
- package/src/structures/ITtscGraphEvidence.ts +9 -0
- package/src/structures/ITtscGraphLookup.ts +42 -9
- package/src/structures/ITtscGraphNext.ts +12 -1
- package/src/structures/ITtscGraphNode.ts +38 -11
- package/src/structures/ITtscGraphOverview.ts +88 -6
- package/src/structures/ITtscGraphSnapshot.ts +117 -2
- package/src/structures/ITtscGraphSpan.ts +9 -0
- package/src/structures/ITtscGraphTour.ts +83 -9
- package/src/structures/ITtscGraphTrace.ts +100 -14
- package/src/structures/RawDump.ts +25 -0
- package/src/structures/RawEdge.ts +22 -0
- package/src/structures/RawNode.ts +31 -0
- package/src/structures/TtscGraphArtifactNodeKind.ts +9 -0
- package/src/structures/TtscGraphDumpEdgeKind.ts +15 -1
- package/src/structures/TtscGraphDumpNodeKind.ts +9 -0
- package/src/structures/TtscGraphEdgeKind.ts +13 -4
- package/src/structures/TtscGraphNodeKind.ts +9 -0
- package/src/structures/TtscGraphNodeModifier.ts +9 -0
- package/src/structures/ViewerLink.ts +22 -0
- package/src/structures/ViewerNode.ts +28 -0
- package/src/structures/ViewerPayload.ts +52 -0
- package/src/view.ts +208 -110
- package/src/viewer/legend.ts +119 -27
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ITtscGraphDump } from "../structures/ITtscGraphDump";
|
|
2
2
|
import { ITtscGraphEdge } from "../structures/ITtscGraphEdge";
|
|
3
|
-
import { ITtscGraphEvidence } from "../structures/ITtscGraphEvidence";
|
|
4
3
|
import { ITtscGraphNode } from "../structures/ITtscGraphNode";
|
|
5
|
-
import { ITtscGraphSpan } from "../structures/ITtscGraphSpan";
|
|
6
|
-
import { isArtifactNodeKind } from "../structures/TtscGraphArtifactNodeKind";
|
|
7
4
|
import { TtscGraphEdgeKind } from "../structures/TtscGraphEdgeKind";
|
|
8
|
-
import {
|
|
5
|
+
import { TtscGraphProjection } from "./TtscGraphProjection";
|
|
6
|
+
import { type TtscGraphReadonly } from "./TtscGraphReadonly";
|
|
9
7
|
import { TtscGraphSourceReader } from "./TtscGraphSourceReader";
|
|
10
8
|
|
|
9
|
+
type SnapshotNode = TtscGraphReadonly<ITtscGraphNode>;
|
|
10
|
+
type SnapshotEdge = TtscGraphReadonly<ITtscGraphEdge>;
|
|
11
|
+
|
|
11
12
|
/**
|
|
12
13
|
* The in-memory resident graph the MCP tools answer from.
|
|
13
14
|
*
|
|
@@ -18,101 +19,254 @@ import { TtscGraphSourceReader } from "./TtscGraphSourceReader";
|
|
|
18
19
|
* implementation relationships are checker facts already present in the dump.
|
|
19
20
|
* Every tool call is then a lookup or traversal over the indexes built here;
|
|
20
21
|
* nothing recompiles.
|
|
22
|
+
*
|
|
23
|
+
* Snapshot records are owned copies and recursively frozen. Borrowed node
|
|
24
|
+
* records and edge buckets have recursively readonly types, so caller changes
|
|
25
|
+
* cannot invalidate generation-keyed indexes and caches.
|
|
26
|
+
*
|
|
27
|
+
* @evidence contracts/common.md#principled-implementation Native facts are preserved while module/file folding, exact owner suffixes and artifact parents synthesize only this layer's structural relationships.
|
|
28
|
+
* @evidence contracts/common.md#clear-and-simple-design One snapshot owns node, name, relation and citation indexes; individual accessors expose that shared model.
|
|
29
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Export surfaces remain checker relationships rather than guessed from local export flags or fixture paths.
|
|
30
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs distinguish compiler facts from synthesized structure, and accessors explain lookup and absence semantics.
|
|
31
|
+
* @evidenceExclude contracts/performance.md#efficient-algorithms from and fromResident own projection/index construction through their private helpers; this class declaration describes the resulting representation.
|
|
32
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work from and fromResident establish each shared generation; the declaration does not independently coordinate requests.
|
|
33
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources from and fromResident transfer generation storage to their caller; session/caller release owns its duration rather than this declaration.
|
|
34
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation an in-memory index over parsed facts; the source reader it owns is the only file reader.
|
|
21
35
|
*/
|
|
22
36
|
export class TtscGraphMemory {
|
|
23
|
-
private readonly
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
private readonly
|
|
37
|
+
private readonly nodeKeys: Map<
|
|
38
|
+
SnapshotNode,
|
|
39
|
+
{ symbols: readonly string[]; targets: readonly string[] }
|
|
40
|
+
>;
|
|
41
|
+
|
|
42
|
+
private readonly byId: Map<string, SnapshotNode>;
|
|
43
|
+
private readonly outEdges: Map<string, readonly SnapshotEdge[]>;
|
|
44
|
+
private readonly inEdges: Map<string, readonly SnapshotEdge[]>;
|
|
45
|
+
private readonly byNameIndex: Map<string, readonly SnapshotNode[]>;
|
|
46
|
+
private readonly bySymbolIndex: Map<string, readonly SnapshotNode[]>;
|
|
47
|
+
private readonly byDocTagTarget: Map<string, readonly SnapshotNode[]>;
|
|
29
48
|
|
|
30
49
|
/** The absolute project root the dump was built for. */
|
|
31
50
|
readonly project: string;
|
|
51
|
+
|
|
32
52
|
/** Every post-fold node, including refined properties and file containers. */
|
|
33
|
-
readonly nodes: readonly
|
|
53
|
+
readonly nodes: readonly SnapshotNode[];
|
|
54
|
+
|
|
34
55
|
/** Every edge, raw plus synthesized containment. */
|
|
35
|
-
readonly edges: readonly
|
|
56
|
+
readonly edges: readonly SnapshotEdge[];
|
|
57
|
+
|
|
36
58
|
/** Provenance-gated source display facts cached for this exact snapshot. */
|
|
37
59
|
readonly source: TtscGraphSourceReader;
|
|
38
60
|
|
|
39
61
|
private constructor(
|
|
40
62
|
project: string,
|
|
41
|
-
nodes:
|
|
42
|
-
edges:
|
|
43
|
-
provenance:
|
|
63
|
+
nodes: readonly SnapshotNode[],
|
|
64
|
+
edges: readonly SnapshotEdge[],
|
|
65
|
+
provenance:
|
|
66
|
+
| ITtscGraphDump.IProvenance
|
|
67
|
+
| TtscGraphReadonly<ITtscGraphDump.IProvenance>
|
|
68
|
+
| undefined,
|
|
69
|
+
private readonly projection?: TtscGraphProjection.State,
|
|
70
|
+
previous?: TtscGraphMemory,
|
|
44
71
|
) {
|
|
45
72
|
this.project = project;
|
|
46
73
|
this.nodes = nodes;
|
|
47
74
|
this.edges = edges;
|
|
48
|
-
this
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
75
|
+
// Source adjudication belongs to this generation even when graph facts
|
|
76
|
+
// remain equivalent. Never transfer cached lines or cached absence.
|
|
77
|
+
this.source = new TtscGraphSourceReader(
|
|
78
|
+
project,
|
|
79
|
+
provenance === undefined
|
|
80
|
+
? undefined
|
|
81
|
+
: {
|
|
82
|
+
capabilities: [...provenance.capabilities],
|
|
83
|
+
sources: provenance.sources.map((source) => ({ ...source })),
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
this.byId = new Map(nodes.map((node) => [node.id, node]));
|
|
87
|
+
this.nodeKeys = new Map();
|
|
54
88
|
for (const node of nodes) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// carriers of one address, while the failure it prevents is a
|
|
70
|
-
// declaration reported twice as implementing one specification.
|
|
71
|
-
if (carriers === undefined) this.byDocTagTarget.set(target, [node]);
|
|
72
|
-
else if (!carriers.includes(node)) carriers.push(node);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
this.outEdges = new Map();
|
|
76
|
-
this.inEdges = new Map();
|
|
77
|
-
for (const edge of edges) {
|
|
78
|
-
push(this.outEdges, edge.from, edge);
|
|
79
|
-
push(this.inEdges, edge.to, edge);
|
|
89
|
+
const retained = previous?.nodeKeys.get(node);
|
|
90
|
+
this.nodeKeys.set(
|
|
91
|
+
node,
|
|
92
|
+
retained ?? {
|
|
93
|
+
symbols:
|
|
94
|
+
node.kind === "file"
|
|
95
|
+
? []
|
|
96
|
+
: node.qualifiedName !== undefined &&
|
|
97
|
+
node.qualifiedName !== node.name
|
|
98
|
+
? [node.name, node.qualifiedName]
|
|
99
|
+
: [node.name],
|
|
100
|
+
targets: docTagTargetsOf(node),
|
|
101
|
+
},
|
|
102
|
+
);
|
|
80
103
|
}
|
|
104
|
+
this.byNameIndex = index(nodes, (node) => node.name, previous?.byNameIndex);
|
|
105
|
+
this.bySymbolIndex = index(
|
|
106
|
+
nodes,
|
|
107
|
+
(node) => this.nodeKeys.get(node)!.symbols,
|
|
108
|
+
previous?.bySymbolIndex,
|
|
109
|
+
);
|
|
110
|
+
this.byDocTagTarget = index(
|
|
111
|
+
nodes,
|
|
112
|
+
(node) => this.nodeKeys.get(node)!.targets,
|
|
113
|
+
previous?.byDocTagTarget,
|
|
114
|
+
);
|
|
115
|
+
this.outEdges = index(edges, (edge) => edge.from, previous?.outEdges);
|
|
116
|
+
this.inEdges = index(edges, (edge) => edge.to, previous?.inEdges);
|
|
117
|
+
Object.freeze(this);
|
|
81
118
|
}
|
|
82
119
|
|
|
83
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Build a model from a parsed dump, synthesizing structural relationships.
|
|
122
|
+
*
|
|
123
|
+
* The parsed dump must describe one valid generation. Node records are copied
|
|
124
|
+
* before member-kind refinement so the caller's dump is unchanged.
|
|
125
|
+
*
|
|
126
|
+
* @evidence contracts/common.md#principled-implementation Synthesis reanchors native module exports and derives containment from exact owner handles and disambiguating declaration ranges before constructing the indexes for that generation.
|
|
127
|
+
* @evidence contracts/common.md#clear-and-simple-design Synthesis owns representation changes; the private constructor owns index construction.
|
|
128
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts No export edges are guessed from flags, and artifact ownership follows its producer rather than TypeScript id heuristics.
|
|
129
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states the valid-generation precondition and caller-dump preservation.
|
|
130
|
+
* @evidence contracts/performance.md#efficient-algorithms Synthesis indexes nodes by file and handle, scanning only colliding owner buckets once per member; owned snapshot copying and index construction scan nodes, edges and facets; per-node target sets make citation deduplication linear in tag population without repeatedly scanning carrier buckets.
|
|
131
|
+
* @evidence contracts/performance.md#reuse-equivalent-work One model builds all indexes once over owned frozen facts and buckets, so external mutation cannot invalidate shared generation identity.
|
|
132
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources The model retains node/edge arrays, lookup indexes and source cache proportional to its generation; the session or direct caller releases the whole model when no longer needed.
|
|
133
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation builds indexes from a parsed dump object and reads no file; source text goes through TtscGraphSourceReader.
|
|
134
|
+
*/
|
|
84
135
|
static from(dump: ITtscGraphDump): TtscGraphMemory {
|
|
85
|
-
const { nodes, edges } =
|
|
136
|
+
const { nodes, edges } = TtscGraphProjection.full(dump);
|
|
86
137
|
return new TtscGraphMemory(dump.project, nodes, edges, dump.provenance);
|
|
87
138
|
}
|
|
88
139
|
|
|
89
|
-
/**
|
|
90
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Project validated frozen resident facts while retaining equivalent work.
|
|
142
|
+
*
|
|
143
|
+
* The shard store invokes this before committing its staged generation. Each
|
|
144
|
+
* model owns new index maps and a new source reader; unchanged facts and
|
|
145
|
+
* ordered index buckets may be shared with the previous immutable model.
|
|
146
|
+
*
|
|
147
|
+
* @evidence contracts/common.md#principled-implementation Validated frozen fact identity and complete projection dependencies qualify component reuse; construction never mutates the preceding model.
|
|
148
|
+
* @evidence contracts/common.md#clear-and-simple-design The projection owner handles synthesis components and this model owns ordered query indexes and source authority.
|
|
149
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts This internal path requires the store's complete validation; public from still detaches caller DTOs and no graph facts or validation are omitted.
|
|
150
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states the validated-input premise, staged commit and per-generation source-reader boundary.
|
|
151
|
+
* @evidence contracts/performance.md#efficient-algorithms Projection scans references and rebuilds only invalidated components; index scans retain equal buckets without allocating their arrays, while maps and generation arrays remain linear in facts.
|
|
152
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Same-file owner/module dependencies and metadata qualify immutable components; exact ordered reference equality qualifies node/relation/citation buckets. New source adjudication is intentionally independent.
|
|
153
|
+
* @evidence contracts/performance.md#bound-retention-and-release-resources Each model retains only its current components, facts, indexes and source reader; unchanged values may also belong to retained old models, without a link retaining prior model generations.
|
|
154
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation Processes only frozen in-memory facts; source IO remains with the per-generation reader.
|
|
155
|
+
*/
|
|
156
|
+
static fromResident(
|
|
157
|
+
dump: TtscGraphReadonly<ITtscGraphDump>,
|
|
158
|
+
previous?: TtscGraphMemory,
|
|
159
|
+
): TtscGraphMemory {
|
|
160
|
+
const projection = TtscGraphProjection.create(dump, previous?.projection);
|
|
161
|
+
return new TtscGraphMemory(
|
|
162
|
+
dump.project,
|
|
163
|
+
projection.nodes,
|
|
164
|
+
projection.edges,
|
|
165
|
+
dump.provenance,
|
|
166
|
+
projection,
|
|
167
|
+
previous,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The node with this exact stable id, or undefined when absent.
|
|
173
|
+
*
|
|
174
|
+
* @evidence contracts/common.md#principled-implementation The id index returns the snapshot's exact node without conflating same-named declarations.
|
|
175
|
+
* @evidence contracts/common.md#clear-and-simple-design This accessor delegates identity lookup to the single model index.
|
|
176
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Missing identities are not replaced by name-matched candidates.
|
|
177
|
+
* @evidence contracts/common.md#meaningful-documentation The native headline states exact-id and missing-result semantics.
|
|
178
|
+
* @evidence contracts/performance.md#efficient-algorithms Exact identity requires one construction-time map lookup and no node scan.
|
|
179
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The accessor borrows a completed id index; from owns shared construction.
|
|
180
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Returning an existing node acquires no handle or independent retained entry.
|
|
181
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation one Map lookup over in-memory facts.
|
|
182
|
+
*/
|
|
183
|
+
node(id: string): SnapshotNode | undefined {
|
|
91
184
|
return this.byId.get(id);
|
|
92
185
|
}
|
|
93
186
|
|
|
94
|
-
/**
|
|
95
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Edges leaving a node (the node is the from endpoint), empty when absent.
|
|
189
|
+
*
|
|
190
|
+
* @evidence contracts/common.md#principled-implementation The outgoing index preserves native and synthesized edge direction for the exact node id.
|
|
191
|
+
* @evidence contracts/common.md#clear-and-simple-design The accessor exposes one readonly bucket without rescanning the edge population.
|
|
192
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Absence returns no edges rather than inferred calls from matching names.
|
|
193
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states endpoint direction, missing behavior and the readonly return contract.
|
|
194
|
+
* @evidence contracts/performance.md#efficient-algorithms A map lookup returns the outgoing bucket without traversing unrelated edges.
|
|
195
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work from owns the reused adjacency computation; the accessor only borrows its result.
|
|
196
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Existing buckets remain generation-owned; the accessor acquires no separate resource.
|
|
197
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation one Map lookup over in-memory edges.
|
|
198
|
+
*/
|
|
199
|
+
outgoing(id: string): readonly SnapshotEdge[] {
|
|
96
200
|
return this.outEdges.get(id) ?? [];
|
|
97
201
|
}
|
|
98
202
|
|
|
99
|
-
/**
|
|
100
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Edges entering a node (the node is the to endpoint), empty when absent.
|
|
205
|
+
*
|
|
206
|
+
* @evidence contracts/common.md#principled-implementation The incoming index selects edges by their original target identity.
|
|
207
|
+
* @evidence contracts/common.md#clear-and-simple-design The accessor shares construction-time adjacency instead of implementing another traversal.
|
|
208
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts No callers are guessed from text or substituted when the bucket is absent.
|
|
209
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose states incoming direction and empty absence before the tags.
|
|
210
|
+
* @evidence contracts/performance.md#efficient-algorithms A map lookup returns the incoming bucket without scanning graph edges.
|
|
211
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This accessor borrows the index already shared by from rather than coordinating another producer.
|
|
212
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources It retains no state beyond the generation's existing edge bucket.
|
|
213
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation one Map lookup over in-memory edges.
|
|
214
|
+
*/
|
|
215
|
+
incoming(id: string): readonly SnapshotEdge[] {
|
|
101
216
|
return this.inEdges.get(id) ?? [];
|
|
102
217
|
}
|
|
103
218
|
|
|
104
|
-
/**
|
|
105
|
-
|
|
219
|
+
/**
|
|
220
|
+
* Every node whose simple name equals name, empty when absent.
|
|
221
|
+
*
|
|
222
|
+
* @evidence contracts/common.md#principled-implementation The exact simple-name index returns all matching identities, preserving ambiguity.
|
|
223
|
+
* @evidence contracts/common.md#clear-and-simple-design A readonly bucket supplies name lookup independently of ranked search.
|
|
224
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Multiple declarations remain candidates rather than selecting the expected fixture's declaration.
|
|
225
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose describes exact matching and empty absence.
|
|
226
|
+
* @evidence contracts/performance.md#efficient-algorithms Exact-name lookup performs one map access instead of filtering all nodes.
|
|
227
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work Name-index construction and validity belong to from, not this borrowed bucket lookup.
|
|
228
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The returned bucket remains generation-owned with no separately retained cache or handle.
|
|
229
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation one Map lookup over in-memory facts.
|
|
230
|
+
*/
|
|
231
|
+
named(name: string): readonly SnapshotNode[] {
|
|
106
232
|
return this.byNameIndex.get(name) ?? [];
|
|
107
233
|
}
|
|
108
234
|
|
|
109
|
-
/**
|
|
110
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Every non-file node whose simple or owner-qualified symbol handle matches.
|
|
237
|
+
*
|
|
238
|
+
* Matches borrow a frozen generation-owned bucket; no match returns an empty
|
|
239
|
+
* readonly list, and several matches remain distinct.
|
|
240
|
+
*
|
|
241
|
+
* @evidence contracts/common.md#principled-implementation The symbol index includes simple and qualified handles but excludes file containers from symbol resolution.
|
|
242
|
+
* @evidence contracts/common.md#clear-and-simple-design One shared index serves all exact-handle consumers without duplicate resolution policy.
|
|
243
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The accessor preserves ambiguity rather than fabricating a unique resolution.
|
|
244
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains non-file selection, qualified handles and multiple/missing matches.
|
|
245
|
+
* @evidence contracts/performance.md#efficient-algorithms Both simple and qualified handles use the construction-time symbol index, so this accessor performs one map lookup without scanning candidates.
|
|
246
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This borrows one already-built symbol bucket; model construction owns shared work.
|
|
247
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Existing candidates remain frozen generation-owned records in a borrowed bucket; the accessor acquires no separate resource or retained entry.
|
|
248
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation one Map lookup over in-memory facts.
|
|
249
|
+
*/
|
|
250
|
+
symbols(handle: string): readonly SnapshotNode[] {
|
|
111
251
|
return this.bySymbolIndex.get(handle) ?? [];
|
|
112
252
|
}
|
|
113
253
|
|
|
114
|
-
/**
|
|
115
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Every workspace node marked exported by the native declaration facts.
|
|
256
|
+
*
|
|
257
|
+
* External declarations are omitted. Module-specific re-export membership is
|
|
258
|
+
* available separately through exports edges.
|
|
259
|
+
*
|
|
260
|
+
* @evidence contracts/common.md#principled-implementation Filtering exported flags and excluding external nodes yields local exported declarations, not a guessed package front door.
|
|
261
|
+
* @evidence contracts/common.md#clear-and-simple-design The accessor performs one explicit population filter; per-module surface remains in relation indexes.
|
|
262
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts The API does not equate declaring-file export flags with all barrel export relationships.
|
|
263
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose distinguishes exported declarations from module-specific re-exports and states external omission.
|
|
264
|
+
* @evidence contracts/performance.md#efficient-algorithms One O(V) filter over generation nodes selects exported nonexternal declarations; no separate export-flag index is built.
|
|
265
|
+
* @evidence contracts/performance.md#reuse-equivalent-work Completed exported-list memoization is not implemented; every call returns a new mutable array over the shared generation nodes.
|
|
266
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The projected array belongs to its caller; this method retains no separate state.
|
|
267
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation filters the in-memory node array; no file, path or process.
|
|
268
|
+
*/
|
|
269
|
+
exported(): SnapshotNode[] {
|
|
116
270
|
return this.nodes.filter((n) => n.exported && !n.external);
|
|
117
271
|
}
|
|
118
272
|
|
|
@@ -131,8 +285,17 @@ export class TtscGraphMemory {
|
|
|
131
285
|
* part of a tag's text names a thing belongs to whatever convention wrote the
|
|
132
286
|
* tag, so this is a selection rule of the consuming layer rather than a fact
|
|
133
287
|
* the producer claims.
|
|
288
|
+
*
|
|
289
|
+
* @evidence contracts/common.md#principled-implementation Exact target lookup returns indexed declaration carriers under documentationTarget's explicit consumer-side selection rule.
|
|
290
|
+
* @evidence contracts/common.md#clear-and-simple-design The reverse citation index is built once alongside node indexes instead of rescanning tags per query.
|
|
291
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts A match identifies a written citation, not a coverage or truth verdict about its target.
|
|
292
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs explain reverse lookup, exact spelling and the consumer heuristic's authority boundary.
|
|
293
|
+
* @evidence contracts/performance.md#efficient-algorithms Reverse citation lookup uses the constructed target index instead of scanning all tags per request.
|
|
294
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work The accessor borrows the shared citation index; from owns synthesis and its validity key.
|
|
295
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources It returns an existing readonly carrier list and acquires no resource or historical cache.
|
|
296
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation one Map lookup over in-memory facts.
|
|
134
297
|
*/
|
|
135
|
-
citing(target: string): readonly
|
|
298
|
+
citing(target: string): readonly SnapshotNode[] {
|
|
136
299
|
return this.byDocTagTarget.get(target) ?? [];
|
|
137
300
|
}
|
|
138
301
|
}
|
|
@@ -145,14 +308,14 @@ export class TtscGraphMemory {
|
|
|
145
308
|
* for it will spell it. Splitting on whitespace alone would key it under
|
|
146
309
|
* `{@link`, which is every link in the project.
|
|
147
310
|
*/
|
|
148
|
-
function docTagTargetsOf(node:
|
|
311
|
+
function docTagTargetsOf(node: SnapshotNode): string[] {
|
|
149
312
|
if (node.docTags === undefined) return [];
|
|
150
|
-
const targets
|
|
313
|
+
const targets = new Set<string>();
|
|
151
314
|
for (const tag of node.docTags) {
|
|
152
315
|
const token = documentationTarget(tag.text);
|
|
153
|
-
if (token !== undefined
|
|
316
|
+
if (token !== undefined) targets.add(token);
|
|
154
317
|
}
|
|
155
|
-
return targets;
|
|
318
|
+
return [...targets];
|
|
156
319
|
}
|
|
157
320
|
|
|
158
321
|
/**
|
|
@@ -178,6 +341,15 @@ function docTagTargetsOf(node: ITtscGraphNode): string[] {
|
|
|
178
341
|
* layer whose audit already declares its selection heuristic. A convention
|
|
179
342
|
* whose addresses look like prose is simply not indexed; nothing is lost from
|
|
180
343
|
* the tag itself, which `details` still returns in full.
|
|
344
|
+
*
|
|
345
|
+
* @evidence contracts/common.md#principled-implementation Leading-token extraction plus interior separators selects address-like tokens while rejecting ordinary prose; this is explicitly a lookup heuristic.
|
|
346
|
+
* @evidence contracts/common.md#clear-and-simple-design One selector owns citation indexing and query normalization, leaving raw tags unchanged in declaration facts.
|
|
347
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Address punctuation is a general convention boundary rather than an allowlist of expected specifications.
|
|
348
|
+
* @evidence contracts/common.md#meaningful-documentation Native paragraphs state false-prose matches, accepted address forms and the limitation for prose-like conventions.
|
|
349
|
+
* @evidence contracts/performance.md#efficient-algorithms Leading-token extraction and address classification scan only the tag text, with no graph-wide lookup.
|
|
350
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This pure token classifier has no completed-work coordinator; from builds the reusable citation index.
|
|
351
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The optional returned string owns no native resource or retained history.
|
|
352
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation tokenizes a tag string; the address it returns is text that is never resolved or opened.
|
|
181
353
|
*/
|
|
182
354
|
export function documentationTarget(
|
|
183
355
|
text: string | undefined,
|
|
@@ -199,6 +371,15 @@ export function documentationTarget(
|
|
|
199
371
|
* An unclosed brace group is not a token: `{@link ISale` with the brace
|
|
200
372
|
* forgotten would otherwise fall through to the whitespace split and index the
|
|
201
373
|
* address `{@link`, which every link in the project shares.
|
|
374
|
+
*
|
|
375
|
+
* @evidence contracts/common.md#principled-implementation Trim and first whitespace preserve the opening token; a leading brace group is returned whole only when closed.
|
|
376
|
+
* @evidence contracts/common.md#clear-and-simple-design This lexical helper is shared by citation selection rather than parsing tag semantics itself.
|
|
377
|
+
* @evidence contracts/common.md#prohibited-implementation-shortcuts Malformed brace groups return absence instead of being coerced into a ubiquitous partial link.
|
|
378
|
+
* @evidence contracts/common.md#meaningful-documentation Native prose explains brace grouping and the malformed-token reason before acknowledgment tags.
|
|
379
|
+
* @evidence contracts/performance.md#efficient-algorithms A single bounded text scan finds the token boundary without constructing a parser or scanning unrelated tags.
|
|
380
|
+
* @evidenceExclude contracts/performance.md#reuse-equivalent-work This pure per-string extraction does not coordinate reusable producer work.
|
|
381
|
+
* @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Only the returned token survives the call; no retained map or handle is acquired.
|
|
382
|
+
* @evidenceExclude contracts/portability.md#os-neutral-implementation splits a string at whitespace or a brace group; the token is never resolved or opened.
|
|
202
383
|
*/
|
|
203
384
|
export function leadingToken(text: string | undefined): string | undefined {
|
|
204
385
|
const trimmed = text?.trim();
|
|
@@ -211,192 +392,49 @@ export function leadingToken(text: string | undefined): string | undefined {
|
|
|
211
392
|
return stop < 0 ? trimmed : trimmed.slice(0, stop);
|
|
212
393
|
}
|
|
213
394
|
|
|
214
|
-
/** Append value to the slice stored at key, creating the slice on first use. */
|
|
215
|
-
function push<K, V>(map: Map<K, V[]>, key: K, value: V): void {
|
|
216
|
-
const bucket = map.get(key);
|
|
217
|
-
if (bucket) bucket.push(value);
|
|
218
|
-
else map.set(key, [value]);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* The within-file identity of a node: its owner-qualified name when it has one
|
|
223
|
-
* (`Class.method`), else its simple name. Two nodes in one file never share a
|
|
224
|
-
* key, so it is the handle the ownership synthesis looks owners up by.
|
|
225
|
-
*/
|
|
226
|
-
function keyOf(node: ITtscGraphNode): string {
|
|
227
|
-
return node.qualifiedName ?? node.name;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
395
|
/**
|
|
231
|
-
*
|
|
396
|
+
* Build an ordered index, copying a bucket only after its membership differs.
|
|
232
397
|
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* the
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (node.qualifiedName === undefined || node.qualifiedName === node.name)
|
|
239
|
-
return undefined;
|
|
240
|
-
const suffix = `.${node.name}`;
|
|
241
|
-
if (!node.qualifiedName.endsWith(suffix)) return undefined;
|
|
242
|
-
const owner = node.qualifiedName.slice(0, -suffix.length);
|
|
243
|
-
return owner === "" ? undefined : owner;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/** A file's id and node name from its dump path coordinate. */
|
|
247
|
-
function fileNodeId(file: string): string {
|
|
248
|
-
return file;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* A wire span with its file put back: the one the builder left out because the
|
|
253
|
-
* reader has it, or the one it kept because it could not be derived (an
|
|
254
|
-
* implementation in another file).
|
|
398
|
+
* The scan compares reference identity at each position with the previous
|
|
399
|
+
* immutable bucket. Prefixes are copied only on the first difference; a
|
|
400
|
+
* shortened bucket is copied at the end. New maps never mutate old maps or
|
|
401
|
+
* frozen buckets. Cost is linear in memberships plus changed bucket sizes;
|
|
402
|
+
* current counts/maps are temporary and no historical index is retained.
|
|
255
403
|
*/
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const slash = file.lastIndexOf("/");
|
|
270
|
-
return slash >= 0 ? file.slice(slash + 1) : file;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Derive the structural layer from a dump's faithful facts: refine class-member
|
|
275
|
-
* variables to properties, add a `file` node per workspace source, connect the
|
|
276
|
-
* `contains` ownership tree, and re-anchor compiler-owned `exports` edges.
|
|
277
|
-
*/
|
|
278
|
-
function synthesize(dump: ITtscGraphDump): {
|
|
279
|
-
nodes: ITtscGraphNode[];
|
|
280
|
-
edges: ITtscGraphEdge[];
|
|
281
|
-
} {
|
|
282
|
-
// A module node is the dump's name for a source file's export surface, and a
|
|
283
|
-
// file node is this layer's name for the same file. Fold the two: the module
|
|
284
|
-
// keeps its file present here even when the file declares nothing (a barrel),
|
|
285
|
-
// and its `exports` edges are re-anchored on the file id every other tool
|
|
286
|
-
// already traverses. What the module carried, the file now carries.
|
|
287
|
-
const moduleFiles = new Set(
|
|
288
|
-
dump.nodes.filter((n) => n.kind === "module").map((n) => n.file),
|
|
289
|
-
);
|
|
290
|
-
const moduleIds = new Map(
|
|
291
|
-
dump.nodes.filter((n) => n.kind === "module").map((n) => [n.id, n.file]),
|
|
292
|
-
);
|
|
293
|
-
// Clone nodes so property refinement does not mutate the caller's dump, and
|
|
294
|
-
// put back the file the builder left out of every span: a node's span is in
|
|
295
|
-
// the node's file, an edge's span is in the file its `from` id names. The
|
|
296
|
-
// builder omits both because they are exactly reconstructible and they are not
|
|
297
|
-
// small — the two copies are 17% of the document, 55 MB of VS Code's 323 MB,
|
|
298
|
-
// paid again in the encode, the pipe, the parse and the validation. Nothing
|
|
299
|
-
// downstream of this line sees a span without its file.
|
|
300
|
-
const nodes: ITtscGraphNode[] = dump.nodes.flatMap((n): ITtscGraphNode[] => {
|
|
301
|
-
if (n.kind === "module") return [];
|
|
302
|
-
const { evidence, implementation, ...rest } = n;
|
|
303
|
-
return [
|
|
304
|
-
{
|
|
305
|
-
...rest,
|
|
306
|
-
kind: n.kind,
|
|
307
|
-
...(evidence !== undefined
|
|
308
|
-
? { evidence: spanIn(evidence, n.file) }
|
|
309
|
-
: {}),
|
|
310
|
-
...(implementation !== undefined
|
|
311
|
-
? { implementation: spanIn(implementation, n.file) }
|
|
312
|
-
: {}),
|
|
313
|
-
},
|
|
314
|
-
];
|
|
315
|
-
});
|
|
316
|
-
const edges: ITtscGraphEdge[] = dump.edges.map((edge) => {
|
|
317
|
-
const { evidence, ...rest } = edge;
|
|
318
|
-
const from = moduleIds.get(edge.from);
|
|
319
|
-
return {
|
|
320
|
-
...rest,
|
|
321
|
-
...(from !== undefined ? { from: fileNodeId(from) } : {}),
|
|
322
|
-
...(evidence !== undefined
|
|
323
|
-
? { evidence: spanIn(evidence, fileOfNodeId(edge.from)) }
|
|
324
|
-
: {}),
|
|
325
|
-
};
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
// Index workspace nodes by (file, within-file key) so ownership can resolve a
|
|
329
|
-
// member to its declaring class/namespace.
|
|
330
|
-
const byFileKey = new Map<string, ITtscGraphNode>();
|
|
331
|
-
for (const node of nodes) {
|
|
332
|
-
if (!node.external) byFileKey.set(node.file + "\0" + keyOf(node), node);
|
|
333
|
-
}
|
|
334
|
-
const owner = (node: ITtscGraphNode): ITtscGraphNode | undefined => {
|
|
335
|
-
const parent = ownerKey(node);
|
|
336
|
-
if (parent === undefined) return undefined;
|
|
337
|
-
return byFileKey.get(node.file + "\0" + parent);
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
// Refine: a `variable` whose owner is a class or interface is a property.
|
|
341
|
-
for (const node of nodes) {
|
|
342
|
-
if (node.kind !== "variable" || node.external) continue;
|
|
343
|
-
const parent = owner(node);
|
|
344
|
-
if (parent && (parent.kind === "class" || parent.kind === "interface")) {
|
|
345
|
-
node.kind = "property";
|
|
404
|
+
function index<T>(
|
|
405
|
+
values: readonly T[],
|
|
406
|
+
keys: (value: T) => string | readonly string[],
|
|
407
|
+
previous?: ReadonlyMap<string, readonly T[]>,
|
|
408
|
+
): Map<string, readonly T[]> {
|
|
409
|
+
const result = new Map<string, readonly T[]>();
|
|
410
|
+
const counts = new Map<string, number>();
|
|
411
|
+
const append = (key: string, value: T): void => {
|
|
412
|
+
const count = counts.get(key) ?? 0;
|
|
413
|
+
let bucket = result.get(key);
|
|
414
|
+
if (bucket === undefined) {
|
|
415
|
+
bucket = previous?.get(key) ?? [];
|
|
416
|
+
result.set(key, bucket);
|
|
346
417
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const addFileNode = (file: string): void => {
|
|
355
|
-
if (file === "" || fileNodes.has(file)) return;
|
|
356
|
-
fileNodes.set(file, {
|
|
357
|
-
id: fileNodeId(file),
|
|
358
|
-
kind: "file",
|
|
359
|
-
name: basename(file),
|
|
360
|
-
file,
|
|
361
|
-
external: false,
|
|
362
|
-
});
|
|
418
|
+
if (bucket === previous?.get(key)) {
|
|
419
|
+
if (bucket[count] !== value) {
|
|
420
|
+
bucket = [...bucket.slice(0, count), value];
|
|
421
|
+
result.set(key, bucket);
|
|
422
|
+
}
|
|
423
|
+
} else (bucket as T[]).push(value);
|
|
424
|
+
counts.set(key, count + 1);
|
|
363
425
|
};
|
|
364
|
-
for (const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
// Ownership: a member is contained by its owner; a top-level declaration by
|
|
371
|
-
// its file. Exports are not synthesized here: the dump's `exports` edges come
|
|
372
|
-
// from the checker's export table, which follows re-exports and barrels, so
|
|
373
|
-
// they say which module puts a symbol on the wire. Deriving them from the
|
|
374
|
-
// `exported` flag instead would say only that the declaring file made it
|
|
375
|
-
// public, which is the fact that cannot tell a package's front door from its
|
|
376
|
-
// legacy subpath.
|
|
377
|
-
const structural: ITtscGraphEdge[] = [];
|
|
378
|
-
for (const node of nodes) {
|
|
379
|
-
// An artifact is contained by the artifact its producer named, and by
|
|
380
|
-
// nothing when that producer named none. It is never contained by a `file`
|
|
381
|
-
// node: a document is already its own node, a Prisma address carries no
|
|
382
|
-
// path on purpose, and an API operation has no file at all.
|
|
383
|
-
if (isArtifactNodeKind(node.kind)) {
|
|
384
|
-
if (node.parent !== undefined && node.parent !== "")
|
|
385
|
-
structural.push({ from: node.parent, to: node.id, kind: "contains" });
|
|
386
|
-
continue;
|
|
426
|
+
for (const value of values) {
|
|
427
|
+
const selected = keys(value);
|
|
428
|
+
if (typeof selected === "string") append(selected, value);
|
|
429
|
+
else {
|
|
430
|
+
for (const key of selected) append(key, value);
|
|
387
431
|
}
|
|
388
|
-
if (node.external || node.file === "") continue;
|
|
389
|
-
const parent = owner(node);
|
|
390
|
-
const container = parent ? parent.id : fileNodeId(node.file);
|
|
391
|
-
structural.push({
|
|
392
|
-
from: container,
|
|
393
|
-
to: node.id,
|
|
394
|
-
kind: "contains",
|
|
395
|
-
});
|
|
396
432
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
433
|
+
for (const [key, bucket] of result) {
|
|
434
|
+
const count = counts.get(key)!;
|
|
435
|
+
if (bucket === previous?.get(key) && bucket.length !== count)
|
|
436
|
+
result.set(key, Object.freeze(bucket.slice(0, count)));
|
|
437
|
+
else if (bucket !== previous?.get(key)) Object.freeze(bucket);
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
402
440
|
}
|