1
1
import path from 'node:path'
2
2
import fs from 'node:fs'
3
+ import babel from '@babel/core'
3
4
import glob from 'fast-glob'
4
5
5
6
const directory = path . resolve ( import . meta. dirname , '..' )
@@ -15,111 +16,240 @@ const matches = glob
15
16
'**/lib-esm/**' ,
16
17
'**/storybook-static/**' ,
17
18
'**/.next/**' ,
18
- '**/*.test.{ts,tsx}' ,
19
- '**/*.types.test.{ts,tsx}' ,
20
19
'**/*.module.css.d.ts' ,
20
+ '**/*.figma.tsx' ,
21
21
] ,
22
22
} )
23
23
. map ( match => {
24
24
const filepath = path . resolve ( directory , match )
25
+ const ast = babel . parseSync ( fs . readFileSync ( filepath , 'utf8' ) , {
26
+ parserOpts : {
27
+ sourceType : 'module' ,
28
+ plugins : [
29
+ 'typescript' ,
30
+ // Language
31
+ 'jsx' ,
32
+ // Proposal
33
+ 'classProperties' ,
34
+ 'classPrivateProperties' ,
35
+ 'classPrivateMethods' ,
36
+ 'decorators-legacy' ,
37
+ 'dynamicImport' ,
38
+ 'exportDefaultFrom' ,
39
+ 'exportNamespaceFrom' ,
40
+ 'importMeta' ,
41
+ 'nullishCoalescingOperator' ,
42
+ 'numericSeparator' ,
43
+ 'objectRestSpread' ,
44
+ 'optionalCatchBinding' ,
45
+ 'optionalChaining' ,
46
+ 'topLevelAwait' ,
47
+ ] ,
48
+ } ,
49
+ } )
25
50
const stats = fs . statSync ( filepath )
51
+ const importSpecifiers : Array < { imported : string ; local : string ; source : string } > = [ ]
52
+
53
+ if ( ast ) {
54
+ babel . traverse ( ast , {
55
+ ImportDeclaration ( path ) {
56
+ for ( const specifier of path . node . specifiers ) {
57
+ if ( specifier . type === 'ImportSpecifier' ) {
58
+ importSpecifiers . push ( {
59
+ imported : specifier . imported . type === 'Identifier' ? specifier . imported . name : specifier . imported . value ,
60
+ local : specifier . local . name ,
61
+ source : path . node . source . value ,
62
+ } )
63
+ } else if ( specifier . type === 'ImportDefaultSpecifier' ) {
64
+ importSpecifiers . push ( {
65
+ imported : 'default' ,
66
+ local : specifier . local . name ,
67
+ source : path . node . source . value ,
68
+ } )
69
+ }
70
+ }
71
+ } ,
72
+ } )
73
+ }
74
+
26
75
return {
27
76
filepath,
28
77
size : stats . size ,
78
+ importSpecifiers,
29
79
}
30
80
} )
31
81
. sort ( ( a , b ) => {
32
82
return b . size - a . size
33
83
} )
34
84
35
- const migrated = matches . filter ( ( { filepath} ) => {
36
- const contents = fs . readFileSync ( filepath , 'utf8' )
37
- return ! hasStyledComponents ( contents )
85
+ const box = matches . filter ( ( { importSpecifiers} ) => {
86
+ return importSpecifiers . some ( specifier => {
87
+ return specifier . imported === 'Box' || specifier . local === 'Box'
88
+ } )
38
89
} )
90
+ const boxSize = box . reduce ( ( acc , { size} ) => acc + size , 0 )
39
91
40
- const notMigrated = matches . filter ( ( { filepath} ) => {
41
- const contents = fs . readFileSync ( filepath , 'utf8' )
42
- return hasStyledComponents ( contents )
92
+ const boxWithFallback = matches . filter ( ( { importSpecifiers} ) => {
93
+ return importSpecifiers . some ( specifier => {
94
+ return specifier . imported === 'BoxWithFallback' || specifier . local === 'BoxWithFallback'
95
+ } )
43
96
} )
97
+ const boxWithFallbackSize = boxWithFallback . reduce ( ( acc , { size} ) => acc + size , 0 )
98
+
99
+ const sx = matches . filter ( ( { importSpecifiers} ) => {
100
+ return importSpecifiers . some ( specifier => {
101
+ return (
102
+ specifier . imported === 'sx' ||
103
+ specifier . local === 'sx' ||
104
+ specifier . imported === 'SxProps' ||
105
+ specifier . local === 'SxProps'
106
+ )
107
+ } )
108
+ } )
109
+ const sxSize = sx . reduce ( ( acc , { size} ) => acc + size , 0 )
44
110
45
- let totalSize = 0
111
+ const styledComponents = matches . filter ( ( { importSpecifiers} ) => {
112
+ return importSpecifiers . some ( specifier => {
113
+ return specifier . source . includes ( 'styled-components' )
114
+ } )
115
+ } )
116
+ const styledComponentsSize = styledComponents . reduce ( ( acc , { size} ) => acc + size , 0 )
46
117
47
- for ( const { size} of matches ) {
48
- totalSize += size
49
- }
118
+ const styledSystem = matches . filter ( ( { importSpecifiers} ) => {
119
+ return importSpecifiers . some ( specifier => {
120
+ return specifier . source . includes ( 'styled-system' ) || specifier . source . includes ( '@styled-system' )
121
+ } )
122
+ } )
123
+ const styledSystemSize = styledSystem . reduce ( ( acc , { size} ) => acc + size , 0 )
50
124
125
+ const totalCount = matches . length
126
+ const totalSize = matches . reduce ( ( acc , { size} ) => acc + size , 0 )
127
+
128
+ const notMigrated = new Set ( [ ...box , ...boxWithFallback , ...sx , ...styledComponents , ...styledSystem ] . map ( match => match . filepath ) )
129
+ const migrated = new Set ( )
130
+ let notMigratedSize = 0
51
131
let migratedSize = 0
52
132
53
- for ( const { size} of migrated ) {
54
- migratedSize += size
133
+ for ( const match of matches ) {
134
+ if ( ! notMigrated . has ( match . filepath ) ) {
135
+ migrated . add ( match . filepath )
136
+ migratedSize += match . size
137
+ } else {
138
+ notMigratedSize += match . size
139
+ }
55
140
}
56
141
57
- console . log ( `
58
- # styled-components Migration
142
+ console . log ( `# styled-components Migration
59
143
60
144
This report tracks our status migrating files from styled-components to CSS Modules.
61
145
62
146
## Status
63
147
64
148
**Status by file count**
65
149
66
-  * 100 ) } )
150
+  * 100 ) } )
67
151
68
152
**Status by file size**
69
153
70
154
 * 100 ) } )
