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 | 'use strict'
|
26 |
|
27 |
|
28 | const fs = require('fs')
|
29 | const path = require('path')
|
30 |
|
31 |
|
32 | const bubbleError = require('bubble-stream-error')
|
33 | const { globSync } = require('glob')
|
34 | const isDirectory = require('is-directory')
|
35 | const sharp = require('sharp')
|
36 |
|
37 |
|
38 | const queue = require('./queue')
|
39 |
|
40 |
|
41 | const EXTENSIONS = {
|
42 | avif: '.avif',
|
43 | dz: '',
|
44 | gif: '.gif',
|
45 | heif: '.avif',
|
46 | jpeg: '.jpg',
|
47 | png: '.png',
|
48 | tiff: '.tiff',
|
49 | webp: '.webp'
|
50 | }
|
51 |
|
52 |
|
53 | module.exports = {
|
54 |
|
55 | files: (input, output, options) => {
|
56 |
|
57 | const files = input.reduce((list, input) => {
|
58 | return list.concat(globSync(input, { absolute: true }))
|
59 | }, [])
|
60 |
|
61 | if (files.length === 0) {
|
62 | return Promise.reject(new Error('No input files'))
|
63 | }
|
64 |
|
65 |
|
66 | const isBatch = files.length > 1
|
67 | const promises = files.map((src) => {
|
68 |
|
69 | const transformer = queue.drain(sharp(options))
|
70 |
|
71 |
|
72 | const parts = path.parse(src)
|
73 | const regex = /\{(root|dir|base|ext|name)\}/g
|
74 | let dest = output
|
75 | let match
|
76 | while ((match = regex.exec(output)) !== null) {
|
77 | const [search, prop] = match
|
78 | dest = dest.replace(search, parts[prop])
|
79 | }
|
80 | dest = path.resolve(dest)
|
81 |
|
82 |
|
83 |
|
84 | const outputAssumeDir = dest === path.resolve(output) && isBatch
|
85 | if (outputAssumeDir || isDirectory.sync(dest)) {
|
86 | const defaultExt = path.extname(src)
|
87 | const desiredExt = transformer.options.formatOut
|
88 | dest = path.format({
|
89 | dir: dest,
|
90 | name: path.basename(src, defaultExt),
|
91 | ext: desiredExt in EXTENSIONS ? EXTENSIONS[desiredExt] : defaultExt
|
92 | })
|
93 | }
|
94 |
|
95 |
|
96 | fs.createReadStream(src).pipe(transformer)
|
97 | return transformer
|
98 | .toFile(dest)
|
99 | .then((info) => Object.assign(info, { src, path: dest }))
|
100 | })
|
101 | return Promise.all(promises)
|
102 | },
|
103 |
|
104 |
|
105 | stream: (inStream, outStream, options) => {
|
106 | return new Promise((resolve, reject) => {
|
107 |
|
108 | const transformer = queue.drain(sharp(options))
|
109 |
|
110 |
|
111 | const info = { }
|
112 | transformer.on('info', (_info) => Object.assign(info, _info))
|
113 |
|
114 |
|
115 | bubbleError(inStream, transformer, outStream)
|
116 | inStream.pipe(transformer).pipe(outStream)
|
117 | outStream.once('error', reject)
|
118 | outStream.on('finish', () => resolve(info))
|
119 | })
|
120 | }
|
121 | }
|