Skip to content
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

feat: support 'latest' as ecmaVersion #3710

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions packages/parser/README.md
Expand Up @@ -53,7 +53,7 @@ interface ParserOptions {
jsx?: boolean;
globalReturn?: boolean;
};
ecmaVersion?: number;
ecmaVersion?: number | 'latest';

jsxPragma?: string | null;
jsxFragmentName?: string | null;
Expand Down Expand Up @@ -97,12 +97,13 @@ This options allows you to tell the parser if you want to allow global `return`

Default `2018`.

Accepts any valid ECMAScript version number:
Accepts any valid ECMAScript version number or `'latest'`:

- A version: es3, es5, es6, es7, es8, es9, es10, es11, ..., or
- A year: es2015, es2016, es2017, es2018, es2019, es2020, ...
- `latest`

The value **must** be a number - so do not include the `es` prefix.
When it's a version or a year, the value **must** be a number - so do not include the `es` prefix.

Specifies the version of ECMAScript syntax you want to use. This is used by the parser to determine how to perform scope analysis, and it affects the default

Expand Down
5 changes: 5 additions & 0 deletions packages/parser/tests/lib/parser.ts
Expand Up @@ -18,6 +18,11 @@ describe('parser', () => {
expect(() => parseForESLint(code, null)).not.toThrow();
});

it("parseForESLint() should work if options.ecmaVersion is `'latest'`", () => {
const code = 'const valid = true;';
expect(() => parseForESLint(code, { ecmaVersion: 'latest' })).not.toThrow();
});

it('parseAndGenerateServices() should be called with options', () => {
const code = 'const valid = true;';
const spy = jest.spyOn(typescriptESTree, 'parseAndGenerateServices');
Expand Down
12 changes: 9 additions & 3 deletions packages/scope-manager/src/ScopeManager.ts
Expand Up @@ -26,7 +26,7 @@ interface ScopeManagerOptions {
globalReturn?: boolean;
sourceType?: 'module' | 'script';
impliedStrict?: boolean;
ecmaVersion?: number;
ecmaVersion?: number | 'latest';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of letting this string trickle all the way down into here such that it needs to be handled differently - I think we should instead convert it to a number at the parser level.

This would be similar to what ESLint does for espree (they annoyingly do it within eslint itself...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handled latest in parser, used 1e8 like acorn and babel

}

class ScopeManager {
Expand Down Expand Up @@ -76,11 +76,17 @@ class ScopeManager {
return this.#options.impliedStrict === true;
}
public isStrictModeSupported(): boolean {
return this.#options.ecmaVersion != null && this.#options.ecmaVersion >= 5;
return (
this.#options.ecmaVersion === 'latest' ||
(this.#options.ecmaVersion != null && this.#options.ecmaVersion >= 5)
);
}

public isES6(): boolean {
return this.#options.ecmaVersion != null && this.#options.ecmaVersion >= 6;
return (
this.#options.ecmaVersion === 'latest' ||
(this.#options.ecmaVersion != null && this.#options.ecmaVersion >= 6)
);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions packages/scope-manager/src/analyze.ts
Expand Up @@ -82,6 +82,10 @@ const DEFAULT_OPTIONS: Required<AnalyzeOptions> = {
};

function mapEcmaVersion(version: EcmaVersion | undefined): Lib {
if (version === 'latest') {
return 'esnext';
}

Comment on lines +85 to +88
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need/want this check any more

if (version == null || version === 3 || version === 5) {
return 'es5';
}
Expand Down
Expand Up @@ -31,11 +31,18 @@ describe('ecma version mapping', () => {
it("should map to 'es2018' when undefined", () => {
expectMapping(undefined, 'es2018');
});

it("should map to 'esnext' when 'latest'", () => {
expectMapping('latest', 'esnext');
});
});

const fakeNode = {} as unknown as TSESTree.Node;

function expectMapping(ecmaVersion: number | undefined, lib: Lib): void {
function expectMapping(
ecmaVersion: number | undefined | 'latest',
lib: Lib,
): void {
(Referencer as jest.Mock).mockClear();
analyze(fakeNode, { ecmaVersion: ecmaVersion as EcmaVersion });
expect(Referencer).toHaveBeenCalledWith(
Expand Down
3 changes: 2 additions & 1 deletion packages/types/src/parser-options.ts
Expand Up @@ -17,7 +17,8 @@ type EcmaVersion =
| 2017
| 2018
| 2019
| 2020;
| 2020
| 'latest';
bradzacher marked this conversation as resolved.
Show resolved Hide resolved

type SourceType = 'script' | 'module';

Expand Down