'use strict' module.exports = move var nodeFs = require('fs') var rimraf = require('rimraf') var validate = require('aproba') var copy = require('copy-concurrently') var RunQueue = require('run-queue') var extend = Object.assign || require('util')._extend function promisify (Promise, fn) { return function () { var args = [].slice.call(arguments) return new Promise(function (resolve, reject) { return fn.apply(null, args.concat(function (err, value) { if (err) { reject(err) } else { resolve(value) } })) }) } } function move (from, to, opts) { validate('SSO|SS', arguments) opts = extend({}, opts || {}) var Promise = opts.Promise || global.Promise var fs = opts.fs || nodeFs var rimrafAsync = promisify(Promise, rimraf) var renameAsync = promisify(Promise, fs.rename) opts.top = from var queue = new RunQueue({ maxConcurrency: opts.maxConcurrency, Promise: Promise }) opts.queue = queue opts.recurseWith = rename queue.add(0, rename, [from, to, opts]) return queue.run().then(function () { return remove(from) }, function (err) { // if the target already exists don't clobber it if (err.code === 'EEXIST' || err.code === 'EPERM') { return passThroughError() } else { return remove(to).then(passThroughError, passThroughError) } function passThroughError () { return Promise.reject(err) } }) function remove (target) { var opts = { unlink: fs.unlink, chmod: fs.chmod, stat: fs.stat, lstat: fs.lstat, rmdir: fs.rmdir, readdir: fs.readdir, glob: false } return rimrafAsync(target, opts) } function rename (from, to, opts, done) { return renameAsync(from, to).catch(function (err) { if (err.code !== 'EXDEV') { return Promise.reject(err) } else { return remove(to).then(function () { return copy.item(from, to, opts) }) } }) } }