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 14305x 14305x 14305x 14305x 57134x 742734x 742734x 742734x 57134x 14305x 14305x 14305x 14305x 14305x 14305x 566629x 566629x 566629x 566629x 566629x 566629x 566629x 385805x 385805x 385805x 385805x 385805x 1039176x 1039176x 653642x 653642x 653642x 653642x 653642x 653642x 653642x 653642x 302088x 302088x 302088x 653642x 653642x 1039176x 351283x 351283x 1039176x 385805x 385805x 385805x 566629x 566629x 566629x 566629x 14305x 14305x 14305x  
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;
}