Skip to content

Commit e3803ce

Browse files
authoredMay 15, 2020
feat: implement the noErrorOnMissing option (#475)
1 parent 8e5bc1b commit e3803ce

9 files changed

+129
-21
lines changed
 

‎README.md

+35-12
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,19 @@ module.exports = {
7474

7575
### Patterns
7676

77-
| Name | Type | Default | Description |
78-
| :---------------------------------: | :-----------------: | :---------------------------------------------: | :---------------------------------------------------------------------------------------------------- |
79-
| [`from`](#from) | `{String}` | `undefined` | Glob or path from where we сopy files. |
80-
| [`to`](#to) | `{String}` | `compiler.options.output` | Output path. |
81-
| [`context`](#context) | `{String}` | `options.context \|\| compiler.options.context` | A path that determines how to interpret the `from` path. |
82-
| [`globOptions`](#globoptions) | `{Object}` | `undefined` | [Options][glob-options] passed to the glob pattern matching library including `ignore` option. |
83-
| [`toType`](#totype) | `{String}` | `undefined` | Determinate what is `to` option - directory, file or template. |
84-
| [`force`](#force) | `{Boolean}` | `false` | Overwrites files already in `compilation.assets` (usually added by other plugins/loaders). |
85-
| [`flatten`](#flatten) | `{Boolean}` | `false` | Removes all directory references and only copies file names. |
86-
| [`transform`](#transform) | `{Function}` | `undefined` | Allows to modify the file contents. |
87-
| [`cacheTransform`](#cacheTransform) | `{Boolean\|Object}` | `false` | Enable `transform` caching. You can use `{ cache: { key: 'my-cache-key' } }` to invalidate the cache. |
88-
| [`transformPath`](#transformpath) | `{Function}` | `undefined` | Allows to modify the writing path. |
77+
| Name | Type | Default | Description |
78+
| :-------------------------------------: | :-----------------: | :---------------------------------------------: | :---------------------------------------------------------------------------------------------------- |
79+
| [`from`](#from) | `{String}` | `undefined` | Glob or path from where we сopy files. |
80+
| [`to`](#to) | `{String}` | `compiler.options.output` | Output path. |
81+
| [`context`](#context) | `{String}` | `options.context \|\| compiler.options.context` | A path that determines how to interpret the `from` path. |
82+
| [`globOptions`](#globoptions) | `{Object}` | `undefined` | [Options][glob-options] passed to the glob pattern matching library including `ignore` option. |
83+
| [`toType`](#totype) | `{String}` | `undefined` | Determinate what is `to` option - directory, file or template. |
84+
| [`force`](#force) | `{Boolean}` | `false` | Overwrites files already in `compilation.assets` (usually added by other plugins/loaders). |
85+
| [`flatten`](#flatten) | `{Boolean}` | `false` | Removes all directory references and only copies file names. |
86+
| [`transform`](#transform) | `{Function}` | `undefined` | Allows to modify the file contents. |
87+
| [`cacheTransform`](#cacheTransform) | `{Boolean\|Object}` | `false` | Enable `transform` caching. You can use `{ cache: { key: 'my-cache-key' } }` to invalidate the cache. |
88+
| [`transformPath`](#transformpath) | `{Function}` | `undefined` | Allows to modify the writing path. |
89+
| [`noErrorOnMissing`](#noerroronmissing) | `{Boolean}` | `false` | Doesn't generate an error on missing file(s). |
8990

9091
#### `from`
9192

@@ -533,6 +534,28 @@ module.exports = {
533534
};
534535
```
535536

537+
### `noErrorOnMissing`
538+
539+
Type: `Boolean`
540+
Default: `false`
541+
542+
Doesn't generate an error on missing file(s);
543+
544+
```js
545+
module.exports = {
546+
plugins: [
547+
new CopyPlugin({
548+
patterns: [
549+
{
550+
from: path.resolve(__dirname, 'missing-file.txt'),
551+
noErrorOnMissing: true,
552+
},
553+
],
554+
}),
555+
],
556+
};
557+
```
558+
536559
### Options
537560

538561
| Name | Type | Default | Description |

‎src/options.json

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"definitions": {
33
"ObjectPattern": {
44
"type": "object",
5+
"additionalProperties": false,
56
"properties": {
67
"from": {
78
"type": "string",
@@ -13,6 +14,9 @@
1314
"context": {
1415
"type": "string"
1516
},
17+
"globOptions": {
18+
"type": "object"
19+
},
1620
"toType": {
1721
"enum": ["dir", "file", "template"]
1822
},
@@ -37,6 +41,9 @@
3741
},
3842
"transformPath": {
3943
"instanceof": "Function"
44+
},
45+
"noErrorOnMissing": {
46+
"type": "boolean"
4047
}
4148
},
4249
"required": ["from"]

‎src/preProcessPattern.js

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ export default async function preProcessPattern(globalRef, pattern) {
2020
pattern.context = path.join(context, pattern.context);
2121
}
2222

23+
pattern.noErrorOnMissing = pattern.noErrorOnMissing || false;
24+
2325
// Todo remove this in next major
2426
const isToDirectory =
2527
path.extname(pattern.to) === '' || pattern.to.slice(-1) === path.sep;

‎src/processPattern.js

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import createPatternGlob from './utils/createPatternGlob';
88

99
export default async function processPattern(globalRef, pattern) {
1010
const { logger, output, compilation } = globalRef;
11+
1112
createPatternGlob(pattern, globalRef);
1213

1314
logger.log(
@@ -17,6 +18,10 @@ export default async function processPattern(globalRef, pattern) {
1718
const paths = await globby(pattern.glob, pattern.globOptions);
1819

1920
if (paths.length === 0) {
21+
if (pattern.noErrorOnMissing) {
22+
return Promise.resolve();
23+
}
24+
2025
const newWarning = new Error(
2126
`unable to locate '${pattern.from}' at '${pattern.absoluteFrom}'`
2227
);

‎src/utils/createPatternGlob.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import path from 'path';
33
import normalizePath from 'normalize-path';
44
import globParent from 'glob-parent';
55

6-
/* eslint-disable no-param-reassign */
7-
86
function getAbsoluteContext(context) {
97
const result = normalizePath(path.resolve(context));
108

@@ -18,6 +16,7 @@ function getAbsoluteContext(context) {
1816
function createPatternGlob(pattern, globalRef) {
1917
const { logger, compilation } = globalRef;
2018

19+
// eslint-disable-next-line no-param-reassign
2120
pattern.globOptions = Object.assign(
2221
{
2322
cwd: pattern.context,
@@ -30,8 +29,10 @@ function createPatternGlob(pattern, globalRef) {
3029
case 'dir':
3130
logger.debug(`determined '${pattern.absoluteFrom}' is a directory`);
3231
logger.debug(`add ${pattern.absoluteFrom} as contextDependencies`);
32+
3333
compilation.contextDependencies.add(pattern.absoluteFrom);
3434

35+
/* eslint-disable no-param-reassign */
3536
pattern.context = pattern.absoluteFrom;
3637
pattern.glob = path.posix.join(
3738
getAbsoluteContext(pattern.absoluteFrom),
@@ -42,20 +43,23 @@ function createPatternGlob(pattern, globalRef) {
4243
if (typeof pattern.globOptions.dot === 'undefined') {
4344
pattern.globOptions.dot = true;
4445
}
46+
/* eslint-enable no-param-reassign */
4547

4648
break;
47-
4849
case 'file':
4950
logger.debug(`determined '${pattern.absoluteFrom}' is a file`);
5051
logger.debug(`add ${pattern.absoluteFrom} as fileDependencies`);
52+
5153
compilation.fileDependencies.add(pattern.absoluteFrom);
5254

55+
/* eslint-disable no-param-reassign */
5356
pattern.context = path.dirname(pattern.absoluteFrom);
5457
pattern.glob = getAbsoluteContext(pattern.absoluteFrom);
5558

5659
if (typeof pattern.globOptions.dot === 'undefined') {
5760
pattern.globOptions.dot = true;
5861
}
62+
/* eslint-enable no-param-reassign */
5963

6064
break;
6165

@@ -68,15 +72,18 @@ function createPatternGlob(pattern, globalRef) {
6872
);
6973

7074
logger.debug(`add ${contextDependencies} as contextDependencies`);
75+
7176
compilation.contextDependencies.add(contextDependencies);
7277

78+
/* eslint-disable no-param-reassign */
7379
pattern.fromType = 'glob';
7480
pattern.glob = path.isAbsolute(pattern.fromOrigin)
7581
? pattern.fromOrigin
7682
: path.posix.join(
7783
getAbsoluteContext(pattern.context),
7884
pattern.fromOrigin
7985
);
86+
/* eslint-enable no-param-reassign */
8087
}
8188

8289
return pattern;

‎test/__snapshots__/validate-options.test.js.snap

+10-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ exports[`validate options should throw an error on the "options" option with "{"
1414
exports[`validate options should throw an error on the "patterns" option with "" value 1`] = `
1515
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
1616
- options.patterns should be an array:
17-
[non-empty string | object { from, to?, context?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, }, ...] (should not have fewer than 1 item)"
17+
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)"
1818
`;
1919
2020
exports[`validate options should throw an error on the "patterns" option with "[""]" value 1`] = `
@@ -27,6 +27,11 @@ exports[`validate options should throw an error on the "patterns" option with "[
2727
- options.patterns should be an non-empty array."
2828
`;
2929
30+
exports[`validate options should throw an error on the "patterns" option with "[{"from":"","to":"dir","context":"context","noErrorOnMissing":"true"}]" value 1`] = `
31+
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
32+
- options.patterns[0].noErrorOnMissing should be a boolean."
33+
`;
34+
3035
exports[`validate options should throw an error on the "patterns" option with "[{"from":"","to":"dir","context":"context"}]" value 1`] = `
3136
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
3237
- options.patterns[0].from should be an non-empty string."
@@ -61,7 +66,7 @@ exports[`validate options should throw an error on the "patterns" option with "[
6166
exports[`validate options should throw an error on the "patterns" option with "[{"from":"test.txt","to":"dir","context":"context"}]" value 1`] = `
6267
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
6368
- options.patterns[0] should be one of these:
64-
non-empty string | object { from, to?, context?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, }
69+
non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }
6570
Details:
6671
* options.patterns[0].cacheTransform should be one of these:
6772
boolean | object { … }
@@ -100,19 +105,19 @@ exports[`validate options should throw an error on the "patterns" option with "[
100105
exports[`validate options should throw an error on the "patterns" option with "{}" value 1`] = `
101106
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
102107
- options.patterns should be an array:
103-
[non-empty string | object { from, to?, context?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, }, ...] (should not have fewer than 1 item)"
108+
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)"
104109
`;
105110
106111
exports[`validate options should throw an error on the "patterns" option with "true" value 1`] = `
107112
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
108113
- options.patterns should be an array:
109-
[non-empty string | object { from, to?, context?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, }, ...] (should not have fewer than 1 item)"
114+
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)"
110115
`;
111116
112117
exports[`validate options should throw an error on the "patterns" option with "true" value 2`] = `
113118
"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
114119
- options.patterns should be an array:
115-
[non-empty string | object { from, to?, context?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, }, ...] (should not have fewer than 1 item)"
120+
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)"
116121
`;
117122
118123
exports[`validate options should throw an error on the "unknown" option with "/test/" value 1`] = `

‎test/globOptions-option.test.js

-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,6 @@ describe('globOptions ignore option', () => {
245245
],
246246
patterns: [
247247
{
248-
ignore: ['file.*'],
249248
from: 'file.txt',
250249
globOptions: {
251250
ignore: ['**/file.*'],

‎test/noErrorOnMissing.test.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { runEmit } from './helpers/run';
2+
3+
describe('noErrorOnMissing option', () => {
4+
describe('is a file', () => {
5+
it('should work', (done) => {
6+
runEmit({
7+
expectedAssetKeys: [],
8+
patterns: [
9+
{
10+
from: 'unknown.unknown',
11+
noErrorOnMissing: true,
12+
},
13+
],
14+
})
15+
.then(done)
16+
.catch(done);
17+
});
18+
});
19+
20+
describe('is a directory', () => {
21+
it('should work', (done) => {
22+
runEmit({
23+
expectedAssetKeys: [],
24+
patterns: [
25+
{
26+
from: 'unknown',
27+
noErrorOnMissing: true,
28+
},
29+
],
30+
})
31+
.then(done)
32+
.catch(done);
33+
});
34+
});
35+
36+
describe('is a glob', () => {
37+
it('should work', (done) => {
38+
runEmit({
39+
expectedAssetKeys: [],
40+
patterns: [
41+
{
42+
from: '*.unknown',
43+
noErrorOnMissing: true,
44+
},
45+
],
46+
})
47+
.then(done)
48+
.catch(done);
49+
});
50+
});
51+
});

‎test/validate-options.test.js

+9
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe('validate options', () => {
5858
transform: () => {},
5959
cacheTransform: true,
6060
transformPath: () => {},
61+
noErrorOnMissing: true,
6162
},
6263
],
6364
[
@@ -175,6 +176,14 @@ describe('validate options', () => {
175176
context: 'context',
176177
},
177178
],
179+
[
180+
{
181+
from: '',
182+
to: 'dir',
183+
context: 'context',
184+
noErrorOnMissing: 'true',
185+
},
186+
],
178187
],
179188
},
180189
options: {

0 commit comments

Comments
 (0)
Please sign in to comment.