mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
module: self referential modules in repl or -r
Load self referential modules from the repl and using the preload flag `-r`. In both cases the base path used for resolution is the current `process.cwd()`. Also fixes an internal cycle bug in the REPL exports resolution. PR-URL: https://github.com/nodejs/node/pull/32261 Fixes: https://github.com/nodejs/node/issues/31595 Reviewed-By: Guy Bedford <guybedford@gmail.com> Reviewed-By: Jan Krems <jan.krems@gmail.com>
This commit is contained in:
parent
6d5c33525a
commit
ec2ffd6b9d
@ -29,6 +29,7 @@ module.exports = {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
ArrayIsArray,
|
ArrayIsArray,
|
||||||
|
ArrayPrototypeJoin,
|
||||||
Error,
|
Error,
|
||||||
JSONParse,
|
JSONParse,
|
||||||
Map,
|
Map,
|
||||||
@ -422,7 +423,23 @@ function findLongestRegisteredExtension(filename) {
|
|||||||
return '.js';
|
return '.js';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trySelfParentPath(parent) {
|
||||||
|
if (!parent) return false;
|
||||||
|
|
||||||
|
if (parent.filename) {
|
||||||
|
return parent.filename;
|
||||||
|
} else if (parent.id === '<repl>' || parent.id === 'internal/preload') {
|
||||||
|
try {
|
||||||
|
return process.cwd() + path.sep;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function trySelf(parentPath, request) {
|
function trySelf(parentPath, request) {
|
||||||
|
if (!parentPath) return false;
|
||||||
|
|
||||||
const { data: pkg, path: basePath } = readPackageScope(parentPath) || {};
|
const { data: pkg, path: basePath } = readPackageScope(parentPath) || {};
|
||||||
if (!pkg || pkg.exports === undefined) return false;
|
if (!pkg || pkg.exports === undefined) return false;
|
||||||
if (typeof pkg.name !== 'string') return false;
|
if (typeof pkg.name !== 'string') return false;
|
||||||
@ -1053,13 +1070,16 @@ Module._resolveFilename = function(request, parent, isMain, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const filename = trySelf(parent.filename, request);
|
}
|
||||||
if (filename) {
|
|
||||||
const cacheKey = request + '\x00' +
|
// Try module self resoultion first
|
||||||
(paths.length === 1 ? paths[0] : paths.join('\x00'));
|
const parentPath = trySelfParentPath(parent);
|
||||||
Module._pathCache[cacheKey] = filename;
|
const selfResolved = trySelf(parentPath, request);
|
||||||
return filename;
|
if (selfResolved) {
|
||||||
}
|
const cacheKey = request + '\x00' +
|
||||||
|
(paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, '\x00'));
|
||||||
|
Module._pathCache[cacheKey] = selfResolved;
|
||||||
|
return selfResolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up the filename first, since that's the cache key.
|
// Look up the filename first, since that's the cache key.
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// This is needed to avoid cycles in esm/resolve <-> cjs/loader
|
||||||
|
require('internal/modules/cjs/loader');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FunctionPrototypeBind,
|
FunctionPrototypeBind,
|
||||||
ObjectSetPrototypeOf,
|
ObjectSetPrototypeOf,
|
||||||
|
@ -32,7 +32,6 @@ const {
|
|||||||
} = require('fs');
|
} = require('fs');
|
||||||
const { getOptionValue } = require('internal/options');
|
const { getOptionValue } = require('internal/options');
|
||||||
const { sep, relative } = require('path');
|
const { sep, relative } = require('path');
|
||||||
const { Module: CJSModule } = require('internal/modules/cjs/loader');
|
|
||||||
const preserveSymlinks = getOptionValue('--preserve-symlinks');
|
const preserveSymlinks = getOptionValue('--preserve-symlinks');
|
||||||
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
||||||
const typeFlag = getOptionValue('--input-type');
|
const typeFlag = getOptionValue('--input-type');
|
||||||
@ -49,11 +48,13 @@ const {
|
|||||||
ERR_UNSUPPORTED_DIR_IMPORT,
|
ERR_UNSUPPORTED_DIR_IMPORT,
|
||||||
ERR_UNSUPPORTED_ESM_URL_SCHEME,
|
ERR_UNSUPPORTED_ESM_URL_SCHEME,
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
|
const { Module: CJSModule } = require('internal/modules/cjs/loader');
|
||||||
|
|
||||||
const packageJsonReader = require('internal/modules/package_json_reader');
|
const packageJsonReader = require('internal/modules/package_json_reader');
|
||||||
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import']);
|
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import']);
|
||||||
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
|
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
|
||||||
|
|
||||||
|
|
||||||
function getConditionsSet(conditions) {
|
function getConditionsSet(conditions) {
|
||||||
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
|
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
|
||||||
if (!ArrayIsArray(conditions)) {
|
if (!ArrayIsArray(conditions)) {
|
||||||
|
4
test/fixtures/self_ref_module/index.js
vendored
Normal file
4
test/fixtures/self_ref_module/index.js
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = 'Self resolution working';
|
||||||
|
|
13
test/fixtures/self_ref_module/package.json
vendored
Normal file
13
test/fixtures/self_ref_module/package.json
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "self_ref",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"exports": "./index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
20
test/parallel/test-preload-self-referential.js
Normal file
20
test/parallel/test-preload-self-referential.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const assert = require('assert');
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
|
const nodeBinary = process.argv[0];
|
||||||
|
|
||||||
|
if (!common.isMainThread)
|
||||||
|
common.skip('process.chdir is not available in Workers');
|
||||||
|
|
||||||
|
const selfRefModule = fixtures.path('self_ref_module');
|
||||||
|
const fixtureA = fixtures.path('printA.js');
|
||||||
|
|
||||||
|
exec(`"${nodeBinary}" -r self_ref "${fixtureA}"`, { cwd: selfRefModule },
|
||||||
|
(err, stdout, stderr) => {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.strictEqual(stdout, 'A\n');
|
||||||
|
});
|
25
test/parallel/test-repl-require-self-referential.js
Normal file
25
test/parallel/test-repl-require-self-referential.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
const assert = require('assert');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
|
||||||
|
if (!common.isMainThread)
|
||||||
|
common.skip('process.chdir is not available in Workers');
|
||||||
|
|
||||||
|
const selfRefModule = fixtures.path('self_ref_module');
|
||||||
|
const child = spawn(process.execPath,
|
||||||
|
['--interactive'],
|
||||||
|
{ cwd: selfRefModule }
|
||||||
|
);
|
||||||
|
let output = '';
|
||||||
|
child.stdout.on('data', (chunk) => output += chunk);
|
||||||
|
child.on('exit', common.mustCall(() => {
|
||||||
|
const results = output.replace(/^> /mg, '').split('\n').slice(2);
|
||||||
|
assert.deepStrictEqual(results, [ "'Self resolution working'", '' ]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
child.stdin.write('require("self_ref");\n');
|
||||||
|
child.stdin.write('.exit');
|
||||||
|
child.stdin.end();
|
Loading…
Reference in New Issue
Block a user