"use strict"; var _fs = _interopRequireDefault(require("fs")); var _os = _interopRequireDefault(require("os")); var _path = require("path"); var _util = require("util"); var _zlib = _interopRequireDefault(require("zlib")); var _crypto = require("crypto"); var _findCacheDir = _interopRequireDefault(require("find-cache-dir")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Original Filesystem Cache implementation by babel-loader * Licensed under the MIT License * * @see https://github.com/babel/babel-loader/commits/master/src/fs-cache.js * @see https://github.com/babel/babel-loader/commits/master/src/cache.js */ /** * Filesystem Cache * * Given a file and a transform function, cache the result into files * or retrieve the previously cached files if the given file is already known. * * @see https://github.com/babel/babel-loader/issues/34 * @see https://github.com/babel/babel-loader/pull/41 */ // Lazily instantiated when needed let defaultCacheDirectory = null; const readFile = (0, _util.promisify)(_fs.default.readFile); const writeFile = (0, _util.promisify)(_fs.default.writeFile); const gunzip = (0, _util.promisify)(_zlib.default.gunzip); const gzip = (0, _util.promisify)(_zlib.default.gzip); /** * Read the contents from the compressed file. * * @async * @params {String} filename * @params {Boolean} compress */ const read = async (filename, compress) => { const data = await readFile(filename + (compress ? '.gz' : '')); const content = compress ? await gunzip(data) : data; return JSON.parse(content.toString()); }; /** * Write contents into a compressed file. * * @async * @params {String} filename * @params {Boolean} compress * @params {String} result */ const write = async (filename, compress, result) => { const content = JSON.stringify(result); const data = compress ? await gzip(content) : content; return writeFile(filename + (compress ? '.gz' : ''), data); }; /** * Build the filename for the cached file * * @params {String} source File source code * @params {String} identifier * @params {Object} options Options used * * @return {String} */ const filename = (source, identifier, options) => { const hash = (0, _crypto.createHash)('md4'); const contents = JSON.stringify({ source, options, identifier }); hash.update(contents); return `${hash.digest('hex')}.json`; }; /** * Handle the cache * * @params {String} directory * @params {Object} params */ const handleCache = async (directory, params) => { const { source, options = {}, transform, cacheIdentifier, cacheDirectory, cacheCompression } = params; const file = (0, _path.join)(directory, filename(source, cacheIdentifier, options)); try { // No errors mean that the file was previously cached // we just need to return it return await read(file, cacheCompression); // eslint-disable-next-line no-empty } catch (err) {} const fallback = typeof cacheDirectory !== 'string' && directory !== _os.default.tmpdir(); // Make sure the directory exists. try { _fs.default.mkdirSync(directory, { recursive: true }); } catch (err) { if (fallback) { return handleCache(_os.default.tmpdir(), params); } throw err; } // Otherwise just transform the file // return it to the user asap and write it in cache const result = await transform(source, options); try { await write(file, cacheCompression, result); } catch (err) { if (fallback) { // Fallback to tmpdir if node_modules folder not writable return handleCache(_os.default.tmpdir(), params); } throw err; } return result; }; /** * Retrieve file from cache, or create a new one for future reads * * @async * @param {Object} params * @param {String} params.cacheDirectory Directory to store cached files * @param {String} params.cacheIdentifier Unique identifier to bust cache * @param {Boolean} params.cacheCompression * @param {String} params.source Original contents of the file to be cached * @param {Object} params.options Options to be given to the transform fn * @param {Function} params.transform Function that will transform the * original file and whose result will be * cached * * @example * * cache({ * cacheDirectory: '.tmp/cache', * cacheIdentifier: 'babel-loader-cachefile', * cacheCompression: true, * source: *source code from file*, * options: { * experimental: true, * runtime: true * }, * transform: function(source, options) { * var content = *do what you need with the source* * return content; * } * }); */ module.exports = async params => { let directory; if (typeof params.cacheDirectory === 'string') { directory = params.cacheDirectory; } else { if (defaultCacheDirectory === null) { defaultCacheDirectory = (0, _findCacheDir.default)({ name: 'eslint-loader' }) || _os.default.tmpdir(); } directory = defaultCacheDirectory; } return handleCache(directory, params); };