@@ -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,22 @@ 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
- if ( path . extname ( hook . fullPath ) . toLowerCase ( ) === ".js" ) {
191
+ if (
192
+ [ ".mjs" , ".cjs" , ".js" ] . includes (
193
+ path . extname ( hook . fullPath ) . toLowerCase ( ) ,
194
+ )
195
+ ) {
183
196
command = process . argv [ 0 ] ;
184
- inProc = this . shouldExecuteInProcess ( this . $fs . readText ( hook . fullPath ) ) ;
197
+ inProc = isESM
198
+ ? true
199
+ : this . shouldExecuteInProcess ( this . $fs . readText ( hook . fullPath ) ) ;
185
200
}
186
201
}
187
202
@@ -190,24 +205,30 @@ export class HooksService implements IHooksService {
190
205
this . $logger . trace (
191
206
"Executing %s hook at ___location %s in-process" ,
192
207
hookName ,
193
- hook . fullPath
208
+ hook . fullPath ,
194
209
) ;
195
- const hookEntryPoint = require ( hook . fullPath ) ;
210
+ let hookEntryPoint ;
211
+ if ( isESM ) {
212
+ const { default : hookFn } = await import ( hook . fullPath ) ;
213
+ hookEntryPoint = hookFn ;
214
+ } else {
215
+ hookEntryPoint = require ( hook . fullPath ) ;
216
+ }
196
217
197
218
this . $logger . trace ( `Validating ${ hookName } arguments.` ) ;
198
219
199
220
const invalidArguments = this . validateHookArguments (
200
221
hookEntryPoint ,
201
- hook . fullPath
222
+ hook . fullPath ,
202
223
) ;
203
224
204
225
if ( invalidArguments . length ) {
205
226
this . $logger . warn (
206
227
`${
207
228
hook . fullPath
208
229
} will NOT be executed because it has invalid arguments - ${ color . grey (
209
- invalidArguments . join ( ", " )
210
- ) } .`
230
+ invalidArguments . join ( ", " ) ,
231
+ ) } .`,
211
232
) ;
212
233
return ;
213
234
}
@@ -220,14 +241,13 @@ export class HooksService implements IHooksService {
220
241
const projectDataHookArg =
221
242
hookArguments [ "hookArgs" ] && hookArguments [ "hookArgs" ] [ "projectData" ] ;
222
243
if ( projectDataHookArg ) {
223
- hookArguments [ "projectData" ] = hookArguments [
224
- "$projectData"
225
- ] = projectDataHookArg ;
244
+ hookArguments [ "projectData" ] = hookArguments [ "$projectData" ] =
245
+ projectDataHookArg ;
226
246
}
227
247
228
248
const maybePromise = this . $injector . resolve (
229
249
hookEntryPoint ,
230
- hookArguments
250
+ hookArguments ,
231
251
) ;
232
252
if ( maybePromise ) {
233
253
this . $logger . trace ( "Hook promises to signal completion" ) ;
@@ -255,15 +275,15 @@ export class HooksService implements IHooksService {
255
275
"Executing %s hook at ___location %s with environment " ,
256
276
hookName ,
257
277
hook . fullPath ,
258
- environment
278
+ environment ,
259
279
) ;
260
280
261
281
const output = await this . $childProcess . spawnFromEvent (
262
282
command ,
263
283
[ hook . fullPath ] ,
264
284
"close" ,
265
285
environment ,
266
- { throwError : false }
286
+ { throwError : false } ,
267
287
) ;
268
288
result = output ;
269
289
@@ -275,7 +295,7 @@ export class HooksService implements IHooksService {
275
295
"Finished executing %s hook at ___location %s with environment " ,
276
296
hookName ,
277
297
hook . fullPath ,
278
- environment
298
+ environment ,
279
299
) ;
280
300
}
281
301
const endTime = this . $performanceService . now ( ) ;
@@ -289,7 +309,7 @@ export class HooksService implements IHooksService {
289
309
private async executeHooksInDirectory (
290
310
directoryPath : string ,
291
311
hookName : string ,
292
- hookArguments ?: IDictionary < any >
312
+ hookArguments ?: IDictionary < any > ,
293
313
) : Promise < any [ ] > {
294
314
hookArguments = hookArguments || { } ;
295
315
const results : any [ ] = [ ] ;
@@ -301,7 +321,7 @@ export class HooksService implements IHooksService {
301
321
directoryPath ,
302
322
hookName ,
303
323
hook ,
304
- hookArguments
324
+ hookArguments ,
305
325
) ;
306
326
307
327
if ( result ) {
@@ -316,14 +336,14 @@ export class HooksService implements IHooksService {
316
336
const hooks : IHook [ ] = [ ] ;
317
337
const customHooks : INsConfigHooks [ ] = this . $projectConfigService . getValue (
318
338
"hooks" ,
319
- [ ]
339
+ [ ] ,
320
340
) ;
321
341
322
342
for ( const cHook of customHooks ) {
323
343
if ( cHook . type === hookName ) {
324
344
const fullPath = path . join (
325
345
this . $projectHelper . projectDir ,
326
- cHook . script
346
+ cHook . script ,
327
347
) ;
328
348
const isFile = this . $fs . getFsStats ( fullPath ) . isFile ( ) ;
329
349
@@ -332,8 +352,8 @@ export class HooksService implements IHooksService {
332
352
hooks . push (
333
353
new Hook (
334
354
this . getBaseFilename ( fileNameParts [ fileNameParts . length - 1 ] ) ,
335
- fullPath
336
- )
355
+ fullPath ,
356
+ ) ,
337
357
) ;
338
358
}
339
359
}
@@ -346,10 +366,10 @@ export class HooksService implements IHooksService {
346
366
const allBaseHooks = this . getHooksInDirectory ( directoryPath ) ;
347
367
const baseHooks = _ . filter (
348
368
allBaseHooks ,
349
- ( hook ) => hook . name . toLowerCase ( ) === hookName . toLowerCase ( )
369
+ ( hook ) => hook . name . toLowerCase ( ) === hookName . toLowerCase ( ) ,
350
370
) ;
351
371
const moreHooks = this . getHooksInDirectory (
352
- path . join ( directoryPath , hookName )
372
+ path . join ( directoryPath , hookName ) ,
353
373
) ;
354
374
return baseHooks . concat ( moreHooks ) ;
355
375
}
@@ -385,13 +405,11 @@ export class HooksService implements IHooksService {
385
405
const clientName = this . $staticConfig . CLIENT_NAME . toUpperCase ( ) ;
386
406
387
407
const environment : IStringDictionary = { } ;
388
- environment [ util . format ( "%s-COMMANDLINE" , clientName ) ] = process . argv . join (
389
- " "
390
- ) ;
408
+ environment [ util . format ( "%s-COMMANDLINE" , clientName ) ] =
409
+ process . argv . join ( " " ) ;
391
410
environment [ util . format ( "%s-HOOK_FULL_PATH" , clientName ) ] = hookFullPath ;
392
- environment [
393
- util . format ( "%s-VERSION" , clientName )
394
- ] = this . $staticConfig . version ;
411
+ environment [ util . format ( "%s-VERSION" , clientName ) ] =
412
+ this . $staticConfig . version ;
395
413
396
414
return {
397
415
cwd : this . $projectHelper . projectDir ,
@@ -463,7 +481,7 @@ export class HooksService implements IHooksService {
463
481
464
482
private validateHookArguments (
465
483
hookConstructor : any ,
466
- hookFullPath : string
484
+ hookFullPath : string ,
467
485
) : string [ ] {
468
486
const invalidArguments : string [ ] = [ ] ;
469
487
@@ -477,7 +495,7 @@ export class HooksService implements IHooksService {
477
495
}
478
496
} catch ( err ) {
479
497
this . $logger . trace (
480
- `Cannot resolve ${ argument } of hook ${ hookFullPath } , reason: ${ err } `
498
+ `Cannot resolve ${ argument } of hook ${ hookFullPath } , reason: ${ err } ` ,
481
499
) ;
482
500
invalidArguments . push ( argument ) ;
483
501
}
0 commit comments