Skip to content
Permalink
Browse files

node: add -c|--check CLI arg to syntax check script

PR-URL: #2411
Reviewed-By: Rod Vagg <rod@vagg.org>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Evan Lucas <evanlucas@me.com>
  • Loading branch information...
bahamas10 authored and jasnell committed Aug 17, 2015
1 parent 4a35ba4 commit 9d65528b0190482707edb0aad684e7bcc0478b21
@@ -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

@@ -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 util = require('util');
const internalModule = require('internal/module');
const internalUtil = require('internal/util');
const runInThisContext = require('vm').runInThisContext;
const assert = require('assert').ok;
@@ -435,29 +436,18 @@ 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);
};


// Native extension for .json
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;
@@ -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',
@@ -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;
@@ -2823,6 +2824,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()));
@@ -3079,6 +3085,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"
@@ -3208,6 +3215,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) {
@@ -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) {
@@ -0,0 +1 @@
var foo bar;
@@ -0,0 +1,2 @@
#!/usr/bin/env node
var foo bar;
@@ -0,0 +1 @@
var foo = 'bar';
@@ -0,0 +1,2 @@
#!/usr/bin/env node
var foo = 'bar';
@@ -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);
});
});

0 comments on commit 9d65528

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.