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

Rule Proposal: matched-token-indentation #9123

Closed
EthanRutherford opened this issue Aug 17, 2017 · 10 comments
Closed

Rule Proposal: matched-token-indentation #9123

EthanRutherford opened this issue Aug 17, 2017 · 10 comments
Labels
archived due to age This issue has been archived; please open a new issue for any further discussion evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules

Comments

@EthanRutherford
Copy link
Contributor

Please describe what the rule should do:
This rule would warn when a closing brace/bracket/paren is on a line with a different indent level than the matching opening token.

What category of rule is this? (place an "X" next to just one item)

[x] Enforces code style
[ ] Warns about a potential error
[ ] Suggests an alternate way of doing something
[ ] Other (please specify:)

Provide 2-3 code examples that this rule will warn about:

// example 1
function foo() {
    // some code here
    }

// example 2
foo(someArray.map(
    () => {
        // some code here
    }));

// example 3
foo(
    [
        // some values here
    ])

Why should this rule be included in ESLint (instead of a plugin)?
Matching the indentation level of two matched tokens can improve readability of source code. When opening and closing tokens are at the same indent level, it becomes visually much easier to detect where a section of code (i.e. function parameters, a function body, an array, an object literal, etc.) begins and ends. When the indent level does not match, one has to read through line by line to try and manually match an opening token with its closing token, which can get very difficult quite easily in a language like javascript, where nesting can potentially get very deep.

@eslintbot eslintbot added the triage An ESLint team member will look at this issue soon label Aug 17, 2017
@platinumazure
Copy link
Member

Since ESLint 4.0.0, the indent rule has gotten a lot smarter and should be catching all of these. Are you using ESLint 4 or later and the new indent rule?

@platinumazure platinumazure added evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules and removed triage An ESLint team member will look at this issue soon labels Aug 17, 2017
@not-an-aardvark
Copy link
Member

I think the indent rule doesn't catch examples 2 and 3 since the indentation itself is correct given the position of the linebreaks, but I think @EthanRutherford would prefer that a linebreak be placed before the closing paren. The indent rule doesn't care where you put linebreaks -- it just indents code appropriately given the locations of the linebreaks.

@EthanRutherford Would #8102 address this, in combination with the indent rule?

@EthanRutherford
Copy link
Contributor Author

EthanRutherford commented Aug 17, 2017

Here are some examples of what I would consider "correct" code with this rule, if it helps:

// example 2 corrected
foo(someArray.map(() => {
    // some code here
}));

// example 2 corrected alternative
foo(someArray.map(
    () => {
        // some code here
    })
);

// example 3 corrected
foo([
    // some values here
])

// example 3 corrected alternative
foo(
    [
        // some values here
    ]
)

I'll take a look at #8102 and see if that does what I'm looking for.

EDIT: looks like it wouldn't quite solve the problem, and moreover would be imposing a different constraint that is tangent to the above issue. This rule would ensure that the indentation level is always equal on the first line of the expression/block and the last line of the expression/block. It's not interested in whether or not each token gets its own line, just so long as they return to their "home" indentation level at the end. (note the two possible "correct" configurations)

@EthanRutherford
Copy link
Contributor Author

Another, less immediately obvious way to see this rule is that if the first line has, say, 3 parens in it, then the last line must have all three matching parens. (in fact, that gives me a better idea for the rule name: "delimiter-symmetry")
i.e.

// correct
foo(bar(baz(
    // some args
)))

// incorrect
foo(bar(baz(
    /* some args */)
))

@not-an-aardvark
Copy link
Member

looks like it wouldn't quite solve the problem, and moreover would be imposing a different constraint that is tangent to the above issue.

Could you give an example of code that would be considered correct by indent and function-paren-newline (with the consistent option), but would be considered incorrect by this rule, or vice versa? I'm unsure how different this rule would be from those two in practice, because it seems like there is a lot of overlap between the cases that they would address.

@EthanRutherford
Copy link
Contributor Author

code that is invalid under indent and function-paren-newline, but valid under this rule

foo(bar(baz(
    1,
    2,
    3,
)));

it is my understanding that this would be invalid, as the "multiline" rule would state that, since the content between the parens is multiline, each paren must have a newline. like so:

foo(
    bar(
        baz(
            1,
            2,
            3,
        )
    )
);

code that is valid under indent and function-paren-newline, but invalid under this rule

const foo = (
    5);

this example is pretty simple: because it's not a function paren, function-paren-newline doesn't even apply to this code.

I will admit, function-paren-newline (in combination with indent) does achieve the desired effect of requiring indent levels to match, but there are a few key things to note.
First, it happens as a side effect. Matching the indent level is not the primary goal of that rule, it simply happens as a side effect of the rule being combined with another.
Second, it imposes a constraint that users who want consistent indentation may not want: it disallows having more than one paren per line if the innermost content ends up being multiline (like in the foo(bar(baz( example above).
And lastly, quite simply that function-paren-newline only deals with a very specific set of delimiters: parens that are specifically part of a function's parameter list. This rule would apply to all delimiters.

If my understanding about how function-paren-newline would behave in the foo(bar(baz( example is incorrect, however, then my second point would be moot, and I think it might be that this combination (combined with other similar rules for the other delimiter types) would achieve the desired effect, so please do correct me if I'm wrong.

@not-an-aardvark
Copy link
Member

If my understanding about how function-paren-newline would behave in the foo(bar(baz( example is incorrect, however, then my second point would be moot, and I think it might be that this combination (combined with other similar rules for the other delimiter types) would achieve the desired effect, so please do correct me if I'm wrong.

Sorry, I should have clarified -- I was referring to the consistent option for function-paren-newline proposed in #8102 (comment). I think that would allow the code in your first example.

@EthanRutherford
Copy link
Contributor Author

Oh, I see the consistent option now, my apologies, I was looking at the doc, which it seems has not been updated to add that option yet.
Yes, I do believe that would achieve the desired effect. Is there a case to add the same consistent option to the other related rules (like array-bracket-newline)?

@EthanRutherford
Copy link
Contributor Author

I would also propose an expression-paren-newline to handle the case above, where parens are used to force precedence or just stylistically enclose an expression.

@EthanRutherford
Copy link
Contributor Author

I'll go ahead and close this issue.

@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Feb 19, 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 Feb 19, 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 evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules
Projects
None yet
Development

No branches or pull requests

4 participants