diff --git a/src/esmockArgs.js b/src/esmockArgs.js index 5be05cc..141bd75 100644 --- a/src/esmockArgs.js +++ b/src/esmockArgs.js @@ -1,4 +1,5 @@ -import resolver from 'resolvewithplus' +import resolvewithplus from 'resolvewithplus' +import pnpResolver from './pnpResolver.js' // extracts path or fileurl from stack, // ' at <anonymous> (/root/test.js:11:31)' -> /root/test.js @@ -7,6 +8,8 @@ import resolver from 'resolvewithplus' // ' at file:///D:/a/test.js:7:9' -> file:///D:/a/test.js const stackpathre = /^.*(\(|at )(.*):[\d]*:[\d]*.*$/ +const resolver = pnpResolver || resolvewithplus + // this function normalizes "overloaded" args signatures, returning // one predictable args list. ex, // [moduleId, defs, gdefs, opts] diff --git a/src/pnpResolver.js b/src/pnpResolver.js new file mode 100644 index 0000000..26edf29 --- /dev/null +++ b/src/pnpResolver.js @@ -0,0 +1,18 @@ +import { isBuiltin } from 'node:module' +import { pathToFileURL } from 'node:url' + +const pnpapi = process.versions.pnp && (await import('pnpapi')).default + +export default pnpapi && ((id, parent) => { + if (isBuiltin(id)) { + return id.startsWith('node:') ? id : `node:${id}` + } + + if (id === 'import') { + return null + } + + const path = pnpapi.resolveRequest(id, parent) + + return path !== null ? pathToFileURL(path).href : null +}) diff --git a/tests/local/pnp/api.js b/tests/local/pnp/api.js new file mode 100644 index 0000000..b1c6ea4 --- /dev/null +++ b/tests/local/pnp/api.js @@ -0,0 +1 @@ +export default {} diff --git a/tests/local/pnp/disable.js b/tests/local/pnp/disable.js new file mode 100644 index 0000000..5d0632d --- /dev/null +++ b/tests/local/pnp/disable.js @@ -0,0 +1 @@ +delete process.versions.pnp diff --git a/tests/local/pnp/enable.js b/tests/local/pnp/enable.js new file mode 100644 index 0000000..bbbbd68 --- /dev/null +++ b/tests/local/pnp/enable.js @@ -0,0 +1,12 @@ +import module from 'node:module' + +async function resolve (specifier, context, next) { + return next( + specifier === 'pnpapi' + ? '../tests/local/pnp/api.js' + : specifier, context) +} + +module.register && (process.versions.pnp = '3') && module.register(` +data:text/javascript, +export ${encodeURIComponent(resolve)}`.slice(1)) diff --git a/tests/package.json b/tests/package.json index 63c715f..dc23784 100644 --- a/tests/package.json +++ b/tests/package.json @@ -26,7 +26,7 @@ "sinon": "^12.0.1" }, "scripts": { - "mini:esmock": "cd .. && cd src && npx esbuild esmock.js --minify --bundle --allow-overwrite --platform=node --format=esm --outfile=esmock.js", + "mini:esmock": "cd .. && cd src && npx esbuild esmock.js --minify --bundle --allow-overwrite --platform=node --format=esm --external:pnpapi --outfile=esmock.js", "mini:esmockLoader": "cd .. && cd src && npx esbuild esmockLoader.js --minify --bundle --allow-overwrite --platform=node --format=esm --outfile=esmockLoader.js", "mini": "npm run mini:esmock && npm run mini:esmockLoader", "isnodelt18": "node -e \"+process.versions.node.split('.')[0] < 18 || process.exit(1)\"", diff --git a/tests/tests-node/esmock.node.resolver-pnp.test.js b/tests/tests-node/esmock.node.resolver-pnp.test.js new file mode 100644 index 0000000..02825ce --- /dev/null +++ b/tests/tests-node/esmock.node.resolver-pnp.test.js @@ -0,0 +1,35 @@ +import test from 'node:test' +import assert from 'node:assert/strict' +import module from 'node:module' +import { fileURLToPath } from 'node:url' +import resolvewithplus from 'resolvewithplus' +import '../local/pnp/enable.js' +import esmock from 'esmock' +import '../local/pnp/disable.js' +import pnpapi from '../local/pnp/api.js' + +const resolver = (id, parent) => { + const url = resolvewithplus(id, parent) + return url !== null ? fileURLToPath(url) : null +} + +test.beforeEach(() => { + delete pnpapi.resolveRequest +}) + +test('should work with pnp resolver', async ({ mock }) => { + if (!module.register) + return assert.ok('skip test') + + pnpapi.resolveRequest = mock.fn(resolver) + + const main = await esmock('../local/main.js', { + '../local/mainUtil.js': { + createString: () => 'test string' + } + }) + + assert.equal(typeof main, 'function') + assert.strictEqual(main(), 'main string, test string') + assert.equal(pnpapi.resolveRequest.mock.callCount(), 2) +})