Skip to content

Commit 5d39ad0

Browse files
committed
fix(init): pass -- through npm create, document negative flags
1 parent b674b63 commit 5d39ad0

9 files changed

Lines changed: 52 additions & 23 deletions

File tree

‎docs/init.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ links:
1010

1111
<!--init-cmd-->
1212
```bash [Terminal]
13-
npm create nuxt@latest [DIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [-t, --template=<template-name>] [-f, --force] [--offline] [--preferOffline] [--install] [--gitInit] [--shell] [--packageManager=<npm|pnpm|yarn|bun|deno|aube|nub>] [-M, --modules=<module-names>] [--nightly=<dist-tag>]
13+
npm create nuxt@latest [DIR] -- [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [-t, --template=<template-name>] [-f, --force] [--offline] [--preferOffline] [--install] [--gitInit] [--shell] [--packageManager=<npm|pnpm|yarn|bun|deno|aube|nub>] [-M, --modules=<module-names>] [--nightly=<dist-tag>]
1414
```
1515
<!--/init-cmd-->
1616

@@ -44,6 +44,7 @@ The `create-nuxt` command initializes a fresh Nuxt project using [unjs/giget](ht
4444
|`--install`|`true`| Install dependencies once the project has been scaffolded |
4545
|`--no-install`|| Skip installing dependencies |
4646
|`--gitInit`|| Initialize git repository |
47+
|`--no-gitInit`|| Skip git repository initialization |
4748
|`--shell`|| Start shell after installation in project directory |
4849
|`--packageManager=<npm\|pnpm\|yarn\|bun\|deno\|aube\|nub>`|| Package manager choice |
4950
|`-M, --modules=<module-names>`|| Nuxt modules to install (comma separated without spaces) |

‎docs/module.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,16 @@ Run it without a module name to pick from the modules compatible with your Nuxt
6565

6666
<!--module-remove-cmd-->
6767
```bash [Terminal]
68-
npx nuxt module remove [MODULENAME] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--skipInstall] [--skipConfig]
68+
npx nuxt module remove [MODULENAME...] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--skipInstall] [--skipConfig]
6969
```
7070
<!--/module-remove-cmd-->
7171

7272
### Arguments
7373

7474
<!--module-remove-args-->
75-
| Argument | Description |
76-
|--------------|--------------------------------------------------------------------|
77-
|`MODULENAME`| Specify one or more modules to remove by name, separated by spaces |
75+
| Argument | Description |
76+
|-----------------|--------------------------------------------------------------------|
77+
|`MODULENAME...`| Specify one or more modules to remove by name, separated by spaces |
7878
<!--/module-remove-args-->
7979

8080
### Options

‎packages/create-nuxt/src/init.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ export default defineCommand({
176176
gitInit: {
177177
type: 'boolean',
178178
description: 'Initialize git repository',
179+
negativeDescription: 'Skip git repository initialization',
179180
},
180181
shell: {
181182
type: 'boolean',

‎packages/nuxt-cli/src/commands/module/remove.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default defineCommand({
4040
type: 'positional',
4141
description: 'Specify one or more modules to remove by name, separated by spaces',
4242
required: false,
43+
multiple: true,
4344
},
4445
skipInstall: {
4546
type: 'boolean',
@@ -52,7 +53,7 @@ export default defineCommand({
5253
},
5354
asyncsetup(ctx){
5455
constcwd=resolve(ctx.args.cwd)
55-
constmodules=ctx.args._.map(e=>e.trim()).filter(Boolean)
56+
constmodules=ctx.args.moduleName.map(e=>e.trim()).filter(Boolean)
5657
constprojectPkg=awaitreadPackageJSON(cwd).catch(()=>({}asPackageJson))
5758

5859
if(!awaitensureNuxtDependency(cwd,projectPkg)){

‎packages/nuxt-cli/src/utils/headless.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export function getHeadlessCommand(options: HeadlessCommandOptions): string[] {
164164
return[
165165
prefix,
166166
quoteArgument(dir,windows),
167+
needsArgumentSeparator(prefix) ? '--' : '',
167168
`--template=${template}`,
168169
`--packageManager=${packageManager}`,
169170
gitInit ? '--gitInit' : '--no-gitInit',
@@ -174,6 +175,17 @@ export function getHeadlessCommand(options: HeadlessCommandOptions): string[] {
174175
].filter(Boolean)
175176
}
176177

178+
/**
179+
* Whether the flags that follow have to be fenced off with `--`. `npm create`
180+
* consumes anything flag-shaped as npm config (`npm warn Unknown cli config`)
181+
* and runs the initializer with the positionals alone, so the separator is the
182+
* only way through. Other package managers forward the whole tail verbatim,
183+
* including a literal `--`, which citty would then treat as the end of parsing.
184+
*/
185+
functionneedsArgumentSeparator(prefix: string): boolean{
186+
returnprefix.startsWith('npm create')
187+
}
188+
177189
exportinterfaceWrapOptions{
178190
/** Columns available for the command itself, excluding any surrounding gutter. */
179191
width?: number

‎packages/nuxt-cli/test/unit/commands/module/remove.spec.ts‎

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe('module remove', () => {
8080
awaitremoveCommand.setup({
8181
args: {
8282
cwd: '/fake-dir',
83-
_: ['content'],
83+
moduleName: ['content'],
8484
},
8585
})
8686

@@ -113,7 +113,7 @@ describe('module remove', () => {
113113
}])
114114

115115
constremoveCommand=await(commandsasCommandsType).subCommands.remove()
116-
awaitremoveCommand.setup({args: {cwd: '/fake-dir',skipConfig: true,_: ['example-module']}})
116+
awaitremoveCommand.setup({args: {cwd: '/fake-dir',skipConfig: true,moduleName: ['example-module']}})
117117

118118
expect(removeDependency).toHaveBeenCalledWith(['example'],expect.objectContaining({cwd: '/fake-dir'}))
119119
})
@@ -123,7 +123,7 @@ describe('module remove', () => {
123123
awaitremoveCommand.setup({
124124
args: {
125125
cwd: '/fake-dir',
126-
_: ['@nuxt/content'],
126+
moduleName: ['@nuxt/content'],
127127
},
128128
})
129129

@@ -141,7 +141,7 @@ describe('module remove', () => {
141141
awaitremoveCommand.setup({
142142
args: {
143143
cwd: '/fake-dir',
144-
_: [],
144+
moduleName: [],
145145
},
146146
})
147147

@@ -157,7 +157,7 @@ describe('module remove', () => {
157157
awaitremoveCommand.setup({
158158
args: {
159159
cwd: '/fake-dir',
160-
_: [],
160+
moduleName: [],
161161
},
162162
})
163163

@@ -171,7 +171,7 @@ describe('module remove', () => {
171171
args: {
172172
cwd: '/fake-dir',
173173
skipInstall: true,
174-
_: ['@nuxt/content'],
174+
moduleName: ['@nuxt/content'],
175175
},
176176
})
177177

@@ -185,7 +185,7 @@ describe('module remove', () => {
185185
awaitexpect(removeCommand.setup({
186186
args: {
187187
cwd: '/fake-dir',
188-
_: ['@nuxt/content'],
188+
moduleName: ['@nuxt/content'],
189189
},
190190
})).rejects.toThrow('process.exit unexpectedly called with "1"')
191191

@@ -198,7 +198,7 @@ describe('module remove', () => {
198198
args: {
199199
cwd: '/fake-dir',
200200
skipConfig: true,
201-
_: ['@nuxt/content'],
201+
moduleName: ['@nuxt/content'],
202202
},
203203
})
204204

@@ -215,7 +215,7 @@ describe('module remove', () => {
215215
awaitremoveCommand.setup({
216216
args: {
217217
cwd: '/fake-dir',
218-
_: ['@nuxt/content'],
218+
moduleName: ['@nuxt/content'],
219219
},
220220
})
221221

@@ -239,7 +239,7 @@ describe('module remove', () => {
239239
awaitremoveCommand.setup({
240240
args: {
241241
cwd: '/fake-dir',
242-
_: ['@vee-validate/nuxt'],
242+
moduleName: ['@vee-validate/nuxt'],
243243
},
244244
})
245245

@@ -265,7 +265,7 @@ describe('module remove', () => {
265265
))
266266

267267
constremoveCommand=await(commandsasCommandsType).subCommands.remove()
268-
awaitremoveCommand.setup({args: {cwd: '/fake-dir',_: ['@example/nuxt']}})
268+
awaitremoveCommand.setup({args: {cwd: '/fake-dir',moduleName: ['@example/nuxt']}})
269269

270270
expect(confirm).not.toHaveBeenCalled()
271271
expect(removeDependency).toHaveBeenCalledWith(['@example/nuxt'],expect.objectContaining({cwd: '/fake-dir'}))
@@ -288,7 +288,7 @@ describe('module remove', () => {
288288
awaitremoveCommand.setup({
289289
args: {
290290
cwd: '/fake-dir',
291-
_: ['@vee-validate/nuxt'],
291+
moduleName: ['@vee-validate/nuxt'],
292292
},
293293
})
294294

@@ -323,7 +323,7 @@ describe('module remove', () => {
323323
})
324324

325325
constremoveCommand=await(commandsasCommandsType).subCommands.remove()
326-
awaitremoveCommand.setup({args: {cwd: '/fake-dir',_: ['@vee-validate/nuxt']}})
326+
awaitremoveCommand.setup({args: {cwd: '/fake-dir',moduleName: ['@vee-validate/nuxt']}})
327327

328328
expect(peak).toBeGreaterThan(1)
329329
})
@@ -351,7 +351,7 @@ describe('module remove', () => {
351351
awaitremoveCommand.setup({
352352
args: {
353353
cwd: '/fake-dir',
354-
_: ['@vee-validate/nuxt'],
354+
moduleName: ['@vee-validate/nuxt'],
355355
},
356356
})
357357

‎packages/nuxt-cli/test/unit/help.spec.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,11 +492,11 @@ describe('help', () => {
492492
expect(awaitusage(awaitsubCommand(commands.module,'remove'),commands.module)).toMatchInlineSnapshot(`
493493
"Remove Nuxt modules (module remove)
494494
495-
USAGE module remove [OPTIONS] [MODULENAME]
495+
USAGE module remove [OPTIONS] [MODULENAME...]
496496
497497
ARGUMENTS
498498
499-
MODULENAME Specify one or more modules to remove by name, separated by spaces
499+
MODULENAME... Specify one or more modules to remove by name, separated by spaces
500500
501501
OPTIONS
502502

‎packages/nuxt-cli/test/unit/utils/headless.spec.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ describe('getHeadlessCommand', () => {
3131
expect(getHeadlessCommand({ ...base,dir: 'my app',modules: ['@nuxt/ui','@nuxt/image'],force: true}).join(' ')).toBe('nuxt init \'my app\' --template=minimal --packageManager=pnpm --gitInit --modules=@nuxt/ui,@nuxt/image --force')
3232
})
3333

34+
it('should separate the options from an `npm create` prefix',()=>{
35+
expect(getHeadlessCommand({ ...base,prefix: 'npm create nuxt@latest'}).join(' ')).toBe('npm create nuxt@latest my-app -- --template=minimal --packageManager=pnpm --gitInit --no-modules')
36+
})
37+
38+
it('should pass the options straight to other package managers',()=>{
39+
expect(getHeadlessCommand({ ...base,prefix: 'pnpm create nuxt@latest'}).join(' ')).toBe('pnpm create nuxt@latest my-app --template=minimal --packageManager=pnpm --gitInit --no-modules')
40+
})
41+
3442
it('should carry the nightly channel through',()=>{
3543
expect(getHeadlessCommand({ ...base,nightly: 'latest'}).join(' ')).toContain('--nightly=latest')
3644
})

‎scripts/generate-command-docs.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ interface DocEntry {
4848
cli?: 'nuxt'|'create-nuxt'
4949
/** Overrides the `npx nuxt <command>` prefix of the usage line. */
5050
usage?: string
51+
/**
52+
* Fence the options off from the prefix with `--`, for a command run through
53+
* `npm create`, which otherwise reads them as npm's own config.
54+
*/
55+
separator?: boolean
5156
}
5257

5358
/**
@@ -70,7 +75,7 @@ const DOCS: DocEntry[] = [
7075
{id: 'docs',file: 'docs.md',command: ['docs']},
7176
{id: 'generate',file: 'generate.md',command: ['generate']},
7277
{id: 'info',file: 'info.md',command: ['info']},
73-
{id: 'init',file: 'init.md',command: [],cli: 'create-nuxt',usage: 'npm create nuxt@latest'},
78+
{id: 'init',file: 'init.md',command: [],cli: 'create-nuxt',usage: 'npm create nuxt@latest',separator: true},
7479
{id: 'module-add',file: 'module.md',command: ['module','add']},
7580
{id: 'module-remove',file: 'module.md',command: ['module','remove']},
7681
{id: 'module-search',file: 'module.md',command: ['module','search']},
@@ -187,6 +192,7 @@ function render(entry: DocEntry, args: ArgsDef, inherited: ArgsDef): Blocks {
187192
constsignature=positionalSignature(name,arg)
188193
returnarg.required===false||arg.default!==undefined ? `[${signature}]` : `<${signature}>`
189194
}),
195+
...entry.separator&&options.length ? ['--'] : [],
190196
...options.map(([name,arg])=>`[${flagSignature(name,arg)}]`),
191197
].join(' ')
192198

0 commit comments

Comments
 (0)