node: add -c|--check CLI arg to syntax check script
PR-URL: https://github.com/nodejs/node/pull/2411 Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Evan Lucas <evanlucas@me.com>
This commit is contained in:
parent
5bbc6df7de
commit
2e6ece44e1
@ -49,6 +49,8 @@ and servers.
|
|||||||
|
|
||||||
-p, --print print result of --eval
|
-p, --print print result of --eval
|
||||||
|
|
||||||
|
-c, --check syntax check script without executing
|
||||||
|
|
||||||
-i, --interactive always enter the REPL even if stdin
|
-i, --interactive always enter the REPL even if stdin
|
||||||
does not appear to be a terminal
|
does not appear to be a terminal
|
||||||
|
|
||||||
|
15
lib/internal/module.js
Normal file
15
lib/internal/module.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports.stripBOM = stripBOM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
|
||||||
|
* because the buffer-to-string conversion in `fs.readFileSync()`
|
||||||
|
* translates it to FEFF, the UTF-16 BOM.
|
||||||
|
*/
|
||||||
|
function stripBOM(content) {
|
||||||
|
if (content.charCodeAt(0) === 0xFEFF) {
|
||||||
|
content = content.slice(1);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const NativeModule = require('native_module');
|
const NativeModule = require('native_module');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
const internalModule = require('internal/module');
|
||||||
const internalUtil = require('internal/util');
|
const internalUtil = require('internal/util');
|
||||||
const runInThisContext = require('vm').runInThisContext;
|
const runInThisContext = require('vm').runInThisContext;
|
||||||
const assert = require('assert').ok;
|
const assert = require('assert').ok;
|
||||||
@ -435,21 +436,10 @@ Module.prototype._compile = function(content, filename) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function stripBOM(content) {
|
|
||||||
// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
|
|
||||||
// because the buffer-to-string conversion in `fs.readFileSync()`
|
|
||||||
// translates it to FEFF, the UTF-16 BOM.
|
|
||||||
if (content.charCodeAt(0) === 0xFEFF) {
|
|
||||||
content = content.slice(1);
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Native extension for .js
|
// Native extension for .js
|
||||||
Module._extensions['.js'] = function(module, filename) {
|
Module._extensions['.js'] = function(module, filename) {
|
||||||
var content = fs.readFileSync(filename, 'utf8');
|
var content = fs.readFileSync(filename, 'utf8');
|
||||||
module._compile(stripBOM(content), filename);
|
module._compile(internalModule.stripBOM(content), filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -457,7 +447,7 @@ Module._extensions['.js'] = function(module, filename) {
|
|||||||
Module._extensions['.json'] = function(module, filename) {
|
Module._extensions['.json'] = function(module, filename) {
|
||||||
var content = fs.readFileSync(filename, 'utf8');
|
var content = fs.readFileSync(filename, 'utf8');
|
||||||
try {
|
try {
|
||||||
module.exports = JSON.parse(stripBOM(content));
|
module.exports = JSON.parse(internalModule.stripBOM(content));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.message = filename + ': ' + err.message;
|
err.message = filename + ': ' + err.message;
|
||||||
throw err;
|
throw err;
|
||||||
|
1
node.gyp
1
node.gyp
@ -70,6 +70,7 @@
|
|||||||
'lib/zlib.js',
|
'lib/zlib.js',
|
||||||
'lib/internal/child_process.js',
|
'lib/internal/child_process.js',
|
||||||
'lib/internal/freelist.js',
|
'lib/internal/freelist.js',
|
||||||
|
'lib/internal/module.js',
|
||||||
'lib/internal/socket_list.js',
|
'lib/internal/socket_list.js',
|
||||||
'lib/internal/repl.js',
|
'lib/internal/repl.js',
|
||||||
'lib/internal/util.js',
|
'lib/internal/util.js',
|
||||||
|
@ -121,6 +121,7 @@ using v8::Value;
|
|||||||
|
|
||||||
static bool print_eval = false;
|
static bool print_eval = false;
|
||||||
static bool force_repl = false;
|
static bool force_repl = false;
|
||||||
|
static bool syntax_check_only = false;
|
||||||
static bool trace_deprecation = false;
|
static bool trace_deprecation = false;
|
||||||
static bool throw_deprecation = false;
|
static bool throw_deprecation = false;
|
||||||
static bool abort_on_uncaught_exception = false;
|
static bool abort_on_uncaught_exception = false;
|
||||||
@ -2811,6 +2812,11 @@ void SetupProcessObject(Environment* env,
|
|||||||
READONLY_PROPERTY(process, "_print_eval", True(env->isolate()));
|
READONLY_PROPERTY(process, "_print_eval", True(env->isolate()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -c, --check
|
||||||
|
if (syntax_check_only) {
|
||||||
|
READONLY_PROPERTY(process, "_syntax_check_only", True(env->isolate()));
|
||||||
|
}
|
||||||
|
|
||||||
// -i, --interactive
|
// -i, --interactive
|
||||||
if (force_repl) {
|
if (force_repl) {
|
||||||
READONLY_PROPERTY(process, "_forceRepl", True(env->isolate()));
|
READONLY_PROPERTY(process, "_forceRepl", True(env->isolate()));
|
||||||
@ -3067,6 +3073,7 @@ static void PrintHelp() {
|
|||||||
" -v, --version print Node.js version\n"
|
" -v, --version print Node.js version\n"
|
||||||
" -e, --eval script evaluate script\n"
|
" -e, --eval script evaluate script\n"
|
||||||
" -p, --print evaluate script and print result\n"
|
" -p, --print evaluate script and print result\n"
|
||||||
|
" -c, --check syntax check script without executing\n"
|
||||||
" -i, --interactive always enter the REPL even if stdin\n"
|
" -i, --interactive always enter the REPL even if stdin\n"
|
||||||
" does not appear to be a terminal\n"
|
" does not appear to be a terminal\n"
|
||||||
" -r, --require module to preload (option can be repeated)\n"
|
" -r, --require module to preload (option can be repeated)\n"
|
||||||
@ -3196,6 +3203,8 @@ static void ParseArgs(int* argc,
|
|||||||
}
|
}
|
||||||
args_consumed += 1;
|
args_consumed += 1;
|
||||||
local_preload_modules[preload_module_count++] = module;
|
local_preload_modules[preload_module_count++] = module;
|
||||||
|
} else if (strcmp(arg, "--check") == 0 || strcmp(arg, "-c") == 0) {
|
||||||
|
syntax_check_only = true;
|
||||||
} else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) {
|
} else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) {
|
||||||
force_repl = true;
|
force_repl = true;
|
||||||
} else if (strcmp(arg, "--no-deprecation") == 0) {
|
} else if (strcmp(arg, "--no-deprecation") == 0) {
|
||||||
|
16
src/node.js
16
src/node.js
@ -93,6 +93,22 @@
|
|||||||
process.argv[1] = path.resolve(process.argv[1]);
|
process.argv[1] = path.resolve(process.argv[1]);
|
||||||
|
|
||||||
var Module = NativeModule.require('module');
|
var Module = NativeModule.require('module');
|
||||||
|
|
||||||
|
// check if user passed `-c` or `--check` arguments to Node.
|
||||||
|
if (process._syntax_check_only != null) {
|
||||||
|
var vm = NativeModule.require('vm');
|
||||||
|
var fs = NativeModule.require('fs');
|
||||||
|
var internalModule = NativeModule.require('internal/module');
|
||||||
|
// read the source
|
||||||
|
var filename = Module._resolveFilename(process.argv[1]);
|
||||||
|
var source = fs.readFileSync(filename, 'utf-8');
|
||||||
|
// remove shebang and BOM
|
||||||
|
source = internalModule.stripBOM(source.replace(/^\#\!.*/, ''));
|
||||||
|
// compile the script, this will throw if it fails
|
||||||
|
new vm.Script(source, {filename: filename, displayErrors: true});
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
startup.preloadModules();
|
startup.preloadModules();
|
||||||
if (global.v8debug &&
|
if (global.v8debug &&
|
||||||
process.execArgv.some(function(arg) {
|
process.execArgv.some(function(arg) {
|
||||||
|
1
test/fixtures/syntax/bad_syntax.js
vendored
Normal file
1
test/fixtures/syntax/bad_syntax.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
var foo bar;
|
2
test/fixtures/syntax/bad_syntax_shebang.js
vendored
Normal file
2
test/fixtures/syntax/bad_syntax_shebang.js
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
var foo bar;
|
1
test/fixtures/syntax/good_syntax.js
vendored
Normal file
1
test/fixtures/syntax/good_syntax.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
var foo = 'bar';
|
2
test/fixtures/syntax/good_syntax_shebang.js
vendored
Normal file
2
test/fixtures/syntax/good_syntax_shebang.js
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
var foo = 'bar';
|
84
test/parallel/test-cli-syntax.js
Normal file
84
test/parallel/test-cli-syntax.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const spawnSync = require('child_process').spawnSync;
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const common = require('../common');
|
||||||
|
|
||||||
|
var node = process.execPath;
|
||||||
|
|
||||||
|
// test both sets of arguments that check syntax
|
||||||
|
var syntaxArgs = [
|
||||||
|
['-c'],
|
||||||
|
['--check']
|
||||||
|
];
|
||||||
|
|
||||||
|
// test good syntax with and without shebang
|
||||||
|
[
|
||||||
|
'syntax/good_syntax.js',
|
||||||
|
'syntax/good_syntax',
|
||||||
|
'syntax/good_syntax_shebang.js',
|
||||||
|
'syntax/good_syntax_shebang',
|
||||||
|
].forEach(function(file) {
|
||||||
|
file = path.join(common.fixturesDir, file);
|
||||||
|
|
||||||
|
// loop each possible option, `-c` or `--check`
|
||||||
|
syntaxArgs.forEach(function(args) {
|
||||||
|
var _args = args.concat(file);
|
||||||
|
var c = spawnSync(node, _args, {encoding: 'utf8'});
|
||||||
|
|
||||||
|
// no output should be produced
|
||||||
|
assert.equal(c.stdout, '', 'stdout produced');
|
||||||
|
assert.equal(c.stderr, '', 'stderr produced');
|
||||||
|
assert.equal(c.status, 0, 'code == ' + c.status);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// test bad syntax with and without shebang
|
||||||
|
[
|
||||||
|
'syntax/bad_syntax.js',
|
||||||
|
'syntax/bad_syntax',
|
||||||
|
'syntax/bad_syntax_shebang.js',
|
||||||
|
'syntax/bad_syntax_shebang'
|
||||||
|
].forEach(function(file) {
|
||||||
|
file = path.join(common.fixturesDir, file);
|
||||||
|
|
||||||
|
// loop each possible option, `-c` or `--check`
|
||||||
|
syntaxArgs.forEach(function(args) {
|
||||||
|
var _args = args.concat(file);
|
||||||
|
var c = spawnSync(node, _args, {encoding: 'utf8'});
|
||||||
|
|
||||||
|
// no stdout should be produced
|
||||||
|
assert.equal(c.stdout, '', 'stdout produced');
|
||||||
|
|
||||||
|
// stderr should have a syntax error message
|
||||||
|
var match = c.stderr.match(/^SyntaxError: Unexpected identifier$/m);
|
||||||
|
assert(match, 'stderr incorrect');
|
||||||
|
|
||||||
|
assert.equal(c.status, 1, 'code == ' + c.status);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// test file not found
|
||||||
|
[
|
||||||
|
'syntax/file_not_found.js',
|
||||||
|
'syntax/file_not_found'
|
||||||
|
].forEach(function(file) {
|
||||||
|
file = path.join(common.fixturesDir, file);
|
||||||
|
|
||||||
|
// loop each possible option, `-c` or `--check`
|
||||||
|
syntaxArgs.forEach(function(args) {
|
||||||
|
var _args = args.concat(file);
|
||||||
|
var c = spawnSync(node, _args, {encoding: 'utf8'});
|
||||||
|
|
||||||
|
// no stdout should be produced
|
||||||
|
assert.equal(c.stdout, '', 'stdout produced');
|
||||||
|
|
||||||
|
// stderr should have a module not found error message
|
||||||
|
var match = c.stderr.match(/^Error: Cannot find module/m);
|
||||||
|
assert(match, 'stderr incorrect');
|
||||||
|
|
||||||
|
assert.equal(c.status, 1, 'code == ' + c.status);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user