@fragments-sdk/cli 0.12.1 → 0.13.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/dist/bin.js +299 -61
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-AM4MRTMN.js → chunk-55KERLWL.js} +2 -2
- package/dist/{chunk-LVWFOLUZ.js → chunk-7K3VROEP.js} +2 -2
- package/dist/{chunk-JJ2VRTBU.js → chunk-EYXVAMEX.js} +2 -2
- package/dist/chunk-EYXVAMEX.js.map +1 -0
- package/dist/{chunk-GVDSFQ4E.js → chunk-FZLPVN32.js} +6 -6
- package/dist/{chunk-WFS63PCW.js → chunk-I34BC3CU.js} +45 -2
- package/dist/chunk-I34BC3CU.js.map +1 -0
- package/dist/{chunk-T5OMVL7E.js → chunk-PJT5IZ37.js} +2 -2
- package/dist/{chunk-4OC7FTJB.js → chunk-TXFCEDOC.js} +2 -2
- package/dist/{chunk-TPWGL2XS.js → chunk-Z5BUXIFJ.js} +5 -5
- package/dist/{chunk-OQKMEFOS.js → chunk-ZKTFKHWN.js} +2 -2
- package/dist/core/index.js +5 -1
- package/dist/{discovery-ZJQSXF56.js → discovery-VDANZAJ2.js} +3 -3
- package/dist/{generate-RJFS2JWA.js → generate-RYWIPDN2.js} +4 -4
- package/dist/index.js +7 -7
- package/dist/{init-ZSX3NRCZ.js → init-U6534EMZ.js} +5 -5
- package/dist/mcp-bin.js +2 -2
- package/dist/{scan-3PMCJ4RB.js → scan-LE2JEIJ4.js} +6 -6
- package/dist/{scan-generate-SYU4PYZD.js → scan-generate-TFZVL3BT.js} +5 -5
- package/dist/{service-VMGNJZ42.js → service-S5LXPKV4.js} +3 -3
- package/dist/{snapshot-XOISO2IS.js → snapshot-C5DYIGIV.js} +2 -2
- package/dist/{static-viewer-5GXH2MGE.js → static-viewer-DUVC4UIM.js} +3 -3
- package/dist/{test-SI4NSHQX.js → test-JW7JIDFG.js} +4 -4
- package/dist/{tokens-T6SIVUT5.js → tokens-OPVTVITP.js} +5 -5
- package/dist/{viewer-7ZEAFBVN.js → viewer-OBTEPVY7.js} +14 -14
- package/dist/viewer-OBTEPVY7.js.map +1 -0
- package/package.json +11 -9
- package/src/bin.ts +67 -0
- package/src/commands/govern.ts +279 -0
- package/src/core/component-extractor.ts +1 -1
- package/src/viewer/vite-plugin.ts +1 -1
- package/dist/chunk-JJ2VRTBU.js.map +0 -1
- package/dist/chunk-WFS63PCW.js.map +0 -1
- package/dist/viewer-7ZEAFBVN.js.map +0 -1
- /package/dist/{chunk-AM4MRTMN.js.map → chunk-55KERLWL.js.map} +0 -0
- /package/dist/{chunk-LVWFOLUZ.js.map → chunk-7K3VROEP.js.map} +0 -0
- /package/dist/{chunk-GVDSFQ4E.js.map → chunk-FZLPVN32.js.map} +0 -0
- /package/dist/{chunk-T5OMVL7E.js.map → chunk-PJT5IZ37.js.map} +0 -0
- /package/dist/{chunk-4OC7FTJB.js.map → chunk-TXFCEDOC.js.map} +0 -0
- /package/dist/{chunk-TPWGL2XS.js.map → chunk-Z5BUXIFJ.js.map} +0 -0
- /package/dist/{chunk-OQKMEFOS.js.map → chunk-ZKTFKHWN.js.map} +0 -0
- /package/dist/{discovery-ZJQSXF56.js.map → discovery-VDANZAJ2.js.map} +0 -0
- /package/dist/{generate-RJFS2JWA.js.map → generate-RYWIPDN2.js.map} +0 -0
- /package/dist/{init-ZSX3NRCZ.js.map → init-U6534EMZ.js.map} +0 -0
- /package/dist/{scan-3PMCJ4RB.js.map → scan-LE2JEIJ4.js.map} +0 -0
- /package/dist/{scan-generate-SYU4PYZD.js.map → scan-generate-TFZVL3BT.js.map} +0 -0
- /package/dist/{service-VMGNJZ42.js.map → service-S5LXPKV4.js.map} +0 -0
- /package/dist/{snapshot-XOISO2IS.js.map → snapshot-C5DYIGIV.js.map} +0 -0
- /package/dist/{static-viewer-5GXH2MGE.js.map → static-viewer-DUVC4UIM.js.map} +0 -0
- /package/dist/{test-SI4NSHQX.js.map → test-JW7JIDFG.js.map} +0 -0
- /package/dist/{tokens-T6SIVUT5.js.map → tokens-OPVTVITP.js.map} +0 -0
package/src/bin.ts
CHANGED
|
@@ -40,6 +40,7 @@ import { perf } from './commands/perf.js';
|
|
|
40
40
|
import { doctor } from './commands/doctor.js';
|
|
41
41
|
import { setup } from './commands/setup.js';
|
|
42
42
|
import { sync } from './commands/sync.js';
|
|
43
|
+
import { governCheck, governInit, governReport, governConnect } from './commands/govern.js';
|
|
43
44
|
|
|
44
45
|
// Import existing commands that were already extracted
|
|
45
46
|
import { runScreenshotCommand } from './screenshot.js';
|
|
@@ -1115,5 +1116,71 @@ program
|
|
|
1115
1116
|
}
|
|
1116
1117
|
});
|
|
1117
1118
|
|
|
1119
|
+
// ============================================================================
|
|
1120
|
+
// GOVERN COMMAND
|
|
1121
|
+
// ============================================================================
|
|
1122
|
+
const governCmd = program
|
|
1123
|
+
.command('govern')
|
|
1124
|
+
.description('AI UI governance checks');
|
|
1125
|
+
|
|
1126
|
+
governCmd
|
|
1127
|
+
.command('check')
|
|
1128
|
+
.description('Validate a UISpec against governance policies')
|
|
1129
|
+
.option('-i, --input <path>', 'Path to UISpec JSON file (or - for stdin)')
|
|
1130
|
+
.option('-c, --config <path>', 'Path to govern.config.ts')
|
|
1131
|
+
.option('-f, --format <format>', 'Output format: summary, json, sarif', 'summary')
|
|
1132
|
+
.option('-q, --quiet', 'Suppress non-error output')
|
|
1133
|
+
.action(async (options) => {
|
|
1134
|
+
try {
|
|
1135
|
+
const { exitCode } = await governCheck({
|
|
1136
|
+
input: options.input,
|
|
1137
|
+
config: options.config,
|
|
1138
|
+
format: options.format,
|
|
1139
|
+
quiet: options.quiet,
|
|
1140
|
+
});
|
|
1141
|
+
process.exit(exitCode);
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
console.error(pc.red('Error:'), error instanceof Error ? error.message : error);
|
|
1144
|
+
process.exit(1);
|
|
1145
|
+
}
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
governCmd
|
|
1149
|
+
.command('init')
|
|
1150
|
+
.description('Generate a fragments.config.ts with govern section')
|
|
1151
|
+
.option('-o, --output <path>', 'Output path', 'fragments.config.ts')
|
|
1152
|
+
.action(async (options) => {
|
|
1153
|
+
try {
|
|
1154
|
+
await governInit({ output: options.output });
|
|
1155
|
+
} catch (error) {
|
|
1156
|
+
console.error(pc.red('Error:'), error instanceof Error ? error.message : error);
|
|
1157
|
+
process.exit(1);
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
1160
|
+
|
|
1161
|
+
governCmd
|
|
1162
|
+
.command('report')
|
|
1163
|
+
.description('Summarize governance audit log')
|
|
1164
|
+
.action(async () => {
|
|
1165
|
+
try {
|
|
1166
|
+
await governReport();
|
|
1167
|
+
} catch (error) {
|
|
1168
|
+
console.error(pc.red('Error:'), error instanceof Error ? error.message : error);
|
|
1169
|
+
process.exit(1);
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
governCmd
|
|
1174
|
+
.command('connect')
|
|
1175
|
+
.description('Connect your project to the Fragments Govern cloud dashboard')
|
|
1176
|
+
.action(async () => {
|
|
1177
|
+
try {
|
|
1178
|
+
await governConnect();
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
console.error(pc.red('Error:'), error instanceof Error ? error.message : error);
|
|
1181
|
+
process.exit(1);
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1184
|
+
|
|
1118
1185
|
// Parse command line arguments
|
|
1119
1186
|
program.parse();
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fragments govern — AI UI governance checks
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* check — Validate a UISpec against governance policies
|
|
6
|
+
* init — Generate a govern.config.ts template
|
|
7
|
+
* report — Summarize audit log
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import pc from 'picocolors';
|
|
11
|
+
import { BRAND } from '../core/index.js';
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Options
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export interface GovernCheckOptions {
|
|
18
|
+
/** Path to UISpec JSON file, or '-' for stdin */
|
|
19
|
+
input?: string;
|
|
20
|
+
/** Path to govern.config.ts */
|
|
21
|
+
config?: string;
|
|
22
|
+
/** Output format */
|
|
23
|
+
format?: 'json' | 'summary' | 'sarif';
|
|
24
|
+
/** Suppress non-error output */
|
|
25
|
+
quiet?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface GovernInitOptions {
|
|
29
|
+
/** Output path (defaults to ./govern.config.ts) */
|
|
30
|
+
output?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// check
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
export async function governCheck(options: GovernCheckOptions = {}): Promise<{ exitCode: number }> {
|
|
38
|
+
console.log(pc.cyan(`\n${BRAND.name} Governance Check\n`));
|
|
39
|
+
|
|
40
|
+
const { cliCheck, formatVerdict } = await import('@fragments-sdk/govern');
|
|
41
|
+
|
|
42
|
+
const result = await cliCheck(options);
|
|
43
|
+
const output = formatVerdict(result.verdict, options.format ?? 'summary');
|
|
44
|
+
|
|
45
|
+
if (!options.quiet) {
|
|
46
|
+
console.log(output);
|
|
47
|
+
console.log();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (result.verdict.passed) {
|
|
51
|
+
console.log(pc.green(`✓ Governance check passed (score: ${result.verdict.score}/100)\n`));
|
|
52
|
+
} else {
|
|
53
|
+
console.log(pc.red(`✗ Governance check failed (score: ${result.verdict.score}/100)\n`));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { exitCode: result.exitCode };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// init
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
export async function governInit(options: GovernInitOptions = {}): Promise<void> {
|
|
64
|
+
const { writeFile } = await import('node:fs/promises');
|
|
65
|
+
const { resolve } = await import('node:path');
|
|
66
|
+
const { generateConfigTemplate } = await import('@fragments-sdk/govern');
|
|
67
|
+
|
|
68
|
+
const outputPath = resolve(options.output ?? 'fragments.config.ts');
|
|
69
|
+
const template = generateConfigTemplate();
|
|
70
|
+
|
|
71
|
+
await writeFile(outputPath, template, 'utf-8');
|
|
72
|
+
console.log(pc.green(`✓ Created ${outputPath}\n`));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// connect
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
export async function governConnect(): Promise<void> {
|
|
80
|
+
const { readFile, writeFile, appendFile } = await import('node:fs/promises');
|
|
81
|
+
const { existsSync } = await import('node:fs');
|
|
82
|
+
const { resolve } = await import('node:path');
|
|
83
|
+
const { platform } = await import('node:os');
|
|
84
|
+
const { exec } = await import('node:child_process');
|
|
85
|
+
const { password, confirm } = await import('@inquirer/prompts');
|
|
86
|
+
|
|
87
|
+
const cloudUrl = process.env.FRAGMENTS_URL ?? 'https://app.usefragments.com';
|
|
88
|
+
|
|
89
|
+
console.log(pc.cyan(`\n ${BRAND.name} — Connect to Cloud\n`));
|
|
90
|
+
console.log(
|
|
91
|
+
pc.dim(' This will connect your project to the Fragments dashboard\n') +
|
|
92
|
+
pc.dim(' for centralized audit tracking and team visibility.\n'),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// ── Step 1: Get API key ──────────────────────────────────────────────────
|
|
96
|
+
console.log(pc.bold(' Step 1 of 3: Get your API key\n'));
|
|
97
|
+
|
|
98
|
+
const dashboardUrl = `${cloudUrl}/dashboard/settings`;
|
|
99
|
+
console.log(pc.dim(` → Opening the dashboard in your browser...`));
|
|
100
|
+
console.log(pc.dim(` Copy your API key from Settings → API Keys\n`));
|
|
101
|
+
|
|
102
|
+
// Open browser (best-effort)
|
|
103
|
+
const os = platform();
|
|
104
|
+
const openCmd = os === 'darwin'
|
|
105
|
+
? `open "${dashboardUrl}"`
|
|
106
|
+
: os === 'win32'
|
|
107
|
+
? `start "" "${dashboardUrl}"`
|
|
108
|
+
: `xdg-open "${dashboardUrl}"`;
|
|
109
|
+
exec(openCmd);
|
|
110
|
+
|
|
111
|
+
let apiKey: string;
|
|
112
|
+
let orgName: string;
|
|
113
|
+
|
|
114
|
+
// eslint-disable-next-line no-constant-condition
|
|
115
|
+
while (true) {
|
|
116
|
+
apiKey = await password({
|
|
117
|
+
message: 'Paste your API key:',
|
|
118
|
+
mask: '*',
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (!apiKey.trim()) {
|
|
122
|
+
console.log(pc.yellow('\n API key cannot be empty. Please try again.\n'));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Verify key against cloud
|
|
127
|
+
console.log(pc.dim('\n Verifying...'));
|
|
128
|
+
try {
|
|
129
|
+
const response = await fetch(`${cloudUrl}/api/verify`, {
|
|
130
|
+
headers: { Authorization: `Bearer ${apiKey.trim()}` },
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
console.log(pc.red(`\n ✗ Invalid API key (HTTP ${response.status}). Please try again.\n`));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const data = (await response.json()) as { valid: boolean; orgName?: string };
|
|
139
|
+
if (!data.valid) {
|
|
140
|
+
console.log(pc.red('\n ✗ API key not recognized. Please try again.\n'));
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
orgName = data.orgName ?? 'your organization';
|
|
145
|
+
console.log(pc.green(`\n ✓ Connected to "${orgName}" (verified)\n`));
|
|
146
|
+
break;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.log(
|
|
149
|
+
pc.red('\n ✗ Could not reach the dashboard.'),
|
|
150
|
+
);
|
|
151
|
+
console.log(
|
|
152
|
+
pc.dim(` ${error instanceof Error ? error.message : 'Network error'}\n`),
|
|
153
|
+
);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ── Step 2: Save configuration ──────────────────────────────────────────
|
|
159
|
+
console.log(pc.bold(' Step 2 of 3: Save configuration\n'));
|
|
160
|
+
|
|
161
|
+
const saveToEnv = await confirm({
|
|
162
|
+
message: 'Save API key to .env file?',
|
|
163
|
+
default: true,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (saveToEnv) {
|
|
167
|
+
const envPath = resolve('.env');
|
|
168
|
+
const envEntry = `FRAGMENTS_API_KEY=${apiKey.trim()}`;
|
|
169
|
+
|
|
170
|
+
if (existsSync(envPath)) {
|
|
171
|
+
const envContent = await readFile(envPath, 'utf-8');
|
|
172
|
+
if (envContent.includes('FRAGMENTS_API_KEY=')) {
|
|
173
|
+
// Replace existing entry
|
|
174
|
+
const updated = envContent.replace(
|
|
175
|
+
/^FRAGMENTS_API_KEY=.*$/m,
|
|
176
|
+
envEntry,
|
|
177
|
+
);
|
|
178
|
+
await writeFile(envPath, updated, 'utf-8');
|
|
179
|
+
console.log(pc.green(' ✓ Updated FRAGMENTS_API_KEY in .env'));
|
|
180
|
+
} else {
|
|
181
|
+
await appendFile(envPath, `\n${envEntry}\n`, 'utf-8');
|
|
182
|
+
console.log(pc.green(' ✓ Added FRAGMENTS_API_KEY to .env'));
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
await writeFile(envPath, `${envEntry}\n`, 'utf-8');
|
|
186
|
+
console.log(pc.green(' ✓ Created .env with FRAGMENTS_API_KEY'));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Write FRAGMENTS_URL only if non-default
|
|
190
|
+
if (cloudUrl !== 'https://app.usefragments.com') {
|
|
191
|
+
const envContent = await readFile(envPath, 'utf-8');
|
|
192
|
+
if (!envContent.includes('FRAGMENTS_URL=')) {
|
|
193
|
+
await appendFile(envPath, `FRAGMENTS_URL=${cloudUrl}\n`, 'utf-8');
|
|
194
|
+
console.log(pc.green(` ✓ Added FRAGMENTS_URL to .env`));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Ensure .env is in .gitignore
|
|
199
|
+
const gitignorePath = resolve('.gitignore');
|
|
200
|
+
if (existsSync(gitignorePath)) {
|
|
201
|
+
const gitignore = await readFile(gitignorePath, 'utf-8');
|
|
202
|
+
if (!gitignore.split('\n').some((line) => line.trim() === '.env')) {
|
|
203
|
+
await appendFile(gitignorePath, '\n.env\n', 'utf-8');
|
|
204
|
+
console.log(pc.green(' ✓ Added .env to .gitignore'));
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
await writeFile(gitignorePath, '.env\n', 'utf-8');
|
|
208
|
+
console.log(pc.green(' ✓ Created .gitignore with .env entry'));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ── Step 3: Config check ────────────────────────────────────────────────
|
|
213
|
+
console.log(pc.bold('\n Step 3 of 3: Config check\n'));
|
|
214
|
+
|
|
215
|
+
const { findGovernConfig } = await import('@fragments-sdk/govern');
|
|
216
|
+
const configPath = findGovernConfig();
|
|
217
|
+
|
|
218
|
+
if (configPath) {
|
|
219
|
+
console.log(pc.green(` ✓ Found govern config: ${configPath}`));
|
|
220
|
+
} else {
|
|
221
|
+
console.log(
|
|
222
|
+
pc.yellow(' No govern config found — run `fragments govern init` to create one'),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ── Done ────────────────────────────────────────────────────────────────
|
|
227
|
+
console.log(pc.dim('\n ─────────────────────────────────────\n'));
|
|
228
|
+
console.log(pc.green(' ✓ All set!') + ' Run `fragments govern check` to send your first audit.\n');
|
|
229
|
+
console.log(pc.dim(` Dashboard: ${cloudUrl}/dashboard\n`));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
// report
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
|
|
236
|
+
export async function governReport(): Promise<void> {
|
|
237
|
+
const { readFile } = await import('node:fs/promises');
|
|
238
|
+
|
|
239
|
+
console.log(pc.cyan(`\n${BRAND.name} Governance Report\n`));
|
|
240
|
+
|
|
241
|
+
let raw: string;
|
|
242
|
+
try {
|
|
243
|
+
raw = await readFile('.govern-audit.jsonl', 'utf-8');
|
|
244
|
+
} catch {
|
|
245
|
+
console.log(pc.yellow('No audit log found (.govern-audit.jsonl)\n'));
|
|
246
|
+
console.log(pc.dim('Run `fragments govern check` to generate audit data.\n'));
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const lines = raw.trim().split('\n').filter(Boolean);
|
|
251
|
+
if (lines.length === 0) {
|
|
252
|
+
console.log(pc.yellow('Audit log is empty.\n'));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
let totalScore = 0;
|
|
257
|
+
let passCount = 0;
|
|
258
|
+
let totalViolations = 0;
|
|
259
|
+
|
|
260
|
+
for (const line of lines) {
|
|
261
|
+
try {
|
|
262
|
+
const entry = JSON.parse(line);
|
|
263
|
+
totalScore += entry.score ?? 0;
|
|
264
|
+
if (entry.passed) passCount++;
|
|
265
|
+
totalViolations += entry.violationCount ?? 0;
|
|
266
|
+
} catch {
|
|
267
|
+
// Skip malformed lines
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const avgScore = Math.round(totalScore / lines.length);
|
|
272
|
+
const passRate = Math.round((passCount / lines.length) * 100);
|
|
273
|
+
|
|
274
|
+
console.log(` Checks: ${lines.length}`);
|
|
275
|
+
console.log(` Pass rate: ${passRate}%`);
|
|
276
|
+
console.log(` Avg score: ${avgScore}/100`);
|
|
277
|
+
console.log(` Violations: ${totalViolations} total`);
|
|
278
|
+
console.log();
|
|
279
|
+
}
|
|
@@ -524,7 +524,7 @@ function extractPropsFromExpression(checker: ts.TypeChecker, expr: ts.Expression
|
|
|
524
524
|
*/
|
|
525
525
|
function extractPropsFromExpressionDeep(checker: ts.TypeChecker, decl: ts.VariableDeclaration): ts.Type | null {
|
|
526
526
|
if (!decl.initializer) return null;
|
|
527
|
-
|
|
527
|
+
const expr = unwrapExpression(decl.initializer);
|
|
528
528
|
|
|
529
529
|
if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
|
|
530
530
|
return extractPropsFromFunctionLike(checker, expr);
|
|
@@ -1139,7 +1139,7 @@ export function fragmentsPlugin(options: FragmentsPluginOptions): Plugin[] {
|
|
|
1139
1139
|
const sourceFile = fragmentFile?.relativePath || `${component}.tsx`;
|
|
1140
1140
|
|
|
1141
1141
|
// Render the component and extract computed styles
|
|
1142
|
-
|
|
1142
|
+
const styleDiffs: Array<{
|
|
1143
1143
|
property: string;
|
|
1144
1144
|
figma: string;
|
|
1145
1145
|
rendered: string;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/component-extractor.ts"],"sourcesContent":["/**\n * ComponentExtractor — persistent LanguageService-based prop extraction.\n *\n * Replaces auto-props.ts with:\n * - Persistent ts.LanguageService (not throwaway ts.createProgram())\n * - Incremental invalidation via projectVersion\n * - Compound component (Object.assign) sub-component prop extraction\n * - Full type serialization to PropMeta format\n *\n * Zero additional dependencies — uses raw TypeScript APIs.\n */\n\nimport ts from 'typescript';\nimport { existsSync, readFileSync, statSync, readdirSync } from 'node:fs';\nimport { resolve, dirname, join } from 'node:path';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface ComponentExtractor {\n /** Extract metadata for a single component by export name */\n extract(filePath: string, exportName?: string): ComponentMeta | null;\n\n /** Extract all exported components found in a file */\n extractAll(filePath: string): ComponentMeta[];\n\n /** Notify extractor that a file changed (incremental) */\n invalidate(filePath: string): void;\n\n /** Clean up resources */\n dispose(): void;\n}\n\nexport interface ComponentMeta {\n name: string;\n filePath: string;\n description: string;\n props: Record<string, PropMeta>;\n composition: CompositionMeta | null;\n exports: string[];\n dependencies: string[];\n}\n\nexport interface PropMeta {\n name: string;\n type: string;\n typeKind: PropTypeKind;\n values?: string[];\n default?: string;\n description?: string;\n required: boolean;\n source: 'local' | 'inherited';\n}\n\nexport type PropTypeKind =\n | 'string' | 'number' | 'boolean'\n | 'enum'\n | 'function'\n | 'node'\n | 'element'\n | 'object' | 'array'\n | 'union'\n | 'custom';\n\nexport interface CompositionMeta {\n pattern: 'compound' | 'controlled' | 'simple';\n parts: PartMeta[];\n required: string[];\n}\n\nexport interface PartMeta {\n name: string;\n props: Record<string, PropMeta>;\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ninterface ResolvedComponent {\n name: string;\n propsType: ts.Type | null;\n componentNode: ts.Node | null;\n compoundParts: Map<string, ts.Type> | null;\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createComponentExtractor(tsconfigPath?: string): ComponentExtractor {\n let projectVersion = 0;\n const fileVersions = new Map<string, number>();\n const fileSnapshots = new Map<string, ts.IScriptSnapshot>();\n\n // Parse tsconfig or use inferred settings\n const rootDir = tsconfigPath ? dirname(resolve(tsconfigPath)) : process.cwd();\n const parsedCommandLine = tsconfigPath\n ? parseTsConfig(tsconfigPath)\n : inferCompilerOptions(rootDir);\n\n const scriptFileNames = new Set(parsedCommandLine.fileNames);\n\n const host: ts.LanguageServiceHost = {\n getProjectVersion: () => projectVersion.toString(),\n getScriptVersion: (fileName) => (fileVersions.get(fileName) ?? 0).toString(),\n getScriptSnapshot: (fileName) => {\n const cached = fileSnapshots.get(fileName);\n if (cached) return cached;\n\n let text: string;\n try {\n text = readFileSync(fileName, 'utf-8');\n } catch {\n return undefined;\n }\n const snapshot = ts.ScriptSnapshot.fromString(text);\n fileSnapshots.set(fileName, snapshot);\n return snapshot;\n },\n getScriptFileNames: () => [...scriptFileNames],\n getCompilationSettings: () => parsedCommandLine.options,\n getCurrentDirectory: () => rootDir,\n getDefaultLibFileName: ts.getDefaultLibFilePath,\n fileExists: ts.sys.fileExists,\n readFile: ts.sys.readFile,\n readDirectory: ts.sys.readDirectory,\n directoryExists: ts.sys.directoryExists,\n getDirectories: ts.sys.getDirectories,\n };\n\n const languageService = ts.createLanguageService(host, ts.createDocumentRegistry());\n\n function ensureFile(filePath: string): void {\n const resolved = resolve(filePath);\n if (!scriptFileNames.has(resolved)) {\n scriptFileNames.add(resolved);\n projectVersion++;\n }\n }\n\n function getChecker(): ts.TypeChecker {\n const program = languageService.getProgram();\n if (!program) throw new Error('Failed to get program from LanguageService');\n return program.getTypeChecker();\n }\n\n function getSourceFile(filePath: string): ts.SourceFile | undefined {\n return languageService.getProgram()?.getSourceFile(resolve(filePath));\n }\n\n return {\n extract(filePath: string, exportName?: string): ComponentMeta | null {\n const resolved = resolve(filePath);\n ensureFile(resolved);\n\n const sourceFile = getSourceFile(resolved);\n if (!sourceFile) return null;\n\n const checker = getChecker();\n const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n if (!moduleSymbol) return null;\n\n const exports = checker.getExportsOfModule(moduleSymbol);\n const targetName = exportName ?? findPrimaryExport(exports, sourceFile);\n if (!targetName) return null;\n\n const exportSymbol = exports.find(s => s.getName() === targetName);\n if (!exportSymbol) return null;\n\n const component = resolveExportedComponent(checker, exportSymbol, sourceFile);\n if (!component) return null;\n\n return buildComponentMeta(checker, component, resolved, sourceFile, exports);\n },\n\n extractAll(filePath: string): ComponentMeta[] {\n const resolved = resolve(filePath);\n ensureFile(resolved);\n\n const sourceFile = getSourceFile(resolved);\n if (!sourceFile) return [];\n\n const checker = getChecker();\n const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n if (!moduleSymbol) return [];\n\n const exports = checker.getExportsOfModule(moduleSymbol);\n const results: ComponentMeta[] = [];\n\n for (const exportSymbol of exports) {\n const name = exportSymbol.getName();\n // Only consider PascalCase exports as potential components\n if (!/^[A-Z]/.test(name)) continue;\n\n const component = resolveExportedComponent(checker, exportSymbol, sourceFile);\n if (!component) continue;\n\n const meta = buildComponentMeta(checker, component, resolved, sourceFile, exports);\n if (meta) results.push(meta);\n }\n\n return results;\n },\n\n invalidate(filePath: string): void {\n const resolved = resolve(filePath);\n fileVersions.set(resolved, (fileVersions.get(resolved) ?? 0) + 1);\n fileSnapshots.delete(resolved);\n projectVersion++;\n },\n\n dispose(): void {\n languageService.dispose();\n fileSnapshots.clear();\n fileVersions.clear();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// tsconfig parsing\n// ---------------------------------------------------------------------------\n\nfunction parseTsConfig(tsconfigPath: string): ts.ParsedCommandLine {\n const resolved = resolve(tsconfigPath);\n const configFile = ts.readConfigFile(resolved, ts.sys.readFile);\n if (configFile.error) {\n throw new Error(`Failed to read tsconfig: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, '\\n')}`);\n }\n\n return ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n dirname(resolved),\n undefined,\n resolved,\n );\n}\n\nfunction inferCompilerOptions(rootDir: string): ts.ParsedCommandLine {\n return {\n options: {\n target: ts.ScriptTarget.ES2022,\n module: ts.ModuleKind.ESNext,\n moduleResolution: ts.ModuleResolutionKind.Bundler,\n jsx: ts.JsxEmit.ReactJSX,\n allowSyntheticDefaultImports: true,\n esModuleInterop: true,\n skipLibCheck: true,\n strict: false,\n noEmit: true,\n },\n fileNames: [],\n errors: [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Export resolution\n// ---------------------------------------------------------------------------\n\n/**\n * Find the \"primary\" export — prefers the default export or the first PascalCase export.\n */\nfunction findPrimaryExport(exports: ts.Symbol[], sourceFile: ts.SourceFile): string | null {\n // Default export\n const defaultExport = exports.find(s => s.getName() === 'default');\n if (defaultExport) return 'default';\n\n // First PascalCase named export\n for (const s of exports) {\n if (/^[A-Z][a-zA-Z0-9]*$/.test(s.getName())) {\n return s.getName();\n }\n }\n\n return null;\n}\n\n/**\n * Resolve an export symbol to a component with its props type.\n * Handles: direct functions, forwardRef, memo, Object.assign, FC<Props>.\n */\nfunction resolveExportedComponent(\n checker: ts.TypeChecker,\n exportSymbol: ts.Symbol,\n sourceFile: ts.SourceFile,\n): ResolvedComponent | null {\n const name = exportSymbol.getName();\n\n // Follow aliases (re-exports)\n let symbol = exportSymbol;\n if (symbol.flags & ts.SymbolFlags.Alias) {\n symbol = checker.getAliasedSymbol(symbol);\n }\n\n const declarations = symbol.getDeclarations();\n if (!declarations || declarations.length === 0) return null;\n\n const declaration = declarations[0];\n\n // Variable declaration: const X = ... (forwardRef, memo, Object.assign, arrow, FC)\n if (ts.isVariableDeclaration(declaration) && declaration.initializer) {\n return resolveFromExpression(checker, name, declaration.initializer, declaration, sourceFile);\n }\n\n // Function declaration: function X(props: Props) { ... }\n if (ts.isFunctionDeclaration(declaration)) {\n const propsType = extractPropsFromFunctionLike(checker, declaration);\n return propsType ? { name, propsType, componentNode: declaration, compoundParts: null } : null;\n }\n\n // Export assignment: export default X\n if (ts.isExportAssignment(declaration) && declaration.expression) {\n return resolveFromExpression(checker, name, declaration.expression, null, sourceFile);\n }\n\n return null;\n}\n\nfunction resolveFromExpression(\n checker: ts.TypeChecker,\n name: string,\n expression: ts.Expression,\n variableDecl: ts.VariableDeclaration | null,\n sourceFile: ts.SourceFile,\n): ResolvedComponent | null {\n // Unwrap parentheses, type assertions\n expression = unwrapExpression(expression);\n\n // Arrow function or function expression\n if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {\n const propsType = extractPropsFromFunctionLike(checker, expression);\n return propsType ? { name, propsType, componentNode: expression, compoundParts: null } : null;\n }\n\n // Call expression: React.forwardRef, React.memo, Object.assign\n if (ts.isCallExpression(expression)) {\n return resolveCallExpression(checker, name, expression, variableDecl, sourceFile);\n }\n\n // Identifier reference — follow to its declaration\n if (ts.isIdentifier(expression)) {\n const sym = checker.getSymbolAtLocation(expression);\n if (sym) {\n const decls = sym.getDeclarations();\n if (decls && decls.length > 0) {\n const decl = decls[0];\n if (ts.isVariableDeclaration(decl) && decl.initializer) {\n return resolveFromExpression(checker, name, decl.initializer, decl, sourceFile);\n }\n if (ts.isFunctionDeclaration(decl)) {\n const propsType = extractPropsFromFunctionLike(checker, decl);\n return propsType ? { name, propsType, componentNode: decl, compoundParts: null } : null;\n }\n }\n }\n }\n\n // FC<Props> typed variable\n if (variableDecl?.type && ts.isTypeReferenceNode(variableDecl.type)) {\n const typeName = variableDecl.type.typeName.getText(sourceFile);\n if (typeName.includes('FC') || typeName.includes('FunctionComponent')) {\n const typeArg = variableDecl.type.typeArguments?.[0];\n if (typeArg) {\n const propsType = checker.getTypeFromTypeNode(typeArg);\n return { name, propsType, componentNode: expression, compoundParts: null };\n }\n }\n }\n\n return null;\n}\n\nfunction resolveCallExpression(\n checker: ts.TypeChecker,\n name: string,\n call: ts.CallExpression,\n variableDecl: ts.VariableDeclaration | null,\n sourceFile: ts.SourceFile,\n): ResolvedComponent | null {\n const callee = call.expression;\n\n // Object.assign(Root, { Header, Body, ... })\n if (isObjectAssignCall(callee, sourceFile)) {\n return resolveObjectAssign(checker, name, call, sourceFile);\n }\n\n // React.forwardRef<Ref, Props>(fn) or forwardRef<Ref, Props>(fn)\n if (isForwardRefCall(callee)) {\n return resolveForwardRef(checker, name, call, sourceFile);\n }\n\n // React.memo(Component) or memo(Component)\n if (isMemoCall(callee)) {\n const innerArg = call.arguments[0];\n if (innerArg) {\n return resolveFromExpression(checker, name, innerArg, variableDecl, sourceFile);\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Object.assign compound component resolution\n// ---------------------------------------------------------------------------\n\nfunction resolveObjectAssign(\n checker: ts.TypeChecker,\n name: string,\n call: ts.CallExpression,\n sourceFile: ts.SourceFile,\n): ResolvedComponent | null {\n if (call.arguments.length < 2) return null;\n\n // First arg is the root component\n const rootExpr = call.arguments[0];\n const rootResult = resolveFromExpression(checker, name, rootExpr, null, sourceFile);\n\n // Second arg is the object literal with sub-components\n const subsArg = call.arguments[1];\n const compoundParts = new Map<string, ts.Type>();\n\n if (ts.isObjectLiteralExpression(subsArg)) {\n for (const prop of subsArg.properties) {\n let subName: string | null = null;\n let subExpression: ts.Expression | null = null;\n\n if (ts.isShorthandPropertyAssignment(prop)) {\n subName = prop.name.text;\n // Resolve the identifier to its type\n const sym = checker.getSymbolAtLocation(prop.name);\n if (sym) {\n const subPropsType = extractPropsFromComponentSymbol(checker, sym);\n if (subPropsType) {\n compoundParts.set(subName, subPropsType);\n }\n }\n } else if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {\n subName = prop.name.text;\n subExpression = prop.initializer;\n if (subExpression) {\n const subType = extractPropsFromExpression(checker, subExpression, sourceFile);\n if (subType) {\n compoundParts.set(subName, subType);\n }\n }\n }\n }\n }\n\n return {\n name,\n propsType: rootResult?.propsType ?? null,\n componentNode: rootResult?.componentNode ?? rootExpr,\n compoundParts: compoundParts.size > 0 ? compoundParts : null,\n };\n}\n\n/**\n * Extract props type from a component symbol (function, variable, etc.)\n */\nfunction extractPropsFromComponentSymbol(checker: ts.TypeChecker, symbol: ts.Symbol): ts.Type | null {\n // Follow aliases\n let sym = symbol;\n if (sym.flags & ts.SymbolFlags.Alias) {\n sym = checker.getAliasedSymbol(sym);\n }\n\n const decls = sym.getDeclarations();\n if (!decls || decls.length === 0) return null;\n\n const decl = decls[0];\n\n if (ts.isFunctionDeclaration(decl)) {\n return extractPropsFromFunctionLike(checker, decl);\n }\n\n if (ts.isVariableDeclaration(decl) && decl.initializer) {\n // forwardRef, memo, arrow function, etc.\n return extractPropsFromExpressionDeep(checker, decl);\n }\n\n return null;\n}\n\n/**\n * Extract props type from an arbitrary expression (used for Object.assign values).\n */\nfunction extractPropsFromExpression(checker: ts.TypeChecker, expr: ts.Expression, sourceFile: ts.SourceFile): ts.Type | null {\n expr = unwrapExpression(expr);\n\n if (ts.isIdentifier(expr)) {\n const sym = checker.getSymbolAtLocation(expr);\n if (sym) return extractPropsFromComponentSymbol(checker, sym);\n }\n\n if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {\n return extractPropsFromFunctionLike(checker, expr);\n }\n\n if (ts.isCallExpression(expr)) {\n if (isForwardRefCall(expr.expression)) {\n const typeArg = expr.typeArguments?.[1];\n if (typeArg) return checker.getTypeFromTypeNode(typeArg);\n const innerArg = expr.arguments[0];\n if (innerArg && (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg))) {\n return extractPropsFromFunctionLike(checker, innerArg);\n }\n }\n if (isMemoCall(expr.expression) && expr.arguments[0]) {\n return extractPropsFromExpression(checker, expr.arguments[0], sourceFile);\n }\n }\n\n return null;\n}\n\n/**\n * Deep extraction from a variable declaration.\n */\nfunction extractPropsFromExpressionDeep(checker: ts.TypeChecker, decl: ts.VariableDeclaration): ts.Type | null {\n if (!decl.initializer) return null;\n let expr = unwrapExpression(decl.initializer);\n\n if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {\n return extractPropsFromFunctionLike(checker, expr);\n }\n\n if (ts.isCallExpression(expr)) {\n if (isForwardRefCall(expr.expression)) {\n const typeArg = expr.typeArguments?.[1];\n if (typeArg) return checker.getTypeFromTypeNode(typeArg);\n const innerArg = expr.arguments[0];\n if (innerArg && (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg))) {\n return extractPropsFromFunctionLike(checker, innerArg);\n }\n }\n if (isMemoCall(expr.expression) && expr.arguments[0]) {\n return extractPropsFromExpressionDeep(checker, {\n ...decl,\n initializer: expr.arguments[0],\n } as ts.VariableDeclaration);\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// forwardRef resolution\n// ---------------------------------------------------------------------------\n\nfunction resolveForwardRef(\n checker: ts.TypeChecker,\n name: string,\n call: ts.CallExpression,\n sourceFile: ts.SourceFile,\n): ResolvedComponent | null {\n // Try type arguments first: forwardRef<Ref, Props>(...)\n const propsTypeArg = call.typeArguments?.[1];\n if (propsTypeArg) {\n const propsType = checker.getTypeFromTypeNode(propsTypeArg);\n const innerArg = call.arguments[0];\n const componentNode = innerArg && (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg))\n ? innerArg : null;\n return { name, propsType, componentNode, compoundParts: null };\n }\n\n // Fall back to inner function's parameter type\n const innerArg = call.arguments[0];\n if (innerArg) {\n if (ts.isArrowFunction(innerArg) || ts.isFunctionExpression(innerArg)) {\n const propsType = extractPropsFromFunctionLike(checker, innerArg);\n return propsType ? { name, propsType, componentNode: innerArg, compoundParts: null } : null;\n }\n if (ts.isIdentifier(innerArg)) {\n const sym = checker.getSymbolAtLocation(innerArg);\n if (sym) {\n const propsType = extractPropsFromComponentSymbol(checker, sym);\n if (propsType) return { name, propsType, componentNode: innerArg, compoundParts: null };\n }\n }\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Props extraction from function-like declarations\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the props type from a function's first parameter.\n */\nfunction extractPropsFromFunctionLike(\n checker: ts.TypeChecker,\n func: ts.FunctionLikeDeclaration,\n): ts.Type | null {\n const firstParam = func.parameters[0];\n if (!firstParam) return null;\n\n // If there's a type annotation, use it\n if (firstParam.type) {\n return checker.getTypeFromTypeNode(firstParam.type);\n }\n\n // Otherwise try to infer from the parameter's symbol\n const paramSymbol = checker.getSymbolAtLocation(firstParam.name);\n if (paramSymbol) {\n return checker.getTypeOfSymbolAtLocation(paramSymbol, firstParam);\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Build ComponentMeta from resolved component\n// ---------------------------------------------------------------------------\n\nfunction buildComponentMeta(\n checker: ts.TypeChecker,\n component: ResolvedComponent,\n filePath: string,\n sourceFile: ts.SourceFile,\n moduleExports: ts.Symbol[],\n): ComponentMeta | null {\n const props: Record<string, PropMeta> = {};\n const sourceFilePath = toPosixPath(sourceFile.fileName);\n\n if (component.propsType) {\n extractPropsFromType(checker, component.propsType, props, sourceFilePath);\n }\n\n // Extract defaults from the component function body\n const defaults = component.componentNode\n ? extractDefaultValues(component.componentNode)\n : {};\n\n // Apply defaults\n for (const [propName, defaultVal] of Object.entries(defaults)) {\n if (props[propName]) {\n props[propName].default = defaultVal;\n }\n }\n\n // Build composition meta\n let composition: CompositionMeta | null = null;\n if (component.compoundParts && component.compoundParts.size > 0) {\n const parts: PartMeta[] = [];\n for (const [partName, partType] of component.compoundParts) {\n const partProps: Record<string, PropMeta> = {};\n extractPropsFromType(checker, partType, partProps, sourceFilePath);\n parts.push({ name: partName, props: partProps });\n }\n\n composition = {\n pattern: 'compound',\n parts,\n required: [], // Could be inferred from usage patterns\n };\n }\n\n // Extract description from JSDoc\n let description = '';\n const componentSymbol = moduleExports.find(s => s.getName() === component.name);\n if (componentSymbol) {\n description = extractJSDocDescription(checker, componentSymbol);\n }\n\n // Collect export names\n const exportNames = moduleExports\n .filter(s => /^[A-Z]/.test(s.getName()))\n .map(s => s.getName());\n\n // Collect import dependencies (other components imported)\n const dependencies = extractDependencies(sourceFile);\n\n return {\n name: component.name,\n filePath,\n description,\n props,\n composition,\n exports: exportNames,\n dependencies,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Type → PropMeta extraction\n// ---------------------------------------------------------------------------\n\nfunction extractPropsFromType(\n checker: ts.TypeChecker,\n propsType: ts.Type,\n result: Record<string, PropMeta>,\n sourceFilePath: string,\n): void {\n for (const symbol of checker.getPropertiesOfType(propsType)) {\n const propName = symbol.getName();\n\n // Skip internal/private props\n if (propName.startsWith('_') || propName.startsWith('$')) continue;\n\n // Skip React internal props\n if (propName === 'key' || propName === 'ref') continue;\n\n const declarations = symbol.getDeclarations() ?? [];\n\n // Determine source: local vs inherited\n const isLocal = declarations.some(\n d => toPosixPath(d.getSourceFile().fileName) === sourceFilePath,\n );\n\n const referenceNode = declarations[0];\n if (!referenceNode) continue;\n\n const propType = checker.getTypeOfSymbolAtLocation(symbol, referenceNode);\n const serialized = serializePropType(checker, propType);\n const description = ts.displayPartsToString(symbol.getDocumentationComment(checker)).trim();\n const required = (symbol.flags & ts.SymbolFlags.Optional) === 0;\n\n // Extract @default from JSDoc tags\n let jsDocDefault: string | undefined;\n const jsDocTags = symbol.getJsDocTags(checker);\n const defaultTag = jsDocTags.find(t => t.name === 'default');\n if (defaultTag?.text) {\n jsDocDefault = ts.displayPartsToString(defaultTag.text).trim();\n }\n\n result[propName] = {\n name: propName,\n type: serialized.type,\n typeKind: serialized.typeKind,\n values: serialized.values,\n default: jsDocDefault,\n description: description || undefined,\n required,\n source: isLocal ? 'local' : 'inherited',\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Type serializer: ts.Type → PropMeta shape\n// ---------------------------------------------------------------------------\n\nfunction serializePropType(\n checker: ts.TypeChecker,\n type: ts.Type,\n): Pick<PropMeta, 'type' | 'typeKind' | 'values'> {\n // Check for ReactNode/ReactElement BEFORE union decomposition,\n // because ReactNode is defined as a large union in React's types.\n const aliasSymbol = type.aliasSymbol;\n if (aliasSymbol) {\n const aliasName = aliasSymbol.getName();\n if (aliasName === 'ReactNode') {\n return { type: 'ReactNode', typeKind: 'node' };\n }\n if (aliasName === 'ReactElement') {\n return { type: 'ReactElement', typeKind: 'element' };\n }\n }\n\n // Handle union types (including optional which adds undefined)\n if (type.isUnion()) {\n const nonNullableTypes = type.types.filter(\n t => !((t.flags & ts.TypeFlags.Undefined) || (t.flags & ts.TypeFlags.Null) || (t.flags & ts.TypeFlags.Void)),\n );\n\n // Single type after filtering nullable\n if (nonNullableTypes.length === 1) {\n return serializePropType(checker, nonNullableTypes[0]);\n }\n\n // All string literals → enum\n if (nonNullableTypes.length > 0 && nonNullableTypes.every(t => t.isStringLiteral())) {\n const values = nonNullableTypes.map(t => (t as ts.StringLiteralType).value);\n return {\n type: values.map(v => `\"${v}\"`).join(' | '),\n typeKind: 'enum',\n values,\n };\n }\n\n // All boolean-like\n if (nonNullableTypes.every(t => isBooleanLike(t))) {\n return { type: 'boolean', typeKind: 'boolean' };\n }\n\n // Mixed union\n const typeStr = checker.typeToString(type, undefined, ts.TypeFormatFlags.NoTruncation);\n return { type: typeStr, typeKind: 'union' };\n }\n\n // Check for ReactNode / ReactElement\n const typeStr = checker.typeToString(type, undefined, ts.TypeFormatFlags.NoTruncation);\n if (typeStr.includes('ReactNode')) {\n return { type: 'ReactNode', typeKind: 'node' };\n }\n if (typeStr.includes('ReactElement') || typeStr.includes('JSX.Element')) {\n return { type: 'ReactElement', typeKind: 'element' };\n }\n\n // Function types\n if (type.getCallSignatures().length > 0) {\n return { type: typeStr, typeKind: 'function' };\n }\n\n // Primitives\n if (type.flags & ts.TypeFlags.String) return { type: 'string', typeKind: 'string' };\n if (type.flags & ts.TypeFlags.Number) return { type: 'number', typeKind: 'number' };\n if (type.flags & ts.TypeFlags.Boolean || type.flags & ts.TypeFlags.BooleanLiteral) {\n return { type: 'boolean', typeKind: 'boolean' };\n }\n\n // String literal (not in union)\n if (type.isStringLiteral()) {\n return { type: `\"${type.value}\"`, typeKind: 'enum', values: [type.value] };\n }\n\n // Array\n if (checker.isArrayType(type) || checker.isTupleType(type)) {\n return { type: typeStr, typeKind: 'array' };\n }\n\n // Object\n if (type.flags & ts.TypeFlags.Object) {\n return { type: typeStr, typeKind: 'object' };\n }\n\n return { type: typeStr, typeKind: 'custom' };\n}\n\n// ---------------------------------------------------------------------------\n// Default value extraction\n// ---------------------------------------------------------------------------\n\nfunction extractDefaultValues(node: ts.Node): Record<string, string> {\n const defaults: Record<string, string> = {};\n\n // Find function-like node\n let funcNode: ts.FunctionLikeDeclaration | null = null;\n if (ts.isFunctionDeclaration(node) || ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {\n funcNode = node;\n }\n\n if (!funcNode?.parameters?.length) return defaults;\n\n const firstParam = funcNode.parameters[0];\n if (!ts.isObjectBindingPattern(firstParam.name)) return defaults;\n\n for (const element of firstParam.name.elements) {\n let propName: string | null = null;\n\n if (element.propertyName) {\n if (ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName)) {\n propName = element.propertyName.text;\n }\n } else if (ts.isIdentifier(element.name)) {\n propName = element.name.text;\n }\n\n if (!propName || !element.initializer) continue;\n\n const value = readLiteralValue(element.initializer);\n if (value !== undefined) {\n defaults[propName] = value;\n }\n }\n\n return defaults;\n}\n\nfunction readLiteralValue(expression: ts.Expression): string | undefined {\n if (ts.isStringLiteral(expression) || ts.isNoSubstitutionTemplateLiteral(expression)) {\n return expression.text;\n }\n if (ts.isNumericLiteral(expression)) {\n return expression.text;\n }\n if (expression.kind === ts.SyntaxKind.TrueKeyword) return 'true';\n if (expression.kind === ts.SyntaxKind.FalseKeyword) return 'false';\n if (expression.kind === ts.SyntaxKind.NullKeyword) return 'null';\n if (\n ts.isPrefixUnaryExpression(expression) &&\n expression.operator === ts.SyntaxKind.MinusToken &&\n ts.isNumericLiteral(expression.operand)\n ) {\n return `-${expression.operand.text}`;\n }\n\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// JSDoc extraction\n// ---------------------------------------------------------------------------\n\nfunction extractJSDocDescription(checker: ts.TypeChecker, symbol: ts.Symbol): string {\n // Follow aliases\n let sym = symbol;\n if (sym.flags & ts.SymbolFlags.Alias) {\n sym = checker.getAliasedSymbol(sym);\n }\n\n const docComment = ts.displayPartsToString(sym.getDocumentationComment(checker)).trim();\n if (docComment) return docComment;\n\n // Try to get from the Props interface\n const decls = sym.getDeclarations();\n if (decls) {\n for (const decl of decls) {\n // Look for the Props type\n const sourceFile = decl.getSourceFile();\n for (const stmt of sourceFile.statements) {\n if (\n (ts.isInterfaceDeclaration(stmt) || ts.isTypeAliasDeclaration(stmt)) &&\n stmt.name.text === `${symbol.getName()}Props`\n ) {\n const propsDoc = ts.displayPartsToString(\n checker.getSymbolAtLocation(stmt.name)?.getDocumentationComment(checker) ?? [],\n ).trim();\n if (propsDoc) return propsDoc;\n }\n }\n }\n }\n\n return '';\n}\n\n// ---------------------------------------------------------------------------\n// Import dependency extraction\n// ---------------------------------------------------------------------------\n\nfunction extractDependencies(sourceFile: ts.SourceFile): string[] {\n const deps: string[] = [];\n for (const stmt of sourceFile.statements) {\n if (!ts.isImportDeclaration(stmt)) continue;\n if (!ts.isStringLiteral(stmt.moduleSpecifier)) continue;\n\n const modulePath = stmt.moduleSpecifier.text;\n // Only relative imports to other components\n if (!modulePath.startsWith('.') && !modulePath.startsWith('/')) continue;\n\n const clause = stmt.importClause;\n if (!clause) continue;\n\n // Default import\n if (clause.name && /^[A-Z]/.test(clause.name.text)) {\n deps.push(clause.name.text);\n }\n\n // Named imports\n if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {\n for (const element of clause.namedBindings.elements) {\n if (/^[A-Z]/.test(element.name.text)) {\n deps.push(element.name.text);\n }\n }\n }\n }\n return deps;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction unwrapExpression(expr: ts.Expression): ts.Expression {\n while (true) {\n if (ts.isParenthesizedExpression(expr)) {\n expr = expr.expression;\n } else if (ts.isAsExpression(expr) || ts.isTypeAssertionExpression(expr)) {\n expr = expr.expression;\n } else {\n return expr;\n }\n }\n}\n\nfunction isObjectAssignCall(callee: ts.Expression, sourceFile: ts.SourceFile): boolean {\n if (\n ts.isPropertyAccessExpression(callee) &&\n ts.isIdentifier(callee.expression) &&\n callee.expression.text === 'Object' &&\n callee.name.text === 'assign'\n ) {\n return true;\n }\n return false;\n}\n\nfunction isForwardRefCall(callee: ts.Expression): boolean {\n // React.forwardRef(...)\n if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'forwardRef') {\n return true;\n }\n // forwardRef(...)\n if (ts.isIdentifier(callee) && callee.text === 'forwardRef') {\n return true;\n }\n return false;\n}\n\nfunction isMemoCall(callee: ts.Expression): boolean {\n if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'memo') {\n return true;\n }\n if (ts.isIdentifier(callee) && callee.text === 'memo') {\n return true;\n }\n return false;\n}\n\nfunction isBooleanLike(type: ts.Type): boolean {\n return (\n (type.flags & ts.TypeFlags.BooleanLike) !== 0 ||\n type.flags === ts.TypeFlags.BooleanLiteral\n );\n}\n\nfunction toPosixPath(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n"],"mappings":"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","names":["innerArg","typeStr"]}
|