postcss 8.3.9 → 8.4.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -23
- package/lib/at-rule.d.ts +58 -49
- package/lib/comment.d.ts +43 -32
- package/lib/container.d.ts +233 -223
- package/lib/container.js +251 -244
- package/lib/css-syntax-error.d.ts +117 -61
- package/lib/css-syntax-error.js +10 -3
- package/lib/declaration.d.ts +85 -61
- package/lib/document.d.ts +27 -16
- package/lib/fromJSON.d.ts +6 -2
- package/lib/input.d.ts +118 -54
- package/lib/input.js +87 -55
- package/lib/lazy-result.d.ts +82 -67
- package/lib/lazy-result.js +234 -232
- package/lib/list.d.ts +53 -47
- package/lib/list.js +16 -14
- package/lib/map-generator.js +231 -172
- package/lib/no-work-result.d.ts +46 -0
- package/lib/no-work-result.js +135 -0
- package/lib/node.d.ts +345 -253
- package/lib/node.js +200 -139
- package/lib/parse.d.ts +6 -2
- package/lib/parser.js +354 -309
- package/lib/postcss.d.mts +72 -0
- package/lib/postcss.d.ts +288 -319
- package/lib/postcss.js +18 -12
- package/lib/postcss.mjs +1 -0
- package/lib/previous-map.d.ts +23 -14
- package/lib/previous-map.js +37 -40
- package/lib/processor.d.ts +55 -41
- package/lib/processor.js +20 -27
- package/lib/result.d.ts +87 -76
- package/lib/root.d.ts +49 -36
- package/lib/root.js +12 -10
- package/lib/rule.d.ts +54 -45
- package/lib/stringifier.d.ts +46 -0
- package/lib/stringifier.js +140 -138
- package/lib/stringify.d.ts +6 -2
- package/lib/terminal-highlight.js +11 -11
- package/lib/tokenize.js +2 -2
- package/lib/warn-once.js +1 -0
- package/lib/warning.d.ts +79 -36
- package/lib/warning.js +6 -4
- package/package.json +20 -10
package/lib/parser.js
CHANGED
@@ -7,6 +7,19 @@ let AtRule = require('./at-rule')
|
|
7
7
|
let Root = require('./root')
|
8
8
|
let Rule = require('./rule')
|
9
9
|
|
10
|
+
const SAFE_COMMENT_NEIGHBOR = {
|
11
|
+
empty: true,
|
12
|
+
space: true
|
13
|
+
}
|
14
|
+
|
15
|
+
function findLastWithPosition(tokens) {
|
16
|
+
for (let i = tokens.length - 1; i >= 0; i--) {
|
17
|
+
let token = tokens[i]
|
18
|
+
let pos = token[3] || token[2]
|
19
|
+
if (pos) return pos
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
10
23
|
class Parser {
|
11
24
|
constructor(input) {
|
12
25
|
this.input = input
|
@@ -18,55 +31,150 @@ class Parser {
|
|
18
31
|
this.customProperty = false
|
19
32
|
|
20
33
|
this.createTokenizer()
|
21
|
-
this.root.source = { input, start: {
|
34
|
+
this.root.source = { input, start: { column: 1, line: 1, offset: 0 } }
|
22
35
|
}
|
23
36
|
|
24
|
-
|
25
|
-
|
26
|
-
|
37
|
+
atrule(token) {
|
38
|
+
let node = new AtRule()
|
39
|
+
node.name = token[1].slice(1)
|
40
|
+
if (node.name === '') {
|
41
|
+
this.unnamedAtrule(node, token)
|
42
|
+
}
|
43
|
+
this.init(node, token[2])
|
44
|
+
|
45
|
+
let type
|
46
|
+
let prev
|
47
|
+
let shift
|
48
|
+
let last = false
|
49
|
+
let open = false
|
50
|
+
let params = []
|
51
|
+
let brackets = []
|
27
52
|
|
28
|
-
parse() {
|
29
|
-
let token
|
30
53
|
while (!this.tokenizer.endOfFile()) {
|
31
54
|
token = this.tokenizer.nextToken()
|
55
|
+
type = token[0]
|
32
56
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
57
|
+
if (type === '(' || type === '[') {
|
58
|
+
brackets.push(type === '(' ? ')' : ']')
|
59
|
+
} else if (type === '{' && brackets.length > 0) {
|
60
|
+
brackets.push('}')
|
61
|
+
} else if (type === brackets[brackets.length - 1]) {
|
62
|
+
brackets.pop()
|
63
|
+
}
|
37
64
|
|
38
|
-
|
39
|
-
|
65
|
+
if (brackets.length === 0) {
|
66
|
+
if (type === ';') {
|
67
|
+
node.source.end = this.getPosition(token[2])
|
68
|
+
node.source.end.offset++
|
69
|
+
this.semicolon = true
|
40
70
|
break
|
41
|
-
|
42
|
-
|
71
|
+
} else if (type === '{') {
|
72
|
+
open = true
|
73
|
+
break
|
74
|
+
} else if (type === '}') {
|
75
|
+
if (params.length > 0) {
|
76
|
+
shift = params.length - 1
|
77
|
+
prev = params[shift]
|
78
|
+
while (prev && prev[0] === 'space') {
|
79
|
+
prev = params[--shift]
|
80
|
+
}
|
81
|
+
if (prev) {
|
82
|
+
node.source.end = this.getPosition(prev[3] || prev[2])
|
83
|
+
node.source.end.offset++
|
84
|
+
}
|
85
|
+
}
|
43
86
|
this.end(token)
|
44
87
|
break
|
88
|
+
} else {
|
89
|
+
params.push(token)
|
90
|
+
}
|
91
|
+
} else {
|
92
|
+
params.push(token)
|
93
|
+
}
|
45
94
|
|
46
|
-
|
47
|
-
|
48
|
-
|
95
|
+
if (this.tokenizer.endOfFile()) {
|
96
|
+
last = true
|
97
|
+
break
|
98
|
+
}
|
99
|
+
}
|
49
100
|
|
50
|
-
|
51
|
-
|
52
|
-
|
101
|
+
node.raws.between = this.spacesAndCommentsFromEnd(params)
|
102
|
+
if (params.length) {
|
103
|
+
node.raws.afterName = this.spacesAndCommentsFromStart(params)
|
104
|
+
this.raw(node, 'params', params)
|
105
|
+
if (last) {
|
106
|
+
token = params[params.length - 1]
|
107
|
+
node.source.end = this.getPosition(token[3] || token[2])
|
108
|
+
node.source.end.offset++
|
109
|
+
this.spaces = node.raws.between
|
110
|
+
node.raws.between = ''
|
111
|
+
}
|
112
|
+
} else {
|
113
|
+
node.raws.afterName = ''
|
114
|
+
node.params = ''
|
115
|
+
}
|
53
116
|
|
54
|
-
|
55
|
-
|
56
|
-
|
117
|
+
if (open) {
|
118
|
+
node.nodes = []
|
119
|
+
this.current = node
|
120
|
+
}
|
121
|
+
}
|
57
122
|
|
58
|
-
|
59
|
-
|
60
|
-
|
123
|
+
checkMissedSemicolon(tokens) {
|
124
|
+
let colon = this.colon(tokens)
|
125
|
+
if (colon === false) return
|
126
|
+
|
127
|
+
let founded = 0
|
128
|
+
let token
|
129
|
+
for (let j = colon - 1; j >= 0; j--) {
|
130
|
+
token = tokens[j]
|
131
|
+
if (token[0] !== 'space') {
|
132
|
+
founded += 1
|
133
|
+
if (founded === 2) break
|
61
134
|
}
|
62
135
|
}
|
63
|
-
|
136
|
+
// If the token is a word, e.g. `!important`, `red` or any other valid property's value.
|
137
|
+
// Then we need to return the colon after that word token. [3] is the "end" colon of that word.
|
138
|
+
// And because we need it after that one we do +1 to get the next one.
|
139
|
+
throw this.input.error(
|
140
|
+
'Missed semicolon',
|
141
|
+
token[0] === 'word' ? token[3] + 1 : token[2]
|
142
|
+
)
|
143
|
+
}
|
144
|
+
|
145
|
+
colon(tokens) {
|
146
|
+
let brackets = 0
|
147
|
+
let token, type, prev
|
148
|
+
for (let [i, element] of tokens.entries()) {
|
149
|
+
token = element
|
150
|
+
type = token[0]
|
151
|
+
|
152
|
+
if (type === '(') {
|
153
|
+
brackets += 1
|
154
|
+
}
|
155
|
+
if (type === ')') {
|
156
|
+
brackets -= 1
|
157
|
+
}
|
158
|
+
if (brackets === 0 && type === ':') {
|
159
|
+
if (!prev) {
|
160
|
+
this.doubleColon(token)
|
161
|
+
} else if (prev[0] === 'word' && prev[1] === 'progid') {
|
162
|
+
continue
|
163
|
+
} else {
|
164
|
+
return i
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
prev = token
|
169
|
+
}
|
170
|
+
return false
|
64
171
|
}
|
65
172
|
|
66
173
|
comment(token) {
|
67
174
|
let node = new Comment()
|
68
175
|
this.init(node, token[2])
|
69
176
|
node.source.end = this.getPosition(token[3] || token[2])
|
177
|
+
node.source.end.offset++
|
70
178
|
|
71
179
|
let text = token[1].slice(2, -2)
|
72
180
|
if (/^\s*$/.test(text)) {
|
@@ -81,84 +189,8 @@ class Parser {
|
|
81
189
|
}
|
82
190
|
}
|
83
191
|
|
84
|
-
|
85
|
-
|
86
|
-
this.init(node, token[2])
|
87
|
-
node.selector = ''
|
88
|
-
node.raws.between = ''
|
89
|
-
this.current = node
|
90
|
-
}
|
91
|
-
|
92
|
-
other(start) {
|
93
|
-
let end = false
|
94
|
-
let type = null
|
95
|
-
let colon = false
|
96
|
-
let bracket = null
|
97
|
-
let brackets = []
|
98
|
-
let customProperty = start[1].startsWith('--')
|
99
|
-
|
100
|
-
let tokens = []
|
101
|
-
let token = start
|
102
|
-
while (token) {
|
103
|
-
type = token[0]
|
104
|
-
tokens.push(token)
|
105
|
-
|
106
|
-
if (type === '(' || type === '[') {
|
107
|
-
if (!bracket) bracket = token
|
108
|
-
brackets.push(type === '(' ? ')' : ']')
|
109
|
-
} else if (customProperty && colon && type === '{') {
|
110
|
-
if (!bracket) bracket = token
|
111
|
-
brackets.push('}')
|
112
|
-
} else if (brackets.length === 0) {
|
113
|
-
if (type === ';') {
|
114
|
-
if (colon) {
|
115
|
-
this.decl(tokens, customProperty)
|
116
|
-
return
|
117
|
-
} else {
|
118
|
-
break
|
119
|
-
}
|
120
|
-
} else if (type === '{') {
|
121
|
-
this.rule(tokens)
|
122
|
-
return
|
123
|
-
} else if (type === '}') {
|
124
|
-
this.tokenizer.back(tokens.pop())
|
125
|
-
end = true
|
126
|
-
break
|
127
|
-
} else if (type === ':') {
|
128
|
-
colon = true
|
129
|
-
}
|
130
|
-
} else if (type === brackets[brackets.length - 1]) {
|
131
|
-
brackets.pop()
|
132
|
-
if (brackets.length === 0) bracket = null
|
133
|
-
}
|
134
|
-
|
135
|
-
token = this.tokenizer.nextToken()
|
136
|
-
}
|
137
|
-
|
138
|
-
if (this.tokenizer.endOfFile()) end = true
|
139
|
-
if (brackets.length > 0) this.unclosedBracket(bracket)
|
140
|
-
|
141
|
-
if (end && colon) {
|
142
|
-
while (tokens.length) {
|
143
|
-
token = tokens[tokens.length - 1][0]
|
144
|
-
if (token !== 'space' && token !== 'comment') break
|
145
|
-
this.tokenizer.back(tokens.pop())
|
146
|
-
}
|
147
|
-
this.decl(tokens, customProperty)
|
148
|
-
} else {
|
149
|
-
this.unknownWord(tokens)
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
rule(tokens) {
|
154
|
-
tokens.pop()
|
155
|
-
|
156
|
-
let node = new Rule()
|
157
|
-
this.init(node, tokens[0][2])
|
158
|
-
|
159
|
-
node.raws.between = this.spacesAndCommentsFromEnd(tokens)
|
160
|
-
this.raw(node, 'selector', tokens)
|
161
|
-
this.current = node
|
192
|
+
createTokenizer() {
|
193
|
+
this.tokenizer = tokenizer(this.input)
|
162
194
|
}
|
163
195
|
|
164
196
|
decl(tokens, customProperty) {
|
@@ -170,7 +202,11 @@ class Parser {
|
|
170
202
|
this.semicolon = true
|
171
203
|
tokens.pop()
|
172
204
|
}
|
173
|
-
|
205
|
+
|
206
|
+
node.source.end = this.getPosition(
|
207
|
+
last[3] || last[2] || findLastWithPosition(tokens)
|
208
|
+
)
|
209
|
+
node.source.end.offset++
|
174
210
|
|
175
211
|
while (tokens[0][0] !== 'word') {
|
176
212
|
if (tokens.length === 1) this.unknownWord(tokens)
|
@@ -208,135 +244,76 @@ class Parser {
|
|
208
244
|
node.raws.before += node.prop[0]
|
209
245
|
node.prop = node.prop.slice(1)
|
210
246
|
}
|
211
|
-
let firstSpaces = this.spacesAndCommentsFromStart(tokens)
|
212
|
-
this.precheckMissedSemicolon(tokens)
|
213
|
-
|
214
|
-
for (let i = tokens.length - 1; i >= 0; i--) {
|
215
|
-
token = tokens[i]
|
216
|
-
if (token[1].toLowerCase() === '!important') {
|
217
|
-
node.important = true
|
218
|
-
let string = this.stringFrom(tokens, i)
|
219
|
-
string = this.spacesFromEnd(tokens) + string
|
220
|
-
if (string !== ' !important') node.raws.important = string
|
221
|
-
break
|
222
|
-
} else if (token[1].toLowerCase() === 'important') {
|
223
|
-
let cache = tokens.slice(0)
|
224
|
-
let str = ''
|
225
|
-
for (let j = i; j > 0; j--) {
|
226
|
-
let type = cache[j][0]
|
227
|
-
if (str.trim().indexOf('!') === 0 && type !== 'space') {
|
228
|
-
break
|
229
|
-
}
|
230
|
-
str = cache.pop()[1] + str
|
231
|
-
}
|
232
|
-
if (str.trim().indexOf('!') === 0) {
|
233
|
-
node.important = true
|
234
|
-
node.raws.important = str
|
235
|
-
tokens = cache
|
236
|
-
}
|
237
|
-
}
|
238
|
-
|
239
|
-
if (token[0] !== 'space' && token[0] !== 'comment') {
|
240
|
-
break
|
241
|
-
}
|
242
|
-
}
|
243
247
|
|
244
|
-
let
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
}
|
251
|
-
|
252
|
-
if (node.value.includes(':') && !customProperty) {
|
253
|
-
this.checkMissedSemicolon(tokens)
|
254
|
-
}
|
255
|
-
}
|
256
|
-
|
257
|
-
atrule(token) {
|
258
|
-
let node = new AtRule()
|
259
|
-
node.name = token[1].slice(1)
|
260
|
-
if (node.name === '') {
|
261
|
-
this.unnamedAtrule(node, token)
|
248
|
+
let firstSpaces = []
|
249
|
+
let next
|
250
|
+
while (tokens.length) {
|
251
|
+
next = tokens[0][0]
|
252
|
+
if (next !== 'space' && next !== 'comment') break
|
253
|
+
firstSpaces.push(tokens.shift())
|
262
254
|
}
|
263
|
-
this.init(node, token[2])
|
264
255
|
|
265
|
-
|
266
|
-
let prev
|
267
|
-
let shift
|
268
|
-
let last = false
|
269
|
-
let open = false
|
270
|
-
let params = []
|
271
|
-
let brackets = []
|
272
|
-
|
273
|
-
while (!this.tokenizer.endOfFile()) {
|
274
|
-
token = this.tokenizer.nextToken()
|
275
|
-
type = token[0]
|
276
|
-
|
277
|
-
if (type === '(' || type === '[') {
|
278
|
-
brackets.push(type === '(' ? ')' : ']')
|
279
|
-
} else if (type === '{' && brackets.length > 0) {
|
280
|
-
brackets.push('}')
|
281
|
-
} else if (type === brackets[brackets.length - 1]) {
|
282
|
-
brackets.pop()
|
283
|
-
}
|
256
|
+
this.precheckMissedSemicolon(tokens)
|
284
257
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
if (prev) {
|
301
|
-
node.source.end = this.getPosition(prev[3] || prev[2])
|
302
|
-
}
|
258
|
+
for (let i = tokens.length - 1; i >= 0; i--) {
|
259
|
+
token = tokens[i]
|
260
|
+
if (token[1].toLowerCase() === '!important') {
|
261
|
+
node.important = true
|
262
|
+
let string = this.stringFrom(tokens, i)
|
263
|
+
string = this.spacesFromEnd(tokens) + string
|
264
|
+
if (string !== ' !important') node.raws.important = string
|
265
|
+
break
|
266
|
+
} else if (token[1].toLowerCase() === 'important') {
|
267
|
+
let cache = tokens.slice(0)
|
268
|
+
let str = ''
|
269
|
+
for (let j = i; j > 0; j--) {
|
270
|
+
let type = cache[j][0]
|
271
|
+
if (str.trim().indexOf('!') === 0 && type !== 'space') {
|
272
|
+
break
|
303
273
|
}
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
274
|
+
str = cache.pop()[1] + str
|
275
|
+
}
|
276
|
+
if (str.trim().indexOf('!') === 0) {
|
277
|
+
node.important = true
|
278
|
+
node.raws.important = str
|
279
|
+
tokens = cache
|
308
280
|
}
|
309
|
-
} else {
|
310
|
-
params.push(token)
|
311
281
|
}
|
312
282
|
|
313
|
-
if (
|
314
|
-
last = true
|
283
|
+
if (token[0] !== 'space' && token[0] !== 'comment') {
|
315
284
|
break
|
316
285
|
}
|
317
286
|
}
|
318
287
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
token = params[params.length - 1]
|
325
|
-
node.source.end = this.getPosition(token[3] || token[2])
|
326
|
-
this.spaces = node.raws.between
|
327
|
-
node.raws.between = ''
|
328
|
-
}
|
329
|
-
} else {
|
330
|
-
node.raws.afterName = ''
|
331
|
-
node.params = ''
|
288
|
+
let hasWord = tokens.some(i => i[0] !== 'space' && i[0] !== 'comment')
|
289
|
+
|
290
|
+
if (hasWord) {
|
291
|
+
node.raws.between += firstSpaces.map(i => i[1]).join('')
|
292
|
+
firstSpaces = []
|
332
293
|
}
|
294
|
+
this.raw(node, 'value', firstSpaces.concat(tokens), customProperty)
|
333
295
|
|
334
|
-
if (
|
335
|
-
|
336
|
-
this.current = node
|
296
|
+
if (node.value.includes(':') && !customProperty) {
|
297
|
+
this.checkMissedSemicolon(tokens)
|
337
298
|
}
|
338
299
|
}
|
339
300
|
|
301
|
+
doubleColon(token) {
|
302
|
+
throw this.input.error(
|
303
|
+
'Double colon',
|
304
|
+
{ offset: token[2] },
|
305
|
+
{ offset: token[2] + token[1].length }
|
306
|
+
)
|
307
|
+
}
|
308
|
+
|
309
|
+
emptyRule(token) {
|
310
|
+
let node = new Rule()
|
311
|
+
this.init(node, token[2])
|
312
|
+
node.selector = ''
|
313
|
+
node.raws.between = ''
|
314
|
+
this.current = node
|
315
|
+
}
|
316
|
+
|
340
317
|
end(token) {
|
341
318
|
if (this.current.nodes && this.current.nodes.length) {
|
342
319
|
this.current.raws.semicolon = this.semicolon
|
@@ -348,6 +325,7 @@ class Parser {
|
|
348
325
|
|
349
326
|
if (this.current.parent) {
|
350
327
|
this.current.source.end = this.getPosition(token[2])
|
328
|
+
this.current.source.end.offset++
|
351
329
|
this.current = this.current.parent
|
352
330
|
} else {
|
353
331
|
this.unexpectedClose(token)
|
@@ -360,6 +338,7 @@ class Parser {
|
|
360
338
|
this.current.raws.semicolon = this.semicolon
|
361
339
|
}
|
362
340
|
this.current.raws.after = (this.current.raws.after || '') + this.spaces
|
341
|
+
this.root.source.end = this.getPosition(this.tokenizer.position())
|
363
342
|
}
|
364
343
|
|
365
344
|
freeSemicolon(token) {
|
@@ -378,66 +357,174 @@ class Parser {
|
|
378
357
|
getPosition(offset) {
|
379
358
|
let pos = this.input.fromOffset(offset)
|
380
359
|
return {
|
381
|
-
|
360
|
+
column: pos.col,
|
382
361
|
line: pos.line,
|
383
|
-
|
362
|
+
offset
|
384
363
|
}
|
385
364
|
}
|
386
365
|
|
387
366
|
init(node, offset) {
|
388
367
|
this.current.push(node)
|
389
368
|
node.source = {
|
390
|
-
|
391
|
-
|
369
|
+
input: this.input,
|
370
|
+
start: this.getPosition(offset)
|
392
371
|
}
|
393
372
|
node.raws.before = this.spaces
|
394
373
|
this.spaces = ''
|
395
374
|
if (node.type !== 'comment') this.semicolon = false
|
396
375
|
}
|
397
376
|
|
398
|
-
|
377
|
+
other(start) {
|
378
|
+
let end = false
|
379
|
+
let type = null
|
380
|
+
let colon = false
|
381
|
+
let bracket = null
|
382
|
+
let brackets = []
|
383
|
+
let customProperty = start[1].startsWith('--')
|
384
|
+
|
385
|
+
let tokens = []
|
386
|
+
let token = start
|
387
|
+
while (token) {
|
388
|
+
type = token[0]
|
389
|
+
tokens.push(token)
|
390
|
+
|
391
|
+
if (type === '(' || type === '[') {
|
392
|
+
if (!bracket) bracket = token
|
393
|
+
brackets.push(type === '(' ? ')' : ']')
|
394
|
+
} else if (customProperty && colon && type === '{') {
|
395
|
+
if (!bracket) bracket = token
|
396
|
+
brackets.push('}')
|
397
|
+
} else if (brackets.length === 0) {
|
398
|
+
if (type === ';') {
|
399
|
+
if (colon) {
|
400
|
+
this.decl(tokens, customProperty)
|
401
|
+
return
|
402
|
+
} else {
|
403
|
+
break
|
404
|
+
}
|
405
|
+
} else if (type === '{') {
|
406
|
+
this.rule(tokens)
|
407
|
+
return
|
408
|
+
} else if (type === '}') {
|
409
|
+
this.tokenizer.back(tokens.pop())
|
410
|
+
end = true
|
411
|
+
break
|
412
|
+
} else if (type === ':') {
|
413
|
+
colon = true
|
414
|
+
}
|
415
|
+
} else if (type === brackets[brackets.length - 1]) {
|
416
|
+
brackets.pop()
|
417
|
+
if (brackets.length === 0) bracket = null
|
418
|
+
}
|
419
|
+
|
420
|
+
token = this.tokenizer.nextToken()
|
421
|
+
}
|
422
|
+
|
423
|
+
if (this.tokenizer.endOfFile()) end = true
|
424
|
+
if (brackets.length > 0) this.unclosedBracket(bracket)
|
425
|
+
|
426
|
+
if (end && colon) {
|
427
|
+
if (!customProperty) {
|
428
|
+
while (tokens.length) {
|
429
|
+
token = tokens[tokens.length - 1][0]
|
430
|
+
if (token !== 'space' && token !== 'comment') break
|
431
|
+
this.tokenizer.back(tokens.pop())
|
432
|
+
}
|
433
|
+
}
|
434
|
+
this.decl(tokens, customProperty)
|
435
|
+
} else {
|
436
|
+
this.unknownWord(tokens)
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
parse() {
|
441
|
+
let token
|
442
|
+
while (!this.tokenizer.endOfFile()) {
|
443
|
+
token = this.tokenizer.nextToken()
|
444
|
+
|
445
|
+
switch (token[0]) {
|
446
|
+
case 'space':
|
447
|
+
this.spaces += token[1]
|
448
|
+
break
|
449
|
+
|
450
|
+
case ';':
|
451
|
+
this.freeSemicolon(token)
|
452
|
+
break
|
453
|
+
|
454
|
+
case '}':
|
455
|
+
this.end(token)
|
456
|
+
break
|
457
|
+
|
458
|
+
case 'comment':
|
459
|
+
this.comment(token)
|
460
|
+
break
|
461
|
+
|
462
|
+
case 'at-word':
|
463
|
+
this.atrule(token)
|
464
|
+
break
|
465
|
+
|
466
|
+
case '{':
|
467
|
+
this.emptyRule(token)
|
468
|
+
break
|
469
|
+
|
470
|
+
default:
|
471
|
+
this.other(token)
|
472
|
+
break
|
473
|
+
}
|
474
|
+
}
|
475
|
+
this.endFile()
|
476
|
+
}
|
477
|
+
|
478
|
+
precheckMissedSemicolon(/* tokens */) {
|
479
|
+
// Hook for Safe Parser
|
480
|
+
}
|
481
|
+
|
482
|
+
raw(node, prop, tokens, customProperty) {
|
399
483
|
let token, type
|
400
484
|
let length = tokens.length
|
401
485
|
let value = ''
|
402
486
|
let clean = true
|
403
487
|
let next, prev
|
404
|
-
let pattern = /^([#.|])?(\w)+/i
|
405
488
|
|
406
489
|
for (let i = 0; i < length; i += 1) {
|
407
490
|
token = tokens[i]
|
408
491
|
type = token[0]
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
if (
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
value += token[1]
|
492
|
+
if (type === 'space' && i === length - 1 && !customProperty) {
|
493
|
+
clean = false
|
494
|
+
} else if (type === 'comment') {
|
495
|
+
prev = tokens[i - 1] ? tokens[i - 1][0] : 'empty'
|
496
|
+
next = tokens[i + 1] ? tokens[i + 1][0] : 'empty'
|
497
|
+
if (!SAFE_COMMENT_NEIGHBOR[prev] && !SAFE_COMMENT_NEIGHBOR[next]) {
|
498
|
+
if (value.slice(-1) === ',') {
|
499
|
+
clean = false
|
500
|
+
} else {
|
501
|
+
value += token[1]
|
502
|
+
}
|
421
503
|
} else {
|
422
504
|
clean = false
|
423
505
|
}
|
424
|
-
|
425
|
-
continue
|
426
|
-
}
|
427
|
-
|
428
|
-
if (type === 'comment' || (type === 'space' && i === length - 1)) {
|
429
|
-
clean = false
|
430
506
|
} else {
|
431
507
|
value += token[1]
|
432
508
|
}
|
433
509
|
}
|
434
510
|
if (!clean) {
|
435
511
|
let raw = tokens.reduce((all, i) => all + i[1], '')
|
436
|
-
node.raws[prop] = {
|
512
|
+
node.raws[prop] = { raw, value }
|
437
513
|
}
|
438
514
|
node[prop] = value
|
439
515
|
}
|
440
516
|
|
517
|
+
rule(tokens) {
|
518
|
+
tokens.pop()
|
519
|
+
|
520
|
+
let node = new Rule()
|
521
|
+
this.init(node, tokens[0][2])
|
522
|
+
|
523
|
+
node.raws.between = this.spacesAndCommentsFromEnd(tokens)
|
524
|
+
this.raw(node, 'selector', tokens)
|
525
|
+
this.current = node
|
526
|
+
}
|
527
|
+
|
441
528
|
spacesAndCommentsFromEnd(tokens) {
|
442
529
|
let lastTokenType
|
443
530
|
let spaces = ''
|
@@ -449,6 +536,8 @@ class Parser {
|
|
449
536
|
return spaces
|
450
537
|
}
|
451
538
|
|
539
|
+
// Errors
|
540
|
+
|
452
541
|
spacesAndCommentsFromStart(tokens) {
|
453
542
|
let next
|
454
543
|
let spaces = ''
|
@@ -480,84 +569,40 @@ class Parser {
|
|
480
569
|
return result
|
481
570
|
}
|
482
571
|
|
483
|
-
colon(tokens) {
|
484
|
-
let brackets = 0
|
485
|
-
let token, type, prev
|
486
|
-
for (let [i, element] of tokens.entries()) {
|
487
|
-
token = element
|
488
|
-
type = token[0]
|
489
|
-
|
490
|
-
if (type === '(') {
|
491
|
-
brackets += 1
|
492
|
-
}
|
493
|
-
if (type === ')') {
|
494
|
-
brackets -= 1
|
495
|
-
}
|
496
|
-
if (brackets === 0 && type === ':') {
|
497
|
-
if (!prev) {
|
498
|
-
this.doubleColon(token)
|
499
|
-
} else if (prev[0] === 'word' && prev[1] === 'progid') {
|
500
|
-
continue
|
501
|
-
} else {
|
502
|
-
return i
|
503
|
-
}
|
504
|
-
}
|
505
|
-
|
506
|
-
prev = token
|
507
|
-
}
|
508
|
-
return false
|
509
|
-
}
|
510
|
-
|
511
|
-
// Errors
|
512
|
-
|
513
|
-
unclosedBracket(bracket) {
|
514
|
-
throw this.input.error('Unclosed bracket', bracket[2])
|
515
|
-
}
|
516
|
-
|
517
|
-
unknownWord(tokens) {
|
518
|
-
throw this.input.error('Unknown word', tokens[0][2])
|
519
|
-
}
|
520
|
-
|
521
|
-
unexpectedClose(token) {
|
522
|
-
throw this.input.error('Unexpected }', token[2])
|
523
|
-
}
|
524
|
-
|
525
572
|
unclosedBlock() {
|
526
573
|
let pos = this.current.source.start
|
527
574
|
throw this.input.error('Unclosed block', pos.line, pos.column)
|
528
575
|
}
|
529
576
|
|
530
|
-
|
531
|
-
throw this.input.error(
|
577
|
+
unclosedBracket(bracket) {
|
578
|
+
throw this.input.error(
|
579
|
+
'Unclosed bracket',
|
580
|
+
{ offset: bracket[2] },
|
581
|
+
{ offset: bracket[2] + 1 }
|
582
|
+
)
|
532
583
|
}
|
533
584
|
|
534
|
-
|
535
|
-
throw this.input.error(
|
585
|
+
unexpectedClose(token) {
|
586
|
+
throw this.input.error(
|
587
|
+
'Unexpected }',
|
588
|
+
{ offset: token[2] },
|
589
|
+
{ offset: token[2] + 1 }
|
590
|
+
)
|
536
591
|
}
|
537
592
|
|
538
|
-
|
539
|
-
|
593
|
+
unknownWord(tokens) {
|
594
|
+
throw this.input.error(
|
595
|
+
'Unknown word',
|
596
|
+
{ offset: tokens[0][2] },
|
597
|
+
{ offset: tokens[0][2] + tokens[0][1].length }
|
598
|
+
)
|
540
599
|
}
|
541
600
|
|
542
|
-
|
543
|
-
let colon = this.colon(tokens)
|
544
|
-
if (colon === false) return
|
545
|
-
|
546
|
-
let founded = 0
|
547
|
-
let token
|
548
|
-
for (let j = colon - 1; j >= 0; j--) {
|
549
|
-
token = tokens[j]
|
550
|
-
if (token[0] !== 'space') {
|
551
|
-
founded += 1
|
552
|
-
if (founded === 2) break
|
553
|
-
}
|
554
|
-
}
|
555
|
-
// If the token is a word, e.g. `!important`, `red` or any other valid property's value.
|
556
|
-
// Then we need to return the colon after that word token. [3] is the "end" colon of that word.
|
557
|
-
// And because we need it after that one we do +1 to get the next one.
|
601
|
+
unnamedAtrule(node, token) {
|
558
602
|
throw this.input.error(
|
559
|
-
'
|
560
|
-
|
603
|
+
'At-rule without name',
|
604
|
+
{ offset: token[2] },
|
605
|
+
{ offset: token[2] + token[1].length }
|
561
606
|
)
|
562
607
|
}
|
563
608
|
}
|