@projectwallace/css-analyzer
Version:
The best CSS analyzer out there. Check design tokens, complexity, specificity, performance and more.
1,222 lines (1,221 loc) • 32.4 kB
JavaScript
import ei from "css-tree/parser";
import v from "css-tree/walker";
import { calculateForAST as ti } from "@bramus/specificity/core";
function He(r, t) {
return t >= 65 && t <= 90 && (t = t | 32), r === t;
}
function S(r, t) {
if (r === t) return !0;
let s = r.length;
if (s !== t.length) return !1;
for (let e = 0; e < s; e++)
if (He(r.charCodeAt(e), t.charCodeAt(e)) === !1)
return !1;
return !0;
}
function O(r, t) {
if (r === t) return !0;
let s = t.length, e = s - r.length;
if (e < 0)
return !1;
for (let n = s - 1; n >= e; n--)
if (He(r.charCodeAt(n - e), t.charCodeAt(n)) === !1)
return !1;
return !0;
}
function We(r, t) {
if (r === t) return !0;
let s = r.length;
if (t.length < s) return !1;
for (let e = 0; e < s; e++)
if (He(r.charCodeAt(e), t.charCodeAt(e)) === !1)
return !1;
return !0;
}
const Te = "Atrule", ii = "MediaQuery", Me = "Rule", Ke = "Selector", Nt = "TypeSelector", G = "PseudoClassSelector", jt = "AttributeSelector", Bt = "PseudoElementSelector", Ve = "Declaration", ri = "Value", R = "Identifier", si = "Nth", li = "Combinator", Yt = "Number", Ne = "Dimension", W = "Operator", ni = "Hash", ai = "Url", je = "Function";
function Ut(r, t, s) {
let e = r.value.children.first;
return S(t, r.property) && e.type === R && S(s, e.name);
}
function oi(r) {
let t = !1;
return v(r, function(s) {
if (s.type === Ve && (Ut(s, "-webkit-appearance", "none") || Ut(s, "-moz-appearance", "meterbar")))
return t = !0, this.break;
}), t;
}
function ui(r) {
let t = !1;
return v(r, function(s) {
let e = s.name, n = s.value;
if (s.type === ii && s.mediaType !== null) {
if (We("\\0", s.mediaType) || O("\\9 ", s.mediaType))
return t = !0, this.break;
} else if (s.type === "Feature" && s.kind === "media") {
if (n && n.unit && n.unit === "\\0")
return t = !0, this.break;
if (S("-moz-images-in-menus", e) || S("min--moz-device-pixel-ratio", e) || S("-ms-high-contrast", e))
return t = !0, this.break;
if (S("min-resolution", e) && n && S(".001", n.value) && S("dpcm", n.unit))
return t = !0, this.break;
if (S("-webkit-min-device-pixel-ratio", e) && n && n.value && (S("0", n.value) || S("10000", n.value)))
return t = !0, this.break;
}
}), t;
}
const Vt = 45;
function E(r) {
return r.charCodeAt(0) === Vt && r.charCodeAt(1) !== Vt && r.indexOf("-", 2) !== -1;
}
class A {
/** @param {string[]} items */
constructor(t) {
this.set = new Set(t);
}
/** @param {string} item */
has(t) {
return this.set.has(t.toLowerCase());
}
}
function Gt(r, t) {
let s = [];
return v(r, {
visit: Ke,
enter: function(e) {
s.push(t(e));
}
}), s;
}
const Qt = new A([
"nth-child",
"where",
"not",
"is",
"has",
"nth-last-child",
"matches",
"-webkit-any",
"-moz-any"
]);
function Zt(r) {
let t = !1;
return v(r, function(s) {
if (s.type === jt) {
let e = s.name.name;
if (S("role", e) || We("aria-", e))
return t = !0, this.break;
} else if (s.type === G && Qt.has(s.name)) {
let e = Gt(s, Zt);
for (let n of e)
if (n === !0) {
t = !0;
break;
}
return this.skip;
}
}), t;
}
function ci(r) {
let t = !1;
return v(r, function(s) {
let e = s.type;
if ((e === Bt || e === Nt || e === G) && E(s.name))
return t = !0, this.break;
}), t;
}
function fi(r) {
let t = [];
return v(r, function(s) {
s.type === G && t.push(s.name);
}), t.length === 0 ? !1 : t;
}
function Jt(r) {
let t = 0;
return v(r, function(s) {
let e = s.type;
if (!(e === Ke || e === si)) {
if (t++, (e === Bt || e === Nt || e === G) && E(s.name) && t++, e === jt)
return s.value && t++, this.skip;
if (e === G && Qt.has(s.name)) {
let n = Gt(s, Jt);
if (n.length === 0) return;
for (let a of n)
t += a;
return this.skip;
}
}
}), t;
}
function pi(r, t) {
v(r, function(s, e) {
if (s.type === li) {
let n = s.loc, a = s.name;
if (n === null) {
let y = e.prev.data.loc.end, b = {
offset: y.offset,
line: y.line,
column: y.column
};
t({
name: a,
loc: {
start: b,
end: {
offset: b.offset + 1,
line: b.line,
column: b.column + 1
}
}
});
} else
t({
name: a,
loc: n
});
}
});
}
const hi = new A([
// CSS Named Colors
// Spec: https://drafts.csswg.org/css-color/#named-colors
// Heuristic: popular names first for quick finding in set.has()
// See: https://docs.google.com/spreadsheets/d/1OU8ahxC5oYU8VRryQs9BzHToaXcOntVlh6KUHjm15G4/edit#gid=2096495459
"white",
"black",
"red",
"gray",
"silver",
"grey",
"green",
"orange",
"blue",
"dimgray",
"whitesmoke",
"lightgray",
"lightgrey",
"yellow",
"gold",
"pink",
"gainsboro",
"magenta",
"purple",
"darkgray",
"navy",
"darkred",
"teal",
"maroon",
"darkgrey",
"tomato",
"darkorange",
"brown",
"crimson",
"lightyellow",
"slategray",
"salmon",
"lightgreen",
"lightblue",
"orangered",
"aliceblue",
"dodgerblue",
"lime",
"darkblue",
"darkgoldenrod",
"skyblue",
"royalblue",
"darkgreen",
"ivory",
"olive",
"aqua",
"turquoise",
"cyan",
"khaki",
"beige",
"snow",
"ghostwhite",
"limegreen",
"coral",
"dimgrey",
"hotpink",
"midnightblue",
"firebrick",
"indigo",
"wheat",
"mediumblue",
"lightpink",
"plum",
"azure",
"violet",
"lavender",
"deepskyblue",
"darkslategrey",
"goldenrod",
"cornflowerblue",
"lightskyblue",
"indianred",
"yellowgreen",
"saddlebrown",
"palegreen",
"bisque",
"tan",
"antiquewhite",
"steelblue",
"forestgreen",
"fuchsia",
"mediumaquamarine",
"seagreen",
"sienna",
"deeppink",
"mediumseagreen",
"peru",
"greenyellow",
"lightgoldenrodyellow",
"orchid",
"cadetblue",
"navajowhite",
"lightsteelblue",
"slategrey",
"linen",
"lightseagreen",
"darkcyan",
"lightcoral",
"aquamarine",
"blueviolet",
"cornsilk",
"lightsalmon",
"chocolate",
"lightslategray",
"floralwhite",
"darkturquoise",
"darkslategray",
"rebeccapurple",
"burlywood",
"chartreuse",
"lightcyan",
"lemonchiffon",
"palevioletred",
"darkslateblue",
"mediumpurple",
"lawngreen",
"slateblue",
"darkseagreen",
"blanchedalmond",
"mistyrose",
"darkolivegreen",
"seashell",
"olivedrab",
"peachpuff",
"darkviolet",
"powderblue",
"darkmagenta",
"lightslategrey",
"honeydew",
"palegoldenrod",
"darkkhaki",
"oldlace",
"mintcream",
"sandybrown",
"mediumturquoise",
"papayawhip",
"paleturquoise",
"mediumvioletred",
"thistle",
"springgreen",
"moccasin",
"rosybrown",
"lavenderblush",
"mediumslateblue",
"darkorchid",
"mediumorchid",
"darksalmon",
"mediumspringgreen"
]), mi = new A([
// CSS System Colors
// Spec: https://drafts.csswg.org/css-color/#css-system-colors
"accentcolor",
"accentcolortext",
"activetext",
"buttonborder",
"buttonface",
"buttontext",
"canvas",
"canvastext",
"field",
"fieldtext",
"graytext",
"highlight",
"highlighttext",
"linktext",
"mark",
"marktext",
"selecteditem",
"selecteditemtext",
"visitedtext"
]), gi = new A([
"rgba",
"rgb",
"hsla",
"hsl",
"oklch",
"color",
"hwb",
"lch",
"lab",
"oklab"
]), di = new A([
"transparent",
"currentcolor"
]), ie = new A([
"auto",
"none",
// for `text-shadow`, `box-shadow` and `background`
"inherit",
"initial",
"unset",
"revert",
"revert-layer"
]);
function te(r) {
let t = r.children, s = t.size;
if (!t || s > 1 || s === 0) return !1;
let e = t.first;
return e.type === R && ie.has(e.name);
}
function Ht(r) {
return parseFloat(r) === 0;
}
function yi(r) {
for (let t of r.children.toArray())
if (!(t.type === Yt && Ht(t.value)) && !(t.type === Ne && Ht(t.value)))
return !1;
return !0;
}
const wi = new A([
"caption",
"icon",
"menu",
"message-box",
"small-caption",
"status-bar"
]), ki = new A([
/* <absolute-size> values */
"xx-small",
"x-small",
"small",
"medium",
"large",
"x-large",
"xx-large",
"xxx-large",
/* <relative-size> values */
"smaller",
"larger"
]), bi = 44, Wt = 47;
function Ie(r) {
let t = r.children.first;
return t === null ? !1 : t.type === R && wi.has(t.name);
}
function xi(r, t, s) {
var b;
let e = [,], n, a;
if (r.children.first.type === "Function" && r.children.first.name.toLowerCase() === "var")
return null;
r.children.forEach(function(w, _) {
let k = _.prev ? _.prev.data : void 0, P = _.next ? _.next.data : void 0;
if (w.type === R && ie.has(w.name) && s({
type: "keyword",
value: w.name
}), P && P.type === W && P.value.charCodeAt(0) === Wt) {
n = t(w);
return;
}
if (k && k.type === W && k.value.charCodeAt(0) === Wt) {
a = t(w);
return;
}
if (P && P.type === W && P.value.charCodeAt(0) === bi && !e[0]) {
e[0] = w, !n && k && (n = t(k));
return;
}
if (w.type !== Yt) {
if (_.next === null) {
e[1] = w, !n && !e[0] && k && (n = t(k));
return;
}
if (w.type === R) {
let D = w.name;
if (ki.has(D)) {
n = D;
return;
}
}
}
});
let y = e[0] || e[1] ? t({
loc: {
start: {
offset: (e[0] || e[1]).loc.start.offset
},
end: {
// Either the node we detected as the last node, or the end of the whole value
// It's never 0 because the first node is always a font-size or font-style
offset: ((b = e[1]) == null ? void 0 : b.loc.end.offset) || r.loc.end.offset
}
}
}) : null;
return {
font_size: n,
line_height: a,
font_family: y
};
}
const Ci = new A([
"linear",
"ease",
"ease-in",
"ease-out",
"ease-in-out",
"step-start",
"step-end"
]), zi = new A([
"cubic-bezier",
"steps"
]);
function Si(r, t) {
let s = !1;
for (let e of r) {
let n = e.type, a = e.name;
n === W ? s = !1 : n === Ne && s === !1 ? (s = !0, t({
type: "duration",
value: e
})) : n === R ? Ci.has(a) ? t({
type: "fn",
value: e
}) : ie.has(a) && t({
type: "keyword",
value: e
}) : n === je && zi.has(a) && t({
type: "fn",
value: e
});
}
}
function Xt(r) {
let t = r.children;
if (!t)
return !1;
for (let s of t) {
let { type: e, name: n } = s;
if (e === R && E(n) || e === je && (E(n) || Xt(s)))
return !0;
}
return !1;
}
class o {
/** @param {boolean} useLocations */
constructor(t = !1) {
this._items = /* @__PURE__ */ new Map(), this._total = 0, t && (this._nodes = []), this._useLocations = t;
}
/**
* @param {string | number} item
* @param {import('css-tree').CssLocation} node_location
*/
p(t, s) {
let e = this._total;
if (this._useLocations) {
let n = s.start, a = n.offset, y = e * 4;
this._nodes[y] = n.line, this._nodes[y + 1] = n.column, this._nodes[y + 2] = a, this._nodes[y + 3] = s.end.offset - a;
}
if (this._items.has(t)) {
this._items.get(t).push(e), this._total++;
return;
}
this._items.set(t, [e]), this._total++;
}
size() {
return this._total;
}
/**
* @typedef CssLocation
* @property {number} line
* @property {number} column
* @property {number} offset
* @property {number} length
*
* @returns {{
* total: number;
* totalUnique: number;
* uniquenessRatio: number;
* unique: Record<string, number>;
* } & ({
* uniqueWithLocations: Record<string, CssLocation[]>
* } | {
* uniqueWithLocations?: undefined
* })}
*/
c() {
let t = /* @__PURE__ */ new Map(), s = {}, e = this._useLocations, n = this._items, a = this._nodes, y = n.size;
n.forEach((_, k) => {
if (e) {
let P = _.map(function(D) {
let T = D * 4;
return {
line: a[T],
column: a[T + 1],
offset: a[T + 2],
length: a[T + 3]
};
});
t.set(k, P);
} else
s[k] = _.length;
});
let b = this._total, w = {
total: b,
totalUnique: y,
unique: s,
uniquenessRatio: b === 0 ? 0 : y / b
};
return e && (w.uniqueWithLocations = Object.fromEntries(t)), w;
}
}
class Ue {
/** @param {boolean} useLocations */
constructor(t) {
this._list = new o(t), this._contexts = /* @__PURE__ */ new Map(), this._useLocations = t;
}
/**
* Add an item to this _list's context
* @param {string} item Item to push
* @param {string} context Context to push Item to
* @param {import('css-tree').CssLocation} node_location
*/
push(t, s, e) {
this._list.p(t, e), this._contexts.has(s) || this._contexts.set(s, new o(this._useLocations)), this._contexts.get(s).p(t, e);
}
count() {
let t = /* @__PURE__ */ new Map();
for (let [s, e] of this._contexts.entries())
t.set(s, e.c());
return Object.assign(this._list.c(), {
itemsPerContext: Object.fromEntries(t)
});
}
}
function _i(r) {
let t = /* @__PURE__ */ new Map(), s = -1, e = 0, n = 0, a = r.length;
for (let y = 0; y < a; y++) {
let b = r[y], w = (t.get(b) || 0) + 1;
t.set(b, w), w > s && (s = w, e = 0, n = 0), w >= s && (e++, n += b);
}
return n / e;
}
class C {
constructor() {
this._items = [], this._sum = 0;
}
/**
* Add a new Integer at the end of this AggregateCollection
* @param {number} item - The item to add
*/
push(t) {
this._items.push(t), this._sum += t;
}
size() {
return this._items.length;
}
aggregate() {
let t = this._items.length;
if (t === 0)
return {
min: 0,
max: 0,
mean: 0,
mode: 0,
range: 0,
sum: 0
};
let s = this._items.slice().sort((b, w) => b - w), e = s[0], n = s[t - 1], a = _i(s), y = this._sum;
return {
min: e,
max: n,
mean: y / t,
mode: a,
range: n - e,
sum: y
};
}
/**
* @returns {number[]} All _items in this collection
*/
toArray() {
return this._items;
}
}
function qi(r) {
if (Be(r) || E(r)) return !1;
let t = r.charCodeAt(0);
return t === 47 || t === 42 || t === 95 || t === 43 || t === 38 || t === 36 || t === 35;
}
function Be(r) {
return r.length < 3 ? !1 : r.charCodeAt(0) === 45 && r.charCodeAt(1) === 45;
}
function m(r, t) {
return Be(t) ? !1 : O(r, t);
}
function vi(r) {
return E(r) ? r.slice(r.indexOf("-", 2) + 1) : r;
}
function Ai(r) {
let t = 5, s = r.indexOf(";"), e = r.indexOf(",");
return s === -1 || e !== -1 && e < s ? r.substring(t, e) : r.substring(t, s);
}
function Pi(r) {
let t = r.children;
if (t) {
let s = t.last;
return s && s.type === R && O("\\9", s.name);
}
return !1;
}
let Li = new A([
"border-radius",
"border-top-left-radius",
"border-top-right-radius",
"border-bottom-right-radius",
"border-bottom-left-radius",
"border-start-start-radius",
"border-start-end-radius",
"border-end-end-radius",
"border-end-start-radius"
]);
function z(r, t) {
return t === 0 ? 0 : r / t;
}
let Oi = {
useLocations: !1
};
function Ei(r, t = {}) {
let e = Object.assign({}, Oi, t).useLocations === !0, n = Date.now();
function a(i) {
return y(i).trim();
}
function y(i) {
let Y = i.loc;
return r.substring(Y.start.offset, Y.end.offset);
}
let b = 0, w = 0, _ = 0, k = {
total: 0,
/** @type {Map<string, { size: number, count: number } & ({ uniqueWithLocations?: undefined } | ({ uniqueWithLocations: { offset: number, line: number, column: number, length: number }[] })) }>} */
unique: /* @__PURE__ */ new Map()
}, P = Date.now(), D = ei(r, {
parseCustomProperty: !0,
// To find font-families, colors, etc.
positions: !0,
// So we can use stringifyNode()
/** @param {string} comment */
onComment: function(i) {
b++, w += i.length;
}
}), T = Date.now(), $t = D.loc.end.line - D.loc.start.line + 1, Ye = new o(e), re = new C(), se = [], Ge = new o(e), le = new o(e), Qe = new o(e), Ze = new o(e), Je = new o(e), Xe = new o(e), $e = new o(e), ne = new o(e), et = new o(e), ae = new o(e), oe = new o(e), tt = new o(e), Q = new o(e), it = new o(e), ue = new C(), rt = new o(e), ce = 0, fe = 0, pe = new C(), he = new C(), me = new C(), st = new o(e), lt = new o(e), nt = new o(e), ge = new C(), at = new o(e), de = new o(e), ot = /* @__PURE__ */ new Set(), ye = new o(e), M, I, ut = new C(), ct = new C(), ft = new C(), pt = new o(e), Z = new C(), ht = new o(e), mt = [], we = new o(e), ke = new o(e), gt = new o(e), dt = new o(e), be = new C(), yt = new o(e), wt = /* @__PURE__ */ new Set(), K = 0, kt = new C(), J = 0, xe = 0, Ce = new o(e), ze = new C(), bt = new o(e), N = new o(e), Se = new o(e), _e = new o(e), X = new o(e), j = new C(), qe = new C(), xt = new o(e), ve = new o(e), Ct = new o(e), zt = new o(e), St = new o(e), Ae = new o(e), Pe = new o(e), Le = new o(e), $ = new o(e), ee = new o(e), U = new Ue(e), V = new o(e), Oe = new Ue(e), _t = new o(e), B = new o(e), qt = new Ue(e), vt = new o(e), L = 0;
v(D, {
enter(i) {
var Y, Mt;
switch (i.type) {
case Te: {
Ye.p(i.name, i.loc), ue.push(L), rt.p(L, i.loc);
let p = i.name;
if (p === "font-face") {
let g = {};
e && Ge.p(i.loc.start.offset, i.loc), i.block.children.forEach((c) => {
c.type === Ve && (g[c.property] = a(c.value));
}), se.push(g), re.push(1);
break;
}
let l = 1;
if (i.prelude !== null) {
let g = i.prelude, c = g && a(i.prelude), f = g.loc;
if (p === "media")
Ze.p(c, f), ui(g) && (Je.p(c, f), l++);
else if (p === "supports")
ne.p(c, f), oi(g) && (et.p(c, f), l++);
else if (O("keyframes", p)) {
let u = "@" + p + " " + c;
E(p) && (oe.p(u, f), l++), ae.p(u, f);
} else if (p === "import")
v(i, function(u) {
if (u.type === "Condition" && u.kind === "supports") {
let h = a(u);
return ne.p(h, u.loc), this.break;
}
}), Qe.p(c, f);
else if (p === "charset")
$e.p(c, f);
else if (p === "container") {
if (tt.p(c, f), ((Y = g.children.first) == null ? void 0 : Y.type) === "Identifier") {
let u = g.children.first.name;
Q.p(u, f);
}
} else p === "property" && it.p(c, f);
} else
p === "layer" && (le.p("<anonymous>", i.loc), l++);
re.push(l);
break;
}
case "Layer": {
i.name !== null && le.p(i.name, i.loc);
break;
}
case "Feature": {
Xe.p(i.name, i.loc);
break;
}
case Me: {
let p = i.prelude, l = i.block, g = p.children, c = l.children, f = g ? g.size : 0, u = c ? c.size : 0;
pe.push(f + u), st.p(f + u, i.loc), he.push(f), lt.p(f, p.loc), me.push(u), nt.p(u, l.loc), ge.push(L), at.p(L, i.loc), ce++, u === 0 && fe++;
break;
}
case Ke: {
let p = a(i);
if (this.atrule && O("keyframes", this.atrule.name))
return de.p(p, i.loc), this.skip;
Zt(i) && ke.p(p, i.loc);
let l = fi(i);
if (l !== !1)
for (let x of l)
gt.p(x, i.loc);
let g = Jt(i);
ci(i) && ye.p(p, i.loc), ot.add(p), Z.push(g), ht.p(g, i.loc), be.push(L - 1), yt.p(L - 1, i.loc);
let c = ti(i).toArray(), [f, u, h] = c;
return pt.p(c.toString(), i.loc), ut.push(f), ct.push(u), ft.push(h), M === void 0 && (M = c), I === void 0 && (I = c), I !== void 0 && Kt(I, c) < 0 && (I = c), M !== void 0 && Kt(M, c) > 0 && (M = c), mt.push(c), f > 0 && we.p(p, i.loc), pi(i, function(q) {
dt.p(q.name, q.loc);
}), this.skip;
}
case Ne: {
if (!this.declaration)
break;
let p = i.unit;
return O("\\9", p) ? Oe.push(p.substring(0, p.length - 2), this.declaration.property, i.loc) : Oe.push(p, this.declaration.property, i.loc), this.skip;
}
case ai: {
if (We("data:", i.value)) {
let p = i.value, l = p.length, g = Ai(p);
k.total++, _ += l;
let c = {
/** @type {number} */
line: i.loc.start.line,
/** @type {number} */
column: i.loc.start.column,
/** @type {number} */
offset: i.loc.start.offset,
/** @type {number} */
length: i.loc.end.offset - i.loc.start.offset
};
if (k.unique.has(g)) {
let f = k.unique.get(g);
f.count++, f.size += l, k.unique.set(g, f), e && f.uniqueWithLocations.push(c);
} else {
let f = {
count: 1,
size: l
};
e && (f.uniqueWithLocations = [c]), k.unique.set(g, f);
}
}
break;
}
case ri: {
if (te(i)) {
qe.push(1), B.p(a(i), i.loc);
break;
}
let p = this.declaration, { property: l, important: g } = p, c = 1;
Xt(i) && (xt.p(a(i), i.loc), c++), typeof g == "string" && (ve.p(y(i) + "!" + g, i.loc), c++), Pi(i) && (ve.p(a(i), i.loc), c++);
let f = i.children, u = i.loc;
if (qe.push(c), m("margin", l) || m("margin-block", l) || m("margin-inline", l) || m("margin-top", l) || m("margin-right", l) || m("margin-bottom", l) || m("margin-left", l) || m("padding", l) || m("padding-block", l) || m("padding-inline", l) || m("padding-top", l) || m("padding-right", l) || m("padding-bottom", l) || m("padding-left", l))
yi(i) && vt.p(l, p.loc);
else {
if (m("z-index", l))
return Ct.p(a(i), u), this.skip;
if (m("font", l)) {
if (Ie(i)) return;
let h = xi(i, a, function(It) {
It.type === "keyword" && B.p(It.value, u);
});
if (!h)
return this.skip;
let { font_size: x, line_height: q, font_family: F } = h;
F && Ae.p(F, u), x && Pe.p(x, u), q && Le.p(q, u);
break;
} else if (m("font-size", l)) {
Ie(i) || Pe.p(a(i), u);
break;
} else if (m("font-family", l)) {
Ie(i) || Ae.p(a(i), u);
break;
} else if (m("line-height", l))
Le.p(a(i), u);
else if (m("transition", l) || m("animation", l)) {
Si(f, function(h) {
h.type === "fn" ? $.p(a(h.value), u) : h.type === "duration" ? ee.p(a(h.value), u) : h.type === "keyword" && B.p(a(h.value), u);
});
break;
} else if (m("animation-duration", l) || m("transition-duration", l)) {
f && f.size > 1 ? f.forEach((h) => {
h.type !== W && ee.p(a(h), u);
}) : ee.p(a(i), u);
break;
} else if (m("transition-timing-function", l) || m("animation-timing-function", l)) {
f && f.size > 1 ? f.forEach((h) => {
h.type !== W && $.p(a(h), u);
}) : $.p(a(i), u);
break;
} else if (m("container-name", l))
Q.p(a(i), u);
else if (m("container", l))
((Mt = f.first) == null ? void 0 : Mt.type) === "Identifier" && Q.p(f.first.name, u);
else if (Li.has(vi(l))) {
te(i) || qt.push(a(i), l, u);
break;
} else m("text-shadow", l) ? te(i) || zt.p(a(i), u) : m("box-shadow", l) && (te(i) || St.p(a(i), u));
}
v(i, function(h) {
let x = h.name;
switch (h.type) {
case ni: {
let q = h.value.length;
return O("\\9", h.value) && (q = q - 2), U.push("#" + h.value, l, u), V.p("hex" + q, u), this.skip;
}
case R: {
ie.has(x) && B.p(x, u);
let q = x.length;
if (q > 20 || q < 3)
return this.skip;
if (di.has(x)) {
let F = a(h);
U.push(F, l, u), V.p(x.toLowerCase(), u);
return;
}
if (hi.has(x)) {
let F = a(h);
U.push(F, l, u), V.p("named", u);
return;
}
if (mi.has(x)) {
let F = a(h);
U.push(F, l, u), V.p("system", u);
return;
}
return this.skip;
}
case je: {
if (S("var", x))
return this.skip;
if (gi.has(x)) {
U.push(a(h), l, h.loc), V.p(x.toLowerCase(), h.loc);
return;
}
if (O("gradient", x)) {
_t.p(a(h), h.loc);
return;
}
}
}
});
break;
}
case Ve: {
if (this.atrulePrelude !== null)
return this.skip;
K++;
let p = 1;
wt.add(a(i)), ze.push(L - 1), bt.p(L - 1, i.loc), i.important === !0 && (J++, p++, this.atrule && O("keyframes", this.atrule.name) && (xe++, p++)), kt.push(p);
let { property: l, loc: { start: g } } = i, c = {
start: {
line: g.line,
column: g.column,
offset: g.offset
},
end: {
offset: g.offset + l.length
}
};
N.p(l, c), E(l) ? (_e.p(l, c), j.push(2)) : qi(l) ? (Se.p(l, c), j.push(2)) : Be(l) ? (X.p(l, c), j.push(i.important ? 3 : 2), i.important === !0 && Ce.p(l, c)) : j.push(1);
break;
}
}
(i.type === Me || i.type === Te) && L++;
},
leave(i) {
(i.type === Me || i.type === Te) && L--;
}
});
let At = wt.size, H = Z.size(), Re = ut.aggregate(), De = ct.aggregate(), Fe = ft.aggregate(), Pt = ot.size, d = Object.assign, Lt = r.length, Ee = se.length, Ot = re.aggregate(), Rt = Z.aggregate(), Dt = kt.aggregate(), Ft = j.aggregate(), Et = qe.aggregate(), Tt = Ye.c();
return {
stylesheet: {
sourceLinesOfCode: Tt.total + H + K + de.size(),
linesOfCode: $t,
size: Lt,
complexity: Ot.sum + Rt.sum + Dt.sum + Ft.sum + Et.sum,
comments: {
total: b,
size: w
},
embeddedContent: {
size: {
total: _,
ratio: z(_, Lt)
},
types: {
total: k.total,
totalUnique: k.unique.size,
uniquenessRatio: z(k.unique.size, k.total),
unique: Object.fromEntries(k.unique)
}
}
},
atrules: d(
Tt,
{
fontface: d({
total: Ee,
totalUnique: Ee,
unique: se,
uniquenessRatio: Ee === 0 ? 0 : 1
}, e ? {
uniqueWithLocations: Ge.c().uniqueWithLocations
} : {}),
import: Qe.c(),
media: d(
Ze.c(),
{
browserhacks: Je.c(),
features: Xe.c()
}
),
charset: $e.c(),
supports: d(
ne.c(),
{
browserhacks: et.c()
}
),
keyframes: d(
ae.c(),
{
prefixed: d(
oe.c(),
{
ratio: z(oe.size(), ae.size())
}
)
}
),
container: d(
tt.c(),
{
names: Q.c()
}
),
layer: le.c(),
property: it.c(),
complexity: Ot,
nesting: d(
ue.aggregate(),
{
items: ue.toArray()
},
rt.c()
)
}
),
rules: {
total: ce,
empty: {
total: fe,
ratio: z(fe, ce)
},
sizes: d(
pe.aggregate(),
{
items: pe.toArray()
},
st.c()
),
nesting: d(
ge.aggregate(),
{
items: ge.toArray()
},
at.c()
),
selectors: d(
he.aggregate(),
{
items: he.toArray()
},
lt.c()
),
declarations: d(
me.aggregate(),
{
items: me.toArray()
},
nt.c()
)
},
selectors: {
total: H,
totalUnique: Pt,
uniquenessRatio: z(Pt, H),
specificity: d(
{
/** @type Specificity */
min: I === void 0 ? [0, 0, 0] : I,
/** @type Specificity */
max: M === void 0 ? [0, 0, 0] : M,
/** @type Specificity */
sum: [Re.sum, De.sum, Fe.sum],
/** @type Specificity */
mean: [Re.mean, De.mean, Fe.mean],
/** @type Specificity */
mode: [Re.mode, De.mode, Fe.mode],
/** @type Specificity */
items: mt
},
pt.c()
),
complexity: d(
Rt,
ht.c(),
{
items: Z.toArray()
}
),
nesting: d(
be.aggregate(),
{
items: be.toArray()
},
yt.c()
),
id: d(
we.c(),
{
ratio: z(we.size(), H)
}
),
pseudoClasses: gt.c(),
accessibility: d(
ke.c(),
{
ratio: z(ke.size(), H)
}
),
keyframes: de.c(),
prefixed: d(
ye.c(),
{
ratio: z(ye.size(), H)
}
),
combinators: dt.c()
},
declarations: {
total: K,
totalUnique: At,
uniquenessRatio: z(At, K),
importants: {
total: J,
ratio: z(J, K),
inKeyframes: {
total: xe,
ratio: z(xe, J)
}
},
complexity: Dt,
nesting: d(
ze.aggregate(),
{
items: ze.toArray()
},
bt.c()
)
},
properties: d(
N.c(),
{
prefixed: d(
_e.c(),
{
ratio: z(_e.size(), N.size())
}
),
custom: d(
X.c(),
{
ratio: z(X.size(), N.size()),
importants: d(
Ce.c(),
{
ratio: z(Ce.size(), X.size())
}
)
}
),
browserhacks: d(
Se.c(),
{
ratio: z(Se.size(), N.size())
}
),
complexity: Ft
}
),
values: {
colors: d(
U.count(),
{
formats: V.c()
}
),
gradients: _t.c(),
fontFamilies: Ae.c(),
fontSizes: Pe.c(),
lineHeights: Le.c(),
zindexes: Ct.c(),
textShadows: zt.c(),
boxShadows: St.c(),
borderRadiuses: qt.count(),
animations: {
durations: ee.c(),
timingFunctions: $.c()
},
prefixes: xt.c(),
browserhacks: ve.c(),
units: Oe.count(),
complexity: Et,
keywords: B.c(),
resets: vt.c()
},
__meta__: {
parseTime: T - P,
analyzeTime: Date.now() - T,
total: Date.now() - n
}
};
}
function Kt(r, t) {
return r[0] === t[0] ? r[1] === t[1] ? t[2] - r[2] : t[1] - r[1] : t[0] - r[0];
}
export {
Ei as analyze,
Kt as compareSpecificity,
E as hasVendorPrefix,
Zt as isAccessibilitySelector,
ui as isMediaBrowserhack,
qi as isPropertyHack,
ci as isSelectorPrefixed,
oi as isSupportsBrowserhack,
Xt as isValuePrefixed,
Jt as selectorComplexity
};