Skip to content

Commit

Permalink
feat: use chokidar to watch file changes
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya committed Apr 24, 2021
1 parent c12ebff commit b228c89
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 32 deletions.
115 changes: 99 additions & 16 deletions lib/paths-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Directory, File } from "atom"
import { union } from "./utils"
import { globifyPath, globifyDirectory, globifyGitIgnoreFile } from "./path-utils"
import glob from "fast-glob"
import * as chokidar from "chokidar"

export default class PathsCache extends EventEmitter {
constructor() {
Expand Down Expand Up @@ -48,7 +49,7 @@ export default class PathsCache extends EventEmitter {
await this._cacheProjectPathsAndRepositories()
const results = await this._cachePaths()

this._addWatchers()
await this._addWatchers()

this.emit("rebuild-cache-done")
return results
Expand All @@ -73,8 +74,8 @@ export default class PathsCache extends EventEmitter {
* @param {boolean} isPackageDispose
*/
dispose(isPackageDispose) {
this._fileWatchersByDirectory.forEach((watcher) => {
watcher.dispose()
this._fileWatchersByDirectory.forEach(async (watcher) => {
await watcher.close()
})
this._fileWatchersByDirectory = new Map()
this._filePathsByProjectDirectory = new Map()
Expand Down Expand Up @@ -164,16 +165,89 @@ export default class PathsCache extends EventEmitter {
* @param {Directory} projectDirectory
* @private
*/
_addWatcherForDirectory(projectDirectory) {
// check if it is not already added
async _addWatcherForDirectory(projectDirectory) {
// close if already added
let watcher = this._fileWatchersByDirectory.get(projectDirectory)
if (watcher !== undefined) {
// add a watcher to run `this._onDirectoryChanged`
watcher = projectDirectory.onDidChange(() => {
return this._onDirectoryChanged(projectDirectory, projectDirectory)
if (watcher !== undefined && typeof watcher.close === "function") {
await watcher.close()
}
// add a watcher to run `this._onDirectoryChanged`
const projectPath = projectDirectory.getPath()
const ignored = await this._getAllIgnoredGlob(projectPath)
// TODO smarter handling of directory changes
// TODO get paths from the watcher itself
// TODO track gitignore file
watcher = chokidar
.watch([projectPath, ...ignored], {
persistent: true,
})
.on("add", (addedFile) => {
this.onAddFile(projectDirectory, addedFile)
})
.on("unlink", (removedFile) => {
this.onRemoveFile(projectDirectory, removedFile)
})
this._fileWatchersByDirectory.set(projectDirectory, watcher)
.on("addDir", (addedDir) => {
this.onAddDir(projectDirectory, addedDir)
})
.on("unlinkDir", (removedDir) => {
this.onRemoveDir(projectDirectory, removedDir)
})
this._fileWatchersByDirectory.set(projectDirectory, watcher)
}

/**
* @param projectDirectory {Directory}
* @param addedFile {string}
*/
onAddFile(projectDirectory, addedFile) {
this.emit("rebuild-cache")
const filePaths = this._filePathsByProjectDirectory.get(projectDirectory.path)
filePaths.push(addedFile)
this._filePathsByProjectDirectory.set(projectDirectory.path, filePaths)
this.emit("rebuild-cache-done")
}

/**
* @param projectDirectory {Directory}
* @param removedFile {string}
*/
onRemoveFile(projectDirectory, removedFile) {
this.emit("rebuild-cache")
/** @type {string[]} */
const filePaths = this._filePathsByProjectDirectory.get(projectDirectory.path)

// delete the removed file
for (let iFile = 0; iFile < filePaths.length; iFile++) {
const file = filePaths[iFile]
if (file === removedFile) {
delete filePaths[iFile]
}
}
this._filePathsByProjectDirectory.set(projectDirectory.path, filePaths)
this.emit("rebuild-cache-done")
}

/**
* @param projectDirectory {Directory}
* @param addedDir {string}
*/
async onAddDir(projectDirectory, addedDir) {
this.emit("rebuild-cache")
const directory = new Directory(addedDir)
await this._cachePathsForDirectory(projectDirectory, directory)
this.emit("rebuild-cache-done")
}

/**
* @param projectDirectory {Directory}
* @param removedDir {string}
*/
onRemoveDir(projectDirectory, removedDir) {
this.emit("rebuild-cache")
const directory = new Directory(removedDir)
this._removeFilePathsForDirectory(projectDirectory, directory)
this.emit("rebuild-cache-done")
}

/**
Expand All @@ -197,9 +271,10 @@ export default class PathsCache extends EventEmitter {
* @private
*/
_cleanWatchersForDirectory(directory) {
this._fileWatchersByDirectory.forEach((watcher, otherDirectory) => {
// TODO promise all
this._fileWatchersByDirectory.forEach(async (watcher, otherDirectory) => {
if (directory.contains(otherDirectory.path)) {
watcher.dispose()
await await watcher.close()
this._fileWatchersByDirectory.delete(otherDirectory)
}
})
Expand Down Expand Up @@ -383,6 +458,17 @@ export default class PathsCache extends EventEmitter {
return []
}

/**
* Get all ignored glob using `this._getGitIgnoreGlob` and `this._getIgnoredPatternsGlob`
* @param {string} directoryPath the given directory path
* @returns {Promise<string[]>}
*/
async _getAllIgnoredGlob(directoryPath) {
const gitignoreGlob = await this._getGitIgnoreGlob(directoryPath)
const ignoredPatternsGlob = await this._getIgnoredPatternsGlob(directoryPath)
return [...gitignoreGlob, ...ignoredPatternsGlob]
}

/**
* Populates cache for the given directory
* @param {string} directoryPath the given directory path
Expand All @@ -391,11 +477,8 @@ export default class PathsCache extends EventEmitter {
*/
async _cachePathsForDirectoryWithGlob(directoryPath) {
const directoryGlob = globifyDirectory(directoryPath)
const gitignoreGlob = await this._getGitIgnoreGlob(directoryPath)
const ignoredPatternsGlob = await this._getIgnoredPatternsGlob(directoryPath)

const files = await glob(
[directoryGlob, ...gitignoreGlob, ...ignoredPatternsGlob],
[directoryGlob, ...(await this._getAllIgnoredGlob(directoryPath))],
// glob options
{
dot: true,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
}
},
"dependencies": {
"chokidar": "^3.5.1",
"fast-glob": "^3.2.5",
"is-glob": "^4.0.1",
"is-valid-path": "^0.1.1",
Expand Down
29 changes: 13 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b228c89

Please sign in to comment.