"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/diff.js" between
npm-cli-7.16.0.tar.gz and npm-cli-7.17.0.tar.gz

About: npm is a JavaScript package manager (requires node v6 or higher).

diff.js  (npm-cli-7.16.0):diff.js  (npm-cli-7.17.0)
const { resolve } = require('path') const { resolve } = require('path')
const semver = require('semver') const semver = require('semver')
const libdiff = require('libnpmdiff') const libnpmdiff = require('libnpmdiff')
const npa = require('npm-package-arg') const npa = require('npm-package-arg')
const Arborist = require('@npmcli/arborist') const Arborist = require('@npmcli/arborist')
const npmlog = require('npmlog') const npmlog = require('npmlog')
const pacote = require('pacote') const pacote = require('pacote')
const pickManifest = require('npm-pick-manifest') const pickManifest = require('npm-pick-manifest')
const getWorkspaces = require('./workspaces/get-workspaces.js')
const readPackageName = require('./utils/read-package-name.js') const readPackageName = require('./utils/read-package-name.js')
const BaseCommand = require('./base-command.js') const BaseCommand = require('./base-command.js')
class Diff extends BaseCommand { class Diff extends BaseCommand {
static get description () { static get description () {
return 'The registry diff command' return 'The registry diff command'
} }
/* istanbul ignore next - see test/lib/load-all-commands.js */ /* istanbul ignore next - see test/lib/load-all-commands.js */
static get name () { static get name () {
return 'diff' return 'diff'
} }
/* istanbul ignore next - see test/lib/load-all-commands.js */ /* istanbul ignore next - see test/lib/load-all-commands.js */
static get usage () { static get usage () {
return [ return [
'[...<paths>]', '[...<paths>]',
'--diff=<pkg-name> [...<paths>]',
'--diff=<version-a> [--diff=<version-b>] [...<paths>]',
'--diff=<spec-a> [--diff=<spec-b>] [...<paths>]',
'[--diff-ignore-all-space] [--diff-name-only] [...<paths>] [...<paths>]',
] ]
} }
/* istanbul ignore next - see test/lib/load-all-commands.js */ /* istanbul ignore next - see test/lib/load-all-commands.js */
static get params () { static get params () {
return [ return [
'diff', 'diff',
'diff-name-only', 'diff-name-only',
'diff-unified', 'diff-unified',
'diff-ignore-all-space', 'diff-ignore-all-space',
'diff-no-prefix', 'diff-no-prefix',
'diff-src-prefix', 'diff-src-prefix',
'diff-dst-prefix', 'diff-dst-prefix',
'diff-text', 'diff-text',
'global', 'global',
'tag', 'tag',
'workspace',
'workspaces',
] ]
} }
get where () {
const globalTop = resolve(this.npm.globalDir, '..')
const global = this.npm.config.get('global')
return global ? globalTop : this.npm.prefix
}
exec (args, cb) { exec (args, cb) {
this.diff(args).then(() => cb()).catch(cb) this.diff(args).then(() => cb()).catch(cb)
} }
execWorkspaces (args, filters, cb) {
this.diffWorkspaces(args, filters).then(() => cb()).catch(cb)
}
async diff (args) { async diff (args) {
const specs = this.npm.config.get('diff').filter(d => d) const specs = this.npm.config.get('diff').filter(d => d)
if (specs.length > 2) { if (specs.length > 2) {
throw new TypeError( throw new TypeError(
'Can\'t use more than two --diff arguments.\n\n' + 'Can\'t use more than two --diff arguments.\n\n' +
`Usage:\n${this.usage}` `Usage:\n${this.usage}`
) )
} }
// diffWorkspaces may have set this already
if (!this.prefix)
this.prefix = this.npm.prefix
// this is the "top" directory, one up from node_modules
// in global mode we have to walk one up from globalDir because our
// node_modules is sometimes under ./lib, and in global mode we're only ever
// walking through node_modules (because we will have been given a package
// name already)
if (this.npm.config.get('global'))
this.top = resolve(this.npm.globalDir, '..')
else
this.top = this.prefix
const [a, b] = await this.retrieveSpecs(specs) const [a, b] = await this.retrieveSpecs(specs)
npmlog.info('diff', { src: a, dst: b }) npmlog.info('diff', { src: a, dst: b })
const res = await libdiff([a, b], { const res = await libnpmdiff([a, b], {
...this.npm.flatOptions, ...this.npm.flatOptions,
diffFiles: args, diffFiles: args,
where: this.where, where: this.top,
}) })
return this.npm.output(res) return this.npm.output(res)
} }
async retrieveSpecs ([a, b]) { async diffWorkspaces (args, filters) {
// no arguments, defaults to comparing cwd const workspaces =
// to its latest published registry version await getWorkspaces(filters, { path: this.npm.localPrefix })
if (!a) for (const workspacePath of workspaces.values()) {
return this.defaultSpec() this.top = workspacePath
this.prefix = workspacePath
// single argument, used to compare wanted versions of an await this.diff(args)
// installed dependency or to compare the cwd to a published version }
if (!b)
return this.transformSingleSpec(a)
const specs = await this.convertVersionsToSpecs([a, b])
return this.findVersionsByPackageName(specs)
} }
async defaultSpec () { // get the package name from the packument at `path`
let noPackageJson // throws if no packument is present OR if it does not have `name` attribute
let pkgName async packageName (path) {
let name
try { try {
pkgName = await readPackageName(this.npm.prefix) // TODO this won't work as expected in global mode
name = await readPackageName(this.prefix)
} catch (e) { } catch (e) {
npmlog.verbose('diff', 'could not read project dir package.json') npmlog.verbose('diff', 'could not read project dir package.json')
noPackageJson = true
} }
if (!pkgName || noPackageJson) { if (!name)
throw new Error( throw this.usageError('Needs multiple arguments to compare or run from a p
'Needs multiple arguments to compare or run from a project dir.\n\n' + roject dir.\n')
`Usage:\n${this.usage}`
)
}
return [ return name
`${pkgName}@${this.npm.config.get('tag')}`,
`file:${this.npm.prefix}`,
]
} }
async transformSingleSpec (a) { async retrieveSpecs ([a, b]) {
if (a && b) {
const specs = await this.convertVersionsToSpecs([a, b])
return this.findVersionsByPackageName(specs)
}
// no arguments, defaults to comparing cwd
// to its latest published registry version
if (!a) {
const pkgName = await this.packageName(this.prefix)
return [
`${pkgName}@${this.npm.config.get('tag')}`,
`file:${this.prefix}`,
]
}
// single argument, used to compare wanted versions of an
// installed dependency or to compare the cwd to a published version
let noPackageJson let noPackageJson
let pkgName let pkgName
try { try {
pkgName = await readPackageName(this.npm.prefix) pkgName = await readPackageName(this.prefix)
} catch (e) { } catch (e) {
npmlog.verbose('diff', 'could not read project dir package.json') npmlog.verbose('diff', 'could not read project dir package.json')
noPackageJson = true noPackageJson = true
} }
const missingPackageJson = new Error(
'Needs multiple arguments to compare or run from a project dir.\n\n' +
`Usage:\n${this.usage}`
)
const specSelf = () => { const missingPackageJson = this.usageError('Needs multiple arguments to comp
if (noPackageJson) are or run from a project dir.\n')
throw missingPackageJson
return `file:${this.npm.prefix}`
}
// using a valid semver range, that means it should just diff // using a valid semver range, that means it should just diff
// the cwd against a published version to the registry using the // the cwd against a published version to the registry using the
// same project name and the provided semver range // same project name and the provided semver range
if (semver.validRange(a)) { if (semver.validRange(a)) {
if (!pkgName) if (!pkgName)
throw missingPackageJson throw missingPackageJson
return [ return [
`${pkgName}@${a}`, `${pkgName}@${a}`,
specSelf(), `file:${this.prefix}`,
] ]
} }
// when using a single package name as arg and it's part of the current // when using a single package name as arg and it's part of the current
// install tree, then retrieve the current installed version and compare // install tree, then retrieve the current installed version and compare
// it against the same value `npm outdated` would suggest you to update to // it against the same value `npm outdated` would suggest you to update to
const spec = npa(a) const spec = npa(a)
if (spec.registry) { if (spec.registry) {
let actualTree let actualTree
let node let node
try { try {
const opts = { const opts = {
...this.npm.flatOptions, ...this.npm.flatOptions,
path: this.where, path: this.top,
} }
const arb = new Arborist(opts) const arb = new Arborist(opts)
actualTree = await arb.loadActual(opts) actualTree = await arb.loadActual(opts)
node = actualTree && node = actualTree &&
actualTree.inventory.query('name', spec.name) actualTree.inventory.query('name', spec.name)
.values().next().value .values().next().value
} catch (e) { } catch (e) {
npmlog.verbose('diff', 'failed to load actual install tree') npmlog.verbose('diff', 'failed to load actual install tree')
} }
if (!node || !node.name || !node.package || !node.package.version) { if (!node || !node.name || !node.package || !node.package.version) {
if (noPackageJson)
throw missingPackageJson
return [ return [
`${spec.name}@${spec.fetchSpec}`, `${spec.name}@${spec.fetchSpec}`,
specSelf(), `file:${this.prefix}`,
] ]
} }
const tryRootNodeSpec = () => const tryRootNodeSpec = () =>
(actualTree && actualTree.edgesOut.get(spec.name) || {}).spec (actualTree && actualTree.edgesOut.get(spec.name) || {}).spec
const tryAnySpec = () => { const tryAnySpec = () => {
for (const edge of node.edgesIn) for (const edge of node.edgesIn)
return edge.spec return edge.spec
} }
skipping to change at line 223 skipping to change at line 232
).version ).version
} }
return [ return [
`${spec.name}@${aSpec}`, `${spec.name}@${aSpec}`,
`${spec.name}@${bSpec}`, `${spec.name}@${bSpec}`,
] ]
} else if (spec.type === 'directory') { } else if (spec.type === 'directory') {
return [ return [
`file:${spec.fetchSpec}`, `file:${spec.fetchSpec}`,
specSelf(), `file:${this.prefix}`,
] ]
} else { } else
throw new Error( throw this.usageError(`Spec type ${spec.type} not supported.\n`)
'Spec type not supported.\n\n' +
`Usage:\n${this.usage}`
)
}
} }
async convertVersionsToSpecs ([a, b]) { async convertVersionsToSpecs ([a, b]) {
const semverA = semver.validRange(a) const semverA = semver.validRange(a)
const semverB = semver.validRange(b) const semverB = semver.validRange(b)
// both specs are semver versions, assume current project dir name // both specs are semver versions, assume current project dir name
if (semverA && semverB) { if (semverA && semverB) {
let pkgName let pkgName
try { try {
pkgName = await readPackageName(this.npm.prefix) pkgName = await readPackageName(this.prefix)
} catch (e) { } catch (e) {
npmlog.verbose('diff', 'could not read project dir package.json') npmlog.verbose('diff', 'could not read project dir package.json')
} }
if (!pkgName) { if (!pkgName)
throw new Error( throw this.usageError('Needs to be run from a project dir in order to di
'Needs to be run from a project dir in order to diff two versions.\n\n ff two versions.\n')
' +
`Usage:\n${this.usage}`
)
}
return [`${pkgName}@${a}`, `${pkgName}@${b}`] return [`${pkgName}@${a}`, `${pkgName}@${b}`]
} }
// otherwise uses the name from the other arg to // otherwise uses the name from the other arg to
// figure out the spec.name of what to compare // figure out the spec.name of what to compare
if (!semverA && semverB) if (!semverA && semverB)
return [a, `${npa(a).name}@${b}`] return [a, `${npa(a).name}@${b}`]
if (semverA && !semverB) if (semverA && !semverB)
return [`${npa(b).name}@${a}`, b] return [`${npa(b).name}@${a}`, b]
// no valid semver ranges used // no valid semver ranges used
return [a, b] return [a, b]
} }
async findVersionsByPackageName (specs) { async findVersionsByPackageName (specs) {
let actualTree let actualTree
try { try {
const opts = { const opts = {
...this.npm.flatOptions, ...this.npm.flatOptions,
path: this.where, path: this.top,
} }
const arb = new Arborist(opts) const arb = new Arborist(opts)
actualTree = await arb.loadActual(opts) actualTree = await arb.loadActual(opts)
} catch (e) { } catch (e) {
npmlog.verbose('diff', 'failed to load actual install tree') npmlog.verbose('diff', 'failed to load actual install tree')
} }
return specs.map(i => { return specs.map(i => {
const spec = npa(i) const spec = npa(i)
if (spec.rawSpec) if (spec.rawSpec)
 End of changes. 29 change blocks. 
73 lines changed or deleted 77 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)