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