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

Create an API to "seed" the parser with an existing program #1442

Closed
bradzacher opened this issue Jan 13, 2020 · 6 comments · Fixed by #3484
Closed

Create an API to "seed" the parser with an existing program #1442

bradzacher opened this issue Jan 13, 2020 · 6 comments · Fixed by #3484
Labels
enhancement New feature or request package: typescript-estree Issues related to @typescript-eslint/typescript-estree

Comments

@bradzacher
Copy link
Member

There are a number of tools (like fork-ts-checker-webpack-plugin) that already manage a TS program, and that would like to integrate with ESLint as well.

Unfortunately, right now our parser is a black box - we create and manage the Programs we use, and our APIs only accept a file path, and file contents as input.

This, brings a problem of wasted memory, because the tool and our parser both create separate Programs.

We should look into creating an API which would "seed" the parser with a given program, using that program instead of creating its own.

I'd imagine something along the lines of:

import { seedParser } from '@typescript-eslint/typescript-estree';
import { CLIEngine } from 'eslint';
import { getProgram } from './my/local/project';

function lint(filePath: string) {
  const program = getProgram();
  seedParser(program);
  const engine = new CLIEngine(eslintOptions);
  engine.executeOnFiles(filePath);
}

cc @johnnyreilly - for fork-ts-checker-webpack-plugin.

Slightly related: #774

@bradzacher bradzacher added enhancement New feature or request package: typescript-estree Issues related to @typescript-eslint/typescript-estree RFC labels Jan 13, 2020
@johnnyreilly
Copy link
Contributor

johnnyreilly commented Jan 13, 2020

cc @piotr-oles @phryneas

@Zerowalker
Copy link

would this allow a svelte preprocess to give the code to the typescript parser in eslint,
rather than just giving it to eslint directly (making it complaing cause it doesn't understand typescript)?

@bradzacher
Copy link
Member Author

@Zerowalker no, you misunderstand how eslint works. ESLint calls our parser to understand typescript code.
Without ESLint our parser is just a parser; a tool that produces an AST from code.

This change is so that tools like fork-ts-checker-webpack-plugin, which coordinate with typescript themselves, can pass us the data structures that they've already gotten from typescript so our parser doesn't have to do the same work, saving time and memory.

@Zerowalker
Copy link

Ah, don't understand it fully i think, but i think i somewhat get it.

Then offtopic, but if i want to send typescript data from something that's been processed,
(like svelte, basically extracting the parts that are javascript/typescript) and send them to the eslint typescript parser,
how would one do that, or rather where can i read up on it as this isn't the right place.

@bradzacher
Copy link
Member Author

When you lint a file, you call ESLint. Whether you lint a file via the CLI (npx eslint src), via your IDE with a plugin, or via webpack (with eslint-loader or fork-ts-checker-webpack-plugin), under the hood they all use exactly the same ESLint API.

If you have typescript code, you configure ESLint to use our parser via the parser field in your .eslintrc. This simply tells ESLint to use our parser, which understands TS, instead of their built-in parser, which doesn't. This doesn't change any of the underlying processing though - ESLint does exactly the same thing under the hood, just with a different parser.

Now if you configure our parser to provide type information via the parserOptions.project, then our parser will use a more advanced typescript API call to parse the file, which causes typescript to parse every file matched by your tsconfig, and generate type information for those files. This process is pretty expensive; it uses a lot of CPU time, and a lot of memory.

Now if you imagine a use case like FTSCWP; it has already done all of this expensive parsing using similar APIs. Right now, if you do a lint as part of a webpack build, then FTSCWP will do its parse, and our parser will do our parse. Probably one after the other, meaning you pay the time and memory cost of typechecking a TS project twice.

So imagine if we could take the result from FTSCWP, and share it with our parser? That's the point of this issue; creating an API in our parser so that you can require it, and give it the result before calling the ESLint API. That way when you call ESLint, the parser is "seeded", and has to do no parsing.


Onto your comment - the short answer is "not easily".
This is the problem with custom "almost js, but not quite js" frameworks; you need to build tooling to support them.
Vue has this problem as well in a big way.
React does not, because JSX is straight-forward syntactic sugar that's built into babel and typescript.

For vue there is a custom parser, which parses vue code, and produces AST fragments. When it encounters a <script> tag, it calls a second parser to handle the code (ofc for Vue TS code, this is configured to be our parser).
https://github.com/mysticatea/vue-eslint-parser

For svelte, there is an eslint-plugin, which uses a ESLint pre-processor to do a similar thing.
https://github.com/sveltejs/eslint-plugin-svelte3

The difference between the two solutions;

  • a parser converts code into an AST, which ESLint uses directly to do the linting.
  • a preprocessor converts code into fragments of code, which ESLint then parses as if they were individual files.

@bradzacher
Copy link
Member Author

Just a heads up - @uniqueiniquity just added an API to do this as a v0.
It does involve manipulating the parserOptions in the user's eslintrc - so it might not yet suit all usecases, but it's a good step in the right direction.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 9, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request package: typescript-estree Issues related to @typescript-eslint/typescript-estree
Projects
None yet
3 participants