feat(transformer): implement some of jsx decode entities (#1086)

This commit is contained in:
Boshen 2023-10-29 14:57:39 +08:00 committed by GitHub
parent 094dfa5604
commit e8a4e81298
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 18 deletions

View file

@ -1076,6 +1076,9 @@ fn print_str<const MINIFY: bool>(s: &str, p: &mut Codegen<{ MINIFY }>) {
// <https://github.com/tc39/proposal-json-superset>
LS => p.print_str(b"\\u2028"),
PS => p.print_str(b"\\u2029"),
'\u{a0}' => {
p.print_str(b"\\xA0");
}
_ => p.print_str(c.escape_default().to_string().as_bytes()),
}
}

View file

@ -442,19 +442,7 @@ impl<'a> ReactJsx<'a> {
fn transform_jsx_child(&mut self, child: &JSXChild<'a>) -> Option<Expression<'a>> {
match child {
JSXChild::Text(text) => {
let text = text.value.trim();
(!text.trim().is_empty()).then(|| {
let text = text
.split(char::is_whitespace)
.map(str::trim)
.filter(|c| !c.is_empty())
.collect::<std::vec::Vec<_>>()
.join(" ");
let s = StringLiteral::new(SPAN, text.into());
self.ast.literal_string_expression(s)
})
}
JSXChild::Text(text) => self.transform_jsx_text(text),
JSXChild::ExpressionContainer(e) => match &e.expression {
JSXExpression::Expression(e) => Some(self.ast.copy(e)),
JSXExpression::EmptyExpression(_) => None,
@ -467,4 +455,53 @@ impl<'a> ReactJsx<'a> {
}
}
}
fn transform_jsx_text(&self, text: &JSXText) -> Option<Expression<'a>> {
let text = text.value.trim();
(!text.trim().is_empty()).then(|| {
let text = text
.split(char::is_whitespace)
.map(str::trim)
.filter(|c| !c.is_empty())
.map(Self::decode_jsx_text)
.collect::<std::vec::Vec<_>>()
.join(" ");
let s = StringLiteral::new(SPAN, text.into());
self.ast.literal_string_expression(s)
})
}
/// * Replace entities like "&nbsp;", "&#123;", and "&#xDEADBEEF;" with the characters they encode.
/// * See https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
/// Code adapted from <https://github.com/microsoft/TypeScript/blob/514f7e639a2a8466c075c766ee9857a30ed4e196/src/compiler/transformers/jsx.ts#L617C1-L635>
fn decode_jsx_text(s: &str) -> String {
let mut buffer = vec![];
let mut chars = s.bytes().enumerate();
let mut prev = 0;
while let Some((i, c)) = chars.next() {
if c == b'&' {
let start = i;
let mut end = None;
for (j, c) in chars.by_ref() {
if c == b';' {
end.replace(j);
break;
}
}
if let Some(end) = end {
let word = &s[start + 1..end];
buffer.extend_from_slice(s[prev..start].as_bytes());
prev = end + 1;
match word {
"amp" => buffer.extend_from_slice(b"&"),
"nbsp" => buffer.extend_from_slice("\u{a0}".as_bytes()),
_ => {}
}
}
}
}
buffer.extend_from_slice(s[prev..].as_bytes());
// Safety: The buffer is constructed from valid utf chars.
unsafe { String::from_utf8_unchecked(buffer) }
}
}

View file

@ -1,4 +1,4 @@
Passed: 226/1083
Passed: 229/1083
# All Passed:
* babel-plugin-transform-numeric-separator
@ -804,7 +804,7 @@ Passed: 226/1083
* regression/11061/input.mjs
* variable-declaration/non-null-in-optional-chain/input.ts
# babel-plugin-transform-react-jsx (77/172)
# babel-plugin-transform-react-jsx (80/172)
* autoImport/after-polyfills-compiled-to-cjs/input.mjs
* autoImport/after-polyfills-script-not-supported/input.js
* autoImport/auto-import-react-source-type-module/input.js
@ -853,12 +853,10 @@ Passed: 226/1083
* react/should-escape-xhtml-jsxtext-babel-7/input.js
* react/should-handle-attributed-elements/input.js
* react/should-not-strip-nbsp-even-coupled-with-other-whitespace/input.js
* react/should-not-strip-tags-with-a-single-child-of-nbsp/input.js
* react/should-support-xml-namespaces-if-flag/input.js
* react/should-throw-error-namespaces-if-not-flag/input.js
* react/should-warn-when-importSource-is-set/input.js
* react/should-warn-when-importSource-pragma-is-set/input.js
* react/weird-symbols/input.js
* react/wraps-props-in-react-spread-for-first-spread-attributes-babel-7/input.js
* react/wraps-props-in-react-spread-for-last-spread-attributes-babel-7/input.js
* react/wraps-props-in-react-spread-for-middle-spread-attributes-babel-7/input.js
@ -880,7 +878,6 @@ Passed: 226/1083
* react-automatic/should-escape-xhtml-jsxtext-babel-7/input.js
* react-automatic/should-handle-attributed-elements/input.js
* react-automatic/should-not-strip-nbsp-even-coupled-with-other-whitespace/input.js
* react-automatic/should-not-strip-tags-with-a-single-child-of-nbsp/input.js
* react-automatic/should-properly-handle-comments-between-props/input.js
* react-automatic/should-throw-error-namespaces-if-not-flag/input.js
* react-automatic/should-throw-when-filter-is-specified/input.js