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 14134x 14134x 14134x 14134x 56451x 747452x 747452x 747452x 56451x 14134x 14134x 14134x 14134x 14134x 14134x 573611x 573611x 573611x 573611x 573611x 573611x 573611x 398360x 398360x 398360x 398360x 398360x 1060794x 1060794x 662704x 662704x 662704x 662704x 662704x 662704x 662704x 662704x 298303x 298303x 298303x 662704x 662704x 1060794x 364131x 364131x 1060794x 398360x 398360x 398360x 573611x 573611x 573611x 573611x 14134x 14134x 14134x  
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;
}