Skip to content

Commit

Permalink
Merge dafc66a into 802596a
Browse files Browse the repository at this point in the history
  • Loading branch information
micnic committed Dec 26, 2021
2 parents 802596a + dafc66a commit ed5bbaa
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 16.x]
node-version: [12.x, 14.x, 16.x]

steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<img src="https://raw.github.com/micnic/recache/master/logo.png"/>

# 0.5.3
[![npm version](https://img.shields.io/npm/v/recache.svg?logo=npm&style=flat-square)](https://www.npmjs.com/package/recache)
[![npm downloads](https://img.shields.io/npm/dm/recache.svg?style=flat-square)](https://www.npmjs.com/package/recache)
[![npm types](https://img.shields.io/npm/types/recache.svg?style=flat-square)](https://www.npmjs.com/package/recache)
[![node version](https://img.shields.io/node/v/recache.svg?style=flat-square)](https://www.npmjs.com/package/recache)
[![license](https://img.shields.io/npm/l/recache.svg?style=flat-square)](https://www.npmjs.com/package/recache)

`recache` is a file system cache, it watches recursively a directory tree or a
file content and updates the data on changes, optionally it may provide the
Expand All @@ -21,7 +25,7 @@ reading its paths, stats and content directly using only its API. `recache` is a
pure JS solution and does not require any code compilation on installation.

#### Any feedback is welcome!
#### Works with node.js 8.0+!
#### Works with node.js 10.0+!

## Installation

Expand Down
33 changes: 9 additions & 24 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,30 +480,15 @@ declare namespace recache {
* Create and start a file system cache
*/
declare function recache(
path: string,
options: recache.CacheOptions,
callback: recache.CacheCallback
...args:
| [path: string]
| [path: string, options: recache.CacheOptions]
| [path: string, callback: recache.CacheCallback]
| [
path: string,
options: recache.CacheOptions,
callback: recache.CacheCallback
]
): recache.Cache;

/**
* Create and start a file system cache
*/
declare function recache(
path: string,
options: recache.CacheOptions
): recache.Cache;

/**
* Create and start a file system cache
*/
declare function recache(
path: string,
callback: recache.CacheCallback
): recache.Cache;

/**
* Create and start a file system cache
*/
declare function recache(path: string): recache.Cache;

export = recache;
6 changes: 2 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
const Cache = require('recache/lib/cache');

/**
* @typedef {import('recache').CacheCallback} CacheCallback
* @typedef {import('recache').CacheOptions} CacheOptions
* @typedef {import('recache/lib/cache').CacheArgs} CacheArgs
* @typedef {import('recache')} recache
*/

/**
* @param {CacheArgs} args
* @type {recache}
*/
module.exports = (...args) => new Cache(...args);
138 changes: 90 additions & 48 deletions lib/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ const {
isBoolean,
isFunction,
isInstanceOf,
isNull,
isNullable,
isObjectOf,
isString,
isUnionOf
isString
} = require('r-assign/lib');

/**
* @typedef {import('fs').FSWatcher} FSWatcher
* @typedef {import('fs').BigIntStats} BigIntStats
* @typedef {import('recache')} recache
* @typedef {import('recache').Cache} CacheInterface
* @typedef {import('recache').CacheElement} CacheElement
* @typedef {import('recache').CacheElementType} CacheElementType
Expand All @@ -34,15 +34,6 @@ const {
* @typedef {import('recache').UserData} UserData
*/

/**
* @typedef {|
* [string] |
* [string, CacheOptions] |
* [string, CacheCallback] |
* [string, CacheOptions, CacheCallback]
* } CacheArgs
*/

/**
* @typedef {(cache: Cache) => void} CacheCallback
*/
Expand Down Expand Up @@ -116,7 +107,7 @@ const getOptions = (options) => {
const isCacheFilter = isFunction([isString, isBigIntStats], isBoolean);

return rAssign({
filter: getType(isUnionOf([isCacheFilter, isNull]), null),
filter: getType(isNullable(isCacheFilter), null),
persistent: getType(isBoolean, false),
store: getType(isBoolean, false)
}, options);
Expand Down Expand Up @@ -150,7 +141,7 @@ class Cache extends EventEmitter {

/**
* Cache constructor
* @param {CacheArgs} args
* @param {Parameters<recache>} args
*/
constructor(...args) {

Expand Down Expand Up @@ -180,38 +171,47 @@ class Cache extends EventEmitter {
this._updating = false;
/** @type {Map<string, FSWatcher>} */
this._watchers = new Map();
this._watching = false;

// Allow multiple elements updates in the same time
this.setMaxListeners(0);

// Start preparing the cache
Cache.prepareCache(this, getCallback(options, callback));
// Start watching process
this.start(getCallback(options, callback));
}

/**
* Destroy the cache data
* @param {() => void} [callback]
*/
destroy() {
destroy(callback) {

// Check if the cache is not already destroyed
if (!this._destroyed) {

// Stop watching the root path for changes
if (this._listener) {
unwatchFile(this.path, this._listener);
}

// Close the fs watchers
this._watchers.forEach((watcher) => {
watcher.close();
});
// Stop watching process
this.stop();

// Mark as destroyed
this._destroyed = true;

// Reset cache properties
this._changed = false;
this._listener = null;
this._ready = false;
this._updating = false;

// Clear the elements container
this._container.clear();

// Emit the destroy event a bit later
setImmediate(() => {
this.emit(destroyEvent);

// Call the provided callback
if (typeof callback === 'function') {
callback();
}
});
}
}
Expand Down Expand Up @@ -267,6 +267,45 @@ class Cache extends EventEmitter {
return list;
}

/**
* Start the watching process
* @param {CacheCallback | null} [callback]
*/
start(callback) {
if (!this._destroyed && !this._watching) {
this._watching = true;

// Start preparing the cache
Cache.prepareCache(this, callback);
}

return this;
}

/**
* Stop the watching process
*/
stop() {
if (!this._destroyed && this._watching) {
this._watching = false;

// Stop watching the root path for changes
if (this._listener) {
unwatchFile(this.path, this._listener);
}

// Close the fs watchers
this._watchers.forEach((watcher) => {
watcher.close();
});

// Clear the fs watchers container
this._watchers.clear();
}

return this;
}

/**
* Add a file system watcher for the provided element path and location
* @param {Cache} cache
Expand All @@ -275,32 +314,35 @@ class Cache extends EventEmitter {
*/
static addWatcher(cache, path, location) {

const watcher = watch(path, cache._options);
if (cache._watching) {

// Add the fs watcher to the list of watchers
cache._watchers.set(location, watcher);
const watcher = watch(path, cache._options);

// Set the fs watcher event listeners
watcher.on(errorEvent, (error) => {
Cache.emitElementError(cache, location, error);
}).on(changeEvent, () => {
Cache.listenChange(cache, location);
});
// Add the fs watcher to the list of watchers
cache._watchers.set(location, watcher);

// Watch root location for rename, move or remove
if (location === rootSymbol) {
// Set the fs watcher event listeners
watcher.on(errorEvent, (error) => {
Cache.emitElementError(cache, location, error);
}).on(changeEvent, () => {
Cache.listenChange(cache, location);
});

// Create and save root change listener
cache._listener = () => {
Cache.listenChange(cache, rootSymbol);
};
// Watch root location for rename, move or remove
if (location === rootSymbol) {

// Watch provided path for changes
watchFile(path, cache._options, cache._listener);
}
// Create and save root change listener
cache._listener = () => {
Cache.listenChange(cache, rootSymbol);
};

// Emit the watched path
cache.emit(watchEvent, path);
// Watch provided path for changes
watchFile(path, cache._options, cache._listener);
}

// Emit the watched path
cache.emit(watchEvent, path);
}
}

/**
Expand Down Expand Up @@ -475,7 +517,7 @@ class Cache extends EventEmitter {
* @param {Cache} cache
* @param {string} location
* @param {string[]} content
* @param {number} [index=0]
* @param {number} [index]
* @returns {Promise<void>}
*/
static async iterateDirectory(cache, location, content, index = 0) {
Expand Down Expand Up @@ -561,7 +603,7 @@ class Cache extends EventEmitter {
/**
* Initiate cache
* @param {Cache} cache
* @param {CacheCallback | null} callback
* @param {CacheCallback | null} [callback]
* @returns {Promise<void>}
*/
static async prepareCache(cache, callback) {
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "recache",
"version": "0.5.3",
"version": "0.6.0",
"description": "File system cache that listens to file changes",
"keywords": [
"cache",
Expand Down Expand Up @@ -30,7 +30,7 @@
"eslint-check": "eslint . --ext .js,.ts",
"eslint-fix": "npm run eslint-check -- --fix",
"prepublishOnly": "npm test && npm run check",
"test": "tap -b test/*.test.js",
"test": "tap -b --no-check-coverage --timeout=60 test/*.test.js",
"test-cov-html": "npm test -- --coverage-report=html",
"test-lcov": "npm test -- --coverage-report=lcov",
"ts-check": "tsc"
Expand All @@ -40,9 +40,9 @@
},
"devDependencies": {
"@types/node": "12.x",
"@typescript-eslint/eslint-plugin": "4.x",
"@typescript-eslint/parser": "4.x",
"eslint": "7.x",
"@typescript-eslint/eslint-plugin": "5.x",
"@typescript-eslint/parser": "5.x",
"eslint": "8.x",
"rimraf": "3.x",
"tap": "15.x",
"typescript": "4.x"
Expand Down
Loading

0 comments on commit ed5bbaa

Please sign in to comment.