forked from zestedesavoir/zmarkdown
/
index.js
108 lines (89 loc) · 3.09 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
const visit = require('unist-util-visit')
const fs = require('fs')
const path = require('path')
const request = require('request-promise')
const shortid = require('shortid')
const url = require('url')
const requestParser = (body, response, resolveWithFullResponse) =>
({response: response, body: body})
const writeFile = (file, data, options) => new Promise((resolve, reject) => {
const cb = (err) => {
if (err) reject(err)
resolve()
}
if (options) {
fs.writeFile(file, data, options, cb)
} else {
fs.writeFile(file, data, cb)
}
})
const mkdir = (path) => new Promise((resolve, reject) => {
fs.stat(path, (err, stats) => {
if (err) {
return fs.mkdir(path, (err) => {
if (err) reject(new Error(`Failed to create dir ${path}`))
resolve()
})
}
if (!stats.isDirectory()) {
reject(new Error(`${path} is not a directory!`))
}
resolve()
})
})
function plugin ({
downloadImages = true,
maxFileSize = 1000000,
dirSizeLimit = 10000000,
downloadDestination = './',
report = console.error
} = {}) {
return function transform (tree) {
if (downloadImages !== true) return
let totalDownloadedSize = 0
// images are downloaded in destinationPath
const destinationPath = path.join(downloadDestination, shortid.generate())
return mkdir(destinationPath)
.then(() => {
const promises = [Promise.resolve()]
visit(tree, 'image', function (node) {
const parsedURI = url.parse(node.url)
if (!parsedURI.host) return
const extension = path.extname(parsedURI.pathname)
const basename = `${shortid.generate()}${extension}`
const destination = path.join(destinationPath, basename)
const imageURL = node.url
promises.push(
isDownloadable(imageURL)
.then(() => request({uri: imageURL, transform: requestParser}))
.then(({body}) => writeFile(destination, body))
.then(() => { node.url = destination })
.catch((err) => report(err)))
})
return Promise.all(promises)
})
.catch((err) => report(err))
.then(() => tree)
function isDownloadable (uri) {
return request.head({uri: uri, transform: requestParser})
.then(({response}) => new Promise((resolve, reject) => {
if (response.headers['content-type'].substring(0, 6) !== 'image/') {
reject(new Error(`Content-Type of ${uri} is not of image/ type`))
}
const fileSize = parseInt(response.headers['content-length'], 10)
if (maxFileSize && fileSize > maxFileSize) {
reject(new Error(
`File at ${uri} weighs ${response.headers['content-length']}, ` +
`max size is ${maxFileSize}`))
}
if (dirSizeLimit && (totalDownloadedSize + fileSize) >= dirSizeLimit) {
reject(new Error(
`Cannot download ${uri} because destination directory reached size limit`))
}
totalDownloadedSize += fileSize
resolve()
}))
}
}
}
module.exports = plugin