create-canaima-app 1.0.3 → 1.0.4
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/index.js +90 -95
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -6,14 +6,16 @@ import path from 'path';
|
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import { exec, spawn } from 'child_process';
|
|
8
8
|
import { promisify } from 'util';
|
|
9
|
+
import readline from 'readline';
|
|
9
10
|
|
|
10
11
|
const execPromise = promisify(exec);
|
|
11
12
|
|
|
12
13
|
// Resolver __dirname en módulos ES
|
|
13
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
15
|
const __dirname = path.dirname(__filename);
|
|
16
|
+
const { resolve } = path;
|
|
15
17
|
|
|
16
|
-
// Colores ANSI
|
|
18
|
+
// Colores ANSI
|
|
17
19
|
const c = {
|
|
18
20
|
reset : (t) => `\x1b[0m${t}\x1b[0m`,
|
|
19
21
|
bold : (t) => `\x1b[1m${t}\x1b[0m`,
|
|
@@ -26,7 +28,7 @@ const c = {
|
|
|
26
28
|
bgGreen: (t) => `\x1b[42m\x1b[30m${t}\x1b[0m`,
|
|
27
29
|
};
|
|
28
30
|
|
|
29
|
-
//
|
|
31
|
+
// Carpetas locales de plantillas
|
|
30
32
|
const TEMPLATES = {
|
|
31
33
|
'tauri-materialize': {
|
|
32
34
|
label : 'Materialize CSS (Clásico / Estable)',
|
|
@@ -47,52 +49,58 @@ class CoatiAnimator {
|
|
|
47
49
|
this.interval = null;
|
|
48
50
|
this.frame = 0;
|
|
49
51
|
this.msgIndex = 0;
|
|
50
|
-
|
|
51
|
-
process.stdout.write('\x1b[?25l');
|
|
52
|
+
this.linesDrawn = 0;
|
|
53
|
+
process.stdout.write('\x1b[?25l'); // Ocultar cursor
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
clear() {
|
|
57
|
+
if (this.linesDrawn > 0) {
|
|
58
|
+
readline.moveCursor(process.stdout, 0, -this.linesDrawn);
|
|
59
|
+
readline.clearScreenDown(process.stdout);
|
|
60
|
+
}
|
|
61
|
+
this.linesDrawn = 0;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
start() {
|
|
55
|
-
this.render();
|
|
65
|
+
this.render();
|
|
56
66
|
this.interval = setInterval(() => {
|
|
57
67
|
this.frame++;
|
|
58
|
-
|
|
59
|
-
|
|
68
|
+
// Cambiar de frase cada 15 frames
|
|
69
|
+
if (this.frame % 15 === 0) {
|
|
60
70
|
this.msgIndex = (this.msgIndex + 1) % this.messages.length;
|
|
61
71
|
}
|
|
62
72
|
this.render();
|
|
63
|
-
},
|
|
73
|
+
}, 250); // Velocidad de la animación
|
|
64
74
|
}
|
|
65
75
|
|
|
66
|
-
render() {
|
|
67
|
-
|
|
68
|
-
if (this.frame > 0) {
|
|
69
|
-
process.stdout.write('\x1b[3A\x1b[0J');
|
|
70
|
-
}
|
|
76
|
+
render(isFinal = false, finalMessage = null) {
|
|
77
|
+
this.clear();
|
|
71
78
|
|
|
72
|
-
const isBlinking = this.frame %
|
|
73
|
-
const face = isBlinking ? '( -_- )' : '( ._. )';
|
|
74
|
-
const msg = this.messages[this.msgIndex];
|
|
79
|
+
const isBlinking = !isFinal && this.frame % 12 === 0;
|
|
80
|
+
const face = isFinal ? '( ^_^ )' : (isBlinking ? '( -_- )' : '( ._. )');
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
const
|
|
82
|
+
const baseMsg = finalMessage || this.messages[this.msgIndex];
|
|
83
|
+
const dots = isFinal ? " " : ".".repeat(this.frame % 4).padEnd(3, " ");
|
|
84
|
+
const displayMsg = baseMsg + dots;
|
|
85
|
+
|
|
86
|
+
const line = '─'.repeat(displayMsg.length + 2);
|
|
87
|
+
|
|
88
|
+
const out = [
|
|
89
|
+
c.cyan(` ^---^ `) + c.dim(`╭${line}╮`),
|
|
90
|
+
c.cyan(` ${face} `) + c.dim(`│ `) + (isFinal ? c.bold(c.green(displayMsg)) : c.bold(c.white(displayMsg))) + c.dim(` │`),
|
|
91
|
+
` ` + c.dim(`╰${line}╯`)
|
|
92
|
+
];
|
|
78
93
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.log(` ` + c.dim(`╰${line}╯`));
|
|
94
|
+
process.stdout.write(out.join('\n') + '\n');
|
|
95
|
+
this.linesDrawn = 3;
|
|
82
96
|
}
|
|
83
97
|
|
|
84
98
|
stop(finalMessage = null) {
|
|
85
99
|
if (this.interval) clearInterval(this.interval);
|
|
86
|
-
// Mostrar cursor
|
|
87
|
-
process.stdout.write('\x1b[?25h');
|
|
100
|
+
process.stdout.write('\x1b[?25h'); // Mostrar cursor
|
|
88
101
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const line = '─'.repeat(finalMessage.length + 2);
|
|
92
|
-
console.log(c.cyan(` ^---^ `) + c.dim(`╭${line}╮`));
|
|
93
|
-
console.log(c.cyan(` ( ^_^ ) `) + c.dim(`│ `) + c.bold(c.white(finalMessage)) + c.dim(` │`));
|
|
94
|
-
console.log(` ` + c.dim(`╰${line}╯\n`));
|
|
95
|
-
}
|
|
102
|
+
this.render(true, finalMessage);
|
|
103
|
+
console.log();
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
|
|
@@ -104,30 +112,26 @@ async function checkAndInstallDependencies() {
|
|
|
104
112
|
let missingApt = false;
|
|
105
113
|
let missingRust = false;
|
|
106
114
|
|
|
107
|
-
// Verificar Rust
|
|
108
115
|
try {
|
|
109
116
|
await execPromise('command -v cargo');
|
|
110
117
|
} catch {
|
|
111
118
|
missingRust = true;
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
// Verificar librerías solo si es Debian/Canaima
|
|
115
121
|
if (isDebian) {
|
|
116
122
|
try {
|
|
117
|
-
// Usamos pkg-config o dpkg para ver si está la librería principal
|
|
118
123
|
await execPromise('dpkg -l libwebkit2gtk-4.1-dev');
|
|
119
124
|
} catch {
|
|
120
125
|
missingApt = true;
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
if (!missingApt && !missingRust) return;
|
|
129
|
+
if (!missingApt && !missingRust) return;
|
|
125
130
|
|
|
126
131
|
console.log(c.yellow('\n ⚠ Faltan dependencias necesarias para compilar Tauri.'));
|
|
127
132
|
|
|
128
133
|
if (missingApt) {
|
|
129
134
|
console.log(c.dim(' Se solicitará tu contraseña para instalar paquetes del sistema...'));
|
|
130
|
-
// Pedimos sudo por adelantado para que no rompa nuestra interfaz ASCII
|
|
131
135
|
try {
|
|
132
136
|
await execPromise('sudo -v', { stdio: 'inherit' });
|
|
133
137
|
} catch (err) {
|
|
@@ -137,11 +141,11 @@ async function checkAndInstallDependencies() {
|
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
const anim = new CoatiAnimator([
|
|
140
|
-
"Revisando el sistema
|
|
141
|
-
"Canaima GNU/Linux: puro talento local
|
|
142
|
-
"Instalando magia negra (y librerías)
|
|
143
|
-
"Estabilidad y rendimiento basados en Debian
|
|
144
|
-
"Descargando herramientas de Rust
|
|
144
|
+
"Revisando el sistema",
|
|
145
|
+
"Canaima GNU/Linux: puro talento local",
|
|
146
|
+
"Instalando magia negra (y librerías)",
|
|
147
|
+
"Estabilidad y rendimiento basados en Debian",
|
|
148
|
+
"Descargando herramientas de Rust",
|
|
145
149
|
"¡Ya casi termino!"
|
|
146
150
|
]);
|
|
147
151
|
|
|
@@ -155,7 +159,6 @@ async function checkAndInstallDependencies() {
|
|
|
155
159
|
|
|
156
160
|
if (missingRust) {
|
|
157
161
|
await execPromise(`curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y`);
|
|
158
|
-
// Aplicar el env al proceso actual de Node por si acaso
|
|
159
162
|
process.env.PATH = `${process.env.HOME}/.cargo/bin:${process.env.PATH}`;
|
|
160
163
|
}
|
|
161
164
|
|
|
@@ -201,64 +204,62 @@ async function askQuestions() {
|
|
|
201
204
|
});
|
|
202
205
|
}
|
|
203
206
|
|
|
204
|
-
// ... [copyTemplate y personalizeProject se mantienen iguales] ...
|
|
205
207
|
async function copyTemplate(folderName, targetDir) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
const npmignorePath = path.join(targetDir, '.npmignore');
|
|
216
|
-
if (true) {
|
|
217
|
-
try { await fs.rename(npmignorePath, path.join(targetDir, '.gitignore')); } catch (e) {}
|
|
208
|
+
const templateDir = path.join(__dirname, folderName);
|
|
209
|
+
await fs.cp(templateDir, targetDir, {
|
|
210
|
+
recursive: true,
|
|
211
|
+
filter: (source) => {
|
|
212
|
+
const basename = path.basename(source);
|
|
213
|
+
return !['node_modules', 'target', '.git', 'package-lock.json', 'dist'].includes(basename);
|
|
218
214
|
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const npmignorePath = path.join(targetDir, '.npmignore');
|
|
218
|
+
try {
|
|
219
|
+
await fs.rename(npmignorePath, path.join(targetDir, '.gitignore'));
|
|
220
|
+
} catch (e) {}
|
|
219
221
|
}
|
|
220
222
|
|
|
221
223
|
async function personalizeProject(targetDir, projectName) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
224
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
225
|
+
try {
|
|
226
|
+
const pkgRaw = await fs.readFile(pkgPath, 'utf-8');
|
|
227
|
+
const pkgJson = JSON.parse(pkgRaw);
|
|
228
|
+
pkgJson.name = projectName;
|
|
229
|
+
await fs.writeFile(pkgPath, JSON.stringify(pkgJson, null, 2) + '\n');
|
|
230
|
+
} catch (err) {}
|
|
231
|
+
|
|
232
|
+
const cargoPath = path.join(targetDir, 'src-tauri', 'Cargo.toml');
|
|
233
|
+
try {
|
|
234
|
+
let cargo = await fs.readFile(cargoPath, 'utf-8');
|
|
235
|
+
cargo = cargo.replace(/^(name\s*=\s*)"[^"]*"/m, `$1"${projectName}"`);
|
|
236
|
+
await fs.writeFile(cargoPath, cargo);
|
|
237
|
+
} catch (err) {}
|
|
238
|
+
|
|
239
|
+
const tauriConfPath = path.join(targetDir, 'src-tauri', 'tauri.conf.json');
|
|
240
|
+
try {
|
|
241
|
+
const confRaw = await fs.readFile(tauriConfPath, 'utf-8');
|
|
242
|
+
const confJson = JSON.parse(confRaw);
|
|
243
|
+
|
|
244
|
+
if (confJson.productName !== undefined) confJson.productName = projectName;
|
|
245
|
+
if (confJson.identifier !== undefined) confJson.identifier = `com.canaima.${projectName}`;
|
|
246
|
+
if (confJson.bundle?.identifier) confJson.bundle.identifier = `com.canaima.${projectName}`;
|
|
247
|
+
|
|
248
|
+
await fs.writeFile(tauriConfPath, JSON.stringify(confJson, null, 2) + '\n');
|
|
249
|
+
} catch (err) {}
|
|
248
250
|
}
|
|
249
251
|
|
|
250
252
|
async function runNpmInstall(targetDir) {
|
|
251
253
|
const anim = new CoatiAnimator([
|
|
252
|
-
"Configurando los nodos
|
|
253
|
-
"Trayendo paquetes del ciberespacio
|
|
254
|
+
"Configurando los nodos",
|
|
255
|
+
"Trayendo paquetes del ciberespacio",
|
|
254
256
|
"¡Preparando el entorno Vue!",
|
|
255
|
-
"Haciendo que todo encaje perfecto
|
|
257
|
+
"Haciendo que todo encaje perfecto"
|
|
256
258
|
]);
|
|
257
259
|
|
|
258
260
|
anim.start();
|
|
259
261
|
|
|
260
262
|
return new Promise((resolve) => {
|
|
261
|
-
// Usamos spawn en background para que no ensucie la TUI
|
|
262
263
|
const child = spawn('npm', ['install'], {
|
|
263
264
|
cwd: targetDir,
|
|
264
265
|
shell: true,
|
|
@@ -278,13 +279,12 @@ async function runNpmInstall(targetDir) {
|
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
async function main() {
|
|
281
|
-
console.log(
|
|
282
|
+
console.log(c.bold(c.white('\n 🚀 Generador de proyectos CanaimaApp (Tauri + Vue + Rust)\n')));
|
|
282
283
|
|
|
283
|
-
// 1. Revisar e instalar dependencias del sistema primero
|
|
284
284
|
await checkAndInstallDependencies();
|
|
285
285
|
|
|
286
|
-
|
|
287
|
-
const { projectName, templateType, installNpm } =
|
|
286
|
+
const answers = await askQuestions();
|
|
287
|
+
const { projectName, templateType, installNpm } = answers;
|
|
288
288
|
if (!projectName || !templateType) process.exit(1);
|
|
289
289
|
|
|
290
290
|
const targetDir = resolve(process.cwd(), projectName);
|
|
@@ -300,15 +300,13 @@ async function main() {
|
|
|
300
300
|
console.log(c.cyan(`\n 📦 Generando archivos del proyecto...`));
|
|
301
301
|
await copyTemplate(template.folder, targetDir);
|
|
302
302
|
await personalizeProject(targetDir, projectName);
|
|
303
|
-
console.log(c.green(' ✔ Archivos base copiados y configurados
|
|
303
|
+
console.log(c.green(' ✔ Archivos base copiados y configurados.\n'));
|
|
304
304
|
|
|
305
|
-
// 3. Instalación de NPM si el usuario aceptó
|
|
306
305
|
if (installNpm) {
|
|
307
|
-
console.log();
|
|
308
306
|
await runNpmInstall(targetDir);
|
|
309
307
|
}
|
|
310
308
|
|
|
311
|
-
console.log(
|
|
309
|
+
console.log(c.bgGreen(c.white(' ✅ ¡Proyecto creado con éxito! ')));
|
|
312
310
|
console.log(c.bold('\n Siguientes pasos:\n'));
|
|
313
311
|
console.log(c.white(` ${c.cyan('$')} cd ${projectName}`));
|
|
314
312
|
if (!installNpm) console.log(c.white(` ${c.cyan('$')} npm install`));
|
|
@@ -321,7 +319,4 @@ async function main() {
|
|
|
321
319
|
}
|
|
322
320
|
}
|
|
323
321
|
|
|
324
|
-
// Helper para path.resolve
|
|
325
|
-
const { resolve } = path;
|
|
326
|
-
|
|
327
322
|
main();
|