@expressive/mvc 0.84.3 → 0.86.0
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 +3 -3
- package/dist/caught.d.ts +5237 -0
- package/dist/caught.js +64 -0
- package/dist/caught.js.map +1 -0
- package/dist/context.d.ts +6 -1
- package/dist/context.js +16 -2
- package/dist/context.js.map +1 -1
- package/dist/dispatch.d.ts +32 -3
- package/dist/dispatch.js +95 -26
- package/dist/dispatch.js.map +1 -1
- package/dist/field/def.js +1 -1
- package/dist/field/get.js +1 -1
- package/dist/field/has.d.ts +11 -3
- package/dist/field/has.js +1 -1
- package/dist/field/has.js.map +1 -1
- package/dist/field/map.js +1 -1
- package/dist/field/ref.js +1 -1
- package/dist/field/set.js +5 -2
- package/dist/field/set.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -0
- package/dist/observable.d.ts +4 -4
- package/dist/observable.js +56 -29
- package/dist/observable.js.map +1 -1
- package/dist/runtime.d.ts +4 -13
- package/dist/runtime.js +4 -15
- package/dist/runtime.js.map +1 -1
- package/dist/state.d.ts +14 -3
- package/dist/state.js +62 -20
- package/dist/state.js.map +1 -1
- package/package.json +1 -1
package/dist/caught.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/caught.ts
|
|
2
|
+
const about = (cause) => {
|
|
3
|
+
const text = cause instanceof Error ? cause.message : String(cause);
|
|
4
|
+
return text ? `: ${text}` : ".";
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Reported to `State.on({ catch })` handlers instead of being thrown or logged.
|
|
8
|
+
* Unhandled, a `warning` goes to `console.warn`; anything else escapes uncaught.
|
|
9
|
+
*/
|
|
10
|
+
var Caught = class Caught extends Error {
|
|
11
|
+
name = "Caught";
|
|
12
|
+
/** Non-urgent - unhandled, it logs as a warning. */
|
|
13
|
+
warning = false;
|
|
14
|
+
constructor(state, message, key, cause) {
|
|
15
|
+
super(message, arguments.length > 3 ? { cause } : void 0);
|
|
16
|
+
this.key = key;
|
|
17
|
+
Object.defineProperty(this, "state", { value: state });
|
|
18
|
+
}
|
|
19
|
+
/** A `catch` handler logging what would otherwise escape uncaught; warnings and destroyed writes pass on. */
|
|
20
|
+
static log(error) {
|
|
21
|
+
if (error.warning || error instanceof Caught.Destroyed) return error;
|
|
22
|
+
console.error(error);
|
|
23
|
+
}
|
|
24
|
+
/** A write to a destroyed state - thrown to the writer unless a handler takes it. */
|
|
25
|
+
static Destroyed = class Destroyed extends Caught {
|
|
26
|
+
name = "Caught.Destroyed";
|
|
27
|
+
constructor(state, key) {
|
|
28
|
+
super(state, `Tried to update ${state}.${key} but state is destroyed.`, key);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
/** A state constructed but never activated. */
|
|
32
|
+
static Inactive = class Inactive extends Caught {
|
|
33
|
+
name = "Caught.Inactive";
|
|
34
|
+
warning = true;
|
|
35
|
+
constructor(state) {
|
|
36
|
+
super(state, `${state} was constructed but never activated.`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
/** A getter threw while refreshing; `cause` is what it threw. */
|
|
40
|
+
static Getter = class Getter extends Caught {
|
|
41
|
+
name = "Caught.Getter";
|
|
42
|
+
constructor(state, key, cause) {
|
|
43
|
+
super(state, `An exception was thrown while refreshing ${state.constructor}.${key}${about(cause)}`, key, cause);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
/** An async initializer rejected; `cause` is the rejection. */
|
|
47
|
+
static Init = class Init extends Caught {
|
|
48
|
+
name = "Caught.Init";
|
|
49
|
+
constructor(state, cause) {
|
|
50
|
+
super(state, `Async error in constructor for ${state.constructor}${about(cause)}`, void 0, cause);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
/** An effect or listener threw during a dispatch flush; `cause` is what it threw. */
|
|
54
|
+
static Effect = class Effect extends Caught {
|
|
55
|
+
name = "Caught.Effect";
|
|
56
|
+
constructor(state, cause) {
|
|
57
|
+
super(state, `An exception was thrown by an effect of ${state.constructor}${about(cause)}`, void 0, cause);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
export { Caught };
|
|
64
|
+
//# sourceMappingURL=caught.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caught.js","names":[],"sources":["../src/caught.ts"],"sourcesContent":["import type { State } from './state';\n\nconst about = (cause: unknown) => {\n const text = cause instanceof Error ? cause.message : String(cause);\n return text ? `: ${text}` : '.';\n};\n\n/**\n * Reported to `State.on({ catch })` handlers instead of being thrown or logged.\n * Unhandled, a `warning` goes to `console.warn`; anything else escapes uncaught.\n */\nclass Caught extends Error {\n readonly name: string = 'Caught';\n\n /** Non-urgent - unhandled, it logs as a warning. */\n readonly warning: boolean = false;\n\n declare readonly state: State;\n\n constructor(\n state: State,\n message: string,\n readonly key?: string,\n cause?: unknown\n ) {\n super(message, arguments.length > 3 ? { cause } : undefined);\n Object.defineProperty(this, 'state', { value: state });\n }\n\n /** A `catch` handler logging what would otherwise escape uncaught; warnings and destroyed writes pass on. */\n static log(error: Caught): Caught | void {\n if (error.warning || error instanceof Caught.Destroyed) return error;\n console.error(error);\n }\n\n /** A write to a destroyed state - thrown to the writer unless a handler takes it. */\n static Destroyed = class Destroyed extends Caught {\n readonly name = 'Caught.Destroyed';\n\n constructor(state: State, key: string) {\n super(state, `Tried to update ${state}.${key} but state is destroyed.`, key);\n }\n };\n\n /** A state constructed but never activated. */\n static Inactive = class Inactive extends Caught {\n readonly name = 'Caught.Inactive';\n readonly warning = true;\n\n constructor(state: State) {\n super(state, `${state} was constructed but never activated.`);\n }\n };\n\n /** A getter threw while refreshing; `cause` is what it threw. */\n static Getter = class Getter extends Caught {\n readonly name = 'Caught.Getter';\n\n constructor(state: State, key: string, cause: unknown) {\n super(state, `An exception was thrown while refreshing ${state.constructor}.${key}${about(cause)}`, key, cause);\n }\n };\n\n /** An async initializer rejected; `cause` is the rejection. */\n static Init = class Init extends Caught {\n readonly name = 'Caught.Init';\n\n constructor(state: State, cause: unknown) {\n super(state, `Async error in constructor for ${state.constructor}${about(cause)}`, undefined, cause);\n }\n };\n\n /** An effect or listener threw during a dispatch flush; `cause` is what it threw. */\n static Effect = class Effect extends Caught {\n readonly name = 'Caught.Effect';\n\n constructor(state: State, cause: unknown) {\n super(state, `An exception was thrown by an effect of ${state.constructor}${about(cause)}`, undefined, cause);\n }\n };\n}\n\ndeclare namespace Caught {\n type Destroyed = InstanceType<typeof Caught.Destroyed>;\n type Inactive = InstanceType<typeof Caught.Inactive>;\n type Getter = InstanceType<typeof Caught.Getter>;\n type Init = InstanceType<typeof Caught.Init>;\n type Effect = InstanceType<typeof Caught.Effect>;\n}\n\nexport { Caught };\n"],"mappings":";AAEA,MAAM,SAAS,UAAmB;CAChC,MAAM,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACnE,QAAO,OAAO,KAAK,SAAS;;;;;;AAO9B,IAAM,SAAN,MAAM,eAAe,MAAM;CACzB,AAAS,OAAe;;CAGxB,AAAS,UAAmB;CAI5B,YACE,OACA,SACA,AAAS,KACT,OACA;AACA,QAAM,SAAS,UAAU,SAAS,IAAI,EAAE,OAAO,GAAG,OAAU;EAHnD;AAIT,SAAO,eAAe,MAAM,SAAS,EAAE,OAAO,OAAO,CAAC;;;CAIxD,OAAO,IAAI,OAA8B;AACvC,MAAI,MAAM,WAAW,iBAAiB,OAAO,UAAW,QAAO;AAC/D,UAAQ,MAAM,MAAM;;;CAItB,OAAO,YAAY,MAAM,kBAAkB,OAAO;EAChD,AAAS,OAAO;EAEhB,YAAY,OAAc,KAAa;AACrC,SAAM,OAAO,mBAAmB,MAAM,GAAG,IAAI,2BAA2B,IAAI;;;;CAKhF,OAAO,WAAW,MAAM,iBAAiB,OAAO;EAC9C,AAAS,OAAO;EAChB,AAAS,UAAU;EAEnB,YAAY,OAAc;AACxB,SAAM,OAAO,GAAG,MAAM,uCAAuC;;;;CAKjE,OAAO,SAAS,MAAM,eAAe,OAAO;EAC1C,AAAS,OAAO;EAEhB,YAAY,OAAc,KAAa,OAAgB;AACrD,SAAM,OAAO,4CAA4C,MAAM,YAAY,GAAG,MAAM,MAAM,MAAM,IAAI,KAAK,MAAM;;;;CAKnH,OAAO,OAAO,MAAM,aAAa,OAAO;EACtC,AAAS,OAAO;EAEhB,YAAY,OAAc,OAAgB;AACxC,SAAM,OAAO,kCAAkC,MAAM,cAAc,MAAM,MAAM,IAAI,QAAW,MAAM;;;;CAKxG,OAAO,SAAS,MAAM,eAAe,OAAO;EAC1C,AAAS,OAAO;EAEhB,YAAY,OAAc,OAAgB;AACxC,SAAM,OAAO,2CAA2C,MAAM,cAAc,MAAM,MAAM,IAAI,QAAW,MAAM"}
|
package/dist/context.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ declare class Context {
|
|
|
54
54
|
*/
|
|
55
55
|
pop(): void;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Add `value` to the context `state` was added to. A context-less `state` holds
|
|
59
|
+
* it instead - every context adding `state` later adds its held children too.
|
|
60
|
+
*/
|
|
61
|
+
declare function join(state: State, value: State): () => void;
|
|
57
62
|
//#endregion
|
|
58
|
-
export { Context };
|
|
63
|
+
export { Context, join };
|
|
59
64
|
//# sourceMappingURL=context.d.ts.map
|
package/dist/context.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { event, listener } from "./observable.js";
|
|
2
1
|
import { State, uid } from "./state.js";
|
|
2
|
+
import { event, listener } from "./observable.js";
|
|
3
3
|
|
|
4
4
|
//#region src/context.ts
|
|
5
5
|
const LOOKUP = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
const HELD = /* @__PURE__ */ new WeakMap();
|
|
6
7
|
let ROOT;
|
|
7
8
|
var Context = class Context {
|
|
8
9
|
static get root() {
|
|
@@ -170,8 +171,10 @@ var Context = class Context {
|
|
|
170
171
|
onDone.forEach((r) => r());
|
|
171
172
|
onDone.clear();
|
|
172
173
|
}
|
|
174
|
+
const held = Array.from(HELD.get(I) || [], (child) => this.add(child));
|
|
173
175
|
function remove() {
|
|
174
176
|
cleanup.delete(remove);
|
|
177
|
+
held.forEach((done) => done());
|
|
175
178
|
flush();
|
|
176
179
|
}
|
|
177
180
|
cleanup.set(remove, remove);
|
|
@@ -206,7 +209,18 @@ var Context = class Context {
|
|
|
206
209
|
Object.defineProperty(Context.prototype, "toString", { value() {
|
|
207
210
|
return `Context-${this.id}`;
|
|
208
211
|
} });
|
|
212
|
+
/**
|
|
213
|
+
* Add `value` to the context `state` was added to. A context-less `state` holds
|
|
214
|
+
* it instead - every context adding `state` later adds its held children too.
|
|
215
|
+
*/
|
|
216
|
+
function join(state, value) {
|
|
217
|
+
const ctx = LOOKUP.get(state.is);
|
|
218
|
+
if (ctx) return ctx.add(value);
|
|
219
|
+
const held = HELD.get(state) || /* @__PURE__ */ new Set();
|
|
220
|
+
HELD.set(state, held.add(value));
|
|
221
|
+
return () => held.delete(value);
|
|
222
|
+
}
|
|
209
223
|
|
|
210
224
|
//#endregion
|
|
211
|
-
export { Context };
|
|
225
|
+
export { Context, join };
|
|
212
226
|
//# sourceMappingURL=context.js.map
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import { listener } from \"./observable\";\nimport { event, State, uid } from \"./state\";\n\nconst LOOKUP = new WeakMap<State, Context>();\nlet ROOT: Context;\n\ntype Accept<T extends State = State> =\n | T\n | State.Type<T>\n | Record<string | number, T | State.Type<T>>;\n\ntype Expect<T extends State = State> = (\n state: T,\n downstream: boolean,\n) => (() => void) | void;\n\ndeclare namespace Context {\n export { Accept, Expect };\n}\n\nclass Context {\n static get root(): Context {\n return ROOT ??= new Context();\n }\n\n /** Get the context for a State. Adapters may override to provide framework context. */\n static get(state?: State): Context {\n return state && LOOKUP.get(state.is) || Context.root;\n }\n\n public id = uid();\n public parent?: Context;\n public scope = new Set<Context>();\n public consume = new Map<\n State.Extends,\n Set<[Expect, boolean | undefined]> | null\n >();\n public provide = new Map<State.Extends, Set<[State, boolean]> | null>();\n\n protected inputs: Record<string | number, State | State.Extends> = {};\n\n private cleanup = new Map<string | number | Function, () => void>();\n\n constructor(arg?: Context | Accept) {\n if (arg instanceof Context) {\n this.parent = arg;\n arg.scope.add(this);\n } else if (arg) {\n this.set(arg);\n }\n }\n\n private traverse(accept: (ctx: Context) => boolean | void) {\n const queue = [...this.scope];\n for (const ctx of queue)\n if (accept(ctx) !== false) for (const c of ctx.scope) queue.push(c);\n }\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [Expect<T>, boolean | undefined],\n asConsumer: true,\n ): () => void;\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [T, boolean],\n asConsumer?: false,\n ): () => void;\n\n private register(type: State.Extends, value: any, asConsumer?: boolean) {\n const mode = asConsumer ? \"consume\" : \"provide\";\n let set = this[mode].get(type) as Set<any>;\n if (!set) this[mode].set(type, (set = new Set()));\n set.add(value);\n\n for (let ctx = this.parent; ctx; ctx = ctx.parent) {\n if (ctx[mode].has(type)) break;\n ctx[mode].set(type, null);\n }\n\n return () => set.delete(value);\n }\n\n /** Find specified type upstream. Throws if not found. */\n public get<T extends State>(Type: State.Extends<T>, required?: true): T;\n\n /** Find specified type upstream. Returns undefined if not found. */\n public get<T extends State>(\n Type: State.Extends<T>,\n required?: boolean,\n ): T | undefined;\n\n /** Subscribe to a type becoming available in context. */\n public get<T extends State>(\n Type: State.Extends<T>,\n callback: Expect<T>,\n downstream?: boolean,\n ): () => void;\n\n /** Lookup excluding a specific instance (used by State.prototype.get for upstream-of-self semantics). */\n public get<T extends State>(\n Type: State.Extends<T>,\n arg: boolean | Expect<T> | undefined,\n downstream: boolean | undefined,\n skip: State,\n ): T | undefined | (() => void);\n\n public get<T extends State>(\n Type: State.Extends<T>,\n arg?: boolean | Expect<T>,\n downstream?: boolean,\n skip?: State,\n ) {\n let found: T | null | undefined;\n let priority = false;\n\n for (let ctx: Context | undefined = this; ctx; ctx = ctx.parent) {\n const entries = ctx.provide.get(Type);\n if (!entries) continue;\n\n for (const [state, explicit] of entries) {\n if (state === skip || found === state) continue;\n if (!found || (explicit && !priority)) {\n found = state as T;\n priority = explicit;\n continue;\n }\n if (!priority) {\n found = null;\n break;\n }\n if (explicit)\n throw new Error(\n `Did find ${Type} in context, but multiple were defined.`,\n );\n }\n if (found !== undefined) break;\n }\n\n if (typeof arg === \"function\") {\n if (found && !downstream) arg(found, false);\n\n if (downstream !== false) {\n this.traverse((ctx) => {\n const has = ctx.provide.get(Type);\n if (has) for (const x of has) if (x[0] !== skip) arg(x[0] as T, true);\n return has !== undefined;\n });\n }\n\n return this.register(Type, [arg as Expect, downstream], true);\n }\n\n if (found) return found;\n if (found === null) return null;\n if (arg !== false) throw new Error(`Could not find ${Type} in context.`);\n }\n\n /**\n * Register one or more States to this context.\n *\n * Context will add or remove States as needed to keep with provided input.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n * @param forEach Optional callback to run for each State registered. Receives\n * whether this context created the State - and so will destroy it - as\n * opposed to it having been provided already active. May return a callback\n * to run before that entry is dropped.\n */\n public set<T extends State>(\n inputs: Accept<T>,\n forEach?: (state: T, owned: boolean) => (() => void) | void,\n ) {\n const init = new Set<() => void>();\n const { cleanup } = this;\n\n if (typeof inputs == \"function\" || inputs instanceof State)\n inputs = { [0]: inputs };\n\n for (const K of Object.keys({ ...this.inputs, ...inputs })) {\n const V = inputs[K];\n const E = this.inputs[K];\n\n if (E === V) continue;\n\n if (E) {\n cleanup.get(K)?.();\n cleanup.delete(K);\n }\n\n if (!V) continue;\n\n // a class is constructed here - and so destroyed here; an instance is\n // adopted as-is and outlives this context\n const owned = State.is(V);\n\n if (!(owned || V instanceof State)) {\n const as = K == \"0\" || K == String(V) ? V : `${V} (as '${K}')`;\n throw new Error(\n `Context can only include an instance or class of State but got ${as}.`,\n );\n }\n\n const state = owned ? new (V as State.Type)() : V.is;\n const remove = this.add(state, true);\n\n init.add(() => {\n event(state);\n const dispose = forEach?.(state as T, owned);\n cleanup.set(K, () => {\n if (typeof dispose == \"function\") dispose();\n remove();\n if (owned) event(state, null);\n });\n });\n }\n\n for (const i of init) i();\n\n this.inputs = inputs;\n\n return this;\n }\n\n add(I: State, explicit = false) {\n const { cleanup, provide } = this;\n const root = this === Context.root;\n const TT: State.Extends[] = [];\n\n function conflict(T: State.Extends) {\n const entries = provide.get(T);\n if (entries)\n for (const entry of entries)\n if (!entry[1] && entry[0] !== I) {\n const type = I.constructor as State.Extends;\n const g = type.global;\n\n if (entry[0].constructor === type && (typeof g == 'function' ? g(I) : g))\n throw new Error(\n `Cannot register ${I} as a global - ${entry[0]} already exists in root. Destroy the existing instance first, or provide additional ones via explicit context.`\n );\n\n return entries.delete(entry);\n }\n }\n\n for (\n let T = I.constructor as State.Extends;\n T !== State;\n T = Object.getPrototypeOf(T)\n )\n if (explicit || !root || !conflict(T)) TT.push(T);\n\n const expects = new Map<Expect, () => void>();\n const onDone = new Set<() => void>();\n\n for (const T of TT) onDone.add(this.register(T, [I, explicit]));\n\n function queue(ctx: Context, downstream: boolean, same?: boolean) {\n let found = false;\n for (const T of TT) {\n const list = ctx.consume.get(T);\n if (list !== undefined) found = true;\n if (list)\n for (const [cb, filter] of list)\n if (same || filter == null || filter === downstream)\n expects.set(cb, () => {\n const r = cb(I, filter ?? downstream);\n if (r) onDone.add(r);\n });\n }\n return found;\n }\n\n queue(this, true, true);\n for (let ctx = this.parent; ctx; ctx = ctx.parent) queue(ctx, true);\n this.traverse((ctx) => queue(ctx, false));\n\n if (!LOOKUP.has(I)) LOOKUP.set(I, this);\n\n listener(I, () => {\n expects.forEach((f) => f());\n expects.clear();\n return null;\n });\n\n function flush() {\n onDone.forEach((r) => r());\n onDone.clear();\n }\n\n function remove() {\n cleanup.delete(remove);\n flush();\n }\n\n cleanup.set(remove, remove);\n\n return remove;\n }\n\n /**\n * Create a child context, optionally registering one or more States to it.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n */\n public push(inputs?: Accept) {\n const next = new Context(this);\n if (inputs) next.set(inputs);\n return next;\n }\n\n /**\n * Remove all States from this context.\n *\n * Will also run any cleanup callbacks registered when States were added.\n */\n public pop() {\n this.inputs = {};\n this.scope.forEach((x) => x.pop());\n this.scope.clear();\n this.cleanup.forEach((cb) => cb());\n this.cleanup.clear();\n this.consume.clear();\n this.provide.clear();\n if (this.parent) {\n this.parent.scope.delete(this);\n }\n }\n}\n\nObject.defineProperty(Context.prototype, \"toString\", {\n value() {\n return `Context-${this.id}`;\n },\n});\n\nexport { Context };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import { listener } from \"./observable\";\nimport { event, State, uid } from \"./state\";\n\nconst LOOKUP = new WeakMap<State, Context>();\nconst HELD = new WeakMap<State, Set<State>>();\nlet ROOT: Context;\n\ntype Accept<T extends State = State> =\n | T\n | State.Type<T>\n | Record<string | number, T | State.Type<T>>;\n\ntype Expect<T extends State = State> = (\n state: T,\n downstream: boolean,\n) => (() => void) | void;\n\ndeclare namespace Context {\n export { Accept, Expect };\n}\n\nclass Context {\n static get root(): Context {\n return ROOT ??= new Context();\n }\n\n /** Get the context for a State. Adapters may override to provide framework context. */\n static get(state?: State): Context {\n return state && LOOKUP.get(state.is) || Context.root;\n }\n\n public id = uid();\n public parent?: Context;\n public scope = new Set<Context>();\n public consume = new Map<\n State.Extends,\n Set<[Expect, boolean | undefined]> | null\n >();\n public provide = new Map<State.Extends, Set<[State, boolean]> | null>();\n\n protected inputs: Record<string | number, State | State.Extends> = {};\n\n private cleanup = new Map<string | number | Function, () => void>();\n\n constructor(arg?: Context | Accept) {\n if (arg instanceof Context) {\n this.parent = arg;\n arg.scope.add(this);\n } else if (arg) {\n this.set(arg);\n }\n }\n\n private traverse(accept: (ctx: Context) => boolean | void) {\n const queue = [...this.scope];\n for (const ctx of queue)\n if (accept(ctx) !== false) for (const c of ctx.scope) queue.push(c);\n }\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [Expect<T>, boolean | undefined],\n asConsumer: true,\n ): () => void;\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [T, boolean],\n asConsumer?: false,\n ): () => void;\n\n private register(type: State.Extends, value: any, asConsumer?: boolean) {\n const mode = asConsumer ? \"consume\" : \"provide\";\n let set = this[mode].get(type) as Set<any>;\n if (!set) this[mode].set(type, (set = new Set()));\n set.add(value);\n\n for (let ctx = this.parent; ctx; ctx = ctx.parent) {\n if (ctx[mode].has(type)) break;\n ctx[mode].set(type, null);\n }\n\n return () => set.delete(value);\n }\n\n /** Find specified type upstream. Throws if not found. */\n public get<T extends State>(Type: State.Extends<T>, required?: true): T;\n\n /** Find specified type upstream. Returns undefined if not found. */\n public get<T extends State>(\n Type: State.Extends<T>,\n required?: boolean,\n ): T | undefined;\n\n /** Subscribe to a type becoming available in context. */\n public get<T extends State>(\n Type: State.Extends<T>,\n callback: Expect<T>,\n downstream?: boolean,\n ): () => void;\n\n /** Lookup excluding a specific instance (used by State.prototype.get for upstream-of-self semantics). */\n public get<T extends State>(\n Type: State.Extends<T>,\n arg: boolean | Expect<T> | undefined,\n downstream: boolean | undefined,\n skip: State,\n ): T | undefined | (() => void);\n\n public get<T extends State>(\n Type: State.Extends<T>,\n arg?: boolean | Expect<T>,\n downstream?: boolean,\n skip?: State,\n ) {\n let found: T | null | undefined;\n let priority = false;\n\n for (let ctx: Context | undefined = this; ctx; ctx = ctx.parent) {\n const entries = ctx.provide.get(Type);\n if (!entries) continue;\n\n for (const [state, explicit] of entries) {\n if (state === skip || found === state) continue;\n if (!found || (explicit && !priority)) {\n found = state as T;\n priority = explicit;\n continue;\n }\n if (!priority) {\n found = null;\n break;\n }\n if (explicit)\n throw new Error(\n `Did find ${Type} in context, but multiple were defined.`,\n );\n }\n if (found !== undefined) break;\n }\n\n if (typeof arg === \"function\") {\n if (found && !downstream) arg(found, false);\n\n if (downstream !== false) {\n this.traverse((ctx) => {\n const has = ctx.provide.get(Type);\n if (has) for (const x of has) if (x[0] !== skip) arg(x[0] as T, true);\n return has !== undefined;\n });\n }\n\n return this.register(Type, [arg as Expect, downstream], true);\n }\n\n if (found) return found;\n if (found === null) return null;\n if (arg !== false) throw new Error(`Could not find ${Type} in context.`);\n }\n\n /**\n * Register one or more States to this context.\n *\n * Context will add or remove States as needed to keep with provided input.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n * @param forEach Optional callback to run for each State registered. Receives\n * whether this context created the State - and so will destroy it - as\n * opposed to it having been provided already active. May return a callback\n * to run before that entry is dropped.\n */\n public set<T extends State>(\n inputs: Accept<T>,\n forEach?: (state: T, owned: boolean) => (() => void) | void,\n ) {\n const init = new Set<() => void>();\n const { cleanup } = this;\n\n if (typeof inputs == \"function\" || inputs instanceof State)\n inputs = { [0]: inputs };\n\n for (const K of Object.keys({ ...this.inputs, ...inputs })) {\n const V = inputs[K];\n const E = this.inputs[K];\n\n if (E === V) continue;\n\n if (E) {\n cleanup.get(K)?.();\n cleanup.delete(K);\n }\n\n if (!V) continue;\n\n // a class is constructed here - and so destroyed here; an instance is\n // adopted as-is and outlives this context\n const owned = State.is(V);\n\n if (!(owned || V instanceof State)) {\n const as = K == \"0\" || K == String(V) ? V : `${V} (as '${K}')`;\n throw new Error(\n `Context can only include an instance or class of State but got ${as}.`,\n );\n }\n\n const state = owned ? new (V as State.Type)() : V.is;\n const remove = this.add(state, true);\n\n init.add(() => {\n event(state);\n const dispose = forEach?.(state as T, owned);\n cleanup.set(K, () => {\n if (typeof dispose == \"function\") dispose();\n remove();\n if (owned) event(state, null);\n });\n });\n }\n\n for (const i of init) i();\n\n this.inputs = inputs;\n\n return this;\n }\n\n add(I: State, explicit = false) {\n const { cleanup, provide } = this;\n const root = this === Context.root;\n const TT: State.Extends[] = [];\n\n function conflict(T: State.Extends) {\n const entries = provide.get(T);\n if (entries)\n for (const entry of entries)\n if (!entry[1] && entry[0] !== I) {\n const type = I.constructor as State.Extends;\n const g = type.global;\n\n if (entry[0].constructor === type && (typeof g == 'function' ? g(I) : g))\n throw new Error(\n `Cannot register ${I} as a global - ${entry[0]} already exists in root. Destroy the existing instance first, or provide additional ones via explicit context.`\n );\n\n return entries.delete(entry);\n }\n }\n\n for (\n let T = I.constructor as State.Extends;\n T !== State;\n T = Object.getPrototypeOf(T)\n )\n if (explicit || !root || !conflict(T)) TT.push(T);\n\n const expects = new Map<Expect, () => void>();\n const onDone = new Set<() => void>();\n\n for (const T of TT) onDone.add(this.register(T, [I, explicit]));\n\n function queue(ctx: Context, downstream: boolean, same?: boolean) {\n let found = false;\n for (const T of TT) {\n const list = ctx.consume.get(T);\n if (list !== undefined) found = true;\n if (list)\n for (const [cb, filter] of list)\n if (same || filter == null || filter === downstream)\n expects.set(cb, () => {\n const r = cb(I, filter ?? downstream);\n if (r) onDone.add(r);\n });\n }\n return found;\n }\n\n queue(this, true, true);\n for (let ctx = this.parent; ctx; ctx = ctx.parent) queue(ctx, true);\n this.traverse((ctx) => queue(ctx, false));\n\n if (!LOOKUP.has(I)) LOOKUP.set(I, this);\n\n listener(I, () => {\n expects.forEach((f) => f());\n expects.clear();\n return null;\n });\n\n function flush() {\n onDone.forEach((r) => r());\n onDone.clear();\n }\n\n const held = Array.from(HELD.get(I) || [], (child) => this.add(child));\n\n function remove() {\n cleanup.delete(remove);\n held.forEach((done) => done());\n flush();\n }\n\n cleanup.set(remove, remove);\n\n return remove;\n }\n\n /**\n * Create a child context, optionally registering one or more States to it.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n */\n public push(inputs?: Accept) {\n const next = new Context(this);\n if (inputs) next.set(inputs);\n return next;\n }\n\n /**\n * Remove all States from this context.\n *\n * Will also run any cleanup callbacks registered when States were added.\n */\n public pop() {\n this.inputs = {};\n this.scope.forEach((x) => x.pop());\n this.scope.clear();\n this.cleanup.forEach((cb) => cb());\n this.cleanup.clear();\n this.consume.clear();\n this.provide.clear();\n if (this.parent) {\n this.parent.scope.delete(this);\n }\n }\n}\n\nObject.defineProperty(Context.prototype, \"toString\", {\n value() {\n return `Context-${this.id}`;\n },\n});\n\n/**\n * Add `value` to the context `state` was added to. A context-less `state` holds\n * it instead - every context adding `state` later adds its held children too.\n */\nfunction join(state: State, value: State): () => void {\n const ctx = LOOKUP.get(state.is);\n\n if (ctx) return ctx.add(value);\n\n const held = HELD.get(state) || new Set();\n HELD.set(state, held.add(value));\n\n return () => held.delete(value);\n}\n\nexport { Context, join };\n"],"mappings":"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"}
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -1,8 +1,37 @@
|
|
|
1
1
|
//#region src/dispatch.d.ts
|
|
2
2
|
type Handler = () => void;
|
|
3
3
|
type Transition = (work: Handler) => void;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type Hold = (retry?: Handler | false) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Hold the work being replayed until the returned callback runs - a subscriber
|
|
7
|
+
* which has not yet absorbed the update takes one, and settlement waits on it
|
|
8
|
+
* rather than on the replay. Returns nothing unless the replay carries pending
|
|
9
|
+
* work, so an unrelated subscriber pays for none of it.
|
|
10
|
+
*/
|
|
11
|
+
declare function hold(detached?: true, transition?: Transition): Hold | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Queue `handler` to replay after this tick. `transition` is how this
|
|
14
|
+
* subscriber defers - it brackets the replay, but only where the scheduled
|
|
15
|
+
* work asked for one.
|
|
16
|
+
*/
|
|
17
|
+
declare function enqueue(handler: Handler, transition?: Transition, owner?: object): void;
|
|
18
|
+
/**
|
|
19
|
+
* Run `work` now, marking the subscriber updates it queues non-urgent - each
|
|
20
|
+
* replays through whatever scheduler it subscribed with. The callback itself is
|
|
21
|
+
* synchronous; only what it notifies is pending.
|
|
22
|
+
*
|
|
23
|
+
* Resolves once every one of those updates has replayed and been absorbed. A
|
|
24
|
+
* subscriber which cannot report absorption resolves on replay; one which can
|
|
25
|
+
* defer brackets its own replay.
|
|
26
|
+
*/
|
|
27
|
+
declare function pending(work: Handler): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Declare the subscriber currently replaying has not absorbed its update yet -
|
|
30
|
+
* settlement waits on the returned callback rather than on the replay. Call
|
|
31
|
+
* only from inside a replay carrying pending work; elsewhere this returns
|
|
32
|
+
* nothing and the subscriber pays for none of it.
|
|
33
|
+
*/
|
|
34
|
+
declare function pending(): (() => void) | undefined;
|
|
6
35
|
//#endregion
|
|
7
|
-
export { enqueue,
|
|
36
|
+
export { enqueue, hold, pending };
|
|
8
37
|
//# sourceMappingURL=dispatch.d.ts.map
|
package/dist/dispatch.js
CHANGED
|
@@ -1,37 +1,106 @@
|
|
|
1
|
+
import { fault } from "./state.js";
|
|
2
|
+
|
|
1
3
|
//#region src/dispatch.ts
|
|
2
4
|
const DISPATCH = /* @__PURE__ */ new Map();
|
|
3
|
-
let
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
let current;
|
|
6
|
+
let replaying;
|
|
7
|
+
/**
|
|
8
|
+
* Await this handler's replay for the work being scheduled. Overlapping calls
|
|
9
|
+
* may each be waiting on the same handler, which replays once.
|
|
10
|
+
*/
|
|
11
|
+
function claim(scheduled) {
|
|
12
|
+
if (!current) return;
|
|
13
|
+
const awaiting = scheduled.awaiting || (scheduled.awaiting = /* @__PURE__ */ new Set());
|
|
14
|
+
for (const record of current) if (!awaiting.has(record)) {
|
|
15
|
+
awaiting.add(record);
|
|
16
|
+
record.count++;
|
|
12
17
|
}
|
|
13
18
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
function drop(scheduled) {
|
|
20
|
+
const { awaiting } = scheduled;
|
|
21
|
+
if (!awaiting) return;
|
|
22
|
+
scheduled.awaiting = void 0;
|
|
23
|
+
for (const record of awaiting) if (!--record.count) record.done();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hold the work being replayed until the returned callback runs - a subscriber
|
|
27
|
+
* which has not yet absorbed the update takes one, and settlement waits on it
|
|
28
|
+
* rather than on the replay. Returns nothing unless the replay carries pending
|
|
29
|
+
* work, so an unrelated subscriber pays for none of it.
|
|
30
|
+
*/
|
|
31
|
+
function hold(detached, transition) {
|
|
32
|
+
const scheduled = replaying || {};
|
|
33
|
+
if (detached) {
|
|
34
|
+
scheduled.transition = transition;
|
|
35
|
+
claim(scheduled);
|
|
36
|
+
} else if (!scheduled.awaiting) return;
|
|
37
|
+
let released = false;
|
|
38
|
+
scheduled.holds = (scheduled.holds || 0) + 1;
|
|
39
|
+
const release = (retry) => {
|
|
40
|
+
if (released) return;
|
|
41
|
+
if (retry === false) return claim(scheduled);
|
|
42
|
+
if (retry) {
|
|
43
|
+
current = scheduled.awaiting;
|
|
44
|
+
enqueue(retry, scheduled.transition);
|
|
45
|
+
current = void 0;
|
|
23
46
|
}
|
|
24
|
-
|
|
47
|
+
released = true;
|
|
48
|
+
if (!--scheduled.holds) drop(scheduled);
|
|
49
|
+
};
|
|
50
|
+
return release;
|
|
51
|
+
}
|
|
52
|
+
function flush() {
|
|
53
|
+
for (const [handler, scheduled] of DISPATCH) {
|
|
54
|
+
DISPATCH.delete(handler);
|
|
55
|
+
const { awaiting, transition } = scheduled;
|
|
56
|
+
current = awaiting;
|
|
57
|
+
replaying = scheduled;
|
|
58
|
+
try {
|
|
59
|
+
if (transition) transition(handler);
|
|
60
|
+
else handler();
|
|
61
|
+
} catch (err) {
|
|
62
|
+
fault(err, scheduled.owner);
|
|
63
|
+
} finally {
|
|
64
|
+
current = replaying = void 0;
|
|
65
|
+
}
|
|
66
|
+
if (!scheduled.holds) drop(scheduled);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Queue `handler` to replay after this tick. `transition` is how this
|
|
71
|
+
* subscriber defers - it brackets the replay, but only where the scheduled
|
|
72
|
+
* work asked for one.
|
|
73
|
+
*/
|
|
74
|
+
function enqueue(handler, transition, owner) {
|
|
75
|
+
if (!DISPATCH.size) queueMicrotask(flush);
|
|
25
76
|
const scheduled = DISPATCH.get(handler);
|
|
26
|
-
if (scheduled) {
|
|
27
|
-
|
|
28
|
-
|
|
77
|
+
if (!scheduled) {
|
|
78
|
+
const next = {
|
|
79
|
+
transition: current ? transition : void 0,
|
|
80
|
+
owner
|
|
81
|
+
};
|
|
82
|
+
DISPATCH.set(handler, next);
|
|
83
|
+
claim(next);
|
|
84
|
+
} else if (current) claim(scheduled);
|
|
85
|
+
else scheduled.transition = void 0;
|
|
29
86
|
}
|
|
30
|
-
function
|
|
31
|
-
if (!
|
|
32
|
-
|
|
87
|
+
function pending(work) {
|
|
88
|
+
if (!work) return hold();
|
|
89
|
+
const parent = current;
|
|
90
|
+
const record = { count: 1 };
|
|
91
|
+
const promise = new Promise((resolve) => {
|
|
92
|
+
record.done = resolve;
|
|
93
|
+
});
|
|
94
|
+
current = parent ? [...parent, record] : [record];
|
|
95
|
+
try {
|
|
96
|
+
work();
|
|
97
|
+
} finally {
|
|
98
|
+
current = parent;
|
|
99
|
+
if (!--record.count) record.done();
|
|
100
|
+
}
|
|
101
|
+
return promise;
|
|
33
102
|
}
|
|
34
103
|
|
|
35
104
|
//#endregion
|
|
36
|
-
export { enqueue,
|
|
105
|
+
export { enqueue, hold, pending };
|
|
37
106
|
//# sourceMappingURL=dispatch.js.map
|
package/dist/dispatch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.js","names":[],"sources":["../src/dispatch.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"dispatch.js","names":[],"sources":["../src/dispatch.ts"],"sourcesContent":["import { fault } from './state';\n\ntype Handler = () => void;\ntype Transition = (work: Handler) => void;\n\ninterface Pending {\n count: number;\n done(): void;\n}\n\ntype Hold = (retry?: Handler | false) => void;\n\ninterface Scheduled {\n /** How this subscriber defers, if it can - supplied where it subscribed. */\n transition?: Transition;\n awaiting?: Set<Pending>;\n holds?: number;\n owner?: object;\n}\n\nconst DISPATCH = new Map<Handler, Scheduled>();\nlet current: Iterable<Pending> | undefined;\nlet replaying: Scheduled | undefined;\n\n/**\n * Await this handler's replay for the work being scheduled. Overlapping calls\n * may each be waiting on the same handler, which replays once.\n */\nfunction claim(scheduled: Scheduled) {\n if (!current) return;\n\n const awaiting = scheduled.awaiting || (scheduled.awaiting = new Set());\n\n for (const record of current)\n if (!awaiting.has(record)) {\n awaiting.add(record);\n record.count++;\n }\n}\n\nfunction drop(scheduled: Scheduled) {\n const { awaiting } = scheduled;\n\n if (!awaiting) return;\n\n scheduled.awaiting = undefined;\n\n for (const record of awaiting)\n if (!--record.count) record.done();\n}\n\n/**\n * Hold the work being replayed until the returned callback runs - a subscriber\n * which has not yet absorbed the update takes one, and settlement waits on it\n * rather than on the replay. Returns nothing unless the replay carries pending\n * work, so an unrelated subscriber pays for none of it.\n */\nfunction hold(detached?: true, transition?: Transition) {\n const scheduled = replaying || {};\n\n if (detached) {\n scheduled.transition = transition;\n claim(scheduled);\n }\n else if (!scheduled.awaiting) return;\n\n let released = false;\n\n scheduled.holds = (scheduled.holds || 0) + 1;\n\n const release: Hold = (retry) => {\n if (released) return;\n if (retry === false) return claim(scheduled);\n\n if (retry) {\n current = scheduled.awaiting;\n enqueue(retry, scheduled.transition);\n current = undefined;\n }\n\n released = true;\n if (!--scheduled.holds!) drop(scheduled);\n };\n\n return release;\n}\n\nfunction flush() {\n for (const [handler, scheduled] of DISPATCH) {\n DISPATCH.delete(handler);\n\n const { awaiting, transition } = scheduled;\n\n current = awaiting;\n replaying = scheduled;\n\n try {\n if (transition) transition(handler);\n else handler();\n } catch (err) {\n fault(err, scheduled.owner);\n } finally {\n current = replaying = undefined;\n }\n\n if (!scheduled.holds) drop(scheduled);\n }\n}\n\n/**\n * Queue `handler` to replay after this tick. `transition` is how this\n * subscriber defers - it brackets the replay, but only where the scheduled\n * work asked for one.\n */\nfunction enqueue(handler: Handler, transition?: Transition, owner?: object) {\n if (!DISPATCH.size) queueMicrotask(flush);\n\n const scheduled = DISPATCH.get(handler);\n\n if (!scheduled) {\n const next: Scheduled = {\n transition: current ? transition : undefined,\n owner\n };\n\n DISPATCH.set(handler, next);\n claim(next);\n } else if (current) {\n claim(scheduled);\n } else {\n scheduled.transition = undefined;\n }\n}\n\n/**\n * Run `work` now, marking the subscriber updates it queues non-urgent - each\n * replays through whatever scheduler it subscribed with. The callback itself is\n * synchronous; only what it notifies is pending.\n *\n * Resolves once every one of those updates has replayed and been absorbed. A\n * subscriber which cannot report absorption resolves on replay; one which can\n * defer brackets its own replay.\n */\nfunction pending(work: Handler): Promise<void>;\n\n/**\n * Declare the subscriber currently replaying has not absorbed its update yet -\n * settlement waits on the returned callback rather than on the replay. Call\n * only from inside a replay carrying pending work; elsewhere this returns\n * nothing and the subscriber pays for none of it.\n */\nfunction pending(): (() => void) | undefined;\n\nfunction pending(work?: Handler): Promise<void> | (() => void) | undefined {\n if (!work) return hold();\n\n const parent = current;\n const record = { count: 1 } as Pending;\n const promise = new Promise<void>((resolve) => {\n record.done = resolve;\n });\n\n current = parent ? [...parent, record] : [record];\n\n try {\n work();\n } finally {\n current = parent;\n if (!--record.count) record.done();\n }\n\n return promise;\n}\n\nexport { enqueue, hold, pending };\n"],"mappings":";;;AAoBA,MAAM,2BAAW,IAAI,KAAyB;AAC9C,IAAI;AACJ,IAAI;;;;;AAMJ,SAAS,MAAM,WAAsB;AACnC,KAAI,CAAC,QAAS;CAEd,MAAM,WAAW,UAAU,aAAa,UAAU,2BAAW,IAAI,KAAK;AAEtE,MAAK,MAAM,UAAU,QACnB,KAAI,CAAC,SAAS,IAAI,OAAO,EAAE;AACzB,WAAS,IAAI,OAAO;AACpB,SAAO;;;AAIb,SAAS,KAAK,WAAsB;CAClC,MAAM,EAAE,aAAa;AAErB,KAAI,CAAC,SAAU;AAEf,WAAU,WAAW;AAErB,MAAK,MAAM,UAAU,SACnB,KAAI,CAAC,EAAE,OAAO,MAAO,QAAO,MAAM;;;;;;;;AAStC,SAAS,KAAK,UAAiB,YAAyB;CACtD,MAAM,YAAY,aAAa,EAAE;AAEjC,KAAI,UAAU;AACZ,YAAU,aAAa;AACvB,QAAM,UAAU;YAET,CAAC,UAAU,SAAU;CAE9B,IAAI,WAAW;AAEf,WAAU,SAAS,UAAU,SAAS,KAAK;CAE3C,MAAM,WAAiB,UAAU;AAC/B,MAAI,SAAU;AACd,MAAI,UAAU,MAAO,QAAO,MAAM,UAAU;AAE5C,MAAI,OAAO;AACT,aAAU,UAAU;AACpB,WAAQ,OAAO,UAAU,WAAW;AACpC,aAAU;;AAGZ,aAAW;AACX,MAAI,CAAC,EAAE,UAAU,MAAQ,MAAK,UAAU;;AAG1C,QAAO;;AAGT,SAAS,QAAQ;AACf,MAAK,MAAM,CAAC,SAAS,cAAc,UAAU;AAC3C,WAAS,OAAO,QAAQ;EAExB,MAAM,EAAE,UAAU,eAAe;AAEjC,YAAU;AACV,cAAY;AAEZ,MAAI;AACF,OAAI,WAAY,YAAW,QAAQ;OAC9B,UAAS;WACP,KAAK;AACZ,SAAM,KAAK,UAAU,MAAM;YACnB;AACR,aAAU,YAAY;;AAGxB,MAAI,CAAC,UAAU,MAAO,MAAK,UAAU;;;;;;;;AASzC,SAAS,QAAQ,SAAkB,YAAyB,OAAgB;AAC1E,KAAI,CAAC,SAAS,KAAM,gBAAe,MAAM;CAEzC,MAAM,YAAY,SAAS,IAAI,QAAQ;AAEvC,KAAI,CAAC,WAAW;EACd,MAAM,OAAkB;GACtB,YAAY,UAAU,aAAa;GACnC;GACD;AAED,WAAS,IAAI,SAAS,KAAK;AAC3B,QAAM,KAAK;YACF,QACT,OAAM,UAAU;KAEhB,WAAU,aAAa;;AAuB3B,SAAS,QAAQ,MAA0D;AACzE,KAAI,CAAC,KAAM,QAAO,MAAM;CAExB,MAAM,SAAS;CACf,MAAM,SAAS,EAAE,OAAO,GAAG;CAC3B,MAAM,UAAU,IAAI,SAAe,YAAY;AAC7C,SAAO,OAAO;GACd;AAEF,WAAU,SAAS,CAAC,GAAG,QAAQ,OAAO,GAAG,CAAC,OAAO;AAEjD,KAAI;AACF,QAAM;WACE;AACR,YAAU;AACV,MAAI,CAAC,EAAE,OAAO,MAAO,QAAO,MAAM;;AAGpC,QAAO"}
|
package/dist/field/def.js
CHANGED
package/dist/field/get.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { capture, listener, observer } from "../observable.js";
|
|
2
1
|
import { STORE, children, parent, update } from "../state.js";
|
|
2
|
+
import { capture, listener, observer } from "../observable.js";
|
|
3
3
|
import { Context } from "../context.js";
|
|
4
4
|
import { def } from "./def.js";
|
|
5
5
|
|
package/dist/field/has.d.ts
CHANGED
|
@@ -4,11 +4,11 @@ import { State } from "../state.js";
|
|
|
4
4
|
type Predicate<T> = (value: T, index: number, self: unknown) => boolean;
|
|
5
5
|
type Mapper<T, U> = (value: T, index: number, self: unknown) => U;
|
|
6
6
|
declare namespace has {
|
|
7
|
-
export { Predicate, Mapper, List, Pool };
|
|
7
|
+
export { Predicate, Mapper, List, Pool, Create, From };
|
|
8
8
|
}
|
|
9
9
|
declare function has<T>(initial?: Iterable<T> | false | null): List<T>;
|
|
10
|
-
declare function has<T extends State>(Type: new (...args: State.Args<T>) => T):
|
|
11
|
-
declare function has<T extends State, K extends State.Field<T>>(Type: new (...args: State.Args<T>) => T, fromKey: K):
|
|
10
|
+
declare function has<T extends State>(Type: new (...args: State.Args<T>) => T): Create<T>;
|
|
11
|
+
declare function has<T extends State, K extends State.Field<T>>(Type: new (...args: State.Args<T>) => T, fromKey: K): From<T, K>;
|
|
12
12
|
declare function has<R, A extends unknown[]>(make: (...args: A) => R): Pool<Exclude<R, null | undefined>, A, R>;
|
|
13
13
|
declare class List<T> {
|
|
14
14
|
constructor(initial?: Iterable<T> | false | null);
|
|
@@ -31,6 +31,14 @@ declare class List<T> {
|
|
|
31
31
|
any(fn: Predicate<T>): boolean;
|
|
32
32
|
all(fn: Predicate<T>): boolean;
|
|
33
33
|
}
|
|
34
|
+
interface Create<T extends State> extends Pool<T, State.Args<T>> {
|
|
35
|
+
add(...args: State.Args<T>): T;
|
|
36
|
+
add(instance: T): T;
|
|
37
|
+
}
|
|
38
|
+
interface From<T extends State, K extends State.Field<T>> extends Pool<T, [from: T[K]]> {
|
|
39
|
+
add(from: T[K]): T;
|
|
40
|
+
add(instance: T): T;
|
|
41
|
+
}
|
|
34
42
|
declare class Pool<T, A extends unknown[] = unknown[], R = T> {
|
|
35
43
|
constructor(make: Function, fromKey?: string);
|
|
36
44
|
get size(): number;
|
package/dist/field/has.js
CHANGED
package/dist/field/has.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"has.js","names":[],"sources":["../../src/field/has.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport { State, parent } from '../state';\nimport { def } from './def';\n\nconst LENGTH = Symbol('length');\nconst SHAPE = Symbol('shape');\n\nconst ITEMS = new WeakMap<object, unknown[]>();\nconst MEMBERS = new WeakMap<object, Set<unknown>>();\nconst OWNED = new WeakMap<object, Map<unknown, () => void>>();\nconst MAKE = new WeakMap<object, Make>();\n\ntype Make = (...args: unknown[]) => unknown;\ntype Predicate<T> = (value: T, index: number, self: unknown) => boolean;\ntype Mapper<T, U> = (value: T, index: number, self: unknown) => U;\n\ndeclare namespace has {\n export { Predicate, Mapper, List, Pool }\n}\n\nfunction has<T>(initial?: Iterable<T> | false | null): List<T>;\n\nfunction has<T extends State>(\n Type: new (...args: State.Args<T>) => T\n): Pool<T, State.Args<T> | [T]>;\n\nfunction has<T extends State, K extends State.Field<T>>(\n Type: new (...args: State.Args<T>) => T,\n fromKey: K\n): Pool<T, [T[K]] | [T]>;\n\nfunction has<R, A extends unknown[]>(\n make: (...args: A) => R\n): Pool<Exclude<R, null | undefined>, A, R>;\n\nfunction has(\n arg?: Iterable<unknown> | Function | false | null,\n fromKey?: string\n): unknown {\n return def((_key, subject) => {\n const value =\n typeof arg == 'function' ? new Pool(arg, fromKey) : new List(arg);\n\n parent(value, subject);\n listener(subject, () => value.clear(), null);\n\n return { set: false, value };\n });\n}\n\nclass List<T> {\n constructor(initial?: Iterable<T> | false | null) {\n ITEMS.set(this, initial ? Array.from(initial) : []);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, LENGTH, items<T>(this).length);\n }\n\n get(): State.Export<T>[];\n get(index: number): T | undefined;\n get(start: number, end: number): T[];\n get(predicate: Predicate<T>): T | undefined;\n get(arg?: number | Predicate<T>, second?: number): any {\n const values = items<T>(this);\n\n if (arg === undefined) return values.map(exportValue);\n\n if (typeof arg === 'function') return findOf(this, arg);\n\n if (typeof second !== 'number') {\n const at = arg < 0 ? values.length + arg : arg;\n\n return at < 0 || at >= values.length\n ? touch(this, LENGTH)\n : touch(this, at, values[at]);\n }\n\n touch(this, LENGTH);\n\n const start = arg < 0 ? Math.max(values.length + arg, 0) : arg;\n\n return values\n .slice(start, Math.min(second, values.length))\n .map((v, i) => touch(this, start + i, v));\n }\n\n set(index: number, value: T) {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const at = index < 0 ? values.length + index : index;\n\n if (at < 0 || at >= values.length || values[at] === value) return;\n\n values[at] = value;\n event(target, at);\n }\n\n put(index: number, ...values: T[]) {\n if (!values.length) return;\n\n const target = source(this);\n const arr = ITEMS.get(target) as T[];\n const at =\n index < 0\n ? Math.max(arr.length + index, 0)\n : Math.min(index, arr.length);\n\n arr.splice(at, 0, ...values);\n\n for (let i = at; i < arr.length; i++) event(target, i);\n event(target, LENGTH);\n }\n\n push(...values: T[]): number {\n this.put(items(this).length, ...values);\n return items(this).length;\n }\n\n pop(): T | undefined;\n pop(index: number): T | undefined;\n pop(index: number, count: number): T[];\n pop(index = -1, count?: number): T | T[] | undefined {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const before = values.length;\n const start =\n index < 0 ? Math.max(before + index, 0) : Math.min(index, before);\n const removed = values.splice(start, count ?? 1);\n\n if (removed.length) {\n const end = Math.max(before, values.length);\n for (let i = start; i < end; i++) event(target, i);\n event(target, LENGTH);\n }\n\n return count === undefined ? removed[0] : removed;\n }\n\n clear() {\n this.pop(0, items(this).length);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = items<T>(this);\n\n touch(this, LENGTH);\n\n for (let i = 0; i < values.length; i++) yield touch(this, i, values[i]);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\nclass Pool<T, A extends unknown[] = unknown[], R = T> {\n constructor(make: Function, fromKey?: string) {\n if (State.is(make)) {\n const Type = make as unknown as State.Type;\n\n make = (...args: State.Args) =>\n args.length == 1 && args[0] instanceof Type ? args[0] :\n fromKey ? new Type({ [fromKey]: args[0] }) :\n new Type(...args);\n }\n\n MEMBERS.set(this, new Set());\n MAKE.set(this, make as Make);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, SHAPE, members<T>(this).size);\n }\n\n add(...args: A): R {\n const target = source(this);\n const made = MAKE.get(target)!(...args) as T | null | undefined;\n\n if (made == null) return made as R;\n\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(made)) {\n values.add(made);\n adopt(target, made, made);\n event(target, made as never);\n event(target, SHAPE);\n }\n\n return made as R;\n }\n\n get(): State.Export<T>[];\n get(predicate: Predicate<T>): T | undefined;\n get(predicate?: Predicate<T>): any {\n return predicate\n ? findOf(this, predicate)\n : Array.from(members<T>(this), exportValue);\n }\n\n has(value: T): boolean {\n return touch(this, value, members<T>(this).has(value));\n }\n\n delete(value: T): boolean {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(value)) return false;\n\n release(target, value);\n values.delete(value);\n\n event(target, value as never);\n event(target, SHAPE);\n\n return true;\n }\n\n clear() {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.size) return;\n\n const removed = Array.from(values);\n\n for (const value of removed) release(target, value);\n\n values.clear();\n\n for (const value of removed) event(target, value as never);\n event(target, SHAPE);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = members<T>(this);\n\n touch(this, SHAPE);\n\n for (const value of values) yield touch(this, value, value);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\nfunction source<T extends object>(from: T): T {\n return OWNED.has(from) ? from : Object.getPrototypeOf(from);\n}\n\nfunction adopt(\n target: { delete(key: never): boolean },\n key: unknown,\n value: unknown\n) {\n if (!(value instanceof State)) return;\n\n const owner = parent(target as object);\n const fresh = parent(value, owner ?? null);\n const evict = listener(value, () => void target.delete(key as never), null);\n\n let detach: (() => void) | undefined;\n\n if (fresh && owner)\n detach = Context.get(owner).add(value);\n\n OWNED.get(target)!.set(key, () => {\n evict();\n if (detach) detach();\n if (fresh) value.set(null);\n });\n\n if (fresh) event(value);\n}\n\nfunction release(target: object, key: unknown) {\n const owned = OWNED.get(target)!;\n const free = owned.get(key);\n\n if (free) {\n owned.delete(key);\n free();\n }\n}\n\nfunction exportValue(value: any) {\n return value && typeof value === 'object' && typeof value.get === 'function'\n ? value.get()\n : value;\n}\n\nfunction items<T>(from: object): T[] {\n return ITEMS.get(source(from)) as T[];\n}\n\nfunction members<T>(from: object): Set<T> {\n return MEMBERS.get(source(from)) as Set<T>;\n}\n\nfunction findOf<T>(\n self: Iterable<T>,\n fn: Predicate<T>\n): T | undefined {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return value;\n}\n\nfunction anyOf<T>(self: Iterable<T>, fn: Predicate<T>): boolean {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return true;\n\n return false;\n}\n\nfunction mapOf<T, U>(\n self: Iterable<T>,\n fn: Mapper<T, U>,\n skip: boolean,\n ignore?: U\n): U[] {\n const out: U[] = [];\n let i = 0;\n\n for (const value of self) {\n const result = fn(value, i++, self);\n if (skip && result === ignore) continue;\n out.push(result);\n }\n\n return out;\n}\n\nfunction filterOf<T>(self: Iterable<T>, fn: Predicate<T>): T[] {\n const out: T[] = [];\n let i = 0;\n\n for (const value of self) if (fn(value, i++, self)) out.push(value);\n\n return out;\n}\n\nObject.assign(has, { List, Pool });\n\nexport { has };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"has.js","names":[],"sources":["../../src/field/has.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport { State, parent } from '../state';\nimport { def } from './def';\n\nconst LENGTH = Symbol('length');\nconst SHAPE = Symbol('shape');\n\nconst ITEMS = new WeakMap<object, unknown[]>();\nconst MEMBERS = new WeakMap<object, Set<unknown>>();\nconst OWNED = new WeakMap<object, Map<unknown, () => void>>();\nconst MAKE = new WeakMap<object, Make>();\n\ntype Make = (...args: unknown[]) => unknown;\ntype Predicate<T> = (value: T, index: number, self: unknown) => boolean;\ntype Mapper<T, U> = (value: T, index: number, self: unknown) => U;\n\ndeclare namespace has {\n export { Predicate, Mapper, List, Pool, Create, From }\n}\n\nfunction has<T>(initial?: Iterable<T> | false | null): List<T>;\n\nfunction has<T extends State>(\n Type: new (...args: State.Args<T>) => T\n): Create<T>;\n\nfunction has<T extends State, K extends State.Field<T>>(\n Type: new (...args: State.Args<T>) => T,\n fromKey: K\n): From<T, K>;\n\nfunction has<R, A extends unknown[]>(\n make: (...args: A) => R\n): Pool<Exclude<R, null | undefined>, A, R>;\n\nfunction has(\n arg?: Iterable<unknown> | Function | false | null,\n fromKey?: string\n): unknown {\n return def((_key, subject) => {\n const value =\n typeof arg == 'function' ? new Pool(arg, fromKey) : new List(arg);\n\n parent(value, subject);\n listener(subject, () => value.clear(), null);\n\n return { set: false, value };\n });\n}\n\nclass List<T> {\n constructor(initial?: Iterable<T> | false | null) {\n ITEMS.set(this, initial ? Array.from(initial) : []);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, LENGTH, items<T>(this).length);\n }\n\n get(): State.Export<T>[];\n get(index: number): T | undefined;\n get(start: number, end: number): T[];\n get(predicate: Predicate<T>): T | undefined;\n get(arg?: number | Predicate<T>, second?: number): any {\n const values = items<T>(this);\n\n if (arg === undefined) return values.map(exportValue);\n\n if (typeof arg === 'function') return findOf(this, arg);\n\n if (typeof second !== 'number') {\n const at = arg < 0 ? values.length + arg : arg;\n\n return at < 0 || at >= values.length\n ? touch(this, LENGTH)\n : touch(this, at, values[at]);\n }\n\n touch(this, LENGTH);\n\n const start = arg < 0 ? Math.max(values.length + arg, 0) : arg;\n\n return values\n .slice(start, Math.min(second, values.length))\n .map((v, i) => touch(this, start + i, v));\n }\n\n set(index: number, value: T) {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const at = index < 0 ? values.length + index : index;\n\n if (at < 0 || at >= values.length || values[at] === value) return;\n\n values[at] = value;\n event(target, at);\n }\n\n put(index: number, ...values: T[]) {\n if (!values.length) return;\n\n const target = source(this);\n const arr = ITEMS.get(target) as T[];\n const at =\n index < 0\n ? Math.max(arr.length + index, 0)\n : Math.min(index, arr.length);\n\n arr.splice(at, 0, ...values);\n\n for (let i = at; i < arr.length; i++) event(target, i);\n event(target, LENGTH);\n }\n\n push(...values: T[]): number {\n this.put(items(this).length, ...values);\n return items(this).length;\n }\n\n pop(): T | undefined;\n pop(index: number): T | undefined;\n pop(index: number, count: number): T[];\n pop(index = -1, count?: number): T | T[] | undefined {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const before = values.length;\n const start =\n index < 0 ? Math.max(before + index, 0) : Math.min(index, before);\n const removed = values.splice(start, count ?? 1);\n\n if (removed.length) {\n const end = Math.max(before, values.length);\n for (let i = start; i < end; i++) event(target, i);\n event(target, LENGTH);\n }\n\n return count === undefined ? removed[0] : removed;\n }\n\n clear() {\n this.pop(0, items(this).length);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = items<T>(this);\n\n touch(this, LENGTH);\n\n for (let i = 0; i < values.length; i++) yield touch(this, i, values[i]);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\ninterface Create<T extends State> extends Pool<T, State.Args<T>> {\n add(...args: State.Args<T>): T;\n add(instance: T): T;\n}\n\ninterface From<T extends State, K extends State.Field<T>>\n extends Pool<T, [from: T[K]]> {\n add(from: T[K]): T;\n add(instance: T): T;\n}\n\nclass Pool<T, A extends unknown[] = unknown[], R = T> {\n constructor(make: Function, fromKey?: string) {\n if (State.is(make)) {\n const Type = make as unknown as State.Type;\n\n make = (...args: State.Args) =>\n args.length == 1 && args[0] instanceof Type ? args[0] :\n fromKey ? new Type({ [fromKey]: args[0] }) :\n new Type(...args);\n }\n\n MEMBERS.set(this, new Set());\n MAKE.set(this, make as Make);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, SHAPE, members<T>(this).size);\n }\n\n add(...args: A): R {\n const target = source(this);\n const made = MAKE.get(target)!(...args) as T | null | undefined;\n\n if (made == null) return made as R;\n\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(made)) {\n values.add(made);\n adopt(target, made, made);\n event(target, made as never);\n event(target, SHAPE);\n }\n\n return made as R;\n }\n\n get(): State.Export<T>[];\n get(predicate: Predicate<T>): T | undefined;\n get(predicate?: Predicate<T>): any {\n return predicate\n ? findOf(this, predicate)\n : Array.from(members<T>(this), exportValue);\n }\n\n has(value: T): boolean {\n return touch(this, value, members<T>(this).has(value));\n }\n\n delete(value: T): boolean {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(value)) return false;\n\n release(target, value);\n values.delete(value);\n\n event(target, value as never);\n event(target, SHAPE);\n\n return true;\n }\n\n clear() {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.size) return;\n\n const removed = Array.from(values);\n\n for (const value of removed) release(target, value);\n\n values.clear();\n\n for (const value of removed) event(target, value as never);\n event(target, SHAPE);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = members<T>(this);\n\n touch(this, SHAPE);\n\n for (const value of values) yield touch(this, value, value);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\nfunction source<T extends object>(from: T): T {\n return OWNED.has(from) ? from : Object.getPrototypeOf(from);\n}\n\nfunction adopt(\n target: { delete(key: never): boolean },\n key: unknown,\n value: unknown\n) {\n if (!(value instanceof State)) return;\n\n const owner = parent(target as object);\n const fresh = parent(value, owner ?? null);\n const evict = listener(value, () => void target.delete(key as never), null);\n\n let detach: (() => void) | undefined;\n\n if (fresh && owner)\n detach = Context.get(owner).add(value);\n\n OWNED.get(target)!.set(key, () => {\n evict();\n if (detach) detach();\n if (fresh) value.set(null);\n });\n\n if (fresh) event(value);\n}\n\nfunction release(target: object, key: unknown) {\n const owned = OWNED.get(target)!;\n const free = owned.get(key);\n\n if (free) {\n owned.delete(key);\n free();\n }\n}\n\nfunction exportValue(value: any) {\n return value && typeof value === 'object' && typeof value.get === 'function'\n ? value.get()\n : value;\n}\n\nfunction items<T>(from: object): T[] {\n return ITEMS.get(source(from)) as T[];\n}\n\nfunction members<T>(from: object): Set<T> {\n return MEMBERS.get(source(from)) as Set<T>;\n}\n\nfunction findOf<T>(\n self: Iterable<T>,\n fn: Predicate<T>\n): T | undefined {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return value;\n}\n\nfunction anyOf<T>(self: Iterable<T>, fn: Predicate<T>): boolean {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return true;\n\n return false;\n}\n\nfunction mapOf<T, U>(\n self: Iterable<T>,\n fn: Mapper<T, U>,\n skip: boolean,\n ignore?: U\n): U[] {\n const out: U[] = [];\n let i = 0;\n\n for (const value of self) {\n const result = fn(value, i++, self);\n if (skip && result === ignore) continue;\n out.push(result);\n }\n\n return out;\n}\n\nfunction filterOf<T>(self: Iterable<T>, fn: Predicate<T>): T[] {\n const out: T[] = [];\n let i = 0;\n\n for (const value of self) if (fn(value, i++, self)) out.push(value);\n\n return out;\n}\n\nObject.assign(has, { List, Pool });\n\nexport { has };\n"],"mappings":"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"}
|
package/dist/field/map.js
CHANGED
package/dist/field/ref.js
CHANGED
package/dist/field/set.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { capture, event, listener } from "../observable.js";
|
|
2
1
|
import { access, compute, update } from "../state.js";
|
|
2
|
+
import { capture, event, listener, observer } from "../observable.js";
|
|
3
3
|
import { def } from "./def.js";
|
|
4
4
|
|
|
5
5
|
//#region src/field/set.ts
|
|
@@ -31,7 +31,10 @@ function set(value, argument) {
|
|
|
31
31
|
if (typeof argument == "function") subject[key] = next;
|
|
32
32
|
else update(subject, key, next, silent, true);
|
|
33
33
|
}
|
|
34
|
-
if (output instanceof Promise) output.then(
|
|
34
|
+
if (output instanceof Promise) output.then((next) => {
|
|
35
|
+
if (observer(subject) !== null) assign(next);
|
|
36
|
+
}, (error) => {
|
|
37
|
+
if (observer(subject) === null) return;
|
|
35
38
|
event(subject, key);
|
|
36
39
|
config.get = () => {
|
|
37
40
|
throw error;
|
package/dist/field/set.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set.js","names":[],"sources":["../../src/field/set.ts"],"sourcesContent":["import { listener, capture } from '../observable';\nimport { access, compute, event, State, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace set {\n type Callback<T, S = any> = (\n this: S,\n next: T,\n previous: T\n ) => ((next: T) => void) | Promise<any> | void | boolean;\n\n type Factory<T, S = any> = (this: S, property: string) => Promise<T> | T;\n}\n\n/**\n * Set a property as a placeholder, initially `undefined` but required.\n *\n * Property cannot be accessed until it is defined. If accessed while undefined, a hybrid\n * `Promise`/`Error` (aka: [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html)) will be thrown.\n *\n * Non-enumerable; writable only if `onUpdate` callback is provided.\n *\n * @param value - Starting value (undefined for suspense placeholder).\n * @param onUpdate - Callback run when property is set.\n */\nfunction set<T>(value?: undefined, onUpdate?: set.Callback<T>): T;\n\n/**\n * Set property with an async factory function.\n * If required is not defined, factory runs lazily on first access.\n * If async, or returns a promise, suspense is thrown upon access until resolved.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg async callback to produce property value.\n * @param required - Pass `true` to run factory immediately and require value.\n */\nfunction set<T>(factory: () => T | Promise<T>, required?: true): T;\n\n/**\n * Set property with a lazy factory, no suspense.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg callback to produce property value.\n * @param required - Pass `false` to allow undefined while pending.\n */\nfunction set<T>(\n factory: () => T | Promise<T>,\n required: boolean\n): T | undefined;\n\n/**\n * Set property with a factory and update callback.\n *\n * Non-enumerable but writable via the callback.\n *\n * @param factory - Callback to produce initial value.\n * @param onUpdate - Callback run when property is updated.\n */\nfunction set<T>(factory: () => T | Promise<T>, onUpdate: set.Callback<T>): T;\n\n/**\n * Define a reactive computed property - the instruction equivalent of a getter.\n *\n * Unlike a zero-arg factory (which runs once and caches), the compute function\n * re-runs whenever any managed property it reads is updated. It receives the\n * instance as both `this` and its first argument, so arrow functions work.\n *\n * Enumerable and read-only, matching a prototype getter. Because it assigns\n * through an instruction rather than a concrete getter, subclasses may refine\n * the property's type with `declare`.\n *\n * @param compute - Function of arity >= 1; receives the instance to derive from.\n */\nfunction set<T, S = any>(compute: (this: S, self: S) => T): T;\n\n/**\n * Set a property with a non-function, non-Promise value.\n *\n * Non-enumerable but writable. Unlike plain assignment (`= value`), this\n * property is excluded from snapshots and `ref(this)`.\n *\n * @param value - Starting value for property.\n * @param onUpdate - Optional callback run when property is set.\n */\n// TODO: if onUpdate is not defined, should this have behavior unique to simple assignment?\n// I'm thinking default behavior should be to assign value directly to property, without triggering any additional updates.\n// All this requires is a default callback which throws true, silent updates are already implemented.\nfunction set<T>(\n value: T extends Promise<any> ? never : T,\n onUpdate?: set.Callback<T>\n): T;\n\nfunction set<T = any>(value?: unknown, argument?: unknown): any {\n return def<T>((key, subject) => {\n if (value instanceof Promise)\n throw new TypeError(\n `Direct promises are not supported in set(${subject}.${key}). Use set(() => promise) instead.`\n );\n\n if (typeof value == 'function' && value.length > 0) {\n compute.call(subject, value as () => unknown, key);\n return;\n }\n\n const config: State.Apply = {\n enumerable: false,\n set: false\n };\n\n let computed = false;\n\n // One-shot factory\n if (typeof value == 'function') {\n const factory = value.bind(subject, key)\n computed = true;\n\n function init() {\n let output: unknown;\n\n try {\n output = attempt(factory);\n } catch (err) {\n console.warn(\n `Generating initial value for ${subject}.${key} failed.`\n );\n throw err;\n }\n\n config.get = argument !== false;\n\n function assign(next: any, silent?: boolean) {\n if (typeof argument == 'function') subject[key] = next;\n else update(subject, key, next, silent, true);\n }\n\n if (output instanceof Promise)\n output.then(assign, (error) => {\n event(subject, key);\n config.get = () => {\n throw error;\n };\n });\n else assign(output, true);\n\n if (argument) return null;\n\n if (output instanceof Promise && argument !== false)\n return access(subject, key, true);\n\n return subject[key];\n }\n\n if (argument) {\n listener(subject, () => {\n init();\n return null;\n });\n } else {\n config.get = init;\n }\n } else if (value !== undefined) {\n config.value = value;\n }\n\n if (typeof argument == 'function') {\n let unset: ((next: T) => void) | undefined;\n\n config.set = function (this: any, value: any, previous: any) {\n capture((release) => {\n const returns = argument.call(this, value, previous);\n\n if (unset) unset(value);\n\n unset = (next: T) => {\n if (typeof returns == 'function') returns(next);\n release();\n };\n });\n };\n } else if (!computed)\n config.set = () => {\n config.get = undefined;\n config.set = undefined;\n };\n\n return config;\n });\n}\n\nfunction attempt(fn: () => any): any {\n function retry(err: unknown) {\n if (err instanceof Promise) return err.then(compute);\n else throw err;\n }\n\n function compute(): any {\n try {\n const output = fn();\n\n return output instanceof Promise ? output.catch(retry) : output;\n } catch (err) {\n return retry(err);\n }\n }\n\n return compute();\n}\n\nexport { set };\n"],"mappings":";;;;;AA8FA,SAAS,IAAa,OAAiB,UAAyB;AAC9D,QAAO,KAAQ,KAAK,YAAY;AAC9B,MAAI,iBAAiB,QACnB,OAAM,IAAI,UACR,4CAA4C,QAAQ,GAAG,IAAI,oCAC5D;AAEH,MAAI,OAAO,SAAS,cAAc,MAAM,SAAS,GAAG;AAClD,WAAQ,KAAK,SAAS,OAAwB,IAAI;AAClD;;EAGF,MAAM,SAAsB;GAC1B,YAAY;GACZ,KAAK;GACN;EAED,IAAI,WAAW;AAGf,MAAI,OAAO,SAAS,YAAY;GAC9B,MAAM,UAAU,MAAM,KAAK,SAAS,IAAI;AACxC,cAAW;GAEX,SAAS,OAAO;IACd,IAAI;AAEJ,QAAI;AACF,cAAS,QAAQ,QAAQ;aAClB,KAAK;AACZ,aAAQ,KACN,gCAAgC,QAAQ,GAAG,IAAI,UAChD;AACD,WAAM;;AAGR,WAAO,MAAM,aAAa;IAE1B,SAAS,OAAO,MAAW,QAAkB;AAC3C,SAAI,OAAO,YAAY,WAAY,SAAQ,OAAO;SAC7C,QAAO,SAAS,KAAK,MAAM,QAAQ,KAAK;;AAG/C,QAAI,kBAAkB,QACpB,QAAO,
|
|
1
|
+
{"version":3,"file":"set.js","names":[],"sources":["../../src/field/set.ts"],"sourcesContent":["import { listener, capture, observer } from '../observable';\nimport { access, compute, event, State, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace set {\n type Callback<T, S = any> = (\n this: S,\n next: T,\n previous: T\n ) => ((next: T) => void) | Promise<any> | void | boolean;\n\n type Factory<T, S = any> = (this: S, property: string) => Promise<T> | T;\n}\n\n/**\n * Set a property as a placeholder, initially `undefined` but required.\n *\n * Property cannot be accessed until it is defined. If accessed while undefined, a hybrid\n * `Promise`/`Error` (aka: [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html)) will be thrown.\n *\n * Non-enumerable; writable only if `onUpdate` callback is provided.\n *\n * @param value - Starting value (undefined for suspense placeholder).\n * @param onUpdate - Callback run when property is set.\n */\nfunction set<T>(value?: undefined, onUpdate?: set.Callback<T>): T;\n\n/**\n * Set property with an async factory function.\n * If required is not defined, factory runs lazily on first access.\n * If async, or returns a promise, suspense is thrown upon access until resolved.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg async callback to produce property value.\n * @param required - Pass `true` to run factory immediately and require value.\n */\nfunction set<T>(factory: () => T | Promise<T>, required?: true): T;\n\n/**\n * Set property with a lazy factory, no suspense.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg callback to produce property value.\n * @param required - Pass `false` to allow undefined while pending.\n */\nfunction set<T>(\n factory: () => T | Promise<T>,\n required: boolean\n): T | undefined;\n\n/**\n * Set property with a factory and update callback.\n *\n * Non-enumerable but writable via the callback.\n *\n * @param factory - Callback to produce initial value.\n * @param onUpdate - Callback run when property is updated.\n */\nfunction set<T>(factory: () => T | Promise<T>, onUpdate: set.Callback<T>): T;\n\n/**\n * Define a reactive computed property - the instruction equivalent of a getter.\n *\n * Unlike a zero-arg factory (which runs once and caches), the compute function\n * re-runs whenever any managed property it reads is updated. It receives the\n * instance as both `this` and its first argument, so arrow functions work.\n *\n * Enumerable and read-only, matching a prototype getter. Because it assigns\n * through an instruction rather than a concrete getter, subclasses may refine\n * the property's type with `declare`.\n *\n * @param compute - Function of arity >= 1; receives the instance to derive from.\n */\nfunction set<T, S = any>(compute: (this: S, self: S) => T): T;\n\n/**\n * Set a property with a non-function, non-Promise value.\n *\n * Non-enumerable but writable. Unlike plain assignment (`= value`), this\n * property is excluded from snapshots and `ref(this)`.\n *\n * @param value - Starting value for property.\n * @param onUpdate - Optional callback run when property is set.\n */\n// TODO: if onUpdate is not defined, should this have behavior unique to simple assignment?\n// I'm thinking default behavior should be to assign value directly to property, without triggering any additional updates.\n// All this requires is a default callback which throws true, silent updates are already implemented.\nfunction set<T>(\n value: T extends Promise<any> ? never : T,\n onUpdate?: set.Callback<T>\n): T;\n\nfunction set<T = any>(value?: unknown, argument?: unknown): any {\n return def<T>((key, subject) => {\n if (value instanceof Promise)\n throw new TypeError(\n `Direct promises are not supported in set(${subject}.${key}). Use set(() => promise) instead.`\n );\n\n if (typeof value == 'function' && value.length > 0) {\n compute.call(subject, value as () => unknown, key);\n return;\n }\n\n const config: State.Apply = {\n enumerable: false,\n set: false\n };\n\n let computed = false;\n\n // One-shot factory\n if (typeof value == 'function') {\n const factory = value.bind(subject, key)\n computed = true;\n\n function init() {\n let output: unknown;\n\n try {\n output = attempt(factory);\n } catch (err) {\n console.warn(\n `Generating initial value for ${subject}.${key} failed.`\n );\n throw err;\n }\n\n config.get = argument !== false;\n\n function assign(next: any, silent?: boolean) {\n if (typeof argument == 'function') subject[key] = next;\n else update(subject, key, next, silent, true);\n }\n\n if (output instanceof Promise)\n output.then((next) => {\n if (observer(subject) !== null) assign(next);\n }, (error) => {\n if (observer(subject) === null) return;\n event(subject, key);\n config.get = () => {\n throw error;\n };\n });\n else assign(output, true);\n\n if (argument) return null;\n\n if (output instanceof Promise && argument !== false)\n return access(subject, key, true);\n\n return subject[key];\n }\n\n if (argument) {\n listener(subject, () => {\n init();\n return null;\n });\n } else {\n config.get = init;\n }\n } else if (value !== undefined) {\n config.value = value;\n }\n\n if (typeof argument == 'function') {\n let unset: ((next: T) => void) | undefined;\n\n config.set = function (this: any, value: any, previous: any) {\n capture((release) => {\n const returns = argument.call(this, value, previous);\n\n if (unset) unset(value);\n\n unset = (next: T) => {\n if (typeof returns == 'function') returns(next);\n release();\n };\n });\n };\n } else if (!computed)\n config.set = () => {\n config.get = undefined;\n config.set = undefined;\n };\n\n return config;\n });\n}\n\nfunction attempt(fn: () => any): any {\n function retry(err: unknown) {\n if (err instanceof Promise) return err.then(compute);\n else throw err;\n }\n\n function compute(): any {\n try {\n const output = fn();\n\n return output instanceof Promise ? output.catch(retry) : output;\n } catch (err) {\n return retry(err);\n }\n }\n\n return compute();\n}\n\nexport { set };\n"],"mappings":";;;;;AA8FA,SAAS,IAAa,OAAiB,UAAyB;AAC9D,QAAO,KAAQ,KAAK,YAAY;AAC9B,MAAI,iBAAiB,QACnB,OAAM,IAAI,UACR,4CAA4C,QAAQ,GAAG,IAAI,oCAC5D;AAEH,MAAI,OAAO,SAAS,cAAc,MAAM,SAAS,GAAG;AAClD,WAAQ,KAAK,SAAS,OAAwB,IAAI;AAClD;;EAGF,MAAM,SAAsB;GAC1B,YAAY;GACZ,KAAK;GACN;EAED,IAAI,WAAW;AAGf,MAAI,OAAO,SAAS,YAAY;GAC9B,MAAM,UAAU,MAAM,KAAK,SAAS,IAAI;AACxC,cAAW;GAEX,SAAS,OAAO;IACd,IAAI;AAEJ,QAAI;AACF,cAAS,QAAQ,QAAQ;aAClB,KAAK;AACZ,aAAQ,KACN,gCAAgC,QAAQ,GAAG,IAAI,UAChD;AACD,WAAM;;AAGR,WAAO,MAAM,aAAa;IAE1B,SAAS,OAAO,MAAW,QAAkB;AAC3C,SAAI,OAAO,YAAY,WAAY,SAAQ,OAAO;SAC7C,QAAO,SAAS,KAAK,MAAM,QAAQ,KAAK;;AAG/C,QAAI,kBAAkB,QACpB,QAAO,MAAM,SAAS;AACpB,SAAI,SAAS,QAAQ,KAAK,KAAM,QAAO,KAAK;QAC1C,UAAU;AACZ,SAAI,SAAS,QAAQ,KAAK,KAAM;AAChC,WAAM,SAAS,IAAI;AACnB,YAAO,YAAY;AACjB,YAAM;;MAER;QACC,QAAO,QAAQ,KAAK;AAEzB,QAAI,SAAU,QAAO;AAErB,QAAI,kBAAkB,WAAW,aAAa,MAC5C,QAAO,OAAO,SAAS,KAAK,KAAK;AAEnC,WAAO,QAAQ;;AAGjB,OAAI,SACF,UAAS,eAAe;AACtB,UAAM;AACN,WAAO;KACP;OAEF,QAAO,MAAM;aAEN,UAAU,OACnB,QAAO,QAAQ;AAGjB,MAAI,OAAO,YAAY,YAAY;GACjC,IAAI;AAEJ,UAAO,MAAM,SAAqB,OAAY,UAAe;AAC3D,aAAS,YAAY;KACnB,MAAM,UAAU,SAAS,KAAK,MAAM,OAAO,SAAS;AAEpD,SAAI,MAAO,OAAM,MAAM;AAEvB,cAAS,SAAY;AACnB,UAAI,OAAO,WAAW,WAAY,SAAQ,KAAK;AAC/C,eAAS;;MAEX;;aAEK,CAAC,SACV,QAAO,YAAY;AACjB,UAAO,MAAM;AACb,UAAO,MAAM;;AAGjB,SAAO;GACP;;AAGJ,SAAS,QAAQ,IAAoB;CACnC,SAAS,MAAM,KAAc;AAC3B,MAAI,eAAe,QAAS,QAAO,IAAI,KAAK,QAAQ;MAC/C,OAAM;;CAGb,SAAS,UAAe;AACtB,MAAI;GACF,MAAM,SAAS,IAAI;AAEnB,UAAO,kBAAkB,UAAU,OAAO,MAAM,MAAM,GAAG;WAClD,KAAK;AACZ,UAAO,MAAM,IAAI;;;AAIrB,QAAO,SAAS"}
|