nuxt-spec 0.3.3 → 0.4.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -1,14 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { getCmd } from './helpers/commands.js'
3
+ import { getCmd, resolvePackageManager } from './helpers/commands.js'
4
4
 
5
5
  /**
6
6
  * CLI tool to scaffold necessary adjustments in project folder.
7
7
  *
8
8
  * Allows `setup` or `update` to be passed as parameter.
9
9
  *
10
- * Second parameter might be a boolean to indicate auto mode
10
+ * Second (optional) parameter might be a boolean to indicate auto mode
11
11
  * (no prompts, force = true) or manual mode (with prompts, force = false).
12
+ *
13
+ * Third (optional) parameter allows explicitly passing the package manager
14
+ * (`npm`, `pnpm`, `yarn`, `bun` or `deno`), bypassing auto-detection.
12
15
  */
13
16
 
14
17
  // get parameters passed by user
@@ -19,19 +22,22 @@ const args = process.argv.slice(2);
19
22
  (async () => {
20
23
  let status = 0
21
24
  try {
25
+ const packageManager = resolvePackageManager(args[2])
26
+ // CLI args are always strings, so 'false' must be parsed explicitly rather than treated as truthy
27
+ const autoRun = args[1] === 'true'
22
28
  switch (args[0]) {
23
29
  case 'setup':
24
- await (await import('./setup.js')).specSetup(args[1] || false)
30
+ await (await import('./setup.js')).specSetup(autoRun, packageManager)
25
31
  break
26
32
  case 'update':
27
- await (await import('./update.js')).specUpdate(args[1] || false)
33
+ await (await import('./update.js')).specUpdate(autoRun, packageManager)
28
34
  break
29
35
  default:
30
- console.log(`Usage: \`${getCmd()} setup [true|false]\` or \`${getCmd()} update [true|false]\``)
36
+ console.log(`[Nuxt Spec] Usage: \`${getCmd(packageManager)} setup [true|false] [npm|pnpm|yarn|bun|deno]\` or \`${getCmd(packageManager)} update [true|false] [npm|pnpm|yarn|bun|deno]\``)
31
37
  status = 1
32
38
  }
33
39
  } catch (error) {
34
- console.error('Setup failed:', error.message)
40
+ console.error('[Nuxt Spec] CLI failed:', error.message)
35
41
  status = 1
36
42
  }
37
43
  process.exit(status)
@@ -1,9 +1,22 @@
1
1
  import { getPackageManager } from 'elrh-cosca'
2
2
 
3
+ export const SUPPORTED_PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun', 'deno']
4
+
5
+ // get the package manager name for usage in commands
6
+ // explicit override takes precedence over auto-detection
7
+ export function resolvePackageManager(override) {
8
+ if (override) {
9
+ if (!SUPPORTED_PACKAGE_MANAGERS.includes(override)) {
10
+ throw new Error(`Unsupported package manager '${override}'. Use one of: ${SUPPORTED_PACKAGE_MANAGERS.join(', ')}`)
11
+ }
12
+ return override
13
+ }
14
+ return getPackageManager()
15
+ }
16
+
3
17
  // use nuxt-spec CLI tool
4
- export function getCmd() {
18
+ export function getCmd(packageManager) {
5
19
  const command = 'nuxt-spec'
6
- const packageManager = getPackageManager()
7
20
  switch (packageManager) {
8
21
  case 'pnpm':
9
22
  return `pnpx ${command}`
@@ -24,19 +37,36 @@ export function getUpdateCmd(packageManager, target) {
24
37
  case 'pnpm':
25
38
  return `pnpm update ${target}`
26
39
  case 'yarn':
27
- return `yarn upgrade ${target}`
40
+ return `yarn up ${target}`
28
41
  case 'bun':
29
42
  return `bun update ${target}`
30
43
  case 'deno':
31
44
  return `deno add npm:${target}`
32
45
  default:
33
- return `npm update ${target}`
46
+ return `npm install ${target}`
47
+ }
48
+ }
49
+
50
+ // generate Nuxt types and auto-imports
51
+ export function getPrepareCmd(packageManager) {
52
+ const command = 'nuxt prepare'
53
+ switch (packageManager) {
54
+ case 'pnpm':
55
+ return `pnpm exec ${command}`
56
+ case 'yarn':
57
+ return `yarn ${command}`
58
+ case 'bun':
59
+ return `bunx ${command}`
60
+ case 'deno':
61
+ return `deno run -A npm:${command}`
62
+ default:
63
+ return `npx ${command}`
34
64
  }
35
65
  }
36
66
 
37
67
  // install/update playwright
38
68
  export function getPlaywrightInstallCmd(packageManager) {
39
- const command = 'playwright-core install'
69
+ const command = 'playwright install'
40
70
  switch (packageManager) {
41
71
  case 'pnpm':
42
72
  return `pnpm exec ${command}`
package/bin/setup.js CHANGED
@@ -1,14 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { execSync } from 'node:child_process'
4
+ import { readFileSync } from 'node:fs'
4
5
  import {
5
- createFileFromWebTemplate, deletePath, getPackageManager, hasJsonKey,
6
+ createFileFromWebTemplate, deletePath,
6
7
  pathExists, promptUser, removeFromJsonFile, showMessage,
7
8
  updateConfigFile, updateJsonFile, updateTextFile,
8
9
  } from 'elrh-cosca'
9
- import { getPlaywrightInstallCmd } from './helpers/commands.js'
10
+ import {
11
+ getPlaywrightInstallCmd, getPrepareCmd,
12
+ } from './helpers/commands.js'
10
13
 
11
- const TARGET_VERSION = '0.3.3'
14
+ const TARGET_VERSION = '0.4.0-alpha.1'
12
15
 
13
16
  /**
14
17
  * CLI tool to scaffold necessary adjustments in project folder.
@@ -23,246 +26,339 @@ const TARGET_VERSION = '0.3.3'
23
26
  * 5) creates default `.nuxtrc` file
24
27
  * 6) adds test-related scripts in `package.json`
25
28
  * 7) creates sample test files
26
- * 8) clear node_modules and lock file(s)
27
- * 9) run install command
28
- * 10) run Playwright setup command
29
+ * 8) adds nuxt-spec related entries to `.gitignore`
30
+ * 9) clear node_modules and lock file(s)
31
+ * 10) run install command
32
+ * 11) run Nuxt prepare command to generate types and auto-imports
33
+ * 12) run Playwright setup command
29
34
  *
30
35
  * @param {boolean} autoRun - Whether to run the setup automatically without any prompts (defaults to false).
36
+ * @param {string} [packageManager] - Package manager to be used (`npm`, `pnpm`, `yarn`, `bun` or `deno`).
31
37
  */
32
- export async function specSetup(autoRun = false) {
33
- showMessage('NUXT SPEC SETUP')
34
- showMessage('This CLI tool will help you include Nuxt Spec in your project.')
35
- showMessage('Refer to the documentation for more information.', 2)
36
-
37
- const isAutoRun = autoRun || await promptUser('Do you want to set everything up automatically (no more prompts)?')
38
- showMessage('')
38
+ export async function specSetup(autoRun = false, packageManager) {
39
+ showMessage({ message: 'NUXT SPEC SETUP' })
40
+ showMessage({ message: 'This CLI tool will help you include Nuxt Spec in your project.' })
41
+ showMessage({ message: 'Refer to the documentation for more information.', linesAfter: 2 })
39
42
 
40
- const packageManager = getPackageManager()
43
+ const isAutoRun = autoRun || await promptUser({ question: '[Nuxt Spec] Do you want to set everything up automatically (no more prompts)?' })
44
+ showMessage({ message: '' })
41
45
 
42
46
  // 1) manage dependencies in package.json
43
47
 
44
48
  // add nuxt-spec
45
49
  try {
46
- await updateJsonFile('package.json', 'dependencies', {
47
- ['nuxt-spec']: TARGET_VERSION,
48
- }, isAutoRun, `This will add 'nuxt-spec' dependency to your 'package.json'. Continue?`)
50
+ await updateJsonFile({
51
+ targetFile: 'package.json',
52
+ jsonKey: 'dependencies',
53
+ patch: {
54
+ ['nuxt-spec']: TARGET_VERSION,
55
+ },
56
+ force: isAutoRun,
57
+ prompt: `[Nuxt Spec] This will add 'nuxt-spec' dependency to your 'package.json'. Continue?`,
58
+ })
49
59
  } catch (error) {
50
- console.error(`Error adding 'nuxt-spec' dependency:\n`, error.message)
60
+ console.error(`[Nuxt Spec] Error adding 'nuxt-spec' dependency:\n`, error.message)
51
61
  }
52
62
 
53
63
  // remove now obsolete nuxt, vue and vue-router
54
- const removeDeps = isAutoRun || await promptUser(`As 'nuxt-spec' provides 'nuxt', 'vue' and 'vue-router' dependencies out of the box, do you want to remove them from your 'package.json' to avoid duplications and possible version clashes?`)
64
+ const removeDeps = isAutoRun || await promptUser({ question: `[Nuxt Spec] As 'nuxt-spec' provides 'nuxt', 'vue' and 'vue-router' dependencies out of the box, do you want to remove them from your 'package.json' to avoid duplications and possible version clashes?` })
55
65
  if (removeDeps) {
56
- if (hasJsonKey('package.json', 'dependencies.nuxt')) {
57
- try {
58
- await removeFromJsonFile('package.json', 'dependencies.nuxt', true)
59
- } catch (error) {
60
- console.error('Error removing \'nuxt\' dependency:\n', error.message)
61
- }
66
+ try {
67
+ await removeFromJsonFile({ targetFile: 'package.json', jsonKey: 'dependencies.nuxt', force: true })
68
+ } catch (error) {
69
+ console.error('[Nuxt Spec] Error removing \'nuxt\' dependency:\n', error.message)
62
70
  }
63
- if (hasJsonKey('package.json', 'dependencies.vue')) {
64
- try {
65
- await removeFromJsonFile('package.json', 'dependencies.vue', true)
66
- } catch (error) {
67
- console.error('Error removing \'vue\' dependency:\n', error.message)
68
- }
71
+ try {
72
+ await removeFromJsonFile({ targetFile: 'package.json', jsonKey: 'dependencies.vue', force: true })
73
+ } catch (error) {
74
+ console.error('[Nuxt Spec] Error removing \'vue\' dependency:\n', error.message)
69
75
  }
70
- if (hasJsonKey('package.json', 'dependencies.vue-router')) {
71
- try {
72
- await removeFromJsonFile('package.json', 'dependencies.vue-router', true)
73
- } catch (error) {
74
- console.error('Error removing \'vue-router\' dependency:\n', error.message)
75
- }
76
+ try {
77
+ await removeFromJsonFile({ targetFile: 'package.json', jsonKey: 'dependencies.vue-router', force: true })
78
+ } catch (error) {
79
+ console.error('[Nuxt Spec] Error removing \'vue-router\' dependency:\n', error.message)
76
80
  }
77
- if (hasJsonKey('package.json', 'devDependencies.nuxt')) {
78
- try {
79
- await removeFromJsonFile('package.json', 'devDependencies.nuxt', true)
80
- } catch (error) {
81
- console.error('Error removing \'nuxt\' devDependency:\n', error.message)
82
- }
81
+ try {
82
+ await removeFromJsonFile({ targetFile: 'package.json', jsonKey: 'devDependencies.nuxt', force: true })
83
+ } catch (error) {
84
+ console.error('[Nuxt Spec] Error removing \'nuxt\' devDependency:\n', error.message)
83
85
  }
84
- if (hasJsonKey('package.json', 'devDependencies.vue')) {
85
- try {
86
- await removeFromJsonFile('package.json', 'devDependencies.vue', true)
87
- } catch (error) {
88
- console.error('Error removing \'vue\' devDependency:\n', error.message)
89
- }
86
+ try {
87
+ await removeFromJsonFile({ targetFile: 'package.json', jsonKey: 'devDependencies.vue', force: true })
88
+ } catch (error) {
89
+ console.error('[Nuxt Spec] Error removing \'vue\' devDependency:\n', error.message)
90
90
  }
91
- if (hasJsonKey('package.json', 'devDependencies.vue-router')) {
92
- try {
93
- await removeFromJsonFile('package.json', 'devDependencies.vue-router', true)
94
- } catch (error) {
95
- console.error('Error removing \'vue-router\' devDependency:\n', error.message)
96
- }
91
+ try {
92
+ await removeFromJsonFile({ targetFile: 'package.json', jsonKey: 'devDependencies.vue-router', force: true })
93
+ } catch (error) {
94
+ console.error('[Nuxt Spec] Error removing \'vue-router\' devDependency:\n', error.message)
97
95
  }
98
96
  }
99
97
 
100
98
  // 2) modify nuxt.config.ts
101
99
  try {
102
- await updateConfigFile('nuxt.config.ts', {
103
- extends: [
104
- 'nuxt-spec',
105
- ],
106
- }, isAutoRun, `This will add 'nuxt-spec' module to your 'nuxt.config.ts'. Continue?`)
100
+ await updateConfigFile({
101
+ targetFile: 'nuxt.config.ts',
102
+ newConfig: {
103
+ extends: [
104
+ 'nuxt-spec',
105
+ ],
106
+ },
107
+ force: isAutoRun,
108
+ prompt: `[Nuxt Spec] This will add 'nuxt-spec' module to your 'nuxt.config.ts'. Continue?`,
109
+ })
107
110
  } catch (error) {
108
- console.error('Error updating \'nuxt.config.ts\':\n', error.message)
111
+ console.error('[Nuxt Spec] Error updating \'nuxt.config.ts\':\n', error.message)
109
112
  }
110
113
 
111
114
  // 3) `pnpm-workspace.yaml` file (only if pnpm is used)
112
115
  if (packageManager === 'pnpm') {
113
116
  try {
114
- if (pathExists('pnpm-workspace.yaml')) {
115
- await updateTextFile('pnpm-workspace.yaml', ['shamefully-hoist: true'], isAutoRun, 'This will adjust \'pnpm-workspace.yaml\' file in your project. Continue?')
117
+ if (pathExists({ targetPath: 'pnpm-workspace.yaml' })) {
118
+ await updateTextFile({
119
+ targetFile: 'pnpm-workspace.yaml',
120
+ rowsToAdd: ['shamefullyHoist: true'],
121
+ force: isAutoRun,
122
+ prompt: '[Nuxt Spec] This will adjust \'pnpm-workspace.yaml\' file in your project. Continue?',
123
+ })
116
124
  } else {
117
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/config/templates/pnpm-workspace.yaml.template`,
118
- 'pnpm-workspace.yaml', isAutoRun, 'This will add \'pnpm-workspace.yaml\' file for your project. Continue?')
125
+ await createFileFromWebTemplate({
126
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/config/templates/pnpm-workspace.yaml.template`,
127
+ targetFile: 'pnpm-workspace.yaml',
128
+ force: isAutoRun,
129
+ prompt: '[Nuxt Spec] This will add \'pnpm-workspace.yaml\' file for your project. Continue?',
130
+ })
119
131
  }
120
132
  } catch (error) {
121
- console.error('Error setting up \'pnpm-workspace.yaml\':\n', error.message)
133
+ console.error('[Nuxt Spec] Error setting up \'pnpm-workspace.yaml\':\n', error.message)
122
134
  }
123
135
  }
124
136
 
125
137
  // 4) create vitest.config.ts
126
138
  try {
127
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/config/templates/vitest.config.ts.template`,
128
- 'vitest.config.ts', isAutoRun, 'This will create a new \'vitest.config.ts\' file for your project. Continue?')
139
+ await createFileFromWebTemplate({
140
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/config/templates/vitest.config.ts.template`,
141
+ targetFile: 'vitest.config.ts',
142
+ force: isAutoRun,
143
+ prompt: '[Nuxt Spec] This will create a new \'vitest.config.ts\' file for your project. Continue?',
144
+ })
129
145
  } catch (error) {
130
- console.error('Error setting up \'vitest.config.ts\':\n', error.message)
146
+ console.error('[Nuxt Spec] Error setting up \'vitest.config.ts\':\n', error.message)
131
147
  }
132
148
 
133
149
  // 5) create .nuxtrc to prevent @nuxt/test-utils setup from running automatically on first start
134
- if (!pathExists('.nuxtrc')) {
150
+ if (!pathExists({ targetPath: '.nuxtrc' })) {
135
151
  try {
136
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/.nuxtrc`, '.nuxtrc', isAutoRun, 'This will create a \'.nuxtrc\' file to prevent @nuxt/test-utils setup from running automatically when dev server starts. Continue?')
152
+ await createFileFromWebTemplate({
153
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/.nuxtrc`,
154
+ targetFile: '.nuxtrc',
155
+ force: isAutoRun,
156
+ prompt: '[Nuxt Spec] This will create a \'.nuxtrc\' file to prevent @nuxt/test-utils setup from running automatically when dev server starts. Continue?',
157
+ })
137
158
  } catch (error) {
138
- console.error('Error creating \'.nuxtrc\':\n', error.message)
159
+ console.error('[Nuxt Spec] Error creating \'.nuxtrc\':\n', error.message)
139
160
  }
140
161
  }
141
162
 
142
163
  // 6) modify package.json with test scripts
143
164
  try {
144
- await updateJsonFile('package.json', 'scripts', {
145
- 'test': 'vitest run',
146
- 'test-u': 'vitest run -u',
147
- 'test-i': 'vitest',
148
- }, isAutoRun, 'This will adjust the test-related commands in your \'package.json\'. Continue?')
165
+ await updateJsonFile({
166
+ targetFile: 'package.json',
167
+ jsonKey: 'scripts',
168
+ patch: {
169
+ 'test': 'vitest run',
170
+ 'test-u': 'vitest run -u',
171
+ 'test-i': 'vitest',
172
+ },
173
+ force: isAutoRun,
174
+ prompt: '[Nuxt Spec] This will adjust the test-related commands in your \'package.json\'. Continue?',
175
+ })
149
176
  } catch (error) {
150
- console.error('Error adjusting scripts in \'package.json\':\n', error.message)
177
+ console.error('[Nuxt Spec] Error adjusting scripts in \'package.json\':\n', error.message)
151
178
  }
152
179
 
153
180
  // 7) create sample test files
154
- const createSampleTests = isAutoRun || await promptUser('Do you want to create sample tests in \'/test\' folder?')
181
+ const createSampleTests = isAutoRun || await promptUser({ question: '[Nuxt Spec] Do you want to create sample tests in \'/test\' folder?' })
155
182
  if (createSampleTests) {
156
183
  try {
157
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/browser/vitest-browser.test.ts`,
158
- 'test/browser/vitest-browser.test.ts', true)
184
+ await createFileFromWebTemplate({
185
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/browser/vitest-browser.test.ts`,
186
+ targetFile: 'test/browser/vitest-browser.test.ts',
187
+ force: true,
188
+ })
189
+ } catch (error) {
190
+ console.error('[Nuxt Spec] Error setting up \'vitest-browser.test.ts\':\n', error.message)
191
+ }
192
+ try {
193
+ await createFileFromWebTemplate({
194
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/e2e/nuxt-e2e.test.ts`,
195
+ targetFile: 'test/e2e/nuxt-e2e.test.ts',
196
+ force: true,
197
+ })
159
198
  } catch (error) {
160
- console.error('Error setting up \'vitest-browser.test.ts\':\n', error.message)
199
+ console.error('[Nuxt Spec] Error setting up \'nuxt-e2e.test.ts\':\n', error.message)
161
200
  }
162
201
  try {
163
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/e2e/nuxt-e2e.test.ts`,
164
- 'test/e2e/nuxt-e2e.test.ts', true)
202
+ await createFileFromWebTemplate({
203
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/e2e/nuxt-visual.test.ts`,
204
+ targetFile: 'test/e2e/nuxt-visual.test.ts',
205
+ force: true,
206
+ })
165
207
  } catch (error) {
166
- console.error('Error setting up \'nuxt-e2e.test.ts\':\n', error.message)
208
+ console.error('[Nuxt Spec] Error setting up \'nuxt-visual.test.ts\':\n', error.message)
167
209
  }
210
+ // pre-existing baseline ensures the sample "wrong" visual test fails as intended
168
211
  try {
169
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/e2e/nuxt-visual.test.ts`,
170
- 'test/e2e/nuxt-visual.test.ts', true)
212
+ await createFileFromWebTemplate({
213
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/e2e/__baseline__/wrong.png`,
214
+ targetFile: 'test/e2e/__baseline__/wrong.png',
215
+ force: true,
216
+ })
171
217
  } catch (error) {
172
- console.error('Error setting up \'nuxt-visual.test.ts\':\n', error.message)
218
+ console.error('[Nuxt Spec] Error setting up \'wrong.png\':\n', error.message)
173
219
  }
174
220
  try {
175
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/nuxt/nuxt-unit.test.ts`,
176
- 'test/nuxt/nuxt-unit.test.ts', true)
221
+ await createFileFromWebTemplate({
222
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/nuxt/nuxt-unit.test.ts`,
223
+ targetFile: 'test/nuxt/nuxt-unit.test.ts',
224
+ force: true,
225
+ })
177
226
  } catch (error) {
178
- console.error('Error setting up \'nuxt-unit.test.ts\':\n', error.message)
227
+ console.error('[Nuxt Spec] Error setting up \'nuxt-unit.test.ts\':\n', error.message)
179
228
  }
180
229
  try {
181
- await createFileFromWebTemplate(`https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/unit/vitest-unit.test.ts`,
182
- 'test/unit/vitest-unit.test.ts', true)
230
+ await createFileFromWebTemplate({
231
+ url: `https://raw.githubusercontent.com/AloisSeckar/nuxt-spec/refs/tags/v${TARGET_VERSION}/test/unit/vitest-unit.test.ts`,
232
+ targetFile: 'test/unit/vitest-unit.test.ts',
233
+ force: true,
234
+ })
183
235
  } catch (error) {
184
- console.error('Error setting up \'vitest-unit.test.ts\':\n', error.message)
236
+ console.error('[Nuxt Spec] Error setting up \'vitest-unit.test.ts\':\n', error.message)
185
237
  }
186
238
  }
187
239
 
188
- // 8) clear node_modules and lock file(s)
189
- const prepareForReinstall = isAutoRun || await promptUser('Dependencies should be re-installed now. Do you want to remove node_modules and the lock file?')
240
+ // 8) add nuxt-spec related entries to .gitignore
241
+ try {
242
+ const gitignoreEntries = [
243
+ ['# vitest output folder', '.vitest'],
244
+ ['# nuxt-spec screenshots folder', '__current__'],
245
+ ['# nuxt-spec HTML test reports folder', '__reports__'],
246
+ ]
247
+ // if .gitignore exists, we rather check for duplicates
248
+ const gitignoreExists = pathExists({ targetPath: '.gitignore' })
249
+ const gitignoreRows = gitignoreExists ? readFileSync('.gitignore', 'utf8').split(/\r?\n/) : []
250
+ const rowsToAdd = gitignoreEntries
251
+ .filter(([, entry]) => !gitignoreRows.includes(entry))
252
+ .flatMap(([comment, entry]) => ['', comment, entry])
253
+ .slice(gitignoreExists ? 0 : 1)
254
+ //
255
+ if (rowsToAdd.length > 0) {
256
+ await updateTextFile({
257
+ targetFile: '.gitignore',
258
+ rowsToAdd,
259
+ allowDuplicates: true,
260
+ createMissing: true,
261
+ force: isAutoRun,
262
+ prompt: '[Nuxt Spec] This will add nuxt-spec related entries to your \'.gitignore\' file. Continue?',
263
+ })
264
+ }
265
+ } catch (error) {
266
+ console.error('[Nuxt Spec] Error updating \'.gitignore\':\n', error.message)
267
+ }
268
+
269
+ // 9) clear node_modules and lock file(s)
270
+ const prepareForReinstall = isAutoRun || await promptUser({ question: '[Nuxt Spec] Dependencies should be re-installed now. Do you want to remove node_modules and the lock file?' })
190
271
  if (prepareForReinstall) {
191
- if (pathExists('node_modules')) {
272
+ if (pathExists({ targetPath: 'node_modules' })) {
192
273
  try {
193
- await deletePath('node_modules', true)
274
+ await deletePath({ targetPath: 'node_modules', force: true })
194
275
  } catch (error) {
195
- console.error('Error deleting \'node_modules\':\n', error.message)
276
+ console.error('[Nuxt Spec] Error deleting \'node_modules\':\n', error.message)
196
277
  }
197
278
  }
198
- if (pathExists('package-lock.json')) {
279
+ if (pathExists({ targetPath: 'package-lock.json' })) {
199
280
  try {
200
- await deletePath('package-lock.json', true)
281
+ await deletePath({ targetPath: 'package-lock.json', force: true })
201
282
  } catch (error) {
202
- console.error('Error deleting \'package-lock.json\':\n', error.message)
283
+ console.error('[Nuxt Spec] Error deleting \'package-lock.json\':\n', error.message)
203
284
  }
204
285
  }
205
- if (pathExists('pnpm-lock.yaml')) {
286
+ if (pathExists({ targetPath: 'pnpm-lock.yaml' })) {
206
287
  try {
207
- await deletePath('pnpm-lock.yaml', true)
288
+ await deletePath({ targetPath: 'pnpm-lock.yaml', force: true })
208
289
  } catch (error) {
209
- console.error('Error deleting \'pnpm-lock.yaml\':\n', error.message)
290
+ console.error('[Nuxt Spec] Error deleting \'pnpm-lock.yaml\':\n', error.message)
210
291
  }
211
292
  }
212
- if (pathExists('yarn.lock')) {
293
+ if (pathExists({ targetPath: 'yarn.lock' })) {
213
294
  try {
214
- await deletePath('yarn.lock', true)
295
+ await deletePath({ targetPath: 'yarn.lock', force: true })
215
296
  } catch (error) {
216
- console.error('Error deleting \'yarn.lock\':\n', error.message)
297
+ console.error('[Nuxt Spec] Error deleting \'yarn.lock\':\n', error.message)
217
298
  }
218
299
  }
219
- if (pathExists('bun.lockb')) {
300
+ if (pathExists({ targetPath: 'bun.lockb' })) {
220
301
  try {
221
- await deletePath('bun.lockb', true)
302
+ await deletePath({ targetPath: 'bun.lockb', force: true })
222
303
  } catch (error) {
223
- console.error('Error deleting \'bun.lockb\':\n', error.message)
304
+ console.error('[Nuxt Spec] Error deleting \'bun.lockb\':\n', error.message)
224
305
  }
225
306
  }
226
- if (pathExists('deno.lock')) {
307
+ if (pathExists({ targetPath: 'deno.lock' })) {
227
308
  try {
228
- await deletePath('deno.lock', true)
309
+ await deletePath({ targetPath: 'deno.lock', force: true })
229
310
  } catch (error) {
230
- console.error('Error deleting \'deno.lock\':\n', error.message)
311
+ console.error('[Nuxt Spec] Error deleting \'deno.lock\':\n', error.message)
231
312
  }
232
313
  }
233
314
  }
234
315
 
235
- // 9) run install command
236
- const runInstall = isAutoRun || await promptUser(`Fresh \`${packageManager} install\` is required. Do you want to run it now?`)
316
+ // 10) run install command
317
+ const runInstall = isAutoRun || await promptUser({ question: `[Nuxt Spec] Fresh \`${packageManager} install\` is required. Do you want to run it now?` })
237
318
  if (runInstall) {
238
319
  try {
239
- showMessage(`Running \`${packageManager} install\`...`)
320
+ showMessage({ message: `Running \`${packageManager} install\`...` })
240
321
  execSync(`${packageManager} install`, { stdio: 'inherit' })
241
322
  } catch (error) {
242
- console.error(`Error running \`${packageManager} install\`:\n`, error.message)
323
+ console.error(`[Nuxt Spec] Error running \`${packageManager} install\`:\n`, error.message)
243
324
  }
244
325
  }
245
326
 
246
- // 10) run Playwright browser install command
327
+ // 11) run Nuxt prepare command to generate types and auto-imports
328
+ const prepareCmd = getPrepareCmd(packageManager)
329
+ const runPrepare = isAutoRun || await promptUser({ question: `[Nuxt Spec] Nuxt needs to generate types and auto-imports before the project is fully usable. Do you want to run \`${prepareCmd}\` now?` })
330
+ if (runPrepare) {
331
+ try {
332
+ showMessage({ message: `Running \`${prepareCmd}\`...` })
333
+ execSync(prepareCmd, { stdio: 'inherit' })
334
+ } catch (error) {
335
+ console.error(`[Nuxt Spec] Error running \`${prepareCmd}\`:\n`, error.message)
336
+ }
337
+ }
338
+
339
+ // 12) run Playwright browser install command
247
340
  const playwrightInstallCmd = getPlaywrightInstallCmd(packageManager)
248
- const runPlaywrightInstall = isAutoRun || await promptUser(`Playwright browser runtimes might need to be installed locally for e2e tests. Do you want to run \`${playwrightInstallCmd}\` now?`)
341
+ const runPlaywrightInstall = isAutoRun || await promptUser({ question: `[Nuxt Spec] Playwright browser runtimes might need to be installed locally for e2e tests. Do you want to run \`${playwrightInstallCmd}\` now?` })
249
342
  if (runPlaywrightInstall) {
250
343
  try {
251
- showMessage(`Running \`${playwrightInstallCmd}\`...`)
344
+ showMessage({ message: `Running \`${playwrightInstallCmd}\`...` })
252
345
  execSync(playwrightInstallCmd, { stdio: 'inherit' })
253
346
  } catch (error) {
254
- console.error(`Error running \`${playwrightInstallCmd}\`:\n`, error.message)
347
+ console.error(`[Nuxt Spec] Error running \`${playwrightInstallCmd}\`:\n`, error.message)
255
348
  }
256
349
  }
257
350
 
258
- // 11) inform user
259
- showMessage('')
260
- showMessage('NUXT SPEC SETUP COMPLETE', 2)
351
+ // 13) inform user
352
+ showMessage({ message: '' })
353
+ showMessage({ message: 'NUXT SPEC SETUP COMPLETE', linesAfter: 2 })
261
354
  if (!runInstall) {
262
- showMessage(`Proceed with \`${packageManager} install\` to install dependencies.`)
355
+ showMessage({ message: `Proceed with \`${packageManager} install\` to install dependencies.` })
356
+ }
357
+ if (!runPrepare) {
358
+ showMessage({ message: `Run \`${prepareCmd}\` to generate the required Nuxt types and auto-imports.` })
263
359
  }
264
360
  if (!runPlaywrightInstall) {
265
- showMessage(`Run \`${playwrightInstallCmd}\` to setup the Playwright browser runtimes for e2e tests.`)
361
+ showMessage({ message: `Run \`${playwrightInstallCmd}\` to setup the Playwright browser runtimes for e2e tests.` })
266
362
  }
267
363
 
268
364
  // force exit to prevent #20