UNPKG

@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
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 };