Skip to content

Commit

Permalink
use babylon instead of espree to support more experimental features. …
Browse files Browse the repository at this point in the history
…see #398
  • Loading branch information
millermedeiros committed Jan 29, 2016
1 parent baf6baa commit c77d994
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 45 deletions.
8 changes: 8 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,17 @@ function logError(e) {
var msg = typeof e === 'string' ? e : e.message;

// esprima.parse errors are in the format 'Line 123: Unexpected token &'
// we support both formats since users might replace the parser
if ((/Line \d+:/).test(msg)) {
// convert into "Error: <filepath>:<line> <error_message>"
msg = 'Error: ' + msg.replace(/[^\d]+(\d+): (.+)/, e.file + ':$1 $2');
} else {
// babylon.parse errors are in the format 'Unexpected token (0:4)'
var m = (/^([^\(]+)\s\((\d+):(\d+)\)/).exec(msg);
if (m) {
// convert into "Error: <filepath>:<line>:<char> <error_message>"
msg = 'Error: ' + e.file + ':' + m[2] + ':' + m[3] + ' ' + m[1];
}
}

// set the error flag to true to use an exit code !== 0
Expand Down
113 changes: 76 additions & 37 deletions lib/format.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
'use strict';

var _options = require('./options');
// we use espree because it supports more ES6 features than esprima at the
// moment and supports JSX
var espree = require('espree');

// we use babylon because it supports more ES6+ features than esprima at the
// moment and also supports JSX
var acornToEsprima = require('acorn-to-esprima');
var babelTraverse = require('babel-traverse').default;
var babylon = require('babylon');
var npmRun = require('npm-run');
var plugins = require('./plugins');
var rocambole = require('rocambole');
var transform = require('./transform');

// need to skip extra properties from babylon otherwise we would format more
// nodes than we need and it also confuses rocambole about {start|end}Token
rocambole.BYPASS_RECURSION.loc = true;
rocambole.BYPASS_RECURSION.leadingComments = true;
rocambole.BYPASS_RECURSION.trailingComments = true;

exports = module.exports = format;
function format(str, opts) {
Expand All @@ -18,13 +26,14 @@ function format(str, opts) {

// remove shebang before pipe because piped commands might not know how
// to handle it
var prefix = '';
if (_options.get('esformatter.allowShebang')) {
prefix = getShebang(str);
if (prefix) {
str = str.replace(prefix, '');
}
var prefix = getShebang(str);
if (prefix && !_options.get('esformatter.allowShebang')) {
throw new Error(
'shebang not allowed! Set esformatter.allowShebang to true if you ' +
'want to support it.'
);
}
str = str.replace(prefix, '');

var pipeCommands = _options.get('pipe');

Expand All @@ -44,35 +53,65 @@ function format(str, opts) {
}


// allows users to override parser
exports.parseFn = espree.parse;
exports.parseContext = espree;
// allows users to override parser if needed
exports.parseFn = function(str, opts) {
var ast = babylon.parse(str, opts);

// remove EOF token, eslint doesn't use this for anything and it interferes with some rules
// see https://github.com/babel/babel-eslint/issues/2 for more info
// todo: find a more elegant way to do this
ast.tokens.pop();

// convert tokens
ast.tokens = acornToEsprima.toTokens(ast.tokens, babylon.tokTypes, str);

// add comments
acornToEsprima.convertComments(ast.comments);

// transform esprima and acorn divergent nodes
acornToEsprima.toAST(ast, babelTraverse, str);

// remove File
ast.type = 'Program';
ast.sourceType = ast.program.sourceType;
ast.directives = ast.program.directives;
ast.body = ast.program.body;
delete ast.program;
delete ast._paths;

acornToEsprima.attachComments(ast, ast.comments, ast.tokens);

return ast;
};

exports.parseContext = null;

exports.parseOptions = {
ecmaFeatures: {
arrowFunctions: true,
blockBindings: true,
destructuring: true,
regexYFlag: true,
regexUFlag: true,
templateStrings: true,
binaryLiterals: true,
octalLiterals: true,
unicodeCodePointEscapes: true,
defaultParams: true,
restParams: true,
forOf: true,
objectLiteralComputedProperties: true,
objectLiteralShorthandMethods: true,
objectLiteralShorthandProperties: true,
objectLiteralDuplicateProperties: true,
generators: true,
spread: true,
classes: true,
modules: true,
jsx: true,
globalReturn: true,
experimentalObjectRestSpread: true
}
allowImportExportEverywhere: false, // consistent with espree
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
locations: true,
onComment: [],
onToken: [],
plugins: [
'asyncFunctions',
'asyncGenerators',
'classConstructorCall',
'classProperties',
'decorators',
'doExpressions',
'exponentiationOperator',
'exportExtensions',
'flow',
'functionBind',
'functionSent',
'jsx',
'objectRestSpread',
'trailingFunctionCommas'
],
ranges: true,
sourceType: 'module',
strictMode: true
};


Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@
"mockery": "^1.4.0"
},
"dependencies": {
"acorn-to-esprima": "^2.0.6",
"babel-traverse": "^6.4.5",
"babylon": "^6.4.5",
"debug": "^0.7.4",
"disparity": "^2.0.0",
"espree": "^2.2.4",
"glob": "^5.0.3",
"minimist": "^1.1.1",
"mout": ">=0.9 <2.0",
Expand Down
4 changes: 2 additions & 2 deletions test/cli.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ describe('Command line interface', function() {
// using match because of absolute path and also because file order might
// be different in some OS. we just make sure that error message contains
// what we expect to find
expect(msg).to.match(/Error: .+invalid-1.js:4 Unexpected token &/);
expect(msg).to.match(/Error: .+invalid-2.js:3 Invalid regular expression/);
expect(msg).to.match(/Error: .+invalid-1.js:4:0 Unexpected token/);
expect(msg).to.match(/Error: .+invalid-2.js:3:9 Invalid regular expression/);
});

});
2 changes: 1 addition & 1 deletion test/compare/error/invalid-2.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

// invalid RegExp
var r = /[\u{61}-b]/u;
var r = /[\u{61}-b]/ugetqweasdasdlk;

// some random invalid tokens
$%899
8 changes: 4 additions & 4 deletions test/format.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/*global describe:false, it:false*/
"use strict";

var espree = require('espree');
var babylon = require('babylon');
var expect = require('chai').expect;
var _glob = require('glob');
var _path = require('path');
Expand Down Expand Up @@ -42,7 +42,7 @@ describe('esformatter.format()', function() {
// result should be valid JS
expect(function() {
try {
espree.parse(result, esformatter.format.parseOptions);
babylon.parse(result, esformatter.format.parseOptions);
} catch (e) {
throw new Error('esformatter.format() result produced a non-valid output.\n' + e);
}
Expand Down Expand Up @@ -78,7 +78,7 @@ describe('esformatter.format()', function() {
// result should be valid JS
expect(function() {
try {
espree.parse(result, esformatter.format.parseOptions);
babylon.parse(result, esformatter.format.parseOptions);
} catch (e) {
throw new Error('esformatter.format() result produced a non-valid output.\n' + e);
}
Expand Down Expand Up @@ -113,7 +113,7 @@ describe('esformatter.format()', function() {
// result should be valid JS
expect(function() {
try {
espree.parse(result, esformatter.format.parseOptions);
babylon.parse(result, esformatter.format.parseOptions);
} catch (e) {
throw new Error('esformatter.format() result produced a non-valid output.\n' + e);
}
Expand Down

0 comments on commit c77d994

Please sign in to comment.