Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

sourcemaps - enhancement for sourcemap-validator #6277

Merged
merged 1 commit into from
Mar 11, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 71 additions & 22 deletions development/sourcemap-validator.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const fs = require('fs')
const { SourceMapConsumer } = require('source-map')
const path = require('path')
const pify = require('pify')
const fsAsync = pify(fs)

//
// Utility to help check if sourcemaps are working
//
Expand All @@ -9,39 +12,85 @@ const path = require('path')
// if not working it may error or print minified garbage
//

start()
start().catch(console.error)


async function start () {
const rawBuild = fs.readFileSync(path.join(__dirname, '/../dist/chrome/', 'inpage.js')
, 'utf8')
const rawSourceMap = fs.readFileSync(path.join(__dirname, '/../dist/sourcemaps/', 'inpage.js.map'), 'utf8')
const targetFiles = [`inpage.js`, `contentscript.js`, `ui.js`, `background.js`]
for (const buildName of targetFiles) {
await validateSourcemapForFile({ buildName })
}
}

async function validateSourcemapForFile ({ buildName }) {
console.log(`build "${buildName}"`)
const platform = `chrome`
// load build and sourcemaps
let rawBuild
try {
const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}`)
rawBuild = await fsAsync.readFile(filePath, 'utf8')
} catch (err) {}
if (!rawBuild) {
throw new Error(`SourcemapValidator - failed to load source file for "${buildName}"`)
}
// attempt to load in dist mode
let rawSourceMap
try {
const filePath = path.join(__dirname, `/../dist/sourcemaps/`, `${buildName}.map`)
rawSourceMap = await fsAsync.readFile(filePath, 'utf8')
} catch (err) {}
// attempt to load in dev mode
try {
const filePath = path.join(__dirname, `/../dist/${platform}/`, `${buildName}.map`)
rawSourceMap = await fsAsync.readFile(filePath, 'utf8')
} catch (err) {}
if (!rawSourceMap) {
throw new Error(`SourcemapValidator - failed to load sourcemaps for "${buildName}"`)
}

const consumer = await new SourceMapConsumer(rawSourceMap)

console.log('hasContentsOfAllSources:', consumer.hasContentsOfAllSources(), '\n')
console.log('sources:')
consumer.sources.map((sourcePath) => console.log(sourcePath))

console.log('\nexamining "new Error" statements:\n')
const sourceLines = rawBuild.split('\n')
sourceLines.map(line => indicesOf('new Error', line))
.forEach((errorIndices, lineIndex) => {
// if (errorIndex === null) return console.log('line does not contain "new Error"')
errorIndices.forEach((errorIndex) => {
const position = { line: lineIndex + 1, column: errorIndex }
const hasContentsOfAllSources = consumer.hasContentsOfAllSources()
if (!hasContentsOfAllSources) console.warn('SourcemapValidator - missing content of some sources...')

console.log(` sampling from ${consumer.sources.length} files`)
let sampleCount = 0

const buildLines = rawBuild.split('\n')
const targetString = 'new Error'
// const targetString = 'null'
const matchesPerLine = buildLines.map(line => indicesOf(targetString, line))
matchesPerLine.forEach((matchIndices, lineIndex) => {
matchIndices.forEach((matchColumn) => {
sampleCount++
const position = { line: lineIndex + 1, column: matchColumn }
const result = consumer.originalPositionFor(position)
if (!result.source) return console.warn(`!! missing source for position: ${position}`)
// filter out deps distributed minified without sourcemaps
if (result.source === 'node_modules/browserify/node_modules/browser-pack/_prelude.js') return // minified mess
if (result.source === 'node_modules/web3/dist/web3.min.js') return // minified mess
// warn if source content is missing
if (!result.source) {
console.warn(`!! missing source for position: ${JSON.stringify(position)}`)
// const buildLine = buildLines[position.line - 1]
console.warn(` origin in build:`)
console.warn(` ${buildLines[position.line - 2]}`)
console.warn(`-> ${buildLines[position.line - 1]}`)
console.warn(` ${buildLines[position.line - 0]}`)
return
}
const sourceContent = consumer.sourceContentFor(result.source)
const sourceLines = sourceContent.split('\n')
const line = sourceLines[result.line - 1]
console.log(`\n========================== ${result.source} ====================================\n`)
console.log(line)
console.log(`\n==============================================================================\n`)
// this sometimes includes the whole line though we tried to match somewhere in the middle
const portion = line.slice(result.column)
const isMaybeValid = portion.includes(targetString)
if (!isMaybeValid) {
console.error('Sourcemap seems invalid:')
console.log(`\n========================== ${result.source} ====================================\n`)
console.log(line)
console.log(`\n==============================================================================\n`)
}
})
})
console.log(` checked ${sampleCount} samples`)
}

function indicesOf (substring, string) {
Expand Down