1 | 'use strict';
|
2 |
|
3 | var path = require('path');
|
4 | var util = require('util');
|
5 | var fs = require('fs-extra');
|
6 | var isObject = require('is-plain-object');
|
7 | var globby = require('globby');
|
8 | var colorette = require('colorette');
|
9 |
|
10 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
11 |
|
12 | var path__default = _interopDefaultLegacy(path);
|
13 | var util__default = _interopDefaultLegacy(util);
|
14 | var fs__default = _interopDefaultLegacy(fs);
|
15 | var isObject__default = _interopDefaultLegacy(isObject);
|
16 | var globby__default = _interopDefaultLegacy(globby);
|
17 |
|
18 | function stringify(value) {
|
19 | return util__default["default"].inspect(value, {
|
20 | breakLength: Infinity
|
21 | });
|
22 | }
|
23 |
|
24 | async function isFile(filePath) {
|
25 | const fileStats = await fs__default["default"].stat(filePath);
|
26 | return fileStats.isFile();
|
27 | }
|
28 |
|
29 | function 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 |
|
34 | async 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 |
|
59 | function 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 |
|
166 | module.exports = copy;
|