This repository has been archived by the owner on Apr 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
index.js
134 lines (117 loc) · 3.35 KB
/
index.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
const fs = require('fs');
const path = require('path');
const async = require('async');
const glob = require('glob');
const minimatch = require('minimatch');
function gathererFromSourceDirectory(source, pattern, {keepConcatenated}) {
return done => {
// We loop over all the files Metalsmith knows of and return an array of all
// the files contents matching the given pattern
return done(
null,
Object.keys(source).reduce((acc, filepath) => {
if (minimatch(filepath, pattern)) {
acc.push(source[filepath].contents);
if (!keepConcatenated) {
delete source[filepath];
}
}
return acc;
}, [])
);
};
}
function gathererFromSearchPaths(rootPath, searchPaths, pattern) {
return done => {
// We loop over the search paths and return an array of all the files
// contents matching the given pattern
async.map(
searchPaths,
(searchPath, callback) => {
const globPattern = path.resolve(rootPath, searchPath, pattern);
glob.glob(
globPattern,
{
ignore: path.resolve(rootPath, 'src/**/*'),
minimatch,
nodir: true
},
(error, filepaths) => {
if (error) {
return callback(error);
}
async.map(
filepaths.map(filepath => path.resolve(rootPath, filepath)),
fs.readFile,
callback
);
}
);
},
(error, filesContents) => {
if (error) {
return done(error);
}
return done(null, [].concat(...filesContents)); // Shallow flatten
}
);
};
}
function metalsmithifyPath(path) {
return path.replace(/[/\\]+/g, '/');
}
module.exports = (options = {}) => {
if (!(typeof options.output === 'string' && options.output.length > 0)) {
throw new Error(
'`options.output` is mandatory and has to be a non-empty string'
);
}
const output = metalsmithifyPath(options.output);
const patterns = (Array.isArray(options.files) ?
options.files :
(typeof options.files === 'string' ?
[options.files] :
['**/*'])
).map(p => metalsmithifyPath(p));
const EOL = typeof options.insertNewline === 'string' ?
options.insertNewline :
(options.insertNewline === false ?
'' :
'\n');
const searchPaths = Array.isArray(options.searchPaths) ?
options.searchPaths :
(typeof options.searchPaths === 'string' ?
[options.searchPaths] :
[]);
const {forceOutput = false, keepConcatenated = false} = options;
return (files, metalsmith, done) => {
if (output in files && !forceOutput) {
return done(
new Error(
`The file "${output}" already exists, see the documentation for 'options.forceOutput'`
)
);
}
// We reduce the array of patterns into an array of gatherers
const gatherers = patterns.reduce(
(acc, pattern) => [
...acc,
gathererFromSourceDirectory(files, pattern, {keepConcatenated}),
gathererFromSearchPaths(metalsmith._directory, searchPaths, pattern)
],
[]
);
// Gather all the files contents and generate the final concatenated file
async.parallel(gatherers, (error, gatherersResults) => {
if (error) {
return done(error);
}
const filesContents = [
...[].concat(...gatherersResults), // Shallow flatten the results from each gatherers [[a], [b]] -> [a, b]
'' // Append an empty string so that the final join result includes a trailing new line
];
files[output] = {contents: Buffer.from(filesContents.join(EOL))};
return done();
});
};
};