Skip to content

Commit 6da3f4a

Browse files
authored
Colocate charcode tokens (#13497)
* use shared tokens * use token constants in candidate parser * use token constants in `isColor` function * add block now that `return null` goes to a new line
1 parent 45dd25e commit 6da3f4a

File tree

5 files changed

+86
-76
lines changed

5 files changed

+86
-76
lines changed

packages/tailwindcss/src/candidate.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { DesignSystem } from './design-system'
2+
import * as Token from './tokens'
23
import { decodeArbitraryValue } from './utils/decode-arbitrary-value'
34
import { segment } from './utils/segment'
45

@@ -257,7 +258,9 @@ export function parseCandidate(input: string, designSystem: DesignSystem): Candi
257258
//
258259
// Otherwise, it is an invalid candidate, and skip continue parsing.
259260
let charCode = baseWithoutModifier.charCodeAt(1)
260-
if (charCode !== 45 && !(charCode >= 97 && charCode <= 122)) return null
261+
if (charCode !== Token.DASH && !(charCode >= Token.LOWER_A && charCode <= Token.LOWER_Z)) {
262+
return null
263+
}
261264

262265
baseWithoutModifier = baseWithoutModifier.slice(1, -1)
263266

@@ -358,14 +361,14 @@ export function parseCandidate(input: string, designSystem: DesignSystem): Candi
358361
let code = arbitraryValue.charCodeAt(i)
359362

360363
// If we hit a ":", we're at the end of a typehint.
361-
if (code === 58 /* ':' */) {
364+
if (code === Token.COLON) {
362365
typehint = arbitraryValue.slice(0, i)
363366
arbitraryValue = arbitraryValue.slice(i + 1)
364367
break
365368
}
366369

367370
// Keep iterating as long as we've only seen valid typehint characters.
368-
if (code === 45 /* '-' */ || (code >= 97 && code <= 122) /* [a-z] */) {
371+
if (code === Token.DASH || (code >= Token.LOWER_A && code <= Token.LOWER_Z)) {
369372
continue
370373
}
371374

packages/tailwindcss/src/css-parser.ts

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,5 @@
11
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'
223

234
export function parse(input: string) {
245
input = input.replaceAll('\r\n', '\n')
@@ -49,7 +30,7 @@ export function parse(input: string) {
4930
// ^
5031
// ```
5132
//
52-
if (currentChar === BACK_SLASH) {
33+
if (currentChar === Token.BACKSLASH) {
5334
buffer += input.slice(i, i + 2)
5435
i += 1
5536
}
@@ -70,19 +51,19 @@ export function parse(input: string) {
7051
// ^^^^^^^^^^^^^
7152
// }
7253
// ```
73-
else if (currentChar === SLASH && input.charCodeAt(i + 1) === ASTERISK) {
54+
else if (currentChar === Token.SLASH && input.charCodeAt(i + 1) === Token.ASTERISK) {
7455
let start = i
7556

7657
for (let j = i + 2; j < input.length; j++) {
7758
peekChar = input.charCodeAt(j)
7859

7960
// Current character is a `\` therefore the next character is escaped.
80-
if (peekChar === BACK_SLASH) {
61+
if (peekChar === Token.BACKSLASH) {
8162
j += 1
8263
}
8364

8465
// 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) {
8667
i = j + 1
8768
break
8869
}
@@ -92,13 +73,13 @@ export function parse(input: string) {
9273

9374
// Collect all license comments so that we can hoist them to the top of
9475
// the AST.
95-
if (commentString.charCodeAt(2) === EXCLAMATION_MARK) {
76+
if (commentString.charCodeAt(2) === Token.EXCLAMATION_MARK) {
9677
licenseComments.push(comment(commentString.slice(2, -2)))
9778
}
9879
}
9980

10081
// Start of a string.
101-
else if (currentChar === SINGLE_QUOTE || currentChar === DOUBLE_QUOTE) {
82+
else if (currentChar === Token.SINGLE_QUOTE || currentChar === Token.DOUBLE_QUOTE) {
10283
let start = i
10384

10485
// We need to ensure that the closing quote is the same as the opening
@@ -115,7 +96,7 @@ export function parse(input: string) {
11596
for (let j = i + 1; j < input.length; j++) {
11697
peekChar = input.charCodeAt(j)
11798
// Current character is a `\` therefore the next character is escaped.
118-
if (peekChar === BACK_SLASH) {
99+
if (peekChar === Token.BACKSLASH) {
119100
j += 1
120101
}
121102

@@ -135,7 +116,7 @@ export function parse(input: string) {
135116
// ^ Missing "
136117
// }
137118
// ```
138-
else if (peekChar === SEMICOLON && input.charCodeAt(j + 1) === LINE_BREAK) {
119+
else if (peekChar === Token.SEMICOLON && input.charCodeAt(j + 1) === Token.LINE_BREAK) {
139120
throw new Error(
140121
`Unterminated string: ${input.slice(start, j + 1) + String.fromCharCode(currentChar)}`,
141122
)
@@ -151,7 +132,7 @@ export function parse(input: string) {
151132
// ^ Missing "
152133
// }
153134
// ```
154-
else if (peekChar === LINE_BREAK) {
135+
else if (peekChar === Token.LINE_BREAK) {
155136
throw new Error(
156137
`Unterminated string: ${input.slice(start, j) + String.fromCharCode(currentChar)}`,
157138
)
@@ -165,19 +146,21 @@ export function parse(input: string) {
165146
// Skip whitespace if the next character is also whitespace. This allows us
166147
// to reduce the amount of whitespace in the AST.
167148
else if (
168-
(currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB) &&
149+
(currentChar === Token.SPACE ||
150+
currentChar === Token.LINE_BREAK ||
151+
currentChar === Token.TAB) &&
169152
(peekChar = input.charCodeAt(i + 1)) &&
170-
(peekChar === SPACE || peekChar === LINE_BREAK || peekChar === TAB)
153+
(peekChar === Token.SPACE || peekChar === Token.LINE_BREAK || peekChar === Token.TAB)
171154
) {
172155
continue
173156
}
174157

175158
// Replace new lines with spaces.
176-
else if (currentChar === LINE_BREAK) {
159+
else if (currentChar === Token.LINE_BREAK) {
177160
if (buffer.length === 0) continue
178161

179162
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) {
181164
buffer += ' '
182165
}
183166
}
@@ -188,7 +171,11 @@ export function parse(input: string) {
188171
// character, even `;` and `}`. Therefore we have to make sure that we are
189172
// at the correct "end" of the custom property by making sure everything is
190173
// 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+
) {
192179
let closingBracketStack = ''
193180

194181
let start = i
@@ -198,45 +185,45 @@ export function parse(input: string) {
198185
peekChar = input.charCodeAt(j)
199186

200187
// Current character is a `\` therefore the next character is escaped.
201-
if (peekChar === BACK_SLASH) {
188+
if (peekChar === Token.BACKSLASH) {
202189
j += 1
203190
}
204191

205192
// 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) {
207194
for (let k = j + 2; k < input.length; k++) {
208195
peekChar = input.charCodeAt(k)
209196
// Current character is a `\` therefore the next character is escaped.
210-
if (peekChar === BACK_SLASH) {
197+
if (peekChar === Token.BACKSLASH) {
211198
k += 1
212199
}
213200

214201
// 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) {
216203
j = k + 1
217204
break
218205
}
219206
}
220207
}
221208

222209
// End of the "property" of the property-value pair.
223-
else if (colonIdx === -1 && peekChar === COLON) {
210+
else if (colonIdx === -1 && peekChar === Token.COLON) {
224211
colonIdx = buffer.length + j - start
225212
}
226213

227214
// End of the custom property.
228-
else if (peekChar === SEMICOLON && closingBracketStack.length === 0) {
215+
else if (peekChar === Token.SEMICOLON && closingBracketStack.length === 0) {
229216
buffer += input.slice(start, j)
230217
i = j
231218
break
232219
}
233220

234221
// Start of a block.
235-
else if (peekChar === OPEN_PARENTHESIS) {
222+
else if (peekChar === Token.OPEN_PAREN) {
236223
closingBracketStack += ')'
237-
} else if (peekChar === OPEN_BRACKET) {
224+
} else if (peekChar === Token.OPEN_BRACKET) {
238225
closingBracketStack += ']'
239-
} else if (peekChar === OPEN_CURLY_BRACKET) {
226+
} else if (peekChar === Token.OPEN_CURLY) {
240227
closingBracketStack += '}'
241228
}
242229

@@ -252,7 +239,7 @@ export function parse(input: string) {
252239
// }
253240
// ```
254241
else if (
255-
(peekChar === CLOSE_CURLY_BRACKET || input.length - 1 === j) &&
242+
(peekChar === Token.CLOSE_CURLY || input.length - 1 === j) &&
256243
closingBracketStack.length === 0
257244
) {
258245
i = j - 1
@@ -262,9 +249,9 @@ export function parse(input: string) {
262249

263250
// End of a block.
264251
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
268255
) {
269256
if (
270257
closingBracketStack.length > 0 &&
@@ -293,7 +280,7 @@ export function parse(input: string) {
293280
// @charset "UTF-8";
294281
// ^
295282
// ```
296-
else if (currentChar === SEMICOLON && buffer.charCodeAt(0) === AT_SIGN) {
283+
else if (currentChar === Token.SEMICOLON && buffer.charCodeAt(0) === Token.AT_SIGN) {
297284
node = rule(buffer, [])
298285

299286
// At-rule is nested inside of a rule, attach it to the parent.
@@ -322,7 +309,7 @@ export function parse(input: string) {
322309
// }
323310
// ```
324311
//
325-
else if (currentChar === SEMICOLON) {
312+
else if (currentChar === Token.SEMICOLON) {
326313
let declaration = parseDeclaration(buffer)
327314
if (parent) {
328315
parent.nodes.push(declaration)
@@ -334,7 +321,7 @@ export function parse(input: string) {
334321
}
335322

336323
// Start of a block.
337-
else if (currentChar === OPEN_CURLY_BRACKET) {
324+
else if (currentChar === Token.OPEN_CURLY) {
338325
closingBracketStack += '}'
339326

340327
// At this point `buffer` should resemble a selector or an at-rule.
@@ -359,7 +346,7 @@ export function parse(input: string) {
359346
}
360347

361348
// End of a block.
362-
else if (currentChar === CLOSE_CURLY_BRACKET) {
349+
else if (currentChar === Token.CLOSE_CURLY) {
363350
if (closingBracketStack === '') {
364351
throw new Error('Missing opening {')
365352
}
@@ -380,7 +367,7 @@ export function parse(input: string) {
380367
// ^
381368
// }
382369
// ```
383-
if (buffer.charCodeAt(0) === AT_SIGN) {
370+
if (buffer.charCodeAt(0) === Token.AT_SIGN) {
384371
node = rule(buffer.trim(), [])
385372

386373
// At-rule is nested inside of a rule, attach it to the parent.
@@ -452,7 +439,9 @@ export function parse(input: string) {
452439
// Skip whitespace at the start of a new node.
453440
if (
454441
buffer.length === 0 &&
455-
(currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB)
442+
(currentChar === Token.SPACE ||
443+
currentChar === Token.LINE_BREAK ||
444+
currentChar === Token.TAB)
456445
) {
457446
continue
458447
}

packages/tailwindcss/src/tokens.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// All numbers are equivalent to the value returned by `String#charCodeAt(0)`
2+
export const BACKSLASH = 0x5c
3+
export const SLASH = 0x2f
4+
export const ASTERISK = 0x2a
5+
export const DOUBLE_QUOTE = 0x22
6+
export const SINGLE_QUOTE = 0x27
7+
export const COLON = 0x3a
8+
export const SEMICOLON = 0x3b
9+
export const LINE_BREAK = 0x0a
10+
export const SPACE = 0x20
11+
export const TAB = 0x09
12+
export const OPEN_CURLY = 0x7b
13+
export const CLOSE_CURLY = 0x7d
14+
export const OPEN_PAREN = 0x28
15+
export const CLOSE_PAREN = 0x29
16+
export const OPEN_BRACKET = 0x5b
17+
export const CLOSE_BRACKET = 0x5d
18+
export const DASH = 0x2d
19+
export const AT_SIGN = 0x40
20+
export const EXCLAMATION_MARK = 0x21
21+
export const LOWER_A = 0x61
22+
export const LOWER_Z = 0x7a
23+
export const HASH = 0x23

packages/tailwindcss/src/utils/is-color.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import * as Token from '../tokens'
2+
13
const NAMED_COLORS = new Set([
24
// CSS Level 1 colors
35
'black',
@@ -197,7 +199,7 @@ const IS_COLOR_FN = /^(rgba?|hsla?|hwb|color|(ok)?(lab|lch)|light-dark|color-mix
197199

198200
export function isColor(value: string): boolean {
199201
return (
200-
value.charCodeAt(0) === 35 /* "#" */ ||
202+
value.charCodeAt(0) === Token.HASH ||
201203
IS_COLOR_FN.test(value) ||
202204
NAMED_COLORS.has(value.toLowerCase())
203205
)

0 commit comments

Comments
 (0)