diff --git a/docs/content/commands/npm-init.md b/docs/content/commands/npm-init.md index cd0be4643e0ea..f3124a7768dfc 100644 --- a/docs/content/commands/npm-init.md +++ b/docs/content/commands/npm-init.md @@ -38,6 +38,8 @@ follows: * `npm init foo` -> `npm exec create-foo` * `npm init @usr/foo` -> `npm exec @usr/create-foo` * `npm init @usr` -> `npm exec @usr/create` +* `npm init @usr@2.0.0` -> `npm exec @usr/create@2.0.0` +* `npm init @usr/foo@2.0.0` -> `npm exec @usr/create-foo@2.0.0` If the initializer is omitted (by just calling `npm init`), init will fall back to legacy init behavior. It will ask you a bunch of questions, and diff --git a/lib/commands/init.js b/lib/commands/init.js index b8b6bd5d53e08..cff8340dcd707 100644 --- a/lib/commands/init.js +++ b/lib/commands/init.js @@ -85,8 +85,13 @@ class Init extends BaseCommand { const [initerName, ...otherArgs] = args let packageName = initerName + // Only a scope, possibly with a version if (/^@[^/]+$/.test(initerName)) { - packageName = initerName + '/create' + const [, scope, version] = initerName.split('@') + packageName = `@${scope}/create` + if (version) { + packageName = `${packageName}@${version}` + } } else { const req = npa(initerName) if (req.type === 'git' && req.hosted) { diff --git a/test/lib/commands/init.js b/test/lib/commands/init.js index 32816adbc272e..e7b2739341437 100644 --- a/test/lib/commands/init.js +++ b/test/lib/commands/init.js @@ -136,6 +136,44 @@ t.test('npm init @scope/name', async t => { await init.exec(['@npmcli/something']) }) +t.test('npm init @scope@spec', async t => { + t.plan(1) + npm.localPrefix = t.testdir({}) + + const Init = t.mock('../../../lib/commands/init.js', { + libnpmexec: ({ args }) => { + t.same( + args, + ['@npmcli/create@foo'], + 'should npx with scoped packages' + ) + }, + }) + const init = new Init(npm) + + process.chdir(npm.localPrefix) + await init.exec(['@npmcli@foo']) +}) + +t.test('npm init @scope/name@spec', async t => { + t.plan(1) + npm.localPrefix = t.testdir({}) + + const Init = t.mock('../../../lib/commands/init.js', { + libnpmexec: ({ args }) => { + t.same( + args, + ['@npmcli/create-something@foo'], + 'should npx with scoped packages' + ) + }, + }) + const init = new Init(npm) + + process.chdir(npm.localPrefix) + await init.exec(['@npmcli/something@foo']) +}) + t.test('npm init git spec', async t => { t.plan(1) npm.localPrefix = t.testdir({})