1
1
import { comment , rule , type AstNode , type Comment , type Declaration , type Rule } from './ast'
2
-
3
- const BACK_SLASH = '\\' . charCodeAt ( 0 )
4
- const SLASH = '/' . charCodeAt ( 0 )
5
- const ASTERISK = '*' . charCodeAt ( 0 )
6
- const DOUBLE_QUOTE = '"' . charCodeAt ( 0 )
7
- const SINGLE_QUOTE = "'" . charCodeAt ( 0 )
8
- const COLON = ':' . charCodeAt ( 0 )
9
- const SEMICOLON = ';' . charCodeAt ( 0 )
10
- const LINE_BREAK = '\n' . charCodeAt ( 0 )
11
- const SPACE = ' ' . charCodeAt ( 0 )
12
- const TAB = '\t' . charCodeAt ( 0 )
13
- const OPEN_CURLY_BRACKET = '{' . charCodeAt ( 0 )
14
- const CLOSE_CURLY_BRACKET = '}' . charCodeAt ( 0 )
15
- const OPEN_PARENTHESIS = '(' . charCodeAt ( 0 )
16
- const CLOSE_PARENTHESIS = ')' . charCodeAt ( 0 )
17
- const OPEN_BRACKET = '[' . charCodeAt ( 0 )
18
- const CLOSE_BRACKET = ']' . charCodeAt ( 0 )
19
- const DASH = '-' . charCodeAt ( 0 )
20
- const AT_SIGN = '@' . charCodeAt ( 0 )
21
- const EXCLAMATION_MARK = '!' . charCodeAt ( 0 )
2
+ import * as Token from './tokens'
22
3
23
4
export function parse ( input : string ) {
24
5
input = input . replaceAll ( '\r\n' , '\n' )
@@ -49,7 +30,7 @@ export function parse(input: string) {
49
30
// ^
50
31
// ```
51
32
//
52
- if ( currentChar === BACK_SLASH ) {
33
+ if ( currentChar === Token . BACKSLASH ) {
53
34
buffer += input . slice ( i , i + 2 )
54
35
i += 1
55
36
}
@@ -70,19 +51,19 @@ export function parse(input: string) {
70
51
// ^^^^^^^^^^^^^
71
52
// }
72
53
// ```
73
- else if ( currentChar === SLASH && input . charCodeAt ( i + 1 ) === ASTERISK ) {
54
+ else if ( currentChar === Token . SLASH && input . charCodeAt ( i + 1 ) === Token . ASTERISK ) {
74
55
let start = i
75
56
76
57
for ( let j = i + 2 ; j < input . length ; j ++ ) {
77
58
peekChar = input . charCodeAt ( j )
78
59
79
60
// Current character is a `\` therefore the next character is escaped.
80
- if ( peekChar === BACK_SLASH ) {
61
+ if ( peekChar === Token . BACKSLASH ) {
81
62
j += 1
82
63
}
83
64
84
65
// End of the comment
85
- else if ( peekChar === ASTERISK && input . charCodeAt ( j + 1 ) === SLASH ) {
66
+ else if ( peekChar === Token . ASTERISK && input . charCodeAt ( j + 1 ) === Token . SLASH ) {
86
67
i = j + 1
87
68
break
88
69
}
@@ -92,13 +73,13 @@ export function parse(input: string) {
92
73
93
74
// Collect all license comments so that we can hoist them to the top of
94
75
// the AST.
95
- if ( commentString . charCodeAt ( 2 ) === EXCLAMATION_MARK ) {
76
+ if ( commentString . charCodeAt ( 2 ) === Token . EXCLAMATION_MARK ) {
96
77
licenseComments . push ( comment ( commentString . slice ( 2 , - 2 ) ) )
97
78
}
98
79
}
99
80
100
81
// Start of a string.
101
- else if ( currentChar === SINGLE_QUOTE || currentChar === DOUBLE_QUOTE ) {
82
+ else if ( currentChar === Token . SINGLE_QUOTE || currentChar === Token . DOUBLE_QUOTE ) {
102
83
let start = i
103
84
104
85
// We need to ensure that the closing quote is the same as the opening
@@ -115,7 +96,7 @@ export function parse(input: string) {
115
96
for ( let j = i + 1 ; j < input . length ; j ++ ) {
116
97
peekChar = input . charCodeAt ( j )
117
98
// Current character is a `\` therefore the next character is escaped.
118
- if ( peekChar === BACK_SLASH ) {
99
+ if ( peekChar === Token . BACKSLASH ) {
119
100
j += 1
120
101
}
121
102
@@ -135,7 +116,7 @@ export function parse(input: string) {
135
116
// ^ Missing "
136
117
// }
137
118
// ```
138
- else if ( peekChar === SEMICOLON && input . charCodeAt ( j + 1 ) === LINE_BREAK ) {
119
+ else if ( peekChar === Token . SEMICOLON && input . charCodeAt ( j + 1 ) === Token . LINE_BREAK ) {
139
120
throw new Error (
140
121
`Unterminated string: ${ input . slice ( start , j + 1 ) + String . fromCharCode ( currentChar ) } ` ,
141
122
)
@@ -151,7 +132,7 @@ export function parse(input: string) {
151
132
// ^ Missing "
152
133
// }
153
134
// ```
154
- else if ( peekChar === LINE_BREAK ) {
135
+ else if ( peekChar === Token . LINE_BREAK ) {
155
136
throw new Error (
156
137
`Unterminated string: ${ input . slice ( start , j ) + String . fromCharCode ( currentChar ) } ` ,
157
138
)
@@ -165,19 +146,21 @@ export function parse(input: string) {
165
146
// Skip whitespace if the next character is also whitespace. This allows us
166
147
// to reduce the amount of whitespace in the AST.
167
148
else if (
168
- ( currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB ) &&
149
+ ( currentChar === Token . SPACE ||
150
+ currentChar === Token . LINE_BREAK ||
151
+ currentChar === Token . TAB ) &&
169
152
( peekChar = input . charCodeAt ( i + 1 ) ) &&
170
- ( peekChar === SPACE || peekChar === LINE_BREAK || peekChar === TAB )
153
+ ( peekChar === Token . SPACE || peekChar === Token . LINE_BREAK || peekChar === Token . TAB )
171
154
) {
172
155
continue
173
156
}
174
157
175
158
// Replace new lines with spaces.
176
- else if ( currentChar === LINE_BREAK ) {
159
+ else if ( currentChar === Token . LINE_BREAK ) {
177
160
if ( buffer . length === 0 ) continue
178
161
179
162
peekChar = buffer . charCodeAt ( buffer . length - 1 )
180
- if ( peekChar !== SPACE && peekChar !== LINE_BREAK && peekChar !== TAB ) {
163
+ if ( peekChar !== Token . SPACE && peekChar !== Token . LINE_BREAK && peekChar !== Token . TAB ) {
181
164
buffer += ' '
182
165
}
183
166
}
@@ -188,7 +171,11 @@ export function parse(input: string) {
188
171
// character, even `;` and ` }`. Therefore we have to make sure that we are
189
172
// at the correct "end" of the custom property by making sure everything is
190
173
// balanced.
191
- else if ( currentChar === DASH && input . charCodeAt ( i + 1 ) === DASH && buffer . length === 0 ) {
174
+ else if (
175
+ currentChar === Token . DASH &&
176
+ input . charCodeAt ( i + 1 ) === Token . DASH &&
177
+ buffer . length === 0
178
+ ) {
192
179
let closingBracketStack = ''
193
180
194
181
let start = i
@@ -198,45 +185,45 @@ export function parse(input: string) {
198
185
peekChar = input . charCodeAt ( j )
199
186
200
187
// Current character is a `\` therefore the next character is escaped.
201
- if ( peekChar === BACK_SLASH ) {
188
+ if ( peekChar === Token . BACKSLASH ) {
202
189
j += 1
203
190
}
204
191
205
192
// Start of a comment.
206
- else if ( peekChar === SLASH && input . charCodeAt ( j + 1 ) === ASTERISK ) {
193
+ else if ( peekChar === Token . SLASH && input . charCodeAt ( j + 1 ) === Token . ASTERISK ) {
207
194
for ( let k = j + 2 ; k < input . length ; k ++ ) {
208
195
peekChar = input . charCodeAt ( k )
209
196
// Current character is a `\` therefore the next character is escaped.
210
- if ( peekChar === BACK_SLASH ) {
197
+ if ( peekChar === Token . BACKSLASH ) {
211
198
k += 1
212
199
}
213
200
214
201
// End of the comment
215
- else if ( peekChar === ASTERISK && input . charCodeAt ( k + 1 ) === SLASH ) {
202
+ else if ( peekChar === Token . ASTERISK && input . charCodeAt ( k + 1 ) === Token . SLASH ) {
216
203
j = k + 1
217
204
break
218
205
}
219
206
}
220
207
}
221
208
222
209
// End of the "property" of the property-value pair.
223
- else if ( colonIdx === - 1 && peekChar === COLON ) {
210
+ else if ( colonIdx === - 1 && peekChar === Token . COLON ) {
224
211
colonIdx = buffer . length + j - start
225
212
}
226
213
227
214
// End of the custom property.
228
- else if ( peekChar === SEMICOLON && closingBracketStack . length === 0 ) {
215
+ else if ( peekChar === Token . SEMICOLON && closingBracketStack . length === 0 ) {
229
216
buffer += input . slice ( start , j )
230
217
i = j
231
218
break
232
219
}
233
220
234
221
// Start of a block.
235
- else if ( peekChar === OPEN_PARENTHESIS ) {
222
+ else if ( peekChar === Token . OPEN_PAREN ) {
236
223
closingBracketStack += ')'
237
- } else if ( peekChar === OPEN_BRACKET ) {
224
+ } else if ( peekChar === Token . OPEN_BRACKET ) {
238
225
closingBracketStack += ']'
239
- } else if ( peekChar === OPEN_CURLY_BRACKET ) {
226
+ } else if ( peekChar === Token . OPEN_CURLY ) {
240
227
closingBracketStack += '}'
241
228
}
242
229
@@ -252,7 +239,7 @@ export function parse(input: string) {
252
239
// }
253
240
// ```
254
241
else if (
255
- ( peekChar === CLOSE_CURLY_BRACKET || input . length - 1 === j ) &&
242
+ ( peekChar === Token . CLOSE_CURLY || input . length - 1 === j ) &&
256
243
closingBracketStack . length === 0
257
244
) {
258
245
i = j - 1
@@ -262,9 +249,9 @@ export function parse(input: string) {
262
249
263
250
// End of a block.
264
251
else if (
265
- peekChar === CLOSE_PARENTHESIS ||
266
- peekChar === CLOSE_BRACKET ||
267
- peekChar === CLOSE_CURLY_BRACKET
252
+ peekChar === Token . CLOSE_PAREN ||
253
+ peekChar === Token . CLOSE_BRACKET ||
254
+ peekChar === Token . CLOSE_CURLY
268
255
) {
269
256
if (
270
257
closingBracketStack . length > 0 &&
@@ -293,7 +280,7 @@ export function parse(input: string) {
293
280
// @charset "UTF-8";
294
281
// ^
295
282
// ```
296
- else if ( currentChar === SEMICOLON && buffer . charCodeAt ( 0 ) === AT_SIGN ) {
283
+ else if ( currentChar === Token . SEMICOLON && buffer . charCodeAt ( 0 ) === Token . AT_SIGN ) {
297
284
node = rule ( buffer , [ ] )
298
285
299
286
// At-rule is nested inside of a rule, attach it to the parent.
@@ -322,7 +309,7 @@ export function parse(input: string) {
322
309
// }
323
310
// ```
324
311
//
325
- else if ( currentChar === SEMICOLON ) {
312
+ else if ( currentChar === Token . SEMICOLON ) {
326
313
let declaration = parseDeclaration ( buffer )
327
314
if ( parent ) {
328
315
parent . nodes . push ( declaration )
@@ -334,7 +321,7 @@ export function parse(input: string) {
334
321
}
335
322
336
323
// Start of a block.
337
- else if ( currentChar === OPEN_CURLY_BRACKET ) {
324
+ else if ( currentChar === Token . OPEN_CURLY ) {
338
325
closingBracketStack += '}'
339
326
340
327
// At this point `buffer` should resemble a selector or an at-rule.
@@ -359,7 +346,7 @@ export function parse(input: string) {
359
346
}
360
347
361
348
// End of a block.
362
- else if ( currentChar === CLOSE_CURLY_BRACKET ) {
349
+ else if ( currentChar === Token . CLOSE_CURLY ) {
363
350
if ( closingBracketStack === '' ) {
364
351
throw new Error ( 'Missing opening {' )
365
352
}
@@ -380,7 +367,7 @@ export function parse(input: string) {
380
367
// ^
381
368
// }
382
369
// ```
383
- if ( buffer . charCodeAt ( 0 ) === AT_SIGN ) {
370
+ if ( buffer . charCodeAt ( 0 ) === Token . AT_SIGN ) {
384
371
node = rule ( buffer . trim ( ) , [ ] )
385
372
386
373
// At-rule is nested inside of a rule, attach it to the parent.
@@ -452,7 +439,9 @@ export function parse(input: string) {
452
439
// Skip whitespace at the start of a new node.
453
440
if (
454
441
buffer . length === 0 &&
455
- ( currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB )
442
+ ( currentChar === Token . SPACE ||
443
+ currentChar === Token . LINE_BREAK ||
444
+ currentChar === Token . TAB )
456
445
) {
457
446
continue
458
447
}
0 commit comments