Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/internal/modules/package_json_reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,13 @@ function findPackageJSON(specifier, base = 'data:') {
cascadedLoader ??= require('internal/modules/esm/loader').getOrInitializeCascadedLoader();

try {
// The problem is here: when an async resolve hook is registered, resolve returns a promise
// I think 2 things are needed:
// 1. detect whether findPackageJSON is being used within a loader
// (possibly piggyback on `allowImportMetaResolve`)
// 2a. When inside, use the default resolve
// (I think it's impossible to use the chain because of re-entry & a deadlock from atomics).
// 2b. When outside, use cascadedLoader.resolveSync (not implemented yet, but the pieces exist).
resolvedTarget = cascadedLoader.resolve(specifier, `${parentURL}`, pjsonImportAttributes).url;
Comment thread
JakobJingleheimer marked this conversation as resolved.
Outdated
} catch (err) {
if (err.code === 'ERR_UNSUPPORTED_DIR_IMPORT') {
Expand Down
46 changes: 46 additions & 0 deletions test/parallel/test-find-package-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const common = require('../common');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
const assert = require('node:assert');
const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const { findPackageJSON } = require('node:module');
const path = require('node:path');
Expand Down Expand Up @@ -149,4 +150,49 @@ describe('findPackageJSON', () => { // Throws when no arguments are provided
});
}));
});

it('should work within a loader', () => {
const importMetaUrl = `${fixtures.fileURL('whatever.ext')}`;
const specifierBase = './packages/root-types-field';
const foundPjsonPath = path.toNamespacedPath(fixtures.path(specifierBase, 'package.json'));
const { status: code, stderr, stdout } = spawnSync(process.execPath, [
'--no-warnings',
'--loader',
[
'data:text/javascript,',
'import module from "node:module";',
`module.findPackageJSON('${specifierBase}','${importMetaUrl}');`,
'export const resolve = async (s, c, n) => n(s);',
].join(''),
'--eval',
'import module from "node:module";', // can be anything that triggers the resolve hook chain
], { encoding: 'utf-8' });

// Error you're trying to fix:
// TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance
// of URL. Received undefined
assert.strictEqual(stderr, '');
assert.match(stdout, new RegExp(foundPjsonPath));
assert.strictEqual(code, 0);
});

it('should work with an async resolve hook registered', () => {
const importMetaUrl = `${fixtures.fileURL('whatever.ext')}`;
const specifierBase = './packages/root-types-field';
const foundPjsonPath = path.toNamespacedPath(fixtures.path(specifierBase, 'package.json'));
const { status: code, stderr, stdout } = spawnSync(process.execPath, [
'--no-warnings',
'--loader',
'data:text/javascript,export const resolve = async (s, c, n) => n(s);',
'--eval',
`console.log(require("node:module").findPackageJSON('${specifierBase}','${importMetaUrl}'));`
], { encoding: 'utf-8' });

// Error you're trying to fix:
// TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance
// of URL. Received undefined
assert.strictEqual(stderr, '');
assert.match(stdout, new RegExp(foundPjsonPath));
assert.strictEqual(code, 0);
});
});