import { readFileSync, existsSync } from "fs"; // TODO import.meta.resolve is supposed to accomplish this without "path" import path from "path"; import { stringify, parse } from "css"; export function style(options) { if (options.inline || options.css === "none") return ""; const rules = load(options); const schemes = rules.find(({ media }) => media === "preferes-color-scheme") ? `\n` : ""; return ``; } export const inline = (options) => { const rules = load(options); return (tag) => { if (!options.inline || options.css === "none") return ""; const styles = reduceVariables(rules, options) .filter(({ selectors }) => selectors && selectors.includes(tag)) .reduce((style, { declarations }) => { declarations.forEach(({ property, value }) => { style = `${style}${property}:${value};`; }); return style; }, ""); return styles !== "" ? ` style="${styles}"` : ""; }; }; export function load(options) { options.css = options.css || (!options.body || !options.inline ? "gmi-web.css" : "gmi.css"); console.log("load:", options.css); if ( ["gmi", "web", "gmi.css", "gmi-web.css"].includes(options.css) || existsSync(options.css) ) { const packageRoot = (file) => path.resolve(path.dirname(new URL(import.meta.url).pathname), file); return parse( readFileSync( path.resolve( ["gmi-web.css", "web"].includes(options.css) ? packageRoot("gmi-web.css") : ["gmi.css", "gmi"].includes(options.css) ? packageRoot("gmi.css") : resolve(options.css) ), "utf-8" ) ).stylesheet.rules } else { throw new Error(`Cannot find file ${options.css}.`); } } export function rootVariables(rules) { const root = rules.find( ({ selectors }) => selectors && selectors.includes(":root") ); if (!root) return {}; return root.declarations.reduce( (obj, { property, value }) => !/^\-\-/.test(property) ? obj : Object.assign(obj, { [property]: value }), {} ); } function reduceVariables(rules, options) { const defaultVariables = rootVariables(rules); const CSS_VAR = /(^var\((?.+)\)|(?.+))/; return rules .filter(({ selectors }) => selectors && !selectors.includes(":root")) .map((rule) => { return Object.assign(rule, { declarations: rule.declarations.map((declaration) => { let { key, val } = CSS_VAR.exec(declaration.value).groups; // only one level of variable referencing is supported key = CSS_VAR.exec(options[key] || defaultVariables[key]).groups.key || key; return Object.assign(declaration, { value: key ? options[key] || defaultVariables[key] : declaration.value, }); }), }); }); }