@principal-ai/subsystems-react 0.33.0 → 0.34.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.
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Referenced symbols inside a component's declaration.
3
+ *
4
+ * A declaration mentions other symbols — parameter/return types, property
5
+ * types, `extends`/`implements`, and related callables (`callers`/`callees`,
6
+ * `references`/`usedBy`). This module flattens the structured declaration into
7
+ * a deduped, lookup-friendly list so the panel can offer a graphify inspection
8
+ * per name, and defines the payload graphify returns for one.
9
+ *
10
+ * Slice 1 is display-only: the inspection payload is produced by the host (or,
11
+ * in stories, by a fixture). Nothing here reads the graph.
12
+ */
13
+
14
+ import type { GraphifyComponentDetail, GraphifyReferenceInfo } from '../graphify';
15
+
16
+ /** One symbol a declaration references, normalized for lookup. */
17
+ export interface DeclarationSymbolRef {
18
+ /** Referenced name as written (e.g. `SessionRecord`), no call/`()` decoration. */
19
+ name: string;
20
+ /** Graphify node id when the backing reference carried one. */
21
+ nodeId?: string;
22
+ /** Reference context (`parameter_type`, `return_type`, `field`, `caller`, …). */
23
+ context?: string;
24
+ /** `L<line>` of the reference site, when known. */
25
+ sourceLocation?: string;
26
+ }
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Graphify inspection payload
30
+ // ---------------------------------------------------------------------------
31
+
32
+ /**
33
+ * How a symbol resolved against the cached graphify graph. Name-first, so it
34
+ * mirrors the type-ref resolver (`graphify/resolve.ts`) rather than component
35
+ * anchoring — there is no claimed file to fall back to.
36
+ */
37
+ export type SymbolInspectionResolution =
38
+ /** Exactly one definition node for the name. */
39
+ | 'resolved'
40
+ /** Referenced, but no definition in this corpus (external / ambient type). */
41
+ | 'unresolved'
42
+ /** Multiple same-label definitions. */
43
+ | 'ambiguous'
44
+ /** The name isn't in the graph at all. */
45
+ | 'missing';
46
+
47
+ export interface SymbolInspectionNode {
48
+ nodeId: string;
49
+ label: string;
50
+ /** Repo-root-relative source path. */
51
+ sourceFile?: string;
52
+ /** `L<line>` of the definition. */
53
+ sourceLocation?: string;
54
+ fileType?: string;
55
+ community?: string;
56
+ }
57
+
58
+ export interface SymbolInspectionCandidate {
59
+ nodeId: string;
60
+ label: string;
61
+ sourceFile?: string;
62
+ }
63
+
64
+ /**
65
+ * The actual source declaration, read from the checkout at the node's anchor.
66
+ * Used when graphify resolved a location but couldn't reconstruct the shape.
67
+ */
68
+ export interface SymbolInspectionSource {
69
+ file: string;
70
+ startLine?: number;
71
+ /** Declaration text as read from source. */
72
+ text: string;
73
+ }
74
+
75
+ /**
76
+ * What graphify has on one symbol. The useful payload is `declaration` — the
77
+ * symbol's declaration shape, rebuilt from graph edges — with `source` as the
78
+ * fallback when graphify knows where the symbol is but not what it is.
79
+ * `resolution` and `candidates` explain a miss; the rest of the graph's
80
+ * inference bookkeeping is deliberately not part of this payload.
81
+ */
82
+ export interface SymbolInspection {
83
+ symbol: string;
84
+ purl?: string;
85
+ resolution: SymbolInspectionResolution;
86
+ node?: SymbolInspectionNode;
87
+ /** The symbol's declaration, when graphify could reconstruct it. */
88
+ declaration?: GraphifyComponentDetail;
89
+ /** The declaration as read from source, when only the location is known. */
90
+ source?: SymbolInspectionSource;
91
+ candidates?: SymbolInspectionCandidate[];
92
+ /** Human-readable reason when there's neither a declaration nor source. */
93
+ reason?: string;
94
+ }
95
+
96
+ /**
97
+ * True when there's no declaration to show — either graphify couldn't resolve
98
+ * the symbol or couldn't reconstruct its shape. The case where offering
99
+ * "add to model + agent" is worthwhile.
100
+ */
101
+ export function isLimitedInspection(
102
+ info: SymbolInspection | null | undefined,
103
+ ): boolean {
104
+ return !info?.declaration;
105
+ }
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Extraction
109
+ // ---------------------------------------------------------------------------
110
+
111
+ /** Names that carry no lookup value — primitives and non-identifiers. */
112
+ const PRIMITIVES: ReadonlySet<string> = new Set([
113
+ 'string',
114
+ 'number',
115
+ 'boolean',
116
+ 'bigint',
117
+ 'symbol',
118
+ 'void',
119
+ 'null',
120
+ 'undefined',
121
+ 'never',
122
+ 'any',
123
+ 'unknown',
124
+ 'object',
125
+ 'true',
126
+ 'false',
127
+ 'self',
128
+ 'None',
129
+ 'True',
130
+ 'False',
131
+ 'bool',
132
+ 'int',
133
+ 'float',
134
+ 'str',
135
+ 'bytes',
136
+ 'list',
137
+ 'dict',
138
+ 'tuple',
139
+ 'set',
140
+ ]);
141
+
142
+ /** A bare (optionally dotted) identifier we can look up by name. */
143
+ function isSimpleSymbolName(type: string | undefined | null): boolean {
144
+ if (!type) return false;
145
+ const t = type.trim();
146
+ if (!/^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/.test(t)) return false;
147
+ return !PRIMITIVES.has(t);
148
+ }
149
+
150
+ /**
151
+ * Normalize a callable/related label (`normalize()`, `.get`, `capture-session`)
152
+ * to a name. Labels are freer than type expressions — kebab-case is common.
153
+ */
154
+ function normalizeRelatedName(raw: string | undefined): string | null {
155
+ if (!raw) return null;
156
+ const t = raw.trim().replace(/^\./, '').replace(/\(\)$/, '');
157
+ if (!/^[A-Za-z_$][\w$.-]*$/.test(t)) return null;
158
+ return PRIMITIVES.has(t) ? null : t;
159
+ }
160
+
161
+ /**
162
+ * Flatten a declaration into the set of symbols it references, deduped by name.
163
+ * Entries backed by a `nodeId` win over bare-name entries.
164
+ */
165
+ export function extractDeclarationSymbolRefs(
166
+ declaration: GraphifyComponentDetail | undefined,
167
+ ): DeclarationSymbolRef[] {
168
+ if (!declaration) return [];
169
+
170
+ const byName = new Map<string, DeclarationSymbolRef>();
171
+ const add = (
172
+ name: string | null | undefined,
173
+ opts: { ref?: GraphifyReferenceInfo; context?: string; sourceLocation?: string } = {},
174
+ ) => {
175
+ if (!name) return;
176
+ const existing = byName.get(name);
177
+ const nodeId = opts.ref?.nodeId;
178
+ const next: DeclarationSymbolRef = {
179
+ name,
180
+ nodeId: nodeId ?? existing?.nodeId,
181
+ context: opts.ref?.context ?? opts.context ?? existing?.context,
182
+ sourceLocation:
183
+ opts.ref?.source_location ?? opts.sourceLocation ?? existing?.sourceLocation,
184
+ };
185
+ // Prefer the richer entry when we already have one with a nodeId.
186
+ if (existing?.nodeId && !nodeId) return;
187
+ byName.set(name, next);
188
+ };
189
+
190
+ const addType = (
191
+ type: string | undefined,
192
+ ref?: GraphifyReferenceInfo,
193
+ context?: string,
194
+ ) => {
195
+ if (!isSimpleSymbolName(type)) return;
196
+ add(type!.trim(), { ref, context });
197
+ };
198
+
199
+ const addCall = (
200
+ call: { name?: string; source_location?: string } | undefined,
201
+ context: string,
202
+ ) => {
203
+ if (!call) return;
204
+ add(normalizeRelatedName(call.name), {
205
+ context,
206
+ sourceLocation: call.source_location,
207
+ });
208
+ };
209
+
210
+ switch (declaration.kind) {
211
+ case 'function':
212
+ for (const p of declaration.parameters ?? []) addType(p.type, p.ref, 'parameter_type');
213
+ addType(declaration.returnType, declaration.returnTypeRef, 'return_type');
214
+ for (const c of declaration.callers ?? []) addCall(c, 'caller');
215
+ for (const c of declaration.callees ?? []) addCall(c, 'callee');
216
+ break;
217
+ case 'method':
218
+ for (const p of declaration.parameters ?? []) addType(p.type, p.ref, 'parameter_type');
219
+ addType(declaration.returnType, undefined, 'return_type');
220
+ break;
221
+ case 'class':
222
+ for (const m of declaration.methods ?? []) {
223
+ for (const p of m.parameters ?? []) addType(p.type, p.ref, 'parameter_type');
224
+ addType(m.returnType, m.returnTypeRef, 'return_type');
225
+ }
226
+ for (const p of declaration.properties ?? []) {
227
+ addType(p.type, p.typeRef, 'field');
228
+ }
229
+ for (const name of declaration.extends ?? []) addType(name, undefined, 'extends');
230
+ for (const name of declaration.implements ?? []) addType(name, undefined, 'implements');
231
+ for (const r of declaration.references ?? []) {
232
+ add(normalizeRelatedName(r.name), { ref: r, context: r.context ?? 'references' });
233
+ }
234
+ break;
235
+ case 'type':
236
+ for (const p of declaration.properties ?? []) {
237
+ addType(p.type, p.typeRef, 'field');
238
+ }
239
+ for (const r of declaration.usedBy ?? []) {
240
+ add(normalizeRelatedName(r.name), { ref: r, context: r.context ?? 'usedBy' });
241
+ }
242
+ for (const name of declaration.implementors ?? []) addType(name, undefined, 'implementor');
243
+ addType(declaration.aliasOf, undefined, 'alias');
244
+ for (const alt of declaration.unionOf ?? []) addType(alt, undefined, 'union');
245
+ break;
246
+ case 'store':
247
+ for (const p of declaration.properties ?? []) {
248
+ addType(p.type, p.typeRef, 'field');
249
+ }
250
+ break;
251
+ default:
252
+ break;
253
+ }
254
+
255
+ return [...byName.values()];
256
+ }