forked from dotansimha/graphql-code-generator
/
hooks.ts
114 lines (106 loc) · 3.74 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
105
106
107
108
109
110
111
112
113
114
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 normalizeHooks(_hooks: Partial<Types.LifecycleHooksDefinition>): {
[key in keyof Types.LifecycleHooksDefinition]: (string | Types.HookFunction)[];
} {
const keys = Object.keys({
...DEFAULT_HOOKS,
..._hooks,
});
return keys.reduce(
(prev: { [key in keyof Types.LifecycleHooksDefinition]: (string | Types.HookFunction)[] }, hookName: string) => {
if (typeof _hooks[hookName] === 'string') {
return {
...prev,
[hookName]: [_hooks[hookName]] as string[],
};
}
if (typeof _hooks[hookName] === 'function') {
return {
...prev,
[hookName]: [_hooks[hookName]],
};
}
if (Array.isArray(_hooks[hookName])) {
return {
...prev,
[hookName]: _hooks[hookName] as string[],
};
}
return prev;
},
{} as { [key in keyof Types.LifecycleHooksDefinition]: (string | Types.HookFunction)[] }
);
}
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 = [],
args: string[] = []
): Promise<void> {
debugLog(`Running lifecycle hook "${hookName}" scripts...`);
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(' ')}...`);
await script(...args);
}
}
}
export const lifecycleHooks = (_hooks: Partial<Types.LifecycleHooksDefinition> = {}) => {
const hooks = normalizeHooks(_hooks);
return {
afterStart: async (): Promise<void> => executeHooks('afterStart', hooks.afterStart),
onWatchTriggered: async (event: string, path: string): Promise<void> =>
executeHooks('onWatchTriggered', hooks.onWatchTriggered, [event, path]),
onError: async (error: string): Promise<void> => executeHooks('onError', hooks.onError, [error]),
afterOneFileWrite: async (path: string): Promise<void> =>
executeHooks('afterOneFileWrite', hooks.afterOneFileWrite, [path]),
afterAllFileWrite: async (paths: string[]): Promise<void> =>
executeHooks('afterAllFileWrite', hooks.afterAllFileWrite, paths),
beforeOneFileWrite: async (path: string): Promise<void> =>
executeHooks('beforeOneFileWrite', hooks.beforeOneFileWrite, [path]),
beforeAllFileWrite: async (paths: string[]): Promise<void> =>
executeHooks('beforeAllFileWrite', hooks.beforeAllFileWrite, paths),
beforeDone: async (): Promise<void> => executeHooks('beforeDone', hooks.beforeDone),
};
};