// - scan dirs
|
// - stat items
|
// - hash files
|
// - stat dir items under
|
// - hash files
|
// - hash files
|
|
const crypto = require('crypto');
|
const fs = require('graceful-fs');
|
const path = require('path');
|
|
const pkgDir = require('pkg-dir');
|
|
const promisify = require('./util/promisify');
|
|
const readFile = promisify(fs.readFile);
|
const readdir = promisify(fs.readdir);
|
const stat = promisify(fs.stat);
|
|
function hashFile(file) {
|
return readFile(file)
|
.then(src => [
|
file,
|
crypto
|
.createHash('md5')
|
.update(src)
|
.digest('hex'),
|
])
|
.catch(() => {});
|
}
|
|
function hashObject(obj) {
|
const hash = crypto.createHash('md5');
|
obj.forEach(item => {
|
hash.update(item[0]);
|
hash.update(item[1]);
|
});
|
return hash.digest('hex');
|
}
|
|
function hashFiles(root, files) {
|
return Promise.all(files.map(file => hashFile(path.join(root, file)))).then(
|
hashes => hashes.filter(Boolean),
|
);
|
}
|
|
function flatten(items) {
|
return (items || []).reduce(
|
(carry, item) => (item ? carry.concat(item) : carry),
|
[],
|
);
|
}
|
|
const inputs = async ({ files, directories, root = process.cwd() } = {}) => {
|
let defaults;
|
if (!files && !directories) {
|
const lockFiles = (await Promise.all(
|
['package-lock.json', 'yarn.lock'].map(f =>
|
stat(path.join(root, f)).then(() => f, () => null),
|
),
|
)).filter(Boolean);
|
if (lockFiles.length) {
|
return lockFiles;
|
}
|
}
|
if (!files) {
|
files = ['package.json'];
|
}
|
if (!directories) {
|
directories = ['node_modules'];
|
}
|
directories = directories.map(d => `${d}/*`);
|
return flatten([files, directories]);
|
};
|
|
module.exports = options => {
|
options = options || {};
|
const root = options.root || pkgDir.sync(process.cwd());
|
let files = options.files;
|
let directories = options.directories;
|
|
let hashDefaults = Promise.resolve();
|
if (!files && !directories) {
|
hashDefaults = hashFiles(root, ['package-lock.json', 'yarn.lock']);
|
}
|
|
return hashDefaults
|
.then(_defaults => {
|
if (_defaults && _defaults.length > 0) {
|
return [_defaults];
|
} else {
|
if (!files) {
|
files = ['package.json'];
|
}
|
if (!directories) {
|
directories = ['node_modules'];
|
}
|
}
|
|
return Promise.all([
|
hashFiles(root, files),
|
Promise.all(
|
directories.map(dir =>
|
readdir(path.join(root, dir))
|
.then(items =>
|
Promise.all(
|
items.map(item =>
|
stat(path.join(root, dir, item))
|
.then(stat => {
|
if (stat.isDirectory()) {
|
return hashFiles(path.join(root, dir, item), files);
|
}
|
if (stat.isFile()) {
|
return hashFile(path.join(root, dir, item)).then(
|
hash => (hash ? [hash] : hash),
|
);
|
}
|
})
|
.catch(function(...args) {
|
console.error(args);
|
}),
|
),
|
).then(hashes => hashes.filter(Boolean)),
|
)
|
.catch(() => {})
|
.then(flatten),
|
),
|
).then(flatten),
|
]);
|
})
|
.then(flatten)
|
.then(items => {
|
items.forEach(item => {
|
item[0] = path.relative(root, item[0]);
|
});
|
// console.log(items);
|
items.sort((a, b) => {
|
if (a[0] < b[0]) {
|
return -1;
|
} else if (a[0] > b[0]) {
|
return 1;
|
}
|
return 0;
|
});
|
return hashObject(items);
|
});
|
};
|
|
module.exports.inputs = inputs;
|