UNPKG

parcel-bundler

Version:

Blazing fast, zero configuration web application bundler

335 lines (269 loc) 9.45 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); const _require = require('source-map'), SourceMapConsumer = _require.SourceMapConsumer, SourceMapGenerator = _require.SourceMapGenerator; const lineCounter = require('./utils/lineCounter'); class SourceMap { constructor(mappings, sources) { this.mappings = this.purifyMappings(mappings); this.sources = sources || {}; this.lineCount = null; } purifyMappings(mappings) { if (Array.isArray(mappings)) { return mappings.filter(mapping => mapping && typeof mapping.original === 'object' && (mapping.original === null || typeof mapping.original.line === 'number' && mapping.original.line > 0 && typeof mapping.original.column === 'number' && mapping.source) && mapping.generated && typeof mapping.generated.line === 'number' && mapping.generated.line > 0 && typeof mapping.generated.column === 'number'); } return []; } getConsumer(map) { return (0, _asyncToGenerator2.default)(function* () { if (map instanceof SourceMapConsumer) { return map; } map = typeof map === 'string' ? JSON.parse(map) : map; if (map.sourceRoot) delete map.sourceRoot; return new SourceMapConsumer(map); })(); } addMap(map, lineOffset = 0, columnOffset = 0) { var _this = this; return (0, _asyncToGenerator2.default)(function* () { if (typeof map === 'string' || typeof map === 'object' && map.version) { let consumer = yield _this.getConsumer(map); if (!consumer) return _this; consumer.eachMapping(mapping => { _this.addConsumerMapping(mapping, lineOffset, columnOffset); if (!_this.sources[mapping.source]) { _this.sources[mapping.source] = consumer.sourceContentFor(mapping.source, true); } }); if (consumer.destroy) { // Only needs to happen in source-map 0.7 consumer.destroy(); } } else if (map.mappings && map.sources) { if (!map.eachMapping) { map = new SourceMap(map.mappings, map.sources); } if (lineOffset === 0 && columnOffset === 0) { _this.mappings = _this.mappings.concat(map.mappings); } else { map.eachMapping(mapping => { _this.addMapping(mapping, lineOffset, columnOffset); }); } Object.keys(map.sources).forEach(sourceName => { if (!_this.sources[sourceName]) { _this.sources[sourceName] = map.sources[sourceName]; } }); } return _this; })(); } addMapping(mapping, lineOffset = 0, columnOffset = 0) { this.mappings.push({ source: mapping.source, name: mapping.name, original: mapping.original, generated: { line: mapping.generated.line + lineOffset, column: mapping.generated.column + columnOffset } }); } addConsumerMapping(mapping, lineOffset = 0, columnOffset = 0) { let original = null; if (typeof mapping.originalLine === 'number' && mapping.originalLine > 0 && typeof mapping.originalColumn === 'number') { original = { line: mapping.originalLine, column: mapping.originalColumn }; } this.mappings.push({ source: original ? mapping.source : null, name: mapping.name, original, generated: { line: mapping.generatedLine + lineOffset, column: mapping.generatedColumn + columnOffset } }); } eachMapping(callback) { this.mappings.forEach(callback); } generateEmptyMap(sourceName, sourceContent) { this.sources[sourceName] = sourceContent; this.lineCount = lineCounter(sourceContent); for (let line = 1; line < this.lineCount + 1; line++) { this.addMapping({ source: sourceName, original: { line: line, column: 0 }, generated: { line: line, column: 0 } }); } return this; } extendSourceMap(original, extension) { var _this2 = this; return (0, _asyncToGenerator2.default)(function* () { if (!(extension instanceof SourceMap)) { extension = yield new SourceMap().addMap(extension); } if (!(original instanceof SourceMap)) { original = yield _this2.getConsumer(original); } extension.eachMapping(mapping => { let originalMapping = original.originalPositionFor({ line: mapping.original.line, column: mapping.original.column }); if (!originalMapping || !originalMapping.line) { return; } _this2.addMapping({ source: originalMapping.source, name: originalMapping.name, original: { line: originalMapping.line, column: originalMapping.column }, generated: { line: mapping.generated.line, column: mapping.generated.column } }); if (!_this2.sources[originalMapping.source]) { _this2.sources[originalMapping.source] = original.sourceContentFor(originalMapping.source, true); } }); if (original.destroy) { // Only needs to happen in source-map 0.7 original.destroy(); } return _this2; })(); } findClosestGenerated(line, column) { if (line < 1) { throw new Error('Line numbers must be >= 1'); } if (column < 0) { throw new Error('Column numbers must be >= 0'); } if (this.mappings.length < 1) { return undefined; } let startIndex = 0; let stopIndex = this.mappings.length - 1; let middleIndex = stopIndex + startIndex >>> 1; while (startIndex < stopIndex && this.mappings[middleIndex].generated.line !== line) { let mid = this.mappings[middleIndex].generated.line; if (line < mid) { stopIndex = middleIndex - 1; } else if (line > mid) { startIndex = middleIndex + 1; } middleIndex = stopIndex + startIndex >>> 1; } let mapping = this.mappings[middleIndex]; if (!mapping || mapping.generated.line !== line) { return this.mappings.length - 1; } while (middleIndex >= 1 && this.mappings[middleIndex - 1].generated.line === line) { middleIndex--; } while (middleIndex < this.mappings.length - 1 && this.mappings[middleIndex + 1].generated.line === line && column > this.mappings[middleIndex].generated.column) { middleIndex++; } return middleIndex; } findClosest(line, column, key) { if (line < 1) { throw new Error('Line numbers must be >= 1'); } if (column < 0) { throw new Error('Column numbers must be >= 0'); } if (this.mappings.length < 1) { return undefined; } let startIndex = 0; let stopIndex = this.mappings.length - 1; let middleIndex = Math.floor((stopIndex + startIndex) / 2); while (startIndex < stopIndex && this.mappings[middleIndex][key].line !== line) { if (line < this.mappings[middleIndex][key].line) { stopIndex = middleIndex - 1; } else if (line > this.mappings[middleIndex][key].line) { startIndex = middleIndex + 1; } middleIndex = Math.floor((stopIndex + startIndex) / 2); } var mapping = this.mappings[middleIndex]; if (!mapping || mapping[key].line !== line) { return this.mappings.length - 1; } while (middleIndex >= 1 && this.mappings[middleIndex - 1][key].line === line) { middleIndex--; } while (middleIndex < this.mappings.length - 1 && this.mappings[middleIndex + 1][key].line === line && column > this.mappings[middleIndex][key].column) { middleIndex++; } return middleIndex; } originalPositionFor(generatedPosition) { let index = this.findClosestGenerated(generatedPosition.line, generatedPosition.column); let mapping = this.mappings[index]; if (!mapping || !mapping.original) { return null; } return { source: mapping.source, name: mapping.name, line: mapping.original.line, column: mapping.original.column }; } generatedPositionFor(originalPosition) { let index = this.findClosest(originalPosition.line, originalPosition.column, 'original'); let mapping = this.mappings[index]; return { source: mapping.source, name: mapping.name, line: mapping.generated.line, column: mapping.generated.column }; } sourceContentFor(fileName) { return this.sources[fileName]; } offset(lineOffset = 0, columnOffset = 0) { this.mappings.map(mapping => { mapping.generated.line = mapping.generated.line + lineOffset; mapping.generated.column = mapping.generated.column + columnOffset; return mapping; }); if (this.lineCount != null) { this.lineCount += lineOffset; } } stringify(file, sourceRoot) { let generator = new SourceMapGenerator({ file, sourceRoot }); this.eachMapping(mapping => generator.addMapping(mapping)); Object.keys(this.sources).forEach(sourceName => generator.setSourceContent(sourceName, this.sources[sourceName])); return generator.toString(); } } module.exports = SourceMap;