@@ -39,14 +39,6 @@ const enumTokenHints = new Set([
3939function reject ( reason ) {
4040 throw new Error ( reason ?? 'Parsing aborted' ) ;
4141}
42- function removeNode ( node , parent ) {
43- // @ts -ignore
44- const index = parent . chi . indexOf ( node ) ;
45- if ( index != - 1 ) {
46- parent . chi . splice ( index , 1 ) ;
47- node . parent = null ;
48- }
49- }
5042function normalizeVisitorKeyName ( keyName ) {
5143 return keyName . replace ( / - ( [ a - z ] ) / g, ( all , one ) => one . toUpperCase ( ) ) ;
5244}
@@ -126,6 +118,8 @@ async function doParse(iter, options = {}) {
126118 const stats = {
127119 src : options . src ?? '' ,
128120 bytesIn : 0 ,
121+ nodesCount : 0 ,
122+ tokensCount : 0 ,
129123 importedBytesIn : 0 ,
130124 parse : `0ms` ,
131125 minify : `0ms` ,
@@ -154,14 +148,75 @@ async function doParse(iter, options = {}) {
154148 src : ''
155149 } ;
156150 }
157- let item ;
158- let node ;
151+ const valuesHandlers = new Map ;
152+ const preValuesHandlers = new Map ;
153+ const postValuesHandlers = new Map ;
154+ const preVisitorsHandlersMap = new Map ;
155+ const visitorsHandlersMap = new Map ;
156+ const postVisitorsHandlersMap = new Map ;
157+ const allValuesHandlers = [ ] ;
159158 const rawTokens = [ ] ;
160159 const imports = [ ] ;
160+ let item ;
161+ let node ;
161162 // @ts -ignore ignore error
162163 let isAsync = typeof iter [ Symbol . asyncIterator ] === 'function' ;
164+ if ( options . visitor != null ) {
165+ for ( const [ key , value ] of Object . entries ( options . visitor ) ) {
166+ if ( key in EnumToken ) {
167+ if ( typeof value == 'function' ) {
168+ valuesHandlers . set ( EnumToken [ key ] , value ) ;
169+ }
170+ else if ( typeof value == 'object' && 'type' in value && 'handler' in value && value . type in WalkerValueEvent ) {
171+ if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Enter ) {
172+ preValuesHandlers . set ( EnumToken [ key ] , value . handler ) ;
173+ }
174+ else if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Leave ) {
175+ postValuesHandlers . set ( EnumToken [ key ] , value . handler ) ;
176+ }
177+ }
178+ else {
179+ errors . push ( { action : 'ignore' , message : `doParse: visitor.${ key } is not a valid key name` } ) ;
180+ }
181+ }
182+ else if ( [ 'Declaration' , 'Rule' , 'AtRule' , 'KeyframesRule' , 'KeyframesAtRule' ] . includes ( key ) ) {
183+ if ( typeof value == 'function' ) {
184+ visitorsHandlersMap . set ( key , value ) ;
185+ }
186+ else if ( typeof value == 'object' ) {
187+ if ( 'type' in value && 'handler' in value && value . type in WalkerValueEvent ) {
188+ if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Enter ) {
189+ preVisitorsHandlersMap . set ( key , value . handler ) ;
190+ }
191+ else if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Leave ) {
192+ postVisitorsHandlersMap . set ( key , value . handler ) ;
193+ }
194+ }
195+ else {
196+ visitorsHandlersMap . set ( key , value ) ;
197+ }
198+ }
199+ else {
200+ errors . push ( { action : 'ignore' , message : `doParse: visitor.${ key } is not a valid key name` } ) ;
201+ }
202+ }
203+ else {
204+ errors . push ( { action : 'ignore' , message : `doParse: visitor.${ key } is not a valid key name` } ) ;
205+ }
206+ }
207+ if ( preValuesHandlers . size > 0 ) {
208+ allValuesHandlers . push ( preValuesHandlers ) ;
209+ }
210+ if ( valuesHandlers . size > 0 ) {
211+ allValuesHandlers . push ( valuesHandlers ) ;
212+ }
213+ if ( postValuesHandlers . size > 0 ) {
214+ allValuesHandlers . push ( postValuesHandlers ) ;
215+ }
216+ }
163217 while ( item = isAsync ? ( await iter . next ( ) ) . value : iter . next ( ) . value ) {
164218 stats . bytesIn = item . bytesIn ;
219+ stats . tokensCount ++ ;
165220 rawTokens . push ( item ) ;
166221 if ( item . hint != null && BadTokensTypes . includes ( item . hint ) ) {
167222 const node = getTokenType ( item . token , item . hint ) ;
@@ -189,7 +244,7 @@ async function doParse(iter, options = {}) {
189244 ast . loc . end = item . end ;
190245 }
191246 if ( item . token == ';' || item . token == '{' ) {
192- node = parseNode ( tokens , context , options , errors , src , map , rawTokens ) ;
247+ node = parseNode ( tokens , context , options , errors , src , map , rawTokens , stats ) ;
193248 rawTokens . length = 0 ;
194249 if ( node != null ) {
195250 if ( 'chi' in node ) {
@@ -233,7 +288,7 @@ async function doParse(iter, options = {}) {
233288 map = new Map ;
234289 }
235290 else if ( item . token == '}' ) {
236- parseNode ( tokens , context , options , errors , src , map , rawTokens ) ;
291+ parseNode ( tokens , context , options , errors , src , map , rawTokens , stats ) ;
237292 rawTokens . length = 0 ;
238293 if ( context . loc != null ) {
239294 context . loc . end = item . end ;
@@ -254,7 +309,7 @@ async function doParse(iter, options = {}) {
254309 }
255310 }
256311 if ( tokens . length > 0 ) {
257- node = parseNode ( tokens , context , options , errors , src , map , rawTokens ) ;
312+ node = parseNode ( tokens , context , options , errors , src , map , rawTokens , stats ) ;
258313 rawTokens . length = 0 ;
259314 if ( node != null ) {
260315 if ( node . typ == EnumToken . AtRuleNodeType && node . nam == 'import' ) {
@@ -317,78 +372,7 @@ async function doParse(iter, options = {}) {
317372 if ( options . expandNestingRules ) {
318373 ast = expand ( ast ) ;
319374 }
320- const valuesHandlers = new Map ;
321- const preValuesHandlers = new Map ;
322- const postValuesHandlers = new Map ;
323- const preVisitorsHandlersMap = new Map ;
324- const visitorsHandlersMap = new Map ;
325- const postVisitorsHandlersMap = new Map ;
326- const allValuesHandlers = [ ] ;
327- if ( options . visitor != null ) {
328- for ( const [ key , value ] of Object . entries ( options . visitor ) ) {
329- if ( key in EnumToken ) {
330- if ( typeof value == 'function' ) {
331- valuesHandlers . set ( EnumToken [ key ] , value ) ;
332- }
333- else if ( typeof value == 'object' && 'type' in value && 'handler' in value && value . type in WalkerValueEvent ) {
334- if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Enter ) {
335- preValuesHandlers . set ( EnumToken [ key ] , value . handler ) ;
336- }
337- else if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Leave ) {
338- postValuesHandlers . set ( EnumToken [ key ] , value . handler ) ;
339- }
340- }
341- else {
342- errors . push ( { action : 'ignore' , message : `doParse: visitor.${ key } is not a valid key name` } ) ;
343- }
344- }
345- else if ( [ 'Declaration' , 'Rule' , 'AtRule' , 'KeyframesRule' , 'KeyframesAtRule' ] . includes ( key ) ) {
346- if ( typeof value == 'function' ) {
347- visitorsHandlersMap . set ( key , value ) ;
348- }
349- else if ( typeof value == 'object' ) {
350- if ( 'type' in value && 'handler' in value && value . type in WalkerValueEvent ) {
351- if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Enter ) {
352- preVisitorsHandlersMap . set ( key , value . handler ) ;
353- }
354- else if ( WalkerValueEvent [ value . type ] == WalkerValueEvent . Leave ) {
355- postVisitorsHandlersMap . set ( key , value . handler ) ;
356- }
357- }
358- else {
359- visitorsHandlersMap . set ( key , value ) ;
360- }
361- }
362- else {
363- errors . push ( { action : 'ignore' , message : `doParse: visitor.${ key } is not a valid key name` } ) ;
364- }
365- }
366- else {
367- errors . push ( { action : 'ignore' , message : `doParse: visitor.${ key } is not a valid key name` } ) ;
368- }
369- }
370- if ( preValuesHandlers . size > 0 ) {
371- allValuesHandlers . push ( preValuesHandlers ) ;
372- }
373- if ( valuesHandlers . size > 0 ) {
374- allValuesHandlers . push ( valuesHandlers ) ;
375- }
376- if ( postValuesHandlers . size > 0 ) {
377- allValuesHandlers . push ( postValuesHandlers ) ;
378- }
379- }
380375 for ( const result of walk ( ast ) ) {
381- if ( result . parent != null && ! isNodeAllowedInContext ( result . node , result . parent ) ) {
382- errors . push ( {
383- action : 'drop' ,
384- message : `${ EnumToken [ result . parent . typ ] } : child ${ EnumToken [ result . node . typ ] } ${ result . node . typ == EnumToken . DeclarationNodeType ? ` '${ result . node . nam } '` : result . node . typ == EnumToken . AtRuleNodeType || result . node . typ == EnumToken . KeyframesAtRuleNodeType ? ` '@${ result . node . nam } '` : '' } not allowed in context${ result . parent . typ == EnumToken . AtRuleNodeType ? ` '@${ result . parent . nam } '` : result . parent . typ == EnumToken . StyleSheetNodeType ? ` 'stylesheet'` : '' } ` ,
385- // @ts -ignore
386- location : result . node . loc ?? map . get ( result . node ) ?? null
387- } ) ;
388- // @ts -ignore
389- removeNode ( result . node , result . parent ) ;
390- continue ;
391- }
392376 if ( allValuesHandlers . length > 0 || preVisitorsHandlersMap . size > 0 || visitorsHandlersMap . size > 0 || postVisitorsHandlersMap . size > 0 ) {
393377 if ( ( result . node . typ == EnumToken . DeclarationNodeType &&
394378 ( preVisitorsHandlersMap . has ( 'Declaration' ) || visitorsHandlersMap . has ( 'Declaration' ) || postVisitorsHandlersMap . has ( 'Declaration' ) ) ) ||
@@ -573,7 +557,7 @@ function getLastNode(context) {
573557 }
574558 return null ;
575559}
576- function parseNode ( results , context , options , errors , src , map , rawTokens ) {
560+ function parseNode ( results , context , options , errors , src , map , rawTokens , stats ) {
577561 let tokens = [ ] ;
578562 for ( const t of results ) {
579563 const node = getTokenType ( t . token , t . hint ) ;
@@ -596,6 +580,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
596580 }
597581 loc = location ;
598582 context . chi . push ( tokens [ i ] ) ;
583+ stats . nodesCount ++ ;
599584 if ( options . sourcemap ) {
600585 tokens [ i ] . loc = loc ;
601586 }
@@ -774,13 +759,18 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
774759 isValid = false ;
775760 }
776761 }
762+ const isAllowed = isNodeAllowedInContext ( node , context ) ;
777763 // @ts -ignore
778764 const valid = options . validation == ValidationLevel . None ? {
779765 valid : SyntaxValidationResult . Valid ,
780766 error : '' ,
781767 node,
782768 syntax : '@' + node . nam
783- } : isValid ? ( node . typ == EnumToken . KeyframesAtRuleNodeType ? validateAtRuleKeyframes ( node ) : validateAtRule ( node , options , context ) ) : {
769+ } : ! isAllowed ? {
770+ valid : SyntaxValidationResult . Drop ,
771+ node,
772+ syntax : '@' + node . nam ,
773+ error : `${ EnumToken [ context . typ ] } : child ${ EnumToken [ node . typ ] } not allowed in context${ context . typ == EnumToken . AtRuleNodeType ? ` '@${ context . nam } '` : context . typ == EnumToken . StyleSheetNodeType ? ` 'stylesheet'` : '' } ` } : isValid ? ( node . typ == EnumToken . KeyframesAtRuleNodeType ? validateAtRuleKeyframes ( node ) : validateAtRule ( node , options , context ) ) : {
784774 valid : SyntaxValidationResult . Drop ,
785775 node,
786776 syntax : '@' + node . nam ,
@@ -804,6 +794,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
804794 } ) , '' ) ;
805795 }
806796 context . chi . push ( node ) ;
797+ stats . nodesCount ++ ;
807798 Object . defineProperties ( node , {
808799 parent : { ...definedPropertySettings , value : context } ,
809800 validSyntax : { ...definedPropertySettings , value : valid . valid == SyntaxValidationResult . Valid }
@@ -907,10 +898,14 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
907898 // @ts -ignore
908899 context . chi . push ( node ) ;
909900 Object . defineProperty ( node , 'parent' , { ...definedPropertySettings , value : context } ) ;
901+ const isAllowed = isNodeAllowedInContext ( node , context ) ;
910902 // @ts -ignore
911903 const valid = options . validation == ValidationLevel . None ? {
912904 valid : SyntaxValidationResult . Valid ,
913905 error : null
906+ } : ! isAllowed ? {
907+ valid : SyntaxValidationResult . Drop ,
908+ error : `${ EnumToken [ context . typ ] } : child ${ EnumToken [ node . typ ] } not allowed in context${ context . typ == EnumToken . AtRuleNodeType ? ` '@${ context . nam } '` : context . typ == EnumToken . StyleSheetNodeType ? ` 'stylesheet'` : '' } `
914909 } : ruleType == EnumToken . KeyFramesRuleNodeType ? validateKeyframeSelector ( tokens ) : validateSelector ( tokens , options , context ) ;
915910 if ( valid . valid != SyntaxValidationResult . Valid ) {
916911 // @ts -ignore
@@ -1025,6 +1020,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
10251020 node . loc . end = { ...map . get ( delim ) . end } ;
10261021 }
10271022 context . chi . push ( node ) ;
1023+ stats . nodesCount ++ ;
10281024 }
10291025 return null ;
10301026 }
@@ -1056,13 +1052,21 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
10561052 if ( context . typ == EnumToken . StyleSheetNodeType && options . lenient ) {
10571053 Object . assign ( node , { typ : EnumToken . InvalidDeclarationNodeType } ) ;
10581054 context . chi . push ( node ) ;
1055+ stats . nodesCount ++ ;
10591056 return null ;
10601057 }
10611058 const result = parseDeclarationNode ( node , errors , location ) ;
10621059 Object . defineProperty ( result , 'parent' , { ...definedPropertySettings , value : context } ) ;
10631060 if ( result != null ) {
10641061 if ( options . validation == ValidationLevel . All ) {
1065- const valid = evaluateSyntax ( result , context , options ) ;
1062+ const isAllowed = isNodeAllowedInContext ( node , context ) ;
1063+ // @ts -ignore
1064+ const valid = ! isAllowed ? {
1065+ valid : SyntaxValidationResult . Drop ,
1066+ error : `${ EnumToken [ node . typ ] } not allowed in context${ context . typ == EnumToken . AtRuleNodeType ? ` '@${ context . nam } '` : context . typ == EnumToken . StyleSheetNodeType ? ` 'stylesheet'` : '' } ` ,
1067+ node,
1068+ syntax : null
1069+ } : evaluateSyntax ( result , context , options ) ;
10661070 Object . defineProperty ( result , 'validSyntax' , {
10671071 ...definedPropertySettings ,
10681072 value : valid . valid == SyntaxValidationResult . Valid
@@ -1082,6 +1086,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
10821086 }
10831087 }
10841088 context . chi . push ( result ) ;
1089+ stats . nodesCount ++ ;
10851090 }
10861091 return null ;
10871092 }
0 commit comments