367 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			367 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*
 | 
						|
	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
						|
	Author Tobias Koppers @sokra
 | 
						|
*/
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const splitIntoLines = require("./splitIntoLines");
 | 
						|
const streamChunksOfSourceMap = require("./streamChunksOfSourceMap");
 | 
						|
 | 
						|
/** @typedef {import("../Source").RawSourceMap} RawSourceMap */
 | 
						|
/** @typedef {import("./getGeneratedSourceInfo").GeneratedSourceInfo} GeneratedSourceInfo */
 | 
						|
/** @typedef {import("./streamChunks").OnChunk} onChunk */
 | 
						|
/** @typedef {import("./streamChunks").OnName} OnName */
 | 
						|
/** @typedef {import("./streamChunks").OnSource} OnSource */
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} source source
 | 
						|
 * @param {RawSourceMap} sourceMap source map
 | 
						|
 * @param {string} innerSourceName inner source name
 | 
						|
 * @param {string} innerSource inner source
 | 
						|
 * @param {RawSourceMap} innerSourceMap inner source map
 | 
						|
 * @param {boolean | undefined} removeInnerSource do remove inner source
 | 
						|
 * @param {onChunk} onChunk on chunk
 | 
						|
 * @param {OnSource} onSource on source
 | 
						|
 * @param {OnName} onName on name
 | 
						|
 * @param {boolean} finalSource finalSource
 | 
						|
 * @param {boolean} columns columns
 | 
						|
 * @returns {GeneratedSourceInfo} generated source info
 | 
						|
 */
 | 
						|
