aliaset
Version:
twind monorepo
65 lines (56 loc) • 1.87 kB
text/typescript
import type { CSSObject, CSSValue } from '../types'
import { interleave } from './interleave'
export function astish(
strings: CSSObject | string | TemplateStringsArray,
interpolations: readonly CSSValue[],
): CSSObject[] {
return Array.isArray(strings)
? astish$(
interleave(strings as TemplateStringsArray, interpolations, (interpolation) =>
interpolation != null && typeof interpolation != 'boolean'
? (interpolation as unknown as string)
: '',
),
)
: typeof strings == 'string'
? astish$(strings)
: [strings as CSSObject]
}
// Based on https://github.com/cristianbote/goober/blob/master/src/core/astish.js
const newRule = / *(?:(?:([\u0080-\uFFFF\w-%@]+) *:? *([^{;]+?);|([^;}{]*?) *{)|(}))/g
/**
* Convert a css style string into a object
*/
function astish$(css: string): CSSObject[] {
css = removeComments(css)
const tree: CSSObject[] = [{}]
const rules: CSSObject[] = [tree[0]]
const conditions: string[] = []
let block: RegExpExecArray | null
while ((block = newRule.exec(css))) {
// Remove the current entry
if (block[4]) {
tree.shift()
conditions.shift()
}
if (block[3]) {
// new nested
conditions.unshift(block[3])
tree.unshift({})
rules.push(conditions.reduce((body, condition) => ({ [condition]: body }), tree[0]))
} else if (!block[4]) {
// if we already have that property — start a new CSSObject
if (tree[0][block[1]]) {
tree.unshift({})
rules.push(conditions.reduce((body, condition) => ({ [condition]: body }), tree[0]))
}
tree[0][block[1]] = block[2]
}
}
// console.log(rules)
return rules
}
// Remove comments (multiline and single line)
function removeComments(css: string): string {
return css.replace(/\/\*[^]*?\*\/|\s\s+|\n/gm, ' ')
}