UNPKG

3.81 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs');
4var path = require('path');
5var debug = require('debug')('metalsmith-changed');
6var mm = require('micromatch');
7var DEFAULTS = {
8 force: false,
9 forcePattern: false,
10 forceAllPattern: false,
11 ctimes: 'metalsmith-changed-ctimes.json' // where to store ctimes
12};
13
14module.exports = function (opts) {
15 opts = Object.assign({}, DEFAULTS, opts);
16 debug('options: ' + JSON.stringify(opts));
17
18 /**
19 * Return true if filename does not match `opts.forcePattern`.
20 */
21 var notForced = function notForced(filename) {
22 var pattern = opts.forcePattern;
23 return pattern === false || !mm.any(filename, pattern);
24 };
25
26 return function changed(files, metalsmith, done) {
27 // files are already read => safe to write current ctimes
28 files[opts.ctimes] = createCtimes(files);
29 if (metalsmith.clean() || opts.force || contains(files, opts.forceAllPattern)) {
30 debug('building all files');
31 } else {
32 var prevCtimes = readCtimes(metalsmith.destination(), opts.ctimes);
33 var filenames = Object.keys(files).filter(notForced);
34 var _iteratorNormalCompletion = true;
35 var _didIteratorError = false;
36 var _iteratorError = undefined;
37
38 try {
39 for (var _iterator = filenames[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
40 var f = _step.value;
41
42 if (!hasCtime(files[f])) {
43 debug(f + ' does not have ctime');
44 continue;
45 }
46 // file has not changed
47 if (prevCtimes[f] && files[f].stats.ctime.getTime() === prevCtimes[f]) {
48 debug('skipping ' + f);
49 delete files[f];
50 }
51 }
52 } catch (err) {
53 _didIteratorError = true;
54 _iteratorError = err;
55 } finally {
56 try {
57 if (!_iteratorNormalCompletion && _iterator.return) {
58 _iterator.return();
59 }
60 } finally {
61 if (_didIteratorError) {
62 throw _iteratorError;
63 }
64 }
65 }
66 }
67 done();
68 };
69};
70
71function hasCtime(file) {
72 return file.stats && file.stats.ctime;
73}
74
75/**
76 * Create a ctimes object of files.
77 *
78 * @param files {object}
79 * @returns {object} Ctimes, { filename: Date.getTime(), ... }
80 */
81function createCtimes(files) {
82 var ctimes = {}; // { 'index.md': 1464763631540, ... }
83 var filenames = Object.keys(files);
84 var _iteratorNormalCompletion2 = true;
85 var _didIteratorError2 = false;
86 var _iteratorError2 = undefined;
87
88 try {
89 for (var _iterator2 = filenames[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
90 var f = _step2.value;
91
92 if (!hasCtime(files[f])) {
93 continue;
94 }
95 var ctime = files[f].stats.ctime.getTime();
96 debug('ctime ' + f + ': ' + ctime);
97 ctimes[f] = ctime;
98 }
99 } catch (err) {
100 _didIteratorError2 = true;
101 _iteratorError2 = err;
102 } finally {
103 try {
104 if (!_iteratorNormalCompletion2 && _iterator2.return) {
105 _iterator2.return();
106 }
107 } finally {
108 if (_didIteratorError2) {
109 throw _iteratorError2;
110 }
111 }
112 }
113
114 return { contents: JSON.stringify(ctimes, null, 2) };
115}
116
117/**
118 * Get ctimes from filename.
119 *
120 * @param folder {string} Path to destination folder.
121 * @param filename {string} Filename.
122 * @returns {object} Ctimes object.
123 */
124function readCtimes(folder, filename) {
125 try {
126 var content = fs.readFileSync(path.join(folder, filename), 'utf8');
127 return JSON.parse(content);
128 } catch (e) {
129 return {};
130 }
131}
132
133/**
134 * Returns true if some of the files matches the pattern.
135 */
136function contains(files, pattern) {
137 return mm(Object.keys(files), pattern).length !== 0;
138}