@ttsc/graph 0.19.3 → 0.20.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/lib/TtscGraphApplication.js +3 -1
- package/lib/TtscGraphApplication.js.map +1 -1
- package/lib/bin.js +15 -3
- package/lib/bin.js.map +1 -1
- package/lib/index.d.ts +13 -2
- package/lib/index.js +24 -30
- package/lib/index.js.map +1 -1
- package/lib/launcherArgs.d.ts +24 -0
- package/lib/launcherArgs.js +136 -0
- package/lib/launcherArgs.js.map +1 -0
- package/lib/model/TtscGraphMemory.d.ts +9 -5
- package/lib/model/TtscGraphMemory.js +35 -58
- package/lib/model/TtscGraphMemory.js.map +1 -1
- package/lib/model/TtscGraphNodeId.d.ts +17 -0
- package/lib/model/TtscGraphNodeId.js +69 -0
- package/lib/model/TtscGraphNodeId.js.map +1 -0
- package/lib/model/TtscGraphSession.d.ts +23 -7
- package/lib/model/TtscGraphSession.js +402 -210
- package/lib/model/TtscGraphSession.js.map +1 -1
- package/lib/model/TtscGraphSourceReader.d.ts +27 -0
- package/lib/model/TtscGraphSourceReader.js +97 -0
- package/lib/model/TtscGraphSourceReader.js.map +1 -0
- package/lib/model/loadGraph.d.ts +4 -4
- package/lib/model/loadGraph.js +233 -168
- package/lib/model/loadGraph.js.map +1 -1
- package/lib/reduce.d.ts +4 -1
- package/lib/reduce.js +112 -29
- package/lib/reduce.js.map +1 -1
- package/lib/server/createServer.js +17 -6
- package/lib/server/createServer.js.map +1 -1
- package/lib/server/pathPolicy.d.ts +6 -0
- package/lib/server/pathPolicy.js +10 -1
- package/lib/server/pathPolicy.js.map +1 -1
- package/lib/server/resolveHandle.js +22 -18
- package/lib/server/resolveHandle.js.map +1 -1
- package/lib/server/resultAudit.d.ts +41 -20
- package/lib/server/resultAudit.js +62 -34
- package/lib/server/resultAudit.js.map +1 -1
- package/lib/server/resultNext.d.ts +5 -0
- package/lib/server/resultNext.js.map +1 -1
- package/lib/server/runDetails.d.ts +2 -2
- package/lib/server/runDetails.js +54 -108
- package/lib/server/runDetails.js.map +1 -1
- package/lib/server/runEntrypoints.js +1 -1
- package/lib/server/runEntrypoints.js.map +1 -1
- package/lib/server/runLookup.js +1 -1
- package/lib/server/runLookup.js.map +1 -1
- package/lib/server/runTour.js +113 -30
- package/lib/server/runTour.js.map +1 -1
- package/lib/server/runTrace.d.ts +22 -0
- package/lib/server/runTrace.js +293 -63
- package/lib/server/runTrace.js.map +1 -1
- package/lib/structures/ITtscGraphDump.d.ts +13 -13
- package/lib/structures/ITtscGraphNode.d.ts +34 -0
- package/lib/structures/ITtscGraphTrace.d.ts +1 -1
- package/lib/view.js +18 -28
- package/lib/view.js.map +1 -1
- package/package.json +5 -5
- package/src/TtscGraphApplication.ts +5 -1
- package/src/bin.ts +13 -3
- package/src/index.ts +34 -27
- package/src/launcherArgs.ts +168 -0
- package/src/model/TtscGraphMemory.ts +34 -60
- package/src/model/TtscGraphNodeId.ts +77 -0
- package/src/model/TtscGraphSession.ts +228 -55
- package/src/model/TtscGraphSourceReader.ts +117 -0
- package/src/model/loadGraph.ts +4 -4
- package/src/reduce.ts +136 -31
- package/src/server/createServer.ts +12 -2
- package/src/server/pathPolicy.ts +10 -1
- package/src/server/resolveHandle.ts +21 -22
- package/src/server/resultAudit.ts +64 -33
- package/src/server/resultNext.ts +6 -0
- package/src/server/runDetails.ts +57 -113
- package/src/server/runEntrypoints.ts +1 -1
- package/src/server/runLookup.ts +1 -1
- package/src/server/runTour.ts +133 -39
- package/src/server/runTrace.ts +401 -65
- package/src/structures/ITtscGraphDump.ts +13 -13
- package/src/structures/ITtscGraphNode.ts +40 -0
- package/src/structures/ITtscGraphTrace.ts +1 -1
- package/src/view.ts +25 -23
|
@@ -26,12 +26,22 @@
|
|
|
26
26
|
* anything was checked afterwards — lost two points and put the file reads
|
|
27
27
|
* back.
|
|
28
28
|
*
|
|
29
|
-
* So the weight is carried by
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
29
|
+
* So the weight is carried by named provenance, not by a loud voice. State who
|
|
30
|
+
* resolved the fact and what this payload did with it, and the instruction that
|
|
31
|
+
* follows reads as a conclusion rather than a demand. Never mystify the result,
|
|
32
|
+
* and never insult the reader for checking it.
|
|
33
|
+
*
|
|
34
|
+
* The claim has to be one this code can keep. An earlier wording said the
|
|
35
|
+
* server assembled the result and "verified them again on the way out" — a
|
|
36
|
+
* second pass, by a second party, after assembly. No such pass exists: this
|
|
37
|
+
* layer holds no `Program` and no checker, it runs one pure projection over an
|
|
38
|
+
* in-memory `TtscGraphMemory`, and it selects a constant by request type
|
|
39
|
+
* (#818). What is true is stronger than it sounds and is what the text now
|
|
40
|
+
* says: the compiler resolved these facts when the snapshot was built, the
|
|
41
|
+
* graph holds what it resolved, and this result is a projection of exactly
|
|
42
|
+
* those facts that adds none of its own. A reader who checks that claim finds
|
|
43
|
+
* it holds; a reader who checked the old one found a promise the code could not
|
|
44
|
+
* have kept.
|
|
35
45
|
*
|
|
36
46
|
* ## Two guarantees, not one
|
|
37
47
|
*
|
|
@@ -47,18 +57,18 @@
|
|
|
47
57
|
* payload, and told it to stop where the shortlist's coverage was exactly what
|
|
48
58
|
* needed judging.
|
|
49
59
|
*
|
|
50
|
-
* So the audits split by what the reader must judge. {@link RESULT_AUDIT}
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* RESULT_AUDIT_SELECTION} covers the ranked shortlists (`lookup`,
|
|
58
|
-
* `tour`): it keeps the same fact-verification and adds that the
|
|
59
|
-
* heuristic, so whether the shortlist covers the question is the
|
|
60
|
-
* judge — and a follow-up request or a read of a cited span is a
|
|
61
|
-
* step, not a failure to trust the result.
|
|
60
|
+
* So the audits split by what the reader must judge. {@link RESULT_AUDIT} covers
|
|
61
|
+
* the walks from an explicit handle or structure (`trace`, `overview`): the
|
|
62
|
+
* result is what the graph holds for what you named, bounded where `truncated`
|
|
63
|
+
* says. {@link RESULT_AUDIT_DETAILS} covers `details`, whose result is not one
|
|
64
|
+
* bounded whole but two halves — a symbol's own shape, returned complete, and
|
|
65
|
+
* its fan-out, returned as a slice with `trace` for the rest — so it names
|
|
66
|
+
* which half to trust outright and which to follow.
|
|
67
|
+
* {@link RESULT_AUDIT_SELECTION} covers the ranked shortlists (`lookup`,
|
|
68
|
+
* `entrypoints`, `tour`): it keeps the same fact-verification and adds that the
|
|
69
|
+
* _selection_ is heuristic, so whether the shortlist covers the question is the
|
|
70
|
+
* caller's to judge — and a follow-up request or a read of a cited span is a
|
|
71
|
+
* sound next step, not a failure to trust the result.
|
|
62
72
|
*
|
|
63
73
|
* Keep both narrow, and keep the stop-or-continue decision with the result's
|
|
64
74
|
* `next`, so neither contradicts a partial result that legitimately asks for
|
|
@@ -69,10 +79,10 @@
|
|
|
69
79
|
export const RESULT_AUDIT: string = `
|
|
70
80
|
AUDITED BEFORE RETURNING. READ FIRST.
|
|
71
81
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
Every fact in this \`result\` — each name, span, edge, signature, and step — was resolved by
|
|
83
|
+
the TypeScript compiler against the program for the snapshot this call synced to, and the
|
|
84
|
+
graph holds what it resolved. This \`result\` is a projection of exactly those facts and adds
|
|
85
|
+
none of its own, so for this snapshot a fact here cannot disagree with the program.
|
|
76
86
|
|
|
77
87
|
This is the structure the graph holds for the handles you named, not a shortlist matched
|
|
78
88
|
against a natural-language question. Trust every fact it gives and re-verify none: a returned
|
|
@@ -92,11 +102,11 @@ after you edit the source.
|
|
|
92
102
|
export const RESULT_AUDIT_SELECTION: string = `
|
|
93
103
|
AUDITED BEFORE RETURNING. READ FIRST.
|
|
94
104
|
|
|
95
|
-
Each fact in this \`result\` — every name, span, edge, and signature — was
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
confirm it.
|
|
105
|
+
Each fact in this \`result\` — every name, span, edge, and signature — was resolved by the
|
|
106
|
+
TypeScript compiler against the program for the snapshot this call synced to, and the graph
|
|
107
|
+
holds what it resolved. This \`result\` is a projection of exactly those facts and adds none of
|
|
108
|
+
its own, so for this snapshot a fact here cannot disagree with the program: a returned span
|
|
109
|
+
is the citation, not a cue to open the file to confirm it.
|
|
100
110
|
|
|
101
111
|
What was selected is heuristic, not exhaustive. This result was matched against your
|
|
102
112
|
natural-language question, scored and ranked, held to a few hits per file, and cut to a
|
|
@@ -113,10 +123,10 @@ Follow \`next\` for where that leaves the question.
|
|
|
113
123
|
*
|
|
114
124
|
* `trace` walks and marks where the walk was cut with `truncated`; `details`
|
|
115
125
|
* does not walk. It resolves a named handle, and its result splits in two. What
|
|
116
|
-
* a symbol
|
|
126
|
+
* a symbol _is_ — its members, its values, its signature — is bounded by the
|
|
117
127
|
* declaration and returned whole, so the old "trust it, do not open the file"
|
|
118
128
|
* is finally true of it rather than contradicted by a capped member list. What
|
|
119
|
-
* a symbol
|
|
129
|
+
* a symbol _reaches or is reached by_ — its calls, its type references, its
|
|
120
130
|
* implementers, its dependents — is bounded by how widely it is used, not by
|
|
121
131
|
* the symbol, so returning it whole is a `trace`/impact answer of a thousand
|
|
122
132
|
* refs in a "what is this" call. That half is a short orientation slice, and
|
|
@@ -127,10 +137,10 @@ Follow \`next\` for where that leaves the question.
|
|
|
127
137
|
export const RESULT_AUDIT_DETAILS: string = `
|
|
128
138
|
AUDITED BEFORE RETURNING. READ FIRST.
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
Every fact in this \`result\` — each name, span, edge, signature, member, and value — was
|
|
141
|
+
resolved by the TypeScript compiler against the program for the snapshot this call synced to,
|
|
142
|
+
and the graph holds what it resolved. This \`result\` is a projection of exactly those facts
|
|
143
|
+
and adds none of its own, so for this snapshot a fact here cannot disagree with the program.
|
|
134
144
|
|
|
135
145
|
This is the structure the graph holds for the handles you named. What a symbol is — its
|
|
136
146
|
members, its values, its signature — is complete: trust it and do not open the file to read
|
|
@@ -143,6 +153,27 @@ Follow \`next\`: answer from this result, and re-call the graph only when it say
|
|
|
143
153
|
after you edit the source.
|
|
144
154
|
`.trim();
|
|
145
155
|
|
|
156
|
+
/**
|
|
157
|
+
* The details audit for a result whose member list a caller cap truncated.
|
|
158
|
+
*
|
|
159
|
+
* The unconditional text tells the reader a symbol's members are complete and
|
|
160
|
+
* not to open the file for them. After `memberLimit` cuts the list that is
|
|
161
|
+
* false, and it is the one claim a caller cannot check from the result: the
|
|
162
|
+
* members that were removed left nothing behind to notice. So the claim is
|
|
163
|
+
* withdrawn for exactly that half and everything else the audit verifies is
|
|
164
|
+
* kept.
|
|
165
|
+
*/
|
|
166
|
+
export const RESULT_AUDIT_DETAILS_CAPPED: string = RESULT_AUDIT_DETAILS.replace(
|
|
167
|
+
// Matched by shape rather than by exact spelling. This file is stored with
|
|
168
|
+
// CRLF, so a needle carrying a plain newline never matches the template
|
|
169
|
+
// literal's real line breaks and the replacement would silently do nothing —
|
|
170
|
+
// the capped audit would come out identical to the uncapped one.
|
|
171
|
+
/What a symbol is[\s\S]*?what is already here\./,
|
|
172
|
+
"What a symbol is — its values and its signature — is complete. Its member list was cut to " +
|
|
173
|
+
"the `memberLimit` you asked for, so it is a slice, not the whole set: re-request with a " +
|
|
174
|
+
"larger cap for the rest.",
|
|
175
|
+
);
|
|
176
|
+
|
|
146
177
|
/** The escape branch carries no graph facts, so it claims none. */
|
|
147
178
|
export const RESULT_AUDIT_ESCAPE: string =
|
|
148
179
|
"This escape carries no graph facts to audit.";
|
package/src/server/resultNext.ts
CHANGED
|
@@ -7,6 +7,12 @@ export interface IRunnerOutput<T> {
|
|
|
7
7
|
|
|
8
8
|
/** How to use the result next. */
|
|
9
9
|
next: ITtscGraphNext;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Set when a caller cap removed members from the result, so the audit can
|
|
13
|
+
* stop claiming the symbol's members are complete.
|
|
14
|
+
*/
|
|
15
|
+
membersCapped?: boolean;
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
export function resultNext(
|
package/src/server/runDetails.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
1
|
import { TtscGraphMemory } from "../model/TtscGraphMemory";
|
|
5
2
|
import { ITtscGraphDecorator } from "../structures/ITtscGraphDecorator";
|
|
6
3
|
import { ITtscGraphDetails } from "../structures/ITtscGraphDetails";
|
|
@@ -15,9 +12,6 @@ import { IRunnerOutput, resultNext } from "./resultNext";
|
|
|
15
12
|
const MAX_SIGNATURE_LINES = 4;
|
|
16
13
|
// A doc summary is one sentence; the rest of the comment is the file's to keep.
|
|
17
14
|
const MAX_DOC_CHARS = 200;
|
|
18
|
-
// An object literal's outline is scanned from source, so a runaway literal is
|
|
19
|
-
// bounded here; the members it does find are not capped.
|
|
20
|
-
const MAX_OBJECT_MEMBER_LINES = 300;
|
|
21
15
|
// A symbol's fan-out — what it calls, what names it in a type, what depends on
|
|
22
16
|
// it — scales with how popular it is, not with the symbol: a central type is
|
|
23
17
|
// named in a thousand places, and returning all of them is a hundred thousand
|
|
@@ -57,7 +51,15 @@ export function runDetails(
|
|
|
57
51
|
// does not: what names or uses a symbol is bounded by its popularity, not by
|
|
58
52
|
// it, so those stay a small slice with `trace` for the rest.
|
|
59
53
|
const memberLimit = limitOf(props.memberLimit);
|
|
60
|
-
|
|
54
|
+
// True once any handle's member list is cut by the cap above. It travels with
|
|
55
|
+
// the result so the audit can withdraw the completeness claim for exactly
|
|
56
|
+
// that half — a caller cannot notice the cut from the result itself.
|
|
57
|
+
let membersCapped = false;
|
|
58
|
+
const neighborLimit = capOf(
|
|
59
|
+
props.neighborLimit,
|
|
60
|
+
DEFAULT_NEIGHBORS,
|
|
61
|
+
MAX_NEIGHBORS,
|
|
62
|
+
);
|
|
61
63
|
const dependencyLimit = capOf(
|
|
62
64
|
props.dependencyLimit,
|
|
63
65
|
DEFAULT_DEPENDENCIES,
|
|
@@ -100,9 +102,9 @@ export function runDetails(
|
|
|
100
102
|
file: node.file,
|
|
101
103
|
};
|
|
102
104
|
if (node.evidence?.startLine) detail.line = node.evidence.startLine;
|
|
103
|
-
const sig = signatureOf(graph
|
|
105
|
+
const sig = signatureOf(graph, node);
|
|
104
106
|
if (sig !== undefined) detail.signature = sig;
|
|
105
|
-
const doc = docOf(graph
|
|
107
|
+
const doc = docOf(graph, node);
|
|
106
108
|
if (doc !== undefined) detail.doc = doc;
|
|
107
109
|
const decorators = decoratorsOf(node);
|
|
108
110
|
if (decorators !== undefined) detail.decorators = decorators;
|
|
@@ -141,16 +143,19 @@ export function runDetails(
|
|
|
141
143
|
);
|
|
142
144
|
if (implementedBy.length > 0) detail.implementedBy = implementedBy;
|
|
143
145
|
if (CONTAINER_KINDS.has(node.kind)) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
// Read one past the cap so the cut is observable. Without it a full list
|
|
147
|
+
// and a truncated one are the same value, and the audit went on claiming
|
|
148
|
+
// the members were whole.
|
|
149
|
+
const list = members(graph, node, memberLimit + 1);
|
|
150
|
+
if (list.length > memberLimit) membersCapped = true;
|
|
151
|
+
const shown = list.slice(0, memberLimit);
|
|
152
|
+
if (shown.length > 0) detail.members = shown;
|
|
146
153
|
}
|
|
147
|
-
if (node.kind === "variable"
|
|
148
|
-
const list = objectLiteralMembers(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
);
|
|
153
|
-
if (list.length > 0) detail.members = list;
|
|
154
|
+
if (node.kind === "variable") {
|
|
155
|
+
const list = objectLiteralMembers(node, memberLimit + 1);
|
|
156
|
+
if (list.length > memberLimit) membersCapped = true;
|
|
157
|
+
const shown = list.slice(0, memberLimit);
|
|
158
|
+
if (shown.length > 0) detail.members = shown;
|
|
154
159
|
}
|
|
155
160
|
// An enum's members ride on its own node rather than on `contains` edges,
|
|
156
161
|
// because they are not nodes: the outline above finds nothing for an enum
|
|
@@ -158,8 +163,10 @@ export function runDetails(
|
|
|
158
163
|
// kind whose entire content is its member list answered with none of it.
|
|
159
164
|
// Uncapped like every other identity list — the members are the enum.
|
|
160
165
|
if (node.kind === "enum") {
|
|
161
|
-
const list = enumMembers(node, memberLimit);
|
|
162
|
-
if (list.length >
|
|
166
|
+
const list = enumMembers(node, memberLimit + 1);
|
|
167
|
+
if (list.length > memberLimit) membersCapped = true;
|
|
168
|
+
const shown = list.slice(0, memberLimit);
|
|
169
|
+
if (shown.length > 0) detail.members = shown;
|
|
163
170
|
}
|
|
164
171
|
if (node.literals !== undefined && node.literals.length > 0) {
|
|
165
172
|
detail.literals = node.literals;
|
|
@@ -183,6 +190,7 @@ export function runDetails(
|
|
|
183
190
|
nodes.push(detail);
|
|
184
191
|
}
|
|
185
192
|
return {
|
|
193
|
+
...(membersCapped ? { membersCapped: true } : {}),
|
|
186
194
|
result: {
|
|
187
195
|
type: "details",
|
|
188
196
|
nodes,
|
|
@@ -224,7 +232,7 @@ function members(
|
|
|
224
232
|
kind: member.kind,
|
|
225
233
|
};
|
|
226
234
|
if (member.evidence?.startLine) m.line = member.evidence.startLine;
|
|
227
|
-
const sig = signatureOf(graph
|
|
235
|
+
const sig = signatureOf(graph, member);
|
|
228
236
|
if (sig !== undefined) m.signature = sig;
|
|
229
237
|
const decorators = decoratorsOf(member);
|
|
230
238
|
if (decorators !== undefined) m.decorators = decorators;
|
|
@@ -257,83 +265,15 @@ function enumMembers(
|
|
|
257
265
|
}
|
|
258
266
|
|
|
259
267
|
function objectLiteralMembers(
|
|
260
|
-
|
|
261
|
-
span: Pick<ITtscGraphEvidence, "file" | "startLine" | "endLine">,
|
|
268
|
+
node: ITtscGraphNode,
|
|
262
269
|
limit: number,
|
|
263
270
|
): ITtscGraphDetails.IMember[] {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const members: ITtscGraphDetails.IMember[] = [];
|
|
271
|
-
let depth = 0;
|
|
272
|
-
let entered = false;
|
|
273
|
-
for (let i = start; i <= end; i++) {
|
|
274
|
-
const raw = lines[i] ?? "";
|
|
275
|
-
const text = stripStrings(raw);
|
|
276
|
-
const before = depth;
|
|
277
|
-
if (entered && before === 1) {
|
|
278
|
-
const member = objectMemberOf(raw, i + 1);
|
|
279
|
-
if (member !== undefined) {
|
|
280
|
-
members.push(member);
|
|
281
|
-
if (members.length >= limit) break;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
for (const char of text) {
|
|
285
|
-
if (char === "{") {
|
|
286
|
-
depth++;
|
|
287
|
-
entered = true;
|
|
288
|
-
} else if (char === "}") {
|
|
289
|
-
depth = Math.max(0, depth - 1);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return members;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function objectMemberOf(
|
|
297
|
-
line: string,
|
|
298
|
-
lineNumber: number,
|
|
299
|
-
): ITtscGraphDetails.IMember | undefined {
|
|
300
|
-
const text = line.trim();
|
|
301
|
-
if (
|
|
302
|
-
text === "" ||
|
|
303
|
-
text.startsWith("//") ||
|
|
304
|
-
text.startsWith("/*") ||
|
|
305
|
-
text.startsWith("*")
|
|
306
|
-
) {
|
|
307
|
-
return undefined;
|
|
308
|
-
}
|
|
309
|
-
const property = /^(['"]?)([A-Za-z_$][\w$-]*)\1\s*\??\s*:/.exec(text);
|
|
310
|
-
if (property !== null) {
|
|
311
|
-
return {
|
|
312
|
-
name: property[2]!,
|
|
313
|
-
kind: "property",
|
|
314
|
-
line: lineNumber,
|
|
315
|
-
signature: signatureLine(text),
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
const method =
|
|
319
|
-
/^(?:async\s+)?(?:get\s+|set\s+)?([A-Za-z_$][\w$-]*)\s*\(/.exec(text);
|
|
320
|
-
if (method !== null) {
|
|
321
|
-
return {
|
|
322
|
-
name: method[1]!,
|
|
323
|
-
kind: "method",
|
|
324
|
-
line: lineNumber,
|
|
325
|
-
signature: signatureLine(text),
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
return undefined;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function signatureLine(text: string): string {
|
|
332
|
-
return text.replace(/\s+/g, " ").replace(/,$/, "");
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function stripStrings(line: string): string {
|
|
336
|
-
return line.replace(/\/\/.*$/, "").replace(/(['"`])(?:\\.|(?!\1).)*\1/g, "");
|
|
271
|
+
return (node.objectMembers ?? []).slice(0, limit).map((member) => ({
|
|
272
|
+
name: member.name,
|
|
273
|
+
kind: member.kind,
|
|
274
|
+
...(member.line !== undefined ? { line: member.line } : {}),
|
|
275
|
+
...(member.signature !== undefined ? { signature: member.signature } : {}),
|
|
276
|
+
}));
|
|
337
277
|
}
|
|
338
278
|
|
|
339
279
|
/** Map dependency edges to references on their far endpoint, dropping structure. */
|
|
@@ -461,8 +401,8 @@ function rankedRefs(
|
|
|
461
401
|
|
|
462
402
|
/**
|
|
463
403
|
* An identity list's cap: none by default, honored when a caller passes one.
|
|
464
|
-
* details answers a named handle's own shape in full — its members, its values
|
|
465
|
-
* so the default is unlimited; the tour passes an explicit number to embed a
|
|
404
|
+
* details answers a named handle's own shape in full — its members, its values
|
|
405
|
+
* — so the default is unlimited; the tour passes an explicit number to embed a
|
|
466
406
|
* compact slice of its own.
|
|
467
407
|
*/
|
|
468
408
|
function limitOf(value: number | undefined): number {
|
|
@@ -476,7 +416,11 @@ function limitOf(value: number | undefined): number {
|
|
|
476
416
|
* uses a symbol grows with its popularity, not with the symbol, so the whole
|
|
477
417
|
* list is a trace/impact answer and details returns an orientation slice.
|
|
478
418
|
*/
|
|
479
|
-
function capOf(
|
|
419
|
+
function capOf(
|
|
420
|
+
value: number | undefined,
|
|
421
|
+
fallback: number,
|
|
422
|
+
max: number,
|
|
423
|
+
): number {
|
|
480
424
|
const n = value === undefined || !Number.isFinite(value) ? fallback : value;
|
|
481
425
|
return Math.max(1, Math.min(max, Math.floor(n)));
|
|
482
426
|
}
|
|
@@ -564,16 +508,6 @@ function evidenceCoordinatesOf(
|
|
|
564
508
|
};
|
|
565
509
|
}
|
|
566
510
|
|
|
567
|
-
/** Read a file's lines once, or undefined when it cannot be read. */
|
|
568
|
-
function fileLines(project: string, file: string): string[] | undefined {
|
|
569
|
-
if (file === "") return undefined;
|
|
570
|
-
try {
|
|
571
|
-
return fs.readFileSync(path.join(project, file), "utf8").split(/\r?\n/);
|
|
572
|
-
} catch {
|
|
573
|
-
return undefined;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
|
|
577
511
|
/**
|
|
578
512
|
* What the declaration says it is: the first sentence of the doc comment
|
|
579
513
|
* written above it.
|
|
@@ -587,12 +521,12 @@ function fileLines(project: string, file: string): string[] | undefined {
|
|
|
587
521
|
* symbol with what it is for is doing an index's job.
|
|
588
522
|
*/
|
|
589
523
|
export function docOf(
|
|
590
|
-
|
|
524
|
+
graph: TtscGraphMemory,
|
|
591
525
|
node: ITtscGraphNode,
|
|
592
526
|
): string | undefined {
|
|
593
527
|
const evidence = node.evidence;
|
|
594
528
|
const lines =
|
|
595
|
-
evidence === undefined ? undefined :
|
|
529
|
+
evidence === undefined ? undefined : graph.source.lines(evidence.file);
|
|
596
530
|
if (lines === undefined || evidence === undefined) return undefined;
|
|
597
531
|
let index = evidence.startLine - 2;
|
|
598
532
|
while (index >= 0 && (lines[index] ?? "").trim() === "") index--;
|
|
@@ -638,12 +572,22 @@ export function docOf(
|
|
|
638
572
|
* the node.
|
|
639
573
|
*/
|
|
640
574
|
export function signatureOf(
|
|
641
|
-
|
|
575
|
+
graph: TtscGraphMemory,
|
|
642
576
|
node: ITtscGraphNode,
|
|
643
577
|
): string | undefined {
|
|
578
|
+
// The producer cuts the head where the compiler says the body opens, so when
|
|
579
|
+
// it supplied one there is nothing left to infer. The scan below only runs
|
|
580
|
+
// where it could not: it reads whole physical lines and stops at the first one
|
|
581
|
+
// holding a `{`, which leaks implementation text when a declaration shares its
|
|
582
|
+
// line with its body and stops early when the head itself contains a brace.
|
|
583
|
+
if (node.signature !== undefined && node.signature !== "") {
|
|
584
|
+
const capped = node.signature.split("\n").slice(0, MAX_SIGNATURE_LINES);
|
|
585
|
+
const head = capped.join("\n").trim();
|
|
586
|
+
if (head !== "") return head;
|
|
587
|
+
}
|
|
644
588
|
const evidence = node.evidence;
|
|
645
589
|
const lines =
|
|
646
|
-
evidence === undefined ? undefined :
|
|
590
|
+
evidence === undefined ? undefined : graph.source.lines(evidence.file);
|
|
647
591
|
if (lines === undefined || evidence === undefined) return undefined;
|
|
648
592
|
const start = Math.max(0, evidence.startLine - 1);
|
|
649
593
|
const last =
|
|
@@ -118,7 +118,7 @@ function nodeOf(
|
|
|
118
118
|
};
|
|
119
119
|
if (node.evidence?.startLine !== undefined)
|
|
120
120
|
out.line = node.evidence.startLine;
|
|
121
|
-
const signature = signatureOf(graph
|
|
121
|
+
const signature = signatureOf(graph, node);
|
|
122
122
|
if (signature !== undefined) out.signature = signature;
|
|
123
123
|
const decorators = decoratorsOf(node);
|
|
124
124
|
if (decorators !== undefined) out.decorators = decorators;
|
package/src/server/runLookup.ts
CHANGED
|
@@ -88,7 +88,7 @@ export function runLookup(
|
|
|
88
88
|
for (const hit of hits) {
|
|
89
89
|
const node = graph.node(hit.id);
|
|
90
90
|
if (node === undefined) continue;
|
|
91
|
-
const sig = signatureOf(graph
|
|
91
|
+
const sig = signatureOf(graph, node);
|
|
92
92
|
if (sig !== undefined) hit.signature = sig;
|
|
93
93
|
}
|
|
94
94
|
return {
|