Skip to content

Instantly share code, notes, and snippets.

@intrnl
Created October 25, 2022 04:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save intrnl/01b8d1a711874a1387223fd49a56de1f to your computer and use it in GitHub Desktop.
Save intrnl/01b8d1a711874a1387223fd49a56de1f to your computer and use it in GitHub Desktop.
import { style } from '@vanilla-extract/css';
const NEW_RULE = /(?:([\u0080-\uFFFF\w-%@]+) *:? *([^{;]+?);|([^;}{]*?) *{)|(}\s*)/g;
const RULE_CLEAN = /\/\*[^]*?\*\/| +/g;
const RULE_NEWLINE = /\n+/g;
const EMPTY = ' ';
/**
* @param {string} val
* @returns {object}
*/
function astish (val) {
const tree = [{}];
let block;
let left;
while ((block = NEW_RULE.exec(val.replace(RULE_CLEAN, '')))) {
// Remove the current entry
if (block[4]) {
tree.shift();
}
else if (block[3]) {
left = block[3].replace(RULE_NEWLINE, EMPTY).trim();
tree.unshift((tree[0][left] = tree[0][left] || {}));
}
else if (block[1] === 'composes') {
tree[0].composes ||= [];
tree[0].composes.push(block[2].replace(RULE_NEWLINE, EMPTY).trim());
}
else {
tree[0][block[1]] = block[2].replace(RULE_NEWLINE, EMPTY).trim();
}
}
return tree[0];
}
function concatenate (str, defs) {
return str.reduce((out, next, i) => {
let tail = defs[i];
return out + next + (tail == null ? '' : tail);
}, '');
};
function walk (obj) {
for (const key in obj) {
const val = obj[key];
if (key[0] === '@') {
if (key[1] === 'm' && key[2] === 'e') {
// handle @media
const condition = key.slice(6).trimStart();
delete obj[key];
walk(val);
obj['@media'] ||= {};
obj['@media'][condition] = { ...obj['@media'][condition], ...val };
}
else if (key[1] === 's' && key[2] === 'u') {
// handle @supports
const condition = key.slice(9).trimStart();
delete obj[key];
walk(val);
obj['@supports'] ||= {};
obj['@supports'][condition] = { ...obj['@supports'][condition], ...val };
}
else if (key[1] === 'c' && key[2] === 'o') {
// handle @container
const condition = key.slice(10).trimStart();
delete obj[key];
walk(val);
obj['@container'] ||= {};
obj['@container'][condition] = { ...obj['@container'][condition], ...val };
}
}
else if (key !== 'composes' && typeof val === 'object' && val) {
delete obj[key];
walk(val);
obj['selectors'] ||= {};
obj['selectors'][key] = { ...obj['selectors'][key], ...val };
}
else if (val !== undefined) {
const transformed = /^--/.test(key) ? key : key.replace(/-[a-z]/g, (match) => match[1].toUpperCase());
if (transformed !== key) {
delete obj[key];
obj[transformed] = val;
}
}
}
}
function css (str, ...defs) {
const concat = concatenate(str, defs);
const ast = astish(concat);
walk(ast);
const debugName = ast.debugName;
delete ast.debugName;
if (ast.composes) {
const composes = ast.composes;
delete ast.composes;
return style([...composes, ast], debugName);
}
return style(ast, debugName);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment