Browse Source

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>
v5.x
Dave Eddy 9 years ago
committed by Rod Vagg
parent
commit
2e6ece44e1
  1. 2
      doc/node.1
  2. 15
      lib/internal/module.js
  3. 16
      lib/module.js
  4. 1
      node.gyp
  5. 9
      src/node.cc
  6. 16
      src/node.js
  7. 1
      test/fixtures/syntax/bad_syntax.js
  8. 2
      test/fixtures/syntax/bad_syntax_shebang.js
  9. 1
      test/fixtures/syntax/good_syntax.js
  10. 2
      test/fixtures/syntax/good_syntax_shebang.js
  11. 84
      test/parallel/test-cli-syntax.js

2
doc/node.1

@ -49,6 +49,8 @@ and servers.
-p, --print print result of --eval
-c, --check syntax check script without executing
-i, --interactive always enter the REPL even if stdin
does not appear to be a terminal

15
lib/internal/module.js

@ -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;
}

16
lib/module.js

@ -2,6 +2,7 @@
const NativeModule = require('native_module');
const util = require('util');
const internalModule = require('internal/module');
const internalUtil = require('internal/util');
const runInThisContext = require('vm').runInThisContext;
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
Module._extensions['.js'] = function(module, filename) {
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) {
var content = fs.readFileSync(filename, 'utf8');
try {
module.exports = JSON.parse(stripBOM(content));
module.exports = JSON.parse(internalModule.stripBOM(content));
} catch (err) {
err.message = filename + ': ' + err.message;
throw err;

1
node.gyp

@ -70,6 +70,7 @@
'lib/zlib.js',
'lib/internal/child_process.js',
'lib/internal/freelist.js',
'lib/internal/module.js',
'lib/internal/socket_list.js',
'lib/internal/repl.js',
'lib/internal/util.js',

9
src/node.cc

@ -121,6 +121,7 @@ using v8::Value;
static bool print_eval = false;
static bool force_repl = false;
static bool syntax_check_only = false;
static bool trace_deprecation = false;
static bool throw_deprecation = false;
static bool abort_on_uncaught_exception = false;
@ -2811,6 +2812,11 @@ void SetupProcessObject(Environment* env,
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
if (force_repl) {
READONLY_PROPERTY(process, "_forceRepl", True(env->isolate()));
@ -3067,6 +3073,7 @@ static void PrintHelp() {
" -v, --version print Node.js version\n"
" -e, --eval script evaluate script\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"
" does not appear to be a terminal\n"
" -r, --require module to preload (option can be repeated)\n"
@ -3196,6 +3203,8 @@ static void ParseArgs(int* argc,
}
args_consumed += 1;
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) {
force_repl = true;
} else if (strcmp(arg, "--no-deprecation") == 0) {

16
src/node.js

@ -93,6 +93,22 @@
process.argv[1] = path.resolve(process.argv[1]);
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();
if (global.v8debug &&
process.execArgv.some(function(arg) {

1
test/fixtures/syntax/bad_syntax.js

@ -0,0 +1 @@
var foo bar;

2
test/fixtures/syntax/bad_syntax_shebang.js

@ -0,0 +1,2 @@
#!/usr/bin/env node
var foo bar;

1
test/fixtures/syntax/good_syntax.js

@ -0,0 +1 @@
var foo = 'bar';

2
test/fixtures/syntax/good_syntax_shebang.js

@ -0,0 +1,2 @@
#!/usr/bin/env node
var foo = 'bar';

84
test/parallel/test-cli-syntax.js

@ -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…
Cancel
Save