@calmdown/rollup-plugin-copy 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +42 -29
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as fs from "node:fs/promises";
2
- import * as path from "node:path";
1
+ import * as FS from "node:fs/promises";
2
+ import * as Path from "node:path";
3
3
 
4
4
  const PLUGIN_NAME = "Copy";
5
5
 
@@ -14,18 +14,18 @@ const EK_UNKNOWN = "unknown";
14
14
 
15
15
  /**
16
16
  * @typedef {Object} CopySingleTarget
17
- * @property {string} srcFile path to the file to be copied
18
- * @property {string} dstFile path to where the file should be copied to
19
- * @property {string} [baseDir] base directory for relative paths (defaults to current directory)
17
+ * @property {string} srcFile path to the file to be copied; relative paths resolve against the current directory
18
+ * @property {string} dstFile path to where the file should be copied to; relative paths resolve against the current directory
20
19
  * @property {"before"|"after"} [trigger="after"] when to run the operation (defaults to "after")
21
20
  */
22
21
 
23
22
  /**
24
23
  * @typedef {Object} CopyManyTarget
25
- * @property {string} dstDir directory to where files should be copied or linked
24
+ * @property {string} dstDir directory to where files should be copied or linked; relative paths resolve against the current directory
26
25
  * @property {string|string[]} include glob pattern(s) of files to include
27
26
  * @property {string|string[]} [exclude] glob pattern(s) to exclude (optional)
28
- * @property {string} [baseDir] base directory for relative paths (defaults to current directory)
27
+ * @property {string} [baseDir] when set, directory structure under this path will be copied to dstDir, otherwise the structure is flattened; relative paths resolve against the current directory
28
+ * @property {string} [flatten=false] when to run the operation (defaults to "after")
29
29
  * @property {"before"|"after"} [trigger="after"] when to run the operation (defaults to "after")
30
30
  */
31
31
 
@@ -34,7 +34,7 @@ const EK_UNKNOWN = "unknown";
34
34
  * @property {(CopySingleTarget | CopyManyTarget)[]} targets desired copy/link operations
35
35
  * @property {boolean} [dryRun=false] whether to perform a dry run, only logging actions without executing them (defaults to false)
36
36
  * @property {boolean} [runOnce=true] when in watch mode, controls whether to only delete files on the first build (defaults to true)
37
- * @property {"ignore"|"copy-file"|"link-absolute"|"link-relative"} [symLinks="ignore"] how to handle symlinks (defaults to "ignore")
37
+ * @property {"ignore"|"copy-file"|"link-relative"|"link-absolute"} [symLinks="ignore"] how to handle symlinks (defaults to "ignore")
38
38
  */
39
39
 
40
40
  /**
@@ -59,15 +59,14 @@ export default function CopyPlugin(pluginOptions) {
59
59
  };
60
60
 
61
61
  const execTarget = async (context, cwd, target) => {
62
- const baseDir = target.baseDir ? path.resolve(cwd, target.baseDir) : cwd;
63
62
  const entries = [];
64
63
  if (target.srcFile) {
65
64
  // single file
66
- const src = path.resolve(baseDir, target.srcFile);
67
- const stats = await fs.stat(src);
65
+ const src = Path.resolve(cwd, target.srcFile);
66
+ const stats = await FS.stat(src);
68
67
  entries.push({
69
68
  src,
70
- dst: path.resolve(baseDir, target.dstFile),
69
+ dst: Path.resolve(cwd, target.dstFile),
71
70
  kind: getKind(stats),
72
71
  });
73
72
  }
@@ -80,12 +79,24 @@ export default function CopyPlugin(pluginOptions) {
80
79
  withFileTypes: true,
81
80
  };
82
81
 
83
- const dstDir = path.resolve(baseDir, target.dstDir);
82
+ const dstDir = Path.resolve(cwd, target.dstDir);
83
+ const baseDir = target.baseDir ? Path.resolve(cwd, target.baseDir) : null;
84
84
  for (const includePattern of include) {
85
- for await (const entry of fs.glob(includePattern, globOptions)) {
85
+ for await (const entry of FS.glob(includePattern, globOptions)) {
86
+ const src = Path.join(entry.parentPath, entry.name);
87
+ let dst = null;
88
+
89
+ if (baseDir) {
90
+ const rel = Path.relative(baseDir, src);
91
+ if (!rel.startsWith("..")) {
92
+ dst = Path.join(dstDir, rel);
93
+ }
94
+ }
95
+
96
+ dst ??= dst = Path.join(dstDir, entry.name);
86
97
  entries.push({
87
- src: path.join(entry.parentPath, entry.name),
88
- dst: path.join(dstDir, entry.name),
98
+ src,
99
+ dst,
89
100
  kind: getKind(entry),
90
101
  });
91
102
  }
@@ -93,10 +104,10 @@ export default function CopyPlugin(pluginOptions) {
93
104
  }
94
105
 
95
106
  for (const entry of entries) {
96
- const dstDir = path.dirname(entry.dst);
107
+ const dstDir = Path.dirname(entry.dst);
97
108
  if (entry.kind === EK_FILE) {
98
- await exec(context, null, () => fs.mkdir(dstDir, { recursive: true }));
99
- await exec(context, `would copy file ${entry.src} -> ${entry.dst}`, () => fs.copyFile(entry.src, entry.dst));
109
+ await exec(context, null, () => FS.mkdir(dstDir, { recursive: true }));
110
+ await exec(context, `would copy file ${entry.src} -> ${entry.dst}`, () => FS.copyFile(entry.src, entry.dst));
100
111
  context.addWatchFile(entry.src);
101
112
  }
102
113
  else if (entry.kind === EK_LINK && symLinks !== SL_IGNORE) {
@@ -105,19 +116,19 @@ export default function CopyPlugin(pluginOptions) {
105
116
  continue;
106
117
  }
107
118
 
108
- await exec(context, null, () => fs.mkdir(dstDir, { recursive: true }));
119
+ await exec(context, null, () => FS.mkdir(dstDir, { recursive: true }));
109
120
  switch (symLinks) {
110
121
  case SL_COPY_FILE:
111
- await exec(context, `would copy file ${linkedPath} -> ${entry.dst} resolved from symlink ${entry.src}`, () => fs.copyFile(linkedPath, entry.dst));
122
+ await exec(context, `would copy file ${linkedPath} -> ${entry.dst} resolved from symlink ${entry.src}`, () => FS.copyFile(linkedPath, entry.dst));
112
123
  break;
113
124
 
114
125
  case SL_LINK_ABSOLUTE:
115
- await exec(context, `would create symlink ${entry.dst} pointing to ${linkedPath} resolved from symlink ${entry.src}`, () => fs.symlink(linkedPath, entry.dst));
126
+ await exec(context, `would create symlink ${entry.dst} pointing to ${linkedPath} resolved from symlink ${entry.src}`, () => FS.symlink(linkedPath, entry.dst));
116
127
  break;
117
128
 
118
129
  case SL_LINK_RELATIVE: {
119
- const linkTargetPath = path.relative(entry.dst, linkedPath);
120
- await exec(context, `would create symlink ${entry.dst} pointing to ${linkTargetPath} resolved from symlink ${entry.src}`, () => fs.symlink(linkTargetPath, entry.dst));
130
+ const linkTargetPath = Path.relative(entry.dst, linkedPath);
131
+ await exec(context, `would create symlink ${entry.dst} pointing to ${linkTargetPath} resolved from symlink ${entry.src}`, () => FS.symlink(linkTargetPath, entry.dst));
121
132
  break;
122
133
  }
123
134
  }
@@ -127,7 +138,6 @@ export default function CopyPlugin(pluginOptions) {
127
138
  }
128
139
  };
129
140
 
130
- let cwd = undefined;
131
141
  let isFirstBeforeRun = true;
132
142
  let isFirstAfterRun = true;
133
143
  return {
@@ -138,7 +148,8 @@ export default function CopyPlugin(pluginOptions) {
138
148
  }
139
149
 
140
150
  isFirstBeforeRun = false;
141
- cwd = process.cwd();
151
+
152
+ const cwd = process.cwd();
142
153
  for (const target of targets) {
143
154
  if (target.trigger === "before") {
144
155
  await execTarget(this, cwd, target);
@@ -151,6 +162,8 @@ export default function CopyPlugin(pluginOptions) {
151
162
  }
152
163
 
153
164
  isFirstAfterRun = false;
165
+
166
+ const cwd = process.cwd();
154
167
  for (const target of targets) {
155
168
  const { trigger } = target;
156
169
  if (trigger === "after" || trigger === undefined) {
@@ -183,15 +196,15 @@ async function resolveSymLink(linkPath, maxDepth = 8) {
183
196
  let current = linkPath;
184
197
  let depth = 0;
185
198
  do {
186
- const st = await fs.stat(current);
199
+ const st = await FS.stat(current);
187
200
  if (!st.isSymbolicLink()) {
188
201
  return current;
189
202
  }
190
203
 
191
- const target = await fs.readlink(current, "utf8");
204
+ const target = await FS.readlink(current, "utf8");
192
205
  visited.add(current);
193
206
 
194
- current = path.join(path.dirname(current), target);
207
+ current = Path.join(Path.dirname(current), target);
195
208
  }
196
209
  while (!visited.has(current) && ++depth < maxDepth);
197
210
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calmdown/rollup-plugin-copy",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "license": "ISC",
5
5
  "type": "module",
6
6
  "exports": {