diff --git a/packages/tailwindcss/src/candidate.ts b/packages/tailwindcss/src/candidate.ts index 33669883c..71a4aa880 100644 --- a/packages/tailwindcss/src/candidate.ts +++ b/packages/tailwindcss/src/candidate.ts @@ -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 } diff --git a/packages/tailwindcss/src/css-parser.ts b/packages/tailwindcss/src/css-parser.ts index dd7fadd29..88a2a0640 100644 --- a/packages/tailwindcss/src/css-parser.ts +++ b/packages/tailwindcss/src/css-parser.ts @@ -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 } diff --git a/packages/tailwindcss/src/tokens.ts b/packages/tailwindcss/src/tokens.ts deleted file mode 100644 index b336e1d6f..000000000 --- a/packages/tailwindcss/src/tokens.ts +++ /dev/null @@ -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 diff --git a/packages/tailwindcss/src/utils/is-color.ts b/packages/tailwindcss/src/utils/is-color.ts index ae372cb1a..e3501aa86 100644 --- a/packages/tailwindcss/src/utils/is-color.ts +++ b/packages/tailwindcss/src/utils/is-color.ts @@ -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()) ) } diff --git a/packages/tailwindcss/src/utils/segment.ts b/packages/tailwindcss/src/utils/segment.ts index 5835793e8..cbb7115f0 100644 --- a/packages/tailwindcss/src/utils/segment.ts +++ b/packages/tailwindcss/src/utils/segment.ts @@ -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