From 20420ae54ace38128e2b9d9cfeb53c8f979621cf Mon Sep 17 00:00:00 2001 From: Eduard Marbach Date: Sun, 27 Oct 2019 12:33:49 +0100 Subject: [PATCH] feat: Add PNPM support --- lib/resolve.js | 43 +++++++++++++++++++++++++++------ test/index.js | 65 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/lib/resolve.js b/lib/resolve.js index 2e9b8d5..8ba6237 100644 --- a/lib/resolve.js +++ b/lib/resolve.js @@ -23,6 +23,30 @@ var requireFunction = ("function" === typeof __webpack_require__ || "function" = ? __non_webpack_require__ : require; +const isInstalledWithPNPM = function(resolved) { + const pnpmDir = sep + '.pnpm'; + + for (const globalPath of globalPaths) { + if (-1 !== globalPath.indexOf(pnpmDir) && -1 !== resolved.indexOf(pnpmDir)) { + return true; + } + } + return false; +} + +const getFirstPartFromNodeModules = function(resolved) { + const nodeModulesDir = sep + 'node_modules'; + + if (-1 !== resolved.indexOf(nodeModulesDir)) { + const parts = resolved.split(nodeModulesDir); + if (parts.length) { + return parts[0]; + } + } + + return null; +} + // Resolver module.exports = function resolve(dirname) { // Check for environmental variable @@ -55,6 +79,16 @@ module.exports = function resolve(dirname) { var alternateMethod = false; var appRootPath = null; + // Check if the globalPaths contain some folders with '.pnpm' in the path + // If yes this means it is most likely installed with pnpm + if (isInstalledWithPNPM(resolved)) { + appRootPath = getFirstPartFromNodeModules(resolved); + + if (appRootPath) { + return appRootPath; + } + } + // Make sure that we're not loaded from a global include path // Eg. $HOME/.node_modules // $HOME/.node_libraries @@ -67,13 +101,8 @@ module.exports = function resolve(dirname) { // If the app-root-path library isn't loaded globally, // and node_modules exists in the path, just split __dirname - var nodeModulesDir = sep + 'node_modules'; - if (!alternateMethod && -1 !== resolved.indexOf(nodeModulesDir)) { - var parts = resolved.split(nodeModulesDir); - if (parts.length) { - appRootPath = parts[0]; - parts = null; - } + if (!alternateMethod) { + appRootPath = getFirstPartFromNodeModules(resolved); } // If the above didn't work, or this module is loaded globally, then diff --git a/test/index.js b/test/index.js index f72ec58..d5e03a2 100644 --- a/test/index.js +++ b/test/index.js @@ -4,9 +4,16 @@ var path = require('path'); var assert = require('assert'); var mockery = require('mockery'); +function globalPathsContainPnpm() { + return undefined !== require('module').globalPaths.find(function(e) { + return e.indexOf('.pnpm') !== -1 + }); +} + describe('The path resolution method', function() { var resolve = require('../lib/resolve.js'); var originalReqMainFilename = require.main.filename; + const isPnpm = globalPathsContainPnpm(); // Make sure env variable isn't set for tests if (process.env.APP_ROOT_PATH) { @@ -21,14 +28,53 @@ describe('The path resolution method', function() { require.main.filename = originalReqMainFilename; }); - // Check global paths - it('should use require.main.filename if the path is in the globalPaths array', function() { - var expected = path.dirname(require.main.filename); - require('module').globalPaths.forEach(function(globalPath) { - var testPath = globalPath + path.sep + 'node-app-root-path'; - assert.equal(resolve(testPath), expected); + if (isPnpm) { + it('should use require.main.filename if the path is in the globalPaths array (PNPM)', function() { + var expected = path.dirname(require.main.filename); + var root = path.resolve(__dirname, '..'); + + require('module').globalPaths.forEach(function(globalPath) { + var testPath = globalPath + path.sep + 'node-app-root-path'; + + if (-1 !== testPath.indexOf('.pnpm')) { + assert.equal(resolve(testPath), root); + } else { + assert.equal(resolve(testPath), expected); + } + }); + }); + + // Check pnpm + it('should use String.split() if installed with pnpm', function() { + var cases = [ + '/var/www/node_modules/.pnpm/node_modules/node-app-root-path', + '/var/www/node_modules/.pnpm/custom_registry/node-app-root-path', + ]; + var expected = '/var/www'; + + cases.forEach(function(testPath) { + assert.equal(resolve(testPath), expected); + }); }); - }); + + // Check root path + it('should still use String.split() in the root directory (PNPM)', function() { + assert.equal(resolve('/node_modules'), path.dirname(require.main.filename)); + }); + } else { + it('should use require.main.filename if the path is in the globalPaths array', function() { + var expected = path.dirname(require.main.filename); + require('module').globalPaths.forEach(function(globalPath) { + var testPath = globalPath + path.sep + 'node-app-root-path'; + assert.equal(resolve(testPath), expected); + }); + }); + + // Check root path + it('should still use String.split() in the root directory', function() { + assert.equal(resolve('/node_modules'), ''); + }); + } // Check bin/ dir in global path it('should correctly handle the global bin/ edge case', function() { @@ -54,11 +100,6 @@ describe('The path resolution method', function() { }); }); - // Check root path - it('should still use String.split() in the root directory', function() { - assert.equal(resolve('/node_modules'), ''); - }); - // Check unexpected path it('should use require.main.filename on unexpected input', function() { var cases = [