diff options
Diffstat (limited to 'deps/npm/lib')
-rw-r--r-- | deps/npm/lib/ci.js | 4 | ||||
-rw-r--r-- | deps/npm/lib/config/cmd-list.js | 1 | ||||
-rw-r--r-- | deps/npm/lib/config/defaults.js | 8 | ||||
-rw-r--r-- | deps/npm/lib/doctor/check-ping.js | 2 | ||||
-rw-r--r-- | deps/npm/lib/fund.js | 202 | ||||
-rw-r--r-- | deps/npm/lib/help.js | 15 | ||||
-rw-r--r-- | deps/npm/lib/install.js | 26 | ||||
-rw-r--r-- | deps/npm/lib/install/actions.js | 2 | ||||
-rw-r--r-- | deps/npm/lib/install/deps.js | 15 | ||||
-rw-r--r-- | deps/npm/lib/install/fund.js | 48 | ||||
-rw-r--r-- | deps/npm/lib/install/inflate-shrinkwrap.js | 7 | ||||
-rw-r--r-- | deps/npm/lib/install/read-shrinkwrap.js | 3 | ||||
-rw-r--r-- | deps/npm/lib/install/validate-args.js | 25 | ||||
-rw-r--r-- | deps/npm/lib/npm.js | 22 | ||||
-rw-r--r-- | deps/npm/lib/pack.js | 4 | ||||
-rw-r--r-- | deps/npm/lib/shrinkwrap.js | 8 | ||||
-rw-r--r-- | deps/npm/lib/token.js | 1 | ||||
-rw-r--r-- | deps/npm/lib/unbuild.js | 7 | ||||
-rw-r--r-- | deps/npm/lib/utils/error-message.js | 5 | ||||
-rw-r--r-- | deps/npm/lib/utils/funding.js | 153 | ||||
-rw-r--r-- | deps/npm/lib/utils/open-url.js | 23 | ||||
-rw-r--r-- | deps/npm/lib/utils/unsupported.js | 5 | ||||
-rw-r--r-- | deps/npm/lib/version.js | 2 |
23 files changed, 543 insertions, 45 deletions
diff --git a/deps/npm/lib/ci.js b/deps/npm/lib/ci.js index 309ad2f784..a0df3b86ff 100644 --- a/deps/npm/lib/ci.js +++ b/deps/npm/lib/ci.js @@ -4,6 +4,7 @@ const npm = require('./npm.js') const Installer = require('libcipm') const log = require('npmlog') const path = require('path') +const pack = require('./pack.js') ci.usage = 'npm ci' @@ -27,7 +28,8 @@ function ci (args, cb) { fmode: npm.modes.file, umask: npm.modes.umask, npmVersion: npm.version, - tmp: npm.tmp + tmp: npm.tmp, + dirPacker: pack.packGitDep } for (const key in npm.config.list[0]) { diff --git a/deps/npm/lib/config/cmd-list.js b/deps/npm/lib/config/cmd-list.js index fa4390fcdc..d9d0d85b7d 100644 --- a/deps/npm/lib/config/cmd-list.js +++ b/deps/npm/lib/config/cmd-list.js @@ -91,6 +91,7 @@ var cmdList = [ 'token', 'profile', 'audit', + 'fund', 'org', 'help', diff --git a/deps/npm/lib/config/defaults.js b/deps/npm/lib/config/defaults.js index f563357d4c..e07da3aaf9 100644 --- a/deps/npm/lib/config/defaults.js +++ b/deps/npm/lib/config/defaults.js @@ -141,6 +141,9 @@ Object.defineProperty(exports, 'defaults', {get: function () { editor: osenv.editor(), 'engine-strict': false, force: false, + 'format-package-lock': true, + + fund: true, 'fetch-retries': 2, 'fetch-retry-factor': 10, @@ -201,7 +204,8 @@ Object.defineProperty(exports, 'defaults', {get: function () { 'user-agent': 'npm/{npm-version} ' + 'node/{node-version} ' + '{platform} ' + - '{arch}', + '{arch} ' + + '{ci}', 'read-only': false, 'rebuild-bundle': true, registry: 'https://registry.npmjs.org/', @@ -282,6 +286,8 @@ exports.types = { editor: String, 'engine-strict': Boolean, force: Boolean, + fund: Boolean, + 'format-package-lock': Boolean, 'fetch-retries': Number, 'fetch-retry-factor': Number, 'fetch-retry-mintimeout': Number, diff --git a/deps/npm/lib/doctor/check-ping.js b/deps/npm/lib/doctor/check-ping.js index 70db255480..58f14fe69e 100644 --- a/deps/npm/lib/doctor/check-ping.js +++ b/deps/npm/lib/doctor/check-ping.js @@ -8,7 +8,7 @@ function checkPing (cb) { if (err && err.code && err.code.match(/^E\d{3}$/)) { return cb(null, [err.code.substr(1)]) } else { - cb(null, [200, 'OK']) + cb(null, [200, 'ok']) } }) } diff --git a/deps/npm/lib/fund.js b/deps/npm/lib/fund.js new file mode 100644 index 0000000000..00954c844d --- /dev/null +++ b/deps/npm/lib/fund.js @@ -0,0 +1,202 @@ +'use strict' + +const path = require('path') + +const archy = require('archy') +const figgyPudding = require('figgy-pudding') +const readPackageTree = require('read-package-tree') + +const npm = require('./npm.js') +const npmConfig = require('./config/figgy-config.js') +const fetchPackageMetadata = require('./fetch-package-metadata.js') +const computeMetadata = require('./install/deps.js').computeMetadata +const readShrinkwrap = require('./install/read-shrinkwrap.js') +const mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js') +const output = require('./utils/output.js') +const openUrl = require('./utils/open-url.js') +const { getFundingInfo, retrieveFunding, validFundingUrl } = require('./utils/funding.js') + +const FundConfig = figgyPudding({ + browser: {}, // used by ./utils/open-url + global: {}, + json: {}, + unicode: {} +}) + +module.exports = fundCmd + +const usage = require('./utils/usage') +fundCmd.usage = usage( + 'fund', + 'npm fund [--json]', + 'npm fund [--browser] [[<@scope>/]<pkg>' +) + +fundCmd.completion = function (opts, cb) { + const argv = opts.conf.argv.remain + switch (argv[2]) { + case 'fund': + return cb(null, []) + default: + return cb(new Error(argv[2] + ' not recognized')) + } +} + +function printJSON (fundingInfo) { + return JSON.stringify(fundingInfo, null, 2) +} + +// the human-printable version does some special things that turned out to +// be very verbose but hopefully not hard to follow: we stack up items +// that have a shared url/type and make sure they're printed at the highest +// level possible, in that process they also carry their dependencies along +// with them, moving those up in the visual tree +function printHuman (fundingInfo, opts) { + // mapping logic that keeps track of seen items in order to be able + // to push all other items from the same type/url in the same place + const seen = new Map() + + function seenKey ({ type, url } = {}) { + return url ? String(type) + String(url) : null + } + + function setStackedItem (funding, result) { + const key = seenKey(funding) + if (key && !seen.has(key)) seen.set(key, result) + } + + function retrieveStackedItem (funding) { + const key = seenKey(funding) + if (key && seen.has(key)) return seen.get(key) + } + + // --- + + const getFundingItems = (fundingItems) => + Object.keys(fundingItems || {}).map((fundingItemName) => { + // first-level loop, prepare the pretty-printed formatted data + const fundingItem = fundingItems[fundingItemName] + const { version, funding } = fundingItem + const { type, url } = funding || {} + + const printableVersion = version ? `@${version}` : '' + const printableType = type && { label: `type: ${funding.type}` } + const printableUrl = url && { label: `url: ${funding.url}` } + const result = { + fundingItem, + label: fundingItemName + printableVersion, + nodes: [] + } + + if (printableType) { + result.nodes.push(printableType) + } + + if (printableUrl) { + result.nodes.push(printableUrl) + } + + setStackedItem(funding, result) + + return result + }).reduce((res, result) => { + // recurse and exclude nodes that are going to be stacked together + const { fundingItem } = result + const { dependencies, funding } = fundingItem + const items = getFundingItems(dependencies) + const stackedResult = retrieveStackedItem(funding) + items.forEach(i => result.nodes.push(i)) + + if (stackedResult && stackedResult !== result) { + stackedResult.label += `, ${result.label}` + items.forEach(i => stackedResult.nodes.push(i)) + return res + } + + res.push(result) + + return res + }, []) + + const [ result ] = getFundingItems({ + [fundingInfo.name]: { + dependencies: fundingInfo.dependencies, + funding: fundingInfo.funding, + version: fundingInfo.version + } + }) + + return archy(result, '', { unicode: opts.unicode }) +} + +function openFundingUrl (packageName, cb) { + function getUrlAndOpen (packageMetadata) { + const { funding } = packageMetadata + const { type, url } = retrieveFunding(funding) || {} + const noFundingError = + new Error(`No funding method available for: ${packageName}`) + noFundingError.code = 'ENOFUND' + const typePrefix = type ? `${type} funding` : 'Funding' + const msg = `${typePrefix} available at the following URL` + + if (validFundingUrl(funding)) { + openUrl(url, msg, cb) + } else { + throw noFundingError + } + } + + fetchPackageMetadata( + packageName, + '.', + { fullMetadata: true }, + function (err, packageMetadata) { + if (err) return cb(err) + getUrlAndOpen(packageMetadata) + } + ) +} + +function fundCmd (args, cb) { + const opts = FundConfig(npmConfig()) + const dir = path.resolve(npm.dir, '..') + const packageName = args[0] + + if (opts.global) { + const err = new Error('`npm fund` does not support globals') + err.code = 'EFUNDGLOBAL' + throw err + } + + if (packageName) { + openFundingUrl(packageName, cb) + return + } + + readPackageTree(dir, function (err, tree) { + if (err) { + process.exitCode = 1 + return cb(err) + } + + readShrinkwrap.andInflate(tree, function () { + const fundingInfo = getFundingInfo( + mutateIntoLogicalTree.asReadInstalled( + computeMetadata(tree) + ) + ) + + const print = opts.json + ? printJSON + : printHuman + + output( + print( + fundingInfo, + opts + ) + ) + cb(err, tree) + }) + }) +} diff --git a/deps/npm/lib/help.js b/deps/npm/lib/help.js index 3f70f2dc1f..61f1f3f94c 100644 --- a/deps/npm/lib/help.js +++ b/deps/npm/lib/help.js @@ -63,7 +63,7 @@ function help (args, cb) { // legacy if (section === 'global') section = 'folders' - else if (section === 'json') section = 'package.json' + else if (section.match(/.*json/)) section = section.replace('.json', '-json') // find either /section.n or /npm-section.n // The glob is used in the glob. The regexp is used much @@ -140,24 +140,21 @@ function viewMan (man, cb) { function htmlMan (man) { var sect = +man.match(/([0-9]+)$/)[1] - var f = path.basename(man).replace(/([0-9]+)$/, 'html') + var f = path.basename(man).replace(/[.]([0-9]+)$/, '') switch (sect) { case 1: - sect = 'cli' - break - case 3: - sect = 'api' + sect = 'cli-commands' break case 5: - sect = 'files' + sect = 'configuring-npm' break case 7: - sect = 'misc' + sect = 'using-npm' break default: throw new Error('invalid man section: ' + sect) } - return path.resolve(__dirname, '..', 'html', 'doc', sect, f) + return path.resolve(__dirname, '..', 'docs', 'public', sect, f, 'index.html') } function npmUsage (valid, cb) { diff --git a/deps/npm/lib/install.js b/deps/npm/lib/install.js index 8cc6d16bdd..378ada7b05 100644 --- a/deps/npm/lib/install.js +++ b/deps/npm/lib/install.js @@ -26,6 +26,7 @@ install.usage = usage( '\nnpm install [<@scope>/]<pkg>@<tag>' + '\nnpm install [<@scope>/]<pkg>@<version>' + '\nnpm install [<@scope>/]<pkg>@<version range>' + + '\nnpm install <alias>@npm:<name>' + '\nnpm install <folder>' + '\nnpm install <tarball file>' + '\nnpm install <tarball url>' + @@ -138,6 +139,10 @@ var validateArgs = require('./install/validate-args.js') var saveRequested = require('./install/save.js').saveRequested var saveShrinkwrap = require('./install/save.js').saveShrinkwrap var audit = require('./install/audit.js') +var { + getPrintFundingReport, + getPrintFundingReportJSON +} = require('./install/fund.js') var getSaveType = require('./install/save.js').getSaveType var doSerialActions = require('./install/actions.js').doSerial var doReverseSerialActions = require('./install/actions.js').doReverseSerial @@ -240,6 +245,7 @@ function Installer (where, dryrun, args, opts) { this.saveOnlyLock = opts.saveOnlyLock this.global = opts.global != null ? opts.global : this.where === path.resolve(npm.globalDir, '..') this.audit = npm.config.get('audit') && !this.global + this.fund = npm.config.get('fund') && !this.global this.started = Date.now() } Installer.prototype = {} @@ -872,7 +878,6 @@ Installer.prototype.printInstalledForHuman = function (diffs, auditResult) { report += ' in ' + ((Date.now() - this.started) / 1000) + 's' output(report) - return auditResult && audit.printInstallReport(auditResult) function packages (num) { return num + ' package' + (num > 1 ? 's' : '') @@ -894,9 +899,27 @@ Installer.prototype.printInstalledForHuman = function (diffs, auditResult) { if (argument.url) returned += ' (' + argument.email + ')' return returned } + + const { fund, idealTree } = this + const printFundingReport = getPrintFundingReport({ + fund, + idealTree + }) + if (printFundingReport.length) { + output(printFundingReport) + } + + if (auditResult) { + return audit.printInstallReport(auditResult) + } } Installer.prototype.printInstalledForJSON = function (diffs, auditResult) { + const { fund, idealTree } = this + const printFundingReport = getPrintFundingReportJSON({ + fund, + idealTree + }) var result = { added: [], removed: [], @@ -905,6 +928,7 @@ Installer.prototype.printInstalledForJSON = function (diffs, auditResult) { failed: [], warnings: [], audit: auditResult, + funding: printFundingReport, elapsed: Date.now() - this.started } var self = this diff --git a/deps/npm/lib/install/actions.js b/deps/npm/lib/install/actions.js index a34d03ffe2..e26432b77c 100644 --- a/deps/npm/lib/install/actions.js +++ b/deps/npm/lib/install/actions.js @@ -49,7 +49,7 @@ Object.keys(actions).forEach(function (actionName) { if (pkg.knownInstallable) { actionP = runAction(action, staging, pkg, log) } else { - actionP = isInstallable(pkg.package).then(() => { + actionP = isInstallable(null, pkg.package).then(() => { pkg.knownInstallable = true return runAction(action, staging, pkg, log) }) diff --git a/deps/npm/lib/install/deps.js b/deps/npm/lib/install/deps.js index bfc94ae504..3d8b333c64 100644 --- a/deps/npm/lib/install/deps.js +++ b/deps/npm/lib/install/deps.js @@ -203,10 +203,15 @@ function removeObsoleteDep (child, log) { function packageRelativePath (tree) { if (!tree) return '' var requested = tree.package._requested || {} - var isLocal = requested.type === 'directory' || requested.type === 'file' - return isLocal ? requested.fetchSpec - : (tree.isLink || tree.isInLink) && !preserveSymlinks() ? tree.realpath - : tree.path + if (requested.type === 'directory') { + return requested.fetchSpec + } else if (requested.type === 'file') { + return path.dirname(requested.fetchSpec) + } else if ((tree.isLink || tree.isInLink) && !preserveSymlinks()) { + return tree.realpath + } else { + return tree.path + } } function matchingDep (tree, name) { @@ -665,7 +670,7 @@ function resolveWithNewModule (pkg, tree, log, next) { validate('OOOF', arguments) log.silly('resolveWithNewModule', packageId(pkg), 'checking installable status') - return isInstallable(pkg, (err) => { + return isInstallable(tree, pkg, (err) => { let installable = !err addBundled(pkg, (bundleErr) => { var parent = earliestInstallable(tree, tree, pkg, log) || tree diff --git a/deps/npm/lib/install/fund.js b/deps/npm/lib/install/fund.js new file mode 100644 index 0000000000..809c05b338 --- /dev/null +++ b/deps/npm/lib/install/fund.js @@ -0,0 +1,48 @@ +'use strict' + +const { EOL } = require('os') + +const computeMetadata = require('./deps.js').computeMetadata +const mutateIntoLogicalTree = require('./mutate-into-logical-tree.js') +var { getFundingInfo } = require('../utils/funding.js') + +exports.getPrintFundingReport = getPrintFundingReport +exports.getPrintFundingReportJSON = getPrintFundingReportJSON + +function getFundingResult ({ fund, idealTree }) { + if (fund) { + const fundingInfoTree = + mutateIntoLogicalTree.asReadInstalled( + computeMetadata(idealTree) + ) + const fundResult = getFundingInfo(fundingInfoTree, { countOnly: true }) + return fundResult + } else { + return {} + } +} + +function getPrintFundingReport ({ fund, idealTree }, opts) { + const fundResult = getFundingResult({ fund, idealTree }) + const { length } = fundResult || {} + const { json } = opts || {} + + function padding (msg) { + return json ? '' : (EOL + msg) + } + + function packageQuantity (amount) { + return `package${amount > 1 ? 's are' : ' is'}` + } + + if (!length) return '' + + return padding('') + length + ' ' + + packageQuantity(length) + + ' looking for funding' + + padding(' run `npm fund` for details\n') +} + +function getPrintFundingReportJSON ({ fund, idealTree }) { + return getPrintFundingReport({ fund, idealTree }, { json: true }) +} diff --git a/deps/npm/lib/install/inflate-shrinkwrap.js b/deps/npm/lib/install/inflate-shrinkwrap.js index b0b71ef6b1..1ec4f9ba6d 100644 --- a/deps/npm/lib/install/inflate-shrinkwrap.js +++ b/deps/npm/lib/install/inflate-shrinkwrap.js @@ -141,6 +141,7 @@ function isGit (sw) { } function makeFakeChild (name, topPath, tree, sw, requested) { + const isDirectory = requested.type === 'directory' const from = sw.from || requested.raw const pkg = { name: name, @@ -167,16 +168,16 @@ function makeFakeChild (name, topPath, tree, sw, requested) { } const child = createChild({ package: pkg, - loaded: true, + loaded: isDirectory, parent: tree, children: [], fromShrinkwrap: requested, fakeChild: sw, fromBundle: sw.bundled ? tree.fromBundle || tree : null, path: childPath(tree.path, pkg), - realpath: requested.type === 'directory' ? requested.fetchSpec : childPath(tree.realpath, pkg), + realpath: isDirectory ? requested.fetchSpec : childPath(tree.realpath, pkg), location: (tree.location === '/' ? '' : tree.location + '/') + pkg.name, - isLink: requested.type === 'directory', + isLink: isDirectory, isInLink: tree.isLink || tree.isInLink, swRequires: sw.requires }) diff --git a/deps/npm/lib/install/read-shrinkwrap.js b/deps/npm/lib/install/read-shrinkwrap.js index 7074678011..1d9fb99c1d 100644 --- a/deps/npm/lib/install/read-shrinkwrap.js +++ b/deps/npm/lib/install/read-shrinkwrap.js @@ -19,8 +19,7 @@ function readShrinkwrap (child, next) { maybeReadFile('npm-shrinkwrap.json', child), // Don't read non-root lockfiles child.isTop && maybeReadFile('package-lock.json', child), - child.isTop && maybeReadFile('package.json', child), - (shrinkwrap, lockfile, pkgJson) => { + (shrinkwrap, lockfile) => { if (shrinkwrap && lockfile) { log.warn('read-shrinkwrap', 'Ignoring package-lock.json because there is already an npm-shrinkwrap.json. Please use only one of the two.') } diff --git a/deps/npm/lib/install/validate-args.js b/deps/npm/lib/install/validate-args.js index 65b660417a..b680a1b24b 100644 --- a/deps/npm/lib/install/validate-args.js +++ b/deps/npm/lib/install/validate-args.js @@ -16,7 +16,7 @@ module.exports = function (idealTree, args, next) { chain([ [hasMinimumFields, pkg], [checkSelf, idealTree, pkg, force], - [isInstallable, pkg] + [isInstallable, idealTree, pkg] ], done) }, next) } @@ -31,13 +31,24 @@ function hasMinimumFields (pkg, cb) { } } -function getWarnings (pkg) { - while (pkg.parent) pkg = pkg.parent - if (!pkg.warnings) pkg.warnings = [] - return pkg.warnings +function setWarnings (idealTree, warn) { + function top (tree) { + if (tree.parent) return top(tree.parent) + return tree + } + + var topTree = top(idealTree) + if (!topTree.warnings) topTree.warnings = [] + + if (topTree.warnings.every(i => ( + i.code !== warn.code || + i.required !== warn.required || + i.pkgid !== warn.pkgid))) { + topTree.warnings.push(warn) + } } -var isInstallable = module.exports.isInstallable = function (pkg, next) { +var isInstallable = module.exports.isInstallable = function (idealTree, pkg, next) { var force = npm.config.get('force') var nodeVersion = npm.config.get('node-version') if (/-/.test(nodeVersion)) { @@ -48,7 +59,7 @@ var isInstallable = module.exports.isInstallable = function (pkg, next) { var strict = npm.config.get('engine-strict') checkEngine(pkg, npm.version, nodeVersion, force, strict, iferr(next, thenWarnEngineIssues)) function thenWarnEngineIssues (warn) { - if (warn) getWarnings(pkg).push(warn) + if (idealTree && warn) setWarnings(idealTree, warn) checkPlatform(pkg, force, next) } } diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js index 2ee9a99126..35850078f8 100644 --- a/deps/npm/lib/npm.js +++ b/deps/npm/lib/npm.js @@ -281,7 +281,27 @@ ua = ua.replace(/\{npm-version\}/gi, npm.version) ua = ua.replace(/\{platform\}/gi, process.platform) ua = ua.replace(/\{arch\}/gi, process.arch) - config.set('user-agent', ua) + + // continuous integration platforms + const ci = process.env.GERRIT_PROJECT ? 'ci/gerrit' + : process.env.GITLAB_CI ? 'ci/gitlab' + : process.env.CIRCLECI ? 'ci/circle-ci' + : process.env.SEMAPHORE ? 'ci/semaphore' + : process.env.DRONE ? 'ci/drone' + : process.env.GITHUB_ACTION ? 'ci/github-actions' + : process.env.TDDIUM ? 'ci/tddium' + : process.env.JENKINS_URL ? 'ci/jenkins' + : process.env['bamboo.buildKey'] ? 'ci/bamboo' + : process.env.GO_PIPELINE_NAME ? 'ci/gocd' + // codeship and a few others + : process.env.CI_NAME ? `ci/${process.env.CI_NAME}` + // test travis last, since many of these mimic it + : process.env.TRAVIS ? 'ci/travis-ci' + : process.env.CI === 'true' || process.env.CI === '1' ? 'ci/custom' + : '' + ua = ua.replace(/\{ci\}/gi, ci) + + config.set('user-agent', ua.trim()) if (config.get('metrics-registry') == null) { config.set('metrics-registry', config.get('registry')) diff --git a/deps/npm/lib/pack.js b/deps/npm/lib/pack.js index 78e5bfd174..8189cb6ced 100644 --- a/deps/npm/lib/pack.js +++ b/deps/npm/lib/pack.js @@ -4,6 +4,9 @@ // Packs the specified package into a .tgz file, which can then // be installed. +// Set this early to avoid issues with circular dependencies. +module.exports = pack + const BB = require('bluebird') const byteSize = require('byte-size') @@ -37,7 +40,6 @@ pack.usage = 'npm pack [[<@scope>/]<pkg>...] [--dry-run]' // if it can be installed, it can be packed. pack.completion = install.completion -module.exports = pack function pack (args, silent, cb) { const cwd = process.cwd() if (typeof cb !== 'function') { diff --git a/deps/npm/lib/shrinkwrap.js b/deps/npm/lib/shrinkwrap.js index 0a3f53546c..5428e7255b 100644 --- a/deps/npm/lib/shrinkwrap.js +++ b/deps/npm/lib/shrinkwrap.js @@ -282,11 +282,15 @@ function checkPackageFile (dir, name) { return readFile( file, 'utf8' ).then((data) => { + const format = npm.config.get('format-package-lock') !== false + const indent = format ? detectIndent(data).indent : 0 + const newline = format ? detectNewline(data) : 0 + return { path: file, raw: data, - indent: detectIndent(data).indent, - newline: detectNewline(data) + indent, + newline } }).catch({code: 'ENOENT'}, () => {}) } diff --git a/deps/npm/lib/token.js b/deps/npm/lib/token.js index 9b1fbef9ce..96a05e4566 100644 --- a/deps/npm/lib/token.js +++ b/deps/npm/lib/token.js @@ -118,7 +118,6 @@ function config () { }) } else { conf = conf.concat({ auth: {} }) - conf.auth = {} } if (conf.otp) conf.auth.otp = conf.otp return conf diff --git a/deps/npm/lib/unbuild.js b/deps/npm/lib/unbuild.js index e06ee5eb30..3e8d3e4f1f 100644 --- a/deps/npm/lib/unbuild.js +++ b/deps/npm/lib/unbuild.js @@ -78,8 +78,11 @@ function rmBins (pkg, folder, parent, top, cb) { const binRoot = top ? npm.bin : path.resolve(parent, '.bin') asyncMap(Object.keys(pkg.bin), function (b, cb) { if (process.platform === 'win32') { - chain([ [gentlyRm, path.resolve(binRoot, b) + '.cmd', true, folder], - [gentlyRm, path.resolve(binRoot, b), true, folder] ], cb) + chain([ + [gentlyRm, path.resolve(binRoot, b) + '.ps1', true, folder], + [gentlyRm, path.resolve(binRoot, b) + '.cmd', true, folder], + [gentlyRm, path.resolve(binRoot, b), true, folder] + ], cb) } else { gentlyRm(path.resolve(binRoot, b), true, folder, cb) } diff --git a/deps/npm/lib/utils/error-message.js b/deps/npm/lib/utils/error-message.js index 5ddfb37682..12f304d1e8 100644 --- a/deps/npm/lib/utils/error-message.js +++ b/deps/npm/lib/utils/error-message.js @@ -280,8 +280,9 @@ function errorMessage (er) { case 'EEXIST': short.push(['', er.message]) - short.push(['', 'File exists: ' + er.path]) - detail.push(['', 'Move it away, and try again.']) + short.push(['', 'File exists: ' + (er.dest || er.path)]) + detail.push(['', 'Remove the existing file and try again, or run npm']) + detail.push(['', 'with --force to overwrite files recklessly.']) break case 'ENEEDAUTH': diff --git a/deps/npm/lib/utils/funding.js b/deps/npm/lib/utils/funding.js new file mode 100644 index 0000000000..c3d06b1089 --- /dev/null +++ b/deps/npm/lib/utils/funding.js @@ -0,0 +1,153 @@ +'use strict' + +const URL = require('url').URL + +exports.getFundingInfo = getFundingInfo +exports.retrieveFunding = retrieveFunding +exports.validFundingUrl = validFundingUrl + +// supports both object funding and string shorthand +function retrieveFunding (funding) { + return typeof funding === 'string' + ? { + url: funding + } + : funding +} + +// Is the value of a `funding` property of a `package.json` +// a valid type+url for `npm fund` to display? +function validFundingUrl (funding) { + if (!funding) return false + + try { + var parsed = new URL(funding.url || funding) + } catch (error) { + return false + } + + if ( + parsed.protocol !== 'https:' && + parsed.protocol !== 'http:' + ) return false + + return Boolean(parsed.host) +} + +function getFundingInfo (idealTree, opts) { + let length = 0 + const seen = new Set() + const { countOnly } = opts || {} + const empty = () => Object.create(null) + const _trailingDependencies = Symbol('trailingDependencies') + + function tracked (name, version) { + const key = String(name) + String(version) + if (seen.has(key)) { + return true + } + seen.add(key) + } + + function retrieveDependencies (dependencies) { + const trailing = dependencies[_trailingDependencies] + + if (trailing) { + return Object.assign( + empty(), + dependencies, + trailing + ) + } + + return dependencies + } + + function hasDependencies (dependencies) { + return dependencies && ( + Object.keys(dependencies).length || + dependencies[_trailingDependencies] + ) + } + + function getFundingDependencies (tree) { + const deps = tree && tree.dependencies + if (!deps) return empty() + + // broken into two steps to make sure items appearance + // within top levels takes precedence over nested ones + return (Object.keys(deps)).map((key) => { + const dep = deps[key] + const { name, funding, version } = dep + + const fundingItem = {} + + // avoids duplicated items within the funding tree + if (tracked(name, version)) return empty() + + if (version) { + fundingItem.version = version + } + + if (funding && validFundingUrl(funding)) { + fundingItem.funding = retrieveFunding(funding) + length++ + } + + return { + dep, + fundingItem + } + }).reduce((res, { dep, fundingItem }, i) => { + if (!fundingItem) return res + + // recurse + const dependencies = dep.dependencies && + Object.keys(dep.dependencies).length > 0 && + getFundingDependencies(dep) + + // if we're only counting items there's no need + // to add all the data to the resulting object + if (countOnly) return null + + if (hasDependencies(dependencies)) { + fundingItem.dependencies = retrieveDependencies(dependencies) + } + + if (fundingItem.funding) { + res[dep.name] = fundingItem + } else if (fundingItem.dependencies) { + res[_trailingDependencies] = + Object.assign( + empty(), + res[_trailingDependencies], + fundingItem.dependencies + ) + } + + return res + }, empty()) + } + + const idealTreeDependencies = getFundingDependencies(idealTree) + const result = { + length + } + + if (!countOnly) { + result.name = idealTree.name || idealTree.path + + if (idealTree && idealTree.version) { + result.version = idealTree.version + } + + if (idealTree && idealTree.funding) { + result.funding = retrieveFunding(idealTree.funding) + } + + result.dependencies = + retrieveDependencies(idealTreeDependencies) + } + + return result +} diff --git a/deps/npm/lib/utils/open-url.js b/deps/npm/lib/utils/open-url.js index 7a48d2e868..e1ed2b3fab 100644 --- a/deps/npm/lib/utils/open-url.js +++ b/deps/npm/lib/utils/open-url.js @@ -5,9 +5,28 @@ const opener = require('opener') // attempt to open URL in web-browser, print address otherwise: module.exports = function open (url, errMsg, cb, browser = npm.config.get('browser')) { - opener(url, { command: npm.config.get('browser') }, (er) => { + function printAlternateMsg () { + const json = npm.config.get('json') + const alternateMsg = json + ? JSON.stringify({ + title: errMsg, + url + }, null, 2) + : `${errMsg}:\n\n${url}` + + output(alternateMsg) + } + + const skipBrowser = process.argv.indexOf('--no-browser') > -1 + + if (skipBrowser) { + printAlternateMsg() + return cb() + } + + opener(url, { command: browser }, (er) => { if (er && er.code === 'ENOENT') { - output(`${errMsg}:\n\n${url}`) + printAlternateMsg() return cb() } else { return cb(er) diff --git a/deps/npm/lib/utils/unsupported.js b/deps/npm/lib/utils/unsupported.js index 20cee157ee..71a304030e 100644 --- a/deps/npm/lib/utils/unsupported.js +++ b/deps/npm/lib/utils/unsupported.js @@ -6,9 +6,10 @@ var supportedNode = [ {ver: '9', min: '9.0.0'}, {ver: '10', min: '10.0.0'}, {ver: '11', min: '11.0.0'}, - {ver: '12', min: '12.0.0'} + {ver: '12', min: '12.0.0'}, + {ver: '13', min: '13.0.0'} ] -var knownBroken = '<6.0.0' +var knownBroken = '<6.2.0 || 9.0 - 9.2' var checkVersion = exports.checkVersion = function (version) { var versionNoPrerelease = version.replace(/-.*$/, '') diff --git a/deps/npm/lib/version.js b/deps/npm/lib/version.js index 0f1e97aedd..a8c2a648c7 100644 --- a/deps/npm/lib/version.js +++ b/deps/npm/lib/version.js @@ -256,7 +256,7 @@ function checkGit (localData, cb) { statGitFolder(function (er) { var doGit = !er && npm.config.get('git-tag-version') if (!doGit) { - if (er) log.verbose('version', 'error checking for .git', er) + if (er && npm.config.get('git-tag-version')) log.verbose('version', 'error checking for .git', er) log.verbose('version', 'not tagging in git') return cb(null, false) } |