module: Allow runMain to be ESM

This follows the EPS an allows the node CLI to have ESM as an entry point.
`node ./example.mjs`. A newer V8 is needed for `import()` so that is not
included. `import.meta` is still in specification stage so that also is not
included.

PR-URL: https://github.com/nodejs/node/pull/14369
Author: Bradley Farias <bradley.meck@gmail.com>
Author: Guy Bedford <guybedford@gmail.com>
Author: Jan Krems <jan.krems@groupon.com>
Author: Timothy Gu <timothygu99@gmail.com>
Author: Michaël Zasso <targos@protonmail.com>
Author: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
Bradley Farias committed 2017-09-07 15:18:32 -05:00
1 parent 46133b5beb
commit c8a389e19f
46 files changed
+1578 -40

No files matched your search

+39 -21
View File
@@ -13,6 +13,7 @@ const path = require('path');
module.exports = function(context) {
// trim required module names
var requiredModules = context.options;
const isESM = context.parserOptions.sourceType === 'module';
const foundModules = [];
@@ -39,39 +40,35 @@ module.exports = function(context) {
return node.callee.type === 'Identifier' && node.callee.name === 'require';
}
/**
* Function to check if the path is a required module and return its name.
* @param {String} str The path to check
* @returns {undefined|String} required module name or undefined
*/
function getRequiredModuleName(str) {
var value = path.basename(str);
// check if value is in required modules array
return requiredModules.indexOf(value) !== -1 ? value : undefined;
}
/**
* Function to check if a node has an argument that is a required module and
* return its name.
* @param {ASTNode} node The node to check
* @returns {undefined|String} required module name or undefined
*/
function getRequiredModuleName(node) {
var moduleName;
function getRequiredModuleNameFromCall(node) {
// node has arguments and first argument is string
if (node.arguments.length && isString(node.arguments[0])) {
var argValue = path.basename(node.arguments[0].value.trim());
// check if value is in required modules array
if (requiredModules.indexOf(argValue) !== -1) {
moduleName = argValue;
}
return getRequiredModuleName(node.arguments[0].value.trim());
}
return moduleName;
return undefined;
}
return {
'CallExpression': function(node) {
if (isRequireCall(node)) {
var requiredModuleName = getRequiredModuleName(node);
if (requiredModuleName) {
foundModules.push(requiredModuleName);
}
}
},
'Program:exit': function(node) {
const rules = {
'Program:exit'(node) {
if (foundModules.length < requiredModules.length) {
var missingModules = requiredModules.filter(
function(module) {
@@ -88,6 +85,27 @@ module.exports = function(context) {
}
}
};
if (isESM) {
rules.ImportDeclaration = (node) => {
var requiredModuleName = getRequiredModuleName(node.source.value);
if (requiredModuleName) {
foundModules.push(requiredModuleName);
}
};
} else {
rules.CallExpression = (node) => {
if (isRequireCall(node)) {
var requiredModuleName = getRequiredModuleNameFromCall(node);
if (requiredModuleName) {
foundModules.push(requiredModuleName);
}
}
};
}
return rules;
};
module.exports.schema = {
+9 -9
View File
@@ -279,9 +279,7 @@ class TapProgressIndicator(SimpleProgressIndicator):
# hard to decipher what test is running when only the filename is printed.
prefix = abspath(join(dirname(__file__), '../test')) + os.sep
command = output.command[-1]
if command.endswith('.js'): command = command[:-3]
if command.startswith(prefix): command = command[len(prefix):]
command = command.replace('\\', '/')
command = NormalizePath(command, prefix)
if output.UnexpectedOutput():
status_line = 'not ok %i %s' % (self._done, command)
@@ -352,9 +350,7 @@ class DeoptsCheckProgressIndicator(SimpleProgressIndicator):
# hard to decipher what test is running when only the filename is printed.
prefix = abspath(join(dirname(__file__), '../test')) + os.sep
command = output.command[-1]
if command.endswith('.js'): command = command[:-3]
if command.startswith(prefix): command = command[len(prefix):]
command = command.replace('\\', '/')
command = NormalizePath(command, prefix)
stdout = output.output.stdout.strip()
printed_file = False
@@ -1509,12 +1505,16 @@ def SplitPath(s):
stripped = [ c.strip() for c in s.split('/') ]
return [ Pattern(s) for s in stripped if len(s) > 0 ]
def NormalizePath(path):
def NormalizePath(path, prefix='test/'):
# strip the extra path information of the specified test
if path.startswith('test/'):
path = path[5:]
prefix = prefix.replace('\\', '/')
path = path.replace('\\', '/')
if path.startswith(prefix):
path = path[len(prefix):]
if path.endswith('.js'):
path = path[:-3]
elif path.endswith('.mjs'):
path = path[:-4]
return path
def GetSpecialCommandProcessor(value):