@projectwallace/css-analyzer
Version:
The best CSS analyzer out there. Check design tokens, complexity, specificity, performance and more.
1,215 lines (1,214 loc) • 32.1 kB
JavaScript
import Xt from "css-tree/parser";
import q from "css-tree/walker";
import { calculateForAST as $t } from "@bramus/specificity/core";
function We(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 (We(r.charCodeAt(e), t.charCodeAt(e)) === !1)
return !1;
return !0;
}
function R(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 (We(r.charCodeAt(n - e), t.charCodeAt(n)) === !1)
return !1;
return !0;
}
function Ke(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 (We(r.charCodeAt(e), t.charCodeAt(e)) === !1)
return !1;
return !0;
}
const Me = "Atrule", ei = "MediaQuery", Ie = "Rule", Ne = "Selector", Wt = "TypeSelector", G = "PseudoClassSelector", Kt = "AttributeSelector", Nt = "PseudoElementSelector", He = "Declaration", ti = "Value", O = "Identifier", ii = "Nth", ri = "Combinator", jt = "Number", je = "Dimension", W = "Operator", si = "Hash", li = "Url", Be = "Function";
function Mt(r, t, s) {
let e = r.value.children.first;
return S(t, r.property) && e.type === O && S(s, e.name);
}
function ni(r) {
let t = !1;
return q(r, function(s) {
if (s.type === He && (Mt(s, "-webkit-appearance", "none") || Mt(s, "-moz-appearance", "meterbar")))
return t = !0, this.break;
}), t;
}
function ai(r) {
let t = !1;
return q(r, function(s) {
let e = s.name, n = s.value;
if (s.type === ei && s.mediaType !== null) {
if (Ke("\\0", s.mediaType) || R("\\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 It = 45;
function F(r) {
return r.charCodeAt(0) === It && r.charCodeAt(1) !== It && 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 Bt(r, t) {
let s = [];
return q(r, {
visit: Ne,
enter: function(e) {
s.push(t(e));
}
}), s;
}
const Yt = new A([
"nth-child",
"where",
"not",
"is",
"has",
"nth-last-child",
"matches",
"-webkit-any",
"-moz-any"
]);
function Gt(r) {
let t = !1;
return q(r, function(s) {
if (s.type === Kt) {
let e = s.name.name;
if (S("role", e) || Ke("aria-", e))
return t = !0, this.break;
} else if (s.type === G && Yt.has(s.name)) {
let e = Bt(s, Gt);
for (let n of e)
if (n === !0) {
t = !0;
break;
}
return this.skip;
}
}), t;
}
function oi(r) {
let t = !1;
return q(r, function(s) {
let e = s.type;
if ((e === Nt || e === Wt || e === G) && F(s.name))
return t = !0, this.break;
}), t;
}
function ui(r) {
let t = [];
return q(r, function(s) {
s.type === G && t.push(s.name);
}), t.length === 0 ? !1 : t;
}
function Qt(r) {
let t = 0;
return q(r, function(s) {
let e = s.type;
if (!(e === Ne || e === ii)) {
if (t++, (e === Nt || e === Wt || e === G) && F(s.name) && t++, e === Kt)
return s.value && t++, this.skip;
if (e === G && Yt.has(s.name)) {
let n = Bt(s, Qt);
if (n.length === 0) return;
for (let a of n)
t += a;
return this.skip;
}
}
}), t;
}
function ci(r, t) {
q(r, function(s, e) {
if (s.type === ri) {
let n = s.loc, a = s.name;
if (n === null) {
let y = e.prev.data.loc.end, k = {
offset: y.offset,
line: y.line,
column: y.column
};
t({
name: a,
loc: {
start: k,
end: {
offset: k.offset + 1,
line: k.line,
column: k.column + 1
}
}
});
} else
t({
name: a,
loc: n
});
}
});
}
const fi = 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"
]), pi = 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"
]), hi = new A([
"rgba",
"rgb",
"hsla",
"hsl",
"oklch",
"color",
"hwb",
"lch",
"lab",
"oklab"
]), mi = 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 === O && ie.has(e.name);
}
function Ut(r) {
return parseFloat(r) === 0;
}
function gi(r) {
for (let t of r.children.toArray())
if (!(t.type === jt && Ut(t.value)) && !(t.type === je && Ut(t.value)))
return !1;
return !0;
}
const di = new A([
"caption",
"icon",
"menu",
"message-box",
"small-caption",
"status-bar"
]), yi = new A([
/* <absolute-size> values */
"xx-small",
"x-small",
"small",
"medium",
"large",
"x-large",
"xx-large",
"xxx-large",
/* <relative-size> values */
"smaller",
"larger"
]), wi = 44, Vt = 47;
function Ue(r) {
let t = r.children.first;
return t === null ? !1 : t.type === O && di.has(t.name);
}
function bi(r, t, s) {
var k;
let e = Array.from({ length: 2 }), n, a;
r.children.forEach(function(w, _) {
let b = _.prev ? _.prev.data : void 0, P = _.next ? _.next.data : void 0;
if (w.type === O && ie.has(w.name) && s({
type: "keyword",
value: w.name
}), P && P.type === W && P.value.charCodeAt(0) === Vt) {
n = t(w);
return;
}
if (b && b.type === W && b.value.charCodeAt(0) === Vt) {
a = t(w);
return;
}
if (P && P.type === W && P.value.charCodeAt(0) === wi && !e[0]) {
e[0] = w, !n && b && (n = t(b));
return;
}
if (w.type !== jt) {
if (_.next === null) {
e[1] = w, !n && !e[0] && b && (n = t(b));
return;
}
if (w.type === O) {
let D = w.name;
if (yi.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: ((k = e[1]) == null ? void 0 : k.loc.end.offset) || r.loc.end.offset
}
}
}) : null;
return {
font_size: n,
line_height: a,
font_family: y
};
}
const ki = new A([
"linear",
"ease",
"ease-in",
"ease-out",
"ease-in-out",
"step-start",
"step-end"
]), xi = new A([
"cubic-bezier",
"steps"
]);
function Ci(r, t) {
let s = !1;
for (let e of r) {
let n = e.type, a = e.name;
n === W ? s = !1 : n === je && s === !1 ? (s = !0, t({
type: "duration",
value: e
})) : n === O ? ki.has(a) ? t({
type: "fn",
value: e
}) : ie.has(a) && t({
type: "keyword",
value: e
}) : n === Be && xi.has(a) && t({
type: "fn",
value: e
});
}
}
function Zt(r) {
let t = r.children;
if (!t)
return !1;
for (let s of t) {
let { type: e, name: n } = s;
if (e === O && F(n) || e === Be && (F(n) || Zt(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((_, b) => {
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(b, P);
} else
s[b] = _.length;
});
let k = this._total, w = {
total: k,
totalUnique: y,
unique: s,
uniquenessRatio: k === 0 ? 0 : y / k
};
return e && (w.uniqueWithLocations = Object.fromEntries(t)), w;
}
}
class Ve {
/** @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 zi(r) {
let t = /* @__PURE__ */ new Map(), s = -1, e = 0, n = 0, a = r.length;
for (let y = 0; y < a; y++) {
let k = r[y], w = (t.get(k) || 0) + 1;
t.set(k, w), w > s && (s = w, e = 0, n = 0), w >= s && (e++, n += k);
}
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((k, w) => k - w), e = s[0], n = s[t - 1], a = zi(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 Si(r) {
if (Ye(r) || F(r)) return !1;
let t = r.charCodeAt(0);
return t === 47 || t === 42 || t === 95 || t === 43 || t === 38 || t === 36 || t === 35;
}
function Ye(r) {
return r.length < 3 ? !1 : r.charCodeAt(0) === 45 && r.charCodeAt(1) === 45;
}
function m(r, t) {
return Ye(t) ? !1 : R(r, t);
}
function _i(r) {
return F(r) ? r.slice(r.indexOf("-", 2) + 1) : r;
}
function vi(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 qi(r) {
let t = r.children;
if (t) {
let s = t.last;
return s && s.type === O && R("\\9", s.name);
}
return !1;
}
let Ai = 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 Pi = {
useLocations: !1
};
function Di(r, t = {}) {
let e = Object.assign({}, Pi, 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 k = 0, w = 0, _ = 0, b = {
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 = Xt(r, {
parseCustomProperty: !0,
// To find font-families, colors, etc.
positions: !0,
// So we can use stringifyNode()
/** @param {string} comment */
onComment: function(i) {
k++, w += i.length;
}
}), T = Date.now(), Jt = D.loc.end.line - D.loc.start.line + 1, re = 0, se = new C(), le = [], Ge = new o(e), ne = new o(e), Qe = new o(e), Ze = new o(e), Je = new o(e), Xe = new o(e), $e = new o(e), ae = new o(e), et = new o(e), oe = new o(e), ue = new o(e), tt = new o(e), Q = new o(e), it = new o(e), ce = new C(), rt = new o(e), fe = 0, pe = 0, he = new C(), me = new C(), ge = new C(), st = new o(e), lt = new o(e), nt = new o(e), de = new C(), at = new o(e), ye = new o(e), ot = /* @__PURE__ */ new Set(), we = 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 = [], be = new o(e), ke = new o(e), gt = new o(e), dt = new o(e), xe = new C(), yt = new o(e), wt = /* @__PURE__ */ new Set(), K = 0, bt = new C(), J = 0, Ce = 0, ze = new o(e), Se = new C(), kt = new o(e), N = new o(e), _e = new o(e), ve = new o(e), X = new o(e), j = new C(), qe = new C(), xt = new o(e), Ae = new o(e), Ct = new o(e), zt = new o(e), St = new o(e), Pe = new o(e), Le = new o(e), Re = new o(e), $ = new o(e), ee = new o(e), U = new Ve(e), V = new o(e), Oe = new Ve(e), _t = new o(e), B = new o(e), vt = new Ve(e), qt = new o(e), L = 0;
q(D, {
enter(i) {
var Y, Tt;
switch (i.type) {
case Me: {
re++, ce.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 === He && (g[c.property] = a(c.value));
}), le.push(g), se.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), ai(g) && (Je.p(c, f), l++);
else if (p === "supports")
ae.p(c, f), ni(g) && (et.p(c, f), l++);
else if (R("keyframes", p)) {
let u = "@" + p + " " + c;
F(p) && (ue.p(u, f), l++), oe.p(u, f);
} else if (p === "import")
q(i, function(u) {
if (u.type === "Condition" && u.kind === "supports") {
let h = a(u);
return ae.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" && (ne.p("<anonymous>", i.loc), l++);
se.push(l);
break;
}
case "Layer": {
i.name !== null && ne.p(i.name, i.loc);
break;
}
case "Feature": {
Xe.p(i.name, i.loc);
break;
}
case Ie: {
let p = i.prelude, l = i.block, g = p.children, c = l.children, f = g ? g.size : 0, u = c ? c.size : 0;
he.push(f + u), st.p(f + u, i.loc), me.push(f), lt.p(f, p.loc), ge.push(u), nt.p(u, l.loc), de.push(L), at.p(L, i.loc), fe++, u === 0 && pe++;
break;
}
case Ne: {
let p = a(i);
if (this.atrule && R("keyframes", this.atrule.name))
return ye.p(p, i.loc), this.skip;
Gt(i) && ke.p(p, i.loc);
let l = ui(i);
if (l !== !1)
for (let x of l)
gt.p(x, i.loc);
let g = Qt(i);
oi(i) && we.p(p, i.loc), ot.add(p), Z.push(g), ht.p(g, i.loc), xe.push(L - 1), yt.p(L - 1, i.loc);
let c = $t(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 && Ht(I, c) < 0 && (I = c), M !== void 0 && Ht(M, c) > 0 && (M = c), mt.push(c), f > 0 && be.p(p, i.loc), ci(i, function(v) {
dt.p(v.name, v.loc);
}), this.skip;
}
case je: {
if (!this.declaration)
break;
let p = i.unit;
return R("\\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 li: {
if (Ke("data:", i.value)) {
let p = i.value, l = p.length, g = vi(p);
b.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 (b.unique.has(g)) {
let f = b.unique.get(g);
f.count++, f.size += l, b.unique.set(g, f), e && f.uniqueWithLocations.push(c);
} else {
let f = {
count: 1,
size: l
};
e && (f.uniqueWithLocations = [c]), b.unique.set(g, f);
}
}
break;
}
case ti: {
if (te(i)) {
qe.push(1), B.p(a(i), i.loc);
break;
}
let p = this.declaration, { property: l, important: g } = p, c = 1;
Zt(i) && (xt.p(a(i), i.loc), c++), typeof g == "string" && (Ae.p(y(i) + "!" + g, i.loc), c++), qi(i) && (Ae.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))
gi(i) && qt.p(l, p.loc);
else {
if (m("z-index", l))
return Ct.p(a(i), u), this.skip;
if (m("font", l)) {
if (Ue(i)) return;
let { font_size: h, line_height: x, font_family: v } = bi(i, a, function(E) {
E.type === "keyword" && B.p(E.value, u);
});
v && Pe.p(v, u), h && Le.p(h, u), x && Re.p(x, u);
break;
} else if (m("font-size", l)) {
Ue(i) || Le.p(a(i), u);
break;
} else if (m("font-family", l)) {
Ue(i) || Pe.p(a(i), u);
break;
} else if (m("line-height", l))
Re.p(a(i), u);
else if (m("transition", l) || m("animation", l)) {
Ci(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))
((Tt = f.first) == null ? void 0 : Tt.type) === "Identifier" && Q.p(f.first.name, u);
else if (Ai.has(_i(l))) {
te(i) || vt.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));
}
q(i, function(h) {
let x = h.name;
switch (h.type) {
case si: {
let v = h.value.length;
return R("\\9", h.value) && (v = v - 2), U.push("#" + h.value, l, u), V.p("hex" + v, u), this.skip;
}
case O: {
ie.has(x) && B.p(x, u);
let v = x.length;
if (v > 20 || v < 3)
return this.skip;
if (mi.has(x)) {
let E = a(h);
U.push(E, l, u), V.p(x.toLowerCase(), u);
return;
}
if (fi.has(x)) {
let E = a(h);
U.push(E, l, u), V.p("named", u);
return;
}
if (pi.has(x)) {
let E = a(h);
U.push(E, l, u), V.p("system", u);
return;
}
return this.skip;
}
case Be: {
if (S("var", x))
return this.skip;
if (hi.has(x)) {
U.push(a(h), l, h.loc), V.p(x.toLowerCase(), h.loc);
return;
}
if (R("gradient", x)) {
_t.p(a(h), h.loc);
return;
}
}
}
});
break;
}
case He: {
if (this.atrulePrelude !== null)
return this.skip;
K++;
let p = 1;
wt.add(a(i)), Se.push(L - 1), kt.p(L - 1, i.loc), i.important === !0 && (J++, p++, this.atrule && R("keyframes", this.atrule.name) && (Ce++, p++)), bt.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), F(l) ? (ve.p(l, c), j.push(2)) : Si(l) ? (_e.p(l, c), j.push(2)) : Ye(l) ? (X.p(l, c), j.push(i.important ? 3 : 2), i.important === !0 && ze.p(l, c)) : j.push(1);
break;
}
}
(i.type === Ie || i.type === Me) && L++;
},
leave(i) {
(i.type === Ie || i.type === Me) && L--;
}
});
let At = wt.size, H = Z.size(), De = ut.aggregate(), Ee = ct.aggregate(), Fe = ft.aggregate(), Pt = ot.size, d = Object.assign, Lt = r.length, Te = le.length, Rt = se.aggregate(), Ot = Z.aggregate(), Dt = bt.aggregate(), Et = j.aggregate(), Ft = qe.aggregate();
return {
stylesheet: {
sourceLinesOfCode: re + H + K + ye.size(),
linesOfCode: Jt,
size: Lt,
complexity: Rt.sum + Ot.sum + Dt.sum + Et.sum + Ft.sum,
comments: {
total: k,
size: w
},
embeddedContent: {
size: {
total: _,
ratio: z(_, Lt)
},
types: {
total: b.total,
totalUnique: b.unique.size,
uniquenessRatio: z(b.unique.size, b.total),
unique: Object.fromEntries(b.unique)
}
}
},
atrules: {
fontface: d({
total: Te,
totalUnique: Te,
unique: le,
uniquenessRatio: Te === 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(
ae.c(),
{
browserhacks: et.c()
}
),
keyframes: d(
oe.c(),
{
prefixed: d(
ue.c(),
{
ratio: z(ue.size(), oe.size())
}
)
}
),
container: d(
tt.c(),
{
names: Q.c()
}
),
layer: ne.c(),
property: it.c(),
total: re,
complexity: Rt,
nesting: d(
ce.aggregate(),
{
items: ce.toArray()
},
rt.c()
)
},
rules: {
total: fe,
empty: {
total: pe,
ratio: z(pe, fe)
},
sizes: d(
he.aggregate(),
{
items: he.toArray()
},
st.c()
),
nesting: d(
de.aggregate(),
{
items: de.toArray()
},
at.c()
),
selectors: d(
me.aggregate(),
{
items: me.toArray()
},
lt.c()
),
declarations: d(
ge.aggregate(),
{
items: ge.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: [De.sum, Ee.sum, Fe.sum],
/** @type Specificity */
mean: [De.mean, Ee.mean, Fe.mean],
/** @type Specificity */
mode: [De.mode, Ee.mode, Fe.mode],
/** @type Specificity */
items: mt
},
pt.c()
),
complexity: d(
Ot,
ht.c(),
{
items: Z.toArray()
}
),
nesting: d(
xe.aggregate(),
{
items: xe.toArray()
},
yt.c()
),
id: d(
be.c(),
{
ratio: z(be.size(), H)
}
),
pseudoClasses: gt.c(),
accessibility: d(
ke.c(),
{
ratio: z(ke.size(), H)
}
),
keyframes: ye.c(),
prefixed: d(
we.c(),
{
ratio: z(we.size(), H)
}
),
combinators: dt.c()
},
declarations: {
total: K,
totalUnique: At,
uniquenessRatio: z(At, K),
importants: {
total: J,
ratio: z(J, K),
inKeyframes: {
total: Ce,
ratio: z(Ce, J)
}
},
complexity: Dt,
nesting: d(
Se.aggregate(),
{
items: Se.toArray()
},
kt.c()
)
},
properties: d(
N.c(),
{
prefixed: d(
ve.c(),
{
ratio: z(ve.size(), N.size())
}
),
custom: d(
X.c(),
{
ratio: z(X.size(), N.size()),
importants: d(
ze.c(),
{
ratio: z(ze.size(), X.size())
}
)
}
),
browserhacks: d(
_e.c(),
{
ratio: z(_e.size(), N.size())
}
),
complexity: Et
}
),
values: {
colors: d(
U.count(),
{
formats: V.c()
}
),
gradients: _t.c(),
fontFamilies: Pe.c(),
fontSizes: Le.c(),
lineHeights: Re.c(),
zindexes: Ct.c(),
textShadows: zt.c(),
boxShadows: St.c(),
borderRadiuses: vt.count(),
animations: {
durations: ee.c(),
timingFunctions: $.c()
},
prefixes: xt.c(),
browserhacks: Ae.c(),
units: Oe.count(),
complexity: Ft,
keywords: B.c(),
resets: qt.c()
},
__meta__: {
parseTime: T - P,
analyzeTime: Date.now() - T,
total: Date.now() - n
}
};
}
function Ht(r, t) {
return r[0] === t[0] ? r[1] === t[1] ? t[2] - r[2] : t[1] - r[1] : t[0] - r[0];
}
export {
Di as analyze,
Ht as compareSpecificity,
F as hasVendorPrefix,
Gt as isAccessibilitySelector,
ai as isMediaBrowserhack,
Si as isPropertyHack,
oi as isSelectorPrefixed,
ni as isSupportsBrowserhack,
Zt as isValuePrefixed,
Qt as selectorComplexity
};