@ttsc/graph 0.19.2 → 0.19.3
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/index.d.ts +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/model/TtscGraphSession.js +109 -49
- package/lib/model/TtscGraphSession.js.map +1 -1
- package/lib/model/loadGraph.d.ts +14 -0
- package/lib/model/loadGraph.js +114 -66
- package/lib/model/loadGraph.js.map +1 -1
- package/lib/resolveGraphBinary.d.ts +9 -3
- package/lib/resolveGraphBinary.js +9 -3
- package/lib/resolveGraphBinary.js.map +1 -1
- package/lib/server/createServer.js +5 -5
- package/lib/server/resultAudit.d.ts +29 -8
- package/lib/server/resultAudit.js +47 -9
- package/lib/server/resultAudit.js.map +1 -1
- package/lib/server/runDetails.d.ts +7 -0
- package/lib/server/runDetails.js +87 -58
- package/lib/server/runDetails.js.map +1 -1
- package/lib/structures/ITtscGraphApplication.d.ts +8 -7
- package/lib/structures/ITtscGraphDetails.d.ts +18 -8
- package/lib/structures/ITtscGraphNode.d.ts +37 -0
- package/lib/structures/ITtscGraphTour.d.ts +1 -1
- package/package.json +5 -2
- package/src/TtscGraphApplication.ts +4 -1
- package/src/index.ts +1 -0
- package/src/model/TtscGraphSession.ts +27 -0
- package/src/model/loadGraph.ts +6 -1
- package/src/resolveGraphBinary.ts +9 -3
- package/src/server/resultAudit.ts +47 -8
- package/src/server/runDetails.ts +95 -70
- package/src/structures/ITtscGraphApplication.ts +8 -7
- package/src/structures/ITtscGraphDetails.ts +18 -8
- package/src/structures/ITtscGraphNode.ts +40 -0
- package/src/structures/ITtscGraphTour.ts +1 -1
|
@@ -47,14 +47,18 @@
|
|
|
47
47
|
* payload, and told it to stop where the shortlist's coverage was exactly what
|
|
48
48
|
* needed judging.
|
|
49
49
|
*
|
|
50
|
-
* So
|
|
51
|
-
* from an explicit handle or structure (`trace`, `
|
|
52
|
-
* result is what the graph holds for what you named, bounded
|
|
53
|
-
* `truncated` says. {@link
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
50
|
+
* So the audits split by what the reader must judge. {@link RESULT_AUDIT}
|
|
51
|
+
* covers the walks from an explicit handle or structure (`trace`, `overview`):
|
|
52
|
+
* the result is what the graph holds for what you named, bounded where
|
|
53
|
+
* `truncated` says. {@link RESULT_AUDIT_DETAILS} covers `details`, whose result
|
|
54
|
+
* is not one bounded whole but two halves — a symbol's own shape, returned
|
|
55
|
+
* complete, and its fan-out, returned as a slice with `trace` for the rest — so
|
|
56
|
+
* it names which half to trust outright and which to follow. {@link
|
|
57
|
+
* RESULT_AUDIT_SELECTION} covers the ranked shortlists (`lookup`, `entrypoints`,
|
|
58
|
+
* `tour`): it keeps the same fact-verification and adds that the _selection_ is
|
|
59
|
+
* heuristic, so whether the shortlist covers the question is the caller's to
|
|
60
|
+
* judge — and a follow-up request or a read of a cited span is a sound next
|
|
61
|
+
* step, not a failure to trust the result.
|
|
58
62
|
*
|
|
59
63
|
* Keep both narrow, and keep the stop-or-continue decision with the result's
|
|
60
64
|
* `next`, so neither contradicts a partial result that legitimately asks for
|
|
@@ -104,6 +108,41 @@ span is a sound next step, not a failure to trust the result.
|
|
|
104
108
|
Follow \`next\` for where that leaves the question.
|
|
105
109
|
`.trim();
|
|
106
110
|
|
|
111
|
+
/**
|
|
112
|
+
* The audit for `details`, whose contract is not the other exact operations'.
|
|
113
|
+
*
|
|
114
|
+
* `trace` walks and marks where the walk was cut with `truncated`; `details`
|
|
115
|
+
* does not walk. It resolves a named handle, and its result splits in two. What
|
|
116
|
+
* a symbol *is* — its members, its values, its signature — is bounded by the
|
|
117
|
+
* declaration and returned whole, so the old "trust it, do not open the file"
|
|
118
|
+
* is finally true of it rather than contradicted by a capped member list. What
|
|
119
|
+
* a symbol *reaches or is reached by* — its calls, its type references, its
|
|
120
|
+
* implementers, its dependents — is bounded by how widely it is used, not by
|
|
121
|
+
* the symbol, so returning it whole is a `trace`/impact answer of a thousand
|
|
122
|
+
* refs in a "what is this" call. That half is a short orientation slice, and
|
|
123
|
+
* the audit has to say which half is which so the reader trusts the complete
|
|
124
|
+
* one and reaches for `trace` on the other, instead of reading the file for a
|
|
125
|
+
* member list that is already here.
|
|
126
|
+
*/
|
|
127
|
+
export const RESULT_AUDIT_DETAILS: string = `
|
|
128
|
+
AUDITED BEFORE RETURNING. READ FIRST.
|
|
129
|
+
|
|
130
|
+
The server assembled this \`result\`, then checked it: every fact in it — each name, span,
|
|
131
|
+
edge, signature, member, and value — was taken back to the type-checked program for the
|
|
132
|
+
snapshot this call synced to, and resolved there, so for this snapshot a fact here cannot be
|
|
133
|
+
wrong.
|
|
134
|
+
|
|
135
|
+
This is the structure the graph holds for the handles you named. What a symbol is — its
|
|
136
|
+
members, its values, its signature — is complete: trust it and do not open the file to read
|
|
137
|
+
what is already here. What a symbol reaches or is reached by — its calls, its type
|
|
138
|
+
references, its implementers, and under \`neighbors\` its dependents — is a short orientation
|
|
139
|
+
slice, not the whole set, because that grows with how widely a symbol is used; \`trace\`
|
|
140
|
+
follows it in full.
|
|
141
|
+
|
|
142
|
+
Follow \`next\`: answer from this result, and re-call the graph only when it says inspect, or
|
|
143
|
+
after you edit the source.
|
|
144
|
+
`.trim();
|
|
145
|
+
|
|
107
146
|
/** The escape branch carries no graph facts, so it claims none. */
|
|
108
147
|
export const RESULT_AUDIT_ESCAPE: string =
|
|
109
148
|
"This escape carries no graph facts to audit.";
|
package/src/server/runDetails.ts
CHANGED
|
@@ -15,17 +15,20 @@ import { IRunnerOutput, resultNext } from "./resultNext";
|
|
|
15
15
|
const MAX_SIGNATURE_LINES = 4;
|
|
16
16
|
// A doc summary is one sentence; the rest of the comment is the file's to keep.
|
|
17
17
|
const MAX_DOC_CHARS = 200;
|
|
18
|
-
//
|
|
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
|
+
// A symbol's fan-out — what it calls, what names it in a type, what depends on
|
|
22
|
+
// it — scales with how popular it is, not with the symbol: a central type is
|
|
23
|
+
// named in a thousand places, and returning all of them is a hundred thousand
|
|
24
|
+
// tokens of "who uses this", which is a trace/impact question, not "what is
|
|
25
|
+
// this". So fan-out is a small default slice; identity (members, literals) is
|
|
26
|
+
// not, because a class's members and a union's values are the symbol itself and
|
|
27
|
+
// are bounded by the declaration.
|
|
19
28
|
const DEFAULT_NEIGHBORS = 2;
|
|
20
29
|
const MAX_NEIGHBORS = 3;
|
|
21
|
-
// A container outline can be long; default to a scannable first page.
|
|
22
|
-
const DEFAULT_MEMBERS = 6;
|
|
23
|
-
const MAX_MEMBERS = 8;
|
|
24
|
-
// Direct dependency groups are orientation slices, not full fan-out dumps.
|
|
25
30
|
const DEFAULT_DEPENDENCIES = 2;
|
|
26
31
|
const MAX_DEPENDENCIES = 4;
|
|
27
|
-
// Object literal outlines are navigation aids, not source excerpts.
|
|
28
|
-
const MAX_OBJECT_MEMBER_LINES = 300;
|
|
29
32
|
// Structural relationships are navigation, not the dependency picture details is for.
|
|
30
33
|
const STRUCTURAL_KINDS = new Set<string>(["contains", "exports", "imports"]);
|
|
31
34
|
// Kinds whose value is their member outline, not implementation text.
|
|
@@ -47,17 +50,17 @@ export function runDetails(
|
|
|
47
50
|
graph: TtscGraphMemory,
|
|
48
51
|
props: ITtscGraphDetails.IRequest,
|
|
49
52
|
): IRunnerOutput<ITtscGraphDetails> {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const memberLimit =
|
|
57
|
-
const
|
|
53
|
+
// Identity is the whole answer. The caller named this handle to learn what it
|
|
54
|
+
// is, and a class's members or a union's values are the symbol itself — cut
|
|
55
|
+
// them and the model reads the file for the rest, the read this index exists
|
|
56
|
+
// to remove. So `memberLimit` and `literals` default to unlimited. Fan-out
|
|
57
|
+
// does not: what names or uses a symbol is bounded by its popularity, not by
|
|
58
|
+
// it, so those stay a small slice with `trace` for the rest.
|
|
59
|
+
const memberLimit = limitOf(props.memberLimit);
|
|
60
|
+
const neighborLimit = capOf(props.neighborLimit, DEFAULT_NEIGHBORS, MAX_NEIGHBORS);
|
|
61
|
+
const dependencyLimit = capOf(
|
|
58
62
|
props.dependencyLimit,
|
|
59
63
|
DEFAULT_DEPENDENCIES,
|
|
60
|
-
1,
|
|
61
64
|
MAX_DEPENDENCIES,
|
|
62
65
|
);
|
|
63
66
|
const wantNeighbors = props.neighbors === true;
|
|
@@ -101,7 +104,6 @@ export function runDetails(
|
|
|
101
104
|
if (sig !== undefined) detail.signature = sig;
|
|
102
105
|
const doc = docOf(graph.project, node);
|
|
103
106
|
if (doc !== undefined) detail.doc = doc;
|
|
104
|
-
const signatureLiterals = literalSummaries(sig);
|
|
105
107
|
const decorators = decoratorsOf(node);
|
|
106
108
|
if (decorators !== undefined) detail.decorators = decorators;
|
|
107
109
|
const implementation = evidenceCoordinatesOf(node.implementation);
|
|
@@ -150,8 +152,18 @@ export function runDetails(
|
|
|
150
152
|
);
|
|
151
153
|
if (list.length > 0) detail.members = list;
|
|
152
154
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
// An enum's members ride on its own node rather than on `contains` edges,
|
|
156
|
+
// because they are not nodes: the outline above finds nothing for an enum
|
|
157
|
+
// and always did. Its signature stops at the `{`, so without this the one
|
|
158
|
+
// kind whose entire content is its member list answered with none of it.
|
|
159
|
+
// Uncapped like every other identity list — the members are the enum.
|
|
160
|
+
if (node.kind === "enum") {
|
|
161
|
+
const list = enumMembers(node, memberLimit);
|
|
162
|
+
if (list.length > 0) detail.members = list;
|
|
163
|
+
}
|
|
164
|
+
if (node.literals !== undefined && node.literals.length > 0) {
|
|
165
|
+
detail.literals = node.literals;
|
|
166
|
+
}
|
|
155
167
|
if (wantNeighbors) {
|
|
156
168
|
detail.dependsOn = refs(
|
|
157
169
|
graph,
|
|
@@ -222,6 +234,28 @@ function members(
|
|
|
222
234
|
return out;
|
|
223
235
|
}
|
|
224
236
|
|
|
237
|
+
/**
|
|
238
|
+
* An enum's members, owner-qualified so the name reads the way the code writes
|
|
239
|
+
* it, with the value each carries as its signature.
|
|
240
|
+
*
|
|
241
|
+
* The name is why this exists. `literals` answers what values the enum admits,
|
|
242
|
+
* but a caller writes `Colors.Red` and never `"red"`, so an enum the graph
|
|
243
|
+
* already held sent a caller that had named it to the file for the one fact it
|
|
244
|
+
* came for (#738).
|
|
245
|
+
*/
|
|
246
|
+
function enumMembers(
|
|
247
|
+
node: ITtscGraphNode,
|
|
248
|
+
limit: number,
|
|
249
|
+
): ITtscGraphDetails.IMember[] {
|
|
250
|
+
return (node.enumMembers ?? []).slice(0, limit).map((member) => ({
|
|
251
|
+
name: `${node.qualifiedName ?? node.name}.${member.name}`,
|
|
252
|
+
kind: "property",
|
|
253
|
+
...(member.value !== undefined
|
|
254
|
+
? { signature: `${member.name} = ${member.value}` }
|
|
255
|
+
: {}),
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
|
|
225
259
|
function objectLiteralMembers(
|
|
226
260
|
project: string,
|
|
227
261
|
span: Pick<ITtscGraphEvidence, "file" | "startLine" | "endLine">,
|
|
@@ -328,13 +362,11 @@ function refs(
|
|
|
328
362
|
if (evidence !== undefined) ref.evidence = evidence;
|
|
329
363
|
ranked.push({ ref, rank: refRank(ref, edge) });
|
|
330
364
|
}
|
|
365
|
+
// Ranked so a caller that does throttle (the tour) keeps the strongest refs,
|
|
366
|
+
// not the ones nearest the top of a file. Uncapped, `limit` is Infinity and
|
|
367
|
+
// the sort is just a stable order.
|
|
331
368
|
ranked.sort((a, b) => a.rank - b.rank);
|
|
332
|
-
|
|
333
|
-
for (const item of ranked) {
|
|
334
|
-
out.push(item.ref);
|
|
335
|
-
if (out.length >= limit) break;
|
|
336
|
-
}
|
|
337
|
-
return out;
|
|
369
|
+
return ranked.map((item) => item.ref).slice(0, limit);
|
|
338
370
|
}
|
|
339
371
|
|
|
340
372
|
const executionKinds = new Set([
|
|
@@ -375,17 +407,7 @@ function dependencyRefs(
|
|
|
375
407
|
rank: refRank(ref, edge),
|
|
376
408
|
});
|
|
377
409
|
}
|
|
378
|
-
ranked
|
|
379
|
-
const out: ITtscGraphDetails.IReference[] = [];
|
|
380
|
-
const seen = new Set<string>();
|
|
381
|
-
for (const item of ranked) {
|
|
382
|
-
const key = `${item.ref.relation}:${item.ref.id}`;
|
|
383
|
-
if (seen.has(key)) continue;
|
|
384
|
-
seen.add(key);
|
|
385
|
-
out.push(item.ref);
|
|
386
|
-
if (out.length >= limit) break;
|
|
387
|
-
}
|
|
388
|
-
return out;
|
|
410
|
+
return rankedRefs(ranked, limit);
|
|
389
411
|
}
|
|
390
412
|
|
|
391
413
|
function incomingDependencyRefs(
|
|
@@ -416,6 +438,14 @@ function incomingDependencyRefs(
|
|
|
416
438
|
rank: refRank(ref, edge),
|
|
417
439
|
});
|
|
418
440
|
}
|
|
441
|
+
return rankedRefs(ranked, limit);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/** Sort by rank, drop duplicate (relation, id) pairs, and cut to `limit`. */
|
|
445
|
+
function rankedRefs(
|
|
446
|
+
ranked: Array<{ ref: ITtscGraphDetails.IReference; rank: number }>,
|
|
447
|
+
limit: number,
|
|
448
|
+
): ITtscGraphDetails.IReference[] {
|
|
419
449
|
ranked.sort((a, b) => a.rank - b.rank);
|
|
420
450
|
const out: ITtscGraphDetails.IReference[] = [];
|
|
421
451
|
const seen = new Set<string>();
|
|
@@ -429,38 +459,26 @@ function incomingDependencyRefs(
|
|
|
429
459
|
return out;
|
|
430
460
|
}
|
|
431
461
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
function cleanLiteral(value: string | undefined): string | undefined {
|
|
444
|
-
const text = value?.replace(/\s+/g, " ").trim();
|
|
445
|
-
if (
|
|
446
|
-
text === undefined ||
|
|
447
|
-
text === "" ||
|
|
448
|
-
text.length > 40 ||
|
|
449
|
-
/^[{}()[\],.:;]+$/.test(text)
|
|
450
|
-
) {
|
|
451
|
-
return undefined;
|
|
452
|
-
}
|
|
453
|
-
return text;
|
|
462
|
+
/**
|
|
463
|
+
* 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
|
|
466
|
+
* compact slice of its own.
|
|
467
|
+
*/
|
|
468
|
+
function limitOf(value: number | undefined): number {
|
|
469
|
+
return value === undefined || !Number.isFinite(value)
|
|
470
|
+
? Infinity
|
|
471
|
+
: Math.max(1, Math.floor(value));
|
|
454
472
|
}
|
|
455
473
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
): number {
|
|
474
|
+
/**
|
|
475
|
+
* A fan-out list's cap: a small default, clamped to a ceiling. What names or
|
|
476
|
+
* uses a symbol grows with its popularity, not with the symbol, so the whole
|
|
477
|
+
* list is a trace/impact answer and details returns an orientation slice.
|
|
478
|
+
*/
|
|
479
|
+
function capOf(value: number | undefined, fallback: number, max: number): number {
|
|
462
480
|
const n = value === undefined || !Number.isFinite(value) ? fallback : value;
|
|
463
|
-
return Math.max(
|
|
481
|
+
return Math.max(1, Math.min(max, Math.floor(n)));
|
|
464
482
|
}
|
|
465
483
|
|
|
466
484
|
/**
|
|
@@ -611,6 +629,13 @@ export function docOf(
|
|
|
611
629
|
* The declaration signature: the head of the declaration up to and including
|
|
612
630
|
* the line that opens its body (`{`), or the single declaration line when there
|
|
613
631
|
* is no brace, capped so a wrapped signature cannot run away.
|
|
632
|
+
*
|
|
633
|
+
* It never runs past the declaration's own span. The stop used to be the brace,
|
|
634
|
+
* the trailing semicolon, or the line cap, and a declaration ending in none of
|
|
635
|
+
* them read its neighbors instead: an enum member ends in a comma, so `VIEW`
|
|
636
|
+
* came back as itself plus the two members after it and the closing brace. The
|
|
637
|
+
* span is the fact that says where the declaration ends, and it was already on
|
|
638
|
+
* the node.
|
|
614
639
|
*/
|
|
615
640
|
export function signatureOf(
|
|
616
641
|
project: string,
|
|
@@ -621,12 +646,12 @@ export function signatureOf(
|
|
|
621
646
|
evidence === undefined ? undefined : fileLines(project, evidence.file);
|
|
622
647
|
if (lines === undefined || evidence === undefined) return undefined;
|
|
623
648
|
const start = Math.max(0, evidence.startLine - 1);
|
|
649
|
+
const last =
|
|
650
|
+
evidence.endLine === undefined
|
|
651
|
+
? lines.length - 1
|
|
652
|
+
: Math.min(lines.length - 1, evidence.endLine - 1);
|
|
624
653
|
const out: string[] = [];
|
|
625
|
-
for (
|
|
626
|
-
let i = start;
|
|
627
|
-
i < lines.length && out.length < MAX_SIGNATURE_LINES;
|
|
628
|
-
i++
|
|
629
|
-
) {
|
|
654
|
+
for (let i = start; i <= last && out.length < MAX_SIGNATURE_LINES; i++) {
|
|
630
655
|
const line = lines[i];
|
|
631
656
|
if (line === undefined) break;
|
|
632
657
|
out.push(line);
|
|
@@ -169,13 +169,14 @@ export namespace ITtscGraphApplication {
|
|
|
169
169
|
* resolves to the type-checked program for the snapshot the call synced to,
|
|
170
170
|
* so opening a file it cites only returns a fact already in it.
|
|
171
171
|
*
|
|
172
|
-
* The audit is operation-aware. For the
|
|
173
|
-
* `
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
172
|
+
* The audit is operation-aware. For the walks from a named handle (`trace`,
|
|
173
|
+
* `overview`) it reports the result as the structure the graph holds,
|
|
174
|
+
* bounded where `truncated` says. For `details` it reports the two halves of
|
|
175
|
+
* a resolved symbol: its own shape returned whole, its fan-out returned as a
|
|
176
|
+
* slice with `trace` for the rest. For the ranked operations (`lookup`,
|
|
177
|
+
* `entrypoints`, `tour`) it adds that the selection is heuristic — matched,
|
|
178
|
+
* scored, ranked, and limited against the question — so the facts are
|
|
179
|
+
* verified but the shortlist's coverage is the caller's to judge.
|
|
179
180
|
*/
|
|
180
181
|
audit: string;
|
|
181
182
|
|
|
@@ -49,24 +49,26 @@ export namespace ITtscGraphDetails {
|
|
|
49
49
|
neighbors?: boolean;
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
52
|
+
* Dependencies and dependents per side when `neighbors:true`. A small
|
|
53
|
+
* orientation slice by default; what uses a symbol grows with its
|
|
54
|
+
* popularity, so `trace` answers the whole "who uses this".
|
|
54
55
|
*
|
|
55
56
|
* @default 2
|
|
56
57
|
*/
|
|
57
58
|
neighborLimit?: number;
|
|
58
59
|
|
|
59
60
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
61
|
+
* Owned members for a container or object literal. The complete outline by
|
|
62
|
+
* default — a class's members and an enum's are the symbol itself, so they
|
|
63
|
+
* are not sampled. Pass a number to cap.
|
|
63
64
|
*/
|
|
64
65
|
memberLimit?: number;
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
|
-
*
|
|
68
|
+
* Direct execution and type references per group. A small orientation slice
|
|
69
|
+
* by default; `trace` follows the whole fan-out.
|
|
68
70
|
*
|
|
69
|
-
* @default
|
|
71
|
+
* @default 2
|
|
70
72
|
*/
|
|
71
73
|
dependencyLimit?: number;
|
|
72
74
|
|
|
@@ -145,7 +147,15 @@ export namespace ITtscGraphDetails {
|
|
|
145
147
|
/** Concrete nodes that implement or override this interface/base member. */
|
|
146
148
|
implementedBy?: IReference[];
|
|
147
149
|
|
|
148
|
-
/**
|
|
150
|
+
/**
|
|
151
|
+
* The complete value set a type alias or enum admits, in TypeScript source
|
|
152
|
+
* form (`"a"`, `1`, `true`, `null`) — the checker's resolved union members,
|
|
153
|
+
* not the quoted tokens that happened to fit in `signature`.
|
|
154
|
+
*
|
|
155
|
+
* Absent when the type has no enumerable value set. A `signature` is capped
|
|
156
|
+
* at the declaration head, so for a union or enum written across several
|
|
157
|
+
* lines this is the field that carries the members.
|
|
158
|
+
*/
|
|
149
159
|
literals?: string[];
|
|
150
160
|
|
|
151
161
|
/**
|
|
@@ -63,6 +63,32 @@ export interface ITtscGraphNode {
|
|
|
63
63
|
/** Declaration modifiers, when the declaration pass recorded any. */
|
|
64
64
|
modifiers?: TtscGraphNodeModifier[];
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* The complete value set of a type alias or enum whose declared type the
|
|
68
|
+
* checker resolved to literals, each in TypeScript source form (`"a"`, `1`,
|
|
69
|
+
* `true`, `null`).
|
|
70
|
+
*
|
|
71
|
+
* Present only when every constituent is enumerable, so the list is the whole
|
|
72
|
+
* type and never a sample of it: `type T = Kind | string` admits values no
|
|
73
|
+
* list can name and carries none. It is resolved from the type, not read off
|
|
74
|
+
* the declaration, so indirection (`type I = Kind | 'f'`) is followed and the
|
|
75
|
+
* answer does not depend on how the declaration is wrapped.
|
|
76
|
+
*/
|
|
77
|
+
literals?: string[];
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* What an enum declares, in checker order: the name a caller writes and the
|
|
81
|
+
* value it carries. Absent on every other kind.
|
|
82
|
+
*
|
|
83
|
+
* `literals` says which values the enum admits, which is what a serializer
|
|
84
|
+
* asks. The code says `Colors.Red`, so the names are the other half, and
|
|
85
|
+
* without them a caller that had already named the enum still had to open the
|
|
86
|
+
* file to learn what to type. The members are not nodes — `Colors.Red` is a
|
|
87
|
+
* string a grep finds exactly — so this fills in the node the graph already
|
|
88
|
+
* holds instead of minting one per member.
|
|
89
|
+
*/
|
|
90
|
+
enumMembers?: ITtscGraphNode.IEnumMember[];
|
|
91
|
+
|
|
66
92
|
/**
|
|
67
93
|
* Decorators written on this declaration, in source order: raw facts
|
|
68
94
|
* (`@Controller`, `@Get`) a consumer interprets without re-parsing source.
|
|
@@ -78,3 +104,17 @@ export interface ITtscGraphNode {
|
|
|
78
104
|
*/
|
|
79
105
|
implementation?: ITtscGraphEvidence;
|
|
80
106
|
}
|
|
107
|
+
export namespace ITtscGraphNode {
|
|
108
|
+
/** One member of an enum: the name a caller writes and the value it carries. */
|
|
109
|
+
export interface IEnumMember {
|
|
110
|
+
/** The member's own name, unqualified (`Red` on `Colors.Red`). */
|
|
111
|
+
name: string;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The value it carries, in TypeScript source form (`"red"`, `1`). Absent
|
|
115
|
+
* for a computed member the checker could not fold to a constant; the name
|
|
116
|
+
* still stands.
|
|
117
|
+
*/
|
|
118
|
+
value?: string;
|
|
119
|
+
}
|
|
120
|
+
}
|