Skip to content

Commit 00aa935

Browse files
dnlupcodebytere
authored andcommittedOct 1, 2020
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: nodejs/node#32261 Backport-PR-URL: nodejs/node#35385 Fixes: nodejs/node#31595 Reviewed-By: Guy Bedford <guybedford@gmail.com> Reviewed-By: Jan Krems <jan.krems@gmail.com>
1 parent d065334 commit 00aa935

File tree

7 files changed

+94
-8
lines changed

7 files changed

+94
-8
lines changed
 

‎lib/internal/modules/cjs/loader.js

+27-7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module.exports = {
2929

3030
const {
3131
ArrayIsArray,
32+
ArrayPrototypeJoin,
3233
Error,
3334
JSONParse,
3435
Map,
@@ -398,7 +399,23 @@ function findLongestRegisteredExtension(filename) {
398399
return '.js';
399400
}
400401

402+
function trySelfParentPath(parent) {
403+
if (!parent) return false;
404+
405+
if (parent.filename) {
406+
return parent.filename;
407+
} else if (parent.id === '<repl>' || parent.id === 'internal/preload') {
408+
try {
409+
return process.cwd() + path.sep;
410+
} catch {
411+
return false;
412+
}
413+
}
414+
}
415+
401416
function trySelf(parentPath, request) {
417+
if (!parentPath) return false;
418+
402419
const { data: pkg, path: basePath } = readPackageScope(parentPath) || {};
403420
if (!pkg || pkg.exports === undefined) return false;
404421
if (typeof pkg.name !== 'string') return false;
@@ -972,13 +989,16 @@ Module._resolveFilename = function(request, parent, isMain, options) {
972989
}
973990
}
974991
}
975-
const filename = trySelf(parent.filename, request);
976-
if (filename) {
977-
const cacheKey = request + '\x00' +
978-
(paths.length === 1 ? paths[0] : paths.join('\x00'));
979-
Module._pathCache[cacheKey] = filename;
980-
return filename;
981-
}
992+
}
993+
994+
// Try module self resoultion first
995+
const parentPath = trySelfParentPath(parent);
996+
const selfResolved = trySelf(parentPath, request);
997+
if (selfResolved) {
998+
const cacheKey = request + '\x00' +
999+
(paths.length === 1 ? paths[0] : ArrayPrototypeJoin(paths, '\x00'));
1000+
Module._pathCache[cacheKey] = selfResolved;
1001+
return selfResolved;
9821002
}
9831003

9841004
// Look up the filename first, since that's the cache key.

‎lib/internal/modules/esm/loader.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use strict';
22

3+
// This is needed to avoid cycles in esm/resolve <-> cjs/loader
4+
require('internal/modules/cjs/loader');
5+
36
const {
47
FunctionPrototypeBind,
58
ObjectSetPrototypeOf,

‎lib/internal/modules/esm/resolve.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ const {
3232
} = require('fs');
3333
const { getOptionValue } = require('internal/options');
3434
const { sep, relative } = require('path');
35-
const { Module: CJSModule } = require('internal/modules/cjs/loader');
3635
const preserveSymlinks = getOptionValue('--preserve-symlinks');
3736
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
3837
const typeFlag = getOptionValue('--input-type');
@@ -49,11 +48,13 @@ const {
4948
ERR_UNSUPPORTED_DIR_IMPORT,
5049
ERR_UNSUPPORTED_ESM_URL_SCHEME,
5150
} = require('internal/errors').codes;
51+
const { Module: CJSModule } = require('internal/modules/cjs/loader');
5252

5353
const packageJsonReader = require('internal/modules/package_json_reader');
5454
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import']);
5555
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
5656

57+
5758
function getConditionsSet(conditions) {
5859
if (conditions !== undefined && conditions !== DEFAULT_CONDITIONS) {
5960
if (!ArrayIsArray(conditions)) {
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
'use strict'
2+
3+
module.exports = 'Self resolution working';
4+
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "self_ref",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"exports": "./index.js",
7+
"scripts": {
8+
"test": "echo \"Error: no test specified\" && exit 1"
9+
},
10+
"keywords": [],
11+
"author": "",
12+
"license": "ISC"
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
const assert = require('assert');
6+
const { exec } = require('child_process');
7+
8+
const nodeBinary = process.argv[0];
9+
10+
if (!common.isMainThread)
11+
common.skip('process.chdir is not available in Workers');
12+
13+
const selfRefModule = fixtures.path('self_ref_module');
14+
const fixtureA = fixtures.path('printA.js');
15+
16+
exec(`"${nodeBinary}" -r self_ref "${fixtureA}"`, { cwd: selfRefModule },
17+
(err, stdout, stderr) => {
18+
assert.ifError(err);
19+
assert.strictEqual(stdout, 'A\n');
20+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fixtures = require('../common/fixtures');
5+
const assert = require('assert');
6+
const { spawn } = require('child_process');
7+
8+
if (!common.isMainThread)
9+
common.skip('process.chdir is not available in Workers');
10+
11+
const selfRefModule = fixtures.path('self_ref_module');
12+
const child = spawn(process.execPath,
13+
['--interactive'],
14+
{ cwd: selfRefModule }
15+
);
16+
let output = '';
17+
child.stdout.on('data', (chunk) => output += chunk);
18+
child.on('exit', common.mustCall(() => {
19+
const results = output.replace(/^> /mg, '').split('\n').slice(2);
20+
assert.deepStrictEqual(results, [ "'Self resolution working'", '' ]);
21+
}));
22+
23+
child.stdin.write('require("self_ref");\n');
24+
child.stdin.write('.exit');
25+
child.stdin.end();

0 commit comments

Comments
 (0)
Failed to load comments.