All files / src/compiler/phases visitors.js

95.83% Statements 69/72
100% Branches 11/11
66.66% Functions 4/6
95.83% Lines 69/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 2x 2x 2x 14152x 14152x 14152x 14152x 56523x 748496x 748496x 748496x 56523x 14152x 14152x 14152x 14152x 14152x 14152x 574403x 574403x 574403x 574403x 574403x 574403x 574403x 398768x 398768x 398768x 398768x 398768x 1061872x 1061872x 663374x 663374x 663374x 663374x 663374x 663374x 663374x 663374x 298615x 298615x 298615x 663374x 663374x 1061872x 364489x 364489x 1061872x 398768x 398768x 398768x 574403x 574403x 574403x 574403x 14152x 14152x 14152x  
const overrides = {
	visit() {
		throw new Error('Cannot call visit() during analysis');
	},
	stop() {
		throw new Error('Cannot call stop() during analysis');
	}
};
 
/**
 * @template {{ type: string }} T
 * @template U
 * @param  {...import('zimmerframe').Visitors<T, U>} tasks
 * @returns
 */
export function merge(...tasks) {
	/** @type {Record<string, any[]>} */
	const visitors = {};
 
	for (const task of tasks) {
		for (const key in task) {
			if (!visitors[key]) visitors[key] = [];
			visitors[key].push(task[key]);
		}
	}
 
	/** @type {import('zimmerframe').Visitors<T, U>} */
	// @ts-expect-error
	const combined = {};
 
	for (const key in visitors) {
		const fns = visitors[key];
 
		/**
		 * @param {T} node
		 * @param {import('zimmerframe').Context<T, U>} context
		 */
		function visitor(node, context) {
			/**
			 * @param {number} i
			 * @param {U} state
			 */
			function go(i, state) {
				const fn = fns[i];
				if (!fn) return context.next(state);
 
				let called_next = false;
 
				fn(node, {
					...context,
					...overrides,
					state,
					next(next_state = state) {
						called_next = true;
						go(i + 1, next_state);
					}
				});
 
				if (!called_next) {
					go(i + 1, state);
				}
			}
 
			go(0, context.state);
		}
 
		// @ts-expect-error
		combined[key] = visitor;
	}
 
	return combined;
}