1
1
'use strict' ;
2
2
3
3
const postcss = require ( 'postcss' ) ;
4
- const Tokenizer = require ( 'css -selector-tokenizer ' ) ;
4
+ const selectorParser = require ( 'postcss -selector-parser ' ) ;
5
5
6
6
const hasOwnProperty = Object . prototype . hasOwnProperty ;
7
7
8
- function getSingleLocalNamesForComposes ( selectors ) {
9
- return selectors . nodes . map ( node => {
8
+ function getSingleLocalNamesForComposes ( root ) {
9
+ return root . nodes . map ( node => {
10
10
if ( node . type !== 'selector' || node . nodes . length !== 1 ) {
11
11
throw new Error (
12
- 'composition is only allowed when selector is single :local class name not in "' +
13
- Tokenizer . stringify ( selectors ) +
14
- '"'
12
+ `composition is only allowed when selector is single :local class name not in "${ root } "`
15
13
) ;
16
14
}
17
15
node = node . nodes [ 0 ] ;
18
16
if (
19
- node . type !== 'nested- pseudo-class ' ||
20
- node . name !== 'local' ||
17
+ node . type !== 'pseudo' ||
18
+ node . value !== ': local' ||
21
19
node . nodes . length !== 1
22
20
) {
23
21
throw new Error (
24
22
'composition is only allowed when selector is single :local class name not in "' +
25
- Tokenizer . stringify ( selectors ) +
23
+ root +
26
24
'", "' +
27
- Tokenizer . stringify ( node ) +
25
+ node +
28
26
'" is weird'
29
27
) ;
30
28
}
31
- node = node . nodes [ 0 ] ;
32
- if ( node . type !== 'selector' || node . nodes . length !== 1 ) {
29
+ node = node . first ;
30
+ if ( node . type !== 'selector' || node . length !== 1 ) {
33
31
throw new Error (
34
32
'composition is only allowed when selector is single :local class name not in "' +
35
- Tokenizer . stringify ( selectors ) +
33
+ root +
36
34
'", "' +
37
- Tokenizer . stringify ( node ) +
35
+ node +
38
36
'" is weird'
39
37
) ;
40
38
}
41
- node = node . nodes [ 0 ] ;
39
+ node = node . first ;
42
40
if ( node . type !== 'class' ) {
43
41
// 'id' is not possible, because you can't compose ids
44
42
throw new Error (
45
43
'composition is only allowed when selector is single :local class name not in "' +
46
- Tokenizer . stringify ( selectors ) +
44
+ root +
47
45
'", "' +
48
- Tokenizer . stringify ( node ) +
46
+ node +
49
47
'" is weird'
50
48
) ;
51
49
}
52
- return node . name ;
50
+ return node . value ;
53
51
} ) ;
54
52
}
55
53
@@ -74,40 +72,45 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
74
72
}
75
73
76
74
function localizeNode ( node ) {
77
- const newNode = Object . create ( node ) ;
78
75
switch ( node . type ) {
79
76
case 'selector' :
80
- newNode . nodes = node . nodes . map ( localizeNode ) ;
81
- return newNode ;
77
+ node . nodes = node . map ( localizeNode ) ;
78
+ return node ;
82
79
case 'class' :
80
+ return selectorParser . className ( {
81
+ value : exportScopedName ( node . value ) ,
82
+ } ) ;
83
83
case 'id' : {
84
- newNode . name = exportScopedName ( node . name ) ;
85
- return newNode ;
84
+ return selectorParser . id ( {
85
+ value : exportScopedName ( node . value ) ,
86
+ } ) ;
86
87
}
87
88
}
88
89
throw new Error (
89
- node . type +
90
- ' ("' +
91
- Tokenizer . stringify ( node ) +
92
- '") is not allowed in a :local block'
90
+ `${ node . type } ("${ node } ") is not allowed in a :local block`
93
91
) ;
94
92
}
95
93
96
94
function traverseNode ( node ) {
97
95
switch ( node . type ) {
98
- case 'nested- pseudo-class ' :
99
- if ( node . name === 'local' ) {
96
+ case 'pseudo' :
97
+ if ( node . value === ': local' ) {
100
98
if ( node . nodes . length !== 1 ) {
101
99
throw new Error ( 'Unexpected comma (",") in :local block' ) ;
102
100
}
103
- return localizeNode ( node . nodes [ 0 ] ) ;
101
+ const selector = localizeNode ( node . first , node . spaces ) ;
102
+ // move the spaces that were around the psuedo selector to the first
103
+ // non-container node
104
+ selector . first . spaces = node . spaces ;
105
+
106
+ node . replaceWith ( selector ) ;
107
+ return ;
104
108
}
105
109
/* falls through */
106
- case 'selectors ' :
110
+ case 'root ' :
107
111
case 'selector' : {
108
- const newNode = Object . create ( node ) ;
109
- newNode . nodes = node . nodes . map ( traverseNode ) ;
110
- return newNode ;
112
+ node . each ( traverseNode ) ;
113
+ break ;
111
114
}
112
115
}
113
116
return node ;
@@ -125,14 +128,16 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
125
128
126
129
// Find any :local classes
127
130
css . walkRules ( rule => {
128
- const selector = Tokenizer . parse ( rule . selector ) ;
129
- const newSelector = traverseNode ( selector ) ;
130
- rule . selector = Tokenizer . stringify ( newSelector ) ;
131
+ let parsedSelector = selectorParser ( ) . astSync ( rule ) ;
132
+
133
+ rule . selector = traverseNode ( parsedSelector . clone ( ) ) . toString ( ) ;
134
+ // console.log(rule.selector);
131
135
rule . walkDecls ( / c o m p o s e s | c o m p o s e - w i t h / , decl => {
132
- const localNames = getSingleLocalNamesForComposes ( selector ) ;
136
+ const localNames = getSingleLocalNamesForComposes ( parsedSelector ) ;
133
137
const classes = decl . value . split ( / \s + / ) ;
134
138
classes . forEach ( className => {
135
139
const global = / ^ g l o b a l \( ( [ ^ \) ] + ) \) $ / . exec ( className ) ;
140
+
136
141
if ( global ) {
137
142
localNames . forEach ( exportedName => {
138
143
exports [ exportedName ] . push ( global [ 1 ] ) ;
@@ -196,7 +201,7 @@ const processor = postcss.plugin('postcss-modules-scope', function(options) {
196
201
exportRule . append ( {
197
202
prop : exportedName ,
198
203
value : exports [ exportedName ] . join ( ' ' ) ,
199
- raws : { before : '\n ' }
204
+ raws : { before : '\n ' } ,
200
205
} )
201
206
) ;
202
207
css . append ( exportRule ) ;
@@ -209,7 +214,7 @@ processor.generateScopedName = function(exportedName, path) {
209
214
. replace ( / \. [ ^ \. \/ \\ ] + $ / , '' )
210
215
. replace ( / [ \W _ ] + / g, '_' )
211
216
. replace ( / ^ _ | _ $ / g, '' ) ;
212
- return `_${ sanitisedPath } __${ exportedName } ` ;
217
+ return `_${ sanitisedPath } __${ exportedName } ` . trim ( ) ;
213
218
} ;
214
219
215
220
module . exports = processor ;
0 commit comments