forked from dotansimha/graphql-code-generator
/
hooks.ts
104 lines (97 loc) · 3.46 KB
/
hooks.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { Types } from '@graphql-codegen/plugin-helpers';
import { debugLog } from './utils/debugging.js';
import { exec } from 'child_process';
import { delimiter, sep } from 'path';
import { quote } from 'shell-quote';
const DEFAULT_HOOKS: Types.LifecycleHooksDefinition = {
afterStart: [],
beforeDone: [],
onWatchTriggered: [],
onError: [],
afterOneFileWrite: [],
afterAllFileWrite: [],
beforeOneFileWrite: [],
beforeAllFileWrite: [],
};
function execShellCommand(cmd: string): Promise<string> {
return new Promise((resolve, reject) => {
exec(
cmd,
{
env: {
...process.env,
PATH: `${process.env.PATH}${delimiter}${process.cwd()}${sep}node_modules${sep}.bin`,
},
},
(error, stdout, stderr) => {
if (error) {
reject(error);
// eslint-disable-next-line no-console
console.error(error);
} else {
debugLog(stdout || stderr);
resolve(stdout || stderr);
}
}
);
});
}
async function executeHooks(
hookName: string,
_scripts: Types.LifeCycleHookValue | Types.LifeCycleAlterHookValue = [],
args: string[] = [],
initialState?: string
): Promise<void | string> {
debugLog(`Running lifecycle hook "${hookName}" scripts...`);
let state = initialState;
const scripts = Array.isArray(_scripts) ? _scripts : [_scripts];
const quotedArgs = quote(args);
for (const script of scripts) {
if (typeof script === 'string') {
debugLog(`Running lifecycle hook "${hookName}" script: ${script} with args: ${quotedArgs}...`);
await execShellCommand(`${script} ${quotedArgs}`);
} else {
debugLog(`Running lifecycle hook "${hookName}" script: ${script.name} with args: ${args.join(' ')}...`);
const hookArgs = state === undefined ? args : [...args, state];
const hookResult = await script(...hookArgs);
if (typeof hookResult === 'string' && typeof state === 'string') {
debugLog(`Received new content from lifecycle hook "${hookName}" script: ${script.name}`);
state = hookResult;
}
}
}
return state;
}
export const lifecycleHooks = (_hooks: Partial<Types.LifecycleHooksDefinition> = {}) => {
const hooks = {
...DEFAULT_HOOKS,
..._hooks,
};
return {
afterStart: async (): Promise<void> => {
await executeHooks('afterStart', hooks.afterStart);
},
onWatchTriggered: async (event: string, path: string): Promise<void> => {
await executeHooks('onWatchTriggered', hooks.onWatchTriggered, [event, path]);
},
onError: async (error: string): Promise<void> => {
await executeHooks('onError', hooks.onError, [error]);
},
afterOneFileWrite: async (path: string): Promise<void> => {
await executeHooks('afterOneFileWrite', hooks.afterOneFileWrite, [path]);
},
afterAllFileWrite: async (paths: string[]): Promise<void> => {
await executeHooks('afterAllFileWrite', hooks.afterAllFileWrite, paths);
},
beforeOneFileWrite: async (path: string, content: string): Promise<string> => {
const result = await executeHooks('beforeOneFileWrite', hooks.beforeOneFileWrite, [path], content);
return typeof result === 'string' ? result : content;
},
beforeAllFileWrite: async (paths: string[]): Promise<void> => {
await executeHooks('beforeAllFileWrite', hooks.beforeAllFileWrite, paths);
},
beforeDone: async (): Promise<void> => {
await executeHooks('beforeDone', hooks.beforeDone);
},
};
};