@principal-ai/principal-view-react 0.16.35 → 0.16.37
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/dist/graphify/consolidated.d.ts +17 -3
- package/dist/graphify/consolidated.d.ts.map +1 -1
- package/dist/graphify/index.d.ts +2 -0
- package/dist/graphify/index.d.ts.map +1 -1
- package/dist/graphify/index.js +1 -1
- package/dist/graphify/index.js.map +1 -1
- package/dist/graphify/resolve.d.ts +48 -0
- package/dist/graphify/resolve.d.ts.map +1 -0
- package/dist/graphify/resolve.js +83 -0
- package/dist/graphify/resolve.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/subsystem/ComponentDetail.d.ts +16 -7
- package/dist/subsystem/ComponentDetail.d.ts.map +1 -1
- package/dist/subsystem/ComponentDetail.js +124 -82
- package/dist/subsystem/ComponentDetail.js.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
- package/dist/subsystem/SubsystemComponentGraph.js +47 -10
- package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
- package/dist/subsystem/model.d.ts +14 -0
- package/dist/subsystem/model.d.ts.map +1 -1
- package/dist/subsystem/model.js +26 -1
- package/dist/subsystem/model.js.map +1 -1
- package/dist/subsystem/paths.d.ts +38 -0
- package/dist/subsystem/paths.d.ts.map +1 -0
- package/dist/subsystem/paths.js +52 -0
- package/dist/subsystem/paths.js.map +1 -0
- package/package.json +1 -1
- package/src/graphify/consolidated.ts +17 -3
- package/src/graphify/index.ts +9 -0
- package/src/graphify/resolve.test.ts +89 -0
- package/src/graphify/resolve.ts +115 -0
- package/src/index.ts +19 -0
- package/src/stories/SubsystemComponentGraph.stories.tsx +331 -11
- package/src/subsystem/ComponentDetail.tsx +355 -156
- package/src/subsystem/SubsystemComponentGraph.tsx +76 -15
- package/src/subsystem/model.test.ts +11 -0
- package/src/subsystem/model.ts +25 -1
- package/src/subsystem/paths.test.ts +62 -0
- package/src/subsystem/paths.ts +69 -0
|
@@ -1,187 +1,386 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ComponentDetail — selection detail panel for a subsystem component
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* ComponentDetail — selection detail panel for a subsystem component, rendered
|
|
3
|
+
* as it would appear in code: a file-path comment + doc comment, then the kind's
|
|
4
|
+
* declaration (`class X extends Y { ... }`, `function f(): T`, ...) with its
|
|
5
|
+
* members as signatures. Graphify relationship drill-downs appear as trailing
|
|
6
|
+
* comments. File content lives in the bottom FileDrawer, not here.
|
|
5
7
|
*/
|
|
6
8
|
|
|
7
|
-
import type
|
|
9
|
+
import { Fragment, type ReactNode } from 'react';
|
|
8
10
|
import { useTheme } from '@principal-ade/industry-theme';
|
|
9
11
|
import {
|
|
10
12
|
KIND_COLOR,
|
|
11
13
|
deriveNameFromSymbol,
|
|
14
|
+
formatPurl,
|
|
12
15
|
type SubsystemComponent,
|
|
13
16
|
} from './model';
|
|
14
|
-
import type { GraphifyComponentDetail } from '../graphify';
|
|
15
17
|
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const rows: Array<[string, string]> = [];
|
|
24
|
-
if (component.symbol) rows.push(['Symbol', component.symbol]);
|
|
25
|
-
if (component.file) rows.push(['File', component.file]);
|
|
26
|
-
if (component.purpose) rows.push(['Purpose', component.purpose]);
|
|
27
|
-
rows.push(['PURL', component.purl]);
|
|
18
|
+
/** Shared affordance for clickable text pieces. */
|
|
19
|
+
const clickableStyle = {
|
|
20
|
+
cursor: 'pointer',
|
|
21
|
+
textDecorationLine: 'underline',
|
|
22
|
+
textDecorationStyle: 'dotted',
|
|
23
|
+
textUnderlineOffset: 2,
|
|
24
|
+
} as const;
|
|
28
25
|
|
|
26
|
+
/** Clickable detail-panel piece — dotted underline signals interactivity. */
|
|
27
|
+
function DetailLink({ children, onClick }: { children: ReactNode; onClick?: () => void }) {
|
|
28
|
+
if (!onClick) return <>{children}</>;
|
|
29
29
|
return (
|
|
30
|
-
<
|
|
30
|
+
<span
|
|
31
|
+
onClick={(e) => {
|
|
32
|
+
e.stopPropagation();
|
|
33
|
+
onClick();
|
|
34
|
+
}}
|
|
31
35
|
style={{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
cursor: 'pointer',
|
|
37
|
+
textDecorationLine: 'underline',
|
|
38
|
+
textDecorationStyle: 'dotted',
|
|
39
|
+
textUnderlineOffset: 2,
|
|
36
40
|
}}
|
|
37
41
|
>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
display: 'flex',
|
|
41
|
-
alignItems: 'center',
|
|
42
|
-
gap: 8,
|
|
43
|
-
fontSize: theme.fontSizes[1],
|
|
44
|
-
fontWeight: 600,
|
|
45
|
-
marginBottom: 6,
|
|
46
|
-
}}
|
|
47
|
-
>
|
|
48
|
-
<span style={{ color }}>{displayName}</span>
|
|
49
|
-
<span
|
|
50
|
-
style={{
|
|
51
|
-
fontSize: theme.fontSizes[0] * 0.8,
|
|
52
|
-
fontFamily: theme.fonts.monospace,
|
|
53
|
-
textTransform: 'uppercase',
|
|
54
|
-
color,
|
|
55
|
-
}}
|
|
56
|
-
>
|
|
57
|
-
{component.kind}
|
|
58
|
-
</span>
|
|
59
|
-
</div>
|
|
60
|
-
{rows.map(([k, v]) => (
|
|
61
|
-
<div
|
|
62
|
-
key={k}
|
|
63
|
-
style={{ display: 'flex', gap: 8, fontSize: theme.fontSizes[0], lineHeight: 1.5 }}
|
|
64
|
-
>
|
|
65
|
-
<span
|
|
66
|
-
style={{
|
|
67
|
-
width: 64,
|
|
68
|
-
flexShrink: 0,
|
|
69
|
-
color: muted,
|
|
70
|
-
fontFamily: theme.fonts.monospace,
|
|
71
|
-
textTransform: 'uppercase',
|
|
72
|
-
fontSize: theme.fontSizes[0] * 0.8,
|
|
73
|
-
}}
|
|
74
|
-
>
|
|
75
|
-
{k}
|
|
76
|
-
</span>
|
|
77
|
-
<span style={{ color: theme.colors.text, fontFamily: theme.fonts.monospace }}>
|
|
78
|
-
{v}
|
|
79
|
-
</span>
|
|
80
|
-
</div>
|
|
81
|
-
))}
|
|
82
|
-
{component.detail && <GraphifyDetailSections detail={component.detail} />}
|
|
83
|
-
</div>
|
|
42
|
+
{children}
|
|
43
|
+
</span>
|
|
84
44
|
);
|
|
85
45
|
}
|
|
86
46
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
47
|
+
/** Panel props. The two callbacks are wired by the graph; standalone usage
|
|
48
|
+
* without them renders the same panel with nothing clickable. */
|
|
49
|
+
export interface ComponentDetailProps {
|
|
50
|
+
component: SubsystemComponent;
|
|
51
|
+
/** File-path click → open that file in the bottom drawer. */
|
|
52
|
+
onOpenFile?: (file: string) => void;
|
|
53
|
+
/** Related-name click (types, callers/callees, implementors, …) → select
|
|
54
|
+
* that component if one matches; unmatched refs no-op. */
|
|
55
|
+
onRelatedSelect?: (ref: string) => void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Detail panel for the selected component — its declaration, code-style. */
|
|
59
|
+
export function ComponentDetail({ component, onOpenFile, onRelatedSelect }: ComponentDetailProps) {
|
|
89
60
|
const { theme } = useTheme();
|
|
90
61
|
const muted = theme.colors.textMuted ?? theme.colors.textSecondary;
|
|
62
|
+
const color = KIND_COLOR[component.kind] ?? '#888';
|
|
63
|
+
const displayName = deriveNameFromSymbol(component.symbol, component.kind, component.name, component.file);
|
|
91
64
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}}
|
|
102
|
-
>
|
|
103
|
-
{k}
|
|
104
|
-
</span>
|
|
65
|
+
// Token styles — keyword / name / member / type / string / punctuation.
|
|
66
|
+
const kw = (text: string) => <span style={{ color: theme.colors.secondary }}>{text}</span>;
|
|
67
|
+
const nm = (text: string) => <span style={{ color }}>{text}</span>;
|
|
68
|
+
const mb = (text: string) => <span style={{ color: theme.colors.info }}>{text}</span>;
|
|
69
|
+
// Type tokens are links into the graph (other components often own them).
|
|
70
|
+
const ty = (text: string) => (
|
|
71
|
+
<DetailLink onClick={onRelatedSelect ? () => onRelatedSelect(text) : undefined}>
|
|
72
|
+
<span style={{ color: theme.colors.accent }}>{text}</span>
|
|
73
|
+
</DetailLink>
|
|
105
74
|
);
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
color: theme.colors.text,
|
|
113
|
-
border: `1px solid ${theme.colors.border}`,
|
|
114
|
-
borderRadius: 4,
|
|
115
|
-
padding: '1px 6px',
|
|
116
|
-
marginRight: 6,
|
|
117
|
-
marginBottom: 4,
|
|
118
|
-
display: 'inline-block',
|
|
119
|
-
}}
|
|
120
|
-
>
|
|
121
|
-
{name}
|
|
122
|
-
{meta ? <span style={{ color: muted }}> {meta}</span> : ''}
|
|
123
|
-
</span>
|
|
124
|
-
);
|
|
125
|
-
const row = (k: string, children: ReactNode) => (
|
|
126
|
-
<div
|
|
127
|
-
style={{ display: 'flex', gap: 8, fontSize: theme.fontSizes[0], lineHeight: 1.5, marginBottom: 4 }}
|
|
128
|
-
>
|
|
129
|
-
{label(k)}
|
|
130
|
-
<div style={{ minWidth: 0 }}>{children}</div>
|
|
75
|
+
const str = (text: string) => <span style={{ color: theme.colors.success }}>{text}</span>;
|
|
76
|
+
const pn = (text: string) => <span style={{ color: muted }}>{text}</span>;
|
|
77
|
+
|
|
78
|
+
const line = (children: ReactNode, key?: string, indent?: boolean) => (
|
|
79
|
+
<div key={key} style={indent ? { paddingLeft: 16 } : undefined}>
|
|
80
|
+
{children}
|
|
131
81
|
</div>
|
|
132
82
|
);
|
|
83
|
+
const commentStyle = { color: muted, fontStyle: 'italic' } as const;
|
|
84
|
+
const commentLine = (text: string, key?: string, indent?: boolean, onClick?: () => void) =>
|
|
85
|
+
line(
|
|
86
|
+
<DetailLink onClick={onClick}>
|
|
87
|
+
<span style={{ ...commentStyle, ...(onClick ? clickableStyle : undefined) }}>{text}</span>
|
|
88
|
+
</DetailLink>,
|
|
89
|
+
key,
|
|
90
|
+
indent,
|
|
91
|
+
);
|
|
92
|
+
// Trailing relationship comments whose names are individually clickable.
|
|
93
|
+
const commentListLine = (prefix: string, names: string[], key?: string) =>
|
|
94
|
+
line(
|
|
95
|
+
<>
|
|
96
|
+
<span style={commentStyle}>{prefix}</span>
|
|
97
|
+
{list(
|
|
98
|
+
names.map((n, i) => (
|
|
99
|
+
<Fragment key={i}>
|
|
100
|
+
<DetailLink onClick={onRelatedSelect ? () => onRelatedSelect(n) : undefined}>
|
|
101
|
+
<span style={{ ...commentStyle, ...(onRelatedSelect ? clickableStyle : undefined) }}>{n}</span>
|
|
102
|
+
</DetailLink>
|
|
103
|
+
</Fragment>
|
|
104
|
+
)),
|
|
105
|
+
)}
|
|
106
|
+
</>,
|
|
107
|
+
key,
|
|
108
|
+
);
|
|
109
|
+
// Comma-join rendered tokens without raw-array key churn.
|
|
110
|
+
const list = (items: ReactNode[]) =>
|
|
111
|
+
items.map((item, i) => (
|
|
112
|
+
<Fragment key={i}>
|
|
113
|
+
{i > 0 ? ', ' : null}
|
|
114
|
+
{item}
|
|
115
|
+
</Fragment>
|
|
116
|
+
));
|
|
133
117
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
118
|
+
const lines: ReactNode[] = [];
|
|
119
|
+
if (component.purl)
|
|
120
|
+
lines.push(commentLine(`// ${formatPurl(component.purl)}`, 'purl'));
|
|
121
|
+
if (component.file)
|
|
122
|
+
lines.push(commentLine(`// ${component.file}`, 'file', false, onOpenFile ? () => onOpenFile(component.file) : undefined));
|
|
123
|
+
if (component.purpose) lines.push(commentLine(`/** ${component.purpose} */`, 'purpose'));
|
|
124
|
+
|
|
125
|
+
const detail = component.detail;
|
|
126
|
+
switch (detail?.kind ?? component.kind) {
|
|
127
|
+
case 'class': {
|
|
128
|
+
const members: ReactNode[] = [];
|
|
129
|
+
if (detail?.kind === 'class') {
|
|
130
|
+
detail.methods.forEach((m, i) =>
|
|
131
|
+
members.push(
|
|
132
|
+
line(
|
|
133
|
+
<>
|
|
134
|
+
{mb(m.name)}
|
|
135
|
+
{pn('(')}
|
|
136
|
+
{(m.parameters ?? []).length > 0 &&
|
|
137
|
+
list(
|
|
138
|
+
(m.parameters ?? []).map((p, j) => (
|
|
139
|
+
<Fragment key={j}>
|
|
140
|
+
{p.name ? (
|
|
141
|
+
<>
|
|
142
|
+
{mb(p.name)}
|
|
143
|
+
{pn(': ')}
|
|
144
|
+
</>
|
|
145
|
+
) : null}
|
|
146
|
+
{ty(p.type)}
|
|
147
|
+
</Fragment>
|
|
148
|
+
)),
|
|
149
|
+
)}
|
|
150
|
+
{pn(')')}
|
|
151
|
+
{m.returnType ? (
|
|
152
|
+
<>
|
|
153
|
+
{pn(': ')}
|
|
154
|
+
{ty(m.returnType)}
|
|
155
|
+
</>
|
|
156
|
+
) : null}
|
|
157
|
+
</>,
|
|
158
|
+
`m${i}`,
|
|
159
|
+
true,
|
|
160
|
+
),
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
detail.properties.forEach((prop, i) =>
|
|
164
|
+
members.push(
|
|
165
|
+
line(
|
|
166
|
+
<>
|
|
167
|
+
{mb(prop.name)}
|
|
168
|
+
{prop.type ? (
|
|
169
|
+
<>
|
|
170
|
+
{pn(': ')}
|
|
171
|
+
{ty(prop.type)}
|
|
172
|
+
</>
|
|
173
|
+
) : null}
|
|
174
|
+
</>,
|
|
175
|
+
`p${i}`,
|
|
176
|
+
true,
|
|
177
|
+
),
|
|
178
|
+
),
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const cls = detail?.kind === 'class' ? detail : undefined;
|
|
182
|
+
const hasBody = members.length > 0;
|
|
183
|
+
lines.push(
|
|
184
|
+
line(
|
|
185
|
+
<>
|
|
186
|
+
{kw('class')}
|
|
187
|
+
{' '}
|
|
188
|
+
{nm(displayName)}
|
|
189
|
+
{cls && cls.extends.length > 0 && (
|
|
190
|
+
<>
|
|
191
|
+
{' '}
|
|
192
|
+
{kw('extends')}
|
|
193
|
+
{' '}
|
|
194
|
+
{list(cls.extends.map((e, i) => <Fragment key={i}>{ty(e)}</Fragment>))}
|
|
195
|
+
</>
|
|
196
|
+
)}
|
|
197
|
+
{cls && cls.implements.length > 0 && (
|
|
198
|
+
<>
|
|
199
|
+
{' '}
|
|
200
|
+
{kw('implements')}
|
|
201
|
+
{' '}
|
|
202
|
+
{list(cls.implements.map((e, i) => <Fragment key={i}>{ty(e)}</Fragment>))}
|
|
203
|
+
</>
|
|
204
|
+
)}
|
|
205
|
+
{hasBody ? pn(' {') : null}
|
|
206
|
+
</>,
|
|
207
|
+
'decl',
|
|
208
|
+
),
|
|
149
209
|
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
210
|
+
lines.push(...members);
|
|
211
|
+
if (hasBody) lines.push(line(pn('}'), 'end'));
|
|
212
|
+
if (cls && cls.instantiations.length > 0)
|
|
213
|
+
lines.push(commentListLine('// constructed by: ', cls.instantiations.map((c) => c.name), 'insts'));
|
|
214
|
+
if (cls && cls.references.length > 0)
|
|
215
|
+
lines.push(commentListLine('// referenced by: ', cls.references.map((r) => r.name), 'refs'));
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case 'function': {
|
|
219
|
+
const fn = detail?.kind === 'function' ? detail : undefined;
|
|
220
|
+
const params = fn?.parameters ?? [];
|
|
221
|
+
lines.push(
|
|
222
|
+
line(
|
|
223
|
+
<>
|
|
224
|
+
{kw('function')}
|
|
225
|
+
{' '}
|
|
226
|
+
{nm(displayName)}
|
|
227
|
+
{pn('(')}
|
|
228
|
+
{params.length > 0 &&
|
|
229
|
+
list(
|
|
230
|
+
params.map((param, i) => (
|
|
231
|
+
<Fragment key={i}>
|
|
232
|
+
{param.name ? (
|
|
233
|
+
<>
|
|
234
|
+
{mb(param.name)}
|
|
235
|
+
{pn(': ')}
|
|
236
|
+
</>
|
|
237
|
+
) : null}
|
|
238
|
+
{ty(param.type)}
|
|
239
|
+
</Fragment>
|
|
240
|
+
)),
|
|
241
|
+
)}
|
|
242
|
+
{pn(')')}
|
|
243
|
+
{fn?.returnType ? (
|
|
244
|
+
<>
|
|
245
|
+
{pn(': ')}
|
|
246
|
+
{ty(fn.returnType)}
|
|
247
|
+
</>
|
|
248
|
+
) : null}
|
|
249
|
+
{pn(';')}
|
|
250
|
+
</>,
|
|
251
|
+
'decl',
|
|
252
|
+
),
|
|
161
253
|
);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
254
|
+
if (fn && fn.callers.length > 0)
|
|
255
|
+
lines.push(commentListLine('// called by: ', fn.callers.map((c) => c.name), 'callers'));
|
|
256
|
+
if (fn && fn.callees.length > 0)
|
|
257
|
+
lines.push(commentListLine('// calls: ', fn.callees.map((c) => c.name), 'callees'));
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
case 'type': {
|
|
261
|
+
const tpe = detail?.kind === 'type' ? detail : undefined;
|
|
262
|
+
const hasBody = (tpe?.properties.length ?? 0) > 0;
|
|
263
|
+
lines.push(
|
|
264
|
+
line(
|
|
265
|
+
<>
|
|
266
|
+
{kw('interface')}
|
|
267
|
+
{' '}
|
|
268
|
+
{nm(displayName)}
|
|
269
|
+
{hasBody ? pn(' {') : null}
|
|
270
|
+
</>,
|
|
271
|
+
'decl',
|
|
272
|
+
),
|
|
172
273
|
);
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
274
|
+
if (tpe) {
|
|
275
|
+
tpe.properties.forEach((prop, i) =>
|
|
276
|
+
lines.push(
|
|
277
|
+
line(
|
|
278
|
+
<>
|
|
279
|
+
{mb(prop.name)}
|
|
280
|
+
{prop.type ? (
|
|
281
|
+
<>
|
|
282
|
+
{pn(': ')}
|
|
283
|
+
{ty(prop.type)}
|
|
284
|
+
</>
|
|
285
|
+
) : null}
|
|
286
|
+
{pn(';')}
|
|
287
|
+
</>,
|
|
288
|
+
`p${i}`,
|
|
289
|
+
true,
|
|
290
|
+
),
|
|
291
|
+
),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if (hasBody) lines.push(line(pn('}'), 'end'));
|
|
295
|
+
if (tpe && tpe.implementors.length > 0)
|
|
296
|
+
lines.push(commentListLine('// implemented by: ', tpe.implementors, 'impl'));
|
|
297
|
+
if (tpe && tpe.usedBy.length > 0)
|
|
298
|
+
lines.push(commentListLine('// used by: ', tpe.usedBy.map((u) => u.name), 'usedBy'));
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case 'module': {
|
|
302
|
+
const mod = detail?.kind === 'module' ? detail : undefined;
|
|
303
|
+
if (mod) {
|
|
304
|
+
mod.imports.forEach((imp, i) =>
|
|
305
|
+
lines.push(
|
|
306
|
+
line(
|
|
307
|
+
<>
|
|
308
|
+
{kw('import')}
|
|
309
|
+
{' '}
|
|
310
|
+
{pn("'")}
|
|
311
|
+
{str(imp.name)}
|
|
312
|
+
{pn("';")}
|
|
313
|
+
</>,
|
|
314
|
+
`imp${i}`,
|
|
315
|
+
),
|
|
316
|
+
),
|
|
317
|
+
);
|
|
318
|
+
if (mod.exports.length > 0)
|
|
319
|
+
lines.push(
|
|
320
|
+
line(
|
|
321
|
+
<>
|
|
322
|
+
{kw('export')}
|
|
323
|
+
{' '}
|
|
324
|
+
{pn('{ ')}
|
|
325
|
+
{list(mod.exports.map((e, i) => <Fragment key={i}>{mb(e)}</Fragment>))}
|
|
326
|
+
{pn(' }')}
|
|
327
|
+
{pn(';')}
|
|
328
|
+
</>,
|
|
329
|
+
'exports',
|
|
330
|
+
),
|
|
331
|
+
);
|
|
332
|
+
if (mod.symbols.length > 0)
|
|
333
|
+
lines.push(commentLine(`// defines: ${mod.symbols.join(', ')}`, 'symbols'));
|
|
334
|
+
} else {
|
|
335
|
+
lines.push(
|
|
336
|
+
line(
|
|
337
|
+
<>
|
|
338
|
+
{kw('module')}
|
|
339
|
+
{' '}
|
|
340
|
+
{nm(displayName)}
|
|
341
|
+
</>,
|
|
342
|
+
'decl',
|
|
343
|
+
),
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
case 'external': {
|
|
349
|
+
lines.push(
|
|
350
|
+
line(
|
|
351
|
+
<>
|
|
352
|
+
{kw('external')}
|
|
353
|
+
{' '}
|
|
354
|
+
{detail?.kind === 'external' ? (
|
|
355
|
+
<>
|
|
356
|
+
{pn("'")}
|
|
357
|
+
{str(detail.label)}
|
|
358
|
+
{pn("'")}
|
|
359
|
+
</>
|
|
360
|
+
) : (
|
|
361
|
+
nm(displayName)
|
|
362
|
+
)}
|
|
363
|
+
</>,
|
|
364
|
+
'decl',
|
|
365
|
+
),
|
|
183
366
|
);
|
|
184
|
-
|
|
185
|
-
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
186
369
|
}
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<div
|
|
373
|
+
style={{
|
|
374
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
375
|
+
background: theme.colors.backgroundSecondary,
|
|
376
|
+
padding: '10px 12px',
|
|
377
|
+
fontFamily: theme.fonts.monospace,
|
|
378
|
+
fontSize: theme.fontSizes[0],
|
|
379
|
+
lineHeight: 1.7,
|
|
380
|
+
wordBreak: 'break-word',
|
|
381
|
+
}}
|
|
382
|
+
>
|
|
383
|
+
{lines}
|
|
384
|
+
</div>
|
|
385
|
+
);
|
|
187
386
|
}
|