lib: rework logic of stripping BOM+Shebang from commonjs
Fixes https://github.com/nodejs/node/issues/27767 PR-URL: https://github.com/nodejs/node/pull/27768 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
73c16b11e0
commit
e2c0c0c680
@ -338,7 +338,7 @@ function initializePolicy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initializeCJSLoader() {
|
function initializeCJSLoader() {
|
||||||
require('internal/modules/cjs/loader')._initPaths();
|
require('internal/modules/cjs/loader').Module._initPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeESMLoader() {
|
function initializeESMLoader() {
|
||||||
@ -387,7 +387,9 @@ function loadPreloadModules() {
|
|||||||
const preloadModules = getOptionValue('--require');
|
const preloadModules = getOptionValue('--require');
|
||||||
if (preloadModules) {
|
if (preloadModules) {
|
||||||
const {
|
const {
|
||||||
|
Module: {
|
||||||
_preloadModules
|
_preloadModules
|
||||||
|
},
|
||||||
} = require('internal/modules/cjs/loader');
|
} = require('internal/modules/cjs/loader');
|
||||||
_preloadModules(preloadModules);
|
_preloadModules(preloadModules);
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,15 @@ const {
|
|||||||
|
|
||||||
const { pathToFileURL } = require('url');
|
const { pathToFileURL } = require('url');
|
||||||
|
|
||||||
const vm = require('vm');
|
|
||||||
const {
|
const {
|
||||||
stripShebang, stripBOM
|
stripShebangOrBOM,
|
||||||
} = require('internal/modules/cjs/helpers');
|
} = require('internal/modules/cjs/helpers');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
Module: {
|
||||||
_resolveFilename: resolveCJSModuleName,
|
_resolveFilename: resolveCJSModuleName,
|
||||||
wrap: wrapCJSModule
|
},
|
||||||
|
wrapSafe,
|
||||||
} = require('internal/modules/cjs/loader');
|
} = require('internal/modules/cjs/loader');
|
||||||
|
|
||||||
// TODO(joyeecheung): not every one of these are necessary
|
// TODO(joyeecheung): not every one of these are necessary
|
||||||
@ -49,9 +50,6 @@ if (process.argv[1] && process.argv[1] !== '-') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkSyntax(source, filename) {
|
function checkSyntax(source, filename) {
|
||||||
// Remove Shebang.
|
|
||||||
source = stripShebang(source);
|
|
||||||
|
|
||||||
const { getOptionValue } = require('internal/options');
|
const { getOptionValue } = require('internal/options');
|
||||||
const experimentalModules = getOptionValue('--experimental-modules');
|
const experimentalModules = getOptionValue('--experimental-modules');
|
||||||
if (experimentalModules) {
|
if (experimentalModules) {
|
||||||
@ -70,10 +68,5 @@ function checkSyntax(source, filename) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove BOM.
|
wrapSafe(filename, stripShebangOrBOM(source));
|
||||||
source = stripBOM(source);
|
|
||||||
// Wrap it.
|
|
||||||
source = wrapCJSModule(source);
|
|
||||||
// Compile the script, this will throw if it fails.
|
|
||||||
new vm.Script(source, { displayErrors: true, filename });
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ const {
|
|||||||
|
|
||||||
prepareMainThreadExecution(true);
|
prepareMainThreadExecution(true);
|
||||||
|
|
||||||
const CJSModule = require('internal/modules/cjs/loader');
|
const CJSModule = require('internal/modules/cjs/loader').Module;
|
||||||
|
|
||||||
markBootstrapComplete();
|
markBootstrapComplete();
|
||||||
|
|
||||||
|
@ -72,6 +72,17 @@ function stripShebang(content) {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Strip either the shebang or UTF BOM of a file.
|
||||||
|
// Note that this only processes one. If both occur in
|
||||||
|
// either order, the one that comes second is not
|
||||||
|
// significant.
|
||||||
|
function stripShebangOrBOM(content) {
|
||||||
|
if (content.charCodeAt(0) === 0xFEFF) {
|
||||||
|
return content.slice(1);
|
||||||
|
}
|
||||||
|
return stripShebang(content);
|
||||||
|
}
|
||||||
|
|
||||||
const builtinLibs = [
|
const builtinLibs = [
|
||||||
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'crypto',
|
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'crypto',
|
||||||
'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'net',
|
'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https', 'net',
|
||||||
@ -137,5 +148,6 @@ module.exports = {
|
|||||||
makeRequireFunction,
|
makeRequireFunction,
|
||||||
normalizeReferrerURL,
|
normalizeReferrerURL,
|
||||||
stripBOM,
|
stripBOM,
|
||||||
stripShebang
|
stripShebang,
|
||||||
|
stripShebangOrBOM,
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,7 @@ const {
|
|||||||
makeRequireFunction,
|
makeRequireFunction,
|
||||||
normalizeReferrerURL,
|
normalizeReferrerURL,
|
||||||
stripBOM,
|
stripBOM,
|
||||||
stripShebang
|
stripShebangOrBOM,
|
||||||
} = require('internal/modules/cjs/helpers');
|
} = require('internal/modules/cjs/helpers');
|
||||||
const { getOptionValue } = require('internal/options');
|
const { getOptionValue } = require('internal/options');
|
||||||
const preserveSymlinks = getOptionValue('--preserve-symlinks');
|
const preserveSymlinks = getOptionValue('--preserve-symlinks');
|
||||||
@ -59,7 +59,7 @@ const {
|
|||||||
const { validateString } = require('internal/validators');
|
const { validateString } = require('internal/validators');
|
||||||
const pendingDeprecation = getOptionValue('--pending-deprecation');
|
const pendingDeprecation = getOptionValue('--pending-deprecation');
|
||||||
|
|
||||||
module.exports = Module;
|
module.exports = { wrapSafe, Module };
|
||||||
|
|
||||||
let asyncESM;
|
let asyncESM;
|
||||||
let ModuleJob;
|
let ModuleJob;
|
||||||
@ -690,22 +690,10 @@ Module.prototype.require = function(id) {
|
|||||||
var resolvedArgv;
|
var resolvedArgv;
|
||||||
let hasPausedEntry = false;
|
let hasPausedEntry = false;
|
||||||
|
|
||||||
// Run the file contents in the correct scope or sandbox. Expose
|
function wrapSafe(filename, content) {
|
||||||
// the correct helper variables (require, module, exports) to
|
|
||||||
// the file.
|
|
||||||
// Returns exception, if any.
|
|
||||||
Module.prototype._compile = function(content, filename) {
|
|
||||||
if (manifest) {
|
|
||||||
const moduleURL = pathToFileURL(filename);
|
|
||||||
manifest.assertIntegrity(moduleURL, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
content = stripShebang(content);
|
|
||||||
|
|
||||||
let compiledWrapper;
|
|
||||||
if (patched) {
|
if (patched) {
|
||||||
const wrapper = Module.wrap(content);
|
const wrapper = Module.wrap(content);
|
||||||
compiledWrapper = vm.runInThisContext(wrapper, {
|
return vm.runInThisContext(wrapper, {
|
||||||
filename,
|
filename,
|
||||||
lineOffset: 0,
|
lineOffset: 0,
|
||||||
displayErrors: true,
|
displayErrors: true,
|
||||||
@ -714,8 +702,9 @@ Module.prototype._compile = function(content, filename) {
|
|||||||
return loader.import(specifier, normalizeReferrerURL(filename));
|
return loader.import(specifier, normalizeReferrerURL(filename));
|
||||||
} : undefined,
|
} : undefined,
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
compiledWrapper = compileFunction(
|
|
||||||
|
const compiledWrapper = compileFunction(
|
||||||
content,
|
content,
|
||||||
filename,
|
filename,
|
||||||
0,
|
0,
|
||||||
@ -732,6 +721,7 @@ Module.prototype._compile = function(content, filename) {
|
|||||||
'__dirname',
|
'__dirname',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
if (experimentalModules) {
|
if (experimentalModules) {
|
||||||
const { callbackMap } = internalBinding('module_wrap');
|
const { callbackMap } = internalBinding('module_wrap');
|
||||||
callbackMap.set(compiledWrapper, {
|
callbackMap.set(compiledWrapper, {
|
||||||
@ -741,8 +731,25 @@ Module.prototype._compile = function(content, filename) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return compiledWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the file contents in the correct scope or sandbox. Expose
|
||||||
|
// the correct helper variables (require, module, exports) to
|
||||||
|
// the file.
|
||||||
|
// Returns exception, if any.
|
||||||
|
Module.prototype._compile = function(content, filename) {
|
||||||
|
if (manifest) {
|
||||||
|
const moduleURL = pathToFileURL(filename);
|
||||||
|
manifest.assertIntegrity(moduleURL, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip after manifest integrity check
|
||||||
|
content = stripShebangOrBOM(content);
|
||||||
|
|
||||||
|
const compiledWrapper = wrapSafe(filename, content);
|
||||||
|
|
||||||
var inspectorWrapper = null;
|
var inspectorWrapper = null;
|
||||||
if (getOptionValue('--inspect-brk') && process._eval == null) {
|
if (getOptionValue('--inspect-brk') && process._eval == null) {
|
||||||
if (!resolvedArgv) {
|
if (!resolvedArgv) {
|
||||||
@ -782,7 +789,7 @@ Module.prototype._compile = function(content, filename) {
|
|||||||
// Native extension for .js
|
// Native extension for .js
|
||||||
Module._extensions['.js'] = function(module, filename) {
|
Module._extensions['.js'] = function(module, filename) {
|
||||||
const content = fs.readFileSync(filename, 'utf8');
|
const content = fs.readFileSync(filename, 'utf8');
|
||||||
module._compile(stripBOM(content), filename);
|
module._compile(content, filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,10 +11,9 @@ const {
|
|||||||
|
|
||||||
const { NativeModule } = require('internal/bootstrap/loaders');
|
const { NativeModule } = require('internal/bootstrap/loaders');
|
||||||
const {
|
const {
|
||||||
stripShebang,
|
|
||||||
stripBOM
|
stripBOM
|
||||||
} = require('internal/modules/cjs/helpers');
|
} = require('internal/modules/cjs/helpers');
|
||||||
const CJSModule = require('internal/modules/cjs/loader');
|
const CJSModule = require('internal/modules/cjs/loader').Module;
|
||||||
const internalURLModule = require('internal/url');
|
const internalURLModule = require('internal/url');
|
||||||
const createDynamicModule = require(
|
const createDynamicModule = require(
|
||||||
'internal/modules/esm/create_dynamic_module');
|
'internal/modules/esm/create_dynamic_module');
|
||||||
@ -48,7 +47,7 @@ translators.set('module', async function moduleStrategy(url) {
|
|||||||
const source = `${await readFileAsync(new URL(url))}`;
|
const source = `${await readFileAsync(new URL(url))}`;
|
||||||
debug(`Translating StandardModule ${url}`);
|
debug(`Translating StandardModule ${url}`);
|
||||||
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
|
const { ModuleWrap, callbackMap } = internalBinding('module_wrap');
|
||||||
const module = new ModuleWrap(stripShebang(source), url);
|
const module = new ModuleWrap(source, url);
|
||||||
callbackMap.set(module, {
|
callbackMap.set(module, {
|
||||||
initializeImportMeta,
|
initializeImportMeta,
|
||||||
importModuleDynamically,
|
importModuleDynamically,
|
||||||
|
@ -53,7 +53,7 @@ function evalModule(source, print) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function evalScript(name, body, breakFirstLine, print) {
|
function evalScript(name, body, breakFirstLine, print) {
|
||||||
const CJSModule = require('internal/modules/cjs/loader');
|
const CJSModule = require('internal/modules/cjs/loader').Module;
|
||||||
const { kVmBreakFirstLineSymbol } = require('internal/util');
|
const { kVmBreakFirstLineSymbol } = require('internal/util');
|
||||||
|
|
||||||
const cwd = tryGetCwd();
|
const cwd = tryGetCwd();
|
||||||
|
@ -24,7 +24,7 @@ function sendInspectorCommand(cb, onError) {
|
|||||||
function installConsoleExtensions(commandLineApi) {
|
function installConsoleExtensions(commandLineApi) {
|
||||||
if (commandLineApi.require) { return; }
|
if (commandLineApi.require) { return; }
|
||||||
const { tryGetCwd } = require('internal/process/execution');
|
const { tryGetCwd } = require('internal/process/execution');
|
||||||
const CJSModule = require('internal/modules/cjs/loader');
|
const CJSModule = require('internal/modules/cjs/loader').Module;
|
||||||
const { makeRequireFunction } = require('internal/modules/cjs/helpers');
|
const { makeRequireFunction } = require('internal/modules/cjs/helpers');
|
||||||
const consoleAPIModule = new CJSModule('<inspector console>');
|
const consoleAPIModule = new CJSModule('<inspector console>');
|
||||||
const cwd = tryGetCwd();
|
const cwd = tryGetCwd();
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = require('internal/modules/cjs/loader');
|
module.exports = require('internal/modules/cjs/loader').Module;
|
||||||
|
@ -65,7 +65,7 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const { Interface } = require('readline');
|
const { Interface } = require('readline');
|
||||||
const { Console } = require('console');
|
const { Console } = require('console');
|
||||||
const CJSModule = require('internal/modules/cjs/loader');
|
const CJSModule = require('internal/modules/cjs/loader').Module;
|
||||||
const domain = require('domain');
|
const domain = require('domain');
|
||||||
const debug = require('internal/util/debuglog').debuglog('repl');
|
const debug = require('internal/util/debuglog').debuglog('repl');
|
||||||
const {
|
const {
|
||||||
|
2
test/fixtures/utf8-bom-shebang.js
vendored
Normal file
2
test/fixtures/utf8-bom-shebang.js
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!shebang
|
||||||
|
module.exports = 42;
|
2
test/fixtures/utf8-shebang-bom.js
vendored
Normal file
2
test/fixtures/utf8-shebang-bom.js
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!shebang
|
||||||
|
module.exports = 42;
|
@ -352,6 +352,13 @@ process.on('exit', function() {
|
|||||||
assert.strictEqual(require('../fixtures/utf8-bom.js'), 42);
|
assert.strictEqual(require('../fixtures/utf8-bom.js'), 42);
|
||||||
assert.strictEqual(require('../fixtures/utf8-bom.json'), 42);
|
assert.strictEqual(require('../fixtures/utf8-bom.json'), 42);
|
||||||
|
|
||||||
|
// Loading files with BOM + shebang.
|
||||||
|
// See https://github.com/nodejs/node/issues/27767
|
||||||
|
assert.throws(() => {
|
||||||
|
require('../fixtures/utf8-bom-shebang.js');
|
||||||
|
}, { name: 'SyntaxError' });
|
||||||
|
assert.strictEqual(require('../fixtures/utf8-shebang-bom.js'), 42);
|
||||||
|
|
||||||
// Error on the first line of a module should
|
// Error on the first line of a module should
|
||||||
// have the correct line number
|
// have the correct line number
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user