diff options
| author | Philipp Tanlak <philipp.tanlak@gmail.com> | 2025-11-24 20:54:57 +0100 |
|---|---|---|
| committer | Philipp Tanlak <philipp.tanlak@gmail.com> | 2025-11-24 20:57:48 +0100 |
| commit | b1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c (patch) | |
| tree | 49d360fd6cbc6a2754efe93524ac47ff0fbe0f7d /node_modules/tailwindcss/src/value-parser/parse.js | |
Docs
Diffstat (limited to 'node_modules/tailwindcss/src/value-parser/parse.js')
| -rw-r--r-- | node_modules/tailwindcss/src/value-parser/parse.js | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/node_modules/tailwindcss/src/value-parser/parse.js b/node_modules/tailwindcss/src/value-parser/parse.js new file mode 100644 index 0000000..4455996 --- /dev/null +++ b/node_modules/tailwindcss/src/value-parser/parse.js @@ -0,0 +1,303 @@ +var openParentheses = '('.charCodeAt(0) +var closeParentheses = ')'.charCodeAt(0) +var singleQuote = "'".charCodeAt(0) +var doubleQuote = '"'.charCodeAt(0) +var backslash = '\\'.charCodeAt(0) +var slash = '/'.charCodeAt(0) +var comma = ','.charCodeAt(0) +var colon = ':'.charCodeAt(0) +var star = '*'.charCodeAt(0) +var uLower = 'u'.charCodeAt(0) +var uUpper = 'U'.charCodeAt(0) +var plus = '+'.charCodeAt(0) +var isUnicodeRange = /^[a-f0-9?-]+$/i + +module.exports = function (input) { + var tokens = [] + var value = input + + var next, quote, prev, token, escape, escapePos, whitespacePos, parenthesesOpenPos + var pos = 0 + var code = value.charCodeAt(pos) + var max = value.length + var stack = [{ nodes: tokens }] + var balanced = 0 + var parent + + var name = '' + var before = '' + var after = '' + + while (pos < max) { + // Whitespaces + if (code <= 32) { + next = pos + do { + next += 1 + code = value.charCodeAt(next) + } while (code <= 32) + token = value.slice(pos, next) + + prev = tokens[tokens.length - 1] + if (code === closeParentheses && balanced) { + after = token + } else if (prev && prev.type === 'div') { + prev.after = token + prev.sourceEndIndex += token.length + } else if ( + code === comma || + code === colon || + (code === slash && + value.charCodeAt(next + 1) !== star && + (!parent || (parent && parent.type === 'function' && false))) + ) { + before = token + } else { + tokens.push({ + type: 'space', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } + + pos = next + + // Quotes + } else if (code === singleQuote || code === doubleQuote) { + next = pos + quote = code === singleQuote ? "'" : '"' + token = { + type: 'string', + sourceIndex: pos, + quote: quote, + } + do { + escape = false + next = value.indexOf(quote, next + 1) + if (~next) { + escapePos = next + while (value.charCodeAt(escapePos - 1) === backslash) { + escapePos -= 1 + escape = !escape + } + } else { + value += quote + next = value.length - 1 + token.unclosed = true + } + } while (escape) + token.value = value.slice(pos + 1, next) + token.sourceEndIndex = token.unclosed ? next : next + 1 + tokens.push(token) + pos = next + 1 + code = value.charCodeAt(pos) + + // Comments + } else if (code === slash && value.charCodeAt(pos + 1) === star) { + next = value.indexOf('*/', pos) + + token = { + type: 'comment', + sourceIndex: pos, + sourceEndIndex: next + 2, + } + + if (next === -1) { + token.unclosed = true + next = value.length + token.sourceEndIndex = next + } + + token.value = value.slice(pos + 2, next) + tokens.push(token) + + pos = next + 2 + code = value.charCodeAt(pos) + + // Operation within calc + } else if ((code === slash || code === star) && parent && parent.type === 'function' && true) { + token = value[pos] + tokens.push({ + type: 'word', + sourceIndex: pos - before.length, + sourceEndIndex: pos + token.length, + value: token, + }) + pos += 1 + code = value.charCodeAt(pos) + + // Dividers + } else if (code === slash || code === comma || code === colon) { + token = value[pos] + + tokens.push({ + type: 'div', + sourceIndex: pos - before.length, + sourceEndIndex: pos + token.length, + value: token, + before: before, + after: '', + }) + before = '' + + pos += 1 + code = value.charCodeAt(pos) + + // Open parentheses + } else if (openParentheses === code) { + // Whitespaces after open parentheses + next = pos + do { + next += 1 + code = value.charCodeAt(next) + } while (code <= 32) + parenthesesOpenPos = pos + token = { + type: 'function', + sourceIndex: pos - name.length, + value: name, + before: value.slice(parenthesesOpenPos + 1, next), + } + pos = next + + if (name === 'url' && code !== singleQuote && code !== doubleQuote) { + next -= 1 + do { + escape = false + next = value.indexOf(')', next + 1) + if (~next) { + escapePos = next + while (value.charCodeAt(escapePos - 1) === backslash) { + escapePos -= 1 + escape = !escape + } + } else { + value += ')' + next = value.length - 1 + token.unclosed = true + } + } while (escape) + // Whitespaces before closed + whitespacePos = next + do { + whitespacePos -= 1 + code = value.charCodeAt(whitespacePos) + } while (code <= 32) + if (parenthesesOpenPos < whitespacePos) { + if (pos !== whitespacePos + 1) { + token.nodes = [ + { + type: 'word', + sourceIndex: pos, + sourceEndIndex: whitespacePos + 1, + value: value.slice(pos, whitespacePos + 1), + }, + ] + } else { + token.nodes = [] + } + if (token.unclosed && whitespacePos + 1 !== next) { + token.after = '' + token.nodes.push({ + type: 'space', + sourceIndex: whitespacePos + 1, + sourceEndIndex: next, + value: value.slice(whitespacePos + 1, next), + }) + } else { + token.after = value.slice(whitespacePos + 1, next) + token.sourceEndIndex = next + } + } else { + token.after = '' + token.nodes = [] + } + pos = next + 1 + token.sourceEndIndex = token.unclosed ? next : pos + code = value.charCodeAt(pos) + tokens.push(token) + } else { + balanced += 1 + token.after = '' + token.sourceEndIndex = pos + 1 + tokens.push(token) + stack.push(token) + tokens = token.nodes = [] + parent = token + } + name = '' + + // Close parentheses + } else if (closeParentheses === code && balanced) { + pos += 1 + code = value.charCodeAt(pos) + + parent.after = after + parent.sourceEndIndex += after.length + after = '' + balanced -= 1 + stack[stack.length - 1].sourceEndIndex = pos + stack.pop() + parent = stack[balanced] + tokens = parent.nodes + + // Words + } else { + next = pos + do { + if (code === backslash) { + next += 1 + } + next += 1 + code = value.charCodeAt(next) + } while ( + next < max && + !( + code <= 32 || + code === singleQuote || + code === doubleQuote || + code === comma || + code === colon || + code === slash || + code === openParentheses || + (code === star && parent && parent.type === 'function' && true) || + (code === slash && parent.type === 'function' && true) || + (code === closeParentheses && balanced) + ) + ) + token = value.slice(pos, next) + + if (openParentheses === code) { + name = token + } else if ( + (uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) && + plus === token.charCodeAt(1) && + isUnicodeRange.test(token.slice(2)) + ) { + tokens.push({ + type: 'unicode-range', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } else { + tokens.push({ + type: 'word', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } + + pos = next + } + } + + for (pos = stack.length - 1; pos; pos -= 1) { + stack[pos].unclosed = true + stack[pos].sourceEndIndex = value.length + } + + return stack[0].nodes +} |