mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(transformer/jsx): escape xhtml in jsx attributes (#1088)
This commit is contained in:
parent
1ad2dca45a
commit
1051f15005
7 changed files with 273 additions and 11 deletions
|
|
@ -9,6 +9,7 @@ extend-exclude = [
|
|||
"tasks/coverage/typescript",
|
||||
"crates/oxc_parser/src/lexer/mod.rs",
|
||||
"crates/oxc_linter/fixtures",
|
||||
"crates/oxc_syntax/src/xml_entities.rs",
|
||||
"**/*.snap",
|
||||
"pnpm-lock.yaml",
|
||||
"crates/oxc_linter_plugin/examples/queries/unicorn/prefer-string-slice/rule.yml"
|
||||
|
|
|
|||
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1828,6 +1828,7 @@ dependencies = [
|
|||
"indexmap 2.0.2",
|
||||
"oxc_index",
|
||||
"oxc_span",
|
||||
"phf",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"unicode-id-start",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ bitflags = { workspace = true }
|
|||
rustc-hash = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
dashmap = { workspace = true }
|
||||
phf = { workspace = true, features = ["macros"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ pub mod precedence;
|
|||
pub mod reference;
|
||||
pub mod scope;
|
||||
pub mod symbol;
|
||||
pub mod xml_entities;
|
||||
|
||||
pub use unicode_id_start;
|
||||
|
||||
|
|
|
|||
261
crates/oxc_syntax/src/xml_entities.rs
Normal file
261
crates/oxc_syntax/src/xml_entities.rs
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
use phf::{phf_map, Map};
|
||||
|
||||
/// XML Entities
|
||||
///
|
||||
/// <https://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references>
|
||||
/// <https://github.com/microsoft/TypeScript/blob/514f7e639a2a8466c075c766ee9857a30ed4e196/src/compiler/transformers/jsx.ts#L681>
|
||||
pub const XML_ENTITIES: Map<&'static str, char> = phf_map! {
|
||||
"quot" => '\u{0022}',
|
||||
"amp" => '&',
|
||||
"apos" => '\u{0027}',
|
||||
"lt" => '<',
|
||||
"gt" => '>',
|
||||
"nbsp" => '\u{00A0}',
|
||||
"iexcl" => '\u{00A1}',
|
||||
"cent" => '\u{00A2}',
|
||||
"pound" => '\u{00A3}',
|
||||
"curren" => '\u{00A4}',
|
||||
"yen" => '\u{00A5}',
|
||||
"brvbar" => '\u{00A6}',
|
||||
"sect" => '\u{00A7}',
|
||||
"uml" => '\u{00A8}',
|
||||
"copy" => '\u{00A9}',
|
||||
"ordf" => '\u{00AA}',
|
||||
"laquo" => '\u{00AB}',
|
||||
"not" => '\u{00AC}',
|
||||
"shy" => '\u{00AD}',
|
||||
"reg" => '\u{00AE}',
|
||||
"macr" => '\u{00AF}',
|
||||
"deg" => '\u{00B0}',
|
||||
"plusmn" => '\u{00B1}',
|
||||
"sup2" => '\u{00B2}',
|
||||
"sup3" => '\u{00B3}',
|
||||
"acute" => '\u{00B4}',
|
||||
"micro" => '\u{00B5}',
|
||||
"para" => '\u{00B6}',
|
||||
"middot" => '\u{00B7}',
|
||||
"cedil" => '\u{00B8}',
|
||||
"sup1" => '\u{00B9}',
|
||||
"ordm" => '\u{00BA}',
|
||||
"raquo" => '\u{00BB}',
|
||||
"frac14" => '\u{00BC}',
|
||||
"frac12" => '\u{00BD}',
|
||||
"frac34" => '\u{00BE}',
|
||||
"iquest" => '\u{00BF}',
|
||||
"Agrave" => '\u{00C0}',
|
||||
"Aacute" => '\u{00C1}',
|
||||
"Acirc" => '\u{00C2}',
|
||||
"Atilde" => '\u{00C3}',
|
||||
"Auml" => '\u{00C4}',
|
||||
"Aring" => '\u{00C5}',
|
||||
"AElig" => '\u{00C6}',
|
||||
"Ccedil" => '\u{00C7}',
|
||||
"Egrave" => '\u{00C8}',
|
||||
"Eacute" => '\u{00C9}',
|
||||
"Ecirc" => '\u{00CA}',
|
||||
"Euml" => '\u{00CB}',
|
||||
"Igrave" => '\u{00CC}',
|
||||
"Iacute" => '\u{00CD}',
|
||||
"Icirc" => '\u{00CE}',
|
||||
"Iuml" => '\u{00CF}',
|
||||
"ETH" => '\u{00D0}',
|
||||
"Ntilde" => '\u{00D1}',
|
||||
"Ograve" => '\u{00D2}',
|
||||
"Oacute" => '\u{00D3}',
|
||||
"Ocirc" => '\u{00D4}',
|
||||
"Otilde" => '\u{00D5}',
|
||||
"Ouml" => '\u{00D6}',
|
||||
"times" => '\u{00D7}',
|
||||
"Oslash" => '\u{00D8}',
|
||||
"Ugrave" => '\u{00D9}',
|
||||
"Uacute" => '\u{00DA}',
|
||||
"Ucirc" => '\u{00DB}',
|
||||
"Uuml" => '\u{00DC}',
|
||||
"Yacute" => '\u{00DD}',
|
||||
"THORN" => '\u{00DE}',
|
||||
"szlig" => '\u{00DF}',
|
||||
"agrave" => '\u{00E0}',
|
||||
"aacute" => '\u{00E1}',
|
||||
"acirc" => '\u{00E2}',
|
||||
"atilde" => '\u{00E3}',
|
||||
"auml" => '\u{00E4}',
|
||||
"aring" => '\u{00E5}',
|
||||
"aelig" => '\u{00E6}',
|
||||
"ccedil" => '\u{00E7}',
|
||||
"egrave" => '\u{00E8}',
|
||||
"eacute" => '\u{00E9}',
|
||||
"ecirc" => '\u{00EA}',
|
||||
"euml" => '\u{00EB}',
|
||||
"igrave" => '\u{00EC}',
|
||||
"iacute" => '\u{00ED}',
|
||||
"icirc" => '\u{00EE}',
|
||||
"iuml" => '\u{00EF}',
|
||||
"eth" => '\u{00F0}',
|
||||
"ntilde" => '\u{00F1}',
|
||||
"ograve" => '\u{00F2}',
|
||||
"oacute" => '\u{00F3}',
|
||||
"ocirc" => '\u{00F4}',
|
||||
"otilde" => '\u{00F5}',
|
||||
"ouml" => '\u{00F6}',
|
||||
"divide" => '\u{00F7}',
|
||||
"oslash" => '\u{00F8}',
|
||||
"ugrave" => '\u{00F9}',
|
||||
"uacute" => '\u{00FA}',
|
||||
"ucirc" => '\u{00FB}',
|
||||
"uuml" => '\u{00FC}',
|
||||
"yacute" => '\u{00FD}',
|
||||
"thorn" => '\u{00FE}',
|
||||
"yuml" => '\u{00FF}',
|
||||
"OElig" => '\u{0152}',
|
||||
"oelig" => '\u{0153}',
|
||||
"Scaron" => '\u{0160}',
|
||||
"scaron" => '\u{0161}',
|
||||
"Yuml" => '\u{0178}',
|
||||
"fnof" => '\u{0192}',
|
||||
"circ" => '\u{02C6}',
|
||||
"tilde" => '\u{02DC}',
|
||||
"Alpha" => '\u{0391}',
|
||||
"Beta" => '\u{0392}',
|
||||
"Gamma" => '\u{0393}',
|
||||
"Delta" => '\u{0394}',
|
||||
"Epsilon" => '\u{0395}',
|
||||
"Zeta" => '\u{0396}',
|
||||
"Eta" => '\u{0397}',
|
||||
"Theta" => '\u{0398}',
|
||||
"Iota" => '\u{0399}',
|
||||
"Kappa" => '\u{039A}',
|
||||
"Lambda" => '\u{039B}',
|
||||
"Mu" => '\u{039C}',
|
||||
"Nu" => '\u{039D}',
|
||||
"Xi" => '\u{039E}',
|
||||
"Omicron" => '\u{039F}',
|
||||
"Pi" => '\u{03A0}',
|
||||
"Rho" => '\u{03A1}',
|
||||
"Sigma" => '\u{03A3}',
|
||||
"Tau" => '\u{03A4}',
|
||||
"Upsilon" => '\u{03A5}',
|
||||
"Phi" => '\u{03A6}',
|
||||
"Chi" => '\u{03A7}',
|
||||
"Psi" => '\u{03A8}',
|
||||
"Omega" => '\u{03A9}',
|
||||
"alpha" => '\u{03B1}',
|
||||
"beta" => '\u{03B2}',
|
||||
"gamma" => '\u{03B3}',
|
||||
"delta" => '\u{03B4}',
|
||||
"epsilon" => '\u{03B5}',
|
||||
"zeta" => '\u{03B6}',
|
||||
"eta" => '\u{03B7}',
|
||||
"theta" => '\u{03B8}',
|
||||
"iota" => '\u{03B9}',
|
||||
"kappa" => '\u{03BA}',
|
||||
"lambda" => '\u{03BB}',
|
||||
"mu" => '\u{03BC}',
|
||||
"nu" => '\u{03BD}',
|
||||
"xi" => '\u{03BE}',
|
||||
"omicron" => '\u{03BF}',
|
||||
"pi" => '\u{03C0}',
|
||||
"rho" => '\u{03C1}',
|
||||
"sigmaf" => '\u{03C2}',
|
||||
"sigma" => '\u{03C3}',
|
||||
"tau" => '\u{03C4}',
|
||||
"upsilon" => '\u{03C5}',
|
||||
"phi" => '\u{03C6}',
|
||||
"chi" => '\u{03C7}',
|
||||
"psi" => '\u{03C8}',
|
||||
"omega" => '\u{03C9}',
|
||||
"thetasym" => '\u{03D1}',
|
||||
"upsih" => '\u{03D2}',
|
||||
"piv" => '\u{03D6}',
|
||||
"ensp" => '\u{2002}',
|
||||
"emsp" => '\u{2003}',
|
||||
"thinsp" => '\u{2009}',
|
||||
"zwnj" => '\u{200C}',
|
||||
"zwj" => '\u{200D}',
|
||||
"lrm" => '\u{200E}',
|
||||
"rlm" => '\u{200F}',
|
||||
"ndash" => '\u{2013}',
|
||||
"mdash" => '\u{2014}',
|
||||
"lsquo" => '\u{2018}',
|
||||
"rsquo" => '\u{2019}',
|
||||
"sbquo" => '\u{201A}',
|
||||
"ldquo" => '\u{201C}',
|
||||
"rdquo" => '\u{201D}',
|
||||
"bdquo" => '\u{201E}',
|
||||
"dagger" => '\u{2020}',
|
||||
"Dagger" => '\u{2021}',
|
||||
"bull" => '\u{2022}',
|
||||
"hellip" => '\u{2026}',
|
||||
"permil" => '\u{2030}',
|
||||
"prime" => '\u{2032}',
|
||||
"Prime" => '\u{2033}',
|
||||
"lsaquo" => '\u{2039}',
|
||||
"rsaquo" => '\u{203A}',
|
||||
"oline" => '\u{203E}',
|
||||
"frasl" => '\u{2044}',
|
||||
"euro" => '\u{20AC}',
|
||||
"image" => '\u{2111}',
|
||||
"weierp" => '\u{2118}',
|
||||
"real" => '\u{211C}',
|
||||
"trade" => '\u{2122}',
|
||||
"alefsym" => '\u{2135}',
|
||||
"larr" => '\u{2190}',
|
||||
"uarr" => '\u{2191}',
|
||||
"rarr" => '\u{2192}',
|
||||
"darr" => '\u{2193}',
|
||||
"harr" => '\u{2194}',
|
||||
"crarr" => '\u{21B5}',
|
||||
"lArr" => '\u{21D0}',
|
||||
"uArr" => '\u{21D1}',
|
||||
"rArr" => '\u{21D2}',
|
||||
"dArr" => '\u{21D3}',
|
||||
"hArr" => '\u{21D4}',
|
||||
"forall" => '\u{2200}',
|
||||
"part" => '\u{2202}',
|
||||
"exist" => '\u{2203}',
|
||||
"empty" => '\u{2205}',
|
||||
"nabla" => '\u{2207}',
|
||||
"isin" => '\u{2208}',
|
||||
"notin" => '\u{2209}',
|
||||
"ni" => '\u{220B}',
|
||||
"prod" => '\u{220F}',
|
||||
"sum" => '\u{2211}',
|
||||
"minus" => '\u{2212}',
|
||||
"lowast" => '\u{2217}',
|
||||
"radic" => '\u{221A}',
|
||||
"prop" => '\u{221D}',
|
||||
"infin" => '\u{221E}',
|
||||
"ang" => '\u{2220}',
|
||||
"and" => '\u{2227}',
|
||||
"or" => '\u{2228}',
|
||||
"cap" => '\u{2229}',
|
||||
"cup" => '\u{222A}',
|
||||
"int" => '\u{222B}',
|
||||
"there4" => '\u{2234}',
|
||||
"sim" => '\u{223C}',
|
||||
"cong" => '\u{2245}',
|
||||
"asymp" => '\u{2248}',
|
||||
"ne" => '\u{2260}',
|
||||
"equiv" => '\u{2261}',
|
||||
"le" => '\u{2264}',
|
||||
"ge" => '\u{2265}',
|
||||
"sub" => '\u{2282}',
|
||||
"sup" => '\u{2283}',
|
||||
"nsub" => '\u{2284}',
|
||||
"sube" => '\u{2286}',
|
||||
"supe" => '\u{2287}',
|
||||
"oplus" => '\u{2295}',
|
||||
"otimes" => '\u{2297}',
|
||||
"perp" => '\u{22A5}',
|
||||
"sdot" => '\u{22C5}',
|
||||
"lceil" => '\u{2308}',
|
||||
"rceil" => '\u{2309}',
|
||||
"lfloor" => '\u{230A}',
|
||||
"rfloor" => '\u{230B}',
|
||||
"lang" => '\u{2329}',
|
||||
"rang" => '\u{232A}',
|
||||
"loz" => '\u{25CA}',
|
||||
"spades" => '\u{2660}',
|
||||
"clubs" => '\u{2663}',
|
||||
"hearts" => '\u{2665}',
|
||||
"diams" => '\u{2666}',
|
||||
};
|
||||
|
|
@ -5,6 +5,7 @@ use std::rc::Rc;
|
|||
use oxc_allocator::Vec;
|
||||
use oxc_ast::{ast::*, AstBuilder};
|
||||
use oxc_span::{Atom, SPAN};
|
||||
use oxc_syntax::xml_entities::XML_ENTITIES;
|
||||
|
||||
pub use self::options::{ReactJsxOptions, ReactJsxRuntime};
|
||||
|
||||
|
|
@ -407,7 +408,9 @@ impl<'a> ReactJsx<'a> {
|
|||
) -> Expression<'a> {
|
||||
match value {
|
||||
Some(JSXAttributeValue::StringLiteral(s)) => {
|
||||
self.ast.literal_string_expression(s.clone())
|
||||
let jsx_text = Self::decode_jsx_text(&s.value);
|
||||
let literal = StringLiteral::new(s.span, jsx_text.into());
|
||||
self.ast.literal_string_expression(literal)
|
||||
}
|
||||
Some(JSXAttributeValue::Element(e)) => {
|
||||
self.transform_jsx(&JSXElementOrFragment::Element(e))
|
||||
|
|
@ -493,10 +496,8 @@ impl<'a> ReactJsx<'a> {
|
|||
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()),
|
||||
_ => {}
|
||||
if let Some(c) = XML_ENTITIES.get(word) {
|
||||
buffer.extend_from_slice(c.to_string().as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Passed: 230/1083
|
||||
Passed: 234/1083
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-numeric-separator
|
||||
|
|
@ -804,7 +804,7 @@ Passed: 230/1083
|
|||
* regression/11061/input.mjs
|
||||
* variable-declaration/non-null-in-optional-chain/input.ts
|
||||
|
||||
# babel-plugin-transform-react-jsx (81/172)
|
||||
# babel-plugin-transform-react-jsx (85/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
|
||||
|
|
@ -847,8 +847,6 @@ Passed: 230/1083
|
|||
* react/should-disallow-spread-children/input.js
|
||||
* react/should-disallow-valueless-key/input.js
|
||||
* react/should-disallow-xml-namespacing/input.js
|
||||
* react/should-escape-xhtml-jsxattribute/input.js
|
||||
* react/should-escape-xhtml-jsxattribute-babel-7/input.js
|
||||
* react/should-escape-xhtml-jsxtext/input.js
|
||||
* react/should-escape-xhtml-jsxtext-babel-7/input.js
|
||||
* react/should-handle-attributed-elements/input.js
|
||||
|
|
@ -872,8 +870,6 @@ Passed: 230/1083
|
|||
* react-automatic/should-disallow-spread-children/input.js
|
||||
* react-automatic/should-disallow-valueless-key/input.js
|
||||
* react-automatic/should-disallow-xml-namespacing/input.js
|
||||
* react-automatic/should-escape-xhtml-jsxattribute/input.js
|
||||
* react-automatic/should-escape-xhtml-jsxattribute-babel-7/input.js
|
||||
* react-automatic/should-escape-xhtml-jsxtext/input.js
|
||||
* react-automatic/should-escape-xhtml-jsxtext-babel-7/input.js
|
||||
* react-automatic/should-handle-attributed-elements/input.js
|
||||
|
|
|
|||
Loading…
Reference in a new issue