@projectwallace/css-analyzer 5.0.0-alpha.2 → 5.1.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,272 @@
1
+ /**
2
+ * Analyze CSS
3
+ * @param {string} css
4
+ */
5
+ export function analyze(css: string): {
6
+ stylesheet: {
7
+ sourceLinesOfCode: number;
8
+ linesOfCode: number;
9
+ size: number;
10
+ comments: {
11
+ total: number;
12
+ size: number;
13
+ };
14
+ embeddedContent: {
15
+ total: number;
16
+ totalUnique: number;
17
+ unique: [index: string];
18
+ uniquenessRatio: number;
19
+ } & {
20
+ size: {
21
+ total: number;
22
+ ratio: number;
23
+ };
24
+ };
25
+ };
26
+ atrules: {
27
+ fontface: {
28
+ total: number;
29
+ totalUnique: number;
30
+ unique: {
31
+ [index: string]: string;
32
+ }[];
33
+ uniquenessRatio: number;
34
+ };
35
+ import: {
36
+ total: number;
37
+ totalUnique: number;
38
+ unique: [index: string];
39
+ uniquenessRatio: number;
40
+ };
41
+ media: {
42
+ total: number;
43
+ totalUnique: number;
44
+ unique: [index: string];
45
+ uniquenessRatio: number;
46
+ };
47
+ charset: {
48
+ total: number;
49
+ totalUnique: number;
50
+ unique: [index: string];
51
+ uniquenessRatio: number;
52
+ };
53
+ supports: {
54
+ total: number;
55
+ totalUnique: number;
56
+ unique: [index: string];
57
+ uniquenessRatio: number;
58
+ };
59
+ keyframes: {
60
+ prefixed: {
61
+ ratio: number;
62
+ total: number;
63
+ totalUnique: number;
64
+ unique: [index: string];
65
+ uniquenessRatio: number;
66
+ };
67
+ total: number;
68
+ totalUnique: number;
69
+ unique: [index: string];
70
+ uniquenessRatio: number;
71
+ };
72
+ container: {
73
+ total: number;
74
+ totalUnique: number;
75
+ unique: [index: string];
76
+ uniquenessRatio: number;
77
+ };
78
+ };
79
+ rules: {
80
+ total: number;
81
+ empty: {
82
+ total: number;
83
+ ratio: number;
84
+ };
85
+ selectors: {
86
+ items: number[];
87
+ min: number;
88
+ max: number;
89
+ mean: number;
90
+ mode: number;
91
+ median: number;
92
+ range: number;
93
+ sum: number;
94
+ };
95
+ declarations: {
96
+ items: number[];
97
+ min: number;
98
+ max: number;
99
+ mean: number;
100
+ mode: number;
101
+ median: number;
102
+ range: number;
103
+ sum: number;
104
+ };
105
+ };
106
+ selectors: {
107
+ total: number;
108
+ totalUnique: number;
109
+ uniquenessRatio: number;
110
+ specificity: {
111
+ min: [number, number, number];
112
+ max: [number, number, number];
113
+ sum: [number, number, number];
114
+ mean: [number, number, number];
115
+ mode: [number, number, number];
116
+ median: [number, number, number];
117
+ items: [number, number, number][];
118
+ };
119
+ complexity: {
120
+ items: number[];
121
+ total: number;
122
+ totalUnique: number;
123
+ unique: [index: string];
124
+ uniquenessRatio: number;
125
+ min: number;
126
+ max: number;
127
+ mean: number;
128
+ mode: number;
129
+ median: number;
130
+ range: number;
131
+ sum: number;
132
+ };
133
+ id: {
134
+ ratio: number;
135
+ total: number;
136
+ totalUnique: number;
137
+ unique: [index: string];
138
+ uniquenessRatio: number;
139
+ };
140
+ accessibility: {
141
+ ratio: number;
142
+ total: number;
143
+ totalUnique: number;
144
+ unique: [index: string];
145
+ uniquenessRatio: number;
146
+ };
147
+ keyframes: {
148
+ ratio: number;
149
+ total: number;
150
+ totalUnique: number;
151
+ unique: [index: string];
152
+ uniquenessRatio: number;
153
+ };
154
+ };
155
+ declarations: {
156
+ total: number;
157
+ unique: {
158
+ total: number;
159
+ ratio: number;
160
+ };
161
+ importants: {
162
+ total: number;
163
+ ratio: number;
164
+ inKeyframes: {
165
+ total: number;
166
+ ratio: number;
167
+ };
168
+ };
169
+ };
170
+ properties: {
171
+ prefixed: {
172
+ ratio: number;
173
+ total: number;
174
+ totalUnique: number;
175
+ unique: [index: string];
176
+ uniquenessRatio: number;
177
+ };
178
+ custom: {
179
+ ratio: number;
180
+ total: number;
181
+ totalUnique: number;
182
+ unique: [index: string];
183
+ uniquenessRatio: number;
184
+ };
185
+ browserhacks: {
186
+ ratio: number;
187
+ total: number;
188
+ totalUnique: number;
189
+ unique: [index: string];
190
+ uniquenessRatio: number;
191
+ };
192
+ total: number;
193
+ totalUnique: number;
194
+ unique: [index: string];
195
+ uniquenessRatio: number;
196
+ };
197
+ values: {
198
+ colors: {
199
+ total: number;
200
+ totalUnique: number;
201
+ unique: [index: string];
202
+ uniquenessRatio: number;
203
+ } & {
204
+ itemsPerContext: [index: string];
205
+ };
206
+ fontFamilies: {
207
+ total: number;
208
+ totalUnique: number;
209
+ unique: [index: string];
210
+ uniquenessRatio: number;
211
+ };
212
+ fontSizes: {
213
+ total: number;
214
+ totalUnique: number;
215
+ unique: [index: string];
216
+ uniquenessRatio: number;
217
+ };
218
+ zindexes: {
219
+ total: number;
220
+ totalUnique: number;
221
+ unique: [index: string];
222
+ uniquenessRatio: number;
223
+ };
224
+ textShadows: {
225
+ total: number;
226
+ totalUnique: number;
227
+ unique: [index: string];
228
+ uniquenessRatio: number;
229
+ };
230
+ boxShadows: {
231
+ total: number;
232
+ totalUnique: number;
233
+ unique: [index: string];
234
+ uniquenessRatio: number;
235
+ };
236
+ animations: {
237
+ durations: {
238
+ total: number;
239
+ totalUnique: number;
240
+ unique: [index: string];
241
+ uniquenessRatio: number;
242
+ };
243
+ timingFunctions: {
244
+ total: number;
245
+ totalUnique: number;
246
+ unique: [index: string];
247
+ uniquenessRatio: number;
248
+ };
249
+ };
250
+ prefixes: {
251
+ total: number;
252
+ totalUnique: number;
253
+ unique: [index: string];
254
+ uniquenessRatio: number;
255
+ };
256
+ units: {
257
+ total: number;
258
+ totalUnique: number;
259
+ unique: [index: string];
260
+ uniquenessRatio: number;
261
+ } & {
262
+ itemsPerContext: [index: string];
263
+ };
264
+ };
265
+ __meta__: {
266
+ parseTime: number;
267
+ analyzeTime: number;
268
+ total: number;
269
+ };
270
+ };
271
+ import { compareSpecificity } from "./selectors/specificity.js";
272
+ export { compareSpecificity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectwallace/css-analyzer",
3
- "version": "5.0.0-alpha.2",
3
+ "version": "5.1.0",
4
4
  "author": "Bart Veneman",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,11 +10,18 @@
10
10
  "issues": "https://github.com/projectwallace/css-analyzer/issues",
11
11
  "license": "MIT",
12
12
  "type": "module",
13
+ "files": [
14
+ "dist"
15
+ ],
13
16
  "source": "src/index.js",
14
- "exports": "./dist/analyzer.js",
15
17
  "main": "./dist/analyzer.cjs",
16
18
  "module": "./dist/analyzer.module.js",
17
19
  "unpkg": "./dist/analyzer.umd.js",
20
+ "exports": {
21
+ "require": "./dist/analyzer.cjs",
22
+ "default": "./dist/analyzer.modern.js"
23
+ },
24
+ "types": "./dist/index.d.ts",
18
25
  "engines": {
19
26
  "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
20
27
  },
@@ -36,16 +43,13 @@
36
43
  "styleguide",
37
44
  "metrics"
38
45
  ],
39
- "files": [
40
- "dist"
41
- ],
42
46
  "dependencies": {
43
47
  "css-tree": "^2.0.1"
44
48
  },
45
49
  "devDependencies": {
46
50
  "benchmark": "^2.1.4",
47
- "microbundle": "^0.13.3",
48
- "uvu": "^0.5.1",
51
+ "microbundle": "^0.14.2",
52
+ "uvu": "^0.5.3",
49
53
  "watchlist": "^0.2.3"
50
54
  }
