Skip to content

Commit

Permalink
create a flat options object to pass to deps
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed May 8, 2020
1 parent b9bc4f0 commit d594d8e
Show file tree
Hide file tree
Showing 5 changed files with 625 additions and 1 deletion.
6 changes: 6 additions & 0 deletions lib/config/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ Object.defineProperty(exports, 'defaults', {get: function () {
'ham-it-up': false,
heading: 'npm',
'if-present': false,
include: [],
'include-staged': false,
'ignore-prepublish': false,
'ignore-scripts': false,
'init-module': path.resolve(home, '.npm-init.js'),
Expand All @@ -185,6 +187,7 @@ Object.defineProperty(exports, 'defaults', {get: function () {
'node-options': null,
'node-version': process.version,
'offline': false,
omit: [],
'onload-script': false,
only: null,
optional: true,
Expand Down Expand Up @@ -304,6 +307,8 @@ exports.types = {
'ham-it-up': Boolean,
'heading': String,
'if-present': Boolean,
include: [Array, 'dev', 'optional', 'peer'],
'include-staged': Boolean,
'ignore-prepublish': Boolean,
'ignore-scripts': Boolean,
'init-module': path,
Expand All @@ -328,6 +333,7 @@ exports.types = {
'node-version': [null, semver],
'noproxy': [null, String, Array],
offline: Boolean,
omit: [Array, 'dev', 'optional', 'peer'],
'onload-script': [null, String],
only: [null, 'dev', 'development', 'prod', 'production'],
optional: Boolean,
Expand Down
216 changes: 216 additions & 0 deletions lib/config/flat-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
// return a flattened config object with canonical names suitable for
// passing to dependencies like arborist, pacote, npm-registry-fetch, etc.

const log = require('npmlog')
const crypto = require('crypto')
const npmSession = crypto.randomBytes(8).toString('hex')
log.verbose('npm-session', npmSession)
const {join} = require('path')

const buildOmitList = npm => {
const include = npm.config.get('include') || []
const omit = new Set((npm.config.get('omit') || [])
.filter(type => !include.includes(type)))
const only = npm.config.get('only')

if (/^prod(uction)?$/.test(only) || npm.config.get('production')) {
omit.add('dev')
}

if (/dev/.test(npm.config.get('also'))) {
omit.delete('dev')
}

if (npm.config.get('dev')) {
omit.delete('dev')
}

if (npm.config.get('optional') === false) {
omit.add('optional')
}

npm.config.set('omit', [...omit])
return [...omit]
}

const flatOptions = npm => npm.flatOptions || Object.freeze({
// Note that many of these do not come from configs or cli flags
// per se, though they may be implied or defined by them.
log,
npmSession,
dmode: npm.modes.exec,
fmode: npm.modes.file,
umask: npm.modes.umask,
hashAlgorithm: 'sha1', // XXX should this be sha512?
color: !!npm.color,
includeStaged: npm.config.get('include-staged'),

projectScope: npm.projectScope,
npmVersion: npm.version,
nodeVersion: npm.config.get('node-version'),
npmCommand: npm.command,

tmp: npm.tmp,
cache: join(npm.config.get('cache'), '_cacache'),
prefix: npm.prefix,
globalPrefix: npm.globalPrefix,
localPrefix: npm.localPrefix,
global: npm.config.get('global'),

metricsRegistry: npm.config.get('metrics-registry'),
sendMetrics: npm.config.get('send-metrics'),
registry: npm.config.get('registry'),
get scope () {
log.warn('FIXME', 'using opts.scope instead of opts.projectScope')
return npm.projectScope
},
access: npm.config.get('access'),
alwaysAuth: npm.config.get('always-auth'),
audit: npm.config.get('audit'),
auditLevel: npm.config.get('audit-level'),
authType: npm.config.get('auth-type'),
before: npm.config.get('before'),
browser: npm.config.get('browser'),
ca: npm.config.get('ca'),
cafile: npm.config.get('cafile'),
cert: npm.config.get('cert'),
key: npm.config.get('key'),

// XXX remove these when we don't use lockfile any more, once
// arborist is handling the installation process
cacheLockRetries: npm.config.get('cache-lock-retries'),
cacheLockStale: npm.config.get('cache-lock-stale'),
cacheLockWait: npm.config.get('cache-lock-wait'),
lockFile: {
retries: npm.config.get('cache-lock-retries'),
stale: npm.config.get('cache-lock-stale'),
wait: npm.config.get('cache-lock-wait')
},

// XXX remove these once no longer used
get cacheMax () {
log.warn('FIXME', 'using deprecated cacheMax option, should use offline/preferOffline/preferOnline')
return npm.config.get('cache-max')
},
get cacheMin () {
log.warn('FIXME', 'using deprecated cacheMin option, should use offline/preferOffline/preferOnline')
return npm.config.get('cache-min')
},

// token creation options
cidr: npm.config.get('cidr'),
readOnly: npm.config.get('read-only'),

// npm version options
preid: npm.config.get('preid'),
tagVersionPrefix: npm.config.get('tag-version-prefix'),
allowSameVersion: npm.config.get('allow-same-version'),

// npm version git options
message: npm.config.get('message'),
commitHooks: npm.config.get('commit-hooks'),
gitTagVersion: npm.config.get('git-tag-version'),
signGitCommit: npm.config.get('sign-git-commit'),
signGitTag: npm.config.get('sign-git-tag'),

// only used for npm ls in v7, not update
depth: npm.config.get('depth'),

// options for npm search
// XXX need to refactor these to a cleaner search: { ... } block,
// since libnpmsearch needs them in a different format anyway, or
// maybe just not include them here at all, and construct an options
// pojo in lib/search.js instead.
description: npm.config.get('description'),
searchexclude: npm.config.get('searchexclude'),
searchlimit: npm.config.get('searchlimit'),
searchopts: npm.config.get('searchopts'),
searchstaleness: npm.config.get('searchstaleness'),

dryRun: npm.config.get('dry-run'),
engineStrict: npm.config.get('engine-strict'),

retry: {
retries: npm.config.get('fetch-retries'),
factor: npm.config.get('fetch-retry-factor'),
maxTimeout: npm.config.get('fetch-retry-maxtimeout'),
minTimeout: npm.config.get('fetch-retry-mintimeout')
},

force: npm.config.get('force'),

formatPackageLock: npm.config.get('format-package-lock'),
fund: npm.config.get('fund'),

// binary locators
git: npm.config.get('git'),
npmBin: require.main.filename,
nodeBin: process.env.NODE || process.execPath,
viewer: npm.config.get('viewer'),
editor: npm.config.get('editor'),

// configs that affect how we build trees
binLinks: npm.config.get('bin-links'),
rebuildBundle: npm.config.get('rebuild-bundle'),
packageLock: npm.config.get('package-lock'),
packageLockOnly: npm.config.get('package-lock-only'),
globalStyle: npm.config.get('global-style'),
legacyBundling: npm.config.get('legacy-bundling'),
omit: buildOmitList(npm),

// used to build up the appropriate {add:{...}} options to Arborist.reify
save: npm.config.get('save'),
saveBundle: npm.config.get('save-bundle'),
saveDev: npm.config.get('save-dev'),
saveOptional: npm.config.get('save-optional'),
savePeer: npm.config.get('save-peer'),
saveProd: npm.config.get('save-prod'),
saveExact: npm.config.get('save-exact'),
savePrefix: npm.config.get('save-prefix'),

// configs for npm-registry-fetch
otp: npm.config.get('otp'),
offline: npm.config.get('offline'),
preferOffline: getPreferOffline(npm),
preferOnline: getPreferOnline(npm),
strictSSL: npm.config.get('strict-ssl'),
defaultTag: npm.config.get('tag'),
get tag () {
log.warn('FIXME', 'using tag option, should be defaultTag')
return npm.config.get('tag')
},
userAgent: npm.config.get('user-agent'),

...getScopesAndAuths(npm)
})

const getPreferOnline = npm => {
const po = npm.config.get('prefer-online')
if (po !== undefined) {
return po
}
return npm.config.get('cache-max') <= 0
}

const getPreferOffline = npm => {
const po = npm.config.get('prefer-offline')
if (po !== undefined) {
return po
}
return npm.config.get('cache-min') >= 9999
}

// pull out all the @scope:<key> and //host:key config fields
// these are used by npm-registry-fetch for authing against registries
const getScopesAndAuths = npm => {
const scopesAndAuths = {}
// pull out all the @scope:... configs into a flat object.
for (const key in npm.config.list[0]) {
if (/@.*:registry$/i.test(key) || /^\/\//.test(key)) {
scopesAndAuths[key] = npm.config.get(key)
}
}
return scopesAndAuths
}

module.exports = flatOptions
6 changes: 5 additions & 1 deletion lib/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@
}

npm.command = c
npm.config.set('command', c)
npm.flatOptions = require('./config/flat-options.js')(npm)
if (commandCache[a]) return commandCache[a]

var cmd = require(path.join(__dirname, a + '.js'))
Expand Down Expand Up @@ -151,6 +153,7 @@
return arg && arg.match
}).join(' ')
npm.referer = registryRefer
npm.config.set('refer', npm.referer)
}

cmd.apply(npm, args)
Expand Down Expand Up @@ -229,6 +232,7 @@
npm.config.loaded = true
loaded = true
loadCb(loadErr = er)
// XXX remove this in v7
onload = onload && npm.config.get('onload-script')
if (onload) {
try {
Expand Down Expand Up @@ -277,7 +281,7 @@

// Include npm-version and node-version in user-agent
var ua = config.get('user-agent') || ''
ua = ua.replace(/\{node-version\}/gi, process.version)
ua = ua.replace(/\{node-version\}/gi, npm.config.get('node-version'))
ua = ua.replace(/\{npm-version\}/gi, npm.version)
ua = ua.replace(/\{platform\}/gi, process.platform)
ua = ua.replace(/\{arch\}/gi, process.arch)
Expand Down
111 changes: 111 additions & 0 deletions tap-snapshots/test-tap-flat-options.js-TAP.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* IMPORTANT
* This snapshot file is auto-generated, but designed for humans.
* It should be checked into source control and tracked carefully.
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`test/tap/flat-options.js TAP basic > flat options 1`] = `
{
log: {},
npmSession: '12345',
dmode: 511,
fmode: 438,
umask: 18,
hashAlgorithm: 'sha1',
color: true,
includeStaged: undefined,
projectScope: '@npmcli',
npmVersion: '7.6.5',
nodeVersion: '1.2.3',
npmCommand: 'test',
tmp: '/tmp',
cache: 'cache/_cacache',
prefix: '/path/to/npm/cli',
globalPrefix: '/usr/local',
localPrefix: '/path/to/npm/cli',
global: 'global',
metricsRegistry: 'metrics-registry',
sendMetrics: 'send-metrics',
registry: 'registry',
scope: '@npmcli',
access: 'access',
alwaysAuth: 'always-auth',
audit: 'audit',
auditLevel: 'audit-level',
authType: 'auth-type',
before: 'before',
browser: 'browser',
ca: 'ca',
cafile: 'cafile',
cert: 'cert',
key: 'key',
cacheLockRetries: 'cache-lock-retries',
cacheLockStale: 'cache-lock-stale',
cacheLockWait: 'cache-lock-wait',
lockFile: {
retries: 'cache-lock-retries',
stale: 'cache-lock-stale',
wait: 'cache-lock-wait'
},
cacheMax: 'cache-max',
cacheMin: 'cache-min',
cidr: 'cidr',
readOnly: 'read-only',
preid: 'preid',
tagVersionPrefix: 'tag-version-prefix',
allowSameVersion: 'allow-same-version',
message: 'message',
commitHooks: 'commit-hooks',
gitTagVersion: 'git-tag-version',
signGitCommit: 'sign-git-commit',
signGitTag: 'sign-git-tag',
depth: 'depth',
description: 'description',
searchexclude: 'searchexclude',
searchlimit: 'searchlimit',
searchopts: 'searchopts',
searchstaleness: 'searchstaleness',
dryRun: 'dry-run',
engineStrict: 'engine-strict',
retry: {
retries: 'fetch-retries',
factor: 'fetch-retry-factor',
maxTimeout: 'fetch-retry-maxtimeout',
minTimeout: 'fetch-retry-mintimeout'
},
force: 'force',
formatPackageLock: 'format-package-lock',
fund: 'fund',
git: 'git',
npmBin: '/path/to/npm/bin.js',
nodeBin: '/path/to/some/node',
viewer: 'viewer',
editor: 'editor',
binLinks: 'bin-links',
rebuildBundle: 'rebuild-bundle',
packageLock: 'package-lock',
packageLockOnly: 'package-lock-only',
globalStyle: 'global-style',
legacyBundling: 'legacy-bundling',
omit: [],
save: 'save',
saveBundle: 'save-bundle',
saveDev: 'save-dev',
saveOptional: 'save-optional',
savePeer: 'save-peer',
saveProd: 'save-prod',
saveExact: 'save-exact',
savePrefix: 'save-prefix',
otp: 'otp',
offline: 'offline',
preferOffline: 'prefer-offline',
preferOnline: 'prefer-online',
strictSSL: 'strict-ssl',
defaultTag: 'tag',
tag: 'tag',
userAgent: 'user-agent',
'@scope:registry': '@scope:registry',
'//nerf.dart:_authToken': '//nerf.dart:_authToken'
}
`
Loading

0 comments on commit d594d8e

Please sign in to comment.