Repository: tivac/modular-css
Pull request #704 (2019-12-17 08:13:20)

refactor: Bye Object.assign
<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->
Using `{ __proto__ : null }` and object spread everywhere.

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
Never liked the `Object.assign()` flow all that much, and while using it + `Object.create(null)` is technically more correct than `{ __proto__ : null }` until someone *actually deprecates* `__proto__` I think it's plenty clear and looks nicer.

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
All tests pass.

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [x] All new and existing tests passed.


netlify[bot]: Deploy preview for *m-css* failed.

Built with commit 81f499bc221012bc89aa77c5985adbd7e2b9371e

https://app.netlify.com/sites/m-css/deploys/5df88e2203b6ba00073fa8ad
codecov[bot]: # [Codecov](https://codecov.io/gh/tivac/modular-css/pull/704?src=pr&el=h1) Report
> Merging [#704](https://codecov.io/gh/tivac/modular-css/pull/704?src=pr&el=desc) into [master](https://codecov.io/gh/tivac/modular-css/commit/c6ebf81e2f43ebc1a833be096b55b3c90a40fbe4?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/tivac/modular-css/pull/704/graphs/tree.svg?width=650&token=EIUJKcuTE8&height=150&src=pr)](https://codecov.io/gh/tivac/modular-css/pull/704?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #704      +/-   ##
==========================================
+ Coverage   98.45%   98.46%   +<.01%     
==========================================
  Files          45       45              
  Lines        1168     1171       +3     
  Branches      181      184       +3     
==========================================
+ Hits         1150     1153       +3     
  Misses         15       15              
  Partials        3        3
```


| [Impacted Files](https://codecov.io/gh/tivac/modular-css/pull/704?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/postcss/postcss.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcG9zdGNzcy9wb3N0Y3NzLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [packages/processor/plugins/values-replace.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcHJvY2Vzc29yL3BsdWdpbnMvdmFsdWVzLXJlcGxhY2UuanM=) | `100% <100%> (ø)` | :arrow_up: |
| [packages/processor/lib/message.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcHJvY2Vzc29yL2xpYi9tZXNzYWdlLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [packages/aliases/aliases.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvYWxpYXNlcy9hbGlhc2VzLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [packages/processor/plugins/values-export.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcHJvY2Vzc29yL3BsdWdpbnMvdmFsdWVzLWV4cG9ydC5qcw==) | `90% <100%> (ø)` | :arrow_up: |
| [packages/webpack/plugin.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvd2VicGFjay9wbHVnaW4uanM=) | `94.87% <100%> (ø)` | :arrow_up: |
| [packages/browserify/browserify.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvYnJvd3NlcmlmeS9icm93c2VyaWZ5Lmpz) | `97.84% <100%> (ø)` | :arrow_up: |
| [packages/rollup-rewriter/rewriter.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcm9sbHVwLXJld3JpdGVyL3Jld3JpdGVyLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [packages/paths/paths.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcGF0aHMvcGF0aHMuanM=) | `100% <100%> (ø)` | :arrow_up: |
| [packages/rollup/rollup.js](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree#diff-cGFja2FnZXMvcm9sbHVwL3JvbGx1cC5qcw==) | `100% <100%> (ø)` | :arrow_up: |
| ... and [3 more](https://codecov.io/gh/tivac/modular-css/pull/704/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tivac/modular-css/pull/704?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/tivac/modular-css/pull/704?src=pr&el=footer). Last update [c6ebf81...81f499b](https://codecov.io/gh/tivac/modular-css/pull/704?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/packages/aliases/aliases.js b/packages/aliases/aliases.js
index 2768848d..eac3f8a1 100644
--- a/packages/aliases/aliases.js
+++ b/packages/aliases/aliases.js
@@ -3,11 +3,11 @@
 const from = require("resolve-from");
 
 module.exports = (args) => {
-    const options = Object.assign(
-        Object.create(null),
-        { aliases : {} },
-        args
-    );
+    const options = {
+        __proto__ : null,
+        aliases   : {},
+        ...args,
+    };
 
     const aliases = Object.keys(options.aliases).map((alias) => ({
         name   : alias,
diff --git a/packages/browserify/browserify.js b/packages/browserify/browserify.js
index 65b1ed87..7404c4b4 100644
--- a/packages/browserify/browserify.js
+++ b/packages/browserify/browserify.js
@@ -26,12 +26,15 @@ const outputs = ({ exports }) => `module.exports = ${
 };`;
 
 module.exports = (browserify, opts) => {
-    const options = Object.assign(Object.create(null), {
-            ext   : ".css",
-            map   : browserify._options.debug,
-            cwd   : browserify._options.basedir || process.cwd(),
-            cache : true,
-        }, opts);
+    const options = {
+        __proto__ : null,
+
+        ext   : ".css",
+        map   : browserify._options.debug,
+        cwd   : browserify._options.basedir || process.cwd(),
+        cache : true,
+        ...opts,
+    };
 
     let processor = options.cache && new Processor(options);
     let bundler;
diff --git a/packages/cli/cli.js b/packages/cli/cli.js
index 8ee1b103..ad323c4a 100755
--- a/packages/cli/cli.js
+++ b/packages/cli/cli.js
@@ -39,11 +39,13 @@ if(!cli.input.length) {
     cli.showHelp();
 }
 
-glob(Object.assign(
-    Object.create(null),
-    cli.flags,
-    { search : cli.input }
-))
+glob({
+    __proto__ : null,
+
+    ...cli.flags,
+    
+    search : cli.input,
+})
 .then((processor) => processor.output({ to : cli.flags.out }))
 .then(({ compositions, css }) => {
     if(cli.flags.json) {
diff --git a/packages/glob/glob.js b/packages/glob/glob.js
index c6366eb0..1566d9fa 100644
--- a/packages/glob/glob.js
+++ b/packages/glob/glob.js
@@ -3,14 +3,13 @@
 const globule = require("globule");
 const Processor = require("@modular-css/processor");
 
-module.exports = async (opts) => {
-    const options = Object.assign(
-            Object.create(null),
-            {
-                search : [ "**/*.css" ],
-            },
-            opts || {}
-        );
+module.exports = async (opts = {}) => {
+    const options = {
+        __proto__ : null,
+        
+        search : [ "**/*.css" ],
+        ...opts,
+    };
 
     const processor = new Processor(options);
 
diff --git a/packages/paths/paths.js b/packages/paths/paths.js
index 7e74e230..c4cb4e36 100644
--- a/packages/paths/paths.js
+++ b/packages/paths/paths.js
@@ -3,13 +3,12 @@
 const from = require("resolve-from");
 
 module.exports = (args) => {
-    const options = Object.assign(
-            Object.create(null),
-            {
-                paths : [],
-            },
-            args
-        );
+    const options = {
+        __proto__ : null,
+        
+        paths : [],
+        ...args,
+    };
     
     return (src, file) => {
         let result;
diff --git a/packages/postcss/postcss.js b/packages/postcss/postcss.js
index 6ce15e8a..4aed90cf 100644
--- a/packages/postcss/postcss.js
+++ b/packages/postcss/postcss.js
@@ -6,13 +6,13 @@ const postcss = require("postcss");
 const mkdirp  = require("mkdirp");
 const Processor = require("@modular-css/processor");
 
-module.exports = postcss.plugin("modular-css", (opts) =>
+module.exports = postcss.plugin("modular-css", (opts = {}) =>
     async (root, result) => {
-        const processor = new Processor(Object.assign(
-            Object.create(null),
-            opts,
-            result.opts
-        ));
+        const processor = new Processor({
+            __proto__ : null,
+            ...opts,
+            ...result.opts,
+        });
 
         const { exports : exported } = await processor.string(result.opts.from, root);
         
diff --git a/packages/processor/lib/message.js b/packages/processor/lib/message.js
index 70a95933..6a739ddd 100644
--- a/packages/processor/lib/message.js
+++ b/packages/processor/lib/message.js
@@ -6,8 +6,9 @@ module.exports = ({ messages }, filter) => {
     const message = find(messages, filter);
 
     // Don't get to mess w/ other plugins objects
-    return Object.assign(
-        Object.create(null),
-        message ? message[filter] : {}
-    );
+    return {
+        __proto__ : null,
+
+        ...(message ? message[filter] : {}),
+    };
 };
diff --git a/packages/processor/plugins/values-export.js b/packages/processor/plugins/values-export.js
index dc56c1ea..6258a2d8 100644
--- a/packages/processor/plugins/values-export.js
+++ b/packages/processor/plugins/values-export.js
@@ -16,11 +16,12 @@ module.exports = (css, { opts, messages }) => {
         .sort((a, b) => order.indexOf(a.plugin) - order.indexOf(b.plugin))
         .reduce((prev, curr) => Object.assign(prev, curr.values), Object.create(null));
     
-    file.values = Object.assign(
-        Object.create(null),
-        values,
-        file.values || {}
-    );
+    file.values = {
+        __proto__ : null,
+        
+        ...values,
+        ...(file.values || {}),
+    };
 };
 
 module.exports.postcssPlugin = "modular-css-values-export";
diff --git a/packages/processor/plugins/values-replace.js b/packages/processor/plugins/values-replace.js
index a8719964..cb809124 100644
--- a/packages/processor/plugins/values-replace.js
+++ b/packages/processor/plugins/values-replace.js
@@ -12,10 +12,11 @@ module.exports = (css, { opts, messages }) => {
     const graph = new Graph();
 
     // Create local copy of values since we're going to merge in namespace stuff
-    const values = Object.assign(
-        Object.create(null),
-        get(opts, [ "files", opts.from, "values" ])
-    );
+    const values = {
+        __proto__ : null,
+        
+        ...get(opts, [ "files", opts.from, "values" ]),
+    };
 
     // Merge namespaced values in w/ prefixed names
     messages
diff --git a/packages/processor/processor.js b/packages/processor/processor.js
index 3fddc0b6..32b74d35 100644
--- a/packages/processor/processor.js
+++ b/packages/processor/processor.js
@@ -20,38 +20,38 @@ const noop = () => true;
 
 const defaultLoadFile = (id) => fs.readFileSync(id, "utf8");
 
-const params = ({ _options, _files, _graph, _resolve }, args) => Object.assign(
-    Object.create(null),
-    _options,
-    _options.postcss,
-    {
-        from    : null,
-        files   : _files,
-        graph   : _graph,
-        resolve : _resolve,
-    },
-    args
-);
+const params = ({ _options, _files, _graph, _resolve }, args) => ({
+    __proto__ : null,
+    ..._options,
+    ..._options.postcss,
+    from      : null,
+    files     : _files,
+    graph     : _graph,
+    resolve   : _resolve,
+    ...args,
+});
+
+const DEFAULTS = {
+    cwd : process.cwd(),
+    map : false,
+
+    dupewarn     : true,
+    exportValues : true,
+    loadFile     : defaultLoadFile,
+    postcss      : {},
+    resolvers    : [],
+    rewrite      : true,
+    verbose      : false,
+};
 
 class Processor {
-    constructor(opts) {
+    constructor(opts = {}) {
         /* eslint max-statements: [ "warn", 25 ] */
-        const options = Object.assign(
-            Object.create(null),
-            {
-                cwd : process.cwd(),
-                map : false,
-
-                dupewarn     : true,
-                exportValues : true,
-                loadFile     : defaultLoadFile,
-                postcss      : {},
-                resolvers    : [],
-                rewrite      : true,
-                verbose      : false,
-            },
-            opts
-        );
+        const options = {
+            __proto__ : null,
+            ...DEFAULTS,
+            ...opts,
+        };
 
         this._options = options;
 
@@ -301,11 +301,12 @@ class Processor {
                 // https://github.com/postcss/postcss/pull/761
                 // https://github.com/tivac/modular-css/pull/157
                 //
-                source : Object.assign(
-                    {},
-                    result.root.source,
-                    { end : result.root.source.start }
-                ),
+                source : {
+                    __proto__ : null,
+
+                    ...result.root.source,
+                    end : result.root.source.start,
+                },
             });
 
             root.append([ comment, ...result.root.nodes ]);
@@ -400,26 +401,28 @@ class Processor {
 
             const { result } = file;
 
-            file.exports = Object.assign(
-                Object.create(null),
+            file.exports = {
+                __proto__ : null,
 
                 // optionally export @value entries
-                this._options.exportValues ?
-                    mapValues(file.values, ({ value }) => value) :
-                    null,
+                ...(
+                    this._options.exportValues ?
+                        mapValues(file.values, ({ value }) => value) :
+                        null
+                ),
 
                 // export classes
-                message(result, "classes"),
+                ...message(result, "classes"),
 
                 // Export anything from plugins named "modular-css-export*"
-                result.messages.reduce((out, { plugin, exports : exported }) => {
+                ...result.messages.reduce((out, { plugin, exports : exported }) => {
                     if(!plugin || plugin.indexOf("modular-css-export") !== 0) {
                         return out;
                     }
 
                     return Object.assign(out, exported);
-                }, Object.create(null))
-            );
+                }, Object.create(null)),
+            };
         }
 
         return {
diff --git a/packages/rollup-rewriter/rewriter.js b/packages/rollup-rewriter/rewriter.js
index 3e0a95c7..80e9ab1e 100644
--- a/packages/rollup-rewriter/rewriter.js
+++ b/packages/rollup-rewriter/rewriter.js
@@ -17,12 +17,18 @@ const formats = {
 
 const supported = new Set(Object.keys(formats).sort());
 
-module.exports = (opts) => {
-    const options = Object.assign(Object.create(null), {
-        loader  : false,
-        loadfn  : false,
-        verbose : false,
-    }, opts);
+const DEFAULTS = {
+    loader  : false,
+    loadfn  : false,
+    verbose : false,
+};
+
+module.exports = (opts = {}) => {
+    const options = {
+        __proto__ : null,
+        ...DEFAULTS,
+        ...opts,
+    };
 
     if(!options.loadfn) {
         throw new Error("options.loadfn must be configured");
diff --git a/packages/rollup/rollup.js b/packages/rollup/rollup.js
index 1d58e105..52d07675 100644
--- a/packages/rollup/rollup.js
+++ b/packages/rollup/rollup.js
@@ -19,20 +19,26 @@ const emptyMappings = {
     mappings : "",
 };
 
-module.exports = (opts) => {
-    const options = Object.assign(Object.create(null), {
-        common       : "common.css",
-        dev          : false,
-        json         : false,
-        meta         : false,
-        namedExports : true,
-        styleExport  : false,
-        verbose      : false,
-        empties      : true,
-
-        // Regexp to work around https://github.com/rollup/rollup-pluginutils/issues/39
-        include : /\.css$/i,
-    }, opts);
+const DEFAULTS = {
+    common       : "common.css",
+    dev          : false,
+    json         : false,
+    meta         : false,
+    namedExports : true,
+    styleExport  : false,
+    verbose      : false,
+    empties      : true,
+
+    // Regexp to work around https://github.com/rollup/rollup-pluginutils/issues/39
+    include : /\.css$/i,
+};
+
+module.exports = (opts = {}) => {
+    const options = {
+        __proto__ : null,
+        ...DEFAULTS,
+        ...opts,
+    };
 
     const filter = utils.createFilter(options.include, options.exclude);
 
@@ -218,11 +224,11 @@ module.exports = (opts) => {
             let mapOpt = map;
 
             if(assetFileNames.includes("[hash]") && typeof mapOpt === "object") {
-                mapOpt = Object.assign(
-                    Object.create(null),
-                    mapOpt,
-                    { annotation : false }
-                );
+                mapOpt = {
+                    __proto__  : null,
+                    ...mapOpt,
+                    annotation : false,
+                };
             }
 
             // Track specified name -> output name for writing out metadata later
diff --git a/packages/webpack/loader.js b/packages/webpack/loader.js
index 8be251fc..e3d25272 100644
--- a/packages/webpack/loader.js
+++ b/packages/webpack/loader.js
@@ -5,15 +5,21 @@ const { keyword } = require("esutils");
 
 const output = require("@modular-css/processor/lib/output.js");
 
+const DEFAULTS = {
+    styleExport   : true,
+    namedExports  : true,
+    defaultExport : true,
+};
+
 // Can't be an arrow function due to `this` usage :(
 module.exports = async function(source) {
-    const defaults  = {
-        styleExport   : true,
-        namedExports  : true,
-        defaultExport : true,
+    const options   = {
+        __proto__ : null,
+        ...DEFAULTS,
+        ...utils.getOptions(this),
     };
-    const options   = Object.assign(Object.create(null), defaults, utils.getOptions(this)) || false;
-    const done      = this.async();
+
+    const done = this.async();
     const processor = this.options ?
         // Webpack 2 & 3
         this.options.processor :
diff --git a/packages/webpack/plugin.js b/packages/webpack/plugin.js
index c80a96d9..5d2bffe1 100644
--- a/packages/webpack/plugin.js
+++ b/packages/webpack/plugin.js
@@ -16,10 +16,10 @@ const getChangedFiles = (prev, curr) =>
         );
 
 function ModularCSS(args) {
-    var options = Object.assign(
-            Object.create(null),
-            args
-        );
+    var options = {
+        __proto__ : null,
+        ...args,
+    };
 
     if(options.cjs) {
         options.namedExports = false;
diff --git a/packages/www/build/svelte.js b/packages/www/build/svelte.js
index 48bbf3fc..d748bba2 100644
--- a/packages/www/build/svelte.js
+++ b/packages/www/build/svelte.js
@@ -13,10 +13,10 @@ module.exports = async ({ file, preprocess = false }) => {
     if(preprocess) {
         const preprocessed = await svelte.preprocess(
             source,
-            Object.assign(
-                { filename : file },
-                preprocess
-            )
+            {
+                filename : file,
+                ...preprocess,
+            }
         );
 
         compiled = svelte.compile(preprocessed.toString(), { generate : "ssr" });
diff --git a/packages/www/src/api/usage-svelte.md b/packages/www/src/api/usage-svelte.md
index 478e4a02..e2e4384e 100644
--- a/packages/www/src/api/usage-svelte.md
+++ b/packages/www/src/api/usage-svelte.md
@@ -51,7 +51,7 @@ const { processor, preprocess } = require("@modular-css/svelte")({
 
 const processed = await svelte.preprocess(
     fs.readFileSync(filename, "utf8"),
-    Object.assign({}, preprocess, { filename })
+    { ...preprocess, filename },
 );
 
 const result = await processor.output();
@@ -132,6 +132,14 @@ If `true` whenever a missing replacement is found like `{css.doesnotexist}` an e
 
 Pass a previously-created `@modular-css/processor` instance into the preprocessor. Will **not** pass through any other options to the processor if this is set, but `strict` will still be honored by the preprocessor.
 
+##### `warnOnUnused`
+
+If `true` any classes in the source CSS that aren't directly utilized by the template (or indirectly used via `composes`) will be logged out as warnings.
+
+⚠️⚡💀⚠️💀⚡⚠️
+Please note that this functionality is **EXPERIMENTAL** and subject to change. The first iteration of this feature is very basic and may lead to considerable false-positive warnings. Use your best judgement before removing CSS!
+⚠️⚡💀⚠️💀⚡⚠️
+
 ##### Shared Options
 
 All options are passed to the underlying `Processor` instance, see the [Processor Options](#processor-options).


Test patch:
diff --git a/packages/postcss/test/postcss.test.js b/packages/postcss/test/postcss.test.js
index 459b1647..bd4b69ec 100644
--- a/packages/postcss/test/postcss.test.js
+++ b/packages/postcss/test/postcss.test.js
@@ -6,17 +6,16 @@ const read    = require("@modular-css/test-utils/read.js")(__dirname);
 const namer   = require("@modular-css/test-utils/namer.js");
 const plugin  = require("../postcss.js");
 
-function process(file, opts) {
+function process(file, opts = {}) {
     return plugin.process(
         fs.readFileSync(file),
-        Object.assign(
-            Object.create(null),
-            {
-                from : file,
-                namer,
-            },
-            opts || {}
-        )
+        {
+            __proto__ : null,
+
+            from : file,
+            namer,
+            ...opts,
+        }
     );
 }