-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Fixes React isCompatTag validator accepting leading dash character #7164
Conversation
Quoting the react docs: [1]
Things like This is also the reason why some tests are failing. [1] https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized |
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 thoughts?
assert(t.react.isCompatTag("-div") === false); | ||
// assert(t.react.isCompatTag("-span") === false); | ||
// assert(t.react.isCompatTag("-a") === false); | ||
// assert(t.react.isCompatTag("-input") === 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.
Why are these commented out?
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.
Ha, my mistake! I forgot to uncomment before committing 😅
// assert(t.react.isCompatTag("-a") === false); | ||
// assert(t.react.isCompatTag("-input") === 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.
Test for trailing dash might be nice. That's a use case that fails currently (but would be fixed by this PR) I think.
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 taking the time to review on a Saturday @bvaughn 😄 Let me update the PR.
Let me ask this though as I'm not clear if we're on the same page: trailing dashes are legal for custom elements, i.e. <input-/>
is a legal custom element name, or am I misreading the spec?
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.
When @hzoo tags me, I come running. (In case there's Mario Kart.)
@@ -1,4 +1,5 @@ | |||
// @flow | |||
export default function isCompatTag(tagName?: string): boolean { | |||
return !!tagName && /^[a-z]|-/.test(tagName); | |||
// Must start with 'a'-'z', can have a dash '-', but must finish with 'a'-'z' | |||
return !!tagName && /^[a-z]+(-?[a-z]+)?$/.test(tagName); |
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 pattern would reject custom element names with more than one hyphen (eg my-custom-tag
).
I think this would work though?
/^[^-]([\-a-z]*[^-])*$/
(['a', 'ab', 'abc', 'a-b', 'a-b-c'])
.map(tag => /^[^-]([\-a-z]*[^-])*$/.test(tag))
.join(',');
// true,true,true,true,true
(['-a', 'a-', '-', '-a-'])
.map(tag => /^[^-]([\-a-z]*[^-])*$/.test(tag))
.join(',');
// false,false,false,false
Edit: This would fail "a--b" though. Could write a simpler regex if you only used it for strings with 3+ characters. 1-2 character strings could be validated with a simple /[a-z]+/
check. Not sure how bulletproof this regex needs to be.
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.
By the way, glancing at the spec it seems like a much broader range of characters than just a-z are allowed for custom elements (eg <emotion-😍>
) 😆 Not sure if we want to try to support them all. Probably not?
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.
Yep the custom elements spec says:
PotentialCustomElementName ::=
[a-z] (PCENChar)* '-' (PCENChar)*
PCENChar ::=
"-" | "." | [0-9] | "_" | [a-z] | #xB7 | [#xC0-#xD6] | [#xD8-#xF6] |
[#xF8-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x203F-#x2040] |
[#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] |
[#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
Do we want to get this far?
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 don't have enough context to answer that. 😄 My guess would be "probably not".
I decided to back out changes to validate the element name and only fix the validator not to accept a leading dash, and add unit tests 😄 The regex can be further complicated if needs to be to match the spec. Thanks @nicolo-ribaudo @bvaughn for the feedback! |
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/6482/ |
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 like I accidentally approved earlier when I only meant to "comment" 😄 Clumsy.
I don't know that I have enough context to approve of this change with confidence. The regex I mentioned on a previous comment seems closer to ideal, even though not perfect, but maybe there are perf considerations?
I'll defer to someone who has more context. 😄
@bvaughn +1 on perf concerns. Also, it seems there are other checks happening before the validator as malformed JSX tags like |
They are rejected by Babylon (the parser). Anyway, I'd still accept this PR if it removes the |
Agreed. Leading "-" fails in master now. Trailing "-" doesn't (but still won't if this change lands). |
Yeah I didn't think this change was necessary and was never reported before (forgot to mention), just wanted to ping someone on the react team for review Ya if it errors in the parser already, I think
|
react-dom IMO it's nice if JSX compilation fails earlier for things that are obviously wrong (like leading Edit: Actually, it looks like trailing slashes are accepted, so clearly I don't know much about this topic: document.createElement('a-')
// <a-></a-> |
What about using function test(tag) {
if (/^[^-](\-?[a-z]+)*-?$/.test(tag)) {
console.log(`creating tag "${tag}"`);
document.createElement(tag);
} else {
console.log(`skipping tag "${tag}"`);
}
}
// valid tags
(['a', 'ab', 'abc', 'a-b', 'a-b-c', 'a-', 'a-b-']).forEach(test);
// creating tag "a"
// creating tag "ab"
// creating tag "abc"
// creating tag "a-b"
// creating tag "a-b-c"
// creating tag "a-"
// creating tag "a-b-"
// invalid tags
(['-a', '-', '-a-', 'a--b']).forEach(test);
// skipping tag "-a"
// skipping tag "-"
// skipping tag "-a-"
// skipping tag "a--b" |
Uppercase letters and numbers are also allowed. e.g. * Babel plugins assume that the AST given to them is valid. The check against invalid ASTs should either be in Babylon or in babel-types. |
@nicolo-ribaudo my thoughts exactly, but I relate with @bvaughn, I'm falling prey to nerd sniping too 😅 |
Uppercase letters and numbers are also allowed. e.g.
In JSX, where all tag names are strings, host components (eg div, span) and
custom components (eg MyButton) are distinguished by the casing of the
first letter.
I assume the intent here is to give helpful warnings as early as possible
rather than to be 100% correct or cover all cases.
That being said, I've weighed in enough here. I have only partial contenxt
and no strong opinions 😄 so I'm bowing out now. 👋
|
assert(t.react.isCompatTag("plastic-button")); // ascii letters | ||
assert(t.react.isCompatTag("math-α")); // non-latin chars | ||
assert(t.react.isCompatTag("img-viewer2")); // numbers | ||
assert(t.react.isCompatTag("emotion-😍")); // emoji |
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.
Not sure if anything besides /^[a-z][a-z-]*$/
is supposed to work, but I don't see why ban it unless the JSX spec forbids 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.
Checked the spec; the spec actually says nothing about compat tags at all; just that the identifier (JSXIdentifier
) is basically the same thing as IdentifierName
but it also allows -
.
I assume that that part is enforced by babylon instead of isCompatTag
so this seems sufficient.
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.
Emojis in source code are cool 😆
Test failure is unrelated (yarnpkg timeout?) |
Yes, it's failing often today (and yesterday). I restarted it but it failed again. I think we can marge this PR anyway since it doesn't affect Babylon? |
Thank you all 😊 |
Fixed regexp test in
isCompatTag
React validator allowing leading dash'-'
characters.Was:
Is: