Declare character code constants per file (#13500)

Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This commit is contained in:
Adam Wathan 2024-04-11 06:44:44 -04:00 • committed by GitHub
parent 6da3f4a37f
commit 0060508c6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 80 additions and 84 deletions

View file

@ -1,8 +1,12 @@
import type { DesignSystem } from './design-system'
import * as Token from './tokens'
import { decodeArbitraryValue } from './utils/decode-arbitrary-value'
import { segment } from './utils/segment'
const COLON = 0x3a
const DASH = 0x2d
const LOWER_A = 0x61
const LOWER_Z = 0x7a
type ArbitraryUtilityValue = {
kind: 'arbitrary'
@ -258,7 +262,7 @@ export function parseCandidate(input: string, designSystem: DesignSystem): Candi
//
// Otherwise, it is an invalid candidate, and skip continue parsing.
let charCode = baseWithoutModifier.charCodeAt(1)
if (charCode !== Token.DASH && !(charCode >= Token.LOWER_A && charCode <= Token.LOWER_Z)) {
if (charCode !== DASH && !(charCode >= LOWER_A && charCode <= LOWER_Z)) {
return null
}
@ -361,14 +365,14 @@ export function parseCandidate(input: string, designSystem: DesignSystem): Candi
let code = arbitraryValue.charCodeAt(i)
// If we hit a ":", we're at the end of a typehint.
if (code === Token.COLON) {
if (code === COLON) {
typehint = arbitraryValue.slice(0, i)
arbitraryValue = arbitraryValue.slice(i + 1)
break
}
// Keep iterating as long as we've only seen valid typehint characters.
if (code === Token.DASH || (code >= Token.LOWER_A && code <= Token.LOWER_Z)) {
if (code === DASH || (code >= LOWER_A && code <= LOWER_Z)) {
continue
}

View file

@ -1,5 +1,24 @@
import { comment, rule, type AstNode, type Comment, type Declaration, type Rule } from './ast'
import * as Token from './tokens'
const BACKSLASH = 0x5c
const SLASH = 0x2f
const ASTERISK = 0x2a
const DOUBLE_QUOTE = 0x22
const SINGLE_QUOTE = 0x27
const COLON = 0x3a
const SEMICOLON = 0x3b
const LINE_BREAK = 0x0a
const SPACE = 0x20
const TAB = 0x09
const OPEN_CURLY = 0x7b
const CLOSE_CURLY = 0x7d
const OPEN_PAREN = 0x28
const CLOSE_PAREN = 0x29
const OPEN_BRACKET = 0x5b
const CLOSE_BRACKET = 0x5d
const DASH = 0x2d
const AT_SIGN = 0x40
const EXCLAMATION_MARK = 0x21
export function parse(input: string) {
input = input.replaceAll('\r\n', '\n')
@ -30,7 +49,7 @@ export function parse(input: string) {
// ^
// ```
//
if (currentChar === Token.BACKSLASH) {
if (currentChar === BACKSLASH) {
buffer += input.slice(i, i + 2)
i += 1
}
@ -51,19 +70,19 @@ export function parse(input: string) {
// ^^^^^^^^^^^^^
// }
// ```
else if (currentChar === Token.SLASH && input.charCodeAt(i + 1) === Token.ASTERISK) {
else if (currentChar === SLASH && input.charCodeAt(i + 1) === ASTERISK) {
let start = i
for (let j = i + 2; j < input.length; j++) {
peekChar = input.charCodeAt(j)
// Current character is a `\` therefore the next character is escaped.
if (peekChar === Token.BACKSLASH) {
if (peekChar === BACKSLASH) {
j += 1
}
// End of the comment
else if (peekChar === Token.ASTERISK && input.charCodeAt(j + 1) === Token.SLASH) {
else if (peekChar === ASTERISK && input.charCodeAt(j + 1) === SLASH) {
i = j + 1
break
}
@ -73,13 +92,13 @@ export function parse(input: string) {
// Collect all license comments so that we can hoist them to the top of
// the AST.
if (commentString.charCodeAt(2) === Token.EXCLAMATION_MARK) {
if (commentString.charCodeAt(2) === EXCLAMATION_MARK) {
licenseComments.push(comment(commentString.slice(2, -2)))
}
}
// Start of a string.
else if (currentChar === Token.SINGLE_QUOTE || currentChar === Token.DOUBLE_QUOTE) {
else if (currentChar === SINGLE_QUOTE || currentChar === DOUBLE_QUOTE) {
let start = i
// We need to ensure that the closing quote is the same as the opening
@ -96,7 +115,7 @@ export function parse(input: string) {
for (let j = i + 1; j < input.length; j++) {
peekChar = input.charCodeAt(j)
// Current character is a `\` therefore the next character is escaped.
if (peekChar === Token.BACKSLASH) {
if (peekChar === BACKSLASH) {
j += 1
}
@ -116,7 +135,7 @@ export function parse(input: string) {
// ^ Missing "
// }
// ```
else if (peekChar === Token.SEMICOLON && input.charCodeAt(j + 1) === Token.LINE_BREAK) {
else if (peekChar === SEMICOLON && input.charCodeAt(j + 1) === LINE_BREAK) {
throw new Error(
`Unterminated string: ${input.slice(start, j + 1) + String.fromCharCode(currentChar)}`,
)
@ -132,7 +151,7 @@ export function parse(input: string) {
// ^ Missing "
// }
// ```
else if (peekChar === Token.LINE_BREAK) {
else if (peekChar === LINE_BREAK) {
throw new Error(
`Unterminated string: ${input.slice(start, j) + String.fromCharCode(currentChar)}`,
)
@ -146,21 +165,19 @@ export function parse(input: string) {
// Skip whitespace if the next character is also whitespace. This allows us
// to reduce the amount of whitespace in the AST.
else if (
(currentChar === Token.SPACE ||
currentChar === Token.LINE_BREAK ||
currentChar === Token.TAB) &&
(currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB) &&
(peekChar = input.charCodeAt(i + 1)) &&
(peekChar === Token.SPACE || peekChar === Token.LINE_BREAK || peekChar === Token.TAB)
(peekChar === SPACE || peekChar === LINE_BREAK || peekChar === TAB)
) {
continue
}
// Replace new lines with spaces.
else if (currentChar === Token.LINE_BREAK) {
else if (currentChar === LINE_BREAK) {
if (buffer.length === 0) continue
peekChar = buffer.charCodeAt(buffer.length - 1)
if (peekChar !== Token.SPACE && peekChar !== Token.LINE_BREAK && peekChar !== Token.TAB) {
if (peekChar !== SPACE && peekChar !== LINE_BREAK && peekChar !== TAB) {
buffer += ' '
}
}
@ -171,11 +188,7 @@ export function parse(input: string) {
// character, even `;` and `}`. Therefore we have to make sure that we are
// at the correct "end" of the custom property by making sure everything is
// balanced.
else if (
currentChar === Token.DASH &&
input.charCodeAt(i + 1) === Token.DASH &&
buffer.length === 0
) {
else if (currentChar === DASH && input.charCodeAt(i + 1) === DASH && buffer.length === 0) {
let closingBracketStack = ''
let start = i
@ -185,21 +198,21 @@ export function parse(input: string) {
peekChar = input.charCodeAt(j)
// Current character is a `\` therefore the next character is escaped.
if (peekChar === Token.BACKSLASH) {
if (peekChar === BACKSLASH) {
j += 1
}
// Start of a comment.
else if (peekChar === Token.SLASH && input.charCodeAt(j + 1) === Token.ASTERISK) {
else if (peekChar === SLASH && input.charCodeAt(j + 1) === ASTERISK) {
for (let k = j + 2; k < input.length; k++) {
peekChar = input.charCodeAt(k)
// Current character is a `\` therefore the next character is escaped.
if (peekChar === Token.BACKSLASH) {
if (peekChar === BACKSLASH) {
k += 1
}
// End of the comment
else if (peekChar === Token.ASTERISK && input.charCodeAt(k + 1) === Token.SLASH) {
else if (peekChar === ASTERISK && input.charCodeAt(k + 1) === SLASH) {
j = k + 1
break
}
@ -207,23 +220,23 @@ export function parse(input: string) {
}
// End of the "property" of the property-value pair.
else if (colonIdx === -1 && peekChar === Token.COLON) {
else if (colonIdx === -1 && peekChar === COLON) {
colonIdx = buffer.length + j - start
}
// End of the custom property.
else if (peekChar === Token.SEMICOLON && closingBracketStack.length === 0) {
else if (peekChar === SEMICOLON && closingBracketStack.length === 0) {
buffer += input.slice(start, j)
i = j
break
}
// Start of a block.
else if (peekChar === Token.OPEN_PAREN) {
else if (peekChar === OPEN_PAREN) {
closingBracketStack += ')'
} else if (peekChar === Token.OPEN_BRACKET) {
} else if (peekChar === OPEN_BRACKET) {
closingBracketStack += ']'
} else if (peekChar === Token.OPEN_CURLY) {
} else if (peekChar === OPEN_CURLY) {
closingBracketStack += '}'
}
@ -239,7 +252,7 @@ export function parse(input: string) {
// }
// ```
else if (
(peekChar === Token.CLOSE_CURLY || input.length - 1 === j) &&
(peekChar === CLOSE_CURLY || input.length - 1 === j) &&
closingBracketStack.length === 0
) {
i = j - 1
@ -249,9 +262,9 @@ export function parse(input: string) {
// End of a block.
else if (
peekChar === Token.CLOSE_PAREN ||
peekChar === Token.CLOSE_BRACKET ||
peekChar === Token.CLOSE_CURLY
peekChar === CLOSE_PAREN ||
peekChar === CLOSE_BRACKET ||
peekChar === CLOSE_CURLY
) {
if (
closingBracketStack.length > 0 &&
@ -280,7 +293,7 @@ export function parse(input: string) {
// @charset "UTF-8";
// ^
// ```
else if (currentChar === Token.SEMICOLON && buffer.charCodeAt(0) === Token.AT_SIGN) {
else if (currentChar === SEMICOLON && buffer.charCodeAt(0) === AT_SIGN) {
node = rule(buffer, [])
// At-rule is nested inside of a rule, attach it to the parent.
@ -309,7 +322,7 @@ export function parse(input: string) {
// }
// ```
//
else if (currentChar === Token.SEMICOLON) {
else if (currentChar === SEMICOLON) {
let declaration = parseDeclaration(buffer)
if (parent) {
parent.nodes.push(declaration)
@ -321,7 +334,7 @@ export function parse(input: string) {
}
// Start of a block.
else if (currentChar === Token.OPEN_CURLY) {
else if (currentChar === OPEN_CURLY) {
closingBracketStack += '}'
// At this point `buffer` should resemble a selector or an at-rule.
@ -346,7 +359,7 @@ export function parse(input: string) {
}
// End of a block.
else if (currentChar === Token.CLOSE_CURLY) {
else if (currentChar === CLOSE_CURLY) {
if (closingBracketStack === '') {
throw new Error('Missing opening {')
}
@ -367,7 +380,7 @@ export function parse(input: string) {
// ^
// }
// ```
if (buffer.charCodeAt(0) === Token.AT_SIGN) {
if (buffer.charCodeAt(0) === AT_SIGN) {
node = rule(buffer.trim(), [])
// At-rule is nested inside of a rule, attach it to the parent.
@ -439,9 +452,7 @@ export function parse(input: string) {
// Skip whitespace at the start of a new node.
if (
buffer.length === 0 &&
(currentChar === Token.SPACE ||
currentChar === Token.LINE_BREAK ||
currentChar === Token.TAB)
(currentChar === SPACE || currentChar === LINE_BREAK || currentChar === TAB)
) {
continue
}

View file

@ -1,23 +0,0 @@
// All numbers are equivalent to the value returned by `String#charCodeAt(0)`
export const BACKSLASH = 0x5c
export const SLASH = 0x2f
export const ASTERISK = 0x2a
export const DOUBLE_QUOTE = 0x22
export const SINGLE_QUOTE = 0x27
export const COLON = 0x3a
export const SEMICOLON = 0x3b
export const LINE_BREAK = 0x0a
export const SPACE = 0x20
export const TAB = 0x09
export const OPEN_CURLY = 0x7b
export const CLOSE_CURLY = 0x7d
export const OPEN_PAREN = 0x28
export const CLOSE_PAREN = 0x29
export const OPEN_BRACKET = 0x5b
export const CLOSE_BRACKET = 0x5d
export const DASH = 0x2d
export const AT_SIGN = 0x40
export const EXCLAMATION_MARK = 0x21
export const LOWER_A = 0x61
export const LOWER_Z = 0x7a
export const HASH = 0x23

View file

@ -1,4 +1,4 @@
import * as Token from '../tokens'
const HASH = 0x23
const NAMED_COLORS = new Set([
// CSS Level 1 colors
@ -199,8 +199,6 @@ const IS_COLOR_FN = /^(rgba?|hsla?|hwb|color|(ok)?(lab|lch)|light-dark|color-mix
export function isColor(value: string): boolean {
return (
value.charCodeAt(0) === Token.HASH ||
IS_COLOR_FN.test(value) ||
NAMED_COLORS.has(value.toLowerCase())
value.charCodeAt(0) === HASH || IS_COLOR_FN.test(value) || NAMED_COLORS.has(value.toLowerCase())
)
}

View file

@ -1,4 +1,10 @@
import * as Token from '../tokens'
const BACKSLASH = 0x5c
const OPEN_CURLY = 0x7b
const CLOSE_CURLY = 0x7d
const OPEN_PAREN = 0x28
const CLOSE_PAREN = 0x29
const OPEN_BRACKET = 0x5b
const CLOSE_BRACKET = 0x5d
// This is a shared buffer that is used to keep track of the current nesting level
// of parens, brackets, and braces. It is used to determine if a character is at
@ -37,25 +43,25 @@ export function segment(input: string, separator: string) {
}
switch (char) {
case Token.BACKSLASH:
case BACKSLASH:
// The next character is escaped, so we skip it.
idx += 1
break
case Token.OPEN_PAREN:
closingBracketStack[stackPos] = Token.CLOSE_PAREN
case OPEN_PAREN:
closingBracketStack[stackPos] = CLOSE_PAREN
stackPos++
break
case Token.OPEN_BRACKET:
closingBracketStack[stackPos] = Token.CLOSE_BRACKET
case OPEN_BRACKET:
closingBracketStack[stackPos] = CLOSE_BRACKET
stackPos++
break
case Token.OPEN_CURLY:
closingBracketStack[stackPos] = Token.CLOSE_CURLY
case OPEN_CURLY:
closingBracketStack[stackPos] = CLOSE_CURLY
stackPos++
break
case Token.CLOSE_BRACKET:
case Token.CLOSE_CURLY:
case Token.CLOSE_PAREN:
case CLOSE_BRACKET:
case CLOSE_CURLY:
case CLOSE_PAREN:
if (stackPos > 0 && char === closingBracketStack[stackPos - 1]) {
// SAFETY: The buffer does not need to be mutated because the stack is
// only ever read from or written to its current position. Its current