mirror of
https://github.com/Sevichecc/Urara-Blog.git
synced 2025-05-06 05:09:13 +08:00
899 lines
29 KiB
Text
899 lines
29 KiB
Text
function escapeRegExp(string) {
|
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
}
|
|
function escapeSelector(str) {
|
|
const length = str.length;
|
|
let index = -1;
|
|
let codeUnit;
|
|
let result = "";
|
|
const firstCodeUnit = str.charCodeAt(0);
|
|
while (++index < length) {
|
|
codeUnit = str.charCodeAt(index);
|
|
if (codeUnit === 0) {
|
|
result += "\uFFFD";
|
|
continue;
|
|
}
|
|
if (codeUnit === 44) {
|
|
result += "\\,";
|
|
continue;
|
|
}
|
|
if (codeUnit >= 1 && codeUnit <= 31 || codeUnit === 127 || index === 0 && codeUnit >= 48 && codeUnit <= 57 || index === 1 && codeUnit >= 48 && codeUnit <= 57 && firstCodeUnit === 45) {
|
|
result += `\\${codeUnit.toString(16)} `;
|
|
continue;
|
|
}
|
|
if (index === 0 && length === 1 && codeUnit === 45) {
|
|
result += `\\${str.charAt(index)}`;
|
|
continue;
|
|
}
|
|
if (codeUnit >= 128 || codeUnit === 45 || codeUnit === 95 || codeUnit >= 48 && codeUnit <= 57 || codeUnit >= 65 && codeUnit <= 90 || codeUnit >= 97 && codeUnit <= 122) {
|
|
result += str.charAt(index);
|
|
continue;
|
|
}
|
|
result += `\\${str.charAt(index)}`;
|
|
}
|
|
return result;
|
|
}
|
|
const e = escapeSelector;
|
|
|
|
function toArray(value = []) {
|
|
return Array.isArray(value) ? value : [value];
|
|
}
|
|
function uniq(value) {
|
|
return Array.from(new Set(value));
|
|
}
|
|
function mergeSet(target, append) {
|
|
append.forEach((i) => target.add(i));
|
|
return target;
|
|
}
|
|
function isString(s) {
|
|
return typeof s === "string";
|
|
}
|
|
|
|
function normalizeCSSEntries(obj) {
|
|
if (isString(obj))
|
|
return obj;
|
|
return (!Array.isArray(obj) ? Object.entries(obj) : obj).filter((i) => i[1] != null);
|
|
}
|
|
function normalizeCSSValues(obj) {
|
|
if (Array.isArray(obj)) {
|
|
if (obj.find((i) => !Array.isArray(i) || Array.isArray(i[0])))
|
|
return obj.map((i) => normalizeCSSEntries(i));
|
|
else
|
|
return [obj];
|
|
} else {
|
|
return [normalizeCSSEntries(obj)];
|
|
}
|
|
}
|
|
function clearIdenticalEntries(entry) {
|
|
return entry.filter(([k, v], idx) => {
|
|
if (k.startsWith("$$"))
|
|
return false;
|
|
for (let i = idx - 1; i >= 0; i--) {
|
|
if (entry[i][0] === k && entry[i][1] === v)
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
function entriesToCss(arr) {
|
|
if (arr == null)
|
|
return "";
|
|
return clearIdenticalEntries(arr).map(([key, value]) => value != null ? `${key}:${value};` : void 0).filter(Boolean).join("");
|
|
}
|
|
function isObject(item) {
|
|
return item && typeof item === "object" && !Array.isArray(item);
|
|
}
|
|
function mergeDeep(original, patch) {
|
|
const o = original;
|
|
const p = patch;
|
|
if (Array.isArray(o))
|
|
return [...p];
|
|
const output = { ...o };
|
|
if (isObject(o) && isObject(p)) {
|
|
Object.keys(p).forEach((key) => {
|
|
if (isObject(o[key]) && isObject(p[key]) || Array.isArray(o[key]) && Array.isArray(p[key]))
|
|
output[key] = mergeDeep(o[key], p[key]);
|
|
else
|
|
Object.assign(output, { [key]: p[key] });
|
|
});
|
|
}
|
|
return output;
|
|
}
|
|
function clone(val) {
|
|
let k, out, tmp;
|
|
if (Array.isArray(val)) {
|
|
out = Array(k = val.length);
|
|
while (k--)
|
|
out[k] = (tmp = val[k]) && typeof tmp === "object" ? clone(tmp) : tmp;
|
|
return out;
|
|
}
|
|
if (Object.prototype.toString.call(val) === "[object Object]") {
|
|
out = {};
|
|
for (k in val) {
|
|
if (k === "__proto__") {
|
|
Object.defineProperty(out, k, {
|
|
value: clone(val[k]),
|
|
configurable: true,
|
|
enumerable: true,
|
|
writable: true
|
|
});
|
|
} else {
|
|
out[k] = (tmp = val[k]) && typeof tmp === "object" ? clone(tmp) : tmp;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
return val;
|
|
}
|
|
function isStaticRule(rule) {
|
|
return isString(rule[0]);
|
|
}
|
|
function isStaticShortcut(sc) {
|
|
return isString(sc[0]);
|
|
}
|
|
|
|
const attributifyRE = /^\[(.+?)~?="(.*)"\]$/;
|
|
const cssIdRE = /\.(css|postcss|sass|scss|less|stylus|styl)$/;
|
|
const validateFilterRE = /(?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:%-?]/;
|
|
const CONTROL_SHORTCUT_NO_MERGE = "$$shortcut-no-merge";
|
|
function isAttributifySelector(selector) {
|
|
return selector.match(attributifyRE);
|
|
}
|
|
function isValidSelector(selector = "") {
|
|
return validateFilterRE.test(selector);
|
|
}
|
|
function normalizeVariant(variant) {
|
|
return typeof variant === "function" ? { match: variant } : variant;
|
|
}
|
|
function isRawUtil(util) {
|
|
return util.length === 3;
|
|
}
|
|
function notNull(value) {
|
|
return value != null;
|
|
}
|
|
function noop() {
|
|
}
|
|
|
|
class TwoKeyMap {
|
|
constructor() {
|
|
this._map = /* @__PURE__ */ new Map();
|
|
}
|
|
get(key1, key2) {
|
|
const m2 = this._map.get(key1);
|
|
if (m2)
|
|
return m2.get(key2);
|
|
}
|
|
getFallback(key1, key2, fallback) {
|
|
let m2 = this._map.get(key1);
|
|
if (!m2) {
|
|
m2 = /* @__PURE__ */ new Map();
|
|
this._map.set(key1, m2);
|
|
}
|
|
if (!m2.has(key2))
|
|
m2.set(key2, fallback);
|
|
return m2.get(key2);
|
|
}
|
|
set(key1, key2, value) {
|
|
let m2 = this._map.get(key1);
|
|
if (!m2) {
|
|
m2 = /* @__PURE__ */ new Map();
|
|
this._map.set(key1, m2);
|
|
}
|
|
m2.set(key2, value);
|
|
return this;
|
|
}
|
|
has(key1, key2) {
|
|
return this._map.get(key1)?.has(key2);
|
|
}
|
|
delete(key1, key2) {
|
|
return this._map.get(key1)?.delete(key2) || false;
|
|
}
|
|
deleteTop(key1) {
|
|
return this._map.delete(key1);
|
|
}
|
|
map(fn) {
|
|
return Array.from(this._map.entries()).flatMap(
|
|
([k1, m2]) => Array.from(m2.entries()).map(([k2, v]) => {
|
|
return fn(v, k1, k2);
|
|
})
|
|
);
|
|
}
|
|
}
|
|
class BetterMap extends Map {
|
|
map(mapFn) {
|
|
const result = [];
|
|
this.forEach((v, k) => {
|
|
result.push(mapFn(v, k));
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
function withLayer(layer, rules) {
|
|
rules.forEach((r) => {
|
|
if (!r[2])
|
|
r[2] = { layer };
|
|
else
|
|
r[2].layer = layer;
|
|
});
|
|
return rules;
|
|
}
|
|
|
|
const regexClassGroup = /([!\w+:_/-]+?)([:-])\(((?:[~!\w\s:/\\,%#.$-]|\[.*?\])*?)\)/gm;
|
|
function expandVariantGroup(str, seperators = ["-", ":"]) {
|
|
regexClassGroup.lastIndex = 0;
|
|
let hasChanged = false;
|
|
let content = str.toString();
|
|
do {
|
|
const before = content;
|
|
content = content.replace(
|
|
regexClassGroup,
|
|
(from, pre, sep, body) => {
|
|
if (!seperators.includes(sep))
|
|
return from;
|
|
return body.split(/\s/g).filter(Boolean).map((i) => i === "~" ? pre : i.replace(/^(!?)(.*)/, `$1${pre}${sep}$2`)).join(" ");
|
|
}
|
|
);
|
|
hasChanged = content !== before;
|
|
} while (hasChanged);
|
|
if (typeof str === "string")
|
|
return content;
|
|
else
|
|
return str.overwrite(0, str.length(), content);
|
|
}
|
|
|
|
const warned = /* @__PURE__ */ new Set();
|
|
function warnOnce(msg) {
|
|
if (warned.has(msg))
|
|
return;
|
|
console.warn("[unocss]", msg);
|
|
warned.add(msg);
|
|
}
|
|
|
|
function createValueHandler(handlers) {
|
|
const handler = function(str) {
|
|
const s = this.__options?.sequence || [];
|
|
this.__options.sequence = [];
|
|
for (const n of s) {
|
|
const res = handlers[n](str);
|
|
if (res != null)
|
|
return res;
|
|
}
|
|
};
|
|
function addProcessor(that, name) {
|
|
if (!that.__options) {
|
|
that.__options = {
|
|
sequence: []
|
|
};
|
|
}
|
|
that.__options.sequence.push(name);
|
|
return that;
|
|
}
|
|
for (const name of Object.keys(handlers)) {
|
|
Object.defineProperty(handler, name, {
|
|
enumerable: true,
|
|
get() {
|
|
return addProcessor(this, name);
|
|
}
|
|
});
|
|
}
|
|
return handler;
|
|
}
|
|
|
|
const splitCode = (code) => code.split(/\\?[\s'"`;=]+/g).filter(isValidSelector);
|
|
const extractorSplit = {
|
|
name: "split",
|
|
order: 0,
|
|
extract({ code }) {
|
|
return new Set(splitCode(code));
|
|
}
|
|
};
|
|
|
|
const extractorSvelte = {
|
|
name: "svelte",
|
|
order: 0,
|
|
extract({ code, id }) {
|
|
let result = splitCode(code);
|
|
if (id && id.endsWith(".svelte")) {
|
|
result = result.map((r) => {
|
|
return r.startsWith("class:") ? r.slice(6) : r;
|
|
});
|
|
}
|
|
return new Set(result);
|
|
}
|
|
};
|
|
|
|
function createNanoEvents() {
|
|
return {
|
|
events: {},
|
|
emit(event, ...args) {
|
|
(this.events[event] || []).forEach((i) => i(...args));
|
|
},
|
|
on(event, cb) {
|
|
(this.events[event] = this.events[event] || []).push(cb);
|
|
return () => this.events[event] = (this.events[event] || []).filter((i) => i !== cb);
|
|
}
|
|
};
|
|
}
|
|
|
|
const LAYER_DEFAULT = "default";
|
|
const LAYER_PREFLIGHTS = "preflights";
|
|
const LAYER_SHORTCUTS = "shortcuts";
|
|
const DEAFULT_LAYERS = {
|
|
[LAYER_PREFLIGHTS]: -100,
|
|
[LAYER_SHORTCUTS]: -10,
|
|
[LAYER_DEFAULT]: 0
|
|
};
|
|
|
|
function resolveShortcuts(shortcuts) {
|
|
return toArray(shortcuts).flatMap((s) => {
|
|
if (Array.isArray(s))
|
|
return [s];
|
|
return Object.entries(s);
|
|
});
|
|
}
|
|
function resolvePreset(preset) {
|
|
const shortcuts = preset.shortcuts ? resolveShortcuts(preset.shortcuts) : void 0;
|
|
preset.shortcuts = shortcuts;
|
|
if (preset.prefix || preset.layer) {
|
|
const apply = (i) => {
|
|
if (!i[2])
|
|
i[2] = {};
|
|
const meta = i[2];
|
|
if (meta.prefix == null && preset.prefix)
|
|
meta.prefix = preset.prefix;
|
|
if (meta.layer == null && preset.layer)
|
|
meta.prefix = preset.layer;
|
|
};
|
|
shortcuts?.forEach(apply);
|
|
preset.rules?.forEach(apply);
|
|
}
|
|
return preset;
|
|
}
|
|
function resolveConfig(userConfig = {}, defaults = {}) {
|
|
const config = Object.assign({}, defaults, userConfig);
|
|
const rawPresets = (config.presets || []).flatMap(toArray).map(resolvePreset);
|
|
const sortedPresets = [
|
|
...rawPresets.filter((p) => p.enforce === "pre"),
|
|
...rawPresets.filter((p) => !p.enforce),
|
|
...rawPresets.filter((p) => p.enforce === "post")
|
|
];
|
|
const layers = Object.assign(DEAFULT_LAYERS, ...rawPresets.map((i) => i.layers), userConfig.layers);
|
|
function mergePresets(key) {
|
|
return uniq([
|
|
...sortedPresets.flatMap((p) => toArray(p[key] || [])),
|
|
...toArray(config[key] || [])
|
|
]);
|
|
}
|
|
const extractors = mergePresets("extractors");
|
|
if (!extractors.length)
|
|
extractors.push(extractorSplit);
|
|
extractors.sort((a, b) => (a.order || 0) - (b.order || 0));
|
|
const rules = mergePresets("rules");
|
|
const rulesStaticMap = {};
|
|
const rulesSize = rules.length;
|
|
rules.forEach((rule, i) => {
|
|
if (isStaticRule(rule)) {
|
|
const prefix = rule[2]?.prefix || "";
|
|
rulesStaticMap[prefix + rule[0]] = [i, rule[1], rule[2], rule];
|
|
delete rules[i];
|
|
}
|
|
});
|
|
const theme = clone([
|
|
...sortedPresets.map((p) => p.theme || {}),
|
|
config.theme || {}
|
|
].reduce((a, p) => mergeDeep(a, p), {}));
|
|
mergePresets("extendTheme").forEach((extendTheme) => extendTheme(theme));
|
|
const autocomplete = {
|
|
templates: uniq(sortedPresets.map((p) => toArray(p.autocomplete?.templates)).flat()),
|
|
extractors: sortedPresets.map((p) => toArray(p.autocomplete?.extractors)).flat().sort((a, b) => (a.order || 0) - (b.order || 0))
|
|
};
|
|
return {
|
|
mergeSelectors: true,
|
|
warn: true,
|
|
blocklist: [],
|
|
sortLayers: (layers2) => layers2,
|
|
...config,
|
|
presets: sortedPresets,
|
|
envMode: config.envMode || "build",
|
|
shortcutsLayer: config.shortcutsLayer || "shortcuts",
|
|
layers,
|
|
theme,
|
|
rulesSize,
|
|
rulesDynamic: rules,
|
|
rulesStaticMap,
|
|
preprocess: mergePresets("preprocess"),
|
|
postprocess: mergePresets("postprocess"),
|
|
preflights: mergePresets("preflights"),
|
|
autocomplete,
|
|
variants: mergePresets("variants").map(normalizeVariant),
|
|
shortcuts: resolveShortcuts(mergePresets("shortcuts")),
|
|
extractors,
|
|
safelist: mergePresets("safelist")
|
|
};
|
|
}
|
|
|
|
const version = "0.45.6";
|
|
|
|
class UnoGenerator {
|
|
constructor(userConfig = {}, defaults = {}) {
|
|
this.userConfig = userConfig;
|
|
this.defaults = defaults;
|
|
this.version = version;
|
|
this._cache = /* @__PURE__ */ new Map();
|
|
this.blocked = /* @__PURE__ */ new Set();
|
|
this.parentOrders = /* @__PURE__ */ new Map();
|
|
this.events = createNanoEvents();
|
|
this.config = resolveConfig(userConfig, defaults);
|
|
this.events.emit("config", this.config);
|
|
}
|
|
setConfig(userConfig, defaults) {
|
|
if (!userConfig)
|
|
return;
|
|
if (defaults)
|
|
this.defaults = defaults;
|
|
this.userConfig = userConfig;
|
|
this.blocked.clear();
|
|
this.parentOrders.clear();
|
|
this._cache.clear();
|
|
this.config = resolveConfig(userConfig, this.defaults);
|
|
this.events.emit("config", this.config);
|
|
}
|
|
async applyExtractors(code, id, set = /* @__PURE__ */ new Set()) {
|
|
const context = {
|
|
get original() {
|
|
return code;
|
|
},
|
|
code,
|
|
id
|
|
};
|
|
for (const extractor of this.config.extractors) {
|
|
const result = await extractor.extract(context);
|
|
result?.forEach((t) => set.add(t));
|
|
}
|
|
return set;
|
|
}
|
|
makeContext(raw, applied) {
|
|
const context = {
|
|
rawSelector: raw,
|
|
currentSelector: applied[1],
|
|
theme: this.config.theme,
|
|
generator: this,
|
|
variantHandlers: applied[2],
|
|
constructCSS: (...args) => this.constructCustomCSS(context, ...args),
|
|
variantMatch: applied
|
|
};
|
|
return context;
|
|
}
|
|
async parseToken(raw, alias) {
|
|
if (this.blocked.has(raw))
|
|
return;
|
|
const cacheKey = `${raw}${alias ? ` ${alias}` : ""}`;
|
|
if (this._cache.has(cacheKey))
|
|
return this._cache.get(cacheKey);
|
|
let current = raw;
|
|
for (const p of this.config.preprocess)
|
|
current = p(raw);
|
|
if (this.isBlocked(current)) {
|
|
this.blocked.add(raw);
|
|
this._cache.set(cacheKey, null);
|
|
return;
|
|
}
|
|
const applied = this.matchVariants(raw, current);
|
|
if (!applied || this.isBlocked(applied[1])) {
|
|
this.blocked.add(raw);
|
|
this._cache.set(cacheKey, null);
|
|
return;
|
|
}
|
|
const context = this.makeContext(
|
|
raw,
|
|
[alias || applied[0], applied[1], applied[2], applied[3]]
|
|
);
|
|
if (this.config.details)
|
|
context.variants = [...applied[3]];
|
|
const expanded = this.expandShortcut(context.currentSelector, context);
|
|
if (expanded) {
|
|
const utils = await this.stringifyShortcuts(context.variantMatch, context, expanded[0], expanded[1]);
|
|
if (utils?.length) {
|
|
this._cache.set(cacheKey, utils);
|
|
return utils;
|
|
}
|
|
} else {
|
|
const utils = (await this.parseUtil(context.variantMatch, context))?.map((i) => this.stringifyUtil(i, context)).filter(notNull);
|
|
if (utils?.length) {
|
|
this._cache.set(cacheKey, utils);
|
|
return utils;
|
|
}
|
|
}
|
|
this._cache.set(cacheKey, null);
|
|
}
|
|
async generate(input, options = {}) {
|
|
const {
|
|
id,
|
|
scope,
|
|
preflights = true,
|
|
safelist = true,
|
|
minify = false
|
|
} = options;
|
|
const tokens = isString(input) ? await this.applyExtractors(input, id) : Array.isArray(input) ? new Set(input) : input;
|
|
if (safelist)
|
|
this.config.safelist.forEach((s) => tokens.add(s));
|
|
const nl = minify ? "" : "\n";
|
|
const layerSet = /* @__PURE__ */ new Set([LAYER_DEFAULT]);
|
|
const matched = /* @__PURE__ */ new Set();
|
|
const sheet = /* @__PURE__ */ new Map();
|
|
let preflightsMap = {};
|
|
const tokenPromises = Array.from(tokens).map(async (raw) => {
|
|
if (matched.has(raw))
|
|
return;
|
|
const payload = await this.parseToken(raw);
|
|
if (payload == null)
|
|
return;
|
|
matched.add(raw);
|
|
for (const item of payload) {
|
|
const parent = item[3] || "";
|
|
const layer = item[4]?.layer;
|
|
if (!sheet.has(parent))
|
|
sheet.set(parent, []);
|
|
sheet.get(parent).push(item);
|
|
if (layer)
|
|
layerSet.add(layer);
|
|
}
|
|
});
|
|
const preflightPromise = (async () => {
|
|
if (!preflights)
|
|
return;
|
|
const preflightContext = {
|
|
generator: this,
|
|
theme: this.config.theme
|
|
};
|
|
const preflightLayerSet = /* @__PURE__ */ new Set([]);
|
|
this.config.preflights.forEach(({ layer = LAYER_PREFLIGHTS }) => {
|
|
layerSet.add(layer);
|
|
preflightLayerSet.add(layer);
|
|
});
|
|
preflightsMap = Object.fromEntries(
|
|
await Promise.all(Array.from(preflightLayerSet).map(
|
|
async (layer) => {
|
|
const preflights2 = await Promise.all(
|
|
this.config.preflights.filter((i) => (i.layer || LAYER_PREFLIGHTS) === layer).map(async (i) => await i.getCSS(preflightContext))
|
|
);
|
|
const css = preflights2.filter(Boolean).join(nl);
|
|
return [layer, css];
|
|
}
|
|
))
|
|
);
|
|
})();
|
|
await Promise.all([
|
|
...tokenPromises,
|
|
preflightPromise
|
|
]);
|
|
const layers = this.config.sortLayers(
|
|
Array.from(layerSet).sort((a, b) => (this.config.layers[a] ?? 0) - (this.config.layers[b] ?? 0) || a.localeCompare(b))
|
|
);
|
|
const layerCache = {};
|
|
const getLayer = (layer) => {
|
|
if (layerCache[layer])
|
|
return layerCache[layer];
|
|
let css = Array.from(sheet).sort((a, b) => (this.parentOrders.get(a[0]) ?? 0) - (this.parentOrders.get(b[0]) ?? 0) || a[0]?.localeCompare(b[0] || "") || 0).map(([parent, items]) => {
|
|
const size = items.length;
|
|
const sorted = items.filter((i) => (i[4]?.layer || LAYER_DEFAULT) === layer).sort((a, b) => a[0] - b[0] || (a[4]?.sort || 0) - (b[4]?.sort || 0) || a[1]?.localeCompare(b[1] || "") || a[2]?.localeCompare(b[2] || "") || 0).map(([, selector, body, , meta]) => {
|
|
const scopedSelector = selector ? applyScope(selector, scope) : selector;
|
|
return [
|
|
[[scopedSelector ?? "", meta?.sort ?? 0]],
|
|
body,
|
|
!!meta?.noMerge
|
|
];
|
|
});
|
|
if (!sorted.length)
|
|
return void 0;
|
|
const rules = sorted.reverse().map(([selectorSortPair, body, noMerge], idx) => {
|
|
if (!noMerge && this.config.mergeSelectors) {
|
|
for (let i = idx + 1; i < size; i++) {
|
|
const current = sorted[i];
|
|
if (current && !current[2] && (selectorSortPair && current[0] || selectorSortPair == null && current[0] == null) && current[1] === body) {
|
|
if (selectorSortPair && current[0])
|
|
current[0].push(...selectorSortPair);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
const selectors = selectorSortPair ? uniq(
|
|
selectorSortPair.sort((a, b) => a[1] - b[1] || a[0]?.localeCompare(b[0] || "") || 0).map((pair) => pair[0]).filter(Boolean)
|
|
) : [];
|
|
return selectors.length ? `${selectors.join(`,${nl}`)}{${body}}` : body;
|
|
}).filter(Boolean).reverse().join(nl);
|
|
if (!parent)
|
|
return rules;
|
|
const parents = parent.split(" $$ ");
|
|
return `${parents.join("{")}{${nl}${rules}${nl}}${parents.map((_) => "").join("}")}`;
|
|
}).filter(Boolean).join(nl);
|
|
if (preflights) {
|
|
css = [preflightsMap[layer], css].filter(Boolean).join(nl);
|
|
}
|
|
const layerMark = minify ? "" : `/* layer: ${layer} */${nl}`;
|
|
return layerCache[layer] = css ? layerMark + css : "";
|
|
};
|
|
const getLayers = (includes = layers, excludes) => {
|
|
return includes.filter((i) => !excludes?.includes(i)).map((i) => getLayer(i) || "").filter(Boolean).join(nl);
|
|
};
|
|
return {
|
|
get css() {
|
|
return getLayers();
|
|
},
|
|
layers,
|
|
matched,
|
|
getLayers,
|
|
getLayer
|
|
};
|
|
}
|
|
matchVariants(raw, current) {
|
|
const variants = /* @__PURE__ */ new Set();
|
|
const handlers = [];
|
|
let processed = current || raw;
|
|
let applied = false;
|
|
const context = {
|
|
rawSelector: raw,
|
|
theme: this.config.theme,
|
|
generator: this
|
|
};
|
|
while (true) {
|
|
applied = false;
|
|
for (const v of this.config.variants) {
|
|
if (!v.multiPass && variants.has(v))
|
|
continue;
|
|
let handler = v.match(processed, context);
|
|
if (!handler)
|
|
continue;
|
|
if (isString(handler))
|
|
handler = { matcher: handler };
|
|
processed = handler.matcher;
|
|
handlers.unshift(handler);
|
|
variants.add(v);
|
|
applied = true;
|
|
break;
|
|
}
|
|
if (!applied)
|
|
break;
|
|
if (handlers.length > 500)
|
|
throw new Error(`Too many variants applied to "${raw}"`);
|
|
}
|
|
return [raw, processed, handlers, variants];
|
|
}
|
|
applyVariants(parsed, variantHandlers = parsed[4], raw = parsed[1]) {
|
|
const handler = [...variantHandlers].sort((a, b) => (a.order || 0) - (b.order || 0)).reverse().reduce(
|
|
(previous, v) => (input) => {
|
|
const entries = v.body?.(input.entries) || input.entries;
|
|
const parents = Array.isArray(v.parent) ? v.parent : [v.parent, void 0];
|
|
return (v.handle ?? defaultVariantHandler)({
|
|
...input,
|
|
entries,
|
|
selector: v.selector?.(input.selector, entries) || input.selector,
|
|
parent: parents[0] || input.parent,
|
|
parentOrder: parents[1] || input.parentOrder,
|
|
layer: v.layer || input.layer,
|
|
sort: v.sort || input.sort
|
|
}, previous);
|
|
},
|
|
(input) => input
|
|
);
|
|
const variantContextResult = handler({
|
|
prefix: "",
|
|
selector: toEscapedSelector(raw),
|
|
pseudo: "",
|
|
entries: parsed[2]
|
|
});
|
|
const { parent, parentOrder } = variantContextResult;
|
|
if (parent != null && parentOrder != null)
|
|
this.parentOrders.set(parent, parentOrder);
|
|
const obj = {
|
|
selector: movePseudoElementsEnd([
|
|
variantContextResult.prefix,
|
|
variantContextResult.selector,
|
|
variantContextResult.pseudo
|
|
].join("")),
|
|
entries: variantContextResult.entries,
|
|
parent,
|
|
layer: variantContextResult.layer,
|
|
sort: variantContextResult.sort
|
|
};
|
|
for (const p of this.config.postprocess)
|
|
p(obj);
|
|
return obj;
|
|
}
|
|
constructCustomCSS(context, body, overrideSelector) {
|
|
const normalizedBody = normalizeCSSEntries(body);
|
|
if (isString(normalizedBody))
|
|
return normalizedBody;
|
|
const { selector, entries, parent } = this.applyVariants([0, overrideSelector || context.rawSelector, normalizedBody, void 0, context.variantHandlers]);
|
|
const cssBody = `${selector}{${entriesToCss(entries)}}`;
|
|
if (parent)
|
|
return `${parent}{${cssBody}}`;
|
|
return cssBody;
|
|
}
|
|
async parseUtil(input, context, internal = false) {
|
|
const [raw, processed, variantHandlers] = isString(input) ? this.matchVariants(input) : input;
|
|
const recordRule = this.config.details ? (r) => {
|
|
context.rules = context.rules ?? [];
|
|
context.rules.push(r);
|
|
} : noop;
|
|
const staticMatch = this.config.rulesStaticMap[processed];
|
|
if (staticMatch) {
|
|
if (staticMatch[1] && (internal || !staticMatch[2]?.internal)) {
|
|
recordRule(staticMatch[3]);
|
|
const index = staticMatch[0];
|
|
const entry = normalizeCSSEntries(staticMatch[1]);
|
|
const meta = staticMatch[2];
|
|
if (isString(entry))
|
|
return [[index, entry, meta]];
|
|
else
|
|
return [[index, raw, entry, meta, variantHandlers]];
|
|
}
|
|
}
|
|
context.variantHandlers = variantHandlers;
|
|
const { rulesDynamic, rulesSize } = this.config;
|
|
for (let i = rulesSize - 1; i >= 0; i--) {
|
|
const rule = rulesDynamic[i];
|
|
if (!rule)
|
|
continue;
|
|
if (rule[2]?.internal && !internal)
|
|
continue;
|
|
const [matcher, handler, meta] = rule;
|
|
if (meta?.prefix && !processed.startsWith(meta.prefix))
|
|
continue;
|
|
const unprefixed = meta?.prefix ? processed.slice(meta.prefix.length) : processed;
|
|
const match = unprefixed.match(matcher);
|
|
if (!match)
|
|
continue;
|
|
const result = await handler(match, context);
|
|
if (!result)
|
|
continue;
|
|
recordRule(rule);
|
|
const entries = normalizeCSSValues(result).filter((i2) => i2.length);
|
|
if (entries.length) {
|
|
return entries.map((e2) => {
|
|
if (isString(e2))
|
|
return [i, e2, meta];
|
|
else
|
|
return [i, raw, e2, meta, variantHandlers];
|
|
});
|
|
}
|
|
}
|
|
}
|
|
stringifyUtil(parsed, context) {
|
|
if (!parsed)
|
|
return;
|
|
if (isRawUtil(parsed))
|
|
return [parsed[0], void 0, parsed[1], void 0, parsed[2], this.config.details ? context : void 0];
|
|
const { selector, entries, parent, layer: variantLayer, sort: variantSort } = this.applyVariants(parsed);
|
|
const body = entriesToCss(entries);
|
|
if (!body)
|
|
return;
|
|
const { layer: metaLayer, sort: metaSort, ...meta } = parsed[3] ?? {};
|
|
const ruleMeta = {
|
|
...meta,
|
|
layer: variantLayer ?? metaLayer,
|
|
sort: variantSort ?? metaSort
|
|
};
|
|
return [parsed[0], selector, body, parent, ruleMeta, this.config.details ? context : void 0];
|
|
}
|
|
expandShortcut(input, context, depth = 5) {
|
|
if (depth === 0)
|
|
return;
|
|
const recordShortcut = this.config.details ? (s) => {
|
|
context.shortcuts = context.shortcuts ?? [];
|
|
context.shortcuts.push(s);
|
|
} : noop;
|
|
let meta;
|
|
let result;
|
|
for (const s of this.config.shortcuts) {
|
|
const unprefixed = s[2]?.prefix ? input.slice(s[2].prefix.length) : input;
|
|
if (isStaticShortcut(s)) {
|
|
if (s[0] === unprefixed) {
|
|
meta = meta || s[2];
|
|
result = s[1];
|
|
recordShortcut(s);
|
|
break;
|
|
}
|
|
} else {
|
|
const match = unprefixed.match(s[0]);
|
|
if (match)
|
|
result = s[1](match, context);
|
|
if (result) {
|
|
meta = meta || s[2];
|
|
recordShortcut(s);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (isString(result))
|
|
result = expandVariantGroup(result).split(/\s+/g);
|
|
if (!result) {
|
|
const [raw, inputWithoutVariant] = isString(input) ? this.matchVariants(input) : input;
|
|
if (raw !== inputWithoutVariant) {
|
|
const expanded = this.expandShortcut(inputWithoutVariant, context, depth - 1);
|
|
if (expanded)
|
|
result = expanded[0].map((item) => isString(item) ? raw.replace(inputWithoutVariant, item) : item);
|
|
}
|
|
}
|
|
if (!result)
|
|
return;
|
|
return [
|
|
result.flatMap((r) => (isString(r) ? this.expandShortcut(r, context, depth - 1)?.[0] : void 0) || [r]).filter(Boolean),
|
|
meta
|
|
];
|
|
}
|
|
async stringifyShortcuts(parent, context, expanded, meta = { layer: this.config.shortcutsLayer }) {
|
|
const selectorMap = new TwoKeyMap();
|
|
const parsed = (await Promise.all(uniq(expanded).map(async (i) => {
|
|
const result = isString(i) ? await this.parseUtil(i, context, true) : [[Infinity, "{inline}", normalizeCSSEntries(i), void 0, []]];
|
|
if (!result)
|
|
warnOnce(`unmatched utility "${i}" in shortcut "${parent[1]}"`);
|
|
return result || [];
|
|
}))).flat(1).filter(Boolean).sort((a, b) => a[0] - b[0]);
|
|
const [raw, , parentVariants] = parent;
|
|
const rawStringfieldUtil = [];
|
|
for (const item of parsed) {
|
|
if (isRawUtil(item)) {
|
|
rawStringfieldUtil.push([item[0], void 0, item[1], void 0, item[2], context]);
|
|
continue;
|
|
}
|
|
const { selector, entries, parent: parent2, sort } = this.applyVariants(item, [...item[4], ...parentVariants], raw);
|
|
const mapItem = selectorMap.getFallback(selector, parent2, [[], item[0]]);
|
|
mapItem[0].push([entries, !!item[3]?.noMerge, sort ?? 0]);
|
|
}
|
|
return rawStringfieldUtil.concat(selectorMap.map(([e2, index], selector, joinedParents) => {
|
|
const stringify = (flatten, noMerge, entrySortPair) => {
|
|
const maxSort = Math.max(...entrySortPair.map((e3) => e3[1]));
|
|
const entriesList = entrySortPair.map((e3) => e3[0]);
|
|
return (flatten ? [entriesList.flat(1)] : entriesList).map((entries) => {
|
|
const body = entriesToCss(entries);
|
|
if (body)
|
|
return [index, selector, body, joinedParents, { ...meta, noMerge, sort: maxSort }, context];
|
|
return void 0;
|
|
});
|
|
};
|
|
const merges = [
|
|
[e2.filter(([, noMerge]) => noMerge).map(([entries, , sort]) => [entries, sort]), true],
|
|
[e2.filter(([, noMerge]) => !noMerge).map(([entries, , sort]) => [entries, sort]), false]
|
|
];
|
|
return merges.map(([e3, noMerge]) => [
|
|
...stringify(false, noMerge, e3.filter(([entries]) => entries.some((entry) => entry[0] === CONTROL_SHORTCUT_NO_MERGE))),
|
|
...stringify(true, noMerge, e3.filter(([entries]) => entries.every((entry) => entry[0] !== CONTROL_SHORTCUT_NO_MERGE)))
|
|
]);
|
|
}).flat(2).filter(Boolean));
|
|
}
|
|
isBlocked(raw) {
|
|
return !raw || this.config.blocklist.some((e2) => isString(e2) ? e2 === raw : e2.test(raw));
|
|
}
|
|
}
|
|
function createGenerator(config, defaults) {
|
|
return new UnoGenerator(config, defaults);
|
|
}
|
|
const regexScopePlaceholder = / \$\$ /;
|
|
const hasScopePlaceholder = (css) => css.match(regexScopePlaceholder);
|
|
function applyScope(css, scope) {
|
|
if (hasScopePlaceholder(css))
|
|
return css.replace(regexScopePlaceholder, scope ? ` ${scope} ` : " ");
|
|
else
|
|
return scope ? `${scope} ${css}` : css;
|
|
}
|
|
function movePseudoElementsEnd(selector) {
|
|
const pseudoElements = selector.match(/::[\w-]+(\([\w-]+\))?/g);
|
|
if (pseudoElements) {
|
|
pseudoElements.forEach((e2) => selector = selector.replace(e2, ""));
|
|
selector += pseudoElements.join("");
|
|
}
|
|
return selector;
|
|
}
|
|
const attributifyRe = /^\[(.+?)(~?=)"(.*)"\]$/;
|
|
function toEscapedSelector(raw) {
|
|
if (attributifyRe.test(raw))
|
|
return raw.replace(attributifyRe, (_, n, s, i) => `[${e(n)}${s}"${e(i)}"]`);
|
|
return `.${e(raw)}`;
|
|
}
|
|
function defaultVariantHandler(input, next) {
|
|
return next(input);
|
|
}
|
|
|
|
export { BetterMap, CONTROL_SHORTCUT_NO_MERGE, TwoKeyMap, UnoGenerator, attributifyRE, clearIdenticalEntries, clone, createGenerator, createValueHandler, cssIdRE, e, entriesToCss, escapeRegExp, escapeSelector, expandVariantGroup, extractorSplit, extractorSvelte, hasScopePlaceholder, isAttributifySelector, isObject, isRawUtil, isStaticRule, isStaticShortcut, isString, isValidSelector, mergeDeep, mergeSet, movePseudoElementsEnd, noop, normalizeCSSEntries, normalizeCSSValues, normalizeVariant, notNull, regexClassGroup, regexScopePlaceholder, toArray, toEscapedSelector, uniq, validateFilterRE, warnOnce, withLayer };
|