-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Improvements for eslint (and try switching to prettier) #3647
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
Conversation
editors/code/src/inlay_hints.ts
Outdated
| if (!hints) return; | ||
| // eslint-disable-next-line @typescript-eslint/no-misused-promises | ||
| this.sourceFiles.forEach((file, uri) => | ||
| this.fetchHints(file).then(hints => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| this.fetchHints(file).then(hints => { | |
| void this.fetchHints(file).then(hints => { |
Does this silence the misused promises error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it might. I'll have to check that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using void did work there.
| } | ||
|
|
||
| export const log = new class { | ||
| export const log = new (class { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh, the rule that requires parentheses for new calls...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah that one is ugly. I'll try to disable it.
Veetaha
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the cleanup! Left some arguments, tho...
editors/code/src/ctx.ts
Outdated
| } | ||
|
|
||
| registerCommand(name: string, factory: (ctx: Ctx) => Cmd) { | ||
| registerCommand<T extends unknown[]>(name: string, factory: (ctx: Ctx) => Cmd<T>): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strongly-typing the Cmd doesn't give us many benefits but gives only increased verbosity and repetition (the passed parameters tuple type just unnecessarily duplicates the type of lambda parameters in command handlers). VSCode doesn't provide the strongly-typed interface for commands so we won't get compile errors for them. This is actually one of the rare cases where we should use any as the function parameters type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And if I could, I'd remove this interface from return types and rely on type inference, so we don't cast strongly-typed lambdas to type-erased Cmd, e.g.:
function createCmdHandler(): Cmd {
return (a: number, b: string) => { /**/ }
}
createCmdHandler()(null, null); // gives no errorvs when infered
function createCmdHandler() {
return (a: number, b: string) => { /* */ }
}
createCmdHandler()(null, null); // compile errorThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't disagree with your thoughts about the strongly typed Cmd. In fact, I agree it doesn't really add much in practice and I almost didn't include this change.
I just really kind of dislike using any. It often seems harmless but can lead to surprising and unfortunate bugs from time to time. I suppose if it's just for the definition of Cmd and it only needs the one use of // eslint-disable @typescript-eslint/no-explicit-any, it's not so bad.
One option which might be acceptable would be to just remove the type annotations from the lambda arguments and only specify them in T for Cmd<T>. That way we don't need any, we don't lose any type information (argument types are still inferrable), and it's in the end not much more verbose.
Example:
export function showReferences(ctx: Ctx): Cmd<[string, lc.Position, lc.Location[]]> {
return (uri: string, position: lc.Position, locations: lc.Location[]): void => {would look like
export function showReferences(ctx: Ctx): Cmd<[string, lc.Position, lc.Location[]]> {
return (uri, position, locations): void => {What do you think? If you prefer, I can still switch back to any.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I am glad, I found one more like-minded person who is passionate about static typing. I do think that any always leads to bugs. I wish all the typescript code avoided it.
However, it is unavoidable in your code due to someone's bad design decisions (e.g. #3629 (comment), and untyped vscode commands api just forces you to deal with any) and bad language design (e.g. catch error variable is always of any type and there is even no way to redefine it to unknown, but I am getting too far...).
Though I do like relying on return type inference, not everyone likes it. So, in this case, your proposal does seem viable, so we do get rid of the dreaded any at least in our code.
| const random = randomU32Numbers(hashString(seed)); | ||
| const randomInt = (min: number, max: number) => { | ||
| return Math.abs(random()) % (max - min + 1) + min; | ||
| const randomInt = (min: number, max: number): number => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do like TypeScript for not forcing you to write types here and there so that the code is very concise but it still provides you with the strong static typing guarantees.
I'd actually even remove all the return type declarations if I had enough impudence, but I'd suggest at least disabling the rule for arrow functions. @matklad ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I can disable that. I agree it can be a bit much.
| function request<TParams, TResult>(method: string) { | ||
| function request<TParams, TResult>( | ||
| method: string, | ||
| ): lc.RequestType<TParams, TResult, unknown, never> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, the verbosity...
| // Or the ability to disable the serverside component of highlighting (but this means that to do tracing we need to disable hihlighting) | ||
| // This also requires considering our settings strategy, which is work which needs doing | ||
| // @ts-ignore The tracer is private to vscode-languageclient, but we need access to it to not log publishDecorations requests | ||
| res._tracer = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One way to avoid ts-ignore here at all is
| res._tracer = { | |
| res['_tracer'] = { |
but ts-ignore kinda brings your attention to the fact that this is a hack.
| DocumentSemanticsTokensSignature, | ||
| } from 'vscode-languageclient/lib/semanticTokens.proposed'; | ||
|
|
||
| export async function createClient(config: Config, serverPath: string): Promise<lc.LanguageClient> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch!
| "If you feel that your platform should be supported, please create an issue " + | ||
| "about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we " + | ||
| "will consider it." | ||
| 'You need to manually clone rust-analyzer repository and ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This indentation us unfortunate ;( ...
|
I made some changes to the formatting based on your feedback:
I had to leave the Same for multi-line operator expressions. I just used |
|
We intentionally use build-in VS Code formatter over prettier |
|
Thought which has not occurred to me before: it probably makes sense to just copy-paste config from https://github.com/Microsoft/vscode-languageserver-node/ |
| "@typescript-eslint" | ||
| plugins: ['@typescript-eslint'], | ||
| extends: [ | ||
| 'eslint:recommended', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We intentionally don't use recommended: #3041
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use it, but the irrelevant rules are explicitly turned off down bellow.
Could you please elaborate on this, @matklad ? |
|
"built in" in my opinion outweighs any benefits of prettier. |
|
Hmm, I don't use any VSCode formatter, I just run |
|
If you would rather not merge this PR because you find the use of recommended eslint rules or the prettier formatting rules too onerous, that's okay. If you would like me to split out some of the other changes made, I can do that too. Otherwise I'm happy to close this out.
@matklad the built-in formatter seems reasonable but it still looks like |
|
Yeah, I just prefer to keep the nodejs side of things as simple as possible, and generally try to stray away from extra tooling. Given the size of the TypeScript codebase, we are not at the point where complex non-built-in tooling makes sense, imo. |
This PR modifies the
eslintconfig to extend default rules for the base linter and the@typescript-eslintplugin, and then it switch fromtsfmttoprettierand integratesprettierinto theeslintconfig. This way, formatting issues now show up as linter issues.I also fixed the lints reported by the stricter config and finally ran
prettieron the output.I don't know if y'all really want to switch from
tsfmttoprettierbut I figured I'd give it a try. One reason to consider switching, aside from the eslint integration, is it looks like thetsfmtrepository may not be maintained anymore (https://github.com/vvakame/typescript-formatter).