mirror of
https://github.com/nodejs/node.git
synced 2025-05-13 18:07:48 +00:00

PR-URL: https://github.com/nodejs/node/pull/41127 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
199 lines
5.1 KiB
JavaScript
199 lines
5.1 KiB
JavaScript
// helper function to output a clearer visualization
|
|
// of the current node and its descendents
|
|
const localeCompare = require('@isaacs/string-locale-compare')('en')
|
|
const util = require('util')
|
|
const relpath = require('./relpath.js')
|
|
|
|
class ArboristNode {
|
|
constructor (tree, path) {
|
|
this.name = tree.name
|
|
if (tree.packageName && tree.packageName !== this.name) {
|
|
this.packageName = tree.packageName
|
|
}
|
|
if (tree.version) {
|
|
this.version = tree.version
|
|
}
|
|
this.location = tree.location
|
|
this.path = tree.path
|
|
if (tree.realpath !== this.path) {
|
|
this.realpath = tree.realpath
|
|
}
|
|
if (tree.resolved !== null) {
|
|
this.resolved = tree.resolved
|
|
}
|
|
if (tree.extraneous) {
|
|
this.extraneous = true
|
|
}
|
|
if (tree.dev) {
|
|
this.dev = true
|
|
}
|
|
if (tree.optional) {
|
|
this.optional = true
|
|
}
|
|
if (tree.devOptional && !tree.dev && !tree.optional) {
|
|
this.devOptional = true
|
|
}
|
|
if (tree.peer) {
|
|
this.peer = true
|
|
}
|
|
if (tree.inBundle) {
|
|
this.bundled = true
|
|
}
|
|
if (tree.inDepBundle) {
|
|
this.bundler = tree.getBundler().location
|
|
}
|
|
if (tree.isProjectRoot) {
|
|
this.isProjectRoot = true
|
|
}
|
|
if (tree.isWorkspace) {
|
|
this.isWorkspace = true
|
|
}
|
|
const bd = tree.package && tree.package.bundleDependencies
|
|
if (bd && bd.length) {
|
|
this.bundleDependencies = bd
|
|
}
|
|
if (tree.inShrinkwrap) {
|
|
this.inShrinkwrap = true
|
|
} else if (tree.hasShrinkwrap) {
|
|
this.hasShrinkwrap = true
|
|
}
|
|
if (tree.error) {
|
|
this.error = treeError(tree.error)
|
|
}
|
|
if (tree.errors && tree.errors.length) {
|
|
this.errors = tree.errors.map(treeError)
|
|
}
|
|
|
|
if (tree.overrides) {
|
|
this.overrides = new Map([...tree.overrides.ruleset.values()]
|
|
.map((override) => [override.key, override.value]))
|
|
}
|
|
|
|
// edgesOut sorted by name
|
|
if (tree.edgesOut.size) {
|
|
this.edgesOut = new Map([...tree.edgesOut.entries()]
|
|
.sort(([a], [b]) => localeCompare(a, b))
|
|
.map(([name, edge]) => [name, new EdgeOut(edge)]))
|
|
}
|
|
|
|
// edgesIn sorted by location
|
|
if (tree.edgesIn.size) {
|
|
this.edgesIn = new Set([...tree.edgesIn]
|
|
.sort((a, b) => localeCompare(a.from.location, b.from.location))
|
|
.map(edge => new EdgeIn(edge)))
|
|
}
|
|
|
|
if (tree.workspaces && tree.workspaces.size) {
|
|
this.workspaces = new Map([...tree.workspaces.entries()]
|
|
.map(([name, path]) => [name, relpath(tree.root.realpath, path)]))
|
|
}
|
|
|
|
// fsChildren sorted by path
|
|
if (tree.fsChildren.size) {
|
|
this.fsChildren = new Set([...tree.fsChildren]
|
|
.sort(({ path: a }, { path: b }) => localeCompare(a, b))
|
|
.map(tree => printableTree(tree, path)))
|
|
}
|
|
|
|
// children sorted by name
|
|
if (tree.children.size) {
|
|
this.children = new Map([...tree.children.entries()]
|
|
.sort(([a], [b]) => localeCompare(a, b))
|
|
.map(([name, tree]) => [name, printableTree(tree, path)]))
|
|
}
|
|
}
|
|
}
|
|
|
|
class ArboristVirtualNode extends ArboristNode {
|
|
constructor (tree, path) {
|
|
super(tree, path)
|
|
this.sourceReference = printableTree(tree.sourceReference, path)
|
|
}
|
|
}
|
|
|
|
class ArboristLink extends ArboristNode {
|
|
constructor (tree, path) {
|
|
super(tree, path)
|
|
this.target = printableTree(tree.target, path)
|
|
}
|
|
}
|
|
|
|
const treeError = ({ code, path }) => ({
|
|
code,
|
|
...(path ? { path } : {}),
|
|
})
|
|
|
|
// print out edges without dumping the full node all over again
|
|
// this base class will toJSON as a plain old object, but the
|
|
// util.inspect() output will be a bit cleaner
|
|
class Edge {
|
|
constructor (edge) {
|
|
this.type = edge.type
|
|
this.name = edge.name
|
|
this.spec = edge.rawSpec || '*'
|
|
if (edge.rawSpec !== edge.spec) {
|
|
this.override = edge.spec
|
|
}
|
|
if (edge.error) {
|
|
this.error = edge.error
|
|
}
|
|
if (edge.peerConflicted) {
|
|
this.peerConflicted = edge.peerConflicted
|
|
}
|
|
}
|
|
}
|
|
|
|
// don't care about 'from' for edges out
|
|
class EdgeOut extends Edge {
|
|
constructor (edge) {
|
|
super(edge)
|
|
this.to = edge.to && edge.to.location
|
|
}
|
|
|
|
[util.inspect.custom] () {
|
|
return `{ ${this.type} ${this.name}@${this.spec}${
|
|
this.override ? ` overridden:${this.override}` : ''
|
|
}${
|
|
this.to ? ' -> ' + this.to : ''
|
|
}${
|
|
this.error ? ' ' + this.error : ''
|
|
}${
|
|
this.peerConflicted ? ' peerConflicted' : ''
|
|
} }`
|
|
}
|
|
}
|
|
|
|
// don't care about 'to' for edges in
|
|
class EdgeIn extends Edge {
|
|
constructor (edge) {
|
|
super(edge)
|
|
this.from = edge.from && edge.from.location
|
|
}
|
|
|
|
[util.inspect.custom] () {
|
|
return `{ ${this.from || '""'} ${this.type} ${this.name}@${this.spec}${
|
|
this.error ? ' ' + this.error : ''
|
|
}${
|
|
this.peerConflicted ? ' peerConflicted' : ''
|
|
} }`
|
|
}
|
|
}
|
|
|
|
const printableTree = (tree, path = []) => {
|
|
if (!tree) {
|
|
return tree
|
|
}
|
|
|
|
const Cls = tree.isLink ? ArboristLink
|
|
: tree.sourceReference ? ArboristVirtualNode
|
|
: ArboristNode
|
|
if (path.includes(tree)) {
|
|
const obj = Object.create(Cls.prototype)
|
|
return Object.assign(obj, { location: tree.location })
|
|
}
|
|
path.push(tree)
|
|
return new Cls(tree, path)
|
|
}
|
|
|
|
module.exports = printableTree
|