@@ -4720,7 +4720,10 @@ const _attrValueOf = (i) => {
47204720 * @param {number } i the attribute
47214721 * @returns {string } the value with its character references resolved
47224722 */
4723- const _attrValueDecoded = ( i ) => decodeEntities ( _attrValueOf ( i ) , true ) ;
4723+ const _attrValueDecoded = ( i ) =>
4724+ xmlMode
4725+ ? decodeXmlEntities ( _attrValueOf ( i ) )
4726+ : decodeEntities ( _attrValueOf ( i ) , true ) ;
47244727
47254728// Linear name lookup in a run — attribute lists are short, a loop beats a Map.
47264729/** @type {(start: number, count: number, name: string) => number } */
@@ -5694,6 +5697,51 @@ const SHELL_END_BODY = 4;
56945697let eofInTag = false ;
56955698let sawSelectedContent = false ;
56965699const decode = decodeEntities ;
5700+
5701+ const XML_NAMED_REFERENCES = {
5702+ amp : "&" ,
5703+ apos : "'" ,
5704+ gt : ">" ,
5705+ lt : "<" ,
5706+ quot : '"'
5707+ } ;
5708+
5709+ /**
5710+ * @param {number } code Unicode code point
5711+ * @returns {boolean } whether XML 1.0 permits the character
5712+ */
5713+ const isXmlChar = ( code ) =>
5714+ code === CC_TAB ||
5715+ code === CC_LF ||
5716+ code === 0x0d ||
5717+ ( code >= 0x20 && code <= 0xd7ff ) ||
5718+ ( code >= 0xe000 && code <= 0xfffd ) ||
5719+ ( code >= 0x10000 && code <= 0x10ffff ) ;
5720+
5721+ /**
5722+ * Decode the five predefined XML entities and numeric character references.
5723+ * Unlike HTML, XML has no built-in entity table beyond those five names.
5724+ * @param {string } value source text
5725+ * @returns {string } decoded text
5726+ */
5727+ const decodeXmlEntities = ( value ) =>
5728+ value . replace (
5729+ / & (?: # (?: x ( [ \d a - f ] + ) | ( \d + ) ) | ( [ a - z ] + ) ) ; / gi,
5730+ ( match , hex , decimal , name ) => {
5731+ if ( name !== undefined ) {
5732+ return Object . prototype . hasOwnProperty . call ( XML_NAMED_REFERENCES , name )
5733+ ? XML_NAMED_REFERENCES [
5734+ /** @type {keyof typeof XML_NAMED_REFERENCES } */ ( name )
5735+ ]
5736+ : match ;
5737+ }
5738+ const code = Number . parseInt (
5739+ hex === undefined ? decimal : hex ,
5740+ hex ? 16 : 10
5741+ ) ;
5742+ return isXmlChar ( code ) ? String . fromCodePoint ( code ) : "\uFFFD" ;
5743+ }
5744+ ) ;
56975745/** @type {MutableToken } */
56985746const tok = {
56995747 type : TOKEN_EOF ,
@@ -8280,7 +8328,11 @@ const handleTextToken = (input, start, end) => {
82808328 _namespaceOf ( top ) === NS_HTML &&
82818329 NO_DECODE_TEXT . has ( _tagNameOf ( top ) ) &&
82828330 ( mode === MODE_TEXT || mode === MODE_IN_BODY ) ;
8283- let data = noDecode ? normalized : decode ( normalized , false ) ;
8331+ let data = noDecode
8332+ ? normalized
8333+ : xmlMode
8334+ ? decodeXmlEntities ( normalized )
8335+ : decode ( normalized , false ) ;
82848336 // In RAWTEXT/RCDATA/script/PLAINTEXT, NULL becomes U+FFFD (tokenizer
82858337 // rule); in data state NULLs pass through to be dropped in "in body".
82868338 if ( rawMode && inputHasNul && data . includes ( "\0" ) ) {
@@ -8364,7 +8416,7 @@ const handleStartTagToken = (
83648416 const name = xmlMode
83658417 ? input . slice ( nameStart , nameEnd )
83668418 : internLowerName ( TAG_NAME_INTERN , input , nameStart , nameEnd ) ;
8367- if ( name === "selectedcontent" ) sawSelectedContent = true ;
8419+ if ( ! xmlMode && name === "selectedcontent" ) sawSelectedContent = true ;
83688420 tok . type = TOKEN_START_TAG ;
83698421 tok . name = name ;
83708422 // The reused token carries the tag's attribute run; every consumer of
0 commit comments