From 9248cec5a44adb46ba76a260c2bdd1579ef4b5b3 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 29 Mar 2019 18:54:51 +0900 Subject: [PATCH 1/5] New: Recoverable Error Handling --- .../2019-recoverable-error-handling/README.md | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 designs/2019-recoverable-error-handling/README.md diff --git a/designs/2019-recoverable-error-handling/README.md b/designs/2019-recoverable-error-handling/README.md new file mode 100644 index 00000000..7a67a0e4 --- /dev/null +++ b/designs/2019-recoverable-error-handling/README.md @@ -0,0 +1,121 @@ +- Start Date: 2019-03-29 +- RFC PR: (leave this empty, to be filled in later) +- Authors: Toru Nagashima <[@mysticatea](https://github.com/mysticatea)> + +# Recoverable Error Handling + +## Summary + +ESLint cannot verify source code if the code has a syntax error. However, we can make valid AST even if several kinds of syntax errors existed. For example, conflict of variable names doesn't break AST. This RFC calls such a syntax error as "Recoverable Errors". + +This RFC adds handling of [Recoverable Errors] into ESLint. + +## Motivation + +The goal of this RFC is that improve ESLint experience by reducing "fixing an error makes more errors." + +## Detailed Design + +### Handling [Recoverable Errors] in ESLint + +1. `Linter` class passes `parserOptions.recoverableErrors` option with `true` to `espree` or custom parsers. +1. If the object the parser returned has `recoverableErrors` property with an array, `Linter` class converts the errors to messages. + +Each element of `recoverableErrors` array has the following form. + +```jsonc +{ + "message": "Identifier 'foo' has already been declared", + "line": 1, // 1-based line number. + "column": 10, // 0-based column number. + "endLine": 1, // Optional. 1-based line number. + "endColumn": 13 // Optional. 0-based column number. +} +``` + +Then `Linter` class converts that to a message: + +```jsonc +{ + "fatal": false, + "ruleId": null, + "severity": 2, + "message": "Identifier 'foo' has already been declared", + "line": 1, // 1-based line number. + "column": 11, // 1-based column number. + "endLine": 1, // Optional. 1-based line number. + "endColumn": 14 // Optional. 1-based column number. +} +``` + +Directive comments such as `/*eslint-disable*/` cannot hide the messages of [Recoverable Errors]. + +### Handling [Recoverable Errors] in Espree + +Acorn, the underlying of `espree`, has `raiseRecoverable(pos, message)` method to customize handling of [Recoverable Errors]. + +If `options.recoverableErrors` was `true` then `espree` collects [Recoverable Errors] and returns the errors along with AST. Otherwise, `espree` throws syntax errors on [Recoverable Errors] as is currently. + +In `acorn@6.1.1`, there are the following [Recoverable Errors]: + +- "Comma is not permitted after the rest element" +- "Parenthesized pattern" +- "Redefinition of `__proto__` property" +- "Redefinition of property" +- "Binding XXX in strict mode" +- "Assigning to XXX in strict mode" +- "Argument name clash" +- "Export 'XXX' is not defined" +- "Multiple default clauses" +- "Identifier 'XXX' has already been declared" +- "Escape sequence in keyword XXX" +- "Invalid regular expression: /a regexp/: An error description" + +> https://github.com/acornjs/acorn/search?q=raiseRecoverable + +### Other parsers + +This RFC doesn't contain the update of custom parsers. But this section considers if some popular custom parsers can applicate this feature. + +- `babel-eslint`
+ I don't have enough knowledge about `babel-eslint` and [Recoverable Errors]. +- `@typescript-eslint/parser`
+ TypeScript parser parses source code loosely, then provides syntax/semantic errors by API along with AST. So currently `@typescript-eslint/parser` manually throws syntax errors if the parse result has syntax/semantic errors. Therefore, it can provide [Recoverable Errors]. +- `vue-eslint-parser`
+ It reports [HTML parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) and JavaScript syntax errors in `