51
55
  }
package/dist/analyzer.js DELETED
@@ -1,2 +0,0 @@
1
- import*as e from"css-tree";function t(){return t=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(e[i]=n[i])}return e},t.apply(this,arguments)}function n(e,t){return e[0]===t[0]?e[1]===t[1]?t[2]-e[2]:t[1]-e[1]:t[0]-e[0]}function i(t){const i=[];return e.walk(t,{visit:"Selector",enter(e){i.push(s(e))}}),i.sort((e,t)=>n(e.specificity,t.specificity))}const s=t=>{let n=0,s=0,r=0,a=0,o=!1;return e.walk(t,{enter:function(t){switch(t.type){case"IdSelector":n++,a++;break;case"ClassSelector":s++,a++;break;case"AttributeSelector":s++,a++,Boolean(t.value)&&a++,o="role"===t.name.name||t.name.name.startsWith("aria-");break;case"PseudoElementSelector":case"TypeSelector":"*"!==t.name&&r++,a++;break;case"PseudoClassSelector":if(["before","after","first-letter","first-line"].includes(t.name))return r++,a++,this.skip;if(["is","has","matches"].includes(t.name)){const o=e.find(t,({type:e})=>"Raw"===e),l=i(e.parse(o.value,{context:"selectorList"})),[u,c,h]=l[0].specificity;n+=u,s+=c,r+=h;for(let e=0;e<l.length;e++)a+=l[e].complexity;return void a++}if("not"===t.name){const e=i(t),[o,l,u]=e[0].specificity;n+=o,s+=l,r+=u;for(let t=0;t<e.length;t++)a+=e[t].complexity;return a++,this.skip}if(["nth-child","nth-last-child"].includes(t.name)){s++;const e=i(t);if(0===e.length)return;const[o,l,u]=e[0].specificity;n+=o,s+=l,r+=u;for(let t=0;t<e.length;t++)a+=e[t].complexity;return void a++}if("where"===t.name){const n=e.find(t,({type:e})=>"Raw"===e),s=i(e.parse(n.value,{context:"selectorList"}));for(let e=0;e<s.length;e++)a+=s[e].complexity;return void a++}a++,s++;break;case"Combinator":a++}}}),{specificity:[n,s,r],complexity:a,isId:n>0,isA11y:o}};class r{constructor(e){this.items=new Uint8Array(e),this.sum=0,this.cursor=0}add(e){this.items[this.cursor]=e,this.sum+=e,this.cursor++}aggregate(){if(0===this.cursor)return{min:0,max:0,mean:0,mode:0,median:0,range:0,sum:0};const e=new Uint8Array(this.items.slice(0,this.cursor)).sort((e,t)=>e-t),t=e[0],n=e[e.length-1],i=function(e){const t=Object.create(null);let n=-1,i=0,s=0;for(let r=0;r<e.length;r++){const a=e[r],o=(t[a]||0)+1;t[a]=o,o>n&&(n=o,i=0,s=0),o>=n&&(i++,s+=a)}return s/i}(e),s=function(e){const t=e.length/2,n=Math.floor(t);return t!==n?e[n]:(e[n]+e[n-1])/2}(e);return{min:t,max:n,mean:this.sum/this.cursor,mode:i,median:s,range:n-t,sum:this.sum}}toArray(){return Array.from(this.items.subarray(0,this.cursor))}}const a=({rules:n})=>{const i=n.length,s=new r(i),a=new r(i);let o=0;for(let t=0;t<i;t++){let i=0,r=0;e.walk(n[t],{enter:function(e){return"Selector"===e.type?(i++,this.skip):"Declaration"===e.type?(r++,this.skip):void 0}}),0===r&&o++,s.add(i),a.add(r)}return{total:i,empty:{total:o,ratio:o/i},selectors:t({},s.aggregate(),{items:s.toArray()}),declarations:t({},a.aggregate(),{items:a.toArray()})}},o={aliceblue:1,antiquewhite:1,aqua:1,aquamarine:1,azure:1,beige:1,bisque:1,black:1,blanchedalmond:1,blue:1,blueviolet:1,brown:1,burlywood:1,cadetblue:1,chartreuse:1,chocolate:1,coral:1,cornflowerblue:1,cornsilk:1,crimson:1,cyan:1,darkblue:1,darkcyan:1,darkgoldenrod:1,darkgray:1,darkgreen:1,darkgrey:1,darkkhaki:1,darkmagenta:1,darkolivegreen:1,darkorange:1,darkorchid:1,darkred:1,darksalmon:1,darkseagreen:1,darkslateblue:1,darkslategray:1,darkslategrey:1,darkturquoise:1,darkviolet:1,deeppink:1,deepskyblue:1,dimgray:1,dimgrey:1,dodgerblue:1,firebrick:1,floralwhite:1,forestgreen:1,fuchsia:1,gainsboro:1,ghostwhite:1,gold:1,goldenrod:1,gray:1,green:1,greenyellow:1,grey:1,honeydew:1,hotpink:1,indianred:1,indigo:1,ivory:1,khaki:1,lavender:1,lavenderblush:1,lawngreen:1,lemonchiffon:1,lightblue:1,lightcoral:1,lightcyan:1,lightgoldenrodyellow:1,lightgray:1,lightgreen:1,lightgrey:1,lightpink:1,lightsalmon:1,lightseagreen:1,lightskyblue:1,lightslategray:1,lightslategrey:1,lightsteelblue:1,lightyellow:1,lime:1,limegreen:1,linen:1,magenta:1,maroon:1,mediumaquamarine:1,mediumblue:1,mediumorchid:1,mediumpurple:1,mediumseagreen:1,mediumslateblue:1,mediumspringgreen:1,mediumturquoise:1,mediumvioletred:1,midnightblue:1,mintcream:1,mistyrose:1,moccasin:1,navajowhite:1,navy:1,oldlace:1,olive:1,olivedrab:1,orange:1,orangered:1,orchid:1,palegoldenrod:1,palegreen:1,paleturquoise:1,palevioletred:1,papayawhip:1,peachpuff:1,peru:1,pink:1,plum:1,powderblue:1,purple:1,rebeccapurple:1,red:1,rosybrown:1,royalblue:1,saddlebrown:1,salmon:1,sandybrown:1,seagreen:1,seashell:1,sienna:1,silver:1,skyblue:1,slateblue:1,slategray:1,slategrey:1,snow:1,springgreen:1,steelblue:1,tan:1,teal:1,thistle:1,tomato:1,turquoise:1,violet:1,wheat:1,white:1,whitesmoke:1,yellow:1,yellowgreen:1,canvas:1,canvastext:1,linktext:1,visitedtext:1,activetext:1,buttonface:1,buttontext:1,buttonborder:1,field:1,fieldtext:1,highlight:1,highlighttext:1,selecteditem:1,selecteditemtext:1,mark:1,marktext:1,graytext:1},l={rgb:1,rgba:1,hsl:1,hsla:1,hwb:1,lab:1,lch:1,oklab:1,oklch:1,color:1},u=({colors:e})=>e.count();class c{constructor(e){if(this.items={},this.total=0,this.totalUnique=0,e)for(let t=0;t<e.length;t++)this.push(e[t])}push(e){this.total++,this.items[e]?this.items[e]++:(this.items[e]=1,this.totalUnique++)}size(){return this.total}count(){return{total:this.total,totalUnique:this.totalUnique,unique:this.items,uniquenessRatio:0===this.total?0:this.totalUnique/this.total}}}const h={inherit:1,initial:1,unset:1,revert:1,caption:1,icon:1,menu:1,"message-box":1,"small-caption":1,"status-bar":1},d={normal:1,"xx-small":1,"x-small":1,small:1,medium:1,large:1,"x-large":1,"xx-large":1,larger:1,smaller:1,bold:1,bolder:1,lighter:1,"ultra-condensed":1,"extra-condensed":1,condensed:1,"semi-condensed":1,"semi-expanded":1,expanded:1,"extra-expanded":1,"ultra-expanded":1,italic:1,oblique:1},m=({fontValues:t,fontFamilyValues:n})=>{const i=new c(n);for(let n=0;n<t.length;n++){const s=t[n],r=s.children.first;if("Identifier"===r.type&&h[r.name])continue;const a=[];e.walk(s,{reverse:!0,enter:function(e){return"String"===e.type||"Operator"===e.type&&44===e.value.charCodeAt(0)?a.unshift(e):"Identifier"===e.type?d[e.name]?this.skip:a.unshift(e):void 0}}),i.push(a.map(e.generate).join(""))}return i.count()},p={"xx-small":1,"x-small":1,small:1,medium:1,large:1,"x-large":1,"xx-large":1,larger:1,smaller:1},g={inherit:1,initial:1,unset:1,revert:1,caption:1,icon:1,menu:1,"message-box":1,"small-caption":1,"status-bar":1},f=({stringifyNode:t,fontSizeValues:n,fontValues:i})=>{const s=new c(n);for(let n=0;n<i.length;n++){const r=i[n],a=r.children.first;if("Identifier"===a.type&&g[a.name])continue;let o,l=!1;e.walk(r,{enter:function(e){switch(e.type){case"Number":if(48===e.value.charCodeAt(0))return o="0",this.break;case"Operator":47===e.value.charCodeAt(0)&&(l=!0);break;case"Dimension":if(!l)return o=t(e),this.break;case"Identifier":if(p[e.name])return o=e.name,this.break}}}),o&&s.push(o)}return s.count()},y=({stringifyNode:e,declarations:t})=>{const n=t.length,i=Object.create(null);let s=0,r=0,a=0;for(let o=0;o<n;o++){const n=t[o];!0===n.important&&(s++,n.inKeyframe&&a++);const l=e(n);i[l]||(i[l]=1,r++)}return{total:n,unique:{total:r,ratio:0===n?0:r/n},importants:{total:s,ratio:0===n?0:s/n,inKeyframes:{total:a,ratio:0===s?0:a/s}}}},b=({stringifyNode:e,selectors:i})=>{const a=Object.create(null),o=Object.create(null),l=i.length;let u,h,d=new r(l),m=new r(l),p=new r(l),g=0;const f=new r(l),y=[],b=[],w=new c,k=new c,x=new c;for(let t=0;t<l;t++){const r=i[t],l=e(r);if(r.isKeyframeSelector){x.push(l);continue}const{specificity:c,complexity:v,isId:q,isA11y:z}=o[l]||s(r);q&&w.push(l),z&&k.push(l),o[l]?a[l]++:(o[l]={complexity:v,specificity:c,isId:q,isA11y:z},g++,a[l]=1),f.add(v),void 0===u&&(u=c),void 0===h&&(h=c),d.add(c[0]),m.add(c[1]),p.add(c[2]),void 0!==h&&n(h,c)<0&&(h=c),void 0!==u&&n(u,c)>0&&(u=c),y.push(c),b.push(v)}const v=d.aggregate(),q=m.aggregate(),z=p.aggregate(),A=new c(b).count();return{total:l,totalUnique:g,uniquenessRatio:g/l,specificity:{sum:[v.sum,q.sum,z.sum],min:h,max:u,mean:[v.mean,q.mean,z.mean],mode:[v.mode,q.mode,z.mode],median:[v.median,q.median,z.median],items:y},complexity:t({},f.aggregate(),A,{items:b}),id:t({},w.count(),{ratio:w.size()/l}),accessibility:t({},k.count(),{ratio:k.size()/l}),keyframes:t({},x.count(),{ratio:x.size()/l})}},w=({properties:e})=>{const n=new c(e.map(e=>e.authored)),i=new c,s=new c,r=new c,a=e.length;for(let t=0;t<a;t++){const n=e[t];n.vendor?i.push(n.authored):n.hack?s.push(n.authored):n.custom&&r.push(n.authored)}return t({},n.count(),{prefixed:t({},i.count(),{ratio:i.size()/a}),custom:t({},r.count(),{ratio:r.size()/a}),browserhacks:t({},s.count(),{ratio:s.size()/a})})},k={auto:1,inherit:1,initial:1,unset:1,revert:1,none:1},x=({values:e,stringifyNode:t})=>{const n=new c;for(let i=0;i<e.length;i++){const s=e[i],r=s.children.first;r&&("Identifier"===r.type&&k[r.name]||n.push(t(s)))}return n.count()},v={linear:1,ease:1,"ease-in":1,"ease-out":1,"ease-in-out":1,"step-start":1,"step-end":1},q=({animations:e,durations:t,timingFunctions:n,stringifyNode:i})=>{const s=new c(t.map(i)),r=new c(n.map(i));for(let t=0;t<e.length;t++){let n=!1;e[t].value.children.forEach(e=>"Operator"===e.type?n=!1:"Dimension"===e.type&&!1===n?(n=!0,s.push(i(e))):"Identifier"===e.type&&v[e.name]?r.push(i(e)):"Function"!==e.type||"cubic-bezier"!==e.name&&"steps"!==e.name?void 0:r.push(i(e)))}return{durations:s.count(),timingFunctions:r.count()}};function z(e){return 45===e.charCodeAt(0)&&45!==e.charCodeAt(1)&&-1!==e.indexOf("-",2)}function A(e){e=e.toArray();for(let t=0;t<e.length;t++){const n=e[t];if("Identifier"===n.type&&n.name.length>=3&&z(n.name))return!0;if("Function"===n.type){if(z(n.name))return!0;if(n.children&&A(n.children))return!0}}return!1}const N=({values:e,stringifyNode:t})=>{const n=new c;for(let i=0;i<e.length;i++){const s=e[i];s.children&&A(s.children)&&n.push(t(s))}return n.count()},C=({atrules:e,stringifyNode:n})=>{const i=[],s=new c,r=new c,a=new c,o=new c,l=new c,u=new c,h=new c,d={"font-face":e=>{const t={};e.block.children.forEach(e=>{t[e.property]=n(e.value)}),i.push(t)},media:e=>r.push(e.prelude.value),supports:e=>o.push(e.prelude.value),keyframes:e=>l.push(`@${e.name} ${e.prelude.value}`),import:e=>s.push(e.prelude.value),charset:e=>a.push(e.prelude.value),container:e=>h.push(e.prelude.value)};for(let t=0;t<e.length;t++){const n=e[t],i=n.name,s=d[i];if(s)s(n);else if(i.endsWith("keyframes")){const e=`@${i} ${n.prelude.value}`;l.push(e),z(i)&&u.push(e)}}return{fontface:{total:i.length,totalUnique:i.length,unique:i,uniquenessRatio:1},import:s.count(),media:r.count(),charset:a.count(),supports:o.count(),keyframes:t({},l.count(),{prefixed:t({},u.count(),{ratio:u.size()/l.size()})}),container:h.count()}};class S{constructor(){this.list=new c,this.contexts={},this.contextCount=0}push(e,t){this.list.push(e),this.contexts[t]||(this.contexts[t]=new c,this.contextCount++),this.contexts[t].push(e)}count(){const e={};for(let t in this.contexts)e[t]=this.contexts[t].count();return Object.assign(this.list.count(),{itemsPerContext:e})}}const O=n=>{const i=new Date,s=n.split(/\r?\n/);function r(e){const t=e.loc.start,n=e.loc.end;if(0==n.line-t.line)return s[t.line-1].substring(t.column-1,n.column-1);const i=[];for(let e=t.line;e<=n.line;e++){const r=s[e-1];i.push(e!==t.line?e!==n.line?r:r.substring(0,n.column-1):r.substring(t.column-1))}return i.join("\n")}const c=new Date;let h=0,d=0;const p=e.parse(n,{parseAtrulePrelude:!1,parseCustomProperty:!0,positions:!0,onComment:function(e){h++,d+=e.length}}),g=new Date,k=[],v=[],z=[],A=[],O=[],I=[],j=[],D=[],F=[],U=[],V=[],P=[],R=[],K=[],L=[],W=new S,$=new S;return e.walk(p,{enter:function(n){switch(n.type){case"Atrule":k.push(n);break;case"Rule":v.push(n);break;case"Selector":return z.push(t({},n,{isKeyframeSelector:this.atrule&&this.atrule.name.endsWith("keyframes")})),this.skip;case"Dimension":if(!this.declaration)break;return $.push(n.unit,this.declaration.property),this.skip;case"Declaration":{A.push(t({},n,{inKeyframe:this.atrule&&this.atrule.name.endsWith("keyframes")}));const{value:i,property:s}=n,a=t({authored:s},e.property(s));switch(O.push(a),I.push(i),a.basename){case"z-index":j.push(i);break;case"text-shadow":D.push(i);break;case"box-shadow":F.push(i);break;case"font":U.push(i);break;case"font-family":return V.push(r(i)),this.skip;case"font-size":P.push(r(i));break;case"transition":case"animation":R.push(n);break;case"animation-duration":case"transition-duration":L.push(i);break;case"transition-timing-function":case"animation-timing-function":K.push(i)}e.walk(n.value,{enter:function(e){switch(e.type){case"Hash":return W.push(r(e),s),this.skip;case"Identifier":{const{name:t}=e;return t.length>20||t.length<3||o[t.toLowerCase()]&&W.push(r(e),s),this.skip}case"Function":l[e.name.toLowerCase()]&&W.push(r(e),s)}}})}}}}),{stylesheet:{sourceLinesOfCode:k.length+z.length+A.length,linesOfCode:s.length,size:n.length,comments:{total:h,size:d}},atrules:C({atrules:k,stringifyNode:r}),rules:a({rules:v}),selectors:b({stringifyNode:r,selectors:z}),declarations:y({stringifyNode:r,declarations:A}),properties:w({properties:O}),values:{colors:u({colors:W}),fontFamilies:m({stringifyNode:r,fontValues:U,fontFamilyValues:V}),fontSizes:f({stringifyNode:r,fontValues:U,fontSizeValues:P}),zindexes:x({values:j,stringifyNode:r}),textShadows:x({values:D,stringifyNode:r}),boxShadows:x({values:F,stringifyNode:r}),animations:q({animations:R,timingFunctions:K,durations:L,stringifyNode:r}),prefixes:N({values:I,stringifyNode:r}),units:$.count()},__meta__:{parseTime:g-c,analyzeTime:new Date-g,total:new Date-i}}};export{O as analyze,n as compareSpecificity};
2
- //# sourceMappingURL=analyzer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"analyzer.js","sources":["../src/selectors/specificity.js","../src/aggregate-collection.js","../src/rules/rules.js","../src/values/colors.js","../src/countable-collection.js","../src/values/font-families.js","../src/values/font-sizes.js","../src/declarations/declarations.js","../src/selectors/selectors.js","../src/properties/properties.js","../src/values/values.js","../src/values/animations.js","../src/vendor-prefix.js","../src/values/vendor-prefix.js","../src/atrules/atrules.js","../src/context-collection.js","../src/index.js"],"sourcesContent":["import * as csstree from 'css-tree'\n\n/**\n * @typedef {[number, number, number]} Specificity\n *\n * @typedef {import('css-tree').Selector} Selector\n */\n\n/**\n * Compare specificity A to Specificity B\n * @param {Specificity} a - Specificity A\n * @param {Specificity} b - Specificity B\n * @returns {number} sortIndex - 0 when a==b, 1 when a<b, -1 when a>b\n */\nfunction compareSpecificity(a, b) {\n if (a[0] === b[0]) {\n if (a[1] === b[1]) {\n return b[2] - a[2]\n }\n\n return b[1] - a[1]\n }\n\n return b[0] - a[0]\n}\n\n/**\n *\n * @param {import('css-tree').SelectorList} selectorListAst\n * @returns {Selector} topSpecificitySelector\n */\nfunction selectorListSpecificities(selectorListAst) {\n const childSelectors = []\n csstree.walk(selectorListAst, {\n visit: 'Selector',\n enter(node) {\n childSelectors.push(analyzeSpecificity(node))\n }\n })\n\n return childSelectors.sort((a, b) => compareSpecificity(a.specificity, b.specificity))\n}\n\n/**\n * Get the Specificity for the AST of a Selector Node\n * @param {import('css-tree').Node} ast - AST Node for a Selector\n * @return {Object}\n * @property {Specificity} specificity\n * @property {number} complexity\n */\nconst analyzeSpecificity = (ast) => {\n let A = 0\n let B = 0\n let C = 0\n let complexity = 0\n let isA11y = false\n\n csstree.walk(ast, {\n enter: function (selector) {\n switch (selector.type) {\n case 'IdSelector': {\n A++\n complexity++\n break\n }\n case 'ClassSelector': {\n B++\n complexity++\n break\n }\n case 'AttributeSelector': {\n B++\n complexity++\n\n if (Boolean(selector.value)) {\n complexity++\n }\n isA11y = selector.name.name === 'role' || selector.name.name.startsWith('aria-')\n break\n }\n case 'PseudoElementSelector':\n case 'TypeSelector': {\n if (selector.name !== '*') {\n C++\n }\n complexity++\n break\n }\n case 'PseudoClassSelector': {\n if (['before', 'after', 'first-letter', 'first-line'].includes(selector.name)) {\n C++\n complexity++\n return this.skip\n }\n // The specificity of an :is(), :not(), or :has() pseudo-class is\n // replaced by the specificity of the most specific complex\n // selector in its selector list argument.\n\n // CSSTree doesn't parse the arguments of :is, :has and :matches,\n // so we need to create an AST out of them ourselves\n if (['is', 'has', 'matches'].includes(selector.name)) {\n const rawSelectorList = csstree.find(selector, ({ type }) => type === 'Raw')\n const childAst = csstree.parse(rawSelectorList.value, { context: 'selectorList' })\n const selectorList = selectorListSpecificities(childAst)\n const [topA, topB, topC] = selectorList[0].specificity\n A += topA\n B += topB\n C += topC\n\n for (let i = 0; i < selectorList.length; i++) {\n complexity += selectorList[i].complexity\n }\n complexity++\n return\n }\n\n // CSSTree *does* parse the arguments of the :not() pseudo-class,\n // so we have direct access to the AST, instead of having to parse\n // the arguments ourselves.\n if (selector.name === 'not') {\n const selectorList = selectorListSpecificities(selector)\n const [topA, topB, topC] = selectorList[0].specificity\n A += topA\n B += topB\n C += topC\n\n for (let i = 0; i < selectorList.length; i++) {\n complexity += selectorList[i].complexity\n }\n complexity++\n return this.skip\n }\n\n // The specificity of an :nth-child() or :nth-last-child() selector\n // is the specificity of the pseudo class itself (counting as one\n // pseudo-class selector) plus the specificity of the most\n // specific complex selector in its selector list argument (if any).\n if (['nth-child', 'nth-last-child'].includes(selector.name)) {\n // +1 for the pseudo class itself\n B++\n\n const childSelectors = selectorListSpecificities(selector)\n\n if (childSelectors.length === 0) {\n return\n }\n\n const [topA, topB, topC] = childSelectors[0].specificity\n A += topA\n B += topB\n C += topC\n\n for (let i = 0; i < childSelectors.length; i++) {\n complexity += childSelectors[i].complexity;\n }\n\n complexity++\n return\n }\n\n // The specificity of a :where() pseudo-class is replaced by zero,\n // but it does count towards complexity.\n if (selector.name === 'where') {\n const rawSelectorList = csstree.find(selector, ({ type }) => type === 'Raw')\n const childAst = csstree.parse(rawSelectorList.value, { context: 'selectorList' })\n const childSelectors = selectorListSpecificities(childAst)\n\n for (let i = 0; i < childSelectors.length; i++) {\n complexity += childSelectors[i].complexity;\n }\n\n complexity++\n return\n }\n\n // Regular pseudo classes have specificity [0,1,0]\n complexity++\n B++\n break\n }\n case 'Combinator': {\n complexity++\n break\n }\n }\n }\n })\n\n return {\n /** @type Specificity */\n specificity: [A, B, C],\n complexity,\n isId: A > 0,\n isA11y\n }\n}\n\nexport {\n analyzeSpecificity,\n compareSpecificity,\n}","/**\n * Find the mode (most occurring value) in an array of Numbers\n * Takes the mean/average of multiple values if multiple values occur the same amount of times.\n *\n * @see https://github.com/angus-c/just/blob/684af9ca0c7808bc78543ec89379b1fdfce502b1/packages/array-mode/index.js\n * @param {Array} arr - Array to find the mode value for\n * @returns {Number} mode - The `mode` value of `arr`\n */\nfunction Mode(arr) {\n const frequencies = Object.create(null)\n let maxOccurrences = -1\n let maxOccurenceCount = 0\n let sum = 0\n\n for (let i = 0; i < arr.length; i++) {\n const element = arr[i]\n const updatedCount = (frequencies[element] || 0) + 1\n frequencies[element] = updatedCount\n\n if (updatedCount > maxOccurrences) {\n maxOccurrences = updatedCount\n maxOccurenceCount = 0\n sum = 0\n }\n\n if (updatedCount >= maxOccurrences) {\n maxOccurenceCount++\n sum += element\n }\n }\n\n return sum / maxOccurenceCount\n}\n\n/**\n * Find the middle number in an Array of Numbers\n * Returns the average of 2 numbers if the Array length is an even number\n * @see https://github.com/angus-c/just/blob/684af9ca0c7808bc78543ec89379b1fdfce502b1/packages/array-median/index.js\n * @param {Array} arr - A sorted Array\n * @returns {Number} - The array's Median\n */\nfunction Median(arr) {\n const middle = arr.length / 2\n const lowerMiddleRank = Math.floor(middle)\n\n if (middle !== lowerMiddleRank) {\n return arr[lowerMiddleRank]\n }\n return (arr[lowerMiddleRank] + arr[lowerMiddleRank - 1]) / 2\n}\n\nclass AggregateCollection {\n constructor(size) {\n /** @type Number[] */\n this.items = new Uint8Array(size)\n this.sum = 0\n this.cursor = 0\n }\n\n /**\n * Add a new Integer to the AggregateCollection\n * @param {number} item - The item to add to the AggregateCollection\n */\n add(item) {\n this.items[this.cursor] = (item)\n this.sum += item\n this.cursor++\n }\n\n aggregate() {\n if (this.cursor === 0) {\n return {\n min: 0,\n max: 0,\n mean: 0,\n mode: 0,\n median: 0,\n range: 0,\n sum: 0,\n }\n }\n\n /** @type Number[] */\n const sorted = new Uint8Array(\n this.items.slice(0, this.cursor)\n ).sort((a, b) => a - b)\n const min = sorted[0]\n const max = sorted[sorted.length - 1]\n\n const mode = Mode(sorted)\n const median = Median(sorted)\n\n return {\n min,\n max,\n mean: this.sum / this.cursor,\n mode,\n median,\n range: max - min,\n sum: this.sum,\n }\n }\n\n toArray() {\n return Array.from(\n this.items.subarray(0, this.cursor)\n )\n }\n}\n\nexport {\n AggregateCollection\n}","import * as csstree from 'css-tree'\nimport { AggregateCollection } from '../aggregate-collection.js'\n\nconst analyzeRules = ({ rules }) => {\n const totalRules = rules.length\n const selectorsPerRule = new AggregateCollection(totalRules)\n const declarationsPerRule = new AggregateCollection(totalRules)\n\n let emptyRules = 0\n\n for (let i = 0; i < totalRules; i++) {\n let selectors = 0\n let declarations = 0\n\n csstree.walk(rules[i], {\n enter: function (childNode) {\n if (childNode.type === 'Selector') {\n selectors++\n return this.skip\n }\n\n if (childNode.type === 'Declaration') {\n declarations++\n return this.skip\n }\n }\n })\n\n if (declarations === 0) {\n emptyRules++\n }\n\n // For later aggregations\n selectorsPerRule.add(selectors)\n declarationsPerRule.add(declarations)\n }\n\n return {\n total: totalRules,\n empty: {\n total: emptyRules,\n ratio: emptyRules / totalRules\n },\n selectors: {\n ...selectorsPerRule.aggregate(),\n items: selectorsPerRule.toArray(),\n },\n declarations: {\n ...declarationsPerRule.aggregate(),\n items: declarationsPerRule.toArray()\n },\n }\n}\n\nexport {\n analyzeRules\n}","export const colorNames = {\n // CSS Named Colors\n // Spec: https://drafts.csswg.org/css-color/#named-colors\n aliceblue: 1,\n antiquewhite: 1,\n aqua: 1,\n aquamarine: 1,\n azure: 1,\n beige: 1,\n bisque: 1,\n black: 1,\n blanchedalmond: 1,\n blue: 1,\n blueviolet: 1,\n brown: 1,\n burlywood: 1,\n cadetblue: 1,\n chartreuse: 1,\n chocolate: 1,\n coral: 1,\n cornflowerblue: 1,\n cornsilk: 1,\n crimson: 1,\n cyan: 1,\n darkblue: 1,\n darkcyan: 1,\n darkgoldenrod: 1,\n darkgray: 1,\n darkgreen: 1,\n darkgrey: 1,\n darkkhaki: 1,\n darkmagenta: 1,\n darkolivegreen: 1,\n darkorange: 1,\n darkorchid: 1,\n darkred: 1,\n darksalmon: 1,\n darkseagreen: 1,\n darkslateblue: 1,\n darkslategray: 1,\n darkslategrey: 1,\n darkturquoise: 1,\n darkviolet: 1,\n deeppink: 1,\n deepskyblue: 1,\n dimgray: 1,\n dimgrey: 1,\n dodgerblue: 1,\n firebrick: 1,\n floralwhite: 1,\n forestgreen: 1,\n fuchsia: 1,\n gainsboro: 1,\n ghostwhite: 1,\n gold: 1,\n goldenrod: 1,\n gray: 1,\n green: 1,\n greenyellow: 1,\n grey: 1,\n honeydew: 1,\n hotpink: 1,\n indianred: 1,\n indigo: 1,\n ivory: 1,\n khaki: 1,\n lavender: 1,\n lavenderblush: 1,\n lawngreen: 1,\n lemonchiffon: 1,\n lightblue: 1,\n lightcoral: 1,\n lightcyan: 1,\n lightgoldenrodyellow: 1,\n lightgray: 1,\n lightgreen: 1,\n lightgrey: 1,\n lightpink: 1,\n lightsalmon: 1,\n lightseagreen: 1,\n lightskyblue: 1,\n lightslategray: 1,\n lightslategrey: 1,\n lightsteelblue: 1,\n lightyellow: 1,\n lime: 1,\n limegreen: 1,\n linen: 1,\n magenta: 1,\n maroon: 1,\n mediumaquamarine: 1,\n mediumblue: 1,\n mediumorchid: 1,\n mediumpurple: 1,\n mediumseagreen: 1,\n mediumslateblue: 1,\n mediumspringgreen: 1,\n mediumturquoise: 1,\n mediumvioletred: 1,\n midnightblue: 1,\n mintcream: 1,\n mistyrose: 1,\n moccasin: 1,\n navajowhite: 1,\n navy: 1,\n oldlace: 1,\n olive: 1,\n olivedrab: 1,\n orange: 1,\n orangered: 1,\n orchid: 1,\n palegoldenrod: 1,\n palegreen: 1,\n paleturquoise: 1,\n palevioletred: 1,\n papayawhip: 1,\n peachpuff: 1,\n peru: 1,\n pink: 1,\n plum: 1,\n powderblue: 1,\n purple: 1,\n rebeccapurple: 1,\n red: 1,\n rosybrown: 1,\n royalblue: 1,\n saddlebrown: 1,\n salmon: 1,\n sandybrown: 1,\n seagreen: 1,\n seashell: 1,\n sienna: 1,\n silver: 1,\n skyblue: 1,\n slateblue: 1,\n slategray: 1,\n slategrey: 1,\n snow: 1,\n springgreen: 1,\n steelblue: 1,\n tan: 1,\n teal: 1,\n thistle: 1,\n tomato: 1,\n turquoise: 1,\n violet: 1,\n wheat: 1,\n white: 1,\n whitesmoke: 1,\n yellow: 1,\n yellowgreen: 1,\n\n // CSS System Colors\n // Spec: https://drafts.csswg.org/css-color/#css-system-colors\n canvas: 1,\n canvastext: 1,\n linktext: 1,\n visitedtext: 1,\n activetext: 1,\n buttonface: 1,\n buttontext: 1,\n buttonborder: 1,\n field: 1,\n fieldtext: 1,\n highlight: 1,\n highlighttext: 1,\n selecteditem: 1,\n selecteditemtext: 1,\n mark: 1,\n marktext: 1,\n graytext: 1,\n\n // TODO: Deprecated CSS System colors\n // Spec: https://drafts.csswg.org/css-color/#deprecated-system-colors\n}\n\nexport const colorFunctions = {\n rgb: 1,\n rgba: 1,\n hsl: 1,\n hsla: 1,\n hwb: 1,\n lab: 1,\n lch: 1,\n oklab: 1,\n oklch: 1,\n color: 1,\n}\n\nexport const analyzeColors = ({ colors }) => {\n return colors.count()\n}\n","class CountableCollection {\n constructor(initial) {\n this.items = {}\n this.total = 0\n this.totalUnique = 0\n\n if (initial) {\n for (let index = 0; index < initial.length; index++) {\n this.push(initial[index])\n }\n }\n }\n\n /**\n *\n * @param {string} item\n */\n push(item) {\n this.total++\n\n if (this.items[item]) {\n this.items[item]++\n return\n }\n\n this.items[item] = 1\n this.totalUnique++\n }\n\n size() {\n return this.total\n }\n\n count() {\n return {\n total: this.total,\n totalUnique: this.totalUnique,\n unique: this.items,\n uniquenessRatio: this.total === 0 ? 0 : this.totalUnique / this.total,\n }\n }\n}\n\nexport {\n CountableCollection\n}","import * as csstree from 'css-tree'\nimport { CountableCollection } from '../countable-collection.js'\n\nconst systemKeywords = {\n // Global CSS keywords\n 'inherit': 1,\n 'initial': 1,\n 'unset': 1,\n 'revert': 1,\n\n // System font keywords\n 'caption': 1,\n 'icon': 1,\n 'menu': 1,\n 'message-box': 1,\n 'small-caption': 1,\n 'status-bar': 1,\n}\n\nconst keywordDisallowList = {\n // font-weight, font-stretch, font-style\n 'normal': 1,\n\n // font-size keywords\n 'xx-small': 1,\n 'x-small': 1,\n 'small': 1,\n 'medium': 1,\n 'large': 1,\n 'x-large': 1,\n 'xx-large': 1,\n 'larger': 1,\n 'smaller': 1,\n\n // font-weight keywords\n 'bold': 1,\n 'bolder': 1,\n 'lighter': 1,\n\n // font-stretch keywords\n 'ultra-condensed': 1,\n 'extra-condensed': 1,\n 'condensed': 1,\n 'semi-condensed': 1,\n 'semi-expanded': 1,\n 'expanded': 1,\n 'extra-expanded': 1,\n 'ultra-expanded': 1,\n\n // font-style keywords\n 'italic': 1,\n 'oblique': 1,\n}\n\nconst COMMA = 44 // ','.charCodeAt(0) === 44\n\nconst analyzeFontFamilies = ({ fontValues, fontFamilyValues }) => {\n const all = new CountableCollection(fontFamilyValues)\n\n for (let index = 0; index < fontValues.length; index++) {\n const value = fontValues[index]\n\n // Avoid tree traversal as soon as possible\n const firstChild = value.children.first\n\n if (firstChild.type === 'Identifier' && systemKeywords[firstChild.name]) {\n continue\n }\n\n const parts = []\n\n csstree.walk(value, {\n reverse: true,\n enter: function (fontNode) {\n if (fontNode.type === 'String') {\n return parts.unshift(fontNode)\n }\n if (fontNode.type === 'Operator' && fontNode.value.charCodeAt(0) === COMMA) {\n return parts.unshift(fontNode)\n }\n if (fontNode.type === 'Identifier') {\n if (keywordDisallowList[fontNode.name]) {\n return this.skip\n }\n return parts.unshift(fontNode)\n }\n }\n })\n\n all.push(parts.map(csstree.generate).join(''))\n }\n\n return all.count()\n}\n\nexport {\n analyzeFontFamilies\n}","import * as csstree from 'css-tree'\nimport { CountableCollection } from '../countable-collection.js'\n\nconst sizeKeywords = {\n 'xx-small': 1,\n 'x-small': 1,\n 'small': 1,\n 'medium': 1,\n 'large': 1,\n 'x-large': 1,\n 'xx-large': 1,\n 'larger': 1,\n 'smaller': 1,\n}\n\nconst keywords = {\n // Global CSS keywords\n 'inherit': 1,\n 'initial': 1,\n 'unset': 1,\n 'revert': 1,\n\n // System font keywords\n 'caption': 1,\n 'icon': 1,\n 'menu': 1,\n 'message-box': 1,\n 'small-caption': 1,\n 'status-bar': 1,\n}\n\nconst ZERO = 48 // '0'.charCodeAt(0) === 48\nconst SLASH = 47 // '/'.charCodeAt(0) === 47\n\nconst analyzeFontSizes = ({ stringifyNode, fontSizeValues, fontValues }) => {\n const all = new CountableCollection(fontSizeValues)\n\n for (let index = 0; index < fontValues.length; index++) {\n const fontNode = fontValues[index];\n // Try to eliminate a keyword before we continue\n const firstChild = fontNode.children.first\n\n if (firstChild.type === 'Identifier' && keywords[firstChild.name]) {\n continue\n }\n\n let operator = false\n let size\n\n csstree.walk(fontNode, {\n enter: function (fontNode) {\n switch (fontNode.type) {\n case 'Number': {\n // Special case for `font: 0/0 a`\n if (fontNode.value.charCodeAt(0) === ZERO) {\n size = '0'\n return this.break\n }\n }\n case 'Operator': {\n if (fontNode.value.charCodeAt(0) === SLASH) {\n operator = true\n }\n break\n }\n case 'Dimension': {\n if (!operator) {\n size = stringifyNode(fontNode)\n return this.break\n }\n }\n case 'Identifier': {\n if (sizeKeywords[fontNode.name]) {\n size = fontNode.name\n return this.break\n }\n }\n }\n }\n })\n\n if (size) {\n all.push(size)\n }\n }\n\n return all.count()\n}\n\nexport {\n analyzeFontSizes\n}","const analyzeDeclarations = ({ stringifyNode, declarations }) => {\n const total = declarations.length\n const cache = Object.create(null)\n let importants = 0\n let totalUnique = 0\n let totalInKeyframes = 0\n\n for (let i = 0; i < total; i++) {\n const declaration = declarations[i]\n\n if (declaration.important === true) {\n importants++\n\n if (declaration.inKeyframe) {\n totalInKeyframes++\n }\n }\n\n const stringified = stringifyNode(declaration)\n\n if (!cache[stringified]) {\n cache[stringified] = 1\n totalUnique++\n }\n }\n\n return {\n total,\n unique: {\n total: totalUnique,\n ratio: total === 0 ? 0 : totalUnique / total,\n },\n importants: {\n total: importants,\n ratio: total === 0 ? 0 : importants / total,\n inKeyframes: {\n total: totalInKeyframes,\n ratio: importants === 0 ? 0 : totalInKeyframes / importants,\n },\n },\n }\n}\n\nexport {\n analyzeDeclarations\n}","import { analyzeSpecificity, compareSpecificity } from './specificity.js'\nimport { AggregateCollection } from '../aggregate-collection.js'\nimport { CountableCollection } from '../countable-collection.js'\n\n/** @typedef {[number, number, number]} Specificity */\n\nconst analyzeSelectors = ({ stringifyNode, selectors }) => {\n const counts = Object.create(null)\n const cache = Object.create(null)\n const totalSelectors = selectors.length\n\n /** @type Specificity|undefined */\n let maxSpecificity\n /** @type Specificity|undefined */\n let minSpecificity\n let specificityA = new AggregateCollection(totalSelectors)\n let specificityB = new AggregateCollection(totalSelectors)\n let specificityC = new AggregateCollection(totalSelectors)\n let totalUnique = 0\n const complexityAggregator = new AggregateCollection(totalSelectors);\n\n const specificities = []\n const complexities = []\n const ids = new CountableCollection()\n const a11y = new CountableCollection()\n const keyframes = new CountableCollection()\n\n for (let i = 0; i < totalSelectors; i++) {\n const node = selectors[i];\n const value = stringifyNode(node)\n\n if (node.isKeyframeSelector) {\n keyframes.push(value)\n // Do not attempt to further analyze <keyframe-selectors>\n continue\n }\n\n const { specificity, complexity, isId, isA11y } = cache[value] || analyzeSpecificity(node)\n\n if (isId) {\n ids.push(value)\n }\n\n if (isA11y) {\n a11y.push(value)\n }\n\n if (!cache[value]) {\n cache[value] = { complexity, specificity, isId, isA11y }\n totalUnique++\n counts[value] = 1\n } else {\n counts[value]++\n }\n\n complexityAggregator.add(complexity)\n\n if (maxSpecificity === undefined) {\n maxSpecificity = specificity\n }\n\n if (minSpecificity === undefined) {\n minSpecificity = specificity\n }\n\n specificityA.add(specificity[0])\n specificityB.add(specificity[1])\n specificityC.add(specificity[2])\n\n if (minSpecificity !== undefined && compareSpecificity(minSpecificity, specificity) < 0) {\n minSpecificity = specificity\n }\n\n if (maxSpecificity !== undefined && compareSpecificity(maxSpecificity, specificity) > 0) {\n maxSpecificity = specificity\n }\n\n specificities.push(specificity)\n complexities.push(complexity)\n }\n\n const aggregatesA = specificityA.aggregate()\n const aggregatesB = specificityB.aggregate()\n const aggregatesC = specificityC.aggregate()\n const complexityCount = new CountableCollection(complexities).count()\n\n return {\n total: totalSelectors,\n totalUnique,\n uniquenessRatio: totalUnique / totalSelectors,\n specificity: {\n sum: [aggregatesA.sum, aggregatesB.sum, aggregatesC.sum],\n min: minSpecificity,\n max: maxSpecificity,\n mean: [aggregatesA.mean, aggregatesB.mean, aggregatesC.mean],\n mode: [aggregatesA.mode, aggregatesB.mode, aggregatesC.mode],\n median: [aggregatesA.median, aggregatesB.median, aggregatesC.median],\n items: specificities\n },\n complexity: {\n ...complexityAggregator.aggregate(),\n ...complexityCount,\n items: complexities,\n },\n id: {\n ...ids.count(),\n ratio: ids.size() / totalSelectors,\n },\n accessibility: {\n ...a11y.count(),\n ratio: a11y.size() / totalSelectors,\n },\n keyframes: {\n ...keyframes.count(),\n ratio: keyframes.size() / totalSelectors,\n }\n }\n}\n\nexport {\n analyzeSelectors\n}","import { CountableCollection } from '../countable-collection.js'\n\nconst analyzeProperties = ({ properties }) => {\n const all = new CountableCollection(properties.map(p => p.authored))\n const prefixed = new CountableCollection()\n const hacks = new CountableCollection()\n const customs = new CountableCollection()\n const totalProperties = properties.length\n\n for (let i = 0; i < totalProperties; i++) {\n const property = properties[i]\n\n if (property.vendor) {\n prefixed.push(property.authored)\n continue\n }\n\n if (property.hack) {\n hacks.push(property.authored)\n continue\n }\n\n if (property.custom) {\n customs.push(property.authored)\n continue\n }\n }\n\n return {\n ...all.count(),\n prefixed: {\n ...prefixed.count(),\n ratio: prefixed.size() / totalProperties,\n },\n custom: {\n ...customs.count(),\n ratio: customs.size() / totalProperties,\n },\n browserhacks: {\n ...hacks.count(),\n ratio: hacks.size() / totalProperties,\n }\n }\n}\n\nexport {\n analyzeProperties\n}","import { CountableCollection } from '../countable-collection.js'\n\nconst keywords = {\n 'auto': 1,\n 'inherit': 1,\n 'initial': 1,\n 'unset': 1,\n 'revert': 1,\n 'none': 1, // for `text-shadow`\n}\n\nconst analyzeValues = ({ values, stringifyNode }) => {\n const all = new CountableCollection()\n\n for (let i = 0; i < values.length; i++) {\n const node = values[i]\n const firstChild = node.children.first\n\n if (!firstChild) continue\n if (firstChild.type === 'Identifier' && keywords[firstChild.name]) continue\n\n all.push(stringifyNode(node))\n }\n\n return all.count()\n}\n\nexport {\n analyzeValues\n}","import { CountableCollection } from '../countable-collection.js'\n\nconst timingKeywords = {\n 'linear': 1,\n 'ease': 1,\n 'ease-in': 1,\n 'ease-out': 1,\n 'ease-in-out': 1,\n 'step-start': 1,\n 'step-end': 1,\n}\n\nconst analyzeAnimations = ({ animations, durations, timingFunctions, stringifyNode }) => {\n const allDurations = new CountableCollection(durations.map(stringifyNode))\n const allTimingFunctions = new CountableCollection(timingFunctions.map(stringifyNode))\n\n for (let index = 0; index < animations.length; index++) {\n const node = animations[index]\n // Flag to know if we've grabbed the first Duration\n // yet (the first Dimension in a shorthand)\n let durationFound = false\n\n node.value.children.forEach(child => {\n // Right after a ',' we start over again\n if (child.type === 'Operator') {\n return durationFound = false\n }\n if (child.type === 'Dimension' && durationFound === false) {\n durationFound = true\n return allDurations.push(stringifyNode(child))\n }\n if (child.type === 'Identifier' && timingKeywords[child.name]) {\n return allTimingFunctions.push(stringifyNode(child))\n }\n if (child.type === 'Function'\n && (\n child.name === 'cubic-bezier' || child.name === 'steps'\n )\n ) {\n return allTimingFunctions.push(stringifyNode(child))\n }\n })\n }\n\n return {\n durations: allDurations.count(),\n timingFunctions: allTimingFunctions.count(),\n }\n}\n\nexport {\n analyzeAnimations\n}","const HYPHENMINUS = 45; // '-'.charCodeAt()\n\nfunction hasVendorPrefix(keyword) {\n if (keyword.charCodeAt(0) === HYPHENMINUS && keyword.charCodeAt(1) !== HYPHENMINUS) {\n // String must have a 2nd occurrence of '-', at least at position 3 (offset=2)\n if (keyword.indexOf('-', 2) !== -1) {\n return true\n }\n }\n\n return false\n}\n\nexport {\n hasVendorPrefix\n}","import { CountableCollection } from '../countable-collection.js'\nimport { hasVendorPrefix } from '../vendor-prefix.js'\n\nfunction isAstVendorPrefixed(children) {\n children = children.toArray()\n\n for (let index = 0; index < children.length; index++) {\n const child = children[index];\n\n if (child.type === 'Identifier' && child.name.length >= 3) {\n if (hasVendorPrefix(child.name)) {\n return true\n }\n }\n\n if (child.type === 'Function') {\n if (hasVendorPrefix(child.name)) {\n return true\n }\n\n if (child.children && isAstVendorPrefixed(child.children)) {\n return true\n }\n }\n }\n return false\n}\n\nconst analyzeVendorPrefixes = ({ values, stringifyNode }) => {\n const all = new CountableCollection()\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n\n if (value.children && isAstVendorPrefixed(value.children)) {\n all.push(stringifyNode(value))\n }\n }\n\n return all.count()\n}\n\nexport {\n analyzeVendorPrefixes\n}","import { CountableCollection } from '../countable-collection.js'\nimport { hasVendorPrefix } from '../vendor-prefix.js'\n\nconst analyzeAtRules = ({ atrules, stringifyNode }) => {\n const fontfaces = []\n const imports = new CountableCollection()\n const medias = new CountableCollection()\n const charsets = new CountableCollection()\n const supports = new CountableCollection()\n const keyframes = new CountableCollection()\n const prefixedKeyframes = new CountableCollection()\n const containers = new CountableCollection()\n\n const machine = {\n 'font-face': (node) => {\n const descriptors = {}\n\n node.block.children.forEach(descriptor => {\n descriptors[descriptor.property] = stringifyNode(descriptor.value)\n })\n\n fontfaces.push(descriptors)\n },\n 'media': node => medias.push(node.prelude.value),\n 'supports': node => supports.push(node.prelude.value),\n 'keyframes': node => keyframes.push(`@${node.name} ${node.prelude.value}`),\n 'import': node => imports.push(node.prelude.value),\n 'charset': node => charsets.push(node.prelude.value),\n 'container': node => containers.push(node.prelude.value),\n }\n\n for (let i = 0; i < atrules.length; i++) {\n const node = atrules[i]\n const nodeName = node.name\n const action = machine[nodeName]\n if (action) {\n action(node)\n continue\n }\n\n if (nodeName.endsWith('keyframes')) {\n const name = `@${nodeName} ${node.prelude.value}`\n keyframes.push(name)\n\n if (hasVendorPrefix(nodeName)) {\n prefixedKeyframes.push(name)\n }\n continue\n }\n }\n\n return {\n fontface: {\n total: fontfaces.length,\n totalUnique: fontfaces.length,\n unique: fontfaces,\n uniquenessRatio: 1\n },\n import: imports.count(),\n media: medias.count(),\n charset: charsets.count(),\n supports: supports.count(),\n keyframes: {\n ...keyframes.count(),\n prefixed: {\n ...prefixedKeyframes.count(),\n ratio: prefixedKeyframes.size() / keyframes.size()\n }\n },\n container: containers.count(),\n }\n}\n\nexport {\n analyzeAtRules\n}","import { CountableCollection } from './countable-collection.js'\n\nclass ContextCollection {\n constructor() {\n this.list = new CountableCollection()\n this.contexts = {}\n this.contextCount = 0\n }\n\n push(item, context) {\n this.list.push(item)\n\n if (!this.contexts[context]) {\n this.contexts[context] = new CountableCollection()\n this.contextCount++\n }\n\n this.contexts[context].push(item)\n }\n\n count() {\n const itemsPerContext = {}\n\n for (let context in this.contexts) {\n itemsPerContext[context] = this.contexts[context].count()\n }\n\n return Object.assign(this.list.count(), {\n itemsPerContext\n })\n }\n}\n\nexport {\n ContextCollection\n}","import * as csstree from 'css-tree'\nimport { compareSpecificity } from './selectors/specificity.js'\nimport { analyzeRules } from './rules/rules.js'\nimport { analyzeColors, colorFunctions, colorNames } from './values/colors.js'\nimport { analyzeFontFamilies } from './values/font-families.js'\nimport { analyzeFontSizes } from './values/font-sizes.js'\nimport { analyzeDeclarations } from './declarations/declarations.js'\nimport { analyzeSelectors } from './selectors/selectors.js'\nimport { analyzeProperties } from './properties/properties.js'\nimport { analyzeValues } from './values/values.js'\nimport { analyzeAnimations } from './values/animations.js'\nimport { analyzeVendorPrefixes } from './values/vendor-prefix.js'\nimport { analyzeAtRules } from './atrules/atrules.js'\nimport { CountableCollection } from './countable-collection.js'\nimport { ContextCollection } from './context-collection.js'\n\n/**\n *\n * @param {string} css\n * @returns\n */\nconst analyze = (css) => {\n const start = new Date()\n\n // We need all lines later on when we need to stringify the AST again\n // e.g. for Selectors\n const lines = css.split(/\\r?\\n/)\n\n /**\n * Recreate the authored CSS from a CSSTree node\n * @param {import('css-tree').Node} node - Node from CSSTree AST to stringify\n * @returns {string} str - The stringified node\n */\n function stringifyNode(node) {\n const start = node.loc.start\n const end = node.loc.end\n const lineCount = end.line - start.line\n\n // Single-line nodes\n if (lineCount === 0) {\n return lines[start.line - 1].substring(start.column - 1, end.column - 1)\n }\n\n // Multi-line nodes\n const value = []\n\n for (let i = start.line; i <= end.line; i++) {\n const line = lines[i - 1]\n // First line\n if (i === start.line) {\n value.push(line.substring(start.column - 1))\n continue\n }\n // Last line\n if (i === end.line) {\n value.push(line.substring(0, end.column - 1))\n continue\n }\n // All lines in between first and last\n value.push(line)\n }\n\n return value.join('\\n')\n }\n\n const startParse = new Date()\n let totalComments = 0\n let commentsSize = 0\n\n const ast = csstree.parse(css, {\n parseAtrulePrelude: false,\n parseCustomProperty: true, // To find font-families, colors, etc.\n positions: true, // So we can use stringifyNode()\n onComment: function (comment) {\n totalComments++\n commentsSize += comment.length\n },\n })\n\n const startAnalysis = new Date()\n const atrules = []\n const rules = []\n const selectors = []\n const declarations = []\n const properties = []\n const values = []\n const zindex = []\n const textShadows = []\n const boxShadows = []\n const fontValues = []\n const fontFamilyValues = []\n const fontSizeValues = []\n const animations = []\n const timingFunctions = []\n const durations = []\n const colors = new ContextCollection()\n const units = new ContextCollection()\n\n csstree.walk(ast, {\n enter: function (node) {\n switch (node.type) {\n case 'Atrule': {\n atrules.push(node)\n break\n }\n case 'Rule': {\n rules.push(node)\n break\n }\n case 'Selector': {\n selectors.push({\n ...node,\n isKeyframeSelector: this.atrule && this.atrule.name.endsWith('keyframes')\n })\n\n // Avoid further walking of selectors to not mess with\n // our specificity calculations in case of a selector\n // with :where() or :is() that contain SelectorLists\n // as children\n return this.skip\n }\n case 'Dimension': {\n if (!this.declaration) {\n break\n }\n\n units.push(node.unit, this.declaration.property)\n\n return this.skip\n }\n case 'Declaration': {\n declarations.push({\n ...node,\n inKeyframe: this.atrule && this.atrule.name.endsWith('keyframes')\n })\n\n const { value, property } = node\n const fullProperty = {\n authored: property,\n ...csstree.property(property)\n }\n\n properties.push(fullProperty)\n values.push(value)\n\n switch (fullProperty.basename) {\n case 'z-index': {\n zindex.push(value)\n break\n }\n case 'text-shadow': {\n textShadows.push(value)\n break\n }\n case 'box-shadow': {\n boxShadows.push(value)\n break\n }\n case 'font': {\n fontValues.push(value)\n break\n }\n case 'font-family': {\n fontFamilyValues.push(stringifyNode(value))\n // Prevent analyzer to find color names in this property\n return this.skip\n }\n case 'font-size': {\n fontSizeValues.push(stringifyNode(value))\n break\n }\n case 'transition':\n case 'animation': {\n animations.push(node)\n break\n }\n case 'animation-duration':\n case 'transition-duration': {\n durations.push(value)\n break\n }\n case 'transition-timing-function':\n case 'animation-timing-function': {\n timingFunctions.push(value)\n break\n }\n }\n\n csstree.walk(node.value, {\n enter: function (valueNode) {\n switch (valueNode.type) {\n case 'Hash': {\n colors.push(stringifyNode(valueNode), property)\n\n return this.skip\n }\n case 'Identifier': {\n const { name } = valueNode\n // Bail out if it can't be a color name\n // 20 === 'lightgoldenrodyellow'.length\n // 3 === 'red'.length\n if (name.length > 20 || name.length < 3) {\n return this.skip\n }\n if (colorNames[name.toLowerCase()]) {\n colors.push(stringifyNode(valueNode), property)\n }\n return this.skip\n }\n case 'Function': {\n if (colorFunctions[valueNode.name.toLowerCase()]) {\n colors.push(stringifyNode(valueNode), property)\n }\n // No this.skip here intentionally,\n // otherwise we'll miss colors in linear-gradient() etc.\n }\n }\n }\n })\n }\n }\n }\n })\n\n return {\n stylesheet: {\n sourceLinesOfCode: atrules.length + selectors.length + declarations.length,\n linesOfCode: lines.length,\n size: css.length,\n comments: {\n total: totalComments,\n size: commentsSize,\n },\n },\n atrules: analyzeAtRules({ atrules, stringifyNode }),\n rules: analyzeRules({ rules }),\n selectors: analyzeSelectors({ stringifyNode, selectors }),\n declarations: analyzeDeclarations({ stringifyNode, declarations }),\n properties: analyzeProperties({ properties }),\n values: {\n colors: analyzeColors({ colors }),\n fontFamilies: analyzeFontFamilies({ stringifyNode, fontValues, fontFamilyValues }),\n fontSizes: analyzeFontSizes({ stringifyNode, fontValues, fontSizeValues }),\n zindexes: analyzeValues({ values: zindex, stringifyNode }),\n textShadows: analyzeValues({ values: textShadows, stringifyNode }),\n boxShadows: analyzeValues({ values: boxShadows, stringifyNode }),\n animations: analyzeAnimations({ animations, timingFunctions, durations, stringifyNode }),\n prefixes: analyzeVendorPrefixes({ values, stringifyNode }),\n units: units.count(),\n },\n __meta__: {\n parseTime: startAnalysis - startParse,\n analyzeTime: new Date() - startAnalysis,\n total: new Date() - start\n }\n }\n}\n\nexport { analyze, compareSpecificity }"],"names":["compareSpecificity","a","b","selectorListSpecificities","selectorListAst","childSelectors","csstree","walk","visit","enter","node","push","analyzeSpecificity","sort","specificity","ast","A","B","C","complexity","isA11y","selector","type","Boolean","value","name","startsWith","includes","skip","rawSelectorList","find","selectorList","parse","context","topA","topB","topC","i","length","isId","AggregateCollection","constructor","size","this","items","Uint8Array","sum","cursor","add","item","aggregate","min","max","mean","mode","median","range","sorted","slice","arr","frequencies","Object","create","maxOccurrences","maxOccurenceCount","element","updatedCount","Mode","middle","lowerMiddleRank","Math","floor","Median","toArray","Array","from","subarray","analyzeRules","rules","totalRules","selectorsPerRule","declarationsPerRule","emptyRules","selectors","declarations","childNode","total","empty","ratio","colorNames","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen","canvas","canvastext","linktext","visitedtext","activetext","buttonface","buttontext","buttonborder","field","fieldtext","highlight","highlighttext","selecteditem","selecteditemtext","mark","marktext","graytext","colorFunctions","rgb","rgba","hsl","hsla","hwb","lab","lch","oklab","oklch","color","analyzeColors","colors","count","CountableCollection","initial","totalUnique","index","unique","uniquenessRatio","systemKeywords","inherit","unset","revert","caption","icon","menu","keywordDisallowList","normal","small","medium","large","larger","smaller","bold","bolder","lighter","condensed","expanded","italic","oblique","analyzeFontFamilies","fontValues","fontFamilyValues","all","firstChild","children","first","parts","reverse","fontNode","charCodeAt","unshift","map","generate","join","sizeKeywords","keywords","analyzeFontSizes","stringifyNode","fontSizeValues","operator","break","analyzeDeclarations","cache","importants","totalInKeyframes","declaration","important","inKeyframe","stringified","inKeyframes","analyzeSelectors","counts","totalSelectors","maxSpecificity","minSpecificity","specificityA","specificityB","specificityC","complexityAggregator","specificities","complexities","ids","a11y","keyframes","isKeyframeSelector","undefined","aggregatesA","aggregatesB","aggregatesC","complexityCount","id","accessibility","analyzeProperties","properties","p","authored","prefixed","hacks","customs","totalProperties","property","vendor","hack","custom","browserhacks","auto","none","analyzeValues","values","timingKeywords","linear","ease","analyzeAnimations","animations","durations","timingFunctions","allDurations","allTimingFunctions","durationFound","forEach","child","hasVendorPrefix","keyword","indexOf","isAstVendorPrefixed","analyzeVendorPrefixes","analyzeAtRules","atrules","fontfaces","imports","medias","charsets","supports","prefixedKeyframes","containers","machine","descriptors","block","descriptor","media","prelude","import","charset","container","nodeName","action","endsWith","fontface","ContextCollection","list","contexts","contextCount","itemsPerContext","assign","analyze","css","start","Date","lines","split","loc","end","line","substring","column","startParse","totalComments","commentsSize","parseAtrulePrelude","parseCustomProperty","positions","onComment","comment","startAnalysis","zindex","textShadows","boxShadows","units","atrule","unit","fullProperty","basename","valueNode","toLowerCase","stylesheet","sourceLinesOfCode","linesOfCode","comments","fontFamilies","fontSizes","zindexes","prefixes","__meta__","parseTime","analyzeTime"],"mappings":"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"}