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

Proposed linting config updates #669

Closed
wants to merge 8 commits into from

Conversation

aoberoi
Copy link
Contributor

@aoberoi aoberoi commented Oct 18, 2020

Summary

This PR explores using a linting configuration that is different in a few key ways:

  • Less strict formatting rules, by removing Prettier. Another way of saying this is authors have more control of formatting. Rules related to best practices and finding logical and syntactical issues are just as strict, if not, more strict.
    • This should improve the behavior of editors (such as VSCode) by dramatically simplifying use of extensions/plugins. Prettier extensions will leave this codebase alone, and ESLint plugins will correct issues that have automatic fixers on save.
  • Fully commented to communicate the meaning and intention of rules. We want source authors to understand the benefit of the rules instead of feeling like they need to obey an arbitrary robot.
    • We'd like the rules to be accessible for discussing new opinions and ideas. That can only happen if the reasoning for existing rules is explained.
  • Generalized to work well on JavaScript, TypeScript, and mixed source codebases. Once this config has had time to bake in a single working codebase, like this one, the config can be extracted into its own package and applied to all JS/TS projects in slackapi.
  • Borrows as much as possible from well-considered community style guides such as AirBnB's JavaScript style guide, ESLint's recommended rules, Node.js recommended rules, JSDoc recommended rules
    • Applies new rules, or overrides existing rules, only when we have an opinion that differs for specific reasons.
  • Config is contained in one file, instead of spread out in several directories and files.
    • Structured using overrides to create an obvious space for additional tweaks based on their desired affects. For example, it's clear where to add new rules that only apply to TypeScript, new rules that apply to both TypeScript and JavaScript, or a rule configuration that overrides an existing rule from the above configs.

Disadvantages

The main disadvantage of this config is the loss of the indent rule within TypeScript. The author of the TypeScript-specific fork of that rule has decided not to maintain it any longer, and has acknowledged that the rule currently in a broken state. The author prefers to use Prettier in their own work, which relieved them of the need to work on that rule. But Prettier is highly opinionated as a formatter, and not nearly as configurable, so in this change we've made the tradeoff that this flexibility is worth the cost of not having a good indent rule in *.ts files.

The next largest disadvantage is lack of enforcement on JSDoc descriptions for all public API. This isn't a regression though, the current config also doesn't enforce this.

A few other rules are less than perfect, but those shortcomings have been described in the comments. Where possible, a link to relevant issues to watch have been added.

Feedback needed

The src/App.ts file was migrated to pass this config in order to aide discussion of this config. Please look at the changes in this one file, and let us know if any changes don't sit well with you. Feel free to be as opinionated or subjective as you want. Now is a good time to get aligned. After that, it should be relatively straight-forward to update the rest of the source files to pass.

  • One particular rule I'm not too sure about is the preference for default exports. It seems to go against the direction which React is now moving towards intentionally. I believe the reasoning is that named exports are more compatible across CommonJS and ESM module formats without any runtime/transpiler support. Should this matter to us?

Are any of the disadvantages dealbreakers?

TODO

  • Update config for *.spec.js and *.spec.ts files, to describe unique environment (mocha globals) and conventions.
  • Do we need any unique/specific rules for type-tests?
  • Migrate the existing sources files to satisfy these rules (besides src/App.ts). This should happen after other maintainers have offered feedback.
  • Update the npm scripts in package.json, re-enable format on save for VSCode in the settings.

Requirements (place an x in each [ ])

what if we remove dependency on Prettier, and solely rely on ESLint?

it seems we will lose some strictness in our enforcement, but possibly
gain a better development experience in this codebase. Prettier reprints
the entire program following its own style (subject to a few config options)
but its style is often subpar for our needs. it also can be tricky
for IDEs, extensions, and CI to integrate with. we've had our fair share
of issues and exploring this direction will allow us to understand what
we might gain and whether its worth it.
TODO: lint rules for test files (*.spec.ts)

starting off with some well considered and inherited rules. will
evaluate the impact of these rules on a file or two to see how well
they hold up.
there are still warnings in the file, and that's okay for now. we're
getting pretty close a good spot to collect feedback.
@gitwave gitwave bot added the untriaged label Oct 18, 2020
Copy link
Member

@stevengill stevengill left a comment

Choose a reason for hiding this comment

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

Did a first pass of the eslintrc and App.ts. Still need to run it locally.

