@@ -139,8 +139,8 @@ export default class HTMLElement extends Node {
139139 private _attrs : Attributes ;
140140 private _rawAttrs : RawAttributes ;
141141 private _parseOptions : Partial < Options > ;
142+ private _id : string ;
142143 public rawTagName : string ; // there is not friend funciton in es
143- public id : string ;
144144 public classList : DOMTokenList ;
145145
146146 /**
@@ -185,7 +185,7 @@ export default class HTMLElement extends Node {
185185 super ( parentNode , range ) ;
186186 this . rawTagName = tagName ;
187187 this . rawAttrs = rawAttrs || '' ;
188- this . id = keyAttrs . id || '' ;
188+ this . _id = keyAttrs . id || '' ;
189189 this . childNodes = [ ] ;
190190 this . _parseOptions = _parseOptions ;
191191 this . classList = new DOMTokenList (
@@ -248,6 +248,13 @@ export default class HTMLElement extends Node {
248248 return this . voidTag . isVoidElement ( this . localName ) ;
249249 }
250250
251+ public get id ( ) {
252+ return this . _id ;
253+ }
254+ public set id ( newid : string ) {
255+ this . setAttribute ( 'id' , newid ) ;
256+ }
257+
251258 /**
252259 * Get escpaed (as-it) text value of current node and its children.
253260 * @return {string } text content
@@ -417,7 +424,7 @@ export default class HTMLElement extends Node {
417424 res . push ( ' ' . repeat ( indention ) + str ) ;
418425 }
419426 function dfs ( node : HTMLElement ) {
420- const idStr = node . id ? `#${ node . id } ` : '' ;
427+ const idStr = node . _id ? `#${ node . _id } ` : '' ;
421428 const classStr = node . classList . length ? `.${ node . classList . value . join ( '.' ) } ` : '' ; // eslint-disable-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-call
422429 write ( `${ node . rawTagName } ${ idStr } ${ classStr } ` ) ;
423430 indention ++ ;
@@ -565,7 +572,7 @@ export default class HTMLElement extends Node {
565572 }
566573
567574 if ( child . nodeType === NodeType . ELEMENT_NODE ) {
568- if ( child . id === id ) {
575+ if ( child . _id === id ) {
569576 return child ;
570577 }
571578
@@ -716,9 +723,9 @@ export default class HTMLElement extends Node {
716723 return `${ name } =${ val } ` ;
717724 } )
718725 . join ( ' ' ) ;
719- // Update this.id
726+ // Update this._id
720727 if ( key === 'id' ) {
721- this . id = '' ;
728+ this . _id = '' ;
722729 }
723730 return this ;
724731 }
@@ -765,9 +772,9 @@ export default class HTMLElement extends Node {
765772 return `${ name } =${ val } ` ;
766773 } )
767774 . join ( ' ' ) ;
768- // Update this.id
775+ // Update this._id
769776 if ( key === 'id' ) {
770- this . id = value ;
777+ this . _id = value ;
771778 }
772779 return this ;
773780 }
@@ -793,6 +800,10 @@ export default class HTMLElement extends Node {
793800 return `${ name } =${ this . quoteAttribute ( String ( val ) ) } ` ;
794801 } )
795802 . join ( ' ' ) ;
803+ // Update this._id
804+ if ( 'id' in attributes ) {
805+ this . _id = attributes [ 'id' ] ;
806+ }
796807 return this ;
797808 }
798809
@@ -1006,6 +1017,9 @@ const kElementsClosedByClosing = {
10061017 th : { tr : true , table : true , TR : true , TABLE : true } ,
10071018 TH : { tr : true , table : true , TR : true , TABLE : true } ,
10081019} as Record < string , Record < string , boolean > > ;
1020+ const kElementsClosedByClosingExcept = {
1021+ p : { a : true , audio : true , del : true , ins : true , map : true , noscript : true , video : true } ,
1022+ } as Record < string , Record < string , boolean > > ;
10091023
10101024export interface Options {
10111025 lowerCaseTagName ?: boolean ;
@@ -1192,22 +1206,44 @@ export function base_parse(data: string, options = {} as Partial<Options>) {
11921206 continue ;
11931207 }
11941208 }
1195- if ( options . closeAllByClosing === true ) {
1196- // If tag was opened, close all nested tags
1197- let i ;
1198- for ( i = stack . length - 2 ; i >= 0 ; i -- ) {
1199- if ( stack [ i ] . rawTagName === tagName ) break ;
1200- }
1201- if ( i >= 0 ) {
1202- while ( stack . length > i ) {
1209+ const openTag =
1210+ currentParent . rawTagName ?
1211+ currentParent . rawTagName . toLowerCase ( ) :
1212+ '' ;
1213+ if ( kElementsClosedByClosingExcept [ openTag ] ) {
1214+ const closingTag = tagName . toLowerCase ( ) ;
1215+ if ( stack . length > 1 ) {
1216+ const possibleContainer = stack [ stack . length - 2 ] ;
1217+ if (
1218+ possibleContainer &&
1219+ possibleContainer . rawTagName &&
1220+ possibleContainer . rawTagName . toLowerCase ( ) === closingTag &&
1221+ ! kElementsClosedByClosingExcept [ openTag ] [ closingTag ]
1222+ ) {
12031223 // Update range end for closed tag
12041224 ( < [ number , number ] > currentParent . range ) [ 1 ] = createRange ( - 1 , Math . max ( lastTextPos , tagEndPos ) ) [ 1 ] ;
12051225 stack . pop ( ) ;
12061226 currentParent = arr_back ( stack ) ;
1227+ continue ;
12071228 }
1208- continue ;
12091229 }
12101230 }
1231+ if ( options . closeAllByClosing === true ) {
1232+ // If tag was opened, close all nested tags
1233+ let i ;
1234+ for ( i = stack . length - 2 ; i >= 0 ; i -- ) {
1235+ if ( stack [ i ] . rawTagName === tagName ) break ;
1236+ }
1237+ if ( i >= 0 ) {
1238+ while ( stack . length > i ) {
1239+ // Update range end for closed tag
1240+ ( < [ number , number ] > currentParent . range ) [ 1 ] = createRange ( - 1 , Math . max ( lastTextPos , tagEndPos ) ) [ 1 ] ;
1241+ stack . pop ( ) ;
1242+ currentParent = arr_back ( stack ) ;
1243+ }
1244+ continue ;
1245+ }
1246+ }
12111247 // Use aggressive strategy to handle unmatching markups.
12121248 break ;
12131249 }
0 commit comments