Skip to content

Instantly share code, notes, and snippets.

@brettinternet
Created July 9, 2020 04:05
Show Gist options
  • Save brettinternet/0ae9e41bfe693a1d5fc1acb0b6143f43 to your computer and use it in GitHub Desktop.
Save brettinternet/0ae9e41bfe693a1d5fc1acb0b6143f43 to your computer and use it in GitHub Desktop.
Watch for write changes to files and move
import chokidar from 'chokidar'
import { existsSync, moveSync, removeSync } from 'fs-extra'
import { join, basename } from 'path'
type WatchFiles = string | string[]
interface OptionsArg {
/**
* Seconds to wait for files to appear
* @default 60
*/
timeout?: number
/**
* Whether to continue to watch after the first change
* https://github.com/paulmillr/chokidar#persistence
* @default true
*/
persistent?: boolean
/**
* Whether to overwrite destination file
* https://github.com/jprichardson/node-fs-extra/blob/HEAD/docs/move-sync.md
* @default false
*/
overwrite?: boolean
}
interface Options extends OptionsArg {
timeout: number
persistent: boolean
overwrite: boolean
}
export class WatchFileMove {
private pollCount = 0
private readonly options: Options = {
timeout: 60,
persistent: true,
overwrite: false,
}
constructor(
private readonly files: WatchFiles,
private readonly outputDir: string,
options?: OptionsArg,
) {
this.options = Object.assign({}, this.options, options)
this.setupWatcher()
}
private async setupWatcher() {
await this.pollFiles(this.files)
this.watch(this.files)
}
private pollFiles = (files: WatchFiles) =>
new Promise((resolve, reject) => {
const waitUntilExists = setInterval(() => {
if (this.filesExists(files)) {
clearInterval(waitUntilExists)
resolve()
} else {
this.pollCount = this.pollCount + 1
if (this.pollCount >= this.options.timeout) {
reject(
Error(
`Unable to locate files ${files} within ${this.options.timeout} seconds`,
),
)
}
}
}, 1000)
})
private filesExists = (files: WatchFiles) =>
Array.isArray(files) ? files.every(this.exists) : this.exists(files)
private exists(file: string) {
return existsSync(file)
}
private watch(files: WatchFiles) {
const watcher = chokidar.watch(files, {
persistent: this.options.persistent,
})
watcher
.on('add', this.move)
.on('unlink', this.delete)
.on('error', this.error)
}
private move = (path: string) => {
const filename = basename(path)
const output = join(this.outputDir, filename)
moveSync(path, output, {
overwrite: this.options.overwrite,
})
}
private delete = (path: string) => {
removeSync(path)
}
private error = (err: Error) => {
console.error(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment