Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuy Adorno <ruyadorno@hotmail.com>2021-01-15 22:48:21 +0300
committerRuy Adorno <ruyadorno@hotmail.com>2021-01-15 22:50:08 +0300
commite5ce6bbbad82b85c8e74a4558503513e4f337476 (patch)
tree0c4e3edef62d9e85749c46dd2a952154c6543c10 /node_modules
parent653769de359b8d24f0d17b8e7e426708f49cadb8 (diff)
chore: update missing files from node_modules
- @npmcli/arborist@2.0.5 - @npmcli/metavuln-calculator@1.0.1 - move-file@1.1.0
Diffstat (limited to 'node_modules')
-rw-r--r--node_modules/@npmcli/arborist/lib/arborist/index.js1
-rw-r--r--node_modules/@npmcli/arborist/lib/arborist/load-actual.js15
-rw-r--r--node_modules/@npmcli/arborist/lib/arborist/reify.js2
-rw-r--r--node_modules/@npmcli/arborist/lib/diff.js5
-rw-r--r--node_modules/@npmcli/arborist/lib/edge.js24
-rw-r--r--node_modules/@npmcli/arborist/lib/index.js1
-rw-r--r--node_modules/@npmcli/arborist/lib/node.js74
-rw-r--r--node_modules/@npmcli/arborist/lib/shrinkwrap.js8
-rw-r--r--node_modules/@npmcli/arborist/package.json9
-rw-r--r--node_modules/@npmcli/metavuln-calculator/lib/advisory.js131
-rw-r--r--node_modules/@npmcli/metavuln-calculator/lib/load-worker.js29
-rw-r--r--node_modules/@npmcli/metavuln-calculator/lib/test-version.js59
-rw-r--r--node_modules/@npmcli/metavuln-calculator/package.json2
-rw-r--r--node_modules/@npmcli/move-file/README.md9
-rw-r--r--node_modules/@npmcli/move-file/index.js83
-rw-r--r--node_modules/@npmcli/move-file/package.json5
16 files changed, 421 insertions, 36 deletions
diff --git a/node_modules/@npmcli/arborist/lib/arborist/index.js b/node_modules/@npmcli/arborist/lib/arborist/index.js
index 4c7e96da4..6c46656eb 100644
--- a/node_modules/@npmcli/arborist/lib/arborist/index.js
+++ b/node_modules/@npmcli/arborist/lib/arborist/index.js
@@ -53,6 +53,7 @@ class Arborist extends Base {
...options,
path: options.path || '.',
cache: options.cache || `${homedir()}/.npm/_cacache`,
+ packumentCache: new Map(),
}
this.cache = resolve(this.options.cache)
this.path = resolve(this.options.path)
diff --git a/node_modules/@npmcli/arborist/lib/arborist/load-actual.js b/node_modules/@npmcli/arborist/lib/arborist/load-actual.js
index abf39e5dc..49e76e265 100644
--- a/node_modules/@npmcli/arborist/lib/arborist/load-actual.js
+++ b/node_modules/@npmcli/arborist/lib/arborist/load-actual.js
@@ -111,7 +111,7 @@ module.exports = cls => class ActualLoader extends cls {
pkg: {},
global,
})
- return this[_loadActualActually]({root, ignoreMissing})
+ return this[_loadActualActually]({root, ignoreMissing, global})
}
// not in global mode, hidden lockfile is allowed, load root pkg too
@@ -154,7 +154,7 @@ module.exports = cls => class ActualLoader extends cls {
return this[_actualTree]
}
- async [_loadActualActually] ({ root, ignoreMissing }) {
+ async [_loadActualActually] ({ root, ignoreMissing, global }) {
await this[_loadFSTree](this[_actualTree])
if (!ignoreMissing)
await this[_findMissingEdges]()
@@ -162,6 +162,17 @@ module.exports = cls => class ActualLoader extends cls {
this[_transplant](root)
await this[_loadWorkspaces](this[_actualTree])
+ if (global) {
+ // need to depend on the children, or else all of them
+ // will end up being flagged as extraneous, since the
+ // global root isn't a "real" project
+ const tree = this[_actualTree]
+ const actualRoot = tree.isLink ? tree.target : tree
+ const { dependencies = {} } = actualRoot.package
+ for (const name of actualRoot.children.keys())
+ dependencies[name] = dependencies[name] || '*'
+ actualRoot.package = { ...actualRoot.package, dependencies }
+ }
// only reset root flags if we're not re-rooting, otherwise leave as-is
calcDepFlags(this[_actualTree], !root)
return this[_actualTree]
diff --git a/node_modules/@npmcli/arborist/lib/arborist/reify.js b/node_modules/@npmcli/arborist/lib/arborist/reify.js
index 661d879eb..5375b6df4 100644
--- a/node_modules/@npmcli/arborist/lib/arborist/reify.js
+++ b/node_modules/@npmcli/arborist/lib/arborist/reify.js
@@ -136,7 +136,7 @@ module.exports = cls => class Reifier extends cls {
async [_validatePath] () {
// don't create missing dirs on dry runs
- if (this[_packageLockOnly] || this[_dryRun] || this[_global])
+ if (this[_packageLockOnly] || this[_dryRun])
return
await mkdirp(resolve(this.path))
diff --git a/node_modules/@npmcli/arborist/lib/diff.js b/node_modules/@npmcli/arborist/lib/diff.js
index 1864a3ea1..ada67f816 100644
--- a/node_modules/@npmcli/arborist/lib/diff.js
+++ b/node_modules/@npmcli/arborist/lib/diff.js
@@ -72,6 +72,11 @@ const allChildren = node => {
if (!node)
return new Map()
+ // if the node is a global root, and also a link, then what we really
+ // want is to traverse the target's children
+ if (node.global && node.isRoot && node.isLink)
+ return allChildren(node.target)
+
const kids = new Map()
for (const n of [node, ...node.fsChildren]) {
for (const kid of n.children.values())
diff --git a/node_modules/@npmcli/arborist/lib/edge.js b/node_modules/@npmcli/arborist/lib/edge.js
index 0e30f4633..c5f00faff 100644
--- a/node_modules/@npmcli/arborist/lib/edge.js
+++ b/node_modules/@npmcli/arborist/lib/edge.js
@@ -1,6 +1,7 @@
// An edge in the dependency graph
// Represents a dependency relationship of some kind
+const util = require('util')
const npa = require('npm-package-arg')
const depValid = require('./dep-valid.js')
const _from = Symbol('_from')
@@ -24,6 +25,21 @@ const types = new Set([
'workspace',
])
+class ArboristEdge {}
+const printableEdge = (edge) => {
+ const edgeFrom = edge.from && edge.from.location
+ const edgeTo = edge.to && edge.to.location
+
+ return Object.assign(new ArboristEdge(), {
+ name: edge.name,
+ spec: edge.spec,
+ type: edge.type,
+ ...(edgeFrom != null ? { from: edgeFrom } : {}),
+ ...(edgeTo ? { to: edgeTo } : {}),
+ ...(edge.error ? { error: edge.error } : {}),
+ })
+}
+
class Edge {
constructor (options) {
const { type, name, spec, accept, from } = options
@@ -185,6 +201,14 @@ class Edge {
get to () {
return this[_to]
}
+
+ toJSON () {
+ return printableEdge(this)
+ }
+
+ [util.inspect.custom] () {
+ return this.toJSON()
+ }
}
Edge.types = [...types]
diff --git a/node_modules/@npmcli/arborist/lib/index.js b/node_modules/@npmcli/arborist/lib/index.js
index 830a88a5f..fd7d88172 100644
--- a/node_modules/@npmcli/arborist/lib/index.js
+++ b/node_modules/@npmcli/arborist/lib/index.js
@@ -2,5 +2,6 @@ module.exports = require('./arborist/index.js')
module.exports.Arborist = module.exports
module.exports.Node = require('./node.js')
module.exports.Link = require('./link.js')
+module.exports.Edge = require('./edge.js')
// XXX export the other classes, too. shrinkwrap, diff, etc.
// they're handy!
diff --git a/node_modules/@npmcli/arborist/lib/node.js b/node_modules/@npmcli/arborist/lib/node.js
index 6e243c049..396bcb58a 100644
--- a/node_modules/@npmcli/arborist/lib/node.js
+++ b/node_modules/@npmcli/arborist/lib/node.js
@@ -40,6 +40,7 @@ const treeCheck = require('./tree-check.js')
const walkUp = require('walk-up-path')
const {resolve, relative, dirname, basename} = require('path')
+const util = require('util')
const _package = Symbol('_package')
const _parent = Symbol('_parent')
const _target = Symbol.for('_target')
@@ -63,6 +64,71 @@ const _meta = Symbol('_meta')
const relpath = require('./relpath.js')
const consistentResolve = require('./consistent-resolve.js')
+// helper function to output a clearer visualization
+// of the current node and its descendents
+class ArboristNode {}
+
+const printableTree = (tree, path = []) =>
+ (path.includes(tree) ? { location: tree.location } : (path.push(tree), Object.assign(new ArboristNode(), {
+ name: tree.name,
+ ...(tree.package && tree.package.version
+ ? { version: tree.package.version }
+ : {}),
+ location: tree.location,
+ path: tree.path,
+ realpath: tree.realpath,
+ ...(tree.isLink ? { target: printableTree(tree.target, path) } : {}),
+ ...(tree.resolved != null ? { resolved: tree.resolved } : {}),
+ ...(tree.extraneous ? { extraneous: true } : {
+ ...(tree.dev ? { dev: true } : {}),
+ ...(tree.optional ? { optional: true } : {}),
+ ...(tree.devOptional && !tree.dev && !tree.optional
+ ? { devOptional: true } : {}),
+ ...(tree.peer ? { peer: true } : {}),
+ }),
+ ...(tree.inBundle ? { bundled: true } : {}),
+ // handle top-level tree error
+ ...(tree.error
+ ? {
+ error: {
+ code: tree.error.code,
+ ...(tree.error.path
+ ? { path: tree.error.path }
+ : {}),
+ },
+ } : {}),
+ // handle errors for each node
+ ...(tree.errors && tree.errors.length
+ ? {
+ errors: tree.errors.map(error => ({
+ code: error.code,
+ ...(error.path
+ ? { path: error.path }
+ : {}),
+ })),
+ } : {}),
+ ...(tree.edgesIn && tree.edgesIn.size ? {
+ edgesIn: new Set([...tree.edgesIn]
+ .sort((a, b) => a.from.location.localeCompare(b.from.location))),
+ } : {}),
+ ...(tree.edgesOut && tree.edgesOut.size ? {
+ edgesOut: new Map([...tree.edgesOut.entries()]
+ .sort((a, b) => a[0].localeCompare(b[0]))),
+ } : {}),
+ ...(tree.fsChildren && tree.fsChildren.size ? {
+ fsChildren: new Set([...tree.fsChildren]
+ .sort((a, b) => a.path.localeCompare(b.path))
+ .map(tree => printableTree(tree, path))),
+ } : {}),
+ ...(tree.target || !tree.children || !tree.children.size
+ ? {}
+ : {
+ children: new Map([...tree.children.entries()]
+ .sort((a, b) => a[0].localeCompare(b[0]))
+ .map(([name, tree]) => [name, printableTree(tree, path)])),
+ }),
+ })))
+
class Node {
constructor (options) {
// NB: path can be null if it's a link target
@@ -1145,6 +1211,14 @@ class Node {
const base = scoped ? `${basename(d)}/${basename(rp)}` : basename(rp)
return base === name && basename(nm) === 'node_modules' ? dir : false
}
+
+ toJSON () {
+ return printableTree(this)
+ }
+
+ [util.inspect.custom] () {
+ return this.toJSON()
+ }
}
module.exports = Node
diff --git a/node_modules/@npmcli/arborist/lib/shrinkwrap.js b/node_modules/@npmcli/arborist/lib/shrinkwrap.js
index a454320a3..9254531e4 100644
--- a/node_modules/@npmcli/arborist/lib/shrinkwrap.js
+++ b/node_modules/@npmcli/arborist/lib/shrinkwrap.js
@@ -200,9 +200,9 @@ class Shrinkwrap {
return s[_maybeStat]().then(([sw, lock]) => {
s.filename = resolve(s.path,
(s.hiddenLockfile ? 'node_modules/.package-lock'
- : s.shrinkwrapOnly || sw && !lock ? 'npm-shrinkwrap'
+ : s.shrinkwrapOnly || sw ? 'npm-shrinkwrap'
: 'package-lock') + '.json')
- s.loadedFromDisk = sw || lock
+ s.loadedFromDisk = !!(sw || lock)
s.type = basename(s.filename)
return s
})
@@ -353,14 +353,14 @@ class Shrinkwrap {
// we don't need to load package-lock.json except for top of tree nodes,
// only npm-shrinkwrap.json.
return this[_maybeRead]().then(([sw, lock, yarn]) => {
- const data = lock || sw || ''
+ const data = sw || lock || ''
// use shrinkwrap only for deps, otherwise prefer package-lock
// and ignore npm-shrinkwrap if both are present.
// TODO: emit a warning here or something if both are present.
this.filename = resolve(this.path,
(this.hiddenLockfile ? 'node_modules/.package-lock'
- : this.shrinkwrapOnly || sw && !lock ? 'npm-shrinkwrap'
+ : this.shrinkwrapOnly || sw ? 'npm-shrinkwrap'
: 'package-lock') + '.json')
this.type = basename(this.filename)
diff --git a/node_modules/@npmcli/arborist/package.json b/node_modules/@npmcli/arborist/package.json
index 6300a5e86..1a46daa19 100644
--- a/node_modules/@npmcli/arborist/package.json
+++ b/node_modules/@npmcli/arborist/package.json
@@ -1,12 +1,12 @@
{
"name": "@npmcli/arborist",
- "version": "2.0.3",
+ "version": "2.0.5",
"description": "Manage node_modules trees",
"dependencies": {
"@npmcli/installed-package-contents": "^1.0.5",
"@npmcli/map-workspaces": "^1.0.1",
- "@npmcli/metavuln-calculator": "^1.0.0",
- "@npmcli/move-file": "^1.0.1",
+ "@npmcli/metavuln-calculator": "^1.0.1",
+ "@npmcli/move-file": "^1.1.0",
"@npmcli/name-from-folder": "^1.0.1",
"@npmcli/node-gyp": "^1.0.1",
"@npmcli/run-script": "^1.8.1",
@@ -19,7 +19,8 @@
"npm-install-checks": "^4.0.0",
"npm-package-arg": "^8.1.0",
"npm-pick-manifest": "^6.1.0",
- "pacote": "^11.1.14",
+ "npm-registry-fetch": "^9.0.0",
+ "pacote": "^11.2.1",
"parse-conflict-json": "^1.1.1",
"promise-all-reject-late": "^1.0.0",
"promise-call-limit": "^1.0.1",
diff --git a/node_modules/@npmcli/metavuln-calculator/lib/advisory.js b/node_modules/@npmcli/metavuln-calculator/lib/advisory.js
index 95bcc6755..15340f5dc 100644
--- a/node_modules/@npmcli/metavuln-calculator/lib/advisory.js
+++ b/node_modules/@npmcli/metavuln-calculator/lib/advisory.js
@@ -65,7 +65,7 @@ class Advisory {
// load up the data from a cache entry and a fetched packument
load (cached, packument) {
- // basic data integrity gutchecks
+ // basic data integrity gutcheck
if (!cached || typeof cached !== 'object') {
throw new TypeError('invalid cached data, expected object')
}
@@ -148,7 +148,42 @@ class Advisory {
}
[_calculateRange] () {
- const metavuln = this.vulnerableVersions.join(' || ').trim()
+ // calling semver.simplifyRange with a massive list of versions, and those
+ // versions all concatenated with `||` is a geometric CPU explosion!
+ // we can try to be a *little* smarter up front by doing x-y for all
+ // contiguous version sets in the list
+ const ranges = []
+ this.versions = semver.sort(this.versions)
+ this.vulnerableVersions = semver.sort(this.vulnerableVersions)
+ for (let v = 0, vulnVer = 0; v < this.versions.length; v++) {
+ // figure out the vulnerable subrange
+ const vr = [this.versions[v]]
+ while (v < this.versions.length) {
+ if (this.versions[v] !== this.vulnerableVersions[vulnVer]) {
+ // we don't test prerelease versions, so just skip past it
+ if (/-/.test(this.versions[v])) {
+ v++
+ continue
+ }
+ break
+ }
+ if (vr.length > 1)
+ vr[1] = this.versions[v]
+ else
+ vr.push(this.versions[v])
+ v++
+ vulnVer++
+ }
+ // it'll either be just the first version, which means no overlap,
+ // or the start and end versions, which might be the same version
+ if (vr.length > 1) {
+ const tail = this.versions[this.versions.length - 1]
+ ranges.push(vr[1] === tail ? `>=${vr[0]}`
+ : vr[0] === vr[1] ? vr[0]
+ : vr.join(' - '))
+ }
+ }
+ const metavuln = ranges.join(' || ').trim()
this.range = !metavuln ? '<0.0.0-0'
: semver.simplifyRange(this.versions, metavuln, semverOpt)
}
@@ -271,25 +306,99 @@ class Advisory {
}
for (const list of versionSets) {
- const headVuln = this.testVersion(list[0])
- const tailVuln = this.testVersion(list[list.length - 1])
+ // it's common to have version lists like:
+ // 1.0.0
+ // 1.0.1-alpha.0
+ // 1.0.1-alpha.1
+ // ...
+ // 1.0.1-alpha.999
+ // 1.0.1
+ // 1.0.2-alpha.0
+ // ...
+ // 1.0.2-alpha.99
+ // 1.0.2
+ // with a huge number of prerelease versions that are not installable
+ // anyway.
+ // If mid has a prerelease tag, and list[0] does not, then walk it
+ // back until we hit a non-prerelease version
+ // If mid has a prerelease tag, and list[list.length-1] does not,
+ // then walk it forward until we hit a version without a prerelease tag
+ // Similarly, if the head/tail is a prerelease, but there is a non-pr
+ // version in the list, then start there instead.
+ let h = 0
+ const origHeadVuln = this.testVersion(list[h])
+ while (h < list.length && /-/.test(String(list[h])))
+ h++
+
+ // don't filter out the whole list! they might all be pr's
+ if (h === list.length)
+ h = 0
+ else if (origHeadVuln) {
+ // if the original was vulnerable, assume so are all of these
+ for (let hh = 0; hh < h; hh++)
+ this[_markVulnerable](list[hh])
+ }
+
+ let t = list.length - 1
+ const origTailVuln = this.testVersion(list[t])
+ while (t > h && /-/.test(String(list[t])))
+ t--
+
+ // don't filter out the whole list! might all be pr's
+ if (t === h)
+ t = list.length - 1
+ else if (origTailVuln) {
+ // if original tail was vulnerable, assume these are as well
+ for (let tt = list.length - 1; tt > t; tt--)
+ this[_markVulnerable](list[tt])
+ }
+
+ const headVuln = h === 0 ? origHeadVuln
+ : this.testVersion(list[h])
+
+ const tailVuln = t === list.length - 1 ? origTailVuln
+ : this.testVersion(list[t])
+
// if head and tail both vulnerable, whole list is thrown out
if (headVuln && tailVuln) {
- for (const v of list.slice(1, -1)) {
- this[_markVulnerable](v)
- }
+ for (let v = h; v < t; v++)
+ this[_markVulnerable](list[v])
continue
}
// if length is 2 or 1, then we marked them all already
- if (list.length <= 2)
+ if (t < h + 2)
continue
const mid = Math.floor(list.length / 2)
- // leave out the ends, since we tested those already
- versionSets.add(list.slice(0, mid))
- versionSets.add(list.slice(mid))
+ const pre = list.slice(0, mid)
+ const post = list.slice(mid)
+
+ // if the parent list wasn't prereleases, then drop pr tags
+ // from end of the pre list, and beginning of the post list,
+ // marking as vulnerable if the midpoint item we picked is.
+ if (!/-/.test(String(pre[0]))) {
+ const midVuln = this.testVersion(pre[pre.length - 1])
+ while (/-/.test(String(pre[pre.length-1]))) {
+ const v = pre.pop()
+ if (midVuln)
+ this[_markVulnerable](v)
+ }
+ }
+
+ if (!/-/.test(String(post[post.length-1]))) {
+ const midVuln = this.testVersion(post[0])
+ while (/-/.test(String(post[0]))) {
+ const v = post.shift()
+ if (midVuln)
+ this[_markVulnerable](v)
+ }
+ }
+
+ versionSets.add(pre)
+ versionSets.add(post)
}
}
}
+
module.exports = Advisory
diff --git a/node_modules/@npmcli/metavuln-calculator/lib/load-worker.js b/node_modules/@npmcli/metavuln-calculator/lib/load-worker.js
new file mode 100644
index 000000000..5c5797b4f
--- /dev/null
+++ b/node_modules/@npmcli/metavuln-calculator/lib/load-worker.js
@@ -0,0 +1,29 @@
+// When Advisory.load() is called in the main thread, it spins up
+// a worker thread to do the actual loading, because this can be
+// a CPU-intensive operation which blocks the main thread otherwise.
+
+const {
+ Worker,
+ isMainThread,
+ parentPort,
+ workerData,
+} = require('worker_threads')
+
+const Advisory = require('./advisory.js')
+const load = async ({ name, source, options, cached, packument }) => {
+ const advisory = new Advisory(name, source, options)
+ // guard against infinite recursion, mostly for testing
+ advisory.inWorkerThread = true
+ await advisory.load(cached, packument)
+ parentPort.postMessage(advisory)
+}
+
+if (isMainThread)
+ module.exports = load
+else
+ load(workerData).catch(er => parentPort.postMessage({
+ error: {
+ message: er.message,
+ stack: er.stack,
+ },
+ }))
diff --git a/node_modules/@npmcli/metavuln-calculator/lib/test-version.js b/node_modules/@npmcli/metavuln-calculator/lib/test-version.js
new file mode 100644
index 000000000..211a46ddd
--- /dev/null
+++ b/node_modules/@npmcli/metavuln-calculator/lib/test-version.js
@@ -0,0 +1,59 @@
+// called by the Advisory[_testVersion] method, and the test-versions worker
+const semver = require('semver')
+const semverOpt = { includePrerelease: true, loose: true }
+const getDepSpec = require('./get-dep-spec.js')
+
+module.exports = opts => {
+ const {
+ version,
+ spec,
+ vulnerableVersions,
+ type,
+ range,
+ packument,
+ dependency,
+ source,
+ } = opts
+
+ const sv = String(version)
+ if (vulnerableVersions.includes(sv))
+ return true
+
+ if (type === 'advisory') {
+ // advisory, just test range
+ return semver.satisfies(version, range, semverOpt)
+ }
+
+ // check the dependency of version on the vulnerable dep
+ // if we got a version that's not in the packument, fall back on
+ // the spec provided, if possible.
+ const mani = packument.versions[version] || {
+ dependencies: {
+ [dependency]: spec,
+ },
+ }
+
+ if (!spec)
+ spec = getDepSpec(mani, dependency)
+
+ // no dep, no vuln
+ if (spec === null)
+ return false
+
+ // not a semver range, nothing we can hope to do about it
+ if (!semver.validRange(spec, semverOpt))
+ return true
+
+ const bd = mani.bundleDependencies
+ const bundled = bd && bd.includes(source.name)
+ // XXX if bundled, then semver.intersects() means vulnerable
+ // else, pick a manifest and see if it can't be avoided
+ // try to pick a version of the dep that isn't vulnerable
+ const avoid = source.range
+
+ if (bundled) {
+ return semver.intersects(spec, avoid, semverOpt)
+ }
+
+ return this[_source].testSpec(spec)
+}
diff --git a/node_modules/@npmcli/metavuln-calculator/package.json b/node_modules/@npmcli/metavuln-calculator/package.json
index ec5eea5a4..7f643cbc5 100644
--- a/node_modules/@npmcli/metavuln-calculator/package.json
+++ b/node_modules/@npmcli/metavuln-calculator/package.json
@@ -1,6 +1,6 @@
{
"name": "@npmcli/metavuln-calculator",
- "version": "1.0.0",
+ "version": "1.0.1",
"main": "lib/index.js",
"files": [
"lib"
diff --git a/node_modules/@npmcli/move-file/README.md b/node_modules/@npmcli/move-file/README.md
index da682ebd5..8a5a57f0f 100644
--- a/node_modules/@npmcli/move-file/README.md
+++ b/node_modules/@npmcli/move-file/README.md
@@ -3,7 +3,7 @@
A fork of [move-file](https://github.com/sindresorhus/move-file) with
compatibility with all node 10.x versions.
-> Move a file
+> Move a file (or directory)
The built-in
[`fs.rename()`](https://nodejs.org/api/fs.html#fs_fs_rename_oldpath_newpath_callback)
@@ -18,6 +18,7 @@ would have expected `fs.rename()` to be.
- Optionally prevent overwriting an existing file.
- Creates non-existent destination directories for you.
- Support for Node versions that lack built-in recursive `fs.mkdir()`
+- Automatically recurses when source is a directory.
## Install
@@ -48,13 +49,13 @@ Returns a `Promise` that resolves when the file has been moved.
Type: `string`
-File you want to move.
+File, or directory, you want to move.
#### destination
Type: `string`
-Where you want the file moved.
+Where you want the file or directory moved.
#### options
@@ -65,4 +66,4 @@ Type: `object`
Type: `boolean`\
Default: `true`
-Overwrite existing destination file.
+Overwrite existing destination file(s).
diff --git a/node_modules/@npmcli/move-file/index.js b/node_modules/@npmcli/move-file/index.js
index d1567d1f6..51f9535d3 100644
--- a/node_modules/@npmcli/move-file/index.js
+++ b/node_modules/@npmcli/move-file/index.js
@@ -1,4 +1,5 @@
-const { dirname } = require('path')
+const { dirname, join, resolve, relative, isAbsolute } = require('path')
+const rimraf_ = require('rimraf')
const { promisify } = require('util')
const {
access: access_,
@@ -7,14 +8,31 @@ const {
copyFileSync,
unlink: unlink_,
unlinkSync,
+ readdir: readdir_,
+ readdirSync,
rename: rename_,
renameSync,
+ stat: stat_,
+ statSync,
+ lstat: lstat_,
+ lstatSync,
+ symlink: symlink_,
+ symlinkSync,
+ readlink: readlink_,
+ readlinkSync
} = require('fs')
const access = promisify(access_)
const copyFile = promisify(copyFile_)
const unlink = promisify(unlink_)
+const readdir = promisify(readdir_)
const rename = promisify(rename_)
+const stat = promisify(stat_)
+const lstat = promisify(lstat_)
+const symlink = promisify(symlink_)
+const readlink = promisify(readlink_)
+const rimraf = promisify(rimraf_)
+const rimrafSync = rimraf_.sync
const mkdirp = require('mkdirp')
@@ -36,7 +54,7 @@ const pathExistsSync = path => {
}
}
-module.exports = async (source, destination, options = {}) => {
+const moveFile = async (source, destination, options = {}, root = true, symlinks = []) => {
if (!source || !destination) {
throw new TypeError('`source` and `destination` file required')
}
@@ -56,15 +74,38 @@ module.exports = async (source, destination, options = {}) => {
await rename(source, destination)
} catch (error) {
if (error.code === 'EXDEV') {
- await copyFile(source, destination)
- await unlink(source)
+ const sourceStat = await lstat(source)
+ if (sourceStat.isDirectory()) {
+ const files = await readdir(source)
+ await Promise.all(files.map((file) => moveFile(join(source, file), join(destination, file), options, false, symlinks)))
+ } else if (sourceStat.isSymbolicLink()) {
+ symlinks.push({ source, destination })
+ } else {
+ await copyFile(source, destination)
+ }
} else {
throw error
}
}
+
+ if (root) {
+ await Promise.all(symlinks.map(async ({ source, destination }) => {
+ let target = await readlink(source)
+ // junction symlinks in windows will be absolute paths, so we need to make sure they point to the destination
+ if (isAbsolute(target))
+ target = resolve(destination, relative(source, target))
+ // try to determine what the actual file is so we can create the correct type of symlink in windows
+ let targetStat
+ try {
+ targetStat = await stat(resolve(dirname(source), target))
+ } catch (err) {}
+ await symlink(target, destination, targetStat && targetStat.isDirectory() ? 'junction' : 'file')
+ }))
+ await rimraf(source)
+ }
}
-module.exports.sync = (source, destination, options = {}) => {
+const moveFileSync = (source, destination, options = {}, root = true, symlinks = []) => {
if (!source || !destination) {
throw new TypeError('`source` and `destination` file required')
}
@@ -84,10 +125,38 @@ module.exports.sync = (source, destination, options = {}) => {
renameSync(source, destination)
} catch (error) {
if (error.code === 'EXDEV') {
- copyFileSync(source, destination)
- unlinkSync(source)
+ const sourceStat = lstatSync(source)
+ if (sourceStat.isDirectory()) {
+ const files = readdirSync(source)
+ for (const file of files) {
+ moveFileSync(join(source, file), join(destination, file), options, false, symlinks)
+ }
+ } else if (sourceStat.isSymbolicLink()) {
+ symlinks.push({ source, destination })
+ } else {
+ copyFileSync(source, destination)
+ }
} else {
throw error
}
}
+
+ if (root) {
+ for (const { source, destination } of symlinks) {
+ let target = readlinkSync(source)
+ // junction symlinks in windows will be absolute paths, so we need to make sure they point to the destination
+ if (isAbsolute(target))
+ target = resolve(destination, relative(source, target))
+ // try to determine what the actual file is so we can create the correct type of symlink in windows
+ let targetStat
+ try {
+ targetStat = statSync(resolve(dirname(source), target))
+ } catch (err) {}
+ symlinkSync(target, destination, targetStat && targetStat.isDirectory() ? 'junction' : 'file')
+ }
+ rimrafSync(source)
+ }
}
+
+module.exports = moveFile
+module.exports.sync = moveFileSync
diff --git a/node_modules/@npmcli/move-file/package.json b/node_modules/@npmcli/move-file/package.json
index 476bc76ba..46b42c9e9 100644
--- a/node_modules/@npmcli/move-file/package.json
+++ b/node_modules/@npmcli/move-file/package.json
@@ -1,12 +1,13 @@
{
"name": "@npmcli/move-file",
- "version": "1.0.1",
+ "version": "1.1.0",
"files": [
"index.js"
],
"description": "move a file (fork of move-file)",
"dependencies": {
- "mkdirp": "^1.0.4"
+ "mkdirp": "^1.0.4",
+ "rimraf": "^2.7.1"
},
"devDependencies": {
"require-inject": "^1.4.4",