astro-ghostcms/.pnpm-store/v3/files/a3/f74fb831113497f17f95bd5bdc4...

304 lines
7.8 KiB
Plaintext

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
}