@@ -24,7 +24,10 @@ import { color } from "../../color";
24
24
import { memoize } from "../decorators" ;
25
25
26
26
class Hook implements IHook {
27
- constructor ( public name : string , public fullPath : string ) { }
27
+ constructor (
28
+ public name : string ,
29
+ public fullPath : string ,
30
+ ) { }
28
31
}
29
32
30
33
export class HooksService implements IHooksService {
@@ -45,7 +48,7 @@ export class HooksService implements IHooksService {
45
48
private $projectHelper : IProjectHelper ,
46
49
private $options : IOptions ,
47
50
private $performanceService : IPerformanceService ,
48
- private $projectConfigService : IProjectConfigService
51
+ private $projectConfigService : IProjectConfigService ,
49
52
) { }
50
53
51
54
public get hookArgsName ( ) : string {
@@ -69,12 +72,12 @@ export class HooksService implements IHooksService {
69
72
70
73
if ( projectDir ) {
71
74
this . hooksDirectories . push (
72
- path . join ( projectDir , HooksService . HOOKS_DIRECTORY_NAME )
75
+ path . join ( projectDir , HooksService . HOOKS_DIRECTORY_NAME ) ,
73
76
) ;
74
77
}
75
78
76
79
this . $logger . trace (
77
- "Hooks directories: " + util . inspect ( this . hooksDirectories )
80
+ "Hooks directories: " + util . inspect ( this . hooksDirectories ) ,
78
81
) ;
79
82
80
83
const customHooks = this . $projectConfigService . getValue ( "hooks" , [ ] ) ;
@@ -91,7 +94,7 @@ export class HooksService implements IHooksService {
91
94
92
95
public executeBeforeHooks (
93
96
commandName : string ,
94
- hookArguments ?: IDictionary < any >
97
+ hookArguments ?: IDictionary < any > ,
95
98
) : Promise < void > {
96
99
const beforeHookName = `before-${ HooksService . formatHookName ( commandName ) } ` ;
97
100
const traceMessage = `BeforeHookName for command ${ commandName } is ${ beforeHookName } ` ;
@@ -100,7 +103,7 @@ export class HooksService implements IHooksService {
100
103
101
104
public executeAfterHooks (
102
105
commandName : string ,
103
- hookArguments ?: IDictionary < any >
106
+ hookArguments ?: IDictionary < any > ,
104
107
) : Promise < void > {
105
108
const afterHookName = `after-${ HooksService . formatHookName ( commandName ) } ` ;
106
109
const traceMessage = `AfterHookName for command ${ commandName } is ${ afterHookName } ` ;
@@ -110,7 +113,7 @@ export class HooksService implements IHooksService {
110
113
private async executeHooks (
111
114
hookName : string ,
112
115
traceMessage : string ,
113
- hookArguments ?: IDictionary < any >
116
+ hookArguments ?: IDictionary < any > ,
114
117
) : Promise < any > {
115
118
if ( this . $config . DISABLE_HOOKS || ! this . $options . hooks ) {
116
119
return ;
@@ -135,8 +138,8 @@ export class HooksService implements IHooksService {
135
138
await this . executeHooksInDirectory (
136
139
hooksDirectory ,
137
140
hookName ,
138
- hookArguments
139
- )
141
+ hookArguments ,
142
+ ) ,
140
143
) ;
141
144
}
142
145
@@ -148,8 +151,8 @@ export class HooksService implements IHooksService {
148
151
this . $projectHelper . projectDir ,
149
152
hookName ,
150
153
hook ,
151
- hookArguments
152
- )
154
+ hookArguments ,
155
+ ) ,
153
156
) ;
154
157
}
155
158
} catch ( err ) {
@@ -160,11 +163,16 @@ export class HooksService implements IHooksService {
160
163
return _ . flatten ( results ) ;
161
164
}
162
165
166
+ private isESModule ( hook : IHook ) : boolean {
167
+ const ext = path . extname ( hook . fullPath ) . toLowerCase ( ) ;
168
+ return ext === ".mjs" ;
169
+ }
170
+
163
171
private async executeHook (
164
172
directoryPath : string ,
165
173
hookName : string ,
166
174
hook : IHook ,
167
- hookArguments ?: IDictionary < any >
175
+ hookArguments ?: IDictionary < any > ,
168
176
) : Promise < any > {
169
177
hookArguments = hookArguments || { } ;
170
178
@@ -173,15 +181,18 @@ export class HooksService implements IHooksService {
173
181
const relativePath = path . relative ( directoryPath , hook . fullPath ) ;
174
182
const trackId = relativePath . replace (
175
183
new RegExp ( "\\" + path . sep , "g" ) ,
176
- AnalyticsEventLabelDelimiter
184
+ AnalyticsEventLabelDelimiter ,
177
185
) ;
186
+ const isESM = this . isESModule ( hook ) ;
178
187
let command = this . getSheBangInterpreter ( hook ) ;
179
188
let inProc = false ;
180
189
if ( ! command ) {
181
190
command = hook . fullPath ;
182
191
if ( [ ".mjs" , ".js" ] . includes ( path . extname ( hook . fullPath ) . toLowerCase ( ) ) ) {
183
192
command = process . argv [ 0 ] ;
184
- inProc = this . shouldExecuteInProcess ( this . $fs . readText ( hook . fullPath ) ) ;
193
+ inProc = isESM
194
+ ? true
195
+ : this . shouldExecuteInProcess ( this . $fs . readText ( hook . fullPath ) ) ;
185
196
}
186
197
}
187
198
@@ -190,24 +201,30 @@ export class HooksService implements IHooksService {
190
201
this . $logger . trace (
191
202
"Executing %s hook at ___location %s in-process" ,
192
203
hookName ,
193
- hook . fullPath
204
+ hook . fullPath ,
194
205
) ;
195
- const hookEntryPoint = require ( hook . fullPath ) ;
206
+ let hookEntryPoint ;
207
+ if ( isESM ) {
208
+ const { default : hookFn } = await import ( hook . fullPath ) ;
209
+ hookEntryPoint = hookFn ;
210
+ } else {
211
+ hookEntryPoint = require ( hook . fullPath ) ;
212
+ }
196
213
197
214
this . $logger . trace ( `Validating ${ hookName } arguments.` ) ;
198
215
199
216
const invalidArguments = this . validateHookArguments (
200
217
hookEntryPoint ,
201
- hook . fullPath
218
+ hook . fullPath ,
202
219
) ;
203
220
204
221
if ( invalidArguments . length ) {
205
222
this . $logger . warn (
206
223
`${
207
224
hook . fullPath
208
225
} will NOT be executed because it has invalid arguments - ${ color . grey (
209
- invalidArguments . join ( ", " )
210
- ) } .`
226
+ invalidArguments . join ( ", " ) ,
227
+ ) } .`,
211
228
) ;
212
229
return ;
213
230
}
@@ -220,14 +237,13 @@ export class HooksService implements IHooksService {
220
237
const projectDataHookArg =
221
238
hookArguments [ "hookArgs" ] && hookArguments [ "hookArgs" ] [ "projectData" ] ;
222
239
if ( projectDataHookArg ) {
223
- hookArguments [ "projectData" ] = hookArguments [
224
- "$projectData"
225
- ] = projectDataHookArg ;
240
+ hookArguments [ "projectData" ] = hookArguments [ "$projectData" ] =
241
+ projectDataHookArg ;
226
242
}
227
243
228
244
const maybePromise = this . $injector . resolve (
229
245
hookEntryPoint ,
230
- hookArguments
246
+ hookArguments ,
231
247
) ;
232
248
if ( maybePromise ) {
233
249
this . $logger . trace ( "Hook promises to signal completion" ) ;
@@ -255,15 +271,15 @@ export class HooksService implements IHooksService {
255
271
"Executing %s hook at ___location %s with environment " ,
256
272
hookName ,
257
273
hook . fullPath ,
258
- environment
274
+ environment ,
259
275
) ;
260
276
261
277
const output = await this . $childProcess . spawnFromEvent (
262
278
command ,
263
279
[ hook . fullPath ] ,
264
280
"close" ,
265
281
environment ,
266
- { throwError : false }
282
+ { throwError : false } ,
267
283
) ;
268
284
result = output ;
269
285
@@ -275,7 +291,7 @@ export class HooksService implements IHooksService {
275
291
"Finished executing %s hook at ___location %s with environment " ,
276
292
hookName ,
277
293
hook . fullPath ,
278
- environment
294
+ environment ,
279
295
) ;
280
296
}
281
297
const endTime = this . $performanceService . now ( ) ;
@@ -289,7 +305,7 @@ export class HooksService implements IHooksService {
289
305
private async executeHooksInDirectory (
290
306
directoryPath : string ,
291
307
hookName : string ,
292
- hookArguments ?: IDictionary < any >
308
+ hookArguments ?: IDictionary < any > ,
293
309
) : Promise < any [ ] > {
294
310
hookArguments = hookArguments || { } ;
295
311
const results : any [ ] = [ ] ;
@@ -301,7 +317,7 @@ export class HooksService implements IHooksService {
301
317
directoryPath ,
302
318
hookName ,
303
319
hook ,
304
- hookArguments
320
+ hookArguments ,
305
321
) ;
306
322
307
323
if ( result ) {
@@ -316,14 +332,14 @@ export class HooksService implements IHooksService {
316
332
const hooks : IHook [ ] = [ ] ;
317
333
const customHooks : INsConfigHooks [ ] = this . $projectConfigService . getValue (
318
334
"hooks" ,
319
- [ ]
335
+ [ ] ,
320
336
) ;
321
337
322
338
for ( const cHook of customHooks ) {
323
339
if ( cHook . type === hookName ) {
324
340
const fullPath = path . join (
325
341
this . $projectHelper . projectDir ,
326
- cHook . script
342
+ cHook . script ,
327
343
) ;
328
344
const isFile = this . $fs . getFsStats ( fullPath ) . isFile ( ) ;
329
345
@@ -332,8 +348,8 @@ export class HooksService implements IHooksService {
332
348
hooks . push (
333
349
new Hook (
334
350
this . getBaseFilename ( fileNameParts [ fileNameParts . length - 1 ] ) ,
335
- fullPath
336
- )
351
+ fullPath ,
352
+ ) ,
337
353
) ;
338
354
}
339
355
}
@@ -346,10 +362,10 @@ export class HooksService implements IHooksService {
346
362
const allBaseHooks = this . getHooksInDirectory ( directoryPath ) ;
347
363
const baseHooks = _ . filter (
348
364
allBaseHooks ,
349
- ( hook ) => hook . name . toLowerCase ( ) === hookName . toLowerCase ( )
365
+ ( hook ) => hook . name . toLowerCase ( ) === hookName . toLowerCase ( ) ,
350
366
) ;
351
367
const moreHooks = this . getHooksInDirectory (
352
- path . join ( directoryPath , hookName )
368
+ path . join ( directoryPath , hookName ) ,
353
369
) ;
354
370
return baseHooks . concat ( moreHooks ) ;
355
371
}
@@ -385,13 +401,11 @@ export class HooksService implements IHooksService {
385
401
const clientName = this . $staticConfig . CLIENT_NAME . toUpperCase ( ) ;
386
402
387
403
const environment : IStringDictionary = { } ;
388
- environment [ util . format ( "%s-COMMANDLINE" , clientName ) ] = process . argv . join (
389
- " "
390
- ) ;
404
+ environment [ util . format ( "%s-COMMANDLINE" , clientName ) ] =
405
+ process . argv . join ( " " ) ;
391
406
environment [ util . format ( "%s-HOOK_FULL_PATH" , clientName ) ] = hookFullPath ;
392
- environment [
393
- util . format ( "%s-VERSION" , clientName )
394
- ] = this . $staticConfig . version ;
407
+ environment [ util . format ( "%s-VERSION" , clientName ) ] =
408
+ this . $staticConfig . version ;
395
409
396
410
return {
397
411
cwd : this . $projectHelper . projectDir ,
@@ -463,7 +477,7 @@ export class HooksService implements IHooksService {
463
477
464
478
private validateHookArguments (
465
479
hookConstructor : any ,
466
- hookFullPath : string
480
+ hookFullPath : string ,
467
481
) : string [ ] {
468
482
const invalidArguments : string [ ] = [ ] ;
469
483
@@ -477,7 +491,7 @@ export class HooksService implements IHooksService {
477
491
}
478
492
} catch ( err ) {
479
493
this . $logger . trace (
480
- `Cannot resolve ${ argument } of hook ${ hookFullPath } , reason: ${ err } `
494
+ `Cannot resolve ${ argument } of hook ${ hookFullPath } , reason: ${ err } ` ,
481
495
) ;
482
496
invalidArguments . push ( argument ) ;
483
497
}
0 commit comments