nestforge-generator 0.4.1 → 0.6.0
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 +38 -0
- package/README.pt-BR.md +38 -0
- package/dist/capabilities.js +19 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli-arguments.js +109 -0
- package/dist/cli-arguments.js.map +1 -0
- package/dist/cli-help.js +40 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/doctor.js +88 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index.js +50 -2
- package/dist/index.js.map +1 -1
- package/dist/options.js +18 -0
- package/dist/options.js.map +1 -0
- package/dist/package-info.js +15 -0
- package/dist/package-info.js.map +1 -0
- package/dist/project-options.js +67 -0
- package/dist/project-options.js.map +1 -0
- package/dist/prompts.js +20 -16
- package/dist/prompts.js.map +1 -1
- package/dist/update-check.js +102 -0
- package/dist/update-check.js.map +1 -0
- package/dist/update-notifier.js +95 -0
- package/dist/update-notifier.js.map +1 -0
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -16,6 +16,44 @@ Run the locally installed CLI:
|
|
|
16
16
|
npx nestforge
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## Command-line usage
|
|
20
|
+
|
|
21
|
+
Running `npx nestforge` without arguments starts the complete interactive flow. You can also provide part of the configuration and answer only the remaining prompts:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx nestforge my-api --orm prisma --database postgres
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Use `--yes` or `--non-interactive` to generate without prompts. Omitted options use the documented defaults: TypeScript, Prisma, PostgreSQL, JWT, all optional features enabled, access control enabled, and automatic `.env` creation.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx nestforge my-api --yes
|
|
31
|
+
npx nestforge my-api --non-interactive --orm drizzle --database sqlite --no-redis
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Available utility commands:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx nestforge --help
|
|
38
|
+
npx nestforge --version
|
|
39
|
+
npx nestforge --list
|
|
40
|
+
npx nestforge --doctor
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Generation flags include `--language`, `--orm`, `--database`, `--auth`, `--docker`, `--swagger`, `--validation`, `--redis`, `--access-control`, and `--env`. Boolean features also accept the corresponding `--no-*` form. Use `--no-update-check` to skip the registry check and `--no-banner` to hide the banner.
|
|
44
|
+
|
|
45
|
+
Invalid values, contradictory toggles, and unsupported combinations terminate with an error instead of silently changing the requested configuration.
|
|
46
|
+
|
|
47
|
+
## Automatic update check
|
|
48
|
+
|
|
49
|
+
When the CLI starts, it checks the npm registry for a newer stable version. If an update is available, you can:
|
|
50
|
+
|
|
51
|
+
- download the latest version with `npx` and restart the CLI;
|
|
52
|
+
- continue with the currently installed version;
|
|
53
|
+
- hide the reminder until the next local day.
|
|
54
|
+
|
|
55
|
+
Registry metadata is cached for six hours in `~/.nestforge/update-check.json`. Network and cache failures are ignored so that the generator remains available offline.
|
|
56
|
+
|
|
19
57
|
For the testing guide, CLI prompts, and complete checklist, see [`TESTING.md`](TESTING.md).
|
|
20
58
|
|
|
21
59
|
## What already works
|
package/README.pt-BR.md
CHANGED
|
@@ -16,6 +16,44 @@ Execute a CLI instalada localmente:
|
|
|
16
16
|
npx nestforge
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## Uso pela linha de comando
|
|
20
|
+
|
|
21
|
+
Executar `npx nestforge` sem argumentos inicia o fluxo interativo completo. Também é possível informar parte da configuração e responder apenas às perguntas restantes:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx nestforge minha-api --orm prisma --database postgres
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Use `--yes` ou `--non-interactive` para gerar sem prompts. As opções omitidas usam os padrões documentados: TypeScript, Prisma, PostgreSQL, JWT, todos os recursos opcionais habilitados, controle de acesso habilitado e criação automática do `.env`.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx nestforge minha-api --yes
|
|
31
|
+
npx nestforge minha-api --non-interactive --orm drizzle --database sqlite --no-redis
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Comandos utilitários disponíveis:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx nestforge --help
|
|
38
|
+
npx nestforge --version
|
|
39
|
+
npx nestforge --list
|
|
40
|
+
npx nestforge --doctor
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
As flags de geração incluem `--language`, `--orm`, `--database`, `--auth`, `--docker`, `--swagger`, `--validation`, `--redis`, `--access-control` e `--env`. Recursos booleanos também aceitam a forma `--no-*` correspondente. Use `--no-update-check` para não consultar o registro e `--no-banner` para ocultar o banner.
|
|
44
|
+
|
|
45
|
+
Valores inválidos, toggles contraditórios e combinações não suportadas encerram a execução com erro, sem modificar silenciosamente a configuração solicitada.
|
|
46
|
+
|
|
47
|
+
## Verificação automática de atualizações
|
|
48
|
+
|
|
49
|
+
Quando a CLI inicia, ela consulta o registro do npm em busca de uma versão estável mais recente. Se houver uma atualização, você pode:
|
|
50
|
+
|
|
51
|
+
* baixar a versão mais recente com `npx` e reiniciar a CLI;
|
|
52
|
+
* continuar com a versão instalada atualmente;
|
|
53
|
+
* ocultar o lembrete até o próximo dia no horário local.
|
|
54
|
+
|
|
55
|
+
Os metadados do registro ficam em cache durante seis horas em `~/.nestforge/update-check.json`. Falhas de rede ou de cache são ignoradas para que o gerador continue disponível offline.
|
|
56
|
+
|
|
19
57
|
Para o guia de testes, perguntas da CLI e checklist completo, consulte [`TESTING.pt-BR.md`](TESTING.pt-BR.md).
|
|
20
58
|
|
|
21
59
|
## O que já funciona
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const CAPABILITIES = `
|
|
2
|
+
Supported NestForge combinations
|
|
3
|
+
|
|
4
|
+
Languages:
|
|
5
|
+
typescript, javascript
|
|
6
|
+
|
|
7
|
+
ORMs and databases:
|
|
8
|
+
prisma postgres, mysql, sqlite, mongodb
|
|
9
|
+
typeorm postgres, mysql, sqlite
|
|
10
|
+
drizzle postgres, mysql, sqlite
|
|
11
|
+
none no database
|
|
12
|
+
|
|
13
|
+
Authentication:
|
|
14
|
+
jwt, session, oauth, none
|
|
15
|
+
|
|
16
|
+
Projects without an ORM currently support only authentication "none".
|
|
17
|
+
MongoDB is currently available only with Prisma.
|
|
18
|
+
`.trim();
|
|
19
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;CAiB3B,CAAC,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { AUTH_STRATEGY_CHOICES, DATABASE_CHOICES, LANGUAGE_CHOICES, ORM_CHOICES, } from './options.js';
|
|
3
|
+
export function parseCliArguments(args) {
|
|
4
|
+
const { values, positionals } = parseArgs({
|
|
5
|
+
args,
|
|
6
|
+
allowPositionals: true,
|
|
7
|
+
strict: true,
|
|
8
|
+
options: {
|
|
9
|
+
help: { type: 'boolean', short: 'h' },
|
|
10
|
+
version: { type: 'boolean', short: 'V' },
|
|
11
|
+
list: { type: 'boolean' },
|
|
12
|
+
doctor: { type: 'boolean' },
|
|
13
|
+
name: { type: 'string' },
|
|
14
|
+
language: { type: 'string' },
|
|
15
|
+
orm: { type: 'string' },
|
|
16
|
+
database: { type: 'string' },
|
|
17
|
+
auth: { type: 'string' },
|
|
18
|
+
'non-interactive': { type: 'boolean' },
|
|
19
|
+
yes: { type: 'boolean', short: 'y' },
|
|
20
|
+
docker: { type: 'boolean' },
|
|
21
|
+
'no-docker': { type: 'boolean' },
|
|
22
|
+
swagger: { type: 'boolean' },
|
|
23
|
+
'no-swagger': { type: 'boolean' },
|
|
24
|
+
validation: { type: 'boolean' },
|
|
25
|
+
'no-validation': { type: 'boolean' },
|
|
26
|
+
redis: { type: 'boolean' },
|
|
27
|
+
'no-redis': { type: 'boolean' },
|
|
28
|
+
'access-control': { type: 'boolean' },
|
|
29
|
+
'no-access-control': { type: 'boolean' },
|
|
30
|
+
env: { type: 'boolean' },
|
|
31
|
+
'no-env': { type: 'boolean' },
|
|
32
|
+
'no-update-check': { type: 'boolean' },
|
|
33
|
+
'no-banner': { type: 'boolean' },
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const commands = [
|
|
37
|
+
values.help && 'help',
|
|
38
|
+
values.version && 'version',
|
|
39
|
+
values.list && 'list',
|
|
40
|
+
values.doctor && 'doctor',
|
|
41
|
+
].filter(Boolean);
|
|
42
|
+
if (commands.length > 1) {
|
|
43
|
+
throw new Error('Use only one command at a time: --help, --version, --list, or --doctor.');
|
|
44
|
+
}
|
|
45
|
+
if (positionals.length > 1) {
|
|
46
|
+
throw new Error('Only one positional project name is allowed.');
|
|
47
|
+
}
|
|
48
|
+
if (values.name && positionals[0] && values.name !== positionals[0]) {
|
|
49
|
+
throw new Error('The positional project name and --name must match when both are provided.');
|
|
50
|
+
}
|
|
51
|
+
const projectName = values.name ?? positionals[0];
|
|
52
|
+
return {
|
|
53
|
+
command: commands[0] ?? 'generate',
|
|
54
|
+
options: {
|
|
55
|
+
projectName,
|
|
56
|
+
language: parseChoice(values.language, LANGUAGE_CHOICES, '--language'),
|
|
57
|
+
orm: parseChoice(values.orm, ORM_CHOICES, '--orm'),
|
|
58
|
+
database: parseChoice(values.database, DATABASE_CHOICES, '--database'),
|
|
59
|
+
authStrategy: parseChoice(values.auth, AUTH_STRATEGY_CHOICES, '--auth'),
|
|
60
|
+
docker: readToggle(values, 'docker'),
|
|
61
|
+
swagger: readToggle(values, 'swagger'),
|
|
62
|
+
validation: readToggle(values, 'validation'),
|
|
63
|
+
redis: readToggle(values, 'redis'),
|
|
64
|
+
accessControl: readToggle(values, 'access-control'),
|
|
65
|
+
createEnv: readToggle(values, 'env'),
|
|
66
|
+
},
|
|
67
|
+
nonInteractive: Boolean(values['non-interactive'] || values.yes),
|
|
68
|
+
checkUpdates: values['no-update-check'] !== true,
|
|
69
|
+
showBanner: values['no-banner'] !== true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function readCliArgumentVector(args = process.argv.slice(2), restartedArgs = process.env.NESTFORGE_RESTART_ARGS) {
|
|
73
|
+
if (!restartedArgs) {
|
|
74
|
+
return args;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(restartedArgs);
|
|
78
|
+
if (Array.isArray(parsed) &&
|
|
79
|
+
parsed.every((argument) => typeof argument === 'string')) {
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Ignore malformed external environment values.
|
|
85
|
+
}
|
|
86
|
+
return args;
|
|
87
|
+
}
|
|
88
|
+
function readToggle(values, name) {
|
|
89
|
+
const enabled = values[name] === true;
|
|
90
|
+
const disabled = values[`no-${name}`] === true;
|
|
91
|
+
if (enabled && disabled) {
|
|
92
|
+
throw new Error(`Options --${name} and --no-${name} cannot be used together.`);
|
|
93
|
+
}
|
|
94
|
+
if (enabled)
|
|
95
|
+
return true;
|
|
96
|
+
if (disabled)
|
|
97
|
+
return false;
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
function parseChoice(value, choices, flag) {
|
|
101
|
+
if (value === undefined) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
if (!choices.includes(value)) {
|
|
105
|
+
throw new Error(`Invalid value for ${flag}: "${value}". Available values: ${choices.join(', ')}.`);
|
|
106
|
+
}
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=cli-arguments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-arguments.js","sourceRoot":"","sources":["../src/cli-arguments.ts"],"names":[],"mappings":"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"}
|
package/dist/cli-help.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const CLI_HELP = `
|
|
2
|
+
NestForge — generate production-ready NestJS projects
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
nestforge [project-name] [options]
|
|
6
|
+
nestforge --name <project-name> [options]
|
|
7
|
+
|
|
8
|
+
Commands:
|
|
9
|
+
-h, --help Show this help
|
|
10
|
+
-V, --version Show the installed version
|
|
11
|
+
--list List supported combinations
|
|
12
|
+
--doctor Check the local environment
|
|
13
|
+
|
|
14
|
+
Generation:
|
|
15
|
+
--language <value> typescript | javascript
|
|
16
|
+
--orm <value> prisma | typeorm | drizzle | none
|
|
17
|
+
--database <value> postgres | mysql | sqlite | mongodb | none
|
|
18
|
+
--auth <value> jwt | session | oauth | none
|
|
19
|
+
-y, --yes Generate non-interactively with defaults
|
|
20
|
+
--non-interactive Never open configuration prompts
|
|
21
|
+
|
|
22
|
+
Feature toggles:
|
|
23
|
+
--docker / --no-docker
|
|
24
|
+
--swagger / --no-swagger
|
|
25
|
+
--validation / --no-validation
|
|
26
|
+
--redis / --no-redis
|
|
27
|
+
--access-control / --no-access-control
|
|
28
|
+
--env / --no-env
|
|
29
|
+
|
|
30
|
+
Output and updates:
|
|
31
|
+
--no-banner Hide the NestForge banner
|
|
32
|
+
--no-update-check Skip the automatic update check
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
nestforge
|
|
36
|
+
nestforge my-api --orm prisma
|
|
37
|
+
nestforge my-api --yes
|
|
38
|
+
nestforge my-api --non-interactive --orm drizzle --database sqlite
|
|
39
|
+
`.trim();
|
|
40
|
+
//# sourceMappingURL=cli-help.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-help.js","sourceRoot":"","sources":["../src/cli-help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCvB,CAAC,IAAI,EAAE,CAAC"}
|
package/dist/doctor.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export async function runDoctorChecks() {
|
|
2
|
+
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
|
3
|
+
const checks = [
|
|
4
|
+
{
|
|
5
|
+
label: 'Node.js',
|
|
6
|
+
status: nodeMajor >= 20 ? 'pass' : 'fail',
|
|
7
|
+
detail: `v${process.versions.node} (NestForge requires Node.js 20 or newer)`,
|
|
8
|
+
},
|
|
9
|
+
];
|
|
10
|
+
try {
|
|
11
|
+
await access(process.cwd(), constants.W_OK);
|
|
12
|
+
checks.push({
|
|
13
|
+
label: 'Current directory',
|
|
14
|
+
status: 'pass',
|
|
15
|
+
detail: 'Writable',
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
checks.push({
|
|
20
|
+
label: 'Current directory',
|
|
21
|
+
status: 'fail',
|
|
22
|
+
detail: 'Not writable',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
checks.push(checkCommand('npm', ['--version'], false));
|
|
26
|
+
checks.push(checkCommand('Git', ['--version'], false, 'git'));
|
|
27
|
+
checks.push(checkCommand('Docker', ['--version'], true, 'docker'));
|
|
28
|
+
return {
|
|
29
|
+
checks,
|
|
30
|
+
healthy: checks.every((check) => check.status !== 'fail'),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function formatDoctorReport(report) {
|
|
34
|
+
const symbols = {
|
|
35
|
+
pass: '✓',
|
|
36
|
+
warning: '!',
|
|
37
|
+
fail: '✗',
|
|
38
|
+
};
|
|
39
|
+
return [
|
|
40
|
+
'NestForge doctor',
|
|
41
|
+
'',
|
|
42
|
+
...report.checks.map((check) => `${symbols[check.status]} ${check.label}: ${check.detail}`),
|
|
43
|
+
'',
|
|
44
|
+
report.healthy
|
|
45
|
+
? 'Environment ready.'
|
|
46
|
+
: 'Resolve the failed checks before generating a project.',
|
|
47
|
+
].join('\n');
|
|
48
|
+
}
|
|
49
|
+
function checkCommand(label, args, optional, command = label) {
|
|
50
|
+
if (process.platform === 'win32') {
|
|
51
|
+
const lookup = spawnSync('where.exe', [command], {
|
|
52
|
+
encoding: 'utf8',
|
|
53
|
+
windowsHide: true,
|
|
54
|
+
});
|
|
55
|
+
if (lookup.status === 0) {
|
|
56
|
+
return {
|
|
57
|
+
label,
|
|
58
|
+
status: 'pass',
|
|
59
|
+
detail: lookup.stdout.trim().split(/\r?\n/)[0],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
label,
|
|
64
|
+
status: optional ? 'warning' : 'fail',
|
|
65
|
+
detail: optional ? 'Not found (optional)' : 'Not found',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const result = spawnSync(command, args, {
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
windowsHide: true,
|
|
71
|
+
});
|
|
72
|
+
if (result.status === 0) {
|
|
73
|
+
return {
|
|
74
|
+
label,
|
|
75
|
+
status: 'pass',
|
|
76
|
+
detail: (result.stdout || result.stderr).trim(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
label,
|
|
81
|
+
status: optional ? 'warning' : 'fail',
|
|
82
|
+
detail: optional ? 'Not found (optional)' : 'Not found',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
import { constants } from 'node:fs';
|
|
86
|
+
import { access } from 'node:fs/promises';
|
|
87
|
+
import { spawnSync } from 'node:child_process';
|
|
88
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,56 @@ import pc from 'picocolors';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { runPrompts } from './prompts.js';
|
|
6
6
|
import { generateProject } from './generator.js';
|
|
7
|
+
import { handleUpdateNotification } from './update-notifier.js';
|
|
8
|
+
import { parseCliArguments, readCliArgumentVector } from './cli-arguments.js';
|
|
9
|
+
import { CLI_HELP } from './cli-help.js';
|
|
10
|
+
import { readPackageInfo } from './package-info.js';
|
|
11
|
+
import { CAPABILITIES } from './capabilities.js';
|
|
12
|
+
import { formatDoctorReport, runDoctorChecks } from './doctor.js';
|
|
13
|
+
import { resolveNonInteractiveOptions } from './project-options.js';
|
|
7
14
|
async function main() {
|
|
8
|
-
|
|
15
|
+
try {
|
|
16
|
+
await run();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
log.error(error instanceof Error ? error.message : String(error));
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function run() {
|
|
24
|
+
const cli = parseCliArguments(readCliArgumentVector());
|
|
25
|
+
if (cli.command === 'help') {
|
|
26
|
+
console.log(CLI_HELP);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (cli.command === 'version') {
|
|
30
|
+
const packageInfo = await readPackageInfo();
|
|
31
|
+
console.log(packageInfo.version);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (cli.command === 'list') {
|
|
35
|
+
console.log(CAPABILITIES);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (cli.command === 'doctor') {
|
|
39
|
+
const report = await runDoctorChecks();
|
|
40
|
+
console.log(formatDoctorReport(report));
|
|
41
|
+
if (!report.healthy) {
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const updateResult = cli.checkUpdates
|
|
47
|
+
? await handleUpdateNotification()
|
|
48
|
+
: 'continue';
|
|
49
|
+
if (updateResult === 'restarted') {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const options = cli.nonInteractive
|
|
53
|
+
? resolveNonInteractiveOptions(cli.options)
|
|
54
|
+
: await runPrompts(cli.options, {
|
|
55
|
+
showBanner: cli.showBanner,
|
|
56
|
+
});
|
|
9
57
|
try {
|
|
10
58
|
const targetDir = await generateProject(options);
|
|
11
59
|
const relativeDir = path.relative(process.cwd(), targetDir) || '.';
|
|
@@ -67,7 +115,7 @@ async function main() {
|
|
|
67
115
|
}
|
|
68
116
|
catch (error) {
|
|
69
117
|
log.error(error instanceof Error ? error.message : String(error));
|
|
70
|
-
process.
|
|
118
|
+
process.exitCode = 1;
|
|
71
119
|
}
|
|
72
120
|
}
|
|
73
121
|
main();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const LANGUAGE_CHOICES = ['typescript', 'javascript'];
|
|
2
|
+
export const ORM_CHOICES = ['prisma', 'typeorm', 'drizzle', 'none'];
|
|
3
|
+
export const DATABASE_CHOICES = ['postgres', 'mysql', 'sqlite', 'mongodb', 'none'];
|
|
4
|
+
export const AUTH_STRATEGY_CHOICES = ['jwt', 'session', 'oauth', 'none'];
|
|
5
|
+
export const FEATURE_NAMES = ['docker', 'swagger', 'validation', 'redis'];
|
|
6
|
+
export const DEFAULT_PROJECT_OPTIONS = {
|
|
7
|
+
language: 'typescript',
|
|
8
|
+
orm: 'prisma',
|
|
9
|
+
database: 'postgres',
|
|
10
|
+
docker: true,
|
|
11
|
+
swagger: true,
|
|
12
|
+
validation: true,
|
|
13
|
+
redis: true,
|
|
14
|
+
authStrategy: 'jwt',
|
|
15
|
+
accessControl: true,
|
|
16
|
+
createEnv: true,
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AA8BA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,YAAY,EAAE,YAAY,CAAU,CAAC;AACtE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAC7E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAC5F,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAU,CAAC;AAElF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,CAAU,CAAC;AAGnF,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACnC,QAAQ,EAAE,YAAY;IACtB,GAAG,EAAE,QAAQ;IACb,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,IAAI;IACX,YAAY,EAAE,KAAK;IACnB,aAAa,EAAE,IAAI;IACnB,SAAS,EAAE,IAAI;CACyC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
const packageJsonPath = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
4
|
+
export async function readPackageInfo() {
|
|
5
|
+
const manifest = (await fs.readJson(packageJsonPath));
|
|
6
|
+
if (typeof manifest.name !== 'string' ||
|
|
7
|
+
typeof manifest.version !== 'string') {
|
|
8
|
+
throw new Error('Unable to read the NestForge package information.');
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
name: manifest.name,
|
|
12
|
+
version: manifest.version,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=package-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-info.js","sourceRoot":"","sources":["../src/package-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,UAAU,CAAC;AAO1B,MAAM,eAAe,GAAG,aAAa,CACjC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAC9C,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,eAAe;IAIjC,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAC/B,eAAe,CAClB,CAAoB,CAAC;IAEtB,IACI,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QACjC,OAAO,QAAQ,CAAC,OAAO,KAAK,QAAQ,EACtC,CAAC;QACC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO;QACH,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,OAAO,EAAE,QAAQ,CAAC,OAAO;KAC5B,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DEFAULT_PROJECT_OPTIONS, } from './options.js';
|
|
2
|
+
export function buildFeatureList(options) {
|
|
3
|
+
return [
|
|
4
|
+
options.docker && 'docker',
|
|
5
|
+
options.swagger && 'swagger',
|
|
6
|
+
options.validation && 'validation',
|
|
7
|
+
options.redis && 'redis',
|
|
8
|
+
].filter((feature) => Boolean(feature));
|
|
9
|
+
}
|
|
10
|
+
export function assertCompatibleOptionInput(input) {
|
|
11
|
+
if (input.orm === 'none' && input.database && input.database !== 'none') {
|
|
12
|
+
throw new Error('Projects without an ORM must use "none" as their database option.');
|
|
13
|
+
}
|
|
14
|
+
if (input.orm === 'none' && input.authStrategy && input.authStrategy !== 'none') {
|
|
15
|
+
throw new Error('Projects without an ORM currently support only the "none" authentication strategy.');
|
|
16
|
+
}
|
|
17
|
+
if (input.orm === 'none' && input.accessControl === true) {
|
|
18
|
+
throw new Error('Access control is not available without an ORM.');
|
|
19
|
+
}
|
|
20
|
+
if (input.database === 'mongodb' && input.orm && input.orm !== 'prisma') {
|
|
21
|
+
throw new Error('MongoDB is currently available only with Prisma.');
|
|
22
|
+
}
|
|
23
|
+
if (input.authStrategy === 'none' && input.accessControl === true) {
|
|
24
|
+
throw new Error('Access control requires an authentication strategy.');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function resolveNonInteractiveOptions(input) {
|
|
28
|
+
assertCompatibleOptionInput(input);
|
|
29
|
+
if (!input.projectName) {
|
|
30
|
+
throw new Error('A project name is required in non-interactive mode.');
|
|
31
|
+
}
|
|
32
|
+
const orm = input.orm ?? DEFAULT_PROJECT_OPTIONS.orm;
|
|
33
|
+
const database = orm === 'none'
|
|
34
|
+
? 'none'
|
|
35
|
+
: input.database ?? DEFAULT_PROJECT_OPTIONS.database;
|
|
36
|
+
const authStrategy = orm === 'none'
|
|
37
|
+
? 'none'
|
|
38
|
+
: input.authStrategy ?? DEFAULT_PROJECT_OPTIONS.authStrategy;
|
|
39
|
+
const accessControl = authStrategy === 'none'
|
|
40
|
+
? false
|
|
41
|
+
: input.accessControl ?? DEFAULT_PROJECT_OPTIONS.accessControl;
|
|
42
|
+
const featureInput = {
|
|
43
|
+
docker: input.docker ?? DEFAULT_PROJECT_OPTIONS.docker,
|
|
44
|
+
swagger: input.swagger ?? DEFAULT_PROJECT_OPTIONS.swagger,
|
|
45
|
+
validation: input.validation ?? DEFAULT_PROJECT_OPTIONS.validation,
|
|
46
|
+
redis: input.redis ?? DEFAULT_PROJECT_OPTIONS.redis,
|
|
47
|
+
};
|
|
48
|
+
const resolved = {
|
|
49
|
+
projectName: input.projectName,
|
|
50
|
+
language: input.language ?? DEFAULT_PROJECT_OPTIONS.language,
|
|
51
|
+
orm,
|
|
52
|
+
database,
|
|
53
|
+
features: buildFeatureList(featureInput),
|
|
54
|
+
authStrategy,
|
|
55
|
+
accessControl,
|
|
56
|
+
createEnv: input.createEnv ?? DEFAULT_PROJECT_OPTIONS.createEnv,
|
|
57
|
+
};
|
|
58
|
+
assertCompatibleOptionInput({
|
|
59
|
+
...input,
|
|
60
|
+
orm: resolved.orm,
|
|
61
|
+
database: resolved.database,
|
|
62
|
+
authStrategy: resolved.authStrategy,
|
|
63
|
+
accessControl: resolved.accessControl,
|
|
64
|
+
});
|
|
65
|
+
return resolved;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=project-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-options.js","sourceRoot":"","sources":["../src/project-options.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,GAG1B,MAAM,cAAc,CAAC;AAEtB,MAAM,UAAU,gBAAgB,CAC5B,OAAgF;IAEhF,OAAO;QACH,OAAO,CAAC,MAAM,IAAI,QAAQ;QAC1B,OAAO,CAAC,OAAO,IAAI,SAAS;QAC5B,OAAO,CAAC,UAAU,IAAI,YAAY;QAClC,OAAO,CAAC,KAAK,IAAI,OAAO;KAC3B,CAAC,MAAM,CAAC,CAAC,OAAO,EAAqB,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,KAAyB;IACjE,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACzF,CAAC;IAED,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;QAC9E,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;IAC1G,CAAC;IAED,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,KAAK,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,KAAyB;IAClE,2BAA2B,CAAC,KAAK,CAAC,CAAC;IAEnC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,uBAAuB,CAAC,GAAG,CAAC;IACrD,MAAM,QAAQ,GAAG,GAAG,KAAK,MAAM;QAC3B,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,uBAAuB,CAAC,QAAQ,CAAC;IACzD,MAAM,YAAY,GAAG,GAAG,KAAK,MAAM;QAC/B,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,KAAK,CAAC,YAAY,IAAI,uBAAuB,CAAC,YAAY,CAAC;IACjE,MAAM,aAAa,GAAG,YAAY,KAAK,MAAM;QACzC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,uBAAuB,CAAC,aAAa,CAAC;IAEnE,MAAM,YAAY,GAAG;QACjB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,uBAAuB,CAAC,MAAM;QACtD,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,uBAAuB,CAAC,OAAO;QACzD,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,uBAAuB,CAAC,UAAU;QAClE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,uBAAuB,CAAC,KAAK;KACtD,CAAC;IAEF,MAAM,QAAQ,GAAmB;QAC7B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,uBAAuB,CAAC,QAAQ;QAC5D,GAAG;QACH,QAAQ;QACR,QAAQ,EAAE,gBAAgB,CAAC,YAAY,CAAC;QACxC,YAAY;QACZ,aAAa;QACb,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,uBAAuB,CAAC,SAAS;KAClE,CAAC;IAEF,2BAA2B,CAAC;QACxB,GAAG,KAAK;QACR,GAAG,EAAE,QAAQ,CAAC,GAAG;QACjB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,aAAa,EAAE,QAAQ,CAAC,aAAa;KACxC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AACpB,CAAC"}
|
package/dist/prompts.js
CHANGED
|
@@ -2,6 +2,7 @@ import { intro, outro, text, select, confirm, isCancel, cancel } from '@clack/pr
|
|
|
2
2
|
import gradient from 'gradient-string';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
4
|
import { validateProjectName } from './project-name.js';
|
|
5
|
+
import { assertCompatibleOptionInput } from './project-options.js';
|
|
5
6
|
// red -> orange, the NestJS colors
|
|
6
7
|
const nestforgeGradient = gradient(['#e0234e', '#ff8a65']);
|
|
7
8
|
const logo = [
|
|
@@ -25,11 +26,14 @@ function handleCancel(value) {
|
|
|
25
26
|
process.exit(0);
|
|
26
27
|
}
|
|
27
28
|
}
|
|
28
|
-
export async function runPrompts() {
|
|
29
|
-
|
|
29
|
+
export async function runPrompts(initial = {}, settings = {}) {
|
|
30
|
+
assertCompatibleOptionInput(initial);
|
|
31
|
+
if (settings.showBanner !== false) {
|
|
32
|
+
showBanner();
|
|
33
|
+
}
|
|
30
34
|
intro(pc.bgMagenta(pc.black(' NestForge ')));
|
|
31
35
|
// 1. Project name
|
|
32
|
-
const projectName = await text({
|
|
36
|
+
const projectName = initial.projectName ?? await text({
|
|
33
37
|
message: 'What is your project name?',
|
|
34
38
|
placeholder: 'my-nest-api',
|
|
35
39
|
defaultValue: 'my-nest-api',
|
|
@@ -37,7 +41,7 @@ export async function runPrompts() {
|
|
|
37
41
|
});
|
|
38
42
|
handleCancel(projectName);
|
|
39
43
|
// 2. Language
|
|
40
|
-
const language = await select({
|
|
44
|
+
const language = initial.language ?? await select({
|
|
41
45
|
message: 'TypeScript or JavaScript?',
|
|
42
46
|
options: [
|
|
43
47
|
{ value: 'typescript', label: 'TypeScript', hint: 'Recommended' },
|
|
@@ -46,7 +50,7 @@ export async function runPrompts() {
|
|
|
46
50
|
});
|
|
47
51
|
handleCancel(language);
|
|
48
52
|
// 3. ORM selection
|
|
49
|
-
const orm = await select({
|
|
53
|
+
const orm = initial.orm ?? await select({
|
|
50
54
|
message: 'Choose the ORM/Query Builder:',
|
|
51
55
|
options: [
|
|
52
56
|
{ value: 'prisma', label: 'Prisma', hint: 'Recommended' },
|
|
@@ -57,8 +61,8 @@ export async function runPrompts() {
|
|
|
57
61
|
});
|
|
58
62
|
handleCancel(orm);
|
|
59
63
|
// 4. Database
|
|
60
|
-
let database = 'none';
|
|
61
|
-
if (orm !== 'none') {
|
|
64
|
+
let database = initial.database ?? 'none';
|
|
65
|
+
if (orm !== 'none' && initial.database === undefined) {
|
|
62
66
|
const databaseSelection = await select({
|
|
63
67
|
message: 'Which database do you want to use?',
|
|
64
68
|
options: [
|
|
@@ -75,28 +79,28 @@ export async function runPrompts() {
|
|
|
75
79
|
}
|
|
76
80
|
// 5. Additional features (one yes/no prompt at a time)
|
|
77
81
|
const features = [];
|
|
78
|
-
const wantsDocker = await confirm({
|
|
82
|
+
const wantsDocker = initial.docker ?? await confirm({
|
|
79
83
|
message: 'Do you want to add Docker?',
|
|
80
84
|
initialValue: true,
|
|
81
85
|
});
|
|
82
86
|
handleCancel(wantsDocker);
|
|
83
87
|
if (wantsDocker)
|
|
84
88
|
features.push('docker');
|
|
85
|
-
const wantsSwagger = await confirm({
|
|
89
|
+
const wantsSwagger = initial.swagger ?? await confirm({
|
|
86
90
|
message: 'Do you want to include Swagger/OpenAPI documentation?',
|
|
87
91
|
initialValue: true,
|
|
88
92
|
});
|
|
89
93
|
handleCancel(wantsSwagger);
|
|
90
94
|
if (wantsSwagger)
|
|
91
95
|
features.push('swagger');
|
|
92
|
-
const wantsValidation = await confirm({
|
|
96
|
+
const wantsValidation = initial.validation ?? await confirm({
|
|
93
97
|
message: 'Do you want to enable global validation with Zod?',
|
|
94
98
|
initialValue: true,
|
|
95
99
|
});
|
|
96
100
|
handleCancel(wantsValidation);
|
|
97
101
|
if (wantsValidation)
|
|
98
102
|
features.push('validation');
|
|
99
|
-
const wantsRedis = await confirm({
|
|
103
|
+
const wantsRedis = initial.redis ?? await confirm({
|
|
100
104
|
message: 'Do you want to include Redis (cache/queues + email through BullMQ)?',
|
|
101
105
|
initialValue: true,
|
|
102
106
|
});
|
|
@@ -104,8 +108,8 @@ export async function runPrompts() {
|
|
|
104
108
|
if (wantsRedis)
|
|
105
109
|
features.push('redis');
|
|
106
110
|
// 6. Authentication strategy
|
|
107
|
-
let authStrategy = 'none';
|
|
108
|
-
if (orm !== 'none') {
|
|
111
|
+
let authStrategy = initial.authStrategy ?? 'none';
|
|
112
|
+
if (orm !== 'none' && initial.authStrategy === undefined) {
|
|
109
113
|
const authStrategySelection = await select({
|
|
110
114
|
message: 'Which authentication strategy do you want to use?',
|
|
111
115
|
options: [
|
|
@@ -119,8 +123,8 @@ export async function runPrompts() {
|
|
|
119
123
|
authStrategy = authStrategySelection;
|
|
120
124
|
}
|
|
121
125
|
// 7. Access control (only applicable when authentication is enabled)
|
|
122
|
-
let accessControl = false;
|
|
123
|
-
if (authStrategy !== 'none') {
|
|
126
|
+
let accessControl = initial.accessControl ?? false;
|
|
127
|
+
if (authStrategy !== 'none' && initial.accessControl === undefined) {
|
|
124
128
|
const wantsAccessControl = await confirm({
|
|
125
129
|
message: '🛡️ Do you want to include access control (RBAC + Permissions)?',
|
|
126
130
|
initialValue: true,
|
|
@@ -129,7 +133,7 @@ export async function runPrompts() {
|
|
|
129
133
|
accessControl = wantsAccessControl;
|
|
130
134
|
}
|
|
131
135
|
// 8. Automatic .env creation
|
|
132
|
-
const createEnv = await confirm({
|
|
136
|
+
const createEnv = initial.createEnv ?? await confirm({
|
|
133
137
|
message: 'Do you want to create the .env file automatically (from .env.example)?',
|
|
134
138
|
initialValue: true,
|
|
135
139
|
});
|
package/dist/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACvF,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import semver from 'semver';
|
|
5
|
+
const REGISTRY_URL = 'https://registry.npmjs.org/nestforge-generator/latest';
|
|
6
|
+
const CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
7
|
+
const REQUEST_TIMEOUT_MS = 2_000;
|
|
8
|
+
export function getUpdateCachePath() {
|
|
9
|
+
return path.join(os.homedir(), '.nestforge', 'update-check.json');
|
|
10
|
+
}
|
|
11
|
+
async function readCache(cachePath) {
|
|
12
|
+
try {
|
|
13
|
+
const cache = (await fs.readJson(cachePath));
|
|
14
|
+
return cache && typeof cache === 'object' ? cache : {};
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function writeCache(cachePath, cache) {
|
|
21
|
+
await fs.outputJson(cachePath, cache, { spaces: 2 });
|
|
22
|
+
}
|
|
23
|
+
async function fetchLatestVersion(fetchImplementation) {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetchImplementation(REGISTRY_URL, {
|
|
28
|
+
headers: {
|
|
29
|
+
accept: 'application/json',
|
|
30
|
+
},
|
|
31
|
+
signal: controller.signal,
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(`The npm registry returned ${response.status}.`);
|
|
35
|
+
}
|
|
36
|
+
const metadata = (await response.json());
|
|
37
|
+
if (typeof metadata.version !== 'string' ||
|
|
38
|
+
!semver.valid(metadata.version)) {
|
|
39
|
+
throw new Error('The npm registry returned an invalid version.');
|
|
40
|
+
}
|
|
41
|
+
return metadata.version;
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export async function checkForUpdate(currentVersion, options = {}) {
|
|
48
|
+
if (!semver.valid(currentVersion)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const now = options.now ?? Date.now();
|
|
52
|
+
const cachePath = options.cachePath ?? getUpdateCachePath();
|
|
53
|
+
try {
|
|
54
|
+
const cache = await readCache(cachePath);
|
|
55
|
+
if (typeof cache.dismissedUntil === 'number' &&
|
|
56
|
+
cache.dismissedUntil > now) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const hasFreshCache = typeof cache.checkedAt === 'number' &&
|
|
60
|
+
typeof cache.latestVersion === 'string' &&
|
|
61
|
+
now - cache.checkedAt < CHECK_INTERVAL_MS &&
|
|
62
|
+
semver.valid(cache.latestVersion);
|
|
63
|
+
const latestVersion = hasFreshCache
|
|
64
|
+
? cache.latestVersion
|
|
65
|
+
: await fetchLatestVersion(options.fetchImplementation ?? fetch);
|
|
66
|
+
if (!hasFreshCache) {
|
|
67
|
+
try {
|
|
68
|
+
await writeCache(cachePath, {
|
|
69
|
+
...cache,
|
|
70
|
+
checkedAt: now,
|
|
71
|
+
latestVersion,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// The update can still be offered without a writable cache.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return semver.gt(latestVersion, currentVersion)
|
|
79
|
+
? { currentVersion, latestVersion }
|
|
80
|
+
: null;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export async function dismissUpdatesForToday(options = {}) {
|
|
87
|
+
const now = options.now ?? Date.now();
|
|
88
|
+
const cachePath = options.cachePath ?? getUpdateCachePath();
|
|
89
|
+
const tomorrow = new Date(now);
|
|
90
|
+
tomorrow.setHours(24, 0, 0, 0);
|
|
91
|
+
try {
|
|
92
|
+
const cache = await readCache(cachePath);
|
|
93
|
+
await writeCache(cachePath, {
|
|
94
|
+
...cache,
|
|
95
|
+
dismissedUntil: tomorrow.getTime(),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// A cache failure must never prevent the CLI from starting.
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=update-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.js","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { isCancel, log, note, select } from '@clack/prompts';
|
|
3
|
+
import pc from 'picocolors';
|
|
4
|
+
import { readPackageInfo } from './package-info.js';
|
|
5
|
+
import { checkForUpdate, dismissUpdatesForToday, } from './update-check.js';
|
|
6
|
+
export function getUpdateProcess(platform = process.platform) {
|
|
7
|
+
if (platform === 'win32') {
|
|
8
|
+
return {
|
|
9
|
+
command: process.env.ComSpec ?? 'cmd.exe',
|
|
10
|
+
args: [
|
|
11
|
+
'/d',
|
|
12
|
+
'/s',
|
|
13
|
+
'/c',
|
|
14
|
+
'npx --yes nestforge-generator@latest',
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
command: 'npx',
|
|
20
|
+
args: ['--yes', 'nestforge-generator@latest'],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export async function runLatestVersion() {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
const updateProcess = getUpdateProcess();
|
|
26
|
+
const child = spawn(updateProcess.command, updateProcess.args, {
|
|
27
|
+
stdio: 'inherit',
|
|
28
|
+
shell: false,
|
|
29
|
+
env: {
|
|
30
|
+
...process.env,
|
|
31
|
+
NESTFORGE_RESTART_ARGS: JSON.stringify(process.argv.slice(2)),
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
let settled = false;
|
|
35
|
+
const finish = (success) => {
|
|
36
|
+
if (settled) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
settled = true;
|
|
40
|
+
resolve(success);
|
|
41
|
+
};
|
|
42
|
+
child.once('error', () => finish(false));
|
|
43
|
+
child.once('exit', (code) => finish(code === 0));
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function promptForUpdate(update) {
|
|
47
|
+
note(`${pc.dim(update.currentVersion)} ${pc.dim('→')} ${pc.green(update.latestVersion)}`, 'NestForge update available');
|
|
48
|
+
const choice = await select({
|
|
49
|
+
message: 'How would you like to continue?',
|
|
50
|
+
options: [
|
|
51
|
+
{
|
|
52
|
+
value: 'update',
|
|
53
|
+
label: 'Update and restart',
|
|
54
|
+
hint: 'Recommended',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
value: 'continue',
|
|
58
|
+
label: `Continue with version ${update.currentVersion}`,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
value: 'dismiss-today',
|
|
62
|
+
label: "Don't remind me today",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
return isCancel(choice) ? 'continue' : choice;
|
|
67
|
+
}
|
|
68
|
+
export async function handleUpdateNotification(options = {}) {
|
|
69
|
+
try {
|
|
70
|
+
const packageInfo = await (options.readCurrentPackage ?? readPackageInfo)();
|
|
71
|
+
const update = await (options.check ?? checkForUpdate)(packageInfo.version);
|
|
72
|
+
if (!update) {
|
|
73
|
+
return 'continue';
|
|
74
|
+
}
|
|
75
|
+
const choice = await (options.prompt ?? promptForUpdate)(update);
|
|
76
|
+
if (choice === 'dismiss-today') {
|
|
77
|
+
await (options.dismiss ?? dismissUpdatesForToday)();
|
|
78
|
+
return 'continue';
|
|
79
|
+
}
|
|
80
|
+
if (choice === 'continue') {
|
|
81
|
+
return 'continue';
|
|
82
|
+
}
|
|
83
|
+
log.info('Downloading the latest NestForge version...');
|
|
84
|
+
const updated = await (options.runLatest ?? runLatestVersion)();
|
|
85
|
+
if (updated) {
|
|
86
|
+
return 'restarted';
|
|
87
|
+
}
|
|
88
|
+
log.warn('The update could not be started. Continuing with the current version.');
|
|
89
|
+
return 'continue';
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return 'continue';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=update-notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-notifier.js","sourceRoot":"","sources":["../src/update-notifier.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nestforge-generator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Interactive CLI for generating a NestJS project from a NestForge starter template",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"build": "tsc -p tsconfig.json && npm run copy:templates",
|
|
20
20
|
"copy:templates": "node scripts/copy-templates.mjs",
|
|
21
21
|
"dev": "tsx src/index.ts",
|
|
22
|
-
"test": "tsx --test test/generator.test.ts",
|
|
22
|
+
"test": "tsx --test test/generator.test.ts test/update-check.test.ts test/cli-arguments.test.ts test/project-options.test.ts",
|
|
23
23
|
"lint": "eslint \"src/**/*.ts\" --fix",
|
|
24
24
|
"prepack": "npm run build",
|
|
25
25
|
"prepublishOnly": "npm test"
|
|
@@ -48,15 +48,17 @@
|
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@clack/prompts": "^0.9.0",
|
|
51
|
-
"picocolors": "^1.1.0",
|
|
52
51
|
"fs-extra": "^11.2.0",
|
|
53
52
|
"gradient-string": "^2.0.2",
|
|
53
|
+
"picocolors": "^1.1.0",
|
|
54
|
+
"semver": "^7.8.5",
|
|
54
55
|
"typescript": "^5.6.0"
|
|
55
56
|
},
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@types/fs-extra": "^11.0.4",
|
|
58
|
-
"@types/node": "^22.0.0",
|
|
59
59
|
"@types/gradient-string": "^1.1.6",
|
|
60
|
+
"@types/node": "^22.0.0",
|
|
61
|
+
"@types/semver": "^7.8.0",
|
|
60
62
|
"tsx": "^4.19.0"
|
|
61
63
|
},
|
|
62
64
|
"engines": {
|