@@ -8,12 +8,24 @@ import type { CodeLens } from 'vscode-languageserver'
8
8
import braces from 'braces'
9
9
import { findAll , indexToPosition } from '../util/find'
10
10
import { absoluteRange } from '../util/absoluteRange'
11
+ import { segment } from '../util/segment'
11
12
12
13
const PATTERN = / @ s o u r c e (?: \s + n o t ) ? \s * i n l i n e \( (?< glob > ' [ ^ ' ] + ' | " [ ^ " ] + " ) / dg
13
14
14
15
export async function provideCodeLens ( state : State , doc : TextDocument ) : Promise < CodeLens [ ] > {
15
16
let text = doc . getText ( )
16
17
18
+ let countFormatter = new Intl . NumberFormat ( 'en' , {
19
+ maximumFractionDigits : 2 ,
20
+ } )
21
+
22
+ let byteFormatter = new Intl . NumberFormat ( 'en' , {
23
+ notation : 'compact' ,
24
+ style : 'unit' ,
25
+ unit : 'byte' ,
26
+ unitDisplay : 'narrow' ,
27
+ } )
28
+
17
29
let lenses : CodeLens [ ] = [ ]
18
30
19
31
for ( let match of findAll ( PATTERN , text ) ) {
@@ -28,14 +40,73 @@ export async function provideCodeLens(state: State, doc: TextDocument): Promise<
28
40
end : indexToPosition ( text , match . indices . groups . glob [ 1 ] ) ,
29
41
} )
30
42
43
+ let size = 0
44
+ for ( let className of expanded ) {
45
+ size += approximateByteSize ( className )
46
+ }
47
+
31
48
lenses . push ( {
32
49
range : slice ,
33
50
command : {
34
- title : `Generates ${ expanded . size } classes` ,
51
+ title : `Generates ${ countFormatter . format ( expanded . size ) } classes` ,
35
52
command : '' ,
36
53
} ,
37
54
} )
55
+
56
+ if ( size >= 1_000_000 ) {
57
+ lenses . push ( {
58
+ range : slice ,
59
+ command : {
60
+ title : `At least ${ byteFormatter . format ( size ) } of CSS` ,
61
+ command : '' ,
62
+ } ,
63
+ } )
64
+
65
+ lenses . push ( {
66
+ range : slice ,
67
+ command : {
68
+ title : `This may slow down your bundler/browser` ,
69
+ command : '' ,
70
+ } ,
71
+ } )
72
+ }
38
73
}
39
74
40
75
return lenses
41
76
}
77
+
78
+ /**
79
+ * Calculates the approximate size of a generated class
80
+ *
81
+ * This is meant to be a lower bound, as the actual size of a class can vary
82
+ * depending on the actual CSS properties and values, configured theme, etc…
83
+ */
84
+ function approximateByteSize ( className : string ) {
85
+ let size = 0
86
+
87
+ // We estimate the size using the following structure which gives a reasonable
88
+ // lower bound on the size of the generated CSS:
89
+ //
90
+ // .class-name {
91
+ // &:variant-1 {
92
+ // &:variant-2 {
93
+ // /* properties */
94
+ // }
95
+ // }
96
+ // }
97
+
98
+ // Class name
99
+ size += 1 + className . length + 3
100
+ size += 2
101
+
102
+ // Variants + nesting
103
+ for ( let [ depth , variantName ] of segment ( className , ':' ) . entries ( ) ) {
104
+ size += ( depth + 1 ) * 2 + 2 + variantName . length + 3
105
+ size += ( depth + 1 ) * 2 + 2
106
+ }
107
+
108
+ // Properties comment
109
+ size += 16
110
+
111
+ return size
112
+ }
0 commit comments