Repository: webpack-contrib/uglifyjs-webpack-plugin (js)

Issue:
Unnecessary warning on "invalid source map" for JSON files
Hi everyone :)

When `import()`ing a json file, the generated source map is valid but "empty", which causes https://github.com/webpack-contrib/uglifyjs-webpack-plugin/pull/268/files#diff-8968c62593320351ced6a0ef776ef599R8 to fail and emit a warning.

See https://github.com/webpack-contrib/uglifyjs-webpack-plugin/pull/268

**Example:**

`data.json`
```json
{
	"hello": "world"
}
```

generates the following source map:

```json
{
 "version":1,
 "sources":[],
 "names":[],
 "mappings":"",
 "file":"data.8efcc96623969177ff47.js",
 "sourceRoot":""
}
```

Unfortunately this causes `isSourceMap()` from https://github.com/webpack-contrib/uglifyjs-webpack-plugin/pull/268/files#diff-8968c62593320351ced6a0ef776ef599 to not recognize it as a valid source map. (`mappings` check fails).

Even when using `SourceMapDevToolPlugin()` https://webpack.js.org/plugins/source-map-dev-tool-plugin/ and explicitely excluding source maps for such files the warning will still be added. This should definitely not happen, I guess? Of course there is "no valid source map", because there is no source map at all.

Ultimately it adds the following warning to the webpack compiler output:
> data.8efcc96623969177ff47.js contain invalid source map

Sidenote: There is a typo, it should be "contains".

Side-Sidenote: This "warning" comes without any "error stack" and is really, really hard to debug. Also searching on google / stackoverflow etc. is extremely hard because it's so generic and there is no way of knowing who warned me. Is it webpack? Babel? Typescript?

I only found the cause by change after intense searching and almost losing my mind. 🤪
Would love to see some improved message here too :)

Cheers and thank you,
Stefan


Pull request description:
fix: improve `isSouceMap` check
fixes #283


Patch:
diff --git a/src/index.js b/src/index.js
index 3104e0b..a604dc1 100644
--- a/src/index.js
+++ b/src/index.js
@@ -149,7 +149,7 @@ class UglifyJsPlugin {
               } else {
                 inputSourceMap = map;
                 compilation.warnings.push(
-                  new Error(`${file} contain invalid source map`),
+                  new Error(`${file} contains invalid source map`),
                 );
               }
             } else {
diff --git a/src/utils/index.js b/src/utils/index.js
index 37b63c9..68ff51e 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -4,8 +4,8 @@ function isSourceMap(input) {
   return Boolean(input &&
     input.version &&
     input.sources &&
-    input.names &&
-    input.mappings);
+    Array.isArray(input.sources) &&
+    typeof input.mappings === 'string');
 }
 
 export default {


Test patch:
diff --git a/test/__snapshots__/source-map-options.test.js.snap b/test/__snapshots__/source-map-options.test.js.snap
index b750e4b..ad1cdd6 100644
--- a/test/__snapshots__/source-map-options.test.js.snap
+++ b/test/__snapshots__/source-map-options.test.js.snap
@@ -4,7 +4,7 @@ exports[`when options.sourceMap true and options.parallel true compilation handl
 
 exports[`when options.sourceMap true and options.parallel true compilation handler when called optimize-chunk-assets handler only calls callback once: warnings 1`] = `
 Array [
-  [Error: test4.js contain invalid source map],
+  [Error: test4.js contains invalid source map],
 ]
 `;
 
@@ -204,7 +204,7 @@ exports[`when options.sourceMap true compilation handler when called optimize-ch
 
 exports[`when options.sourceMap true compilation handler when called optimize-chunk-assets handler only calls callback once: warnings 1`] = `
 Array [
-  [Error: test4.js contain invalid source map],
+  [Error: test4.js contains invalid source map],
 ]
 `;
 
diff --git a/test/utils/index.test.js b/test/utils/index.test.js
index 3899b08..3a27a19 100644
--- a/test/utils/index.test.js
+++ b/test/utils/index.test.js
@@ -10,12 +10,25 @@ describe('utils', () => {
       sourceRoot: 'http://example.com/www/js/',
       mappings: 'CAAC,IAAI,IAAM,SAAUA,GAClB,OAAOC,IAAID;CCDb,IAAI,IAAM,SAAUE,GAClB,OAAOA',
     };
+    const emptyRawSourceMap = {
+      version: 3,
+      sources: [],
+      mappings: '',
+    };
 
     expect(utils.isSourceMap(null)).toBe(false);
     expect(utils.isSourceMap()).toBe(false);
     expect(utils.isSourceMap({})).toBe(false);
     expect(utils.isSourceMap([])).toBe(false);
     expect(utils.isSourceMap('foo')).toBe(false);
+    expect(utils.isSourceMap({ version: 3 })).toBe(false);
+    expect(utils.isSourceMap({ sources: '' })).toBe(false);
+    expect(utils.isSourceMap({ mappings: [] })).toBe(false);
+    expect(utils.isSourceMap({ version: 3, sources: '' })).toBe(false);
+    expect(utils.isSourceMap({ version: 3, mappings: [] })).toBe(false);
+    expect(utils.isSourceMap({ sources: '', mappings: [] })).toBe(false);
+    expect(utils.isSourceMap({ version: 3, sources: '', mappings: [] })).toBe(false);
     expect(utils.isSourceMap(rawSourceMap)).toBe(true);
+    expect(utils.isSourceMap(emptyRawSourceMap)).toBe(true);
   });
 });