Files
talk/scripts/watcher/ChokidarWatcher.ts
T
Kiwi 044e1c2863 Watcher infrastructure (#1724)
* wip

* Adding chokidar and types

* specifiying build tasks

* new structure, new types, executor and watchers

* Adding log

* Fully implemented watchers

* adapt vscode launc

* Add .babelrc.js to toplevel tsconfig project

* Typo

* Get schema path from .graphqlconfig

* Use watcher binary

* Add joi validation to watcher

* Remove fb-watchman for now

* Use correct ignore path

* Fix dist folder

* Allow setting watcher

* Per default only spawn one process at a time

* Support runOnInit

* Rename RestartingExecutor to LongRunningExecutor

* Use debounce instead of throttle

* Remove console log

* Debounce command execution

* Simplify debounce

* Watcher name change

* Typos

* Rename "watcher" root level config to "backend"
2018-07-03 12:21:58 -06:00

82 lines
2.2 KiB
TypeScript

import chokidar from "chokidar";
import { Watcher, WatchOptions } from "./types";
export default class ChokidarWatcher implements Watcher {
public watch(
paths: ReadonlyArray<string>,
options: WatchOptions = {}
): AsyncIterable<string> {
const client = chokidar.watch(paths as string[], {
ignored: options.ignore,
});
// An array to hold all changes, that has not yet been yield.
const queue: string[] = [];
let firstError: Error | null = null;
// If this is set, a pending promise is waiting for the next result.
let pending:
| ({ resolve: (result: string) => void; reject: (error: Error) => void })
| null = null;
// Listen for errors
client.on("error", (error: Error) => {
// Resolve pending request.
if (pending) {
pending.reject(error);
pending = null;
return;
}
if (!firstError) {
firstError = error;
}
});
// Listen for changes
client.on("change", (pathFile: string) => {
// Resolve pending request.
if (pending) {
pending.resolve(pathFile);
pending = null;
return;
}
// There is no pending request, save it into the queue.
queue.unshift(pathFile);
});
return {
[Symbol.asyncIterator]() {
return {
next: () =>
new Promise<IteratorResult<string>>((resolve, reject) => {
const wrapped = {
resolve: (pathFile: string) =>
resolve({
done: false,
value: pathFile,
}),
reject: (error: Error) =>
reject({
done: true,
value: error,
}),
};
// We already have a change to return
if (firstError) {
wrapped.reject(firstError);
return;
}
if (queue.length) {
wrapped.resolve(queue.pop()!);
return;
}
// We need to wait for the next change event.
pending = wrapped;
}),
};
},
};
}
}