@principal-ai/principal-view-react 0.16.45 → 0.16.46

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,84 @@
1
+ /**
2
+ * Tokenize a formatted TypeScript declaration string into SubsystemDeclToken[]
3
+ * using highlight.js.
4
+ *
5
+ * highlight.js produces HTML with `<span class="hljs-...">` wrappers. This
6
+ * module parses that output into our token format so the renderer stays
7
+ * language-agnostic.
8
+ */
9
+ import hljs from 'highlight.js/lib/core';
10
+ import typescript from 'highlight.js/lib/languages/typescript';
11
+ // Register once — safe to call multiple times.
12
+ try {
13
+ hljs.registerLanguage('typescript', typescript);
14
+ }
15
+ catch {
16
+ // Already registered.
17
+ }
18
+ // hljs class → our token kind
19
+ const CLASS_MAP = {
20
+ 'hljs-keyword': 'keyword',
21
+ 'hljs-title': 'name',
22
+ 'hljs-title.function_': 'name',
23
+ 'hljs-params': 'member',
24
+ 'hljs-type': 'type',
25
+ 'hljs-built_in': 'type',
26
+ 'hljs-string': 'string',
27
+ 'hljs-number': 'string',
28
+ 'hljs-comment': 'punctuation',
29
+ };
30
+ /**
31
+ * Tokenize a formatted TypeScript string into SubsystemDeclToken[].
32
+ * The input should already be formatted by Prettier (or be valid TS).
33
+ */
34
+ export function tokenizeFormatted(code) {
35
+ const result = hljs.highlight(code, { language: 'typescript' });
36
+ return parseHighlightedHtml(result.value);
37
+ }
38
+ // ---------------------------------------------------------------------------
39
+ // HTML parser — walks the hljs output and extracts tokens
40
+ // ---------------------------------------------------------------------------
41
+ function unescapeHtml(text) {
42
+ return text
43
+ .replace(/&quot;/g, '"')
44
+ .replace(/&lt;/g, '<')
45
+ .replace(/&gt;/g, '>')
46
+ .replace(/&amp;/g, '&')
47
+ .replace(/&#39;/g, "'");
48
+ }
49
+ function parseHighlightedHtml(html) {
50
+ const tokens = [];
51
+ // Regex matches either `<span class="hljs-...">`, `</span>`, or text content.
52
+ const re = /<span class="([^"]+)">|<\/span>|[^<]+/g;
53
+ const classStack = [];
54
+ let match;
55
+ while ((match = re.exec(html)) !== null) {
56
+ const chunk = match[0];
57
+ if (chunk.startsWith('<span')) {
58
+ // Opening tag — push class onto stack.
59
+ classStack.push(match[1]);
60
+ }
61
+ else if (chunk === '</span>') {
62
+ // Closing tag — pop class.
63
+ classStack.pop();
64
+ }
65
+ else {
66
+ // Text content — emit tokens for each line segment.
67
+ const currentClass = classStack[classStack.length - 1] ?? '';
68
+ const kind = CLASS_MAP[currentClass] ?? 'punctuation';
69
+ const text = chunk;
70
+ // Split on newlines so each line becomes its own token set.
71
+ const lines = text.split('\n');
72
+ for (let i = 0; i < lines.length; i++) {
73
+ if (i > 0) {
74
+ tokens.push({ text: '', kind: 'newline' });
75
+ }
76
+ if (lines[i]) {
77
+ tokens.push({ text: unescapeHtml(lines[i]), kind });
78
+ }
79
+ }
80
+ }
81
+ }
82
+ return tokens;
83
+ }
84
+ //# sourceMappingURL=tokenizeFormatted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenizeFormatted.js","sourceRoot":"","sources":["../../src/subsystem/tokenizeFormatted.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@principal-ai/principal-view-react",
3
- "version": "0.16.45",
3
+ "version": "0.16.46",
4
4
  "description": "React components for graph-based principal view framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,13 +14,14 @@
