diff --git a/babylon-to-espree/attachComments.js b/babylon-to-espree/attachComments.js index 9fc9f339..8c608a45 100644 --- a/babylon-to-espree/attachComments.js +++ b/babylon-to-espree/attachComments.js @@ -1,7 +1,7 @@ "use strict"; // comment fixes -module.exports = function (ast, comments, tokens) { +module.exports = function(ast, comments, tokens) { if (comments.length) { var firstComment = comments[0]; var lastComment = comments[comments.length - 1]; diff --git a/babylon-to-espree/convertComments.js b/babylon-to-espree/convertComments.js index 19c6ce8c..17d71173 100644 --- a/babylon-to-espree/convertComments.js +++ b/babylon-to-espree/convertComments.js @@ -1,6 +1,6 @@ "use strict"; -module.exports = function (comments) { +module.exports = function(comments) { for (var i = 0; i < comments.length; i++) { var comment = comments[i]; if (comment.type === "CommentBlock") { diff --git a/babylon-to-espree/convertTemplateType.js b/babylon-to-espree/convertTemplateType.js index 8b647c39..d8892f99 100644 --- a/babylon-to-espree/convertTemplateType.js +++ b/babylon-to-espree/convertTemplateType.js @@ -1,24 +1,25 @@ "use strict"; -module.exports = function (tokens, tt) { - var startingToken = 0; - var currentToken = 0; - var numBraces = 0; // track use of {} - var numBackQuotes = 0; // track number of nested templates +module.exports = function(tokens, tt) { + var startingToken = 0; + var currentToken = 0; + var numBraces = 0; // track use of {} + var numBackQuotes = 0; // track number of nested templates function isBackQuote(token) { return tokens[token].type === tt.backQuote; } function isTemplateStarter(token) { - return isBackQuote(token) || - // only can be a template starter when in a template already - tokens[token].type === tt.braceR && numBackQuotes > 0; + return ( + isBackQuote(token) || + // only can be a template starter when in a template already + (tokens[token].type === tt.braceR && numBackQuotes > 0) + ); } function isTemplateEnder(token) { - return isBackQuote(token) || - tokens[token].type === tt.dollarBraceL; + return isBackQuote(token) || tokens[token].type === tt.dollarBraceL; } // append the values between start and end @@ -44,8 +45,8 @@ module.exports = function (tokens, tt) { end: tokens[end].end, loc: { start: tokens[start].loc.start, - end: tokens[end].loc.end - } + end: tokens[end].loc.end, + }, }; // put new token in place of old tokens @@ -70,7 +71,10 @@ module.exports = function (tokens, tt) { currentToken = startingToken + 1; // check if token after template start is "template" - if (currentToken >= tokens.length - 1 || tokens[currentToken].type !== tt.template) { + if ( + currentToken >= tokens.length - 1 || + tokens[currentToken].type !== tt.template + ) { break; } diff --git a/babylon-to-espree/index.js b/babylon-to-espree/index.js index d19c9b07..ecd8eee6 100644 --- a/babylon-to-espree/index.js +++ b/babylon-to-espree/index.js @@ -1,11 +1,11 @@ "use strict"; -var attachComments = require("./attachComments"); +var attachComments = require("./attachComments"); var convertComments = require("./convertComments"); -var toTokens = require("./toTokens"); -var toAST = require("./toAST"); +var toTokens = require("./toTokens"); +var toAST = require("./toAST"); -module.exports = function (ast, traverse, tt, code) { +module.exports = function(ast, traverse, tt, code) { // 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 // todo: find a more elegant way to do this diff --git a/babylon-to-espree/toAST.js b/babylon-to-espree/toAST.js index 2830f5dc..7e3e6876 100644 --- a/babylon-to-espree/toAST.js +++ b/babylon-to-espree/toAST.js @@ -3,12 +3,18 @@ var t = require("babel-types"); var convertComments = require("./convertComments"); -module.exports = function (ast, traverse, code) { +module.exports = function(ast, traverse, code) { var state = { source: code }; // Monkey patch visitor keys in order to be able to traverse the estree nodes t.VISITOR_KEYS.Property = t.VISITOR_KEYS.ObjectProperty; - t.VISITOR_KEYS.MethodDefinition = ["key", "value", "decorators", "returnType", "typeParameters"]; + t.VISITOR_KEYS.MethodDefinition = [ + "key", + "value", + "decorators", + "returnType", + "typeParameters", + ]; traverse(ast, astTransformVisitor, null, state); @@ -18,7 +24,7 @@ module.exports = function (ast, traverse, code) { var astTransformVisitor = { noScope: true, - enter (path) { + enter(path) { var node = path.node; // private var to track original node type @@ -37,7 +43,7 @@ var astTransformVisitor = { convertComments(node.leadingComments); } }, - exit (path) { + exit(path) { var node = path.node; if (path.isJSXText()) { @@ -49,11 +55,19 @@ var astTransformVisitor = { if (!node.shorthand) node.shorthand = false; } - if (path.isRestElement() && path.parent && path.parent.type === "ObjectPattern") { + if ( + path.isRestElement() && + path.parent && + path.parent.type === "ObjectPattern" + ) { node.type = "ExperimentalRestProperty"; } - if (path.isSpreadElement() && path.parent && path.parent.type === "ObjectExpression") { + if ( + path.isSpreadElement() && + path.parent && + path.parent.type === "ObjectExpression" + ) { node.type = "ExperimentalSpreadProperty"; } @@ -105,5 +119,5 @@ var astTransformVisitor = { } } } - } + }, }; diff --git a/babylon-to-espree/toToken.js b/babylon-to-espree/toToken.js index 6173f760..9c5a49ef 100644 --- a/babylon-to-espree/toToken.js +++ b/babylon-to-espree/toToken.js @@ -1,29 +1,47 @@ "use strict"; -module.exports = function (token, tt, source) { +module.exports = function(token, tt, source) { var type = token.type; token.range = [token.start, token.end]; if (type === tt.name) { token.type = "Identifier"; - } else if (type === tt.semi || type === tt.comma || - type === tt.parenL || type === tt.parenR || - type === tt.braceL || type === tt.braceR || - type === tt.slash || type === tt.dot || - type === tt.bracketL || type === tt.bracketR || - type === tt.ellipsis || type === tt.arrow || - type === tt.star || type === tt.incDec || - type === tt.colon || type === tt.question || - type === tt.template || type === tt.backQuote || - type === tt.dollarBraceL || type === tt.at || - type === tt.logicalOR || type === tt.logicalAND || - type === tt.bitwiseOR || type === tt.bitwiseXOR || - type === tt.bitwiseAND || type === tt.equality || - type === tt.relational || type === tt.bitShift || - type === tt.plusMin || type === tt.modulo || - type === tt.exponent || type === tt.prefix || - type === tt.doubleColon || - type.isAssign) { + } else if ( + type === tt.semi || + type === tt.comma || + type === tt.parenL || + type === tt.parenR || + type === tt.braceL || + type === tt.braceR || + type === tt.slash || + type === tt.dot || + type === tt.bracketL || + type === tt.bracketR || + type === tt.ellipsis || + type === tt.arrow || + type === tt.star || + type === tt.incDec || + type === tt.colon || + type === tt.question || + type === tt.template || + type === tt.backQuote || + type === tt.dollarBraceL || + type === tt.at || + type === tt.logicalOR || + type === tt.logicalAND || + type === tt.bitwiseOR || + type === tt.bitwiseXOR || + type === tt.bitwiseAND || + type === tt.equality || + type === tt.relational || + type === tt.bitShift || + type === tt.plusMin || + type === tt.modulo || + type === tt.exponent || + type === tt.prefix || + type === tt.doubleColon || + type.isAssign + ) { token.type = "Punctuator"; if (!token.value) token.value = type.label; } else if (type === tt.jsxTagStart) { @@ -53,7 +71,7 @@ module.exports = function (token, tt, source) { var value = token.value; token.regex = { pattern: value.pattern, - flags: value.flags + flags: value.flags, }; token.value = `/${value.pattern}/${value.flags}`; } diff --git a/babylon-to-espree/toTokens.js b/babylon-to-espree/toTokens.js index 81ec9850..a863b871 100644 --- a/babylon-to-espree/toTokens.js +++ b/babylon-to-espree/toTokens.js @@ -3,7 +3,7 @@ var convertTemplateType = require("./convertTemplateType"); var toToken = require("./toToken"); -module.exports = function (tokens, tt, code) { +module.exports = function(tokens, tt, code) { // transform tokens to type "Template" convertTemplateType(tokens, tt); diff --git a/index.js b/index.js index 5beabc74..ecedcb50 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,10 @@ var babylonToEspree = require("./babylon-to-espree"); -var Module = require("module"); -var path = require("path"); -var parse = require("babylon").parse; -var t = require("babel-types"); -var tt = require("babylon").tokTypes; -var traverse = require("babel-traverse").default; +var Module = require("module"); +var path = require("path"); +var parse = require("babylon").parse; +var t = require("babel-types"); +var tt = require("babylon").tokTypes; +var traverse = require("babel-traverse").default; var codeFrameColumns = require("babel-code-frame").codeFrameColumns; var hasPatched = false; @@ -30,10 +30,11 @@ function getModules() { try { var escope = eslintMod.require("eslint-scope"); - var Definition = eslintMod.require("eslint-scope/lib/definition").Definition; + var Definition = eslintMod.require("eslint-scope/lib/definition") + .Definition; var referencer = eslintMod.require("eslint-scope/lib/referencer"); } catch (err) { - escope = eslintMod.require("escope"); + escope = eslintMod.require("escope"); Definition = eslintMod.require("escope/lib/definition").Definition; referencer = eslintMod.require("escope/lib/referencer"); } @@ -61,7 +62,7 @@ function monkeypatch(modules) { estraverse.VisitorKeys.Property.push("decorators"); var analyze = escope.analyze; - escope.analyze = function (ast, opts) { + escope.analyze = function(ast, opts) { opts = opts || {}; opts.ecmaVersion = eslintOptions.ecmaVersion; opts.sourceType = eslintOptions.sourceType; @@ -94,7 +95,7 @@ function monkeypatch(modules) { "FunctionExpression", "Identifier", "ObjectPattern", - "RestElement" + "RestElement", ]); var visitorKeysMap = Object.keys(t.VISITOR_KEYS).reduce(function(acc, key) { var value = t.VISITOR_KEYS[key]; @@ -120,7 +121,7 @@ function monkeypatch(modules) { // others typeAnnotation: { type: "typeAnnotation" }, typeParameters: { type: "typeParameters" }, - id: { type: "id" } + id: { type: "id" }, }; function visitTypeAnnotation(node) { @@ -182,7 +183,13 @@ function monkeypatch(modules) { function nestTypeParamScope(manager, node) { var parentScope = manager.__currentScope; - var scope = new escope.Scope(manager, "type-parameters", parentScope, node, false); + var scope = new escope.Scope( + manager, + "type-parameters", + parentScope, + node, + false + ); manager.__nestScope(scope); for (var j = 0; j < node.typeParameters.params.length; j++) { var name = node.typeParameters.params[j]; @@ -296,16 +303,10 @@ function monkeypatch(modules) { variableDeclaration.call(this, node); }; - function createScopeVariable (node, name) { - this.currentScope().variableScope.__define(name, - new Definition( - "Variable", - name, - node, - null, - null, - null - ) + function createScopeVariable(node, name) { + this.currentScope().variableScope.__define( + name, + new Definition("Variable", name, node, null, null, null) ); } @@ -339,10 +340,9 @@ function monkeypatch(modules) { } }; - referencer.prototype.DeclareModule = - referencer.prototype.DeclareFunction = - referencer.prototype.DeclareVariable = - referencer.prototype.DeclareClass = function(node) { + referencer.prototype.DeclareModule = referencer.prototype.DeclareFunction = referencer.prototype.DeclareVariable = referencer.prototype.DeclareClass = function( + node + ) { if (node.id) { createScopeVariable.call(this, node, node.id); } @@ -357,11 +357,13 @@ function monkeypatch(modules) { }; } -exports.parse = function (code, options) { +exports.parse = function(code, options) { options = options || {}; eslintOptions.ecmaVersion = options.ecmaVersion = options.ecmaVersion || 6; - eslintOptions.sourceType = options.sourceType = options.sourceType || "module"; - eslintOptions.allowImportExportEverywhere = options.allowImportExportEverywhere = options.allowImportExportEverywhere || false; + eslintOptions.sourceType = options.sourceType = + options.sourceType || "module"; + eslintOptions.allowImportExportEverywhere = options.allowImportExportEverywhere = + options.allowImportExportEverywhere || false; if (options.sourceType === "module") { eslintOptions.globalReturn = false; } else { @@ -381,7 +383,7 @@ exports.parse = function (code, options) { return exports.parseNoPatch(code, options); }; -exports.parseNoPatch = function (code, options) { +exports.parseNoPatch = function(code, options) { var opts = { codeFrame: options.hasOwnProperty("codeFrame") ? options.codeFrame : true, sourceType: options.sourceType, @@ -410,7 +412,7 @@ exports.parseNoPatch = function (code, options) { "optionalChaining", "importMeta", "classPrivateProperties", - ] + ], }; var ast; @@ -418,7 +420,6 @@ exports.parseNoPatch = function (code, options) { ast = parse(code, opts); } catch (err) { if (err instanceof SyntaxError) { - err.lineNumber = err.loc.line; err.column = err.loc.column; @@ -427,15 +428,23 @@ exports.parseNoPatch = function (code, options) { err.column = err.loc.column + 1; // remove trailing "(LINE:COLUMN)" acorn message and add in esprima syntax error message start - err.message = "Line " + err.lineNumber + ": " + err.message.replace(/ \((\d+):(\d+)\)$/, "") + - // add codeframe - "\n\n" + - codeFrameColumns(code, { - start: { - line: err.lineNumber, - column: err.column, - }, - }, { highlightCode: true }); + err.message = + "Line " + + err.lineNumber + + ": " + + err.message.replace(/ \((\d+):(\d+)\)$/, "") + + // add codeframe + "\n\n" + + codeFrameColumns( + code, + { + start: { + line: err.lineNumber, + column: err.column, + }, + }, + { highlightCode: true } + ); } } diff --git a/test/babel-eslint.js b/test/babel-eslint.js index 31d3918c..2ac2d3af 100644 --- a/test/babel-eslint.js +++ b/test/babel-eslint.js @@ -1,9 +1,9 @@ -var assert = require("assert"); +var assert = require("assert"); var babelEslint = require(".."); -var espree = require("espree"); -var escope = require("escope"); -var util = require("util"); -var unpad = require("dedent"); +var espree = require("espree"); +var escope = require("escope"); +var util = require("util"); +var unpad = require("dedent"); // Checks if the source ast implements the target ast. Ignores extra keys on source ast function assertImplementsAST(target, source, path) { @@ -20,9 +20,18 @@ function assertImplementsAST(target, source, path) { var typeA = target === null ? "null" : typeof target; var typeB = source === null ? "null" : typeof source; if (typeA !== typeB) { - error(`have different types (${typeA} !== ${typeB}) (${target} !== ${source})`); - } else if (typeA === "object" && ["RegExp"].indexOf(target.constructor.name) !== -1 && target.constructor.name !== source.constructor.name) { - error(`object have different constructors (${target.constructor.name} !== ${source.constructor.name}`); + error( + `have different types (${typeA} !== ${typeB}) (${target} !== ${source})` + ); + } else if ( + typeA === "object" && + ["RegExp"].indexOf(target.constructor.name) !== -1 && + target.constructor.name !== source.constructor.name + ) { + error( + `object have different constructors (${target.constructor + .name} !== ${source.constructor.name}` + ); } else if (typeA === "object") { var keysTarget = Object.keys(target); for (var i in keysTarget) { @@ -32,28 +41,36 @@ function assertImplementsAST(target, source, path) { path.pop(); } } else if (target !== source) { - error(`are different (${JSON.stringify(target)} !== ${JSON.stringify(source)})`); + error( + `are different (${JSON.stringify(target)} !== ${JSON.stringify(source)})` + ); } } function lookup(obj, keypath, backwardsDepth) { - if (!keypath) { return obj; } + if (!keypath) { + return obj; + } - return keypath.split(".").slice(0, -1 * backwardsDepth) - .reduce((base, segment) => { return base && base[segment], obj; }); + return keypath + .split(".") + .slice(0, -1 * backwardsDepth) + .reduce((base, segment) => { + return base && base[segment], obj; + }); } function parseAndAssertSame(code) { var esAST = espree.parse(code, { ecmaFeatures: { - // enable JSX parsing + // enable JSX parsing jsx: true, - // enable return in global scope + // enable return in global scope globalReturn: true, - // enable implied strict mode (if ecmaVersion >= 5) + // enable implied strict mode (if ecmaVersion >= 5) impliedStrict: true, - // allow experimental object rest/spread - experimentalObjectRestSpread: true + // allow experimental object rest/spread + experimentalObjectRestSpread: true, }, tokens: true, loc: true, @@ -61,7 +78,7 @@ function parseAndAssertSame(code) { comment: true, attachComment: true, ecmaVersion: 8, - sourceType: "module" + sourceType: "module", }); var babylonAST = babelEslint.parse(code); try { @@ -76,9 +93,15 @@ function parseAndAssertSame(code) { } err.message += unpad(` espree: - ${util.inspect(lookup(esAST, traversal, 2), { depth: err.depth, colors: true })} + ${util.inspect(lookup(esAST, traversal, 2), { + depth: err.depth, + colors: true, + })} babel-eslint: - ${util.inspect(lookup(babylonAST, traversal, 2), { depth: err.depth, colors: true })} + ${util.inspect(lookup(babylonAST, traversal, 2), { + depth: err.depth, + colors: true, + })} `); throw err; } @@ -90,9 +113,13 @@ describe("babylon-to-esprima", () => { it("should allow ast.analyze to be called without options", function() { var esAST = babelEslint.parse("`test`"); - assert.doesNotThrow(() => { - escope.analyze(esAST); - }, TypeError, "Should allow no options argument."); + assert.doesNotThrow( + () => { + escope.analyze(esAST); + }, + TypeError, + "Should allow no options argument." + ); }); }); @@ -138,11 +165,15 @@ describe("babylon-to-esprima", () => { }); it("template with nested function/object", () => { - parseAndAssertSame("`outer${{x: {y: 10}}}bar${`nested${function(){return 1;}}endnest`}end`"); + parseAndAssertSame( + "`outer${{x: {y: 10}}}bar${`nested${function(){return 1;}}endnest`}end`" + ); }); it("template with braces inside and outside of template string #96", () => { - parseAndAssertSame("if (a) { var target = `{}a:${webpackPort}{}}}}`; } else { app.use(); }"); + parseAndAssertSame( + "if (a) { var target = `{}a:${webpackPort}{}}}}`; } else { app.use(); }" + ); }); it("template also with braces #96", () => { @@ -218,19 +249,19 @@ describe("babylon-to-esprima", () => { }); it("default import", () => { - parseAndAssertSame("import foo from \"foo\";"); + parseAndAssertSame('import foo from "foo";'); }); it("import specifier", () => { - parseAndAssertSame("import { foo } from \"foo\";"); + parseAndAssertSame('import { foo } from "foo";'); }); it("import specifier with name", () => { - parseAndAssertSame("import { foo as bar } from \"foo\";"); + parseAndAssertSame('import { foo as bar } from "foo";'); }); it("import bare", () => { - parseAndAssertSame("import \"foo\";"); + parseAndAssertSame('import "foo";'); }); it("export default class declaration", () => { @@ -250,7 +281,7 @@ describe("babylon-to-esprima", () => { }); it("export all", () => { - parseAndAssertSame("export * from \"foo\";"); + parseAndAssertSame('export * from "foo";'); }); it("export named", () => { @@ -331,11 +362,11 @@ describe("babylon-to-esprima", () => { }); it("regexp in a template string", () => { - parseAndAssertSame("`${/\\d/.exec(\"1\")[0]}`"); + parseAndAssertSame('`${/\\d/.exec("1")[0]}`'); }); it("first line is empty", () => { - parseAndAssertSame("\nimport Immutable from \"immutable\";"); + parseAndAssertSame('\nimport Immutable from "immutable";'); }); it("empty", () => { @@ -383,7 +414,9 @@ describe("babylon-to-esprima", () => { }); it("MethodDefinition 2", () => { - parseAndAssertSame("export default class Bar { get bar() { return 42; }}"); + parseAndAssertSame( + "export default class Bar { get bar() { return 42; }}" + ); }); it("ClassMethod", () => { @@ -443,7 +476,7 @@ describe("babylon-to-esprima", () => { it("do not allow import export everywhere", () => { assert.throws(() => { - parseAndAssertSame("function F() { import a from \"a\"; }"); + parseAndAssertSame('function F() { import a from "a"; }'); }, /SyntaxError: 'import' and 'export' may only appear at the top level/); }); diff --git a/test/integration.js b/test/integration.js index c446ed34..8e93631a 100644 --- a/test/integration.js +++ b/test/integration.js @@ -13,8 +13,8 @@ var errorLevel = 2; var baseEslintOpts = { parser: require.resolve(".."), parserOptions: { - sourceType: "script" - } + sourceType: "script", + }, }; /** @@ -23,7 +23,7 @@ var baseEslintOpts = { * @param object opts * @param function done */ -function lint (opts, done) { +function lint(opts, done) { readFixture(opts.fixture, (err, src) => { if (err) return done(err); done(null, eslint.linter.verify(src, opts.eslint)); @@ -35,14 +35,10 @@ function lint (opts, done) { * @param string|array id * @param function done */ -function readFixture (id, done) { +function readFixture(id, done) { if (Array.isArray(id)) id = path.join.apply(path, id); if (!path.extname(id)) id += ".js"; - fs.readFile( - path.join(paths.fixtures, id), - encoding, - done - ); + fs.readFile(path.join(paths.fixtures, id), encoding, done); } // readFixture @@ -51,7 +47,7 @@ describe("Rules:", () => { }); // describe -function strictSuite () { +function strictSuite() { var ruleId = "strict"; describe("when set to 'never'", () => { @@ -60,19 +56,20 @@ function strictSuite () { }); eslintOpts.rules[ruleId] = [errorLevel, "never"]; - ["global-with", "function-with"].forEach((fixture) => { - it(`should error on ${fixture.match(/^[^-]+/)[0]} directive`, - (done) => { - lint({ + ["global-with", "function-with"].forEach(fixture => { + it(`should error on ${fixture.match(/^[^-]+/)[0]} directive`, done => { + lint( + { fixture: ["strict", fixture], eslint: eslintOpts, - }, (err, report) => { + }, + (err, report) => { if (err) return done(err); assert(report[0].ruleId === ruleId); done(); - }); - } - ); + } + ); + }); // it }); }); @@ -80,63 +77,75 @@ function strictSuite () { describe("when set to 'global'", () => { var eslintOpts = Object.assign({}, baseEslintOpts, { - rules: {} + rules: {}, }); eslintOpts.rules[ruleId] = [errorLevel, "global"]; - it("shouldn't error on single global directive", (done) => { - lint({ - fixture: ["strict", "global-with"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - assert(!report.length); - done(); - }); + it("shouldn't error on single global directive", done => { + lint( + { + fixture: ["strict", "global-with"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(!report.length); + done(); + } + ); }); // it - it("should error twice on global directive: no and function directive: yes", (done) => { - lint({ - fixture: ["strict", "function-with"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - [0, 1].forEach((i) => { - assert(report[i].ruleId === ruleId); - }); - done(); - }); + it("should error twice on global directive: no and function directive: yes", done => { + lint( + { + fixture: ["strict", "function-with"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + [0, 1].forEach(i => { + assert(report[i].ruleId === ruleId); + }); + done(); + } + ); }); // it - it("should error on function directive", (done) => { - lint({ - fixture: ["strict", "global-with-function-with"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - assert(report[0].ruleId === ruleId); - - // This is to make sure the test fails prior to adapting Babel AST - // directive representation to ESLint format. Otherwise it reports an - // error for missing global directive that masquerades as the expected - // result of the previous assertion. - assert(report[0].nodeType !== "Program"); - done(); - }); + it("should error on function directive", done => { + lint( + { + fixture: ["strict", "global-with-function-with"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(report[0].ruleId === ruleId); + + // This is to make sure the test fails prior to adapting Babel AST + // directive representation to ESLint format. Otherwise it reports an + // error for missing global directive that masquerades as the expected + // result of the previous assertion. + assert(report[0].nodeType !== "Program"); + done(); + } + ); }); // it - it("should error on no directive", (done) => { - lint({ - fixture: ["strict", "none"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - assert(report[0].ruleId === ruleId); - done(); - }); + it("should error on no directive", done => { + lint( + { + fixture: ["strict", "none"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(report[0].ruleId === ruleId); + done(); + } + ); }); // it }); @@ -144,108 +153,130 @@ function strictSuite () { describe("when set to 'function'", () => { var eslintOpts = Object.assign({}, baseEslintOpts, { - rules: {} + rules: {}, }); eslintOpts.rules[ruleId] = [errorLevel, "function"]; - it("shouldn't error on single function directive", (done) => { - lint({ - fixture: ["strict", "function-with"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - assert(!report.length); - done(); - }); + it("shouldn't error on single function directive", done => { + lint( + { + fixture: ["strict", "function-with"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(!report.length); + done(); + } + ); }); // it - it("should error twice on function directive: no and global directive: yes", (done) => { - lint({ - fixture: ["strict", "global-with-function-without"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - [0, 1].forEach((i) => { - assert(report[i].ruleId === ruleId); - }); - done(); - }); + it("should error twice on function directive: no and global directive: yes", done => { + lint( + { + fixture: ["strict", "global-with-function-without"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + [0, 1].forEach(i => { + assert(report[i].ruleId === ruleId); + }); + done(); + } + ); }); // it - it("should error on only global directive", (done) => { - lint({ - fixture: ["strict", "global-with"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - assert(report[0].ruleId === ruleId); - done(); - }); + it("should error on only global directive", done => { + lint( + { + fixture: ["strict", "global-with"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(report[0].ruleId === ruleId); + done(); + } + ); }); // it - it("should error on extraneous global directive", (done) => { - lint({ - fixture: ["strict", "global-with-function-with"], - eslint: eslintOpts, - }, (err, report) => { - if (err) return done(err); - assert(report[0].ruleId === ruleId); - assert(report[0].nodeType.indexOf("Function") === -1); - done(); - }); + it("should error on extraneous global directive", done => { + lint( + { + fixture: ["strict", "global-with-function-with"], + eslint: eslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(report[0].ruleId === ruleId); + assert(report[0].nodeType.indexOf("Function") === -1); + done(); + } + ); }); // it }); // describe - describe("When \"codeFrame\"", () => { + describe('When "codeFrame"', () => { // Strip chalk colors, these are not relevant for the test - const stripAnsi = (str) => str.replace( - /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, - "" - ); - - it("should display codeFrame when option is absent", (done) => { - lint({ - fixture: ["syntax-error"], - eslint: baseEslintOpts - }, (err, report) => { - if (err) return done(err); - assert(stripAnsi(report[0].message).indexOf("^\n 5 |") > -1); - done(); - }); + const stripAnsi = str => + str.replace( + /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, + "" + ); + + it("should display codeFrame when option is absent", done => { + lint( + { + fixture: ["syntax-error"], + eslint: baseEslintOpts, + }, + (err, report) => { + if (err) return done(err); + assert(stripAnsi(report[0].message).indexOf("^\n 5 |") > -1); + done(); + } + ); }); - it("should display codeFrame when option is true", (done) => { - lint({ - fixture: ["syntax-error"], - eslint: Object.assign({}, baseEslintOpts, { - parserOptions: { - codeFrame: true - } - }) - }, (err, report) => { - if (err) return done(err); - assert(stripAnsi(report[0].message).indexOf("^\n 5 |") > -1); - done(); - }); + it("should display codeFrame when option is true", done => { + lint( + { + fixture: ["syntax-error"], + eslint: Object.assign({}, baseEslintOpts, { + parserOptions: { + codeFrame: true, + }, + }), + }, + (err, report) => { + if (err) return done(err); + assert(stripAnsi(report[0].message).indexOf("^\n 5 |") > -1); + done(); + } + ); }); - it("should not display codeFrame when option is false", (done) => { - lint({ - fixture: ["syntax-error"], - eslint: Object.assign({}, baseEslintOpts, { - parserOptions: { - codeFrame: false - } - }) - }, (err, report) => { - if (err) return done(err); - assert(stripAnsi(report[0].message).indexOf("^\n 5 |") === -1); - done(); - }); + it("should not display codeFrame when option is false", done => { + lint( + { + fixture: ["syntax-error"], + eslint: Object.assign({}, baseEslintOpts, { + parserOptions: { + codeFrame: false, + }, + }), + }, + (err, report) => { + if (err) return done(err); + assert(stripAnsi(report[0].message).indexOf("^\n 5 |") === -1); + done(); + } + ); }); }); } diff --git a/test/non-regression.js b/test/non-regression.js index 26bf95af..f382801f 100644 --- a/test/non-regression.js +++ b/test/non-regression.js @@ -3,23 +3,29 @@ var eslint = require("eslint"); var unpad = require("dedent"); -function verifyAndAssertMessages(code, rules, expectedMessages, sourceType, overrideConfig) { +function verifyAndAssertMessages( + code, + rules, + expectedMessages, + sourceType, + overrideConfig +) { var config = { parser: require.resolve(".."), rules, env: { node: true, - es6: true + es6: true, }, parserOptions: { ecmaVersion: 8, ecmaFeatures: { jsx: true, experimentalObjectRestSpread: true, - globalReturn: true + globalReturn: true, }, - sourceType - } + sourceType, + }, }; if (overrideConfig) { @@ -31,11 +37,19 @@ function verifyAndAssertMessages(code, rules, expectedMessages, sourceType, over var messages = eslint.linter.verify(code, config); if (messages.length !== expectedMessages.length) { - throw new Error(`Expected ${expectedMessages.length} message(s), got ${messages.length}\n${JSON.stringify(messages, null, 2)}`); + throw new Error( + `Expected ${expectedMessages.length} message(s), got ${messages.length}\n${JSON.stringify( + messages, + null, + 2 + )}` + ); } messages.forEach((message, i) => { - var formatedMessage = `${message.line}:${message.column} ${message.message}${(message.ruleId ? ` ${message.ruleId}` : "")}`; + var formatedMessage = `${message.line}:${message.column} ${message.message}${message.ruleId + ? ` ${message.ruleId}` + : ""}`; if (formatedMessage !== expectedMessages[i]) { throw new Error( unpad(` @@ -50,27 +64,21 @@ function verifyAndAssertMessages(code, rules, expectedMessages, sourceType, over describe("verify", () => { it("arrow function support (issue #1)", () => { - verifyAndAssertMessages( - "describe('stuff', () => {});", - {}, - [] - ); + verifyAndAssertMessages("describe('stuff', () => {});", {}, []); }); it("EOL validation (issue #2)", () => { verifyAndAssertMessages( - "module.exports = \"something\";", - { "eol-last": 1, "semi": 1 }, - [ "1:30 Newline required at end of file but not found. eol-last" ] + 'module.exports = "something";', + { "eol-last": 1, semi: 1 }, + ["1:30 Newline required at end of file but not found. eol-last"] ); }); xit("Readable error messages (issue #3)", () => { - verifyAndAssertMessages( - "{ , res }", - {}, - [ "1:3 Parsing error: Unexpected token" ] - ); + verifyAndAssertMessages("{ , res }", {}, [ + "1:3 Parsing error: Unexpected token", + ]); }); it("Modules support (issue #5)", () => { @@ -120,7 +128,7 @@ describe("verify", () => { it("JSX attribute names marked as variables (issue #12)", () => { verifyAndAssertMessages( - "module.exports =
", + 'module.exports = ', { "no-undef": 1 }, [] ); @@ -136,8 +144,8 @@ describe("verify", () => { it("Arrow function with non-block bodies (issue #20)", () => { verifyAndAssertMessages( - "\"use strict\"; () => 1", - { "strict": [1, "global"] }, + '"use strict"; () => 1', + { strict: [1, "global"] }, [], "script" ); @@ -145,7 +153,7 @@ describe("verify", () => { it("#242", () => { verifyAndAssertMessages( - "\"use strict\"; asdf;", + '"use strict"; asdf;', { "no-irregular-whitespace": 1 }, [], {} @@ -191,19 +199,11 @@ describe("verify", () => { }); it("type alias", () => { - verifyAndAssertMessages( - "type SomeNewType = any;", - { "no-undef": 1 }, - [] - ); + verifyAndAssertMessages("type SomeNewType = any;", { "no-undef": 1 }, []); }); it("type cast expression #102", () => { - verifyAndAssertMessages( - "for (let a of (a: Array)) {}", - {}, - [] - ); + verifyAndAssertMessages("for (let a of (a: Array)) {}", {}, []); }); it("multiple nullable type annotations and return #108", () => { @@ -231,7 +231,7 @@ describe("verify", () => { }; `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "2:11 'Bar' is defined but never used. no-unused-vars" ] + ["2:11 'Bar' is defined but never used. no-unused-vars"] ); }); @@ -246,7 +246,7 @@ describe("verify", () => { new Log(); `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "3:34 'T4' is defined but never used. no-unused-vars" ] + ["3:34 'T4' is defined but never used. no-unused-vars"] ); }); @@ -259,9 +259,11 @@ describe("verify", () => { new Foo(); `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "1:1 'T' is not defined. no-undef", + [ + "1:1 'T' is not defined. no-undef", "2:11 'T' is defined but never used. no-unused-vars", - "3:1 'T' is not defined. no-undef" ] + "3:1 'T' is not defined. no-undef", + ] ); }); @@ -274,8 +276,10 @@ describe("verify", () => { } `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "2:11 'Log' is defined but never used. no-unused-vars", - "2:38 'T4' is defined but never used. no-unused-vars" ] + [ + "2:11 'Log' is defined but never used. no-unused-vars", + "2:38 'T4' is defined but never used. no-unused-vars", + ] ); }); @@ -288,9 +292,11 @@ describe("verify", () => { Foo; `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "1:1 'T' is not defined. no-undef", + [ + "1:1 'T' is not defined. no-undef", "2:15 'T' is defined but never used. no-unused-vars", - "3:1 'T' is not defined. no-undef" ] + "3:1 'T' is not defined. no-undef", + ] ); }); @@ -304,8 +310,10 @@ describe("verify", () => { }; `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "2:6 'Log' is defined but never used. no-unused-vars", - "2:29 'T3' is defined but never used. no-unused-vars" ] + [ + "2:6 'Log' is defined but never used. no-unused-vars", + "2:29 'T3' is defined but never used. no-unused-vars", + ] ); }); @@ -318,9 +326,11 @@ describe("verify", () => { Foo; `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "1:1 'T' is not defined. no-undef", + [ + "1:1 'T' is not defined. no-undef", "2:10 'T' is defined but never used. no-unused-vars", - "3:1 'T' is not defined. no-undef" ] + "3:1 'T' is not defined. no-undef", + ] ); }); @@ -333,7 +343,7 @@ describe("verify", () => { log(1, 2); `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "3:37 'T4' is defined but never used. no-unused-vars" ] + ["3:37 'T4' is defined but never used. no-unused-vars"] ); }); @@ -346,9 +356,11 @@ describe("verify", () => { log; `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "1:1 'T' is not defined. no-undef", + [ + "1:1 'T' is not defined. no-undef", "2:14 'T' is defined but never used. no-unused-vars", - "3:1 'T' is not defined. no-undef" ] + "3:1 'T' is not defined. no-undef", + ] ); }); @@ -544,8 +556,10 @@ describe("verify", () => { var b: T = 1; b; `), { "no-unused-vars": 1, "no-undef": 1 }, - [ "1:21 'T' is defined but never used. no-unused-vars", - "2:8 'T' is not defined. no-undef" ] + [ + "1:21 'T' is defined but never used. no-unused-vars", + "2:8 'T' is not defined. no-undef", + ] ); }); @@ -556,7 +570,7 @@ describe("verify", () => { export class Foo extends Bar