@@ -98,17 +98,43 @@ export class Merger {
98
98
}
99
99
}
100
100
101
+ private loadManifestJs ( ) : any {
102
+ trace . debug ( "merger.manifestJs" ) ;
103
+
104
+ // build environment object from --env parameter
105
+ const env = { } ;
106
+ ( this . settings . env || [ ] ) . forEach ( kvp => {
107
+ const [ key , ...value ] = kvp . split ( '=' ) ;
108
+ env [ key ] = value . join ( '=' ) ;
109
+ } ) ;
110
+
111
+ const fullJsFile = path . resolve ( this . settings . manifestJs ) ;
112
+ const manifestModuleFn = require ( fullJsFile ) ;
113
+ if ( ! manifestModuleFn || typeof manifestModuleFn != "function" ) {
114
+ throw new Error ( `Missing export function from manifest-js file ${ fullJsFile } ` )
115
+ }
116
+ const manifestData = manifestModuleFn ( env ) ;
117
+ if ( ! manifestData ) {
118
+ throw new Error ( `The export function from manifest-js file ${ fullJsFile } must return the manifest object` )
119
+ }
120
+ return manifestData ;
121
+ }
122
+
101
123
/**
102
124
* Finds all manifests and merges them into two JS Objects: vsoManifest and vsixManifest
103
125
* @return Q.Promise<SplitManifest> An object containing the two manifests
104
126
*/
105
- public merge ( ) : Promise < VsixComponents > {
127
+ public async merge ( ) : Promise < VsixComponents > {
106
128
trace . debug ( "merger.merge" ) ;
107
129
108
- return this . gatherManifests ( ) . then ( files => {
109
- let overridesProvided = false ;
110
- const manifestPromises : Promise < any > [ ] = [ ] ;
111
- files . forEach ( file => {
130
+ const manifestPromises : Promise < any > [ ] = [ ] ;
131
+ let overridesProvided = false ;
132
+
133
+ if ( this . settings . manifestJs ) {
134
+ manifestPromises . push ( Promise . resolve ( this . loadManifestJs ( ) ) ) ;
135
+ } else {
136
+ let manifestFiles = await this . gatherManifests ( ) ;
137
+ manifestFiles . forEach ( file => {
112
138
manifestPromises . push (
113
139
promisify ( readFile ) ( file , "utf8" ) . then ( data => {
114
140
const jsonData = data . replace ( / ^ \uFEFF / , "" ) ;
@@ -129,141 +155,141 @@ export class Merger {
129
155
if ( this . settings . overrides ) {
130
156
overridesProvided = true ;
131
157
manifestPromises . push ( Promise . resolve ( this . settings . overrides ) ) ;
132
- }
158
+ }
159
+ }
133
160
134
- return Promise . all ( manifestPromises ) . then ( partials => {
135
- // Determine the targets so we can construct the builders
136
- let targets : TargetDeclaration [ ] = [ ] ;
137
- partials . forEach ( partial => {
138
- if ( _ . isArray ( partial [ "targets" ] ) ) {
139
- targets = targets . concat ( partial [ "targets" ] ) ;
140
- }
141
- } ) ;
142
- this . extensionComposer = ComposerFactory . GetComposer ( this . settings , targets ) ;
143
- this . manifestBuilders = this . extensionComposer . getBuilders ( ) ;
144
- let updateVersionPromise = Promise . resolve < void > ( null ) ;
145
- partials . forEach ( ( partial , partialIndex ) => {
146
- // Rev the version if necessary
147
- if ( this . settings . revVersion ) {
148
- if ( partial [ "version" ] && partial . __origin ) {
149
- try {
150
- const parsedVersion = version . DynamicVersion . parse ( partial [ "version" ] ) ;
151
- const newVersion = version . DynamicVersion . increase ( parsedVersion ) ;
152
- const newVersionString = newVersion . toString ( ) ;
153
- partial [ "version" ] = newVersionString ;
154
-
155
- updateVersionPromise = promisify ( readFile ) ( partial . __origin , "utf8" ) . then ( versionPartial => {
156
- try {
157
- let newPartial : any ;
158
- if ( this . settings . json5 ) {
159
- const parsed = jju . parse ( versionPartial ) ;
160
- parsed [ "version" ] = newVersionString ;
161
- newPartial = jju . update ( versionPartial , parsed ) ;
162
- } else {
163
- newPartial = jsonInPlace ( versionPartial ) . set ( "version" , newVersionString ) ;
164
- }
165
- return promisify ( writeFile ) ( partial . __origin , newPartial ) ;
166
- } catch ( e ) {
167
- trace . warn (
168
- "Failed to lex partial as JSON to update the version. Skipping version rev..." ,
169
- ) ;
161
+ return Promise . all ( manifestPromises ) . then ( partials => {
162
+ // Determine the targets so we can construct the builders
163
+ let targets : TargetDeclaration [ ] = [ ] ;
164
+ partials . forEach ( partial => {
165
+ if ( _ . isArray ( partial [ "targets" ] ) ) {
166
+ targets = targets . concat ( partial [ "targets" ] ) ;
167
+ }
168
+ } ) ;
169
+ this . extensionComposer = ComposerFactory . GetComposer ( this . settings , targets ) ;
170
+ this . manifestBuilders = this . extensionComposer . getBuilders ( ) ;
171
+ let updateVersionPromise = Promise . resolve < void > ( null ) ;
172
+ partials . forEach ( ( partial , partialIndex ) => {
173
+ // Rev the version if necessary
174
+ if ( this . settings . revVersion ) {
175
+ if ( partial [ "version" ] && partial . __origin ) {
176
+ try {
177
+ const parsedVersion = version . DynamicVersion . parse ( partial [ "version" ] ) ;
178
+ const newVersion = version . DynamicVersion . increase ( parsedVersion ) ;
179
+ const newVersionString = newVersion . toString ( ) ;
180
+ partial [ "version" ] = newVersionString ;
181
+
182
+ updateVersionPromise = promisify ( readFile ) ( partial . __origin , "utf8" ) . then ( versionPartial => {
183
+ try {
184
+ let newPartial : any ;
185
+ if ( this . settings . json5 ) {
186
+ const parsed = jju . parse ( versionPartial ) ;
187
+ parsed [ "version" ] = newVersionString ;
188
+ newPartial = jju . update ( versionPartial , parsed ) ;
189
+ } else {
190
+ newPartial = jsonInPlace ( versionPartial ) . set ( "version" , newVersionString ) ;
170
191
}
171
- } ) ;
172
- } catch ( e ) {
173
- trace . warn (
174
- "Could not parse %s as a version (e.g. major.minor.patch). Skipping version rev..." ,
175
- partial [ "version" ] ,
176
- ) ;
177
- }
192
+ return promisify ( writeFile ) ( partial . __origin , newPartial ) ;
193
+ } catch ( e ) {
194
+ trace . warn (
195
+ "Failed to lex partial as JSON to update the version. Skipping version rev..." ,
196
+ ) ;
197
+ }
198
+ } ) ;
199
+ } catch ( e ) {
200
+ trace . warn (
201
+ "Could not parse %s as a version (e.g. major.minor.patch). Skipping version rev..." ,
202
+ partial [ "version" ] ,
203
+ ) ;
178
204
}
179
205
}
206
+ }
180
207
181
- // Transform asset paths to be relative to the root of all manifests, verify assets
182
- if ( _ . isArray ( partial [ "files" ] ) ) {
183
- ( < Array < FileDeclaration > > partial [ "files" ] ) . forEach ( asset => {
184
- const keys = Object . keys ( asset ) ;
185
- if ( keys . indexOf ( "path" ) < 0 ) {
186
- throw new Error ( "Files must have an absolute or relative (to the manifest) path." ) ;
187
- }
188
- let absolutePath ;
189
- if ( path . isAbsolute ( asset . path ) ) {
190
- absolutePath = asset . path ;
191
- } else {
192
- absolutePath = path . join ( path . dirname ( partial . __origin ) , asset . path ) ;
193
- }
194
- asset . path = path . relative ( this . settings . root , absolutePath ) ;
195
- } ) ;
196
- }
197
- // Transform icon paths as above
198
- if ( _ . isObject ( partial [ "icons" ] ) ) {
199
- const icons = partial [ "icons" ] ;
200
- Object . keys ( icons ) . forEach ( ( iconKind : string ) => {
201
- const absolutePath = path . join ( path . dirname ( partial . __origin ) , icons [ iconKind ] ) ;
202
- icons [ iconKind ] = path . relative ( this . settings . root , absolutePath ) ;
203
- } ) ;
204
- }
208
+ // Transform asset paths to be relative to the root of all manifests, verify assets
209
+ if ( _ . isArray ( partial [ "files" ] ) ) {
210
+ ( < Array < FileDeclaration > > partial [ "files" ] ) . forEach ( asset => {
211
+ const keys = Object . keys ( asset ) ;
212
+ if ( keys . indexOf ( "path" ) < 0 ) {
213
+ throw new Error ( "Files must have an absolute or relative (to the manifest) path." ) ;
214
+ }
215
+ let absolutePath ;
216
+ if ( path . isAbsolute ( asset . path ) ) {
217
+ absolutePath = asset . path ;
218
+ } else {
219
+ absolutePath = path . join ( path . dirname ( partial . __origin ) , asset . path ) ;
220
+ }
221
+ asset . path = path . relative ( this . settings . root , absolutePath ) ;
222
+ } ) ;
223
+ }
224
+ // Transform icon paths as above
225
+ if ( _ . isObject ( partial [ "icons" ] ) ) {
226
+ const icons = partial [ "icons" ] ;
227
+ Object . keys ( icons ) . forEach ( ( iconKind : string ) => {
228
+ const absolutePath = path . join ( path . dirname ( partial . __origin ) , icons [ iconKind ] ) ;
229
+ icons [ iconKind ] = path . relative ( this . settings . root , absolutePath ) ;
230
+ } ) ;
231
+ }
205
232
206
- // Expand any directories listed in the files array
207
- if ( _ . isArray ( partial [ "files" ] ) ) {
208
- for ( let i = partial [ "files" ] . length - 1 ; i >= 0 ; -- i ) {
209
- const fileDecl : FileDeclaration = partial [ "files" ] [ i ] ;
210
- const fsPath = path . join ( this . settings . root , fileDecl . path ) ;
211
- if ( fs . lstatSync ( fsPath ) . isDirectory ( ) ) {
212
- Array . prototype . splice . apply (
213
- partial [ "files" ] ,
214
- ( < any [ ] > [ i , 1 ] ) . concat ( this . pathToFileDeclarations ( fsPath , this . settings . root , fileDecl ) ) ,
215
- ) ;
216
- }
233
+ // Expand any directories listed in the files array
234
+ if ( _ . isArray ( partial [ "files" ] ) ) {
235
+ for ( let i = partial [ "files" ] . length - 1 ; i >= 0 ; -- i ) {
236
+ const fileDecl : FileDeclaration = partial [ "files" ] [ i ] ;
237
+ const fsPath = path . join ( this . settings . root , fileDecl . path ) ;
238
+ if ( fs . lstatSync ( fsPath ) . isDirectory ( ) ) {
239
+ Array . prototype . splice . apply (
240
+ partial [ "files" ] ,
241
+ ( < any [ ] > [ i , 1 ] ) . concat ( this . pathToFileDeclarations ( fsPath , this . settings . root , fileDecl ) ) ,
242
+ ) ;
217
243
}
218
244
}
245
+ }
219
246
220
- // Process each key by each manifest builder.
221
- Object . keys ( partial ) . forEach ( key => {
222
- const isOverridePartial = partials . length - 1 === partialIndex && overridesProvided ;
223
- if ( partial [ key ] !== undefined && ( partial [ key ] !== null || isOverridePartial ) ) {
224
- // Notify each manifest builder of the key/value pair
225
- this . manifestBuilders . forEach ( builder => {
226
- builder . processKey ( key , partial [ key ] , isOverridePartial ) ;
227
- } ) ;
228
- }
229
- } ) ;
247
+ // Process each key by each manifest builder.
248
+ Object . keys ( partial ) . forEach ( key => {
249
+ const isOverridePartial = partials . length - 1 === partialIndex && overridesProvided ;
250
+ if ( partial [ key ] !== undefined && ( partial [ key ] !== null || isOverridePartial ) ) {
251
+ // Notify each manifest builder of the key/value pair
252
+ this . manifestBuilders . forEach ( builder => {
253
+ builder . processKey ( key , partial [ key ] , isOverridePartial ) ;
254
+ } ) ;
255
+ }
230
256
} ) ;
257
+ } ) ;
231
258
232
- // Generate localization resources
233
- const locPrepper = new loc . LocPrep . LocKeyGenerator ( this . manifestBuilders ) ;
234
- const resources = locPrepper . generateLocalizationKeys ( ) ;
259
+ // Generate localization resources
260
+ const locPrepper = new loc . LocPrep . LocKeyGenerator ( this . manifestBuilders ) ;
261
+ const resources = locPrepper . generateLocalizationKeys ( ) ;
235
262
236
- // Build up resource data by reading the translations from disk
237
- return this . buildResourcesData ( ) . then ( resourceData => {
238
- if ( resourceData ) {
239
- resourceData [ "defaults" ] = resources . combined ;
240
- }
263
+ // Build up resource data by reading the translations from disk
264
+ return this . buildResourcesData ( ) . then ( resourceData => {
265
+ if ( resourceData ) {
266
+ resourceData [ "defaults" ] = resources . combined ;
267
+ }
241
268
242
- // Build up a master file list
243
- const packageFiles : PackageFiles = { } ;
244
- this . manifestBuilders . forEach ( builder => {
245
- _ . assign ( packageFiles , builder . files ) ;
246
- } ) ;
269
+ // Build up a master file list
270
+ const packageFiles : PackageFiles = { } ;
271
+ this . manifestBuilders . forEach ( builder => {
272
+ _ . assign ( packageFiles , builder . files ) ;
273
+ } ) ;
247
274
248
- const components : VsixComponents = { builders : this . manifestBuilders , resources : resources } ;
249
-
250
- // Finalize each builder
251
- return Promise . all (
252
- [ updateVersionPromise ] . concat (
253
- this . manifestBuilders . map ( b => b . finalize ( packageFiles , resourceData , this . manifestBuilders ) ) ,
254
- ) ,
255
- ) . then ( ( ) => {
256
- // const the composer do validation
257
- return this . extensionComposer . validate ( components ) . then ( validationResult => {
258
- if ( validationResult . length === 0 || this . settings . bypassValidation ) {
259
- return components ;
260
- } else {
261
- throw new Error (
262
- "There were errors with your extension. Address the following and re-run the tool.\n" +
263
- validationResult ,
264
- ) ;
265
- }
266
- } ) ;
275
+ const components : VsixComponents = { builders : this . manifestBuilders , resources : resources } ;
276
+
277
+ // Finalize each builder
278
+ return Promise . all (
279
+ [ updateVersionPromise ] . concat (
280
+ this . manifestBuilders . map ( b => b . finalize ( packageFiles , resourceData , this . manifestBuilders ) ) ,
281
+ ) ,
282
+ ) . then ( ( ) => {
283
+ // const the composer do validation
284
+ return this . extensionComposer . validate ( components ) . then ( validationResult => {
285
+ if ( validationResult . length === 0 || this . settings . bypassValidation ) {
286
+ return components ;
287
+ } else {
288
+ throw new Error (
289
+ "There were errors with your extension. Address the following and re-run the tool.\n" +
290
+ validationResult ,
291
+ ) ;
292
+ }
267
293
} ) ;
268
294
} ) ;
269
295
} ) ;
0 commit comments