-
Notifications
You must be signed in to change notification settings - Fork 943
eslint rules for firebase projects #1831
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
Is You can see what's implemented and what's not here. Also I recommend using eslint-config-prettier and eslint-plugin-prettier instead of defining style rules. Or if we do TSLint instead, there's TSLint versions of these two as well. Example here. |
For the tslint rules that are not available in I don't think we need to include any code formatting related rules in eslint, since it will be dealt with by prettier. I also don't want to fail compilation because of the formatting issue. |
That's exactly what these two do. One disables formatting related rules of ESLint and the other checks Prettier for formatting. So formatting will be dealt with by Prettier, but within ESLint. I think that would make things easier, since we wouldn't have to run two different scripts for prepush and CI tests.
It wouldn't fail compilation, it would fail tests. That's where my packages (messaging and installations) run linters. And I thought CI tests checked formatting already? Or is that only the prepush script?
That is true, but you can run fix / format on save in most editors (including VSCode, which is what I use). Anyway, I don't feel strongly about any of these, just my two cents. |
config/.eslintrc.json
Outdated
"error", | ||
"as-needed", | ||
{ | ||
"requireReturnForObjectLiteral": true |
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.
But why? 😞 I always tell people that they can do () => ({ ... })
in readability reviews.
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 was confused by the syntax the first time when I saw it, but I don't feel strongly about it.
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.
After going through Firestore errors, we are not a fan of "arrow-body-style" at all. We have 566 violations.
Some of them would be fine to change (though unclear benefit), but some would be worse. For example, it would cause all of our tests to change from, e.g.:
it('can set documents', () => {
return integrationHelpers.withTestDoc(persistence, doc => {
return doc.firestore
.batch()
.set(doc, { foo: 'bar' })
.commit()
.then(() => doc.get())
.then(snapshot => {
expect(snapshot.exists).to.equal(true);
expect(snapshot.data()).to.deep.equal({ foo: 'bar' });
});
});
});
to:
it('can set documents', () =>
integrationHelpers.withTestDoc(persistence, doc =>
doc.firestore
.batch()
.set(doc, { foo: 'bar' })
.commit()
.then(() => doc.get())
.then(snapshot => {
expect(snapshot.exists).to.equal(true);
expect(snapshot.data()).to.deep.equal({ foo: 'bar' });
})
));
We are not in favor of this, since:
- We think braces can be a useful tool when coding for denoting long blocks of code (even if it's just chaining method calls).
- [quoting @wilhuff] Any multiline block that currently contains a single return statement can end up with multiple statements easily. Refactoring the extra statements in is error prone. This is why we require braces around if statements
So I'd advocate for removing this rule at the Firebase level. And if we keep it, we (Firestore) will likely decide to disable it.
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.
Replaced this rule with tslint "arrow-return-shorthand": true
which is currently enabled in firestore.
It enforces arrow function shorthand, but will ignore functions that span multiple lines (this option is not available in the eslint rule arrow-body-style
).
config/.eslintrc.json
Outdated
], | ||
"curly": [ | ||
"error", | ||
"multi-line" |
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.
Even though it's a bit stricter than Google TS style (doesn't allow braceless single line if), I vote for "all"
.
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'd be fine with "all". I'm leaving it unresolved for a couple of days to see if anyone objects.
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.
Firestore is a fan of "all" too, thought this will probably create some violations since currently we allow no braces iff the statement is on the same line as the if, e.g.:
if (result.skip) continue;
Looks like eslint doesn't have a similar configuration, so we'll probably lose that... but I think that's okay.
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.
Changed to "all"
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 putting this together! I'm mostly on board but there are a couple rules causing me some concern. :-)
packages/firestore/package.json
Outdated
@@ -8,6 +8,7 @@ | |||
"build:console": "node tools/console.build.js", | |||
"dev": "rollup -c -w", | |||
"lint": "tslint -p tsconfig.json -c tslint.json 'src/**/*.ts' 'test/**/*.ts'", | |||
"lint:eslint": "eslint -c .eslintrc.json '**/*.ts'", |
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.
It looks like we need to exclude "dist" somehow.
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.
Added the --ignore-path ../../.gitignore
config/.eslintrc.json
Outdated
"@typescript-eslint/no-unused-vars": [ | ||
"error", | ||
{ | ||
"varsIgnorePattern": "^_*$" |
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'm not sure if this is working... For Firestore I'm seeing some errors like:
/Users/mikelehen/src/firebase-js-sdk/packages/firestore/src/local/memory_persistence.ts
...
357:60 error '_' is defined but never used @typescript-eslint/no-unused-vars
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.
Added "argsIgnorePattern": "^_"
.
I didn't realize argsIgnorePattern
and varsIgnorePattern
are 2 different options util now. :(
"allowExpressions": true | ||
} | ||
], | ||
"@typescript-eslint/no-unused-vars": [ |
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.
FWIW- Looking through the Firestore errors, this is the other rule we run into a lot. Our current tslint rules prevent unused variables but allow unused arguments, and we have a lot of violations (~170 though some of those are for _
, see below), and the ones I've looked at are mostly intentional... Basically there are many places where a function is implementing some contract and we want the function signature to convey the contract, even if the function implementation doesn't need everything provided by the contract.
As a simple example:
return documentsStore
.iterate((key, doc) => {
const path = new ResourcePath(key);
...
});
Here, It so happens that doc
isn't needed, but the iterate function will be passed 'key' and 'doc', and it would be confusing to make it look like it's not!
We also have various interfaces with multiple implementations, and not all implementations need all the function arguments provided... but it's still worth explicitly conforming to the contract.
We could suppress all of these, but I wouldn't be excited about adding that kind of clutter... So I would suggest that we make the ignore pattern be something like "^_"
and then change all of the intentionally unused parameters to just be prefixed with an underscore, e.g. "_doc" above. That way we can keep the rule, but cleanly mark all the intentional ones without it being too awkward.
WDYT?
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.
Yes! That's the intention, but I made a mistake in the regex (I meant to have ^_.*$
). Update the regex to "^_".
config/.eslintrc.json
Outdated
"error", | ||
"as-needed", | ||
{ | ||
"requireReturnForObjectLiteral": true |
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.
After going through Firestore errors, we are not a fan of "arrow-body-style" at all. We have 566 violations.
Some of them would be fine to change (though unclear benefit), but some would be worse. For example, it would cause all of our tests to change from, e.g.:
it('can set documents', () => {
return integrationHelpers.withTestDoc(persistence, doc => {
return doc.firestore
.batch()
.set(doc, { foo: 'bar' })
.commit()
.then(() => doc.get())
.then(snapshot => {
expect(snapshot.exists).to.equal(true);
expect(snapshot.data()).to.deep.equal({ foo: 'bar' });
});
});
});
to:
it('can set documents', () =>
integrationHelpers.withTestDoc(persistence, doc =>
doc.firestore
.batch()
.set(doc, { foo: 'bar' })
.commit()
.then(() => doc.get())
.then(snapshot => {
expect(snapshot.exists).to.equal(true);
expect(snapshot.data()).to.deep.equal({ foo: 'bar' });
})
));
We are not in favor of this, since:
- We think braces can be a useful tool when coding for denoting long blocks of code (even if it's just chaining method calls).
- [quoting @wilhuff] Any multiline block that currently contains a single return statement can end up with multiple statements easily. Refactoring the extra statements in is error prone. This is why we require braces around if statements
So I'd advocate for removing this rule at the Firebase level. And if we keep it, we (Firestore) will likely decide to disable it.
config/.eslintrc.json
Outdated
], | ||
"curly": [ | ||
"error", | ||
"multi-line" |
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.
Firestore is a fan of "all" too, thought this will probably create some violations since currently we allow no braces iff the statement is on the same line as the if, e.g.:
if (result.skip) continue;
Looks like eslint doesn't have a similar configuration, so we'll probably lose that... but I think that's okay.
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! I'm happy with where this has landed.
Create the base eslint rules for firebase projects. We will apply it to all repos eventually.
As the first step, we need to agree on the set of rules, so feedback is welcomed.
I have run this set of rules against all projects, and there are about 4000 issues. Given the large number of issues, we will enable the eslint rules for project one by one in a few followup PRs.
The set of rules derives from the google tslint rules. I made a document to show what rules from google tslint rules are included/excluded and what additional rules are included in this PR.