@dbcube/cli 5.1.4 → 5.2.1
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/README.md +59 -0
- package/package.json +24 -8
- package/src/commands/dev.js +83 -0
- package/src/commands/doctor.js +99 -0
- package/src/commands/generate.js +160 -0
- package/src/commands/help.js +24 -8
- package/src/commands/init.js +82 -0
- package/src/commands/migrate/lib.js +125 -0
- package/src/commands/migrate/rollback.js +72 -0
- package/src/commands/migrate/status.js +55 -0
- package/src/commands/run/database/create/index.js +10 -12
- package/src/commands/run/pull.js +249 -0
- package/src/commands/run/seeder/add.js +4 -3
- package/src/commands/run/table/alter.js +55 -3
- package/src/commands/run/table/fresh.js +81 -35
- package/src/commands/run/table/refresh.js +4 -4
- package/src/commands/run/trigger/fresh.js +4 -3
- package/src/commands/validate.js +70 -0
- package/src/commands/version.js +66 -29
- package/src/index.js +162 -92
- package/src/utils/ConfigFileUtils.js +3 -2
- package/.npmignore +0 -58
- package/bun.lock +0 -192
- package/dbcube.config.js +0 -15
- package/pnpm-workspace.yaml +0 -3
|
@@ -1,35 +1,81 @@
|
|
|
1
|
-
const
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} else
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { Schema } = require('@dbcube/schema-builder');
|
|
3
|
+
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* dbcube run table:fresh [--seeder] [--force]
|
|
7
|
+
* DESTRUCTIVO: dropea y recrea todas las tablas desde los .table.cube.
|
|
8
|
+
* Pide confirmación ESCRITA (el nombre de la base de datos) salvo con --force.
|
|
9
|
+
*/
|
|
10
|
+
async function confirmDestruction(databases) {
|
|
11
|
+
const { input } = require('@inquirer/prompts');
|
|
12
|
+
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(` ${chalk.bgRed.white.bold(' ⚠ DESTRUCTIVE OPERATION ')}`);
|
|
15
|
+
console.log('');
|
|
16
|
+
console.log(` ${chalk.red('table:fresh will DROP and recreate ALL tables.')}`);
|
|
17
|
+
console.log(` ${chalk.red.bold('ALL DATA WILL BE PERMANENTLY LOST')} in:`);
|
|
18
|
+
for (const db of databases) {
|
|
19
|
+
console.log(` ${chalk.yellow('•')} ${chalk.bold(db.name)} ${chalk.gray(`(${db.type})`)}`);
|
|
20
|
+
}
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log(` ${chalk.gray('To update schemas WITHOUT losing data use:')} ${chalk.white('npx dbcube run table:refresh')}`);
|
|
23
|
+
console.log('');
|
|
24
|
+
|
|
25
|
+
const expected = databases.length === 1 ? databases[0].name : 'all';
|
|
26
|
+
const answer = await input({
|
|
27
|
+
message: `Type ${chalk.bold(expected)} to confirm (anything else aborts):`,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
return answer.trim() === expected;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
try {
|
|
35
|
+
const args = process.argv.slice(2);
|
|
36
|
+
const runSeeders = args.includes('--seeder');
|
|
37
|
+
const force = args.includes('--force') || args.includes('-y') || args.includes('--yes');
|
|
38
|
+
|
|
39
|
+
const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
|
|
40
|
+
|
|
41
|
+
if (!force) {
|
|
42
|
+
if (!process.stdin.isTTY) {
|
|
43
|
+
console.error(`\n${chalk.red('❌ table:fresh is destructive and needs confirmation.')}`);
|
|
44
|
+
console.error(`${chalk.gray('Non-interactive environment detected — pass')} ${chalk.white('--force')} ${chalk.gray('to proceed (e.g. in CI).')}\n`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const confirmed = await confirmDestruction(configuredDatabases);
|
|
48
|
+
if (!confirmed) {
|
|
49
|
+
console.log(`\n${chalk.yellow('Aborted.')} ${chalk.gray('No changes were made.')}\n`);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const config of configuredDatabases) {
|
|
55
|
+
const schema = new Schema(config.name);
|
|
56
|
+
await schema.freshTables();
|
|
57
|
+
if (runSeeders) {
|
|
58
|
+
await schema.executeSeeders();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (error.name === 'ExitPromptError') {
|
|
63
|
+
console.log(`\n${chalk.yellow('Aborted.')} ${chalk.gray('No changes were made.')}\n`);
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
if (error.message.includes("reading 'init'")) {
|
|
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
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
main().catch(console.error);
|
|
@@ -2,7 +2,6 @@ const { Schema } = require('@dbcube/schema-builder');
|
|
|
2
2
|
const ConfigFileUtils = require('./../../../utils/ConfigFileUtils');
|
|
3
3
|
|
|
4
4
|
async function main() {
|
|
5
|
-
console.clear();
|
|
6
5
|
try {
|
|
7
6
|
const configuredDatabases = await ConfigFileUtils.getConfiguredDatabases();
|
|
8
7
|
// Recorrer cada archivo y mostrar su contenido
|
|
@@ -14,14 +13,15 @@ async function main() {
|
|
|
14
13
|
if (error.message.includes("reading 'init'")) {
|
|
15
14
|
console.error('❌ Configuracion de base de datos no encontrada\n');
|
|
16
15
|
console.error('Ejecute el comando para crear una nueva base de datos:');
|
|
17
|
-
console.error(`\
|
|
16
|
+
console.error(`\tnpx dbcube run database:create`);
|
|
18
17
|
console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
|
|
19
18
|
process.exit(1);
|
|
20
19
|
} else if (error.message.includes("reading 'getDatabase'")) {
|
|
21
20
|
console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
|
|
22
21
|
} else {
|
|
23
|
-
console.error(
|
|
24
|
-
console.error(
|
|
22
|
+
console.error(`❌ ${error.message}`);
|
|
23
|
+
if (process.env.DEBUG) console.error(error);
|
|
24
|
+
process.exit(1);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -14,14 +14,15 @@ async function main() {
|
|
|
14
14
|
if (error.message.includes("reading 'init'")) {
|
|
15
15
|
console.error('❌ Configuracion de base de datos no encontrada\n');
|
|
16
16
|
console.error('Ejecute el comando para crear una nueva base de datos:');
|
|
17
|
-
console.error(`\
|
|
17
|
+
console.error(`\tnpx dbcube run database:create`);
|
|
18
18
|
console.error('\nO verifique que la base de datos este configurada en el archivo dbcube.config.js\n');
|
|
19
19
|
process.exit(1);
|
|
20
20
|
} else if (error.message.includes("reading 'getDatabase'")) {
|
|
21
21
|
console.error('- Se sugiere cambiar el linea o crear la base de datos a la que se hace referencia.');
|
|
22
22
|
} else {
|
|
23
|
-
console.error(
|
|
24
|
-
console.error(
|
|
23
|
+
console.error(`❌ ${error.message}`);
|
|
24
|
+
if (process.env.DEBUG) console.error(error);
|
|
25
|
+
process.exit(1);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
console.log('\n');
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { CubeValidator } = require('@dbcube/schema-builder');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* dbcube validate — Validates every .cube file in dbcube/ without executing
|
|
8
|
+
* anything. Exit code 1 when any file is invalid (CI-friendly).
|
|
9
|
+
*/
|
|
10
|
+
function collectCubeFiles(dir, acc = []) {
|
|
11
|
+
if (!fs.existsSync(dir)) return acc;
|
|
12
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
13
|
+
const full = path.join(dir, entry.name);
|
|
14
|
+
if (entry.isDirectory()) {
|
|
15
|
+
if (!['triggers', 'logs', 'node_modules'].includes(entry.name)) collectCubeFiles(full, acc);
|
|
16
|
+
} else if (entry.name.endsWith('.cube')) {
|
|
17
|
+
acc.push(full);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return acc;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function main() {
|
|
24
|
+
const cubesDir = path.join(process.cwd(), 'dbcube');
|
|
25
|
+
const files = collectCubeFiles(cubesDir);
|
|
26
|
+
|
|
27
|
+
if (files.length === 0) {
|
|
28
|
+
console.log(`${chalk.yellow('⚠')} No .cube files found in dbcube/`);
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(`\n🔎 ${chalk.green('Validating')} ${files.length} cube file(s)...\n`);
|
|
33
|
+
|
|
34
|
+
const validator = new CubeValidator();
|
|
35
|
+
let errorCount = 0;
|
|
36
|
+
|
|
37
|
+
for (const file of files) {
|
|
38
|
+
const rel = path.relative(process.cwd(), file);
|
|
39
|
+
// CubeValidator covers .table.cube structure; other types get a syntax-level pass
|
|
40
|
+
let result;
|
|
41
|
+
try {
|
|
42
|
+
result = validator.validateCubeFile(file);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
result = { isValid: false, errors: [{ error: e.message, lineNumber: 1 }] };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (result.isValid) {
|
|
48
|
+
console.log(` ${chalk.green('✓')} ${rel}`);
|
|
49
|
+
} else {
|
|
50
|
+
errorCount++;
|
|
51
|
+
console.log(` ${chalk.red('✗')} ${rel}`);
|
|
52
|
+
for (const err of result.errors) {
|
|
53
|
+
const line = err.lineNumber ? chalk.gray(`:${err.lineNumber}`) : '';
|
|
54
|
+
console.log(` ${chalk.red('[error]')} ${err.error}${line}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log('');
|
|
60
|
+
if (errorCount > 0) {
|
|
61
|
+
console.log(`${chalk.red('✗')} ${errorCount} file(s) with errors\n`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
console.log(`${chalk.green('✓')} All cube files are valid\n`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
main().catch(error => {
|
|
68
|
+
console.error('Error fatal:', error);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
});
|
package/src/commands/version.js
CHANGED
|
@@ -1,29 +1,66 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
try {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* dbcube version — CLI, packages, engine binaries, and environment info.
|
|
7
|
+
*/
|
|
8
|
+
function readVersion(pkgPath) {
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version;
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function findEngineVersions() {
|
|
17
|
+
const binDir = path.join(process.cwd(), '.dbcube', 'bin');
|
|
18
|
+
const engines = {};
|
|
19
|
+
try {
|
|
20
|
+
for (const f of fs.readdirSync(binDir)) {
|
|
21
|
+
const m = f.match(/^(query-engine|schema-engine|sqlite-engine)-v([\d.]+)-/);
|
|
22
|
+
if (m) engines[m[1]] = `v${m[2]}`;
|
|
23
|
+
}
|
|
24
|
+
} catch { /* no binaries downloaded yet */ }
|
|
25
|
+
return engines;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function showVersion() {
|
|
29
|
+
try {
|
|
30
|
+
const cliVersion = readVersion(path.join(__dirname, '../../package.json'));
|
|
31
|
+
const row = (label, value, dim = false) =>
|
|
32
|
+
console.log(` ${chalk.gray(label.padEnd(16))} ${dim ? chalk.gray(value) : chalk.white(value)}`);
|
|
33
|
+
|
|
34
|
+
console.log('');
|
|
35
|
+
console.log(` ${chalk.green.bold('▣ DBCube CLI')} ${chalk.bold('v' + cliVersion)}`);
|
|
36
|
+
console.log(` ${chalk.gray('─'.repeat(40))}`);
|
|
37
|
+
|
|
38
|
+
// Local package versions (when resolvable from the project)
|
|
39
|
+
const localPkgs = ['dbcube', '@dbcube/query-builder', '@dbcube/schema-builder', '@dbcube/core'];
|
|
40
|
+
for (const pkg of localPkgs) {
|
|
41
|
+
try {
|
|
42
|
+
const pkgJson = require.resolve(`${pkg}/package.json`, { paths: [process.cwd()] });
|
|
43
|
+
const v = readVersion(pkgJson);
|
|
44
|
+
if (v) row(pkg, 'v' + v);
|
|
45
|
+
} catch { /* not installed in this project */ }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const engines = findEngineVersions();
|
|
49
|
+
for (const [name, v] of Object.entries(engines)) {
|
|
50
|
+
row(name, `${v} ${chalk.gray('(rust)')}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log(` ${chalk.gray('─'.repeat(40))}`);
|
|
54
|
+
row('node', process.version, true);
|
|
55
|
+
row('platform', `${process.platform}-${process.arch}`, true);
|
|
56
|
+
console.log('');
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('❌ Error al obtener la versión:', error.message);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
showVersion().catch(error => {
|
|
64
|
+
console.error('Error fatal:', error);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
});
|
package/src/index.js
CHANGED
|
@@ -1,92 +1,162 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
for (let i = 2; i < args.length; i++) {
|
|
17
|
-
commandArgs.push(args[i]);
|
|
18
|
-
}
|
|
19
|
-
} else if (args[0].includes('create:')) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
'run:table:
|
|
39
|
-
'run:table:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
'run:database:create': '../src/commands/run/database/create/
|
|
47
|
-
'run:database:create:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
'run:
|
|
52
|
-
|
|
53
|
-
'
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'
|
|
57
|
-
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
|
|
5
|
+
// Obtener los argumentos pasados al comando
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
|
|
8
|
+
// Procesar los argumentos
|
|
9
|
+
let mainCommand = '';
|
|
10
|
+
const commandArgs = [];
|
|
11
|
+
|
|
12
|
+
if (args.length > 0) {
|
|
13
|
+
// Si el primer argumento es "run", combinamos con el segundo para formar el comando
|
|
14
|
+
if (args[0] === 'run' && args.length > 1) {
|
|
15
|
+
mainCommand = 'run:' + args[1];
|
|
16
|
+
for (let i = 2; i < args.length; i++) {
|
|
17
|
+
commandArgs.push(args[i]);
|
|
18
|
+
}
|
|
19
|
+
} else if (args[0].includes('create:')) {
|
|
20
|
+
mainCommand = args[0];
|
|
21
|
+
for (let i = 1; i < args.length; i++) {
|
|
22
|
+
commandArgs.push(args[i]);
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
mainCommand = args[0];
|
|
26
|
+
for (let i = 1; i < args.length; i++) {
|
|
27
|
+
commandArgs.push(args[i]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
// Sin argumentos: mostrar ayuda en lugar de fallar
|
|
32
|
+
mainCommand = '--help';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Mapa de comandos para mapear nombres de comandos a rutas de archivo
|
|
36
|
+
const commandMap = {
|
|
37
|
+
'run:table:fresh': '../src/commands/run/table/fresh.js',
|
|
38
|
+
'run:table:refresh': '../src/commands/run/table/refresh.js',
|
|
39
|
+
'run:table:alter': '../src/commands/run/table/alter.js',
|
|
40
|
+
|
|
41
|
+
'run:trigger:fresh': '../src/commands/run/trigger/fresh.js',
|
|
42
|
+
|
|
43
|
+
'run:seeder:add': '../src/commands/run/seeder/add.js',
|
|
44
|
+
|
|
45
|
+
'run:database:create': '../src/commands/run/database/create/index.js',
|
|
46
|
+
'run:database:create:config': '../src/commands/run/database/create/addDatabaseConfig.js',
|
|
47
|
+
'run:database:create:physical': '../src/commands/run/database/create/createDatabase.js',
|
|
48
|
+
// Alias sin "run" (el help histórico lo documenta así)
|
|
49
|
+
'database:create': '../src/commands/run/database/create/index.js',
|
|
50
|
+
|
|
51
|
+
'run:pull': '../src/commands/run/pull.js',
|
|
52
|
+
|
|
53
|
+
'run:download': '../src/commands/run/download.js',
|
|
54
|
+
'run:update': '../src/commands/run/update.js',
|
|
55
|
+
|
|
56
|
+
'init': '../src/commands/init.js',
|
|
57
|
+
'generate': '../src/commands/generate.js',
|
|
58
|
+
'validate': '../src/commands/validate.js',
|
|
59
|
+
'doctor': '../src/commands/doctor.js',
|
|
60
|
+
'dev': '../src/commands/dev.js',
|
|
61
|
+
|
|
62
|
+
'migrate:status': '../src/commands/migrate/status.js',
|
|
63
|
+
'migrate:rollback': '../src/commands/migrate/rollback.js',
|
|
64
|
+
|
|
65
|
+
'update': '../src/commands/update.js',
|
|
66
|
+
|
|
67
|
+
'version': '../src/commands/version.js',
|
|
68
|
+
'--version': '../src/commands/version.js',
|
|
69
|
+
'-v': '../src/commands/version.js',
|
|
70
|
+
|
|
71
|
+
'help': '../src/commands/help.js',
|
|
72
|
+
'--help': '../src/commands/help.js',
|
|
73
|
+
'-h': '../src/commands/help.js',
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Distancia de Levenshtein para sugerencias "did you mean"
|
|
77
|
+
function levenshtein(a, b) {
|
|
78
|
+
const m = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);
|
|
79
|
+
for (let j = 0; j <= b.length; j++) m[0][j] = j;
|
|
80
|
+
for (let i = 1; i <= a.length; i++) {
|
|
81
|
+
for (let j = 1; j <= b.length; j++) {
|
|
82
|
+
m[i][j] = Math.min(
|
|
83
|
+
m[i - 1][j] + 1,
|
|
84
|
+
m[i][j - 1] + 1,
|
|
85
|
+
m[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return m[a.length][b.length];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function suggestCommand(input) {
|
|
93
|
+
// Candidatos: forma completa ("run table:fresh") y forma corta ("table:fresh"),
|
|
94
|
+
// ambos mostrando siempre la forma completa al usuario.
|
|
95
|
+
const candidates = [];
|
|
96
|
+
for (const c of Object.keys(commandMap)) {
|
|
97
|
+
if (c.startsWith('-')) continue;
|
|
98
|
+
if (c.startsWith('run:')) {
|
|
99
|
+
const display = 'run ' + c.slice(4);
|
|
100
|
+
candidates.push({ match: display, display });
|
|
101
|
+
candidates.push({ match: c.slice(4), display });
|
|
102
|
+
} else {
|
|
103
|
+
candidates.push({ match: c, display: c });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const scored = candidates
|
|
108
|
+
.map(({ match, display }) => ({ display, d: levenshtein(input.toLowerCase(), match.toLowerCase()) }))
|
|
109
|
+
.sort((x, y) => x.d - y.d);
|
|
110
|
+
|
|
111
|
+
if (scored.length === 0 || scored[0].d > Math.max(3, Math.floor(input.length / 2))) return [];
|
|
112
|
+
|
|
113
|
+
const seen = new Set();
|
|
114
|
+
return scored
|
|
115
|
+
.filter(s => s.d <= scored[0].d + 1)
|
|
116
|
+
.filter(s => !seen.has(s.display) && seen.add(s.display))
|
|
117
|
+
.slice(0, 3)
|
|
118
|
+
.map(s => s.display);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Función para ejecutar comandos basados en los argumentos
|
|
122
|
+
async function executeCommand(command, commandArgs) {
|
|
123
|
+
if (commandMap[command]) {
|
|
124
|
+
const examplePath = path.join(__dirname, commandMap[command]);
|
|
125
|
+
const originalArgv = process.argv;
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
process.argv = [process.argv[0], process.argv[1], ...commandArgs];
|
|
129
|
+
await require(examplePath);
|
|
130
|
+
} finally {
|
|
131
|
+
process.argv = originalArgv;
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
// Comando desconocido: error claro + sugerencias
|
|
135
|
+
const typed = [args[0], args[1]].filter(Boolean).join(' ');
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(` ${chalk.bgRed.white.bold(' ERROR ')} ${chalk.red(`Unknown command:`)} ${chalk.bold(typed)}`);
|
|
138
|
+
|
|
139
|
+
const suggestions = suggestCommand(typed);
|
|
140
|
+
if (suggestions.length > 0) {
|
|
141
|
+
console.log('');
|
|
142
|
+
console.log(` ${chalk.cyan('Did you mean:')}`);
|
|
143
|
+
for (const s of suggestions) {
|
|
144
|
+
console.log(` ${chalk.green('→')} ${chalk.white('npx dbcube ' + s)}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log(` ${chalk.gray('Run')} ${chalk.yellow('npx dbcube help')} ${chalk.gray('to see all available commands.')}`);
|
|
150
|
+
console.log('');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Ejecutar el comando correspondiente
|
|
156
|
+
executeCommand(mainCommand, commandArgs).catch(err => {
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log(` ${chalk.bgRed.white.bold(' FATAL ')} ${chalk.red(err.message)}`);
|
|
159
|
+
console.log(` ${chalk.gray('Run')} ${chalk.yellow('npx dbcube doctor')} ${chalk.gray('to diagnose your setup.')}`);
|
|
160
|
+
console.log('');
|
|
161
|
+
process.exit(1);
|
|
162
|
+
});
|
|
@@ -78,8 +78,9 @@ class ConfigFileUtils {
|
|
|
78
78
|
}
|
|
79
79
|
return arrayDatabases;
|
|
80
80
|
} catch (error) {
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
// Fallar claro: devolver una DB inventada ocultaría el problema
|
|
82
|
+
// y haría que los comandos operen contra una base inexistente
|
|
83
|
+
throw new Error(`No se pudo cargar la configuración desde ${configPath}: ${error.message}`);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
package/.npmignore
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# Directories
|
|
2
|
-
examples
|
|
3
|
-
|
|
4
|
-
# Ignorar dependencias y configuraciones de desarrollo
|
|
5
|
-
node_modules/
|
|
6
|
-
npm-debug.log*
|
|
7
|
-
yarn-debug.log*
|
|
8
|
-
yarn-error.log*
|
|
9
|
-
|
|
10
|
-
# Ignorar carpetas y archivos irrelevantes
|
|
11
|
-
.vscode/
|
|
12
|
-
.lh
|
|
13
|
-
.idea/
|
|
14
|
-
.DS_Store
|
|
15
|
-
Thumbs.db
|
|
16
|
-
*.log
|
|
17
|
-
|
|
18
|
-
# Ignorar configuraciones del proyecto
|
|
19
|
-
.env
|
|
20
|
-
.env.*.local
|
|
21
|
-
package-lock.json
|
|
22
|
-
|
|
23
|
-
# Ignorar archivos del sistema
|
|
24
|
-
*.swp
|
|
25
|
-
*.swo
|
|
26
|
-
*.tmp
|
|
27
|
-
*.temp
|
|
28
|
-
|
|
29
|
-
# Ignorar carpetas de trabajo
|
|
30
|
-
temp/
|
|
31
|
-
logs/
|
|
32
|
-
debug/
|
|
33
|
-
|
|
34
|
-
# Ignorar archivos de compilación
|
|
35
|
-
src/
|
|
36
|
-
tsconfig.json
|
|
37
|
-
tsconfig.tsbuildinfo
|
|
38
|
-
|
|
39
|
-
# Ignorar pruebas y configuraciones
|
|
40
|
-
tests/
|
|
41
|
-
__tests__/
|
|
42
|
-
__mocks__/
|
|
43
|
-
coverage/
|
|
44
|
-
jest.config.js
|
|
45
|
-
|
|
46
|
-
# Ignorar documentación o ejemplos no necesarios
|
|
47
|
-
docs/
|
|
48
|
-
examples/
|
|
49
|
-
|
|
50
|
-
# Asegurarse de incluir solo lo esencial
|
|
51
|
-
!.npmignore
|
|
52
|
-
tsconfig.json
|
|
53
|
-
tsup.config.ts
|
|
54
|
-
|
|
55
|
-
.dbcube
|
|
56
|
-
dbcube
|
|
57
|
-
.env
|
|
58
|
-
*.db
|