Skip to content

Commit 7fe0c06

Browse files
Fetzevilebottnawi
authored andcommitted
feat: add support for target path transform (#284)
1 parent dc7aa5d commit 7fe0c06

File tree

3 files changed

+176
-2
lines changed

3 files changed

+176
-2
lines changed

README.md

+38
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Or, in case of just a `from` with the default destination, you can also use a `{
6060
|[`ignore`](#ignore)|`{Array}`|`[]`|Globs to ignore for this pattern|
6161
|`flatten`|`{Boolean}`|`false`|Removes all directory references and only copies file names.⚠️ If files have the same name, the result is non-deterministic|
6262
|[`transform`](#transform)|`{Function\|Promise}`|`(content, path) => content`|Function or Promise that modifies file contents before copying|
63+
|[`transformPath`](#transformPath)|`{Function\|Promise}`|`(targetPath, sourcePath) => path`|Function or Promise that modifies file writing path|
6364
|[`cache`](#cache)|`{Boolean\|Object}`|`false`|Enable `transform` caching. You can use `{ cache: { key: 'my-cache-key' } }` to invalidate the cache|
6465
|[`context`](#context)|`{String}`|`options.context \|\| compiler.options.context`|A path that determines how to interpret the `from` path|
6566

@@ -234,6 +235,43 @@ and so on...
234235
]
235236
```
236237

238+
### `transformPath`
239+
240+
#### `{Function}`
241+
242+
**webpack.config.js**
243+
```js
244+
[
245+
new CopyWebpackPlugin([
246+
{
247+
from: 'src/*.png',
248+
to: 'dest/',
249+
transformPath (targetPath, absolutePath) {
250+
return 'newPath';
251+
}
252+
}
253+
], options)
254+
]
255+
```
256+
257+
#### `{Promise}`
258+
259+
**webpack.config.js**
260+
```js
261+
[
262+
new CopyWebpackPlugin([
263+
{
264+
from: 'src/*.png',
265+
to: 'dest/',
266+
transform (targePath, absolutePath) {
267+
return Promise.resolve('newPath')
268+
}
269+
}
270+
], options)
271+
]
272+
```
273+
274+
237275
### `cache`
238276

239277
**webpack.config.js**

src/writeFile.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ export default function writeFile(globalRef, pattern, file) {
6363

6464
return content;
6565
}).then((content) => {
66-
const hash = loaderUtils.getHashDigest(content);
67-
6866
if (pattern.toType === 'template') {
6967
info(`interpolating template '${file.webpackTo}' for '${file.relativeFrom}'`);
7068

@@ -84,6 +82,20 @@ export default function writeFile(globalRef, pattern, file) {
8482
}
8583
);
8684
}
85+
86+
return content;
87+
}).then((content) => {
88+
if (pattern.transformPath) {
89+
return Promise.resolve(
90+
pattern.transformPath(file.webpackTo, file.absoluteFrom)
91+
).then((newPath) => {
92+
file.webpackTo = newPath;
93+
}).then(() => content);
94+
}
95+
96+
return content;
97+
}).then((content) => {
98+
const hash = loaderUtils.getHashDigest(content);
8799

88100
if (!copyUnmodified &&
89101
written[file.absoluteFrom] &&

tests/index.js

+124
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,57 @@ describe('apply function', () => {
319319
.catch(done);
320320
});
321321

322+
it('can transform target path of every file in glob', (done) => {
323+
runEmit({
324+
expectedAssetKeys: [
325+
'/some/path/(special-*file).txt.tst',
326+
'/some/path/binextension.bin.tst',
327+
'/some/path/file.txt.tst',
328+
'/some/path/file.txt.gz.tst',
329+
'/some/path/directoryfile.txt.tst',
330+
'/some/path/nestedfile.txt.tst',
331+
'/some/path/noextension.tst',
332+
'/some/path/hello.txt.tst'
333+
],
334+
patterns: [{
335+
from: '**/*',
336+
transformPath: function(targetPath, absoluteFrom) {
337+
expect(absoluteFrom).to.have.string(HELPER_DIR);
338+
return '/some/path/' + path.basename(targetPath) + '.tst';
339+
}
340+
}]
341+
})
342+
.then(done)
343+
.catch(done);
344+
});
345+
346+
it('can transform target path of every file in glob after applying template', (done) => {
347+
runEmit({
348+
expectedAssetKeys: [
349+
'transformed/[!]/hello-d41d8c.txt',
350+
'transformed/[special?directory]/directoryfile-22af64.txt',
351+
'transformed/[special?directory]/(special-*file)-0bd650.txt',
352+
'transformed/[special?directory]/nested/nestedfile-d41d8c.txt',
353+
'transformed/binextension-d41d8c.bin',
354+
'transformed/file-22af64.txt',
355+
'transformed/file.txt-5b311c.gz',
356+
'transformed/directory/directoryfile-22af64.txt',
357+
'transformed/directory/nested/nestedfile-d41d8c.txt',
358+
'transformed/noextension-d41d8c'
359+
],
360+
patterns: [{
361+
from: '**/*',
362+
to: 'nested/[path][name]-[hash:6].[ext]',
363+
transformPath: function(targetPath, absoluteFrom) {
364+
expect(absoluteFrom).to.have.string(HELPER_DIR);
365+
return targetPath.replace('nested/', 'transformed/');
366+
}
367+
}]
368+
})
369+
.then(done)
370+
.catch(done);
371+
});
372+
322373
it('can use a glob to move multiple files in a different relative context to a non-root directory', (done) => {
323374
runEmit({
324375
expectedAssetKeys: [
@@ -539,6 +590,23 @@ describe('apply function', () => {
539590
.catch(done);
540591
});
541592

593+
it('can transform target path', (done) => {
594+
runEmit({
595+
expectedAssetKeys: [
596+
'subdir/test.txt'
597+
],
598+
patterns: [{
599+
from: 'file.txt',
600+
transformPath: function(targetPath, absoluteFrom) {
601+
expect(absoluteFrom).to.equal(path.join(HELPER_DIR, 'file.txt'));
602+
return targetPath.replace('file.txt', 'subdir/test.txt');
603+
}
604+
}]
605+
})
606+
.then(done)
607+
.catch(done);
608+
});
609+
542610
it('warns when file not found', (done) => {
543611
runEmit({
544612
expectedAssetKeys: [],
@@ -570,6 +638,23 @@ describe('apply function', () => {
570638
.catch(done);
571639
});
572640

641+
it('warns when tranformPath failed', (done) => {
642+
runEmit({
643+
expectedAssetKeys: [],
644+
expectedErrors: [
645+
'a failure happened'
646+
],
647+
patterns: [{
648+
from: 'file.txt',
649+
transformPath: function() {
650+
throw 'a failure happened';
651+
}
652+
}]
653+
})
654+
.then(done)
655+
.catch(done);
656+
});
657+
573658
it('can use an absolute path to move a file to the root directory', (done) => {
574659
const absolutePath = path.resolve(HELPER_DIR, 'file.txt');
575660

@@ -987,6 +1072,26 @@ describe('apply function', () => {
9871072
.catch(done);
9881073
});
9891074

1075+
it('transformPath with promise', (done) => {
1076+
runEmit({
1077+
expectedAssetKeys: [
1078+
'/some/path/file.txt'
1079+
],
1080+
patterns: [{
1081+
from: 'file.txt',
1082+
transformPath: function(targetPath, absoluteFrom) {
1083+
expect(absoluteFrom).to.have.string(HELPER_DIR);
1084+
1085+
return new Promise((resolve) => {
1086+
resolve('/some/path/' + path.basename(targetPath));
1087+
});
1088+
}
1089+
}]
1090+
})
1091+
.then(done)
1092+
.catch(done);
1093+
});
1094+
9901095
it('same file to multiple targets', (done) => {
9911096
runEmit({
9921097
expectedAssetKeys: [
@@ -1022,6 +1127,25 @@ describe('apply function', () => {
10221127
.catch(done);
10231128
});
10241129

1130+
it('can transform target path of every file in directory', (done) => {
1131+
runEmit({
1132+
expectedAssetKeys: [
1133+
'/some/path/.dottedfile',
1134+
'/some/path/directoryfile.txt',
1135+
'/some/path/nestedfile.txt'
1136+
],
1137+
patterns: [{
1138+
from: 'directory',
1139+
transformPath: function(targetPath, absoluteFrom) {
1140+
expect(absoluteFrom).to.have.string(path.join(HELPER_DIR, 'directory'));
1141+
return '/some/path/' + path.basename(targetPath);
1142+
}
1143+
}]
1144+
})
1145+
.then(done)
1146+
.catch(done);
1147+
});
1148+
10251149
it('can move a directory\'s contents to the root directory using from with special characters', (done) => {
10261150
runEmit({
10271151
expectedAssetKeys: [

0 commit comments

Comments
 (0)