novatec-cli 3.0.5 → 3.0.7
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/index.js +37 -6
- package/lib/create.js +52 -5
- package/lib/generators/backend.js +14 -8
- package/lib/generators/frontend.js +17 -2
- package/lib/prompts.js +66 -32
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -26,8 +26,9 @@ async function checkForUpdates() {
|
|
|
26
26
|
async function showBanner() {
|
|
27
27
|
console.clear();
|
|
28
28
|
const logo = figlet.textSync('NOVATEC', { font: 'Slant' });
|
|
29
|
+
const grad = (await import('gradient-string')).default;
|
|
29
30
|
console.log();
|
|
30
|
-
logo.split('\n').filter(l => l.trim()).forEach(l => console.log(' ' +
|
|
31
|
+
logo.split('\n').filter(l => l.trim()).forEach(l => console.log(' ' + grad.cristal.multiline(l)));
|
|
31
32
|
console.log();
|
|
32
33
|
const now = new Date().toLocaleDateString('es-MX', { day: '2-digit', month: 'short', year: 'numeric' });
|
|
33
34
|
console.log(' ' + chalk.gray(`v${pkg.version} · Enterprise Fullstack CLI · ${now}`));
|
|
@@ -36,10 +37,40 @@ async function showBanner() {
|
|
|
36
37
|
console.log();
|
|
37
38
|
console.log(boxen(
|
|
38
39
|
chalk.bold.white(' STACK DISPONIBLE\n\n') +
|
|
39
|
-
chalk.white.bold(' Frontend ') + chalk.gray(' │ ') +
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
chalk.white.bold(' Frontend ') + chalk.gray(' │ ') +
|
|
41
|
+
[
|
|
42
|
+
grad('#61DAFB','#21D4FD')(' React'),
|
|
43
|
+
grad('#fff','#888')(' Next.js'),
|
|
44
|
+
grad('#42b883','#35495e')(' Vue'),
|
|
45
|
+
grad('#00DC82','#003543')(' Nuxt'),
|
|
46
|
+
grad('#FF5D01','#BC52EE')(' Astro'),
|
|
47
|
+
grad('#FF3E00','#FF8C00')(' Svelte'),
|
|
48
|
+
grad('#2C4F7C','#446B9E')(' Solid'),
|
|
49
|
+
grad('#DD0031','#C3002F')(' Angular'),
|
|
50
|
+
grad('#121212','#818CF8')(' Remix'),
|
|
51
|
+
grad('#18B6F6','#AC7EF4')(' Qwik'),
|
|
52
|
+
].join(chalk.gray(' · ')) + '\n\n' +
|
|
53
|
+
chalk.white.bold(' Backend ') + chalk.gray(' │ ') +
|
|
54
|
+
[
|
|
55
|
+
grad('#fff','#aaa')(' Express'),
|
|
56
|
+
grad('#E0234E','#FF6B6B')(' NestJS'),
|
|
57
|
+
grad('#000','#888')(' Fastify'),
|
|
58
|
+
grad('#FF5733','#FF8C00')(' Hono'),
|
|
59
|
+
grad('#009688','#26A69A')(' FastAPI'),
|
|
60
|
+
grad('#092E20','#44B78B')(' Django'),
|
|
61
|
+
grad('#fff','#aaa')(' Flask'),
|
|
62
|
+
grad('#6DB33F','#77BC1F')(' Spring'),
|
|
63
|
+
grad('#fff','#aaa')(' Deno'),
|
|
64
|
+
grad('#00ACD7','#5DC9E2')(' Go/Gin'),
|
|
65
|
+
].join(chalk.gray(' · ')) + '\n\n' +
|
|
66
|
+
chalk.white.bold(' Database ') + chalk.gray(' │ ') +
|
|
67
|
+
[
|
|
68
|
+
grad('#336791','#4A90D9')(' PostgreSQL'),
|
|
69
|
+
grad('#4479A1','#00758F')(' MySQL'),
|
|
70
|
+
grad('#47A248','#00ED64')(' MongoDB'),
|
|
71
|
+
grad('#003B57','#0F80CC')(' SQLite'),
|
|
72
|
+
grad('#3ECF8E','#1C1C1C')(' Supabase'),
|
|
73
|
+
].join(chalk.gray(' · ')) + '\n\n' +
|
|
43
74
|
chalk.white.bold(' Comandos ') + chalk.gray(' │ ') +
|
|
44
75
|
[chalk.white('create'), chalk.white('add'), chalk.white('doctor'), chalk.white('build'), chalk.white('deploy'), chalk.white('list'), chalk.white('update')]
|
|
45
76
|
.join(chalk.gray(' · ')),
|
|
@@ -48,7 +79,7 @@ async function showBanner() {
|
|
|
48
79
|
console.log();
|
|
49
80
|
console.log(boxen(
|
|
50
81
|
chalk.gray(' $ novatec create my-app\n') +
|
|
51
|
-
chalk.gray(' $ novatec create my-app --
|
|
82
|
+
chalk.gray(' $ novatec create my-app --frontend next --backend express --db postgres\n') +
|
|
52
83
|
chalk.gray(' $ novatec add crud Product\n') +
|
|
53
84
|
chalk.gray(' $ novatec doctor'),
|
|
54
85
|
{ padding: { top: 0, bottom: 0, left: 1, right: 4 }, margin: { left: 2 }, borderStyle: 'single', borderColor: 'gray', dimBorder: true }
|
package/lib/create.js
CHANGED
|
@@ -118,18 +118,65 @@ export async function runCreate(nameArg, options) {
|
|
|
118
118
|
|
|
119
119
|
// ── ARQUITECTURA ──────────────────────────────────────────────────────────────
|
|
120
120
|
async function applyArchitecture(config, root) {
|
|
121
|
-
const beDir = path.join(root, 'backend', 'src');
|
|
122
121
|
const arch = config.architecture || 'mvc';
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
// Backend
|
|
124
|
+
const beDirs = {
|
|
125
125
|
mvc: ['controllers', 'models', 'routes', 'middlewares', 'services'],
|
|
126
126
|
hexagonal: ['domain/entities', 'domain/ports', 'application/usecases', 'infrastructure/adapters', 'infrastructure/repositories', 'interfaces/http'],
|
|
127
127
|
clean: ['domain/entities', 'domain/usecases', 'data/repositories', 'data/datasources', 'presentation/controllers', 'presentation/routes'],
|
|
128
128
|
};
|
|
129
|
+
const beBase = path.join(root, 'backend', 'src');
|
|
130
|
+
for (const dir of (beDirs[arch] || beDirs.mvc)) {
|
|
131
|
+
await fse.ensureDir(path.join(beBase, dir));
|
|
132
|
+
await fse.writeFile(path.join(beBase, dir, '.gitkeep'), '');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Frontend — estructura de src según arquitectura
|
|
136
|
+
const feDirs = {
|
|
137
|
+
mvc: [
|
|
138
|
+
'components',
|
|
139
|
+
'pages',
|
|
140
|
+
'services',
|
|
141
|
+
'hooks',
|
|
142
|
+
'utils',
|
|
143
|
+
'assets',
|
|
144
|
+
],
|
|
145
|
+
hexagonal: [
|
|
146
|
+
'domain/entities',
|
|
147
|
+
'domain/ports',
|
|
148
|
+
'application/usecases',
|
|
149
|
+
'infrastructure/api',
|
|
150
|
+
'infrastructure/storage',
|
|
151
|
+
'presentation/components',
|
|
152
|
+
'presentation/pages',
|
|
153
|
+
'presentation/hooks',
|
|
154
|
+
],
|
|
155
|
+
clean: [
|
|
156
|
+
'domain/entities',
|
|
157
|
+
'domain/usecases',
|
|
158
|
+
'data/repositories',
|
|
159
|
+
'data/datasources',
|
|
160
|
+
'presentation/components',
|
|
161
|
+
'presentation/pages',
|
|
162
|
+
'presentation/hooks',
|
|
163
|
+
'core/utils',
|
|
164
|
+
],
|
|
165
|
+
};
|
|
129
166
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
167
|
+
const feBase = path.join(root, 'frontend', 'src');
|
|
168
|
+
// Solo crear si existe el directorio src (algunos frameworks lo generan, otros no)
|
|
169
|
+
if (await fse.pathExists(feBase)) {
|
|
170
|
+
for (const dir of (feDirs[arch] || feDirs.mvc)) {
|
|
171
|
+
await fse.ensureDir(path.join(feBase, dir));
|
|
172
|
+
await fse.writeFile(path.join(feBase, dir, '.gitkeep'), '');
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
// Si no existe src aún (ej: nuxt, astro), crearlo igual
|
|
176
|
+
for (const dir of (feDirs[arch] || feDirs.mvc)) {
|
|
177
|
+
await fse.ensureDir(path.join(feBase, dir));
|
|
178
|
+
await fse.writeFile(path.join(feBase, dir, '.gitkeep'), '');
|
|
179
|
+
}
|
|
133
180
|
}
|
|
134
181
|
}
|
|
135
182
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import fse from 'fs-extra';
|
|
4
|
+
import gradient from 'gradient-string';
|
|
4
5
|
import { execSync } from 'child_process';
|
|
5
6
|
import { isInstalled } from '../utils.js';
|
|
6
7
|
|
|
7
|
-
// DB packages por backend type
|
|
8
8
|
const NODE_DB_DEPS = {
|
|
9
9
|
postgres: ['pg', 'pg-hstore'],
|
|
10
10
|
mysql: ['mysql2'],
|
|
@@ -14,13 +14,17 @@ const NODE_DB_DEPS = {
|
|
|
14
14
|
none: [],
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
+
const COLORS = {
|
|
18
|
+
express: ['#ffffff', '#aaaaaa'], nestjs: ['#E0234E', '#FF6B6B'],
|
|
19
|
+
fastify: ['#000000', '#888888'], hono: ['#FF5733', '#FF8C00'],
|
|
20
|
+
fastapi: ['#009688', '#26A69A'], django: ['#092E20', '#44B78B'],
|
|
21
|
+
flask: ['#ffffff', '#aaaaaa'], spring: ['#6DB33F', '#77BC1F'],
|
|
22
|
+
deno: ['#ffffff', '#aaaaaa'], gin: ['#00ACD7', '#5DC9E2'],
|
|
23
|
+
};
|
|
24
|
+
|
|
17
25
|
function installNodeDeps(prod, dev, cwd) {
|
|
18
|
-
if (prod.length) {
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
if (dev && dev.length) {
|
|
22
|
-
execSync(`npm install -D ${dev.join(' ')}`, { cwd, stdio: 'pipe' });
|
|
23
|
-
}
|
|
26
|
+
if (prod.length) execSync(`npm install ${prod.join(' ')}`, { cwd, stdio: 'pipe' });
|
|
27
|
+
if (dev && dev.length) execSync(`npm install -D ${dev.join(' ')}`, { cwd, stdio: 'pipe' });
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
function backendPath(projectPath) {
|
|
@@ -28,7 +32,9 @@ function backendPath(projectPath) {
|
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export async function generateBackend(config, projectPath) {
|
|
31
|
-
|
|
35
|
+
const [c1, c2] = COLORS[config.backend] || ['#ffffff', '#aaaaaa'];
|
|
36
|
+
const label = gradient(c1, c2)(` ◆ ${config.backend.toUpperCase()} `);
|
|
37
|
+
console.log(`\n ${label} ${chalk.gray('Generando backend...')}`);
|
|
32
38
|
const handlers = { express, nestjs, fastify, hono, fastapi, django, flask, spring, deno, gin };
|
|
33
39
|
const fn = handlers[config.backend];
|
|
34
40
|
if (!fn) throw new Error(`Backend no soportado: ${config.backend}`);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import fse from 'fs-extra';
|
|
4
|
+
import gradient from 'gradient-string';
|
|
4
5
|
import { execSync } from 'child_process';
|
|
5
6
|
|
|
6
|
-
// Comandos de scaffolding por framework
|
|
7
7
|
const SCAFFOLD = {
|
|
8
8
|
react: 'npm create vite@latest frontend -- --template react',
|
|
9
9
|
vue: 'npm create vite@latest frontend -- --template vue',
|
|
@@ -17,11 +17,26 @@ const SCAFFOLD = {
|
|
|
17
17
|
qwik: 'npm create qwik@latest frontend -- --no-install',
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
const COLORS = {
|
|
21
|
+
react: ['#61DAFB', '#21D4FD'],
|
|
22
|
+
next: ['#ffffff', '#888888'],
|
|
23
|
+
vue: ['#42b883', '#35495e'],
|
|
24
|
+
nuxt: ['#00DC82', '#003543'],
|
|
25
|
+
astro: ['#FF5D01', '#BC52EE'],
|
|
26
|
+
svelte: ['#FF3E00', '#FF8C00'],
|
|
27
|
+
solid: ['#2C4F7C', '#446B9E'],
|
|
28
|
+
angular: ['#DD0031', '#C3002F'],
|
|
29
|
+
remix: ['#818CF8', '#6366F1'],
|
|
30
|
+
qwik: ['#18B6F6', '#AC7EF4'],
|
|
31
|
+
};
|
|
32
|
+
|
|
20
33
|
export async function generateFrontend(config, projectPath) {
|
|
21
34
|
const cmd = SCAFFOLD[config.frontend];
|
|
22
35
|
if (!cmd) throw new Error(`Frontend no soportado: ${config.frontend}`);
|
|
23
36
|
|
|
24
|
-
|
|
37
|
+
const [c1, c2] = COLORS[config.frontend] || ['#ffffff', '#aaaaaa'];
|
|
38
|
+
const label = gradient(c1, c2)(` ◆ ${config.frontend.toUpperCase()} `);
|
|
39
|
+
console.log(chalk.blue(`\n ${label} ${chalk.gray('Generando frontend...')}`));
|
|
25
40
|
|
|
26
41
|
try {
|
|
27
42
|
execSync(cmd, { cwd: projectPath, stdio: 'pipe' });
|
package/lib/prompts.js
CHANGED
|
@@ -1,54 +1,88 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import gradient from 'gradient-string';
|
|
3
4
|
import fse from 'fs-extra';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
import boxen from 'boxen';
|
|
6
7
|
|
|
8
|
+
// Colores reales de cada framework/DB
|
|
9
|
+
const g = {
|
|
10
|
+
react: gradient('#61DAFB', '#21D4FD'),
|
|
11
|
+
next: gradient('#ffffff', '#888888'),
|
|
12
|
+
vue: gradient('#42b883', '#35495e'),
|
|
13
|
+
nuxt: gradient('#00DC82', '#003543'),
|
|
14
|
+
astro: gradient('#FF5D01', '#BC52EE'),
|
|
15
|
+
svelte: gradient('#FF3E00', '#FF8C00'),
|
|
16
|
+
solid: gradient('#2C4F7C', '#446B9E'),
|
|
17
|
+
angular: gradient('#DD0031', '#C3002F'),
|
|
18
|
+
remix: gradient('#121212', '#818CF8'),
|
|
19
|
+
qwik: gradient('#18B6F6', '#AC7EF4'),
|
|
20
|
+
express: gradient('#ffffff', '#aaaaaa'),
|
|
21
|
+
nestjs: gradient('#E0234E', '#FF6B6B'),
|
|
22
|
+
fastify: gradient('#000000', '#888888'),
|
|
23
|
+
hono: gradient('#FF5733', '#FF8C00'),
|
|
24
|
+
fastapi: gradient('#009688', '#26A69A'),
|
|
25
|
+
django: gradient('#092E20', '#44B78B'),
|
|
26
|
+
flask: gradient('#ffffff', '#aaaaaa'),
|
|
27
|
+
spring: gradient('#6DB33F', '#77BC1F'),
|
|
28
|
+
deno: gradient('#ffffff', '#aaaaaa'),
|
|
29
|
+
gin: gradient('#00ACD7', '#5DC9E2'),
|
|
30
|
+
postgres: gradient('#336791', '#4A90D9'),
|
|
31
|
+
mysql: gradient('#4479A1', '#00758F'),
|
|
32
|
+
mongo: gradient('#47A248', '#00ED64'),
|
|
33
|
+
sqlite: gradient('#003B57', '#0F80CC'),
|
|
34
|
+
supabase: gradient('#3ECF8E', '#1C1C1C'),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function logo(key, text) {
|
|
38
|
+
return g[key] ? g[key](text) : chalk.white(text);
|
|
39
|
+
}
|
|
40
|
+
|
|
7
41
|
export const FRONTEND_CHOICES = [
|
|
8
|
-
{ name: 'React
|
|
9
|
-
{ name: 'Next.js
|
|
10
|
-
{ name: 'Vue 3
|
|
11
|
-
{ name: 'Nuxt 3
|
|
12
|
-
{ name: 'Astro
|
|
13
|
-
{ name: 'SvelteKit
|
|
14
|
-
{ name: 'SolidJS
|
|
15
|
-
{ name: 'Angular
|
|
16
|
-
{ name: 'Remix
|
|
17
|
-
{ name: 'Qwik
|
|
42
|
+
{ name: logo('react', ' ◆ React ') + chalk.gray(' — Vite + React 18'), value: 'react' },
|
|
43
|
+
{ name: logo('next', ' ▲ Next.js ') + chalk.gray(' — SSR/SSG App Router'), value: 'next' },
|
|
44
|
+
{ name: logo('vue', ' ◈ Vue 3 ') + chalk.gray(' — Vite + Composition API'), value: 'vue' },
|
|
45
|
+
{ name: logo('nuxt', ' ◈ Nuxt 3 ') + chalk.gray(' — Vue SSR/SSG'), value: 'nuxt' },
|
|
46
|
+
{ name: logo('astro', ' ✦ Astro ') + chalk.gray(' — MPA ultra-rápido'), value: 'astro' },
|
|
47
|
+
{ name: logo('svelte', ' ◆ SvelteKit ') + chalk.gray(' — Svelte SSR/SSG'), value: 'svelte' },
|
|
48
|
+
{ name: logo('solid', ' ◆ SolidJS ') + chalk.gray(' — Sin Virtual DOM'), value: 'solid' },
|
|
49
|
+
{ name: logo('angular', ' ◆ Angular ') + chalk.gray(' — Framework empresarial'), value: 'angular' },
|
|
50
|
+
{ name: logo('remix', ' ◆ Remix ') + chalk.gray(' — Full-stack React'), value: 'remix' },
|
|
51
|
+
{ name: logo('qwik', ' ⚡ Qwik ') + chalk.gray(' — Resumability'), value: 'qwik' },
|
|
18
52
|
];
|
|
19
53
|
|
|
20
54
|
export const BACKEND_CHOICES = [
|
|
21
|
-
{ name: 'Express
|
|
22
|
-
{ name: 'NestJS
|
|
23
|
-
{ name: 'Fastify
|
|
24
|
-
{ name: 'Hono
|
|
25
|
-
{ name: 'FastAPI
|
|
26
|
-
{ name: 'Django
|
|
27
|
-
{ name: 'Flask
|
|
28
|
-
{ name: 'Spring Boot — Empresarial Java', value: 'spring' },
|
|
29
|
-
{ name: 'Deno/Oak
|
|
30
|
-
{ name: 'Go/Gin
|
|
55
|
+
{ name: logo('express', ' ◆ Express ') + chalk.gray(' — Minimalista Node.js'), value: 'express' },
|
|
56
|
+
{ name: logo('nestjs', ' ◆ NestJS ') + chalk.gray(' — Modular TypeScript'), value: 'nestjs' },
|
|
57
|
+
{ name: logo('fastify', ' ⚡ Fastify ') + chalk.gray(' — Ultra-rápido Node'), value: 'fastify' },
|
|
58
|
+
{ name: logo('hono', ' ◆ Hono ') + chalk.gray(' — Edge-ready ligero'), value: 'hono' },
|
|
59
|
+
{ name: logo('fastapi', ' ◆ FastAPI ') + chalk.gray(' — Async Python'), value: 'fastapi' },
|
|
60
|
+
{ name: logo('django', ' ◆ Django ') + chalk.gray(' — Baterías incluidas'), value: 'django' },
|
|
61
|
+
{ name: logo('flask', ' ◆ Flask ') + chalk.gray(' — Micro-framework Python'), value: 'flask' },
|
|
62
|
+
{ name: logo('spring', ' ◆ Spring Boot') + chalk.gray(' — Empresarial Java'), value: 'spring' },
|
|
63
|
+
{ name: logo('deno', ' ◆ Deno/Oak ') + chalk.gray(' — TypeScript seguro'), value: 'deno' },
|
|
64
|
+
{ name: logo('gin', ' ◆ Go/Gin ') + chalk.gray(' — Rendimiento extremo'), value: 'gin' },
|
|
31
65
|
];
|
|
32
66
|
|
|
33
67
|
export const DB_CHOICES = [
|
|
34
|
-
{ name: 'PostgreSQL
|
|
35
|
-
{ name: 'MySQL
|
|
36
|
-
{ name: 'MongoDB
|
|
37
|
-
{ name: 'SQLite
|
|
38
|
-
{ name: 'Supabase
|
|
39
|
-
{ name: 'Ninguna',
|
|
68
|
+
{ name: logo('postgres', ' ◆ PostgreSQL ') + chalk.gray(' — Relacional robusto'), value: 'postgres' },
|
|
69
|
+
{ name: logo('mysql', ' ◆ MySQL ') + chalk.gray(' — Relacional popular'), value: 'mysql' },
|
|
70
|
+
{ name: logo('mongo', ' ◆ MongoDB ') + chalk.gray(' — NoSQL documentos'), value: 'mongo' },
|
|
71
|
+
{ name: logo('sqlite', ' ◆ SQLite ') + chalk.gray(' — Embebido ligero'), value: 'sqlite' },
|
|
72
|
+
{ name: logo('supabase', ' ◆ Supabase ') + chalk.gray(' — BaaS con Auth incluida'), value: 'supabase' },
|
|
73
|
+
{ name: chalk.gray(' ○ Ninguna'), value: 'none' },
|
|
40
74
|
];
|
|
41
75
|
|
|
42
76
|
export const ARCH_CHOICES = [
|
|
43
|
-
{ name: 'MVC
|
|
44
|
-
{ name: 'Hexagonal
|
|
45
|
-
{ name: 'Clean
|
|
77
|
+
{ name: chalk.white(' ◆ MVC ') + chalk.gray(' — Model-View-Controller (clásico)'), value: 'mvc' },
|
|
78
|
+
{ name: chalk.white(' ◆ Hexagonal ') + chalk.gray(' — Ports & Adapters'), value: 'hexagonal' },
|
|
79
|
+
{ name: chalk.white(' ◆ Clean ') + chalk.gray(' — Clean Architecture (capas)'), value: 'clean' },
|
|
46
80
|
];
|
|
47
81
|
|
|
48
82
|
export const PM_CHOICES = [
|
|
49
|
-
{ name: 'npm', value: 'npm' },
|
|
50
|
-
{ name: 'pnpm', value: 'pnpm' },
|
|
51
|
-
{ name: 'yarn', value: 'yarn' },
|
|
83
|
+
{ name: chalk.white(' ◆ npm'), value: 'npm' },
|
|
84
|
+
{ name: chalk.white(' ◆ pnpm'), value: 'pnpm' },
|
|
85
|
+
{ name: chalk.white(' ◆ yarn'), value: 'yarn' },
|
|
52
86
|
];
|
|
53
87
|
|
|
54
88
|
export async function askProjectOptions(nameArg, options) {
|
package/package.json
CHANGED