-
Notifications
You must be signed in to change notification settings - Fork 9
/
index.js
108 lines (91 loc) · 2.69 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
import { parse } from 'path'
import { cloneDeep } from 'lodash'
import minimatch from 'minimatch'
import Debug from 'debug'
import Sharp from 'sharp'
const debug = Debug('metalsmith-sharp')
function replacePlaceholders(text, placeholders) {
return text.replace(/\{([^}]+)\}/g, (match, pattern) => {
if (pattern in placeholders) {
return placeholders[pattern]
}
return match
})
}
function getReplacements(path) {
const parsedPath = parse(path)
if (parsedPath.dir.length) {
parsedPath.dir = `${parsedPath.dir}/`
}
return parsedPath
}
function runSharp(image, options) {
const sharp = Sharp(image.contents)
return sharp.metadata().then((metadata) => {
options.methods.forEach((method) => {
let args
if (typeof method.args === 'function') {
args = method.args(metadata)
} else {
args = [].concat(method.args)
}
sharp[method.name](...args)
})
return sharp.toBuffer()
})
}
export default function(userOptions) {
const defaultOptions = {
src: '**/*.jpg',
namingPattern: '{dir}{base}',
methods: [],
moveFile: false,
}
const optionsList = [].concat(userOptions)
// Return metalsmith plugin.
return function(files, metalsmith, done) {
Object.keys(files)
.reduce((fileSequence, filename) => {
return fileSequence.then(() => {
const file = files[filename]
const replacements = getReplacements(filename)
// Iterate over all option sets.
return optionsList.reduce((stepSequence, options) => {
const stepOptions = {
...defaultOptions,
...options,
}
if (!minimatch(filename, stepOptions.src)) {
return stepSequence
}
debug(`processing ${filename}`)
const image = cloneDeep(file)
// Run sharp and save new file.
return stepSequence
.then(() => runSharp(image, stepOptions))
.catch((err) => {
err.message = `Could not process file "${filename}":\n${err.message}`
return Promise.reject(err)
})
.then((buffer, info) => {
const dist = replacePlaceholders(
stepOptions.namingPattern,
replacements
)
image.contents = buffer
files[dist] = image
if (filename !== dist && stepOptions.moveFile) {
delete files[filename]
}
})
}, Promise.resolve())
})
}, Promise.resolve())
.then(() => {
done()
})
.catch((err) => {
done(err)
})
}
}