All files / src/compiler/preprocess replace_in_code.js

100% Statements 72/72
100% Branches 8/8
100% Functions 5/5
100% Lines 71/71

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 722x 2x 2x 2x 2x 2x 2x 2x 2x 344x 344x 344x 344x 344x 344x 344x 2x 2x 2x 2x 2x 2x 66x 66x 66x 66x 66x 66x 75x 75x 75x 75x 75x 75x 75x 75x 66x 66x 66x 2x 2x 2x 2x 2x 2x 66x 66x 66x 66x 75x 75x 75x 75x 75x 75x 66x 66x 66x 66x 66x 2x 2x 2x 2x 2x 2x 2x 2x 66x 66x 66x  
import { MappedCode } from '../utils/mapped_code.js';
 
/**
 * @param {string} code_slice
 * @param {number} offset
 * @param {import('./private.js').Source} opts
 * @returns {import('./private.js').Source}
 */
export function slice_source(code_slice, offset, { file_basename, filename, get_location }) {
	return {
		source: code_slice,
		get_location: (index) => get_location(index + offset),
		file_basename,
		filename
	};
}
 
/**
 * @param {RegExp} re
 * @param {(...match: any[]) => Promise<MappedCode>} get_replacement
 * @param {string} source
 */
function calculate_replacements(re, get_replacement, source) {
	/**
	 * @type {Array<Promise<import('./private.js').Replacement>>}
	 */
	const replacements = [];
	source.replace(re, (...match) => {
		replacements.push(
			get_replacement(...match).then((replacement) => {
				const matched_string = match[0];
				const offset = match[match.length - 2];
				return { offset, length: matched_string.length, replacement };
			})
		);
		return '';
	});
	return Promise.all(replacements);
}
 
/**
 * @param {import('./private.js').Replacement[]} replacements
 * @param {import('./private.js').Source} source
 * @returns {MappedCode}
 */
function perform_replacements(replacements, source) {
	const out = new MappedCode();
	let last_end = 0;
	for (const { offset, length, replacement } of replacements) {
		const unchanged_prefix = MappedCode.from_source(
			slice_source(source.source.slice(last_end, offset), last_end, source)
		);
		out.concat(unchanged_prefix).concat(replacement);
		last_end = offset + length;
	}
	const unchanged_suffix = MappedCode.from_source(
		slice_source(source.source.slice(last_end), last_end, source)
	);
	return out.concat(unchanged_suffix);
}
 
/**
 * @param {RegExp} regex
 * @param {(...match: any[]) => Promise<MappedCode>} get_replacement
 * @param {import('./private.js').Source} location
 * @returns {Promise<MappedCode>}
 */
export async function replace_in_code(regex, get_replacement, location) {
	const replacements = await calculate_replacements(regex, get_replacement, location.source);
	return perform_replacements(replacements, location);
}