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
Update: Add configurability to generator star spacing #8985
Update: Add configurability to generator star spacing #8985
Conversation
Thanks for the pull request, @EthanRutherford! I took a look to make sure it's ready for merging and found some changes are needed:
Can you please update the pull request to address these? (More information can be found in our pull request guide.) |
@EthanRutherford, thanks for your PR! By analyzing the history of the files in this pull request, we identified @not-an-aardvark, @btmills and @mysticatea to be potential reviewers. |
d5b8788
to
d1eddb2
Compare
LGTM |
docs/rules/generator-star-spacing.md
Outdated
@@ -85,7 +104,7 @@ Examples of **correct** code for this rule with the `"before"` option: | |||
/*eslint generator-star-spacing: ["error", {"before": true, "after": false}]*/ | |||
/*eslint-env es6*/ | |||
|
|||
function *generator() {} | |||
function *generator() {}; |
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.
nitpick: I don't think these semi are necessary.
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.
True enough.. I added them for consistency, though I realize now that these didn't have them before because they're function declarations.
LGTM |
d3416fc
to
f4286f0
Compare
LGTM |
f4286f0
to
bcd64ee
Compare
LGTM |
Could I get some review on this? |
Hi, sorry about the lack of a response here. I think the holdup is mainly because #8918 is not accepted yet (it still has the "evaluating" label). We generally accept enhancements only after the team reaches consensus that they should be added (by having 3 👍s from team members on the issue, and having one team member willing to champion the proposal). The goal of this is to only accept enhancements that are clearly justified and generally useful (in order to ensure ESLint is maintainable in the long term, we can't accept all enhancements that people propose). Unfortunately, this does sometimes slow down the process of accepting enhancements. |
Ah, I see. Well, hopefully we can get some more eyes on the issue soon. I think it's a pretty important enhancement, as the core of the issue is a conflict between the current implementation of |
Marking this PR as accepted because the corresponding issue has reached consensus. |
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.
Some nitpicks about the documentation, otherwise LGTM. Thanks!
docs/rules/generator-star-spacing.md
Outdated
@@ -75,6 +75,25 @@ An example of shorthand configuration: | |||
"generator-star-spacing": ["error", "after"] | |||
``` | |||
|
|||
Additionally, this rule allows further configurability via overrides per function 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.
Could this line end with a punctuation mark (either period/full stop or colon)?
docs/rules/generator-star-spacing.md
Outdated
@@ -137,6 +156,27 @@ var anonymous = function*() {}; | |||
var shorthand = { *generator() {} }; | |||
``` | |||
|
|||
Examples of **correct** code for this rule with overrides present |
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.
Could this line end with a colon?
LGTM |
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 pull request! I left some comments.
docs/rules/generator-star-spacing.md
Outdated
@@ -137,6 +156,27 @@ var anonymous = function*() {}; | |||
var shorthand = { *generator() {} }; | |||
``` | |||
|
|||
Examples of **correct** code for this rule with overrides present: |
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.
Can you add examples of incorrect code with the overrides?
docs/rules/generator-star-spacing.md
Outdated
* `named` provides overrides for named functions | ||
* `anonymous` provides overrides for anonymous functions | ||
* `method` provides overrides for class methods or property function shorthand | ||
* `static` provides overrides for static class methods |
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 noticed there's an additional option for static
here, which wasn't in the original proposal in #8918. I'm wondering if that design is the best choice. static
methods are also methods, so it seems like this could cause confusion if someone configures the method
option. Additionally, it seems like this could create the need for several more options when async generators are introduced (e.g. will we have asyncStatic
as well as asyncMethod
?)
At the moment I'm thinking the static
option should be left out for now and combined with method
unless there's a compelling need for it, but I'm open to discussion on this.
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 included it simply because it is, technically, its own distinct case. I could imagine someone wishing to have methods as
class Foo {
...
*method() {}
}
but static methods as
class Bar {
...
static* method() {}
}
I don't necessarily feel strongly about it, however.
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 possible solution would be to support "static" as an override to the "method" override.. an override of an override. Starts to make the schema pretty complex, though.
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.
Given that the "before"
option is currently ignored for methods anyway, could we just not ignore it for static methods? That way people can use the method
option for both.
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 opposed, though the case I described above would not be possible. I don't expect to see anyone necessarily asking for that specific combination of configs, so we can probably ignore that.
docs/rules/generator-star-spacing.md
Outdated
"anonymous": "neither", | ||
"method": "neither", | ||
"static": {"before": true, "after": 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.
Can you update the documentation to explain what this configuration does? In particular, I'm unsure about what happens when "before"
and "after"
are used as top-level options alongside the more configurable options.
lib/rules/generator-star-spacing.js
Outdated
after: { type: "boolean" } | ||
}, | ||
additionalProperties: false | ||
} |
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.
Nitpick: This schema is repeated several times. Can you extract the object into a constant?
const SPECIFIC_CONFIG_SCHEMA = {
oneOf: [
// ...
]
};
lib/rules/generator-star-spacing.js
Outdated
return typeof option === "string" ? optionDefinitions[option] : { | ||
before: "before" in option ? option.before : defaults.before, | ||
after: "after" in option ? option.after : defaults.after | ||
}; |
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.
Nitpick: I think this line would be more readable if it used Object.assign
:
return typeof option === "string"
? optionDefinitions[options]
: Object.assign({}, defaults, option);
{ | ||
code: "class Foo { * foo(){} }", | ||
options: [{ before: false, after: false, method: "both" }] | ||
}, |
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.
Can you add tests for a method on an object?
({ *foo() {} })
{ | ||
code: "class Foo { static * foo(){} }", | ||
options: [{ before: false, after: false, static: "both" }] | ||
}, |
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.
Can you add tests where a specific override is used in object form (e.g. named: {before: true, after: false}
)?
{ | ||
code: "class Foo { static * foo(){} }", | ||
options: [{ before: false, after: false, static: "both" }] | ||
}, |
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.
Can you add tests where an override is used, but that override doesn't apply to the given code?
e.g.
{
code: "function* foo() {}",
options: [{ before: false, after: true, method: "before" }]
}
{ | ||
code: "class Foo { static * foo(){} }", | ||
options: [{ before: false, after: false, static: "both" }] | ||
}, |
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.
Can you add tests where an override is used and top-level before
and after
are not used? In that case, the rule default should be used ("before"
).
{
code: "function *foo() {}",
options: [{ method: "after" }]
}
{ | ||
code: "class Foo { static * foo(){} }", | ||
options: [{ before: false, after: false, static: "both" }] | ||
}, |
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.
Can you add tests where the object option is specified, but only one of before
or after
is provided? Then I would expect the other option to fall back to the default.
{
code: "function * foo(){}",
options: [{ before: true, after: false, named: { after: true } }]
}
LGTM |
@not-an-aardvark @platinumazure, code review comments have been addressed. Let me know if there's anything else that needs attention. |
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, this looks good in general -- I just have a few minor suggestions.
docs/rules/generator-star-spacing.md
Outdated
class Class { static * method() {} } | ||
``` | ||
|
||
Examples of **incorrect** code for this rule with overrides present: |
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.
Very minor nitpick: In most of the documentation, incorrect code is listed before correct code. It would be nice to also do that here.
lib/rules/generator-star-spacing.js
Outdated
@@ -79,17 +121,19 @@ module.exports = { | |||
|
|||
/** | |||
* Checks the spacing between two tokens before or after the star token. | |||
* | |||
* @param {string} kind Either "named", "anonymous", "method", or "static" |
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 comment should probably be updated to remove "static".
lib/rules/generator-star-spacing.js
Outdated
} | ||
|
||
const nextToken = sourceCode.getTokenAfter(starToken); | ||
// Only check before when preceded by `function`|`static` keyword | ||
if (kind !== "method" || prevToken.value === "static") { |
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 wondering if this check could be expressed in a better way. Conceptually, it seems like the case we care about isn't whether the value of the previous token happens to be static
-- it's that we don't want to enforce spacing before the star when it's the first token of the given property.
class Foo {
*bar() {} // '*' is the first token of the MethodDefinition
}
class Foo {
static bar() {} // '*' is not the first token of the MethodDefinition (it's preceded by `static`)
}
// (experimental syntax)
class Foo {
async *bar(){} // '*' is not the first token of the MethodDefinition (it's preceded by `async`)
}
So it might be better to express this statement as
if (!(kind === "method" && starToken === sourceCode.getFirstToken(node.parent))) {
checkSpacing(kind, "before", prevToken, starToken);
}
This matters because although we don't explicitly support specific custom/experimental syntax in core rules, the rule will probably be run with various custom parsers, so it's useful to make the rule robust when dealing with unrecognized syntax in general. To that end, it helps to make rule's conditionals semantically correct so that they behave reasonably when they encounter syntax they don't know how to deal with.
LGTM |
Thanks for the feedback. I think I've addressed everything now. |
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.
Looks good to me. Thanks!
@platinumazure Would you mind confirming whether your comments have been addressed? If so, I think we can merge this. |
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.
Sorry for the delay. LGTM, thanks for contributing!
What is the purpose of this pull request? (put an "X" next to item)
[ ] Documentation update
[ ] Bug fix (template)
[ ] New rule (template)
[x] Changes an existing rule (template)
[ ] Add autofixing to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:
#8918
What changes did you make? (Give an overview)
Added configurability to generator star spacing.
Users of the rule will now be able to override the behavior of this rule per method type.
The types of methods allowing overrides are named function declarations, anonymous function declarations, function property shorthand/method declarations, and static method declarations.
Is there anything you'd like reviewers to focus on?
Let me know if there's a better way to provide documentation on the new functionality without drastically increasing the length of that document.
Also, let me know if there's anything that I missed that needs to be updated.