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

Proposal: jsx-child-element-spacing proposal #1519

Merged
merged 8 commits into from
Dec 1, 2017

Conversation

pfhayes
Copy link
Contributor

@pfhayes pfhayes commented Nov 7, 2017

Failing tests to illustrate use cases for #1515

@pfhayes
Copy link
Contributor Author

pfhayes commented Nov 7, 2017

@ljharb

@pfhayes
Copy link
Contributor Author

pfhayes commented Nov 7, 2017

Open to feedback on

  • Does this make sense, and would it be a desirable rule to add
  • Naming and preferred language for error messages

code: `
<App>
foo
<a>bar</a>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would the output be if you wanted this autofixed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think as you pointed out in the original issue, the intent is ambiguous so autofixing may not be feasible.

If we were to autofix, replacing with the comment form would maintain the semantic without too much disruption (though would perhaps be less aesthetically pleasing)

I would advocate for no automatic action since, in my experience, the developer most often intended to add a space, though I could be convinced otherwise

@ljharb
Copy link
Member

ljharb commented Nov 7, 2017

Could you add a bunch more valid and invalid examples? That would help evaluate the usefulness of the rule.

@pfhayes
Copy link
Contributor Author

pfhayes commented Nov 8, 2017

Thanks @ljharb - I've added some more test cases that cover some different case. Please let me know if that helps or if I can provide cases of another type

<App>
<a>
<b>nested1</b>
<b>nested2</b>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this an error? are you going to keep a list of inline-by-default elements? What about when the display is changed via css?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be an error because it would render as nested1nested2 which is unlikely to be the developers intent

We certainly could just use the complete list of inline elements here: https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements

Certainly it would not be feasible to capture changes to display by CSS. I wouldn't be overly concerned about it because...

  • If the developer uses CSS to make a block element inline, then the rule will not catch this. However without this rule they are equally likely not to catch this. I would also expect that, since the developer is already modifying the default layout, they are likely to be visually inspecting the results manually to look for inconsistencies
  • If the developer uses CSS to make an inline element into a block, then the rule may error unnecessarily. However the error can be silenced by adding either an explicit space or a comment form, as above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless there's already a package that keeps the list of inline elements up to date, i'd be hesitant to hardcode it in this package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A fair concern - here's one that I found: https://www.npmjs.com/package/block-elements (and it's less popular cousin https://www.npmjs.com/package/inline-elements)

Worth noting that React, when tackling a similar problem, opted to just hardcode a list of relevant tags

https://github.com/facebook/react/blob/17aa4d4682aa5c6fdbd3fb0d65e2d69769fe2d61/packages/react-dom/src/client/validateDOMNesting.js#L29

Another alternative would be not to do any special-casing on tag type and treat any adjacent tags as problematic, though I suspect that would get annoying pretty fast with adjacent divs.

Another concern - custom React classes for which it would be infeasible to detect the display type statically. This leads me to believe the rule should only report cases where we know the tag is inline - I think this covers a lot of common cases (like tags in text)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The real ideal would be if we could use React's list directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, they are not the same use case

Note: this does not catch all invalid nesting, nor does it try to (as it's
  // not clear what practical benefit doing so provides); instead, we warn only
  // for cases where the parser will give a parse tree differing from what React
  // intended. For example, <b><div></div></b> is invalid but we don't warn
  // because it still parses correctly; we do warn for other cases like nested
  // <p> tags where the beginning of the second element implicitly closes the
  // first, causing a confusing mess.

@pfhayes
Copy link
Contributor Author

pfhayes commented Nov 16, 2017

I've updated this PR to reduce its scope.

Originally I was hoping to catch cases like

<p>
  <a href="https://google.com>link 1</a>
  <a href="https://google.com>link 2</a>
</p>

the original draft of this rule searched for cases like that. Ultimately there were just too many false positives (such as a's, span's, button's that used CSS to distinguish between them).

By reducing the scope to just search for

<p>
  Here is a
  <a href="https://google.com>link</a>
</p>

the rule became much more useful and has very few false positives. I ran this on about 60k lines of React code and the results were

Legitimate errors caught: 35
Not an error, but original was ambiguous and could be improved: 17
False Positives: 2

The majority of the error cases were a's, code's, strong's appearing inside paragraphs. The majority of the ambiguous cases were checkboxes appearing next to text. The false positives were that were separately styled with CSS

This suggests to me this is a useful rule and I submit it for your consideration

cc @ljharb

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I think this LGTM.

@@ -0,0 +1,102 @@
'use strict';

const INLINE_ELEMENTS = [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you add a comment here that links to the source of this list?


const isInlineElement = node => (
node.type === 'JSXElement' &&
INLINE_ELEMENTS.indexOf(elementName(node)) !== -1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be made into a Set instead?

@pfhayes
Copy link
Contributor Author

pfhayes commented Nov 22, 2017

comments addressed @ljharb

@ljharb ljharb changed the title Proposal: jsx-child-element-spacing proposal [in-progress] Proposal: jsx-child-element-spacing proposal Dec 1, 2017
@ljharb ljharb merged commit 06e1667 into jsx-eslint:master Dec 1, 2017
@pfhayes pfhayes deleted the spaces branch January 30, 2018 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

3 participants