Skip to content

Commit e07036b

Browse files
joshblackCopilot
andauthored
ci(migration-status): update styled-components migration status report (#6605)
Co-authored-by: Copilot <[email protected]>
1 parent fd4ac72 commit e07036b

File tree

2 files changed

+185
-56
lines changed

2 files changed

+185
-56
lines changed

package-lock.json

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 184 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import path from 'node:path'
22
import fs from 'node:fs'
3+
import babel from '@babel/core'
34
import glob from 'fast-glob'
45

56
const directory = path.resolve(import.meta.dirname, '..')
@@ -15,111 +16,240 @@ const matches = glob
1516
'**/lib-esm/**',
1617
'**/storybook-static/**',
1718
'**/.next/**',
18-
'**/*.test.{ts,tsx}',
19-
'**/*.types.test.{ts,tsx}',
2019
'**/*.module.css.d.ts',
20+
'**/*.figma.tsx',
2121
],
2222
})
2323
.map(match => {
2424
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+
})
2550
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+
2675
return {
2776
filepath,
2877
size: stats.size,
78+
importSpecifiers,
2979
}
3080
})
3181
.sort((a, b) => {
3282
return b.size - a.size
3383
})
3484

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+
})
3889
})
90+
const boxSize = box.reduce((acc, {size}) => acc + size, 0)
3991

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+
})
4396
})
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)
44110

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)
46117

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)
50124

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
51131
let migratedSize = 0
52132

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+
}
55140
}
56141

57-
console.log(`
58-
# styled-components Migration
142+
console.log(`# styled-components Migration
59143
60144
This report tracks our status migrating files from styled-components to CSS Modules.
61145
62146
## Status
63147
64148
**Status by file count**
65149
66-
![Status by file count](https://geps.dev/progress/${Math.floor((migrated.length / matches.length) * 100)})
150+
![Status by file count](https://geps.dev/progress/${Math.floor((migrated.size / totalCount) * 100)})
67151
68152
**Status by file size**
69153
70154
![Status by file size](https://geps.dev/progress/${Math.floor((migratedSize / totalSize) * 100)})
71-
`)
72155
73-
console.log(`
74-
## Not Migrated (${notMigrated.length})
156+
## Box
75157
76-
| Filepath | Size (kB) |
77-
| :------- | :-------- |`)
158+
**Status by file count**
78159
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+
![Status by file count](https://geps.dev/progress/${Math.floor(((totalCount - box.length) / totalCount) * 100)})
84161
85-
console.log(`## Migrated (${migrated.length})
162+
**Status by file size**
86163
87-
There are ${migrated.length} files that do not include styled-components in Primer React.
164+
![Status by file size](https://geps.dev/progress/${Math.floor(((totalSize - boxSize) / totalSize) * 100)})
88165
89166
<details>
90-
<summary>All files</summary>
167+
<summary>Files</summary>
91168
92-
| Filepath | Size (kB) |
93-
| :------- | :-------- |`)
169+
${getTable(box)}
170+
</details>
94171
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
100173
101-
console.log(`\n</details>`)
174+
**Status by file count**
102175
103-
function round(value: number): number {
104-
return Math.round((value + Number.EPSILON) * 100) / 100
105-
}
176+
![Status by file count](https://geps.dev/progress/${Math.floor(((totalCount - boxWithFallback.length) / totalCount) * 100)})
106177
107-
function hasStyledComponents(contents: string): boolean {
108-
if (contents.match(/styled-components/)) {
109-
return true
110-
}
178+
**Status by file size**
111179
112-
if (contents.match(/SxProp/)) {
113-
return true
114-
}
180+
![Status by file size](https://geps.dev/progress/${Math.floor(((totalSize - boxWithFallbackSize) / totalSize) * 100)})
115181
116-
if (contents.match(/Box/)) {
117-
return true
118-
}
182+
<details>
183+
<summary>Files</summary>
184+
185+
${getTable(boxWithFallback)}
186+
</details>
187+
188+
## sx
119189
120-
if (contents.match(/BoxWithFallback/)) {
121-
return true
190+
**Status by file count**
191+
192+
![Status by file count](https://geps.dev/progress/${Math.floor(((totalCount - sx.length) / totalCount) * 100)})
193+
194+
**Status by file size**
195+
196+
![Status by file size](https://geps.dev/progress/${Math.floor(((totalSize - sxSize) / 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+
![Status by file count](https://geps.dev/progress/${Math.floor(((totalCount - styledComponents.length) / totalCount) * 100)})
209+
210+
**Status by file size**
211+
212+
![Status by file size](https://geps.dev/progress/${Math.floor(((totalSize - styledComponentsSize) / 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+
![Status by file count](https://geps.dev/progress/${Math.floor(((totalCount - styledSystem.length) / totalCount) * 100)})
225+
226+
**Status by file size**
227+
228+
![Status by file size](https://geps.dev/progress/${Math.floor(((totalSize - styledSystemSize) / 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`
122248
}
123249

124-
return false
250+
return output
251+
}
252+
253+
function round(value: number): number {
254+
return Math.round((value + Number.EPSILON) * 100) / 100
125255
}

0 commit comments

Comments
 (0)