.eslintrc.js Show resolved Hide resolved
// no reason we cannot adopt this syntax now.
// NOTE: The `@typescript-eslint/no-require-imports` rule can also achieve the same effect, but it is less
// configurable and only built to provide a migration path from TSLint.
'import/no-commonjs': ['error', {
Copy link
Member

Choose a reason for hiding this comment

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

can this rule still be overridden inline? I've seen a few places in our code that require('package.json'). Importing it instead breaks our dist

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good question! let me know if it breaks the dist after you try. not sure if this is what you've tried in the past, but i also updated the tsconfig.json to turn on the resolveJsonModule option. that might make the difference.

Copy link
Member

Choose a reason for hiding this comment

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

I used resolveJsonModule option last time I tried. Just pulled this locally and this issue exists. You can see it by running npm pack in your root directly (the command npm publish uses under the hood to build the archive). The package that is created is missing all of dist pretty much.

.eslintrc.js Show resolved Hide resolved

// Allow cyclical imports. Turning this rule on is mainly a way to manage the performance concern for linting
// time. Our projects are not large enough to warrant this. Overrides AirBnB styles.
'import/no-cycle': 'off',
Copy link
Member

Choose a reason for hiding this comment

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

I believe we have inline exceptions to this rule, but I'll have to look it up

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sounds like we can remove those inline exceptions then 🙌 . this is a good reminder that as we update the other sources for this config (item in the TODO) we should audit all the inline exceptions with a goal to remove as many as possible.

Copy link
Member

Choose a reason for hiding this comment

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

Last time I looked I didn't manage to remove the exceptions for this. We can take another spin this go around

.eslintrc.js Show resolved Hide resolved
src/App.ts Outdated Show resolved Hide resolved
(this.receiver as ExpressReceiver).installer !== undefined &&
(this.receiver as ExpressReceiver).installer!.authorize !== undefined
) {
if ((this.receiver as ExpressReceiver).installer !== undefined
Copy link
Member

Choose a reason for hiding this comment

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

this looks way better IMO

Copy link
Contributor Author

@aoberoi aoberoi Oct 20, 2020

Choose a reason for hiding this comment

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

thanks for the validation! humans: 1, prettier: 0. this takes a small manual effort and an eye for clarity, but i hope we all feel the result is worth it.

src/App.ts Show resolved Hide resolved
@@ -380,10 +367,11 @@ export default class App {
callbackIdOrConstraints: string | RegExp | Constraints,
...listeners: Middleware<SlackShortcutMiddlewareArgs<Extract<Shortcut, { type: Constraints['type'] }>>>[]
): void {
const constraints: ShortcutConstraints =
const constraints: ShortcutConstraints = (
Copy link
Member

Choose a reason for hiding this comment

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

I like that we are bringing back the round bracket to encapsulate the code below. I like this style better. Prettier removed them.

: type === IncomingEventType.Command
? ((body as SlackCommandMiddlewareArgs['body']).user_id as string)
: undefined,
const teamId: string = (() => {
Copy link
Member

Choose a reason for hiding this comment

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

This refactor is much easier to read and follow. Good stuff!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i'm pretty happy that there are a lot less type assertions this way!

import { Agent } from 'http';
import { SecureContextOptions } from 'tls';
import util from 'util';
import { WebClient, ChatPostMessageArguments, addAppMetadata, WebClientOptions } from '@slack/web-api';
import { Logger, LogLevel, ConsoleLogger } from '@slack/logger';
import axios, { AxiosInstance } from 'axios';
import allSettled from 'promise.allsettled';
Copy link
Member

Choose a reason for hiding this comment

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

I also want to add that I saw issues with removing require from allSettled last time too, but I don't remember what that issue was off the top of my head

@@ -0,0 +1,15 @@
import { WebClient, WebClientOptions } from '@slack/web-api';
Copy link
Member

Choose a reason for hiding this comment

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

I like this idea but how about doing this in another (smaller) pull request?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

its related to getting the lint rules to pass. the rule is max-classes-per-file. we could do this in a separate PR if we want to land it before this PR. otherwise this PR will be blocked on failing its own lint.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for sharing the context.

we could do this in a separate PR if we want to land it before this PR

I think there is no blocker for it. If we separate this change, we can quickly review and merge it. Also, if the change has issues by any chance, it's much easier to revert.

aoberoi added a commit to aoberoi/bolt that referenced this pull request Dec 14, 2020
Once we removed StringIndexed from SlackEvent types, many property lookups
became typechecking errors.

I borrowed this refactor mostly from a WIP PR to improve our style/linting
in a proactive effort to redue conflicts when that PR lands. The only
changes I needed to add were the Org Apps changes that had landed on main.

slackapi#669

In a few cases, the event types had other issues that became apparent only
after removing the aggressive casting we had before. Those are fixed.

It's now evident that there's more type related problems with respect to the Authorize, its related types, especially the OrgApps variants. I'll try to fix these next.

It's also not clear if buildSource needs the orgInstall argument. Will seek advice in code review for that.
@CLAassistant
Copy link

CLAassistant commented Feb 11, 2021

CLA assistant check
All committers have signed the CLA.

@seratch
Copy link
Member

seratch commented Mar 23, 2021

@stevengill will revisit this soon.

@seratch seratch added discussion M-T: An issue where more input is needed to reach a decision tests M-T: Testing work only TypeScript-specific and removed untriaged labels Mar 23, 2021
@seratch seratch added this to the 3.5.0 milestone Mar 23, 2021
@seratch seratch modified the milestones: 3.5.0, 4.0.0 Jun 5, 2021
filmaj added a commit that referenced this pull request Jul 29, 2021
…oving fully to eslint from tslint. All of these changes are courtesy of @aoberoi and the work they put into #669 🙇
@filmaj
Copy link
Contributor

filmaj commented Jul 29, 2021

Closing this in favour of #1024 - which is wholly based on the efforts in this PR. Thank you to everyone involved!

@filmaj filmaj closed this Jul 29, 2021
filmaj added a commit that referenced this pull request Jul 30, 2021
…oving fully to eslint from tslint. All of these changes are courtesy of @aoberoi and the work they put into #669 🙇
filmaj added a commit that referenced this pull request Aug 25, 2021
…oving fully to eslint from tslint. All of these changes are courtesy of @aoberoi and the work they put into #669 🙇
filmaj added a commit that referenced this pull request Aug 27, 2021
…oving fully to eslint from tslint. All of these changes are courtesy of @aoberoi and the work they put into #669 🙇
filmaj added a commit that referenced this pull request Aug 27, 2021
…oving fully to eslint from tslint. All of these changes are courtesy of @aoberoi and the work they put into #669 🙇
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion M-T: An issue where more input is needed to reach a decision tests M-T: Testing work only TypeScript-specific
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants