diff --git a/node_modules/read-package-tree/README.md b/node_modules/read-package-tree/README.md index c8edffd2bcc2e..aa0cc934cf47e 100644 --- a/node_modules/read-package-tree/README.md +++ b/node_modules/read-package-tree/README.md @@ -29,6 +29,9 @@ rpt('/path/to/pkg/root', function (node, kidName) { // error: // } }) + +// or promise-style +rpt('/path/to/pkg/root').then(data => { ... }) ``` That's it. It doesn't figure out if dependencies are met, it doesn't diff --git a/node_modules/read-package-tree/package.json b/node_modules/read-package-tree/package.json index 948f096620033..2173171af80ff 100644 --- a/node_modules/read-package-tree/package.json +++ b/node_modules/read-package-tree/package.json @@ -1,8 +1,8 @@ { "_from": "read-package-tree@latest", - "_id": "read-package-tree@5.2.2", + "_id": "read-package-tree@5.3.1", "_inBundle": false, - "_integrity": "sha512-rW3XWUUkhdKmN2JKB4FL563YAgtINifso5KShykufR03nJ5loGFlkUMe1g/yxmqX073SoYYTsgXu7XdDinKZuA==", + "_integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", "_location": "/read-package-tree", "_phantomChildren": {}, "_requested": { @@ -20,10 +20,10 @@ "/", "/licensee" ], - "_resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.2.tgz", - "_shasum": "4b6a0ef2d943c1ea36a578214c9a7f6b7424f7a8", + "_resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "_shasum": "a32cb64c7f31eb8a6f31ef06f9cedf74068fe636", "_spec": "read-package-tree@latest", - "_where": "/Users/zkat/Documents/code/work/npm", + "_where": "/Users/isaacs/dev/npm/cli", "author": { "name": "Isaac Z. Schlueter", "email": "i@izs.me", @@ -34,11 +34,9 @@ }, "bundleDependencies": false, "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "once": "^1.3.0", "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0" + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" }, "deprecated": false, "description": "Read the contents of node_modules.", @@ -46,13 +44,14 @@ "archy": "^1.0.0", "mkdirp": "^0.5.1", "tacks": "^1.2.1", - "tap": "^12.5.2" + "tap": "^12.7.0" }, "directories": { "test": "test" }, "files": [ - "rpt.js" + "rpt.js", + "realpath.js" ], "homepage": "https://github.com/npm/read-package-tree", "license": "ISC", @@ -63,7 +62,14 @@ "url": "git+https://github.com/npm/read-package-tree.git" }, "scripts": { - "test": "tap test/*.js" + "postpublish": "git push origin --follow-tags", + "postversion": "npm publish", + "preversion": "npm test", + "snap": "TAP_SNAPSHOT=1 tap test/*.js --100", + "test": "tap test/*.js --100" }, - "version": "5.2.2" + "tap": { + "100": true + }, + "version": "5.3.1" } diff --git a/node_modules/read-package-tree/rpt.js b/node_modules/read-package-tree/rpt.js index fd43be9c22c0c..b12a09dfb3b20 100644 --- a/node_modules/read-package-tree/rpt.js +++ b/node_modules/read-package-tree/rpt.js @@ -1,249 +1,169 @@ -var fs = require('fs') -var rpj = require('read-package-json') -var path = require('path') -var dz = require('dezalgo') -var once = require('once') -var readdir = require('readdir-scoped-modules') -var debug = require('debuglog')('rpt') - -function asyncForEach (items, todo, done) { - var remaining = items.length - if (remaining === 0) return done() - var seenErr - items.forEach(function (item) { - todo(item, handleComplete) - }) - function handleComplete (err) { - if (seenErr) return - if (err) { - seenErr = true - return done(err) - } - if (--remaining === 0) done() +const fs = require('fs') +/* istanbul ignore next */ +const promisify = require('util').promisify || require('util-promisify') +const { resolve, basename, dirname, join } = require('path') +const rpj = promisify(require('read-package-json')) +const readdir = promisify(require('readdir-scoped-modules')) +const realpath = require('./realpath.js') + +let ID = 0 +class Node { + constructor (pkg, logical, physical, er, cache) { + // should be impossible. + const cached = cache.get(physical) + /* istanbul ignore next */ + if (cached && !cached.then) + throw new Error('re-creating already instantiated node') + + cache.set(physical, this) + + const parent = basename(dirname(logical)) + if (parent.charAt(0) === '@') + this.name = `${parent}/${basename(logical)}` + else + this.name = basename(logical) + this.path = logical + this.realpath = physical + this.error = er + this.id = ID++ + this.package = pkg || {} + this.parent = null + this.isLink = false + this.children = [] } } -function dpath (p) { - if (!p) return '' - if (p.indexOf(process.cwd()) === 0) { - p = p.substr(process.cwd().length + 1) +class Link extends Node { + constructor (pkg, logical, physical, realpath, er, cache) { + super(pkg, logical, physical, er, cache) + + // if the target has started, but not completed, then + // a Promise will be in the cache to indicate this. + const cachedTarget = cache.get(realpath) + if (cachedTarget && cachedTarget.then) + cachedTarget.then(node => { + this.target = node + this.children = node.children + }) + + this.target = cachedTarget || new Node(pkg, logical, realpath, er, cache) + this.realpath = realpath + this.isLink = true + this.error = er + this.children = this.target.children } - return p -} - -module.exports = rpt - -rpt.Node = Node -rpt.Link = Link - -var ID = 0 -function Node (pkg, logical, physical, er, cache, fromLink) { - if (!(this instanceof Node)) { - return new Node(pkg, logical, physical, er, cache) - } - - var node = cache[physical] || this - if (fromLink && cache[physical]) return cache[physical] - - debug(node.constructor.name, dpath(physical), pkg && pkg._id) - - const parent = path.basename(path.dirname(logical)) - if (parent[0] === '@') { - node.name = parent + '/' + path.basename(logical) - } else { - node.name = path.basename(logical) - } - node.path = logical - node.realpath = physical - node.error = er - if (!cache[physical]) { - node.id = ID++ - node.package = pkg || {} - node.parent = null - node.isLink = false - node.children = [] - } - return cache[physical] = node } -Node.prototype.package = null -Node.prototype.path = '' -Node.prototype.realpath = '' -Node.prototype.children = null -Node.prototype.error = null - -function Link (pkg, logical, physical, realpath, er, cache) { - if (cache[physical]) return cache[physical] - - if (!(this instanceof Link)) { - return new Link(pkg, logical, physical, realpath, er, cache) - } - - cache[physical] = this - - debug(this.constructor.name, dpath(physical), pkg && pkg._id) - - const parent = path.basename(path.dirname(logical)) - if (parent[0] === '@') { - this.name = parent + '/' + path.basename(logical) - } else { - this.name = path.basename(logical) - } - this.id = ID++ - this.path = logical - this.realpath = realpath - this.package = pkg || {} - this.parent = null - this.target = new Node(this.package, logical, realpath, er, cache, true) - this.isLink = true - this.children = this.target.children - this.error = er -} - -Link.prototype = Object.create(Node.prototype, { - constructor: { value: Link } -}) -Link.prototype.target = null -Link.prototype.realpath = '' - -function loadNode (logical, physical, cache, cb) { - debug('loadNode', dpath(logical)) - return fs.realpath(physical, thenReadPackageJson) - - var realpath - function thenReadPackageJson (er, real) { - if (er) { - var node = new Node(null, logical, physical, er, cache) - return cb(null, node) - } - debug('realpath l=%j p=%j real=%j', dpath(logical), dpath(physical), dpath(real)) - var pj = path.join(real, 'package.json') - realpath = real - return rpj(pj, thenCreateNode) - } - function thenCreateNode (er, pkg) { - pkg = pkg || null - var node - if (physical === realpath) { - node = new Node(pkg, logical, physical, er, cache) - } else { - node = new Link(pkg, logical, physical, realpath, er, cache) - } - - cb(null, node) - } +// this is the way it is to expose a timing issue which is difficult to +// test otherwise. The creation of a Node may take slightly longer than +// the creation of a Link that targets it. If the Node has _begun_ its +// creation phase (and put a Promise in the cache) then the Link will +// get a Promise as its cachedTarget instead of an actual Node object. +// This is not a problem, because it gets resolved prior to returning +// the tree or attempting to load children. However, it IS remarkably +// difficult to get to happen in a test environment to verify reliably. +// Hence this kludge. +const newNode = (pkg, logical, physical, er, cache) => + process.env._TEST_RPT_SLOW_LINK_TARGET_ === '1' + ? new Promise(res => setTimeout(() => + res(new Node(pkg, logical, physical, er, cache)), 10)) + : new Node(pkg, logical, physical, er, cache) + +const loadNode = (logical, physical, cache, rpcache, stcache) => { + // cache temporarily holds a promise placeholder so we + // don't try to create the same node multiple times. + // this is very rare to encounter, given the aggressive + // caching on fs.realpath and fs.lstat calls, but + // it can happen in theory. + const cached = cache.get(physical) + /* istanbul ignore next */ + if (cached) + return Promise.resolve(cached) + + const p = realpath(physical, rpcache, stcache, 0).then(real => + rpj(join(real, 'package.json')) + .then(pkg => [pkg, null], er => [null, er]) + .then(([pkg, er]) => + physical === real ? newNode(pkg, logical, physical, er, cache) + : new Link(pkg, logical, physical, real, er, cache) + ), + // if the realpath fails, don't bother with the rest + er => new Node(null, logical, physical, er, cache)) + + cache.set(physical, p) + return p } -function loadChildren (node, cache, filterWith, cb) { - debug('loadChildren', dpath(node.path)) - // needed 'cause we process all kids async-like and errors - // short circuit, so we have to be sure that after an error - // the cbs from other kids don't result in calling cb a second - // (or more) time. - cb = once(cb) - var nm = path.join(node.path, 'node_modules') - var rm - return fs.realpath(path.join(node.path, 'node_modules'), thenReaddir) - - function thenReaddir (er, real_nm) { - if (er) return cb(null, node) - rm = real_nm - readdir(nm, thenLoadKids) - } - - function thenLoadKids (er, kids) { - // If there are no children, that's fine, just return - if (er) return cb(null, node) - - kids = kids.filter(function (kid) { - return kid[0] !== '.' && (!filterWith || filterWith(node, kid)) +const loadChildren = (node, cache, filterWith, rpcache, stcache) => { + // if a Link target has started, but not completed, then + // a Promise will be in the cache to indicate this. + // + // XXX When we can one day loadChildren on the link *target* instead of + // the link itself, to match real dep resolution, then we may end up with + // a node target in the cache that isn't yet done resolving when we get + // here. For now, though, this line will never be reached, so it's hidden + // + // if (node.then) + // return node.then(node => loadChildren(node, cache, filterWith, rpcache, stcache)) + + const nm = join(node.path, 'node_modules') + return realpath(nm, rpcache, stcache, 0) + .then(rm => readdir(rm).then(kids => [rm, kids])) + .then(([rm, kids]) => Promise.all( + kids.filter(kid => + kid.charAt(0) !== '.' && (!filterWith || filterWith(node, kid))) + .map(kid => loadNode(join(nm, kid), join(rm, kid), cache, rpcache, stcache))) + ).then(kidNodes => { + kidNodes.forEach(k => k.parent = node) + node.children.push.apply(node.children, kidNodes.sort((a, b) => + (a.package.name ? a.package.name.toLowerCase() : a.path) + .localeCompare( + (b.package.name ? b.package.name.toLowerCase() : b.path) + ))) + return node }) - - asyncForEach(kids, thenLoadNode, thenSortChildren) - } - function thenLoadNode (kid, done) { - var kidPath = path.join(nm, kid) - var kidRealPath = path.join(rm, kid) - loadNode(kidPath, kidRealPath, cache, andAddNode(done)) - } - function andAddNode (done) { - return function (er, kid) { - if (er) return done(er) - node.children.push(kid) - kid.parent = node - done() - } - } - function thenSortChildren (er) { - sortChildren(node) - cb(er, node) - } + .catch(() => node) } -function sortChildren (node) { - node.children = node.children.sort(function (a, b) { - a = a.package.name ? a.package.name.toLowerCase() : a.path - b = b.package.name ? b.package.name.toLowerCase() : b.path - return a > b ? 1 : -1 - }) +const loadTree = (node, did, cache, filterWith, rpcache, stcache) => { + // impossible except in pathological ELOOP cases + /* istanbul ignore next */ + if (did.has(node.realpath)) + return Promise.resolve(node) + + did.add(node.realpath) + + // load children on the target, not the link + return loadChildren(node, cache, filterWith, rpcache, stcache) + .then(node => Promise.all( + node.children + .filter(kid => !did.has(kid.realpath)) + .map(kid => loadTree(kid, did, cache, filterWith, rpcache, stcache)) + )).then(() => node) } -function loadTree (node, did, cache, filterWith, cb) { - debug('loadTree', dpath(node.path), !!cache[node.path]) - - if (did[node.realpath]) { - return dz(cb)(null, node) +// XXX Drop filterWith and/or cb in next semver major bump +const rpt = (root, filterWith, cb) => { + if (!cb && typeof filterWith === 'function') { + cb = filterWith + filterWith = null } - did[node.realpath] = true + const cache = new Map() + // we can assume that the cwd is real enough + const cwd = process.cwd() + const rpcache = new Map([[ cwd, cwd ]]) + const stcache = new Map() + const p = realpath(root, rpcache, stcache, 0) + .then(realRoot => loadNode(root, realRoot, cache, rpcache, stcache)) + .then(node => loadTree(node, new Set(), cache, filterWith, rpcache, stcache)) - // needed 'cause we process all kids async-like and errors - // short circuit, so we have to be sure that after an error - // the cbs from other kids don't result in calling cb a second - // (or more) time. - cb = once(cb) - return loadChildren(node, cache, filterWith, thenProcessChildren) - - function thenProcessChildren (er, node) { - if (er) return cb(er) - - var kids = node.children.filter(function (kid) { - return !did[kid.realpath] - }) + if (typeof cb === 'function') + p.then(tree => cb(null, tree), cb) - return asyncForEach(kids, loadTreeForKid, cb) - } - function loadTreeForKid (kid, done) { - loadTree(kid, did, cache, filterWith, done) - } + return p } -function rpt (root, filterWith, cb) { - if (!cb) { - cb = filterWith - filterWith = null - } - var cache = Object.create(null) - var topErr - var tree - return fs.realpath(root, thenLoadNode) - - function thenLoadNode (er, realRoot) { - if (er) return cb(er) - debug('rpt', dpath(realRoot)) - loadNode(root, realRoot, cache, thenLoadTree) - } - function thenLoadTree(er, node) { - // even if there's an error, it's fine, as long as we got a node - if (node) { - topErr = er - tree = node - loadTree(node, {}, cache, filterWith, thenHandleErrors) - } else { - cb(er) - } - } - function thenHandleErrors (er) { - cb(topErr && topErr.code !== 'ENOENT' ? topErr : er, tree) - } -} +rpt.Node = Node +rpt.Link = Link +module.exports = rpt diff --git a/package-lock.json b/package-lock.json index d5fac967d49f9..ae373549e49b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1224,7 +1224,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -1433,7 +1432,6 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", - "dev": true, "requires": { "es-to-primitive": "^1.1.1", "function-bind": "^1.1.1", @@ -1446,7 +1444,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -2193,8 +2190,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function-loop": { "version": "1.0.2", @@ -2416,7 +2412,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -2438,8 +2433,7 @@ "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, "has-unicode": { "version": "2.0.1", @@ -2671,8 +2665,7 @@ "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-ci": { "version": "1.1.0", @@ -2700,8 +2693,7 @@ "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-fullwidth-code-point": { "version": "1.0.0", @@ -2753,7 +2745,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, "requires": { "has": "^1.0.1" } @@ -2778,7 +2769,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, "requires": { "has-symbols": "^1.0.0" } @@ -4252,8 +4242,16 @@ "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", - "dev": true + "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } }, "on-finished": { "version": "2.3.0", @@ -4898,15 +4896,13 @@ } }, "read-package-tree": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.2.2.tgz", - "integrity": "sha512-rW3XWUUkhdKmN2JKB4FL563YAgtINifso5KShykufR03nJ5loGFlkUMe1g/yxmqX073SoYYTsgXu7XdDinKZuA==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "once": "^1.3.0", "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0" + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" } }, "read-pkg": { @@ -6337,6 +6333,14 @@ "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index 7f686930b646c..594efe4332f4f 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "read-cmd-shim": "~1.0.1", "read-installed": "~4.0.3", "read-package-json": "^2.0.13", - "read-package-tree": "^5.2.2", + "read-package-tree": "^5.3.1", "readable-stream": "^3.3.0", "readdir-scoped-modules": "^1.1.0", "request": "^2.88.0", diff --git a/test/tap/no-scan-full-global-dir.js b/test/tap/no-scan-full-global-dir.js index 4ec403ddcaa44..7856ff33f41f2 100644 --- a/test/tap/no-scan-full-global-dir.js +++ b/test/tap/no-scan-full-global-dir.js @@ -6,6 +6,9 @@ var requireInject = require('require-inject') var osenv = require('osenv') var npm = require('../../lib/npm.js') +// XXX update this when rpt's realpath.js is extracted out +var rptRealpath = require.resolve('read-package-tree/realpath.js') + const common = require('../common-tap.js') const pkg = common.pkg var packages = { @@ -41,6 +44,8 @@ mockFs.realpath = function (dir, cb) { return cb(null, dir) } +const mockRptRealpath = path => Promise.resolve(path) + test('setup', function (t) { npm.load(function () { t.pass('npm loaded') @@ -54,7 +59,8 @@ test('installer', function (t) { 'fs': mockFs, 'readdir-scoped-modules': mockReaddir, 'read-package-json': mockReadPackageJson, - 'mkdirp': function (path, cb) { cb() } + 'mkdirp': function (path, cb) { cb() }, + [rptRealpath]: mockRptRealpath }) var Installer = installer.Installer @@ -83,7 +89,8 @@ test('uninstaller', function (t) { 'fs': mockFs, 'readdir-scoped-modules': mockReaddir, 'read-package-json': mockReadPackageJson, - 'mkdirp': function (path, cb) { cb() } + 'mkdirp': function (path, cb) { cb() }, + [rptRealpath]: mockRptRealpath }) var Uninstaller = uninstaller.Uninstaller