@blac/core 2.0.17 → 2.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/StateContainerRegistry-4Ljd9EJx.js +1018 -0
- package/dist/StateContainerRegistry-4Ljd9EJx.js.map +1 -0
- package/dist/StateContainerRegistry-CEWpc1bj.cjs +1113 -0
- package/dist/StateContainerRegistry-CEWpc1bj.cjs.map +1 -0
- package/dist/StateContainerRegistry-CSNm2Ws5.cjs +1085 -0
- package/dist/StateContainerRegistry-CSNm2Ws5.cjs.map +1 -0
- package/dist/StateContainerRegistry-CvBOhAT2.js +996 -0
- package/dist/StateContainerRegistry-CvBOhAT2.js.map +1 -0
- package/dist/acquire-B1Wuqla6.cjs +46 -0
- package/dist/acquire-B1Wuqla6.cjs.map +1 -0
- package/dist/acquire-BP-ZfUH2.js +35 -0
- package/dist/acquire-BP-ZfUH2.js.map +1 -0
- package/dist/acquire-BZIs6tpN.cjs +46 -0
- package/dist/acquire-BZIs6tpN.cjs.map +1 -0
- package/dist/acquire-CwB083au.js +35 -0
- package/dist/acquire-CwB083au.js.map +1 -0
- package/dist/config-C7Ktkjh2.cjs +32 -0
- package/dist/config-C7Ktkjh2.cjs.map +1 -0
- package/dist/config-COT4Xkbc.js +16 -0
- package/dist/config-COT4Xkbc.js.map +1 -0
- package/dist/config-b2z51Y_C.cjs +32 -0
- package/dist/config-b2z51Y_C.cjs.map +1 -0
- package/dist/config-buwpT7l3.js +16 -0
- package/dist/config-buwpT7l3.js.map +1 -0
- package/dist/core/Cubit.d.ts +4 -4
- package/dist/core/StateContainer.d.ts +34 -38
- package/dist/core/StateContainerRegistry.d.ts +1 -1
- package/dist/core/meta.d.ts +73 -0
- package/dist/core/symbols.d.ts +10 -17
- package/dist/debug.cjs +3 -3
- package/dist/debug.js +3 -3
- package/dist/ensure-B9oOqpOB.cjs +558 -0
- package/dist/ensure-B9oOqpOB.cjs.map +1 -0
- package/dist/ensure-BfYnvAsI.js +709 -0
- package/dist/ensure-BfYnvAsI.js.map +1 -0
- package/dist/ensure-C1a8IFWy.js +535 -0
- package/dist/ensure-C1a8IFWy.js.map +1 -0
- package/dist/ensure-_Oh8XPm4.cjs +732 -0
- package/dist/ensure-_Oh8XPm4.cjs.map +1 -0
- package/dist/index.cjs +9 -9
- package/dist/index.d.cts +4 -7
- package/dist/index.d.ts +4 -7
- package/dist/index.js +7 -7
- package/dist/management-14vsHr4t.cjs +85 -0
- package/dist/management-14vsHr4t.cjs.map +1 -0
- package/dist/management-BqGBdL01.js +38 -0
- package/dist/management-BqGBdL01.js.map +1 -0
- package/dist/management-BvUAjril.js +38 -0
- package/dist/management-BvUAjril.js.map +1 -0
- package/dist/management-Df7Y2sF1.cjs +85 -0
- package/dist/management-Df7Y2sF1.cjs.map +1 -0
- package/dist/plugin/BlacPlugin.d.ts +11 -12
- package/dist/plugin/PluginManager.d.ts +3 -4
- package/dist/plugins.cjs +1 -1
- package/dist/plugins.js +1 -1
- package/dist/testing.cjs +10 -15
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -6
- package/dist/testing.d.ts +4 -6
- package/dist/testing.js +10 -14
- package/dist/testing.js.map +1 -1
- package/dist/watch-CfrSSrRY.js +59 -0
- package/dist/watch-CfrSSrRY.js.map +1 -0
- package/dist/watch-Cnh3PtQA.cjs +70 -0
- package/dist/watch-Cnh3PtQA.cjs.map +1 -0
- package/dist/watch-D8hwbFU1.js +59 -0
- package/dist/watch-D8hwbFU1.js.map +1 -0
- package/dist/watch-DVmvZBMD.cjs +70 -0
- package/dist/watch-DVmvZBMD.cjs.map +1 -0
- package/dist/watch-entry.cjs +1 -1
- package/dist/watch-entry.js +1 -1
- package/package.json +3 -3
package/dist/testing.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_StateContainerRegistry = require("./StateContainerRegistry-
|
|
3
|
-
const require_ensure = require("./ensure-
|
|
4
|
-
const require_config = require("./config-
|
|
5
|
-
const require_acquire = require("./acquire-
|
|
2
|
+
const require_StateContainerRegistry = require("./StateContainerRegistry-CSNm2Ws5.cjs");
|
|
3
|
+
const require_ensure = require("./ensure-B9oOqpOB.cjs");
|
|
4
|
+
const require_config = require("./config-C7Ktkjh2.cjs");
|
|
5
|
+
const require_acquire = require("./acquire-B1Wuqla6.cjs");
|
|
6
6
|
//#region src/testing.ts
|
|
7
7
|
/** Synthetic owner id used by test helpers for pre-wired deps. */
|
|
8
8
|
const TESTING_DEPS_OWNER = "testing-deps";
|
|
@@ -52,7 +52,7 @@ function overrideEnsure(BlocClass, instance, fn, args) {
|
|
|
52
52
|
}
|
|
53
53
|
function createCubitStub(BlocClass, options) {
|
|
54
54
|
const instance = new BlocClass();
|
|
55
|
-
if (options?.args != null) instance.
|
|
55
|
+
if (options?.args != null) instance[require_StateContainerRegistry.INIT_CONFIG]({ args: options.args });
|
|
56
56
|
if (options?.state != null) {
|
|
57
57
|
if (instance instanceof require_ensure.Cubit) {
|
|
58
58
|
const currentState = instance.state;
|
|
@@ -63,7 +63,7 @@ function createCubitStub(BlocClass, options) {
|
|
|
63
63
|
if (options?.methods) {
|
|
64
64
|
for (const [key, impl] of Object.entries(options.methods)) if (typeof impl === "function") instance[key] = impl;
|
|
65
65
|
}
|
|
66
|
-
if (options?.deps != null) instance[
|
|
66
|
+
if (options?.deps != null) instance[require_StateContainerRegistry.APPLY_DEPS](TESTING_DEPS_OWNER, options.deps);
|
|
67
67
|
return instance;
|
|
68
68
|
}
|
|
69
69
|
function withBlocState(BlocClass, state, args) {
|
|
@@ -81,28 +81,23 @@ function withBlocMethod(BlocClass, methodName, impl, args) {
|
|
|
81
81
|
return instance;
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
|
-
* Drain pending microtasks so any channel-flushed effects (
|
|
85
|
-
*
|
|
84
|
+
* Drain pending microtasks so any channel-flushed effects (channel
|
|
85
|
+
* subscribers, `onSystemEvent('stateChanged')` handlers, plugin hooks) run
|
|
86
86
|
* before the next assertion.
|
|
87
87
|
*
|
|
88
88
|
* The default `MicrotaskScheduler` coalesces emits within a tick; tests
|
|
89
|
-
* that emit and then assert on
|
|
90
|
-
*
|
|
89
|
+
* that emit and then assert on subscriber side-effects need `await flush()`
|
|
90
|
+
* between the two.
|
|
91
91
|
*/
|
|
92
92
|
async function flush() {
|
|
93
93
|
await Promise.resolve();
|
|
94
94
|
await Promise.resolve();
|
|
95
95
|
}
|
|
96
|
-
/** @deprecated Alias for `flush()`. */
|
|
97
|
-
async function flushBlocUpdates() {
|
|
98
|
-
await flush();
|
|
99
|
-
}
|
|
100
96
|
//#endregion
|
|
101
97
|
exports.blacTestSetup = blacTestSetup;
|
|
102
98
|
exports.createCubitStub = createCubitStub;
|
|
103
99
|
exports.createTestRegistry = createTestRegistry;
|
|
104
100
|
exports.flush = flush;
|
|
105
|
-
exports.flushBlocUpdates = flushBlocUpdates;
|
|
106
101
|
exports.overrideEnsure = overrideEnsure;
|
|
107
102
|
exports.registerOverride = registerOverride;
|
|
108
103
|
exports.withBlocMethod = withBlocMethod;
|
package/dist/testing.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.cjs","names":["StateContainerRegistry","getRegistry","resolveInstanceKey","Cubit","APPLY_DEPS","ensure"],"sources":["../src/testing.ts"],"sourcesContent":["import { Cubit } from './core/Cubit';\nimport { StateContainerRegistry } from './core/StateContainerRegistry';\nimport { APPLY_DEPS } from './core/symbols';\nimport { ensure, getRegistry, setRegistry } from './registry';\nimport { resolveInstanceKey } from './registry/acquire';\nimport type {\n ExtractArgs,\n ExtractDeps,\n ExtractState,\n StateContainerConstructor,\n} from './types/utilities';\n\n/** Synthetic owner id used by test helpers for pre-wired deps. */\nconst TESTING_DEPS_OWNER = 'testing-deps';\n\ndeclare const beforeEach: (fn: () => void) => void;\ndeclare const afterEach: (fn: () => void) => void;\n\n// --- createTestRegistry + withTestRegistry ---\n\nexport function createTestRegistry(): StateContainerRegistry {\n return new StateContainerRegistry();\n}\n\nexport function withTestRegistry<T>(\n fn: (registry: StateContainerRegistry) => T,\n): T {\n const previous = getRegistry();\n const testRegistry = createTestRegistry();\n setRegistry(testRegistry);\n try {\n const result = fn(testRegistry);\n if (result instanceof Promise) {\n return result.then(\n (value) => {\n setRegistry(previous);\n return value;\n },\n (error) => {\n setRegistry(previous);\n throw error;\n },\n ) as T;\n }\n setRegistry(previous);\n return result;\n } catch (error) {\n setRegistry(previous);\n throw error;\n }\n}\n\n// --- blacTestSetup ---\n\nexport function blacTestSetup(): void {\n let savedRegistry: StateContainerRegistry;\n beforeEach(() => {\n savedRegistry = getRegistry();\n setRegistry(new StateContainerRegistry());\n });\n afterEach(() => {\n setRegistry(savedRegistry);\n });\n}\n\n// --- registerOverride + overrideEnsure ---\n\nexport function registerOverride<T extends StateContainerConstructor>(\n BlocClass: T,\n instance: InstanceType<T>,\n args?: ExtractArgs<T>,\n): void {\n const registry = getRegistry();\n const key = resolveInstanceKey(BlocClass, args);\n registry.insertInstance(\n BlocClass,\n key,\n instance,\n new Map([['testing-override', 1]]),\n );\n}\n\nexport function overrideEnsure<T extends StateContainerConstructor, R>(\n BlocClass: T,\n instance: InstanceType<T>,\n fn: () => R,\n args?: ExtractArgs<T>,\n): R {\n return withTestRegistry(() => {\n registerOverride(BlocClass, instance, args);\n return fn();\n });\n}\n\n// --- createCubitStub ---\n\ntype MethodKeys<T> = {\n [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;\n}[keyof T];\n\nexport interface CubitStubOptions<T extends StateContainerConstructor> {\n state?: ExtractState<T> extends Record<string, any>\n ? Partial<ExtractState<T>>\n : ExtractState<T>;\n methods?: Partial<\n Record<MethodKeys<InstanceType<T>>, (...args: any[]) => any>\n >;\n /**\n * Args to pass to init(). If the bloc's Args type is not void, supplying\n * args here causes initConfig({ args }) to be called so init() runs.\n */\n args?: ExtractArgs<T> extends void ? never : ExtractArgs<T>;\n /**\n * Deps slice to pre-wire via the core [APPLY_DEPS] path (synthetic owner\n * \"testing-deps\"), so onDepsChanged fires during tests.\n */\n deps?: Partial<ExtractDeps<T>>;\n}\n\nexport function createCubitStub<T extends StateContainerConstructor>(\n BlocClass: T,\n options?: CubitStubOptions<T>,\n): InstanceType<T> {\n const instance = new BlocClass() as InstanceType<T>;\n\n // Run init() if args are supplied — goes through the same initConfig path\n // that the registry uses, so lifecycle hooks fire correctly.\n if (options?.args != null) {\n instance
|
|
1
|
+
{"version":3,"file":"testing.cjs","names":["StateContainerRegistry","getRegistry","resolveInstanceKey","INIT_CONFIG","Cubit","APPLY_DEPS","ensure"],"sources":["../src/testing.ts"],"sourcesContent":["import { Cubit } from './core/Cubit';\nimport { StateContainerRegistry } from './core/StateContainerRegistry';\nimport { APPLY_DEPS, INIT_CONFIG } from './core/symbols';\nimport { ensure, getRegistry, setRegistry } from './registry';\nimport { resolveInstanceKey } from './registry/acquire';\nimport type {\n ExtractArgs,\n ExtractDeps,\n ExtractState,\n StateContainerConstructor,\n} from './types/utilities';\n\n/** Synthetic owner id used by test helpers for pre-wired deps. */\nconst TESTING_DEPS_OWNER = 'testing-deps';\n\ndeclare const beforeEach: (fn: () => void) => void;\ndeclare const afterEach: (fn: () => void) => void;\n\n// --- createTestRegistry + withTestRegistry ---\n\nexport function createTestRegistry(): StateContainerRegistry {\n return new StateContainerRegistry();\n}\n\nexport function withTestRegistry<T>(\n fn: (registry: StateContainerRegistry) => T,\n): T {\n const previous = getRegistry();\n const testRegistry = createTestRegistry();\n setRegistry(testRegistry);\n try {\n const result = fn(testRegistry);\n if (result instanceof Promise) {\n return result.then(\n (value) => {\n setRegistry(previous);\n return value;\n },\n (error) => {\n setRegistry(previous);\n throw error;\n },\n ) as T;\n }\n setRegistry(previous);\n return result;\n } catch (error) {\n setRegistry(previous);\n throw error;\n }\n}\n\n// --- blacTestSetup ---\n\nexport function blacTestSetup(): void {\n let savedRegistry: StateContainerRegistry;\n beforeEach(() => {\n savedRegistry = getRegistry();\n setRegistry(new StateContainerRegistry());\n });\n afterEach(() => {\n setRegistry(savedRegistry);\n });\n}\n\n// --- registerOverride + overrideEnsure ---\n\nexport function registerOverride<T extends StateContainerConstructor>(\n BlocClass: T,\n instance: InstanceType<T>,\n args?: ExtractArgs<T>,\n): void {\n const registry = getRegistry();\n const key = resolveInstanceKey(BlocClass, args);\n registry.insertInstance(\n BlocClass,\n key,\n instance,\n new Map([['testing-override', 1]]),\n );\n}\n\nexport function overrideEnsure<T extends StateContainerConstructor, R>(\n BlocClass: T,\n instance: InstanceType<T>,\n fn: () => R,\n args?: ExtractArgs<T>,\n): R {\n return withTestRegistry(() => {\n registerOverride(BlocClass, instance, args);\n return fn();\n });\n}\n\n// --- createCubitStub ---\n\ntype MethodKeys<T> = {\n [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;\n}[keyof T];\n\nexport interface CubitStubOptions<T extends StateContainerConstructor> {\n state?: ExtractState<T> extends Record<string, any>\n ? Partial<ExtractState<T>>\n : ExtractState<T>;\n methods?: Partial<\n Record<MethodKeys<InstanceType<T>>, (...args: any[]) => any>\n >;\n /**\n * Args to pass to init(). If the bloc's Args type is not void, supplying\n * args here causes initConfig({ args }) to be called so init() runs.\n */\n args?: ExtractArgs<T> extends void ? never : ExtractArgs<T>;\n /**\n * Deps slice to pre-wire via the core [APPLY_DEPS] path (synthetic owner\n * \"testing-deps\"), so onDepsChanged fires during tests.\n */\n deps?: Partial<ExtractDeps<T>>;\n}\n\nexport function createCubitStub<T extends StateContainerConstructor>(\n BlocClass: T,\n options?: CubitStubOptions<T>,\n): InstanceType<T> {\n const instance = new BlocClass() as InstanceType<T>;\n\n // Run init() if args are supplied — goes through the same initConfig path\n // that the registry uses, so lifecycle hooks fire correctly.\n if (options?.args != null) {\n instance[INIT_CONFIG]({ args: options.args });\n }\n\n if (options?.state != null) {\n if (instance instanceof Cubit) {\n const currentState = instance.state;\n if (\n typeof currentState === 'object' &&\n currentState !== null &&\n typeof options.state === 'object' &&\n options.state !== null\n ) {\n instance.patch(options.state as any);\n } else {\n instance.emit(options.state as any);\n }\n }\n }\n if (options?.methods) {\n for (const [key, impl] of Object.entries(options.methods)) {\n if (typeof impl === 'function') {\n (instance as any)[key] = impl;\n }\n }\n }\n\n // Pre-wire deps via the core merge path so onDepsChanged fires in tests.\n if (options?.deps != null) {\n (instance as any)[APPLY_DEPS](TESTING_DEPS_OWNER, options.deps);\n }\n\n return instance;\n}\n\n// --- withBlocState ---\n\nexport function withBlocState<T extends StateContainerConstructor>(\n BlocClass: T,\n state: ExtractState<T> extends Record<string, any>\n ? Partial<ExtractState<T>>\n : ExtractState<T>,\n args?: ExtractArgs<T>,\n): InstanceType<T> {\n const instance = ensure(BlocClass, { args });\n if (instance instanceof Cubit) {\n const currentState = instance.state;\n if (\n typeof currentState === 'object' &&\n currentState !== null &&\n typeof state === 'object' &&\n state !== null\n ) {\n instance.patch(state as any);\n } else {\n instance.emit(state as any);\n }\n }\n return instance;\n}\n\n// --- withBlocMethod ---\n\nexport function withBlocMethod<T extends StateContainerConstructor>(\n BlocClass: T,\n methodName: keyof InstanceType<T>,\n impl: (...args: any[]) => any,\n args?: ExtractArgs<T>,\n): InstanceType<T> {\n const instance = ensure(BlocClass, { args });\n (instance as any)[methodName] = impl;\n return instance;\n}\n\n// --- flush ---\n\n/**\n * Drain pending microtasks so any channel-flushed effects (channel\n * subscribers, `onSystemEvent('stateChanged')` handlers, plugin hooks) run\n * before the next assertion.\n *\n * The default `MicrotaskScheduler` coalesces emits within a tick; tests\n * that emit and then assert on subscriber side-effects need `await flush()`\n * between the two.\n */\nexport async function flush(): Promise<void> {\n // queueMicrotask wins the race against the channel's own queued flush —\n // we resolve after the channel has drained its current pending flush.\n await Promise.resolve();\n await Promise.resolve();\n}\n"],"mappings":";;;;;;;AAaA,MAAM,qBAAqB;AAO3B,SAAgB,qBAA6C;CAC3D,OAAO,IAAIA,+BAAAA,uBAAuB;AACpC;AAEA,SAAgB,iBACd,IACG;CACH,MAAM,WAAWC,eAAAA,YAAY;CAC7B,MAAM,eAAe,mBAAmB;CACxC,eAAA,YAAY,YAAY;CACxB,IAAI;EACF,MAAM,SAAS,GAAG,YAAY;EAC9B,IAAI,kBAAkB,SACpB,OAAO,OAAO,MACX,UAAU;GACT,eAAA,YAAY,QAAQ;GACpB,OAAO;EACT,IACC,UAAU;GACT,eAAA,YAAY,QAAQ;GACpB,MAAM;EACR,CACF;EAEF,eAAA,YAAY,QAAQ;EACpB,OAAO;CACT,SAAS,OAAO;EACd,eAAA,YAAY,QAAQ;EACpB,MAAM;CACR;AACF;AAIA,SAAgB,gBAAsB;CACpC,IAAI;CACJ,iBAAiB;EACf,gBAAgBA,eAAAA,YAAY;EAC5B,eAAA,YAAY,IAAID,+BAAAA,uBAAuB,CAAC;CAC1C,CAAC;CACD,gBAAgB;EACd,eAAA,YAAY,aAAa;CAC3B,CAAC;AACH;AAIA,SAAgB,iBACd,WACA,UACA,MACM;CACN,MAAM,WAAWC,eAAAA,YAAY;CAC7B,MAAM,MAAMC,gBAAAA,mBAAmB,WAAW,IAAI;CAC9C,SAAS,eACP,WACA,KACA,UACA,IAAI,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CACnC;AACF;AAEA,SAAgB,eACd,WACA,UACA,IACA,MACG;CACH,OAAO,uBAAuB;EAC5B,iBAAiB,WAAW,UAAU,IAAI;EAC1C,OAAO,GAAG;CACZ,CAAC;AACH;AA2BA,SAAgB,gBACd,WACA,SACiB;CACjB,MAAM,WAAW,IAAI,UAAU;CAI/B,IAAI,SAAS,QAAQ,MACnB,SAASC,+BAAAA,aAAa,EAAE,MAAM,QAAQ,KAAK,CAAC;CAG9C,IAAI,SAAS,SAAS;MAChB,oBAAoBC,eAAAA,OAAO;GAC7B,MAAM,eAAe,SAAS;GAC9B,IACE,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,OAAO,QAAQ,UAAU,YACzB,QAAQ,UAAU,MAElB,SAAS,MAAM,QAAQ,KAAY;QAEnC,SAAS,KAAK,QAAQ,KAAY;EAEtC;;CAEF,IAAI,SAAS;OACN,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,QAAQ,OAAO,GACtD,IAAI,OAAO,SAAS,YAClB,SAAkB,OAAO;CAAA;CAM/B,IAAI,SAAS,QAAQ,MACnB,SAAkBC,+BAAAA,YAAY,oBAAoB,QAAQ,IAAI;CAGhE,OAAO;AACT;AAIA,SAAgB,cACd,WACA,OAGA,MACiB;CACjB,MAAM,WAAWC,eAAAA,OAAO,WAAW,EAAE,KAAK,CAAC;CAC3C,IAAI,oBAAoBF,eAAAA,OAAO;EAC7B,MAAM,eAAe,SAAS;EAC9B,IACE,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,OAAO,UAAU,YACjB,UAAU,MAEV,SAAS,MAAM,KAAY;OAE3B,SAAS,KAAK,KAAY;CAE9B;CACA,OAAO;AACT;AAIA,SAAgB,eACd,WACA,YACA,MACA,MACiB;CACjB,MAAM,WAAWE,eAAAA,OAAO,WAAW,EAAE,KAAK,CAAC;CAC3C,SAAkB,cAAc;CAChC,OAAO;AACT;;;;;;;;;;AAaA,eAAsB,QAAuB;CAG3C,MAAM,QAAQ,QAAQ;CACtB,MAAM,QAAQ,QAAQ;AACxB"}
|
package/dist/testing.d.cts
CHANGED
|
@@ -26,15 +26,13 @@ export declare function createCubitStub<T extends StateContainerConstructor>(Blo
|
|
|
26
26
|
export declare function withBlocState<T extends StateContainerConstructor>(BlocClass: T, state: ExtractState<T> extends Record<string, any> ? Partial<ExtractState<T>> : ExtractState<T>, args?: ExtractArgs<T>): InstanceType<T>;
|
|
27
27
|
export declare function withBlocMethod<T extends StateContainerConstructor>(BlocClass: T, methodName: keyof InstanceType<T>, impl: (...args: any[]) => any, args?: ExtractArgs<T>): InstanceType<T>;
|
|
28
28
|
/**
|
|
29
|
-
* Drain pending microtasks so any channel-flushed effects (
|
|
30
|
-
*
|
|
29
|
+
* Drain pending microtasks so any channel-flushed effects (channel
|
|
30
|
+
* subscribers, `onSystemEvent('stateChanged')` handlers, plugin hooks) run
|
|
31
31
|
* before the next assertion.
|
|
32
32
|
*
|
|
33
33
|
* The default `MicrotaskScheduler` coalesces emits within a tick; tests
|
|
34
|
-
* that emit and then assert on
|
|
35
|
-
*
|
|
34
|
+
* that emit and then assert on subscriber side-effects need `await flush()`
|
|
35
|
+
* between the two.
|
|
36
36
|
*/
|
|
37
37
|
export declare function flush(): Promise<void>;
|
|
38
|
-
/** @deprecated Alias for `flush()`. */
|
|
39
|
-
export declare function flushBlocUpdates(): Promise<void>;
|
|
40
38
|
export {};
|
package/dist/testing.d.ts
CHANGED
|
@@ -26,15 +26,13 @@ export declare function createCubitStub<T extends StateContainerConstructor>(Blo
|
|
|
26
26
|
export declare function withBlocState<T extends StateContainerConstructor>(BlocClass: T, state: ExtractState<T> extends Record<string, any> ? Partial<ExtractState<T>> : ExtractState<T>, args?: ExtractArgs<T>): InstanceType<T>;
|
|
27
27
|
export declare function withBlocMethod<T extends StateContainerConstructor>(BlocClass: T, methodName: keyof InstanceType<T>, impl: (...args: any[]) => any, args?: ExtractArgs<T>): InstanceType<T>;
|
|
28
28
|
/**
|
|
29
|
-
* Drain pending microtasks so any channel-flushed effects (
|
|
30
|
-
*
|
|
29
|
+
* Drain pending microtasks so any channel-flushed effects (channel
|
|
30
|
+
* subscribers, `onSystemEvent('stateChanged')` handlers, plugin hooks) run
|
|
31
31
|
* before the next assertion.
|
|
32
32
|
*
|
|
33
33
|
* The default `MicrotaskScheduler` coalesces emits within a tick; tests
|
|
34
|
-
* that emit and then assert on
|
|
35
|
-
*
|
|
34
|
+
* that emit and then assert on subscriber side-effects need `await flush()`
|
|
35
|
+
* between the two.
|
|
36
36
|
*/
|
|
37
37
|
export declare function flush(): Promise<void>;
|
|
38
|
-
/** @deprecated Alias for `flush()`. */
|
|
39
|
-
export declare function flushBlocUpdates(): Promise<void>;
|
|
40
38
|
export {};
|
package/dist/testing.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as StateContainerRegistry } from "./StateContainerRegistry-
|
|
2
|
-
import {
|
|
3
|
-
import { r as setRegistry, t as getRegistry } from "./config-
|
|
4
|
-
import { n as resolveInstanceKey } from "./acquire-
|
|
1
|
+
import { a as INIT_CONFIG, i as APPLY_DEPS, t as StateContainerRegistry } from "./StateContainerRegistry-CvBOhAT2.js";
|
|
2
|
+
import { n as Cubit, t as ensure } from "./ensure-C1a8IFWy.js";
|
|
3
|
+
import { r as setRegistry, t as getRegistry } from "./config-buwpT7l3.js";
|
|
4
|
+
import { n as resolveInstanceKey } from "./acquire-BP-ZfUH2.js";
|
|
5
5
|
//#region src/testing.ts
|
|
6
6
|
/** Synthetic owner id used by test helpers for pre-wired deps. */
|
|
7
7
|
const TESTING_DEPS_OWNER = "testing-deps";
|
|
@@ -51,7 +51,7 @@ function overrideEnsure(BlocClass, instance, fn, args) {
|
|
|
51
51
|
}
|
|
52
52
|
function createCubitStub(BlocClass, options) {
|
|
53
53
|
const instance = new BlocClass();
|
|
54
|
-
if (options?.args != null) instance
|
|
54
|
+
if (options?.args != null) instance[INIT_CONFIG]({ args: options.args });
|
|
55
55
|
if (options?.state != null) {
|
|
56
56
|
if (instance instanceof Cubit) {
|
|
57
57
|
const currentState = instance.state;
|
|
@@ -80,23 +80,19 @@ function withBlocMethod(BlocClass, methodName, impl, args) {
|
|
|
80
80
|
return instance;
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
|
-
* Drain pending microtasks so any channel-flushed effects (
|
|
84
|
-
*
|
|
83
|
+
* Drain pending microtasks so any channel-flushed effects (channel
|
|
84
|
+
* subscribers, `onSystemEvent('stateChanged')` handlers, plugin hooks) run
|
|
85
85
|
* before the next assertion.
|
|
86
86
|
*
|
|
87
87
|
* The default `MicrotaskScheduler` coalesces emits within a tick; tests
|
|
88
|
-
* that emit and then assert on
|
|
89
|
-
*
|
|
88
|
+
* that emit and then assert on subscriber side-effects need `await flush()`
|
|
89
|
+
* between the two.
|
|
90
90
|
*/
|
|
91
91
|
async function flush() {
|
|
92
92
|
await Promise.resolve();
|
|
93
93
|
await Promise.resolve();
|
|
94
94
|
}
|
|
95
|
-
/** @deprecated Alias for `flush()`. */
|
|
96
|
-
async function flushBlocUpdates() {
|
|
97
|
-
await flush();
|
|
98
|
-
}
|
|
99
95
|
//#endregion
|
|
100
|
-
export { blacTestSetup, createCubitStub, createTestRegistry, flush,
|
|
96
|
+
export { blacTestSetup, createCubitStub, createTestRegistry, flush, overrideEnsure, registerOverride, withBlocMethod, withBlocState, withTestRegistry };
|
|
101
97
|
|
|
102
98
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../src/testing.ts"],"sourcesContent":["import { Cubit } from './core/Cubit';\nimport { StateContainerRegistry } from './core/StateContainerRegistry';\nimport { APPLY_DEPS } from './core/symbols';\nimport { ensure, getRegistry, setRegistry } from './registry';\nimport { resolveInstanceKey } from './registry/acquire';\nimport type {\n ExtractArgs,\n ExtractDeps,\n ExtractState,\n StateContainerConstructor,\n} from './types/utilities';\n\n/** Synthetic owner id used by test helpers for pre-wired deps. */\nconst TESTING_DEPS_OWNER = 'testing-deps';\n\ndeclare const beforeEach: (fn: () => void) => void;\ndeclare const afterEach: (fn: () => void) => void;\n\n// --- createTestRegistry + withTestRegistry ---\n\nexport function createTestRegistry(): StateContainerRegistry {\n return new StateContainerRegistry();\n}\n\nexport function withTestRegistry<T>(\n fn: (registry: StateContainerRegistry) => T,\n): T {\n const previous = getRegistry();\n const testRegistry = createTestRegistry();\n setRegistry(testRegistry);\n try {\n const result = fn(testRegistry);\n if (result instanceof Promise) {\n return result.then(\n (value) => {\n setRegistry(previous);\n return value;\n },\n (error) => {\n setRegistry(previous);\n throw error;\n },\n ) as T;\n }\n setRegistry(previous);\n return result;\n } catch (error) {\n setRegistry(previous);\n throw error;\n }\n}\n\n// --- blacTestSetup ---\n\nexport function blacTestSetup(): void {\n let savedRegistry: StateContainerRegistry;\n beforeEach(() => {\n savedRegistry = getRegistry();\n setRegistry(new StateContainerRegistry());\n });\n afterEach(() => {\n setRegistry(savedRegistry);\n });\n}\n\n// --- registerOverride + overrideEnsure ---\n\nexport function registerOverride<T extends StateContainerConstructor>(\n BlocClass: T,\n instance: InstanceType<T>,\n args?: ExtractArgs<T>,\n): void {\n const registry = getRegistry();\n const key = resolveInstanceKey(BlocClass, args);\n registry.insertInstance(\n BlocClass,\n key,\n instance,\n new Map([['testing-override', 1]]),\n );\n}\n\nexport function overrideEnsure<T extends StateContainerConstructor, R>(\n BlocClass: T,\n instance: InstanceType<T>,\n fn: () => R,\n args?: ExtractArgs<T>,\n): R {\n return withTestRegistry(() => {\n registerOverride(BlocClass, instance, args);\n return fn();\n });\n}\n\n// --- createCubitStub ---\n\ntype MethodKeys<T> = {\n [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;\n}[keyof T];\n\nexport interface CubitStubOptions<T extends StateContainerConstructor> {\n state?: ExtractState<T> extends Record<string, any>\n ? Partial<ExtractState<T>>\n : ExtractState<T>;\n methods?: Partial<\n Record<MethodKeys<InstanceType<T>>, (...args: any[]) => any>\n >;\n /**\n * Args to pass to init(). If the bloc's Args type is not void, supplying\n * args here causes initConfig({ args }) to be called so init() runs.\n */\n args?: ExtractArgs<T> extends void ? never : ExtractArgs<T>;\n /**\n * Deps slice to pre-wire via the core [APPLY_DEPS] path (synthetic owner\n * \"testing-deps\"), so onDepsChanged fires during tests.\n */\n deps?: Partial<ExtractDeps<T>>;\n}\n\nexport function createCubitStub<T extends StateContainerConstructor>(\n BlocClass: T,\n options?: CubitStubOptions<T>,\n): InstanceType<T> {\n const instance = new BlocClass() as InstanceType<T>;\n\n // Run init() if args are supplied — goes through the same initConfig path\n // that the registry uses, so lifecycle hooks fire correctly.\n if (options?.args != null) {\n instance
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../src/testing.ts"],"sourcesContent":["import { Cubit } from './core/Cubit';\nimport { StateContainerRegistry } from './core/StateContainerRegistry';\nimport { APPLY_DEPS, INIT_CONFIG } from './core/symbols';\nimport { ensure, getRegistry, setRegistry } from './registry';\nimport { resolveInstanceKey } from './registry/acquire';\nimport type {\n ExtractArgs,\n ExtractDeps,\n ExtractState,\n StateContainerConstructor,\n} from './types/utilities';\n\n/** Synthetic owner id used by test helpers for pre-wired deps. */\nconst TESTING_DEPS_OWNER = 'testing-deps';\n\ndeclare const beforeEach: (fn: () => void) => void;\ndeclare const afterEach: (fn: () => void) => void;\n\n// --- createTestRegistry + withTestRegistry ---\n\nexport function createTestRegistry(): StateContainerRegistry {\n return new StateContainerRegistry();\n}\n\nexport function withTestRegistry<T>(\n fn: (registry: StateContainerRegistry) => T,\n): T {\n const previous = getRegistry();\n const testRegistry = createTestRegistry();\n setRegistry(testRegistry);\n try {\n const result = fn(testRegistry);\n if (result instanceof Promise) {\n return result.then(\n (value) => {\n setRegistry(previous);\n return value;\n },\n (error) => {\n setRegistry(previous);\n throw error;\n },\n ) as T;\n }\n setRegistry(previous);\n return result;\n } catch (error) {\n setRegistry(previous);\n throw error;\n }\n}\n\n// --- blacTestSetup ---\n\nexport function blacTestSetup(): void {\n let savedRegistry: StateContainerRegistry;\n beforeEach(() => {\n savedRegistry = getRegistry();\n setRegistry(new StateContainerRegistry());\n });\n afterEach(() => {\n setRegistry(savedRegistry);\n });\n}\n\n// --- registerOverride + overrideEnsure ---\n\nexport function registerOverride<T extends StateContainerConstructor>(\n BlocClass: T,\n instance: InstanceType<T>,\n args?: ExtractArgs<T>,\n): void {\n const registry = getRegistry();\n const key = resolveInstanceKey(BlocClass, args);\n registry.insertInstance(\n BlocClass,\n key,\n instance,\n new Map([['testing-override', 1]]),\n );\n}\n\nexport function overrideEnsure<T extends StateContainerConstructor, R>(\n BlocClass: T,\n instance: InstanceType<T>,\n fn: () => R,\n args?: ExtractArgs<T>,\n): R {\n return withTestRegistry(() => {\n registerOverride(BlocClass, instance, args);\n return fn();\n });\n}\n\n// --- createCubitStub ---\n\ntype MethodKeys<T> = {\n [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;\n}[keyof T];\n\nexport interface CubitStubOptions<T extends StateContainerConstructor> {\n state?: ExtractState<T> extends Record<string, any>\n ? Partial<ExtractState<T>>\n : ExtractState<T>;\n methods?: Partial<\n Record<MethodKeys<InstanceType<T>>, (...args: any[]) => any>\n >;\n /**\n * Args to pass to init(). If the bloc's Args type is not void, supplying\n * args here causes initConfig({ args }) to be called so init() runs.\n */\n args?: ExtractArgs<T> extends void ? never : ExtractArgs<T>;\n /**\n * Deps slice to pre-wire via the core [APPLY_DEPS] path (synthetic owner\n * \"testing-deps\"), so onDepsChanged fires during tests.\n */\n deps?: Partial<ExtractDeps<T>>;\n}\n\nexport function createCubitStub<T extends StateContainerConstructor>(\n BlocClass: T,\n options?: CubitStubOptions<T>,\n): InstanceType<T> {\n const instance = new BlocClass() as InstanceType<T>;\n\n // Run init() if args are supplied — goes through the same initConfig path\n // that the registry uses, so lifecycle hooks fire correctly.\n if (options?.args != null) {\n instance[INIT_CONFIG]({ args: options.args });\n }\n\n if (options?.state != null) {\n if (instance instanceof Cubit) {\n const currentState = instance.state;\n if (\n typeof currentState === 'object' &&\n currentState !== null &&\n typeof options.state === 'object' &&\n options.state !== null\n ) {\n instance.patch(options.state as any);\n } else {\n instance.emit(options.state as any);\n }\n }\n }\n if (options?.methods) {\n for (const [key, impl] of Object.entries(options.methods)) {\n if (typeof impl === 'function') {\n (instance as any)[key] = impl;\n }\n }\n }\n\n // Pre-wire deps via the core merge path so onDepsChanged fires in tests.\n if (options?.deps != null) {\n (instance as any)[APPLY_DEPS](TESTING_DEPS_OWNER, options.deps);\n }\n\n return instance;\n}\n\n// --- withBlocState ---\n\nexport function withBlocState<T extends StateContainerConstructor>(\n BlocClass: T,\n state: ExtractState<T> extends Record<string, any>\n ? Partial<ExtractState<T>>\n : ExtractState<T>,\n args?: ExtractArgs<T>,\n): InstanceType<T> {\n const instance = ensure(BlocClass, { args });\n if (instance instanceof Cubit) {\n const currentState = instance.state;\n if (\n typeof currentState === 'object' &&\n currentState !== null &&\n typeof state === 'object' &&\n state !== null\n ) {\n instance.patch(state as any);\n } else {\n instance.emit(state as any);\n }\n }\n return instance;\n}\n\n// --- withBlocMethod ---\n\nexport function withBlocMethod<T extends StateContainerConstructor>(\n BlocClass: T,\n methodName: keyof InstanceType<T>,\n impl: (...args: any[]) => any,\n args?: ExtractArgs<T>,\n): InstanceType<T> {\n const instance = ensure(BlocClass, { args });\n (instance as any)[methodName] = impl;\n return instance;\n}\n\n// --- flush ---\n\n/**\n * Drain pending microtasks so any channel-flushed effects (channel\n * subscribers, `onSystemEvent('stateChanged')` handlers, plugin hooks) run\n * before the next assertion.\n *\n * The default `MicrotaskScheduler` coalesces emits within a tick; tests\n * that emit and then assert on subscriber side-effects need `await flush()`\n * between the two.\n */\nexport async function flush(): Promise<void> {\n // queueMicrotask wins the race against the channel's own queued flush —\n // we resolve after the channel has drained its current pending flush.\n await Promise.resolve();\n await Promise.resolve();\n}\n"],"mappings":";;;;;;AAaA,MAAM,qBAAqB;AAO3B,SAAgB,qBAA6C;CAC3D,OAAO,IAAI,uBAAuB;AACpC;AAEA,SAAgB,iBACd,IACG;CACH,MAAM,WAAW,YAAY;CAC7B,MAAM,eAAe,mBAAmB;CACxC,YAAY,YAAY;CACxB,IAAI;EACF,MAAM,SAAS,GAAG,YAAY;EAC9B,IAAI,kBAAkB,SACpB,OAAO,OAAO,MACX,UAAU;GACT,YAAY,QAAQ;GACpB,OAAO;EACT,IACC,UAAU;GACT,YAAY,QAAQ;GACpB,MAAM;EACR,CACF;EAEF,YAAY,QAAQ;EACpB,OAAO;CACT,SAAS,OAAO;EACd,YAAY,QAAQ;EACpB,MAAM;CACR;AACF;AAIA,SAAgB,gBAAsB;CACpC,IAAI;CACJ,iBAAiB;EACf,gBAAgB,YAAY;EAC5B,YAAY,IAAI,uBAAuB,CAAC;CAC1C,CAAC;CACD,gBAAgB;EACd,YAAY,aAAa;CAC3B,CAAC;AACH;AAIA,SAAgB,iBACd,WACA,UACA,MACM;CACN,MAAM,WAAW,YAAY;CAC7B,MAAM,MAAM,mBAAmB,WAAW,IAAI;CAC9C,SAAS,eACP,WACA,KACA,UACA,IAAI,IAAI,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CACnC;AACF;AAEA,SAAgB,eACd,WACA,UACA,IACA,MACG;CACH,OAAO,uBAAuB;EAC5B,iBAAiB,WAAW,UAAU,IAAI;EAC1C,OAAO,GAAG;CACZ,CAAC;AACH;AA2BA,SAAgB,gBACd,WACA,SACiB;CACjB,MAAM,WAAW,IAAI,UAAU;CAI/B,IAAI,SAAS,QAAQ,MACnB,SAAS,aAAa,EAAE,MAAM,QAAQ,KAAK,CAAC;CAG9C,IAAI,SAAS,SAAS;MAChB,oBAAoB,OAAO;GAC7B,MAAM,eAAe,SAAS;GAC9B,IACE,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,OAAO,QAAQ,UAAU,YACzB,QAAQ,UAAU,MAElB,SAAS,MAAM,QAAQ,KAAY;QAEnC,SAAS,KAAK,QAAQ,KAAY;EAEtC;;CAEF,IAAI,SAAS;OACN,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,QAAQ,OAAO,GACtD,IAAI,OAAO,SAAS,YAClB,SAAkB,OAAO;CAAA;CAM/B,IAAI,SAAS,QAAQ,MACnB,SAAkB,YAAY,oBAAoB,QAAQ,IAAI;CAGhE,OAAO;AACT;AAIA,SAAgB,cACd,WACA,OAGA,MACiB;CACjB,MAAM,WAAW,OAAO,WAAW,EAAE,KAAK,CAAC;CAC3C,IAAI,oBAAoB,OAAO;EAC7B,MAAM,eAAe,SAAS;EAC9B,IACE,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,OAAO,UAAU,YACjB,UAAU,MAEV,SAAS,MAAM,KAAY;OAE3B,SAAS,KAAK,KAAY;CAE9B;CACA,OAAO;AACT;AAIA,SAAgB,eACd,WACA,YACA,MACA,MACiB;CACjB,MAAM,WAAW,OAAO,WAAW,EAAE,KAAK,CAAC;CAC3C,SAAkB,cAAc;CAChC,OAAO;AACT;;;;;;;;;;AAaA,eAAsB,QAAuB;CAG3C,MAAM,QAAQ,QAAQ;CACtB,MAAM,QAAQ,QAAQ;AACxB"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { t as getRegistry } from "./config-COT4Xkbc.js";
|
|
2
|
+
import { n as resolveInstanceKey } from "./acquire-CwB083au.js";
|
|
3
|
+
import { ALL_PATHS } from "@dirtytalk/structural";
|
|
4
|
+
//#region src/watch/watch.ts
|
|
5
|
+
const STOP = Symbol("watch.STOP");
|
|
6
|
+
const BLOC_REF_MARKER = Symbol("BlocRef");
|
|
7
|
+
/**
|
|
8
|
+
* Create a reference to a specific bloc instance, identified by its `args`.
|
|
9
|
+
* The key is derived the same way `useBloc`/`acquire` derive it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {
|
|
14
|
+
* console.log(userBloc.state.name);
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function instance(BlocClass, args) {
|
|
19
|
+
return {
|
|
20
|
+
[BLOC_REF_MARKER]: true,
|
|
21
|
+
blocClass: BlocClass,
|
|
22
|
+
instanceId: resolveInstanceKey(BlocClass, args)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function isBlocRef(input) {
|
|
26
|
+
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
|
|
27
|
+
}
|
|
28
|
+
function resolveBloc(input) {
|
|
29
|
+
const registry = getRegistry();
|
|
30
|
+
if (isBlocRef(input)) return registry.ensure(input.blocClass, input.instanceId);
|
|
31
|
+
return registry.ensure(input, registry.resolveKey(input, void 0, void 0));
|
|
32
|
+
}
|
|
33
|
+
function isArray(input) {
|
|
34
|
+
return Array.isArray(input);
|
|
35
|
+
}
|
|
36
|
+
function watchImpl(blocsOrBloc, callback) {
|
|
37
|
+
const isSingle = !isArray(blocsOrBloc);
|
|
38
|
+
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
|
|
39
|
+
let disposed = false;
|
|
40
|
+
const subscriptions = [];
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
if (disposed) return;
|
|
43
|
+
disposed = true;
|
|
44
|
+
for (const unsub of subscriptions) unsub();
|
|
45
|
+
subscriptions.length = 0;
|
|
46
|
+
};
|
|
47
|
+
const runCallback = () => {
|
|
48
|
+
if (disposed) return;
|
|
49
|
+
if (callback(isSingle ? instances[0] : instances) === STOP) cleanup();
|
|
50
|
+
};
|
|
51
|
+
for (const inst of instances) subscriptions.push(inst.channel.subscribe(() => ALL_PATHS, runCallback));
|
|
52
|
+
runCallback();
|
|
53
|
+
return cleanup;
|
|
54
|
+
}
|
|
55
|
+
const watch = Object.assign(watchImpl, { STOP });
|
|
56
|
+
//#endregion
|
|
57
|
+
export { watch as n, instance as t };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=watch-CfrSSrRY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch-CfrSSrRY.js","names":[],"sources":["../src/watch/watch.ts"],"sourcesContent":["import { ALL_PATHS } from '@dirtytalk/structural';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n}\n\nfunction resolveBloc(input: BlocInput): StateContainerInstance {\n const registry = getRegistry();\n if (isBlocRef(input)) {\n return registry.ensure(input.blocClass, input.instanceId);\n }\n return registry.ensure(\n input,\n registry.resolveKey(input, undefined, undefined),\n );\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n *\n * Thin wrapper around `container.channel.subscribe(ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions.\n *\n * Note: subscriptions are microtask-deferred (per the DirtyChannel default\n * scheduler), so callbacks land asynchronously after `emit()`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, { userId: 'user-123' }),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n\n const instances = inputs.map(resolveBloc);\n\n let disposed = false;\n const subscriptions: (() => void)[] = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n for (const unsub of subscriptions) unsub();\n subscriptions.length = 0;\n };\n\n const runCallback = () => {\n if (disposed) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n for (const inst of instances) {\n subscriptions.push(inst.channel.subscribe(() => ALL_PATHS, runCallback));\n }\n\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n"],"mappings":";;;;AASA,MAAM,OAAsB,OAAO,YAAY;AAG/C,MAAM,kBAAkB,OAAO,SAAS;;;;;;;;;;;;AAwBxC,SAAgB,SACd,WACA,MACY;CACZ,OAAO;GACJ,kBAAkB;EACnB,WAAW;EACX,YAAY,mBAAmB,WAAW,IAAI;CAChD;AACF;AAEA,SAAS,UACP,OAC6C;CAC7C,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;AAEtE;AAiDA,SAAS,YAAY,OAA0C;CAC7D,MAAM,WAAW,YAAY;CAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,SAAS,OAAO,MAAM,WAAW,MAAM,UAAU;CAE1D,OAAO,SAAS,OACd,OACA,SAAS,WAAW,OAAO,KAAA,GAAW,KAAA,CAAS,CACjD;AACF;AAEA,SAAS,QAAQ,OAA+C;CAC9D,OAAO,MAAM,QAAQ,KAAK;AAC5B;AA2DA,SAAS,UACP,aACA,UACY;CACZ,MAAM,WAAW,CAAC,QAAQ,WAAW;CAGrC,MAAM,aAFS,WAAW,CAAC,WAAW,IAAI,aAEjB,IAAI,WAAW;CAExC,IAAI,WAAW;CACf,MAAM,gBAAgC,CAAC;CAEvC,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,KAAK,MAAM,SAAS,eAAe,MAAM;EACzC,cAAc,SAAS;CACzB;CAEA,MAAM,oBAAoB;EACxB,IAAI,UAAU;EAGd,IADe,SADH,WAAW,UAAU,KAAK,SAE7B,MAAM,MAAM,QAAQ;CAC/B;CAEA,KAAK,MAAM,QAAQ,WACjB,cAAc,KAAK,KAAK,QAAQ,gBAAgB,WAAW,WAAW,CAAC;CAIzE,YAAY;CAEZ,OAAO;AACT;AAEA,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,KAAK,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const require_config = require("./config-C7Ktkjh2.cjs");
|
|
2
|
+
const require_acquire = require("./acquire-B1Wuqla6.cjs");
|
|
3
|
+
let _dirtytalk_structural = require("@dirtytalk/structural");
|
|
4
|
+
//#region src/watch/watch.ts
|
|
5
|
+
const STOP = Symbol("watch.STOP");
|
|
6
|
+
const BLOC_REF_MARKER = Symbol("BlocRef");
|
|
7
|
+
/**
|
|
8
|
+
* Create a reference to a specific bloc instance, identified by its `args`.
|
|
9
|
+
* The key is derived the same way `useBloc`/`acquire` derive it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {
|
|
14
|
+
* console.log(userBloc.state.name);
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function instance(BlocClass, args) {
|
|
19
|
+
return {
|
|
20
|
+
[BLOC_REF_MARKER]: true,
|
|
21
|
+
blocClass: BlocClass,
|
|
22
|
+
instanceId: require_acquire.resolveInstanceKey(BlocClass, args)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function isBlocRef(input) {
|
|
26
|
+
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
|
|
27
|
+
}
|
|
28
|
+
function resolveBloc(input) {
|
|
29
|
+
const registry = require_config.getRegistry();
|
|
30
|
+
if (isBlocRef(input)) return registry.ensure(input.blocClass, input.instanceId);
|
|
31
|
+
return registry.ensure(input, registry.resolveKey(input, void 0, void 0));
|
|
32
|
+
}
|
|
33
|
+
function isArray(input) {
|
|
34
|
+
return Array.isArray(input);
|
|
35
|
+
}
|
|
36
|
+
function watchImpl(blocsOrBloc, callback) {
|
|
37
|
+
const isSingle = !isArray(blocsOrBloc);
|
|
38
|
+
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
|
|
39
|
+
let disposed = false;
|
|
40
|
+
const subscriptions = [];
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
if (disposed) return;
|
|
43
|
+
disposed = true;
|
|
44
|
+
for (const unsub of subscriptions) unsub();
|
|
45
|
+
subscriptions.length = 0;
|
|
46
|
+
};
|
|
47
|
+
const runCallback = () => {
|
|
48
|
+
if (disposed) return;
|
|
49
|
+
if (callback(isSingle ? instances[0] : instances) === STOP) cleanup();
|
|
50
|
+
};
|
|
51
|
+
for (const inst of instances) subscriptions.push(inst.channel.subscribe(() => _dirtytalk_structural.ALL_PATHS, runCallback));
|
|
52
|
+
runCallback();
|
|
53
|
+
return cleanup;
|
|
54
|
+
}
|
|
55
|
+
const watch = Object.assign(watchImpl, { STOP });
|
|
56
|
+
//#endregion
|
|
57
|
+
Object.defineProperty(exports, "instance", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: function() {
|
|
60
|
+
return instance;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(exports, "watch", {
|
|
64
|
+
enumerable: true,
|
|
65
|
+
get: function() {
|
|
66
|
+
return watch;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=watch-Cnh3PtQA.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch-Cnh3PtQA.cjs","names":["resolveInstanceKey","getRegistry","ALL_PATHS"],"sources":["../src/watch/watch.ts"],"sourcesContent":["import { ALL_PATHS } from '@dirtytalk/structural';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n}\n\nfunction resolveBloc(input: BlocInput): StateContainerInstance {\n const registry = getRegistry();\n if (isBlocRef(input)) {\n return registry.ensure(input.blocClass, input.instanceId);\n }\n return registry.ensure(\n input,\n registry.resolveKey(input, undefined, undefined),\n );\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n *\n * Thin wrapper around `container.channel.subscribe(ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions.\n *\n * Note: subscriptions are microtask-deferred (per the DirtyChannel default\n * scheduler), so callbacks land asynchronously after `emit()`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, { userId: 'user-123' }),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n\n const instances = inputs.map(resolveBloc);\n\n let disposed = false;\n const subscriptions: (() => void)[] = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n for (const unsub of subscriptions) unsub();\n subscriptions.length = 0;\n };\n\n const runCallback = () => {\n if (disposed) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n for (const inst of instances) {\n subscriptions.push(inst.channel.subscribe(() => ALL_PATHS, runCallback));\n }\n\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n"],"mappings":";;;;AASA,MAAM,OAAsB,OAAO,YAAY;AAG/C,MAAM,kBAAkB,OAAO,SAAS;;;;;;;;;;;;AAwBxC,SAAgB,SACd,WACA,MACY;CACZ,OAAO;GACJ,kBAAkB;EACnB,WAAW;EACX,YAAYA,gBAAAA,mBAAmB,WAAW,IAAI;CAChD;AACF;AAEA,SAAS,UACP,OAC6C;CAC7C,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;AAEtE;AAiDA,SAAS,YAAY,OAA0C;CAC7D,MAAM,WAAWC,eAAAA,YAAY;CAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,SAAS,OAAO,MAAM,WAAW,MAAM,UAAU;CAE1D,OAAO,SAAS,OACd,OACA,SAAS,WAAW,OAAO,KAAA,GAAW,KAAA,CAAS,CACjD;AACF;AAEA,SAAS,QAAQ,OAA+C;CAC9D,OAAO,MAAM,QAAQ,KAAK;AAC5B;AA2DA,SAAS,UACP,aACA,UACY;CACZ,MAAM,WAAW,CAAC,QAAQ,WAAW;CAGrC,MAAM,aAFS,WAAW,CAAC,WAAW,IAAI,aAEjB,IAAI,WAAW;CAExC,IAAI,WAAW;CACf,MAAM,gBAAgC,CAAC;CAEvC,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,KAAK,MAAM,SAAS,eAAe,MAAM;EACzC,cAAc,SAAS;CACzB;CAEA,MAAM,oBAAoB;EACxB,IAAI,UAAU;EAGd,IADe,SADH,WAAW,UAAU,KAAK,SAE7B,MAAM,MAAM,QAAQ;CAC/B;CAEA,KAAK,MAAM,QAAQ,WACjB,cAAc,KAAK,KAAK,QAAQ,gBAAgBC,sBAAAA,WAAW,WAAW,CAAC;CAIzE,YAAY;CAEZ,OAAO;AACT;AAEA,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,KAAK,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { t as getRegistry } from "./config-buwpT7l3.js";
|
|
2
|
+
import { n as resolveInstanceKey } from "./acquire-BP-ZfUH2.js";
|
|
3
|
+
import { ALL_PATHS } from "@dirtytalk/structural";
|
|
4
|
+
//#region src/watch/watch.ts
|
|
5
|
+
const STOP = Symbol("watch.STOP");
|
|
6
|
+
const BLOC_REF_MARKER = Symbol("BlocRef");
|
|
7
|
+
/**
|
|
8
|
+
* Create a reference to a specific bloc instance, identified by its `args`.
|
|
9
|
+
* The key is derived the same way `useBloc`/`acquire` derive it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {
|
|
14
|
+
* console.log(userBloc.state.name);
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function instance(BlocClass, args) {
|
|
19
|
+
return {
|
|
20
|
+
[BLOC_REF_MARKER]: true,
|
|
21
|
+
blocClass: BlocClass,
|
|
22
|
+
instanceId: resolveInstanceKey(BlocClass, args)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function isBlocRef(input) {
|
|
26
|
+
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
|
|
27
|
+
}
|
|
28
|
+
function resolveBloc(input) {
|
|
29
|
+
const registry = getRegistry();
|
|
30
|
+
if (isBlocRef(input)) return registry.ensure(input.blocClass, input.instanceId);
|
|
31
|
+
return registry.ensure(input, registry.resolveKey(input, void 0, void 0));
|
|
32
|
+
}
|
|
33
|
+
function isArray(input) {
|
|
34
|
+
return Array.isArray(input);
|
|
35
|
+
}
|
|
36
|
+
function watchImpl(blocsOrBloc, callback) {
|
|
37
|
+
const isSingle = !isArray(blocsOrBloc);
|
|
38
|
+
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
|
|
39
|
+
let disposed = false;
|
|
40
|
+
const subscriptions = [];
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
if (disposed) return;
|
|
43
|
+
disposed = true;
|
|
44
|
+
for (const unsub of subscriptions) unsub();
|
|
45
|
+
subscriptions.length = 0;
|
|
46
|
+
};
|
|
47
|
+
const runCallback = () => {
|
|
48
|
+
if (disposed) return;
|
|
49
|
+
if (callback(isSingle ? instances[0] : instances) === STOP) cleanup();
|
|
50
|
+
};
|
|
51
|
+
for (const inst of instances) subscriptions.push(inst.channel.subscribe(() => ALL_PATHS, runCallback));
|
|
52
|
+
runCallback();
|
|
53
|
+
return cleanup;
|
|
54
|
+
}
|
|
55
|
+
const watch = Object.assign(watchImpl, { STOP });
|
|
56
|
+
//#endregion
|
|
57
|
+
export { watch as n, instance as t };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=watch-D8hwbFU1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch-D8hwbFU1.js","names":[],"sources":["../src/watch/watch.ts"],"sourcesContent":["import { ALL_PATHS } from '@dirtytalk/structural';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n}\n\nfunction resolveBloc(input: BlocInput): StateContainerInstance {\n const registry = getRegistry();\n if (isBlocRef(input)) {\n return registry.ensure(input.blocClass, input.instanceId);\n }\n return registry.ensure(\n input,\n registry.resolveKey(input, undefined, undefined),\n );\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n *\n * Thin wrapper around `container.channel.subscribe(ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions.\n *\n * Note: subscriptions are microtask-deferred (per the DirtyChannel default\n * scheduler), so callbacks land asynchronously after `emit()`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, { userId: 'user-123' }),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n\n const instances = inputs.map(resolveBloc);\n\n let disposed = false;\n const subscriptions: (() => void)[] = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n for (const unsub of subscriptions) unsub();\n subscriptions.length = 0;\n };\n\n const runCallback = () => {\n if (disposed) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n for (const inst of instances) {\n subscriptions.push(inst.channel.subscribe(() => ALL_PATHS, runCallback));\n }\n\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n"],"mappings":";;;;AASA,MAAM,OAAsB,OAAO,YAAY;AAG/C,MAAM,kBAAkB,OAAO,SAAS;;;;;;;;;;;;AAwBxC,SAAgB,SACd,WACA,MACY;CACZ,OAAO;GACJ,kBAAkB;EACnB,WAAW;EACX,YAAY,mBAAmB,WAAW,IAAI;CAChD;AACF;AAEA,SAAS,UACP,OAC6C;CAC7C,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;AAEtE;AAiDA,SAAS,YAAY,OAA0C;CAC7D,MAAM,WAAW,YAAY;CAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,SAAS,OAAO,MAAM,WAAW,MAAM,UAAU;CAE1D,OAAO,SAAS,OACd,OACA,SAAS,WAAW,OAAO,KAAA,GAAW,KAAA,CAAS,CACjD;AACF;AAEA,SAAS,QAAQ,OAA+C;CAC9D,OAAO,MAAM,QAAQ,KAAK;AAC5B;AA2DA,SAAS,UACP,aACA,UACY;CACZ,MAAM,WAAW,CAAC,QAAQ,WAAW;CAGrC,MAAM,aAFS,WAAW,CAAC,WAAW,IAAI,aAEjB,IAAI,WAAW;CAExC,IAAI,WAAW;CACf,MAAM,gBAAgC,CAAC;CAEvC,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,KAAK,MAAM,SAAS,eAAe,MAAM;EACzC,cAAc,SAAS;CACzB;CAEA,MAAM,oBAAoB;EACxB,IAAI,UAAU;EAGd,IADe,SADH,WAAW,UAAU,KAAK,SAE7B,MAAM,MAAM,QAAQ;CAC/B;CAEA,KAAK,MAAM,QAAQ,WACjB,cAAc,KAAK,KAAK,QAAQ,gBAAgB,WAAW,WAAW,CAAC;CAIzE,YAAY;CAEZ,OAAO;AACT;AAEA,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,KAAK,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const require_config = require("./config-b2z51Y_C.cjs");
|
|
2
|
+
const require_acquire = require("./acquire-BZIs6tpN.cjs");
|
|
3
|
+
let _dirtytalk_structural = require("@dirtytalk/structural");
|
|
4
|
+
//#region src/watch/watch.ts
|
|
5
|
+
const STOP = Symbol("watch.STOP");
|
|
6
|
+
const BLOC_REF_MARKER = Symbol("BlocRef");
|
|
7
|
+
/**
|
|
8
|
+
* Create a reference to a specific bloc instance, identified by its `args`.
|
|
9
|
+
* The key is derived the same way `useBloc`/`acquire` derive it.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {
|
|
14
|
+
* console.log(userBloc.state.name);
|
|
15
|
+
* });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
function instance(BlocClass, args) {
|
|
19
|
+
return {
|
|
20
|
+
[BLOC_REF_MARKER]: true,
|
|
21
|
+
blocClass: BlocClass,
|
|
22
|
+
instanceId: require_acquire.resolveInstanceKey(BlocClass, args)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function isBlocRef(input) {
|
|
26
|
+
return typeof input === "object" && input !== null && BLOC_REF_MARKER in input;
|
|
27
|
+
}
|
|
28
|
+
function resolveBloc(input) {
|
|
29
|
+
const registry = require_config.getRegistry();
|
|
30
|
+
if (isBlocRef(input)) return registry.ensure(input.blocClass, input.instanceId);
|
|
31
|
+
return registry.ensure(input, registry.resolveKey(input, void 0, void 0));
|
|
32
|
+
}
|
|
33
|
+
function isArray(input) {
|
|
34
|
+
return Array.isArray(input);
|
|
35
|
+
}
|
|
36
|
+
function watchImpl(blocsOrBloc, callback) {
|
|
37
|
+
const isSingle = !isArray(blocsOrBloc);
|
|
38
|
+
const instances = (isSingle ? [blocsOrBloc] : blocsOrBloc).map(resolveBloc);
|
|
39
|
+
let disposed = false;
|
|
40
|
+
const subscriptions = [];
|
|
41
|
+
const cleanup = () => {
|
|
42
|
+
if (disposed) return;
|
|
43
|
+
disposed = true;
|
|
44
|
+
for (const unsub of subscriptions) unsub();
|
|
45
|
+
subscriptions.length = 0;
|
|
46
|
+
};
|
|
47
|
+
const runCallback = () => {
|
|
48
|
+
if (disposed) return;
|
|
49
|
+
if (callback(isSingle ? instances[0] : instances) === STOP) cleanup();
|
|
50
|
+
};
|
|
51
|
+
for (const inst of instances) subscriptions.push(inst.channel.subscribe(() => _dirtytalk_structural.ALL_PATHS, runCallback));
|
|
52
|
+
runCallback();
|
|
53
|
+
return cleanup;
|
|
54
|
+
}
|
|
55
|
+
const watch = Object.assign(watchImpl, { STOP });
|
|
56
|
+
//#endregion
|
|
57
|
+
Object.defineProperty(exports, "instance", {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
get: function() {
|
|
60
|
+
return instance;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(exports, "watch", {
|
|
64
|
+
enumerable: true,
|
|
65
|
+
get: function() {
|
|
66
|
+
return watch;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=watch-DVmvZBMD.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch-DVmvZBMD.cjs","names":["resolveInstanceKey","getRegistry","ALL_PATHS"],"sources":["../src/watch/watch.ts"],"sourcesContent":["import { ALL_PATHS } from '@dirtytalk/structural';\nimport { getRegistry } from '../registry';\nimport { resolveInstanceKey } from '../registry/acquire';\nimport type {\n ExtractArgs,\n StateContainerConstructor,\n StateContainerInstance,\n} from '../types/utilities';\n\nconst STOP: unique symbol = Symbol('watch.STOP');\ntype StopSymbol = typeof STOP;\n\nconst BLOC_REF_MARKER = Symbol('BlocRef');\n\n/**\n * Reference to a specific bloc instance, identified by class + the resolved\n * key derived from its `args`.\n */\nexport interface BlocRef<T extends StateContainerConstructor> {\n [BLOC_REF_MARKER]: true;\n blocClass: T;\n /** @internal The resolved instance key (derived from `args`). */\n instanceId: string;\n}\n\n/**\n * Create a reference to a specific bloc instance, identified by its `args`.\n * The key is derived the same way `useBloc`/`acquire` derive it.\n *\n * @example\n * ```ts\n * watch(instance(UserBloc, { userId: 'user-123' }), (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n */\nexport function instance<T extends StateContainerConstructor>(\n BlocClass: T,\n args?: ExtractArgs<T>,\n): BlocRef<T> {\n return {\n [BLOC_REF_MARKER]: true,\n blocClass: BlocClass,\n instanceId: resolveInstanceKey(BlocClass, args),\n };\n}\n\nfunction isBlocRef(\n input: unknown,\n): input is BlocRef<StateContainerConstructor> {\n return (\n typeof input === 'object' && input !== null && BLOC_REF_MARKER in input\n );\n}\n\ntype BlocInput = StateContainerConstructor | BlocRef<StateContainerConstructor>;\n\ntype ExtractInstance<T> =\n T extends BlocRef<infer C>\n ? InstanceType<C>\n : T extends StateContainerConstructor\n ? InstanceType<T>\n : never;\n\ntype ExtractInstances<T extends readonly BlocInput[]> = {\n [K in keyof T]: ExtractInstance<T[K]>;\n};\n\n/**\n * Watch function signature for single bloc.\n */\nexport interface WatchSingleFn {\n <T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Watch function signature for multiple blocs.\n */\nexport interface WatchMultipleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n\n STOP: StopSymbol;\n}\n\n/**\n * Combined watch function type.\n */\nexport interface WatchFn extends WatchSingleFn {\n <T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n ): () => void;\n}\n\nfunction resolveBloc(input: BlocInput): StateContainerInstance {\n const registry = getRegistry();\n if (isBlocRef(input)) {\n return registry.ensure(input.blocClass, input.instanceId);\n }\n return registry.ensure(\n input,\n registry.resolveKey(input, undefined, undefined),\n );\n}\n\nfunction isArray(input: unknown): input is readonly BlocInput[] {\n return Array.isArray(input);\n}\n\n/**\n * Watch one or more blocs for state changes.\n *\n * Thin wrapper around `container.channel.subscribe(ALL_PATHS, ...)`. The\n * callback fires once immediately, then on every state change of any of the\n * passed blocs. Returning `watch.STOP` from the callback tears down all\n * subscriptions.\n *\n * Note: subscriptions are microtask-deferred (per the DirtyChannel default\n * scheduler), so callbacks land asynchronously after `emit()`.\n *\n * @example Single bloc\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * console.log(userBloc.state.name);\n * });\n * ```\n *\n * @example Multiple blocs\n * ```ts\n * const unwatch = watch(\n * [UserBloc, SettingsBloc] as const,\n * ([userBloc, settingsBloc]) => {\n * console.log(userBloc.state.name, settingsBloc.state.theme);\n * }\n * );\n * ```\n *\n * @example With specific instance\n * ```ts\n * const unwatch = watch(\n * instance(UserBloc, { userId: 'user-123' }),\n * (userBloc) => {\n * console.log(userBloc.state.name);\n * }\n * );\n * ```\n *\n * @example Stop watching from callback\n * ```ts\n * const unwatch = watch(UserBloc, (userBloc) => {\n * if (userBloc.state.done) {\n * return watch.STOP;\n * }\n * });\n * ```\n */\nfunction watchImpl<T extends StateContainerConstructor>(\n bloc: T | BlocRef<T>,\n callback: (bloc: InstanceType<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl<T extends readonly BlocInput[]>(\n blocs: T,\n callback: (blocs: ExtractInstances<T>) => void | StopSymbol,\n): () => void;\n\nfunction watchImpl(\n blocsOrBloc: BlocInput | readonly BlocInput[],\n callback: (blocsOrBloc: any) => void | StopSymbol,\n): () => void {\n const isSingle = !isArray(blocsOrBloc);\n const inputs = isSingle ? [blocsOrBloc] : blocsOrBloc;\n\n const instances = inputs.map(resolveBloc);\n\n let disposed = false;\n const subscriptions: (() => void)[] = [];\n\n const cleanup = () => {\n if (disposed) return;\n disposed = true;\n for (const unsub of subscriptions) unsub();\n subscriptions.length = 0;\n };\n\n const runCallback = () => {\n if (disposed) return;\n const arg = isSingle ? instances[0] : instances;\n const result = callback(arg);\n if (result === STOP) cleanup();\n };\n\n for (const inst of instances) {\n subscriptions.push(inst.channel.subscribe(() => ALL_PATHS, runCallback));\n }\n\n // Fire once immediately so the consumer sees the current state.\n runCallback();\n\n return cleanup;\n}\n\nexport const watch: WatchFn = Object.assign(watchImpl, { STOP }) as WatchFn;\n"],"mappings":";;;;AASA,MAAM,OAAsB,OAAO,YAAY;AAG/C,MAAM,kBAAkB,OAAO,SAAS;;;;;;;;;;;;AAwBxC,SAAgB,SACd,WACA,MACY;CACZ,OAAO;GACJ,kBAAkB;EACnB,WAAW;EACX,YAAYA,gBAAAA,mBAAmB,WAAW,IAAI;CAChD;AACF;AAEA,SAAS,UACP,OAC6C;CAC7C,OACE,OAAO,UAAU,YAAY,UAAU,QAAQ,mBAAmB;AAEtE;AAiDA,SAAS,YAAY,OAA0C;CAC7D,MAAM,WAAWC,eAAAA,YAAY;CAC7B,IAAI,UAAU,KAAK,GACjB,OAAO,SAAS,OAAO,MAAM,WAAW,MAAM,UAAU;CAE1D,OAAO,SAAS,OACd,OACA,SAAS,WAAW,OAAO,KAAA,GAAW,KAAA,CAAS,CACjD;AACF;AAEA,SAAS,QAAQ,OAA+C;CAC9D,OAAO,MAAM,QAAQ,KAAK;AAC5B;AA2DA,SAAS,UACP,aACA,UACY;CACZ,MAAM,WAAW,CAAC,QAAQ,WAAW;CAGrC,MAAM,aAFS,WAAW,CAAC,WAAW,IAAI,aAEjB,IAAI,WAAW;CAExC,IAAI,WAAW;CACf,MAAM,gBAAgC,CAAC;CAEvC,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,KAAK,MAAM,SAAS,eAAe,MAAM;EACzC,cAAc,SAAS;CACzB;CAEA,MAAM,oBAAoB;EACxB,IAAI,UAAU;EAGd,IADe,SADH,WAAW,UAAU,KAAK,SAE7B,MAAM,MAAM,QAAQ;CAC/B;CAEA,KAAK,MAAM,QAAQ,WACjB,cAAc,KAAK,KAAK,QAAQ,gBAAgBC,sBAAAA,WAAW,WAAW,CAAC;CAIzE,YAAY;CAEZ,OAAO;AACT;AAEA,MAAa,QAAiB,OAAO,OAAO,WAAW,EAAE,KAAK,CAAC"}
|
package/dist/watch-entry.cjs
CHANGED
package/dist/watch-entry.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as watch, t as instance } from "./watch-
|
|
1
|
+
import { n as watch, t as instance } from "./watch-D8hwbFU1.js";
|
|
2
2
|
export { instance, watch };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blac/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Brendan Mullins <jsnanigans@gmail.com>",
|
|
6
6
|
"description": "Type-safe, class-based state management with proxy tracking and plugin system",
|
|
@@ -118,11 +118,11 @@
|
|
|
118
118
|
{
|
|
119
119
|
"name": "@blac/core (ESM, brotli)",
|
|
120
120
|
"path": "dist/index.js",
|
|
121
|
-
"limit": "8 kB"
|
|
121
|
+
"limit": "7.8 kB"
|
|
122
122
|
}
|
|
123
123
|
],
|
|
124
124
|
"dependencies": {
|
|
125
|
-
"@dirtytalk/structural": "^0.0.
|
|
125
|
+
"@dirtytalk/structural": "^0.0.6"
|
|
126
126
|
},
|
|
127
127
|
"devDependencies": {
|
|
128
128
|
"@size-limit/preset-small-lib": "^11.1.6",
|