/usr/local/lib/node_modules/npm/lib/commands
NameSizeModeActions
trust/-0755rm
access.js63130644editdlrm
adduser.js13210644editdlrm
audit.js32480644editdlrm
bugs.js8470644editdlrm
cache.js117540644editdlrm
ci.js43390644editdlrm
completion.js110850644editdlrm
config.js117530644editdlrm
dedupe.js14500644editdlrm
deprecate.js24880644editdlrm
diff.js81090644editdlrm
dist-tag.js56290644editdlrm
docs.js4490644editdlrm
doctor.js102260644editdlrm
edit.js17650644editdlrm
exec.js34750644editdlrm
explain.js36310644editdlrm
explore.js21580644editdlrm
find-dupes.js5780644editdlrm
fund.js65330644editdlrm
get.js5380644editdlrm
help-search.js56620644editdlrm
help.js37310644editdlrm
init.js71860644editdlrm
install-ci-test.js3080644editdlrm
install-test.js3030644editdlrm
install.js52210644editdlrm
link.js53640644editdlrm
ll.js2340644editdlrm
login.js13180644editdlrm
logout.js14530644editdlrm
ls.js184640644editdlrm
org.js40540644editdlrm
outdated.js81110644editdlrm
owner.js60940644editdlrm
pack.js28330644editdlrm
ping.js8730644editdlrm
pkg.js36670644editdlrm
prefix.js3090644editdlrm
profile.js105470644editdlrm
prune.js7700644editdlrm
publish.js96980644editdlrm
query.js38400644editdlrm
rebuild.js22020644editdlrm
repo.js12740644editdlrm
restart.js3030644editdlrm
root.js2950644editdlrm
run.js64170644editdlrm
sbom.js45780644editdlrm
search.js18770644editdlrm
set.js6320644editdlrm
shrinkwrap.js26910644editdlrm
star.js19200644editdlrm
stars.js10580644editdlrm
start.js2930644editdlrm
stop.js2880644editdlrm
team.js44360644editdlrm
test.js2880644editdlrm
token.js81530644editdlrm
undeprecate.js3020644editdlrm
uninstall.js15220644editdlrm
unpublish.js53680644editdlrm
unstar.js1830644editdlrm
update.js17330644editdlrm
version.js36210644editdlrm
view.js138020644editdlrm
whoami.js5270644editdlrm
Edit: /usr/local/lib/node_modules/npm/lib/commands/diff.js (8109B)
const { resolve } = require('node:path') const semver = require('semver') const libnpmdiff = require('libnpmdiff') const npa = require('npm-package-arg') const pacote = require('pacote') const pickManifest = require('npm-pick-manifest') const { log, output } = require('proc-log') const pkgJson = require('@npmcli/package-json') const BaseCommand = require('../base-cmd.js') class Diff extends BaseCommand { static description = 'The registry diff command' static name = 'diff' static usage = [ '[...]', ] static params = [ 'diff', 'diff-name-only', 'diff-unified', 'diff-ignore-all-space', 'diff-no-prefix', 'diff-src-prefix', 'diff-dst-prefix', 'diff-text', 'global', 'tag', 'workspace', 'workspaces', 'include-workspace-root', ] static workspaces = true static ignoreImplicitWorkspace = false async exec (args) { const specs = this.npm.config.get('diff').filter(d => d) if (specs.length > 2) { throw this.usageError(`Can't use more than two --diff arguments.`) } // execWorkspaces 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.global) { this.top = resolve(this.npm.globalDir, '..') } else { this.top = this.prefix } const [a, b] = await this.retrieveSpecs(specs) log.info('diff', { src: a, dst: b }) const res = await libnpmdiff([a, b], { ...this.npm.flatOptions, diffFiles: args, where: this.top, }) return output.standard(res) } async execWorkspaces (args) { await this.setWorkspaces() for (const workspacePath of this.workspacePaths) { this.top = workspacePath this.prefix = workspacePath await this.exec(args) } } // get the package name from the packument at `path` // throws if no packument is present OR if it does not have `name` attribute async packageName () { let name try { const { content: pkg } = await pkgJson.normalize(this.prefix) name = pkg.name } catch { log.verbose('diff', 'could not read project dir package.json') } if (!name) { throw this.usageError('Needs multiple arguments to compare or run from a project dir.') } return name } 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() 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 pkgName try { const { content: pkg } = await pkgJson.normalize(this.prefix) pkgName = pkg.name } catch { log.verbose('diff', 'could not read project dir package.json') noPackageJson = true } const missingPackageJson = this.usageError('Needs multiple arguments to compare or run from a project dir.') // using a valid semver range, that means it should just diff the cwd against a published version to the registry using the same project name and the provided semver range if (semver.validRange(a)) { if (!pkgName) { throw missingPackageJson } return [ `${pkgName}@${a}`, `file:${this.prefix}`, ] } // 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 it against the same value `npm outdated` would suggest you to update to const spec = npa(a) if (spec.registry) { let actualTree let node const Arborist = require('@npmcli/arborist') try { const opts = { ...this.npm.flatOptions, path: this.top, } const arb = new Arborist(opts) actualTree = await arb.loadActual(opts) node = actualTree && actualTree.inventory.query('name', spec.name) .values().next().value } catch { log.verbose('diff', 'failed to load actual install tree') } if (!node || !node.name || !node.package || !node.package.version) { if (noPackageJson) { throw missingPackageJson } return [ `${spec.name}@${spec.fetchSpec}`, `file:${this.prefix}`, ] } const tryRootNodeSpec = () => (actualTree && actualTree.edgesOut.get(spec.name) || {}).spec const tryAnySpec = () => { for (const edge of node.edgesIn) { return edge.spec } } const aSpec = `file:${node.realpath}` // finds what version of the package to compare against // if an exact version or tag was passed than it should use that // otherwise, work from the top of the arborist tree to find the original semver range declared in the package that depends on the package. let bSpec if (spec.rawSpec !== '*') { bSpec = spec.rawSpec } else { const bTargetVersion = tryRootNodeSpec() || tryAnySpec() // figure out what to compare against // follows same logic to npm outdated "Wanted" results const packument = await pacote.packument(spec, { ...this.npm.flatOptions, preferOnline: true, _isRoot: true, }) bSpec = pickManifest( packument, bTargetVersion, { ...this.npm.flatOptions } ).version } return [ `${spec.name}@${aSpec}`, `${spec.name}@${bSpec}`, ] } else if (spec.type === 'directory') { return [ `file:${spec.fetchSpec}`, `file:${this.prefix}`, ] } else { throw this.usageError(`Spec type ${spec.type} not supported.`) } } async convertVersionsToSpecs ([a, b]) { const semverA = semver.validRange(a) const semverB = semver.validRange(b) // both specs are semver versions, assume current project dir name if (semverA && semverB) { let pkgName try { const { content: pkg } = await pkgJson.normalize(this.prefix) pkgName = pkg.name } catch { log.verbose('diff', 'could not read project dir package.json') } if (!pkgName) { throw this.usageError('Needs to be run from a project dir in order to diff two versions.') } return [`${pkgName}@${a}`, `${pkgName}@${b}`] } // otherwise uses the name from the other arg to figure out the spec.name of what to compare if (!semverA && semverB) { return [a, `${npa(a).name}@${b}`] } if (semverA && !semverB) { return [`${npa(b).name}@${a}`, b] } // no valid semver ranges used return [a, b] } async findVersionsByPackageName (specs) { let actualTree const Arborist = require('@npmcli/arborist') try { const opts = { ...this.npm.flatOptions, path: this.top, } const arb = new Arborist(opts) actualTree = await arb.loadActual(opts) } catch { log.verbose('diff', 'failed to load actual install tree') } return specs.map(i => { const spec = npa(i) if (spec.rawSpec !== '*') { return i } const node = actualTree && actualTree.inventory.query('name', spec.name) .values().next().value const res = !node || !node.package || !node.package.version ? spec.fetchSpec : `file:${node.realpath}` return `${spec.name}@${res}` }) } } module.exports = Diff