diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 1d021d1e82e7..c35605b54a2b 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -938,22 +938,25 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser }); }); - const eventGenerator = new CodePathAnalyzer(new NodeEventGenerator(emitter)); + // only run code path analyzer if the top level node is "Program", skip otherwise + if (nodeQueue[0].node.type === "Program") { + const eventGenerator = new CodePathAnalyzer(new NodeEventGenerator(emitter)); - nodeQueue.forEach(traversalInfo => { - currentNode = traversalInfo.node; + nodeQueue.forEach(traversalInfo => { + currentNode = traversalInfo.node; - try { - if (traversalInfo.isEntering) { - eventGenerator.enterNode(currentNode); - } else { - eventGenerator.leaveNode(currentNode); + try { + if (traversalInfo.isEntering) { + eventGenerator.enterNode(currentNode); + } else { + eventGenerator.leaveNode(currentNode); + } + } catch (err) { + err.currentNode = currentNode; + throw err; } - } catch (err) { - err.currentNode = currentNode; - throw err; - } - }); + }); + } return lintingProblems; } diff --git a/tests/fixtures/parsers/linter-test-parsers.js b/tests/fixtures/parsers/linter-test-parsers.js index dc81e34ecb9e..9f871a4b5831 100644 --- a/tests/fixtures/parsers/linter-test-parsers.js +++ b/tests/fixtures/parsers/linter-test-parsers.js @@ -10,5 +10,6 @@ module.exports = { noLineError: require("./no-line-error"), enhancedParser2: require("./enhanced-parser2"), enhancedParser3: require("./enhanced-parser3"), - throwsWithOptions: require("./throws-with-options") + throwsWithOptions: require("./throws-with-options"), + nonJSParser: require('./non-js-parser') }; diff --git a/tests/fixtures/parsers/non-js-parser.js b/tests/fixtures/parsers/non-js-parser.js new file mode 100644 index 000000000000..86b6d9393673 --- /dev/null +++ b/tests/fixtures/parsers/non-js-parser.js @@ -0,0 +1,238 @@ +/** + * Source code: + * function foo(a: number=0): Foo { } + */ + +exports.parseForESLint = () => ({ + ast: { + "kind": "Document", + "definitions": [ + { + "kind": "ObjectTypeExtension", + "name": { + "kind": "Name", + "value": "Query", + "loc": { + "start": 12, + "end": 17 + }, + "type": "Name" + }, + "interfaces": [], + "directives": [], + "fields": [ + { + "kind": "FieldDefinition", + "name": { + "kind": "Name", + "value": "login", + "loc": { + "start": 24, + "end": 29 + }, + "type": "Name" + }, + "arguments": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "input", + "loc": { + "start": 30, + "end": 35 + }, + "type": "Name" + }, + "type": "InputValueDefinition", + "directives": [], + "loc": { + "start": 30, + "end": 49 + }, + "fieldType": { + "kind": "NonNullType", + "type": "NonNullType", + "loc": { + "start": 37, + "end": 49 + }, + "fieldType": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "Credentials", + "loc": { + "start": 37, + "end": 48 + }, + "type": "Name" + }, + "loc": { + "start": 37, + "end": 48 + }, + "type": "NamedType" + } + } + } + ], + "type": "FieldDefinition", + "directives": [], + "loc": { + "start": 24, + "end": 63 + }, + "fieldType": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "UserProfile", + "loc": { + "start": 52, + "end": 63 + }, + "type": "Name" + }, + "loc": { + "start": 52, + "end": 63 + }, + "type": "NamedType" + } + } + ], + "loc": { + "start": 0, + "end": 65 + }, + "type": "ObjectTypeExtension" + }, + { + "kind": "InputObjectTypeDefinition", + "name": { + "kind": "Name", + "value": "Credentials", + "loc": { + "start": 73, + "end": 84 + }, + "type": "Name" + }, + "directives": [], + "fields": [ + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "login", + "loc": { + "start": 91, + "end": 96 + }, + "type": "Name" + }, + "type": "InputValueDefinition", + "directives": [], + "loc": { + "start": 91, + "end": 105 + }, + "fieldType": { + "kind": "NonNullType", + "type": "NonNullType", + "loc": { + "start": 98, + "end": 105 + }, + "fieldType": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String", + "loc": { + "start": 98, + "end": 104 + }, + "type": "Name" + }, + "loc": { + "start": 98, + "end": 104 + }, + "type": "NamedType" + } + } + }, + { + "kind": "InputValueDefinition", + "name": { + "kind": "Name", + "value": "password", + "loc": { + "start": 110, + "end": 118 + }, + "type": "Name" + }, + "type": "InputValueDefinition", + "directives": [], + "loc": { + "start": 110, + "end": 127 + }, + "fieldType": { + "kind": "NonNullType", + "type": "NonNullType", + "loc": { + "start": 120, + "end": 127 + }, + "fieldType": { + "kind": "NamedType", + "name": { + "kind": "Name", + "value": "String", + "loc": { + "start": 120, + "end": 126 + }, + "type": "Name" + }, + "loc": { + "start": 120, + "end": 126 + }, + "type": "NamedType" + } + } + } + ], + "loc": { + "start": 67, + "end": 129 + }, + "type": "InputObjectTypeDefinition" + } + ], + "loc": { + "start": 0, + "end": 130 + }, + "type": "Document", + "tokens": [], + "comments": [], + "range": {} + }, + services: {}, + scopeManager: { variables: [], scopes: [{ set: new Map(), variables: [], through: [] }], getDeclaredVariables: () => {} }, + visitorKeys: { + Document: ['definitions'], + ObjectTypeDefinition: ['interfaces', 'directives', 'fields'], + ObjectTypeExtension: ['interfaces', 'directives', 'fields'], + InputObjectTypeDefinition: ['directives', 'fields'], + InputValueDefinition: ['directives', 'fieldType'], + FieldDefinition: ['directives', 'fieldType', 'arguments'], + EnumTypeDefinition: ['directives', 'values'] + } +}); diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index 56d028e5c629..679d045b890d 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -5247,6 +5247,16 @@ var a = "test2"; assert.strictEqual(messages.length, 0); }); + it("should not throw or return errors when the custom parser returns unknown AST nodes", () => { + const code = "foo && bar %% baz"; + + linter.defineParser("non-js-parser", testParsers.nonJSParser); + + const messages = linter.verify(code, { parser: "non-js-parser" }, filename, true); + + assert.strictEqual(messages.length, 0); + }); + it("should strip leading line: prefix from parser error", () => { linter.defineParser("line-error", testParsers.lineError); const messages = linter.verify(";", { parser: "line-error" }, "filename");