From 1f58816a4bdc44cefe807ae28b13dd0ad38af462 Mon Sep 17 00:00:00 2001 From: Gleb Kochergin Date: Mon, 5 Jul 2021 18:48:47 +0500 Subject: [PATCH] WIP --- index.js | 94 ++++++++++++++++++++++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/index.js b/index.js index dbb0344..54d1995 100644 --- a/index.js +++ b/index.js @@ -1,39 +1,91 @@ +const fs = require("fs"); +const path = require("path"); + +function findMainPackageJson(entryPath, packageName) { + entryPath = entryPath.replace(/\//g, path.sep); + let directoryName = path.dirname(entryPath); + while (directoryName && !directoryName.endsWith(packageName)) { + const parentDirectoryName = path.resolve(directoryName, ".."); + if (parentDirectoryName === directoryName) { + break; + } + directoryName = parentDirectoryName; + } + + const suspect = path.resolve(directoryName, "package.json"); + if (fs.existsSync(suspect)) { + return JSON.parse(fs.readFileSync(suspect).toString()); + } + + return null; +} + module.exports = (request, options) => { - let pkgName = ""; + let packageName = ""; let submoduleName = ""; // NOTE: jest-sequencer is a special prefixed jest request - if ( + const isNodeModuleRequest = !request.startsWith(".") && !request.startsWith("/") && - !request.startsWith("jest-sequencer") - ) { + !request.startsWith("jest-sequencer"); + + if (isNodeModuleRequest) { const pkgPathParts = request.split("/"); if (request.startsWith("@") && pkgPathParts.length > 2) { - pkgName = pkgPathParts.slice(0, 2).join("/"); + packageName = pkgPathParts.slice(0, 2).join("/"); submoduleName = `./${pkgPathParts.slice(2).join("/")}`; } else if (!request.startsWith("@") && pkgPathParts.length > 1) { - pkgName = pkgPathParts[0]; + packageName = pkgPathParts[0]; submoduleName = `./${pkgPathParts.slice(1).join("/")}`; } } - const submoduleHasExtension = /\.\w+$/.test(submoduleName); - if (pkgName && submoduleName && !submoduleHasExtension) { - let pkg; + const extension = path.extname(submoduleName); + if (packageName && submoduleName && !extension) { + let packageJson = undefined; + try { - pkg = require(`${pkgName}/package.json`); - } catch (e) { - console.log(`Error while trying to get ${pkgName}'s package.json:`); - console.error(e); + packageJson = require(`${packageName}/package.json`); + } catch (requireError) { + if (requireError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") { + // modules's package.json does not provide the "./package.json" path at it's "exports" field + // try to resolve manually + try { + const requestPath = require.resolve(packageName); + packageJson = + requestPath && findMainPackageJson(requestPath, packageName); + } catch (resolveError) { + if (resolveError.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") { + console.warn( + `Could not retrieve package.json neither through require (package.json itself is not within "exports" field), nor through require.resolve (package.json does not specify "main" field) - falling back to default resolver logic` + ); + } else { + console.log( + `Unexpected error while performing require.resolve(${packageName}):` + ); + console.error(resolveError); + return null; + } + } + } else { + console.log(`Unexpected error while requiring ${packageName}:`); + console.error(requireError); + return null; + } } - if ( - pkg && - pkg.exports && - Object.keys(pkg.exports).every((k) => k.startsWith(".")) - ) { - const exportValue = pkg.exports[submoduleName]; + if (!packageJson) { + console.error(`Failed to find package.json for ${packageName}`); + } + + const hasExports = packageJson && packageJson.exports; + const isEntryPointsExports = + hasExports && + Object.keys(packageJson.exports).every((k) => k.startsWith(".")); + + if (hasExports && isEntryPointsExports) { + const exportValue = packageJson.exports[submoduleName]; let targetFilePath; if (typeof exportValue === "string") { @@ -45,13 +97,13 @@ module.exports = (request, options) => { targetFilePath = exportValue.require; } - if (!targetFilePath && pkg.type !== "module") { + if (!targetFilePath && packageJson.type !== "module") { targetFilePath = exportValue.default; } } if (targetFilePath) { - const target = targetFilePath.replace("./", `${pkgName}/`); + const target = targetFilePath.replace("./", `${packageName}/`); return options.defaultResolver(target, options); } } diff --git a/package.json b/package.json index e0cecaf..f8ecc4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jest-node-exports-resolver", - "version": "1.0.1", + "version": "1.0.2", "description": "Jest resolver to handle node's 'exports' package entry points.", "main": "index.js", "repository": "https://github.com/k-g-a/jest-node-exports-resolver.git",