@wot-ui/cli 0.0.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ {
2
+ "latest": "2.0.0-alpha.5",
3
+ "supported": [
4
+ "2.0.0-alpha.5"
5
+ ],
6
+ "aliases": {
7
+ "v2": "2.0.0-alpha.5",
8
+ "latest": "2.0.0-alpha.5"
9
+ }
10
+ }
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.mjs ADDED
@@ -0,0 +1,416 @@
1
+ #!/usr/bin/env node
2
+ import { a as resolveVersion, i as listComponents, n as lintProject, o as loadMetadataFile, r as findComponent, t as analyzeUsage } from "./scanner-BFHnD5iE.mjs";
3
+ import process from "node:process";
4
+ import { Command } from "commander";
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { join, resolve } from "node:path";
7
+
8
+ //#region src/commands/shared.ts
9
+ function addQueryOptions(command) {
10
+ return command.option("--format <format>", "output format: text, json, markdown", "text").option("--lang <lang>", "output language: zh, en", "zh").option("--version <version>", "target wot-ui version");
11
+ }
12
+ function normalizeQueryOptions(options) {
13
+ return {
14
+ format: options.format === "json" || options.format === "markdown" ? options.format : "text",
15
+ lang: options.lang === "en" ? "en" : "zh",
16
+ version: typeof options.version === "string" ? options.version : void 0
17
+ };
18
+ }
19
+ function printError(message, format) {
20
+ if (format === "json") console.log(JSON.stringify({
21
+ error: true,
22
+ message
23
+ }, null, 2));
24
+ else console.error(message);
25
+ }
26
+ function getComponentLabel(component, lang) {
27
+ return lang === "zh" ? `${component.name} ${component.nameZh}` : component.name;
28
+ }
29
+ function getComponentDescription(component, lang) {
30
+ return lang === "zh" ? component.descriptionZh : component.description;
31
+ }
32
+ function formatCssVars(cssVars) {
33
+ return cssVars.map((cssVar) => ({
34
+ name: cssVar.name,
35
+ defaultValue: cssVar.defaultValue ?? cssVar.token ?? "-",
36
+ description: cssVar.description
37
+ }));
38
+ }
39
+
40
+ //#endregion
41
+ //#region src/commands/changelog.ts
42
+ function registerChangelogCommand(program) {
43
+ addQueryOptions(program.command("changelog").argument("[versionOrComponent]", "Version or component name").argument("[component]", "Optional component name").description("Show changelog entries")).action((versionOrComponent, componentArg, options) => {
44
+ const query = normalizeQueryOptions(options);
45
+ try {
46
+ const metadata = loadMetadataFile(resolveVersion(query.version));
47
+ let versionFilter;
48
+ let componentFilter;
49
+ if (versionOrComponent && /^v?\d/.test(versionOrComponent)) versionFilter = versionOrComponent;
50
+ else if (versionOrComponent) componentFilter = versionOrComponent;
51
+ if (componentArg) componentFilter = componentArg;
52
+ const entries = (metadata.changelog ?? []).filter((entry) => {
53
+ const versionMatches = versionFilter ? entry.version === versionFilter || `v${entry.version}` === versionFilter : true;
54
+ const componentMatches = componentFilter ? (entry.components ?? []).some((component) => component.toLowerCase() === componentFilter.toLowerCase()) : true;
55
+ return versionMatches && componentMatches;
56
+ });
57
+ if (query.format === "json") {
58
+ console.log(JSON.stringify({ entries }, null, 2));
59
+ return;
60
+ }
61
+ const lines = entries.flatMap((entry) => [
62
+ `${entry.version}${entry.date ? ` (${entry.date})` : ""}`,
63
+ entry.summary,
64
+ ...entry.highlights.map((item) => `- ${item}`),
65
+ ""
66
+ ]);
67
+ console.log(lines.join("\n").trim());
68
+ } catch (error) {
69
+ printError(error instanceof Error ? error.message : "Failed to load changelog", query.format);
70
+ process.exitCode = 1;
71
+ }
72
+ });
73
+ }
74
+
75
+ //#endregion
76
+ //#region src/commands/demo.ts
77
+ function registerDemoCommand(program) {
78
+ addQueryOptions(program.command("demo").argument("<component>", "Component name or wd-* tag").argument("[name]", "Demo name").description("Show component demo source code")).action((componentName, demoName, options) => {
79
+ const query = normalizeQueryOptions(options);
80
+ try {
81
+ const component = findComponent(componentName, query.version);
82
+ if (!component) {
83
+ printError(`Component not found: ${componentName}`, query.format);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ const demos = component.demos ?? [];
88
+ if (!demoName) {
89
+ if (query.format === "json") {
90
+ console.log(JSON.stringify({
91
+ component: component.name,
92
+ demos
93
+ }, null, 2));
94
+ return;
95
+ }
96
+ console.log(demos.map((demo$1) => `- ${demo$1.name}: ${demo$1.title}`).join("\n"));
97
+ return;
98
+ }
99
+ const demo = demos.find((item) => item.name.toLowerCase() === demoName.toLowerCase());
100
+ if (!demo) {
101
+ printError(`Demo not found: ${demoName}`, query.format);
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+ if (query.format === "json") {
106
+ console.log(JSON.stringify({
107
+ component: component.name,
108
+ demo
109
+ }, null, 2));
110
+ return;
111
+ }
112
+ console.log(demo.code);
113
+ } catch (error) {
114
+ printError(error instanceof Error ? error.message : "Failed to load demo", query.format);
115
+ process.exitCode = 1;
116
+ }
117
+ });
118
+ }
119
+
120
+ //#endregion
121
+ //#region src/commands/doc.ts
122
+ function registerDocCommand(program) {
123
+ addQueryOptions(program.command("doc").argument("<component>", "Component name or wd-* tag").description("Print component markdown documentation")).action((componentName, options) => {
124
+ const query = normalizeQueryOptions(options);
125
+ try {
126
+ const component = findComponent(componentName, query.version);
127
+ if (!component?.doc) {
128
+ printError(`Documentation not found: ${componentName}`, query.format);
129
+ process.exitCode = 1;
130
+ return;
131
+ }
132
+ if (query.format === "json") {
133
+ console.log(JSON.stringify({
134
+ name: component.name,
135
+ doc: component.doc
136
+ }, null, 2));
137
+ return;
138
+ }
139
+ console.log(component.doc);
140
+ } catch (error) {
141
+ printError(error instanceof Error ? error.message : "Failed to load documentation", query.format);
142
+ process.exitCode = 1;
143
+ }
144
+ });
145
+ }
146
+
147
+ //#endregion
148
+ //#region src/utils/project.ts
149
+ function readPackageJson(dir) {
150
+ const packageJsonPath = join(dir, "package.json");
151
+ if (!existsSync(packageJsonPath)) return void 0;
152
+ return JSON.parse(readFileSync(packageJsonPath, "utf8"));
153
+ }
154
+ function getDependencyVersion(pkg, name) {
155
+ return pkg?.dependencies?.[name] ?? pkg?.devDependencies?.[name];
156
+ }
157
+ function detectWotDependency(pkg) {
158
+ for (const name of ["wot-design-uni", "wot-ui"]) {
159
+ const version = getDependencyVersion(pkg, name);
160
+ if (version) return `${name}@${version}`;
161
+ }
162
+ if (pkg?.dependencies) {
163
+ const scoped = Object.keys(pkg.dependencies).find((name) => name.includes("wot"));
164
+ if (scoped) return `${scoped}@${pkg.dependencies[scoped]}`;
165
+ }
166
+ }
167
+ function createCheck(name, status, message, suggestion) {
168
+ if (status === "pass") return {
169
+ name,
170
+ status,
171
+ message
172
+ };
173
+ return {
174
+ name,
175
+ status,
176
+ severity: status === "fail" ? "error" : "warning",
177
+ message,
178
+ suggestion
179
+ };
180
+ }
181
+ function diagnoseProject(targetDir) {
182
+ const dir = resolve(targetDir);
183
+ const pkg = readPackageJson(dir);
184
+ const checks = [];
185
+ if (!pkg) {
186
+ checks.push(createCheck("package-json", "fail", "No package.json found in target directory.", "Run the command in a project root or pass a directory containing package.json."));
187
+ return {
188
+ dir,
189
+ checks
190
+ };
191
+ }
192
+ checks.push(createCheck("package-json", "pass", "package.json found."));
193
+ const wotVersion = detectWotDependency(pkg);
194
+ if (wotVersion) checks.push(createCheck("wot-ui-installed", "pass", `Detected ${wotVersion}.`));
195
+ else checks.push(createCheck("wot-ui-installed", "fail", "No wot-ui dependency detected.", "Add wot-ui or wot-design-uni to dependencies before using doctor, usage, and lint."));
196
+ const vueVersion = getDependencyVersion(pkg, "vue");
197
+ if (vueVersion) checks.push(createCheck("vue-version", vueVersion.includes("3") ? "pass" : "warn", `Detected vue ${vueVersion}.`, vueVersion.includes("3") ? void 0 : "wot-ui v2 is designed for Vue 3 based projects."));
198
+ else checks.push(createCheck("vue-version", "warn", "Vue dependency not found.", "Add vue@3 to align with wot-ui v2 expectations."));
199
+ const uniAppVersion = getDependencyVersion(pkg, "@dcloudio/uni-app") ?? getDependencyVersion(pkg, "uni-app");
200
+ if (uniAppVersion) checks.push(createCheck("uni-app-version", "pass", `Detected uni-app ${uniAppVersion}.`));
201
+ else checks.push(createCheck("uni-app-version", "warn", "uni-app dependency not found.", "If this is a uni-app project, add @dcloudio/uni-app."));
202
+ const typescriptVersion = getDependencyVersion(pkg, "typescript");
203
+ if (typescriptVersion) checks.push(createCheck("typescript", "pass", `Detected typescript ${typescriptVersion}.`));
204
+ else checks.push(createCheck("typescript", "warn", "TypeScript dependency not found.", "Add TypeScript if you want type-safe wot-ui development and CLI analysis."));
205
+ const hasNodeModules = existsSync(join(dir, "node_modules"));
206
+ checks.push(createCheck("node-modules", hasNodeModules ? "pass" : "warn", hasNodeModules ? "node_modules directory found." : "node_modules directory not found.", hasNodeModules ? void 0 : "Run your package manager install command before deeper diagnostics."));
207
+ return {
208
+ dir,
209
+ checks
210
+ };
211
+ }
212
+
213
+ //#endregion
214
+ //#region src/commands/doctor.ts
215
+ function registerDoctorCommand(program) {
216
+ addQueryOptions(program.command("doctor").argument("[dir]", "Project directory", ".").description("Diagnose a wot-ui project")).action((dir, options) => {
217
+ const query = normalizeQueryOptions(options);
218
+ try {
219
+ const report = diagnoseProject(resolve(dir));
220
+ if (query.format === "json") {
221
+ console.log(JSON.stringify(report, null, 2));
222
+ return;
223
+ }
224
+ const lines = [`Directory: ${report.dir}`, ...report.checks.map((check) => `${check.status.toUpperCase()} ${check.name}: ${check.message}${check.suggestion ? ` | ${check.suggestion}` : ""}`)];
225
+ console.log(lines.join("\n"));
226
+ } catch (error) {
227
+ printError(error instanceof Error ? error.message : "Failed to diagnose project", query.format);
228
+ process.exitCode = 1;
229
+ }
230
+ });
231
+ }
232
+
233
+ //#endregion
234
+ //#region src/commands/info.ts
235
+ function registerInfoCommand(program) {
236
+ addQueryOptions(program.command("info").argument("<component>", "Component name or wd-* tag").description("Show component props, events, slots and CSS variables")).action((componentName, options) => {
237
+ const query = normalizeQueryOptions(options);
238
+ try {
239
+ const component = findComponent(componentName, query.version);
240
+ if (!component) {
241
+ printError(`Component not found: ${componentName}`, query.format);
242
+ process.exitCode = 1;
243
+ return;
244
+ }
245
+ if (query.format === "json") {
246
+ console.log(JSON.stringify(component, null, 2));
247
+ return;
248
+ }
249
+ const lines = [
250
+ `${getComponentLabel(component, query.lang)} (${component.tag})`,
251
+ getComponentDescription(component, query.lang),
252
+ "",
253
+ "Props:",
254
+ ...component.props.map((prop) => `- ${prop.name}: ${prop.type}${prop.default ? ` = ${prop.default}` : ""} | ${prop.description}`),
255
+ "",
256
+ "Events:",
257
+ ...component.events.map((event) => `- ${event.name}${event.payload ? ` (${event.payload})` : ""}: ${event.description}`),
258
+ "",
259
+ "Slots:",
260
+ ...component.slots.map((slot) => `- ${slot.name}: ${slot.description}`),
261
+ "",
262
+ "CSS Variables:",
263
+ ...component.cssVars.map((cssVar) => {
264
+ const defaultValue = cssVar.defaultValue ?? cssVar.token;
265
+ return `- ${cssVar.name}${defaultValue ? ` = ${defaultValue}` : ""}: ${cssVar.description}`;
266
+ })
267
+ ];
268
+ console.log(lines.join("\n"));
269
+ } catch (error) {
270
+ printError(error instanceof Error ? error.message : "Failed to load component info", query.format);
271
+ process.exitCode = 1;
272
+ }
273
+ });
274
+ }
275
+
276
+ //#endregion
277
+ //#region src/commands/lint.ts
278
+ function registerLintCommand(program) {
279
+ addQueryOptions(program.command("lint").argument("[dir]", "Project directory", ".").description("Lint wot-ui usage")).action((dir, options) => {
280
+ const query = normalizeQueryOptions(options);
281
+ try {
282
+ const report = lintProject(resolve(dir), query.version);
283
+ if (query.format === "json") {
284
+ console.log(JSON.stringify(report, null, 2));
285
+ return;
286
+ }
287
+ if (!report.issues.length) {
288
+ console.log(`No lint issues found. Scanned files: ${report.scannedFiles}`);
289
+ return;
290
+ }
291
+ const lines = [`Scanned files: ${report.scannedFiles}`, ...report.issues.map((issue) => `${issue.severity.toUpperCase()} ${issue.file}:${issue.line} [${issue.rule}] ${issue.message}`)];
292
+ console.log(lines.join("\n"));
293
+ } catch (error) {
294
+ printError(error instanceof Error ? error.message : "Failed to lint project", query.format);
295
+ process.exitCode = 1;
296
+ }
297
+ });
298
+ }
299
+
300
+ //#endregion
301
+ //#region src/commands/list.ts
302
+ function registerListCommand(program) {
303
+ addQueryOptions(program.command("list").description("List available wot-ui components")).action((options) => {
304
+ const query = normalizeQueryOptions(options);
305
+ try {
306
+ const components = listComponents(query.version);
307
+ if (query.format === "json") {
308
+ console.log(JSON.stringify({ components }, null, 2));
309
+ return;
310
+ }
311
+ const lines = components.map((component) => `- ${getComponentLabel(component, query.lang)} (${component.tag}): ${getComponentDescription(component, query.lang)}`);
312
+ console.log(lines.join("\n"));
313
+ } catch (error) {
314
+ printError(error instanceof Error ? error.message : "Failed to list components", query.format);
315
+ process.exitCode = 1;
316
+ }
317
+ });
318
+ }
319
+
320
+ //#endregion
321
+ //#region src/commands/mcp.ts
322
+ function registerMcpCommand(program) {
323
+ program.command("mcp").description("Start the wot-ui MCP server").action(async () => {
324
+ const { startMcpServer } = await import("./server-HjZltXBO.mjs");
325
+ await startMcpServer();
326
+ });
327
+ }
328
+
329
+ //#endregion
330
+ //#region src/commands/token.ts
331
+ function registerTokenCommand(program) {
332
+ addQueryOptions(program.command("token").argument("[component]", "Component name or wd-* tag").description("Query component CSS variables")).action((componentName, options) => {
333
+ const query = normalizeQueryOptions(options);
334
+ try {
335
+ if (!componentName) {
336
+ const tokens = listComponents(query.version).flatMap((component$1) => component$1.cssVars.map((cssVar) => ({
337
+ component: component$1.name,
338
+ ...cssVar
339
+ })));
340
+ console.log(JSON.stringify(tokens, null, 2));
341
+ return;
342
+ }
343
+ const component = findComponent(componentName, query.version);
344
+ if (!component) {
345
+ printError(`Component not found: ${componentName}`, query.format);
346
+ process.exitCode = 1;
347
+ return;
348
+ }
349
+ if (query.format === "json") {
350
+ console.log(JSON.stringify({
351
+ name: component.name,
352
+ cssVars: formatCssVars(component.cssVars)
353
+ }, null, 2));
354
+ return;
355
+ }
356
+ const lines = [component.name, ...component.cssVars.map((cssVar) => {
357
+ const defaultValue = cssVar.defaultValue ?? cssVar.token;
358
+ return `- ${cssVar.name}${defaultValue ? ` = ${defaultValue}` : ""}: ${cssVar.description}`;
359
+ })];
360
+ console.log(lines.join("\n"));
361
+ } catch (error) {
362
+ printError(error instanceof Error ? error.message : "Failed to query CSS variables", query.format);
363
+ process.exitCode = 1;
364
+ }
365
+ });
366
+ }
367
+
368
+ //#endregion
369
+ //#region src/commands/usage.ts
370
+ function registerUsageCommand(program) {
371
+ addQueryOptions(program.command("usage").argument("[dir]", "Project directory", ".").description("Analyze project usage of wot-ui")).action((dir, options) => {
372
+ const query = normalizeQueryOptions(options);
373
+ try {
374
+ const report = analyzeUsage(resolve(dir), query.version);
375
+ if (query.format === "json") {
376
+ console.log(JSON.stringify(report, null, 2));
377
+ return;
378
+ }
379
+ const lines = [
380
+ `Scanned files: ${report.scannedFiles}`,
381
+ "Components:",
382
+ ...report.components.map((component) => `- ${component.name} (${component.tag}): ${component.count} in ${component.files.join(", ")}`)
383
+ ];
384
+ if (report.imports.length) lines.push("", "Imports:", ...report.imports.map((item) => `- ${item}`));
385
+ console.log(lines.join("\n"));
386
+ } catch (error) {
387
+ printError(error instanceof Error ? error.message : "Failed to analyze project usage", query.format);
388
+ process.exitCode = 1;
389
+ }
390
+ });
391
+ }
392
+
393
+ //#endregion
394
+ //#region src/app.ts
395
+ function createCliProgram() {
396
+ const program = new Command();
397
+ program.name("wot").description("wot-ui AI toolkit CLI").version("0.0.0");
398
+ registerListCommand(program);
399
+ registerInfoCommand(program);
400
+ registerDocCommand(program);
401
+ registerDemoCommand(program);
402
+ registerTokenCommand(program);
403
+ registerChangelogCommand(program);
404
+ registerDoctorCommand(program);
405
+ registerUsageCommand(program);
406
+ registerLintCommand(program);
407
+ registerMcpCommand(program);
408
+ return program;
409
+ }
410
+
411
+ //#endregion
412
+ //#region src/index.ts
413
+ await createCliProgram().parseAsync(process.argv);
414
+
415
+ //#endregion
416
+ export { };
@@ -0,0 +1,199 @@
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import { dirname, join, relative, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { gunzipSync } from "node:zlib";
5
+ import { parse } from "@vue/compiler-sfc";
6
+
7
+ //#region src/data/loader.ts
8
+ const currentDir = dirname(fileURLToPath(import.meta.url));
9
+ function resolveDataDir() {
10
+ const candidates = [
11
+ join(currentDir, "..", "data"),
12
+ join(currentDir, "..", "..", "data"),
13
+ join(currentDir, "data")
14
+ ];
15
+ for (const candidate of candidates) if (existsSync(join(candidate, "versions.json")) || existsSync(join(candidate, "versions.json.gz"))) return candidate;
16
+ throw new Error("Unable to locate bundled data directory");
17
+ }
18
+ const dataDir = resolveDataDir();
19
+ function readJsonFile(baseName) {
20
+ const jsonPath = join(dataDir, `${baseName}.json`);
21
+ if (existsSync(jsonPath)) return JSON.parse(readFileSync(jsonPath, "utf8"));
22
+ const gzipPath = join(dataDir, `${baseName}.json.gz`);
23
+ if (existsSync(gzipPath)) {
24
+ const compressed = readFileSync(gzipPath);
25
+ return JSON.parse(gunzipSync(compressed).toString("utf8"));
26
+ }
27
+ throw new Error(`Data file not found for ${baseName}`);
28
+ }
29
+ function loadVersionsFile() {
30
+ return readJsonFile("versions");
31
+ }
32
+ function loadMetadataFile(versionKey) {
33
+ return readJsonFile(versionKey);
34
+ }
35
+
36
+ //#endregion
37
+ //#region src/data/version.ts
38
+ const VERSION_KEY = "v2";
39
+ function resolveVersion(requested) {
40
+ const versions = loadVersionsFile();
41
+ if (!requested) return VERSION_KEY;
42
+ const normalized = requested.trim();
43
+ if (versions.aliases[normalized]) return VERSION_KEY;
44
+ if (versions.supported.includes(normalized)) return VERSION_KEY;
45
+ if (normalized === VERSION_KEY) return VERSION_KEY;
46
+ throw new Error(`Unsupported wot-ui version: ${requested}`);
47
+ }
48
+
49
+ //#endregion
50
+ //#region src/data/metadata.ts
51
+ function loadResolvedMetadata(version) {
52
+ return loadMetadataFile(resolveVersion(version));
53
+ }
54
+ function listComponents(version) {
55
+ return loadResolvedMetadata(version).components;
56
+ }
57
+ function findComponent(name, version) {
58
+ const normalized = name.trim().toLowerCase();
59
+ return listComponents(version).find((component) => component.name.toLowerCase() === normalized || component.tag.toLowerCase() === normalized);
60
+ }
61
+
62
+ //#endregion
63
+ //#region src/utils/files.ts
64
+ const DEFAULT_IGNORES = new Set([
65
+ ".git",
66
+ ".idea",
67
+ ".output",
68
+ ".turbo",
69
+ ".vscode",
70
+ "dist",
71
+ "build",
72
+ "coverage",
73
+ "node_modules"
74
+ ]);
75
+ function walkFiles(rootDir, extensions) {
76
+ const results = [];
77
+ function visit(dir) {
78
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
79
+ if (DEFAULT_IGNORES.has(entry.name)) continue;
80
+ const fullPath = join(dir, entry.name);
81
+ if (entry.isDirectory()) {
82
+ visit(fullPath);
83
+ continue;
84
+ }
85
+ if (extensions.some((extension) => entry.name.endsWith(extension))) results.push(fullPath);
86
+ }
87
+ }
88
+ visit(rootDir);
89
+ return results;
90
+ }
91
+ function safeRelative(rootDir, filePath) {
92
+ return relative(rootDir, filePath) || ".";
93
+ }
94
+
95
+ //#endregion
96
+ //#region src/utils/scanner.ts
97
+ const IMPORT_RE = /from\s+['"]([^'"]*wot[^'"]*)['"]/g;
98
+ const TAG_RE = /<\s*(wd-[a-z0-9-]+)/gi;
99
+ const BUTTON_RE = /<wd-button\b([^>]*)>([\s\S]*?)<\/wd-button>|<wd-button\b([^>]*)\/>/gi;
100
+ function getLineNumber(source, index) {
101
+ return source.slice(0, index).split("\n").length;
102
+ }
103
+ function collectTemplateTags(content) {
104
+ const counts = /* @__PURE__ */ new Map();
105
+ for (const match of content.matchAll(TAG_RE)) {
106
+ const tag = match[1]?.toLowerCase();
107
+ if (!tag) continue;
108
+ counts.set(tag, (counts.get(tag) ?? 0) + 1);
109
+ }
110
+ return counts;
111
+ }
112
+ function collectImports(scriptContent) {
113
+ const imports = /* @__PURE__ */ new Set();
114
+ for (const match of scriptContent.matchAll(IMPORT_RE)) if (match[1]) imports.add(match[1]);
115
+ return [...imports];
116
+ }
117
+ function analyzeUsage(targetDir, version) {
118
+ const dir = resolve(targetDir);
119
+ const files = walkFiles(dir, [".vue"]);
120
+ const knownByTag = new Map(listComponents(version).map((component) => [component.tag.toLowerCase(), component]));
121
+ const usageMap = /* @__PURE__ */ new Map();
122
+ const imports = /* @__PURE__ */ new Set();
123
+ for (const file of files) {
124
+ const parsed = parse(readFileSync(file, "utf8"), { filename: file });
125
+ const template = parsed.descriptor.template?.content ?? "";
126
+ const script = [parsed.descriptor.script?.content ?? "", parsed.descriptor.scriptSetup?.content ?? ""].filter(Boolean).join("\n");
127
+ for (const item of collectImports(script)) imports.add(item);
128
+ for (const [tag, count] of collectTemplateTags(template)) {
129
+ const known = knownByTag.get(tag);
130
+ const key = known?.name ?? tag;
131
+ const existing = usageMap.get(key);
132
+ if (existing) {
133
+ existing.count += count;
134
+ if (!existing.files.includes(safeRelative(dir, file))) existing.files.push(safeRelative(dir, file));
135
+ continue;
136
+ }
137
+ usageMap.set(key, {
138
+ name: known?.name ?? tag,
139
+ tag,
140
+ count,
141
+ files: [safeRelative(dir, file)]
142
+ });
143
+ }
144
+ }
145
+ return {
146
+ scannedFiles: files.length,
147
+ components: [...usageMap.values()].sort((left, right) => right.count - left.count || left.name.localeCompare(right.name)),
148
+ imports: [...imports].sort()
149
+ };
150
+ }
151
+ function lintProject(targetDir, version) {
152
+ const dir = resolve(targetDir);
153
+ const files = walkFiles(dir, [".vue"]);
154
+ const issues = [];
155
+ for (const file of files) {
156
+ const template = parse(readFileSync(file, "utf8"), { filename: file }).descriptor.template?.content ?? "";
157
+ for (const match of template.matchAll(TAG_RE)) {
158
+ const tag = match[1]?.toLowerCase();
159
+ if (!tag) continue;
160
+ if (!findComponent(tag, version)) issues.push({
161
+ file: safeRelative(dir, file),
162
+ line: getLineNumber(template, match.index ?? 0),
163
+ rule: "unknown-component",
164
+ severity: "warning",
165
+ message: `Unknown wot-ui component tag: ${tag}`
166
+ });
167
+ }
168
+ for (const match of template.matchAll(BUTTON_RE)) {
169
+ const attrs = (match[1] ?? match[3] ?? "").trim();
170
+ const body = (match[2] ?? "").replace(/<[^>]+>/g, "").trim();
171
+ if (!/\bicon\s*=/.test(attrs) && !body) issues.push({
172
+ file: safeRelative(dir, file),
173
+ line: getLineNumber(template, match.index ?? 0),
174
+ rule: "button-content",
175
+ severity: "warning",
176
+ message: "wd-button should include visible text content or an icon attribute."
177
+ });
178
+ const component = findComponent("wd-button", version);
179
+ for (const prop of component?.props ?? []) {
180
+ if (!prop.deprecated) continue;
181
+ if (!(/* @__PURE__ */ new RegExp(`\\b${prop.name}\\b`)).test(attrs)) continue;
182
+ issues.push({
183
+ file: safeRelative(dir, file),
184
+ line: getLineNumber(template, match.index ?? 0),
185
+ rule: "deprecated-prop",
186
+ severity: "warning",
187
+ message: prop.replacement ? `Deprecated prop ${prop.name} detected on wd-button. Use ${prop.replacement} instead.` : `Deprecated prop ${prop.name} detected on wd-button.`
188
+ });
189
+ }
190
+ }
191
+ }
192
+ return {
193
+ scannedFiles: files.length,
194
+ issues
195
+ };
196
+ }
197
+
198
+ //#endregion
199
+ export { resolveVersion as a, listComponents as i, lintProject as n, loadMetadataFile as o, findComponent as r, analyzeUsage as t };