-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy path_copy.js
More file actions
138 lines (115 loc) · 3.66 KB
/
_copy.js
File metadata and controls
138 lines (115 loc) · 3.66 KB
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import util from "node:util";
import path from "node:path";
import fs from "fs-extra";
import { globby } from "globby";
import { bold, green, yellow } from "colorette";
// These are a simplified version of rollup-plugin-copy (https://github.com/vladshcherbin/rollup-plugin-copy)
function stringify(value) {
return util.inspect(value, { breakLength: Infinity });
}
async function isFile(filePath) {
try {
const fileStats = await fs.stat(filePath);
return fileStats.isFile();
} catch {
return false;
}
}
async function isDirectory(filePath) {
try {
const fileStats = await fs.stat(filePath);
return fileStats.isDirectory();
} catch {
return false;
}
}
function isObject(value) {
return value !== null && typeof value === "object";
}
/**
* Get a target ready for globby by following the same basic context/src
* conversion rules as `copy-webpack-plugin`.
*
* Ref: https://github.com/webpack-contrib/copy-webpack-plugin/blob/master/README.md#different-variants-of-from-glob-file-or-dir
*/
async function normalizeTarget({ context, src, ...rest }) {
const result = { ...rest };
if (context) {
result.context = context;
result.src = src;
} else if (await isFile(src)) {
result.context = path.dirname(src);
result.src = path.basename(src);
} else if (await isDirectory(src)) {
result.context = src;
result.src = "**/*";
} else {
result.context = ".";
result.src = src;
}
return result;
}
async function generateCopyTarget(context, src, dest, { transform }) {
if (transform && !(await isFile(src))) {
throw new Error(`"transform" option works only on files: '${src}' must be a file`);
}
const { base, dir } = path.parse(src);
const srcPath = path.join(context, src);
const destPath = path.join(dest, dir, base);
const destContents = transform && (await transform(await fs.readFile(srcPath), base));
return {
src: srcPath,
dest: destPath,
...(destContents && { contents: destContents }),
transformed: transform,
};
}
export default async function copy({ targets = [], verbose = false }) {
const copyTargets = [];
if (Array.isArray(targets) && targets.length) {
for (const target of targets) {
if (!isObject(target)) {
throw new Error(`${stringify(target)} target must be an object`);
}
if (!target.src || !target.dest) {
throw new Error(`${stringify(target)} target must have "src" and "dest" properties`);
}
const { dest, src, context, transform } = await normalizeTarget(target);
const matchedPaths = await globby(src, {
cwd: context,
expandDirectories: false,
onlyFiles: true,
});
if (matchedPaths.length) {
for (const matchedPath of matchedPaths) {
copyTargets.push(await generateCopyTarget(context, matchedPath, dest, { transform }));
}
}
}
}
if (copyTargets.length) {
if (verbose) {
console.log(green("copied:"));
}
for (const copyTarget of copyTargets) {
const { contents, dest, src, transformed } = copyTarget;
if (transformed) {
await fs.outputFile(dest, contents);
} else {
await fs.copy(src, dest);
}
if (verbose) {
let message = green(` ${bold(src)} → ${bold(dest)}`);
const flags = Object.entries(copyTarget)
.filter(([key, value]) => ["renamed", "transformed"].includes(key) && value)
.map(([key]) => key.charAt(0).toUpperCase());
if (flags.length) {
message = `${message} ${yellow(`[${flags.join(", ")}]`)}`;
}
console.log(message);
}
}
} else if (verbose) {
console.log(yellow("no items to copy"));
}
}