brutx-vue 0.1.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.d.ts +2 -0
- package/dist/index.js +914 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { createRequire } from "module";
|
|
6
|
+
|
|
7
|
+
// src/commands/init.ts
|
|
8
|
+
import ora from "ora";
|
|
9
|
+
import inquirer from "inquirer";
|
|
10
|
+
import fs3 from "fs-extra";
|
|
11
|
+
import path3 from "path";
|
|
12
|
+
|
|
13
|
+
// ../shared/src/components.ts
|
|
14
|
+
var COMPONENTS = {
|
|
15
|
+
alert: { name: "alert", dependencies: ["lucide-vue-next"] },
|
|
16
|
+
avatar: { name: "avatar", dependencies: ["reka-ui"] },
|
|
17
|
+
badge: { name: "badge", dependencies: [] },
|
|
18
|
+
button: { name: "button", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
19
|
+
calendar: { name: "calendar", dependencies: ["v-calendar", "lucide-vue-next"] },
|
|
20
|
+
card: { name: "card", dependencies: [] },
|
|
21
|
+
checkbox: { name: "checkbox", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
22
|
+
combobox: {
|
|
23
|
+
name: "combobox",
|
|
24
|
+
dependencies: ["reka-ui", "lucide-vue-next"]
|
|
25
|
+
},
|
|
26
|
+
command: { name: "command", dependencies: ["reka-ui"] },
|
|
27
|
+
dialog: { name: "dialog", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
28
|
+
"dropdown-menu": {
|
|
29
|
+
name: "dropdown-menu",
|
|
30
|
+
dependencies: ["reka-ui", "lucide-vue-next"]
|
|
31
|
+
},
|
|
32
|
+
input: { name: "input", dependencies: [] },
|
|
33
|
+
label: { name: "label", dependencies: ["reka-ui"] },
|
|
34
|
+
pagination: { name: "pagination", dependencies: ["lucide-vue-next"] },
|
|
35
|
+
popover: { name: "popover", dependencies: ["reka-ui"] },
|
|
36
|
+
"scroll-area": { name: "scroll-area", dependencies: ["reka-ui"] },
|
|
37
|
+
select: { name: "select", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
38
|
+
separator: { name: "separator", dependencies: ["reka-ui"] },
|
|
39
|
+
skeleton: { name: "skeleton", dependencies: [] },
|
|
40
|
+
spinner: { name: "spinner", dependencies: [] },
|
|
41
|
+
"submit-button": { name: "submit-button", dependencies: ["lucide-vue-next"] },
|
|
42
|
+
switch: { name: "switch", dependencies: ["reka-ui"] },
|
|
43
|
+
table: { name: "table", dependencies: [] },
|
|
44
|
+
tabs: { name: "tabs", dependencies: ["reka-ui"] },
|
|
45
|
+
textarea: { name: "textarea", dependencies: [] },
|
|
46
|
+
toast: { name: "toast", dependencies: ["lucide-vue-next"] },
|
|
47
|
+
tooltip: { name: "tooltip", dependencies: ["reka-ui"] },
|
|
48
|
+
"saas-pricing": { name: "saas-pricing", dependencies: ["lucide-vue-next"] },
|
|
49
|
+
"dashboard-stats": { name: "dashboard-stats", dependencies: ["lucide-vue-next"] },
|
|
50
|
+
form: { name: "form", dependencies: ["vee-validate", "@vee-validate/zod", "zod", "reka-ui"] },
|
|
51
|
+
"alert-dialog": { name: "alert-dialog", dependencies: ["reka-ui"] },
|
|
52
|
+
sheet: { name: "sheet", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
53
|
+
"radio-group": { name: "radio-group", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
54
|
+
slider: { name: "slider", dependencies: ["reka-ui"] },
|
|
55
|
+
progress: { name: "progress", dependencies: ["reka-ui"] },
|
|
56
|
+
toggle: { name: "toggle", dependencies: ["reka-ui"] },
|
|
57
|
+
"toggle-group": { name: "toggle-group", dependencies: ["reka-ui"] },
|
|
58
|
+
"brutalist-hero": { name: "brutalist-hero", dependencies: ["lucide-vue-next"] },
|
|
59
|
+
"pricing-section": { name: "pricing-section", dependencies: ["lucide-vue-next"] },
|
|
60
|
+
"auth-card": { name: "auth-card", dependencies: ["lucide-vue-next"] },
|
|
61
|
+
"dashboard-shell": { name: "dashboard-shell", dependencies: ["lucide-vue-next"] },
|
|
62
|
+
"empty-state": { name: "empty-state", dependencies: ["lucide-vue-next"] },
|
|
63
|
+
"waitlist-page": { name: "waitlist-page", dependencies: ["lucide-vue-next"] },
|
|
64
|
+
accordion: { name: "accordion", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
65
|
+
"tags-input": { name: "tags-input", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
66
|
+
"number-input": { name: "number-input", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
67
|
+
"copy-to-clipboard": { name: "copy-to-clipboard", dependencies: ["lucide-vue-next"] },
|
|
68
|
+
breadcrumb: { name: "breadcrumb", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
69
|
+
marquee: { name: "marquee", dependencies: [] },
|
|
70
|
+
"before-after": { name: "before-after", dependencies: [] },
|
|
71
|
+
"code-block": { name: "code-block", dependencies: ["lucide-vue-next"] },
|
|
72
|
+
timeline: { name: "timeline", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
73
|
+
carousel: { name: "carousel", dependencies: ["embla-carousel-vue", "lucide-vue-next"] },
|
|
74
|
+
"tree-view": { name: "tree-view", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
75
|
+
kanban: { name: "kanban", dependencies: ["lucide-vue-next"] },
|
|
76
|
+
"chat-bubble": { name: "chat-bubble", dependencies: ["reka-ui", "lucide-vue-next"] },
|
|
77
|
+
kbd: { name: "kbd", dependencies: [] },
|
|
78
|
+
counter: { name: "counter", dependencies: [] },
|
|
79
|
+
stepper: { name: "stepper", dependencies: ["lucide-vue-next"] }
|
|
80
|
+
};
|
|
81
|
+
var AVAILABLE_COMPONENTS = Object.keys(COMPONENTS);
|
|
82
|
+
|
|
83
|
+
// src/lib/constants.ts
|
|
84
|
+
var CONFIG_FILES = {
|
|
85
|
+
vite: ["vite.config.js", "vite.config.ts", "vite.config.mjs"],
|
|
86
|
+
nuxt: ["nuxt.config.js", "nuxt.config.ts", "nuxt.config.mjs"],
|
|
87
|
+
tailwind: [
|
|
88
|
+
"tailwind.config.ts",
|
|
89
|
+
"tailwind.config.js",
|
|
90
|
+
"tailwind.config.mjs",
|
|
91
|
+
"tailwind.config.cjs"
|
|
92
|
+
],
|
|
93
|
+
tsconfig: ["tsconfig.json", "jsconfig.json"],
|
|
94
|
+
lockfiles: {
|
|
95
|
+
pnpm: "pnpm-lock.yaml",
|
|
96
|
+
yarn: "yarn.lock",
|
|
97
|
+
bun: "bun.lockb"
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var CSS_LOCATIONS = {
|
|
101
|
+
"vite-vue": ["src/index.css", "src/App.css", "src/assets/main.css", "index.css"],
|
|
102
|
+
"vite-vue-src": ["src/index.css", "src/App.css", "src/assets/main.css", "src/styles/index.css"],
|
|
103
|
+
nuxt: ["assets/css/main.css", "assets/css/tailwind.css", "assets/css/global.css"],
|
|
104
|
+
unknown: [
|
|
105
|
+
"src/index.css",
|
|
106
|
+
"src/assets/main.css",
|
|
107
|
+
"src/styles/index.css",
|
|
108
|
+
"assets/css/main.css",
|
|
109
|
+
"index.css"
|
|
110
|
+
]
|
|
111
|
+
};
|
|
112
|
+
var BASE_DEPENDENCIES = [
|
|
113
|
+
"clsx",
|
|
114
|
+
"tailwind-merge",
|
|
115
|
+
"class-variance-authority",
|
|
116
|
+
"lucide-vue-next",
|
|
117
|
+
"reka-ui"
|
|
118
|
+
];
|
|
119
|
+
var DEFAULT_ALIASES = {
|
|
120
|
+
components: "@/components",
|
|
121
|
+
utils: "@/lib/utils"
|
|
122
|
+
};
|
|
123
|
+
var DEFAULT_TAILWIND_CONFIG = "tailwind.config.js";
|
|
124
|
+
var SCHEMA_URL = "https://lidaixingchen.github.io/brutxui-vue3/schema.json";
|
|
125
|
+
var DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/lidaixingchen/brutxui-vue3/main/packages/registry/registry";
|
|
126
|
+
var BRUTALIST_CSS_STYLES = `
|
|
127
|
+
:root {
|
|
128
|
+
--brutal-border-width: 3px;
|
|
129
|
+
--brutal-border-color: #000000;
|
|
130
|
+
--brutal-shadow-color: #000000;
|
|
131
|
+
--brutal-shadow-offset-sm: 2px;
|
|
132
|
+
--brutal-shadow-offset: 4px;
|
|
133
|
+
--brutal-shadow-offset-lg: 6px;
|
|
134
|
+
--brutal-shadow-offset-xl: 8px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.dark {
|
|
138
|
+
--brutal-border-color: #ffffff;
|
|
139
|
+
--brutal-shadow-color: #ffffff;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.border-3 {
|
|
143
|
+
border-width: var(--brutal-border-width, 3px);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.border-brutal {
|
|
147
|
+
border-color: var(--brutal-border-color, #000000);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.shadow-brutal {
|
|
151
|
+
box-shadow: var(--brutal-shadow-offset, 4px) var(--brutal-shadow-offset, 4px) 0px 0px var(--brutal-shadow-color, #000000);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.shadow-brutal-sm {
|
|
155
|
+
box-shadow: var(--brutal-shadow-offset-sm, 2px) var(--brutal-shadow-offset-sm, 2px) 0px 0px var(--brutal-shadow-color, #000000);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.shadow-brutal-lg {
|
|
159
|
+
box-shadow: var(--brutal-shadow-offset-lg, 6px) var(--brutal-shadow-offset-lg, 6px) 0px 0px var(--brutal-shadow-color, #000000);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.shadow-brutal-xl {
|
|
163
|
+
box-shadow: var(--brutal-shadow-offset-xl, 8px) var(--brutal-shadow-offset-xl, 8px) 0px 0px var(--brutal-shadow-color, #000000);
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
var UTILS_TEMPLATE = `import { type ClassValue, clsx } from "clsx";
|
|
167
|
+
import { twMerge } from "tailwind-merge";
|
|
168
|
+
|
|
169
|
+
export function cn(...inputs: ClassValue[]) {
|
|
170
|
+
return twMerge(clsx(inputs));
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
// src/lib/project.ts
|
|
175
|
+
import fs from "fs-extra";
|
|
176
|
+
import path from "path";
|
|
177
|
+
function hasAnyFile(cwd, files) {
|
|
178
|
+
return files.some((file) => fs.existsSync(path.join(cwd, file)));
|
|
179
|
+
}
|
|
180
|
+
function findFirstExisting(cwd, files) {
|
|
181
|
+
for (const file of files) {
|
|
182
|
+
if (fs.existsSync(path.join(cwd, file))) {
|
|
183
|
+
return file;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
function hasVueDependency(cwd) {
|
|
189
|
+
try {
|
|
190
|
+
const packageJson = fs.readJsonSync(path.join(cwd, "package.json"));
|
|
191
|
+
return Boolean(
|
|
192
|
+
packageJson.dependencies?.["vue"] || packageJson.devDependencies?.["vue"] || packageJson.dependencies?.["nuxt"] || packageJson.devDependencies?.["nuxt"]
|
|
193
|
+
);
|
|
194
|
+
} catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function detectProjectType(cwd) {
|
|
199
|
+
const hasNuxt = hasAnyFile(cwd, CONFIG_FILES.nuxt);
|
|
200
|
+
const hasVite = hasAnyFile(cwd, CONFIG_FILES.vite);
|
|
201
|
+
const hasSrc = fs.existsSync(path.join(cwd, "src"));
|
|
202
|
+
if (hasNuxt) return "nuxt";
|
|
203
|
+
if (hasVite && hasVueDependency(cwd)) {
|
|
204
|
+
return hasSrc ? "vite-vue-src" : "vite-vue";
|
|
205
|
+
}
|
|
206
|
+
if (hasVueDependency(cwd)) {
|
|
207
|
+
return hasSrc ? "vite-vue-src" : "vite-vue";
|
|
208
|
+
}
|
|
209
|
+
return "unknown";
|
|
210
|
+
}
|
|
211
|
+
function detectPackageManager(cwd) {
|
|
212
|
+
const { lockfiles } = CONFIG_FILES;
|
|
213
|
+
if (fs.existsSync(path.join(cwd, lockfiles.pnpm))) return "pnpm";
|
|
214
|
+
if (fs.existsSync(path.join(cwd, lockfiles.yarn))) return "yarn";
|
|
215
|
+
if (fs.existsSync(path.join(cwd, lockfiles.bun))) return "bun";
|
|
216
|
+
return "npm";
|
|
217
|
+
}
|
|
218
|
+
function readTsConfig(cwd) {
|
|
219
|
+
for (const configFile of CONFIG_FILES.tsconfig) {
|
|
220
|
+
const configPath = path.join(cwd, configFile);
|
|
221
|
+
if (!fs.existsSync(configPath)) continue;
|
|
222
|
+
try {
|
|
223
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
224
|
+
const jsonContent = content.replace(/\/\*[\s\S]*?\*\/|(?<!:)\/\/.*/g, "");
|
|
225
|
+
return JSON.parse(jsonContent);
|
|
226
|
+
} catch {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
function findTailwindConfig(cwd) {
|
|
233
|
+
return findFirstExisting(cwd, CONFIG_FILES.tailwind);
|
|
234
|
+
}
|
|
235
|
+
function findCssFile(cwd, projectType) {
|
|
236
|
+
const locations = CSS_LOCATIONS[projectType];
|
|
237
|
+
return findFirstExisting(cwd, locations);
|
|
238
|
+
}
|
|
239
|
+
function getAliasFromTsConfig(cwd) {
|
|
240
|
+
const tsConfig = readTsConfig(cwd);
|
|
241
|
+
const paths = tsConfig?.compilerOptions?.paths;
|
|
242
|
+
if (!paths) return null;
|
|
243
|
+
for (const alias of Object.keys(paths)) {
|
|
244
|
+
if (alias.endsWith("/*")) {
|
|
245
|
+
const prefix = alias.replace("/*", "");
|
|
246
|
+
return {
|
|
247
|
+
components: `${prefix}/components`,
|
|
248
|
+
utils: `${prefix}/lib/utils`
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
function resolveAliasPath(alias, cwd) {
|
|
255
|
+
const match = alias.match(/^(@[^/]*|~)\/(.*)/);
|
|
256
|
+
if (!match) {
|
|
257
|
+
return path.join(cwd, alias);
|
|
258
|
+
}
|
|
259
|
+
const [, aliasPrefix, relativePath] = match;
|
|
260
|
+
const resolvedFromConfig = resolveFromTsConfig(cwd, aliasPrefix, relativePath);
|
|
261
|
+
if (resolvedFromConfig) return resolvedFromConfig;
|
|
262
|
+
return resolveByProjectType(cwd, relativePath);
|
|
263
|
+
}
|
|
264
|
+
function resolveFromTsConfig(cwd, aliasPrefix, relativePath) {
|
|
265
|
+
const tsConfig = readTsConfig(cwd);
|
|
266
|
+
const paths = tsConfig?.compilerOptions?.paths;
|
|
267
|
+
if (!paths) return null;
|
|
268
|
+
const aliasPattern = `${aliasPrefix}/*`;
|
|
269
|
+
const baseUrl = tsConfig?.compilerOptions?.baseUrl || ".";
|
|
270
|
+
if (paths[aliasPattern]) {
|
|
271
|
+
const targetPath = paths[aliasPattern][0];
|
|
272
|
+
const resolvedBase = targetPath.replace("/*", "");
|
|
273
|
+
return path.join(cwd, baseUrl, resolvedBase, relativePath);
|
|
274
|
+
}
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
function resolveByProjectType(cwd, relativePath) {
|
|
278
|
+
const projectType = detectProjectType(cwd);
|
|
279
|
+
const projectTypeToBase = {
|
|
280
|
+
"vite-vue-src": "src",
|
|
281
|
+
"vite-vue": "",
|
|
282
|
+
nuxt: "",
|
|
283
|
+
unknown: fs.existsSync(path.join(cwd, "src")) ? "src" : ""
|
|
284
|
+
};
|
|
285
|
+
const base = projectTypeToBase[projectType];
|
|
286
|
+
return path.join(cwd, base, relativePath);
|
|
287
|
+
}
|
|
288
|
+
function inferTailwindVersionFromConfig(cwd) {
|
|
289
|
+
const hasConfig = CONFIG_FILES.tailwind.some((file) => fs.existsSync(path.join(cwd, file)));
|
|
290
|
+
return hasConfig ? "v3" : "v4";
|
|
291
|
+
}
|
|
292
|
+
function getDefaultAliases(cwd) {
|
|
293
|
+
return getAliasFromTsConfig(cwd) ?? { ...DEFAULT_ALIASES };
|
|
294
|
+
}
|
|
295
|
+
function resolveImportAlias(content, config) {
|
|
296
|
+
return content.replace(/["']@\/lib\/utils["']/g, `"${config.aliases.utils}"`).replace(/["']@\/components\/(.*?)["']/g, `"${config.aliases.components}/$1"`);
|
|
297
|
+
}
|
|
298
|
+
function isSafePath(targetPath, cwd) {
|
|
299
|
+
const resolvedTarget = path.resolve(targetPath).toLowerCase();
|
|
300
|
+
const resolvedCwd = path.resolve(cwd).toLowerCase();
|
|
301
|
+
return resolvedTarget.startsWith(resolvedCwd + path.sep) || resolvedTarget === resolvedCwd;
|
|
302
|
+
}
|
|
303
|
+
function detectTailwindVersion(cwd) {
|
|
304
|
+
try {
|
|
305
|
+
const pkgJsonPath = path.join(cwd, "package.json");
|
|
306
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
307
|
+
const pkg2 = fs.readJsonSync(pkgJsonPath);
|
|
308
|
+
const tailwindVersion = pkg2.dependencies?.["tailwindcss"] || pkg2.devDependencies?.["tailwindcss"];
|
|
309
|
+
if (tailwindVersion) {
|
|
310
|
+
const cleanVersion = tailwindVersion.replace(/^[^0-9]+/, "");
|
|
311
|
+
if (cleanVersion.startsWith("4")) {
|
|
312
|
+
return "v4";
|
|
313
|
+
}
|
|
314
|
+
if (cleanVersion.startsWith("3")) {
|
|
315
|
+
return "v3";
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
return inferTailwindVersionFromConfig(cwd);
|
|
321
|
+
}
|
|
322
|
+
return inferTailwindVersionFromConfig(cwd);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/lib/package-manager.ts
|
|
326
|
+
import { execFileSync } from "child_process";
|
|
327
|
+
var INSTALL_COMMANDS = {
|
|
328
|
+
pnpm: "pnpm add",
|
|
329
|
+
yarn: "yarn add",
|
|
330
|
+
bun: "bun add",
|
|
331
|
+
npm: "npm install"
|
|
332
|
+
};
|
|
333
|
+
function installPackages(packageManager, packages, cwd) {
|
|
334
|
+
if (packages.length === 0) return;
|
|
335
|
+
const [command, ...baseArgs] = INSTALL_COMMANDS[packageManager].split(" ");
|
|
336
|
+
execFileSync(command, [...baseArgs, ...packages], { stdio: "inherit", cwd });
|
|
337
|
+
}
|
|
338
|
+
function getInstallCommand(packageManager, packages) {
|
|
339
|
+
return `${INSTALL_COMMANDS[packageManager]} ${packages.join(" ")}`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// src/lib/logger.ts
|
|
343
|
+
import chalk from "chalk";
|
|
344
|
+
var Logger = class {
|
|
345
|
+
constructor() {
|
|
346
|
+
this.silent = false;
|
|
347
|
+
}
|
|
348
|
+
setSilent(silent) {
|
|
349
|
+
this.silent = silent;
|
|
350
|
+
}
|
|
351
|
+
log(message) {
|
|
352
|
+
if (!this.silent) {
|
|
353
|
+
console.log(message);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
info(message) {
|
|
357
|
+
this.log(chalk.gray(message));
|
|
358
|
+
}
|
|
359
|
+
success(message) {
|
|
360
|
+
this.log(chalk.green(message));
|
|
361
|
+
}
|
|
362
|
+
warn(message) {
|
|
363
|
+
this.log(chalk.yellow(message));
|
|
364
|
+
}
|
|
365
|
+
error(message) {
|
|
366
|
+
this.log(chalk.red(message));
|
|
367
|
+
}
|
|
368
|
+
bold(message) {
|
|
369
|
+
this.log(chalk.bold(message));
|
|
370
|
+
}
|
|
371
|
+
highlight(message) {
|
|
372
|
+
this.log(chalk.cyan(message));
|
|
373
|
+
}
|
|
374
|
+
dim(message) {
|
|
375
|
+
this.log(chalk.dim(message));
|
|
376
|
+
}
|
|
377
|
+
newLine() {
|
|
378
|
+
this.log("");
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
var logger = new Logger();
|
|
382
|
+
|
|
383
|
+
// src/lib/registry.ts
|
|
384
|
+
import fs2 from "fs-extra";
|
|
385
|
+
import path2 from "path";
|
|
386
|
+
function isUrl(str) {
|
|
387
|
+
return str.startsWith("http://") || str.startsWith("https://");
|
|
388
|
+
}
|
|
389
|
+
function validateRegistryFile(file, itemName) {
|
|
390
|
+
if (typeof file !== "object" || file === null) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
const f = file;
|
|
394
|
+
if (typeof f.path !== "string" || f.path.length === 0) {
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Invalid registry file in "${itemName}": "path" must be a non-empty string.`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (typeof f.content !== "string") {
|
|
400
|
+
throw new Error(
|
|
401
|
+
`Invalid registry file in "${itemName}": "content" must be a string.`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
function validateRegistryItem(data, name) {
|
|
407
|
+
if (typeof data !== "object" || data === null) {
|
|
408
|
+
throw new Error(`Invalid registry data for "${name}": expected an object.`);
|
|
409
|
+
}
|
|
410
|
+
const item = data;
|
|
411
|
+
if (typeof item.name !== "string" || item.name.length === 0) {
|
|
412
|
+
throw new Error(`Invalid registry data for "${name}": "name" must be a non-empty string.`);
|
|
413
|
+
}
|
|
414
|
+
if (typeof item.type !== "string") {
|
|
415
|
+
throw new Error(`Invalid registry data for "${name}": "type" must be a string.`);
|
|
416
|
+
}
|
|
417
|
+
if (!Array.isArray(item.files)) {
|
|
418
|
+
throw new Error(`Invalid registry data for "${name}": "files" must be an array.`);
|
|
419
|
+
}
|
|
420
|
+
for (const file of item.files) {
|
|
421
|
+
validateRegistryFile(file, name);
|
|
422
|
+
}
|
|
423
|
+
if (item.dependencies !== void 0 && !Array.isArray(item.dependencies)) {
|
|
424
|
+
throw new Error(`Invalid registry data for "${name}": "dependencies" must be an array.`);
|
|
425
|
+
}
|
|
426
|
+
if (item.registryDependencies !== void 0 && !Array.isArray(item.registryDependencies)) {
|
|
427
|
+
throw new Error(
|
|
428
|
+
`Invalid registry data for "${name}": "registryDependencies" must be an array.`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async function getItem(name, source = DEFAULT_REGISTRY_URL) {
|
|
433
|
+
let data;
|
|
434
|
+
if (isUrl(source)) {
|
|
435
|
+
const url = `${source}/${name}.json`;
|
|
436
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
437
|
+
if (!res.ok) {
|
|
438
|
+
throw new Error(`Failed to fetch component "${name}" from registry: ${res.statusText}`);
|
|
439
|
+
}
|
|
440
|
+
data = await res.json();
|
|
441
|
+
} else {
|
|
442
|
+
const filePath = path2.resolve(source, `${name}.json`);
|
|
443
|
+
if (!filePath.startsWith(path2.resolve(source) + path2.sep)) {
|
|
444
|
+
throw new Error(`Security Error: Path traversal detected in component name "${name}".`);
|
|
445
|
+
}
|
|
446
|
+
if (!await fs2.pathExists(filePath)) {
|
|
447
|
+
throw new Error(`Component "${name}" not found in local registry: ${filePath}`);
|
|
448
|
+
}
|
|
449
|
+
data = await fs2.readJson(filePath);
|
|
450
|
+
}
|
|
451
|
+
validateRegistryItem(data, name);
|
|
452
|
+
return data;
|
|
453
|
+
}
|
|
454
|
+
async function resolveDeps(names, source = DEFAULT_REGISTRY_URL) {
|
|
455
|
+
const resolved = [];
|
|
456
|
+
const visited = /* @__PURE__ */ new Set();
|
|
457
|
+
const active = /* @__PURE__ */ new Set();
|
|
458
|
+
async function dfs(fullName) {
|
|
459
|
+
let cleanName = fullName;
|
|
460
|
+
let itemSource = source;
|
|
461
|
+
if (fullName.includes("@")) {
|
|
462
|
+
const match = fullName.match(/^([a-z0-9-]+)@([a-zA-Z0-9._-]+)$/);
|
|
463
|
+
if (match) {
|
|
464
|
+
cleanName = match[1];
|
|
465
|
+
const version = match[2];
|
|
466
|
+
if (source === DEFAULT_REGISTRY_URL) {
|
|
467
|
+
itemSource = `https://raw.githubusercontent.com/lidaixingchen/brutxui-vue3/${version}/packages/registry/registry`;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (active.has(cleanName)) {
|
|
472
|
+
throw new Error(`Circular dependency detected: ${cleanName}`);
|
|
473
|
+
}
|
|
474
|
+
if (visited.has(cleanName)) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
active.add(cleanName);
|
|
478
|
+
try {
|
|
479
|
+
const item = await getItem(cleanName, itemSource);
|
|
480
|
+
if (item.registryDependencies && item.registryDependencies.length > 0) {
|
|
481
|
+
for (const dep of item.registryDependencies) {
|
|
482
|
+
await dfs(dep);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
active.delete(cleanName);
|
|
486
|
+
visited.add(cleanName);
|
|
487
|
+
resolved.push(item);
|
|
488
|
+
} catch (err) {
|
|
489
|
+
active.delete(cleanName);
|
|
490
|
+
throw err;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
for (const name of names) {
|
|
494
|
+
await dfs(name);
|
|
495
|
+
}
|
|
496
|
+
return resolved;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/commands/init.ts
|
|
500
|
+
async function detectSettings(cwd) {
|
|
501
|
+
const projectType = detectProjectType(cwd);
|
|
502
|
+
const tailwindVersion = detectTailwindVersion(cwd);
|
|
503
|
+
const tailwindConfig = findTailwindConfig(cwd);
|
|
504
|
+
const cssFile = findCssFile(cwd, projectType);
|
|
505
|
+
const aliases = getDefaultAliases(cwd);
|
|
506
|
+
const fallbackCss = projectType === "nuxt" ? "assets/css/main.css" : projectType.includes("src") ? "src/index.css" : "index.css";
|
|
507
|
+
return {
|
|
508
|
+
tailwind: {
|
|
509
|
+
config: tailwindVersion === "v4" ? "" : tailwindConfig ?? DEFAULT_TAILWIND_CONFIG,
|
|
510
|
+
css: cssFile ?? fallbackCss
|
|
511
|
+
},
|
|
512
|
+
aliases
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
async function promptForConfig(defaults) {
|
|
516
|
+
const answers = await inquirer.prompt([
|
|
517
|
+
{
|
|
518
|
+
type: "input",
|
|
519
|
+
name: "tailwindConfig",
|
|
520
|
+
message: "Where is your tailwind.config located?",
|
|
521
|
+
default: defaults.tailwind.config,
|
|
522
|
+
when: () => defaults.tailwind.config !== ""
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
type: "input",
|
|
526
|
+
name: "globalCss",
|
|
527
|
+
message: "Where is your global CSS file?",
|
|
528
|
+
default: defaults.tailwind.css
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
type: "input",
|
|
532
|
+
name: "componentsAlias",
|
|
533
|
+
message: "Configure the import alias for components:",
|
|
534
|
+
default: defaults.aliases.components
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
type: "input",
|
|
538
|
+
name: "utilsAlias",
|
|
539
|
+
message: "Configure the import alias for utils:",
|
|
540
|
+
default: defaults.aliases.utils
|
|
541
|
+
}
|
|
542
|
+
]);
|
|
543
|
+
return {
|
|
544
|
+
tailwind: {
|
|
545
|
+
config: answers.tailwindConfig ?? defaults.tailwind.config,
|
|
546
|
+
css: answers.globalCss
|
|
547
|
+
},
|
|
548
|
+
aliases: {
|
|
549
|
+
components: answers.componentsAlias,
|
|
550
|
+
utils: answers.utilsAlias
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
async function createConfigFile(cwd, settings) {
|
|
555
|
+
const config = {
|
|
556
|
+
$schema: SCHEMA_URL,
|
|
557
|
+
style: "brutalism",
|
|
558
|
+
tailwind: settings.tailwind,
|
|
559
|
+
aliases: settings.aliases
|
|
560
|
+
};
|
|
561
|
+
const configPath = path3.join(cwd, "components.json");
|
|
562
|
+
await fs3.writeJson(configPath, config, { spaces: 2 });
|
|
563
|
+
}
|
|
564
|
+
async function addBrutalistStyles(cwd, cssPath) {
|
|
565
|
+
const fullPath = path3.join(cwd, cssPath);
|
|
566
|
+
if (!isSafePath(fullPath, cwd)) {
|
|
567
|
+
throw new Error(`Security Error: CSS path traversal detected. Access denied to path "${fullPath}".`);
|
|
568
|
+
}
|
|
569
|
+
await fs3.ensureDir(path3.dirname(fullPath));
|
|
570
|
+
const tailwindVersion = detectTailwindVersion(cwd);
|
|
571
|
+
let content = "";
|
|
572
|
+
if (await fs3.pathExists(fullPath)) {
|
|
573
|
+
content = await fs3.readFile(fullPath, "utf-8");
|
|
574
|
+
if (content.includes("shadow-brutal")) {
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
content += BRUTALIST_CSS_STYLES;
|
|
578
|
+
} else {
|
|
579
|
+
if (tailwindVersion === "v4") {
|
|
580
|
+
content = `@import "tailwindcss";
|
|
581
|
+
${BRUTALIST_CSS_STYLES}`;
|
|
582
|
+
} else {
|
|
583
|
+
content = `@tailwind base;
|
|
584
|
+
@tailwind components;
|
|
585
|
+
@tailwind utilities;
|
|
586
|
+
${BRUTALIST_CSS_STYLES}`;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
await fs3.writeFile(fullPath, content);
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
async function shouldProceed(cwd, options) {
|
|
593
|
+
const configPath = path3.join(cwd, "components.json");
|
|
594
|
+
if (!await fs3.pathExists(configPath)) {
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
if (options.force) {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
if (options.yes) {
|
|
601
|
+
logger.warn("Brutx-Vue is already initialized. Use --force to overwrite.");
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
const { overwrite } = await inquirer.prompt([
|
|
605
|
+
{
|
|
606
|
+
type: "confirm",
|
|
607
|
+
name: "overwrite",
|
|
608
|
+
message: "Brutx-Vue is already initialized. Overwrite?",
|
|
609
|
+
default: false
|
|
610
|
+
}
|
|
611
|
+
]);
|
|
612
|
+
if (!overwrite) {
|
|
613
|
+
logger.warn("Aborted.");
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
async function init(options) {
|
|
619
|
+
const cwd = options.cwd ?? process.cwd();
|
|
620
|
+
const projectType = detectProjectType(cwd);
|
|
621
|
+
logger.setSilent(options.silent ?? false);
|
|
622
|
+
logger.bold("\n\u{1F3A8} Brutx-Vue - Neo-Brutalism Vue 3 Component Library\n");
|
|
623
|
+
logger.info(` Detected project: ${projectType}
|
|
624
|
+
`);
|
|
625
|
+
if (!await shouldProceed(cwd, options)) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
let settings = await detectSettings(cwd);
|
|
629
|
+
if (!options.yes && !options.defaults) {
|
|
630
|
+
settings = await promptForConfig(settings);
|
|
631
|
+
}
|
|
632
|
+
const spinner = options.silent ? null : ora("Initializing Brutx-Vue...").start();
|
|
633
|
+
try {
|
|
634
|
+
await createConfigFile(cwd, settings);
|
|
635
|
+
const utilsPath = resolveAliasPath(settings.aliases.utils, cwd) + ".ts";
|
|
636
|
+
await fs3.ensureDir(path3.dirname(utilsPath));
|
|
637
|
+
if (!await fs3.pathExists(utilsPath)) {
|
|
638
|
+
await fs3.writeFile(utilsPath, UTILS_TEMPLATE);
|
|
639
|
+
spinner?.info("Created utility helper at " + settings.aliases.utils);
|
|
640
|
+
} else {
|
|
641
|
+
spinner?.info("Utility helper already exists, skipping.");
|
|
642
|
+
}
|
|
643
|
+
const componentsDir = resolveAliasPath(settings.aliases.components, cwd);
|
|
644
|
+
await fs3.ensureDir(path3.join(componentsDir, "ui"));
|
|
645
|
+
spinner?.info("Created components/ui directory");
|
|
646
|
+
const stylesAdded = await addBrutalistStyles(cwd, settings.tailwind.css);
|
|
647
|
+
if (stylesAdded) {
|
|
648
|
+
spinner?.info("Added brutalist styles to " + settings.tailwind.css);
|
|
649
|
+
} else {
|
|
650
|
+
spinner?.info("Brutalist design tokens already present in " + settings.tailwind.css + ", skipped duplicate injection.");
|
|
651
|
+
}
|
|
652
|
+
spinner?.succeed("Brutx-Vue initialized successfully!");
|
|
653
|
+
const packageManager = detectPackageManager(cwd);
|
|
654
|
+
logger.newLine();
|
|
655
|
+
logger.bold(`Installing dependencies with ${packageManager}...`);
|
|
656
|
+
try {
|
|
657
|
+
installPackages(packageManager, [...BASE_DEPENDENCIES], cwd);
|
|
658
|
+
logger.success("\u2713 Dependencies installed");
|
|
659
|
+
} catch {
|
|
660
|
+
logger.warn("\u26A0 Failed to install dependencies automatically.");
|
|
661
|
+
logger.info(
|
|
662
|
+
` Run manually: ${getInstallCommand(packageManager, [...BASE_DEPENDENCIES])}`
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
logger.newLine();
|
|
666
|
+
logger.bold("Next steps:");
|
|
667
|
+
logger.highlight(" 1. Add components:");
|
|
668
|
+
logger.info(" npx brutx-vue@latest add button");
|
|
669
|
+
logger.info(" npx brutx-vue@latest add --all");
|
|
670
|
+
logger.newLine();
|
|
671
|
+
logger.dim("Documentation: https://lidaixingchen.github.io/brutxui-vue3/");
|
|
672
|
+
} catch (error) {
|
|
673
|
+
spinner?.fail("Failed to initialize Brutx-Vue");
|
|
674
|
+
console.error(error);
|
|
675
|
+
process.exit(1);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// src/commands/add.ts
|
|
680
|
+
import ora2 from "ora";
|
|
681
|
+
import inquirer2 from "inquirer";
|
|
682
|
+
import fs4 from "fs-extra";
|
|
683
|
+
import path4 from "path";
|
|
684
|
+
async function ensureInitialized(cwd) {
|
|
685
|
+
const configPath = path4.join(cwd, "components.json");
|
|
686
|
+
if (!await fs4.pathExists(configPath)) {
|
|
687
|
+
logger.error("Error: Brutx-Vue is not initialized.");
|
|
688
|
+
logger.warn("Run: npx brutx-vue@latest init");
|
|
689
|
+
process.exit(1);
|
|
690
|
+
}
|
|
691
|
+
const config = await fs4.readJson(configPath);
|
|
692
|
+
if (!config?.aliases?.components || !config?.aliases?.utils) {
|
|
693
|
+
logger.error('Error: Invalid components.json. Missing required "aliases.components" or "aliases.utils".');
|
|
694
|
+
logger.warn("Run: npx brutx-vue@latest init --force to regenerate.");
|
|
695
|
+
process.exit(1);
|
|
696
|
+
}
|
|
697
|
+
return config;
|
|
698
|
+
}
|
|
699
|
+
async function validateComponents(components) {
|
|
700
|
+
const cleanComponents = components.map((c) => c.split("@")[0]);
|
|
701
|
+
const invalid = cleanComponents.filter((c) => !AVAILABLE_COMPONENTS.includes(c));
|
|
702
|
+
if (invalid.length > 0) {
|
|
703
|
+
logger.newLine();
|
|
704
|
+
logger.error(`Unknown components: ${invalid.join(", ")}`);
|
|
705
|
+
logger.warn("Please choose from the available list or run npx brutx-vue add interactively without arguments.");
|
|
706
|
+
logger.warn(`Available: ${AVAILABLE_COMPONENTS.join(", ")}`);
|
|
707
|
+
process.exit(1);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
async function selectComponents(inputComponents, options) {
|
|
711
|
+
if (options.all) {
|
|
712
|
+
return [...AVAILABLE_COMPONENTS];
|
|
713
|
+
}
|
|
714
|
+
if (inputComponents.length > 0) {
|
|
715
|
+
return inputComponents;
|
|
716
|
+
}
|
|
717
|
+
if (options.yes) {
|
|
718
|
+
logger.error("Error: No components specified.");
|
|
719
|
+
logger.warn("Use: npx brutx-vue@latest add [component] or --all");
|
|
720
|
+
process.exit(1);
|
|
721
|
+
}
|
|
722
|
+
const { selected } = await inquirer2.prompt([
|
|
723
|
+
{
|
|
724
|
+
type: "checkbox",
|
|
725
|
+
name: "selected",
|
|
726
|
+
message: "Which components would you like to add?",
|
|
727
|
+
choices: AVAILABLE_COMPONENTS.map((name) => ({ name, value: name })),
|
|
728
|
+
pageSize: 15
|
|
729
|
+
}
|
|
730
|
+
]);
|
|
731
|
+
return selected;
|
|
732
|
+
}
|
|
733
|
+
function resolveComponentFilePath(registryPath, config, cwd) {
|
|
734
|
+
if (registryPath.startsWith("components/")) {
|
|
735
|
+
const relative = registryPath.replace("components/", "");
|
|
736
|
+
const aliasPath = resolveAliasPath(config.aliases.components, cwd);
|
|
737
|
+
return path4.join(aliasPath, relative);
|
|
738
|
+
}
|
|
739
|
+
if (registryPath.startsWith("lib/utils")) {
|
|
740
|
+
return resolveAliasPath(config.aliases.utils, cwd) + ".ts";
|
|
741
|
+
}
|
|
742
|
+
if (registryPath.startsWith("lib/")) {
|
|
743
|
+
const relative = registryPath.slice(4);
|
|
744
|
+
const aliasPath = resolveAliasPath(config.aliases.utils, cwd);
|
|
745
|
+
return path4.join(path4.dirname(aliasPath), relative);
|
|
746
|
+
}
|
|
747
|
+
return path4.join(cwd, registryPath);
|
|
748
|
+
}
|
|
749
|
+
async function ensureUtilsFile(utilsPath) {
|
|
750
|
+
if (await fs4.pathExists(utilsPath)) {
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
753
|
+
await fs4.ensureDir(path4.dirname(utilsPath));
|
|
754
|
+
await fs4.writeFile(utilsPath, UTILS_TEMPLATE);
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
async function writeRegistryFiles(items, config, cwd, options, spinner) {
|
|
758
|
+
const added = [];
|
|
759
|
+
const skippedSet = /* @__PURE__ */ new Set();
|
|
760
|
+
const filesWritten = [];
|
|
761
|
+
for (const item of items) {
|
|
762
|
+
let itemAdded = false;
|
|
763
|
+
for (const file of item.files) {
|
|
764
|
+
const normalizedPath = path4.normalize(file.path);
|
|
765
|
+
if (normalizedPath.startsWith("..") || path4.isAbsolute(normalizedPath)) {
|
|
766
|
+
throw new Error(`Security Error: Malicious component file path detected: "${file.path}".`);
|
|
767
|
+
}
|
|
768
|
+
const targetPath = resolveComponentFilePath(file.path, config, cwd);
|
|
769
|
+
if (!isSafePath(targetPath, cwd)) {
|
|
770
|
+
throw new Error(`Security Error: Path traversal detected. Access denied to path "${targetPath}".`);
|
|
771
|
+
}
|
|
772
|
+
if (await fs4.pathExists(targetPath)) {
|
|
773
|
+
if (!options.overwrite) {
|
|
774
|
+
spinner?.info(`Skipping file "${file.path}" for "${item.name}" (already exists). Use --overwrite to overwrite.`);
|
|
775
|
+
skippedSet.add(item.name);
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (options.dryRun) {
|
|
780
|
+
spinner?.info(`[Dry Run] Would create file: ${targetPath}`);
|
|
781
|
+
itemAdded = true;
|
|
782
|
+
filesWritten.push(targetPath);
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
await fs4.ensureDir(path4.dirname(targetPath));
|
|
786
|
+
const resolvedContent = resolveImportAlias(file.content, config);
|
|
787
|
+
await fs4.writeFile(targetPath, resolvedContent, "utf-8");
|
|
788
|
+
itemAdded = true;
|
|
789
|
+
filesWritten.push(targetPath);
|
|
790
|
+
}
|
|
791
|
+
if (itemAdded && !skippedSet.has(item.name)) {
|
|
792
|
+
added.push(item.name);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return { added, skipped: Array.from(skippedSet), filesWritten };
|
|
796
|
+
}
|
|
797
|
+
function installComponentDeps(deps, cwd, dryRun) {
|
|
798
|
+
if (deps.length === 0) return;
|
|
799
|
+
const packageManager = detectPackageManager(cwd);
|
|
800
|
+
logger.newLine();
|
|
801
|
+
if (dryRun) {
|
|
802
|
+
logger.bold(`[Dry Run] Would install dependencies using ${packageManager}:`);
|
|
803
|
+
logger.info(` ${deps.join(", ")}`);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
logger.bold(`Installing dependencies with ${packageManager}...`);
|
|
807
|
+
try {
|
|
808
|
+
installPackages(packageManager, deps, cwd);
|
|
809
|
+
logger.success("\u2713 Dependencies installed");
|
|
810
|
+
} catch {
|
|
811
|
+
logger.warn("\u26A0 Failed to install dependencies automatically.");
|
|
812
|
+
logger.info(` Run manually: ${getInstallCommand(packageManager, deps)}`);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
function toPascalCase(str) {
|
|
816
|
+
return str.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
817
|
+
}
|
|
818
|
+
function printUsageExample(component, componentsAlias) {
|
|
819
|
+
const componentName = toPascalCase(component);
|
|
820
|
+
logger.info(` import ${componentName} from "${componentsAlias}/ui/${component}/${componentName}.vue"`);
|
|
821
|
+
}
|
|
822
|
+
async function add(components, options) {
|
|
823
|
+
const cwd = options.cwd ?? process.cwd();
|
|
824
|
+
const targetCwd = options.path ? path4.resolve(cwd, options.path) : cwd;
|
|
825
|
+
if (options.path && !isSafePath(targetCwd, cwd)) {
|
|
826
|
+
throw new Error(`Security Error: Path traversal detected. Access denied to path "${targetCwd}".`);
|
|
827
|
+
}
|
|
828
|
+
logger.setSilent(options.silent ?? false);
|
|
829
|
+
const config = await ensureInitialized(cwd);
|
|
830
|
+
await validateComponents(components);
|
|
831
|
+
const selectedComponents = await selectComponents(components, options);
|
|
832
|
+
if (selectedComponents.length === 0) {
|
|
833
|
+
logger.warn("No components selected.");
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const utilsPath = resolveAliasPath(config.aliases.utils, targetCwd) + ".ts";
|
|
837
|
+
const spinner = options.silent ? null : ora2("Resolving components and checking dependencies...").start();
|
|
838
|
+
try {
|
|
839
|
+
const registryItems = await resolveDeps(selectedComponents, options.registry);
|
|
840
|
+
if (spinner) {
|
|
841
|
+
spinner.stop();
|
|
842
|
+
}
|
|
843
|
+
logger.bold("\n\u{1F4E6} Brutx-Vue CLI - Installation Plan:");
|
|
844
|
+
logger.info(` Registry source: ${options.registry || "Default Brutx-Vue hosted registry"}`);
|
|
845
|
+
logger.newLine();
|
|
846
|
+
logger.bold("\u{1F9E9} Components to install/update:");
|
|
847
|
+
for (const item of registryItems) {
|
|
848
|
+
const depsStr = item.registryDependencies && item.registryDependencies.length > 0 ? ` (depends on: ${item.registryDependencies.join(", ")})` : "";
|
|
849
|
+
logger.info(` - ${item.name}${depsStr}`);
|
|
850
|
+
}
|
|
851
|
+
logger.newLine();
|
|
852
|
+
const allDeps = /* @__PURE__ */ new Set();
|
|
853
|
+
for (const item of registryItems) {
|
|
854
|
+
if (item.dependencies) {
|
|
855
|
+
item.dependencies.forEach((dep) => allDeps.add(dep));
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
if (allDeps.size > 0) {
|
|
859
|
+
logger.bold("\u{1F4DA} Required npm packages:");
|
|
860
|
+
logger.info(` ${Array.from(allDeps).join(", ")}`);
|
|
861
|
+
logger.newLine();
|
|
862
|
+
}
|
|
863
|
+
if (spinner) {
|
|
864
|
+
spinner.start("Adding component files...");
|
|
865
|
+
}
|
|
866
|
+
if (!options.dryRun) {
|
|
867
|
+
const utilsCreated = await ensureUtilsFile(utilsPath);
|
|
868
|
+
if (utilsCreated) {
|
|
869
|
+
spinner?.info(`Created utility file at ${utilsPath}`);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const { added, skipped, filesWritten } = await writeRegistryFiles(
|
|
873
|
+
registryItems,
|
|
874
|
+
config,
|
|
875
|
+
targetCwd,
|
|
876
|
+
options,
|
|
877
|
+
spinner
|
|
878
|
+
);
|
|
879
|
+
const summary = skipped.length > 0 ? `Added ${added.length} component(s), skipped ${skipped.length}` : `Added ${added.length} component(s)`;
|
|
880
|
+
if (options.dryRun) {
|
|
881
|
+
spinner?.succeed(`[Dry Run] Simulated: ${summary}`);
|
|
882
|
+
} else {
|
|
883
|
+
spinner?.succeed(summary);
|
|
884
|
+
}
|
|
885
|
+
if (added.length > 0 && filesWritten.length > 0) {
|
|
886
|
+
logger.newLine();
|
|
887
|
+
logger.bold("\u{1F4BE} Files written to disk:");
|
|
888
|
+
for (const filePath of filesWritten) {
|
|
889
|
+
const relativePath = path4.relative(targetCwd, filePath);
|
|
890
|
+
logger.success(` \u2713 ${relativePath}`);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
installComponentDeps(Array.from(allDeps), cwd, options.dryRun ?? false);
|
|
894
|
+
if (added.length > 0) {
|
|
895
|
+
logger.newLine();
|
|
896
|
+
logger.bold("Usage:");
|
|
897
|
+
printUsageExample(added[0], config.aliases.components);
|
|
898
|
+
}
|
|
899
|
+
} catch (error) {
|
|
900
|
+
spinner?.fail("Failed to add components");
|
|
901
|
+
logger.error(error?.message || error);
|
|
902
|
+
process.exit(1);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// src/index.ts
|
|
907
|
+
var require2 = createRequire(import.meta.url);
|
|
908
|
+
var pkg = require2("../package.json");
|
|
909
|
+
var program = new Command();
|
|
910
|
+
program.name("brutx-vue").description("CLI for adding Brutx-Vue components to your project").version(pkg.version);
|
|
911
|
+
program.command("init").description("Initialize Brutx in your project").option("-y, --yes", "Skip confirmation prompts", false).option("-d, --defaults", "Use default configuration", false).option("-c, --cwd <cwd>", "The working directory", process.cwd()).option("-f, --force", "Force overwrite of existing configuration", false).option("-s, --silent", "Mute output", false).action(init);
|
|
912
|
+
program.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompts", false).option("-a, --all", "Add all components", false).option("-o, --overwrite", "Overwrite existing files", false).option("-p, --path <path>", "The path to add the component to").option("-c, --cwd <cwd>", "The working directory", process.cwd()).option("-s, --silent", "Mute output", false).option("--dry-run", "Simulate addition without writing files", false).option("-r, --registry <registry>", "Specify registry path or URL").action(add);
|
|
913
|
+
program.parse();
|
|
914
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../../shared/src/components.ts","../src/lib/constants.ts","../src/lib/project.ts","../src/lib/package-manager.ts","../src/lib/logger.ts","../src/lib/registry.ts","../src/commands/add.ts"],"sourcesContent":["import { Command } from 'commander';\r\nimport { createRequire } from 'module';\r\nimport { init } from './commands/init.js';\r\nimport { add } from './commands/add.js';\r\n\r\nconst require = createRequire(import.meta.url);\r\nconst pkg = require('../package.json');\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('brutx-vue')\r\n .description('CLI for adding Brutx-Vue components to your project')\r\n .version(pkg.version);\r\n\r\nprogram\r\n .command('init')\r\n .description('Initialize Brutx in your project')\r\n .option('-y, --yes', 'Skip confirmation prompts', false)\r\n .option('-d, --defaults', 'Use default configuration', false)\r\n .option('-c, --cwd <cwd>', 'The working directory', process.cwd())\r\n .option('-f, --force', 'Force overwrite of existing configuration', false)\r\n .option('-s, --silent', 'Mute output', false)\r\n .action(init);\r\n\r\nprogram\r\n .command('add')\r\n .description('Add components to your project')\r\n .argument('[components...]', 'Components to add')\r\n .option('-y, --yes', 'Skip confirmation prompts', false)\r\n .option('-a, --all', 'Add all components', false)\r\n .option('-o, --overwrite', 'Overwrite existing files', false)\r\n .option('-p, --path <path>', 'The path to add the component to')\r\n .option('-c, --cwd <cwd>', 'The working directory', process.cwd())\r\n .option('-s, --silent', 'Mute output', false)\r\n .option('--dry-run', 'Simulate addition without writing files', false)\r\n .option('-r, --registry <registry>', 'Specify registry path or URL')\r\n .action(add);\r\n\r\nprogram.parse();\r\n","import ora from 'ora';\nimport inquirer from 'inquirer';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nimport {\n type InitOptions,\n type BrutalistConfig,\n type TailwindConfig,\n type AliasConfig,\n BASE_DEPENDENCIES,\n BRUTALIST_CSS_STYLES,\n SCHEMA_URL,\n DEFAULT_TAILWIND_CONFIG,\n UTILS_TEMPLATE,\n detectProjectType,\n detectPackageManager,\n findTailwindConfig,\n findCssFile,\n getDefaultAliases,\n resolveAliasPath,\n detectTailwindVersion,\n installPackages,\n getInstallCommand,\n isSafePath,\n logger,\n} from '../lib/index.js';\n\ninterface DetectedSettings {\n tailwind: TailwindConfig;\n aliases: AliasConfig;\n}\n\nasync function detectSettings(cwd: string): Promise<DetectedSettings> {\n const projectType = detectProjectType(cwd);\n const tailwindVersion = detectTailwindVersion(cwd);\n\n const tailwindConfig = findTailwindConfig(cwd);\n const cssFile = findCssFile(cwd, projectType);\n const aliases = getDefaultAliases(cwd);\n\n const fallbackCss = projectType === 'nuxt'\n ? 'assets/css/main.css'\n : (projectType.includes('src') ? 'src/index.css' : 'index.css');\n\n return {\n tailwind: {\n config: tailwindVersion === 'v4' ? '' : (tailwindConfig ?? DEFAULT_TAILWIND_CONFIG),\n css: cssFile ?? fallbackCss,\n },\n aliases,\n };\n}\n\nasync function promptForConfig(defaults: DetectedSettings): Promise<DetectedSettings> {\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'tailwindConfig',\n message: 'Where is your tailwind.config located?',\n default: defaults.tailwind.config,\n when: () => defaults.tailwind.config !== '',\n },\n {\n type: 'input',\n name: 'globalCss',\n message: 'Where is your global CSS file?',\n default: defaults.tailwind.css,\n },\n {\n type: 'input',\n name: 'componentsAlias',\n message: 'Configure the import alias for components:',\n default: defaults.aliases.components,\n },\n {\n type: 'input',\n name: 'utilsAlias',\n message: 'Configure the import alias for utils:',\n default: defaults.aliases.utils,\n },\n ]);\n\n return {\n tailwind: {\n config: answers.tailwindConfig ?? defaults.tailwind.config,\n css: answers.globalCss,\n },\n aliases: {\n components: answers.componentsAlias,\n utils: answers.utilsAlias,\n },\n };\n}\n\nasync function createConfigFile(cwd: string, settings: DetectedSettings): Promise<void> {\n const config: BrutalistConfig = {\n $schema: SCHEMA_URL,\n style: 'brutalism',\n tailwind: settings.tailwind,\n aliases: settings.aliases,\n };\n\n const configPath = path.join(cwd, 'components.json');\n await fs.writeJson(configPath, config, { spaces: 2 });\n}\n\nasync function addBrutalistStyles(cwd: string, cssPath: string): Promise<boolean> {\n const fullPath = path.join(cwd, cssPath);\n\n if (!isSafePath(fullPath, cwd)) {\n throw new Error(`Security Error: CSS path traversal detected. Access denied to path \"${fullPath}\".`);\n }\n\n await fs.ensureDir(path.dirname(fullPath));\n\n const tailwindVersion = detectTailwindVersion(cwd);\n\n let content = '';\n if (await fs.pathExists(fullPath)) {\n content = await fs.readFile(fullPath, 'utf-8');\n if (content.includes('shadow-brutal')) {\n return false;\n }\n content += BRUTALIST_CSS_STYLES;\n } else {\n if (tailwindVersion === 'v4') {\n content = `@import \"tailwindcss\";\\n${BRUTALIST_CSS_STYLES}`;\n } else {\n content = `@tailwind base;\\n@tailwind components;\\n@tailwind utilities;\\n${BRUTALIST_CSS_STYLES}`;\n }\n }\n\n await fs.writeFile(fullPath, content);\n return true;\n}\n\nasync function shouldProceed(cwd: string, options: InitOptions): Promise<boolean> {\n const configPath = path.join(cwd, 'components.json');\n\n if (!(await fs.pathExists(configPath))) {\n return true;\n }\n\n if (options.force) {\n return true;\n }\n\n if (options.yes) {\n logger.warn('Brutx-Vue is already initialized. Use --force to overwrite.');\n return false;\n }\n\n const { overwrite } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'overwrite',\n message: 'Brutx-Vue is already initialized. Overwrite?',\n default: false,\n },\n ]);\n\n if (!overwrite) {\n logger.warn('Aborted.');\n return false;\n }\n\n return true;\n}\n\nexport async function init(options: InitOptions): Promise<void> {\n const cwd = options.cwd ?? process.cwd();\n const projectType = detectProjectType(cwd);\n\n logger.setSilent(options.silent ?? false);\n\n logger.bold('\\nšØ Brutx-Vue - Neo-Brutalism Vue 3 Component Library\\n');\n logger.info(` Detected project: ${projectType}\\n`);\n\n if (!(await shouldProceed(cwd, options))) {\n return;\n }\n\n let settings = await detectSettings(cwd);\n\n if (!options.yes && !options.defaults) {\n settings = await promptForConfig(settings);\n }\n\n const spinner = options.silent ? null : ora('Initializing Brutx-Vue...').start();\n\n try {\n await createConfigFile(cwd, settings);\n\n const utilsPath = resolveAliasPath(settings.aliases.utils, cwd) + '.ts';\n await fs.ensureDir(path.dirname(utilsPath));\n if (!(await fs.pathExists(utilsPath))) {\n await fs.writeFile(utilsPath, UTILS_TEMPLATE);\n spinner?.info('Created utility helper at ' + settings.aliases.utils);\n } else {\n spinner?.info('Utility helper already exists, skipping.');\n }\n\n const componentsDir = resolveAliasPath(settings.aliases.components, cwd);\n await fs.ensureDir(path.join(componentsDir, 'ui'));\n spinner?.info('Created components/ui directory');\n\n const stylesAdded = await addBrutalistStyles(cwd, settings.tailwind.css);\n if (stylesAdded) {\n spinner?.info('Added brutalist styles to ' + settings.tailwind.css);\n } else {\n spinner?.info('Brutalist design tokens already present in ' + settings.tailwind.css + ', skipped duplicate injection.');\n }\n\n spinner?.succeed('Brutx-Vue initialized successfully!');\n\n const packageManager = detectPackageManager(cwd);\n logger.newLine();\n logger.bold(`Installing dependencies with ${packageManager}...`);\n\n try {\n installPackages(packageManager, [...BASE_DEPENDENCIES], cwd);\n logger.success('ā Dependencies installed');\n } catch {\n logger.warn('ā Failed to install dependencies automatically.');\n logger.info(\n ` Run manually: ${getInstallCommand(packageManager, [...BASE_DEPENDENCIES])}`\n );\n }\n\n logger.newLine();\n logger.bold('Next steps:');\n logger.highlight(' 1. Add components:');\n logger.info(' npx brutx-vue@latest add button');\n logger.info(' npx brutx-vue@latest add --all');\n logger.newLine();\n logger.dim('Documentation: https://lidaixingchen.github.io/brutxui-vue3/');\n } catch (error) {\n spinner?.fail('Failed to initialize Brutx-Vue');\n console.error(error);\n process.exit(1);\n }\n}\n","import type { ComponentMeta } from './types.js';\n\nexport const COMPONENTS: Record<string, ComponentMeta> = {\n alert: { name: 'alert', dependencies: ['lucide-vue-next'] },\n avatar: { name: 'avatar', dependencies: ['reka-ui'] },\n badge: { name: 'badge', dependencies: [] },\n button: { name: 'button', dependencies: ['reka-ui', 'lucide-vue-next'] },\n calendar: { name: 'calendar', dependencies: ['v-calendar', 'lucide-vue-next'] },\n card: { name: 'card', dependencies: [] },\n checkbox: { name: 'checkbox', dependencies: ['reka-ui', 'lucide-vue-next'] },\n combobox: {\n name: 'combobox',\n dependencies: ['reka-ui', 'lucide-vue-next'],\n },\n command: { name: 'command', dependencies: ['reka-ui'] },\n dialog: { name: 'dialog', dependencies: ['reka-ui', 'lucide-vue-next'] },\n 'dropdown-menu': {\n name: 'dropdown-menu',\n dependencies: ['reka-ui', 'lucide-vue-next'],\n },\n input: { name: 'input', dependencies: [] },\n label: { name: 'label', dependencies: ['reka-ui'] },\n pagination: { name: 'pagination', dependencies: ['lucide-vue-next'] },\n popover: { name: 'popover', dependencies: ['reka-ui'] },\n 'scroll-area': { name: 'scroll-area', dependencies: ['reka-ui'] },\n select: { name: 'select', dependencies: ['reka-ui', 'lucide-vue-next'] },\n separator: { name: 'separator', dependencies: ['reka-ui'] },\n skeleton: { name: 'skeleton', dependencies: [] },\n spinner: { name: 'spinner', dependencies: [] },\n 'submit-button': { name: 'submit-button', dependencies: ['lucide-vue-next'] },\n switch: { name: 'switch', dependencies: ['reka-ui'] },\n table: { name: 'table', dependencies: [] },\n tabs: { name: 'tabs', dependencies: ['reka-ui'] },\n textarea: { name: 'textarea', dependencies: [] },\n toast: { name: 'toast', dependencies: ['lucide-vue-next'] },\n tooltip: { name: 'tooltip', dependencies: ['reka-ui'] },\n 'saas-pricing': { name: 'saas-pricing', dependencies: ['lucide-vue-next'] },\n 'dashboard-stats': { name: 'dashboard-stats', dependencies: ['lucide-vue-next'] },\n form: { name: 'form', dependencies: ['vee-validate', '@vee-validate/zod', 'zod', 'reka-ui'] },\n 'alert-dialog': { name: 'alert-dialog', dependencies: ['reka-ui'] },\n sheet: { name: 'sheet', dependencies: ['reka-ui', 'lucide-vue-next'] },\n 'radio-group': { name: 'radio-group', dependencies: ['reka-ui', 'lucide-vue-next'] },\n slider: { name: 'slider', dependencies: ['reka-ui'] },\n progress: { name: 'progress', dependencies: ['reka-ui'] },\n toggle: { name: 'toggle', dependencies: ['reka-ui'] },\n 'toggle-group': { name: 'toggle-group', dependencies: ['reka-ui'] },\n 'brutalist-hero': { name: 'brutalist-hero', dependencies: ['lucide-vue-next'] },\n 'pricing-section': { name: 'pricing-section', dependencies: ['lucide-vue-next'] },\n 'auth-card': { name: 'auth-card', dependencies: ['lucide-vue-next'] },\n 'dashboard-shell': { name: 'dashboard-shell', dependencies: ['lucide-vue-next'] },\n 'empty-state': { name: 'empty-state', dependencies: ['lucide-vue-next'] },\n 'waitlist-page': { name: 'waitlist-page', dependencies: ['lucide-vue-next'] },\n accordion: { name: 'accordion', dependencies: ['reka-ui', 'lucide-vue-next'] },\n 'tags-input': { name: 'tags-input', dependencies: ['reka-ui', 'lucide-vue-next'] },\n 'number-input': { name: 'number-input', dependencies: ['reka-ui', 'lucide-vue-next'] },\n 'copy-to-clipboard': { name: 'copy-to-clipboard', dependencies: ['lucide-vue-next'] },\n breadcrumb: { name: 'breadcrumb', dependencies: ['reka-ui', 'lucide-vue-next'] },\n marquee: { name: 'marquee', dependencies: [] },\n 'before-after': { name: 'before-after', dependencies: [] },\n 'code-block': { name: 'code-block', dependencies: ['lucide-vue-next'] },\n timeline: { name: 'timeline', dependencies: ['reka-ui', 'lucide-vue-next'] },\n carousel: { name: 'carousel', dependencies: ['embla-carousel-vue', 'lucide-vue-next'] },\n 'tree-view': { name: 'tree-view', dependencies: ['reka-ui', 'lucide-vue-next'] },\n kanban: { name: 'kanban', dependencies: ['lucide-vue-next'] },\n 'chat-bubble': { name: 'chat-bubble', dependencies: ['reka-ui', 'lucide-vue-next'] },\n kbd: { name: 'kbd', dependencies: [] },\n counter: { name: 'counter', dependencies: [] },\n stepper: { name: 'stepper', dependencies: ['lucide-vue-next'] },\n} as const;\n\nexport const AVAILABLE_COMPONENTS = Object.keys(COMPONENTS);\n","import type { ProjectType } from './types.js';\n\nexport { COMPONENTS, AVAILABLE_COMPONENTS } from 'brutx-shared-vue';\nexport type { ComponentMeta as ComponentInfo } from 'brutx-shared-vue';\n\nexport const CONFIG_FILES = {\n vite: ['vite.config.js', 'vite.config.ts', 'vite.config.mjs'],\n nuxt: ['nuxt.config.js', 'nuxt.config.ts', 'nuxt.config.mjs'],\n tailwind: [\n 'tailwind.config.ts',\n 'tailwind.config.js',\n 'tailwind.config.mjs',\n 'tailwind.config.cjs',\n ],\n tsconfig: ['tsconfig.json', 'jsconfig.json'],\n lockfiles: {\n pnpm: 'pnpm-lock.yaml',\n yarn: 'yarn.lock',\n bun: 'bun.lockb',\n },\n} as const;\n\nexport const CSS_LOCATIONS: Record<ProjectType, readonly string[]> = {\n 'vite-vue': ['src/index.css', 'src/App.css', 'src/assets/main.css', 'index.css'],\n 'vite-vue-src': ['src/index.css', 'src/App.css', 'src/assets/main.css', 'src/styles/index.css'],\n nuxt: ['assets/css/main.css', 'assets/css/tailwind.css', 'assets/css/global.css'],\n unknown: [\n 'src/index.css',\n 'src/assets/main.css',\n 'src/styles/index.css',\n 'assets/css/main.css',\n 'index.css',\n ],\n} as const;\n\nexport const BASE_DEPENDENCIES = [\n 'clsx',\n 'tailwind-merge',\n 'class-variance-authority',\n 'lucide-vue-next',\n 'reka-ui',\n] as const;\n\nexport const DEFAULT_ALIASES = {\n components: '@/components',\n utils: '@/lib/utils',\n} as const;\n\nexport const DEFAULT_TAILWIND_CONFIG = 'tailwind.config.js';\n\nexport const SCHEMA_URL = 'https://lidaixingchen.github.io/brutxui-vue3/schema.json';\n\nexport const DEFAULT_REGISTRY_URL = 'https://raw.githubusercontent.com/lidaixingchen/brutxui-vue3/main/packages/registry/registry';\n\nexport const BRUTALIST_CSS_STYLES = `\n:root {\n --brutal-border-width: 3px;\n --brutal-border-color: #000000;\n --brutal-shadow-color: #000000;\n --brutal-shadow-offset-sm: 2px;\n --brutal-shadow-offset: 4px;\n --brutal-shadow-offset-lg: 6px;\n --brutal-shadow-offset-xl: 8px;\n}\n\n.dark {\n --brutal-border-color: #ffffff;\n --brutal-shadow-color: #ffffff;\n}\n\n.border-3 {\n border-width: var(--brutal-border-width, 3px);\n}\n\n.border-brutal {\n border-color: var(--brutal-border-color, #000000);\n}\n\n.shadow-brutal {\n box-shadow: var(--brutal-shadow-offset, 4px) var(--brutal-shadow-offset, 4px) 0px 0px var(--brutal-shadow-color, #000000);\n}\n\n.shadow-brutal-sm {\n box-shadow: var(--brutal-shadow-offset-sm, 2px) var(--brutal-shadow-offset-sm, 2px) 0px 0px var(--brutal-shadow-color, #000000);\n}\n\n.shadow-brutal-lg {\n box-shadow: var(--brutal-shadow-offset-lg, 6px) var(--brutal-shadow-offset-lg, 6px) 0px 0px var(--brutal-shadow-color, #000000);\n}\n\n.shadow-brutal-xl {\n box-shadow: var(--brutal-shadow-offset-xl, 8px) var(--brutal-shadow-offset-xl, 8px) 0px 0px var(--brutal-shadow-color, #000000);\n}\n`;\n\nexport const UTILS_TEMPLATE = `import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n`;\n","import fs from 'fs-extra';\nimport path from 'path';\nimport type { ProjectType, TsConfig, AliasConfig, PackageManager, BrutalistConfig } from './types.js';\nimport { CONFIG_FILES, CSS_LOCATIONS, DEFAULT_ALIASES } from './constants.js';\n\nfunction hasAnyFile(cwd: string, files: readonly string[]): boolean {\n return files.some((file) => fs.existsSync(path.join(cwd, file)));\n}\n\nfunction findFirstExisting(cwd: string, files: readonly string[]): string | null {\n for (const file of files) {\n if (fs.existsSync(path.join(cwd, file))) {\n return file;\n }\n }\n return null;\n}\n\nfunction hasVueDependency(cwd: string): boolean {\n try {\n const packageJson = fs.readJsonSync(path.join(cwd, 'package.json'));\n return Boolean(\n packageJson.dependencies?.['vue'] ||\n packageJson.devDependencies?.['vue'] ||\n packageJson.dependencies?.['nuxt'] ||\n packageJson.devDependencies?.['nuxt']\n );\n } catch {\n return false;\n }\n}\n\nexport function detectProjectType(cwd: string): ProjectType {\n const hasNuxt = hasAnyFile(cwd, CONFIG_FILES.nuxt);\n const hasVite = hasAnyFile(cwd, CONFIG_FILES.vite);\n const hasSrc = fs.existsSync(path.join(cwd, 'src'));\n\n if (hasNuxt) return 'nuxt';\n\n if (hasVite && hasVueDependency(cwd)) {\n return hasSrc ? 'vite-vue-src' : 'vite-vue';\n }\n\n if (hasVueDependency(cwd)) {\n return hasSrc ? 'vite-vue-src' : 'vite-vue';\n }\n\n return 'unknown';\n}\n\nexport function detectPackageManager(cwd: string): PackageManager {\n const { lockfiles } = CONFIG_FILES;\n\n if (fs.existsSync(path.join(cwd, lockfiles.pnpm))) return 'pnpm';\n if (fs.existsSync(path.join(cwd, lockfiles.yarn))) return 'yarn';\n if (fs.existsSync(path.join(cwd, lockfiles.bun))) return 'bun';\n\n return 'npm';\n}\n\nexport function readTsConfig(cwd: string): TsConfig | null {\n for (const configFile of CONFIG_FILES.tsconfig) {\n const configPath = path.join(cwd, configFile);\n\n if (!fs.existsSync(configPath)) continue;\n\n try {\n const content = fs.readFileSync(configPath, 'utf-8');\n const jsonContent = content.replace(/\\/\\*[\\s\\S]*?\\*\\/|(?<!:)\\/\\/.*/g, '');\n return JSON.parse(jsonContent);\n } catch {\n continue;\n }\n }\n return null;\n}\n\nexport function findTailwindConfig(cwd: string): string | null {\n return findFirstExisting(cwd, CONFIG_FILES.tailwind);\n}\n\nexport function findCssFile(cwd: string, projectType: ProjectType): string | null {\n const locations = CSS_LOCATIONS[projectType];\n return findFirstExisting(cwd, locations);\n}\n\nexport function getAliasFromTsConfig(cwd: string): AliasConfig | null {\n const tsConfig = readTsConfig(cwd);\n const paths = tsConfig?.compilerOptions?.paths;\n\n if (!paths) return null;\n\n for (const alias of Object.keys(paths)) {\n if (alias.endsWith('/*')) {\n const prefix = alias.replace('/*', '');\n return {\n components: `${prefix}/components`,\n utils: `${prefix}/lib/utils`,\n };\n }\n }\n\n return null;\n}\n\nexport function resolveAliasPath(alias: string, cwd: string): string {\n const match = alias.match(/^(@[^/]*|~)\\/(.*)/);\n\n if (!match) {\n return path.join(cwd, alias);\n }\n\n const [, aliasPrefix, relativePath] = match;\n\n const resolvedFromConfig = resolveFromTsConfig(cwd, aliasPrefix, relativePath);\n if (resolvedFromConfig) return resolvedFromConfig;\n\n return resolveByProjectType(cwd, relativePath);\n}\n\nfunction resolveFromTsConfig(\n cwd: string,\n aliasPrefix: string,\n relativePath: string\n): string | null {\n const tsConfig = readTsConfig(cwd);\n const paths = tsConfig?.compilerOptions?.paths;\n\n if (!paths) return null;\n\n const aliasPattern = `${aliasPrefix}/*`;\n const baseUrl = tsConfig?.compilerOptions?.baseUrl || '.';\n\n if (paths[aliasPattern]) {\n const targetPath = paths[aliasPattern][0];\n const resolvedBase = targetPath.replace('/*', '');\n return path.join(cwd, baseUrl, resolvedBase, relativePath);\n }\n\n return null;\n}\n\nfunction resolveByProjectType(cwd: string, relativePath: string): string {\n const projectType = detectProjectType(cwd);\n\n const projectTypeToBase: Record<ProjectType, string> = {\n 'vite-vue-src': 'src',\n 'vite-vue': '',\n nuxt: '',\n unknown: fs.existsSync(path.join(cwd, 'src')) ? 'src' : '',\n };\n\n const base = projectTypeToBase[projectType];\n return path.join(cwd, base, relativePath);\n}\n\nfunction inferTailwindVersionFromConfig(cwd: string): 'v3' | 'v4' {\n const hasConfig = CONFIG_FILES.tailwind.some(file => fs.existsSync(path.join(cwd, file)));\n return hasConfig ? 'v3' : 'v4';\n}\n\nexport function getDefaultAliases(cwd: string): AliasConfig {\n return getAliasFromTsConfig(cwd) ?? { ...DEFAULT_ALIASES };\n}\n\nexport function resolveImportAlias(content: string, config: BrutalistConfig): string {\n return content\n .replace(/[\"']@\\/lib\\/utils[\"']/g, `\"${config.aliases.utils}\"`)\n .replace(/[\"']@\\/components\\/(.*?)[\"']/g, `\"${config.aliases.components}/$1\"`);\n}\n\nexport function isSafePath(targetPath: string, cwd: string): boolean {\n const resolvedTarget = path.resolve(targetPath).toLowerCase();\n const resolvedCwd = path.resolve(cwd).toLowerCase();\n return resolvedTarget.startsWith(resolvedCwd + path.sep) || resolvedTarget === resolvedCwd;\n}\n\nexport function detectTailwindVersion(cwd: string): 'v3' | 'v4' {\n try {\n const pkgJsonPath = path.join(cwd, 'package.json');\n if (fs.existsSync(pkgJsonPath)) {\n const pkg = fs.readJsonSync(pkgJsonPath);\n const tailwindVersion = pkg.dependencies?.['tailwindcss'] || pkg.devDependencies?.['tailwindcss'];\n\n if (tailwindVersion) {\n const cleanVersion = tailwindVersion.replace(/^[^0-9]+/, '');\n if (cleanVersion.startsWith('4')) {\n return 'v4';\n }\n if (cleanVersion.startsWith('3')) {\n return 'v3';\n }\n }\n }\n } catch {\n return inferTailwindVersionFromConfig(cwd);\n }\n\n return inferTailwindVersionFromConfig(cwd);\n}\n","import { execFileSync } from 'child_process';\r\nimport type { PackageManager } from './types.js';\r\n\r\nconst INSTALL_COMMANDS: Record<PackageManager, string> = {\r\n pnpm: 'pnpm add',\r\n yarn: 'yarn add',\r\n bun: 'bun add',\r\n npm: 'npm install',\r\n};\r\n\r\nexport function installPackages(\r\n packageManager: PackageManager,\r\n packages: string[],\r\n cwd: string\r\n): void {\r\n if (packages.length === 0) return;\r\n\r\n const [command, ...baseArgs] = INSTALL_COMMANDS[packageManager].split(' ');\r\n execFileSync(command, [...baseArgs, ...packages], { stdio: 'inherit', cwd });\r\n}\r\n\r\nexport function getInstallCommand(packageManager: PackageManager, packages: string[]): string {\r\n return `${INSTALL_COMMANDS[packageManager]} ${packages.join(' ')}`;\r\n}\r\n","import chalk from 'chalk';\r\n\r\nclass Logger {\r\n private silent: boolean = false;\r\n\r\n setSilent(silent: boolean): void {\r\n this.silent = silent;\r\n }\r\n\r\n log(message: string): void {\r\n if (!this.silent) {\r\n console.log(message);\r\n }\r\n }\r\n\r\n info(message: string): void {\r\n this.log(chalk.gray(message));\r\n }\r\n\r\n success(message: string): void {\r\n this.log(chalk.green(message));\r\n }\r\n\r\n warn(message: string): void {\r\n this.log(chalk.yellow(message));\r\n }\r\n\r\n error(message: string): void {\r\n this.log(chalk.red(message));\r\n }\r\n\r\n bold(message: string): void {\r\n this.log(chalk.bold(message));\r\n }\r\n\r\n highlight(message: string): void {\r\n this.log(chalk.cyan(message));\r\n }\r\n\r\n dim(message: string): void {\r\n this.log(chalk.dim(message));\r\n }\r\n\r\n newLine(): void {\r\n this.log('');\r\n }\r\n}\r\n\r\nexport const logger = new Logger();\r\n","import fs from 'fs-extra';\r\nimport path from 'path';\r\nimport type { RegistryItem, RegistryFile } from './types.js';\r\nimport { DEFAULT_REGISTRY_URL } from './constants.js';\r\n\r\nfunction isUrl(str: string): boolean {\r\n return str.startsWith('http://') || str.startsWith('https://');\r\n}\r\n\r\nfunction validateRegistryFile(file: unknown, itemName: string): file is RegistryFile {\r\n if (typeof file !== 'object' || file === null) {\r\n return false;\r\n }\r\n\r\n const f = file as Record<string, unknown>;\r\n\r\n if (typeof f.path !== 'string' || f.path.length === 0) {\r\n throw new Error(\r\n `Invalid registry file in \"${itemName}\": \"path\" must be a non-empty string.`\r\n );\r\n }\r\n\r\n if (typeof f.content !== 'string') {\r\n throw new Error(\r\n `Invalid registry file in \"${itemName}\": \"content\" must be a string.`\r\n );\r\n }\r\n\r\n return true;\r\n}\r\n\r\nfunction validateRegistryItem(data: unknown, name: string): asserts data is RegistryItem {\r\n if (typeof data !== 'object' || data === null) {\r\n throw new Error(`Invalid registry data for \"${name}\": expected an object.`);\r\n }\r\n\r\n const item = data as Record<string, unknown>;\r\n\r\n if (typeof item.name !== 'string' || item.name.length === 0) {\r\n throw new Error(`Invalid registry data for \"${name}\": \"name\" must be a non-empty string.`);\r\n }\r\n\r\n if (typeof item.type !== 'string') {\r\n throw new Error(`Invalid registry data for \"${name}\": \"type\" must be a string.`);\r\n }\r\n\r\n if (!Array.isArray(item.files)) {\r\n throw new Error(`Invalid registry data for \"${name}\": \"files\" must be an array.`);\r\n }\r\n\r\n for (const file of item.files) {\r\n validateRegistryFile(file, name);\r\n }\r\n\r\n if (item.dependencies !== undefined && !Array.isArray(item.dependencies)) {\r\n throw new Error(`Invalid registry data for \"${name}\": \"dependencies\" must be an array.`);\r\n }\r\n\r\n if (item.registryDependencies !== undefined && !Array.isArray(item.registryDependencies)) {\r\n throw new Error(\r\n `Invalid registry data for \"${name}\": \"registryDependencies\" must be an array.`\r\n );\r\n }\r\n}\r\n\r\nexport async function getItem(name: string, source: string = DEFAULT_REGISTRY_URL): Promise<RegistryItem> {\r\n let data: unknown;\r\n\r\n if (isUrl(source)) {\r\n const url = `${source}/${name}.json`;\r\n const res = await fetch(url, { signal: AbortSignal.timeout(30000) });\r\n if (!res.ok) {\r\n throw new Error(`Failed to fetch component \"${name}\" from registry: ${res.statusText}`);\r\n }\r\n data = await res.json();\r\n } else {\r\n const filePath = path.resolve(source, `${name}.json`);\r\n if (!filePath.startsWith(path.resolve(source) + path.sep)) {\r\n throw new Error(`Security Error: Path traversal detected in component name \"${name}\".`);\r\n }\r\n if (!(await fs.pathExists(filePath))) {\r\n throw new Error(`Component \"${name}\" not found in local registry: ${filePath}`);\r\n }\r\n data = await fs.readJson(filePath);\r\n }\r\n\r\n validateRegistryItem(data, name);\r\n return data;\r\n}\r\n\r\nexport async function resolveDeps(names: string[], source: string = DEFAULT_REGISTRY_URL): Promise<RegistryItem[]> {\r\n const resolved: RegistryItem[] = [];\r\n const visited = new Set<string>();\r\n const active = new Set<string>();\r\n\r\n async function dfs(fullName: string) {\r\n let cleanName = fullName;\r\n let itemSource = source;\r\n\r\n if (fullName.includes('@')) {\r\n const match = fullName.match(/^([a-z0-9-]+)@([a-zA-Z0-9._-]+)$/);\r\n if (match) {\r\n cleanName = match[1];\r\n const version = match[2];\r\n\r\n if (source === DEFAULT_REGISTRY_URL) {\r\n itemSource = `https://raw.githubusercontent.com/lidaixingchen/brutxui-vue3/${version}/packages/registry/registry`;\r\n }\r\n }\r\n }\r\n\r\n if (active.has(cleanName)) {\r\n throw new Error(`Circular dependency detected: ${cleanName}`);\r\n }\r\n if (visited.has(cleanName)) {\r\n return;\r\n }\r\n\r\n active.add(cleanName);\r\n\r\n try {\r\n const item = await getItem(cleanName, itemSource);\r\n\r\n if (item.registryDependencies && item.registryDependencies.length > 0) {\r\n for (const dep of item.registryDependencies) {\r\n await dfs(dep);\r\n }\r\n }\r\n\r\n active.delete(cleanName);\r\n visited.add(cleanName);\r\n resolved.push(item);\r\n } catch (err) {\r\n active.delete(cleanName);\r\n throw err;\r\n }\r\n }\r\n\r\n for (const name of names) {\r\n await dfs(name);\r\n }\r\n\r\n return resolved;\r\n}\r\n","import type { Ora } from 'ora';\nimport ora from 'ora';\nimport inquirer from 'inquirer';\nimport fs from 'fs-extra';\nimport path from 'path';\n\nimport {\n type AddOptions,\n type BrutalistConfig,\n type RegistryItem,\n AVAILABLE_COMPONENTS,\n UTILS_TEMPLATE,\n detectPackageManager,\n resolveAliasPath,\n resolveImportAlias,\n installPackages,\n getInstallCommand,\n getItem,\n resolveDeps,\n isSafePath,\n logger,\n} from '../lib/index.js';\n\nasync function ensureInitialized(cwd: string): Promise<BrutalistConfig> {\n const configPath = path.join(cwd, 'components.json');\n\n if (!(await fs.pathExists(configPath))) {\n logger.error('Error: Brutx-Vue is not initialized.');\n logger.warn('Run: npx brutx-vue@latest init');\n process.exit(1);\n }\n\n const config = await fs.readJson(configPath);\n if (!config?.aliases?.components || !config?.aliases?.utils) {\n logger.error('Error: Invalid components.json. Missing required \"aliases.components\" or \"aliases.utils\".');\n logger.warn('Run: npx brutx-vue@latest init --force to regenerate.');\n process.exit(1);\n }\n return config;\n}\n\nasync function validateComponents(components: string[]): Promise<void> {\n const cleanComponents = components.map(c => c.split('@')[0]);\n const invalid = cleanComponents.filter((c) => !AVAILABLE_COMPONENTS.includes(c));\n\n if (invalid.length > 0) {\n logger.newLine();\n logger.error(`Unknown components: ${invalid.join(', ')}`);\n logger.warn('Please choose from the available list or run npx brutx-vue add interactively without arguments.');\n logger.warn(`Available: ${AVAILABLE_COMPONENTS.join(', ')}`);\n process.exit(1);\n }\n}\n\nasync function selectComponents(inputComponents: string[], options: AddOptions): Promise<string[]> {\n if (options.all) {\n return [...AVAILABLE_COMPONENTS];\n }\n\n if (inputComponents.length > 0) {\n return inputComponents;\n }\n\n if (options.yes) {\n logger.error('Error: No components specified.');\n logger.warn('Use: npx brutx-vue@latest add [component] or --all');\n process.exit(1);\n }\n\n const { selected } = await inquirer.prompt([\n {\n type: 'checkbox',\n name: 'selected',\n message: 'Which components would you like to add?',\n choices: AVAILABLE_COMPONENTS.map((name) => ({ name, value: name })),\n pageSize: 15,\n },\n ]);\n\n return selected;\n}\n\nfunction resolveComponentFilePath(registryPath: string, config: BrutalistConfig, cwd: string): string {\n if (registryPath.startsWith('components/')) {\n const relative = registryPath.replace('components/', '');\n const aliasPath = resolveAliasPath(config.aliases.components, cwd);\n return path.join(aliasPath, relative);\n }\n\n if (registryPath.startsWith('lib/utils')) {\n return resolveAliasPath(config.aliases.utils, cwd) + '.ts';\n }\n\n if (registryPath.startsWith('lib/')) {\n const relative = registryPath.slice(4);\n const aliasPath = resolveAliasPath(config.aliases.utils, cwd);\n return path.join(path.dirname(aliasPath), relative);\n }\n\n return path.join(cwd, registryPath);\n}\n\nasync function ensureUtilsFile(utilsPath: string): Promise<boolean> {\n if (await fs.pathExists(utilsPath)) {\n return false;\n }\n\n await fs.ensureDir(path.dirname(utilsPath));\n await fs.writeFile(utilsPath, UTILS_TEMPLATE);\n return true;\n}\n\nasync function writeRegistryFiles(\n items: RegistryItem[],\n config: BrutalistConfig,\n cwd: string,\n options: AddOptions,\n spinner: Ora | null\n): Promise<{ added: string[]; skipped: string[]; filesWritten: string[] }> {\n const added: string[] = [];\n const skippedSet = new Set<string>();\n const filesWritten: string[] = [];\n\n for (const item of items) {\n let itemAdded = false;\n\n for (const file of item.files) {\n const normalizedPath = path.normalize(file.path);\n if (normalizedPath.startsWith('..') || path.isAbsolute(normalizedPath)) {\n throw new Error(`Security Error: Malicious component file path detected: \"${file.path}\".`);\n }\n\n const targetPath = resolveComponentFilePath(file.path, config, cwd);\n\n if (!isSafePath(targetPath, cwd)) {\n throw new Error(`Security Error: Path traversal detected. Access denied to path \"${targetPath}\".`);\n }\n\n if (await fs.pathExists(targetPath)) {\n if (!options.overwrite) {\n spinner?.info(`Skipping file \"${file.path}\" for \"${item.name}\" (already exists). Use --overwrite to overwrite.`);\n skippedSet.add(item.name);\n continue;\n }\n }\n\n if (options.dryRun) {\n spinner?.info(`[Dry Run] Would create file: ${targetPath}`);\n itemAdded = true;\n filesWritten.push(targetPath);\n continue;\n }\n\n await fs.ensureDir(path.dirname(targetPath));\n const resolvedContent = resolveImportAlias(file.content, config);\n await fs.writeFile(targetPath, resolvedContent, 'utf-8');\n itemAdded = true;\n filesWritten.push(targetPath);\n }\n\n if (itemAdded && !skippedSet.has(item.name)) {\n added.push(item.name);\n }\n }\n\n return { added, skipped: Array.from(skippedSet), filesWritten };\n}\n\nfunction installComponentDeps(deps: string[], cwd: string, dryRun: boolean): void {\n if (deps.length === 0) return;\n\n const packageManager = detectPackageManager(cwd);\n logger.newLine();\n\n if (dryRun) {\n logger.bold(`[Dry Run] Would install dependencies using ${packageManager}:`);\n logger.info(` ${deps.join(', ')}`);\n return;\n }\n\n logger.bold(`Installing dependencies with ${packageManager}...`);\n\n try {\n installPackages(packageManager, deps, cwd);\n logger.success('ā Dependencies installed');\n } catch {\n logger.warn('ā Failed to install dependencies automatically.');\n logger.info(` Run manually: ${getInstallCommand(packageManager, deps)}`);\n }\n}\n\nfunction toPascalCase(str: string): string {\n return str\n .split('-')\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join('');\n}\n\nfunction printUsageExample(component: string, componentsAlias: string): void {\n const componentName = toPascalCase(component);\n logger.info(` import ${componentName} from \"${componentsAlias}/ui/${component}/${componentName}.vue\"`);\n}\n\nexport async function add(components: string[], options: AddOptions): Promise<void> {\n const cwd = options.cwd ?? process.cwd();\n const targetCwd = options.path ? path.resolve(cwd, options.path) : cwd;\n\n if (options.path && !isSafePath(targetCwd, cwd)) {\n throw new Error(`Security Error: Path traversal detected. Access denied to path \"${targetCwd}\".`);\n }\n\n logger.setSilent(options.silent ?? false);\n\n const config = await ensureInitialized(cwd);\n\n await validateComponents(components);\n\n const selectedComponents = await selectComponents(components, options);\n\n if (selectedComponents.length === 0) {\n logger.warn('No components selected.');\n return;\n }\n\n const utilsPath = resolveAliasPath(config.aliases.utils, targetCwd) + '.ts';\n\n const spinner = options.silent ? null : ora('Resolving components and checking dependencies...').start();\n\n try {\n const registryItems = await resolveDeps(selectedComponents, options.registry);\n\n if (spinner) {\n spinner.stop();\n }\n\n logger.bold('\\nš¦ Brutx-Vue CLI - Installation Plan:');\n logger.info(` Registry source: ${options.registry || 'Default Brutx-Vue hosted registry'}`);\n logger.newLine();\n\n logger.bold('š§© Components to install/update:');\n for (const item of registryItems) {\n const depsStr = item.registryDependencies && item.registryDependencies.length > 0\n ? ` (depends on: ${item.registryDependencies.join(', ')})`\n : '';\n logger.info(` - ${item.name}${depsStr}`);\n }\n logger.newLine();\n\n const allDeps = new Set<string>();\n for (const item of registryItems) {\n if (item.dependencies) {\n item.dependencies.forEach((dep) => allDeps.add(dep));\n }\n }\n\n if (allDeps.size > 0) {\n logger.bold('š Required npm packages:');\n logger.info(` ${Array.from(allDeps).join(', ')}`);\n logger.newLine();\n }\n\n if (spinner) {\n spinner.start('Adding component files...');\n }\n\n if (!options.dryRun) {\n const utilsCreated = await ensureUtilsFile(utilsPath);\n if (utilsCreated) {\n spinner?.info(`Created utility file at ${utilsPath}`);\n }\n }\n\n const { added, skipped, filesWritten } = await writeRegistryFiles(\n registryItems,\n config,\n targetCwd,\n options,\n spinner\n );\n\n const summary = skipped.length > 0\n ? `Added ${added.length} component(s), skipped ${skipped.length}`\n : `Added ${added.length} component(s)`;\n\n if (options.dryRun) {\n spinner?.succeed(`[Dry Run] Simulated: ${summary}`);\n } else {\n spinner?.succeed(summary);\n }\n\n if (added.length > 0 && filesWritten.length > 0) {\n logger.newLine();\n logger.bold('š¾ Files written to disk:');\n for (const filePath of filesWritten) {\n const relativePath = path.relative(targetCwd, filePath);\n logger.success(` ā ${relativePath}`);\n }\n }\n\n installComponentDeps(Array.from(allDeps), cwd, options.dryRun ?? false);\n\n if (added.length > 0) {\n logger.newLine();\n logger.bold('Usage:');\n printUsageExample(added[0], config.aliases.components);\n }\n\n } catch (error: any) {\n spinner?.fail('Failed to add components');\n logger.error(error?.message || error);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["fs","path","pkg","fs","path","path","fs","path","fs","ora","inquirer","fs","path","path","fs","inquirer","ora","require"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "brutx-vue",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for adding Neo-Brutalist Vue 3 UI components to your project",
|
|
5
|
+
"bin": {
|
|
6
|
+
"brutx-vue": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"start": "node dist/index.js",
|
|
17
|
+
"test": "vitest run"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"brutx-shared-vue": "workspace:*",
|
|
21
|
+
"chalk": "^5.3.0",
|
|
22
|
+
"commander": "^12.0.0",
|
|
23
|
+
"fs-extra": "^11.2.0",
|
|
24
|
+
"inquirer": "^9.2.12",
|
|
25
|
+
"ora": "^8.0.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/fs-extra": "^11.0.4",
|
|
29
|
+
"@types/node": "^20.17.15",
|
|
30
|
+
"tsup": "^8.0.1",
|
|
31
|
+
"typescript": "^5.7.2",
|
|
32
|
+
"vitest": "^1.3.1"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"brutx-vue",
|
|
36
|
+
"cli",
|
|
37
|
+
"neo-brutalism",
|
|
38
|
+
"vue",
|
|
39
|
+
"vue3",
|
|
40
|
+
"components",
|
|
41
|
+
"tailwindcss"
|
|
42
|
+
],
|
|
43
|
+
"author": "lidaixingchen",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/lidaixingchen/brutxui-vue3"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://lidaixingchen.github.io/brutxui-vue3/"
|
|
50
|
+
}
|