diff --git a/lib/commands/config.js b/lib/commands/config.js index d9b593064b001..31dbc074a8372 100644 --- a/lib/commands/config.js +++ b/lib/commands/config.js @@ -366,6 +366,9 @@ ${defData} const { content } = await pkgJson.normalize(this.npm.prefix).catch(() => ({ content: {} })) if (content.publishConfig) { + for (const key in content.publishConfig) { + this.npm.config.checkUnknown('publishConfig', key) + } const pkgPath = resolve(this.npm.prefix, 'package.json') msg.push(`; "publishConfig" from ${pkgPath}`) msg.push('; This set of config values will be used at publish-time.', '') diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 1967e05a23534..cc15087f0b368 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -266,6 +266,11 @@ class Publish extends BaseCommand { // corresponding `publishConfig` settings const filteredPublishConfig = Object.fromEntries( Object.entries(manifest.publishConfig).filter(([key]) => !(key in cliFlags))) + if (logWarnings) { + for (const key in filteredPublishConfig) { + this.npm.config.checkUnknown('publishConfig', key) + } + } flatten(filteredPublishConfig, opts) } return manifest diff --git a/lib/commands/unpublish.js b/lib/commands/unpublish.js index 4944888fe5aca..e1c06d3184057 100644 --- a/lib/commands/unpublish.js +++ b/lib/commands/unpublish.js @@ -145,6 +145,9 @@ class Unpublish extends BaseCommand { // corresponding `publishConfig` settings const filteredPublishConfig = Object.fromEntries( Object.entries(manifest.publishConfig).filter(([key]) => !(key in cliFlags))) + for (const key in filteredPublishConfig) { + this.npm.config.checkUnknown('publishConfig', key) + } flatten(filteredPublishConfig, opts) } diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index 0d62bacd45fa1..df1505cea26a3 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -413,6 +413,13 @@ color = {COLOR} ; "publishConfig" from {CWD}/prefix/package.json ; This set of config values will be used at publish-time. -_authToken = (protected) +//some.registry:_authToken = (protected) +other = "not defined" registry = "https://some.registry" ` + +exports[`test/lib/commands/config.js TAP config list with publishConfig local > warns about unknown config 1`] = ` +Array [ + "Unknown publishConfig config /"other/". This will stop working in the next major version of npm.", +] +` diff --git a/tap-snapshots/test/lib/commands/publish.js.test.cjs b/tap-snapshots/test/lib/commands/publish.js.test.cjs index 81c7dbe908d24..4d3606b93bfa6 100644 --- a/tap-snapshots/test/lib/commands/publish.js.test.cjs +++ b/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -290,6 +290,15 @@ exports[`test/lib/commands/publish.js TAP re-loads publishConfig.registry if add exports[`test/lib/commands/publish.js TAP respects publishConfig.registry, runs appropriate scripts > new package version 1`] = ` +> @npmcli/test-package@1.0.0 prepublishOnly +> touch scripts-prepublishonly + +> @npmcli/test-package@1.0.0 publish +> touch scripts-publish + +> @npmcli/test-package@1.0.0 postpublish +> touch scripts-postpublish ++ @npmcli/test-package@1.0.0 ` exports[`test/lib/commands/publish.js TAP restricted access > must match snapshot 1`] = ` diff --git a/test/lib/commands/config.js b/test/lib/commands/config.js index 849f832554aab..bcd88915dc97a 100644 --- a/test/lib/commands/config.js +++ b/test/lib/commands/config.js @@ -164,8 +164,9 @@ t.test('config list with publishConfig', async t => { prefixDir: { 'package.json': JSON.stringify({ publishConfig: { + other: 'not defined', registry: 'https://some.registry', - _authToken: 'mytoken', + '//some.registry:_authToken': 'mytoken', }, }), }, @@ -173,7 +174,7 @@ t.test('config list with publishConfig', async t => { }) t.test('local', async t => { - const { npm, joinedOutput } = await loadMockNpmWithPublishConfig(t) + const { npm, logs, joinedOutput } = await loadMockNpmWithPublishConfig(t) await npm.exec('config', ['list']) @@ -182,6 +183,7 @@ t.test('config list with publishConfig', async t => { t.match(output, 'registry = "https://some.registry"') t.matchSnapshot(output, 'output matches snapshot') + t.matchSnapshot(logs.warn, 'warns about unknown config') }) t.test('global', async t => { diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index f310587418b1f..3d1d629e31ba4 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -29,11 +29,14 @@ t.test('respects publishConfig.registry, runs appropriate scripts', async t => { publish: 'touch scripts-publish', postpublish: 'touch scripts-postpublish', }, - publishConfig: { registry: alternateRegistry }, + publishConfig: { + other: 'not defined', + registry: alternateRegistry, + }, } - const { npm, joinedOutput, prefix, registry } = await loadNpmWithRegistry(t, { + const { npm, joinedOutput, logs, prefix, registry } = await loadNpmWithRegistry(t, { config: { - loglevel: 'silent', + loglevel: 'warn', [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token', }, prefixDir: { @@ -49,6 +52,7 @@ t.test('respects publishConfig.registry, runs appropriate scripts', async t => { t.equal(fs.existsSync(path.join(prefix, 'scripts-prepublish')), false, 'did not run prepublish') t.equal(fs.existsSync(path.join(prefix, 'scripts-publish')), true, 'ran publish') t.equal(fs.existsSync(path.join(prefix, 'scripts-postpublish')), true, 'ran postpublish') + t.same(logs.warn, ['Unknown publishConfig config "other". This will stop working in the next major version of npm.']) }) t.test('re-loads publishConfig.registry if added during script process', async t => { diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index 31dc77ea46cd0..996edf2b881fc 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -380,7 +380,7 @@ t.test('dryRun with no args', async t => { t.test('publishConfig no spec', async t => { const alternateRegistry = 'https://other.registry.npmjs.org' - const { joinedOutput, npm } = await loadMockNpm(t, { + const { logs, joinedOutput, npm } = await loadMockNpm(t, { config: { force: true, '//other.registry.npmjs.org/:_authToken': 'test-other-token', @@ -390,6 +390,7 @@ t.test('publishConfig no spec', async t => { name: pkg, version: '1.0.0', publishConfig: { + other: 'not defined', registry: alternateRegistry, }, }, null, 2), @@ -406,6 +407,10 @@ t.test('publishConfig no spec', async t => { registry.unpublish({ manifest }) await npm.exec('unpublish', []) t.equal(joinedOutput(), '- test-package') + t.same(logs.warn, [ + 'using --force Recommended protections disabled.', + 'Unknown publishConfig config "other". This will stop working in the next major version of npm.', + ]) }) t.test('prioritize CLI flags over publishConfig no spec', async t => { diff --git a/workspaces/config/lib/index.js b/workspaces/config/lib/index.js index fbc8c2365ac0d..cba2ebd3621c5 100644 --- a/workspaces/config/lib/index.js +++ b/workspaces/config/lib/index.js @@ -584,14 +584,14 @@ class Config { } // Some defaults like npm-version are not user-definable and thus don't have definitions if (where !== 'default') { - this.#checkUnknown(where, key) + this.checkUnknown(where, key) } conf.data[k] = v } } } - #checkUnknown (where, key) { + checkUnknown (where, key) { if (!this.definitions[key]) { if (internalEnv.includes(key)) { return