@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/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
- return candidates.find(
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 store = loadMetadataForVersion(versionInfo.version);
289
- if (store.components.length === 0) {
290
- console.log("No component data available.");
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
- const data = store.components.map((c) => ({
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 store.components) {
412
+ for (const c of components) {
312
413
  const desc = c.description || c.descriptionZh || "";
313
- lines.push(`| **${c.name}** | ${c.nameZh ?? ""} | ${desc} | ${c.since ?? ""} |`);
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 = store.components.map((c) => [
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 mapProps(props, lang, detail) {
401
- return props.map(
402
- (p) => detail ? [p.name, p.type, p.default, p.since ?? "-", localize(p.description, p.descriptionZh, lang) || "-"] : [p.name, p.type, p.default, p.since ?? "-"]
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 store = loadMetadataForVersion(versionInfo.version);
411
- const comp = findComponent(store, component);
412
- if (!comp) {
413
- const names = getAllComponentNames(store);
414
- const suggestion = fuzzyMatch(component, names);
415
- const err = createError(
416
- ErrorCodes.COMPONENT_NOT_FOUND,
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
- if (opts.detail) {
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 = comp.nameZh ? `${comp.name} (${comp.nameZh})` : comp.name;
476
- console.log(`${nameLabel} \u2014 ${desc}`);
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
- console.log(formatTable(headers, mapProps(comp.props, lang, opts.detail), fmt));
484
- if (comp.subComponentProps) {
485
- for (const [subName, subProps] of Object.entries(comp.subComponentProps)) {
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
- console.log(formatTable(headers, mapProps(subProps, lang, opts.detail), fmt));
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 && comp.related && comp.related.length > 0) {
527
+ if (opts.detail && "related" in result && result.related.length > 0) {
493
528
  console.log(`
494
- Related: ${comp.related.join(", ")}`);
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 store = loadMetadataForVersion(versionInfo.version);
506
- const comp = findComponent(store, component);
507
- if (!comp) {
508
- const names = getAllComponentNames(store);
509
- const suggestion = fuzzyMatch(component, names);
510
- const err = createError(
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: comp.name, doc }, "json");
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 store = loadMetadataForVersion(versionInfo.version);
544
- const comp = findComponent(store, component);
545
- if (!comp) {
546
- const names = getAllComponentNames(store);
547
- const suggestion = fuzzyMatch(component, names);
548
- const err = createError(
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
- const demos = comp.demos || [];
558
- if (!name) {
618
+ if ("code" in result) {
559
619
  if (opts.format === "json") {
560
- output(
561
- {
562
- component: comp.name,
563
- demos: demos.map((d) => ({
564
- name: d.name,
565
- title: d.title,
566
- description: d.description
567
- }))
568
- },
569
- "json"
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(`${comp.name} Demos:`);
631
+ console.log(`${result.component} Demos:`);
573
632
  console.log("");
574
- for (const demo2 of demos) {
575
- console.log(` ${demo2.name} \u2014 ${demo2.title}`);
576
- console.log(` ${demo2.description}`);
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
- if (versionInfo.majorVersion === "v4") {
623
- const err = createError(
624
- ErrorCodes.UNSUPPORTED_VERSION_FEATURE,
625
- "Design Token system is not available in antd v4",
626
- "Upgrade to antd v5+ to use Design Tokens"
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
- const store = loadMetadataForVersion(versionInfo.version);
633
- if (!component) {
634
- const globalTokens = store.globalTokens || [];
635
- if (globalTokens.length === 0) {
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({ tokens: globalTokens }, "json");
699
+ output(result, "json");
641
700
  return;
642
701
  }
643
702
  console.log("Global Design Tokens:");
644
703
  console.log("");
645
- const headers2 = ["Token", "Type", "Default", "Description"];
646
- const rows2 = globalTokens.map((t) => [
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(headers2, rows2, opts.format === "markdown" ? "markdown" : "text"));
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 store = loadMetadataForVersion(versionInfo.version);
691
- const comp = findComponent(store, component);
692
- if (!comp) {
693
- const names = getAllComponentNames(store);
694
- const suggestion = fuzzyMatch(component, names);
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
- const structure = comp.semanticStructure || [];
705
- if (structure.length === 0) {
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({ name: comp.name, semanticStructure: structure }, "json");
741
+ output(result, "json");
711
742
  return;
712
743
  }
713
- console.log(`${comp.name} Semantic Structure:`);
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(` <${comp.name} classNames={{ ${structure[0]?.key}: 'my-${structure[0]?.key}' }} />`);
721
- console.log(` <${comp.name} styles={{ ${structure[0]?.key}: { background: '#fff' } }} />`);
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 runApiDiff(v1, v2, component, opts) {
793
- const store1 = loadMetadataForVersion(v1);
794
- const store2 = loadMetadataForVersion(v2);
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
- printError(createError(ErrorCodes.VERSION_NOT_FOUND, `No data available for version ${v1}`), opts.format);
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
- printError(createError(ErrorCodes.VERSION_NOT_FOUND, `No data available for version ${v2}`), opts.format);
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
- printError(
813
- createError(ErrorCodes.COMPONENT_NOT_FOUND, `Component '${component}' not found in either version`, suggestion ? `Did you mean '${suggestion}'?` : void 0),
814
- opts.format
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
- if (opts.format === "json") {
836
- const result = component && diffs.length > 0 ? { from: v1, to: v2, ...diffs[0] } : { from: v1, to: v2, diffs };
837
- output(result, "json");
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 ${v1} and ${v2}.`);
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: ${v1} \u2192 ${v2}`);
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 store = loadMetadataForVersion(versionInfo.version);
866
- const changelog = store.changelog || [];
867
- if (changelog.length === 0) {
868
- console.log("No changelog data available.");
869
- return;
870
- }
871
- const entries = filterEntries(changelog, v1);
872
- if (entries.length === 0) {
873
- const err = createError(
874
- ErrorCodes.VERSION_NOT_FOUND,
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
- printChangelog(entries, opts.format, v1);
934
+ printChangelogEntries(result.entries, opts.format, result.versionArg);
883
935
  } else {
884
- if (compare(v1, v2) > 0) {
885
- const err = createError(
886
- ErrorCodes.INVALID_ARGUMENT,
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
- runApiDiff(v1, v2, component, opts);
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 parseAntdImports(content) {
933
- const names = [];
934
- ANTD_IMPORT_RE.lastIndex = 0;
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
- return names;
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
- var SUB_COMPONENT_RE = /\b(\w+)\.(\w+)\b/g;
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
- const importedNames = parseAntdImports(content);
1330
- for (const name of importedNames) {
1331
- if (!result.has(name)) {
1332
- result.set(name, { count: 0, subComponents: /* @__PURE__ */ new Map() });
1333
- }
1334
- result.get(name).count++;
1335
- }
1336
- SUB_COMPONENT_RE.lastIndex = 0;
1337
- let match;
1338
- while ((match = SUB_COMPONENT_RE.exec(content)) !== null) {
1339
- const [, parent, child] = match;
1340
- if (importedNames.includes(parent) && /^[A-Z]/.test(child)) {
1341
- const entry = result.get(parent);
1342
- const subKey = `${parent}.${child}`;
1343
- entry.subComponents.set(subKey, (entry.subComponents.get(subKey) || 0) + 1);
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
- function escapeRegExp(s) {
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 hasNearbyMatch(lines, i, lookahead, pattern) {
1454
- const end = Math.min(i + lookahead, lines.length);
1455
- for (let j = i; j < end; j++) {
1456
- if (pattern.test(lines[j])) return true;
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 false;
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
- const lines = content.split("\n");
1469
- const importedComponents = parseAntdImports(content);
1470
- if (importedComponents.length === 0) return [];
1471
- const deprecatedChecks = [];
1472
- if (!only || only === "deprecated") {
1473
- for (const compName of importedComponents) {
1474
- const deprecations = deprecatedMap.get(compName);
1475
- if (!deprecations) continue;
1476
- for (const dep of deprecations) {
1477
- deprecatedChecks.push({ compName, dep, regex: new RegExp(`\\b${escapeRegExp(dep.prop)}\\b\\s*[=({]`) });
1478
- }
1479
- }
1480
- }
1481
- const hasImage = importedComponents.includes("Image");
1482
- const hasSelect = importedComponents.includes("Select") || importedComponents.includes("TreeSelect");
1483
- const hasButton = importedComponents.includes("Button");
1484
- const hasCheckbox = importedComponents.includes("Checkbox");
1485
- const hasDivider = importedComponents.includes("Divider");
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
- if (hasButton && /<Button\b/.test(line)) {
1566
- if (hasNearbyMatch(lines, i, 5, /\bghost\b/) && hasNearbyMatch(lines, i, 5, /type\s*=\s*['"{](?:link|text)['"}\s]/)) {
1567
- issues.push({
1568
- file: filePath,
1569
- line: i + 1,
1570
- rule: "usage",
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
- if (hasCheckbox && /<Checkbox\b/.test(line) && !/Checkbox\.Group/.test(line)) {
1577
- if (hasNearbyMatch(lines, i, 5, /\bvalue\s*=/)) {
1578
- issues.push({
1579
- file: filePath,
1580
- line: i + 1,
1581
- rule: "usage",
1582
- severity: "warning",
1583
- message: "Checkbox `value` is not a valid prop outside Checkbox.Group, did you mean `checked`?"
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
- if (hasDivider && /<Divider\b/.test(line)) {
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
- if (hasSelect && /<Select\b/.test(line)) {
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
- if (hasMenu && /<Menu\b/.test(line)) {
1610
- if (hasNearbyMatch(lines, i, 10, /inlineCollapsed\s*=/) && !hasNearbyMatch(lines, i, 10, /mode\s*=\s*['"{]inline['"}]/)) {
1611
- issues.push({
1612
- file: filePath,
1613
- line: i + 1,
1614
- rule: "usage",
1615
- severity: "warning",
1616
- message: 'Menu `inlineCollapsed` should only be used with `mode="inline"`'
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 (hasQRCode && /<QRCode\b/.test(line) && !hasNearbyMatch(lines, i, 10, /\bvalue\s*=/)) {
1621
- issues.push({
1622
- file: filePath,
1623
- line: i + 1,
1624
- rule: "usage",
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
- if (hasTypography && /<Typography\.Text\b/.test(line)) {
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 (hasRadio && /<Radio\b/.test(line) && !/<Radio\.Group\b/.test(line)) {
1652
- if (hasNearbyMatch(lines, i, 5, /optionType\s*=/)) {
1653
- issues.push({
1654
- file: filePath,
1655
- line: i + 1,
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
- if (hasTreeSelect && /<TreeSelect\b/.test(line)) {
1663
- if (hasNearbyMatch(lines, i, 10, /multiple\s*=\s*\{?\s*false/) && hasNearbyMatch(lines, i, 10, /treeCheckable\b/)) {
1664
- issues.push({
1665
- file: filePath,
1666
- line: i + 1,
1667
- rule: "usage",
1668
- severity: "warning",
1669
- message: "TreeSelect `multiple={false}` is ignored when `treeCheckable` is true"
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
- if (!only || only === "performance") {
1675
- if (hasSelect && /<(?:Select|TreeSelect)\b/.test(line) && hasNearbyMatch(lines, i, 10, /virtual\s*=\s*\{?\s*false/)) {
1676
- issues.push({
1677
- file: filePath,
1678
- line: i + 1,
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.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 @ant-design/cli. DO NOT REMOVE -->
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.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.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();