mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(transformer): implement some of jsx decode entities (#1086)
This commit is contained in:
parent
094dfa5604
commit
e8a4e81298
3 changed files with 55 additions and 18 deletions
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 " ", "{", and "�" 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) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue