|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- 'use strict';
- const fs = require('fs');
- const path = require('path');
- const hasha = require('hasha');
- const makeDir = require('make-dir');
- const writeFileAtomic = require('write-file-atomic');
- const packageHash = require('package-hash');
-
- let ownHash = '';
- function getOwnHash() {
- ownHash = packageHash.sync(path.join(__dirname, 'package.json'));
- return ownHash;
- }
-
- function wrap(opts) {
- if (!(opts.factory || opts.transform) || (opts.factory && opts.transform)) {
- throw new Error('Specify factory or transform but not both');
- }
-
- if (typeof opts.cacheDir !== 'string' && !opts.disableCache) {
- throw new Error('cacheDir must be a string');
- }
-
- opts = {
- ext: '',
- salt: '',
- hashData: () => [],
- filenamePrefix: () => '',
- onHash: () => {},
- ...opts
- };
-
- let transformFn = opts.transform;
- const {factory, cacheDir, shouldTransform, disableCache, hashData, onHash, filenamePrefix, ext, salt} = opts;
- const cacheDirCreated = opts.createCacheDir === false;
- let created = transformFn && cacheDirCreated;
- const encoding = opts.encoding === 'buffer' ? undefined : opts.encoding || 'utf8';
-
- function transform(input, metadata, hash) {
- if (!created) {
- if (!cacheDirCreated && !disableCache) {
- makeDir.sync(cacheDir);
- }
-
- if (!transformFn) {
- transformFn = factory(cacheDir);
- }
-
- created = true;
- }
-
- return transformFn(input, metadata, hash);
- }
-
- return function (input, metadata) {
- if (shouldTransform && !shouldTransform(input, metadata)) {
- return input;
- }
-
- if (disableCache) {
- return transform(input, metadata);
- }
-
- const data = [
- ownHash || getOwnHash(),
- input,
- salt,
- ...[].concat(hashData(input, metadata))
- ];
- const hash = hasha(data, {algorithm: 'sha256'});
- const cachedPath = path.join(cacheDir, filenamePrefix(metadata) + hash + ext);
-
- onHash(input, metadata, hash);
-
- let result;
- let retry = 0;
- /* eslint-disable-next-line no-constant-condition */
- while (true) {
- try {
- return fs.readFileSync(cachedPath, encoding);
- } catch (readError) {
- if (!result) {
- result = transform(input, metadata, hash);
- }
-
- try {
- writeFileAtomic.sync(cachedPath, result, {encoding});
- return result;
- } catch (error) {
- /* Likely https://github.com/npm/write-file-atomic/issues/28
- * Make up to 3 attempts to read or write the cache. */
- retry++;
- if (retry > 3) {
- throw error;
- }
- }
- }
- }
- };
- }
-
- module.exports = wrap;
|