1- import * as csstree from 'css-tree'
21import { TreeNode } from './TreeNode.js'
2+ import { NODE_AT_RULE , NODE_PRELUDE_IMPORT_LAYER , NODE_PRELUDE_LAYER_NAME , parse , walk_enter_leave } from '../../css-parser/dist/index.js'
33
4- /**
5- * @typedef Location
6- * @property {number } line
7- * @property {number } column
8- * @property {number } start
9- * @property {number } end
10- */
11-
12- /**
13- * @param {import('css-tree').CssNode } node
14- * @returns {Location | undefined }
15- */
16- function get_location ( node ) {
17- let loc = node . loc
18- if ( ! loc ) return
19- return {
20- line : loc . start . line ,
21- column : loc . start . column ,
22- start : loc . start . offset ,
23- end : loc . end . offset ,
24- }
25- }
26-
27- /** @param {import('css-tree').Atrule } node */
28- function is_layer ( node ) {
29- return node . name . toLowerCase ( ) === 'layer'
4+ /** @param {string } name */
5+ function get_layer_names ( name ) {
6+ return name . split ( '.' ) . map ( ( s ) => s . trim ( ) )
307}
318
32- /**
33- * @param {import('css-tree').AtrulePrelude } prelude
34- * @returns {string[] }
35- */
36- function get_layer_names ( prelude ) {
37- return csstree
38- // @todo : fewer loops plz
39- . generate ( prelude )
40- . split ( '.' )
41- . map ( ( s ) => s . trim ( ) )
42- }
43-
44- /**
45- * @param {import('css-tree').CssNode } ast
46- */
9+ /** @param {import('../../css-parser').CSSNode } ast */
4710export function layer_tree_from_ast ( ast ) {
4811 /** @type {string[] } */
4912 let current_stack = [ ]
@@ -56,79 +19,89 @@ export function layer_tree_from_ast(ast) {
5619 return `__anonymous-${ anonymous_counter } __`
5720 }
5821
59- csstree . walk ( ast , {
60- visit : 'Atrule' ,
22+ walk_enter_leave ( ast , {
6123 enter ( node ) {
62- if ( is_layer ( node ) ) {
63- let location = get_location ( node )
24+ if ( node . type !== NODE_AT_RULE ) return
6425
65- if ( node . prelude === null ) {
66- let layer_name = get_anonymous_id ( )
67- root . add_child ( current_stack , layer_name , location )
68- current_stack . push ( layer_name )
69- } else if ( node . prelude . type === 'AtrulePrelude' ) {
70- if ( node . block === null ) {
71- // @ts -expect-error CSSTree types are not updated yet in @types/css-tree
72- let prelude = csstree . findAll ( node . prelude , n => n . type === 'Layer' ) . map ( n => n . name )
73- for ( let name of prelude ) {
74- // Split the layer name by dots to handle nested layers
75- let parts = name . split ( '.' ) . map ( ( /** @type {string } */ s ) => s . trim ( ) )
26+ if ( node . name === 'layer' ) {
27+ let has_prelude = node . has_children && node . children . some ( ( c ) => c . type === NODE_PRELUDE_LAYER_NAME )
7628
77- // Ensure all parent layers exist and add them to the tree
78- for ( let i = 0 ; i < parts . length ; i ++ ) {
79- let path = parts . slice ( 0 , i )
80- let layerName = parts [ i ]
81- // Only add location to the final layer in dotted notation
82- // Create a new copy to avoid sharing references
83- let loc = i === parts . length - 1 ? { ...location } : undefined
84- root . add_child ( path , layerName , loc )
29+ if ( ! has_prelude ) {
30+ let name = get_anonymous_id ( )
31+ root . add_child ( current_stack , name , {
32+ line : node . line ,
33+ start : node . offset ,
34+ } )
35+ current_stack . push ( name )
36+ } else {
37+ let has_block = node . has_children && node . children . some ( ( c ) => c . type !== NODE_PRELUDE_LAYER_NAME )
38+ if ( ! has_block ) {
39+ for ( let child of node . children ) {
40+ if ( child . type === NODE_PRELUDE_LAYER_NAME ) {
41+ root . add_child ( current_stack , child . text , {
42+ line : node . line ,
43+ start : node . offset ,
44+ } )
8545 }
8646 }
8747 } else {
88- for ( let layer_name of get_layer_names ( node . prelude ) ) {
89- root . add_child ( current_stack , layer_name , location )
90- current_stack . push ( layer_name )
48+ for ( let child of node . children ) {
49+ if ( child . type === NODE_PRELUDE_LAYER_NAME ) {
50+ root . add_child ( current_stack , child . text , {
51+ line : node . line ,
52+ start : node . offset ,
53+ } )
54+ current_stack . push ( child . text )
55+ }
9156 }
9257 }
9358 }
94- } else if ( node . name . toLowerCase ( ) === 'import' && node . prelude !== null && node . prelude . type === 'AtrulePrelude' ) {
95- let location = get_location ( node )
96- let prelude = node . prelude
97-
59+ } else if ( node . name === 'import' ) {
9860 // @import url("foo.css") layer(test);
9961 // OR
10062 // @import url("foo.css") layer(test.nested);
101- // @ts -expect-error CSSTree types are not updated to v3 yet
102- let layer = csstree . find ( prelude , n => n . type === 'Layer' )
103- if ( layer ) {
104- // @ts -expect-error CSSTree types are not updated to v3 yet
105- for ( let layer_name of get_layer_names ( layer ) ) {
106- root . add_child ( current_stack , layer_name , location )
107- current_stack . push ( layer_name )
63+ let layerNode = node . children . find ( ( child ) => child . type === NODE_PRELUDE_IMPORT_LAYER )
64+ if ( layerNode ) {
65+ if ( layerNode . name . trim ( ) ) {
66+ for ( let layer_name of get_layer_names ( layerNode . name ) ) {
67+ root . add_child ( current_stack , layer_name , {
68+ line : node . line ,
69+ start : node . offset ,
70+ } )
71+ current_stack . push ( layer_name )
72+ }
73+ } else {
74+ // @import url("foo.css") layer;
75+ let name = get_anonymous_id ( )
76+ root . add_child ( [ ] , name , {
77+ line : node . line ,
78+ start : node . offset ,
79+ } )
10880 }
109- return this . skip
110- }
111-
112- // @import url("foo.css") layer;
113- let layer_keyword = csstree . find ( prelude , n => n . type === 'Identifier' && n . name . toLowerCase ( ) === 'layer' )
114- if ( layer_keyword ) {
115- root . add_child ( [ ] , get_anonymous_id ( ) , location )
116- return this . skip
11781 }
11882 }
11983 } ,
12084 leave ( node ) {
121- if ( is_layer ( node ) ) {
122- if ( node . prelude !== null && node . prelude . type === 'AtrulePrelude' ) {
123- let layer_names = get_layer_names ( node . prelude )
124- for ( let i = 0 ; i < layer_names . length ; i ++ ) {
125- current_stack . pop ( )
85+ if ( node . type !== NODE_AT_RULE ) return
86+
87+ if ( node . name === 'layer' ) {
88+ let has_prelude = node . has_children && node . children . some ( ( c ) => c . type === NODE_PRELUDE_LAYER_NAME )
89+ if ( has_prelude ) {
90+ let has_block = node . has_children && node . children . some ( ( c ) => c . type !== NODE_PRELUDE_LAYER_NAME )
91+ if ( has_block ) {
92+ let name = node . children . find ( ( child ) => child . type === NODE_PRELUDE_LAYER_NAME )
93+ if ( name ) {
94+ let layer_names = get_layer_names ( name . text )
95+ for ( let i = 0 ; i < layer_names . length ; i ++ ) {
96+ current_stack . pop ( )
97+ }
98+ }
12699 }
127100 } else {
128101 // pop the anonymous layer
129102 current_stack . pop ( )
130103 }
131- } else if ( node . name . toLowerCase ( ) === 'import' ) {
104+ } else if ( node . name === 'import' ) {
132105 // clear the stack, imports can not be nested
133106 current_stack . length = 0
134107 }
@@ -142,13 +115,11 @@ export function layer_tree_from_ast(ast) {
142115 * @param {string } css
143116 */
144117export function layer_tree ( css ) {
145- let ast = csstree . parse ( css , {
146- positions : true ,
147- parseAtrulePrelude : true ,
148- parseValue : false ,
149- parseRulePrelude : false ,
150- parseCustomProperty : false ,
118+ let ast = parse ( css , {
119+ parse_selectors : false ,
120+ parse_values : false ,
121+ skip_comments : true ,
151122 } )
152123
153124 return layer_tree_from_ast ( ast )
154- }
125+ }
0 commit comments