const streamChunksOfCombinedSourceMap = (
 | 
						|
	source,
 | 
						|
	sourceMap,
 | 
						|
	innerSourceName,
 | 
						|
	innerSource,
 | 
						|
	innerSourceMap,
 | 
						|
	removeInnerSource,
 | 
						|
	onChunk,
 | 
						|
	onSource,
 | 
						|
	onName,
 | 
						|
	finalSource,
 | 
						|
	columns,
 | 
						|
) => {
 | 
						|
	/** @type {Map<string | null, number>} */
 | 
						|
	const sourceMapping = new Map();
 | 
						|
	/** @type {Map<string, number>} */
 | 
						|
	const nameMapping = new Map();
 | 
						|
	/** @type {number[]} */
 | 
						|
	const sourceIndexMapping = [];
 | 
						|
	/** @type {number[]} */
 | 
						|
	const nameIndexMapping = [];
 | 
						|
	/** @type {string[]} */
 | 
						|
	const nameIndexValueMapping = [];
 | 
						|
	let outerSourceIndex = -2;
 | 
						|
	/** @type {number[]} */
 | 
						|
	const innerSourceIndexMapping = [];
 | 
						|
	/** @type {[string | null, string | undefined][]} */
 | 
						|
	const innerSourceIndexValueMapping = [];
 | 
						|
	/** @type {(string | undefined)[]} */
 | 
						|
	const innerSourceContents = [];
 | 
						|
	/** @type {(null | undefined | string[])[]} */
 | 
						|
	const innerSourceContentLines = [];
 | 
						|
	/** @type {number[]} */
 | 
						|
	const innerNameIndexMapping = [];
 | 
						|
	/** @type {string[]} */
 | 
						|
	const innerNameIndexValueMapping = [];
 | 
						|
	/** @typedef {[number, number, number, number, number] | number[]} MappingsData */
 | 
						|
	/** @type {{ chunks: string[], mappingsData: MappingsData }[]} */
 | 
						|
	const innerSourceMapLineData = [];
 | 
						|
	/**
 | 
						|
	 * @param {number} line line
 | 
						|
	 * @param {number} column column
 | 
						|
	 * @returns {number} result
 | 
						|
	 */
 | 
						|
	const findInnerMapping = (line, column) => {
 | 
						|
		if (line > innerSourceMapLineData.length) return -1;
 | 
						|
		const { mappingsData } = innerSourceMapLineData[line - 1];
 | 
						|
		let l = 0;
 | 
						|
		let r = mappingsData.length / 5;
 | 
						|
		while (l < r) {
 | 
						|
			const m = (l + r) >> 1;
 | 
						|
			if (mappingsData[m * 5] <= column) {
 | 
						|
				l = m + 1;
 | 
						|
			} else {
 | 
						|
				r = m;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (l === 0) return -1;
 | 
						|
		return l - 1;
 | 
						|
	};
 | 
						|
	return streamChunksOfSourceMap(
 | 
						|
		source,
 | 
						|
		sourceMap,
 | 
						|
		(
 | 
						|
			chunk,
 | 
						|
			generatedLine,
 | 
						|
			generatedColumn,
 | 
						|
			sourceIndex,
 | 
						|
			originalLine,
 | 
						|
			originalColumn,
 | 
						|
			nameIndex,
 | 
						|
		) => {
 | 
						|
			// Check if this is a mapping to the inner source
 | 
						|
			if (sourceIndex === outerSourceIndex) {
 | 
						|
				// Check if there is a mapping in the inner source
 | 
						|
				const idx = findInnerMapping(originalLine, originalColumn);
 | 
						|
				if (idx !== -1) {
 | 
						|
					const { chunks, mappingsData } =
 | 
						|
						innerSourceMapLineData[originalLine - 1];
 | 
						|
					const mi = idx * 5;
 | 
						|
					const innerSourceIndex = mappingsData[mi + 1];
 | 
						|
					const innerOriginalLine = mappingsData[mi + 2];
 | 
						|
					let innerOriginalColumn = mappingsData[mi + 3];
 | 
						|
					let innerNameIndex = mappingsData[mi + 4];
 | 
						|
					if (innerSourceIndex >= 0) {
 | 
						|
						// Check for an identity mapping
 | 
						|
						// where we are allowed to adjust the original column
 | 
						|
						const innerChunk = chunks[idx];
 | 
						|
						const innerGeneratedColumn = mappingsData[mi];
 | 
						|
						const locationInChunk = originalColumn - innerGeneratedColumn;
 | 
						|
						if (locationInChunk > 0) {
 | 
						|
							let originalSourceLines =
 | 
						|
								innerSourceIndex < innerSourceContentLines.length
 | 
						|
									? innerSourceContentLines[innerSourceIndex]
 | 
						|
									: null;
 | 
						|
							if (originalSourceLines === undefined) {
 | 
						|
								const originalSource = innerSourceContents[innerSourceIndex];
 | 
						|
								originalSourceLines = originalSource
 | 
						|
									? splitIntoLines(originalSource)
 | 
						|
									: null;
 | 
						|
								innerSourceContentLines[innerSourceIndex] = originalSourceLines;
 | 
						|
							}
 | 
						|
							if (originalSourceLines !== null) {
 | 
						|
								const originalChunk =
 | 
						|
									innerOriginalLine <= originalSourceLines.length
 | 
						|
										? originalSourceLines[innerOriginalLine - 1].slice(
 | 
						|
												innerOriginalColumn,
 | 
						|
												innerOriginalColumn + locationInChunk,
 | 
						|
											)
 | 
						|
										: "";
 | 
						|
								if (innerChunk.slice(0, locationInChunk) === originalChunk) {
 | 
						|
									innerOriginalColumn += locationInChunk;
 | 
						|
									innerNameIndex = -1;
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
 | 
						|
						// We have a inner mapping to original source
 | 
						|
 | 
						|
						// emit source when needed and compute global source index
 | 
						|
						let sourceIndex =
 | 
						|
							innerSourceIndex < innerSourceIndexMapping.length
 | 
						|
								? innerSourceIndexMapping[innerSourceIndex]
 | 
						|
								: -2;
 | 
						|
						if (sourceIndex === -2) {
 | 
						|
							const [source, sourceContent] =
 | 
						|
								innerSourceIndex < innerSourceIndexValueMapping.length
 | 
						|
									? innerSourceIndexValueMapping[innerSourceIndex]
 | 
						|
									: [null, undefined];
 | 
						|
							let globalIndex = sourceMapping.get(source);
 | 
						|
							if (globalIndex === undefined) {
 | 
						|
								sourceMapping.set(source, (globalIndex = sourceMapping.size));
 | 
						|
								onSource(globalIndex, source, sourceContent);
 | 
						|
							}
 | 
						|
							sourceIndex = globalIndex;
 | 
						|
							innerSourceIndexMapping[innerSourceIndex] = sourceIndex;
 | 
						|
						}
 | 
						|
 | 
						|
						// emit name when needed and compute global name index
 | 
						|
						let finalNameIndex = -1;
 | 
						|
						if (innerNameIndex >= 0) {
 | 
						|
							// when we have a inner name
 | 
						|
							finalNameIndex =
 | 
						|
								innerNameIndex < innerNameIndexMapping.length
 | 
						|
									? innerNameIndexMapping[innerNameIndex]
 | 
						|
									: -2;
 | 
						|
							if (finalNameIndex === -2) {
 | 
						|
								const name =
 | 
						|
									innerNameIndex < innerNameIndexValueMapping.length
 | 
						|
										? innerNameIndexValueMapping[innerNameIndex]
 | 
						|
										: undefined;
 | 
						|
								if (name) {
 | 
						|
									let globalIndex = nameMapping.get(name);
 | 
						|
									if (globalIndex === undefined) {
 | 
						|
										nameMapping.set(name, (globalIndex = nameMapping.size));
 | 
						|
										onName(globalIndex, name);
 | 
						|
									}
 | 
						|
									finalNameIndex = globalIndex;
 | 
						|
								} else {
 | 
						|
									finalNameIndex = -1;
 | 
						|
								}
 | 
						|
								innerNameIndexMapping[innerNameIndex] = finalNameIndex;
 | 
						|
							}
 | 
						|
						} else if (nameIndex >= 0) {
 | 
						|
							// when we don't have an inner name,
 | 
						|
							// but we have an outer name
 | 
						|
							// it can be used when inner original code equals to the name
 | 
						|
							let originalSourceLines =
 | 
						|
								innerSourceContentLines[innerSourceIndex];
 | 
						|
							if (originalSourceLines === undefined) {
 | 
						|
								const originalSource = innerSourceContents[innerSourceIndex];
 | 
						|
								originalSourceLines = originalSource
 | 
						|
									? splitIntoLines(originalSource)
 | 
						|
									: null;
 | 
						|
								innerSourceContentLines[innerSourceIndex] = originalSourceLines;
 | 
						|
							}
 | 
						|
							if (originalSourceLines !== null) {
 | 
						|
								const name = nameIndexValueMapping[nameIndex];
 | 
						|
								const originalName =
 | 
						|
									innerOriginalLine <= originalSourceLines.length
 | 
						|
										? originalSourceLines[innerOriginalLine - 1].slice(
 | 
						|
												innerOriginalColumn,
 | 
						|
												innerOriginalColumn + name.length,
 | 
						|
											)
 | 
						|
										: "";
 | 
						|
								if (name === originalName) {
 | 
						|
									finalNameIndex =
 | 
						|
										nameIndex < nameIndexMapping.length
 | 
						|
											? nameIndexMapping[nameIndex]
 | 
						|
											: -2;
 | 
						|
									if (finalNameIndex === -2) {
 | 
						|
										const name = nameIndexValueMapping[nameIndex];
 | 
						|
										if (name) {
 | 
						|
											let globalIndex = nameMapping.get(name);
 | 
						|
											if (globalIndex === undefined) {
 | 
						|
												nameMapping.set(name, (globalIndex = nameMapping.size));
 | 
						|
												onName(globalIndex, name);
 | 
						|
											}
 | 
						|
											finalNameIndex = globalIndex;
 | 
						|
										} else {
 | 
						|
											finalNameIndex = -1;
 | 
						|
										}
 | 
						|
										nameIndexMapping[nameIndex] = finalNameIndex;
 | 
						|
									}
 | 
						|
								}
 | 
						|
							}
 | 
						|
						}
 | 
						|
						onChunk(
 | 
						|
							chunk,
 | 
						|
							generatedLine,
 | 
						|
							generatedColumn,
 | 
						|
							sourceIndex,
 | 
						|
							innerOriginalLine,
 | 
						|
							innerOriginalColumn,
 | 
						|
							finalNameIndex,
 | 
						|
						);
 | 
						|
						return;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				// We have a mapping to the inner source, but no inner mapping
 | 
						|
				if (removeInnerSource) {
 | 
						|
					onChunk(chunk, generatedLine, generatedColumn, -1, -1, -1, -1);
 | 
						|
					return;
 | 
						|
				}
 | 
						|
				if (sourceIndexMapping[sourceIndex] === -2) {
 | 
						|
					let globalIndex = sourceMapping.get(innerSourceName);
 | 
						|
					if (globalIndex === undefined) {
 | 
						|
						sourceMapping.set(source, (globalIndex = sourceMapping.size));
 | 
						|
						onSource(globalIndex, innerSourceName, innerSource);
 | 
						|
					}
 | 
						|
					sourceIndexMapping[sourceIndex] = globalIndex;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			const finalSourceIndex =
 | 
						|
				sourceIndex < 0 || sourceIndex >= sourceIndexMapping.length
 | 
						|
					? -1
 | 
						|
					: sourceIndexMapping[sourceIndex];
 | 
						|
			if (finalSourceIndex < 0) {
 | 
						|
				// no source, so we make it a generated chunk
 | 
						|
				onChunk(chunk, generatedLine, generatedColumn, -1, -1, -1, -1);
 | 
						|
			} else {
 | 
						|
				// Pass through the chunk with mapping
 | 
						|
				let finalNameIndex = -1;
 | 
						|
				if (nameIndex >= 0 && nameIndex < nameIndexMapping.length) {
 | 
						|
					finalNameIndex = nameIndexMapping[nameIndex];
 | 
						|
					if (finalNameIndex === -2) {
 | 
						|
						const name = nameIndexValueMapping[nameIndex];
 | 
						|
						let globalIndex = nameMapping.get(name);
 | 
						|
						if (globalIndex === undefined) {
 | 
						|
							nameMapping.set(name, (globalIndex = nameMapping.size));
 | 
						|
							onName(globalIndex, name);
 | 
						|
						}
 | 
						|
						finalNameIndex = globalIndex;
 | 
						|
						nameIndexMapping[nameIndex] = finalNameIndex;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				onChunk(
 | 
						|
					chunk,
 | 
						|
					generatedLine,
 | 
						|
					generatedColumn,
 | 
						|
					finalSourceIndex,
 | 
						|
					originalLine,
 | 
						|
					originalColumn,
 | 
						|
					finalNameIndex,
 | 
						|
				);
 | 
						|
			}
 | 
						|
		},
 | 
						|
		(i, source, sourceContent) => {
 | 
						|
			if (source === innerSourceName) {
 | 
						|
				outerSourceIndex = i;
 | 
						|
				if (innerSource !== undefined) sourceContent = innerSource;
 | 
						|
				else innerSource = /** @type {string} */ (sourceContent);
 | 
						|
				sourceIndexMapping[i] = -2;
 | 
						|
				streamChunksOfSourceMap(
 | 
						|
					/** @type {string} */
 | 
						|
					(sourceContent),
 | 
						|
					innerSourceMap,
 | 
						|
					(
 | 
						|
						chunk,
 | 
						|
						generatedLine,
 | 
						|
						generatedColumn,
 | 
						|
						sourceIndex,
 | 
						|
						originalLine,
 | 
						|
						originalColumn,
 | 
						|
						nameIndex,
 | 
						|
					) => {
 | 
						|
						while (innerSourceMapLineData.length < generatedLine) {
 | 
						|
							innerSourceMapLineData.push({
 | 
						|
								mappingsData: [],
 | 
						|
								chunks: [],
 | 
						|
							});
 | 
						|
						}
 | 
						|
						const data = innerSourceMapLineData[generatedLine - 1];
 | 
						|
						data.mappingsData.push(
 | 
						|
							generatedColumn,
 | 
						|
							sourceIndex,
 | 
						|
							originalLine,
 | 
						|
							originalColumn,
 | 
						|
							nameIndex,
 | 
						|
						);
 | 
						|
						data.chunks.push(/** @type {string} */ (chunk));
 | 
						|
					},
 | 
						|
					(i, source, sourceContent) => {
 | 
						|
						innerSourceContents[i] = sourceContent;
 | 
						|
						innerSourceContentLines[i] = undefined;
 | 
						|
						innerSourceIndexMapping[i] = -2;
 | 
						|
						innerSourceIndexValueMapping[i] = [source, sourceContent];
 | 
						|
					},
 | 
						|
					(i, name) => {
 | 
						|
						innerNameIndexMapping[i] = -2;
 | 
						|
						innerNameIndexValueMapping[i] = name;
 | 
						|
					},
 | 
						|
					false,
 | 
						|
					columns,
 | 
						|
				);
 | 
						|
			} else {
 | 
						|
				let globalIndex = sourceMapping.get(source);
 | 
						|
				if (globalIndex === undefined) {
 | 
						|
					sourceMapping.set(source, (globalIndex = sourceMapping.size));
 | 
						|
					onSource(globalIndex, source, sourceContent);
 | 
						|
				}
 | 
						|
				sourceIndexMapping[i] = globalIndex;
 | 
						|
			}
 | 
						|
		},
 | 
						|
		(i, name) => {
 | 
						|
			nameIndexMapping[i] = -2;
 | 
						|
			nameIndexValueMapping[i] = name;
 | 
						|
		},
 | 
						|
		finalSource,
 | 
						|
		columns,
 | 
						|
	);
 | 
						|
};
 | 
						|
 | 
						|
module.exports = streamChunksOfCombinedSourceMap;
 |