devstarter-tool 0.1.0 → 0.2.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 +82 -62
- package/dist/cli.js +2 -0
- package/dist/commands/init/collector.js +32 -7
- package/dist/generators/createMonorepo.js +12 -3
- package/dist/generators/createProject.js +7 -2
- package/dist/prompts/initPrompts.js +24 -6
- package/dist/templates/frontend/basic/index.html +12 -0
- package/dist/templates/frontend/basic/package.json.tpl +8 -1
- package/dist/templates/frontend/basic/src/main.ts +6 -1
- package/dist/templates/frontend/basic/tsconfig.json +12 -0
- package/dist/types/project.js +1 -0
- package/dist/utils/injectVitest.js +68 -0
- package/dist/utils/printDryRun.js +2 -1
- package/dist/utils/printSummary.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,126 +1,146 @@
|
|
|
1
|
-
#
|
|
1
|
+
# devstarter-tool
|
|
2
2
|
|
|
3
|
-
CLI
|
|
3
|
+
CLI to generate projects with best practices and predefined configurations.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install -g devstarter-
|
|
8
|
+
npm install -g devstarter-tool
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Or run directly with npx:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npx devstarter-
|
|
14
|
+
npx devstarter-tool init my-app
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Usage
|
|
18
18
|
|
|
19
|
-
###
|
|
19
|
+
### Basic command
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
devstarter init [
|
|
22
|
+
devstarter init [project-name]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
###
|
|
25
|
+
### Options
|
|
26
26
|
|
|
27
|
-
|
|
|
27
|
+
| Option | Description |
|
|
28
28
|
|--------|-------------|
|
|
29
|
-
| `-y, --yes` |
|
|
30
|
-
| `-t, --type <
|
|
31
|
-
| `--
|
|
29
|
+
| `-y, --yes` | Use default values without prompting |
|
|
30
|
+
| `-t, --type <type>` | Project type: `frontend` or `backend` |
|
|
31
|
+
| `--template <name>` | Template to use |
|
|
32
|
+
| `--dry-run` | Preview changes without creating files |
|
|
32
33
|
|
|
33
|
-
###
|
|
34
|
+
### Examples
|
|
34
35
|
|
|
35
36
|
```bash
|
|
36
|
-
#
|
|
37
|
+
# Full interactive mode
|
|
37
38
|
devstarter init
|
|
38
39
|
|
|
39
|
-
#
|
|
40
|
+
# Create project with specific name
|
|
40
41
|
devstarter init my-app
|
|
41
42
|
|
|
42
|
-
#
|
|
43
|
+
# Create frontend project without prompts
|
|
43
44
|
devstarter init my-app --type frontend -y
|
|
44
45
|
|
|
45
|
-
#
|
|
46
|
+
# Preview what files would be created
|
|
46
47
|
devstarter init my-app --type frontend --dry-run
|
|
47
48
|
```
|
|
48
49
|
|
|
49
|
-
##
|
|
50
|
+
## Project Structures
|
|
51
|
+
|
|
52
|
+
### Basic (single project)
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
my-app/
|
|
56
|
+
├── src/
|
|
57
|
+
│ └── main.ts (or main.tsx for React)
|
|
58
|
+
├── package.json
|
|
59
|
+
├── README.md
|
|
60
|
+
└── .git/ (if git is initialized)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Monorepo (full-stack)
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
my-app/
|
|
67
|
+
├── apps/
|
|
68
|
+
│ ├── web/ <- frontend template
|
|
69
|
+
│ └── api/ <- backend template
|
|
70
|
+
├── packages/
|
|
71
|
+
│ └── shared/ <- shared code
|
|
72
|
+
├── package.json
|
|
73
|
+
├── pnpm-workspace.yaml
|
|
74
|
+
├── tsconfig.base.json
|
|
75
|
+
└── README.md
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Available Templates
|
|
50
79
|
|
|
51
80
|
### Frontend
|
|
52
81
|
|
|
53
|
-
| Template |
|
|
82
|
+
| Template | Description |
|
|
54
83
|
|----------|-------------|
|
|
55
|
-
| `basic` | TypeScript
|
|
84
|
+
| `basic` | Minimal TypeScript with basic structure |
|
|
56
85
|
| `react` | React 18 + Vite + TypeScript |
|
|
57
86
|
|
|
58
87
|
### Backend
|
|
59
88
|
|
|
60
|
-
| Template |
|
|
89
|
+
| Template | Description |
|
|
61
90
|
|----------|-------------|
|
|
62
91
|
| `basic` | Express + TypeScript |
|
|
63
92
|
|
|
64
|
-
##
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
my-app/
|
|
68
|
-
├── src/
|
|
69
|
-
│ └── main.ts (o main.tsx para React)
|
|
70
|
-
├── package.json
|
|
71
|
-
├── README.md
|
|
72
|
-
└── .git/ (si se inicializa git)
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Caracteristicas
|
|
93
|
+
## Features
|
|
76
94
|
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
95
|
+
- Project structure selection (basic or monorepo)
|
|
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
|
|
83
102
|
|
|
84
|
-
##
|
|
103
|
+
## Development
|
|
85
104
|
|
|
86
|
-
###
|
|
105
|
+
### Requirements
|
|
87
106
|
|
|
88
107
|
- Node.js 18+
|
|
89
|
-
- npm, pnpm
|
|
108
|
+
- npm, pnpm or yarn
|
|
90
109
|
|
|
91
110
|
### Setup
|
|
92
111
|
|
|
93
112
|
```bash
|
|
94
|
-
#
|
|
95
|
-
git clone https://github.com/abraham-diaz/
|
|
96
|
-
cd
|
|
113
|
+
# Clone repository
|
|
114
|
+
git clone https://github.com/abraham-diaz/devstarter-cli.git
|
|
115
|
+
cd devstarter-cli
|
|
97
116
|
|
|
98
|
-
#
|
|
117
|
+
# Install dependencies
|
|
99
118
|
npm install
|
|
100
119
|
|
|
101
|
-
#
|
|
120
|
+
# Build
|
|
102
121
|
npm run build
|
|
103
122
|
|
|
104
|
-
#
|
|
123
|
+
# Run locally
|
|
105
124
|
node dist/cli.js init test-app --dry-run
|
|
106
125
|
```
|
|
107
126
|
|
|
108
|
-
### Scripts
|
|
127
|
+
### Available Scripts
|
|
109
128
|
|
|
110
|
-
| Script |
|
|
129
|
+
| Script | Description |
|
|
111
130
|
|--------|-------------|
|
|
112
|
-
| `npm run build` |
|
|
113
|
-
| `npm run dev` |
|
|
114
|
-
| `npm run
|
|
115
|
-
| `npm run
|
|
131
|
+
| `npm run build` | Compile TypeScript and copy templates |
|
|
132
|
+
| `npm run dev` | Watch mode for development |
|
|
133
|
+
| `npm run test` | Run tests |
|
|
134
|
+
| `npm run lint` | Run ESLint |
|
|
135
|
+
| `npm run format` | Format code with Prettier |
|
|
116
136
|
|
|
117
|
-
###
|
|
137
|
+
### Adding New Templates
|
|
118
138
|
|
|
119
|
-
1.
|
|
120
|
-
2.
|
|
121
|
-
3.
|
|
122
|
-
4.
|
|
139
|
+
1. Create folder in `src/templates/<type>/<template-name>/`
|
|
140
|
+
2. Add template files (use `.tpl` extension for files with placeholders)
|
|
141
|
+
3. Available placeholders: `{{projectName}}`
|
|
142
|
+
4. Run `npm run build`
|
|
123
143
|
|
|
124
|
-
##
|
|
144
|
+
## License
|
|
125
145
|
|
|
126
146
|
MIT
|
package/dist/cli.js
CHANGED
|
@@ -13,5 +13,7 @@ program
|
|
|
13
13
|
.option('-t, --type <type>', 'Project type (frontend | backend)')
|
|
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
|
+
.option('--no-git', 'Skip git repository initialization')
|
|
17
|
+
.option('--no-vitest', 'Skip Vitest testing framework')
|
|
16
18
|
.action(initCommand);
|
|
17
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, } from '../../prompts/initPrompts.js';
|
|
2
|
+
import { askProjectName, askProjectStructure, askInitQuestions, askTemplate, askInitGit, askIncludeVitest, } 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';
|
|
@@ -39,20 +39,27 @@ async function collectStructure(useDefaults) {
|
|
|
39
39
|
}
|
|
40
40
|
async function collectBasicContext(projectName, options, useDefaults) {
|
|
41
41
|
const typeFromFlag = resolveProjectType(options.type);
|
|
42
|
-
|
|
42
|
+
const gitFlagProvided = options.git !== undefined;
|
|
43
|
+
const vitestFlagProvided = options.vitest !== undefined;
|
|
44
|
+
// Obtener tipo de proyecto, initGit e includeVitest
|
|
43
45
|
let projectType;
|
|
44
46
|
let initGit;
|
|
47
|
+
let includeVitest;
|
|
45
48
|
if (useDefaults) {
|
|
46
49
|
projectType = typeFromFlag ?? DEFAULT_INIT_OPTIONS.projectType;
|
|
47
|
-
initGit = DEFAULT_INIT_OPTIONS.initGit;
|
|
50
|
+
initGit = gitFlagProvided ? options.git : DEFAULT_INIT_OPTIONS.initGit;
|
|
51
|
+
includeVitest = vitestFlagProvided ? options.vitest : DEFAULT_INIT_OPTIONS.includeVitest;
|
|
48
52
|
}
|
|
49
53
|
else {
|
|
50
54
|
const answers = await askInitQuestions({
|
|
51
55
|
skipProjectName: true,
|
|
52
56
|
skipProjectType: Boolean(typeFromFlag),
|
|
57
|
+
skipInitGit: gitFlagProvided,
|
|
58
|
+
skipVitest: vitestFlagProvided,
|
|
53
59
|
});
|
|
54
60
|
projectType = typeFromFlag ?? answers.projectType;
|
|
55
|
-
initGit = answers.initGit;
|
|
61
|
+
initGit = gitFlagProvided ? options.git : answers.initGit;
|
|
62
|
+
includeVitest = vitestFlagProvided ? options.vitest : answers.includeVitest;
|
|
56
63
|
}
|
|
57
64
|
// Obtener template
|
|
58
65
|
const templates = listTemplates(projectType);
|
|
@@ -64,6 +71,7 @@ async function collectBasicContext(projectName, options, useDefaults) {
|
|
|
64
71
|
projectType,
|
|
65
72
|
template,
|
|
66
73
|
initGit,
|
|
74
|
+
includeVitest,
|
|
67
75
|
packageManager: detectPackageManager(),
|
|
68
76
|
isDryRun: Boolean(options.dryRun),
|
|
69
77
|
};
|
|
@@ -72,13 +80,17 @@ async function collectMonorepoContext(projectName, useDefaults, options) {
|
|
|
72
80
|
// Templates para web (frontend) y api (backend)
|
|
73
81
|
const frontendTemplates = listTemplates('frontend');
|
|
74
82
|
const backendTemplates = listTemplates('backend');
|
|
83
|
+
const gitFlagProvided = options.git !== undefined;
|
|
84
|
+
const vitestFlagProvided = options.vitest !== undefined;
|
|
75
85
|
let webTemplate;
|
|
76
86
|
let apiTemplate;
|
|
77
87
|
let initGit;
|
|
88
|
+
let includeVitest;
|
|
78
89
|
if (useDefaults) {
|
|
79
90
|
webTemplate = frontendTemplates[0] ?? 'basic';
|
|
80
91
|
apiTemplate = backendTemplates[0] ?? 'basic';
|
|
81
|
-
initGit = DEFAULT_INIT_OPTIONS.initGit;
|
|
92
|
+
initGit = gitFlagProvided ? options.git : DEFAULT_INIT_OPTIONS.initGit;
|
|
93
|
+
includeVitest = vitestFlagProvided ? options.vitest : DEFAULT_INIT_OPTIONS.includeVitest;
|
|
82
94
|
}
|
|
83
95
|
else {
|
|
84
96
|
const webAnswer = await askTemplate({
|
|
@@ -91,8 +103,20 @@ async function collectMonorepoContext(projectName, useDefaults, options) {
|
|
|
91
103
|
message: 'Template for apps/api (backend):',
|
|
92
104
|
});
|
|
93
105
|
apiTemplate = apiAnswer.template;
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
if (gitFlagProvided) {
|
|
107
|
+
initGit = options.git;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
const gitAnswer = await askInitGit();
|
|
111
|
+
initGit = gitAnswer.initGit;
|
|
112
|
+
}
|
|
113
|
+
if (vitestFlagProvided) {
|
|
114
|
+
includeVitest = options.vitest;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const vitestAnswer = await askIncludeVitest();
|
|
118
|
+
includeVitest = vitestAnswer.includeVitest;
|
|
119
|
+
}
|
|
96
120
|
}
|
|
97
121
|
return {
|
|
98
122
|
structure: 'monorepo',
|
|
@@ -100,6 +124,7 @@ async function collectMonorepoContext(projectName, useDefaults, options) {
|
|
|
100
124
|
webTemplate,
|
|
101
125
|
apiTemplate,
|
|
102
126
|
initGit,
|
|
127
|
+
includeVitest,
|
|
103
128
|
packageManager: 'pnpm', // Monorepo usa pnpm por defecto
|
|
104
129
|
isDryRun: Boolean(options.dryRun),
|
|
105
130
|
};
|
|
@@ -3,7 +3,8 @@ 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
|
-
|
|
6
|
+
import { injectVitest } from '../utils/injectVitest.js';
|
|
7
|
+
export async function createMonorepo({ projectName, webTemplate, apiTemplate, initGit, includeVitest, }) {
|
|
7
8
|
// 1. Resolver ruta absoluta del proyecto
|
|
8
9
|
const projectRoot = path.resolve(process.cwd(), projectName);
|
|
9
10
|
// 2. Evitar sobrescribir carpetas existentes
|
|
@@ -17,18 +18,26 @@ export async function createMonorepo({ projectName, webTemplate, apiTemplate, in
|
|
|
17
18
|
// 4. Crear archivos de configuración del monorepo
|
|
18
19
|
await createMonorepoConfig(projectRoot, projectName);
|
|
19
20
|
// 5. Copiar template de frontend a apps/web
|
|
21
|
+
const webPath = path.join(projectRoot, 'apps', 'web');
|
|
20
22
|
const webTemplatePath = getTemplatePath('frontend', webTemplate);
|
|
21
23
|
if (await fs.pathExists(webTemplatePath)) {
|
|
22
|
-
await copyTemplate(webTemplatePath,
|
|
24
|
+
await copyTemplate(webTemplatePath, webPath, {
|
|
23
25
|
projectName: `${projectName}-web`,
|
|
24
26
|
});
|
|
27
|
+
if (includeVitest) {
|
|
28
|
+
await injectVitest(webPath, 'frontend', webTemplate);
|
|
29
|
+
}
|
|
25
30
|
}
|
|
26
31
|
// 6. Copiar template de backend a apps/api
|
|
32
|
+
const apiPath = path.join(projectRoot, 'apps', 'api');
|
|
27
33
|
const apiTemplatePath = getTemplatePath('backend', apiTemplate);
|
|
28
34
|
if (await fs.pathExists(apiTemplatePath)) {
|
|
29
|
-
await copyTemplate(apiTemplatePath,
|
|
35
|
+
await copyTemplate(apiTemplatePath, apiPath, {
|
|
30
36
|
projectName: `${projectName}-api`,
|
|
31
37
|
});
|
|
38
|
+
if (includeVitest) {
|
|
39
|
+
await injectVitest(apiPath, 'backend', apiTemplate);
|
|
40
|
+
}
|
|
32
41
|
}
|
|
33
42
|
// 7. Crear package shared básico
|
|
34
43
|
await createSharedPackage(projectRoot, projectName);
|
|
@@ -3,7 +3,8 @@ 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
|
-
|
|
6
|
+
import { injectVitest } from '../utils/injectVitest.js';
|
|
7
|
+
export async function createProject({ projectName, projectType, template, initGit, includeVitest, }) {
|
|
7
8
|
// 1. Resolver ruta absoluta del proyecto
|
|
8
9
|
const projectRoot = path.resolve(process.cwd(), projectName);
|
|
9
10
|
// 2. Evitar sobrescribir carpetas existentes
|
|
@@ -21,7 +22,11 @@ export async function createProject({ projectName, projectType, template, initGi
|
|
|
21
22
|
await copyTemplate(templatePath, projectRoot, {
|
|
22
23
|
projectName,
|
|
23
24
|
});
|
|
24
|
-
// 6.
|
|
25
|
+
// 6. Inyectar Vitest (si aplica)
|
|
26
|
+
if (includeVitest) {
|
|
27
|
+
await injectVitest(projectRoot, projectType, template);
|
|
28
|
+
}
|
|
29
|
+
// 7. Inicializar Git (si aplica)
|
|
25
30
|
if (initGit) {
|
|
26
31
|
initGitRepo(projectRoot);
|
|
27
32
|
}
|
|
@@ -48,12 +48,22 @@ export async function askInitQuestions(options = {}) {
|
|
|
48
48
|
],
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
if (!options.skipInitGit) {
|
|
52
|
+
questions.push({
|
|
53
|
+
type: 'confirm',
|
|
54
|
+
name: 'initGit',
|
|
55
|
+
message: 'Initialize a git repository?',
|
|
56
|
+
initial: true,
|
|
57
|
+
});
|
|
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
|
+
}
|
|
57
67
|
return prompts(questions, { onCancel });
|
|
58
68
|
}
|
|
59
69
|
export async function askTemplate(options) {
|
|
@@ -78,3 +88,11 @@ export async function askInitGit() {
|
|
|
78
88
|
initial: true,
|
|
79
89
|
}, { onCancel });
|
|
80
90
|
}
|
|
91
|
+
export async function askIncludeVitest() {
|
|
92
|
+
return prompts({
|
|
93
|
+
type: 'confirm',
|
|
94
|
+
name: 'includeVitest',
|
|
95
|
+
message: 'Include Vitest for testing?',
|
|
96
|
+
initial: true,
|
|
97
|
+
}, { onCancel });
|
|
98
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{projectName}}",
|
|
3
3
|
"private": true,
|
|
4
|
+
"type": "module",
|
|
4
5
|
"scripts": {
|
|
5
|
-
"dev": "
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build",
|
|
8
|
+
"preview": "vite preview"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"typescript": "^5.5.4",
|
|
12
|
+
"vite": "^5.4.0"
|
|
6
13
|
}
|
|
7
14
|
}
|
package/dist/types/project.js
CHANGED
|
@@ -0,0 +1,68 @@
|
|
|
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
|
+
}
|
|
@@ -12,7 +12,8 @@ export function printDryRun(context) {
|
|
|
12
12
|
else {
|
|
13
13
|
printBasicPlan(context);
|
|
14
14
|
}
|
|
15
|
-
console.log(`${styles.info('- Git:')} ${context.initGit ? 'would initialize' : 'skipped'}
|
|
15
|
+
console.log(`${styles.info('- Git:')} ${context.initGit ? 'would initialize' : 'skipped'}`);
|
|
16
|
+
console.log(`${styles.info('- Vitest:')} ${context.includeVitest ? 'would add' : 'skipped'}\n`);
|
|
16
17
|
console.log(styles.title('Next steps'));
|
|
17
18
|
console.log(` ${styles.highlight(`cd ${context.projectName}`)}`);
|
|
18
19
|
console.log(` ${styles.highlight(`${context.packageManager} install`)}`);
|
|
@@ -11,7 +11,8 @@ 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')}
|
|
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`);
|
|
15
16
|
console.log(styles.title('Next steps'));
|
|
16
17
|
console.log(` ${styles.highlight(`cd ${context.projectName}`)}`);
|
|
17
18
|
console.log(` ${styles.highlight(`${context.packageManager} install`)}`);
|