@@ -15,63 +15,68 @@ export const enum Platform {
15
15
16
16
export const PLATFORMS : ReadonlyArray < Platform > = [ Platform . ANDROID , Platform . IOS ] ;
17
17
18
- export interface ResourceTypeRunOptions {
18
+ export type Sources = ( string | Source ) [ ] ;
19
+
20
+ export interface GeneratedResource extends ResourceKeyValues {
21
+ type : ResourceType ;
22
+ srckey : ResourceKey ;
23
+ platform : Platform ;
24
+ nodeName : string ;
25
+ nodeAttributes : ReadonlyArray < ResourceKey > ;
26
+ }
27
+
28
+ export interface SimpleResourceOptions {
19
29
sources : string [ ] ;
20
30
}
21
31
22
- export interface AndroidAdaptiveIconsRunOptions {
32
+ export interface SimpleResourceResult {
33
+ resources : GeneratedResource [ ] ;
34
+ source : ResolvedSource ;
35
+ }
36
+
37
+ export interface AdaptiveIconResourceOptions {
23
38
foreground : {
24
- sources : ( string | Source ) [ ] ;
39
+ sources : Sources ;
25
40
} ;
26
41
background : {
27
- sources : ( string | Source ) [ ] ;
42
+ sources : Sources ;
28
43
} ;
29
44
}
30
45
31
46
export interface RunPlatformOptions {
32
- [ ResourceType . ADAPTIVE_ICON ] ?: AndroidAdaptiveIconsRunOptions ;
33
- [ ResourceType . ICON ] ?: ResourceTypeRunOptions ;
34
- [ ResourceType . SPLASH ] ?: ResourceTypeRunOptions ;
35
- }
36
-
37
- export interface GeneratedResource extends ResourceKeyValues {
38
- type : ResourceType ;
39
- srckey : ResourceKey ;
40
- platform : Platform ;
41
- nodeName : string ;
42
- nodeAttributes : ReadonlyArray < ResourceKey > ;
47
+ [ ResourceType . ADAPTIVE_ICON ] ?: AdaptiveIconResourceOptions ;
48
+ [ ResourceType . ICON ] ?: SimpleResourceOptions ;
49
+ [ ResourceType . SPLASH ] ?: SimpleResourceOptions ;
43
50
}
44
51
45
52
export interface RunPlatformResult {
46
53
resources : GeneratedResource [ ] ;
47
54
sources : ResolvedSource [ ] ;
48
55
}
49
56
50
- export interface RunTypeResult {
51
- resources : GeneratedResource [ ] ;
52
- source : ResolvedSource ;
53
- }
54
-
57
+ /**
58
+ * Run resource generation for the given platform.
59
+ */
55
60
export async function run ( platform : Platform , resourcesDirectory : string , options : Readonly < RunPlatformOptions > , errstream ?: NodeJS . WritableStream ) : Promise < RunPlatformResult > {
56
61
debug ( 'Running %s platform with options: %O' , platform , options ) ;
57
62
58
63
const resources : GeneratedResource [ ] = [ ] ;
59
64
const sources : ResolvedSource [ ] = [ ] ;
60
- const adaptiveResult = await runAdaptive ( platform , resourcesDirectory , options [ ResourceType . ADAPTIVE_ICON ] , errstream ) ;
65
+ const adaptiveResult = await safelyGenerateAdaptiveIconResources ( platform , resourcesDirectory , options [ ResourceType . ADAPTIVE_ICON ] , errstream ) ;
61
66
62
67
if ( adaptiveResult && adaptiveResult . resources . length > 0 ) {
63
68
resources . push ( ...adaptiveResult . resources ) ;
64
69
sources . push ( ...adaptiveResult . sources ) ;
65
70
} else {
66
- const iconResult = await runType ( ResourceType . ICON , platform , resourcesDirectory , options [ ResourceType . ICON ] , errstream ) ;
71
+ const iconResult = await generateSimpleResources ( ResourceType . ICON , platform , resourcesDirectory , options [ ResourceType . ICON ] , errstream ) ;
67
72
68
73
if ( iconResult ) {
69
74
resources . push ( ...iconResult . resources ) ;
70
75
sources . push ( iconResult . source ) ;
71
76
}
72
77
}
73
78
74
- const splashResult = await runType ( ResourceType . SPLASH , platform , resourcesDirectory , options [ ResourceType . SPLASH ] , errstream ) ;
79
+ const splashResult = await generateSimpleResources ( ResourceType . SPLASH , platform , resourcesDirectory , options [ ResourceType . SPLASH ] , errstream ) ;
75
80
76
81
if ( splashResult ) {
77
82
resources . push ( ...splashResult . resources ) ;
@@ -84,23 +89,16 @@ export async function run(platform: Platform, resourcesDirectory: string, option
84
89
} ;
85
90
}
86
91
87
- export async function runAdaptive ( platform : Platform , resourcesDirectory : string , options ?: Readonly < AndroidAdaptiveIconsRunOptions > , errstream ?: NodeJS . WritableStream ) : Promise < RunPlatformResult | undefined > {
88
- if ( platform !== Platform . ANDROID || ! options ) {
89
- return ;
90
- }
91
-
92
- try {
93
- return await runAdaptiveType ( platform , resourcesDirectory , options , errstream ) ;
94
- } catch ( e ) {
95
- debug ( 'Error with adaptive icons: %O' , e ) ;
96
-
97
- if ( ! ( e instanceof ResolveSourceImageError ) ) {
98
- throw e ;
99
- }
100
- }
101
- }
102
-
103
- export async function runType ( type : ResourceType . ICON | ResourceType . SPLASH , platform : Platform , resourcesDirectory : string , options ?: Readonly < ResourceTypeRunOptions > , errstream ?: NodeJS . WritableStream ) : Promise < RunTypeResult | undefined > {
92
+ /**
93
+ * Generate simple icons or splash screens.
94
+ *
95
+ * Icon and Splash Screen generation is "simple" because there's one source
96
+ * image type and one set of resources to generate.
97
+ *
98
+ * If there are no options given for this resource, this function resolves
99
+ * with `undefined`.
100
+ */
101
+ export async function generateSimpleResources ( type : ResourceType . ICON | ResourceType . SPLASH , platform : Platform , resourcesDirectory : string , options ?: Readonly < SimpleResourceOptions > , errstream ?: NodeJS . WritableStream ) : Promise < SimpleResourceResult | undefined > {
104
102
if ( ! options ) {
105
103
return ;
106
104
}
@@ -112,19 +110,45 @@ export async function runType(type: ResourceType.ICON | ResourceType.SPLASH, pla
112
110
debug ( 'Using %O for %s source image for %s' , source . image . src , type , platform ) ;
113
111
114
112
const config = getResourcesConfig ( platform , type ) ;
115
- const resources = await Promise . all ( config . resources . map ( async resource => ( { ...resource , ...await generateImageResource ( type , platform , resourcesDirectory , config , source . image , resource , ResourceKey . SRC , errstream ) } ) ) ) ;
113
+ const resources = await Promise . all ( config . resources . map (
114
+ async ( resource ) : Promise < GeneratedResource > => ( {
115
+ ...resource ,
116
+ ...await generateImageResource ( type , platform , resourcesDirectory , config , source . image , resource , ResourceKey . SRC , errstream ) ,
117
+ } )
118
+ ) ) ;
116
119
117
120
return {
118
121
resources,
119
122
source,
120
123
} ;
121
124
}
122
125
123
- export async function runAdaptiveType ( platform : Platform , resourcesDirectory : string , options : Readonly < AndroidAdaptiveIconsRunOptions > , errstream ?: NodeJS . WritableStream ) : Promise < RunPlatformResult > {
124
- if ( platform !== Platform . ANDROID ) {
125
- throw new BadInputError ( `Adaptive icons can only be generated for "${ Platform . ANDROID } " platform (not "${ platform } ")` ) ;
126
+ /**
127
+ * Attempt to generate Adaptive Icons for any platform.
128
+ *
129
+ * If there are no options given for this resource or if the platform or
130
+ * source images are not suitable, this function resolves with `undefined`.
131
+ */
132
+ export async function safelyGenerateAdaptiveIconResources ( platform : Platform , resourcesDirectory : string , options ?: Readonly < AdaptiveIconResourceOptions > , errstream ?: NodeJS . WritableStream ) : Promise < RunPlatformResult | undefined > {
133
+ if ( platform !== Platform . ANDROID || ! options ) {
134
+ return ;
126
135
}
127
136
137
+ try {
138
+ return await generateAdaptiveIconResources ( resourcesDirectory , options , errstream ) ;
139
+ } catch ( e ) {
140
+ debug ( 'Error with adaptive icons: %O' , e ) ;
141
+
142
+ if ( ! ( e instanceof ResolveSourceImageError ) ) {
143
+ throw e ;
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Generate Android Adaptive Icons.
150
+ */
151
+ export async function generateAdaptiveIconResources ( resourcesDirectory : string , options : Readonly < AdaptiveIconResourceOptions > , errstream ?: NodeJS . WritableStream ) : Promise < RunPlatformResult > {
128
152
if ( options . foreground . sources . length === 0 || options . background . sources . length === 0 ) {
129
153
throw new BadInputError ( 'Adaptive icons require sources for both foreground and background.' ) ;
130
154
}
@@ -137,9 +161,9 @@ export async function runAdaptiveType(platform: Platform, resourcesDirectory: st
137
161
throw new BadInputError ( 'Adaptive icon foreground source must be an image.' ) ;
138
162
}
139
163
140
- debug ( 'Building %s resources for %s platform ' , ResourceType . ADAPTIVE_ICON , platform ) ;
164
+ debug ( 'Building %s resources' , ResourceType . ADAPTIVE_ICON ) ;
141
165
142
- const { resources : foregroundResources , source : foregroundSource } = await runAdaptiveSource ( resourcesDirectory , foregroundSources , ResourceKey . FOREGROUND , errstream ) ;
166
+ const { resources : foregroundResources , source : foregroundSource } = await generateAdaptiveIconType ( resourcesDirectory , foregroundSources , ResourceKey . FOREGROUND , errstream ) ;
143
167
const resolvedBackgroundSource = await resolveSource ( ResourceType . ADAPTIVE_ICON , ResourceKey . BACKGROUND , options . background . sources , errstream ) ;
144
168
const config = getResourcesConfig ( Platform . ANDROID , ResourceType . ADAPTIVE_ICON ) ;
145
169
@@ -163,31 +187,10 @@ export async function runAdaptiveType(platform: Platform, resourcesDirectory: st
163
187
} ;
164
188
}
165
189
166
- export async function resolveSource ( type : ResourceType , name : string , sources : ( string | Source ) [ ] , errstream ?: NodeJS . WritableStream ) : Promise < ResolvedSource > {
167
- for ( const source of sources ) {
168
- if ( typeof source === 'string' || source . type === SourceType . RASTER ) {
169
- const src = typeof source === 'string' ? source : source . src ;
170
-
171
- try {
172
- return await readSourceImage ( type , src ) ;
173
- } catch ( e ) {
174
- debugSourceImage ( src , e , errstream ) ;
175
- }
176
- } else if ( source . type === SourceType . COLOR ) {
177
- const color = source . color . toUpperCase ( ) ;
178
-
179
- if ( ! color . match ( COLOR_REGEX ) ) {
180
- throw new BadInputError ( `Color ${ color } does not match regex ${ COLOR_REGEX } .` ) ;
181
- }
182
-
183
- return { type : SourceType . COLOR , name, color } ;
184
- }
185
- }
186
-
187
- throw new BadInputError ( `Missing source for "${ type } " (sources: ${ sources . join ( ', ' ) } )` ) ;
188
- }
189
-
190
- export async function runAdaptiveSource ( resourcesDirectory : string , sources : string [ ] , type : ResourceKey . FOREGROUND | ResourceKey . BACKGROUND , errstream ?: NodeJS . WritableStream ) : Promise < RunTypeResult > {
190
+ /**
191
+ * Generate the foreground or background portion of Adaptive Icons.
192
+ */
193
+ export async function generateAdaptiveIconType ( resourcesDirectory : string , sources : string [ ] , type : ResourceKey . FOREGROUND | ResourceKey . BACKGROUND , errstream ?: NodeJS . WritableStream ) : Promise < SimpleResourceResult > {
191
194
const source = await resolveSourceImage ( ResourceType . ADAPTIVE_ICON , sources , errstream ) ;
192
195
193
196
debug ( 'Using %O for %s source image for %s' , source . image . src , ResourceType . ADAPTIVE_ICON , Platform . ANDROID ) ;
@@ -235,6 +238,30 @@ export async function generateImageResource(type: ResourceType, platform: Platfo
235
238
} ;
236
239
}
237
240
241
+ export async function resolveSource ( type : ResourceType , name : string , sources : Sources , errstream ?: NodeJS . WritableStream ) : Promise < ResolvedSource > {
242
+ for ( const source of sources ) {
243
+ if ( typeof source === 'string' || source . type === SourceType . RASTER ) {
244
+ const src = typeof source === 'string' ? source : source . src ;
245
+
246
+ try {
247
+ return await readSourceImage ( type , src ) ;
248
+ } catch ( e ) {
249
+ debugSourceImage ( src , e , errstream ) ;
250
+ }
251
+ } else if ( source . type === SourceType . COLOR ) {
252
+ const color = source . color . toUpperCase ( ) ;
253
+
254
+ if ( ! color . match ( COLOR_REGEX ) ) {
255
+ throw new BadInputError ( `Color ${ color } does not match regex ${ COLOR_REGEX } .` ) ;
256
+ }
257
+
258
+ return { type : SourceType . COLOR , name, color } ;
259
+ }
260
+ }
261
+
262
+ throw new BadInputError ( `Missing source for "${ type } " (sources: ${ sources . join ( ', ' ) } )` ) ;
263
+ }
264
+
238
265
export function validatePlatforms ( platforms : ReadonlyArray < string > ) : Platform [ ] {
239
266
const result : Platform [ ] = [ ] ;
240
267
0 commit comments