From 6b5223d3ade359749af7f424cddb0383b52d2d52 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Tue, 20 Mar 2018 20:51:13 +0800 Subject: [PATCH] lib: add cache utility --- .gitignore | 1 + lib/cache.js | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 lib/cache.js diff --git a/.gitignore b/.gitignore index aa03f654..b18e0d55 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ tmp coverage.lcov tmp-* .eslintcache +.ncu diff --git a/lib/cache.js b/lib/cache.js new file mode 100644 index 00000000..3dc5ccc2 --- /dev/null +++ b/lib/cache.js @@ -0,0 +1,103 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const { writeJson, readJson, writeFile, readFile } = require('./file'); + +function isAsync(fn) { + return fn[Symbol.toStringTag] === 'AsyncFunction'; +} + +class Cache { + constructor(dir) { + this.dir = dir || path.join(__dirname, '..', '.ncu', 'cache'); + this.originals = {}; + this.disabled = process.argv.includes('--enable-cache'); + } + + disable() { + this.disabled = true; + } + + enable() { + this.disabled = false; + } + + getFilename(key, ext) { + return path.join(this.dir, key) + ext; + } + + has(key, ext) { + if (this.disabled) { + return false; + } + + return fs.existsSync(this.getFilename(key, ext)); + } + + get(key, ext) { + if (!this.has(key, ext)) { + return undefined; + } + if (ext === '.json') { + return readJson(this.getFilename(key, ext)); + } else { + return readFile(this.getFilename(key, ext)); + } + } + + write(key, ext, content) { + if (this.disabled) { + return; + } + const filename = this.getFilename(key, ext); + if (ext === '.json') { + return writeJson(filename, content); + } else { + return writeFile(filename, content); + } + } + + wrapAsync(original, identity) { + const cache = this; + return async function(...args) { + const { key, ext } = identity.call(this, ...args); + const cached = cache.get(key, ext); + if (cached) { + return cached; + } + const result = await original.call(this, ...args); + cache.write(key, ext, result); + return result; + }; + } + + wrapNormal(original, identity) { + const cache = this; + return function(...args) { + const { key, ext } = identity.call(this, ...args); + const cached = cache.get(key, ext); + if (cached) { + return cached; + } + const result = original.call(this, ...args); + cache.write(key, ext, result); + return result; + }; + } + + wrap(Class, identities) { + for (let method of Object.keys(identities)) { + const original = Class.prototype[method]; + const identity = identities[method]; + this.originals[method] = original; + if (isAsync(original)) { + Class.prototype[method] = this.wrapAsync(original, identity); + } else { + Class.prototype[method] = this.wrapNormal(original, identity); + } + } + } +} + +module.exports = Cache;