@wot-ui/cli 0.0.1-beta.10

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