UNPKG

4.99 kBJavaScriptView Raw
1'use strict';
2
3var path = require('path');
4var util = require('util');
5var fs = require('fs-extra');
6var isObject = require('is-plain-object');
7var globby = require('globby');
8var colorette = require('colorette');
9
10function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
12var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
13var util__default = /*#__PURE__*/_interopDefaultLegacy(util);
14var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
15var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
16var globby__default = /*#__PURE__*/_interopDefaultLegacy(globby);
17
18function stringify(value) {
19 return util__default["default"].inspect(value, {
20 breakLength: Infinity
21 });
22}
23
24async function isFile(filePath) {
25 const fileStats = await fs__default["default"].stat(filePath);
26 return fileStats.isFile();
27}
28
29function renameTarget(target, rename, src) {
30 const parsedPath = path__default["default"].parse(target);
31 return typeof rename === 'string' ? rename : rename(parsedPath.name, parsedPath.ext.replace('.', ''), src);
32}
33
34async function generateCopyTarget(src, dest, {
35 flatten,
36 rename,
37 transform
38}) {
39 if (transform && !(await isFile(src))) {
40 throw new Error(`"transform" option works only on files: '${src}' must be a file`);
41 }
42
43 const {
44 base,
45 dir
46 } = path__default["default"].parse(src);
47 const destinationFolder = flatten || !flatten && !dir ? dest : dir.replace(dir.split('/')[0], dest);
48 return {
49 src,
50 dest: path__default["default"].join(destinationFolder, rename ? renameTarget(base, rename, src) : base),
51 ...(transform && {
52 contents: await transform(await fs__default["default"].readFile(src), base)
53 }),
54 renamed: rename,
55 transformed: transform
56 };
57}
58
59function copy(options = {}) {
60 const {
61 copyOnce = false,
62 copySync = false,
63 flatten = true,
64 hook = 'buildEnd',
65 targets = [],
66 verbose = false,
67 ...restPluginOptions
68 } = options;
69 let copied = false;
70 return {
71 name: 'copy',
72 [hook]: async () => {
73 if (copyOnce && copied) {
74 return;
75 }
76
77 const copyTargets = [];
78
79 if (Array.isArray(targets) && targets.length) {
80 for (const target of targets) {
81 if (!isObject__default["default"](target)) {
82 throw new Error(`${stringify(target)} target must be an object`);
83 }
84
85 const {
86 dest,
87 rename,
88 src,
89 transform,
90 ...restTargetOptions
91 } = target;
92
93 if (!src || !dest) {
94 throw new Error(`${stringify(target)} target must have "src" and "dest" properties`);
95 }
96
97 if (rename && typeof rename !== 'string' && typeof rename !== 'function') {
98 throw new Error(`${stringify(target)} target's "rename" property must be a string or a function`);
99 }
100
101 const matchedPaths = await globby__default["default"](src, {
102 expandDirectories: false,
103 onlyFiles: false,
104 ...restPluginOptions,
105 ...restTargetOptions
106 });
107
108 if (matchedPaths.length) {
109 for (const matchedPath of matchedPaths) {
110 const generatedCopyTargets = Array.isArray(dest) ? await Promise.all(dest.map(destination => generateCopyTarget(matchedPath, destination, {
111 flatten,
112 rename,
113 transform
114 }))) : [await generateCopyTarget(matchedPath, dest, {
115 flatten,
116 rename,
117 transform
118 })];
119 copyTargets.push(...generatedCopyTargets);
120 }
121 }
122 }
123 }
124
125 if (copyTargets.length) {
126 if (verbose) {
127 console.log(colorette.green('copied:'));
128 }
129
130 for (const copyTarget of copyTargets) {
131 const {
132 contents,
133 dest,
134 src,
135 transformed
136 } = copyTarget;
137
138 if (transformed) {
139 await fs__default["default"].outputFile(dest, contents, restPluginOptions);
140 } else if (!copySync) {
141 await fs__default["default"].copy(src, dest, restPluginOptions);
142 } else {
143 fs__default["default"].copySync(src, dest, restPluginOptions);
144 }
145
146 if (verbose) {
147 let message = colorette.green(` ${colorette.bold(src)}${colorette.bold(dest)}`);
148 const flags = Object.entries(copyTarget).filter(([key, value]) => ['renamed', 'transformed'].includes(key) && value).map(([key]) => key.charAt(0).toUpperCase());
149
150 if (flags.length) {
151 message = `${message} ${colorette.yellow(`[${flags.join(', ')}]`)}`;
152 }
153
154 console.log(message);
155 }
156 }
157 } else if (verbose) {
158 console.log(colorette.yellow('no items to copy'));
159 }
160
161 copied = true;
162 }
163 };
164}
165
166module.exports = copy;