Skip to content

Commit

Permalink
install: add support for package aliases (npm#3)
Browse files Browse the repository at this point in the history
PR-URL: npm#3
Credit: @zkat
Reviewed-By: @aeschright
  • Loading branch information
zkat authored Feb 18, 2019
1 parent 2ce23ba commit b7b54f2
Show file tree
Hide file tree
Showing 14 changed files with 382 additions and 63 deletions.
24 changes: 19 additions & 5 deletions lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ Installer.prototype.normalizeCurrentTree = function (cb) {
if (this.currentTree.error) {
for (let child of this.currentTree.children) {
if (!child.fakeChild && isExtraneous(child)) {
this.currentTree.package.dependencies[child.package.name] = computeVersionSpec(this.currentTree, child)
this.currentTree.package.dependencies[moduleName(child)] = computeVersionSpec(this.currentTree, child)
}
}
}
Expand Down Expand Up @@ -825,7 +825,11 @@ Installer.prototype.printInstalledForHuman = function (diffs, auditResult) {
var report = ''
if (this.args.length && (added || updated)) {
report += this.args.map((p) => {
return `+ ${p.name}@${p.version}`
return `+ ${p.name}@${p.version}${
!p._requested.name || p._requested.name === p.name
? ''
: ` (as ${p._requested.name})`
}`
}).join('\n') + '\n'
}
var actions = []
Expand Down Expand Up @@ -922,10 +926,14 @@ Installer.prototype.printInstalledForJSON = function (diffs, auditResult) {
function recordAction (action) {
var mutation = action[0]
var child = action[1]
const isAlias = child.package && child.package._requested && child.package._requested.type === 'alias'
const name = isAlias
? child.package._requested.name
: child.package && child.package.name
var result = {
action: mutation,
name: moduleName(child),
version: child.package && child.package.version,
name,
version: child.package && `${isAlias ? `npm:${child.package.name}@` : ''}${child.package.version}`,
path: child.path
}
if (mutation === 'move') {
Expand All @@ -947,10 +955,16 @@ Installer.prototype.printInstalledForParseable = function (diffs) {
} else if (mutation === 'update') {
var previousVersion = child.oldPkg.package && child.oldPkg.package.version
}
const isAlias = child.package._requested && child.package._requested.type === 'alias'
const version = child.package && isAlias
? `npm:${child.package.name}@${child.package.version}`
: child.package
? child.package.version
: ''
output(
mutation + '\t' +
moduleName(child) + '\t' +
(child.package ? child.package.version : '') + '\t' +
version + '\t' +
(child.path ? path.relative(self.where, child.path) : '') + '\t' +
(previousVersion || '') + '\t' +
(previousPath || ''))
Expand Down
3 changes: 2 additions & 1 deletion lib/install/action/extract.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const figgyPudding = require('figgy-pudding')
const stat = BB.promisify(require('graceful-fs').stat)
const gentlyRm = BB.promisify(require('../../utils/gently-rm.js'))
const mkdirp = BB.promisify(require('mkdirp'))
const moduleName = require('../../utils/module-name.js')
const moduleStagingPath = require('../module-staging-path.js')
const move = require('../../utils/move.js')
const npa = require('npm-package-arg')
Expand Down Expand Up @@ -113,7 +114,7 @@ function readBundled (pkg, staging, extractTo) {
}

function stageBundledModule (bundler, child, staging, parentPath) {
const stageFrom = path.join(parentPath, 'node_modules', child.package.name)
const stageFrom = path.join(parentPath, 'node_modules', moduleName(child))
const stageTo = moduleStagingPath(staging, child)

return BB.map(child.children, (child) => {
Expand Down
3 changes: 2 additions & 1 deletion lib/install/action/global-install.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ var path = require('path')
var npm = require('../../npm.js')
var Installer = require('../../install.js').Installer
var packageId = require('../../utils/package-id.js')
var moduleName = require('../../utils/module-name.js')

module.exports = function (staging, pkg, log, next) {
log.silly('global-install', packageId(pkg))
var globalRoot = path.resolve(npm.globalDir, '..')
npm.config.set('global', true)
var install = new Installer(globalRoot, false, [pkg.package.name + '@' + pkg.package._requested.fetchSpec])
var install = new Installer(globalRoot, false, [moduleName(pkg) + '@' + pkg.package._requested.rawSpec])
install.link = false
install.run(function () {
npm.config.set('global', false)
Expand Down
3 changes: 2 additions & 1 deletion lib/install/action/global-link.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
'use strict'
var moduleName = require('../../utils/module-name.js')
var npm = require('../../npm.js')
var packageId = require('../../utils/package-id.js')

module.exports = function (staging, pkg, log, next) {
log.silly('global-link', packageId(pkg))
npm.link(pkg.package.name, next)
npm.link(moduleName(pkg), next)
}
3 changes: 2 additions & 1 deletion lib/install/and-add-parent-to-errors.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
'use strict'
var moduleName = require('../utils/module-name.js')
var validate = require('aproba')

module.exports = function (parent, cb) {
validate('F', [cb])
return function (er) {
if (!er) return cb.apply(null, arguments)
if (er instanceof Error && parent && parent.package && parent.package.name) {
er.parent = parent.package.name
er.parent = moduleName(parent)
}
cb(er)
}
Expand Down
23 changes: 17 additions & 6 deletions lib/install/deps.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ function doesChildVersionMatch (child, requested, requestor) {
}
}

if (requested.type === 'alias') {
return doesChildVersionMatch(child, requested.subSpec, requestor)
}

if (!registryTypes[requested.type]) {
var childReq = child.package._requested
if (childReq) {
Expand All @@ -81,7 +85,7 @@ function doesChildVersionMatch (child, requested, requestor) {
// You'll see this scenario happen with at least tags and git dependencies.
// Some buggy clients will write spaces into the module name part of a _from.
if (child.package._from) {
var fromReq = npa.resolve(moduleName(child), child.package._from.replace(new RegExp('^\\s*' + moduleName(child) + '\\s*@'), ''))
var fromReq = npa(child.package._from)
if (fromReq.rawSpec === requested.rawSpec) return true
if (fromReq.type === requested.type && fromReq.saveSpec && fromReq.saveSpec === requested.saveSpec) return true
}
Expand Down Expand Up @@ -298,11 +302,13 @@ function computeVersionSpec (tree, child) {
var requested
var childReq = child.package._requested
if (child.isLink) {
requested = npa.resolve(child.package.name, 'file:' + child.realpath, getTop(tree).path)
requested = npa.resolve(moduleName(child), 'file:' + child.realpath, getTop(tree).path)
} else if (childReq && (isNotEmpty(childReq.saveSpec) || (isNotEmpty(childReq.rawSpec) && isNotEmpty(childReq.fetchSpec)))) {
requested = child.package._requested
} else if (child.package._from) {
requested = npa(child.package._from, tree.path)
} else if (child.name && child.name !== child.package.name) {
requested = npa.resolve(child.name, `npm:${child.package.name}@${child.package.version})`)
} else {
requested = npa.resolve(child.package.name, child.package.version)
}
Expand All @@ -314,6 +320,9 @@ function computeVersionSpec (tree, child) {
!npm.config.get('save-exact')) {
rangeDescriptor = npm.config.get('save-prefix')
}
if (requested.type === 'alias') {
rangeDescriptor = `npm:${requested.subSpec.name}@${rangeDescriptor}`
}
return rangeDescriptor + version
} else if (requested.type === 'directory' || requested.type === 'file') {
return 'file:' + unixFormatPath(path.relative(getTop(tree).path, requested.fetchSpec))
Expand All @@ -333,7 +342,7 @@ exports.removeDeps = function (args, tree, saveToDependencies, next) {
for (let pkg of args) {
var pkgName = moduleName(pkg)
var toRemove = tree.children.filter(moduleNameMatches(pkgName))
var pkgToRemove = toRemove[0] || createChild({package: {name: pkgName}})
var pkgToRemove = toRemove[0] || createChild({name: pkgName})
var saveType = getSaveType(tree, pkg) || 'dependencies'
if (tree.isTop && saveToDependencies) {
pkgToRemove.save = saveType
Expand Down Expand Up @@ -661,11 +670,13 @@ function resolveWithNewModule (pkg, tree, log, next) {
addBundled(pkg, (bundleErr) => {
var parent = earliestInstallable(tree, tree, pkg, log) || tree
var isLink = pkg._requested.type === 'directory'
var name = pkg._requested.name || pkg.name
var child = createChild({
name,
package: pkg,
parent: parent,
path: path.join(parent.isLink ? parent.realpath : parent.path, 'node_modules', pkg.name),
realpath: isLink ? pkg._requested.fetchSpec : path.join(parent.realpath, 'node_modules', pkg.name),
path: path.join(parent.isLink ? parent.realpath : parent.path, 'node_modules', name),
realpath: isLink ? pkg._requested.fetchSpec : path.join(parent.realpath, 'node_modules', name),
children: pkg._bundled || [],
isLink: isLink,
isInLink: parent.isLink,
Expand Down Expand Up @@ -768,7 +779,7 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr
validate('OOOO', arguments)

function undeletedModuleMatches (child) {
return !child.removed && moduleName(child) === pkg.name
return !child.removed && moduleName(child) === ((pkg._requested && pkg._requested.name) || pkg.name)
}
const undeletedMatches = tree.children.filter(undeletedModuleMatches)
if (undeletedMatches.length) {
Expand Down
3 changes: 2 additions & 1 deletion lib/install/is-only-optional.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
module.exports = isOptional

const isOptDep = require('./is-opt-dep.js')
const moduleName = require('../utils/module-name.js')

function isOptional (node, seen) {
if (!seen) seen = new Set()
Expand All @@ -15,6 +16,6 @@ function isOptional (node, seen) {
const swOptional = node.fromShrinkwrap && node.package._optional
return node.requiredBy.every(function (req) {
if (req.fakeChild && swOptional) return true
return isOptDep(req, node.package.name) || isOptional(req, seen)
return isOptDep(req, moduleName(node)) || isOptional(req, seen)
})
}
12 changes: 9 additions & 3 deletions lib/ls.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var readPackageTree = require('read-package-tree')
var archy = require('archy')
var semver = require('semver')
var color = require('ansicolors')
var moduleName = require('./utils/module-name.js')
var npa = require('npm-package-arg')
var sortedObject = require('sorted-object')
var npm = require('./npm.js')
Expand Down Expand Up @@ -59,7 +60,9 @@ var lsFromTree = ls.fromTree = function (dir, physicalTree, args, silent, cb) {
args = []
} else {
args = args.map(function (a) {
if (typeof a === 'object') {
if (typeof a === 'object' && a.package._requested.type === 'alias') {
return [moduleName(a), `npm:${a.package.name}@${a.package.version}`, a]
} else if (typeof a === 'object') {
return [a.package.name, a.package.version, a]
} else {
var p = npa(a)
Expand Down Expand Up @@ -392,8 +395,11 @@ function makeArchy_ (data, long, dir, depth, parent, d) {
}

var out = {}
// the top level is a bit special.
out.label = data._id || ''
if (data._requested && data._requested.type === 'alias') {
out.label = `${d}@npm:${data._id}`
} else {
out.label = data._id || ''
}
if (data._found === 'explicit' && data._id) {
if (npm.color) {
out.label = color.bgBlack(color.yellow(out.label.trim())) + ' '
Expand Down
92 changes: 54 additions & 38 deletions lib/outdated.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,30 @@ outdated.usage = 'npm outdated [[<@scope>/]<pkg> ...]'

outdated.completion = require('./utils/completion/installed-deep.js')

var os = require('os')
var url = require('url')
var path = require('path')
var readPackageTree = require('read-package-tree')
var asyncMap = require('slide').asyncMap
var color = require('ansicolors')
var styles = require('ansistyles')
var table = require('text-table')
var semver = require('semver')
var npa = require('libnpm/parse-arg')
var pickManifest = require('npm-pick-manifest')
var fetchPackageMetadata = require('./fetch-package-metadata.js')
var mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js')
var npm = require('./npm.js')
const os = require('os')
const url = require('url')
const path = require('path')
const readPackageTree = require('read-package-tree')
const asyncMap = require('slide').asyncMap
const color = require('ansicolors')
const styles = require('ansistyles')
const table = require('text-table')
const semver = require('semver')
const npa = require('libnpm/parse-arg')
const pickManifest = require('npm-pick-manifest')
const fetchPackageMetadata = require('./fetch-package-metadata.js')
const mutateIntoLogicalTree = require('./install/mutate-into-logical-tree.js')
const npm = require('./npm.js')
const npmConfig = require('./config/figgy-config.js')
const figgyPudding = require('figgy-pudding')
const packument = require('libnpm/packument')
var long = npm.config.get('long')
var isExtraneous = require('./install/is-extraneous.js')
var computeMetadata = require('./install/deps.js').computeMetadata
var computeVersionSpec = require('./install/deps.js').computeVersionSpec
var moduleName = require('./utils/module-name.js')
var output = require('./utils/output.js')
var ansiTrim = require('./utils/ansi-trim')
const long = npm.config.get('long')
const isExtraneous = require('./install/is-extraneous.js')
const computeMetadata = require('./install/deps.js').computeMetadata
const computeVersionSpec = require('./install/deps.js').computeVersionSpec
const moduleName = require('./utils/module-name.js')
const output = require('./utils/output.js')
const ansiTrim = require('./utils/ansi-trim')

const OutdatedConfig = figgyPudding({
also: {},
Expand Down Expand Up @@ -215,8 +215,8 @@ function makeJSON (list, opts) {

function outdated_ (args, path, tree, parentHas, depth, opts, cb) {
if (!tree.package) tree.package = {}
if (path && tree.package.name) path += ' > ' + tree.package.name
if (!path && tree.package.name) path = tree.package.name
if (path && moduleName(tree)) path += ' > ' + tree.package.name
if (!path && moduleName(tree)) path = tree.package.name
if (depth > opts.depth) {
return cb(null, [])
}
Expand Down Expand Up @@ -298,10 +298,10 @@ function outdated_ (args, path, tree, parentHas, depth, opts, cb) {

var has = Object.create(parentHas)
tree.children.forEach(function (child) {
if (child.package.name && child.package.private) {
if (moduleName(child) && child.package.private) {
deps = deps.filter(function (dep) { return dep !== child })
}
has[child.package.name] = {
has[moduleName(child)] = {
version: child.isLink ? 'linked' : child.package.version,
from: child.isLink ? 'file:' + child.path : child.package._from
}
Expand Down Expand Up @@ -349,13 +349,6 @@ function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, opts, cb, type
cb)
}

function doIt (wanted, latest) {
if (!long) {
return cb(null, [[tree, dep, curr && curr.version, wanted, latest, req, null, pkgpath]])
}
cb(null, [[tree, dep, curr && curr.version, wanted, latest, req, type, pkgpath]])
}

if (args.length && args.indexOf(dep) === -1) return skip()

if (tree.isLink && req == null) return skip()
Expand All @@ -374,11 +367,22 @@ function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, opts, cb, type
} else if (parsed.type === 'file') {
return updateLocalDeps()
} else {
return packument(dep, opts.concat({
return packument(parsed, opts.concat({
'prefer-online': true
})).nodeify(updateDeps)
}

function doIt (wanted, latest) {
let c = curr && curr.version
if (parsed.type === 'alias') {
c = `npm:${parsed.subSpec.name}@${c}`
}
if (!long) {
return cb(null, [[tree, dep, c, wanted, latest, req, null, pkgpath]])
}
cb(null, [[tree, dep, c, wanted, latest, req, type, pkgpath]])
}

function updateLocalDeps (latestRegistryVersion) {
fetchPackageMetadata('file:' + parsed.fetchSpec, '.', (er, localDependency) => {
if (er) return cb()
Expand All @@ -405,6 +409,9 @@ function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, opts, cb, type
function updateDeps (er, d) {
if (er) return cb(er)

if (parsed.type === 'alias') {
req = parsed.subSpec.rawSpec
}
try {
var l = pickManifest(d, 'latest')
var m = pickManifest(d, req)
Expand All @@ -421,11 +428,20 @@ function shouldUpdate (args, tree, dep, has, req, depth, pkgpath, opts, cb, type
var dFromUrl = m._from && url.parse(m._from).protocol
var cFromUrl = curr && curr.from && url.parse(curr.from).protocol

if (!curr ||
(dFromUrl && cFromUrl && m._from !== curr.from) ||
m.version !== curr.version ||
m.version !== l.version) {
doIt(m.version, l.version)
if (
!curr ||
(dFromUrl && cFromUrl && m._from !== curr.from) ||
m.version !== curr.version ||
m.version !== l.version
) {
if (parsed.type === 'alias') {
doIt(
`npm:${parsed.subSpec.name}@${m.version}`,
`npm:${parsed.subSpec.name}@${l.version}`
)
} else {
doIt(m.version, l.version)
}
} else {
skip()
}
Expand Down
Loading

0 comments on commit b7b54f2

Please # to comment.