123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
- const { forEachBail } = require("enhanced-resolve");
- const asyncLib = require("neo-async");
- const getLazyHashedEtag = require("./cache/getLazyHashedEtag");
- const mergeEtags = require("./cache/mergeEtags");
- /** @typedef {import("./Cache")} Cache */
- /** @typedef {import("./Cache").Etag} Etag */
- /** @typedef {import("./WebpackError")} WebpackError */
- /** @typedef {import("./cache/getLazyHashedEtag").HashableObject} HashableObject */
- /** @typedef {typeof import("./util/Hash")} HashConstructor */
- /**
- * @template T
- * @callback CallbackCache
- * @param {(Error | null)=} err
- * @param {(T | null)=} result
- * @returns {void}
- */
- /**
- * @template T
- * @callback CallbackNormalErrorCache
- * @param {(Error | null)=} err
- * @param {T=} result
- * @returns {void}
- */
- class MultiItemCache {
- /**
- * @param {ItemCacheFacade[]} items item caches
- */
- constructor(items) {
- this._items = items;
- if (items.length === 1) return /** @type {any} */ (items[0]);
- }
- /**
- * @template T
- * @param {CallbackCache<T>} callback signals when the value is retrieved
- * @returns {void}
- */
- get(callback) {
- forEachBail(this._items, (item, callback) => item.get(callback), callback);
- }
- /**
- * @template T
- * @returns {Promise<T>} promise with the data
- */
- getPromise() {
- /**
- * @param {number} i index
- * @returns {Promise<T>} promise with the data
- */
- const next = i => {
- return this._items[i].getPromise().then(result => {
- if (result !== undefined) return result;
- if (++i < this._items.length) return next(i);
- });
- };
- return next(0);
- }
- /**
- * @template T
- * @param {T} data the value to store
- * @param {CallbackCache<void>} callback signals when the value is stored
- * @returns {void}
- */
- store(data, callback) {
- asyncLib.each(
- this._items,
- (item, callback) => item.store(data, callback),
- callback
- );
- }
- /**
- * @template T
- * @param {T} data the value to store
- * @returns {Promise<void>} promise signals when the value is stored
- */
- storePromise(data) {
- return Promise.all(this._items.map(item => item.storePromise(data))).then(
- () => {}
- );
- }
- }
- class ItemCacheFacade {
- /**
- * @param {Cache} cache the root cache
- * @param {string} name the child cache item name
- * @param {Etag | null} etag the etag
- */
- constructor(cache, name, etag) {
- this._cache = cache;
- this._name = name;
- this._etag = etag;
- }
- /**
- * @template T
- * @param {CallbackCache<T>} callback signals when the value is retrieved
- * @returns {void}
- */
- get(callback) {
- this._cache.get(this._name, this._etag, callback);
- }
- /**
- * @template T
- * @returns {Promise<T>} promise with the data
- */
- getPromise() {
- return new Promise((resolve, reject) => {
- this._cache.get(this._name, this._etag, (err, data) => {
- if (err) {
- reject(err);
- } else {
- resolve(data);
- }
- });
- });
- }
- /**
- * @template T
- * @param {T} data the value to store
- * @param {CallbackCache<void>} callback signals when the value is stored
- * @returns {void}
- */
- store(data, callback) {
- this._cache.store(this._name, this._etag, data, callback);
- }
- /**
- * @template T
- * @param {T} data the value to store
- * @returns {Promise<void>} promise signals when the value is stored
- */
- storePromise(data) {
- return new Promise((resolve, reject) => {
- this._cache.store(this._name, this._etag, data, err => {
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- });
- }
- /**
- * @template T
- * @param {function(CallbackNormalErrorCache<T>): void} computer function to compute the value if not cached
- * @param {CallbackNormalErrorCache<T>} callback signals when the value is retrieved
- * @returns {void}
- */
- provide(computer, callback) {
- this.get((err, cacheEntry) => {
- if (err) return callback(err);
- if (cacheEntry !== undefined) return cacheEntry;
- computer((err, result) => {
- if (err) return callback(err);
- this.store(result, err => {
- if (err) return callback(err);
- callback(null, result);
- });
- });
- });
- }
- /**
- * @template T
- * @param {function(): Promise<T> | T} computer function to compute the value if not cached
- * @returns {Promise<T>} promise with the data
- */
- async providePromise(computer) {
- const cacheEntry = await this.getPromise();
- if (cacheEntry !== undefined) return cacheEntry;
- const result = await computer();
- await this.storePromise(result);
- return result;
- }
- }
- class CacheFacade {
- /**
- * @param {Cache} cache the root cache
- * @param {string} name the child cache name
- * @param {(string | HashConstructor)=} hashFunction the hash function to use
- */
- constructor(cache, name, hashFunction) {
- this._cache = cache;
- this._name = name;
- this._hashFunction = hashFunction;
- }
- /**
- * @param {string} name the child cache name#
- * @returns {CacheFacade} child cache
- */
- getChildCache(name) {
- return new CacheFacade(
- this._cache,
- `${this._name}|${name}`,
- this._hashFunction
- );
- }
- /**
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @returns {ItemCacheFacade} item cache
- */
- getItemCache(identifier, etag) {
- return new ItemCacheFacade(
- this._cache,
- `${this._name}|${identifier}`,
- etag
- );
- }
- /**
- * @param {HashableObject} obj an hashable object
- * @returns {Etag} an etag that is lazy hashed
- */
- getLazyHashedEtag(obj) {
- return getLazyHashedEtag(obj, this._hashFunction);
- }
- /**
- * @param {Etag} a an etag
- * @param {Etag} b another etag
- * @returns {Etag} an etag that represents both
- */
- mergeEtags(a, b) {
- return mergeEtags(a, b);
- }
- /**
- * @template T
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @param {CallbackCache<T>} callback signals when the value is retrieved
- * @returns {void}
- */
- get(identifier, etag, callback) {
- this._cache.get(`${this._name}|${identifier}`, etag, callback);
- }
- /**
- * @template T
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @returns {Promise<T>} promise with the data
- */
- getPromise(identifier, etag) {
- return new Promise((resolve, reject) => {
- this._cache.get(`${this._name}|${identifier}`, etag, (err, data) => {
- if (err) {
- reject(err);
- } else {
- resolve(data);
- }
- });
- });
- }
- /**
- * @template T
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @param {T} data the value to store
- * @param {CallbackCache<void>} callback signals when the value is stored
- * @returns {void}
- */
- store(identifier, etag, data, callback) {
- this._cache.store(`${this._name}|${identifier}`, etag, data, callback);
- }
- /**
- * @template T
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @param {T} data the value to store
- * @returns {Promise<void>} promise signals when the value is stored
- */
- storePromise(identifier, etag, data) {
- return new Promise((resolve, reject) => {
- this._cache.store(`${this._name}|${identifier}`, etag, data, err => {
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- });
- }
- /**
- * @template T
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @param {function(CallbackNormalErrorCache<T>): void} computer function to compute the value if not cached
- * @param {CallbackNormalErrorCache<T>} callback signals when the value is retrieved
- * @returns {void}
- */
- provide(identifier, etag, computer, callback) {
- this.get(identifier, etag, (err, cacheEntry) => {
- if (err) return callback(err);
- if (cacheEntry !== undefined) return cacheEntry;
- computer((err, result) => {
- if (err) return callback(err);
- this.store(identifier, etag, result, err => {
- if (err) return callback(err);
- callback(null, result);
- });
- });
- });
- }
- /**
- * @template T
- * @param {string} identifier the cache identifier
- * @param {Etag | null} etag the etag
- * @param {function(): Promise<T> | T} computer function to compute the value if not cached
- * @returns {Promise<T>} promise with the data
- */
- async providePromise(identifier, etag, computer) {
- const cacheEntry = await this.getPromise(identifier, etag);
- if (cacheEntry !== undefined) return cacheEntry;
- const result = await computer();
- await this.storePromise(identifier, etag, result);
- return result;
- }
- }
- module.exports = CacheFacade;
- module.exports.ItemCacheFacade = ItemCacheFacade;
- module.exports.MultiItemCache = MultiItemCache;
|