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

New: Allow decimal arguments to indent's VariableDeclarator (fixes #3339) #8975

Closed
wants to merge 1 commit into from

Conversation

sauyon
Copy link

@sauyon sauyon commented Jul 21, 2017

#3339

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:

What rule do you want to change?

indent VariableDeclarator

Does this change cause the rule to produce more or fewer warnings?

Neither

How will the change be implemented? (New option, new default behavior, etc.)?

Slightly modified checking and adding a Math.round

Please provide some example code that this change will affect:

const foo = 'bar',
      baz = 'foo';

if (foo === 'bar') {
    console.log(baz);
}

What does the rule currently do for this code?

There is no nice way to make eslint accept this code.

What will the rule do after it's changed?

Make eslint accept the code.

What changes did you make? (Give an overview)

Allow number parameters to indent VariableDeclarator, add a Math.round around offset calculation.

Is there anything you'd like reviewers to focus on?

@jsf-clabot
Copy link

jsf-clabot commented Jul 21, 2017

CLA assistant check
All committers have signed the CLA.

@eslintbot
Copy link

Thanks for the pull request, @sauyon! I took a look to make sure it's ready for merging and found some changes are needed:

  • The commit summary must be 72 characters or shorter. Please check out our guide for how to properly format your commit summary and update it on this pull request.

Can you please update the pull request to address these?

(More information can be found in our pull request guide.)

@mention-bot
Copy link

@sauyon, thanks for your PR! By analyzing the history of the files in this pull request, we identified @not-an-aardvark, @valorkin and @vitorbal to be potential reviewers.

@sauyon
Copy link
Author

sauyon commented Jul 21, 2017

Note: I get ERR! test failed from npm test but the output appears fine:

> eslint@4.2.0 test /home/sauyon/devel/eslint
> node Makefile.js test

Validating Makefile.js
Validating JSON Files
Validating Markdown Files
Validating JavaScript files
Validating JavaScript test files
Validating rules

  [▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬․]
  [▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬]

  16973 passing (43s)

=============================================================================
Writing coverage object [/home/sauyon/devel/eslint/coverage/coverage.json]
Writing coverage reports at [/home/sauyon/devel/eslint/coverage]
=============================================================================

=============================== Coverage summary ===============================
Statements   : 99.48% ( 13321/13391 ), 157 ignored
Branches     : 98.3% ( 10187/10363 ), 116 ignored
Functions    : 99.87% ( 2286/2289 ), 26 ignored
Lines        : 99.48% ( 13211/13280 )
================================================================================
[BABEL] Note: The code generator has deoptimised the styling of "/home/sauyon/devel/eslint/node_modules/lodash/lodash.js" as it exceeds the max of "500KB".

START:
21 07 2017 05:43:15.728:WARN [watcher]: All files matched by "/home/sauyon/devel/eslint/node_modules/mocha/mocha.js" were excluded or matched by prior matchers.
21 07 2017 05:43:16.281:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9876/
21 07 2017 05:43:16.282:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
21 07 2017 05:43:16.286:INFO [launcher]: Starting browser PhantomJS
21 07 2017 05:44:16.346:WARN [launcher]: PhantomJS have not captured in 60000 ms, killing.
21 07 2017 05:44:18.348:WARN [launcher]: PhantomJS was not killed in 2000 ms, sending SIGKILL.
21 07 2017 05:44:20.350:WARN [launcher]: PhantomJS was not killed by SIGKILL in 2000 ms, continuing.

Finished in 0 secs / 0 secs @ 05:44:20 GMT+0100 (BST)

npm ERR! Test failed.  See above for more details.

@not-an-aardvark
Copy link
Member

Thanks for the contribution. I'm not opposed to allowing code like this to be aligned, but I'm also not a big fan of the proposed solution here. Allowing decimal offsets and rounding the result seems like a very hacky workaround to me.

If we're going to support alignment, I would prefer an option like VariableDeclarator: "first" that auto-aligns the code, rather than making people specify decimal offsets.

@not-an-aardvark not-an-aardvark added enhancement This change enhances an existing feature of ESLint evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion indent Relates to the `indent` rule rule Relates to ESLint's core rules labels Jul 21, 2017
@sauyon
Copy link
Author

sauyon commented Jul 21, 2017

That does seem better, yeah. I just implemented the suggestion in that issue thread without thinking.

I'll play around and see if I can get that set up - though from my cursory glance at the code for the indent rule I suspect it would take some refactoring for it to work properly.

@not-an-aardvark
Copy link
Member

not-an-aardvark commented Jul 21, 2017

Yeah, I think if we were going to implement that, we would want to refactor the VariableDeclaration listener to use the addElementListIndent helper. Off the top of my head it seems like that should be doable, but I haven't tried it yet so there might be edge-cases I'm missing.

@not-an-aardvark
Copy link
Member

By the way, you're certainly free to try to implement the "first" option if you want, but keep in mind that the team hasn't accepted the proposal yet, so there's a chance the proposal would be rejected and your time would have been wasted. If you'd like, you can create an issue for the proposal first and wait for it to hopefully get accepted before starting the implementation, so that you wouldn't risk wasting your time.

@not-an-aardvark
Copy link
Member

Seems doable, but would require enhancing how "first" works, to allow indent collapsing behavior to be ignored.

