New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change Request: provide option to allow parsing specific ES3 reserved words #15327
Comments
I’m not sure we want to add an option that is only relevant when ecmaVersion is 3. That seems like a recipe for confusion. Reverting to previous behavior is an option, but would be a breaking change and would also not fulfill the goal of the change: to provide a strict ES3 parser. @ljharb since it seems like you are doing some regular IE6 testing, can you get us a list of reserved words that do throw an error? |
TSC Summary:* In v8.0, we changed the behavior of ecmaVersion:3 to forbid reserved words. IE 6 actually allows some (or all) reserved words to be used. This request is to provide a looser ES3 variant for such purposes. TSC Question: How do we want to address this? |
My thinking was that it would apply to every ecmaVersion, to ensure it was generic and wouldn’t need attending to in the future. I’ll certainly check IE 6-8, and a few other ES3 browsers, and report back with a list. As for the goal: what value is there In a strict ES3 parser if no accessible engine actually implements it? My hope would be for a strict “matches implementations” parser, for as many implementation tranches as were practical. |
I ran this jsbin: https://jsbin.com/zihosuh/edit?js,output populated with this info: https://mathiasbynens.be/notes/reserved-keywords via this link: https://output.jsbin.com/zihosuh and got these results: IE 6es2: int (var) es2: int (prop) es2: int (fn) es2: byte (var) es2: byte (prop) es2: byte (fn) es2: char (var) es2: char (prop) es2: char (fn) es2: goto (var) es2: goto (prop) es2: goto (fn) es2: long (var) es2: long (prop) es2: long (fn) es2: final (var) es2: final (prop) es2: final (fn) es2: float (var) es2: float (prop) es2: float (fn) es2: short (var) es2: short (prop) es2: short (fn) es2: double (var) es2: double (prop) es2: double (fn) es2: native (var) es2: native (prop) es2: native (fn) es2: public (var) es2: public (prop) es2: public (fn) es2: static (var) es2: static (prop) es2: static (fn) es2: throws (var) es2: throws (prop) es2: throws (fn) es2: boolean (var) es2: boolean (prop) es2: boolean (fn) es2: package (var) es2: package (prop) es2: package (fn) es2: private (var) es2: private (prop) es2: private (fn) es2: abstract (var) es2: abstract (prop) es2: abstract (fn) es2: volatile (var) es2: volatile (prop) es2: volatile (fn) es2: interface (var) es2: interface (prop) es2: interface (fn) es2: protected (var) es2: protected (prop) es2: protected (fn) es2: transient (var) es2: transient (prop) es2: transient (fn) es2: implements (var) es2: implements (prop) es2: implements (fn) es2: synchronized (var) es2: synchronized (prop) es2: synchronized (fn) es5: eval (var)IE 7es2: int (var) es2: int (prop) es2: int (fn) es2: byte (var) es2: byte (prop) es2: byte (fn) es2: char (var) es2: char (prop) es2: char (fn) es2: goto (var) es2: goto (prop) es2: goto (fn) es2: long (var) es2: long (prop) es2: long (fn) es2: final (var) es2: final (prop) es2: final (fn) es2: float (var) es2: float (prop) es2: float (fn) es2: short (var) es2: short (prop) es2: short (fn) es2: double (var) es2: double (prop) es2: double (fn) es2: native (var) es2: native (prop) es2: native (fn) es2: public (var) es2: public (prop) es2: public (fn) es2: static (var) es2: static (prop) es2: static (fn) es2: throws (var) es2: throws (prop) es2: throws (fn) es2: boolean (var) es2: boolean (prop) es2: boolean (fn) es2: package (var) es2: package (prop) es2: package (fn) es2: private (var) es2: private (prop) es2: private (fn) es2: abstract (var) es2: abstract (prop) es2: abstract (fn) es2: volatile (var) es2: volatile (prop) es2: volatile (fn) es2: interface (var) es2: interface (prop) es2: interface (fn) es2: protected (var) es2: protected (prop) es2: protected (fn) es2: transient (var) es2: transient (prop) es2: transient (fn) es2: implements (var) es2: implements (prop) es2: implements (fn) es2: synchronized (var) es2: synchronized (prop) es2: synchronized (fn) es5: eval (var)IE 8es2: int (var) es2: int (prop) es2: int (fn) es2: byte (var) es2: byte (prop) es2: byte (fn) es2: char (var) es2: char (prop) es2: char (fn) es2: goto (var) es2: goto (prop) es2: goto (fn) es2: long (var) es2: long (prop) es2: long (fn) es2: final (var) es2: final (prop) es2: final (fn) es2: float (var) es2: float (prop) es2: float (fn) es2: short (var) es2: short (prop) es2: short (fn) es2: double (var) es2: double (prop) es2: double (fn) es2: native (var) es2: native (prop) es2: native (fn) es2: public (var) es2: public (prop) es2: public (fn) es2: static (var) es2: static (prop) es2: static (fn) es2: throws (var) es2: throws (prop) es2: throws (fn) es2: boolean (var) es2: boolean (prop) es2: boolean (fn) es2: package (var) es2: package (prop) es2: package (fn) es2: private (var) es2: private (prop) es2: private (fn) es2: abstract (var) es2: abstract (prop) es2: abstract (fn) es2: volatile (var) es2: volatile (prop) es2: volatile (fn) es2: interface (var) es2: interface (prop) es2: interface (fn) es2: protected (var) es2: protected (prop) es2: protected (fn) es2: transient (var) es2: transient (prop) es2: transient (fn) es2: implements (var) es2: implements (prop) es2: implements (fn) es2: synchronized (var) es2: synchronized (prop) es2: synchronized (fn) es5: eval (var)FF 3es1: do (prop) es1: do (fn) es1: if (prop) es1: if (fn) es1: in (prop) es1: in (fn) es1: for (prop) es1: for (fn) es1: new (prop) es1: new (fn) es1: try (prop) es1: try (fn) es1: var (prop) es1: var (fn) es1: case (prop) es1: case (fn) es1: else (prop) es1: else (fn) es1: enum (var) es1: enum (prop) es1: enum (fn) es1: null (prop) es1: null (fn) es1: this (prop) es1: this (fn) es1: true (prop) es1: true (fn) es1: void (prop) es1: void (fn) es1: with (prop) es1: with (fn) es1: break (prop) es1: break (fn) es1: catch (prop) es1: catch (fn) es1: class (var) es1: class (prop) es1: class (fn) es1: const (prop) es1: const (fn) es1: false (prop) es1: false (fn) es1: super (var) es1: super (prop) es1: super (fn) es1: throw (prop) es1: throw (fn) es1: while (prop) es1: while (fn) es1: delete (prop) es1: delete (fn) es1: export (prop) es1: export (fn) es1: import (prop) es1: import (fn) es1: return (prop) es1: return (fn) es1: switch (prop) es1: switch (fn) es1: typeof (prop) es1: typeof (fn) es1: default (prop) es1: default (fn) es1: extends (var) es1: extends (prop) es1: extends (fn) es1: finally (prop) es1: finally (fn) es1: continue (prop) es1: continue (fn) es1: debugger (prop) es1: debugger (fn) es1: function (prop) es1: function (fn) es2: do (prop) es2: do (fn) es2: if (prop) es2: if (fn) es2: in (prop) es2: in (fn) es2: for (prop) es2: for (fn) es2: int (var) es2: int (prop) es2: int (fn) es2: new (prop) es2: new (fn) es2: try (prop) es2: try (fn) es2: var (prop) es2: var (fn) es2: byte (var) es2: byte (prop) es2: byte (fn) es2: case (prop) es2: case (fn) es2: char (var) es2: char (prop) es2: char (fn) es2: else (prop) es2: else (fn) es2: enum (var) es2: enum (prop) es2: enum (fn) es2: goto (var) es2: goto (prop) es2: goto (fn) es2: long (var) es2: long (prop) es2: long (fn) es2: null (prop) es2: null (fn) es2: this (prop) es2: this (fn) es2: true (prop) es2: true (fn) es2: void (prop) es2: void (fn) es2: with (prop) es2: with (fn) es2: break (prop) es2: break (fn) es2: catch (prop) es2: catch (fn) es2: class (var) es2: class (prop) es2: class (fn) es2: const (prop) es2: const (fn) es2: false (prop) es2: false (fn) es2: final (var) es2: final (prop) es2: final (fn) es2: float (var) es2: float (prop) es2: float (fn) es2: short (var) es2: short (prop) es2: short (fn) es2: super (var) es2: super (prop) es2: super (fn) es2: throw (prop) es2: throw (fn) es2: while (prop) es2: while (fn) es2: delete (prop) es2: delete (fn) es2: double (var) es2: double (prop) es2: double (fn) es2: export (prop) es2: export (fn) es2: import (prop) es2: import (fn) es2: native (var) es2: native (prop) es2: native (fn) es2: public (var) es2: public (prop) es2: public (fn) es2: return (prop) es2: return (fn) es2: static (var) es2: static (prop) es2: static (fn) es2: switch (prop) es2: switch (fn) es2: throws (var) es2: throws (prop) es2: throws (fn) es2: typeof (prop) es2: typeof (fn) es2: boolean (var) es2: boolean (prop) es2: boolean (fn) es2: default (prop) es2: default (fn) es2: extends (var) es2: extends (prop) es2: extends (fn) es2: finally (prop) es2: finally (fn) es2: package (var) es2: package (prop) es2: package (fn) es2: private (var) es2: private (prop) es2: private (fn) es2: abstract (var) es2: abstract (prop) es2: abstract (fn) es2: continue (prop) es2: continue (fn) es2: debugger (prop) es2: debugger (fn) es2: function (prop) es2: function (fn) es2: volatile (var) es2: volatile (prop) es2: volatile (fn) es2: interface (var) es2: interface (prop) es2: interface (fn) es2: protected (var) es2: protected (prop) es2: protected (fn) es2: transient (var) es2: transient (prop) es2: transient (fn) es2: implements (var) es2: implements (prop) es2: implements (fn) es2: instanceof (prop) es2: instanceof (fn) es2: synchronized (var) es2: synchronized (prop) es2: synchronized (fn) es5: do (prop) es5: do (fn) es5: if (prop) es5: if (fn) es5: in (prop) es5: in (fn) es5: for (prop) es5: for (fn) es5: new (prop) es5: new (fn) es5: try (prop) es5: try (fn) es5: var (prop) es5: var (fn) es5: case (prop) es5: case (fn) es5: else (prop) es5: else (fn) es5: enum (var) es5: enum (prop) es5: enum (fn) es5: eval (var)Safari 4es2: int (var) es2: int (prop) es2: int (fn) es2: byte (var) es2: byte (prop) es2: byte (fn) es2: char (var) es2: char (prop) es2: char (fn) es2: goto (var) es2: goto (prop) es2: goto (fn) es2: long (var) es2: long (prop) es2: long (fn) es2: final (var) es2: final (prop) es2: final (fn) es2: float (var) es2: float (prop) es2: float (fn) es2: short (var) es2: short (prop) es2: short (fn) es2: double (var) es2: double (prop) es2: double (fn) es2: native (var) es2: native (prop) es2: native (fn) es2: public (var) es2: public (prop) es2: public (fn) es2: static (var) es2: static (prop) es2: static (fn) es2: throws (var) es2: throws (prop) es2: throws (fn) es2: boolean (var) es2: boolean (prop) es2: boolean (fn) es2: package (var) es2: package (prop) es2: package (fn) es2: private (var) es2: private (prop) es2: private (fn) es2: abstract (var) es2: abstract (prop) es2: abstract (fn) es2: volatile (var) es2: volatile (prop) es2: volatile (fn) es2: interface (var) es2: interface (prop) es2: interface (fn) es2: protected (var) es2: protected (prop) es2: protected (fn) es2: transient (var) es2: transient (prop) es2: transient (fn) es2: implements (var) es2: implements (prop) es2: implements (fn) es2: synchronized (var) es2: synchronized (prop) es2: synchronized (fn) es5: eval (var)In other words, all of these are things that are reserved, and should be failing, but actually do work - and I think it's reasonable for eslint to parse them. The spec is only fiction unless implementations follow it - when every implementation does something different from the spec, TC39 changes the spec to match reality. |
In the 2021-11-18 TSC meeting, we agreed to add an |
Following up on @ljharb’s Discord message. The changes actually need to happen in Espree. You’d want to check that if allowReserved is present that ecmaVersion is 3 in this function (otherwise throw error): Down below you can set the value of allowReserved: https://github.com/eslint/espree/blob/ed95791c0d9334383ddf59ae0d0968842801c171/lib/options.js#L95 And a couple of tests here: https://github.com/eslint/espree/blob/main/tests/lib/options.js |
Oh and don’t forget to update the README with the new option. |
Thanks! Filed eslint/espree#522, please review :-) |
* feat: add `allowReserved` parser option Fixes #15327 * update package.json
ESLint version
v8.2.0
What problem do you want to solve?
#15017 was great in spirit - I agreed with it - but my agreement assumed that
was the case. I can't speak for
char
, because I don't use that anywhere - but I do use.native
andint
as identifiers/property names, and these work perfectly fine in everyone's favorite ES3 engine, IE 6 (and presumably in many of the others). I use.native
in the runtime code path ofresolve
, which has extensive usage, so I'm pretty confident it doesn't actually throw a runtime error anywhere that matters.This parsing error means I can't upgrade to eslint 8 on
resolve
ores-abstract
(so far; i've only tested a dozen or two out of my ~350 packages) without making an undesirable and unnecessary code change.What do you think is the correct solution?
Add a parserOption that allows specific reserved words to parse as identifiers or property names anyways (it could apply to any ecmaVersion). This would be a generic escape hatch, that would allow anyone to lint code that works on what most implementations are: not precisely matching any arbitrary spec edition.
I tried adding
parserOptions.allowReserved: true
, but this doesn't seem to do it.Participation
Additional comments
Sorry for not realizing this would be the consequence sooner :-)
The text was updated successfully, but these errors were encountered: