@ant-design/cli 6.3.3 → 6.3.5-beta.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.
- package/README.md +22 -1
- package/README.zh-CN.md +22 -1
- package/data/v4.json.gz +0 -0
- package/data/v5.json.gz +0 -0
- package/data/v6.3.4.json.gz +0 -0
- package/data/v6.json.gz +0 -0
- package/data/versions.json +1 -1
- package/dist/index.js +887 -612
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/skills/antd/SKILL.md +19 -0
package/dist/index.js
CHANGED
|
@@ -8,17 +8,88 @@ import { readFileSync, existsSync } from "fs";
|
|
|
8
8
|
import { gunzipSync } from "zlib";
|
|
9
9
|
import { join, dirname } from "path";
|
|
10
10
|
import { fileURLToPath } from "url";
|
|
11
|
+
|
|
12
|
+
// src/output/error.ts
|
|
13
|
+
var ErrorCodes = {
|
|
14
|
+
COMPONENT_NOT_FOUND: "COMPONENT_NOT_FOUND",
|
|
15
|
+
VERSION_NOT_FOUND: "VERSION_NOT_FOUND",
|
|
16
|
+
NO_PROJECT_DETECTED: "NO_PROJECT_DETECTED",
|
|
17
|
+
METADATA_FETCH_FAILED: "METADATA_FETCH_FAILED",
|
|
18
|
+
UNSUPPORTED_VERSION_FEATURE: "UNSUPPORTED_VERSION_FEATURE",
|
|
19
|
+
DEMO_NOT_FOUND: "DEMO_NOT_FOUND",
|
|
20
|
+
INVALID_ARGUMENT: "INVALID_ARGUMENT",
|
|
21
|
+
TITLE_REQUIRED: "TITLE_REQUIRED",
|
|
22
|
+
GH_NOT_FOUND: "GH_NOT_FOUND",
|
|
23
|
+
GH_SUBMIT_FAILED: "GH_SUBMIT_FAILED",
|
|
24
|
+
DOC_NOT_AVAILABLE: "DOC_NOT_AVAILABLE",
|
|
25
|
+
UNKNOWN_TOOL: "UNKNOWN_TOOL"
|
|
26
|
+
};
|
|
27
|
+
function createError(code, message, suggestion) {
|
|
28
|
+
return { error: true, code, message, suggestion };
|
|
29
|
+
}
|
|
30
|
+
function printError(err, format) {
|
|
31
|
+
if (format === "json") {
|
|
32
|
+
console.error(JSON.stringify(err, null, 2));
|
|
33
|
+
} else {
|
|
34
|
+
console.error(`Error: ${err.message}`);
|
|
35
|
+
if (err.suggestion) {
|
|
36
|
+
console.error(`Suggestion: ${err.suggestion}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function fuzzyMatch(input, candidates) {
|
|
41
|
+
if (candidates.length === 0) return void 0;
|
|
42
|
+
const lower = input.toLowerCase();
|
|
43
|
+
const exact = candidates.find((c) => c.toLowerCase() === lower);
|
|
44
|
+
if (exact) return exact;
|
|
45
|
+
const prefix = candidates.find((c) => c.toLowerCase().startsWith(lower));
|
|
46
|
+
if (prefix) return prefix;
|
|
47
|
+
const contains = candidates.find((c) => c.toLowerCase().includes(lower));
|
|
48
|
+
if (contains) return contains;
|
|
49
|
+
let best;
|
|
50
|
+
let bestDist = Infinity;
|
|
51
|
+
for (const candidate of candidates) {
|
|
52
|
+
const dist = levenshtein(lower, candidate.toLowerCase());
|
|
53
|
+
if (dist <= 3) {
|
|
54
|
+
const sameFirstLetter = lower[0] === candidate[0]?.toLowerCase();
|
|
55
|
+
const bestSameFirstLetter = best ? lower[0] === best[0]?.toLowerCase() : false;
|
|
56
|
+
if (dist < bestDist || dist === bestDist && sameFirstLetter && !bestSameFirstLetter) {
|
|
57
|
+
bestDist = dist;
|
|
58
|
+
best = candidate;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return best;
|
|
63
|
+
}
|
|
64
|
+
function levenshtein(a, b) {
|
|
65
|
+
const m = a.length;
|
|
66
|
+
const n = b.length;
|
|
67
|
+
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
68
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
69
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
70
|
+
for (let i = 1; i <= m; i++) {
|
|
71
|
+
for (let j = 1; j <= n; j++) {
|
|
72
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return dp[m][n];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/data/loader.ts
|
|
11
79
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
80
|
+
var cachedDataPath;
|
|
12
81
|
function getDataPath() {
|
|
82
|
+
if (cachedDataPath) return cachedDataPath;
|
|
13
83
|
const candidates = [
|
|
14
84
|
join(__dirname, "..", "data"),
|
|
15
85
|
// from dist/
|
|
16
86
|
join(__dirname, "..", "..", "data")
|
|
17
87
|
// from src/data/
|
|
18
88
|
];
|
|
19
|
-
|
|
89
|
+
cachedDataPath = candidates.find(
|
|
20
90
|
(p) => existsSync(join(p, "v5.json.gz")) || existsSync(join(p, "v5.json"))
|
|
21
91
|
) ?? candidates[0];
|
|
92
|
+
return cachedDataPath;
|
|
22
93
|
}
|
|
23
94
|
function readDataFile(filePath) {
|
|
24
95
|
const gzPath = filePath + ".gz";
|
|
@@ -54,7 +125,15 @@ function loadMetadata(majorVersion) {
|
|
|
54
125
|
};
|
|
55
126
|
}
|
|
56
127
|
}
|
|
128
|
+
var metadataCache = /* @__PURE__ */ new Map();
|
|
57
129
|
function loadMetadataForVersion(version) {
|
|
130
|
+
const cached = metadataCache.get(version);
|
|
131
|
+
if (cached) return cached;
|
|
132
|
+
const result = loadMetadataForVersionUncached(version);
|
|
133
|
+
metadataCache.set(version, result);
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function loadMetadataForVersionUncached(version) {
|
|
58
137
|
const parts = version.split(".");
|
|
59
138
|
const major = parts[0];
|
|
60
139
|
const majorVersion = `v${major}`;
|
|
@@ -105,6 +184,20 @@ function findComponent(store, name) {
|
|
|
105
184
|
function getAllComponentNames(store) {
|
|
106
185
|
return store.components.map((c) => c.name);
|
|
107
186
|
}
|
|
187
|
+
function resolveComponent(component, version) {
|
|
188
|
+
const store = loadMetadataForVersion(version);
|
|
189
|
+
const comp = findComponent(store, component);
|
|
190
|
+
if (!comp) {
|
|
191
|
+
const names = getAllComponentNames(store);
|
|
192
|
+
const suggestion = fuzzyMatch(component, names);
|
|
193
|
+
return createError(
|
|
194
|
+
ErrorCodes.COMPONENT_NOT_FOUND,
|
|
195
|
+
`Component '${component}' not found`,
|
|
196
|
+
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return { store, comp };
|
|
200
|
+
}
|
|
108
201
|
|
|
109
202
|
// src/data/version.ts
|
|
110
203
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
@@ -281,24 +374,32 @@ function output(data, format) {
|
|
|
281
374
|
}
|
|
282
375
|
|
|
283
376
|
// src/commands/list.ts
|
|
377
|
+
function listComponents(opts) {
|
|
378
|
+
const store = loadMetadataForVersion(opts.version);
|
|
379
|
+
return store.components.map((c) => ({
|
|
380
|
+
name: c.name,
|
|
381
|
+
nameZh: c.nameZh ?? "",
|
|
382
|
+
description: c.description,
|
|
383
|
+
descriptionZh: c.descriptionZh ?? "",
|
|
384
|
+
since: c.since ?? "",
|
|
385
|
+
category: c.category ?? ""
|
|
386
|
+
}));
|
|
387
|
+
}
|
|
284
388
|
function registerListCommand(program2) {
|
|
285
389
|
program2.command("list").description("List all components with bilingual names, descriptions, and first-supported version").action(() => {
|
|
286
390
|
const opts = program2.opts();
|
|
287
391
|
const versionInfo = detectVersion(opts.version);
|
|
288
|
-
const
|
|
289
|
-
if (
|
|
290
|
-
|
|
392
|
+
const components = listComponents({ version: versionInfo.version });
|
|
393
|
+
if (components.length === 0) {
|
|
394
|
+
if (opts.format === "json") {
|
|
395
|
+
output([], "json");
|
|
396
|
+
} else {
|
|
397
|
+
console.log("No component data available.");
|
|
398
|
+
}
|
|
291
399
|
return;
|
|
292
400
|
}
|
|
293
401
|
if (opts.format === "json") {
|
|
294
|
-
|
|
295
|
-
name: c.name,
|
|
296
|
-
nameZh: c.nameZh ?? "",
|
|
297
|
-
description: c.description,
|
|
298
|
-
descriptionZh: c.descriptionZh ?? "",
|
|
299
|
-
since: c.since ?? ""
|
|
300
|
-
}));
|
|
301
|
-
output(data, "json");
|
|
402
|
+
output(components, "json");
|
|
302
403
|
return;
|
|
303
404
|
}
|
|
304
405
|
if (opts.format === "markdown") {
|
|
@@ -308,19 +409,19 @@ function registerListCommand(program2) {
|
|
|
308
409
|
"| Component | \u7EC4\u4EF6\u540D | Description | Since |",
|
|
309
410
|
"|-----------|--------|-------------|-------|"
|
|
310
411
|
];
|
|
311
|
-
for (const c of
|
|
412
|
+
for (const c of components) {
|
|
312
413
|
const desc = c.description || c.descriptionZh || "";
|
|
313
|
-
lines.push(`| **${c.name}** | ${c.nameZh
|
|
414
|
+
lines.push(`| **${c.name}** | ${c.nameZh} | ${desc} | ${c.since} |`);
|
|
314
415
|
}
|
|
315
416
|
console.log(lines.join("\n"));
|
|
316
417
|
return;
|
|
317
418
|
}
|
|
318
419
|
const headers = ["Component", "\u7EC4\u4EF6\u540D", "Description", "Since"];
|
|
319
|
-
const rows =
|
|
420
|
+
const rows = components.map((c) => [
|
|
320
421
|
c.name,
|
|
321
|
-
c.nameZh
|
|
422
|
+
c.nameZh,
|
|
322
423
|
c.description,
|
|
323
|
-
c.since
|
|
424
|
+
c.since
|
|
324
425
|
]);
|
|
325
426
|
console.log(formatTable(headers, rows, "text"));
|
|
326
427
|
});
|
|
@@ -332,393 +433,324 @@ function localize(en, zh, lang) {
|
|
|
332
433
|
return en || "";
|
|
333
434
|
}
|
|
334
435
|
|
|
335
|
-
// src/output/error.ts
|
|
336
|
-
var ErrorCodes = {
|
|
337
|
-
COMPONENT_NOT_FOUND: "COMPONENT_NOT_FOUND",
|
|
338
|
-
VERSION_NOT_FOUND: "VERSION_NOT_FOUND",
|
|
339
|
-
NO_PROJECT_DETECTED: "NO_PROJECT_DETECTED",
|
|
340
|
-
METADATA_FETCH_FAILED: "METADATA_FETCH_FAILED",
|
|
341
|
-
UNSUPPORTED_VERSION_FEATURE: "UNSUPPORTED_VERSION_FEATURE",
|
|
342
|
-
DEMO_NOT_FOUND: "DEMO_NOT_FOUND",
|
|
343
|
-
INVALID_ARGUMENT: "INVALID_ARGUMENT",
|
|
344
|
-
TITLE_REQUIRED: "TITLE_REQUIRED",
|
|
345
|
-
GH_NOT_FOUND: "GH_NOT_FOUND",
|
|
346
|
-
GH_SUBMIT_FAILED: "GH_SUBMIT_FAILED"
|
|
347
|
-
};
|
|
348
|
-
function createError(code, message, suggestion) {
|
|
349
|
-
return { error: true, code, message, suggestion };
|
|
350
|
-
}
|
|
351
|
-
function printError(err, format) {
|
|
352
|
-
if (format === "json") {
|
|
353
|
-
console.error(JSON.stringify(err, null, 2));
|
|
354
|
-
} else {
|
|
355
|
-
console.error(`Error: ${err.message}`);
|
|
356
|
-
if (err.suggestion) {
|
|
357
|
-
console.error(`Suggestion: ${err.suggestion}`);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
function fuzzyMatch(input, candidates) {
|
|
362
|
-
if (candidates.length === 0) return void 0;
|
|
363
|
-
const lower = input.toLowerCase();
|
|
364
|
-
const exact = candidates.find((c) => c.toLowerCase() === lower);
|
|
365
|
-
if (exact) return exact;
|
|
366
|
-
const prefix = candidates.find((c) => c.toLowerCase().startsWith(lower));
|
|
367
|
-
if (prefix) return prefix;
|
|
368
|
-
const contains = candidates.find((c) => c.toLowerCase().includes(lower));
|
|
369
|
-
if (contains) return contains;
|
|
370
|
-
let best;
|
|
371
|
-
let bestDist = Infinity;
|
|
372
|
-
for (const candidate of candidates) {
|
|
373
|
-
const dist = levenshtein(lower, candidate.toLowerCase());
|
|
374
|
-
if (dist <= 3) {
|
|
375
|
-
const sameFirstLetter = lower[0] === candidate[0]?.toLowerCase();
|
|
376
|
-
const bestSameFirstLetter = best ? lower[0] === best[0]?.toLowerCase() : false;
|
|
377
|
-
if (dist < bestDist || dist === bestDist && sameFirstLetter && !bestSameFirstLetter) {
|
|
378
|
-
bestDist = dist;
|
|
379
|
-
best = candidate;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
return best;
|
|
384
|
-
}
|
|
385
|
-
function levenshtein(a, b) {
|
|
386
|
-
const m = a.length;
|
|
387
|
-
const n = b.length;
|
|
388
|
-
const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
389
|
-
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
390
|
-
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
391
|
-
for (let i = 1; i <= m; i++) {
|
|
392
|
-
for (let j = 1; j <= n; j++) {
|
|
393
|
-
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
return dp[m][n];
|
|
397
|
-
}
|
|
398
|
-
|
|
399
436
|
// src/commands/info.ts
|
|
400
|
-
function
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
437
|
+
function getComponentInfo(component, opts) {
|
|
438
|
+
const resolved = resolveComponent(component, opts.version);
|
|
439
|
+
if ("error" in resolved) return resolved;
|
|
440
|
+
const { comp } = resolved;
|
|
441
|
+
const desc = localize(comp.description, comp.descriptionZh, opts.lang);
|
|
442
|
+
const whenToUse = localize(comp.whenToUse, comp.whenToUseZh, opts.lang);
|
|
443
|
+
if (opts.detail) {
|
|
444
|
+
return {
|
|
445
|
+
name: comp.name,
|
|
446
|
+
nameZh: comp.nameZh ?? "",
|
|
447
|
+
description: desc,
|
|
448
|
+
whenToUse: whenToUse || "",
|
|
449
|
+
props: comp.props.map((p) => ({
|
|
450
|
+
...p,
|
|
451
|
+
description: localize(p.description, p.descriptionZh, opts.lang)
|
|
452
|
+
})),
|
|
453
|
+
subComponentProps: comp.subComponentProps ? Object.fromEntries(
|
|
454
|
+
Object.entries(comp.subComponentProps).map(([name, props]) => [
|
|
455
|
+
name,
|
|
456
|
+
props.map((p) => ({ ...p, description: localize(p.description, p.descriptionZh, opts.lang) }))
|
|
457
|
+
])
|
|
458
|
+
) : void 0,
|
|
459
|
+
methods: comp.methods || [],
|
|
460
|
+
related: comp.related || [],
|
|
461
|
+
faq: comp.faq || []
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
name: comp.name,
|
|
466
|
+
nameZh: comp.nameZh ?? "",
|
|
467
|
+
description: desc,
|
|
468
|
+
props: comp.props.map((p) => ({
|
|
469
|
+
name: p.name,
|
|
470
|
+
type: p.type,
|
|
471
|
+
default: p.default,
|
|
472
|
+
since: p.since ?? ""
|
|
473
|
+
})),
|
|
474
|
+
subComponentProps: comp.subComponentProps ? Object.fromEntries(
|
|
475
|
+
Object.entries(comp.subComponentProps).map(([name, props]) => [
|
|
476
|
+
name,
|
|
477
|
+
props.map((p) => ({ name: p.name, type: p.type, default: p.default }))
|
|
478
|
+
])
|
|
479
|
+
) : void 0
|
|
480
|
+
};
|
|
404
481
|
}
|
|
405
482
|
function registerInfoCommand(program2) {
|
|
406
483
|
program2.command("info <component>").description("Query component API: props, type definitions, default values").action((component) => {
|
|
407
484
|
const opts = program2.opts();
|
|
408
485
|
const lang = opts.lang;
|
|
409
486
|
const versionInfo = detectVersion(opts.version);
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
`Component '${component}' not found`,
|
|
418
|
-
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
419
|
-
);
|
|
420
|
-
printError(err, opts.format);
|
|
487
|
+
const result = getComponentInfo(component, {
|
|
488
|
+
lang,
|
|
489
|
+
version: versionInfo.version,
|
|
490
|
+
detail: opts.detail
|
|
491
|
+
});
|
|
492
|
+
if ("error" in result) {
|
|
493
|
+
printError(result, opts.format);
|
|
421
494
|
process.exitCode = 1;
|
|
422
495
|
return;
|
|
423
496
|
}
|
|
424
|
-
const desc = localize(comp.description, comp.descriptionZh, lang);
|
|
425
|
-
const whenToUse = localize(comp.whenToUse, comp.whenToUseZh, lang);
|
|
426
497
|
if (opts.format === "json") {
|
|
427
|
-
|
|
428
|
-
output(
|
|
429
|
-
{
|
|
430
|
-
name: comp.name,
|
|
431
|
-
nameZh: comp.nameZh ?? "",
|
|
432
|
-
description: desc,
|
|
433
|
-
whenToUse: whenToUse || "",
|
|
434
|
-
props: comp.props.map((p) => ({
|
|
435
|
-
...p,
|
|
436
|
-
description: localize(p.description, p.descriptionZh, lang)
|
|
437
|
-
})),
|
|
438
|
-
subComponentProps: comp.subComponentProps ? Object.fromEntries(
|
|
439
|
-
Object.entries(comp.subComponentProps).map(([name, props]) => [
|
|
440
|
-
name,
|
|
441
|
-
props.map((p) => ({ ...p, description: localize(p.description, p.descriptionZh, lang) }))
|
|
442
|
-
])
|
|
443
|
-
) : void 0,
|
|
444
|
-
methods: comp.methods || [],
|
|
445
|
-
related: comp.related || [],
|
|
446
|
-
faq: comp.faq || []
|
|
447
|
-
},
|
|
448
|
-
"json"
|
|
449
|
-
);
|
|
450
|
-
} else {
|
|
451
|
-
output(
|
|
452
|
-
{
|
|
453
|
-
name: comp.name,
|
|
454
|
-
nameZh: comp.nameZh ?? "",
|
|
455
|
-
description: desc,
|
|
456
|
-
props: comp.props.map((p) => ({
|
|
457
|
-
name: p.name,
|
|
458
|
-
type: p.type,
|
|
459
|
-
default: p.default,
|
|
460
|
-
since: p.since ?? ""
|
|
461
|
-
})),
|
|
462
|
-
subComponentProps: comp.subComponentProps ? Object.fromEntries(
|
|
463
|
-
Object.entries(comp.subComponentProps).map(([name, props]) => [
|
|
464
|
-
name,
|
|
465
|
-
props.map((p) => ({ name: p.name, type: p.type, default: p.default }))
|
|
466
|
-
])
|
|
467
|
-
) : void 0
|
|
468
|
-
},
|
|
469
|
-
"json"
|
|
470
|
-
);
|
|
471
|
-
}
|
|
498
|
+
output(result, "json");
|
|
472
499
|
return;
|
|
473
500
|
}
|
|
474
501
|
const fmt = opts.format === "markdown" ? "markdown" : "text";
|
|
475
|
-
const nameLabel =
|
|
476
|
-
console.log(`${nameLabel} \u2014 ${
|
|
477
|
-
if (opts.detail && whenToUse) {
|
|
502
|
+
const nameLabel = result.nameZh ? `${result.name} (${result.nameZh})` : result.name;
|
|
503
|
+
console.log(`${nameLabel} \u2014 ${result.description}`);
|
|
504
|
+
if (opts.detail && "whenToUse" in result && result.whenToUse) {
|
|
478
505
|
console.log(`
|
|
479
|
-
When to use: ${whenToUse}`);
|
|
506
|
+
When to use: ${result.whenToUse}`);
|
|
480
507
|
}
|
|
481
508
|
console.log("");
|
|
482
509
|
const headers = opts.detail ? ["Property", "Type", "Default", "Since", "Description"] : ["Property", "Type", "Default", "Since"];
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
510
|
+
const rows = result.props.map((p) => {
|
|
511
|
+
const s = "since" in p && p.since ? String(p.since) : "-";
|
|
512
|
+
return opts.detail && "description" in p ? [p.name, p.type, p.default, s, p.description || "-"] : [p.name, p.type, p.default, s];
|
|
513
|
+
});
|
|
514
|
+
console.log(formatTable(headers, rows, fmt));
|
|
515
|
+
if (result.subComponentProps) {
|
|
516
|
+
for (const [subName, subProps] of Object.entries(result.subComponentProps)) {
|
|
486
517
|
console.log(`
|
|
487
518
|
${subName}`);
|
|
488
519
|
console.log("");
|
|
489
|
-
|
|
520
|
+
const subRows = subProps.map((p) => {
|
|
521
|
+
const prop = p;
|
|
522
|
+
return opts.detail ? [prop.name, prop.type, prop.default, prop.since || "-", prop.description || "-"] : [prop.name, prop.type, prop.default, prop.since || "-"];
|
|
523
|
+
});
|
|
524
|
+
console.log(formatTable(headers, subRows, fmt));
|
|
490
525
|
}
|
|
491
526
|
}
|
|
492
|
-
if (opts.detail &&
|
|
527
|
+
if (opts.detail && "related" in result && result.related.length > 0) {
|
|
493
528
|
console.log(`
|
|
494
|
-
Related: ${
|
|
529
|
+
Related: ${result.related.join(", ")}`);
|
|
495
530
|
}
|
|
496
531
|
});
|
|
497
532
|
}
|
|
498
533
|
|
|
499
534
|
// src/commands/doc.ts
|
|
535
|
+
function getComponentDoc(component, opts) {
|
|
536
|
+
const resolved = resolveComponent(component, opts.version);
|
|
537
|
+
if ("error" in resolved) return resolved;
|
|
538
|
+
const { comp } = resolved;
|
|
539
|
+
const doc = localize(comp.doc, comp.docZh, opts.lang);
|
|
540
|
+
if (!doc) {
|
|
541
|
+
return createError(
|
|
542
|
+
ErrorCodes.DOC_NOT_AVAILABLE,
|
|
543
|
+
`Documentation not available for '${comp.name}'`,
|
|
544
|
+
"Try upgrading to a newer version of the CLI"
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
return { name: comp.name, doc };
|
|
548
|
+
}
|
|
500
549
|
function registerDocCommand(program2) {
|
|
501
550
|
program2.command("doc <component>").description("Output the full API documentation for a component in markdown").action((component) => {
|
|
502
551
|
const opts = program2.opts();
|
|
503
552
|
const lang = opts.lang;
|
|
504
553
|
const versionInfo = detectVersion(opts.version);
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
ErrorCodes.COMPONENT_NOT_FOUND,
|
|
512
|
-
`Component '${component}' not found`,
|
|
513
|
-
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
514
|
-
);
|
|
515
|
-
printError(err, opts.format);
|
|
516
|
-
process.exitCode = 1;
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
const doc = localize(comp.doc, comp.docZh, lang);
|
|
520
|
-
if (!doc) {
|
|
521
|
-
const err = createError(
|
|
522
|
-
"DOC_NOT_AVAILABLE",
|
|
523
|
-
`Documentation not available for '${comp.name}'`,
|
|
524
|
-
"Try upgrading to a newer version of the CLI"
|
|
525
|
-
);
|
|
526
|
-
printError(err, opts.format);
|
|
554
|
+
const result = getComponentDoc(component, {
|
|
555
|
+
lang,
|
|
556
|
+
version: versionInfo.version
|
|
557
|
+
});
|
|
558
|
+
if ("error" in result) {
|
|
559
|
+
printError(result, opts.format);
|
|
527
560
|
process.exitCode = 1;
|
|
528
561
|
return;
|
|
529
562
|
}
|
|
530
563
|
if (opts.format === "json") {
|
|
531
|
-
output({ name:
|
|
564
|
+
output({ name: result.name, doc: result.doc }, "json");
|
|
532
565
|
return;
|
|
533
566
|
}
|
|
534
|
-
process.stdout.write(doc + "\n");
|
|
567
|
+
process.stdout.write(result.doc + "\n");
|
|
535
568
|
});
|
|
536
569
|
}
|
|
537
570
|
|
|
538
571
|
// src/commands/demo.ts
|
|
572
|
+
function getComponentDemo(component, opts) {
|
|
573
|
+
const resolved = resolveComponent(component, opts.version);
|
|
574
|
+
if ("error" in resolved) return resolved;
|
|
575
|
+
const { comp } = resolved;
|
|
576
|
+
const demos = comp.demos || [];
|
|
577
|
+
if (!opts.name) {
|
|
578
|
+
return {
|
|
579
|
+
component: comp.name,
|
|
580
|
+
demos: demos.map((d) => ({
|
|
581
|
+
name: d.name,
|
|
582
|
+
title: d.title,
|
|
583
|
+
description: d.description
|
|
584
|
+
}))
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
const demo = demos.find((d) => d.name.toLowerCase() === opts.name.toLowerCase());
|
|
588
|
+
if (!demo) {
|
|
589
|
+
const demoNames = demos.map((d) => d.name);
|
|
590
|
+
const suggestion = fuzzyMatch(opts.name, demoNames);
|
|
591
|
+
return createError(
|
|
592
|
+
ErrorCodes.DEMO_NOT_FOUND,
|
|
593
|
+
`Demo '${opts.name}' not found for ${comp.name}`,
|
|
594
|
+
suggestion ? `Did you mean '${suggestion}'?` : `Available demos: ${demoNames.join(", ") || "none"}`
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
component: comp.name,
|
|
599
|
+
demo: demo.name,
|
|
600
|
+
title: demo.title,
|
|
601
|
+
description: demo.description,
|
|
602
|
+
code: demo.code
|
|
603
|
+
};
|
|
604
|
+
}
|
|
539
605
|
function registerDemoCommand(program2) {
|
|
540
606
|
program2.command("demo <component> [name]").description("Get demo source code for a component").action((component, name) => {
|
|
541
607
|
const opts = program2.opts();
|
|
542
608
|
const versionInfo = detectVersion(opts.version);
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
ErrorCodes.COMPONENT_NOT_FOUND,
|
|
550
|
-
`Component '${component}' not found`,
|
|
551
|
-
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
552
|
-
);
|
|
553
|
-
printError(err, opts.format);
|
|
609
|
+
const result = getComponentDemo(component, {
|
|
610
|
+
version: versionInfo.version,
|
|
611
|
+
name
|
|
612
|
+
});
|
|
613
|
+
if ("error" in result) {
|
|
614
|
+
printError(result, opts.format);
|
|
554
615
|
process.exitCode = 1;
|
|
555
616
|
return;
|
|
556
617
|
}
|
|
557
|
-
|
|
558
|
-
if (!name) {
|
|
618
|
+
if ("code" in result) {
|
|
559
619
|
if (opts.format === "json") {
|
|
560
|
-
output(
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
);
|
|
620
|
+
output(result, "json");
|
|
621
|
+
} else {
|
|
622
|
+
console.log(`${result.component} / ${result.title}`);
|
|
623
|
+
console.log(`${result.description}`);
|
|
624
|
+
console.log("");
|
|
625
|
+
console.log(result.code);
|
|
626
|
+
}
|
|
627
|
+
} else {
|
|
628
|
+
if (opts.format === "json") {
|
|
629
|
+
output(result, "json");
|
|
571
630
|
} else {
|
|
572
|
-
console.log(`${
|
|
631
|
+
console.log(`${result.component} Demos:`);
|
|
573
632
|
console.log("");
|
|
574
|
-
for (const
|
|
575
|
-
console.log(` ${
|
|
576
|
-
console.log(` ${
|
|
633
|
+
for (const demo of result.demos) {
|
|
634
|
+
console.log(` ${demo.name} \u2014 ${demo.title}`);
|
|
635
|
+
console.log(` ${demo.description}`);
|
|
577
636
|
}
|
|
578
|
-
if (demos.length === 0) {
|
|
637
|
+
if (result.demos.length === 0) {
|
|
579
638
|
console.log(" No demos available.");
|
|
580
639
|
}
|
|
581
640
|
}
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
const demo = demos.find((d) => d.name.toLowerCase() === name.toLowerCase());
|
|
585
|
-
if (!demo) {
|
|
586
|
-
const demoNames = demos.map((d) => d.name);
|
|
587
|
-
const suggestion = fuzzyMatch(name, demoNames);
|
|
588
|
-
const err = createError(
|
|
589
|
-
ErrorCodes.DEMO_NOT_FOUND,
|
|
590
|
-
`Demo '${name}' not found for ${comp.name}`,
|
|
591
|
-
suggestion ? `Did you mean '${suggestion}'?` : `Available demos: ${demoNames.join(", ") || "none"}`
|
|
592
|
-
);
|
|
593
|
-
printError(err, opts.format);
|
|
594
|
-
process.exitCode = 1;
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
if (opts.format === "json") {
|
|
598
|
-
output(
|
|
599
|
-
{
|
|
600
|
-
component: comp.name,
|
|
601
|
-
demo: demo.name,
|
|
602
|
-
title: demo.title,
|
|
603
|
-
description: demo.description,
|
|
604
|
-
code: demo.code
|
|
605
|
-
},
|
|
606
|
-
"json"
|
|
607
|
-
);
|
|
608
|
-
} else {
|
|
609
|
-
console.log(`${comp.name} / ${demo.title}`);
|
|
610
|
-
console.log(`${demo.description}`);
|
|
611
|
-
console.log("");
|
|
612
|
-
console.log(demo.code);
|
|
613
641
|
}
|
|
614
642
|
});
|
|
615
643
|
}
|
|
616
644
|
|
|
617
645
|
// src/commands/token.ts
|
|
646
|
+
function getTokens(component, opts) {
|
|
647
|
+
const major = `v${opts.version.split(".")[0]}`;
|
|
648
|
+
if (major === "v4") {
|
|
649
|
+
return createError(
|
|
650
|
+
ErrorCodes.UNSUPPORTED_VERSION_FEATURE,
|
|
651
|
+
"Design Token system is not available in antd v4",
|
|
652
|
+
"Upgrade to antd v5+ to use Design Tokens"
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
if (!component) {
|
|
656
|
+
const store = loadMetadataForVersion(opts.version);
|
|
657
|
+
const globalTokens = store.globalTokens || [];
|
|
658
|
+
return { tokens: globalTokens };
|
|
659
|
+
}
|
|
660
|
+
const resolved = resolveComponent(component, opts.version);
|
|
661
|
+
if ("error" in resolved) return resolved;
|
|
662
|
+
const { comp } = resolved;
|
|
663
|
+
const tokens = comp.tokens || [];
|
|
664
|
+
return { component: comp.name, tokens };
|
|
665
|
+
}
|
|
618
666
|
function registerTokenCommand(program2) {
|
|
619
667
|
program2.command("token [component]").description("Query Design Tokens (global or component-level)").action((component) => {
|
|
620
668
|
const opts = program2.opts();
|
|
621
669
|
const versionInfo = detectVersion(opts.version);
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
);
|
|
628
|
-
printError(err, opts.format);
|
|
670
|
+
const result = getTokens(component, {
|
|
671
|
+
lang: opts.lang,
|
|
672
|
+
version: versionInfo.version
|
|
673
|
+
});
|
|
674
|
+
if ("error" in result) {
|
|
675
|
+
printError(result, opts.format);
|
|
629
676
|
process.exitCode = 1;
|
|
630
677
|
return;
|
|
631
678
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
679
|
+
if ("component" in result) {
|
|
680
|
+
if (result.tokens.length === 0) {
|
|
681
|
+
console.log(`No component tokens available for ${result.component}.`);
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
if (opts.format === "json") {
|
|
685
|
+
output(result, "json");
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
console.log(`${result.component} Component Tokens:`);
|
|
689
|
+
console.log("");
|
|
690
|
+
const headers = ["Token", "Type", "Default"];
|
|
691
|
+
const rows = result.tokens.map((t) => [t.name, t.type, t.default]);
|
|
692
|
+
console.log(formatTable(headers, rows, opts.format === "markdown" ? "markdown" : "text"));
|
|
693
|
+
} else {
|
|
694
|
+
if (result.tokens.length === 0) {
|
|
636
695
|
console.log("No global token data available.");
|
|
637
696
|
return;
|
|
638
697
|
}
|
|
639
698
|
if (opts.format === "json") {
|
|
640
|
-
output(
|
|
699
|
+
output(result, "json");
|
|
641
700
|
return;
|
|
642
701
|
}
|
|
643
702
|
console.log("Global Design Tokens:");
|
|
644
703
|
console.log("");
|
|
645
|
-
const
|
|
646
|
-
const
|
|
704
|
+
const headers = ["Token", "Type", "Default", "Description"];
|
|
705
|
+
const rows = result.tokens.map((t) => [
|
|
647
706
|
t.name,
|
|
648
707
|
t.type,
|
|
649
708
|
t.default,
|
|
650
709
|
localize(t.description, t.descriptionZh, opts.lang) || "-"
|
|
651
710
|
]);
|
|
652
|
-
console.log(formatTable(
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
const comp = findComponent(store, component);
|
|
656
|
-
if (!comp) {
|
|
657
|
-
const names = getAllComponentNames(store);
|
|
658
|
-
const suggestion = fuzzyMatch(component, names);
|
|
659
|
-
const err = createError(
|
|
660
|
-
ErrorCodes.COMPONENT_NOT_FOUND,
|
|
661
|
-
`Component '${component}' not found`,
|
|
662
|
-
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
663
|
-
);
|
|
664
|
-
printError(err, opts.format);
|
|
665
|
-
process.exitCode = 1;
|
|
666
|
-
return;
|
|
711
|
+
console.log(formatTable(headers, rows, opts.format === "markdown" ? "markdown" : "text"));
|
|
667
712
|
}
|
|
668
|
-
const tokens = comp.tokens || [];
|
|
669
|
-
if (tokens.length === 0) {
|
|
670
|
-
console.log(`No component tokens available for ${comp.name}.`);
|
|
671
|
-
return;
|
|
672
|
-
}
|
|
673
|
-
if (opts.format === "json") {
|
|
674
|
-
output({ component: comp.name, tokens }, "json");
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
console.log(`${comp.name} Component Tokens:`);
|
|
678
|
-
console.log("");
|
|
679
|
-
const headers = ["Token", "Type", "Default"];
|
|
680
|
-
const rows = tokens.map((t) => [t.name, t.type, t.default]);
|
|
681
|
-
console.log(formatTable(headers, rows, opts.format === "markdown" ? "markdown" : "text"));
|
|
682
713
|
});
|
|
683
714
|
}
|
|
684
715
|
|
|
685
716
|
// src/commands/semantic.ts
|
|
717
|
+
function getSemanticStructure(component, opts) {
|
|
718
|
+
const resolved = resolveComponent(component, opts.version);
|
|
719
|
+
if ("error" in resolved) return resolved;
|
|
720
|
+
const { comp } = resolved;
|
|
721
|
+
const structure = comp.semanticStructure || [];
|
|
722
|
+
return { name: comp.name, semanticStructure: structure };
|
|
723
|
+
}
|
|
686
724
|
function registerSemanticCommand(program2) {
|
|
687
725
|
program2.command("semantic <component>").description("Query the semantic customization structure of a component").action((component) => {
|
|
688
726
|
const opts = program2.opts();
|
|
689
727
|
const versionInfo = detectVersion(opts.version);
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const err = createError(
|
|
696
|
-
ErrorCodes.COMPONENT_NOT_FOUND,
|
|
697
|
-
`Component '${component}' not found`,
|
|
698
|
-
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
699
|
-
);
|
|
700
|
-
printError(err, opts.format);
|
|
728
|
+
const result = getSemanticStructure(component, {
|
|
729
|
+
version: versionInfo.version
|
|
730
|
+
});
|
|
731
|
+
if ("error" in result) {
|
|
732
|
+
printError(result, opts.format);
|
|
701
733
|
process.exitCode = 1;
|
|
702
734
|
return;
|
|
703
735
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
console.log(`No semantic structure data available for ${comp.name}.`);
|
|
736
|
+
if (result.semanticStructure.length === 0) {
|
|
737
|
+
console.log(`No semantic structure data available for ${result.name}.`);
|
|
707
738
|
return;
|
|
708
739
|
}
|
|
709
740
|
if (opts.format === "json") {
|
|
710
|
-
output(
|
|
741
|
+
output(result, "json");
|
|
711
742
|
return;
|
|
712
743
|
}
|
|
713
|
-
console.log(`${
|
|
744
|
+
console.log(`${result.name} Semantic Structure:`);
|
|
745
|
+
const structure = result.semanticStructure;
|
|
714
746
|
for (let i = 0; i < structure.length; i++) {
|
|
715
747
|
const prefix = i === structure.length - 1 ? "\u2514\u2500\u2500" : "\u251C\u2500\u2500";
|
|
716
748
|
console.log(`${prefix} ${structure[i].key} # ${structure[i].description}`);
|
|
717
749
|
}
|
|
718
750
|
console.log("");
|
|
719
751
|
console.log("Usage:");
|
|
720
|
-
console.log(` <${
|
|
721
|
-
console.log(` <${
|
|
752
|
+
console.log(` <${result.name} classNames={{ ${structure[0]?.key}: 'my-${structure[0]?.key}' }} />`);
|
|
753
|
+
console.log(` <${result.name} styles={{ ${structure[0]?.key}: { background: '#fff' } }} />`);
|
|
722
754
|
});
|
|
723
755
|
}
|
|
724
756
|
|
|
@@ -748,21 +780,6 @@ var EMOJI_MAP = {
|
|
|
748
780
|
breaking: "\u{1F525}",
|
|
749
781
|
other: "\u{1F6E0}"
|
|
750
782
|
};
|
|
751
|
-
function printChangelog(entries, format, versionArg) {
|
|
752
|
-
if (format === "json") {
|
|
753
|
-
output(versionArg ? entries : { latest: entries }, "json");
|
|
754
|
-
return;
|
|
755
|
-
}
|
|
756
|
-
for (const entry of entries) {
|
|
757
|
-
console.log(`## ${entry.version} (${entry.date})`);
|
|
758
|
-
console.log("");
|
|
759
|
-
for (const change of entry.changes) {
|
|
760
|
-
const emoji = EMOJI_MAP[change.type] || "\u2022";
|
|
761
|
-
console.log(` ${emoji} ${change.component} ${change.description}`);
|
|
762
|
-
}
|
|
763
|
-
console.log("");
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
783
|
function diffProps(oldProps, newProps) {
|
|
767
784
|
const oldMap = new Map(oldProps.map((p) => [p.name, p]));
|
|
768
785
|
const newMap = new Map(newProps.map((p) => [p.name, p]));
|
|
@@ -789,32 +806,53 @@ function diffProps(oldProps, newProps) {
|
|
|
789
806
|
}
|
|
790
807
|
return { added, removed, changed };
|
|
791
808
|
}
|
|
792
|
-
function
|
|
793
|
-
const
|
|
794
|
-
const
|
|
809
|
+
function queryChangelog(opts) {
|
|
810
|
+
const store = loadMetadataForVersion(opts.snapshotVersion);
|
|
811
|
+
const changelog = store.changelog || [];
|
|
812
|
+
if (changelog.length === 0) {
|
|
813
|
+
return createError(
|
|
814
|
+
ErrorCodes.VERSION_NOT_FOUND,
|
|
815
|
+
"No changelog data available"
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
const entries = filterEntries(changelog, opts.entryFilter);
|
|
819
|
+
if (entries.length === 0) {
|
|
820
|
+
return createError(
|
|
821
|
+
ErrorCodes.VERSION_NOT_FOUND,
|
|
822
|
+
`No changelog entries found for "${opts.entryFilter}"`,
|
|
823
|
+
`Available versions: ${changelog.map((e) => e.version).join(", ")}`
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
return { entries, versionArg: opts.entryFilter };
|
|
827
|
+
}
|
|
828
|
+
function diffChangelog(opts) {
|
|
829
|
+
if (compare(opts.v1, opts.v2) > 0) {
|
|
830
|
+
return createError(
|
|
831
|
+
ErrorCodes.INVALID_ARGUMENT,
|
|
832
|
+
`Version order is invalid: "${opts.v1}" is newer than "${opts.v2}"`,
|
|
833
|
+
`Swap the versions: v1=${opts.v2}, v2=${opts.v1}`
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
const store1 = loadMetadataForVersion(opts.v1);
|
|
837
|
+
const store2 = loadMetadataForVersion(opts.v2);
|
|
795
838
|
if (store1.components.length === 0) {
|
|
796
|
-
|
|
797
|
-
process.exitCode = 1;
|
|
798
|
-
return;
|
|
839
|
+
return createError(ErrorCodes.VERSION_NOT_FOUND, `No data available for version ${opts.v1}`);
|
|
799
840
|
}
|
|
800
841
|
if (store2.components.length === 0) {
|
|
801
|
-
|
|
802
|
-
process.exitCode = 1;
|
|
803
|
-
return;
|
|
842
|
+
return createError(ErrorCodes.VERSION_NOT_FOUND, `No data available for version ${opts.v2}`);
|
|
804
843
|
}
|
|
805
|
-
const componentsToCompare = component ? [component] : [.../* @__PURE__ */ new Set([...getAllComponentNames(store1), ...getAllComponentNames(store2)])];
|
|
806
|
-
if (component) {
|
|
807
|
-
const c1 = findComponent(store1, component);
|
|
808
|
-
const c2 = findComponent(store2, component);
|
|
844
|
+
const componentsToCompare = opts.component ? [opts.component] : [.../* @__PURE__ */ new Set([...getAllComponentNames(store1), ...getAllComponentNames(store2)])];
|
|
845
|
+
if (opts.component) {
|
|
846
|
+
const c1 = findComponent(store1, opts.component);
|
|
847
|
+
const c2 = findComponent(store2, opts.component);
|
|
809
848
|
if (!c1 && !c2) {
|
|
810
849
|
const allNames = [.../* @__PURE__ */ new Set([...getAllComponentNames(store1), ...getAllComponentNames(store2)])];
|
|
811
|
-
const suggestion = fuzzyMatch(component, allNames);
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
opts.
|
|
850
|
+
const suggestion = fuzzyMatch(opts.component, allNames);
|
|
851
|
+
return createError(
|
|
852
|
+
ErrorCodes.COMPONENT_NOT_FOUND,
|
|
853
|
+
`Component '${opts.component}' not found in either version`,
|
|
854
|
+
suggestion ? `Did you mean '${suggestion}'?` : void 0
|
|
815
855
|
);
|
|
816
|
-
process.exitCode = 1;
|
|
817
|
-
return;
|
|
818
856
|
}
|
|
819
857
|
}
|
|
820
858
|
const diffs = [];
|
|
@@ -832,18 +870,36 @@ function runApiDiff(v1, v2, component, opts) {
|
|
|
832
870
|
}
|
|
833
871
|
}
|
|
834
872
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
873
|
+
return { from: opts.v1, to: opts.v2, diffs, component: opts.component };
|
|
874
|
+
}
|
|
875
|
+
function printChangelogEntries(entries, format, versionArg) {
|
|
876
|
+
if (format === "json") {
|
|
877
|
+
output(versionArg ? entries : { latest: entries }, "json");
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
for (const entry of entries) {
|
|
881
|
+
console.log(`## ${entry.version} (${entry.date})`);
|
|
882
|
+
console.log("");
|
|
883
|
+
for (const change of entry.changes) {
|
|
884
|
+
const emoji = EMOJI_MAP[change.type] || "\u2022";
|
|
885
|
+
console.log(` ${emoji} ${change.component} ${change.description}`);
|
|
886
|
+
}
|
|
887
|
+
console.log("");
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
function printApiDiff(result, format) {
|
|
891
|
+
if (format === "json") {
|
|
892
|
+
const jsonResult = result.component && result.diffs.length > 0 ? { from: result.from, to: result.to, ...result.diffs[0] } : { from: result.from, to: result.to, diffs: result.diffs };
|
|
893
|
+
output(jsonResult, "json");
|
|
838
894
|
return;
|
|
839
895
|
}
|
|
840
|
-
if (diffs.length === 0) {
|
|
841
|
-
console.log(`No API differences found between ${
|
|
896
|
+
if (result.diffs.length === 0) {
|
|
897
|
+
console.log(`No API differences found between ${result.from} and ${result.to}.`);
|
|
842
898
|
return;
|
|
843
899
|
}
|
|
844
|
-
console.log(`API Diff: ${
|
|
900
|
+
console.log(`API Diff: ${result.from} \u2192 ${result.to}`);
|
|
845
901
|
console.log("");
|
|
846
|
-
for (const diff of diffs) {
|
|
902
|
+
for (const diff of result.diffs) {
|
|
847
903
|
console.log(` ${diff.component}:`);
|
|
848
904
|
for (const p of diff.added) console.log(` + ${p.name}: ${p.type}`);
|
|
849
905
|
for (const p of diff.removed) {
|
|
@@ -862,36 +918,28 @@ function registerChangelogCommand(program2) {
|
|
|
862
918
|
const v1ForDetect = v1?.includes("..") ? v1.split("..")[1] : v1;
|
|
863
919
|
const versionForDetect = opts.version ?? (v1ForDetect && /^\d+\.\d+\.\d+$/.test(v1ForDetect) ? v1ForDetect : void 0);
|
|
864
920
|
const versionInfo = detectVersion(versionForDetect);
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
`No changelog entries found for "${v1}"`,
|
|
876
|
-
`Available versions: ${changelog.map((e) => e.version).join(", ")}`
|
|
877
|
-
);
|
|
878
|
-
printError(err, opts.format);
|
|
921
|
+
const result = queryChangelog({
|
|
922
|
+
snapshotVersion: versionInfo.version,
|
|
923
|
+
entryFilter: v1
|
|
924
|
+
});
|
|
925
|
+
if ("error" in result) {
|
|
926
|
+
if (result.code === ErrorCodes.VERSION_NOT_FOUND && !result.suggestion) {
|
|
927
|
+
console.log("No changelog data available.");
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
printError(result, opts.format);
|
|
879
931
|
process.exitCode = 1;
|
|
880
932
|
return;
|
|
881
933
|
}
|
|
882
|
-
|
|
934
|
+
printChangelogEntries(result.entries, opts.format, result.versionArg);
|
|
883
935
|
} else {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
`Version order is invalid: "${v1}" is newer than "${v2}"`,
|
|
888
|
-
`Did you mean: antd changelog ${v2} ${v1}${component ? " " + component : ""}?`
|
|
889
|
-
);
|
|
890
|
-
printError(err, opts.format);
|
|
936
|
+
const result = diffChangelog({ v1, v2, component });
|
|
937
|
+
if ("error" in result) {
|
|
938
|
+
printError(result, opts.format);
|
|
891
939
|
process.exitCode = 1;
|
|
892
940
|
return;
|
|
893
941
|
}
|
|
894
|
-
|
|
942
|
+
printApiDiff(result, opts.format);
|
|
895
943
|
}
|
|
896
944
|
});
|
|
897
945
|
}
|
|
@@ -905,7 +953,6 @@ import { readFileSync as readFileSync3, readdirSync, statSync } from "fs";
|
|
|
905
953
|
import { join as join3, extname } from "path";
|
|
906
954
|
var SCAN_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
907
955
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next"]);
|
|
908
|
-
var ANTD_IMPORT_RE = /import\s+\{([^}]+)\}\s+from\s+['"]antd(?:\/[^'"]*)?['"]/g;
|
|
909
956
|
function collectFiles(dir) {
|
|
910
957
|
const files = [];
|
|
911
958
|
try {
|
|
@@ -929,15 +976,14 @@ function collectFiles(dir) {
|
|
|
929
976
|
}
|
|
930
977
|
return files;
|
|
931
978
|
}
|
|
932
|
-
function
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
let match;
|
|
936
|
-
while ((match = ANTD_IMPORT_RE.exec(content)) !== null) {
|
|
937
|
-
const parsed = match[1].split(",").map((n) => n.trim()).filter((n) => Boolean(n) && !/^type\s/.test(n));
|
|
938
|
-
names.push(...parsed);
|
|
979
|
+
function getJSXElementName(name) {
|
|
980
|
+
if (name.type === "JSXMemberExpression") {
|
|
981
|
+
return getJSXElementName(name.object) + "." + name.property.name;
|
|
939
982
|
}
|
|
940
|
-
|
|
983
|
+
if (name.type === "JSXIdentifier") {
|
|
984
|
+
return name.name;
|
|
985
|
+
}
|
|
986
|
+
return "";
|
|
941
987
|
}
|
|
942
988
|
function readJson(path) {
|
|
943
989
|
try {
|
|
@@ -1317,7 +1363,7 @@ function registerDoctorCommand(program2) {
|
|
|
1317
1363
|
|
|
1318
1364
|
// src/commands/usage.ts
|
|
1319
1365
|
import { readFileSync as readFileSync5 } from "fs";
|
|
1320
|
-
|
|
1366
|
+
import { parseSync, Visitor } from "oxc-parser";
|
|
1321
1367
|
function scanFile(filePath) {
|
|
1322
1368
|
const result = /* @__PURE__ */ new Map();
|
|
1323
1369
|
let content;
|
|
@@ -1326,23 +1372,43 @@ function scanFile(filePath) {
|
|
|
1326
1372
|
} catch {
|
|
1327
1373
|
return result;
|
|
1328
1374
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1375
|
+
if (!content.includes("antd")) return result;
|
|
1376
|
+
const parsed = parseSync(filePath, content);
|
|
1377
|
+
if (parsed.errors.length > 0) return result;
|
|
1378
|
+
const importedNames = /* @__PURE__ */ new Set();
|
|
1379
|
+
const visitor = new Visitor({
|
|
1380
|
+
ImportDeclaration(node) {
|
|
1381
|
+
const source = node.source.value;
|
|
1382
|
+
if (source !== "antd" && !source.startsWith("antd/")) return;
|
|
1383
|
+
if (node.importKind === "type") return;
|
|
1384
|
+
for (const spec of node.specifiers) {
|
|
1385
|
+
if (spec.type === "ImportSpecifier") {
|
|
1386
|
+
if (spec.importKind === "type") continue;
|
|
1387
|
+
const name = spec.imported?.name || spec.local?.name;
|
|
1388
|
+
if (name) {
|
|
1389
|
+
importedNames.add(name);
|
|
1390
|
+
if (!result.has(name)) {
|
|
1391
|
+
result.set(name, { count: 0, subComponents: /* @__PURE__ */ new Map() });
|
|
1392
|
+
}
|
|
1393
|
+
result.get(name).count++;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
},
|
|
1398
|
+
// Detect sub-component JSX usage: <Form.Item>, <Table.Column>, etc.
|
|
1399
|
+
JSXOpeningElement(node) {
|
|
1400
|
+
const fullName = getJSXElementName(node.name);
|
|
1401
|
+
if (!fullName.includes(".")) return;
|
|
1402
|
+
const [parent] = fullName.split(".");
|
|
1403
|
+
if (importedNames.has(parent)) {
|
|
1404
|
+
const entry = result.get(parent);
|
|
1405
|
+
if (entry) {
|
|
1406
|
+
entry.subComponents.set(fullName, (entry.subComponents.get(fullName) || 0) + 1);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1344
1409
|
}
|
|
1345
|
-
}
|
|
1410
|
+
});
|
|
1411
|
+
visitor.visit(parsed.program);
|
|
1346
1412
|
return result;
|
|
1347
1413
|
}
|
|
1348
1414
|
function registerUsageCommand(program2) {
|
|
@@ -1429,9 +1495,7 @@ Non-component antd exports (${nonComponents.length}):`);
|
|
|
1429
1495
|
|
|
1430
1496
|
// src/commands/lint.ts
|
|
1431
1497
|
import { readFileSync as readFileSync6 } from "fs";
|
|
1432
|
-
|
|
1433
|
-
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1434
|
-
}
|
|
1498
|
+
import { parseSync as parseSync2, Visitor as Visitor2 } from "oxc-parser";
|
|
1435
1499
|
function getDeprecatedProps(store) {
|
|
1436
1500
|
const result = /* @__PURE__ */ new Map();
|
|
1437
1501
|
for (const comp of store.components) {
|
|
@@ -1450,248 +1514,197 @@ function getDeprecatedProps(store) {
|
|
|
1450
1514
|
}
|
|
1451
1515
|
return result;
|
|
1452
1516
|
}
|
|
1453
|
-
function
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1517
|
+
function findAttr(attrs, name) {
|
|
1518
|
+
return attrs.find((a) => a.type === "JSXAttribute" && a.name?.name === name) ?? null;
|
|
1519
|
+
}
|
|
1520
|
+
function hasAttr(attrs, name) {
|
|
1521
|
+
return findAttr(attrs, name) !== null;
|
|
1522
|
+
}
|
|
1523
|
+
function getStringAttrValue(attrs, name) {
|
|
1524
|
+
const a = findAttr(attrs, name);
|
|
1525
|
+
if (!a) return null;
|
|
1526
|
+
if (a.value?.type === "Literal" && typeof a.value.value === "string") {
|
|
1527
|
+
return a.value.value;
|
|
1528
|
+
}
|
|
1529
|
+
if (a.value?.type === "JSXExpressionContainer" && a.value.expression?.type === "Literal" && typeof a.value.expression.value === "string") {
|
|
1530
|
+
return a.value.expression.value;
|
|
1531
|
+
}
|
|
1532
|
+
return null;
|
|
1533
|
+
}
|
|
1534
|
+
function isBooleanFalse(attrs, name) {
|
|
1535
|
+
const a = findAttr(attrs, name);
|
|
1536
|
+
if (!a) return false;
|
|
1537
|
+
return a.value?.type === "JSXExpressionContainer" && a.value.expression?.type === "Literal" && a.value.expression.value === false;
|
|
1538
|
+
}
|
|
1539
|
+
function isObjectExpression(attrs, name) {
|
|
1540
|
+
const a = findAttr(attrs, name);
|
|
1541
|
+
if (!a) return false;
|
|
1542
|
+
return a.value?.type === "JSXExpressionContainer" && a.value.expression?.type === "ObjectExpression";
|
|
1543
|
+
}
|
|
1544
|
+
function getObjectExpressionKeys(attrs, name) {
|
|
1545
|
+
const a = findAttr(attrs, name);
|
|
1546
|
+
if (!a) return [];
|
|
1547
|
+
if (a.value?.type === "JSXExpressionContainer" && a.value.expression?.type === "ObjectExpression") {
|
|
1548
|
+
return a.value.expression.properties.filter((p) => p.type === "Property" && p.key).map((p) => p.key.name || p.key.value).filter(Boolean);
|
|
1457
1549
|
}
|
|
1458
|
-
return
|
|
1550
|
+
return [];
|
|
1459
1551
|
}
|
|
1460
1552
|
function lintFile(filePath, deprecatedMap, only) {
|
|
1461
|
-
const issues = [];
|
|
1462
1553
|
let content;
|
|
1463
1554
|
try {
|
|
1464
1555
|
content = readFileSync6(filePath, "utf-8");
|
|
1465
1556
|
} catch {
|
|
1466
1557
|
return [];
|
|
1467
1558
|
}
|
|
1468
|
-
|
|
1469
|
-
const
|
|
1470
|
-
if (
|
|
1471
|
-
const
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
const hasMenu = importedComponents.includes("Menu");
|
|
1487
|
-
const hasQRCode = importedComponents.includes("QRCode");
|
|
1488
|
-
const hasRadio = importedComponents.includes("Radio");
|
|
1489
|
-
const hasTreeSelect = importedComponents.includes("TreeSelect");
|
|
1490
|
-
const hasTypography = importedComponents.includes("Typography");
|
|
1491
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1492
|
-
const line = lines[i];
|
|
1493
|
-
for (const { compName, dep, regex } of deprecatedChecks) {
|
|
1494
|
-
if (regex.test(line)) {
|
|
1495
|
-
issues.push({
|
|
1496
|
-
file: filePath,
|
|
1497
|
-
line: i + 1,
|
|
1498
|
-
rule: "deprecated",
|
|
1499
|
-
severity: "warning",
|
|
1500
|
-
message: `${compName} ${dep.message}`
|
|
1501
|
-
});
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
if (!only || only === "deprecated") {
|
|
1505
|
-
if (/<BackTop\b/.test(line)) {
|
|
1506
|
-
issues.push({
|
|
1507
|
-
file: filePath,
|
|
1508
|
-
line: i + 1,
|
|
1509
|
-
rule: "deprecated",
|
|
1510
|
-
severity: "warning",
|
|
1511
|
-
message: "`BackTop` is deprecated, use `FloatButton.BackTop` instead"
|
|
1512
|
-
});
|
|
1513
|
-
}
|
|
1514
|
-
if (hasButton && /<Button\.Group\b/.test(line)) {
|
|
1515
|
-
issues.push({
|
|
1516
|
-
file: filePath,
|
|
1517
|
-
line: i + 1,
|
|
1518
|
-
rule: "deprecated",
|
|
1519
|
-
severity: "warning",
|
|
1520
|
-
message: "`Button.Group` is deprecated, use `Space.Compact` instead"
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1523
|
-
if (/<Input\.Group\b/.test(line)) {
|
|
1524
|
-
issues.push({
|
|
1525
|
-
file: filePath,
|
|
1526
|
-
line: i + 1,
|
|
1527
|
-
rule: "deprecated",
|
|
1528
|
-
severity: "warning",
|
|
1529
|
-
message: "`Input.Group` is deprecated, use `Space.Compact` instead"
|
|
1530
|
-
});
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
if (!only || only === "a11y") {
|
|
1534
|
-
if (hasImage && /<Image\b/.test(line) && !hasNearbyMatch(lines, i, 5, /alt\s*=/)) {
|
|
1535
|
-
issues.push({
|
|
1536
|
-
file: filePath,
|
|
1537
|
-
line: i + 1,
|
|
1538
|
-
rule: "a11y",
|
|
1539
|
-
severity: "warning",
|
|
1540
|
-
message: "Image component is missing `alt` prop for accessibility"
|
|
1541
|
-
});
|
|
1542
|
-
}
|
|
1543
|
-
if (/<\w+Icon\b/.test(line) && /onClick\s*=/.test(line) && !hasNearbyMatch(lines, i, 3, /aria-label\s*=/)) {
|
|
1544
|
-
issues.push({
|
|
1545
|
-
file: filePath,
|
|
1546
|
-
line: i + 1,
|
|
1547
|
-
rule: "a11y",
|
|
1548
|
-
severity: "warning",
|
|
1549
|
-
message: "Clickable icon should have `aria-label` for screen readers"
|
|
1550
|
-
});
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
if (!only || only === "usage") {
|
|
1554
|
-
if (/Form\.Item\b/.test(line)) {
|
|
1555
|
-
if (hasNearbyMatch(lines, i, 10, /shouldUpdate\s*[=]/) && hasNearbyMatch(lines, i, 10, /dependencies\s*[=]/)) {
|
|
1556
|
-
issues.push({
|
|
1557
|
-
file: filePath,
|
|
1558
|
-
line: i + 1,
|
|
1559
|
-
rule: "usage",
|
|
1560
|
-
severity: "warning",
|
|
1561
|
-
message: "`shouldUpdate` and `dependencies` should not be used together on Form.Item"
|
|
1562
|
-
});
|
|
1559
|
+
if (!content.includes("antd")) return [];
|
|
1560
|
+
const result = parseSync2(filePath, content);
|
|
1561
|
+
if (result.errors.length > 0) return [];
|
|
1562
|
+
const issues = [];
|
|
1563
|
+
const importedComponents = /* @__PURE__ */ new Set();
|
|
1564
|
+
const report = (rule, severity, line, message) => {
|
|
1565
|
+
issues.push({ file: filePath, line, rule, severity, message });
|
|
1566
|
+
};
|
|
1567
|
+
const visitor = new Visitor2({
|
|
1568
|
+
ImportDeclaration(node) {
|
|
1569
|
+
const source = node.source.value;
|
|
1570
|
+
if (source !== "antd" && !source.startsWith("antd/")) return;
|
|
1571
|
+
if (node.importKind === "type") return;
|
|
1572
|
+
for (const spec of node.specifiers) {
|
|
1573
|
+
if (spec.type === "ImportSpecifier") {
|
|
1574
|
+
if (spec.importKind === "type") continue;
|
|
1575
|
+
const name = spec.imported?.name || spec.local?.name;
|
|
1576
|
+
if (name) importedComponents.add(name);
|
|
1563
1577
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
severity: "warning",
|
|
1572
|
-
message: 'Button `ghost` prop cannot be used with `type="link"` or `type="text"`'
|
|
1573
|
-
});
|
|
1578
|
+
if ((!only || only === "performance") && (spec.type === "ImportDefaultSpecifier" || spec.type === "ImportNamespaceSpecifier")) {
|
|
1579
|
+
report(
|
|
1580
|
+
"performance",
|
|
1581
|
+
"error",
|
|
1582
|
+
node.loc?.start?.line ?? 0,
|
|
1583
|
+
"Avoid wildcard import from antd. Use named imports: `import { Button } from 'antd'`"
|
|
1584
|
+
);
|
|
1574
1585
|
}
|
|
1575
1586
|
}
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1587
|
+
},
|
|
1588
|
+
JSXOpeningElement(node) {
|
|
1589
|
+
const compName = getJSXElementName(node.name);
|
|
1590
|
+
if (!compName) return;
|
|
1591
|
+
const attrs = node.attributes || [];
|
|
1592
|
+
const line = node.loc?.start?.line ?? 0;
|
|
1593
|
+
if (!only || only === "deprecated") {
|
|
1594
|
+
if (compName === "BackTop" && importedComponents.has("BackTop")) {
|
|
1595
|
+
report("deprecated", "warning", line, "`BackTop` is deprecated, use `FloatButton.BackTop` instead");
|
|
1585
1596
|
}
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
if (hasNearbyMatch(lines, i, 5, /type\s*=\s*['"{]vertical['"}]/) && (!hasNearbyMatch(lines, i, 3, /\/>/) || hasNearbyMatch(lines, i, 5, /\bchildren\s*=/))) {
|
|
1589
|
-
issues.push({
|
|
1590
|
-
file: filePath,
|
|
1591
|
-
line: i + 1,
|
|
1592
|
-
rule: "usage",
|
|
1593
|
-
severity: "warning",
|
|
1594
|
-
message: 'Divider `children` are not supported in `type="vertical"` mode'
|
|
1595
|
-
});
|
|
1597
|
+
if (compName === "Button.Group" && importedComponents.has("Button")) {
|
|
1598
|
+
report("deprecated", "warning", line, "`Button.Group` is deprecated, use `Space.Compact` instead");
|
|
1596
1599
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
if (hasNearbyMatch(lines, i, 10, /maxCount\s*=/) && !hasNearbyMatch(lines, i, 10, /mode\s*=\s*['"{](?:multiple|tags)['"}]/)) {
|
|
1600
|
-
issues.push({
|
|
1601
|
-
file: filePath,
|
|
1602
|
-
line: i + 1,
|
|
1603
|
-
rule: "usage",
|
|
1604
|
-
severity: "warning",
|
|
1605
|
-
message: 'Select `maxCount` only works with `mode="multiple"` or `mode="tags"`'
|
|
1606
|
-
});
|
|
1600
|
+
if (compName === "Input.Group" && importedComponents.has("Input")) {
|
|
1601
|
+
report("deprecated", "warning", line, "`Input.Group` is deprecated, use `Space.Compact` instead");
|
|
1607
1602
|
}
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1603
|
+
const baseName = compName.includes(".") ? compName.split(".")[0] : compName;
|
|
1604
|
+
if (importedComponents.has(baseName) || importedComponents.has(compName)) {
|
|
1605
|
+
const deprecations = deprecatedMap.get(compName);
|
|
1606
|
+
if (deprecations) {
|
|
1607
|
+
for (const attr of attrs) {
|
|
1608
|
+
if (attr.type !== "JSXAttribute") continue;
|
|
1609
|
+
const propName = attr.name?.name;
|
|
1610
|
+
const dep = deprecations.find((d) => d.prop === propName);
|
|
1611
|
+
if (dep) {
|
|
1612
|
+
report("deprecated", "warning", attr.loc?.start?.line ?? line, `${compName} ${dep.message}`);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1618
1616
|
}
|
|
1619
1617
|
}
|
|
1620
|
-
if (
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
severity: "warning",
|
|
1626
|
-
message: "QRCode is missing required `value` prop"
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1629
|
-
if (hasTypography && /<Typography\.Link\b/.test(line)) {
|
|
1630
|
-
if (hasNearbyMatch(lines, i, 5, /ellipsis\s*=\s*\{\{/)) {
|
|
1631
|
-
issues.push({
|
|
1632
|
-
file: filePath,
|
|
1633
|
-
line: i + 1,
|
|
1634
|
-
rule: "usage",
|
|
1635
|
-
severity: "warning",
|
|
1636
|
-
message: "Typography.Link `ellipsis` only supports boolean value, not object config"
|
|
1637
|
-
});
|
|
1618
|
+
if (!only || only === "a11y") {
|
|
1619
|
+
if (compName === "Image" && importedComponents.has("Image")) {
|
|
1620
|
+
if (!hasAttr(attrs, "alt")) {
|
|
1621
|
+
report("a11y", "warning", line, "Image component is missing `alt` prop for accessibility");
|
|
1622
|
+
}
|
|
1638
1623
|
}
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
if (hasNearbyMatch(lines, i, 10, /ellipsis\s*=\s*\{\{/) && hasNearbyMatch(lines, i, 10, /\b(?:expandable|rows)\s*[=:]/)) {
|
|
1642
|
-
issues.push({
|
|
1643
|
-
file: filePath,
|
|
1644
|
-
line: i + 1,
|
|
1645
|
-
rule: "usage",
|
|
1646
|
-
severity: "warning",
|
|
1647
|
-
message: "Typography.Text `ellipsis` does not support `expandable` or `rows`"
|
|
1648
|
-
});
|
|
1624
|
+
if (compName.endsWith("Icon") && hasAttr(attrs, "onClick") && !hasAttr(attrs, "aria-label")) {
|
|
1625
|
+
report("a11y", "warning", line, "Clickable icon should have `aria-label` for screen readers");
|
|
1649
1626
|
}
|
|
1650
1627
|
}
|
|
1651
|
-
if (
|
|
1652
|
-
if (
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
rule: "usage",
|
|
1657
|
-
severity: "warning",
|
|
1658
|
-
message: "`optionType` is only supported on Radio.Group, not Radio"
|
|
1659
|
-
});
|
|
1628
|
+
if (!only || only === "usage") {
|
|
1629
|
+
if (compName === "Form.Item" && importedComponents.has("Form")) {
|
|
1630
|
+
if (hasAttr(attrs, "shouldUpdate") && hasAttr(attrs, "dependencies")) {
|
|
1631
|
+
report("usage", "warning", line, "`shouldUpdate` and `dependencies` should not be used together on Form.Item");
|
|
1632
|
+
}
|
|
1660
1633
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1634
|
+
if (compName === "Button" && importedComponents.has("Button")) {
|
|
1635
|
+
if (hasAttr(attrs, "ghost")) {
|
|
1636
|
+
const typeVal = getStringAttrValue(attrs, "type");
|
|
1637
|
+
if (typeVal === "link" || typeVal === "text") {
|
|
1638
|
+
report("usage", "warning", line, 'Button `ghost` prop cannot be used with `type="link"` or `type="text"`');
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
if (compName === "Checkbox" && importedComponents.has("Checkbox")) {
|
|
1643
|
+
if (hasAttr(attrs, "value")) {
|
|
1644
|
+
report("usage", "warning", line, "Checkbox `value` is not a valid prop outside Checkbox.Group, did you mean `checked`?");
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
if (compName === "Divider" && importedComponents.has("Divider")) {
|
|
1648
|
+
const typeVal = getStringAttrValue(attrs, "type");
|
|
1649
|
+
if (typeVal === "vertical" && (!node.selfClosing || hasAttr(attrs, "children"))) {
|
|
1650
|
+
report("usage", "warning", line, 'Divider `children` are not supported in `type="vertical"` mode');
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
if (compName === "Select" && importedComponents.has("Select")) {
|
|
1654
|
+
if (hasAttr(attrs, "maxCount")) {
|
|
1655
|
+
const modeVal = getStringAttrValue(attrs, "mode");
|
|
1656
|
+
if (modeVal !== "multiple" && modeVal !== "tags") {
|
|
1657
|
+
report("usage", "warning", line, 'Select `maxCount` only works with `mode="multiple"` or `mode="tags"`');
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
if (compName === "Menu" && importedComponents.has("Menu")) {
|
|
1662
|
+
if (hasAttr(attrs, "inlineCollapsed")) {
|
|
1663
|
+
const modeVal = getStringAttrValue(attrs, "mode");
|
|
1664
|
+
if (modeVal !== "inline") {
|
|
1665
|
+
report("usage", "warning", line, 'Menu `inlineCollapsed` should only be used with `mode="inline"`');
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
if (compName === "QRCode" && importedComponents.has("QRCode")) {
|
|
1670
|
+
if (!hasAttr(attrs, "value")) {
|
|
1671
|
+
report("usage", "warning", line, "QRCode is missing required `value` prop");
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
if (compName === "Typography.Link" && importedComponents.has("Typography")) {
|
|
1675
|
+
if (isObjectExpression(attrs, "ellipsis")) {
|
|
1676
|
+
report("usage", "warning", line, "Typography.Link `ellipsis` only supports boolean value, not object config");
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
if (compName === "Typography.Text" && importedComponents.has("Typography")) {
|
|
1680
|
+
if (isObjectExpression(attrs, "ellipsis")) {
|
|
1681
|
+
const keys = getObjectExpressionKeys(attrs, "ellipsis");
|
|
1682
|
+
if (keys.includes("expandable") || keys.includes("rows")) {
|
|
1683
|
+
report("usage", "warning", line, "Typography.Text `ellipsis` does not support `expandable` or `rows`");
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
if (compName === "Radio" && importedComponents.has("Radio")) {
|
|
1688
|
+
if (hasAttr(attrs, "optionType")) {
|
|
1689
|
+
report("usage", "warning", line, "`optionType` is only supported on Radio.Group, not Radio");
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
if (compName === "TreeSelect" && importedComponents.has("TreeSelect")) {
|
|
1693
|
+
if (isBooleanFalse(attrs, "multiple") && hasAttr(attrs, "treeCheckable")) {
|
|
1694
|
+
report("usage", "warning", line, "TreeSelect `multiple={false}` is ignored when `treeCheckable` is true");
|
|
1695
|
+
}
|
|
1671
1696
|
}
|
|
1672
1697
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
rule: "performance",
|
|
1680
|
-
severity: "warning",
|
|
1681
|
-
message: "Disabling `virtual` scroll on Select may cause performance issues with large datasets"
|
|
1682
|
-
});
|
|
1683
|
-
}
|
|
1684
|
-
if (/import\s+antd\b/.test(line) || /import\s+\*\s+as\s+\w+\s+from\s+['"]antd['"]/.test(line)) {
|
|
1685
|
-
issues.push({
|
|
1686
|
-
file: filePath,
|
|
1687
|
-
line: i + 1,
|
|
1688
|
-
rule: "performance",
|
|
1689
|
-
severity: "error",
|
|
1690
|
-
message: "Avoid wildcard import from antd. Use named imports: `import { Button } from 'antd'`"
|
|
1691
|
-
});
|
|
1698
|
+
if (!only || only === "performance") {
|
|
1699
|
+
if (compName === "Select" && importedComponents.has("Select") || compName === "TreeSelect" && importedComponents.has("TreeSelect")) {
|
|
1700
|
+
if (isBooleanFalse(attrs, "virtual")) {
|
|
1701
|
+
report("performance", "warning", line, "Disabling `virtual` scroll on Select may cause performance issues with large datasets");
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1692
1704
|
}
|
|
1693
1705
|
}
|
|
1694
|
-
}
|
|
1706
|
+
});
|
|
1707
|
+
visitor.visit(result.program);
|
|
1695
1708
|
return issues;
|
|
1696
1709
|
}
|
|
1697
1710
|
function registerLintCommand(program2) {
|
|
@@ -2817,7 +2830,7 @@ function collectAntdEnv(cwd, versionOverride) {
|
|
|
2817
2830
|
function collectCliEnv() {
|
|
2818
2831
|
let cliVersion;
|
|
2819
2832
|
try {
|
|
2820
|
-
cliVersion = "6.3.
|
|
2833
|
+
cliVersion = "6.3.5-beta.0";
|
|
2821
2834
|
} catch (err) {
|
|
2822
2835
|
console.error("Failed to get CLI version:", err);
|
|
2823
2836
|
cliVersion = "unknown";
|
|
@@ -2837,7 +2850,7 @@ function buildAntdIssueBody(fields) {
|
|
|
2837
2850
|
const expected = fields.expected || PLACEHOLDER;
|
|
2838
2851
|
const actual = fields.actual || PLACEHOLDER;
|
|
2839
2852
|
const extra = fields.extra || "";
|
|
2840
|
-
let body = `<!-- generated by
|
|
2853
|
+
let body = `<!-- generated by ant-design-issue-helper. DO NOT REMOVE -->
|
|
2841
2854
|
|
|
2842
2855
|
### Reproduction link
|
|
2843
2856
|
|
|
@@ -3082,6 +3095,266 @@ function registerBugCliCommand(program2) {
|
|
|
3082
3095
|
});
|
|
3083
3096
|
}
|
|
3084
3097
|
|
|
3098
|
+
// src/commands/mcp.ts
|
|
3099
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3100
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3101
|
+
import {
|
|
3102
|
+
CallToolRequestSchema,
|
|
3103
|
+
ListToolsRequestSchema,
|
|
3104
|
+
ListPromptsRequestSchema,
|
|
3105
|
+
GetPromptRequestSchema
|
|
3106
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
3107
|
+
|
|
3108
|
+
// src/mcp/tools.ts
|
|
3109
|
+
function toMcpResult(data) {
|
|
3110
|
+
if (data && typeof data === "object" && "error" in data && data.error === true) {
|
|
3111
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }], isError: true };
|
|
3112
|
+
}
|
|
3113
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
3114
|
+
}
|
|
3115
|
+
var TOOL_DEFINITIONS = [
|
|
3116
|
+
{
|
|
3117
|
+
name: "antd_list",
|
|
3118
|
+
description: "List all available antd components with names, categories, and descriptions.",
|
|
3119
|
+
inputSchema: {
|
|
3120
|
+
type: "object",
|
|
3121
|
+
properties: {},
|
|
3122
|
+
required: []
|
|
3123
|
+
}
|
|
3124
|
+
},
|
|
3125
|
+
{
|
|
3126
|
+
name: "antd_info",
|
|
3127
|
+
description: "Get component API information including props, types, and default values.",
|
|
3128
|
+
inputSchema: {
|
|
3129
|
+
type: "object",
|
|
3130
|
+
properties: {
|
|
3131
|
+
component: { type: "string", description: "Component name (e.g. Button, Table)" },
|
|
3132
|
+
detail: { type: "boolean", description: "Include full detail (whenToUse, methods, related, faq)" }
|
|
3133
|
+
},
|
|
3134
|
+
required: ["component"]
|
|
3135
|
+
}
|
|
3136
|
+
},
|
|
3137
|
+
{
|
|
3138
|
+
name: "antd_doc",
|
|
3139
|
+
description: "Get the full markdown documentation for a component.",
|
|
3140
|
+
inputSchema: {
|
|
3141
|
+
type: "object",
|
|
3142
|
+
properties: {
|
|
3143
|
+
component: { type: "string", description: "Component name (e.g. Button, Table)" }
|
|
3144
|
+
},
|
|
3145
|
+
required: ["component"]
|
|
3146
|
+
}
|
|
3147
|
+
},
|
|
3148
|
+
{
|
|
3149
|
+
name: "antd_demo",
|
|
3150
|
+
description: "Get demo source code for a component. Without a name, lists all demos; with a name, returns specific demo code.",
|
|
3151
|
+
inputSchema: {
|
|
3152
|
+
type: "object",
|
|
3153
|
+
properties: {
|
|
3154
|
+
component: { type: "string", description: "Component name (e.g. Button, Table)" },
|
|
3155
|
+
name: { type: "string", description: "Demo name to get specific demo code" }
|
|
3156
|
+
},
|
|
3157
|
+
required: ["component"]
|
|
3158
|
+
}
|
|
3159
|
+
},
|
|
3160
|
+
{
|
|
3161
|
+
name: "antd_token",
|
|
3162
|
+
description: "Query design tokens. Without a component, returns global tokens; with a component, returns component-level tokens.",
|
|
3163
|
+
inputSchema: {
|
|
3164
|
+
type: "object",
|
|
3165
|
+
properties: {
|
|
3166
|
+
component: { type: "string", description: "Component name for component-level tokens" }
|
|
3167
|
+
},
|
|
3168
|
+
required: []
|
|
3169
|
+
}
|
|
3170
|
+
},
|
|
3171
|
+
{
|
|
3172
|
+
name: "antd_semantic",
|
|
3173
|
+
description: "Query the semantic customization structure (classNames/styles) of a component.",
|
|
3174
|
+
inputSchema: {
|
|
3175
|
+
type: "object",
|
|
3176
|
+
properties: {
|
|
3177
|
+
component: { type: "string", description: "Component name (e.g. Button, Table)" }
|
|
3178
|
+
},
|
|
3179
|
+
required: ["component"]
|
|
3180
|
+
}
|
|
3181
|
+
},
|
|
3182
|
+
{
|
|
3183
|
+
name: "antd_changelog",
|
|
3184
|
+
description: "Query changelog entries or diff API between two versions. Provide v1+v2 for diff mode, or version for changelog query mode.",
|
|
3185
|
+
inputSchema: {
|
|
3186
|
+
type: "object",
|
|
3187
|
+
properties: {
|
|
3188
|
+
version: { type: "string", description: "Version or range filter for changelog query (e.g. 5.20.0 or 5.18.0..5.20.0)" },
|
|
3189
|
+
v1: { type: "string", description: "Start version for API diff (e.g. 5.18.0)" },
|
|
3190
|
+
v2: { type: "string", description: "End version for API diff (e.g. 5.20.0)" },
|
|
3191
|
+
component: { type: "string", description: "Filter diff to a specific component" }
|
|
3192
|
+
},
|
|
3193
|
+
required: []
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
];
|
|
3197
|
+
function createToolHandler(ctx) {
|
|
3198
|
+
return async (name, params) => {
|
|
3199
|
+
switch (name) {
|
|
3200
|
+
case "antd_list": {
|
|
3201
|
+
const components = listComponents({ version: ctx.version });
|
|
3202
|
+
const trimmed = components.map(({ name: name2, nameZh, category, description }) => ({
|
|
3203
|
+
name: name2,
|
|
3204
|
+
nameZh,
|
|
3205
|
+
category,
|
|
3206
|
+
description
|
|
3207
|
+
}));
|
|
3208
|
+
return toMcpResult(trimmed);
|
|
3209
|
+
}
|
|
3210
|
+
case "antd_info": {
|
|
3211
|
+
const result = getComponentInfo(params.component, {
|
|
3212
|
+
lang: ctx.lang,
|
|
3213
|
+
version: ctx.version,
|
|
3214
|
+
detail: params.detail ?? false
|
|
3215
|
+
});
|
|
3216
|
+
return toMcpResult(result);
|
|
3217
|
+
}
|
|
3218
|
+
case "antd_doc": {
|
|
3219
|
+
const result = getComponentDoc(params.component, {
|
|
3220
|
+
lang: ctx.lang,
|
|
3221
|
+
version: ctx.version
|
|
3222
|
+
});
|
|
3223
|
+
return toMcpResult(result);
|
|
3224
|
+
}
|
|
3225
|
+
case "antd_demo": {
|
|
3226
|
+
const result = getComponentDemo(params.component, {
|
|
3227
|
+
version: ctx.version,
|
|
3228
|
+
name: params.name
|
|
3229
|
+
});
|
|
3230
|
+
return toMcpResult(result);
|
|
3231
|
+
}
|
|
3232
|
+
case "antd_token": {
|
|
3233
|
+
const result = getTokens(params.component, {
|
|
3234
|
+
lang: ctx.lang,
|
|
3235
|
+
version: ctx.version
|
|
3236
|
+
});
|
|
3237
|
+
return toMcpResult(result);
|
|
3238
|
+
}
|
|
3239
|
+
case "antd_semantic": {
|
|
3240
|
+
const result = getSemanticStructure(params.component, {
|
|
3241
|
+
version: ctx.version
|
|
3242
|
+
});
|
|
3243
|
+
return toMcpResult(result);
|
|
3244
|
+
}
|
|
3245
|
+
case "antd_changelog": {
|
|
3246
|
+
const v1 = params.v1;
|
|
3247
|
+
const v2 = params.v2;
|
|
3248
|
+
if (v1 && !v2 || !v1 && v2) {
|
|
3249
|
+
return toMcpResult(
|
|
3250
|
+
createError(
|
|
3251
|
+
ErrorCodes.INVALID_ARGUMENT,
|
|
3252
|
+
"Both v1 and v2 are required for diff mode",
|
|
3253
|
+
"Provide both versions (v1 + v2), or omit both to use query mode"
|
|
3254
|
+
)
|
|
3255
|
+
);
|
|
3256
|
+
}
|
|
3257
|
+
if (v1 && v2) {
|
|
3258
|
+
const result2 = diffChangelog({
|
|
3259
|
+
v1,
|
|
3260
|
+
v2,
|
|
3261
|
+
component: params.component
|
|
3262
|
+
});
|
|
3263
|
+
return toMcpResult(result2);
|
|
3264
|
+
}
|
|
3265
|
+
const result = queryChangelog({
|
|
3266
|
+
snapshotVersion: ctx.version,
|
|
3267
|
+
entryFilter: params.version
|
|
3268
|
+
});
|
|
3269
|
+
return toMcpResult(result);
|
|
3270
|
+
}
|
|
3271
|
+
default:
|
|
3272
|
+
return toMcpResult(
|
|
3273
|
+
createError(ErrorCodes.UNKNOWN_TOOL, `Unknown tool: ${name}`)
|
|
3274
|
+
);
|
|
3275
|
+
}
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
// src/mcp/prompts.ts
|
|
3280
|
+
var SHARED_TOOL_WORKFLOW = `## Tool usage workflow
|
|
3281
|
+
1. Use **antd_list** to discover available components
|
|
3282
|
+
2. Use **antd_info** to get component props and API details
|
|
3283
|
+
3. Use **antd_doc** to read full component documentation
|
|
3284
|
+
4. Use **antd_demo** to get example code for a component
|
|
3285
|
+
|
|
3286
|
+
## Additional tools
|
|
3287
|
+
- Use **antd_token** for querying design tokens (global or component-level) for theming
|
|
3288
|
+
- Use **antd_semantic** for querying semantic classNames/styles customization structure
|
|
3289
|
+
- Use **antd_changelog** for querying version changes and cross-version API diffs
|
|
3290
|
+
|
|
3291
|
+
## Rules
|
|
3292
|
+
- Avoid duplicate tool calls \u2014 do not call the same tool with the same parameters twice
|
|
3293
|
+
- Always query component docs before generating code that uses the component
|
|
3294
|
+
- Prefer reading real documentation over guessing API usage`;
|
|
3295
|
+
var ANTD_EXPERT_PROMPT = `You are an expert assistant for Ant Design (antd), a React UI component library.
|
|
3296
|
+
|
|
3297
|
+
${SHARED_TOOL_WORKFLOW}
|
|
3298
|
+
`;
|
|
3299
|
+
var ANTD_PAGE_GENERATOR_PROMPT = `You are an expert Ant Design page generator. Your job is to produce complete, runnable React pages using antd components.
|
|
3300
|
+
|
|
3301
|
+
${SHARED_TOOL_WORKFLOW}
|
|
3302
|
+
- Before generating code, fetch ALL relevant component docs and examples
|
|
3303
|
+
- Produce complete, runnable code with all necessary imports
|
|
3304
|
+
- Include proper TypeScript types when applicable
|
|
3305
|
+
`;
|
|
3306
|
+
|
|
3307
|
+
// src/commands/mcp.ts
|
|
3308
|
+
function registerMcpCommand(program2) {
|
|
3309
|
+
program2.command("mcp").description("Start MCP (Model Context Protocol) server for AI assistant integration").action(async () => {
|
|
3310
|
+
const opts = program2.opts();
|
|
3311
|
+
const versionInfo = detectVersion(opts.version);
|
|
3312
|
+
const server = new Server(
|
|
3313
|
+
{ name: "antd", version: "6.3.5-beta.0" },
|
|
3314
|
+
{ capabilities: { tools: {}, prompts: {} } }
|
|
3315
|
+
);
|
|
3316
|
+
const handleTool = createToolHandler({
|
|
3317
|
+
version: versionInfo.version,
|
|
3318
|
+
lang: opts.lang
|
|
3319
|
+
});
|
|
3320
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
3321
|
+
tools: TOOL_DEFINITIONS
|
|
3322
|
+
}));
|
|
3323
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
3324
|
+
const { name, arguments: params } = request.params;
|
|
3325
|
+
return handleTool(name, params ?? {});
|
|
3326
|
+
});
|
|
3327
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
3328
|
+
prompts: [
|
|
3329
|
+
{
|
|
3330
|
+
name: "antd-expert",
|
|
3331
|
+
description: "General Ant Design expert assistant prompt"
|
|
3332
|
+
},
|
|
3333
|
+
{
|
|
3334
|
+
name: "antd-page-generator",
|
|
3335
|
+
description: "Ant Design page generation assistant prompt"
|
|
3336
|
+
}
|
|
3337
|
+
]
|
|
3338
|
+
}));
|
|
3339
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
3340
|
+
const { name } = request.params;
|
|
3341
|
+
if (name === "antd-expert") {
|
|
3342
|
+
return {
|
|
3343
|
+
messages: [{ role: "user", content: { type: "text", text: ANTD_EXPERT_PROMPT } }]
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
if (name === "antd-page-generator") {
|
|
3347
|
+
return {
|
|
3348
|
+
messages: [{ role: "user", content: { type: "text", text: ANTD_PAGE_GENERATOR_PROMPT } }]
|
|
3349
|
+
};
|
|
3350
|
+
}
|
|
3351
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
3352
|
+
});
|
|
3353
|
+
const transport = new StdioServerTransport();
|
|
3354
|
+
await server.connect(transport);
|
|
3355
|
+
});
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3085
3358
|
// src/utils/update-check.ts
|
|
3086
3359
|
import { readFileSync as readFileSync7, writeFileSync, mkdirSync, existsSync as existsSync3 } from "fs";
|
|
3087
3360
|
import { join as join6 } from "path";
|
|
@@ -3157,7 +3430,7 @@ function printUpdateNotice(currentVersion, latestVersion) {
|
|
|
3157
3430
|
}
|
|
3158
3431
|
async function checkForUpdate() {
|
|
3159
3432
|
if (process.env.CI || process.env.NO_UPDATE_CHECK) return;
|
|
3160
|
-
const currentVersion = "6.3.
|
|
3433
|
+
const currentVersion = "6.3.5-beta.0";
|
|
3161
3434
|
if (!valid(currentVersion)) return;
|
|
3162
3435
|
const now = Date.now();
|
|
3163
3436
|
const cache = readCache();
|
|
@@ -3176,7 +3449,7 @@ async function checkForUpdate() {
|
|
|
3176
3449
|
}
|
|
3177
3450
|
|
|
3178
3451
|
// src/index.ts
|
|
3179
|
-
var CLI_VERSION = "6.3.
|
|
3452
|
+
var CLI_VERSION = "6.3.5-beta.0";
|
|
3180
3453
|
var program = new Command();
|
|
3181
3454
|
program.name("antd").description("CLI tool for querying antd knowledge and analyzing antd usage").option("--format <format>", "Output format: json, text, or markdown", "text").option("--version <version>", "Target antd version (e.g. 5.20.0)").option("--lang <lang>", "Output language: en or zh", "en").option("--detail", "Full information output", false);
|
|
3182
3455
|
program.addOption(new Option("-V, --cli-version", "Output the CLI version number"));
|
|
@@ -3191,6 +3464,7 @@ registerDoctorCommand(program);
|
|
|
3191
3464
|
registerUsageCommand(program);
|
|
3192
3465
|
registerLintCommand(program);
|
|
3193
3466
|
registerMigrateCommand(program);
|
|
3467
|
+
registerMcpCommand(program);
|
|
3194
3468
|
registerBugCommand(program);
|
|
3195
3469
|
registerBugCliCommand(program);
|
|
3196
3470
|
program.hook("postAction", async () => {
|
|
@@ -3200,6 +3474,7 @@ var idx = process.argv.indexOf("-V");
|
|
|
3200
3474
|
var idx2 = process.argv.indexOf("--cli-version");
|
|
3201
3475
|
if (idx !== -1 || idx2 !== -1) {
|
|
3202
3476
|
console.log(CLI_VERSION);
|
|
3477
|
+
await checkForUpdate();
|
|
3203
3478
|
process.exit(0);
|
|
3204
3479
|
}
|
|
3205
3480
|
program.parse();
|