WIP implementation (doesn't handle all cases correctly)
diff --git a/lib/rules/indent.js b/lib/rules/indent.js
index ec3f7917..d10e66ae 100644
--- a/lib/rules/indent.js
+++ b/lib/rules/indent.js
@@ -508,25 +508,13 @@ module.exports = {
                     },
                     VariableDeclarator: {
                         oneOf: [
-                            {
-                                type: "integer",
-                                minimum: 0
-                            },
+                            ELEMENT_LIST_SCHEMA,
                             {
                                 type: "object",
                                 properties: {
-                                    var: {
-                                        type: "integer",
-                                        minimum: 0
-                                    },
-                                    let: {
-                                        type: "integer",
-                                        minimum: 0
-                                    },
-                                    const: {
-                                        type: "integer",
-                                        minimum: 0
-                                    }
+                                    var: ELEMENT_LIST_SCHEMA,
+                                    let: ELEMENT_LIST_SCHEMA,
+                                    const: ELEMENT_LIST_SCHEMA
                                 },
                                 additionalProperties: false
                             }
@@ -631,7 +619,7 @@ module.exports = {
             if (context.options[1]) {
                 lodash.merge(options, context.options[1]);
 
-                if (typeof options.VariableDeclarator === "number") {
+                if (typeof options.VariableDeclarator !== "undefined" && typeof options.VariableDeclarator !== "object") {
                     options.VariableDeclarator = {
                         var: options.VariableDeclarator,
                         let: options.VariableDeclarator,
@@ -759,9 +747,10 @@ module.exports = {
         * @param {Token} startToken The start token of the list that element should be aligned against, e.g. '['
         * @param {Token} endToken The end token of the list, e.g. ']'
         * @param {number|string} offset The amount that the elements should be offset
+        * @param {boolean} force `true` if collapsing should be disabled
         * @returns {void}
         */
-        function addElementListIndent(elements, startToken, endToken, offset) {
+        function addElementListIndent(elements, startToken, endToken, offset, force) {
 
             /**
             * Gets the first token of a given element, including surrounding parentheses.
@@ -781,7 +770,8 @@ module.exports = {
             offsets.setDesiredOffsets(
                 [startToken.range[1], endToken.range[0]],
                 startToken,
-                offset === "first" ? 1 : offset
+                offset === "first" ? 1 : offset,
+                force
             );
             offsets.setDesiredOffset(endToken, startToken, 0);
 
@@ -1274,6 +1264,13 @@ module.exports = {
             },
 
             VariableDeclaration(node) {
+                const variableKeyword = sourceCode.getFirstToken(node);
+
+                /*
+                 * TODO: this is a bit of a hack because addElementsListIndent expects there to be a "last token"
+                 * (like a closing array bracket) which is always aligned with the first token.
+                 */
+                const semicolon = sourceCode.getLastToken(node);
                 const variableIndent = options.VariableDeclarator.hasOwnProperty(node.kind) ? options.VariableDeclarator[node.kind] : DEFAULT_VARIABLE_INDENT;
 
                 if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) {
@@ -1297,16 +1294,13 @@ module.exports = {
                      * on the same line as the start of the declaration, provided that there are declarators that
                      * follow this one.
                      */
-                    const firstToken = sourceCode.getFirstToken(node);
-
-                    offsets.setDesiredOffsets(node.range, firstToken, variableIndent, true);
+                    addElementListIndent(node.declarations, variableKeyword, semicolon, variableIndent, true);
                 } else {
-                    offsets.setDesiredOffsets(node.range, sourceCode.getFirstToken(node), variableIndent);
+                    addElementListIndent(node.declarations, variableKeyword, semicolon, variableIndent);
                 }
-                const lastToken = sourceCode.getLastToken(node);
 
-                if (astUtils.isSemicolonToken(lastToken)) {
-                    offsets.ignoreToken(lastToken);
+                if (astUtils.isSemicolonToken(semicolon)) {
+                    offsets.ignoreToken(semicolon);
                 }
             },
 
diff --git a/tests/lib/rules/indent.js b/tests/lib/rules/indent.js
index fb621cb4..722d3cee 100644
--- a/tests/lib/rules/indent.js
+++ b/tests/lib/rules/indent.js
@@ -4859,6 +4859,14 @@ ruleTester.run("indent", rule, {
                     );
                 }
             `
+        },
+        {
+            code: unIndent`
+                const foo = {
+                      },
+                      baz = 1
+            `,
+            options: [4, { VariableDeclarator: "first" }]
         }
     ],
 
@@ -9098,6 +9106,20 @@ ruleTester.run("indent", rule, {
                 </div>
             `,
             errors: expectedErrors([3, 8, 6, "Block"])
+        },
+        {
+            code: unIndent`
+                const foo = 1,
+                    bar = 2,
+                    baz = 3
+            `,
+            output: unIndent`
+                const foo = 1,
+                      bar = 2,
+                      baz = 3
+            `,
+            options: [4, { VariableDeclarator: "first" }],
+            errors: expectedErrors([[2, 6, 4, "Identifier"], [3, 6, 4, "Identifier"]])
         }
     ]
 });

@kaicataldo
Copy link
Member

Where does this PR stand? It looks like the corresponding issue was actually closed quite a while ago.

@not-an-aardvark
Copy link
Member

not-an-aardvark commented Sep 10, 2017

I think #8976 is now the current issue discussing this (although it's discussing a different solution than the one implemented in this PR).

@kaicataldo
Copy link
Member

I'm 👎 for this implementation but am 👍 for this issue: #8976

@not-an-aardvark
Copy link
Member

Closing this PR since there seems to be consensus that it's not the right approach. We appreciate the contribution regardless!

Let's move further discussion to #8976.

@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Mar 12, 2018
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Mar 12, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
archived due to age This issue has been archived; please open a new issue for any further discussion enhancement This change enhances an existing feature of ESLint evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion indent Relates to the `indent` rule rule Relates to ESLint's core rules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants