@dbcube/cli 5.2.4 → 5.2.6
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/package.json +3 -3
- package/src/commands/dev.js +6 -8
- package/src/commands/doctor.js +8 -9
- package/src/commands/generate.js +2 -4
- package/src/commands/help.js +6 -9
- package/src/commands/init.js +9 -9
- package/src/commands/migrate/rollback.js +2 -4
- package/src/commands/migrate/status.js +2 -4
- package/src/commands/run/database/create/addDatabaseConfig.js +1 -2
- package/src/commands/run/database/create/createDatabase.js +2 -2
- package/src/commands/run/database/create/index.js +17 -25
- package/src/commands/run/download.js +2 -4
- package/src/commands/run/pull.js +7 -5
- package/src/commands/run/seeder/add.js +21 -33
- package/src/commands/run/table/alter.js +14 -25
- package/src/commands/run/table/fresh.js +3 -13
- package/src/commands/run/table/refresh.js +17 -30
- package/src/commands/run/trigger/fresh.js +18 -32
- package/src/commands/update.js +2 -4
- package/src/commands/validate.js +2 -4
- package/src/commands/version.js +4 -7
- package/src/utils/ConfigFileUtils.js +121 -56
- package/src/utils/EnvLoader.js +94 -0
- package/src/utils/ui.js +89 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dbcube/cli",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.6",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dbcube": "node src/index.js"
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@dbcube/schema-builder": "^5.2.
|
|
31
|
+
"@dbcube/schema-builder": "^5.2.6",
|
|
32
32
|
"@inquirer/prompts": "^8.5.2",
|
|
33
33
|
"alwait": "^1.0.0",
|
|
34
34
|
"chalk": "4.1.2",
|
|
35
|
-
"dbcube": "^5.2.
|
|
35
|
+
"dbcube": "^5.2.6",
|
|
36
36
|
"dotenv": "^17.4.2",
|
|
37
37
|
"fs-extra": "^11.3.5",
|
|
38
38
|
"glob": "^13.0.6",
|
package/src/commands/dev.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
+
const ui = require('../utils/ui');
|
|
4
5
|
const { execSync } = require('child_process');
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -66,18 +67,15 @@ function onChange(filename) {
|
|
|
66
67
|
async function main() {
|
|
67
68
|
const cubesDir = path.join(process.cwd(), 'dbcube');
|
|
68
69
|
if (!fs.existsSync(cubesDir)) {
|
|
69
|
-
|
|
70
|
+
ui.error('dbcube/ directory not found.', ['Run: npx dbcube init']);
|
|
70
71
|
process.exit(1);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.log(`${chalk.green('
|
|
74
|
+
ui.header('DBCube dev mode', '🛰️');
|
|
75
|
+
ui.dim('Save a .cube file and the change applies automatically.');
|
|
76
|
+
console.log(`${chalk.green('›')} watching dbcube/ ... ${chalk.gray('(Ctrl+C to stop)')}\n`);
|
|
76
77
|
|
|
77
78
|
fs.watch(cubesDir, { recursive: true }, (_event, filename) => onChange(filename));
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
main().catch(
|
|
81
|
-
console.error('Error fatal:', error);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
});
|
|
81
|
+
main().catch(ui.handleError);
|
package/src/commands/doctor.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const ConfigFileUtils = require('../utils/ConfigFileUtils');
|
|
5
|
+
const ui = require('../utils/ui');
|
|
5
6
|
const { Engine } = require('@dbcube/schema-builder');
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -13,7 +14,7 @@ const warn = (msg) => console.log(` ${chalk.yellow('⚠')} ${msg}`);
|
|
|
13
14
|
const fail = (msg) => console.log(` ${chalk.red('✗')} ${msg}`);
|
|
14
15
|
|
|
15
16
|
async function main() {
|
|
16
|
-
|
|
17
|
+
ui.header('DBCube Doctor', '🩺');
|
|
17
18
|
let problems = 0;
|
|
18
19
|
|
|
19
20
|
// 1. Node version
|
|
@@ -21,13 +22,14 @@ async function main() {
|
|
|
21
22
|
if (major >= 16) ok(`Node.js ${process.versions.node}`);
|
|
22
23
|
else { fail(`Node.js ${process.versions.node} — DBCube requires >= 16`); problems++; }
|
|
23
24
|
|
|
24
|
-
// 2. Config file
|
|
25
|
-
const configPath =
|
|
25
|
+
// 2. Config file (.js o .cjs — getConfigPath prefiere .cjs en proyectos ESM)
|
|
26
|
+
const configPath = ConfigFileUtils.getConfigPath();
|
|
27
|
+
const configName = path.basename(configPath);
|
|
26
28
|
if (!fs.existsSync(configPath)) {
|
|
27
|
-
fail(
|
|
29
|
+
fail(`${configName} not found — run: npx dbcube init`);
|
|
28
30
|
problems++;
|
|
29
31
|
} else {
|
|
30
|
-
ok(
|
|
32
|
+
ok(`${configName} found`);
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
// 3. Configured databases
|
|
@@ -93,7 +95,4 @@ async function main() {
|
|
|
93
95
|
process.exit(0);
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
main().catch(
|
|
97
|
-
console.error('Error fatal:', error);
|
|
98
|
-
process.exit(1);
|
|
99
|
-
});
|
|
98
|
+
main().catch(ui.handleError);
|
package/src/commands/generate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
+
const ui = require('../utils/ui');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* dbcube generate — Generates TypeScript interfaces from .table.cube files.
|
|
@@ -154,7 +155,4 @@ async function main() {
|
|
|
154
155
|
console.log(` const rows = await db.table('${schemaEntries[0] ? schemaEntries[0].tableName : 'users'}').get() as ${schemaEntries[0] ? schemaEntries[0].ifaceName : 'User'}[];\n`);
|
|
155
156
|
}
|
|
156
157
|
|
|
157
|
-
main().catch(
|
|
158
|
-
console.error('Error fatal:', error);
|
|
159
|
-
process.exit(1);
|
|
160
|
-
});
|
|
158
|
+
main().catch(ui.handleError);
|
package/src/commands/help.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const ui = require('../utils/ui');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Shows help information with all available Dbcube CLI commands
|
|
5
6
|
*/
|
|
6
7
|
async function showHelp() {
|
|
7
8
|
try {
|
|
8
|
-
|
|
9
|
-
console.log(
|
|
10
|
-
|
|
9
|
+
ui.banner();
|
|
10
|
+
console.log('');
|
|
11
|
+
|
|
11
12
|
console.log(`${chalk.cyan.bold('USAGE:')}`);
|
|
12
13
|
console.log(` ${chalk.white('npx dbcube')} ${chalk.yellow('<command>')} ${chalk.gray('[options]')}\n`);
|
|
13
14
|
|
|
@@ -97,13 +98,9 @@ async function showHelp() {
|
|
|
97
98
|
console.log(` ${chalk.white('Issues:')} ${chalk.blue('https://github.com/Dbcube/query-builder/issues')}\n`);
|
|
98
99
|
|
|
99
100
|
} catch (error) {
|
|
100
|
-
|
|
101
|
-
process.exit(1);
|
|
101
|
+
ui.handleError(error);
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// Ejecutar función
|
|
106
|
-
showHelp().catch(
|
|
107
|
-
console.error('Error fatal:', error);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
});
|
|
106
|
+
showHelp().catch(ui.handleError);
|
package/src/commands/init.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const ConfigFileUtils = require('../utils/ConfigFileUtils');
|
|
5
|
+
const ui = require('../utils/ui');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* dbcube init — Scaffolds a new DBCube project:
|
|
@@ -9,15 +10,17 @@ const ConfigFileUtils = require('../utils/ConfigFileUtils');
|
|
|
9
10
|
*/
|
|
10
11
|
async function main() {
|
|
11
12
|
const root = process.cwd();
|
|
12
|
-
|
|
13
|
+
ui.header('Initializing DBCube project', '📦');
|
|
14
|
+
console.log('');
|
|
13
15
|
|
|
14
|
-
// 1. dbcube.config.js
|
|
15
|
-
const configPath =
|
|
16
|
+
// 1. dbcube.config.(js|cjs) — getConfigPath elige .cjs en proyectos ESM
|
|
17
|
+
const configPath = ConfigFileUtils.getConfigPath();
|
|
18
|
+
const configName = path.basename(configPath);
|
|
16
19
|
if (fs.existsSync(configPath)) {
|
|
17
|
-
console.log(` ${chalk.yellow('•')}
|
|
20
|
+
console.log(` ${chalk.yellow('•')} ${configName} already exists — skipped`);
|
|
18
21
|
} else {
|
|
19
22
|
ConfigFileUtils.crearArchivoConfig(configPath);
|
|
20
|
-
console.log(` ${chalk.green('✓')}
|
|
23
|
+
console.log(` ${chalk.green('✓')} ${configName} created`);
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
// 2. dbcube/ directory
|
|
@@ -76,7 +79,4 @@ async function main() {
|
|
|
76
79
|
console.log(` 4. ${chalk.white('npx dbcube generate')} ${chalk.gray('— generate TypeScript types')}\n`);
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
main().catch(
|
|
80
|
-
console.error('Error fatal:', error);
|
|
81
|
-
process.exit(1);
|
|
82
|
-
});
|
|
82
|
+
main().catch(ui.handleError);
|
|
@@ -3,6 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const { Schema } = require('@dbcube/schema-builder');
|
|
5
5
|
const ConfigFileUtils = require('../../utils/ConfigFileUtils');
|
|
6
|
+
const ui = require('../../utils/ui');
|
|
6
7
|
const { loadHistory, saveHistory } = require('./lib');
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -66,7 +67,4 @@ async function main() {
|
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
main().catch(
|
|
70
|
-
console.error(`${chalk.red('❌ Rollback failed:')}`, error.message);
|
|
71
|
-
process.exit(1);
|
|
72
|
-
});
|
|
70
|
+
main().catch(ui.handleError);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const chalk = require('chalk');
|
|
3
|
+
const ui = require('../../utils/ui');
|
|
3
4
|
const { loadHistory, hashFile, collectAlterFiles } = require('./lib');
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -49,7 +50,4 @@ async function main() {
|
|
|
49
50
|
console.log('');
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
main().catch(
|
|
53
|
-
console.error('Error fatal:', error);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
});
|
|
53
|
+
main().catch(ui.handleError);
|
|
@@ -21,8 +21,7 @@ async function addDatabaseConfiguration(databaseName = null, motor = null) {
|
|
|
21
21
|
databaseName = await input({
|
|
22
22
|
message: 'Nombre de referencia a la base de datos:',
|
|
23
23
|
validate: (value) => {
|
|
24
|
-
const
|
|
25
|
-
const configPath = path.join(rootPath, 'dbcube.config.js');
|
|
24
|
+
const configPath = ConfigFileUtils.getConfigPath();
|
|
26
25
|
const getconfig = require(configPath);
|
|
27
26
|
const config = new Config();
|
|
28
27
|
getconfig(config);
|
|
@@ -63,13 +63,13 @@ async function main() {
|
|
|
63
63
|
|
|
64
64
|
await createDatabasePhysically(parsedArgs.name);
|
|
65
65
|
} catch (error) {
|
|
66
|
-
console.error('
|
|
66
|
+
console.error(`\n${chalk.red('✖')} ${error.message || error}`);
|
|
67
67
|
process.exit(1);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// Ejecutar el comando
|
|
72
72
|
main().catch(error => {
|
|
73
|
-
console.error('
|
|
73
|
+
console.error(`\n${chalk.red('✖')} ${error.message || error}`);
|
|
74
74
|
process.exit(1);
|
|
75
75
|
});
|
|
@@ -10,22 +10,15 @@ const path = require('path');
|
|
|
10
10
|
* Función para crear una nueva base de datos con configuración (Proceso completo en dos fases)
|
|
11
11
|
*/
|
|
12
12
|
async function createNewDatabase() {
|
|
13
|
-
console.clear();
|
|
14
13
|
try {
|
|
15
|
-
|
|
16
|
-
console.log('📋 Fase 1: Configuración');
|
|
17
|
-
console.log('🏗️ Fase 2: Creación física\n');
|
|
18
|
-
|
|
19
|
-
// Fase 1: Ejecutar addDatabaseConfig.js
|
|
20
|
-
console.log('🔧 Iniciando configuración de base de datos...');
|
|
21
|
-
|
|
14
|
+
// Fase 1: configuración interactiva (addDatabaseConfig.js trae su propia UI)
|
|
22
15
|
try {
|
|
23
16
|
execFileSync(process.execPath, [path.join(__dirname, 'addDatabaseConfig.js')], {
|
|
24
17
|
stdio: 'inherit',
|
|
25
18
|
cwd: process.cwd()
|
|
26
19
|
});
|
|
27
20
|
} catch (error) {
|
|
28
|
-
console.error('
|
|
21
|
+
console.error(`\n${chalk.red('✖')} No se pudo completar la configuración.`);
|
|
29
22
|
process.exit(1);
|
|
30
23
|
}
|
|
31
24
|
|
|
@@ -37,32 +30,24 @@ async function createNewDatabase() {
|
|
|
37
30
|
try {
|
|
38
31
|
databaseName = fs.readFileSync(tempFile, 'utf8');
|
|
39
32
|
} catch (error) {
|
|
40
|
-
console.error('
|
|
33
|
+
console.error(`\n${chalk.red('✖')} No se pudo obtener el nombre de la base de datos configurada.`);
|
|
41
34
|
process.exit(1);
|
|
42
35
|
} finally {
|
|
43
|
-
// Limpiar el archivo temporal pase lo que pase
|
|
44
36
|
try { fs.unlinkSync(tempFile); } catch { /* ya no existe */ }
|
|
45
37
|
}
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// Fase 2: Ejecutar createDatabase.js. execFileSync con array de
|
|
50
|
-
// argumentos: el nombre no pasa por el shell (sin inyección de comandos)
|
|
39
|
+
// Fase 2: creación física (createDatabase.js trae su propia UI de resumen)
|
|
51
40
|
try {
|
|
52
41
|
execFileSync(process.execPath, [path.join(__dirname, 'createDatabase.js'), `--name=${databaseName}`], {
|
|
53
42
|
stdio: 'inherit',
|
|
54
43
|
cwd: process.cwd()
|
|
55
44
|
});
|
|
56
45
|
} catch (error) {
|
|
57
|
-
|
|
46
|
+
// createDatabase.js ya imprimió el detalle del error
|
|
58
47
|
process.exit(1);
|
|
59
48
|
}
|
|
60
|
-
|
|
61
|
-
console.log(`\n🎉 ${chalk.green("¡Base de datos creada exitosamente!")}`);
|
|
62
|
-
console.log(`✅ Configuración y creación de '${databaseName}' completadas\n`);
|
|
63
|
-
|
|
64
49
|
} catch (error) {
|
|
65
|
-
console.error('
|
|
50
|
+
console.error(`\n${chalk.red('✖')} ${error.message}`);
|
|
66
51
|
process.exit(1);
|
|
67
52
|
}
|
|
68
53
|
}
|
|
@@ -81,12 +66,12 @@ async function useExistingDatabase(databaseName) {
|
|
|
81
66
|
cwd: process.cwd()
|
|
82
67
|
});
|
|
83
68
|
} catch (error) {
|
|
84
|
-
|
|
69
|
+
// createDatabase.js ya imprimió el detalle del error
|
|
85
70
|
process.exit(1);
|
|
86
71
|
}
|
|
87
72
|
|
|
88
73
|
} catch (error) {
|
|
89
|
-
console.
|
|
74
|
+
console.error(`\n${chalk.red('✖')} ${error.message}`);
|
|
90
75
|
process.exit(1);
|
|
91
76
|
}
|
|
92
77
|
}
|
|
@@ -134,12 +119,19 @@ async function main() {
|
|
|
134
119
|
await useExistingDatabase(selected);
|
|
135
120
|
}
|
|
136
121
|
} catch (error) {
|
|
137
|
-
|
|
122
|
+
// Ctrl+C / cierre del prompt interactivo: salir en silencio, sin stack.
|
|
123
|
+
if (error && (error.name === 'ExitPromptError' || /force closed/i.test(error.message || ''))) {
|
|
124
|
+
console.log(`\n${chalk.gray('Cancelado.')}`);
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
// Errores de config ya vienen con mensaje claro y accionable.
|
|
128
|
+
console.error(`\n${chalk.red('✖')} ${error.message}`);
|
|
129
|
+
process.exit(1);
|
|
138
130
|
}
|
|
139
131
|
}
|
|
140
132
|
|
|
141
133
|
// Ejecutar el ejemplo
|
|
142
134
|
main().catch(error => {
|
|
143
|
-
console.error('
|
|
135
|
+
console.error(`\n${chalk.red('✖')} ${error.message}`);
|
|
144
136
|
process.exit(1);
|
|
145
137
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const chalk = require('chalk');
|
|
3
|
+
const ui = require('../../utils/ui');
|
|
3
4
|
const { select } = require('@inquirer/prompts');
|
|
4
5
|
const path = require('path');
|
|
5
6
|
const fs = require('fs');
|
|
@@ -292,7 +293,4 @@ async function main() {
|
|
|
292
293
|
}
|
|
293
294
|
}
|
|
294
295
|
|
|
295
|
-
main().catch(
|
|
296
|
-
console.error(chalk.red('\n❌ Error inesperado:'), err.message);
|
|
297
|
-
process.exit(1);
|
|
298
|
-
});
|
|
296
|
+
main().catch(ui.handleError);
|
package/src/commands/run/pull.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const ConfigFileUtils = require('../../utils/ConfigFileUtils');
|
|
5
|
+
const ui = require('../../utils/ui');
|
|
5
6
|
const { Engine } = require('@dbcube/schema-builder');
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -211,7 +212,11 @@ async function main() {
|
|
|
211
212
|
const dbs = targetDb ? configured.filter(d => d.name === targetDb) : configured;
|
|
212
213
|
|
|
213
214
|
if (dbs.length === 0) {
|
|
214
|
-
|
|
215
|
+
ui.error(
|
|
216
|
+
targetDb ? `Database '${targetDb}' is not configured in dbcube.config.js`
|
|
217
|
+
: 'No databases configured in dbcube.config.js',
|
|
218
|
+
['Run: npx dbcube run database:create']
|
|
219
|
+
);
|
|
215
220
|
process.exit(1);
|
|
216
221
|
}
|
|
217
222
|
|
|
@@ -247,7 +252,4 @@ async function main() {
|
|
|
247
252
|
process.exit(0);
|
|
248
253
|
}
|
|
249
254
|
|
|
250
|
-
main().catch(
|
|
251
|
-
console.error(`${chalk.red('❌ Pull failed:')}`, error.message);
|
|
252
|
-
process.exit(1);
|
|
253
|
-
});
|
|
255
|
+
main().catch(ui.handleError);
|
|
@@ -1,33 +1,21 @@
|
|
|
1
|
-
const { Schema } = require('@dbcube/schema-builder');
|
|
2
|
-
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} else if (error.message.includes("reading 'getDatabase'")) {
|
|
23
|
-
console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
|
|
24
|
-
} else {
|
|
25
|
-
console.error(`❌ ${error.message}`);
|
|
26
|
-
if (process.env.DEBUG) console.error(error);
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Ejecutar el ejemplo
|
|
33
|
-
main().catch(console.error);
|
|
1
|
+
const { Schema } = require('@dbcube/schema-builder');
|
|
2
|
+
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
|
+
const ui = require('./../../../utils/ui');
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const seederName = args.find(a => !a.startsWith('--'));
|
|
9
|
+
|
|
10
|
+
const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
|
|
11
|
+
|
|
12
|
+
for (const config of configuredDatabases) {
|
|
13
|
+
const schema = new Schema(config.name);
|
|
14
|
+
await schema.executeSeeders(seederName);
|
|
15
|
+
}
|
|
16
|
+
} catch (error) {
|
|
17
|
+
ui.handleError(error);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
main().catch(ui.handleError);
|
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { Schema } = require('@dbcube/schema-builder');
|
|
4
4
|
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
5
|
+
const ui = require('./../../../utils/ui');
|
|
5
6
|
const { loadHistory, saveHistory, hashFile, collectAlterFiles, buildReverse } = require('../../migrate/lib');
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -73,33 +74,21 @@ async function main() {
|
|
|
73
74
|
console.log(' Status: npx dbcube migrate:status · Rollback: npx dbcube migrate:rollback\n');
|
|
74
75
|
}
|
|
75
76
|
} catch (error) {
|
|
76
|
-
if (error.message.includes("
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.error(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
console.error(' @table("nombre_tabla");');
|
|
88
|
-
console.error('');
|
|
89
|
-
console.error(' @addColumn({');
|
|
90
|
-
console.error(' nueva_columna: {');
|
|
91
|
-
console.error(' type: "varchar";');
|
|
92
|
-
console.error(' length: "255";');
|
|
93
|
-
console.error(' options: ["not null"];');
|
|
94
|
-
console.error(' };');
|
|
95
|
-
console.error(' });');
|
|
96
|
-
console.error('');
|
|
97
|
-
process.exit(1);
|
|
98
|
-
} else {
|
|
99
|
-
console.error('Error:', error.message);
|
|
77
|
+
if (error.message && error.message.includes("There are no .alter.cube files")) {
|
|
78
|
+
ui.error('No .alter.cube files found in dbcube/.', [
|
|
79
|
+
'Create one, e.g. dbcube/add_email.alter.cube:',
|
|
80
|
+
]);
|
|
81
|
+
console.error(ui.chalk.gray([
|
|
82
|
+
' @database("my_db");',
|
|
83
|
+
' @table("users");',
|
|
84
|
+
' @addColumn({',
|
|
85
|
+
' email: { type: "varchar"; length: "255"; options: ["not null"]; };',
|
|
86
|
+
' });',
|
|
87
|
+
].join('\n')) + '\n');
|
|
100
88
|
process.exit(1);
|
|
101
89
|
}
|
|
90
|
+
ui.handleError(error);
|
|
102
91
|
}
|
|
103
92
|
}
|
|
104
93
|
|
|
105
|
-
main().catch(
|
|
94
|
+
main().catch(ui.handleError);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const { Schema } = require('@dbcube/schema-builder');
|
|
3
3
|
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
4
|
+
const ui = require('./../../../utils/ui');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* dbcube run table:fresh [--seeder] [--force]
|
|
@@ -63,19 +64,8 @@ async function main() {
|
|
|
63
64
|
console.log(`\n${chalk.yellow('Aborted.')} ${chalk.gray('No changes were made.')}\n`);
|
|
64
65
|
process.exit(0);
|
|
65
66
|
}
|
|
66
|
-
|
|
67
|
-
console.error('❌ Configuracion de base de datos no encontrada\n');
|
|
68
|
-
console.error('Ejecute el comando para crear una nueva base de datos:');
|
|
69
|
-
console.error(`\tdbcube run database:create`);
|
|
70
|
-
console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
|
|
71
|
-
process.exit(1);
|
|
72
|
-
} else if (error.message.includes("reading 'getDatabase'")) {
|
|
73
|
-
console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
|
|
74
|
-
} else {
|
|
75
|
-
console.error('Error:', error.message);
|
|
76
|
-
process.exit(1);
|
|
77
|
-
}
|
|
67
|
+
ui.handleError(error);
|
|
78
68
|
}
|
|
79
69
|
}
|
|
80
70
|
|
|
81
|
-
main().catch(
|
|
71
|
+
main().catch(ui.handleError);
|
|
@@ -1,30 +1,17 @@
|
|
|
1
|
-
const { Schema } = require('@dbcube/schema-builder');
|
|
2
|
-
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
for (const config of configuredDatabases) {
|
|
9
|
-
const schema = new Schema(config.name);
|
|
10
|
-
await schema.refreshTables();
|
|
11
|
-
}
|
|
12
|
-
} catch (error) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
process.exit(1);
|
|
19
|
-
} else if (error.message.includes("reading 'getDatabase'")) {
|
|
20
|
-
console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
|
|
21
|
-
} else {
|
|
22
|
-
console.error(`❌ ${error.message}`);
|
|
23
|
-
if (process.env.DEBUG) console.error(error);
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Ejecutar el ejemplo
|
|
30
|
-
main().catch(console.error);
|
|
1
|
+
const { Schema } = require('@dbcube/schema-builder');
|
|
2
|
+
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
|
+
const ui = require('./../../../utils/ui');
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
|
|
8
|
+
for (const config of configuredDatabases) {
|
|
9
|
+
const schema = new Schema(config.name);
|
|
10
|
+
await schema.refreshTables();
|
|
11
|
+
}
|
|
12
|
+
} catch (error) {
|
|
13
|
+
ui.handleError(error);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
main().catch(ui.handleError);
|
|
@@ -1,32 +1,18 @@
|
|
|
1
|
-
const { Schema } = require('@dbcube/schema-builder');
|
|
2
|
-
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
for (const config of configuredDatabases) {
|
|
10
|
-
const schema = new Schema(config.name);
|
|
11
|
-
await schema.executeTriggers();
|
|
12
|
-
}
|
|
13
|
-
} catch (error) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
process.exit(1);
|
|
20
|
-
} else if (error.message.includes("reading 'getDatabase'")) {
|
|
21
|
-
console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
|
|
22
|
-
} else {
|
|
23
|
-
console.error(`❌ ${error.message}`);
|
|
24
|
-
if (process.env.DEBUG) console.error(error);
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
console.log('\n');
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Ejecutar el ejemplo
|
|
32
|
-
main().catch(console.error);
|
|
1
|
+
const { Schema } = require('@dbcube/schema-builder');
|
|
2
|
+
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
|
+
const ui = require('./../../../utils/ui');
|
|
4
|
+
|
|
5
|
+
async function main() {
|
|
6
|
+
try {
|
|
7
|
+
const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
|
|
8
|
+
|
|
9
|
+
for (const config of configuredDatabases) {
|
|
10
|
+
const schema = new Schema(config.name);
|
|
11
|
+
await schema.executeTriggers();
|
|
12
|
+
}
|
|
13
|
+
} catch (error) {
|
|
14
|
+
ui.handleError(error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main().catch(ui.handleError);
|
package/src/commands/update.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const chalk = require('chalk');
|
|
3
|
+
const ui = require('../utils/ui');
|
|
3
4
|
const ora = require('ora');
|
|
4
5
|
const path = require('path');
|
|
5
6
|
const fs = require('fs');
|
|
@@ -409,7 +410,4 @@ async function main() {
|
|
|
409
410
|
}
|
|
410
411
|
}
|
|
411
412
|
|
|
412
|
-
main().catch(
|
|
413
|
-
console.error(chalk.red('\n❌ Unexpected error:'), err.message);
|
|
414
|
-
process.exit(1);
|
|
415
|
-
});
|
|
413
|
+
main().catch(ui.handleError);
|
package/src/commands/validate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
+
const ui = require('../utils/ui');
|
|
4
5
|
const { CubeValidator } = require('@dbcube/schema-builder');
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -64,7 +65,4 @@ async function main() {
|
|
|
64
65
|
console.log(`${chalk.green('✓')} All cube files are valid\n`);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
main().catch(
|
|
68
|
-
console.error('Error fatal:', error);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
});
|
|
68
|
+
main().catch(ui.handleError);
|
package/src/commands/version.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
+
const ui = require('../utils/ui');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* dbcube version — CLI, packages, engine binaries, and environment info.
|
|
@@ -32,7 +33,7 @@ async function showVersion() {
|
|
|
32
33
|
console.log(` ${chalk.gray(label.padEnd(16))} ${dim ? chalk.gray(value) : chalk.white(value)}`);
|
|
33
34
|
|
|
34
35
|
console.log('');
|
|
35
|
-
console.log(` ${
|
|
36
|
+
console.log(` ${ui.brand('◆ DBCube CLI')} ${chalk.bold('v' + cliVersion)}`);
|
|
36
37
|
console.log(` ${chalk.gray('─'.repeat(40))}`);
|
|
37
38
|
|
|
38
39
|
// Local package versions (when resolvable from the project)
|
|
@@ -55,12 +56,8 @@ async function showVersion() {
|
|
|
55
56
|
row('platform', `${process.platform}-${process.arch}`, true);
|
|
56
57
|
console.log('');
|
|
57
58
|
} catch (error) {
|
|
58
|
-
|
|
59
|
-
process.exit(1);
|
|
59
|
+
ui.handleError(error);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
showVersion().catch(
|
|
64
|
-
console.error('Error fatal:', error);
|
|
65
|
-
process.exit(1);
|
|
66
|
-
});
|
|
63
|
+
showVersion().catch(ui.handleError);
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const EnvLoader = require('./EnvLoader');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detecta si el proyecto está marcado como ESM ("type": "module" en
|
|
7
|
+
* package.json), lo que hace que dbcube.config.js (CommonJS) no se pueda
|
|
8
|
+
* cargar con require(). Devuelve true si es ESM.
|
|
9
|
+
*/
|
|
10
|
+
function projectIsESM() {
|
|
11
|
+
try {
|
|
12
|
+
const pkgPath = path.resolve(process.cwd(), 'package.json');
|
|
13
|
+
if (!fs.existsSync(pkgPath)) return false;
|
|
14
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
15
|
+
return pkg.type === 'module';
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
3
20
|
|
|
4
21
|
/**
|
|
5
22
|
* Clase para manejar operaciones sobre el archivo de configuración
|
|
@@ -10,10 +27,15 @@ class ConfigFileUtils {
|
|
|
10
27
|
* @returns {string} - Ruta al archivo de configuración
|
|
11
28
|
*/
|
|
12
29
|
static getConfigPath() {
|
|
13
|
-
// Usar la ruta raíz del proyecto
|
|
14
30
|
const rootPath = path.resolve(process.cwd());
|
|
15
|
-
const
|
|
16
|
-
|
|
31
|
+
const cjsPath = path.join(rootPath, 'dbcube.config.cjs');
|
|
32
|
+
const jsPath = path.join(rootPath, 'dbcube.config.js');
|
|
33
|
+
// Si ya existe alguno, ese manda (preferimos .cjs).
|
|
34
|
+
if (fs.existsSync(cjsPath)) return cjsPath;
|
|
35
|
+
if (fs.existsSync(jsPath)) return jsPath;
|
|
36
|
+
// Si no existe ninguno (se va a crear): en proyectos ESM
|
|
37
|
+
// ("type": "module") debe ser .cjs para poder cargarse con require().
|
|
38
|
+
return projectIsESM() ? cjsPath : jsPath;
|
|
17
39
|
}
|
|
18
40
|
|
|
19
41
|
/**
|
|
@@ -21,19 +43,16 @@ class ConfigFileUtils {
|
|
|
21
43
|
* @returns {Promise<Array<string>>} - Array con los nombres de las bases de datos
|
|
22
44
|
*/
|
|
23
45
|
static async getConfiguredDatabases() {
|
|
24
|
-
try
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return this.loadDatabasesFromPath(configPath);
|
|
34
|
-
} catch (error) {
|
|
35
|
-
throw new Error('Error al obtener las bases de datos configuradas:', error);
|
|
46
|
+
// Sin try/catch que oculte el error: loadDatabasesFromPath ya lanza
|
|
47
|
+
// mensajes explícitos y accionables. (Antes, `new Error('msg', error)`
|
|
48
|
+
// descartaba el segundo argumento y se perdía la causa real.)
|
|
49
|
+
const configPath = this.getConfigPath();
|
|
50
|
+
|
|
51
|
+
if (!fs.existsSync(configPath)) {
|
|
52
|
+
ConfigFileUtils.crearArchivoConfig(configPath);
|
|
36
53
|
}
|
|
54
|
+
|
|
55
|
+
return this.loadDatabasesFromPath(configPath);
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
/**
|
|
@@ -42,46 +61,91 @@ class ConfigFileUtils {
|
|
|
42
61
|
* @returns {Array<string>} - Nombres de las bases de datos
|
|
43
62
|
*/
|
|
44
63
|
static loadDatabasesFromPath(configPath) {
|
|
64
|
+
// Carga automática de .env (cargador propio de DBCube): el usuario no
|
|
65
|
+
// necesita instalar dotenv ni escribir require("dotenv") en su config.
|
|
66
|
+
EnvLoader.load();
|
|
67
|
+
|
|
68
|
+
let config;
|
|
45
69
|
try {
|
|
46
70
|
// Borrar la caché del módulo para asegurarnos de cargar la versión más reciente
|
|
47
71
|
delete require.cache[require.resolve(configPath)];
|
|
48
|
-
|
|
49
72
|
// Cargar el archivo de configuración
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
config = require(configPath);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
const missing = (error.message.match(/Cannot find module '([^']+)'/) || [])[1];
|
|
76
|
+
// ¿El módulo que no se encuentra es el PROPIO config? Entonces el
|
|
77
|
+
// problema es de carga (típicamente ESM). Si es OTRO módulo, es una
|
|
78
|
+
// dependencia del config que falta (p. ej. dotenv).
|
|
79
|
+
const missingIsConfig = missing && (configPath.includes(missing) || missing.includes('dbcube.config'));
|
|
80
|
+
|
|
81
|
+
// Caso 1: falta una dependencia que el config requiere.
|
|
82
|
+
if (error.code === 'MODULE_NOT_FOUND' && missing && !missingIsConfig) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`dbcube.config.js requiere un módulo que no está instalado: "${missing}".\n` +
|
|
85
|
+
` Instálalo (p. ej. npm install ${missing}).\n` +
|
|
86
|
+
` Nota: DBCube ya carga el .env automáticamente — puedes quitar require("dotenv") de tu config.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
// Caso 2: proyecto ESM ("type": "module") → require() del config falla
|
|
90
|
+
// o el .js se interpreta como módulo ES y `module.exports` no aplica.
|
|
91
|
+
if (projectIsESM() || error.code === 'ERR_REQUIRE_ESM') {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`No se pudo cargar dbcube.config.js porque el proyecto está marcado como ESM ` +
|
|
94
|
+
`("type": "module" en package.json), pero la configuración usa CommonJS (module.exports).\n` +
|
|
95
|
+
` Solución: renombra el archivo a "dbcube.config.cjs", o quita "type": "module" de package.json.`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
// Cualquier otro error de carga: mostrarlo tal cual.
|
|
99
|
+
throw new Error(`No se pudo cargar la configuración desde ${configPath}:\n ${error.message}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Validar que la config exporte una función (firma esperada).
|
|
103
|
+
if (typeof config !== 'function') {
|
|
104
|
+
const hint = projectIsESM()
|
|
105
|
+
? ` El proyecto es ESM ("type": "module"): renombra el archivo a "dbcube.config.cjs" o quita "type": "module".`
|
|
106
|
+
: ` Debe exportar una función: module.exports = function (config) { config.set({ databases: {...} }); }.`;
|
|
107
|
+
throw new Error(`dbcube.config.js no exporta una configuración válida.${hint}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Crear una instancia temporal de Config para obtener los datos
|
|
111
|
+
const tempConfig = {
|
|
112
|
+
databases: {},
|
|
113
|
+
data: {},
|
|
114
|
+
set: function(configData) {
|
|
115
|
+
this.data = configData;
|
|
116
|
+
if (configData.databases) {
|
|
117
|
+
this.databases = configData.databases;
|
|
64
118
|
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
config(tempConfig);
|
|
69
|
-
|
|
70
|
-
// Obtener los nombres de las bases de datos
|
|
71
|
-
const databaseNames = Object.keys(tempConfig.getAllDatabases());
|
|
72
|
-
const arrayDatabases = [];
|
|
73
|
-
for (const database of databaseNames) {
|
|
74
|
-
arrayDatabases.push({
|
|
75
|
-
name: database,
|
|
76
|
-
type: tempConfig.getAllDatabases()[database].type
|
|
77
|
-
});
|
|
119
|
+
},
|
|
120
|
+
getAllDatabases: function() {
|
|
121
|
+
return this.databases;
|
|
78
122
|
}
|
|
79
|
-
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Ejecutar la función de configuración
|
|
126
|
+
try {
|
|
127
|
+
config(tempConfig);
|
|
80
128
|
} catch (error) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
129
|
+
throw new Error(`dbcube.config.js lanzó un error al evaluarse:\n ${error.message}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const allDatabases = tempConfig.getAllDatabases();
|
|
133
|
+
if (!allDatabases || Object.keys(allDatabases).length === 0) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`dbcube.config.js no define ninguna base de datos.\n` +
|
|
136
|
+
` Añade al menos una en config.set({ databases: { miBase: { type, config } } }).`
|
|
137
|
+
);
|
|
84
138
|
}
|
|
139
|
+
|
|
140
|
+
const databaseNames = Object.keys(allDatabases);
|
|
141
|
+
const arrayDatabases = [];
|
|
142
|
+
for (const database of databaseNames) {
|
|
143
|
+
arrayDatabases.push({
|
|
144
|
+
name: database,
|
|
145
|
+
type: allDatabases[database].type
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return arrayDatabases;
|
|
85
149
|
}
|
|
86
150
|
|
|
87
151
|
/**
|
|
@@ -271,15 +335,16 @@ class ConfigFileUtils {
|
|
|
271
335
|
* @param {string} rutaDestino - Ruta completa donde se debe crear el archivo.
|
|
272
336
|
*/
|
|
273
337
|
static crearArchivoConfig(rutaDestino) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
|
|
338
|
+
// DBCube carga el .env automáticamente, así que el template ya NO
|
|
339
|
+
// necesita require('dotenv') (que además requeriría instalar el paquete).
|
|
340
|
+
const contenido = `// DBCube carga .env automáticamente — usa process.env.MI_VAR sin dotenv.
|
|
341
|
+
module.exports = function (config) {
|
|
342
|
+
config.set({
|
|
343
|
+
databases: {
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
`;
|
|
283
348
|
|
|
284
349
|
// Asegurarse de que el directorio existe
|
|
285
350
|
const dir = path.dirname(rutaDestino);
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Cargador de variables de entorno propio de DBCube.
|
|
6
|
+
*
|
|
7
|
+
* Evita que el usuario tenga que instalar `dotenv` y escribir
|
|
8
|
+
* `require("dotenv").config()` al inicio de su dbcube.config.js. DBCube carga
|
|
9
|
+
* el `.env` del proyecto automáticamente ANTES de evaluar la configuración.
|
|
10
|
+
*
|
|
11
|
+
* Estrategia:
|
|
12
|
+
* 1. `process.loadEnvFile()` — nativo de Node 20.6+ (cero dependencias).
|
|
13
|
+
* 2. Fallback: parser propio mínimo (KEY=VALUE, comillas, comentarios, export).
|
|
14
|
+
*
|
|
15
|
+
* No sobrescribe variables ya presentes en process.env (las del shell mandan).
|
|
16
|
+
*/
|
|
17
|
+
class EnvLoader {
|
|
18
|
+
/**
|
|
19
|
+
* Carga el archivo .env indicado (o ./.env del cwd) en process.env.
|
|
20
|
+
* Silencioso si el archivo no existe. Devuelve true si cargó algo.
|
|
21
|
+
* @param {string} [envPath]
|
|
22
|
+
* @returns {boolean}
|
|
23
|
+
*/
|
|
24
|
+
static load(envPath) {
|
|
25
|
+
const file = envPath || path.resolve(process.cwd(), '.env');
|
|
26
|
+
if (!fs.existsSync(file)) return false;
|
|
27
|
+
|
|
28
|
+
// Camino preferido: cargador nativo de Node (20.6+).
|
|
29
|
+
if (typeof process.loadEnvFile === 'function') {
|
|
30
|
+
try {
|
|
31
|
+
process.loadEnvFile(file);
|
|
32
|
+
return true;
|
|
33
|
+
} catch {
|
|
34
|
+
// Cae al parser propio si el nativo falla por algún motivo.
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
40
|
+
const parsed = EnvLoader.parse(content);
|
|
41
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
42
|
+
if (process.env[key] === undefined) {
|
|
43
|
+
process.env[key] = value;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Parser mínimo de formato .env. Soporta:
|
|
54
|
+
* KEY=value · KEY="value con espacios" · KEY='literal' · export KEY=value
|
|
55
|
+
* comentarios con # · líneas en blanco · \n \t en comillas dobles.
|
|
56
|
+
* @param {string} content
|
|
57
|
+
* @returns {Record<string,string>}
|
|
58
|
+
*/
|
|
59
|
+
static parse(content) {
|
|
60
|
+
const out = {};
|
|
61
|
+
for (let rawLine of content.split(/\r?\n/)) {
|
|
62
|
+
const line = rawLine.trim();
|
|
63
|
+
if (!line || line.startsWith('#')) continue;
|
|
64
|
+
|
|
65
|
+
// Permite el prefijo `export` (estilo shell).
|
|
66
|
+
const withoutExport = line.startsWith('export ') ? line.slice(7).trim() : line;
|
|
67
|
+
|
|
68
|
+
const eq = withoutExport.indexOf('=');
|
|
69
|
+
if (eq === -1) continue;
|
|
70
|
+
|
|
71
|
+
const key = withoutExport.slice(0, eq).trim();
|
|
72
|
+
if (!key) continue;
|
|
73
|
+
|
|
74
|
+
let value = withoutExport.slice(eq + 1).trim();
|
|
75
|
+
|
|
76
|
+
// Comillas dobles: interpreta escapes. Comillas simples: literal.
|
|
77
|
+
if (value.length >= 2 && value[0] === '"' && value[value.length - 1] === '"') {
|
|
78
|
+
value = value.slice(1, -1).replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\"/g, '"');
|
|
79
|
+
} else if (value.length >= 2 && value[0] === "'" && value[value.length - 1] === "'") {
|
|
80
|
+
value = value.slice(1, -1);
|
|
81
|
+
} else {
|
|
82
|
+
// Sin comillas: corta un comentario en línea (espacio + #).
|
|
83
|
+
const hash = value.indexOf(' #');
|
|
84
|
+
if (hash !== -1) value = value.slice(0, hash).trim();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
out[key] = value;
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = EnvLoader;
|
|
94
|
+
module.exports.EnvLoader = EnvLoader;
|
package/src/utils/ui.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* UI compartida del CLI de DBCube. Un solo lugar para el estilo visual:
|
|
5
|
+
* colores de marca, símbolos de estado y el manejo de errores consistente.
|
|
6
|
+
* Así todos los comandos se ven como parte del mismo producto.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Verde de marca DBCube (con fallback si la terminal no soporta truecolor).
|
|
10
|
+
const brandGreen = (t) => (chalk.level >= 2 ? chalk.hex('#22C55E') : chalk.green)(t);
|
|
11
|
+
|
|
12
|
+
const ui = {
|
|
13
|
+
chalk,
|
|
14
|
+
brand: (t) => brandGreen(chalk.bold(t)),
|
|
15
|
+
|
|
16
|
+
/** Banner de marca para el header del CLI/help. */
|
|
17
|
+
banner(subtitle = 'Database toolkit powered by Rust') {
|
|
18
|
+
const line = chalk.gray('─'.repeat(54));
|
|
19
|
+
console.log('');
|
|
20
|
+
console.log(` ${brandGreen('◆')} ${ui.brand('DBCube')} ${chalk.gray('CLI')}`);
|
|
21
|
+
console.log(` ${chalk.gray(subtitle)}`);
|
|
22
|
+
console.log(` ${line}`);
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
/** Cabecera de comando: ícono + título + línea separadora. */
|
|
26
|
+
header(title, icon = '🧊') {
|
|
27
|
+
console.log(`\n${icon} ${ui.brand(title.toUpperCase())}`);
|
|
28
|
+
console.log(chalk.gray('─'.repeat(54)));
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/** Línea de detalle bajo una cabecera (clave: valor). */
|
|
32
|
+
item(label, value) {
|
|
33
|
+
if (value === undefined) {
|
|
34
|
+
console.log(`${chalk.gray('│')} ${label}`);
|
|
35
|
+
} else {
|
|
36
|
+
console.log(`${chalk.gray('│')} ${chalk.gray(label + ':')} ${chalk.white(value)}`);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
success(message) { console.log(`${chalk.green('✔')} ${message}`); },
|
|
41
|
+
info(message) { console.log(`${chalk.cyan('ℹ')} ${message}`); },
|
|
42
|
+
warn(message) { console.log(`${chalk.yellow('⚠')} ${message}`); },
|
|
43
|
+
dim(message) { console.log(chalk.gray(message)); },
|
|
44
|
+
step(message) { console.log(`${chalk.cyan('›')} ${message}`); },
|
|
45
|
+
|
|
46
|
+
/** Error con título en rojo y pistas opcionales (→ ...). */
|
|
47
|
+
error(message, hints = []) {
|
|
48
|
+
console.error(`\n${chalk.red('✖')} ${chalk.red(message)}`);
|
|
49
|
+
for (const h of hints) console.error(` ${chalk.gray('→')} ${chalk.gray(h)}`);
|
|
50
|
+
console.error('');
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/** "Cancelado." silencioso (Ctrl+C / prompt cerrado). */
|
|
54
|
+
cancelled() {
|
|
55
|
+
console.log(`\n${chalk.gray('Cancelled.')}`);
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Manejador central de errores de comando. Llamar desde cada catch.
|
|
60
|
+
* Traduce los fallos comunes a mensajes claros y accionables, sin stacks
|
|
61
|
+
* (salvo DBCUBE_DEBUG=1), y cierra el proceso con el código adecuado.
|
|
62
|
+
*/
|
|
63
|
+
handleError(error) {
|
|
64
|
+
// Ctrl+C / cierre del prompt interactivo.
|
|
65
|
+
if (error && (error.name === 'ExitPromptError' || /force closed/i.test(error.message || ''))) {
|
|
66
|
+
ui.cancelled();
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const msg = (error && error.message) || String(error);
|
|
71
|
+
|
|
72
|
+
// Base de datos/config no inicializada (errores internos típicos).
|
|
73
|
+
if (msg.includes("reading 'init'") || msg.includes("reading 'getDatabase'") || msg.includes("reading 'type'")) {
|
|
74
|
+
ui.error('Database configuration not found.', [
|
|
75
|
+
'Run: npx dbcube run database:create',
|
|
76
|
+
'Or check that the database is configured in dbcube.config.js',
|
|
77
|
+
]);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
ui.error(msg);
|
|
82
|
+
if (process.env.DBCUBE_DEBUG === '1' || process.env.DBCUBE_DEBUG === 'true') {
|
|
83
|
+
console.error(error);
|
|
84
|
+
}
|
|
85
|
+
process.exit(1);
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
module.exports = ui;
|