/
watcher.ts
123 lines (107 loc) · 3.54 KB
/
watcher.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
115
116
117
118
119
120
121
122
123
import { executeCodegen } from '../codegen';
import { Types } from '@graphql-codegen/plugin-helpers';
import { normalizeInstanceOrArray, normalizeOutputParam } from '../helpers';
import * as isValidPath from 'is-valid-path';
import * as isGlob from 'is-glob';
import * as logSymbols from 'log-symbols';
import { debugLog } from './debugging';
import { getLogger } from './logger';
import path from 'path';
function log(msg: string) {
// double spaces to inline the message with Listr
getLogger().info(` ${msg}`);
}
function emitWatching() {
log(`${logSymbols.info} Watching for changes...`);
}
export const createWatcher = (config: Types.Config, onNext: (result: Types.FileOutput[]) => Promise<Types.FileOutput[]>) => {
debugLog(`[Watcher] Starting watcher...`);
const files: string[] = [];
const documents = normalizeInstanceOrArray<Types.OperationDocument>(config.documents);
const schemas = normalizeInstanceOrArray<Types.Schema>(config.schema);
// Add schemas and documents from "generates"
Object.keys(config.generates)
.map(filename => normalizeOutputParam(config.generates[filename]))
.forEach(conf => {
schemas.push(...normalizeInstanceOrArray<Types.Schema>(conf.schema));
documents.push(...normalizeInstanceOrArray<Types.OperationDocument>(conf.documents));
});
if (documents) {
documents.forEach(doc => {
if (typeof doc === 'string') {
files.push(doc);
} else {
files.push(...Object.keys(doc));
}
});
}
schemas.forEach((schema: string) => {
if (isGlob(schema) || isValidPath(schema)) {
files.push(schema);
}
});
if (typeof config.watch !== 'boolean') {
files.push(...normalizeInstanceOrArray<string>(config.watch));
}
let watcher: any;
const runWatcher = async () => {
const chokidar = await import('chokidar');
emitWatching();
const ignored: string[] = [];
Object.keys(config.generates)
.map(filename => ({ filename, config: normalizeOutputParam(config.generates[filename]) }))
.forEach(entry => {
if (entry.config.preset) {
const extension = entry.config.presetConfig && entry.config.presetConfig.extension;
if (extension) {
ignored.push(path.join(entry.filename, '**', '*' + extension));
}
} else {
ignored.push(entry.filename);
}
});
watcher = chokidar.watch(files, {
persistent: true,
ignoreInitial: true,
followSymlinks: true,
cwd: process.cwd(),
disableGlobbing: false,
usePolling: true,
interval: 100,
binaryInterval: 300,
depth: 99,
awaitWriteFinish: true,
ignorePermissionErrors: false,
atomic: true,
ignored,
});
debugLog(`[Watcher] Started`);
let isShutdown = false;
const shutdown = async () => {
isShutdown = true;
debugLog(`[Watcher] Shutting down`);
log(`Shutting down watch...`);
watcher.close();
};
// it doesn't matter what has changed, need to run whole process anyway
watcher.on('all', () => {
if (!isShutdown) {
executeCodegen(config)
.then(onNext, () => Promise.resolve())
.then(() => emitWatching());
}
});
process.once('SIGINT', shutdown);
process.once('SIGTERM', shutdown);
};
// the promise never resolves to keep process running
return new Promise((_, reject) => {
executeCodegen(config)
.then(onNext, () => Promise.resolve())
.then(runWatcher)
.catch(err => {
watcher.close();
reject(err);
});
});
};