gladvn 0.2.30 → 0.2.31
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/bin/cli.js +217 -192
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -6,14 +6,29 @@ import { execSync } from 'child_process';
|
|
|
6
6
|
import readline from 'readline';
|
|
7
7
|
|
|
8
8
|
const cyan = "\x1b[36m";
|
|
9
|
-
const green = "\x1b[32m";
|
|
10
9
|
const yellow = "\x1b[33m";
|
|
11
10
|
const bold = "\x1b[1m";
|
|
12
11
|
const dim = "\x1b[90m";
|
|
13
12
|
const reset = "\x1b[0m";
|
|
14
13
|
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
// Read version from package.json
|
|
18
|
+
const pkgPath = path.resolve(__dirname, "../package.json");
|
|
19
|
+
const pkgContent = fs.readFileSync(pkgPath, "utf-8");
|
|
20
|
+
const pkg = JSON.parse(pkgContent);
|
|
21
|
+
const VERSION = pkg.version;
|
|
22
|
+
|
|
23
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
24
|
+
console.log(`gladvn v${VERSION}`);
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
16
29
|
console.log(`
|
|
30
|
+
gladvn v${VERSION}
|
|
31
|
+
|
|
17
32
|
Usage:
|
|
18
33
|
npx gladvn init [destination]
|
|
19
34
|
npx gladvn add <component | --all> [destination]
|
|
@@ -22,6 +37,7 @@ Usage:
|
|
|
22
37
|
Options:
|
|
23
38
|
[destination] The folder where components will be copied. Defaults to "gladvn".
|
|
24
39
|
--help, -h Show this help message.
|
|
40
|
+
--version, -v Show the current version.
|
|
25
41
|
`);
|
|
26
42
|
process.exit(0);
|
|
27
43
|
}
|
|
@@ -54,13 +70,15 @@ if (args[0] === "init") {
|
|
|
54
70
|
userDest = args[0];
|
|
55
71
|
}
|
|
56
72
|
|
|
57
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
58
|
-
const __dirname = path.dirname(__filename);
|
|
59
|
-
|
|
60
73
|
const destPath = path.resolve(process.cwd(), userDest);
|
|
61
74
|
const srcDir = path.resolve(__dirname, "../src");
|
|
62
75
|
|
|
63
|
-
//
|
|
76
|
+
// Helper: check if a file is a test file
|
|
77
|
+
function isTestFile(filename) {
|
|
78
|
+
return /\.test\.(tsx?|jsx?)$/.test(filename);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Recursive file scanner for CSS files
|
|
64
82
|
const IGNORE_DIRS = ['node_modules', '.git', '.next', 'dist', 'build', 'out', 'coverage', '.cache', userDest];
|
|
65
83
|
|
|
66
84
|
function findCssFiles(dir, fileList = []) {
|
|
@@ -83,6 +101,23 @@ function findCssFiles(dir, fileList = []) {
|
|
|
83
101
|
return fileList;
|
|
84
102
|
}
|
|
85
103
|
|
|
104
|
+
// Recursive directory copy with optional filter
|
|
105
|
+
function copyDirFiltered(src, dest, filter) {
|
|
106
|
+
if (!fs.existsSync(src)) return;
|
|
107
|
+
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
108
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
const srcPath = path.join(src, entry.name);
|
|
111
|
+
const destPath = path.join(dest, entry.name);
|
|
112
|
+
if (entry.isDirectory()) {
|
|
113
|
+
copyDirFiltered(srcPath, destPath, filter);
|
|
114
|
+
} else {
|
|
115
|
+
if (filter && !filter(entry.name)) continue;
|
|
116
|
+
fs.cpSync(srcPath, destPath, { force: true });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
86
121
|
// Native arrow key selector
|
|
87
122
|
async function selectOption(message, options) {
|
|
88
123
|
return new Promise((resolve) => {
|
|
@@ -141,82 +176,33 @@ async function selectOption(message, options) {
|
|
|
141
176
|
});
|
|
142
177
|
}
|
|
143
178
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
options.forEach((opt, index) => {
|
|
156
|
-
const isChecked = selected.has(index);
|
|
157
|
-
const checkbox = isChecked ? '\x1b[32m◉\x1b[0m' : '\x1b[90m◯\x1b[0m';
|
|
158
|
-
if (index === selectedIndex) {
|
|
159
|
-
console.log(` \x1b[36m❯ ${checkbox} ${opt}\x1b[0m`);
|
|
160
|
-
} else {
|
|
161
|
-
console.log(` ${checkbox} ${opt}`);
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
readline.moveCursor(process.stdout, 0, -(options.length + 1));
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
render();
|
|
168
|
-
|
|
169
|
-
const onKeyPress = (str, key) => {
|
|
170
|
-
if (key.name === 'up') {
|
|
171
|
-
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : options.length - 1;
|
|
172
|
-
render();
|
|
173
|
-
} else if (key.name === 'down') {
|
|
174
|
-
selectedIndex = selectedIndex < options.length - 1 ? selectedIndex + 1 : 0;
|
|
175
|
-
render();
|
|
176
|
-
} else if (key.name === 'space') {
|
|
177
|
-
if (selected.has(selectedIndex)) {
|
|
178
|
-
selected.delete(selectedIndex);
|
|
179
|
-
} else {
|
|
180
|
-
selected.add(selectedIndex);
|
|
181
|
-
}
|
|
182
|
-
render();
|
|
183
|
-
} else if (key.name === 'return' || key.name === 'enter') {
|
|
184
|
-
cleanup();
|
|
185
|
-
const results = Array.from(selected).map(idx => options[idx]);
|
|
186
|
-
console.log(`\x1b[32m✔\x1b[0m \x1b[1m${message}\x1b[0m \x1b[90m…\x1b[0m \x1b[36m${results.length} selected\x1b[0m`);
|
|
187
|
-
resolve(results);
|
|
188
|
-
} else if (key.name === 'c' && key.ctrl) {
|
|
189
|
-
cleanup();
|
|
190
|
-
console.log('\n\x1b[31m✖ Cancelled.\x1b[0m');
|
|
191
|
-
process.exit(1);
|
|
179
|
+
// Helper: ensure lib/ and hooks/ exist in destPath (needed for add/add-block)
|
|
180
|
+
function ensureCoreDeps(srcDir, destPath) {
|
|
181
|
+
const coreDeps = ['lib', 'hooks'];
|
|
182
|
+
let copied = false;
|
|
183
|
+
for (const dir of coreDeps) {
|
|
184
|
+
const targetDir = path.join(destPath, dir);
|
|
185
|
+
if (!fs.existsSync(targetDir)) {
|
|
186
|
+
const sourceDir = path.join(srcDir, dir);
|
|
187
|
+
if (fs.existsSync(sourceDir)) {
|
|
188
|
+
copyDirFiltered(sourceDir, targetDir, (name) => !isTestFile(name));
|
|
189
|
+
copied = true;
|
|
192
190
|
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
process.stdin.pause();
|
|
199
|
-
readline.moveCursor(process.stdout, 0, options.length + 1);
|
|
200
|
-
process.stdout.write('\x1B[?25h');
|
|
201
|
-
readline.moveCursor(process.stdout, 0, -(options.length + 1));
|
|
202
|
-
readline.clearScreenDown(process.stdout);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
readline.emitKeypressEvents(process.stdin);
|
|
206
|
-
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
207
|
-
process.stdin.resume();
|
|
208
|
-
process.stdin.on('keypress', onKeyPress);
|
|
209
|
-
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (copied) {
|
|
194
|
+
console.log(`\x1b[32m✔ Copied required core dependencies (lib, hooks)\x1b[0m`);
|
|
195
|
+
}
|
|
210
196
|
}
|
|
211
197
|
|
|
212
198
|
async function main() {
|
|
213
199
|
console.log(`\n${cyan}╔══════════════════════════════════════════════════════════════════╗${reset}`);
|
|
214
200
|
if (command === "add") {
|
|
215
|
-
console.log(`${cyan}║ ${bold}gladvn${reset}${cyan} — Add Component
|
|
201
|
+
console.log(`${cyan}║ ${bold}gladvn${reset} ${dim}v${VERSION}${reset}${cyan} — Add Component ║${reset}`);
|
|
216
202
|
} else if (command === "add-block") {
|
|
217
|
-
console.log(`${cyan}║ ${bold}gladvn${reset}${cyan} — Add Block
|
|
203
|
+
console.log(`${cyan}║ ${bold}gladvn${reset} ${dim}v${VERSION}${reset}${cyan} — Add Block ║${reset}`);
|
|
218
204
|
} else {
|
|
219
|
-
console.log(`${cyan}║ ${bold}gladvn${reset}${cyan} — Initialization
|
|
205
|
+
console.log(`${cyan}║ ${bold}gladvn${reset} ${dim}v${VERSION}${reset}${cyan} — Initialization ║${reset}`);
|
|
220
206
|
}
|
|
221
207
|
console.log(`${cyan}╚══════════════════════════════════════════════════════════════════╝${reset}\n`);
|
|
222
208
|
|
|
@@ -233,7 +219,7 @@ async function main() {
|
|
|
233
219
|
if (fs.existsSync(subPath)) {
|
|
234
220
|
const files = fs.readdirSync(subPath);
|
|
235
221
|
for (const file of files) {
|
|
236
|
-
if (file.endsWith('.tsx') || file.endsWith('.ts')) {
|
|
222
|
+
if ((file.endsWith('.tsx') || file.endsWith('.ts')) && !isTestFile(file)) {
|
|
237
223
|
availableComponents.push(`${sub}/${file}`);
|
|
238
224
|
}
|
|
239
225
|
}
|
|
@@ -247,17 +233,21 @@ async function main() {
|
|
|
247
233
|
if (fs.existsSync(blocksDir)) {
|
|
248
234
|
const files = fs.readdirSync(blocksDir);
|
|
249
235
|
for (const file of files) {
|
|
250
|
-
if (file.endsWith('.tsx') || file.endsWith('.ts')) {
|
|
236
|
+
if ((file.endsWith('.tsx') || file.endsWith('.ts')) && !isTestFile(file)) {
|
|
251
237
|
availableBlocks.push(file);
|
|
252
238
|
}
|
|
253
239
|
}
|
|
254
240
|
}
|
|
255
241
|
|
|
256
242
|
if (command === "add") {
|
|
243
|
+
// ── ADD COMMAND ──────────────────────────────────────────────────────
|
|
257
244
|
if (!fs.existsSync(destPath)) {
|
|
258
245
|
fs.mkdirSync(destPath, { recursive: true });
|
|
259
246
|
}
|
|
260
247
|
|
|
248
|
+
// Ensure lib/ and hooks/ exist for component imports
|
|
249
|
+
ensureCoreDeps(srcDir, destPath);
|
|
250
|
+
|
|
261
251
|
if (componentToAdd === "--all") {
|
|
262
252
|
console.log(`\x1b[36mAdding all components to ${userDest}...\x1b[0m`);
|
|
263
253
|
let addedCount = 0;
|
|
@@ -301,7 +291,9 @@ async function main() {
|
|
|
301
291
|
hasErrors = true;
|
|
302
292
|
}
|
|
303
293
|
}
|
|
294
|
+
|
|
304
295
|
} else if (command === "add-block") {
|
|
296
|
+
// ── ADD-BLOCK COMMAND ────────────────────────────────────────────────
|
|
305
297
|
console.log(`\x1b[36mAdding block ${componentToAdd} to ${userDest}...\x1b[0m`);
|
|
306
298
|
const blockMatches = availableBlocks.filter(b => b === `${componentToAdd}.tsx` || b === `${componentToAdd}.ts`);
|
|
307
299
|
if (blockMatches.length === 0) {
|
|
@@ -312,6 +304,10 @@ async function main() {
|
|
|
312
304
|
if (!fs.existsSync(destPath)) {
|
|
313
305
|
fs.mkdirSync(destPath, { recursive: true });
|
|
314
306
|
}
|
|
307
|
+
|
|
308
|
+
// Ensure lib/ and hooks/ exist for block imports
|
|
309
|
+
ensureCoreDeps(srcDir, destPath);
|
|
310
|
+
|
|
315
311
|
const block = blockMatches[0];
|
|
316
312
|
const sourcePath = path.join(blocksDir, block);
|
|
317
313
|
const targetPath = path.join(destPath, 'blocks', block);
|
|
@@ -326,8 +322,9 @@ async function main() {
|
|
|
326
322
|
console.error(`\x1b[31m✖ Failed to add block ${block}: ${err.message}\x1b[0m`);
|
|
327
323
|
hasErrors = true;
|
|
328
324
|
}
|
|
325
|
+
|
|
329
326
|
} else {
|
|
330
|
-
//
|
|
327
|
+
// ── INIT COMMAND ─────────────────────────────────────────────────────
|
|
331
328
|
let targetCss = "app/globals.css";
|
|
332
329
|
const cssFilesFull = findCssFiles(process.cwd());
|
|
333
330
|
const cssFiles = cssFilesFull.map(f => path.relative(process.cwd(), f));
|
|
@@ -376,149 +373,177 @@ async function main() {
|
|
|
376
373
|
cssFilePath = path.resolve(process.cwd(), targetCss);
|
|
377
374
|
}
|
|
378
375
|
|
|
379
|
-
// 1. Copy files
|
|
376
|
+
// Step 1. Copy files
|
|
380
377
|
console.log(`\n\x1b[36mInitializing gladvn components into ${userDest}...\x1b[0m`);
|
|
381
378
|
|
|
382
379
|
if (!fs.existsSync(destPath)) {
|
|
383
380
|
fs.mkdirSync(destPath, { recursive: true });
|
|
384
381
|
}
|
|
385
382
|
|
|
386
|
-
//
|
|
383
|
+
// Copy core directories (excluding test files)
|
|
384
|
+
const coreDirs = ['hooks', 'lib', 'styles', 'components', 'blocks'];
|
|
385
|
+
for (const dir of coreDirs) {
|
|
386
|
+
const sourceDir = path.join(srcDir, dir);
|
|
387
|
+
const targetDir = path.join(destPath, dir);
|
|
388
|
+
if (fs.existsSync(sourceDir)) {
|
|
389
|
+
try {
|
|
390
|
+
copyDirFiltered(sourceDir, targetDir, (name) => !isTestFile(name));
|
|
391
|
+
} catch (err) {
|
|
392
|
+
console.error(`\x1b[31m✖ Failed to copy core ${dir}/: ${err.message}\x1b[0m`);
|
|
393
|
+
hasErrors = true;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
387
397
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
+
// Copy root-level files (index.ts, preset.ts)
|
|
399
|
+
const rootFiles = ['index.ts', 'preset.ts'];
|
|
400
|
+
for (const file of rootFiles) {
|
|
401
|
+
const sourceFile = path.join(srcDir, file);
|
|
402
|
+
const targetFile = path.join(destPath, file);
|
|
403
|
+
if (fs.existsSync(sourceFile)) {
|
|
404
|
+
try {
|
|
405
|
+
fs.cpSync(sourceFile, targetFile, { force: true });
|
|
406
|
+
} catch (err) {
|
|
407
|
+
console.error(`\x1b[31m✖ Failed to copy ${file}: ${err.message}\x1b[0m`);
|
|
408
|
+
hasErrors = true;
|
|
409
|
+
}
|
|
398
410
|
}
|
|
399
411
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
412
|
+
|
|
413
|
+
console.log(`\x1b[32m✔ Copied core files and all components (lib, hooks, styles, components, blocks)\x1b[0m`);
|
|
414
|
+
|
|
415
|
+
// Step 2. Inject CSS (tokens.css MUST come before gladvn.css)
|
|
416
|
+
if (cssFilePath && fs.existsSync(cssFilePath)) {
|
|
417
|
+
let cssContent = fs.readFileSync(cssFilePath, 'utf8');
|
|
418
|
+
const stylesDir = path.join(destPath, 'styles');
|
|
419
|
+
const relDir = path.relative(path.dirname(cssFilePath), stylesDir).replace(/\\/g, '/');
|
|
420
|
+
const prefix = relDir.startsWith('.') ? relDir : './' + relDir;
|
|
421
|
+
|
|
422
|
+
const tokensImport = `@import "${prefix}/tokens.css";`;
|
|
423
|
+
const gladvnImport = `@import "${prefix}/gladvn.css";`;
|
|
424
|
+
const combinedImport = `${tokensImport}\n${gladvnImport}`;
|
|
425
|
+
|
|
426
|
+
const needsTokens = !cssContent.includes('tokens.css');
|
|
427
|
+
const needsGladvn = !cssContent.includes('gladvn.css');
|
|
428
|
+
|
|
429
|
+
if (needsTokens || needsGladvn) {
|
|
430
|
+
const toInject = needsTokens && needsGladvn
|
|
431
|
+
? combinedImport
|
|
432
|
+
: needsTokens ? tokensImport : gladvnImport;
|
|
433
|
+
|
|
434
|
+
if (cssContent.includes('@import "tailwindcss";')) {
|
|
435
|
+
cssContent = cssContent.replace('@import "tailwindcss";', `@import "tailwindcss";\n${toInject}`);
|
|
436
|
+
} else if (cssContent.includes('@tailwind base;')) {
|
|
437
|
+
cssContent = cssContent.replace('@tailwind base;', `@tailwind base;\n${toInject}`);
|
|
438
|
+
} else {
|
|
439
|
+
cssContent = `${toInject}\n${cssContent}`;
|
|
440
|
+
}
|
|
441
|
+
fs.writeFileSync(cssFilePath, cssContent);
|
|
442
|
+
console.log(`\x1b[32m✔ Injected gladvn styles (tokens + theme) into ${path.basename(cssFilePath)}\x1b[0m`);
|
|
417
443
|
}
|
|
418
|
-
console.log(`\x1b[32m✔ Injected gladvn CSS into ${path.basename(cssFilePath)}\x1b[0m`);
|
|
419
444
|
}
|
|
420
|
-
}
|
|
421
445
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
446
|
+
// Step 3. Configure TypeScript Path Alias
|
|
447
|
+
const tsconfigFiles = ['tsconfig.app.json', 'tsconfig.json', 'jsconfig.json'];
|
|
448
|
+
let tsconfigPath = null;
|
|
449
|
+
for (const file of tsconfigFiles) {
|
|
450
|
+
const p = path.join(process.cwd(), file);
|
|
451
|
+
if (fs.existsSync(p)) {
|
|
452
|
+
tsconfigPath = p;
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
430
455
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
456
|
+
|
|
457
|
+
if (tsconfigPath) {
|
|
458
|
+
let content = fs.readFileSync(tsconfigPath, 'utf8');
|
|
459
|
+
if (!content.includes('@gladvn/*')) {
|
|
460
|
+
const pathsEmptyRegex = /"paths"\s*:\s*\{\s*\}/;
|
|
461
|
+
const compilerOptionsEmptyRegex = /"compilerOptions"\s*:\s*\{\s*\}/;
|
|
462
|
+
|
|
463
|
+
if (pathsEmptyRegex.test(content)) {
|
|
464
|
+
content = content.replace(pathsEmptyRegex, `"paths": {\n "@gladvn/*": ["./${userDest}/*"]\n }`);
|
|
465
|
+
} else if (content.match(/"paths"\s*:\s*\{/)) {
|
|
466
|
+
content = content.replace(/"paths"\s*:\s*\{/, `"paths": {\n "@gladvn/*": ["./${userDest}/*"],`);
|
|
467
|
+
} else if (compilerOptionsEmptyRegex.test(content)) {
|
|
468
|
+
content = content.replace(compilerOptionsEmptyRegex, `"compilerOptions": {\n "paths": {\n "@gladvn/*": ["./${userDest}/*"]\n }\n }`);
|
|
469
|
+
} else if (content.match(/"compilerOptions"\s*:\s*\{/)) {
|
|
470
|
+
content = content.replace(/"compilerOptions"\s*:\s*\{/, `"compilerOptions": {\n "paths": {\n "@gladvn/*": ["./${userDest}/*"]\n },`);
|
|
471
|
+
} else if (!content.includes('"compilerOptions"')) {
|
|
472
|
+
content = content.replace(/\{/, `{\n "compilerOptions": {\n "paths": {\n "@gladvn/*": ["./${userDest}/*"]\n }\n },`);
|
|
473
|
+
}
|
|
474
|
+
fs.writeFileSync(tsconfigPath, content);
|
|
475
|
+
console.log(`\x1b[32m✔ Configured path alias @gladvn/* in ${path.basename(tsconfigPath)}\x1b[0m`);
|
|
449
476
|
}
|
|
450
|
-
fs.writeFileSync(tsconfigPath, content);
|
|
451
|
-
console.log(`\x1b[32m✔ Configured path alias @gladvn/* in ${path.basename(tsconfigPath)}\x1b[0m`);
|
|
452
477
|
}
|
|
453
|
-
}
|
|
454
478
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
479
|
+
// Step 4. Configure Vite Alias
|
|
480
|
+
const viteConfigFiles = ['vite.config.ts', 'vite.config.js', 'vite.config.mts', 'vite.config.mjs'];
|
|
481
|
+
let viteConfigPath = null;
|
|
482
|
+
for (const file of viteConfigFiles) {
|
|
483
|
+
const p = path.join(process.cwd(), file);
|
|
484
|
+
if (fs.existsSync(p)) {
|
|
485
|
+
viteConfigPath = p;
|
|
486
|
+
break;
|
|
487
|
+
}
|
|
463
488
|
}
|
|
464
|
-
}
|
|
465
489
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (content.includes('import ')) {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
490
|
+
if (viteConfigPath) {
|
|
491
|
+
let content = fs.readFileSync(viteConfigPath, 'utf8');
|
|
492
|
+
if (!content.includes('@gladvn')) {
|
|
493
|
+
// Add `import path from "path"` if missing
|
|
494
|
+
if (!content.includes('import path from') && !content.includes('require("path")')) {
|
|
495
|
+
if (content.includes('import ')) {
|
|
496
|
+
const lastImportIndex = content.lastIndexOf('import ');
|
|
497
|
+
const endOfLine = content.indexOf('\n', lastImportIndex);
|
|
498
|
+
if (endOfLine !== -1) {
|
|
499
|
+
content = content.slice(0, endOfLine + 1) + 'import path from "path"\n' + content.slice(endOfLine + 1);
|
|
500
|
+
} else {
|
|
501
|
+
content = 'import path from "path"\n' + content;
|
|
502
|
+
}
|
|
475
503
|
} else {
|
|
476
504
|
content = 'import path from "path"\n' + content;
|
|
477
505
|
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const resolveAlias = `\n resolve: {\n alias: {\n "@gladvn": path.resolve(__dirname, "./${userDest}"),\n },\n },`;
|
|
509
|
+
|
|
510
|
+
if (content.includes('resolve: {')) {
|
|
511
|
+
if (content.includes('alias: {')) {
|
|
512
|
+
content = content.replace(/alias:\s*\{/, `alias: {\n "@gladvn": path.resolve(__dirname, "./${userDest}"),`);
|
|
513
|
+
} else {
|
|
514
|
+
content = content.replace(/resolve:\s*\{/, `resolve: {\n alias: {\n "@gladvn": path.resolve(__dirname, "./${userDest}"),\n },`);
|
|
515
|
+
}
|
|
478
516
|
} else {
|
|
479
|
-
|
|
517
|
+
content = content.replace(/defineConfig\s*\(\s*\{/, `defineConfig({${resolveAlias}`);
|
|
480
518
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (content.includes('resolve: {')) {
|
|
486
|
-
if (content.includes('alias: {')) {
|
|
487
|
-
content = content.replace(/alias:\s*\{/, `alias: {\n "@gladvn": path.resolve(__dirname, "./${userDest}"),`);
|
|
488
|
-
} else {
|
|
489
|
-
content = content.replace(/resolve:\s*\{/, `resolve: {\n alias: {\n "@gladvn": path.resolve(__dirname, "./${userDest}"),\n },`);
|
|
490
|
-
}
|
|
491
|
-
} else {
|
|
492
|
-
content = content.replace(/defineConfig\s*\(\s*\{/, `defineConfig({${resolveAlias}`);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
fs.writeFileSync(viteConfigPath, content);
|
|
496
|
-
console.log(`\x1b[32m✔ Configured resolve.alias in ${path.basename(viteConfigPath)}\x1b[0m`);
|
|
497
|
-
|
|
498
|
-
if (viteConfigPath.endsWith('.ts')) {
|
|
499
|
-
try {
|
|
500
|
-
const userPkgPath = path.resolve(process.cwd(), 'package.json');
|
|
501
|
-
if (fs.existsSync(userPkgPath)) {
|
|
502
|
-
const userPkg = JSON.parse(fs.readFileSync(userPkgPath, 'utf8'));
|
|
503
|
-
if (!userPkg.devDependencies) userPkg.devDependencies = {};
|
|
504
|
-
if (!userPkg.devDependencies['@types/node'] && (!userPkg.dependencies || !userPkg.dependencies['@types/node'])) {
|
|
505
|
-
userPkg.devDependencies['@types/node'] = '^20.0.0';
|
|
506
|
-
fs.writeFileSync(userPkgPath, JSON.stringify(userPkg, null, 2));
|
|
507
|
-
console.log(`\x1b[32m✔ Added @types/node to devDependencies\x1b[0m`);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
} catch (e) {}
|
|
519
|
+
|
|
520
|
+
fs.writeFileSync(viteConfigPath, content);
|
|
521
|
+
console.log(`\x1b[32m✔ Configured resolve.alias in ${path.basename(viteConfigPath)}\x1b[0m`);
|
|
511
522
|
}
|
|
512
523
|
}
|
|
513
|
-
}
|
|
514
524
|
|
|
515
525
|
} // END OF INIT COMMAND
|
|
516
526
|
|
|
517
|
-
//
|
|
527
|
+
// Step 5. Install dependencies
|
|
528
|
+
// Track extra deps needed (e.g. @types/node for Vite TS projects)
|
|
529
|
+
const extraDepsToInstall = [];
|
|
530
|
+
|
|
531
|
+
// Check if we need @types/node (Vite + TypeScript)
|
|
532
|
+
const viteConfigExists = ['vite.config.ts', 'vite.config.mts'].some(f => fs.existsSync(path.join(process.cwd(), f)));
|
|
533
|
+
if (viteConfigExists) {
|
|
534
|
+
try {
|
|
535
|
+
const userPkgPath = path.resolve(process.cwd(), 'package.json');
|
|
536
|
+
if (fs.existsSync(userPkgPath)) {
|
|
537
|
+
const userPkg = JSON.parse(fs.readFileSync(userPkgPath, 'utf8'));
|
|
538
|
+
const allUserDeps = { ...userPkg.dependencies, ...userPkg.devDependencies };
|
|
539
|
+
if (!allUserDeps['@types/node']) {
|
|
540
|
+
extraDepsToInstall.push('@types/node@"^20.0.0"');
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
} catch (e) {}
|
|
544
|
+
}
|
|
545
|
+
|
|
518
546
|
try {
|
|
519
|
-
const pkgPath = path.resolve(__dirname, "../package.json");
|
|
520
|
-
const pkgContent = fs.readFileSync(pkgPath, "utf-8");
|
|
521
|
-
const pkg = JSON.parse(pkgContent);
|
|
522
547
|
const depsObj = pkg.dependencies || {};
|
|
523
548
|
|
|
524
549
|
if (Object.keys(depsObj).length > 0) {
|
|
@@ -558,7 +583,7 @@ async function main() {
|
|
|
558
583
|
}
|
|
559
584
|
}
|
|
560
585
|
|
|
561
|
-
if (usedDeps.size > 0) {
|
|
586
|
+
if (usedDeps.size > 0 || extraDepsToInstall.length > 0) {
|
|
562
587
|
// Check user's package.json to see what is already installed
|
|
563
588
|
const userPkgPath = path.resolve(process.cwd(), 'package.json');
|
|
564
589
|
let userDeps = {};
|
|
@@ -569,7 +594,7 @@ async function main() {
|
|
|
569
594
|
} catch (e) {}
|
|
570
595
|
}
|
|
571
596
|
|
|
572
|
-
const depsToInstall = [];
|
|
597
|
+
const depsToInstall = [...extraDepsToInstall];
|
|
573
598
|
for (const dep of usedDeps) {
|
|
574
599
|
if (!userDeps[dep]) {
|
|
575
600
|
depsToInstall.push(`${dep}@"${depsObj[dep]}"`);
|
package/package.json
CHANGED