Skip to content

Commit

Permalink
New: provide parser, parserName on RuleContext (fixes eslint#3670)
Browse files Browse the repository at this point in the history
  • Loading branch information
benmosher committed Dec 15, 2015
1 parent 06ead20 commit c8aef1d
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 33 deletions.
51 changes: 28 additions & 23 deletions lib/eslint.js
Expand Up @@ -502,12 +502,10 @@ module.exports = (function() {
sourceCode = null;

/**
* Parses text into an AST. Moved out here because the try-catch prevents
* optimization of functions, so it's best to keep the try-catch as isolated
* as possible
* @param {string} text The text to parse.
* @param {Object} config The ESLint configuration object.
* @returns {ASTNode} The AST if successful or null if not.
* Parses text into an AST, but does not catch exceptions.
* @param {string} text The text to parse.
* @param {Object} config The ESLint configuration object.
* @returns {ASTNode} The AST.
* @private
*/
function parse(text, config) {
Expand All @@ -522,33 +520,34 @@ module.exports = (function() {
attachComment: true
};

try {
parser = require(config.parser);
} catch (ex) {
messages.push({
fatal: true,
severity: 2,
message: ex.message,
line: 0,
column: 0
});

return null;
}
parser = require(config.parser);

// merge in any additional parser options
if (config.parserOptions) {
parserOptions = assign({}, config.parserOptions, parserOptions);
}

return parser.parse(text, parserOptions);
}

/**
* Parses text into an AST. Moved out here because the try-catch prevents
* optimization of functions, so it's best to keep the try-catch as isolated
* as possible
* @param {string} text The text to parse.
* @param {Object} config The ESLint configuration object.
* @returns {ASTNode} The AST if successful or null if not.
* @private
*/
function tryParse(text, config) {
/*
* Check for parsing errors first. If there's a parsing error, nothing
* else can happen. However, a parsing error does not throw an error
* from this method - it's just considered a fatal error message, a
* problem that ESLint identified just like any other.
*/
try {
return parser.parse(text, parserOptions);
return parse(text, config);
} catch (ex) {

// If the message includes a leading line number, strip it:
Expand Down Expand Up @@ -674,7 +673,7 @@ module.exports = (function() {
return messages;
}

ast = parse(text.replace(/^#!([^\r\n]+)/, function(match, captured) {
ast = tryParse(text.replace(/^#!([^\r\n]+)/, function(match, captured) {
shebang = captured;
return "//" + captured;
}), config);
Expand Down Expand Up @@ -703,7 +702,8 @@ module.exports = (function() {
var ruleCreator,
severity,
options,
rule;
rule,
ruleParse;

ruleCreator = rules.get(key);
if (!ruleCreator) {
Expand All @@ -718,11 +718,16 @@ module.exports = (function() {

severity = getRuleSeverity(config.rules[key]);
options = getRuleOptions(config.rules[key]);
// close over config to simplify for rules
ruleParse = function(t) {
return parse(t, config);
};

try {
rule = ruleCreator(new RuleContext(
key, api, severity, options,
config.settings, config.parserOptions
config.settings, config.parserOptions,
ruleParse
));

// add all the node types as listeners
Expand Down
5 changes: 4 additions & 1 deletion lib/rule-context.js
Expand Up @@ -70,14 +70,17 @@ var PASSTHROUGHS = [
* @param {array} options The configuration information to be added to the rule.
* @param {object} settings The configuration settings passed from the config file.
* @param {object} parserOptions The parserOptions settings passed from the config file.
* @param {function} parse The 'parse' function from ESLint, closed over the config object.
*/
function RuleContext(ruleId, eslint, severity, options, settings, parserOptions) {
function RuleContext(ruleId, eslint, severity, options, settings, parserOptions, parse) {
// public.
this.id = ruleId;
this.options = options;
this.settings = settings;
this.parserOptions = parserOptions;

this.parse = parse;

// private.
this.eslint = eslint;
this.severity = severity;
Expand Down
2 changes: 1 addition & 1 deletion tests/lib/eslint.js
Expand Up @@ -3193,7 +3193,7 @@ describe("eslint", function() {
var messages = eslint.verify(code, { parser: "esprima-fbxyz" }, "filename");
assert.equal(messages.length, 1);
assert.equal(messages[0].severity, 2);
assert.equal(messages[0].message, "Cannot find module 'esprima-fbxyz'");
assert.equal(messages[0].message, "Parsing error: Cannot find module 'esprima-fbxyz'");
});

it("should strip leading line: prefix from parser error", function() {
Expand Down
27 changes: 19 additions & 8 deletions tests/lib/rule-context.js
Expand Up @@ -9,7 +9,8 @@
// Requirements
//------------------------------------------------------------------------------

var sinon = require("sinon"),
var assert = require("chai").assert,
sinon = require("sinon"),
leche = require("leche"),
realESLint = require("../../lib/eslint"),
RuleContext = require("../../lib/rule-context");
Expand All @@ -19,15 +20,15 @@ var sinon = require("sinon"),
//------------------------------------------------------------------------------

describe("RuleContext", function() {
var sandbox = sinon.sandbox.create();
var sandbox = sinon.sandbox.create(),
ruleContext, eslint;

describe("report()", function() {
var ruleContext, eslint;
beforeEach(function() {
eslint = leche.fake(realESLint);
ruleContext = new RuleContext("fake-rule", eslint, 2, {}, {}, {}, require("espree").parse);
});

beforeEach(function() {
eslint = leche.fake(realESLint);
ruleContext = new RuleContext("fake-rule", eslint, 2, {}, {}, {});
});
describe("report()", function() {

describe("old-style call with location", function() {
it("should call eslint.report() with rule ID and severity prepended", function() {
Expand Down Expand Up @@ -93,6 +94,16 @@ describe("RuleContext", function() {
mockESLint.verify();
});
});

});

describe("parse()", function() {
it("is present", function() {
assert.isFunction(ruleContext.parse);
});
it("works", function() {
assert.isObject(ruleContext.parse("function answer() { return 42; }"));
});
});

});

0 comments on commit c8aef1d

Please sign in to comment.