UNPKG

4.07 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * Filesystem cache
5 *
6 * Given a file and a transform function, cache the result into files
7 * or retrieve the previously cached files if the given file is already known.
8 *
9 * @see https://github.com/babel/babel-loader/issues/34
10 * @see https://github.com/babel/babel-loader/pull/41
11 */
12var crypto = require('crypto');
13var mkdirp = require('mkdirp');
14var fs = require('fs');
15var os = require('os');
16var path = require('path');
17var zlib = require('zlib');
18
19/**
20 * Read the contents from the compressed file.
21 *
22 * @async
23 * @params {String} filename
24 * @params {Function} callback
25 */
26var read = function(filename, callback) {
27 return fs.readFile(filename, function(err, data) {
28 if (err) { return callback(err); }
29
30 return zlib.gunzip(data, function(err, content) {
31 var result = {};
32
33 if (err) { return callback(err); }
34
35 try {
36 result = JSON.parse(content);
37 } catch (e) {
38 return callback(e);
39 }
40
41 return callback(null, result);
42 });
43 });
44};
45
46
47/**
48 * Write contents into a compressed file.
49 *
50 * @async
51 * @params {String} filename
52 * @params {String} result
53 * @params {Function} callback
54 */
55var write = function(filename, result, callback) {
56 var content = JSON.stringify(result);
57
58 return zlib.gzip(content, function(err, data) {
59 if (err) { return callback(err); }
60
61 return fs.writeFile(filename, data, callback);
62 });
63};
64
65
66/**
67 * Build the filename for the cached file
68 *
69 * @params {String} source File source code
70 * @params {Object} options Options used
71 *
72 * @return {String}
73 */
74var filename = function(source, identifier, options) {
75 var hash = crypto.createHash('SHA1');
76 var contents = JSON.stringify({
77 source: source,
78 options: options,
79 identifier: identifier,
80 });
81
82 hash.end(contents);
83
84 return hash.read().toString('hex') + '.json.gzip';
85};
86
87/**
88 * Retrieve file from cache, or create a new one for future reads
89 *
90 * @async
91 * @param {Object} params
92 * @param {String} params.directory Directory to store cached files
93 * @param {String} params.identifier Unique identifier to bust cache
94 * @param {String} params.source Original contents of the file to be cached
95 * @param {Object} params.options Options to be given to the transform fn
96 * @param {Function} params.transform Function that will transform the
97 * original file and whose result will be
98 * cached
99 *
100 * @param {Function<err, result>} callback
101 *
102 * @example
103 *
104 * cache({
105 * directory: '.tmp/cache',
106 * identifier: 'babel-loader-cachefile',
107 * source: *source code from file*,
108 * options: {
109 * experimental: true,
110 * runtime: true
111 * },
112 * transform: function(source, options) {
113 * var content = *do what you need with the source*
114 * return content;
115 * }
116 * }, function(err, result) {
117 *
118 * });
119 */
120var cache = module.exports = function(params, callback) {
121 // Spread params into named variables
122 // Forgive user whenever possible
123 var source = params.source;
124 var options = params.options || {};
125 var transform = params.transform;
126 var identifier = params.identifier;
127 var directory = (typeof params.directory === 'string') ?
128 params.directory :
129 os.tmpdir();
130 var file = path.join(directory, filename(source, identifier, options));
131
132 // Make sure the directory exists.
133 return mkdirp(directory, function(err) {
134 if (err) { return callback(err); }
135
136 return read(file, function(err, content) {
137 var result = {};
138 // No errors mean that the file was previously cached
139 // we just need to return it
140 if (!err) { return callback(null, content); }
141
142 // Otherwise just transform the file
143 // return it to the user asap and write it in cache
144 try {
145 result = transform(source, options);
146 } catch (error) {
147 return callback(error);
148 }
149
150 return write(file, result, function(err) {
151 return callback(err, result);
152 });
153 });
154 });
155};