Repository: webpack-contrib/copy-webpack-plugin
Pull request #453 (2020-04-28 17:14:20)

refactor: remove the global `context` option
<!--
  HOLY CRAP a Pull Request. We ❤️ those!

  If you remove or skip this template, you'll make the 🐼 sad and the mighty god
  of Github will appear and pile-drive the close button from a great height
  while making animal noises.

  Please place an x (no spaces!) in all [ ] that apply
-->

This PR contains a:

- [ ] **bugfix**
- [ ] new **feature**
- [x] **code refactor**
- [x] **test update** <!-- if bug or feature is checked, this should be too -->
- [ ] **typo fix**
- [ ] **metadata update**

### Motivation / Use-Case

No need extra option (less options), you already have `context` option on pattern level

### Breaking Changes

BREAKING CHANGE: the global `context` option was removed in favor the `patten.context` option

### Additional Info

No

codecov[bot]: # [Codecov](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=h1) Report
> Merging [#453](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=desc) into [master](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/commit/f6da280abe3953990bfdad4dd1225c6e58382611&el=desc) will **decrease** coverage by `0.12%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453/graphs/tree.svg?width=650&height=150&src=pr&token=fEoU9iBFGL)](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #453      +/-   ##
==========================================
- Coverage   94.59%   94.46%   -0.13%     
==========================================
  Files           9        9              
  Lines         259      253       -6     
  Branches       64       62       -2     
==========================================
- Hits          245      239       -6     
  Misses         13       13              
  Partials        1        1              
```


| [Impacted Files](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/preProcessPattern.js](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453/diff?src=pr&el=tree#diff-c3JjL3ByZVByb2Nlc3NQYXR0ZXJuLmpz) | `97.40% <ø> (ø)` | |
| [src/index.js](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453/diff?src=pr&el=tree#diff-c3JjL2luZGV4Lmpz) | `94.73% <100.00%> (-0.72%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=footer). Last update [f6da280...7d039d4](https://codecov.io/gh/webpack-contrib/copy-webpack-plugin/pull/453?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index 8fe97fe..47a03bd 100644
--- a/README.md
+++ b/README.md
@@ -547,10 +547,9 @@ module.exports = {
 
 ### Options
 
-|         Name          |    Type    |          Default           | Description                                                                      |
-| :-------------------: | :--------: | :------------------------: | :------------------------------------------------------------------------------- |
-|  [`ignore`](#ignore)  | `{Array}`  |            `[]`            | Array of globs to ignore (applied to `from`)                                     |
-| [`context`](#context) | `{String}` | `compiler.options.context` | A path that determines how to interpret the `from` path, shared for all patterns |
+|        Name         |   Type    | Default | Description                                  |
+| :-----------------: | :-------: | :-----: | :------------------------------------------- |
+| [`ignore`](#ignore) | `{Array}` |  `[]`   | Array of globs to ignore (applied to `from`) |
 
 #### `ignore`
 
@@ -569,23 +568,6 @@ module.exports = {
 };
 ```
 
-#### `context`
-
-A path that determines how to interpret the `from` path, shared for all patterns.
-
-**webpack.config.js**
-
-```js
-module.exports = {
-  plugins: [
-    new CopyPlugin({
-      patterns: [...patterns],
-      options: { context: '/app' },
-    }),
-  ],
-};
-```
-
 ## Contributing
 
 Please take a moment to read our contributing guidelines if you haven't yet done so.
diff --git a/src/index.js b/src/index.js
index cc5f27f..5a0ab85 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,5 +1,3 @@
-import path from 'path';
-
 import validateOptions from 'schema-utils';
 
 import schema from './options.json';
@@ -21,40 +19,26 @@ class CopyPlugin {
   apply(compiler) {
     const fileDependencies = new Set();
     const contextDependencies = new Set();
-
-    let context;
-
-    if (!this.options.context) {
-      ({ context } = compiler.options);
-    } else if (!path.isAbsolute(this.options.context)) {
-      context = path.join(compiler.options.context, this.options.context);
-    } else {
-      ({ context } = this.options);
-    }
-
-    const logger = compiler.getInfrastructureLogger('copy-webpack-plugin');
-
     const plugin = { name: 'CopyPlugin' };
+    const logger = compiler.getInfrastructureLogger('copy-webpack-plugin');
 
     compiler.hooks.emit.tapAsync(plugin, (compilation, callback) => {
       logger.debug('starting emit');
 
       const globalRef = {
+        context: compiler.options.context,
         logger,
         compilation,
         fileDependencies,
         contextDependencies,
-        context,
         inputFileSystem: compiler.inputFileSystem,
         output: compiler.options.output.path,
         ignore: this.options.ignore || [],
         concurrency: this.options.concurrency,
       };
 
-      const { patterns } = this;
-
       Promise.all(
-        patterns.map((pattern) =>
+        this.patterns.map((pattern) =>
           Promise.resolve()
             .then(() => preProcessPattern(globalRef, pattern))
             // Every source (from) is assumed to exist here
diff --git a/src/options.json b/src/options.json
index 738bc29..9b5f6ea 100644
--- a/src/options.json
+++ b/src/options.json
@@ -90,9 +90,6 @@
       "type": "object",
       "additionalProperties": false,
       "properties": {
-        "context": {
-          "type": "string"
-        },
         "ignore": {
           "type": "array"
         }
diff --git a/src/preProcessPattern.js b/src/preProcessPattern.js
index e41085a..53d7e3e 100644
--- a/src/preProcessPattern.js
+++ b/src/preProcessPattern.js
@@ -11,8 +11,8 @@ import { stat } from './utils/promisify';
 
 export default function preProcessPattern(globalRef, pattern) {
   const {
-    logger,
     context,
+    logger,
     inputFileSystem,
     fileDependencies,
     contextDependencies,


Test patch:
diff --git a/test/CopyPlugin.test.js b/test/CopyPlugin.test.js
index 7a5b242..512aa5b 100644
--- a/test/CopyPlugin.test.js
+++ b/test/CopyPlugin.test.js
@@ -387,9 +387,11 @@ describe('apply function', () => {
         patterns: [
           {
             from: 'tempfile1.txt',
+            context: 'watch',
           },
           {
             from: 'tempfile2.txt',
+            context: 'watch',
           },
         ],
       })
@@ -414,7 +416,7 @@ describe('apply function', () => {
         ),
         patterns: [
           {
-            from: 'directory',
+            from: 'watch/directory',
           },
         ],
       })
@@ -439,7 +441,7 @@ describe('apply function', () => {
         ),
         patterns: [
           {
-            context: 'directory',
+            context: 'watch/directory',
             from: '**/*.txt',
             to: 'dest1',
           },
@@ -471,12 +473,12 @@ describe('apply function', () => {
         ),
         patterns: [
           {
-            context: 'directory',
+            context: 'watch/directory',
             from: '**/*.txt',
             to: 'dest1',
           },
           {
-            context: 'directory',
+            context: 'watch/directory',
             from: '**/*.txt',
             to: 'dest2',
           },
@@ -502,11 +504,12 @@ describe('apply function', () => {
         newFileLoc2: path.join(FIXTURES_DIR, 'watch', 'tempfile2.txt'),
         patterns: [
           {
-            context: 'directory',
+            context: 'watch/directory',
             from: '**/*.txt',
             to: 'dest1',
           },
           {
+            context: 'watch',
             from: '**/*.txt',
             to: 'dest2',
           },
diff --git a/test/__snapshots__/validate-options.test.js.snap b/test/__snapshots__/validate-options.test.js.snap
index e57173a..336e5ad 100644
--- a/test/__snapshots__/validate-options.test.js.snap
+++ b/test/__snapshots__/validate-options.test.js.snap
@@ -1,16 +1,17 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`validate options should throw an error on the "options" option with "{"context":true}" value 1`] = `
-"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
- - options.options.context should be a string."
-`;
-
 exports[`validate options should throw an error on the "options" option with "{"ignore":true}" value 1`] = `
 "Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
  - options.options.ignore should be an array:
    [any, ...]"
 `;
 
+exports[`validate options should throw an error on the "options" option with "{"unknown":true}" value 1`] = `
+"Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
+ - options.options has an unknown property 'unknown'. These properties are valid:
+   object { ignore? }"
+`;
+
 exports[`validate options should throw an error on the "patterns" option with "" value 1`] = `
 "Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
  - options.patterns should be an array:
diff --git a/test/context-option.test.js b/test/context-option.test.js
index f7069bc..561911a 100644
--- a/test/context-option.test.js
+++ b/test/context-option.test.js
@@ -5,7 +5,7 @@ import { runEmit } from './helpers/run';
 const FIXTURES_DIR = path.join(__dirname, 'fixtures');
 
 describe('context option', () => {
-  it('should work when "from" is a file', (done) => {
+  it('should work when "from" is a file and "context" is a relative path', (done) => {
     runEmit({
       expectedAssetKeys: ['directoryfile.txt'],
       patterns: [
@@ -19,13 +19,13 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a file and "context" with special characters', (done) => {
+  it('should work when "from" is a directory and "context" is a relative path', (done) => {
     runEmit({
-      expectedAssetKeys: ['directoryfile.txt'],
+      expectedAssetKeys: ['deep-nested/deepnested.txt', 'nestedfile.txt'],
       patterns: [
         {
-          from: 'directoryfile.txt',
-          context: '[special?directory]',
+          from: 'nested',
+          context: 'directory',
         },
       ],
     })
@@ -33,12 +33,15 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a directory', (done) => {
+  it('should work when "from" is a glob and "context" is a relative path', (done) => {
     runEmit({
-      expectedAssetKeys: ['deep-nested/deepnested.txt', 'nestedfile.txt'],
+      expectedAssetKeys: [
+        'nested/deep-nested/deepnested.txt',
+        'nested/nestedfile.txt',
+      ],
       patterns: [
         {
-          from: 'nested',
+          from: 'nested/**/*',
           context: 'directory',
         },
       ],
@@ -47,17 +50,13 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a directory and "to" is a new directory', (done) => {
+  it('should work when "from" is a file and "context" is an absolute path', (done) => {
     runEmit({
-      expectedAssetKeys: [
-        'newdirectory/deep-nested/deepnested.txt',
-        'newdirectory/nestedfile.txt',
-      ],
+      expectedAssetKeys: ['directoryfile.txt'],
       patterns: [
         {
-          context: 'directory',
-          from: 'nested',
-          to: 'newdirectory',
+          from: 'directoryfile.txt',
+          context: path.join(FIXTURES_DIR, 'directory'),
         },
       ],
     })
@@ -65,18 +64,13 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a directory and "context" with special characters', (done) => {
+  it('should work when "from" is a directory and "context" is an absolute path', (done) => {
     runEmit({
-      expectedAssetKeys: [
-        'directoryfile.txt',
-        '(special-*file).txt',
-        'nested/nestedfile.txt',
-      ],
+      expectedAssetKeys: ['deep-nested/deepnested.txt', 'nestedfile.txt'],
       patterns: [
         {
-          // Todo strange behavour when you use `FIXTURES_DIR`, need investigate for next major release
-          from: '.',
-          context: '[special?directory]',
+          from: 'nested',
+          context: path.join(FIXTURES_DIR, 'directory'),
         },
       ],
     })
@@ -84,7 +78,7 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a glob', (done) => {
+  it('should work when "from" is a glob and "context" is an absolute path', (done) => {
     runEmit({
       expectedAssetKeys: [
         'nested/deep-nested/deepnested.txt',
@@ -93,7 +87,7 @@ describe('context option', () => {
       patterns: [
         {
           from: 'nested/**/*',
-          context: 'directory',
+          context: path.join(FIXTURES_DIR, 'directory'),
         },
       ],
     })
@@ -101,18 +95,13 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a glob and "to" is a directory', (done) => {
+  it('should work when "from" is a file and "context" with special characters', (done) => {
     runEmit({
-      expectedAssetKeys: [
-        'nested/directoryfile.txt',
-        'nested/nested/deep-nested/deepnested.txt',
-        'nested/nested/nestedfile.txt',
-      ],
+      expectedAssetKeys: ['directoryfile.txt'],
       patterns: [
         {
-          context: 'directory',
-          from: '**/*',
-          to: 'nested',
+          from: 'directoryfile.txt',
+          context: '[special?directory]',
         },
       ],
     })
@@ -120,18 +109,18 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a glob and "to" is a directory and "content" is an absolute path', (done) => {
+  it('should work when "from" is a directory and "context" with special characters', (done) => {
     runEmit({
       expectedAssetKeys: [
-        'nested/directoryfile.txt',
-        'nested/nested/deep-nested/deepnested.txt',
-        'nested/nested/nestedfile.txt',
+        'directoryfile.txt',
+        '(special-*file).txt',
+        'nested/nestedfile.txt',
       ],
       patterns: [
         {
-          context: path.join(FIXTURES_DIR, 'directory'),
-          from: '**/*',
-          to: 'nested',
+          // Todo strange behavour when you use `FIXTURES_DIR`, need investigate for next major release
+          from: '.',
+          context: '[special?directory]',
         },
       ],
     })
@@ -171,32 +160,13 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should work when "from" is a file and "context" is an absolute path', (done) => {
+  it('should work when "from" is a file and "to" is a directory', (done) => {
     runEmit({
-      expectedAssetKeys: ['directoryfile.txt'],
+      expectedAssetKeys: ['newdirectory/directoryfile.txt'],
       patterns: [
         {
+          context: 'directory',
           from: 'directoryfile.txt',
-          context: path.join(FIXTURES_DIR, 'directory'),
-        },
-      ],
-    })
-      .then(done)
-      .catch(done);
-  });
-
-  it('should override webpack config context with an absolute path', (done) => {
-    runEmit({
-      expectedAssetKeys: [
-        'newdirectory/deep-nested/deepnested.txt',
-        'newdirectory/nestedfile.txt',
-      ],
-      options: {
-        context: path.join(FIXTURES_DIR, 'directory'),
-      },
-      patterns: [
-        {
-          from: 'nested',
           to: 'newdirectory',
         },
       ],
@@ -205,17 +175,15 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should override webpack config context with a relative path', (done) => {
+  it('should work when "from" is a directory and "to" is a directory', (done) => {
     runEmit({
       expectedAssetKeys: [
         'newdirectory/deep-nested/deepnested.txt',
         'newdirectory/nestedfile.txt',
       ],
-      options: {
-        context: 'directory',
-      },
       patterns: [
         {
+          context: 'directory',
           from: 'nested',
           to: 'newdirectory',
         },
@@ -225,41 +193,18 @@ describe('context option', () => {
       .catch(done);
   });
 
-  it('should override global context on pattern context with a relative path', (done) => {
-    runEmit({
-      expectedAssetKeys: [
-        'newdirectory/deep-nested/deepnested.txt',
-        'newdirectory/nestedfile.txt',
-      ],
-      options: {
-        context: 'directory',
-      },
-      patterns: [
-        {
-          context: 'nested',
-          from: '.',
-          to: 'newdirectory',
-        },
-      ],
-    })
-      .then(done)
-      .catch(done);
-  });
-
-  it('overrides webpack config context with an absolute path', (done) => {
+  it('should work when "from" is a glob and "to" is a directory', (done) => {
     runEmit({
       expectedAssetKeys: [
-        'newdirectory/file.txt',
-        'newdirectory/nesteddir/deepnesteddir/deepnesteddir.txt',
-        'newdirectory/nesteddir/nestedfile.txt',
+        'nested/directoryfile.txt',
+        'nested/nested/deep-nested/deepnested.txt',
+        'nested/nested/nestedfile.txt',
       ],
-      options: {
-        context: path.join(FIXTURES_DIR, 'dir (86)'),
-      },
       patterns: [
         {
+          context: 'directory',
           from: '**/*',
-          to: 'newdirectory',
+          to: 'nested',
         },
       ],
     })
diff --git a/test/helpers/run.js b/test/helpers/run.js
index c7edbbb..bffb087 100644
--- a/test/helpers/run.js
+++ b/test/helpers/run.js
@@ -173,7 +173,7 @@ function runChange(opts) {
 
   return run({
     compiler,
-    options: Object.assign({}, opts.options, { context: 'watch' }),
+    options: Object.assign({}, opts.options),
     patterns: opts.patterns,
   })
     .then(() => {
diff --git a/test/validate-options.test.js b/test/validate-options.test.js
index 13ada82..cf779cc 100644
--- a/test/validate-options.test.js
+++ b/test/validate-options.test.js
@@ -235,8 +235,8 @@ describe('validate options', () => {
       ],
     },
     options: {
-      success: [{ context: 'context' }, { ignore: ['test'] }],
-      failure: [{ context: true }, { ignore: true }],
+      success: [{ ignore: ['test'] }],
+      failure: [{ unknown: true }, { ignore: true }],
     },
     unknown: {
       success: [],