Skip to content

Commit

Permalink
feat: validate options (#419)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilebottnawi committed Dec 9, 2019
1 parent 4826e56 commit 452539a
Show file tree
Hide file tree
Showing 7 changed files with 527 additions and 110 deletions.
43 changes: 17 additions & 26 deletions README.md
Expand Up @@ -60,23 +60,23 @@ module.exports = {

### Patterns

| Name | Type | Default | Description |
| :-------------------------------: | :-------------------: | :---------------------------------------------: | :---------------------------------------------------------------------------------------------------- |
| [`from`](#from) | `{String\|Object}` | `undefined` | Glob or path from where we сopy files. |
| [`to`](#to) | `{String}` | `compiler.options.output` | Output path. |
| [`context`](#context) | `{String}` | `options.context \|\| compiler.options.context` | A path that determines how to interpret the `from` path. |
| [`toType`](#totype) | `{String}` | `undefined` | Determinate what is `to` option - directory, file or template. |
| [`test`](#test) | `{RegExp}` | `undefined` | Pattern for extracting elements to be used in `to` templates. |
| [`force`](#force) | `{Boolean}` | `false` | Overwrites files already in `compilation.assets` (usually added by other plugins/loaders). |
| [`ignore`](#ignore) | `{Array}` | `[]` | Globs to ignore files. |
| [`flatten`](#flatten) | `{Boolean}` | `false` | Removes all directory references and only copies file names. |
| [`cache`](#cache) | `{Boolean\|Object}` | `false` | Enable `transform` caching. You can use `{ cache: { key: 'my-cache-key' } }` to invalidate the cache. |
| [`transform`](#transform) | `{Function\|Promise}` | `undefined` | Allows to modify the file contents. |
| [`transformPath`](#transformpath) | `{Function\|Promise}` | `undefined` | Allows to modify the writing path. |
| Name | Type | Default | Description |
| :-------------------------------: | :-----------------: | :---------------------------------------------: | :---------------------------------------------------------------------------------------------------- |
| [`from`](#from) | `{String\|Object}` | `undefined` | Glob or path from where we сopy files. |
| [`to`](#to) | `{String}` | `compiler.options.output` | Output path. |
| [`context`](#context) | `{String}` | `options.context \|\| compiler.options.context` | A path that determines how to interpret the `from` path. |
| [`toType`](#totype) | `{String}` | `undefined` | Determinate what is `to` option - directory, file or template. |
| [`test`](#test) | `{String\|RegExp}` | `undefined` | Pattern for extracting elements to be used in `to` templates. |
| [`force`](#force) | `{Boolean}` | `false` | Overwrites files already in `compilation.assets` (usually added by other plugins/loaders). |
| [`ignore`](#ignore) | `{Array}` | `[]` | Globs to ignore files. |
| [`flatten`](#flatten) | `{Boolean}` | `false` | Removes all directory references and only copies file names. |
| [`cache`](#cache) | `{Boolean\|Object}` | `false` | Enable `transform` caching. You can use `{ cache: { key: 'my-cache-key' } }` to invalidate the cache. |
| [`transform`](#transform) | `{Function}` | `undefined` | Allows to modify the file contents. |
| [`transformPath`](#transformpath) | `{Function}` | `undefined` | Allows to modify the writing path. |

#### `from`

Type: `String\|Object`
Type: `String|Object`
Default: `undefined`

Glob or path from where we сopy files.
Expand All @@ -99,7 +99,6 @@ module.exports = {
'relative/path/to/dir',
'/absolute/path/to/dir',
'**/*',
{ glob: '**/*', dot: false },
{
from: '**/*',
globOptions: {
Expand Down Expand Up @@ -240,7 +239,7 @@ module.exports = {

#### `test`

Type: `RegExp`
Type: `string|RegExp`
Default: `undefined`

Pattern for extracting elements to be used in `to` templates.
Expand Down Expand Up @@ -367,13 +366,11 @@ module.exports = {

#### `transform`

Type: `Function|Promise`
Type: `Function`
Default: `undefined`

Allows to modify the file contents.

##### `{Function}`

**webpack.config.js**

```js
Expand All @@ -392,8 +389,6 @@ module.exports = {
};
```

##### `{Promise}`

**webpack.config.js**

```js
Expand All @@ -414,7 +409,7 @@ module.exports = {

#### `transformPath`

Type: `Function|Promise`
Type: `Function`
Default: `undefined`

Allows to modify the writing path.
Expand All @@ -423,8 +418,6 @@ Allows to modify the writing path.
> On Windows, the forward slash and the backward slash are both separators.
> Instead please use `/` or `path` methods.
##### `{Function}`

**webpack.config.js**

```js
Expand All @@ -443,8 +436,6 @@ module.exports = {
};
```

##### `{Promise}`

**webpack.config.js**

```js
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
@@ -1,16 +1,16 @@
import path from 'path';

import validateOptions from 'schema-utils';
import log from 'webpack-log';

import schema from './options.json';
import preProcessPattern from './preProcessPattern';
import processPattern from './processPattern';
import postProcessPattern from './postProcessPattern';

class CopyPlugin {
constructor(patterns = [], options = {}) {
if (!Array.isArray(patterns)) {
throw new Error('[copy-webpack-plugin] patterns must be an array');
}
validateOptions(schema, patterns, this.constructor.name);

this.patterns = patterns;
this.options = options;
Expand Down
81 changes: 81 additions & 0 deletions src/options.json
@@ -0,0 +1,81 @@
{
"definitions": {
"ObjectPattern": {
"type": "object",
"properties": {
"from": {
"anyOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "object"
}
]
},
"to": {
"type": "string"
},
"context": {
"type": "string"
},
"toType": {
"enum": ["dir", "file", "template"]
},
"test": {
"anyOf": [
{
"type": "string"
},
{
"instanceof": "RegExp"
}
]
},
"force": {
"type": "boolean"
},
"ignore": {
"type": "array"
},
"flatten": {
"type": "boolean"
},
"cache": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "object"
}
]
},
"transform": {
"instanceof": "Function"
},
"transformPath": {
"instanceof": "Function"
}
},
"required": ["from"]
},
"StringPattern": {
"type": "string",
"minLength": 1
}
},
"type": "array",
"minItems": 1,
"items": {
"anyOf": [
{
"$ref": "#/definitions/StringPattern"
},
{
"$ref": "#/definitions/ObjectPattern"
}
]
}
}
8 changes: 0 additions & 8 deletions src/preProcessPattern.js
Expand Up @@ -25,14 +25,6 @@ export default function preProcessPattern(globalRef, pattern) {
? { from: pattern }
: Object.assign({}, pattern);

if (pattern.from === '') {
const message = 'path "from" cannot be empty string';

logger.error(message);

compilation.errors.push(new Error(message));
}

pattern.to = pattern.to || '';
pattern.context = pattern.context || context;

Expand Down
73 changes: 0 additions & 73 deletions test/CopyPlugin.test.js
@@ -1,7 +1,5 @@
import path from 'path';

import CopyPlugin from '../src/index';

import { MockCompiler } from './utils/mocks';
import { run, runEmit, runChange } from './utils/run';

Expand Down Expand Up @@ -341,77 +339,6 @@ describe('apply function', () => {
});
});

describe('errors', () => {
it('should not throw an error if no patterns are passed', (done) => {
runEmit({
expectedAssetKeys: [],
patterns: undefined, // eslint-disable-line no-undefined
})
.then(done)
.catch(done);
});

it('should throw an error if the patterns are an object', () => {
const createPluginWithObject = () => {
// eslint-disable-next-line no-new
new CopyPlugin({});
};

expect(createPluginWithObject).toThrow(Error);
});

it('should throw an error if the patterns are null', () => {
const createPluginWithNull = () => {
// eslint-disable-next-line no-new
new CopyPlugin(null);
};

expect(createPluginWithNull).toThrow(Error);
});

it('should throw an error if the "from" path is an empty string', () => {
const createPluginWithNull = () => {
// eslint-disable-next-line no-new
new CopyPlugin({
from: '',
});
};

expect(createPluginWithNull).toThrow(Error);
});

it('should warn when pattern is empty', (done) => {
runEmit({
expectedAssetKeys: [
'.file.txt',
'[!]/hello.txt',
'[special?directory]/(special-*file).txt',
'[special?directory]/directoryfile.txt',
'[special?directory]/nested/nestedfile.txt',
'binextension.bin',
'dir (86)/file.txt',
'dir (86)/nesteddir/deepnesteddir/deepnesteddir.txt',
'dir (86)/nesteddir/nestedfile.txt',
'directory/.dottedfile',
'directory/directoryfile.txt',
'directory/nested/deep-nested/deepnested.txt',
'directory/nested/nestedfile.txt',
'file.txt',
'file.txt.gz',
'noextension',
],
expectedErrors: [new Error(`path "from" cannot be empty string`)],
patterns: [
{
from: '',
},
],
})
.then(done)
.catch(done);
});
});

describe('dev server', () => {
it('should work with absolute to if outpath is defined with webpack-dev-server', (done) => {
runEmit({
Expand Down

0 comments on commit 452539a

Please sign in to comment.