mirror of
https://github.com/wassname/talk.git
synced 2026-06-27 19:49:20 +08:00
97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
import chokidar from "chokidar";
|
|
import path from "path";
|
|
import { Watcher, WatchOptions } from "./types";
|
|
|
|
function prependRootDir(
|
|
prepend: string,
|
|
paths: ReadonlyArray<string>
|
|
): string[] {
|
|
const prependFunc = (p: string) => path.resolve(prepend, p);
|
|
return paths.map(prependFunc);
|
|
}
|
|
|
|
export default class ChokidarWatcher implements Watcher {
|
|
public watch(
|
|
rootDir: string,
|
|
paths: ReadonlyArray<string>,
|
|
options: WatchOptions = {}
|
|
): AsyncIterable<string> {
|
|
const resolvedPaths = prependRootDir(rootDir, paths);
|
|
|
|
// 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;
|
|
|
|
// Only start client if we have something to watch.
|
|
if (paths.length) {
|
|
const client = chokidar.watch(resolvedPaths, {
|
|
ignored: options.ignore && prependRootDir(rootDir, options.ignore),
|
|
});
|
|
|
|
// 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;
|
|
}),
|
|
};
|
|
},
|
|
};
|
|
}
|
|
}
|