71
- ` )
72
155
73
- console . log ( `
74
- ## Not Migrated (${ notMigrated . length } )
156
+ ## Box
75
157
76
- | Filepath | Size (kB) |
77
- | :------- | :-------- |` )
158
+ **Status by file count**
78
159
79
- for ( const { filepath, size} of notMigrated ) {
80
- const relativePath = path . relative ( directory , filepath )
81
- const link = `[\`${ relativePath } \`](https://github.com/primer/react/blob/main/${ relativePath } )`
82
- console . log ( `| ${ link } | ${ round ( size / 1024 ) } kB |` )
83
- }
160
+  / totalCount ) * 100 ) } )
84
161
85
- console . log ( `## Migrated ( ${ migrated . length } )
162
+ **Status by file size**
86
163
87
- There are ${ migrated . length } files that do not include styled-components in Primer React.
164
+  / totalSize ) * 100 ) } )
88
165
89
166
<details>
90
- <summary>All files </summary>
167
+ <summary>Files </summary>
91
168
92
- | Filepath | Size (kB) |
93
- | :------- | :-------- |` )
169
+ ${ getTable ( box ) }
170
+ </details>
94
171
95
- for ( const { filepath, size} of migrated ) {
96
- const relativePath = path . relative ( directory , filepath )
97
- const link = `[\`${ relativePath } \`](https://github.com/primer/react/blob/main/${ relativePath } )`
98
- console . log ( `| ${ link } | ${ round ( size / 1024 ) } kB |` )
99
- }
172
+ ## BoxWithFallback
100
173
101
- console . log ( `\n</details>` )
174
+ **Status by file count**
102
175
103
- function round ( value : number ) : number {
104
- return Math . round ( ( value + Number . EPSILON ) * 100 ) / 100
105
- }
176
+  / totalCount ) * 100 ) } )
106
177
107
- function hasStyledComponents ( contents : string ) : boolean {
108
- if ( contents . match ( / s t y l e d - c o m p o n e n t s / ) ) {
109
- return true
110
- }
178
+ **Status by file size**
111
179
112
- if ( contents . match ( / S x P r o p / ) ) {
113
- return true
114
- }
180
+  / totalSize ) * 100 ) } )
115
181
116
- if ( contents . match ( / B o x / ) ) {
117
- return true
118
- }
182
+ <details>
183
+ <summary>Files</summary>
184
+
185
+ ${ getTable ( boxWithFallback ) }
186
+ </details>
187
+
188
+ ## sx
119
189
120
- if ( contents . match ( / B o x W i t h F a l l b a c k / ) ) {
121
- return true
190
+ **Status by file count**
191
+
192
+  / totalCount ) * 100 ) } )
193
+
194
+ **Status by file size**
195
+
196
+  / totalSize ) * 100 ) } )
197
+
198
+ <details>
199
+ <summary>Files</summary>
200
+
201
+ ${ getTable ( sx ) }
202
+ </details>
203
+
204
+ ## styled-components
205
+
206
+ **Status by file count**
207
+
208
+  / totalCount ) * 100 ) } )
209
+
210
+ **Status by file size**
211
+
212
+  / totalSize ) * 100 ) } )
213
+
214
+ <details>
215
+ <summary>Files</summary>
216
+
217
+ ${ getTable ( styledComponents ) }
218
+ </details>
219
+
220
+ ## styled-system
221
+
222
+ **Status by file count**
223
+
224
+  / totalCount ) * 100 ) } )
225
+
226
+ **Status by file size**
227
+
228
+  / totalSize ) * 100 ) } )
229
+
230
+ <details>
231
+ <summary>Files</summary>
232
+
233
+ ${ getTable ( styledSystem ) }
234
+ </details>
235
+ ` )
236
+
237
+ function getTable ( collection : Array < { filepath : string ; size : number } > ) : string {
238
+ const rows = collection . sort ( ( a , b ) => b . size - a . size )
239
+ let output = ''
240
+
241
+ output += '| Filepath | Size (kB) |\n'
242
+ output += '| :------- | :-------- |\n'
243
+
244
+ for ( const { filepath, size} of rows ) {
245
+ const relativePath = path . relative ( directory , filepath )
246
+ const link = `[\`${ relativePath } \`](https://github.com/primer/react/blob/main/${ relativePath } )`
247
+ output += `| ${ link } | ${ round ( size / 1024 ) } kB |\n`
122
248
}
123
249
124
- return false
250
+ return output
251
+ }
252
+
253
+ function round ( value : number ) : number {
254
+ return Math . round ( ( value + Number . EPSILON ) * 100 ) / 100
125
255
}
0 commit comments