UNPKG

2.14 kBJavaScriptView Raw
1const fs = require('fs');
2const path = require('path');
3const debug = require('debug')('metalsmith-changed');
4const mm = require('micromatch');
5const DEFAULTS = {
6 force: false,
7 forcePattern: false,
8 ctimes: 'metalsmith-changed-ctimes.json' // where to store ctimes
9};
10
11module.exports = function (opts) {
12 opts = Object.assign({}, DEFAULTS, opts);
13 debug(`options: ${JSON.stringify(opts)}`);
14
15 /**
16 * Return true if filename does not match `opts.forcePattern`.
17 */
18 const notForced = function (filename) {
19 const pattern = opts.forcePattern;
20 return pattern === false || !mm.isMatch(filename, pattern);
21 };
22
23 /**
24 * Write ctimes to `filename`.
25 *
26 * @param files {object}
27 * @param filename {string}
28 */
29 function createCtimes (files, filename) {
30 // write ctimes to input folder
31 let ctimes = {}; // { 'index.md': 1464763631540, ... }
32 let filenames = Object.keys(files);
33 for (let f of filenames) {
34 if (!hasCtime(files[f])) {
35 continue;
36 }
37 let ctime = files[f].stats.ctime.getTime();
38 debug(`ctime ${f}: ${ctime}`);
39 ctimes[f] = ctime;
40 }
41 fs.writeFileSync(filename, JSON.stringify(ctimes, null, 2));
42 }
43
44 return function changed (files, metalsmith, done) {
45 // files are already read => safe to write current ctimes
46 createCtimes(files, path.join(metalsmith.source(), opts.ctimes));
47 if (metalsmith.clean() || opts.force || !files[opts.ctimes]) {
48 debug('building all files');
49 } else {
50 const prevCtimes = JSON.parse(files[opts.ctimes].contents.toString());
51 const filenames = Object.keys(files).filter(notForced);
52 for (let f of filenames) {
53 if (!hasCtime(files[f])) {
54 debug(`${f} does not have ctime`);
55 continue;
56 }
57 // file has not changed
58 if (prevCtimes[f] && files[f].stats.ctime.getTime() === prevCtimes[f]) {
59 debug(`skipping ${f}`);
60 delete files[f];
61 }
62 }
63 }
64 // remove opts.ctimes from the build
65 delete files[opts.ctimes];
66 done();
67 };
68};
69
70function hasCtime (file) {
71 return file.stats && file.stats.ctime;
72}
73