const MATH_FUNCTIONS = [
'calc',
'min',
'max',
'clamp',
'mod',
'rem',
'sin',
'cos',
'tan',
'asin',
'acos',
'atan',
'atan2',
'pow',
'sqrt',
'hypot',
'log',
'exp',
'round',
]
const KNOWN_DASHED_FUNCTIONS = ['anchor-size']
const DASHED_FUNCTIONS_REGEX = new RegExp(`(${KNOWN_DASHED_FUNCTIONS.join('|')})\\(`, 'g')
export function hasMathFn(input: string) {
return input.indexOf('(') !== -1 && MATH_FUNCTIONS.some((fn) => input.includes(`${fn}(`))
}
export function addWhitespaceAroundMathOperators(input: string) {
if (!MATH_FUNCTIONS.some((fn) => input.includes(fn))) {
return input
}
let hasKnownFunctions = false
if (KNOWN_DASHED_FUNCTIONS.some((fn) => input.includes(fn))) {
DASHED_FUNCTIONS_REGEX.lastIndex = 0
input = input.replace(DASHED_FUNCTIONS_REGEX, (_, fn) => {
hasKnownFunctions = true
return `$${KNOWN_DASHED_FUNCTIONS.indexOf(fn)}$(`
})
}
let result = ''
let formattable: boolean[] = []
for (let i = 0; i < input.length; i++) {
let char = input[i]
if (char === '(') {
result += char
let start = i
for (let j = i - 1; j >= 0; j--) {
let inner = input.charCodeAt(j)
if (inner >= 48 && inner <= 57) {
start = j
} else if (inner >= 97 && inner <= 122) {
start = j
} else {
break
}
}
let fn = input.slice(start, i)
if (MATH_FUNCTIONS.includes(fn)) {
formattable.unshift(true)
continue
}
else if (formattable[0] && fn === '') {
formattable.unshift(true)
continue
}
formattable.unshift(false)
continue
}
else if (char === ')') {
result += char
formattable.shift()
}
else if (char === ',' && formattable[0]) {
result += `, `
continue
}
else if (char === ' ' && formattable[0] && result[result.length - 1] === ' ') {
continue
}
else if ((char === '+' || char === '*' || char === '/' || char === '-') && formattable[0]) {
let trimmed = result.trimEnd()
let prev = trimmed[trimmed.length - 1]
if (prev === '+' || prev === '*' || prev === '/' || prev === '-') {
result += char
continue
}
else if (prev === '(' || prev === ',') {
result += char
continue
}
else if (input[i - 1] === ' ') {
result += `${char} `
}
else {
result += ` ${char} `
}
}
else if (formattable[0] && input.startsWith('to-zero', i)) {
let start = i
i += 7
result += input.slice(start, i + 1)
}
else {
result += char
}
}
if (hasKnownFunctions) {
return result.replace(/\$(\d+)\$/g, (fn, idx) => KNOWN_DASHED_FUNCTIONS[idx] ?? fn)
}
return result
}