parse() — tailwindcss Function Reference
Architecture documentation for the parse() function in selector-parser.ts from the tailwindcss codebase.
Entity Profile
Dependency Diagram
graph TD cb368927_d6ec_d016_7fb3_2ea287d31108["parse()"] 3a7318a6_ec18_9d9c_0667_804b7d2f542d["createConverterCache()"] 3a7318a6_ec18_9d9c_0667_804b7d2f542d -->|calls| cb368927_d6ec_d016_7fb3_2ea287d31108 1e85b11a_69b5_68fc_237d_f0167751c10b["substituteFunctionsInValue()"] 1e85b11a_69b5_68fc_237d_f0167751c10b -->|calls| cb368927_d6ec_d016_7fb3_2ea287d31108 025cd786_c6cd_4dc8_21b2_25bd225f52f3["allVariablesAreUsed()"] 025cd786_c6cd_4dc8_21b2_25bd225f52f3 -->|calls| cb368927_d6ec_d016_7fb3_2ea287d31108 24d8d1d0_89ac_76a1_956a_704ad43fcba6["modernizeArbitraryValuesVariant()"] 24d8d1d0_89ac_76a1_956a_704ad43fcba6 -->|calls| cb368927_d6ec_d016_7fb3_2ea287d31108 1d9d6293_9d1d_5445_6e1b_8f6256992b8a["resolveVariablesInValue()"] 1d9d6293_9d1d_5445_6e1b_8f6256992b8a -->|calls| cb368927_d6ec_d016_7fb3_2ea287d31108 cb063cf6_f495_bb4b_84d1_f1d23fb0dae1["createVariantSignatureCache()"] cb063cf6_f495_bb4b_84d1_f1d23fb0dae1 -->|calls| cb368927_d6ec_d016_7fb3_2ea287d31108 63943b72_e55f_b9bc_fe20_d9dc11bf39ec["selector()"] cb368927_d6ec_d016_7fb3_2ea287d31108 -->|calls| 63943b72_e55f_b9bc_fe20_d9dc11bf39ec 21a6cfbd_fa36_3f5c_04ee_2ab3e7b7692a["separator()"] cb368927_d6ec_d016_7fb3_2ea287d31108 -->|calls| 21a6cfbd_fa36_3f5c_04ee_2ab3e7b7692a 6b151bdb_99b2_3551_4557_da802c5097cf["combinator()"] cb368927_d6ec_d016_7fb3_2ea287d31108 -->|calls| 6b151bdb_99b2_3551_4557_da802c5097cf 98f22c20_7d63_ea2e_e3d7_109fd71f519e["fun()"] cb368927_d6ec_d016_7fb3_2ea287d31108 -->|calls| 98f22c20_7d63_ea2e_e3d7_109fd71f519e 9723f170_c888_e761_a795_b80b77a12bca["value()"] cb368927_d6ec_d016_7fb3_2ea287d31108 -->|calls| 9723f170_c888_e761_a795_b80b77a12bca style cb368927_d6ec_d016_7fb3_2ea287d31108 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
packages/tailwindcss/src/selector-parser.ts lines 109–421
export function parse(input: string) {
input = input.replaceAll('\r\n', '\n')
let ast: SelectorAstNode[] = []
let stack: (SelectorFunctionNode | null)[] = []
let parent = null as SelectorFunctionNode | null
let buffer = ''
let peekChar
for (let i = 0; i < input.length; i++) {
let currentChar = input.charCodeAt(i)
switch (currentChar) {
// E.g.:
//
// ```css
// .foo .bar
// ^
//
// .foo > .bar
// ^^^
// ```
case COMMA:
case GREATER_THAN:
case NEWLINE:
case SPACE:
case PLUS:
case TAB:
case TILDE: {
// 1. Handle everything before the combinator as a selector
if (buffer.length > 0) {
let node = selector(buffer)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
buffer = ''
}
// 2. Look ahead and find the end of the combinator
let start = i
let end = i + 1
for (; end < input.length; end++) {
peekChar = input.charCodeAt(end)
if (
peekChar !== COMMA &&
peekChar !== GREATER_THAN &&
peekChar !== NEWLINE &&
peekChar !== SPACE &&
peekChar !== PLUS &&
peekChar !== TAB &&
peekChar !== TILDE
) {
break
}
}
i = end - 1
let contents = input.slice(start, end)
let node = contents.trim() === ',' ? separator(contents) : combinator(contents)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
break
}
// Start of a function call.
//
// E.g.:
//
// ```css
// .foo:not(.bar)
// ^
// ```
case OPEN_PAREN: {
let node = fun(buffer, [])
buffer = ''
// If the function is not one of the following, we combine all it's
// contents into a single value node
if (
node.value !== ':not' &&
node.value !== ':where' &&
node.value !== ':has' &&
node.value !== ':is'
) {
// Find the end of the function call
let start = i + 1
let nesting = 0
// Find the closing bracket.
for (let j = i + 1; j < input.length; j++) {
peekChar = input.charCodeAt(j)
if (peekChar === OPEN_PAREN) {
nesting++
continue
}
if (peekChar === CLOSE_PAREN) {
if (nesting === 0) {
i = j
break
}
nesting--
}
}
let end = i
node.nodes.push(value(input.slice(start, end)))
buffer = ''
i = end
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
break
}
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
stack.push(node)
parent = node
break
}
// End of a function call.
//
// E.g.:
//
// ```css
// foo(bar, baz)
// ^
// ```
case CLOSE_PAREN: {
let tail = stack.pop()
// Handle everything before the closing paren a selector
if (buffer.length > 0) {
let node = selector(buffer)
tail!.nodes.push(node)
buffer = ''
}
if (stack.length > 0) {
parent = stack[stack.length - 1]
} else {
parent = null
}
break
}
// Split compound selectors.
//
// E.g.:
//
// ```css
// .foo.bar
// ^
// ```
case FULL_STOP:
case COLON:
case NUMBER_SIGN: {
// Handle everything before the combinator as a selector and
// start a new selector
if (buffer.length > 0) {
let node = selector(buffer)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
}
buffer = input[i]
break
}
// Start of an attribute selector.
//
// NOTE: Right now we don't care about the individual parts of the
// attribute selector, we just want to find the matching closing bracket.
//
// If we need more information from inside the attribute selector in the
// future, then we can use the `AttributeSelectorParser` here (and even
// inline it if needed)
case OPEN_BRACKET: {
// Handle everything before the combinator as a selector
if (buffer.length > 0) {
let node = selector(buffer)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
}
buffer = ''
let start = i
let nesting = 0
// Find the closing bracket.
for (let j = i + 1; j < input.length; j++) {
peekChar = input.charCodeAt(j)
if (peekChar === OPEN_BRACKET) {
nesting++
continue
}
if (peekChar === CLOSE_BRACKET) {
if (nesting === 0) {
i = j
break
}
nesting--
}
}
// Adjust `buffer` to include the string.
buffer += input.slice(start, i + 1)
break
}
// Start of a string.
case SINGLE_QUOTE:
case DOUBLE_QUOTE: {
let start = i
// We need to ensure that the closing quote is the same as the opening
// quote.
//
// E.g.:
//
// ```css
// "This is a string with a 'quote' in it"
// ^ ^ -> These are not the end of the 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 === BACKSLASH) {
j += 1
}
// End of the string.
else if (peekChar === currentChar) {
i = j
break
}
}
// Adjust `buffer` to include the string.
buffer += input.slice(start, i + 1)
break
}
// Nesting `&` is always a new selector.
// Universal `*` is always a new selector.
case AMPERSAND:
case ASTERISK: {
// 1. Handle everything before the combinator as a selector
if (buffer.length > 0) {
let node = selector(buffer)
if (parent) {
parent.nodes.push(node)
} else {
ast.push(node)
}
buffer = ''
}
// 2. Handle the `&` or `*` as a selector on its own
if (parent) {
parent.nodes.push(selector(input[i]))
} else {
ast.push(selector(input[i]))
}
break
}
// Escaped characters.
case BACKSLASH: {
buffer += input[i] + input[i + 1]
i += 1
break
}
// Everything else will be collected in the buffer
default: {
buffer += input[i]
}
}
}
// Collect the remainder as a word
if (buffer.length > 0) {
ast.push(selector(buffer))
}
return ast
}
Domain
Subdomains
Called By
Source
Frequently Asked Questions
What does parse() do?
parse() is a function in the tailwindcss codebase.
What does parse() call?
parse() calls 5 function(s): combinator, fun, selector, separator, value.
What calls parse()?
parse() is called by 6 function(s): allVariablesAreUsed, createConverterCache, createVariantSignatureCache, modernizeArbitraryValuesVariant, resolveVariablesInValue, substituteFunctionsInValue.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free