devstarter-tool 0.2.0 → 0.2.2
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 +72 -27
- package/dist/cli.js +1 -1
- package/dist/commands/init/collector.js +28 -19
- package/dist/generators/createMonorepo.js +13 -13
- package/dist/generators/createProject.js +9 -6
- package/dist/prompts/initPrompts.js +4 -12
- package/dist/types/project.js +1 -1
- package/dist/utils/installDependencies.js +8 -0
- package/dist/utils/printDryRun.js +1 -2
- package/dist/utils/printSummary.js +1 -3
- package/dist/utils/setupVitest.js +31 -0
- package/package.json +4 -2
- package/dist/utils/injectVitest.js +0 -68
package/README.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
CLI to generate projects with best practices and predefined configurations.
|
|
4
4
|
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Project structures**: Basic (single project) or Monorepo (full-stack)
|
|
8
|
+
- **Automatic dependency installation**: No need to run `npm install` manually
|
|
9
|
+
- **Vitest integration**: Optional testing setup with one flag
|
|
10
|
+
- **Package manager detection**: Automatically uses npm, pnpm, or yarn
|
|
11
|
+
- **Git initialization**: Optional repository setup
|
|
12
|
+
- **Interactive prompts**: Guided project creation
|
|
13
|
+
- **Dry-run mode**: Preview changes before creating files
|
|
14
|
+
|
|
5
15
|
## Installation
|
|
6
16
|
|
|
7
17
|
```bash
|
|
@@ -14,12 +24,26 @@ Or run directly with npx:
|
|
|
14
24
|
npx devstarter-tool init my-app
|
|
15
25
|
```
|
|
16
26
|
|
|
17
|
-
##
|
|
27
|
+
## Quick Start
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
```bash
|
|
30
|
+
# Interactive mode - guided setup
|
|
31
|
+
devstarter init
|
|
32
|
+
|
|
33
|
+
# Quick project with defaults
|
|
34
|
+
devstarter init my-app -y
|
|
35
|
+
|
|
36
|
+
# Frontend project with Vitest
|
|
37
|
+
devstarter init my-app --type frontend --vitest
|
|
38
|
+
|
|
39
|
+
# Preview without creating files
|
|
40
|
+
devstarter init my-app --dry-run
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
20
44
|
|
|
21
45
|
```bash
|
|
22
|
-
devstarter init [project-name]
|
|
46
|
+
devstarter init [project-name] [options]
|
|
23
47
|
```
|
|
24
48
|
|
|
25
49
|
### Options
|
|
@@ -28,7 +52,9 @@ devstarter init [project-name]
|
|
|
28
52
|
|--------|-------------|
|
|
29
53
|
| `-y, --yes` | Use default values without prompting |
|
|
30
54
|
| `-t, --type <type>` | Project type: `frontend` or `backend` |
|
|
31
|
-
| `--template <name>` | Template to use |
|
|
55
|
+
| `--template <name>` | Template to use (e.g., `basic`, `react`) |
|
|
56
|
+
| `--vitest` | Add Vitest for testing |
|
|
57
|
+
| `--no-git` | Skip Git repository initialization |
|
|
32
58
|
| `--dry-run` | Preview changes without creating files |
|
|
33
59
|
|
|
34
60
|
### Examples
|
|
@@ -40,11 +66,17 @@ devstarter init
|
|
|
40
66
|
# Create project with specific name
|
|
41
67
|
devstarter init my-app
|
|
42
68
|
|
|
43
|
-
#
|
|
69
|
+
# Frontend with React template
|
|
70
|
+
devstarter init my-app --type frontend --template react
|
|
71
|
+
|
|
72
|
+
# Backend with testing setup
|
|
73
|
+
devstarter init my-api --type backend --vitest
|
|
74
|
+
|
|
75
|
+
# Quick frontend with all defaults
|
|
44
76
|
devstarter init my-app --type frontend -y
|
|
45
77
|
|
|
46
|
-
#
|
|
47
|
-
devstarter init my-app --
|
|
78
|
+
# Create without Git
|
|
79
|
+
devstarter init my-app --no-git
|
|
48
80
|
```
|
|
49
81
|
|
|
50
82
|
## Project Structures
|
|
@@ -54,10 +86,12 @@ devstarter init my-app --type frontend --dry-run
|
|
|
54
86
|
```
|
|
55
87
|
my-app/
|
|
56
88
|
├── src/
|
|
57
|
-
│ └── main.ts
|
|
89
|
+
│ └── main.ts
|
|
58
90
|
├── package.json
|
|
59
|
-
├──
|
|
60
|
-
|
|
91
|
+
├── tsconfig.json
|
|
92
|
+
├── vitest.config.ts # if --vitest
|
|
93
|
+
├── node_modules/
|
|
94
|
+
└── .git/ # if git initialized
|
|
61
95
|
```
|
|
62
96
|
|
|
63
97
|
### Monorepo (full-stack)
|
|
@@ -65,10 +99,16 @@ my-app/
|
|
|
65
99
|
```
|
|
66
100
|
my-app/
|
|
67
101
|
├── apps/
|
|
68
|
-
│ ├── web/
|
|
69
|
-
│
|
|
102
|
+
│ ├── web/ # frontend template
|
|
103
|
+
│ │ ├── src/
|
|
104
|
+
│ │ ├── package.json
|
|
105
|
+
│ │ └── vitest.config.ts
|
|
106
|
+
│ └── api/ # backend template
|
|
107
|
+
│ ├── src/
|
|
108
|
+
│ ├── package.json
|
|
109
|
+
│ └── vitest.config.ts
|
|
70
110
|
├── packages/
|
|
71
|
-
│ └── shared/
|
|
111
|
+
│ └── shared/ # shared code
|
|
72
112
|
├── package.json
|
|
73
113
|
├── pnpm-workspace.yaml
|
|
74
114
|
├── tsconfig.base.json
|
|
@@ -81,7 +121,7 @@ my-app/
|
|
|
81
121
|
|
|
82
122
|
| Template | Description |
|
|
83
123
|
|----------|-------------|
|
|
84
|
-
| `basic` |
|
|
124
|
+
| `basic` | Vite + TypeScript |
|
|
85
125
|
| `react` | React 18 + Vite + TypeScript |
|
|
86
126
|
|
|
87
127
|
### Backend
|
|
@@ -90,24 +130,29 @@ my-app/
|
|
|
90
130
|
|----------|-------------|
|
|
91
131
|
| `basic` | Express + TypeScript |
|
|
92
132
|
|
|
93
|
-
##
|
|
133
|
+
## Vitest Integration
|
|
94
134
|
|
|
95
|
-
|
|
96
|
-
- Automatic package manager detection (npm, pnpm, yarn)
|
|
97
|
-
- Interactive template selection
|
|
98
|
-
- Optional Git repository initialization
|
|
99
|
-
- Dry-run mode to preview changes
|
|
100
|
-
- Automatic project name normalization (kebab-case)
|
|
101
|
-
- Colored output for better readability
|
|
135
|
+
When using `--vitest`, the CLI adds:
|
|
102
136
|
|
|
103
|
-
|
|
137
|
+
- `vitest` as a dev dependency
|
|
138
|
+
- `vitest.config.ts` with basic configuration
|
|
139
|
+
- `test` and `test:run` scripts in package.json
|
|
104
140
|
|
|
105
|
-
|
|
141
|
+
```bash
|
|
142
|
+
# Create project with Vitest
|
|
143
|
+
devstarter init my-app --vitest
|
|
144
|
+
|
|
145
|
+
# Then run tests
|
|
146
|
+
cd my-app
|
|
147
|
+
npm test
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Requirements
|
|
106
151
|
|
|
107
152
|
- Node.js 18+
|
|
108
|
-
- npm, pnpm or yarn
|
|
153
|
+
- npm, pnpm, or yarn
|
|
109
154
|
|
|
110
|
-
|
|
155
|
+
## Development
|
|
111
156
|
|
|
112
157
|
```bash
|
|
113
158
|
# Clone repository
|
|
@@ -124,7 +169,7 @@ npm run build
|
|
|
124
169
|
node dist/cli.js init test-app --dry-run
|
|
125
170
|
```
|
|
126
171
|
|
|
127
|
-
###
|
|
172
|
+
### Scripts
|
|
128
173
|
|
|
129
174
|
| Script | Description |
|
|
130
175
|
|--------|-------------|
|
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,6 @@ program
|
|
|
14
14
|
.option('--template <name>', 'Template variant (e.g. basic, react)')
|
|
15
15
|
.option('--dry-run', 'Show what would be generated without creating files')
|
|
16
16
|
.option('--no-git', 'Skip git repository initialization')
|
|
17
|
-
.option('--
|
|
17
|
+
.option('--vitest', 'Add Vitest for testing')
|
|
18
18
|
.action(initCommand);
|
|
19
19
|
program.parse(process.argv);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_INIT_OPTIONS } from '../../types/project.js';
|
|
2
|
-
import { askProjectName, askProjectStructure, askInitQuestions, askTemplate, askInitGit,
|
|
2
|
+
import { askProjectName, askProjectStructure, askInitQuestions, askTemplate, askInitGit, askUseVitest, } from '../../prompts/initPrompts.js';
|
|
3
3
|
import { normalizeProjectName } from '../../utils/normalize.js';
|
|
4
4
|
import { detectPackageManager } from '../../utils/detectPackageManager.js';
|
|
5
5
|
import { listTemplates } from '../../utils/listTemplate.js';
|
|
@@ -40,38 +40,45 @@ async function collectStructure(useDefaults) {
|
|
|
40
40
|
async function collectBasicContext(projectName, options, useDefaults) {
|
|
41
41
|
const typeFromFlag = resolveProjectType(options.type);
|
|
42
42
|
const gitFlagProvided = options.git !== undefined;
|
|
43
|
-
|
|
44
|
-
// Obtener tipo de proyecto, initGit e includeVitest
|
|
43
|
+
// Obtener tipo de proyecto e initGit
|
|
45
44
|
let projectType;
|
|
46
45
|
let initGit;
|
|
47
|
-
let includeVitest;
|
|
48
46
|
if (useDefaults) {
|
|
49
47
|
projectType = typeFromFlag ?? DEFAULT_INIT_OPTIONS.projectType;
|
|
50
48
|
initGit = gitFlagProvided ? options.git : DEFAULT_INIT_OPTIONS.initGit;
|
|
51
|
-
includeVitest = vitestFlagProvided ? options.vitest : DEFAULT_INIT_OPTIONS.includeVitest;
|
|
52
49
|
}
|
|
53
50
|
else {
|
|
54
51
|
const answers = await askInitQuestions({
|
|
55
52
|
skipProjectName: true,
|
|
56
53
|
skipProjectType: Boolean(typeFromFlag),
|
|
57
54
|
skipInitGit: gitFlagProvided,
|
|
58
|
-
skipVitest: vitestFlagProvided,
|
|
59
55
|
});
|
|
60
56
|
projectType = typeFromFlag ?? answers.projectType;
|
|
61
57
|
initGit = gitFlagProvided ? options.git : answers.initGit;
|
|
62
|
-
includeVitest = vitestFlagProvided ? options.vitest : answers.includeVitest;
|
|
63
58
|
}
|
|
64
59
|
// Obtener template
|
|
65
60
|
const templates = listTemplates(projectType);
|
|
66
61
|
const templateFromFlag = resolveTemplateFlag(options.template, templates);
|
|
67
62
|
const template = await collectTemplate(templateFromFlag, templates, useDefaults);
|
|
63
|
+
// Obtener useVitest
|
|
64
|
+
const vitestFlagProvided = options.vitest !== undefined;
|
|
65
|
+
let useVitest;
|
|
66
|
+
if (vitestFlagProvided) {
|
|
67
|
+
useVitest = options.vitest;
|
|
68
|
+
}
|
|
69
|
+
else if (useDefaults) {
|
|
70
|
+
useVitest = DEFAULT_INIT_OPTIONS.useVitest;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
useVitest = (await askUseVitest()).useVitest;
|
|
74
|
+
}
|
|
68
75
|
return {
|
|
69
76
|
structure: 'basic',
|
|
70
77
|
projectName,
|
|
71
78
|
projectType,
|
|
72
79
|
template,
|
|
73
80
|
initGit,
|
|
74
|
-
|
|
81
|
+
useVitest,
|
|
75
82
|
packageManager: detectPackageManager(),
|
|
76
83
|
isDryRun: Boolean(options.dryRun),
|
|
77
84
|
};
|
|
@@ -81,16 +88,13 @@ async function collectMonorepoContext(projectName, useDefaults, options) {
|
|
|
81
88
|
const frontendTemplates = listTemplates('frontend');
|
|
82
89
|
const backendTemplates = listTemplates('backend');
|
|
83
90
|
const gitFlagProvided = options.git !== undefined;
|
|
84
|
-
const vitestFlagProvided = options.vitest !== undefined;
|
|
85
91
|
let webTemplate;
|
|
86
92
|
let apiTemplate;
|
|
87
93
|
let initGit;
|
|
88
|
-
let includeVitest;
|
|
89
94
|
if (useDefaults) {
|
|
90
95
|
webTemplate = frontendTemplates[0] ?? 'basic';
|
|
91
96
|
apiTemplate = backendTemplates[0] ?? 'basic';
|
|
92
97
|
initGit = gitFlagProvided ? options.git : DEFAULT_INIT_OPTIONS.initGit;
|
|
93
|
-
includeVitest = vitestFlagProvided ? options.vitest : DEFAULT_INIT_OPTIONS.includeVitest;
|
|
94
98
|
}
|
|
95
99
|
else {
|
|
96
100
|
const webAnswer = await askTemplate({
|
|
@@ -110,13 +114,18 @@ async function collectMonorepoContext(projectName, useDefaults, options) {
|
|
|
110
114
|
const gitAnswer = await askInitGit();
|
|
111
115
|
initGit = gitAnswer.initGit;
|
|
112
116
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
}
|
|
118
|
+
// Obtener useVitest
|
|
119
|
+
const vitestFlagProvided = options.vitest !== undefined;
|
|
120
|
+
let useVitest;
|
|
121
|
+
if (vitestFlagProvided) {
|
|
122
|
+
useVitest = options.vitest;
|
|
123
|
+
}
|
|
124
|
+
else if (useDefaults) {
|
|
125
|
+
useVitest = DEFAULT_INIT_OPTIONS.useVitest;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
useVitest = (await askUseVitest()).useVitest;
|
|
120
129
|
}
|
|
121
130
|
return {
|
|
122
131
|
structure: 'monorepo',
|
|
@@ -124,7 +133,7 @@ async function collectMonorepoContext(projectName, useDefaults, options) {
|
|
|
124
133
|
webTemplate,
|
|
125
134
|
apiTemplate,
|
|
126
135
|
initGit,
|
|
127
|
-
|
|
136
|
+
useVitest,
|
|
128
137
|
packageManager: 'pnpm', // Monorepo usa pnpm por defecto
|
|
129
138
|
isDryRun: Boolean(options.dryRun),
|
|
130
139
|
};
|
|
@@ -3,8 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import { getTemplatePath } from '../utils/getTemplatePath.js';
|
|
4
4
|
import { copyTemplate } from '../utils/copyTemplate.js';
|
|
5
5
|
import { initGitRepo } from '../utils/git.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { setupVitest } from '../utils/setupVitest.js';
|
|
7
|
+
import { installDependencies } from '../utils/installDependencies.js';
|
|
8
|
+
export async function createMonorepo({ projectName, webTemplate, apiTemplate, initGit, useVitest, packageManager, }) {
|
|
8
9
|
// 1. Resolver ruta absoluta del proyecto
|
|
9
10
|
const projectRoot = path.resolve(process.cwd(), projectName);
|
|
10
11
|
// 2. Evitar sobrescribir carpetas existentes
|
|
@@ -18,30 +19,29 @@ export async function createMonorepo({ projectName, webTemplate, apiTemplate, in
|
|
|
18
19
|
// 4. Crear archivos de configuración del monorepo
|
|
19
20
|
await createMonorepoConfig(projectRoot, projectName);
|
|
20
21
|
// 5. Copiar template de frontend a apps/web
|
|
21
|
-
const webPath = path.join(projectRoot, 'apps', 'web');
|
|
22
22
|
const webTemplatePath = getTemplatePath('frontend', webTemplate);
|
|
23
23
|
if (await fs.pathExists(webTemplatePath)) {
|
|
24
|
-
await copyTemplate(webTemplatePath,
|
|
24
|
+
await copyTemplate(webTemplatePath, path.join(projectRoot, 'apps', 'web'), {
|
|
25
25
|
projectName: `${projectName}-web`,
|
|
26
26
|
});
|
|
27
|
-
if (includeVitest) {
|
|
28
|
-
await injectVitest(webPath, 'frontend', webTemplate);
|
|
29
|
-
}
|
|
30
27
|
}
|
|
31
28
|
// 6. Copiar template de backend a apps/api
|
|
32
|
-
const apiPath = path.join(projectRoot, 'apps', 'api');
|
|
33
29
|
const apiTemplatePath = getTemplatePath('backend', apiTemplate);
|
|
34
30
|
if (await fs.pathExists(apiTemplatePath)) {
|
|
35
|
-
await copyTemplate(apiTemplatePath,
|
|
31
|
+
await copyTemplate(apiTemplatePath, path.join(projectRoot, 'apps', 'api'), {
|
|
36
32
|
projectName: `${projectName}-api`,
|
|
37
33
|
});
|
|
38
|
-
if (includeVitest) {
|
|
39
|
-
await injectVitest(apiPath, 'backend', apiTemplate);
|
|
40
|
-
}
|
|
41
34
|
}
|
|
42
35
|
// 7. Crear package shared básico
|
|
43
36
|
await createSharedPackage(projectRoot, projectName);
|
|
44
|
-
// 8.
|
|
37
|
+
// 8. Configurar Vitest en apps (si aplica)
|
|
38
|
+
if (useVitest) {
|
|
39
|
+
await setupVitest(path.join(projectRoot, 'apps', 'web'));
|
|
40
|
+
await setupVitest(path.join(projectRoot, 'apps', 'api'));
|
|
41
|
+
}
|
|
42
|
+
// 9. Instalar dependencias
|
|
43
|
+
installDependencies(projectRoot, packageManager);
|
|
44
|
+
// 10. Inicializar Git (si aplica)
|
|
45
45
|
if (initGit) {
|
|
46
46
|
initGitRepo(projectRoot);
|
|
47
47
|
}
|
|
@@ -3,8 +3,9 @@ import path from 'node:path';
|
|
|
3
3
|
import { getTemplatePath } from '../utils/getTemplatePath.js';
|
|
4
4
|
import { copyTemplate } from '../utils/copyTemplate.js';
|
|
5
5
|
import { initGitRepo } from '../utils/git.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import { setupVitest } from '../utils/setupVitest.js';
|
|
7
|
+
import { installDependencies } from '../utils/installDependencies.js';
|
|
8
|
+
export async function createProject({ projectName, projectType, template, initGit, useVitest, packageManager, }) {
|
|
8
9
|
// 1. Resolver ruta absoluta del proyecto
|
|
9
10
|
const projectRoot = path.resolve(process.cwd(), projectName);
|
|
10
11
|
// 2. Evitar sobrescribir carpetas existentes
|
|
@@ -22,11 +23,13 @@ export async function createProject({ projectName, projectType, template, initGi
|
|
|
22
23
|
await copyTemplate(templatePath, projectRoot, {
|
|
23
24
|
projectName,
|
|
24
25
|
});
|
|
25
|
-
// 6.
|
|
26
|
-
if (
|
|
27
|
-
await
|
|
26
|
+
// 6. Configurar Vitest (si aplica)
|
|
27
|
+
if (useVitest) {
|
|
28
|
+
await setupVitest(projectRoot);
|
|
28
29
|
}
|
|
29
|
-
// 7.
|
|
30
|
+
// 7. Instalar dependencias
|
|
31
|
+
installDependencies(projectRoot, packageManager);
|
|
32
|
+
// 8. Inicializar Git (si aplica)
|
|
30
33
|
if (initGit) {
|
|
31
34
|
initGitRepo(projectRoot);
|
|
32
35
|
}
|
|
@@ -56,14 +56,6 @@ export async function askInitQuestions(options = {}) {
|
|
|
56
56
|
initial: true,
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
-
if (!options.skipVitest) {
|
|
60
|
-
questions.push({
|
|
61
|
-
type: 'confirm',
|
|
62
|
-
name: 'includeVitest',
|
|
63
|
-
message: 'Include Vitest for testing?',
|
|
64
|
-
initial: true,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
59
|
return prompts(questions, { onCancel });
|
|
68
60
|
}
|
|
69
61
|
export async function askTemplate(options) {
|
|
@@ -88,11 +80,11 @@ export async function askInitGit() {
|
|
|
88
80
|
initial: true,
|
|
89
81
|
}, { onCancel });
|
|
90
82
|
}
|
|
91
|
-
export async function
|
|
83
|
+
export async function askUseVitest() {
|
|
92
84
|
return prompts({
|
|
93
85
|
type: 'confirm',
|
|
94
|
-
name: '
|
|
95
|
-
message: '
|
|
96
|
-
initial:
|
|
86
|
+
name: 'useVitest',
|
|
87
|
+
message: 'Add Vitest for testing?',
|
|
88
|
+
initial: false,
|
|
97
89
|
}, { onCancel });
|
|
98
90
|
}
|
package/dist/types/project.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
export function installDependencies(projectRoot, packageManager) {
|
|
3
|
+
const command = packageManager === 'yarn' ? 'yarn' : `${packageManager} install`;
|
|
4
|
+
execSync(command, {
|
|
5
|
+
cwd: projectRoot,
|
|
6
|
+
stdio: 'inherit',
|
|
7
|
+
});
|
|
8
|
+
}
|
|
@@ -12,8 +12,7 @@ export function printDryRun(context) {
|
|
|
12
12
|
else {
|
|
13
13
|
printBasicPlan(context);
|
|
14
14
|
}
|
|
15
|
-
console.log(`${styles.info('- Git:')} ${context.initGit ? 'would initialize' : 'skipped'}`);
|
|
16
|
-
console.log(`${styles.info('- Vitest:')} ${context.includeVitest ? 'would add' : 'skipped'}\n`);
|
|
15
|
+
console.log(`${styles.info('- Git:')} ${context.initGit ? 'would initialize' : 'skipped'}\n`);
|
|
17
16
|
console.log(styles.title('Next steps'));
|
|
18
17
|
console.log(` ${styles.highlight(`cd ${context.projectName}`)}`);
|
|
19
18
|
console.log(` ${styles.highlight(`${context.packageManager} install`)}`);
|
|
@@ -11,11 +11,9 @@ export function printSummary(context) {
|
|
|
11
11
|
console.log(`${styles.info('- Template:')} ${context.projectType}/${context.template}`);
|
|
12
12
|
}
|
|
13
13
|
console.log(`${styles.info('- Directory:')} ./${context.projectName}`);
|
|
14
|
-
console.log(`${styles.info('- Git:')} ${context.initGit ? styles.success('initialized') : styles.muted('not initialized')}`);
|
|
15
|
-
console.log(`${styles.info('- Vitest:')} ${context.includeVitest ? styles.success('added') : styles.muted('not included')}\n`);
|
|
14
|
+
console.log(`${styles.info('- Git:')} ${context.initGit ? styles.success('initialized') : styles.muted('not initialized')}\n`);
|
|
16
15
|
console.log(styles.title('Next steps'));
|
|
17
16
|
console.log(` ${styles.highlight(`cd ${context.projectName}`)}`);
|
|
18
|
-
console.log(` ${styles.highlight(`${context.packageManager} install`)}`);
|
|
19
17
|
console.log(` ${styles.highlight(`${context.packageManager} run dev`)}`);
|
|
20
18
|
console.log('');
|
|
21
19
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const VITEST_CONFIG = `import { defineConfig } from 'vitest/config';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
test: {
|
|
7
|
+
globals: true,
|
|
8
|
+
environment: 'node',
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
`;
|
|
12
|
+
export async function setupVitest(projectRoot) {
|
|
13
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
14
|
+
// Leer package.json existente
|
|
15
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
16
|
+
// Añadir devDependencies
|
|
17
|
+
packageJson.devDependencies = {
|
|
18
|
+
...packageJson.devDependencies,
|
|
19
|
+
vitest: '^3.0.0',
|
|
20
|
+
};
|
|
21
|
+
// Añadir scripts de test
|
|
22
|
+
packageJson.scripts = {
|
|
23
|
+
...packageJson.scripts,
|
|
24
|
+
test: 'vitest',
|
|
25
|
+
'test:run': 'vitest run',
|
|
26
|
+
};
|
|
27
|
+
// Escribir package.json actualizado
|
|
28
|
+
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
29
|
+
// Crear vitest.config.ts
|
|
30
|
+
await fs.writeFile(path.join(projectRoot, 'vitest.config.ts'), VITEST_CONFIG);
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devstarter-tool",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI to generate projects with best practices (basic or monorepo)",
|
|
6
6
|
"author": "abraham-diaz",
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"backend",
|
|
23
23
|
"boilerplate",
|
|
24
24
|
"starter",
|
|
25
|
-
"devstarter"
|
|
25
|
+
"devstarter",
|
|
26
|
+
"vitest",
|
|
27
|
+
"testing"
|
|
26
28
|
],
|
|
27
29
|
"engines": {
|
|
28
30
|
"node": ">=18.0.0"
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import fs from 'fs-extra';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
const VITEST_CONFIG = `import { defineConfig } from 'vitest/config';
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
test: {
|
|
7
|
-
globals: true,
|
|
8
|
-
},
|
|
9
|
-
});
|
|
10
|
-
`;
|
|
11
|
-
const VITEST_CONFIG_REACT = `import { defineConfig } from 'vitest/config';
|
|
12
|
-
import react from '@vitejs/plugin-react';
|
|
13
|
-
|
|
14
|
-
export default defineConfig({
|
|
15
|
-
plugins: [react()],
|
|
16
|
-
test: {
|
|
17
|
-
globals: true,
|
|
18
|
-
environment: 'jsdom',
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
`;
|
|
22
|
-
function getExampleTest(projectType, template) {
|
|
23
|
-
if (projectType === 'frontend' && template === 'react') {
|
|
24
|
-
return `import { describe, it, expect } from 'vitest';
|
|
25
|
-
|
|
26
|
-
describe('Example test', () => {
|
|
27
|
-
it('should pass', () => {
|
|
28
|
-
expect(1 + 1).toBe(2);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
`;
|
|
32
|
-
}
|
|
33
|
-
return `import { describe, it, expect } from 'vitest';
|
|
34
|
-
|
|
35
|
-
describe('Example test', () => {
|
|
36
|
-
it('should pass', () => {
|
|
37
|
-
expect(1 + 1).toBe(2);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
`;
|
|
41
|
-
}
|
|
42
|
-
export async function injectVitest(projectRoot, projectType, template) {
|
|
43
|
-
// 1. Modificar package.json
|
|
44
|
-
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
45
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
46
|
-
// Agregar script test
|
|
47
|
-
packageJson.scripts = packageJson.scripts || {};
|
|
48
|
-
packageJson.scripts.test = 'vitest';
|
|
49
|
-
// Agregar devDependencies
|
|
50
|
-
packageJson.devDependencies = packageJson.devDependencies || {};
|
|
51
|
-
packageJson.devDependencies.vitest = '^3.1.4';
|
|
52
|
-
// Para React, agregar jsdom
|
|
53
|
-
if (projectType === 'frontend' && template === 'react') {
|
|
54
|
-
packageJson.devDependencies.jsdom = '^26.1.0';
|
|
55
|
-
}
|
|
56
|
-
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
57
|
-
// 2. Crear vitest.config.ts
|
|
58
|
-
const vitestConfigPath = path.join(projectRoot, 'vitest.config.ts');
|
|
59
|
-
const configContent = projectType === 'frontend' && template === 'react'
|
|
60
|
-
? VITEST_CONFIG_REACT
|
|
61
|
-
: VITEST_CONFIG;
|
|
62
|
-
await fs.writeFile(vitestConfigPath, configContent);
|
|
63
|
-
// 3. Crear test de ejemplo
|
|
64
|
-
const testDir = path.join(projectRoot, 'src', '__tests__');
|
|
65
|
-
await fs.ensureDir(testDir);
|
|
66
|
-
const testFilePath = path.join(testDir, 'example.test.ts');
|
|
67
|
-
await fs.writeFile(testFilePath, getExampleTest(projectType, template));
|
|
68
|
-
}
|