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 14206x 14206x 14206x 14206x 56739x 751538x 751538x 751538x 56739x 14206x 14206x 14206x 14206x 14206x 14206x 576719x 576719x 576719x 576719x 576719x 576719x 576719x 400702x 400702x 400702x 400702x 400702x 1067033x 1067033x 666599x 666599x 666599x 666599x 666599x 666599x 666599x 666599x 300206x 300206x 300206x 666599x 666599x 1067033x 366125x 366125x 1067033x 400702x 400702x 400702x 576719x 576719x 576719x 576719x 14206x 14206x 14206x  
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;
}