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 13866x 13866x 13866x 13866x 55383x 679840x 679840x 679840x 55383x 13866x 13866x 13866x 13866x 13866x 13866x 539392x 539392x 539392x 539392x 539392x 539392x 539392x 364961x 364961x 364961x 364961x 364961x 795907x 795907x 431208x 431208x 431208x 431208x 431208x 431208x 431208x 431208x 281009x 281009x 281009x 431208x 431208x 795907x 149937x 149937x 795907x 364961x 364961x 364961x 539392x 539392x 539392x 539392x 13866x 13866x 13866x  
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;
}