@@ -15,6 +15,10 @@ import * as fs from 'node:fs/promises';
15
15
import { AsyncLocalStorage } from 'node:async_hooks' ;
16
16
17
17
18
+ //
19
+ // Setup
20
+ //
21
+
18
22
type Logger = Pick < Console , 'info' | 'error' | 'log' > ;
19
23
type Services = { logger : Logger } ;
20
24
const servicesStorage = new AsyncLocalStorage < Services > ( ) ;
@@ -26,13 +30,28 @@ const getServices = () => {
26
30
27
31
type ScriptArgs = {
28
32
values : {
29
- help ?: undefined | boolean ,
30
- silent ?: undefined | boolean ,
33
+ 'help' ?: undefined | boolean ,
34
+ 'silent' ?: undefined | boolean ,
35
+ 'dry-run' ?: undefined | boolean ,
31
36
} ,
32
37
positionals : Array < string > ,
33
38
} ;
34
39
35
40
41
+ //
42
+ // Common
43
+ //
44
+
45
+ // Return a relative path to the given absolute path, relative to the current CWD
46
+ const rel = ( absolutePath : string ) : string => {
47
+ return path . relative ( process . cwd ( ) , absolutePath ) ;
48
+ } ;
49
+
50
+
51
+ //
52
+ // Commands
53
+ //
54
+
36
55
/*
37
56
Takes CSS variables of the form `--<var-name>: <expr>;` (as exported from Figma) and converts it to Sass variables. We
38
57
expect the same variable to be in the input exactly twice, the first is assumed to be the light mode variant, the
@@ -101,9 +120,9 @@ const runParseTokens = async (args: ScriptArgs) => {
101
120
const runCreateIconsManifest = async ( args : ScriptArgs ) => {
102
121
const { logger } = getServices ( ) ;
103
122
104
- const pathIcons = path . join ( process . cwd ( ) , './src/assets/icons' ) ;
123
+ const pathIconsSource = path . join ( process . cwd ( ) , './src/assets/icons' ) ;
105
124
106
- const files = await fs . readdir ( pathIcons ) ;
125
+ const files = await fs . readdir ( pathIconsSource ) ;
107
126
const icons = [ ] ;
108
127
for ( const fileName of files ) {
109
128
const iconName = fileName . replace ( / \. s v g $ / , '' ) ;
@@ -117,67 +136,106 @@ const runCreateIconsManifest = async (args: ScriptArgs) => {
117
136
} as const satisfies Record<string, IconDef>;
118
137
` ;
119
138
120
- const manifestPath = path . join ( pathIcons , '_icons.ts' ) ;
121
- logger . info ( `Writing file: ${ manifestPath } ` )
139
+ const manifestPath = path . join ( pathIconsSource , '_icons.ts' ) ;
140
+ logger . info ( `Writing file: ${ manifestPath } ` ) ;
122
141
await fs . writeFile ( manifestPath , manifest , { encoding : 'utf-8' } ) ;
123
142
} ;
124
143
125
144
const runImportIcons = async ( args : ScriptArgs ) => {
126
145
const { logger } = getServices ( ) ;
127
146
147
+ const isDryRun = args . values [ 'dry-run' ] ?? false ;
148
+
128
149
const kebabCase = ( string : string ) => string
129
150
. replace ( / ( [ a - z ] ) ( [ A - Z ] ) / g, "$1-$2" )
130
151
. replace ( / [ \s _ ] + / g, '-' )
131
152
. toLowerCase ( ) ;
132
153
133
- const remove : Array < string > = [
134
- // Remove other company/project icons
135
- 'apache' ,
154
+ const skippedIcons : Array < string > = [
155
+ 'apache' , // Skip other company/project icons
156
+ 'ai-guardrails' , // Same as "send"?
157
+ 'complete' , // Same as "success"?
158
+ 'table-settings' , // Same as "edit-params"?
136
159
] ;
137
- const rename : Record < string , string > = {
160
+ const renamedIcons : Record < string , string > = {
138
161
'ki' : 'fortanix-ki' ,
139
- 'security-objects' : 'security-object' ,
140
- 'carrot-down' : 'caret-down' , // Typo
141
- 'page-fwd' : 'page-forward' ,
162
+ 'security-objects' : 'security-object' , // Should be singular
163
+ 'users' : 'user' , // Should be singular
164
+ 'apps' : 'app' , // Should be singular
165
+ 'groups' : 'group' , // Should be singular
166
+ 'workflows' : 'workflow' , // Should be singular
167
+ 'integrations' : 'integration' , // Should be singular
168
+ 'scripts' : 'script' , // Should be singular
169
+ 'plugins' : 'plugin' , // Should be singular
170
+ 'page-fwd' : 'page-forward' , // Do not abbreviate
142
171
'user-account' : 'user-profile' , // "User account" is a misleading term considering our information architecture
143
- 'users' : 'user' ,
144
- // NOTE: missing `account` icon
172
+ 'alert-01' : 'bell' ,
173
+ 'alert-02' : 'warning' ,
174
+ 'assessment' : 'badge-assessment' , // Depicts a security badge specifically
175
+ 'gen-ai' : 'badge-dashboard' , // Does not specifically depict anything to do with GenAI
176
+ 'authentication' : 'user-authentication' , // Depicts a user specifically (as opposed to e.g. app automation)
177
+ 'cancel' : 'status-cancelled' , // Visually related
178
+ 'success' : 'status-success' , // Visually related
179
+ 'failed' : 'status-failed' , // Visually related
180
+ 'ellipsis' : 'ellipsis-vertical' ,
181
+ 'filter' : 'filter-closed' , // Make consistent with `filter-open`
182
+ 'eye' : 'eye-open' , // Visually related
183
+ 'hide' : 'eye-closed' , // Visually related
184
+ 'infrastructure' : 'compute-node' ,
185
+ 'log-out' : 'logout' , // Make consistent with `login`
186
+ 'new-tab' : 'link-external' ,
187
+ 'new-query' : 'conversation-new' , // Note: 'query' is already used for a different concept/icon
145
188
} ;
146
189
147
- const pathIcons = path . join ( process . cwd ( ) , './src/assets/icons_new ' ) ;
148
- const pathIconsOut = path . join ( process . cwd ( ) , './src/assets/icons' ) ;
190
+ const pathIconsSource = path . join ( process . cwd ( ) , './src/assets/icons_source ' ) ;
191
+ const pathIconsTarget = path . join ( process . cwd ( ) , './src/assets/icons' ) ;
149
192
150
193
// Delete existing icons
151
- for ( const file of await fs . readdir ( pathIconsOut ) ) {
152
- await fs . unlink ( path . join ( pathIconsOut , file ) ) ;
194
+ logger . log ( `Deleting existing icons in ${ rel ( pathIconsTarget ) } ` ) ;
195
+ if ( ! isDryRun ) {
196
+ for ( const fileName of await fs . readdir ( pathIconsTarget ) ) {
197
+ await fs . unlink ( path . join ( pathIconsTarget , fileName ) ) ;
198
+ }
153
199
}
154
200
155
- const files = await fs . readdir ( pathIcons ) ;
201
+ const files = await fs . readdir ( pathIconsSource ) ;
156
202
for ( const fileName of files ) {
203
+ if ( ! fileName . includes ( '.svg' ) ) { continue ; }
204
+
157
205
const fileNameKebab = kebabCase ( fileName . replace ( / \. s v g $ / , '' ) ) ;
158
206
const iconName = ( ( ) : string => {
159
- if ( Object . hasOwn ( rename , fileNameKebab ) && rename [ fileNameKebab ] ) {
160
- return rename [ fileNameKebab ] ;
207
+ if ( Object . hasOwn ( renamedIcons , fileNameKebab ) && renamedIcons [ fileNameKebab ] ) {
208
+ return renamedIcons [ fileNameKebab ] ;
161
209
} else {
162
210
return fileNameKebab ;
163
211
}
164
212
} ) ( ) ;
165
213
166
- if ( iconName in remove ) {
214
+ if ( skippedIcons . includes ( iconName ) ) {
215
+ logger . log ( `Skipping icon: ${ iconName } ` ) ;
167
216
continue ;
168
217
}
169
218
170
- const pathSource = path . join ( pathIcons , fileName ) ;
171
- const pathTarget = path . join ( pathIconsOut , `${ iconName } .svg` )
172
- logger . log ( `Copying '${ pathSource } ' to '${ pathTarget } '` ) ;
173
- await fs . copyFile ( pathSource , pathTarget ) ;
219
+ const pathSource = path . join ( pathIconsSource , fileName ) ;
220
+ const pathTarget = path . join ( pathIconsTarget , `${ iconName } .svg` )
221
+ logger . log ( `Copying '${ rel ( pathSource ) } ' to '${ rel ( pathTarget ) } '` ) ;
222
+ if ( ! isDryRun ) {
223
+ await fs . copyFile ( pathSource , pathTarget ) ;
224
+ }
174
225
}
175
226
176
227
// Create `_icons.ts` manifest file
177
- await runCreateIconsManifest ( args ) ;
228
+ logger . log ( `Creating '_icons.ts' manifest file.` ) ;
229
+ if ( ! isDryRun ) {
230
+ await runCreateIconsManifest ( args ) ;
231
+ }
178
232
} ;
179
233
180
234
235
+ //
236
+ // Run
237
+ //
238
+
181
239
const printUsage = ( ) => {
182
240
const { logger } = getServices ( ) ;
183
241
@@ -197,8 +255,9 @@ export const run = async (argsRaw: Array<string>): Promise<void> => {
197
255
args : argsRaw ,
198
256
allowPositionals : true ,
199
257
options : {
200
- help : { type : 'boolean' , short : 'h' } ,
201
- silent : { type : 'boolean' } ,
258
+ 'help' : { type : 'boolean' , short : 'h' } ,
259
+ 'silent' : { type : 'boolean' } ,
260
+ 'dry-run' : { type : 'boolean' } ,
202
261
} ,
203
262
} ) ;
204
263
0 commit comments