@expressive/mvc 0.88.0 → 0.90.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 +18 -18
- package/dist/component.d.ts +11 -19
- package/dist/component.js +5 -51
- package/dist/component.js.map +1 -1
- package/dist/context.d.ts +22 -35
- package/dist/context.js +42 -68
- package/dist/context.js.map +1 -1
- package/dist/field/def.d.ts +3 -3
- package/dist/field/def.js +6 -6
- package/dist/field/def.js.map +1 -1
- package/dist/field/get.d.ts +16 -16
- package/dist/field/get.js +3 -3
- package/dist/field/get.js.map +1 -1
- package/dist/field/has.d.ts +8 -8
- package/dist/field/has.js +3 -3
- package/dist/field/has.js.map +1 -1
- package/dist/field/map.d.ts +2 -2
- package/dist/field/map.js +2 -2
- package/dist/field/map.js.map +1 -1
- package/dist/field/ref.d.ts +8 -8
- package/dist/field/ref.js +3 -3
- package/dist/field/ref.js.map +1 -1
- package/dist/field/set.js.map +1 -1
- package/dist/hot.d.ts +4 -4
- package/dist/hot.js +7 -11
- package/dist/hot.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime.d.ts +2 -2
- package/dist/jsx-runtime.js +1 -3
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/observable.d.ts +7 -4
- package/dist/observable.js +94 -27
- package/dist/observable.js.map +1 -1
- package/dist/state.d.ts +110 -96
- package/dist/state.js +53 -39
- package/dist/state.js.map +1 -1
- package/package.json +1 -1
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>();\nconst HELD = new WeakMap<State, Map<State, Set<() => void>>>();\nconst HOST = new WeakMap<Context, 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 const single = typeof inputs == \"function\" || inputs instanceof State;\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 if (single && this !== ROOT) HOST.set(this, state);\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) return entries.delete(entry);\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, added]) => {\n const done = this.add(child);\n added.add(done);\n return () => {\n if (added.delete(done)) done();\n };\n });\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 Map();\n const added = new Set<() => void>();\n\n HELD.set(state, held.set(value, added));\n\n return () => {\n held.delete(value);\n added.forEach((done) => {\n added.delete(done);\n done();\n });\n };\n}\n\n/** The State a host mounted `state` under - the one its nearest enclosing context was set up for. */\nfunction host(state: State) {\n for (let ctx = LOOKUP.get(state); ctx; ctx = ctx.parent) {\n const found = HOST.get(ctx);\n if (found && found !== state) return found;\n }\n}\n\nexport { Context, host, join };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import { listener } from \"./observable\";\nimport { event, Model, uid } from \"./state\";\n\nconst LOOKUP = new WeakMap<Model, Context>();\nconst HELD = new WeakMap<Model, Map<Model, Set<() => void>>>();\nconst HOST = new WeakMap<Context, Model>();\nconst CLEANUP = new WeakMap<Context, Set<() => void>>();\nlet ROOT: Context;\n\ntype Accept<T extends Model = Model> =\n | T\n | Model.Type<T>\n | Record<string | number, T | Model.Type<T>>;\n\ntype Expect<T extends Model = Model> = (\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 Model. Adapters may override to provide framework context. */\n static get(state?: Model): 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 Model.Extends,\n Set<[Expect, boolean | undefined]> | null\n >();\n public provide = new Map<Model.Extends, Set<[Model, boolean]> | null>();\n\n constructor(arg?: Context | Accept) {\n CLEANUP.set(this, new Set());\n\n if (arg instanceof Context) {\n this.parent = arg;\n arg.scope.add(this);\n } else if (arg) {\n insert(this, 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 Model>(\n type: Model.Extends<T>,\n value: [Expect<T>, boolean | undefined],\n asConsumer: true,\n ): () => void;\n\n private register<T extends Model>(\n type: Model.Extends<T>,\n value: [T, boolean],\n asConsumer?: false,\n ): () => void;\n\n private register(type: Model.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 Model>(Type: Model.Extends<T>, required?: true): T;\n\n /** Find specified type upstream. Returns undefined if not found. */\n public get<T extends Model>(\n Type: Model.Extends<T>,\n required?: boolean,\n ): T | undefined;\n\n /** Subscribe to a type becoming available in context. */\n public get<T extends Model>(\n Type: Model.Extends<T>,\n callback: Expect<T>,\n downstream?: boolean,\n ): () => void;\n\n /** Lookup excluding a specific instance (used by Model.prototype.get for upstream-of-self semantics). */\n public get<T extends Model>(\n Type: Model.Extends<T>,\n arg: boolean | Expect<T> | undefined,\n downstream: boolean | undefined,\n skip: Model,\n ): T | undefined | (() => void);\n\n public get<T extends Model>(\n Type: Model.Extends<T>,\n arg?: boolean | Expect<T>,\n downstream?: boolean,\n skip?: Model,\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 add(I: Model, explicit = false) {\n const { provide } = this;\n const root = this === Context.root;\n const TT: Model.Extends[] = [];\n\n function conflict(T: Model.Extends) {\n const entries = provide.get(T);\n if (entries)\n for (const entry of entries)\n if (!entry[1] && entry[0] !== I) return entries.delete(entry);\n }\n\n for (\n let T = I.constructor as Model.Extends;\n T !== Model;\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 cleanup = CLEANUP.get(this)!;\n const held = Array.from(HELD.get(I) || [], ([child, added]) => {\n const done = this.add(child);\n added.add(done);\n return () => {\n if (added.delete(done)) done();\n };\n });\n\n function remove() {\n cleanup.delete(remove);\n held.forEach((done) => done());\n flush();\n }\n\n cleanup.add(remove);\n\n return remove;\n }\n\n /**\n * Create a child context, optionally registering Models to it.\n *\n * @param input Model instance to adopt, Model class to create - and destroy when the context pops - or an object of them, all registered before any activates.\n * @param cleanup Called once when the context pops, before its Models are removed.\n */\n public push(input?: Accept, cleanup?: () => void) {\n const next = new Context(this);\n\n if (cleanup) CLEANUP.get(next)!.add(cleanup);\n if (input) insert(next, input);\n\n return next;\n }\n\n /**\n * Remove all Models from this context.\n *\n * Will also run any cleanup callbacks registered when Models were added.\n */\n public pop() {\n this.scope.forEach((x) => x.pop());\n this.scope.clear();\n const cleanup = CLEANUP.get(this)!;\n cleanup.forEach((cb) => cb());\n 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: Model, value: Model): () => void {\n const ctx = LOOKUP.get(state.is);\n\n if (ctx) return ctx.add(value);\n\n const held = HELD.get(state) || new Map();\n const added = new Set<() => void>();\n\n HELD.set(state, held.set(value, added));\n\n return () => {\n held.delete(value);\n added.forEach((done) => {\n added.delete(done);\n done();\n });\n };\n}\n\n/** The Model a host mounted `state` under - the one its nearest enclosing context was set up for. */\nfunction host(state: Model) {\n for (let ctx = LOOKUP.get(state); ctx; ctx = ctx.parent) {\n const found = HOST.get(ctx);\n if (found && found !== state) return found;\n }\n}\n\nfunction insert(into: Context, input: Accept) {\n const single = typeof input == \"function\" || input instanceof Model;\n const entries = Object.entries(single ? { input } : input);\n const init: Model[] = [];\n const owns: Model[] = [];\n\n for (const [K, V] of entries) {\n const owned = Model.is(V);\n\n if (!(owned || V instanceof Model)) {\n const as = single || K == String(V) ? V : `${V} (as '${K}')`;\n throw new Error(\n `Context can only include an instance or class of Model but got ${as}.`,\n );\n }\n\n const state = owned ? new V() : V.is;\n\n into.add(state, true);\n init.push(state);\n\n if (single) HOST.set(into, state);\n if (owned) owns.push(state);\n }\n\n const cleanup = CLEANUP.get(into)!;\n\n for (const state of owns) cleanup.add(() => event(state, null));\n for (const state of init) event(state);\n}\n\nexport { Context, host, join };\n"],"mappings":"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"}
|
package/dist/field/def.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model } from "../state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/field/def.d.ts
|
|
4
4
|
declare namespace def {
|
|
@@ -6,8 +6,8 @@ declare namespace def {
|
|
|
6
6
|
* Property initializer, will run upon instance creation.
|
|
7
7
|
* Optional returned callback will run when once upon first access.
|
|
8
8
|
*/
|
|
9
|
-
type Factory<T = any, M extends
|
|
10
|
-
interface Config<T = any> extends
|
|
9
|
+
type Factory<T = any, M extends Model = any> = (this: M, key: Extract<Model.Field<M>, string>, thisArg: M, state: Model.Values<M>) => def.Config<T> | (() => void) | void;
|
|
10
|
+
interface Config<T = any> extends Model.Apply<T> {
|
|
11
11
|
destroy?: () => void;
|
|
12
12
|
}
|
|
13
13
|
}
|
package/dist/field/def.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { listener } from "../observable.js";
|
|
2
|
-
import { PENDING, STORE,
|
|
2
|
+
import { Model, PENDING, STORE, apply, uid } from "../state.js";
|
|
3
3
|
|
|
4
4
|
//#region src/field/def.ts
|
|
5
5
|
const APPLY = /* @__PURE__ */ new Map();
|
|
6
6
|
const RESET = () => APPLY.clear();
|
|
7
7
|
function def(arg1) {
|
|
8
|
-
if (!PENDING.size || PENDING.size == 1 && PENDING.has(RESET)) throw new Error("Instruction created with no
|
|
8
|
+
if (!PENDING.size || PENDING.size == 1 && PENDING.has(RESET)) throw new Error("Instruction created with no Model under construction.");
|
|
9
9
|
PENDING.add(RESET);
|
|
10
10
|
const token = Symbol("field-" + uid());
|
|
11
|
-
APPLY.set(token, [arg1, [...PENDING].filter((x) => x instanceof
|
|
11
|
+
APPLY.set(token, [arg1, [...PENDING].filter((x) => x instanceof Model)]);
|
|
12
12
|
return token;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
Model.on({ setup(self) {
|
|
15
15
|
const store = STORE.get(self);
|
|
16
16
|
for (const key in self) {
|
|
17
17
|
const property = Object.getOwnPropertyDescriptor(self, key) || {};
|
|
18
18
|
const entry = APPLY.get(property.value);
|
|
19
|
-
if (entry === null) throw new Error(`${self}.${key} has an instruction applied to another
|
|
19
|
+
if (entry === null) throw new Error(`${self}.${key} has an instruction applied to another Model.`);
|
|
20
20
|
if (!entry) continue;
|
|
21
21
|
if (key[0] == "_") throw new Error(`${self}.${key} is unmanaged - instructions cannot apply to _ keys.`);
|
|
22
22
|
const [instruction, pending] = entry;
|
|
@@ -31,7 +31,7 @@ State.on({ setup(self) {
|
|
|
31
31
|
}
|
|
32
32
|
} });
|
|
33
33
|
/**
|
|
34
|
-
* Drop pending
|
|
34
|
+
* Drop pending Models constructed after `self` and before the instruction -
|
|
35
35
|
* products of its own initializers, discarded when this token replaced them.
|
|
36
36
|
*/
|
|
37
37
|
function discard(self, pending) {
|
package/dist/field/def.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"def.js","names":[],"sources":["../../src/field/def.ts"],"sourcesContent":["import { listener } from '../observable';\nimport { PENDING,
|
|
1
|
+
{"version":3,"file":"def.js","names":[],"sources":["../../src/field/def.ts"],"sourcesContent":["import { listener } from '../observable';\nimport { PENDING, Model, STORE, uid, apply } from '../state';\n\ndeclare namespace def {\n /**\n * Property initializer, will run upon instance creation.\n * Optional returned callback will run when once upon first access.\n */\n type Factory<T = any, M extends Model = any> = (\n this: M,\n key: Extract<Model.Field<M>, string>,\n thisArg: M,\n state: Model.Values<M>\n ) => def.Config<T> | (() => void) | void;\n\n interface Config<T = any> extends Model.Apply<T> {\n destroy?: () => void;\n }\n}\n\nconst APPLY = new Map<symbol, [def.Factory, Model[]] | null>();\nconst RESET = () => APPLY.clear();\n\nfunction def<T>(arg1: def.Factory<T>) {\n if (!PENDING.size || (PENDING.size == 1 && PENDING.has(RESET)))\n throw new Error(\n 'Instruction created with no Model under construction.'\n );\n\n PENDING.add(RESET);\n\n const token = Symbol('field-' + uid());\n\n APPLY.set(token, [arg1, [...PENDING].filter((x) => x instanceof Model) as Model[]]);\n\n return token as T extends void ? unknown : T;\n}\n\nModel.on({\n setup(self) {\n const store = STORE.get(self)!;\n\n for (const key in self) {\n const property: PropertyDescriptor = Object.getOwnPropertyDescriptor(self, key) || {};\n const entry = APPLY.get(property.value);\n\n if (entry === null)\n throw new Error(\n `${self}.${key} has an instruction applied to another Model.`\n );\n\n if (!entry) continue;\n\n if (key[0] == '_')\n throw new Error(`${self}.${key} is unmanaged - instructions cannot apply to _ keys.`);\n\n const [instruction, pending] = entry;\n\n APPLY.set(property.value, null);\n discard(self, pending);\n delete (self as any)[key];\n\n const output = instruction.call(self, key, self, store);\n\n if (!output) continue;\n\n const desc = typeof output == 'function' ? { destroy: output } : output;\n\n if (desc.destroy) listener(self, desc.destroy, null);\n\n apply(self, key, desc, true);\n }\n }\n});\n\n/**\n * Drop pending Models constructed after `self` and before the instruction -\n * products of its own initializers, discarded when this token replaced them.\n */\nfunction discard(self: Model, pending: Model[]) {\n let seen = false;\n\n for (const item of pending)\n if (!seen) seen = item === self;\n else PENDING.delete(item);\n}\n\nexport { def };\n"],"mappings":";;;;AAoBA,MAAM,wBAAQ,IAAI,KAA4C;AAC9D,MAAM,cAAc,MAAM,OAAO;AAEjC,SAAS,IAAO,MAAsB;AACpC,KAAI,CAAC,QAAQ,QAAS,QAAQ,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAC3D,OAAM,IAAI,MACR,wDACD;AAEH,SAAQ,IAAI,MAAM;CAElB,MAAM,QAAQ,OAAO,WAAW,KAAK,CAAC;AAEtC,OAAM,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,MAAM,aAAa,MAAM,CAAY,CAAC;AAEnF,QAAO;;AAGT,MAAM,GAAG,EACP,MAAM,MAAM;CACV,MAAM,QAAQ,MAAM,IAAI,KAAK;AAE7B,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,WAA+B,OAAO,yBAAyB,MAAM,IAAI,IAAI,EAAE;EACrF,MAAM,QAAQ,MAAM,IAAI,SAAS,MAAM;AAEvC,MAAI,UAAU,KACZ,OAAM,IAAI,MACR,GAAG,KAAK,GAAG,IAAI,+CAChB;AAEH,MAAI,CAAC,MAAO;AAEZ,MAAI,IAAI,MAAM,IACZ,OAAM,IAAI,MAAM,GAAG,KAAK,GAAG,IAAI,sDAAsD;EAEvF,MAAM,CAAC,aAAa,WAAW;AAE/B,QAAM,IAAI,SAAS,OAAO,KAAK;AAC/B,UAAQ,MAAM,QAAQ;AACtB,SAAQ,KAAa;EAErB,MAAM,SAAS,YAAY,KAAK,MAAM,KAAK,MAAM,MAAM;AAEvD,MAAI,CAAC,OAAQ;EAEb,MAAM,OAAO,OAAO,UAAU,aAAa,EAAE,SAAS,QAAQ,GAAG;AAEjE,MAAI,KAAK,QAAS,UAAS,MAAM,KAAK,SAAS,KAAK;AAEpD,QAAM,MAAM,KAAK,MAAM,KAAK;;GAGjC,CAAC;;;;;AAMF,SAAS,QAAQ,MAAa,SAAkB;CAC9C,IAAI,OAAO;AAEX,MAAK,MAAM,QAAQ,QACjB,KAAI,CAAC,KAAM,QAAO,SAAS;KACtB,SAAQ,OAAO,KAAK"}
|
package/dist/field/get.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model } from "../state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/field/get.d.ts
|
|
4
4
|
declare namespace get {
|
|
5
|
-
type Callback<T = any> = (state: T, subject:
|
|
5
|
+
type Callback<T = any> = (state: T, subject: Model) => void | boolean | (() => void);
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Fetches upstream
|
|
8
|
+
* Fetches upstream Model from context with optional lifecycle callback.
|
|
9
9
|
* Callback runs on mount and can return cleanup function for unmount.
|
|
10
10
|
*
|
|
11
|
-
* @param Type - Type of
|
|
11
|
+
* @param Type - Type of Model to fetch.
|
|
12
12
|
* @param callback - Optional lifecycle callback, receives (state, subject). Can return cleanup function.
|
|
13
13
|
*/
|
|
14
|
-
declare function get<T extends
|
|
14
|
+
declare function get<T extends Model>(Type: Model.Extends<T>, callback?: get.Callback<T>): T;
|
|
15
15
|
/**
|
|
16
16
|
* Fetches and assigns the controller which spawned this host.
|
|
17
17
|
* When parent assigns an instance via `use()` directive, it
|
|
@@ -20,38 +20,38 @@ declare function get<T extends State>(Type: State.Extends<T>, callback?: get.Cal
|
|
|
20
20
|
* @param Type - Type of controller compatible with this class.
|
|
21
21
|
* @param required - If false, property may be undefined. Otherwise will throw.
|
|
22
22
|
*/
|
|
23
|
-
declare function get<T extends
|
|
23
|
+
declare function get<T extends Model>(Type: Model.Extends<T>, required: false): T | undefined;
|
|
24
24
|
/**
|
|
25
|
-
* Collects downstream
|
|
26
|
-
* for which this is an ancestor. Returns an array that updates as
|
|
25
|
+
* Collects downstream Models, accumulating all instances of specified type
|
|
26
|
+
* for which this is an ancestor. Returns an array that updates as Models
|
|
27
27
|
* are added or removed. Callback runs on each registration and can return
|
|
28
28
|
* cleanup or false to prevent registration.
|
|
29
29
|
*
|
|
30
|
-
* @param Type - Type of
|
|
30
|
+
* @param Type - Type of Model to collect.
|
|
31
31
|
* @param downstream - Must be true to enable downstream mode.
|
|
32
32
|
* @param callback - Optional lifecycle callback, receives (state, subject). May return false to prevent registration.
|
|
33
33
|
*/
|
|
34
|
-
declare function get<T extends
|
|
34
|
+
declare function get<T extends Model>(Type: Model.Extends<T>, downstream: true, callback?: get.Callback<T>): T[];
|
|
35
35
|
/**
|
|
36
|
-
* Fetches a single downstream
|
|
36
|
+
* Fetches a single downstream Model of specified type.
|
|
37
37
|
* Updates when a matching child appears or is removed.
|
|
38
38
|
* Throws if not found.
|
|
39
39
|
*
|
|
40
|
-
* @param Type - Type of
|
|
40
|
+
* @param Type - Type of Model to fetch.
|
|
41
41
|
* @param downstream - Must be true to enable downstream mode.
|
|
42
42
|
* @param required - Throw if no match found.
|
|
43
43
|
*/
|
|
44
|
-
declare function get<T extends
|
|
44
|
+
declare function get<T extends Model>(Type: Model.Extends<T>, downstream: true, single: true): T;
|
|
45
45
|
/**
|
|
46
|
-
* Fetches a single downstream
|
|
46
|
+
* Fetches a single downstream Model of specified type.
|
|
47
47
|
* Updates when a matching child appears or is removed.
|
|
48
48
|
* Returns undefined if not found.
|
|
49
49
|
*
|
|
50
|
-
* @param Type - Type of
|
|
50
|
+
* @param Type - Type of Model to fetch.
|
|
51
51
|
* @param downstream - Must be true to enable downstream mode.
|
|
52
52
|
* @param required - If false, returns undefined if no match found.
|
|
53
53
|
*/
|
|
54
|
-
declare function get<T extends
|
|
54
|
+
declare function get<T extends Model>(Type: Model.Extends<T>, downstream: true, required: false): T | undefined;
|
|
55
55
|
//#endregion
|
|
56
56
|
export { get };
|
|
57
57
|
//# sourceMappingURL=get.d.ts.map
|
package/dist/field/get.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { capture, listener, observer } from "../observable.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Model, STORE, children, owned, parent, update } from "../state.js";
|
|
3
3
|
import { Context } from "../context.js";
|
|
4
4
|
import { def } from "./def.js";
|
|
5
5
|
|
|
@@ -23,7 +23,7 @@ function above(Type, argument) {
|
|
|
23
23
|
assign(hasParent);
|
|
24
24
|
return {};
|
|
25
25
|
}
|
|
26
|
-
if (Type ===
|
|
26
|
+
if (Type === Model) {
|
|
27
27
|
if (argument === false) return {
|
|
28
28
|
get: false,
|
|
29
29
|
enumerable: false
|
|
@@ -83,7 +83,7 @@ function above(Type, argument) {
|
|
|
83
83
|
function below(Type, arg) {
|
|
84
84
|
return def((key, subject) => {
|
|
85
85
|
const context = Context.get(subject);
|
|
86
|
-
const watch = (callback) => Type ===
|
|
86
|
+
const watch = (callback) => Type === Model ? owned(subject, callback) : context.get(Type, callback, true);
|
|
87
87
|
if (typeof arg == "boolean") {
|
|
88
88
|
watch((state) => {
|
|
89
89
|
update(subject, key, state);
|
package/dist/field/get.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get.js","names":[],"sources":["../../src/field/get.ts"],"sourcesContent":["import { capture, listener, observer } from '../observable';\nimport { Context } from '../context';\nimport {
|
|
1
|
+
{"version":3,"file":"get.js","names":[],"sources":["../../src/field/get.ts"],"sourcesContent":["import { capture, listener, observer } from '../observable';\nimport { Context } from '../context';\nimport { Model, children, owned, parent, STORE, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace get {\n type Callback<T = any> = (\n state: T,\n subject: Model\n ) => void | boolean | (() => void);\n}\n\n/**\n * Fetches upstream Model from context with optional lifecycle callback.\n * Callback runs on mount and can return cleanup function for unmount.\n *\n * @param Type - Type of Model to fetch.\n * @param callback - Optional lifecycle callback, receives (state, subject). Can return cleanup function.\n */\nfunction get<T extends Model>(\n Type: Model.Extends<T>,\n callback?: get.Callback<T>\n): T;\n\n/**\n * Fetches and assigns the controller which spawned this host.\n * When parent assigns an instance via `use()` directive, it\n * will be made available to child upon this request.\n *\n * @param Type - Type of controller compatible with this class.\n * @param required - If false, property may be undefined. Otherwise will throw.\n */\nfunction get<T extends Model>(\n Type: Model.Extends<T>,\n required: false\n): T | undefined;\n\n/**\n * Collects downstream Models, accumulating all instances of specified type\n * for which this is an ancestor. Returns an array that updates as Models\n * are added or removed. Callback runs on each registration and can return\n * cleanup or false to prevent registration.\n *\n * @param Type - Type of Model to collect.\n * @param downstream - Must be true to enable downstream mode.\n * @param callback - Optional lifecycle callback, receives (state, subject). May return false to prevent registration.\n */\nfunction get<T extends Model>(\n Type: Model.Extends<T>,\n downstream: true,\n callback?: get.Callback<T>\n): T[];\n\n/**\n * Fetches a single downstream Model of specified type.\n * Updates when a matching child appears or is removed.\n * Throws if not found.\n *\n * @param Type - Type of Model to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - Throw if no match found.\n */\nfunction get<T extends Model>(\n Type: Model.Extends<T>,\n downstream: true,\n single: true\n): T;\n\n/**\n * Fetches a single downstream Model of specified type.\n * Updates when a matching child appears or is removed.\n * Returns undefined if not found.\n *\n * @param Type - Type of Model to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - If false, returns undefined if no match found.\n */\nfunction get<T extends Model>(\n Type: Model.Extends<T>,\n downstream: true,\n required: false\n): T | undefined;\n\nfunction get<T extends Model>(\n Type: Model.Extends<T>,\n arg1?: get.Callback<T> | boolean,\n arg2?: get.Callback<T> | boolean\n) {\n return arg1 === true ? below(Type, arg2) : above(Type, arg1);\n}\n\nfunction above<T extends Model>(\n Type: Model.Extends<T>,\n argument: get.Callback<T> | boolean | undefined\n) {\n return def<T>((key, subject) => {\n const hasParent = parent(subject);\n const callback =\n typeof argument === 'function'\n ? (argument as get.Callback<T>)\n : undefined;\n\n function assign(value: T) {\n if (STORE.get(subject)![key] === value) return;\n\n if (callback) {\n const result = callback(value, subject);\n if (typeof result === 'function') subject.set(null, result);\n }\n update(subject, key, value);\n }\n\n if (hasParent && hasParent instanceof Type) {\n assign(hasParent as T);\n return {};\n }\n\n if (Type === Model) {\n if (argument === false) return { get: false, enumerable: false };\n throw new Error(`${subject} has no owner.`);\n }\n\n let found = false;\n let depth = Infinity;\n let level = 0;\n\n for (let p: Model | null | undefined = hasParent; p; p = parent(p), level++) {\n const at = level;\n\n if (p instanceof Type) {\n if (!found) {\n found = true;\n depth = at;\n assign(p as T);\n }\n break;\n }\n\n const remove = children(p, (child) => {\n if (child !== subject && child instanceof Type && at <= depth) {\n found = true;\n depth = at;\n assign(child as T);\n }\n });\n\n subject.set(null, () => { remove(); });\n }\n\n if (!found) {\n const remove = Context.get(subject).get(Type, (state) => {\n if (depth !== Infinity) return;\n found = true;\n assign(state);\n }, false, subject) as () => void;\n\n subject.set(null, () => { remove(); });\n }\n\n if (!found && argument !== false) {\n const missing = () =>\n new Error(`Required ${Type} not found in context for ${subject}.`);\n\n let activating: Model | undefined;\n\n for (\n let p: Model | null | undefined = hasParent;\n p && !observer(p)!.ready;\n p = parent(p)\n )\n activating = p;\n\n if (!activating) throw missing();\n\n listener(activating, () => {\n if (!found) throw missing();\n return null;\n }, true);\n }\n\n return {\n get: argument !== false,\n enumerable: false\n };\n });\n}\n\nfunction below<T extends Model>(\n Type: Model.Extends<T>,\n arg: get.Callback<T> | boolean | undefined\n) {\n return def<T[]>((key, subject) => {\n const context = Context.get(subject);\n const watch = (callback: (state: T) => (() => void) | void) =>\n Type === Model\n ? owned(subject, callback as (state: Model) => (() => void) | void)\n : context.get(Type, callback, true);\n\n if (typeof arg == 'boolean') {\n watch(\n (state) => {\n update(subject, key, state);\n return state.set(null, () => {\n update(subject, key, undefined);\n });\n }\n );\n\n return {\n get: arg,\n value: undefined,\n enumerable: false\n };\n }\n\n const applied = new Set<Model>();\n\n watch(\n (state) => {\n let remove: (() => void) | undefined;\n let release: (() => void) | undefined;\n\n if (applied.has(state)) return;\n\n if (arg) {\n let rejected = false;\n\n capture((fn) => {\n const done = arg(state, subject);\n\n if (done === false) rejected = true;\n else if (typeof done == 'function') remove = done;\n\n release = fn;\n });\n\n if (rejected) return;\n }\n\n applied.add(state);\n update(subject, key, [...applied]);\n\n function done() {\n if (release) release();\n ignore();\n\n applied.delete(state);\n update(subject, key, [...applied]);\n\n if (typeof remove == 'function') remove();\n }\n\n const ignore = state.set(null, done);\n\n return done;\n }\n );\n\n return {\n value: [],\n enumerable: false\n };\n });\n}\n\nexport { get };\n"],"mappings":"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"}
|
package/dist/field/has.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model } from "../state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/field/has.d.ts
|
|
4
4
|
type Predicate<T> = (value: T, index: number, self: unknown) => boolean;
|
|
@@ -7,13 +7,13 @@ declare namespace has {
|
|
|
7
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
|
|
11
|
-
declare function has<T extends
|
|
10
|
+
declare function has<T extends Model>(Type: new (...args: Model.Args<T>) => T): Create<T>;
|
|
11
|
+
declare function has<T extends Model, K extends Model.Field<T>>(Type: new (...args: Model.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);
|
|
15
15
|
get size(): number;
|
|
16
|
-
get():
|
|
16
|
+
get(): Model.Export<T>[];
|
|
17
17
|
get(index: number): T | undefined;
|
|
18
18
|
get(start: number, end: number): T[];
|
|
19
19
|
get(predicate: Predicate<T>): T | undefined;
|
|
@@ -31,11 +31,11 @@ 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
|
|
35
|
-
add(...args:
|
|
34
|
+
interface Create<T extends Model> extends Pool<T, Model.Args<T>> {
|
|
35
|
+
add(...args: Model.Args<T>): T;
|
|
36
36
|
add(instance: T): T;
|
|
37
37
|
}
|
|
38
|
-
interface From<T extends
|
|
38
|
+
interface From<T extends Model, K extends Model.Field<T>> extends Pool<T, [from: T[K]]> {
|
|
39
39
|
add(from: T[K]): T;
|
|
40
40
|
add(instance: T): T;
|
|
41
41
|
}
|
|
@@ -43,7 +43,7 @@ declare class Pool<T, A extends unknown[] = unknown[], R = T> {
|
|
|
43
43
|
constructor(make: Function, fromKey?: string);
|
|
44
44
|
get size(): number;
|
|
45
45
|
add(...args: A): R;
|
|
46
|
-
get():
|
|
46
|
+
get(): Model.Export<T>[];
|
|
47
47
|
get(predicate: Predicate<T>): T | undefined;
|
|
48
48
|
has(value: T): boolean;
|
|
49
49
|
delete(value: T): boolean;
|
package/dist/field/has.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { event, listener, touch } from "../observable.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Model, parent } from "../state.js";
|
|
3
3
|
import { Context } from "../context.js";
|
|
4
4
|
import { def } from "./def.js";
|
|
5
5
|
|
|
@@ -99,7 +99,7 @@ var List = class {
|
|
|
99
99
|
};
|
|
100
100
|
var Pool = class {
|
|
101
101
|
constructor(make, fromKey) {
|
|
102
|
-
if (
|
|
102
|
+
if (Model.is(make)) {
|
|
103
103
|
const Type = make;
|
|
104
104
|
make = (...args) => args.length == 1 && args[0] instanceof Type ? args[0] : fromKey ? new Type({ [fromKey]: args[0] }) : new Type(...args);
|
|
105
105
|
}
|
|
@@ -172,7 +172,7 @@ function source(from) {
|
|
|
172
172
|
return OWNED.has(from) ? from : Object.getPrototypeOf(from);
|
|
173
173
|
}
|
|
174
174
|
function adopt(target, key, value) {
|
|
175
|
-
if (!(value instanceof
|
|
175
|
+
if (!(value instanceof Model)) return;
|
|
176
176
|
const owner = parent(target);
|
|
177
177
|
const fresh = parent(value, owner ?? null);
|
|
178
178
|
const evict = listener(value, () => void target.delete(key), null);
|
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, 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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"}
|
|
1
|
+
{"version":3,"file":"has.js","names":[],"sources":["../../src/field/has.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport { Model, 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 Model>(\n Type: new (...args: Model.Args<T>) => T\n): Create<T>;\n\nfunction has<T extends Model, K extends Model.Field<T>>(\n Type: new (...args: Model.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(): Model.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 Model> extends Pool<T, Model.Args<T>> {\n add(...args: Model.Args<T>): T;\n add(instance: T): T;\n}\n\ninterface From<T extends Model, K extends Model.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 (Model.is(make)) {\n const Type = make as unknown as Model.Type;\n\n make = (...args: Model.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(): Model.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 Model)) 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.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model } from "../state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/field/map.d.ts
|
|
4
4
|
declare namespace map {
|
|
@@ -15,7 +15,7 @@ declare function map<A extends [unknown, ...unknown[]], V>(make: (...args: A) =>
|
|
|
15
15
|
declare class Managed<K, V> extends Map<K, V> {
|
|
16
16
|
constructor(arg?: Iterable<readonly [K, V]> | Function | false | null);
|
|
17
17
|
get size(): number;
|
|
18
|
-
get(): ReadonlyMap<K,
|
|
18
|
+
get(): ReadonlyMap<K, Model.Export<V>>;
|
|
19
19
|
get(key: K): V | undefined;
|
|
20
20
|
has(key: K): boolean;
|
|
21
21
|
set(key: K, ...rest: unknown[]): this;
|
package/dist/field/map.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { event, listener, touch } from "../observable.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Model, parent } from "../state.js";
|
|
3
3
|
import { Context } from "../context.js";
|
|
4
4
|
import { def } from "./def.js";
|
|
5
5
|
|
|
@@ -111,7 +111,7 @@ function store(target, key, value) {
|
|
|
111
111
|
release(target, key);
|
|
112
112
|
}
|
|
113
113
|
MAP.set.call(target, key, value);
|
|
114
|
-
if (value instanceof
|
|
114
|
+
if (value instanceof Model) {
|
|
115
115
|
const owner = parent(target);
|
|
116
116
|
const fresh = parent(value, owner ?? null);
|
|
117
117
|
const evict = listener(value, () => void target.delete(key), null);
|
package/dist/field/map.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"map.js","names":[],"sources":["../../src/field/map.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport {
|
|
1
|
+
{"version":3,"file":"map.js","names":[],"sources":["../../src/field/map.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport { Model, parent } from '../state';\nimport { def } from './def';\n\nconst SHAPE = Symbol('shape');\nconst KEYED = (_key: unknown, value: unknown) => value;\n\nconst MAKE = new WeakMap<object, Function>();\nconst OWNED = new WeakMap<object, Map<unknown, () => void>>();\n\nconst MAP = Map.prototype;\nconst MAP_SIZE = Object.getOwnPropertyDescriptor(MAP, 'size')!.get!;\n\ndeclare namespace map {\n export interface Create<A extends [unknown, ...unknown[]], V> extends Managed<A[0], V> {\n set(...args: A): this;\n }\n\n export interface Insert<K, V> extends Managed<K, V> {\n set(key: K, value: V): this;\n }\n\n export { Managed };\n}\n\nfunction map<K, V>(\n entries?: Iterable<readonly [K, V]> | false | null\n): map.Insert<K, V>;\n\nfunction map<A extends [unknown, ...unknown[]], V>(\n make: (...args: A) => V\n): map.Create<A, V>;\n\nfunction map(\n arg?: Iterable<readonly [unknown, unknown]> | Function | false | null\n): unknown {\n return def((_key, subject) => {\n const value = new Managed(typeof arg == 'function' && arg);\n\n parent(value, subject);\n listener(subject, () => value.clear(), null);\n\n if (arg && typeof arg == 'object')\n for (const [key, entry] of arg) value.set(key, entry);\n\n return { set: false, value };\n });\n}\n\nclass Managed<K, V> extends Map<K, V> {\n constructor(arg?: Iterable<readonly [K, V]> | Function | false | null) {\n super();\n\n MAKE.set(this, typeof arg == 'function' ? arg : KEYED);\n OWNED.set(this, new Map());\n\n event(this);\n\n if (arg && typeof arg != 'function')\n for (const [key, value] of arg) store(this, key, value);\n }\n\n get size(): number {\n return touch(this, SHAPE, MAP_SIZE.call(source(this)));\n }\n\n get(): ReadonlyMap<K, Model.Export<V>>;\n get(key: K): V | undefined;\n get(key?: K): unknown {\n const target = source(this);\n\n return arguments.length\n ? touch(this, key, super.get.call(target, key as K)) \n : new Map(\n Array.from(MAP.entries.call(target), ([key, value]) => [\n key,\n value && typeof value === 'object' && typeof value.get === 'function'\n ? value.get()\n : value\n ])\n );\n }\n\n has(key: K): boolean {\n return touch(this, key, MAP.has.call(source(this), key));\n }\n\n set(key: K, ...rest: unknown[]): this {\n const target = source(this);\n const value = MAKE.get(target)!(key, ...rest) as V;\n\n store(target, key, value);\n return this;\n }\n\n delete(key: K) {\n const target = source(this);\n\n if (!MAP.has.call(target, key)) return false;\n\n release(target, key);\n MAP.delete.call(target, key);\n\n event(target, key as never);\n event(target, SHAPE);\n\n return true;\n }\n\n clear() {\n const target = source(this);\n const keys = Array.from(MAP.keys.call(target));\n\n if (!keys.length) return;\n\n for (const key of keys) release(target, key);\n\n MAP.clear.call(target);\n\n for (const key of keys) event(target, key as never);\n event(target, SHAPE);\n }\n\n entries(): MapIterator<[K, V]>;\n entries<R>(fn: (entry: [K, V]) => R): Iterable<R>;\n entries(fn?: (entry: [K, V]) => unknown): any {\n const self = this;\n function* iterate() {\n const target = source(self);\n\n touch(self, SHAPE);\n\n for (const [key, value] of MAP.entries.call(target))\n yield [key, touch(self, key, value)] as [K, V];\n }\n\n return fn ? transform(iterate, fn) : iterate();\n }\n\n keys(): MapIterator<K>;\n keys<R>(fn: (key: K) => R): Iterable<R>;\n keys(fn?: (key: K) => unknown): any {\n const self = this;\n function* iterate() {\n touch(self, SHAPE);\n yield* MAP.keys.call(source(self)) as IterableIterator<K>;\n }\n\n return fn ? transform(iterate, fn) : iterate();\n }\n\n values(): MapIterator<V>;\n values<R>(fn: (value: V, key: K) => R): Iterable<R>;\n values(fn?: (value: V, key: K) => unknown): any {\n if (fn)\n return this.entries(([key, value]) => fn(value, key));\n\n const self = this;\n return (function* () {\n for (const [, value] of self.entries())\n yield value;\n })();\n }\n\n forEach(\n callbackfn: (value: V, key: K, map: this) => void,\n thisArg?: unknown\n ) {\n for (const [key, value] of this.entries())\n callbackfn.call(thisArg, value, key, this);\n }\n\n [Symbol.iterator]() {\n return this.entries();\n }\n}\n\nObject.assign(map, { Managed });\n\nfunction transform<T, R>(\n iterate: () => Generator<T>,\n fn: (item: T) => R\n): Iterable<R> {\n return {\n *[Symbol.iterator]() {\n for (const item of iterate())\n try {\n yield fn(item);\n } catch (err) {\n if (err !== false) throw err;\n }\n }\n };\n}\n\nfunction store<K, V>(target: Managed<K, V>, key: K, value: V) {\n const exists = MAP.has.call(target, key);\n\n if (exists) {\n if (MAP.get.call(target, key) === value) return;\n\n release(target, key);\n }\n\n MAP.set.call(target, key, value);\n\n if (value instanceof Model) {\n const owner = parent(target);\n const fresh = parent(value, owner ?? null);\n const evict = listener(value, () => void target.delete(key), 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\n event(target, key as never);\n\n if (!exists) event(target, SHAPE);\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 source<T extends object>(from: T): T {\n return OWNED.has(from) ? from : Object.getPrototypeOf(from);\n}\n\nexport { map };\n"],"mappings":"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"}
|
package/dist/field/ref.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model } from "../state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/field/ref.d.ts
|
|
4
4
|
declare namespace ref {
|
|
5
|
-
type Map<T extends
|
|
5
|
+
type Map<T extends Model, R> = (this: T, key: Model.Field<T> & string, state: T) => R;
|
|
6
6
|
type Callback<T> = (argument: T) => ((next: T | null) => void) | Promise<void> | void | boolean;
|
|
7
7
|
/** Callable ref that also exposes ref-object properties. */
|
|
8
8
|
interface Object<T = any> {
|
|
@@ -10,8 +10,8 @@ declare namespace ref {
|
|
|
10
10
|
(value: T | null): void;
|
|
11
11
|
/** Current value held by this reference. */
|
|
12
12
|
current: T;
|
|
13
|
-
/**
|
|
14
|
-
is:
|
|
13
|
+
/** Model instance this reference belongs to. */
|
|
14
|
+
is: Model;
|
|
15
15
|
/** Key of property on state this reference belongs to. */
|
|
16
16
|
key: string;
|
|
17
17
|
/**
|
|
@@ -25,10 +25,10 @@ declare namespace ref {
|
|
|
25
25
|
get(): T | null;
|
|
26
26
|
}
|
|
27
27
|
/** Object with references to all managed values of `T`. */
|
|
28
|
-
type Proxy<T extends
|
|
28
|
+
type Proxy<T extends Model> = { [P in Model.Field<T>]-?: Object<T[P]> } & {
|
|
29
29
|
get(): T;
|
|
30
30
|
};
|
|
31
|
-
type CustomProxy<T extends
|
|
31
|
+
type CustomProxy<T extends Model, R> = { [P in Model.Field<T>]-?: R } & {
|
|
32
32
|
get(): T;
|
|
33
33
|
};
|
|
34
34
|
}
|
|
@@ -42,7 +42,7 @@ declare namespace ref {
|
|
|
42
42
|
*
|
|
43
43
|
* @param state - Source state from which to reference values.
|
|
44
44
|
*/
|
|
45
|
-
declare function ref<T extends
|
|
45
|
+
declare function ref<T extends Model>(state: T): ref.Proxy<T>;
|
|
46
46
|
/**
|
|
47
47
|
* Creates an object with values based on managed values.
|
|
48
48
|
* Each property will invoke map function on first access supply
|
|
@@ -53,7 +53,7 @@ declare function ref<T extends State>(state: T): ref.Proxy<T>;
|
|
|
53
53
|
* @param state - Source state from which to reference values.
|
|
54
54
|
* @param map - Function producing the placeholder value for any given property.
|
|
55
55
|
*/
|
|
56
|
-
declare function ref<T extends
|
|
56
|
+
declare function ref<T extends Model, R>(state: T, map: ref.Map<T, R>): ref.CustomProxy<T, R>;
|
|
57
57
|
/**
|
|
58
58
|
* Creates a ref-compatible property.
|
|
59
59
|
* Callable to set the value, with ref-object properties for reading and subscribing.
|
package/dist/field/ref.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { capture, listener } from "../observable.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Model, update } from "../state.js";
|
|
3
3
|
import { def } from "./def.js";
|
|
4
4
|
|
|
5
5
|
//#region src/field/ref.ts
|
|
6
6
|
const { defineProperty, defineProperties } = Object;
|
|
7
7
|
function ref(arg, arg2) {
|
|
8
|
-
if (arg instanceof
|
|
9
|
-
if (typeof arg == "object") throw new Error("ref instruction requires a
|
|
8
|
+
if (arg instanceof Model) return proxy(arg, arg2);
|
|
9
|
+
if (typeof arg == "object") throw new Error("ref instruction requires a Model instance, got a plain object");
|
|
10
10
|
return property(arg, arg2);
|
|
11
11
|
}
|
|
12
12
|
function defaultMap(key) {
|