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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 49x 60x 60x 60x 60x 60x 49x 49x 49x 32x 32x 32x 32x 32x 32x 49x 49x 49x 2x 2x 2x 2x 49x 49x 2x 2x 2x 1x 1x 1x 2x 49x 49x 11x 1x 1x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 11x 11x 49x 49x 49x 49x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 49x 49x 49x 4x 4x 4x 4x 4x 1x 1x 3x 3x 3x 3x 3x 3x 3x 4x 49x 49x 1x 1x 1x 1x 1x 1x 1x 1x 49x 49x 49x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 45x 49x 49x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 49x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 45x 45x 45x 45x | import {
Action,
Domain,
DomainContext,
MutableStore,
Reducer,
Thunk,
ModuleFactory,
ResolveModule,
DispatchArgs,
OnDispatch,
} from "../types";
import { withUse } from "../withUse";
import { emitter } from "../emitter";
import { StoreImpl } from "./store";
// --- Domain Implementation ---
class DomainImpl<TAction extends Action> implements Domain<TAction> {
name: string;
private stores = new Set<StoreImpl<any, any, TAction>>();
private subdomains = new Set<DomainImpl<any>>();
private dispatchEmitter =
emitter<DispatchArgs<TAction, DomainContext<TAction>>>();
private descendantEmitter = emitter<DispatchArgs<any, any>>();
// Module System
private moduleCache = new Map<ModuleFactory<any, any>, any>();
private moduleOverrides = new Map<
ModuleFactory<any, any>,
ModuleFactory<any, any>
>();
constructor(name: string, private notifyParent?: OnDispatch) {
this.name = name;
withUse(this);
}
use: any;
// --- Context ---
private getContext(): DomainContext<TAction> {
return {
dispatch: this.dispatch,
get: this.get,
};
}
// --- Child Dispatch Handling ---
private handleChildDispatch = (args: DispatchArgs<any, any>) => {
// 1. Notify our listeners (descendants only)
this.descendantEmitter.emit(args);
// 2. Bubble up to parent
this.notifyParent?.(args);
};
// --- Dispatch System ---
onDispatch = (
listener: (args: DispatchArgs<TAction, DomainContext<TAction>>) => void
) => {
return this.dispatchEmitter.on(listener);
};
onAnyDispatch = (listener: OnDispatch) => {
const unsub1 = this.dispatchEmitter.on(listener as any); // Listen to direct dispatches
const unsub2 = this.descendantEmitter.on(listener); // Listen to descendant dispatches
return () => {
unsub1();
unsub2();
};
};
dispatch = (actionOrThunk: TAction | Thunk<any>) => {
if (typeof actionOrThunk === "function") {
return actionOrThunk(this.getContext());
}
const action = actionOrThunk as TAction;
const context = this.getContext();
// 1. Notify Domain Listeners
this.dispatchEmitter.emit({ action, source: this.name, context });
// 2. Broadcast Downstream
// To Stores
this.stores.forEach((store) => store._receiveDomainAction(action));
// To SubDomains
this.subdomains.forEach((sub) => sub._receiveDomainAction(action));
this.notifyParent?.({ action, source: this.name, context });
};
// Internal: Called by Parent Domain to inject global actions
// @internal
_receiveDomainAction(action: TAction) {
const context = this.getContext();
// 1. Notify Domain Listeners (Local)
this.dispatchEmitter.emit({ action, source: this.name, context });
// 2. Broadcast Downstream
this.stores.forEach((store) => store._receiveDomainAction(action));
this.subdomains.forEach((sub) => sub._receiveDomainAction(action));
// DO NOT bubble up to parent (prevents loops)
}
// --- Module System ---
get: ResolveModule<TAction> = (factory) => {
// 1. Check Overrides
const effectiveFactory = this.moduleOverrides.get(factory) || factory;
// 2. Check Cache (Memoization)
if (this.moduleCache.has(effectiveFactory)) {
return this.moduleCache.get(effectiveFactory);
}
// 3. Instantiate
// We pass 'this' (Domain) to the factory
const instance = effectiveFactory(this);
this.moduleCache.set(effectiveFactory, instance.service);
return instance.service;
};
override<TService>(
source: ModuleFactory<TService, TAction>,
override: ModuleFactory<TService, TAction>
): VoidFunction {
this.moduleOverrides.set(source, override);
return () => {
this.moduleOverrides.delete(source);
};
}
// --- Factory Methods ---
store<TState, TStoreActions extends Action = TAction>(
name: string,
initial: TState,
reducer: Reducer<TState, TStoreActions>
): MutableStore<TState, TStoreActions, TAction> {
const fullName = `${this.name}.${name}`;
const store = new StoreImpl<TState, TStoreActions, TAction>(
fullName,
initial,
reducer,
this.getContext() as any,
this.handleChildDispatch
);
this.stores.add(store);
return store;
}
domain<SubAction extends Action = never>(
name: string
): Domain<SubAction | TAction> {
const fullName = `${this.name}.${name}`;
const sub = new DomainImpl<SubAction | TAction>(
fullName,
this.handleChildDispatch
);
this.subdomains.add(sub);
return sub;
}
}
// --- Public Factory ---
/**
* Create a new FluxDom domain.
*
* A domain is the root container for state management. It provides:
* - Store creation via `domain.store()`
* - Module resolution via `domain.get()`
* - Action dispatch via `domain.dispatch()`
* - Sub-domain creation via `domain.domain()`
*
* @example
* ```ts
* const appDomain = domain<AppAction>("app");
* const counterStore = appDomain.store("counter", 0, counterReducer);
* ```
*
* @param name - Identifier for the domain (used for debugging)
* @returns A new Domain instance
*/
export function domain<TAction extends Action = Action>(
name: string
): Domain<TAction> {
return new DomainImpl<TAction>(name);
}
|