/
hash-store.js
98 lines (82 loc) · 2.28 KB
/
hash-store.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
const fs = require('node:fs/promises');
const path = require('node:path');
const debug = require('debug')('connect:cachify-static');
const calculateHash = require('./hash');
module.exports = hashStore;
async function hashStore(root, match, formatPathFn) {
async function format(path, file) {
const hash = await calculateHash(file);
return {
path: formatPathFn(path, hash.value),
integrity: hash.integrity
};
}
const my = {
hashes2paths: Object.create(null),
paths2hashes: Object.create(null)
};
debug('Calculating hashes for files in %s.', root);
const files = await readdir(root, {
filter: makeFilter(match)
});
const tasks = files.map(async file => {
const path = file.slice(root.length);
const hash = await format(path, file);
my.hashes2paths[hash.path] = path;
my.paths2hashes[path] = hash;
});
await Promise.all(tasks);
debug('Calculating hashes for %d files', Object.keys(my.paths2hashes).length);
debug('Calculated %j', my);
return {
getPath,
getHash,
cachify,
filter
};
function getPath(hash) {
return hash && my.hashes2paths[hash];
}
function getHash(path, integrity) {
const v = my.paths2hashes[path];
if (v) {
return integrity ? v : v.path;
}
}
function cachify(path, integrity) {
const hash = getHash(path, integrity);
if (!hash) {
debug('cachify called for unknown path %s', path);
return integrity ? { path } : path;
}
return hash;
}
function filter(match, integrity) {
const is = makeFilter(match);
return Object.keys(my.paths2hashes)
.filter(is)
.map(path => getHash(path, integrity));
}
}
function makeFilter(value = true) {
if (Array.isArray(value)) {
const filters = value.map(makeFilter);
return file => filters.some(filter => filter(file));
}
if (typeof value === 'function') {
return file => value(file);
}
if (typeof value === 'string') {
return file => file === value;
}
if (value instanceof RegExp) {
return file => value.test(file);
}
if (typeof value === 'boolean') {
return () => value;
}
}
async function readdir(root, { filter }) {
const files = await fs.readdir(root, { recursive: true });
return files.map(n => path.resolve(root, n)).filter(filter);
}