From dff8358983f29c167ef127e6ec4d5cb2ca1753b1 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Fri, 6 Dec 2019 23:24:48 -0800 Subject: [PATCH] errors --- lighthouse-core/computed/bundle-analysis.js | 18 +- .../test/computed/bundle-analysis-test.js | 156 ++++++++++++++++++ 2 files changed, 167 insertions(+), 7 deletions(-) diff --git a/lighthouse-core/computed/bundle-analysis.js b/lighthouse-core/computed/bundle-analysis.js index 0e7e7f02ea2a..cb20a36faf19 100644 --- a/lighthouse-core/computed/bundle-analysis.js +++ b/lighthouse-core/computed/bundle-analysis.js @@ -39,7 +39,12 @@ function computeGeneratedFileSizes(map, content) { const lines = content.split('\n'); /** @type {Record} */ const files = {}; - let mappedBytes = 0; + const totalBytes = content.length; + let unmappedBytes = totalBytes; + + // If the map + contents don't line up, return a result that + // denotes nothing is mapped. + const failureResult = {files: {}, unmappedBytes, totalBytes}; // @ts-ignore: This function is added in SDK.js map.computeLastGeneratedColumns(); @@ -60,14 +65,14 @@ function computeGeneratedFileSizes(map, content) { if (line === null) { // @ts-ignore log.error(`${map.compiledURL} mapping for line out of bounds: ${lineNum + 1}`); - break; + return failureResult; } // Columns are 0-based if (colNum >= line.length) { // @ts-ignore log.error(`${map.compiledURL} mapping for column out of bounds: ${lineNum + 1}:${colNum}`); - break; + return failureResult; } let mappingLength = 0; @@ -76,7 +81,7 @@ function computeGeneratedFileSizes(map, content) { // @ts-ignore // eslint-disable-next-line max-len log.error(`${map.compiledURL} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`); - break; + return failureResult; } mappingLength = lastColNum - colNum; } else { @@ -84,13 +89,12 @@ function computeGeneratedFileSizes(map, content) { mappingLength = line.length - colNum; } files[source] = (files[source] || 0) + mappingLength; - mappedBytes += mappingLength; + unmappedBytes -= mappingLength; } - const totalBytes = content.length; return { files, - unmappedBytes: totalBytes - mappedBytes, + unmappedBytes, totalBytes, }; } diff --git a/lighthouse-core/test/computed/bundle-analysis-test.js b/lighthouse-core/test/computed/bundle-analysis-test.js index 5fdc07a74b65..afe3976ee921 100644 --- a/lighthouse-core/test/computed/bundle-analysis-test.js +++ b/lighthouse-core/test/computed/bundle-analysis-test.js @@ -77,6 +77,51 @@ describe('BundleAnalysis computed artifact', () => { `); }); + it('works (simple map) (null sources)', async () => { + // This map is from source-map-explorer. + // https://github.com/danvk/source-map-explorer/tree/4b95f6e7dfe0058d791dcec2107fee43a1ebf02e/tests + const {map, content} = load('foo.min'); + map.sources[3] = null; + const networkRecords = [{url: 'https://example.com/foo.min.js'}]; + const artifacts = { + SourceMaps: [{scriptUrl: 'https://example.com/foo.min.js', map}], + ScriptElements: [{src: 'https://example.com/foo.min.js', content}], + devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(networkRecords)}, + }; + const context = {computedCache: new Map()}; + const results = await BundleAnalysis.request(artifacts, context); + + expect(results).toHaveLength(1); + const result = results[0]; + + // Determine sizes. + expect(result.sizes).toMatchInlineSnapshot(` + Object { + "files": Object { + "node_modules/browser-pack/_prelude.js": 480, + "src/bar.js": 104, + "src/foo.js": 97, + }, + "totalBytes": 718, + "unmappedBytes": 37, + } + `); + + // Test the mapping. + const entry = result.map.findEntry(0, 644); + expect(entry).toMatchInlineSnapshot(` + SourceMapEntry { + "columnNumber": 644, + "lastColumnNumber": 648, + "lineNumber": 0, + "name": "bar", + "sourceColumnNumber": 15, + "sourceLineNumber": 3, + "sourceURL": "src/foo.js", + } + `); + }); + it('works (complex map)', async () => { const {map, content} = load('squoosh'); const networkRecords = [{url: 'https://squoosh.app/main-app.js'}]; @@ -188,4 +233,115 @@ describe('BundleAnalysis computed artifact', () => { } `); }); + + it('handles faulty maps', async () => { + let data; + let map; + let content; + + function init() { + data = load('foo.min'); + map = data.map; + content = data.content; + } + async function test() { + const networkRecords = [{url: 'https://example.com/foo.min.js'}]; + const artifacts = { + SourceMaps: [{scriptUrl: 'https://example.com/foo.min.js', map}], + ScriptElements: [{src: 'https://example.com/foo.min.js', content}], + devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(networkRecords)}, + }; + const context = {computedCache: new Map()}; + const results = await BundleAnalysis.request(artifacts, context); + const result = results[0]; + return {sizes: result.sizes, entry: result.map.findEntry(0, 644)}; + } + + init(); + map.mappings = 'blahblah blah'; + expect(await test()).toMatchInlineSnapshot(` + Object { + "entry": SourceMapEntry { + "columnNumber": -13, + "lineNumber": 0, + "name": "r", + "sourceColumnNumber": -418, + "sourceLineNumber": -432, + "sourceURL": undefined, + }, + "sizes": Object { + "files": Object {}, + "totalBytes": 718, + "unmappedBytes": 718, + }, + } + `); + + init(); + content = 'blahblah blah'; + expect(await test()).toMatchInlineSnapshot(` + Object { + "entry": SourceMapEntry { + "columnNumber": 644, + "lastColumnNumber": 648, + "lineNumber": 0, + "name": "bar", + "sourceColumnNumber": 15, + "sourceLineNumber": 3, + "sourceURL": "src/foo.js", + }, + "sizes": Object { + "files": Object {}, + "totalBytes": 13, + "unmappedBytes": 13, + }, + } + `); + + init(); + content = ''; + expect(await test()).toMatchInlineSnapshot(` + Object { + "entry": SourceMapEntry { + "columnNumber": 644, + "lastColumnNumber": 648, + "lineNumber": 0, + "name": "bar", + "sourceColumnNumber": 15, + "sourceLineNumber": 3, + "sourceURL": "src/foo.js", + }, + "sizes": Object { + "files": Object {}, + "totalBytes": 0, + "unmappedBytes": 0, + }, + } + `); + + init(); + map.names = ['blah']; + expect(await test()).toMatchInlineSnapshot(` + Object { + "entry": SourceMapEntry { + "columnNumber": 644, + "lastColumnNumber": 648, + "lineNumber": 0, + "name": undefined, + "sourceColumnNumber": 15, + "sourceLineNumber": 3, + "sourceURL": "src/foo.js", + }, + "sizes": Object { + "files": Object { + "node_modules/browser-pack/_prelude.js": 480, + "src/bar.js": 104, + "src/foo.js": 97, + }, + "totalBytes": 718, + "unmappedBytes": 37, + }, + } + `); + }); });