Declare character code constants per file (#13500)
Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com>
This commit is contained in:
parent
6da3f4a37f
commit
0060508c6e
5 changed files with 80 additions and 84 deletions
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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())
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue