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
feat: add allowLineSeparatedGroups option to sort-keys (fixes #12759) #13573
Conversation
allowLineSeparatedGroups
option to sort-keys
rule #12759
allowLineSeparatedGroups
option to sort-keys
rule #12759
lib/rules/sort-keys.js
Outdated
const isLineSeparatedGroups = prevEndLine && checkLineSeparatedGroups(thisStartLine, prevEndLine); | ||
|
||
if (thisStartLine !== null) { | ||
stack.prevEndLine = thisStartLine; |
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 seems to treat the multiline property as a group separator because it compares the start line of the previous property
and the start line of the current property
. So the below case has no lint error.
{
code: `
var obj = {
b: 1, // 1st Group
c () { // 1st Group
},
a: 3 // 2nd Group ?? No Error
}
`,
options: ["asc", { allowLineSeparatedGroups: true }],
parserOptions: { ecmaVersion: 6 }
},
Maybe, we should compare the end line of the previous property
with the start line of the current property
as what "sort-import" does
/*eslint sort-imports: ["error", { "allowSeparatedGroups": true }]*/
import b from 'foo.js';
import d
from 'bar.js';
import a from 'baz.js'; // Lint error, cause it's not separated from previous
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 !!!!
I made a mistake while clean the code.
It was stack.prevEndLine = node.loc.end.line;
before PR.
Thank you !
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 !!!!
I made a mistake while clean the code.
There's no need to be sorry :)
Can we add a test case for ensuring it? (maybe in invalid cases?)
{
code: `
var obj = {
b: 1,
c () {
},
a: 3
}
`,
options: ["asc", { allowLineSeparatedGroups: true }],
parserOptions: { ecmaVersion: 6 }
},
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 contribution 👍 I left some comments :)
lib/rules/sort-keys.js
Outdated
} | ||
}, | ||
additionalProperties: false | ||
} | ||
], | ||
|
||
messages: { | ||
allowLineSeparatedGroups: "'{{thisName}}' should be before '{{prevName}}'. To separate groups by line break, apply the allowLineSeparatedGroups option.", |
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 it's good to give option information to those who don't use this option.
I want to hear other member's opinion
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 think we should remove this message, and just use the existing one. I believe we don't have any error messages that advise users to reconfigure the rule.
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 advice !!
I'll remove 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.
@JJoGeon Thanks for the change :) I left some comments.
I made a mistake while clean the code.
It was stack.prevEndLine = node.loc.end.line; before PR.
Can we add a test case for ensuring it? (maybe in invalid cases?)
{
code: `
var obj = {
b: 1,
c () {
},
a: 3
}
`,
options: ["asc", { allowLineSeparatedGroups: true }],
parserOptions: { ecmaVersion: 6 },
errors : [/* ... */]
},
lib/rules/sort-keys.js
Outdated
* @returns {number} number of lines between nodes. | ||
* @private | ||
*/ | ||
function checkLineSeparatedGroups(thisStartLine, prevEndLine) { |
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 we change the function name to getLinesBetween
or getNumberOfLinesBetween
?
IMO check
prefixed name seems to represent return boolean
or call context.report()
but actually it returns the number of lines between two.
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.
May I change it to !!Math.max(thisStartLine - prevEndLine - 1, 0);
?
In this function, distances the value of the two is not important but whether they are separated from each other is important.
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.
May I change it to !!Math.max(thisStartLine - prevEndLine - 1, 0); ?
sure :). it makes sense to me
lib/rules/sort-keys.js
Outdated
const thisStartLine = node.loc.start.line; | ||
const isLineSeparatedGroups = prevEndLine && checkLineSeparatedGroups(thisStartLine, prevEndLine); | ||
|
||
if (thisStartLine !== null) { |
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.
const thisStartLine = node.loc.start.line;
//...
if (thisStartLine !== null) {
I think it's unneeded condition since thisStartLine
seems equals with node.loc.start.line
(number
).
so thisStartLine !== null
seems always true
Modification is complete! thank you ! |
Should the option insist on a blank line, as in the original issue, or just check if the properties aren't on consecutive lines as it is implemented in the actual iteration. For example: /* eslint sort-keys: ["error", "asc", { "allowLineSeparatedGroups": true} ] */
var obj = {
b,
// comment
a
} |
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.
Also, the actual rule skips computed keys (except for simple ones), but compares non-computed keys around them:
/* eslint sort-keys: ["error", "asc"] */
var obj = {
b,
[foo + bar]: 1,
a // sort-keys: 'a' should be before 'b'
}
If the option is "allowLineSeparatedGroups": true
, what should be checked in the above example?
In the actual iteration, this code would produce an error, while it probably shouldn't:
/* eslint sort-keys: ["error", "asc", { "allowLineSeparatedGroups": true } ] */
var obj = {
b,
[foo + bar]: 1,
a // sort-keys: 'a' should be before 'b'
}
docs/rules/sort-keys.md
Outdated
Examples of **incorrect** code for the `{allowLineSeparatedGroups: true}` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: 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.
/*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: true}]*// | |
/*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: true}]*/ |
Examples of **correct** code for the `{allowLineSeparatedGroups: true}` option: | ||
|
||
```js | ||
/*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: 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.
/*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: true}]*// | |
/*eslint sort-keys: ["error", "asc", {allowLineSeparatedGroups: true}]*/ |
We recently added allowSeparatedGroups to the However, for |
HI @mdjermanovic :)
for double-check, Is this mean a comment line cannot create groups? /* eslint sort-keys: ["error", "asc", { "allowLineSeparatedGroups": true} ] */
var obj = {
b,
[foo + bar]: 1,
a // lint-error
}
var obj = {
b,
[foo + bar]: 1,
// comments
a // lint-error
}
var obj = {
b,
[foo + bar]: 1,
// comments
a // lint-free
}
var obj = {
b,
[foo + bar]: 1,
// comments
a // lint-free
} |
Yes, I think comment lines shouldn't create groups. That way, I believe it would be easier to explain this option in the docs, and much easier for users to understand how this option exactly works: it simply checks if there are any blank lines between properties. That's just my opinion, it could be wrong. I also tried the tslint rule mentioned in the original post of the issue, and it seems to be working like that: TSLint playground link (we don't have to match the behavior, but it looks reasonable to me) |
HI @mdjermanovic @yeonjuan !! Thank you for the good Opinion! var sampleObject1 = {
a: 1,
b: 2,
// c description
c: 3
} // one object, one group
var sampleObject2 = {
a: 1,
b: 2,
// another group description
c: 3
} // one object, two group We don't know what that comment means. (eslint too.) var sampleObject1 = {
a: 1,
b: 2,
// c or another group description
c: 3
} // one object, one group
var sampleObject2 = {
a: 1,
b: 2,
// c or another group description
c: 3
} // one object, two group |
I agree with it 👍 thanks for the reply |
Hi @yeonjuan, @mdjermanovic ! :) Finish comment line check logic. |
*/ | ||
function checkLineSeparatedGroups(thisStartLine, prevEndLine, sourceCodeLines) { | ||
let blockCommentFlag = false; | ||
let commentOffset = 0; |
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 used the forEach function to check the comment line, but I'm not sure if it's okay.
Is there a better way?
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.
@JJoGeon
Thanks for keep working it.
I left comments about false positives and suggestions.
}); | ||
|
||
return !!Math.max(thisStartLine - prevEndLine - commentOffset - 1, 0); | ||
} |
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 has some false positives when we use /*
, */
, //
as a value in code.
{
code: `
var obj = {
c: "/*",
a: "*/", // Error. Expected object keys to be in ascending order. 'a' should be before 'c'.
}
`,
options: ["asc", { allowLineSeparatedGroups: true }]
}
Is there a better way?
🤔 IMO, we can use SourceCode methods for it. there are some methods for treating comment as a node or token
getTokenAfter(nodeOrToken, {includeComments: true})
getTokenBefore(nodeOrToken, {includeComments: 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.
Thank you @yeonjuan !!
in this case,
var sampleObject1 = {
a: 1,
b: 2,
// comment 1
// comment 2
c: 3
}
I used getTokensBefore
.
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 think this would be a complicated way to find out if there's a blank line.
For example, this is a false positive:
/* eslint sort-keys: ["error", "asc", { allowLineSeparatedGroups: true }] */
var obj = {
b,
/*
*/ //
a
}
comments offset is calculated as 3
, but it doesn't take into account if there are lines between comments or not.
Could we maybe simplify this? We could take tokens between properties and then see if there's a blank line between any two successive tokens.
More precisely, if we want to check if there's a blank line between two properties (property1
and property2
), than we could check if there's a blank line between any two of the following items:
property1
- comma after
property1
- comment1
- comment2
- ....
- commentN
property2
Hi, @mdjermanovic !! :) I modified the code to pass all test cases. thank you ! |
@JJoGeon thanks for the changes and sorry for the delay from my side! I left a comment here |
Hi, @mdjermanovic !! :) I improved the Please check the upgraded Thank you for your continued good opinion. |
This wouldn't work well with the comma-first style. For example, this would be a false negative: /* eslint sort-keys: ["error", "asc", { "allowLineSeparatedGroups": true }] */
var obj = {
b: 1
// comment
, a: 2
}; Can we maybe check if there's a blank line between two properties by checking for blank lines between consecutive nodes/tokens (incl. comments), instead of calculating comments offset?
|
@JJoGeon are you still working on this? |
@nzakas yes. For personal reasons, i couldn't work this issue. |
@JJoGeon great, happy to hear it! |
@mdjermanovic I solved the comma first style problem you told me.
But this suggestion not solved. Then isn't there only a way to calculate the offset with the line information of the two nodes? I want to finish with a better code. |
@mdjermanovic please take a look |
@JJoGeon sorry for the delay. I thought I left an answer, but apparently I didn't.
There isn't a built-in helper function to determine if there is a blank line between two nodes, but we can easily determine that by checking their lines: If |
@mdjermanovic Thank you for your advice. I'll wrap it up soon and PR again. |
@JJoGeon Really looking forward to this improvement if you or anyone is able to push it forward :) |
@JJoGeon any updates on this? |
I'll finish this. |
Thank you very much! You are the hero we don't deserve. |
Thank you for your interest in my PR. I'll try to finish it as soon as possible. But it's okay for good people to finish before I finish. (@alexthehurst , @mvuherer , @snitin315) |
Closing in favor of #16138 |
Prerequisites checklist
What is the purpose of this pull request? (put an "X" next to an item)
[x] 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:
What changes did you make? (Give an overview)
Add
allowLineSeparatedGroups
option tosort-keys
rule #12759Is there anything you'd like reviewers to focus on?
None