Skip to content

Commit

Permalink
lib,repl: ignore canBeRequiredByUsers built-in
Browse files Browse the repository at this point in the history
e.g. `wasi` under no `--experimental-wasi-unstable-preview1` flag
shouldn't be pre-required.
  • Loading branch information
XadillaX committed Aug 30, 2021
1 parent 52abf27 commit 47bccb6
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/internal/main/eval_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const { addBuiltinLibsToObject } = require('internal/modules/cjs/helpers');
const { getOptionValue } = require('internal/options');

prepareMainThreadExecution();
addBuiltinLibsToObject(globalThis);
addBuiltinLibsToObject(globalThis, '<eval>');
markBootstrapComplete();

const source = getOptionValue('--eval');
Expand Down
13 changes: 10 additions & 3 deletions lib/internal/modules/cjs/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,16 @@ function stripBOM(content) {
return content;
}

function addBuiltinLibsToObject(object) {
function addBuiltinLibsToObject(object, dummyModuleName) {
// Make built-in modules available directly (loaded lazily).
const { builtinModules } = require('internal/modules/cjs/loader').Module;
const Module = require('internal/modules/cjs/loader').Module;
const { builtinModules } = Module;

// To require built-in modules in user-land and ignore modules whose
// `canBeRequiredByUsers` is false. So we create a dummy module object and not
// use `require()` directly.
const dummyModule = new Module(dummyModuleName);

ArrayPrototypeForEach(builtinModules, (name) => {
// Neither add underscored modules, nor ones that contain slashes (e.g.,
// 'fs/promises') or ones that are already defined.
Expand All @@ -157,7 +164,7 @@ function addBuiltinLibsToObject(object) {

ObjectDefineProperty(object, name, {
get: () => {
const lib = require(name);
const lib = dummyModule.require(name);

// Disable the current getter/setter and set up a new
// non-enumerable property.
Expand Down
2 changes: 1 addition & 1 deletion lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ REPLServer.prototype.createContext = function() {
value: makeRequireFunction(replModule)
});

addBuiltinLibsToObject(context);
addBuiltinLibsToObject(context, '<REPL>');

return context;
};
Expand Down
53 changes: 53 additions & 0 deletions test/parallel/test-repl-built-in-modules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict';

const common = require('../common');
const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const spawn = require('child_process').spawn;

tmpdir.refresh();

function run(wasiPreview) {
let resolve;
const promise = new Promise((_resolve) => {
resolve = _resolve;
});

// Use -i to force node into interactive mode, despite stdout not being a TTY
const args = ['-i'];
if (wasiPreview) args.push('--experimental-wasi-unstable-preview1');
const child = spawn(process.execPath, args);

const input = 'require(\'events\');\nrequire(\'wasi\');';
let stdout = '';
let stderr = '';

child.stdout.setEncoding('utf8');
child.stdout.on('data', (c) => stdout += c);
child.stderr.setEncoding('utf8');
child.stderr.on('data', (c) => stderr += c);

child.stdin.end(input);

child.on('exit', () => {
resolve({ stdout, stderr });
});

return promise;
}

(async function() {
const ret1 = await run(false);
const ret2 = await run(true);

assert.match(ret1.stdout, /\[Function: EventEmitter\] {/);
assert.match(
ret1.stdout,
/Uncaught Error: Cannot find module 'wasi'[\w\W]+- <repl>\n/)

assert.match(ret2.stdout, /\[Function: EventEmitter\] {/);
assert.doesNotMatch(
ret2.stdout,
/Uncaught Error: Cannot find module 'wasi'[\w\W]+- <repl>\n/)
assert.match(ret2.stdout, /{ WASI: \[class WASI\] }/);
})().then(common.mustCall());

0 comments on commit 47bccb6

Please sign in to comment.