Skip to content
Open
34 changes: 29 additions & 5 deletions lib/base-cmd.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { log } = require('proc-log')
const { definitions: globalDefinitions } = require('@npmcli/config/lib/definitions')

class BaseCommand {
// these defaults can be overridden by individual commands
Expand All @@ -10,11 +11,11 @@ class BaseCommand {
static name = null
static description = null
static params = null
static definitions = globalDefinitions

// this is a static so that we can read from it without instantiating a command
// which would require loading the config
static get describeUsage () {
const { definitions } = require('@npmcli/config/lib/definitions')
const { aliases: cmdAliases } = require('./utils/cmd-list')
const seenExclusive = new Set()
const wrapWidth = 80
Expand All @@ -35,14 +36,14 @@ class BaseCommand {
if (seenExclusive.has(param)) {
continue
}
const { exclusive } = definitions[param]
let paramUsage = `${definitions[param].usage}`
const exclusive = this.definitions[param]?.exclusive
let paramUsage = this.definitions[param]?.usage || ''
if (exclusive) {
const exclusiveParams = [paramUsage]
seenExclusive.add(param)
for (const e of exclusive) {
seenExclusive.add(e)
exclusiveParams.push(definitions[e].usage)
exclusiveParams.push(this.definitions[e].usage)
}
paramUsage = `${exclusiveParams.join('|')}`
}
Expand Down Expand Up @@ -77,7 +78,17 @@ class BaseCommand {
constructor (npm) {
this.npm = npm

const { config } = this.npm
// If this command has custom definitions different from global, create a command-specific config
if (this.definitions !== globalDefinitions) {
this.config = this.npm.createConfig(this.definitions)
this.config.loadSync()
// Warn about unknown configs with custom definitions
if (!this.constructor.skipConfigValidation) {
this.config.warn(this.definitions)
}
}

const { config } = this

if (!this.constructor.skipConfigValidation) {
config.validate()
Expand All @@ -88,10 +99,23 @@ class BaseCommand {
}
}

get config () {
// Return command-specific config if it exists, otherwise use npm's config
return this._config || this.npm.config
}

set config (value) {
this._config = value
}

get name () {
return this.constructor.name
}

get definitions () {
return this.constructor.definitions
}

get description () {
return this.constructor.description
}
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ ${defData}

if (content.publishConfig) {
for (const key in content.publishConfig) {
this.npm.config.checkUnknown('publishConfig', key)
this.npm.config.checkUnknown('publishConfig', key, true)
}
const pkgPath = resolve(this.npm.prefix, 'package.json')
msg.push(`; "publishConfig" from ${pkgPath}`)
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class Publish extends BaseCommand {
Object.entries(manifest.publishConfig).filter(([key]) => !(key in cliFlags)))
if (logWarnings) {
for (const key in filteredPublishConfig) {
this.npm.config.checkUnknown('publishConfig', key)
this.npm.config.checkUnknown('publishConfig', key, true)
}
}
flatten(filteredPublishConfig, opts)
Expand Down
2 changes: 1 addition & 1 deletion lib/commands/unpublish.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class Unpublish extends BaseCommand {
const filteredPublishConfig = Object.fromEntries(
Object.entries(manifest.publishConfig).filter(([key]) => !(key in cliFlags)))
for (const key in filteredPublishConfig) {
this.npm.config.checkUnknown('publishConfig', key)
this.npm.config.checkUnknown('publishConfig', key, true)
}
flatten(filteredPublishConfig, opts)
}
Expand Down
23 changes: 19 additions & 4 deletions lib/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const { resolve, dirname, join } = require('node:path')
const Config = require('@npmcli/config')
const which = require('which')
const fs = require('node:fs/promises')
const { definitions, flatten, nerfDarts, shorthands } = require('@npmcli/config/lib/definitions')
const { definitions: globalDefinitions, flatten, nerfDarts, shorthands } = require('@npmcli/config/lib/definitions')
const usage = require('./utils/npm-usage.js')
const LogFile = require('./utils/log-file.js')
const Timers = require('./utils/timers.js')
Expand Down Expand Up @@ -37,6 +37,8 @@ class Npm {
#runId = new Date().toISOString().replace(/[.:]/g, '_')
#title = 'npm'
#argvClean = []
#argv = undefined
#excludeNpmCwd = undefined
#npmRoot = null

#display = null
Expand Down Expand Up @@ -64,14 +66,20 @@ class Npm {
} = {}) {
this.#display = new Display({ stdout, stderr })
this.#npmRoot = npmRoot
this.config = new Config({
this.#argv = argv
this.#excludeNpmCwd = excludeNpmCwd
this.config = this.createConfig(globalDefinitions)
}

createConfig (definitions) {
return new Config({
npmPath: this.#npmRoot,
definitions,
flatten,
nerfDarts,
shorthands,
argv: [...process.argv, ...argv],
excludeNpmCwd,
argv: [...process.argv, ...this.#argv],
excludeNpmCwd: this.#excludeNpmCwd,
})
}

Expand Down Expand Up @@ -227,6 +235,13 @@ class Npm {
process.env.npm_command = this.command
}

if (Command.definitions === globalDefinitions) {
this.config?.warn()
} else {
const cloned = this.config?.clone()
cloned.loadDefinitions(Command.definitions).warn()
}

if (this.config.get('usage')) {
return output.standard(command.usage)
}
Expand Down
18 changes: 9 additions & 9 deletions tap-snapshots/test/lib/commands/install.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ silly logfile done cleaning log files
verbose stack Error: The developer of this package has specified the following through devEngines
verbose stack Invalid devEngines.runtime
verbose stack Invalid name "nondescript" does not match "node" for "runtime"
verbose stack at Install.checkDevEngines ({CWD}/lib/base-cmd.js:181:27)
verbose stack at MockNpm.#exec ({CWD}/lib/npm.js:252:7)
verbose stack at MockNpm.exec ({CWD}/lib/npm.js:208:9)
verbose stack at Install.checkDevEngines ({CWD}/lib/base-cmd.js:205:27)
verbose stack at MockNpm.#exec ({CWD}/lib/npm.js:267:7)
verbose stack at MockNpm.exec ({CWD}/lib/npm.js:216:9)
error code EBADDEVENGINES
error EBADDEVENGINES The developer of this package has specified the following through devEngines
error EBADDEVENGINES Invalid devEngines.runtime
Expand Down Expand Up @@ -199,9 +199,9 @@ warn EBADDEVENGINES }
verbose stack Error: The developer of this package has specified the following through devEngines
verbose stack Invalid devEngines.runtime
verbose stack Invalid name "nondescript" does not match "node" for "runtime"
verbose stack at Install.checkDevEngines ({CWD}/lib/base-cmd.js:181:27)
verbose stack at MockNpm.#exec ({CWD}/lib/npm.js:252:7)
verbose stack at MockNpm.exec ({CWD}/lib/npm.js:208:9)
verbose stack at Install.checkDevEngines ({CWD}/lib/base-cmd.js:205:27)
verbose stack at MockNpm.#exec ({CWD}/lib/npm.js:267:7)
verbose stack at MockNpm.exec ({CWD}/lib/npm.js:216:9)
error code EBADDEVENGINES
error EBADDEVENGINES The developer of this package has specified the following through devEngines
error EBADDEVENGINES Invalid devEngines.runtime
Expand All @@ -225,9 +225,9 @@ silly logfile done cleaning log files
verbose stack Error: The developer of this package has specified the following through devEngines
verbose stack Invalid devEngines.runtime
verbose stack Invalid name "nondescript" does not match "node" for "runtime"
verbose stack at Install.checkDevEngines ({CWD}/lib/base-cmd.js:181:27)
verbose stack at MockNpm.#exec ({CWD}/lib/npm.js:252:7)
verbose stack at MockNpm.exec ({CWD}/lib/npm.js:208:9)
verbose stack at Install.checkDevEngines ({CWD}/lib/base-cmd.js:205:27)
verbose stack at MockNpm.#exec ({CWD}/lib/npm.js:267:7)
verbose stack at MockNpm.exec ({CWD}/lib/npm.js:216:9)
error code EBADDEVENGINES
error EBADDEVENGINES The developer of this package has specified the following through devEngines
error EBADDEVENGINES Invalid devEngines.runtime
Expand Down
Loading
Loading