@expressive/mvc 0.42.0 → 0.43.1

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/dist/index.d.ts CHANGED
@@ -2,18 +2,22 @@ declare namespace Model {
2
2
  /** Any type of Model, using own class constructor as its identifier. */
3
3
  type Type<T extends Model = Model> = abstract new (...args: any[]) => T;
4
4
  /** A type of Model which may be created without constructor arguments. */
5
- type New<T extends Model = Model> = (new (arg?: Model.Argument) => T) & typeof Model;
5
+ type New<T extends Model = Model> = (new (arg?: Argument) => T) & typeof Model;
6
6
  /**
7
7
  * Model constructor callback - is called when Model finishes intializing.
8
8
  * Returned function will call when model is destroyed.
9
9
  */
10
- type Callback = (() => (() => void) | void);
10
+ type Callback<T extends Model = Model> = (this: T, thisArg: T) => (() => void) | Assign<T> | void;
11
11
  /** Model constructor argument */
12
- type Argument = string | Callback | undefined;
12
+ type Argument<T extends Model = Model> = string | Callback<T> | Assign<T> | undefined;
13
13
  /** Subset of `keyof T` which are not methods or defined by base Model U. **/
14
14
  type Field<T> = Exclude<keyof T, keyof Model>;
15
15
  /** Any valid key for controller, including but not limited to Field<T>. */
16
16
  type Event<T> = Field<T> | (string & {}) | number | symbol;
17
+ /** Object overlay which may be used to override values and methods while creating model. */
18
+ type Assign<T> = {
19
+ [K in Exclude<keyof T, keyof Model>]?: T[K] extends (...args: any[]) => infer R ? (this: T, ...args: Parameters<T[K]>) => ReturnType<T[K]> : T[K];
20
+ } & Record<string, unknown>;
17
21
  /** Export/Import compatible value for a given property in a Model. */
18
22
  type Export<R> = R extends {
19
23
  get(): infer T;
@@ -49,7 +53,7 @@ declare namespace Model {
49
53
  *
50
54
  * @returns A callback function which will be called when this effect is stale.
51
55
  */
52
- type Effect<T> = (this: T, current: T, update: Set<Model.Event<T>>) => EffectCallback | Promise<void> | null | void;
56
+ type Effect<T> = (this: T, current: T, update: Set<Event<T>>) => EffectCallback | Promise<void> | null | void;
53
57
  /**
54
58
  * A callback function returned by effect. Will be called when effect is stale.
55
59
  *
@@ -70,7 +74,7 @@ declare namespace Model {
70
74
  * Property initializer, will run upon instance creation.
71
75
  * Optional returned callback will run when once upon first access.
72
76
  */
73
- type Instruction<T = any, M extends Model = any> = (this: M, key: Model.Field<M> & string, thisArg: M, state: Model.State<M>) => Instruction.Descriptor<T> | Instruction.Getter<T> | void;
77
+ type Instruction<T = any, M extends Model = any> = (this: M, key: Field<M> & string, thisArg: M, state: State<M>) => Instruction.Descriptor<T> | Instruction.Getter<T> | void;
74
78
  }
75
79
  interface Model {
76
80
  /**
@@ -159,6 +163,11 @@ declare class Model {
159
163
  * @returns Promise which resolves an array of keys which were updated.
160
164
  */
161
165
  set(key: Model.Event<this>): PromiseLike<Model.Event<this>[]>;
166
+ /**
167
+ * Update mulitple properties at once. Merges argument with current state.
168
+ * Properties which are not managed by this controller will be ignored.
169
+ */
170
+ set(assign: Model.Assign<this>): PromiseLike<Model.Event<this>[]> | undefined;
162
171
  /**
163
172
  * Update a property with value.
164
173
  *
@@ -176,7 +185,7 @@ declare class Model {
176
185
  *
177
186
  * @param args - arguments sent to constructor
178
187
  */
179
- static new<T extends Model>(this: Model.New<T>, arg?: Model.Argument): T;
188
+ static new<T extends Model>(this: Model.New<T>, arg?: Model.Argument<T>): T;
180
189
  /**
181
190
  * Static equivalent of `x instanceof this`.
182
191
  * Determines if provided class is a subtype of this one.
package/dist/index.js CHANGED
@@ -149,7 +149,7 @@ function effect(target, callback) {
149
149
 
150
150
  // src/model.ts
151
151
  var FLATTEN;
152
- var REGISTER = /* @__PURE__ */ new WeakMap();
152
+ var NAMES = /* @__PURE__ */ new WeakMap();
153
153
  var STATE = /* @__PURE__ */ new WeakMap();
154
154
  var NOTIFY = /* @__PURE__ */ new WeakMap();
155
155
  var PENDING2 = /* @__PURE__ */ new WeakMap();
@@ -160,38 +160,20 @@ var Model = class _Model {
160
160
  constructor(arg) {
161
161
  const state = {};
162
162
  let Type = this.constructor;
163
+ bindMethods(Type);
163
164
  define(this, "is", { value: this });
164
165
  STATE.set(this, state);
165
- REGISTER.set(this, typeof arg == "string" ? arg : `${Type}-${uid()}`);
166
+ NAMES.set(this, typeof arg == "string" ? arg : `${Type}-${uid()}`);
166
167
  while (true) {
167
168
  new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
168
169
  if (Type === _Model)
169
170
  break;
170
- const desc = Object.getOwnPropertyDescriptors(Type.prototype);
171
- for (const key in desc) {
172
- let { value } = desc[key];
173
- if (typeof value == "function" && key !== "constructor") {
174
- const bind = (value2) => {
175
- const method = value2.bind(this);
176
- METHOD.set(method, value2);
177
- define(this, key, {
178
- value: method,
179
- configurable: false
180
- });
181
- return method;
182
- };
183
- Object.defineProperty(Type.prototype, key, {
184
- get: () => this.hasOwnProperty(key) ? value : bind(value),
185
- set: bind
186
- });
187
- }
188
- }
189
171
  Type = Object.getPrototypeOf(Type);
190
172
  }
191
173
  addListener(this, () => {
192
- let onDone;
193
- if (typeof arg == "function")
194
- onDone = arg.call(this);
174
+ const apply = typeof arg == "function" ? arg.call(this, this) : arg;
175
+ if (typeof apply == "object")
176
+ assign(this, apply);
195
177
  for (const key in this) {
196
178
  const desc = Object.getOwnPropertyDescriptor(this, key);
197
179
  if ("value" in desc) {
@@ -209,8 +191,8 @@ var Model = class _Model {
209
191
  for (const [_, value] of this)
210
192
  if (value instanceof _Model && PARENT.get(value) === this)
211
193
  value.set(null);
212
- if (typeof onDone == "function")
213
- onDone();
194
+ if (typeof apply == "function")
195
+ apply();
214
196
  Object.freeze(state);
215
197
  }, null);
216
198
  return null;
@@ -264,7 +246,9 @@ var Model = class _Model {
264
246
  });
265
247
  if (arg1 === null)
266
248
  return event(this, null);
267
- if (arg1 !== void 0)
249
+ if (typeof arg1 == "object")
250
+ assign(self, arg1);
251
+ else if (arg1 !== void 0)
268
252
  if (1 in arguments)
269
253
  update(self, arg1, arg2, arg3);
270
254
  else
@@ -322,7 +306,7 @@ var Model = class _Model {
322
306
  };
323
307
  define(Model.prototype, "toString", {
324
308
  value() {
325
- return REGISTER.get(this.is);
309
+ return NAMES.get(this.is);
326
310
  }
327
311
  });
328
312
  define(Model, "toString", {
@@ -380,6 +364,40 @@ function push(subject, key, silent) {
380
364
  if (!silent)
381
365
  event(subject, key);
382
366
  }
367
+ var METHODS = new WeakMap([[Model, []]]);
368
+ function assign(to, values) {
369
+ const methods = METHODS.get(to.constructor);
370
+ const applicable = new Set(Object.keys(to).concat(methods));
371
+ for (const key in values)
372
+ if (applicable.has(key))
373
+ to[key] = values[key];
374
+ }
375
+ function bindMethods(type) {
376
+ let keys = METHODS.get(type);
377
+ if (!keys) {
378
+ METHODS.set(type, keys = bindMethods(Object.getPrototypeOf(type)).slice());
379
+ const desc = Object.getOwnPropertyDescriptors(type.prototype);
380
+ for (const key in desc)
381
+ if (key != "constructor" && "value" in desc[key]) {
382
+ let bind2 = function(method) {
383
+ const value2 = method.bind(this.is);
384
+ METHOD.set(value2, method);
385
+ define(this.is, key, { value: value2, writable: true });
386
+ return value2;
387
+ };
388
+ var bind = bind2;
389
+ let { value } = desc[key];
390
+ keys.push(key);
391
+ Object.defineProperty(type.prototype, key, {
392
+ set: bind2,
393
+ get() {
394
+ return this.hasOwnProperty(key) ? value : bind2.call(this, value);
395
+ }
396
+ });
397
+ }
398
+ }
399
+ return keys;
400
+ }
383
401
  function uid() {
384
402
  return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
385
403
  }
@@ -805,12 +823,12 @@ function has(type, argument) {
805
823
  return add((key, subject, state) => {
806
824
  if (typeof argument == "boolean") {
807
825
  Context.request(type, subject, (model) => {
826
+ subject.set(key, model);
808
827
  const remove = () => {
809
828
  drop();
810
829
  if (state[key] === model)
811
830
  delete state[key];
812
831
  };
813
- subject.set(key, model);
814
832
  const drop = model.get(null, remove);
815
833
  return remove;
816
834
  });
package/dist/index.mjs CHANGED
@@ -115,7 +115,7 @@ function effect(target, callback) {
115
115
 
116
116
  // src/model.ts
117
117
  var FLATTEN;
118
- var REGISTER = /* @__PURE__ */ new WeakMap();
118
+ var NAMES = /* @__PURE__ */ new WeakMap();
119
119
  var STATE = /* @__PURE__ */ new WeakMap();
120
120
  var NOTIFY = /* @__PURE__ */ new WeakMap();
121
121
  var PENDING2 = /* @__PURE__ */ new WeakMap();
@@ -126,38 +126,20 @@ var Model = class _Model {
126
126
  constructor(arg) {
127
127
  const state = {};
128
128
  let Type = this.constructor;
129
+ bindMethods(Type);
129
130
  define(this, "is", { value: this });
130
131
  STATE.set(this, state);
131
- REGISTER.set(this, typeof arg == "string" ? arg : `${Type}-${uid()}`);
132
+ NAMES.set(this, typeof arg == "string" ? arg : `${Type}-${uid()}`);
132
133
  while (true) {
133
134
  new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
134
135
  if (Type === _Model)
135
136
  break;
136
- const desc = Object.getOwnPropertyDescriptors(Type.prototype);
137
- for (const key in desc) {
138
- let { value } = desc[key];
139
- if (typeof value == "function" && key !== "constructor") {
140
- const bind = (value2) => {
141
- const method = value2.bind(this);
142
- METHOD.set(method, value2);
143
- define(this, key, {
144
- value: method,
145
- configurable: false
146
- });
147
- return method;
148
- };
149
- Object.defineProperty(Type.prototype, key, {
150
- get: () => this.hasOwnProperty(key) ? value : bind(value),
151
- set: bind
152
- });
153
- }
154
- }
155
137
  Type = Object.getPrototypeOf(Type);
156
138
  }
157
139
  addListener(this, () => {
158
- let onDone;
159
- if (typeof arg == "function")
160
- onDone = arg.call(this);
140
+ const apply = typeof arg == "function" ? arg.call(this, this) : arg;
141
+ if (typeof apply == "object")
142
+ assign(this, apply);
161
143
  for (const key in this) {
162
144
  const desc = Object.getOwnPropertyDescriptor(this, key);
163
145
  if ("value" in desc) {
@@ -175,8 +157,8 @@ var Model = class _Model {
175
157
  for (const [_, value] of this)
176
158
  if (value instanceof _Model && PARENT.get(value) === this)
177
159
  value.set(null);
178
- if (typeof onDone == "function")
179
- onDone();
160
+ if (typeof apply == "function")
161
+ apply();
180
162
  Object.freeze(state);
181
163
  }, null);
182
164
  return null;
@@ -230,7 +212,9 @@ var Model = class _Model {
230
212
  });
231
213
  if (arg1 === null)
232
214
  return event(this, null);
233
- if (arg1 !== void 0)
215
+ if (typeof arg1 == "object")
216
+ assign(self, arg1);
217
+ else if (arg1 !== void 0)
234
218
  if (1 in arguments)
235
219
  update(self, arg1, arg2, arg3);
236
220
  else
@@ -288,7 +272,7 @@ var Model = class _Model {
288
272
  };
289
273
  define(Model.prototype, "toString", {
290
274
  value() {
291
- return REGISTER.get(this.is);
275
+ return NAMES.get(this.is);
292
276
  }
293
277
  });
294
278
  define(Model, "toString", {
@@ -346,6 +330,40 @@ function push(subject, key, silent) {
346
330
  if (!silent)
347
331
  event(subject, key);
348
332
  }
333
+ var METHODS = new WeakMap([[Model, []]]);
334
+ function assign(to, values) {
335
+ const methods = METHODS.get(to.constructor);
336
+ const applicable = new Set(Object.keys(to).concat(methods));
337
+ for (const key in values)
338
+ if (applicable.has(key))
339
+ to[key] = values[key];
340
+ }
341
+ function bindMethods(type) {
342
+ let keys = METHODS.get(type);
343
+ if (!keys) {
344
+ METHODS.set(type, keys = bindMethods(Object.getPrototypeOf(type)).slice());
345
+ const desc = Object.getOwnPropertyDescriptors(type.prototype);
346
+ for (const key in desc)
347
+ if (key != "constructor" && "value" in desc[key]) {
348
+ let bind2 = function(method) {
349
+ const value2 = method.bind(this.is);
350
+ METHOD.set(value2, method);
351
+ define(this.is, key, { value: value2, writable: true });
352
+ return value2;
353
+ };
354
+ var bind = bind2;
355
+ let { value } = desc[key];
356
+ keys.push(key);
357
+ Object.defineProperty(type.prototype, key, {
358
+ set: bind2,
359
+ get() {
360
+ return this.hasOwnProperty(key) ? value : bind2.call(this, value);
361
+ }
362
+ });
363
+ }
364
+ }
365
+ return keys;
366
+ }
349
367
  function uid() {
350
368
  return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
351
369
  }
@@ -771,12 +789,12 @@ function has(type, argument) {
771
789
  return add((key, subject, state) => {
772
790
  if (typeof argument == "boolean") {
773
791
  Context.request(type, subject, (model) => {
792
+ subject.set(key, model);
774
793
  const remove = () => {
775
794
  drop();
776
795
  if (state[key] === model)
777
796
  delete state[key];
778
797
  };
779
- subject.set(key, model);
780
798
  const drop = model.get(null, remove);
781
799
  return remove;
782
800
  });
package/package.json CHANGED
@@ -28,6 +28,6 @@
28
28
  "prebuild": "rm -rf dist",
29
29
  "preversion": "npm run test && npm run build"
30
30
  },
31
- "version": "0.42.0",
32
- "gitHead": "a49c69c9d8cfec956664046510d4e862505cdd1e"
31
+ "version": "0.43.1",
32
+ "gitHead": "1fce74756afb4499f6b4da1c52bfbc2021b73ebb"
33
33
  }