@projectwallace/css-analyzer 9.4.0 → 9.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ //#region src/keyword-set.d.ts
2
+ /**
3
+ * @description A Set-like construct to search CSS keywords in a case-insensitive way
4
+ */
5
+ declare class KeywordSet {
6
+ set: Set<string>;
7
+ constructor(items: Lowercase<string>[]);
8
+ has(item: string): boolean;
9
+ }
10
+ //#endregion
11
+ export { KeywordSet as t };
@@ -0,0 +1,16 @@
1
+ //#region src/keyword-set.ts
2
+ /**
3
+ * @description A Set-like construct to search CSS keywords in a case-insensitive way
4
+ */
5
+ var KeywordSet = class {
6
+ set;
7
+ constructor(items) {
8
+ /** @type {Set<string>} */
9
+ this.set = new Set(items);
10
+ }
11
+ has(item) {
12
+ return this.set.has(item.toLowerCase());
13
+ }
14
+ };
15
+ //#endregion
16
+ export { KeywordSet as t };
@@ -0,0 +1,2 @@
1
+ import { a as shorthand_properties, i as isHack, n as basename, r as border_radius_properties, t as SPACING_RESET_PROPERTIES } from "../property-utils-MKX6iGvg.js";
2
+ export { basename, border_radius_properties, isHack as is_property_hack, shorthand_properties, SPACING_RESET_PROPERTIES as spacing_reset_properties };
@@ -0,0 +1,2 @@
1
+ import { a as shorthand_properties, i as isHack, n as basename, r as border_radius_properties, t as SPACING_RESET_PROPERTIES } from "../property-utils-B3n9KkA9.js";
2
+ export { basename, border_radius_properties, isHack as is_property_hack, shorthand_properties, SPACING_RESET_PROPERTIES as spacing_reset_properties };
@@ -0,0 +1,107 @@
1
+ import { t as KeywordSet } from "./keyword-set-qSyAMR9o.js";
2
+ import { is_custom, is_vendor_prefixed } from "@projectwallace/css-parser";
3
+ //#region src/properties/property-utils.ts
4
+ const shorthand_properties = new Set([
5
+ "all",
6
+ "animation",
7
+ "background",
8
+ "border",
9
+ "border-block-end",
10
+ "border-block-start",
11
+ "border-bottom",
12
+ "border-color",
13
+ "border-image",
14
+ "border-inline-end",
15
+ "border-inline-start",
16
+ "border-left",
17
+ "border-radius",
18
+ "border-right",
19
+ "border-style",
20
+ "border-top",
21
+ "border-width",
22
+ "column-rule",
23
+ "columns",
24
+ "contain-intrinsic-size",
25
+ "flex",
26
+ "flex-flow",
27
+ "font",
28
+ "gap",
29
+ "grid",
30
+ "grid-area",
31
+ "grid-column",
32
+ "grid-row",
33
+ "grid-template",
34
+ "inset",
35
+ "list-style",
36
+ "margin",
37
+ "mask",
38
+ "offset",
39
+ "outline",
40
+ "overflow",
41
+ "padding",
42
+ "place-content",
43
+ "place-items",
44
+ "place-self",
45
+ "scroll-margin",
46
+ "scroll-padding",
47
+ "scroll-timeline",
48
+ "text-decoration",
49
+ "text-emphasis",
50
+ "transition",
51
+ "vertical-align"
52
+ ]);
53
+ const SPACING_RESET_PROPERTIES = new Set([
54
+ "margin",
55
+ "margin-block",
56
+ "margin-inline",
57
+ "margin-top",
58
+ "margin-block-start",
59
+ "margin-block-end",
60
+ "margin-inline-end",
61
+ "margin-inline-end",
62
+ "margin-right",
63
+ "margin-bottom",
64
+ "margin-left",
65
+ "padding",
66
+ "padding-block",
67
+ "padding-inline",
68
+ "padding-top",
69
+ "padding-right",
70
+ "padding-bottom",
71
+ "padding-left",
72
+ "padding-block-start",
73
+ "padding-block-end",
74
+ "padding-inline-start",
75
+ "padding-inline-end"
76
+ ]);
77
+ const border_radius_properties = new KeywordSet([
78
+ "border-radius",
79
+ "border-top-left-radius",
80
+ "border-top-right-radius",
81
+ "border-bottom-right-radius",
82
+ "border-bottom-left-radius",
83
+ "border-start-start-radius",
84
+ "border-start-end-radius",
85
+ "border-end-end-radius",
86
+ "border-end-start-radius"
87
+ ]);
88
+ /**
89
+ * @see https://github.com/csstree/csstree/blob/master/lib/utils/names.js#L69
90
+ */
91
+ function isHack(property) {
92
+ if (is_custom(property) || is_vendor_prefixed(property)) return false;
93
+ let code = property.charCodeAt(0);
94
+ return code === 47 || code === 42 || code === 95 || code === 43 || code === 38 || code === 36 || code === 35;
95
+ }
96
+ /**
97
+ * Get the normalized basename for a property with a vendor prefix
98
+ * @returns The property name without vendor prefix
99
+ */
100
+ function basename(property) {
101
+ if (is_custom(property)) return property;
102
+ if (is_vendor_prefixed(property)) return property.slice(property.indexOf("-", 2) + 1).toLowerCase();
103
+ if (isHack(property)) return property.slice(1).toLowerCase();
104
+ return property.toLowerCase();
105
+ }
106
+ //#endregion
107
+ export { shorthand_properties as a, isHack as i, basename as n, border_radius_properties as r, SPACING_RESET_PROPERTIES as t };
@@ -0,0 +1,17 @@
1
+ import { t as KeywordSet } from "./keyword-set-BXSoLQ6m.js";
2
+
3
+ //#region src/properties/property-utils.d.ts
4
+ declare const shorthand_properties: Set<string>;
5
+ declare const SPACING_RESET_PROPERTIES: Set<string>;
6
+ declare const border_radius_properties: KeywordSet;
7
+ /**
8
+ * @see https://github.com/csstree/csstree/blob/master/lib/utils/names.js#L69
9
+ */
10
+ declare function isHack(property: string): boolean;
11
+ /**
12
+ * Get the normalized basename for a property with a vendor prefix
13
+ * @returns The property name without vendor prefix
14
+ */
15
+ declare function basename(property: string): string;
16
+ //#endregion
17
+ export { shorthand_properties as a, isHack as i, basename as n, border_radius_properties as r, SPACING_RESET_PROPERTIES as t };
@@ -0,0 +1,2 @@
1
+ import { a as calculate, i as isPrefixed, n as getComplexity, o as calculateForAST, r as isAccessibility, s as compare, t as getCombinators } from "../utils-DJb_IpTO.js";
2
+ export { compare as compareSpecificity, getCombinators, getComplexity, calculate as getSpecificity, calculateForAST as getSpecificityForAST, isAccessibility, isPrefixed };
@@ -0,0 +1,3 @@
1
+ import "../string-utils-C97yyuqE.js";
2
+ import { a as getComplexity, i as getCombinators, n as calculateForAST, o as isAccessibility, r as compare, s as isPrefixed, t as calculate } from "../specificity-BKdu6JZr.js";
3
+ export { compare as compareSpecificity, getCombinators, getComplexity, calculate as getSpecificity, calculateForAST as getSpecificityForAST, isAccessibility, isPrefixed };
@@ -0,0 +1,269 @@
1
+ import { t as KeywordSet } from "./keyword-set-qSyAMR9o.js";
2
+ import { n as unquote } from "./string-utils-C97yyuqE.js";
3
+ import { ATTRIBUTE_SELECTOR, CLASS_SELECTOR, COMBINATOR, ID_SELECTOR, NTH_OF_SELECTOR, NTH_SELECTOR, PSEUDO_CLASS_SELECTOR, PSEUDO_ELEMENT_SELECTOR, SELECTOR, SELECTOR_LIST, SKIP, TYPE_SELECTOR, str_equals, str_starts_with, walk } from "@projectwallace/css-parser";
4
+ import { parse_selector } from "@projectwallace/css-parser/parse-selector";
5
+ //#region src/selectors/utils.ts
6
+ const PSEUDO_FUNCTIONS = new KeywordSet([
7
+ "nth-child",
8
+ "where",
9
+ "not",
10
+ "is",
11
+ "has",
12
+ "nth-last-child",
13
+ "matches",
14
+ "-webkit-any",
15
+ "-moz-any"
16
+ ]);
17
+ function isPrefixed(selector, on_selector) {
18
+ walk(selector, function(node) {
19
+ if (node.type === PSEUDO_ELEMENT_SELECTOR || node.type === PSEUDO_CLASS_SELECTOR || node.type === TYPE_SELECTOR) {
20
+ if (node.is_vendor_prefixed) {
21
+ let prefix = "";
22
+ if (node.type === PSEUDO_CLASS_SELECTOR) prefix = ":";
23
+ else if (node.type === PSEUDO_ELEMENT_SELECTOR) prefix = "::";
24
+ on_selector(prefix + (node.name || node.text));
25
+ }
26
+ }
27
+ });
28
+ }
29
+ /**
30
+ * Check if a Wallace selector is an accessibility selector (has aria-* or role attribute)
31
+ */
32
+ function isAccessibility(selector, on_selector) {
33
+ function normalize(node) {
34
+ let clone = node.clone();
35
+ if (clone.value) return "[" + clone.name?.toLowerCase() + clone.attr_operator + "\"" + unquote(clone.value.toString()) + "\"]";
36
+ return "[" + clone.name?.toLowerCase() + "]";
37
+ }
38
+ walk(selector, function(node) {
39
+ if (node.type === ATTRIBUTE_SELECTOR) {
40
+ const name = node.name || "";
41
+ if (str_equals("role", name) || str_starts_with(name, "aria-")) on_selector(normalize(node));
42
+ }
43
+ });
44
+ }
45
+ /**
46
+ * Get the Complexity for a Wallace Selector Node
47
+ * @param selector - Wallace CSSNode for a Selector
48
+ * @return The numeric complexity of the Selector
49
+ */
50
+ function getComplexity(selector) {
51
+ let complexity = 0;
52
+ function findSelectors(node, complexities) {
53
+ walk(node, function(n) {
54
+ if (n.type === SELECTOR) complexities.push(getComplexity(n));
55
+ });
56
+ }
57
+ walk(selector, function(node) {
58
+ const type = node.type;
59
+ if (type === SELECTOR) return;
60
+ if (type === NTH_SELECTOR) {
61
+ if (node.text && node.text.trim()) complexity++;
62
+ return;
63
+ }
64
+ complexity++;
65
+ if (type === PSEUDO_ELEMENT_SELECTOR || type === TYPE_SELECTOR || type === PSEUDO_CLASS_SELECTOR) {
66
+ if (node.is_vendor_prefixed) complexity++;
67
+ }
68
+ if (type === ATTRIBUTE_SELECTOR) {
69
+ if (node.value) complexity++;
70
+ return SKIP;
71
+ }
72
+ if (type === PSEUDO_CLASS_SELECTOR) {
73
+ const name = node.name || "";
74
+ if (PSEUDO_FUNCTIONS.has(name.toLowerCase())) {
75
+ const childComplexities = [];
76
+ if (node.has_children) for (const child of node) if (child.type === SELECTOR) childComplexities.push(getComplexity(child));
77
+ else findSelectors(child, childComplexities);
78
+ if (childComplexities.length > 0) {
79
+ for (const c of childComplexities) complexity += c;
80
+ return SKIP;
81
+ }
82
+ }
83
+ }
84
+ });
85
+ return complexity;
86
+ }
87
+ /**
88
+ * Walk a selector node and trigger a callback every time a Combinator was found
89
+ */
90
+ function getCombinators(selector, onMatch) {
91
+ walk(selector, function(node) {
92
+ if (node.type === COMBINATOR) onMatch({
93
+ name: node.name?.trim() === "" ? " " : node.name,
94
+ loc: {
95
+ offset: node.start,
96
+ line: node.line,
97
+ column: node.column,
98
+ length: 1
99
+ }
100
+ });
101
+ });
102
+ }
103
+ //#endregion
104
+ //#region src/selectors/specificity.ts
105
+ /**
106
+ * @returns 0 if s1 equals s2, a negative number if s1 is lower than s2, or a positive number if s1 higher than s2
107
+ */
108
+ function compare(s1, s2) {
109
+ if (s1[0] === s2[0]) {
110
+ if (s1[1] === s2[1]) return s1[2] - s2[2];
111
+ return s1[1] - s2[1];
112
+ }
113
+ return s1[0] - s2[0];
114
+ }
115
+ function max(list) {
116
+ return list.sort(compare).at(-1);
117
+ }
118
+ const calculateForAST = (selectorAST) => {
119
+ let a = 0;
120
+ let b = 0;
121
+ let c = 0;
122
+ let current = selectorAST.first_child;
123
+ while (current) {
124
+ switch (current.type) {
125
+ case ID_SELECTOR:
126
+ a += 1;
127
+ break;
128
+ case ATTRIBUTE_SELECTOR:
129
+ case CLASS_SELECTOR:
130
+ b += 1;
131
+ break;
132
+ case PSEUDO_CLASS_SELECTOR:
133
+ switch (current.name?.toLowerCase()) {
134
+ case "where": break;
135
+ case "-webkit-any":
136
+ case "any":
137
+ if (current.first_child) b += 1;
138
+ break;
139
+ case "-moz-any":
140
+ case "is":
141
+ case "matches":
142
+ case "not":
143
+ case "has":
144
+ if (current.has_children) {
145
+ const childSelectorList = current.first_child;
146
+ if (childSelectorList?.type === SELECTOR_LIST) {
147
+ const max1 = max(calculate(childSelectorList));
148
+ a += max1[0];
149
+ b += max1[1];
150
+ c += max1[2];
151
+ }
152
+ }
153
+ break;
154
+ case "nth-child":
155
+ case "nth-last-child":
156
+ b += 1;
157
+ const nthOf = current.first_child;
158
+ if (nthOf?.type === NTH_OF_SELECTOR && nthOf.selector) {
159
+ const max2 = max(calculate(nthOf.selector));
160
+ a += max2[0];
161
+ b += max2[1];
162
+ c += max2[2];
163
+ }
164
+ break;
165
+ case "host-context":
166
+ case "host":
167
+ b += 1;
168
+ const childSelector = current.first_child?.first_child;
169
+ if (childSelector?.type === SELECTOR) {
170
+ let childPart = childSelector.first_child;
171
+ while (childPart) {
172
+ if (childPart.type === COMBINATOR) break;
173
+ const partSpecificity = calculateForAST({
174
+ type_name: "Selector",
175
+ first_child: childPart,
176
+ has_children: true
177
+ });
178
+ a += partSpecificity[0] ?? 0;
179
+ b += partSpecificity[1] ?? 0;
180
+ c += partSpecificity[2] ?? 0;
181
+ childPart = childPart.next_sibling;
182
+ }
183
+ }
184
+ break;
185
+ case "after":
186
+ case "before":
187
+ case "first-letter":
188
+ case "first-line":
189
+ c += 1;
190
+ break;
191
+ default:
192
+ b += 1;
193
+ break;
194
+ }
195
+ break;
196
+ case PSEUDO_ELEMENT_SELECTOR:
197
+ switch (current.name?.toLowerCase()) {
198
+ case "slotted":
199
+ c += 1;
200
+ const childSelector = current.first_child?.first_child;
201
+ if (childSelector?.type === SELECTOR) {
202
+ let childPart = childSelector.first_child;
203
+ while (childPart) {
204
+ if (childPart.type === COMBINATOR) break;
205
+ const partSpecificity = calculateForAST({
206
+ type_name: "Selector",
207
+ first_child: childPart,
208
+ has_children: true
209
+ });
210
+ a += partSpecificity[0] ?? 0;
211
+ b += partSpecificity[1] ?? 0;
212
+ c += partSpecificity[2] ?? 0;
213
+ childPart = childPart.next_sibling;
214
+ }
215
+ }
216
+ break;
217
+ case "view-transition-group":
218
+ case "view-transition-image-pair":
219
+ case "view-transition-old":
220
+ case "view-transition-new":
221
+ if (current.first_child?.text === "*") break;
222
+ c += 1;
223
+ break;
224
+ default:
225
+ c += 1;
226
+ break;
227
+ }
228
+ break;
229
+ case TYPE_SELECTOR:
230
+ let typeSelector = current.name ?? "";
231
+ if (typeSelector.includes("|")) typeSelector = typeSelector.split("|")[1] ?? "";
232
+ if (typeSelector !== "*") c += 1;
233
+ break;
234
+ default: break;
235
+ }
236
+ current = current.next_sibling;
237
+ }
238
+ return [
239
+ a,
240
+ b,
241
+ c
242
+ ];
243
+ };
244
+ const convertToAST = (source) => {
245
+ if (typeof source === "string") try {
246
+ return parse_selector(source);
247
+ } catch (e) {
248
+ const message = e instanceof Error ? e.message : String(e);
249
+ throw new TypeError(`Could not convert passed in source '${source}' to SelectorList: ${message}`);
250
+ }
251
+ if (source instanceof Object) {
252
+ if (source.type === SELECTOR_LIST) return source;
253
+ throw new TypeError(`Passed in source is an Object but no AST / AST of the type SelectorList`);
254
+ }
255
+ throw new TypeError(`Passed in source is not a String nor an Object. I don't know what to do with it.`);
256
+ };
257
+ const calculate = (selector) => {
258
+ if (!selector) return [];
259
+ const ast = convertToAST(selector);
260
+ const specificities = [];
261
+ let selectorNode = ast.first_child;
262
+ while (selectorNode) {
263
+ specificities.push(calculateForAST(selectorNode));
264
+ selectorNode = selectorNode.next_sibling;
265
+ }
266
+ return specificities;
267
+ };
268
+ //#endregion
269
+ export { getComplexity as a, getCombinators as i, calculateForAST as n, isAccessibility as o, compare as r, isPrefixed as s, calculate as t };
@@ -0,0 +1,34 @@
1
+ import "@projectwallace/css-parser";
2
+ //#region src/string-utils.ts
3
+ function unquote(str) {
4
+ return str.replaceAll(/(?:^['"])|(?:['"]$)/g, "");
5
+ }
6
+ /**
7
+ * Case-insensitive compare two character codes
8
+ * @see https://github.com/csstree/csstree/blob/41f276e8862d8223eeaa01a3d113ab70bb13d2d9/lib/tokenizer/utils.js#L22
9
+ */
10
+ function compareChar(referenceCode, testCode) {
11
+ if (testCode >= 65 && testCode <= 90) testCode = testCode | 32;
12
+ return referenceCode === testCode;
13
+ }
14
+ /**
15
+ * Case-insensitive testing whether a string ends with a given substring
16
+ *
17
+ * @example
18
+ * endsWith('test', 'my-test') // true
19
+ * endsWith('test', 'est') // false
20
+ *
21
+ * @param base e.g. '-webkit-transform'
22
+ * @param maybe e.g. 'transform'
23
+ * @returns true if `test` ends with `base`, false otherwise
24
+ */
25
+ function endsWith(base, maybe) {
26
+ if (base === maybe) return true;
27
+ let len = maybe.length;
28
+ let offset = len - base.length;
29
+ if (offset < 0) return false;
30
+ for (let i = len - 1; i >= offset; i--) if (compareChar(base.charCodeAt(i - offset), maybe.charCodeAt(i)) === false) return false;
31
+ return true;
32
+ }
33
+ //#endregion
34
+ export { unquote as n, endsWith as t };
@@ -0,0 +1,54 @@
1
+ import { CSSNode } from "@projectwallace/css-parser";
2
+
3
+ //#region src/collection.d.ts
4
+ type Location = {
5
+ line: number;
6
+ column: number;
7
+ offset: number;
8
+ length: number;
9
+ };
10
+ type UniqueWithLocations = Record<string, Location[]>;
11
+ type CollectionCount<WithLocations extends boolean = false> = {
12
+ total: number;
13
+ totalUnique: number;
14
+ unique: Record<string, number>;
15
+ uniquenessRatio: number;
16
+ } & (WithLocations extends true ? {
17
+ uniqueWithLocations: UniqueWithLocations;
18
+ } : {
19
+ uniqueWithLocations?: undefined;
20
+ });
21
+ //#endregion
22
+ //#region src/selectors/specificity.d.ts
23
+ type Specificity = [number, number, number];
24
+ /**
25
+ * @returns 0 if s1 equals s2, a negative number if s1 is lower than s2, or a positive number if s1 higher than s2
26
+ */
27
+ declare function compare(s1: Specificity, s2: Specificity): number;
28
+ declare const calculateForAST: (selectorAST: CSSNode) => Specificity;
29
+ declare const calculate: (selector: string | CSSNode) => Specificity[];
30
+ //#endregion
31
+ //#region src/selectors/utils.d.ts
32
+ declare function isPrefixed(selector: CSSNode, on_selector: (prefix: string) => void): void;
33
+ /**
34
+ * Check if a Wallace selector is an accessibility selector (has aria-* or role attribute)
35
+ */
36
+ declare function isAccessibility(selector: CSSNode, on_selector: (a11y_selector: string) => void): void;
37
+ /**
38
+ * Get the Complexity for a Wallace Selector Node
39
+ * @param selector - Wallace CSSNode for a Selector
40
+ * @return The numeric complexity of the Selector
41
+ */
42
+ declare function getComplexity(selector: CSSNode): number;
43
+ /**
44
+ * Walk a selector node and trigger a callback every time a Combinator was found
45
+ */
46
+ declare function getCombinators(selector: CSSNode, onMatch: ({
47
+ name,
48
+ loc
49
+ }: {
50
+ name: string;
51
+ loc: Location;
52
+ }) => void): void;
53
+ //#endregion
54
+ export { calculate as a, CollectionCount as c, isPrefixed as i, Location as l, getComplexity as n, calculateForAST as o, isAccessibility as r, compare as s, getCombinators as t, UniqueWithLocations as u };
@@ -0,0 +1,7 @@
1
+ import { a as namedColors, i as colorKeywords, n as keywords, o as systemColors, r as colorFunctions, t as isValueReset } from "../values-B5nDaGc_.js";
2
+ import { CSSNode } from "@projectwallace/css-parser";
3
+
4
+ //#region src/values/browserhacks.d.ts
5
+ declare function isIe9Hack(node: CSSNode): boolean;
6
+ //#endregion
7
+ export { colorFunctions, colorKeywords, isIe9Hack, isValueReset, keywords, namedColors, systemColors };
@@ -0,0 +1,3 @@
1
+ import "../string-utils-C97yyuqE.js";
2
+ import { a as colorKeywords, i as colorFunctions, n as isValueReset, o as namedColors, r as keywords, s as systemColors, t as isIe9Hack } from "../browserhacks-Ckz2JiOQ.js";
3
+ export { colorFunctions, colorKeywords, isIe9Hack, isValueReset, keywords, namedColors, systemColors };
@@ -0,0 +1,17 @@
1
+ import { t as KeywordSet } from "./keyword-set-BXSoLQ6m.js";
2
+ import { CSSNode } from "@projectwallace/css-parser";
3
+
4
+ //#region src/values/colors.d.ts
5
+ declare const namedColors: KeywordSet;
6
+ declare const systemColors: KeywordSet;
7
+ declare const colorFunctions: KeywordSet;
8
+ declare const colorKeywords: KeywordSet;
9
+ //#endregion
10
+ //#region src/values/values.d.ts
11
+ declare const keywords: KeywordSet;
12
+ /**
13
+ * Test whether a value is a reset (0, 0px, -0.0e0 etc.)
14
+ */
15
+ declare function isValueReset(node: CSSNode): boolean;
16
+ //#endregion
17
+ export { namedColors as a, colorKeywords as i, keywords as n, systemColors as o, colorFunctions as r, isValueReset as t };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@projectwallace/css-analyzer",
3
3
  "description": "The best CSS analyzer out there. Check design tokens, complexity, specificity, performance and more.",
4
- "version": "9.4.0",
4
+ "version": "9.6.0",
5
5
  "author": "Bart Veneman",
6
6
  "repository": {
7
7
  "type": "git",
@@ -17,8 +17,26 @@
17
17
  "main": "./dist/index.js",
18
18
  "types": "./dist/index.d.ts",
19
19
  "exports": {
20
- "types": "./dist/index.d.ts",
21
- "default": "./dist/index.js"
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "./selectors": {
25
+ "types": "./dist/selectors/index.d.ts",
26
+ "default": "./dist/selectors/index.js"
27
+ },
28
+ "./atrules": {
29
+ "types": "./dist/atrules/index.d.ts",
30
+ "default": "./dist/atrules/index.js"
31
+ },
32
+ "./values": {
33
+ "types": "./dist/values/index.d.ts",
34
+ "default": "./dist/values/index.js"
35
+ },
36
+ "./properties": {
37
+ "types": "./dist/properties/index.d.ts",
38
+ "default": "./dist/properties/index.js"
39
+ }
22
40
  },
23
41
  "engines": {
24
42
  "node": ">=18.0.0"
@@ -54,7 +72,7 @@
54
72
  "devDependencies": {
55
73
  "@codecov/rollup-plugin": "^1.9.1",
56
74
  "@vitest/coverage-v8": "^4.0.18",
57
- "knip": "^5.83.1",
75
+ "knip": "^6.0.4",
58
76
  "oxlint": "^1.43.0",
59
77
  "prettier": "^3.6.2",
60
78
  "publint": "^0.3.17",