All files / src/xgroup xgroup.ts

54.76% Statements 23/42
30.43% Branches 7/23
61.11% Functions 11/18
54.76% Lines 23/42

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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109                4x   4x                 8x 8x 8x 8x         8x       1x     2x     13x           6x   6x 6x 8x     6x 4x 4x         8x 11x                   11x         6x                                                               4x 2x    
import {
	XGroup,
	XGroupSpec,
	XInit,
	XGroupEvent,
	XUnsubsribe,
	WithXEventsBySpec,
} from '../typing';
import { defineStaticProperies } from '../utils';
 
export function createXGroup<
	D extends string,
	G extends XGroupSpec,
	I extends XInit,
>(
	descr: D,
	spec: G,
	init?: I,
): XGroup<D, G, I> {
	let listeners = 0;
	const keys = Object.keys(spec);
	const path = init ? init.group.$path().concat(init.name) : [] as string[];
	const group = defineStaticProperies({} as XGroup<D, G, I>, {
		$use: (xevents?: WithXEventsBySpec<G, true>) => {
			return overrideXEvents(group, xevents);
		},
 
		$observed: () => (listeners > 0) && (!init || init.group.$observed()),
 
		$keys: () => keys,
 
		$descr: () => descr,
 
		$clone: <NI extends XInit = I>(ninit?: NI) => {
			return createXGroup(descr, spec, (ninit || init) as NI)
		},
 
		$path: () => path,
		
		$name: () => init?.name,
		$group: () => init?.group,
 
		$on: (listener: (xevt: XGroupEvent<G>) => void): XUnsubsribe => {
			const list = [] as XUnsubsribe[];
			
			listeners++;
			keys.forEach(key => {
				list.push(group[key].$on(listener));
			});
 
			return () => {
				listeners--;
				list.forEach(callUnsubsribe);
			};
		},
	});
	
	return keys.reduce((group, name) => {
		Object.defineProperty(group, name, {
			value: spec[name].$clone({
				name,
				group,
			}),
			enumerable: true,
			configurable: false,
			writable: false,
		});
 
		return group;
	}, group);
}
 
function callUnsubsribe(fn: XUnsubsribe) {
	fn();
}
 
function overrideXEvents(group: XGroup<any, any, any>, xevents?: WithXEventsBySpec<any, true>) {
	if (xevents == null) {
		return group;
	}
 
	return group.$keys().reduce((xover, key: string) => {
		const orig = group[key];
		const extra = xevents[key];
 
		if (extra === void 0) {
			xover[key] = orig;
		} else if (orig.$keys !== void 0) {
			xover[key] = overrideXEvents(group[key], extra as any);
		} else {
			xover[key] = function (data: object) {
				orig(data);
				try {
					(extra as any).call(data);
				} catch (err) {
					console.error(err);
				}
			};
		}
 
		return xover;
	}, {});
}
 
 
export function isXGroup(val: any): val is XGroup<string, XGroupSpec, XInit> {
	return val ? typeof val.$observed === 'function' : false;
}