All files / src/compiler/preprocess replace_in_code.js

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

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 72 732x 2x 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 { Source, Replacement } from './private.js' */
import { MappedCode } from '../utils/mapped_code.js';
 
/**
 * @param {string} code_slice
 * @param {number} offset
 * @param {Source} opts
 * @returns {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<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 {Replacement[]} replacements
 * @param {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 {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);
}