14
14
  "build-storybook": "storybook build"
15
15
  },
16
16
  "dependencies": {
17
+ "@pierre/trees": "1.0.0-beta.6",
17
18
  "@xyflow/react": "^12.11.3",
18
19
  "elkjs": "^0.12.0",
19
- "@pierre/trees": "1.0.0-beta.6",
20
20
  "hast-util-sanitize": "^5.0.2",
21
21
  "highlight.js": "^11.11.1",
22
22
  "js-yaml": "4.1.1",
23
23
  "lucide-react": "0.554.0",
24
+ "prettier": "3",
24
25
  "react-markdown": "^10.1.0",
25
26
  "react-zoom-pan-pinch": "^3.7.0",
26
27
  "rehype-highlight": "^7.0.2",
@@ -0,0 +1,290 @@
1
+ import React from 'react';
2
+ import '@xyflow/react/dist/style.css';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
+ import { ComponentDeclaration } from '../subsystem/ComponentDeclaration';
6
+ import type { SubsystemComponent } from '../subsystem/model';
7
+ import type { GraphifyComponentDetail } from '../graphify';
8
+
9
+ const meta = {
10
+ title: 'Subsystem/Component Declaration Audit',
11
+ component: ComponentDeclaration,
12
+ parameters: { layout: 'padded' },
13
+ tags: ['autodocs'],
14
+ argTypes: {
15
+ constrained: { control: 'boolean', description: 'Toggle 80ch max-width wrapping' },
16
+ },
17
+ args: {
18
+ constrained: true,
19
+ },
20
+ decorators: [
21
+ (Story, ctx) => (
22
+ <ThemeProvider theme={defaultEditorTheme}>
23
+ <div style={{ maxWidth: ctx.args.constrained ? '80ch' : 'none', margin: '0 auto' }}>
24
+ <Story />
25
+ </div>
26
+ </ThemeProvider>
27
+ ),
28
+ ],
29
+ } satisfies Meta<typeof ComponentDeclaration>;
30
+ export default meta;
31
+ type Story = StoryObj<typeof ComponentDeclaration>;
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // All cases — one SubsystemComponent per shape, rendered stacked
35
+ // ---------------------------------------------------------------------------
36
+
37
+ const cases: { label: string; component: SubsystemComponent }[] = [
38
+ {
39
+ label: 'function — no params',
40
+ component: {
41
+ id: 'fn-void',
42
+ name: 'flush',
43
+ kind: 'function',
44
+ file: 'src/event-processing/sink.ts',
45
+ purl: 'pkg:github/principal-ai/agent-monitoring',
46
+ symbol: 'flush',
47
+ detail: {
48
+ kind: 'function',
49
+ parameters: [],
50
+ } satisfies GraphifyComponentDetail,
51
+ },
52
+ },
53
+ {
54
+ label: 'function — single param',
55
+ component: {
56
+ id: 'fn-one',
57
+ name: 'normalize',
58
+ kind: 'function',
59
+ file: 'src/session/SessionReader.ts',
60
+ purl: 'pkg:github/principal-ai/agent-monitoring',
61
+ symbol: 'SessionReader.normalize',
62
+ detail: {
63
+ kind: 'function',
64
+ parameters: [{ name: 'session', type: 'SessionRecord' }],
65
+ returnType: 'SessionEvent[]',
66
+ } satisfies GraphifyComponentDetail,
67
+ },
68
+ },
69
+ {
70
+ label: 'function — two params',
71
+ component: {
72
+ id: 'fn-two',
73
+ name: 'normalizeSession',
74
+ kind: 'function',
75
+ file: 'src/event-processing/normalize.ts',
76
+ purl: 'pkg:github/principal-ai/agent-monitoring',
77
+ symbol: 'normalizeSession',
78
+ detail: {
79
+ kind: 'function',
80
+ parameters: [
81
+ { name: 'session', type: 'SessionRecord' },
82
+ { name: 'limit', type: 'number' },
83
+ ],
84
+ returnType: 'SessionEvent[]',
85
+ } satisfies GraphifyComponentDetail,
86
+ },
87
+ },
88
+ {
89
+ label: 'function — rich params (positional, union, callback, generic return)',
90
+ component: {
91
+ id: 'fn-rich',
92
+ name: 'mergeSessions',
93
+ kind: 'function',
94
+ file: 'src/session/merge.ts',
95
+ purl: 'pkg:github/principal-ai/agent-monitoring',
96
+ symbol: 'mergeSessions',
97
+ detail: {
98
+ kind: 'function',
99
+ parameters: [
100
+ { name: 'sessions', type: 'SessionRecord[]' },
101
+ { type: 'MergeOptions' },
102
+ { name: 'strategy', type: "'append' | 'replace' | 'skip'" },
103
+ { name: 'onConflict', type: '((a: SessionRecord, b: SessionRecord) => SessionRecord)' },
104
+ ],
105
+ returnType: 'Promise<Map<string, SessionEvent[]>>',
106
+ } satisfies GraphifyComponentDetail,
107
+ },
108
+ },
109
+ {
110
+ label: 'class — no body',
111
+ component: {
112
+ id: 'class-empty',
113
+ name: 'EmptyClass',
114
+ kind: 'class',
115
+ file: 'src/empty.ts',
116
+ purl: 'pkg:github/principal-ai/agent-monitoring',
117
+ symbol: 'EmptyClass',
118
+ detail: {
119
+ kind: 'class',
120
+ } satisfies GraphifyComponentDetail,
121
+ },
122
+ },
123
+ {
124
+ label: 'class — properties only',
125
+ component: {
126
+ id: 'class-props',
127
+ name: 'Config',
128
+ kind: 'class',
129
+ file: 'src/config.ts',
130
+ purl: 'pkg:github/principal-ai/agent-monitoring',
131
+ symbol: 'Config',
132
+ detail: {
133
+ kind: 'class',
134
+ properties: [
135
+ { name: 'host', type: 'string' },
136
+ { name: 'port', type: 'number' },
137
+ { name: 'tls', type: 'boolean' },
138
+ ],
139
+ } satisfies GraphifyComponentDetail,
140
+ },
141
+ },
142
+ {
143
+ label: 'class — methods + properties + extends + implements',
144
+ component: {
145
+ id: 'class-rich',
146
+ name: 'EventProcessor',
147
+ kind: 'class',
148
+ file: 'src/event-processing/EventProcessor.ts',
149
+ purl: 'pkg:github/principal-ai/agent-monitoring',
150
+ symbol: 'EventProcessor',
151
+ detail: {
152
+ kind: 'class',
153
+ methods: [
154
+ { name: 'process', parameters: [{ type: 'RawEvent' }, { type: 'ProcessingOptions' }], returnType: 'ProcessedEvent' },
155
+ { name: 'batch', parameters: [{ type: 'RawEvent[]' }], returnType: 'Promise<ProcessedEvent[]>' },
156
+ { name: 'onError', parameters: [{ type: 'Error' }] },
157
+ { name: 'dispose' },
158
+ ],
159
+ properties: [
160
+ { name: 'queue', type: 'RawEvent[]' },
161
+ { name: 'options', type: 'Required<ProcessingOptions>' },
162
+ { name: 'retryLimit', type: 'number' },
163
+ ],
164
+ extends: ['BaseProcessor'],
165
+ implements: ['Disposable', 'EventEmitterLike'],
166
+ } satisfies GraphifyComponentDetail,
167
+ },
168
+ },
169
+ {
170
+ label: 'type — properties',
171
+ component: {
172
+ id: 'type-props',
173
+ name: 'SessionRecord',
174
+ kind: 'type',
175
+ file: 'src/session/transcript.ts',
176
+ purl: 'pkg:github/principal-ai/agent-monitoring',
177
+ symbol: 'SessionRecord',
178
+ detail: {
179
+ kind: 'type',
180
+ properties: [
181
+ { name: 'id', type: 'string' },
182
+ { name: 'admittedSeq', type: 'number' },
183
+ ],
184
+ } satisfies GraphifyComponentDetail,
185
+ },
186
+ },
187
+ {
188
+ label: 'type — no properties',
189
+ component: {
190
+ id: 'type-empty',
191
+ name: 'BrandedId',
192
+ kind: 'type',
193
+ file: 'src/types.ts',
194
+ purl: 'pkg:github/principal-ai/agent-monitoring',
195
+ symbol: 'BrandedId',
196
+ detail: {
197
+ kind: 'type',
198
+ } satisfies GraphifyComponentDetail,
199
+ },
200
+ },
201
+ {
202
+ label: 'module — imports + exports',
203
+ component: {
204
+ id: 'mod-full',
205
+ name: 'index',
206
+ kind: 'module',
207
+ file: 'src/index.ts',
208
+ purl: 'pkg:github/principal-ai/agent-monitoring',
209
+ symbol: 'index',
210
+ detail: {
211
+ kind: 'module',
212
+ imports: [
213
+ { name: './session/SessionReader' },
214
+ { name: './event-processing/EventProcessor' },
215
+ ],
216
+ exports: ['SessionReader', 'EventProcessor'],
217
+ symbols: ['SessionReader', 'EventProcessor', 'normalizeSession'],
218
+ } satisfies GraphifyComponentDetail,
219
+ },
220
+ },
221
+ {
222
+ label: 'module — no detail (fallback)',
223
+ component: {
224
+ id: 'mod-plain',
225
+ name: 'utils',
226
+ kind: 'module',
227
+ file: 'src/utils.ts',
228
+ purl: 'pkg:github/principal-ai/agent-monitoring',
229
+ symbol: 'utils',
230
+ },
231
+ },
232
+ {
233
+ label: 'external',
234
+ component: {
235
+ id: 'ext',
236
+ name: 'trail-viewer',
237
+ kind: 'external',
238
+ file: '',
239
+ purl: 'pkg:npm/@principal-ai/trail-viewer',
240
+ symbol: '',
241
+ detail: {
242
+ kind: 'external',
243
+ label: 'pkg:npm/@principal-ai/trail-viewer',
244
+ } satisfies GraphifyComponentDetail,
245
+ },
246
+ },
247
+ {
248
+ label: 'function — no symbol (uses name fallback)',
249
+ component: {
250
+ id: 'fn-no-symbol',
251
+ name: 'anonymousHelper',
252
+ kind: 'function',
253
+ file: 'src/helpers.ts',
254
+ purl: 'pkg:github/principal-ai/agent-monitoring',
255
+ detail: {
256
+ kind: 'function',
257
+ parameters: [{ name: 'input', type: 'string' }],
258
+ returnType: 'void',
259
+ } satisfies GraphifyComponentDetail,
260
+ },
261
+ },
262
+ ];
263
+
264
+ // ---------------------------------------------------------------------------
265
+ // Story — all cases stacked
266
+ // ---------------------------------------------------------------------------
267
+
268
+ export const AllCases: StoryObj<{ constrained: boolean }> = {
269
+ render: ({ constrained }) => (
270
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
271
+ {cases.map((c) => (
272
+ <div key={c.label}>
273
+ <div
274
+ style={{
275
+ fontFamily: 'monospace',
276
+ fontSize: 11,
277
+ color: '#888',
278
+ marginBottom: 4,
279
+ textTransform: 'uppercase',
280
+ letterSpacing: '0.05em',
281
+ }}
282
+ >
283
+ {c.label}
284
+ </div>
285
+ <ComponentDeclaration component={c.component} maxWidth={constrained ? '80ch' : undefined} />
286
+ </div>
287
+ ))}
288
+ </div>
289
+ ),
290
+ };