@@ -39,24 +39,112 @@ CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
3939 */
4040CSSOM . CSSStyleSheet . prototype . insertRule = function ( rule , index ) {
4141 if ( rule === undefined && index === undefined ) {
42- errorUtils . throwMissingArguments ( this , 'insertRule' , 'CSSStyleSheet' ) ;
42+ errorUtils . throwMissingArguments ( this , 'insertRule' , this . constructor . name ) ;
4343 }
4444 if ( index === void 0 ) {
4545 index = 0 ;
4646 }
47- if ( index < 0 || index > this . cssRules . length ) {
48- errorUtils . throwIndexSizeError ( this ) ;
47+ index = Number ( index ) ;
48+ if ( index < 0 ) {
49+ index = 4294967296 + index ;
50+ }
51+ if ( index > this . cssRules . length ) {
52+ errorUtils . throwIndexError ( this , 'insertRule' , this . constructor . name , index , this . cssRules . length ) ;
4953 }
54+
5055 var ruleToParse = String ( rule ) ;
5156 var parsedSheet = CSSOM . parse ( ruleToParse ) ;
5257 if ( parsedSheet . cssRules . length !== 1 ) {
53- var domExceptionName = "SyntaxError" ;
54- if ( ruleToParse . trimStart ( ) . startsWith ( '@namespace' ) ) {
55- domExceptionName = "InvalidStateError" ;
56- }
57- errorUtils . throwParseError ( this , 'insertRule' , 'CSSStyleSheet' , ruleToParse , domExceptionName ) ;
58+ errorUtils . throwParseError ( this , 'insertRule' , this . constructor . name , ruleToParse , 'SyntaxError' ) ;
5859 }
5960 var cssRule = parsedSheet . cssRules [ 0 ] ;
61+
62+ // Helper function to find the last index of a specific rule constructor
63+ function findLastIndexOfConstructor ( rules , constructorName ) {
64+ for ( var i = rules . length - 1 ; i >= 0 ; i -- ) {
65+ if ( rules [ i ] . constructor . name === constructorName ) {
66+ return i ;
67+ }
68+ }
69+ return - 1 ;
70+ }
71+
72+ // Helper function to find the first index of a rule that's NOT of specified constructors
73+ function findFirstNonConstructorIndex ( rules , constructorNames ) {
74+ for ( var i = 0 ; i < rules . length ; i ++ ) {
75+ if ( constructorNames . indexOf ( rules [ i ] . constructor . name ) === - 1 ) {
76+ return i ;
77+ }
78+ }
79+ return rules . length ;
80+ }
81+
82+ // Validate rule ordering based on CSS specification
83+ if ( cssRule . constructor . name === 'CSSImportRule' ) {
84+ // @import rules cannot be inserted after @layer rules that already exist
85+ // They can only be inserted at the beginning or after other @import rules
86+ var firstLayerIndex = findFirstNonConstructorIndex ( this . cssRules , [ 'CSSImportRule' ] ) ;
87+ if ( firstLayerIndex < this . cssRules . length && this . cssRules [ firstLayerIndex ] . constructor . name === 'CSSLayerStatementRule' && index > firstLayerIndex ) {
88+ errorUtils . throwError ( this , 'DOMException' ,
89+ "Failed to execute 'insertRule' on '" + this . constructor . name + "': Failed to insert the rule." ,
90+ 'HierarchyRequestError' ) ;
91+ }
92+
93+ // Also cannot insert after @namespace or other rules
94+ var firstNonImportIndex = findFirstNonConstructorIndex ( this . cssRules , [ 'CSSImportRule' ] ) ;
95+ if ( index > firstNonImportIndex && firstNonImportIndex < this . cssRules . length &&
96+ this . cssRules [ firstNonImportIndex ] . constructor . name !== 'CSSLayerStatementRule' ) {
97+ errorUtils . throwError ( this , 'DOMException' ,
98+ "Failed to execute 'insertRule' on '" + this . constructor . name + "': Failed to insert the rule." ,
99+ 'HierarchyRequestError' ) ;
100+ }
101+ } else if ( cssRule . constructor . name === 'CSSNamespaceRule' ) {
102+ // @namespace rules can come after @layer and @import, but before any other rules
103+ // They cannot come before @import rules
104+ var firstImportIndex = - 1 ;
105+ for ( var i = 0 ; i < this . cssRules . length ; i ++ ) {
106+ if ( this . cssRules [ i ] . constructor . name === 'CSSImportRule' ) {
107+ firstImportIndex = i ;
108+ break ;
109+ }
110+ }
111+ var firstNonImportNamespaceIndex = findFirstNonConstructorIndex ( this . cssRules , [
112+ 'CSSLayerStatementRule' ,
113+ 'CSSImportRule' ,
114+ 'CSSNamespaceRule'
115+ ] ) ;
116+
117+ // Cannot insert before @import rules
118+ if ( firstImportIndex !== - 1 && index <= firstImportIndex ) {
119+ errorUtils . throwError ( this , 'DOMException' ,
120+ "Failed to execute 'insertRule' on '" + this . constructor . name + "': Failed to insert the rule." ,
121+ 'HierarchyRequestError' ) ;
122+ }
123+
124+ // Cannot insert after other types of rules
125+ if ( index > firstNonImportNamespaceIndex ) {
126+ errorUtils . throwError ( this , 'DOMException' ,
127+ "Failed to execute 'insertRule' on '" + this . constructor . name + "': Failed to insert the rule." ,
128+ 'HierarchyRequestError' ) ;
129+ }
130+ } else if ( cssRule . constructor . name === 'CSSLayerStatementRule' ) {
131+ // @layer statement rules can be inserted anywhere before @import and @namespace
132+ // No additional restrictions beyond what's already handled
133+ } else {
134+ // Any other rule cannot be inserted before @import and @namespace
135+ var firstNonSpecialRuleIndex = findFirstNonConstructorIndex ( this . cssRules , [
136+ 'CSSLayerStatementRule' ,
137+ 'CSSImportRule' ,
138+ 'CSSNamespaceRule'
139+ ] ) ;
140+
141+ if ( index < firstNonSpecialRuleIndex ) {
142+ errorUtils . throwError ( this , 'DOMException' ,
143+ "Failed to execute 'insertRule' on '" + this . constructor . name + "': Failed to insert the rule." ,
144+ 'HierarchyRequestError' ) ;
145+ }
146+ }
147+
60148 cssRule . __parentStyleSheet = this ;
61149 this . cssRules . splice ( index , 0 , cssRule ) ;
62150 return index ;
@@ -78,21 +166,21 @@ CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
78166 */
79167CSSOM . CSSStyleSheet . prototype . deleteRule = function ( index ) {
80168 if ( index === undefined ) {
81- errorUtils . throwMissingArguments ( this , 'deleteRule' , 'CSSStyleSheet' ) ;
169+ errorUtils . throwMissingArguments ( this , 'deleteRule' , this . constructor . name ) ;
82170 }
83171 index = Number ( index ) ;
84172 if ( index < 0 ) {
85173 index = 4294967296 + index ;
86174 }
87175 if ( index >= this . cssRules . length ) {
88- errorUtils . throwIndexError ( this , 'deleteRule' , 'CSSStyleSheet' , index , this . cssRules . length ) ;
176+ errorUtils . throwIndexError ( this , 'deleteRule' , this . constructor . name , index , this . cssRules . length ) ;
89177 }
90178 if ( this . cssRules [ index ] && this . cssRules [ index ] . constructor . name == "CSSNamespaceRule" ) {
91179 var shouldContinue = this . cssRules . every ( function ( rule ) {
92180 return [ 'CSSImportRule' , 'CSSLayerStatementRule' , 'CSSNamespaceRule' ] . indexOf ( rule . constructor . name ) !== - 1
93181 } ) ;
94182 if ( ! shouldContinue ) {
95- errorUtils . throwError ( this , 'DOMException' , "Failed to execute 'deleteRule' on 'CSSStyleSheet': Deleting a CSSNamespaceRule is not allowed when there is rules other than @import, @layer statement, or @namespace ." , "InvalidStateError" ) ;
183+ errorUtils . throwError ( this , 'DOMException' , "Failed to execute 'deleteRule' on '" + this . constructor . name + "': Failed to delete rule .", "InvalidStateError" ) ;
96184 }
97185 }
98186 this . cssRules . splice ( index , 1 ) ;
0 commit comments