@expressive/mvc 0.0.4 → 0.2.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/lib/index.d.ts +35 -11
- package/lib/index.esm.js +79 -74
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +79 -74
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -51,10 +51,10 @@ function issues(register) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const Oops$c = issues({
|
|
54
|
-
|
|
54
|
+
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
55
55
|
});
|
|
56
56
|
function suspend(source, key) {
|
|
57
|
-
const error = Oops$c.
|
|
57
|
+
const error = Oops$c.NotReady(source.subject, key);
|
|
58
58
|
const promise = new Promise(resolve => {
|
|
59
59
|
const release = source.addListener(forKey => {
|
|
60
60
|
if (forKey == key)
|
|
@@ -95,7 +95,7 @@ function mayRetry(fn) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
const Oops$b = issues({
|
|
98
|
-
|
|
98
|
+
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
99
99
|
});
|
|
100
100
|
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
101
101
|
function define(target, key, value) {
|
|
@@ -120,7 +120,7 @@ function createEffect(callback) {
|
|
|
120
120
|
if (unSet instanceof Promise)
|
|
121
121
|
unSet = undefined;
|
|
122
122
|
if (unSet && typeof unSet !== "function")
|
|
123
|
-
throw Oops$b.
|
|
123
|
+
throw Oops$b.BadCallback();
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
function createValueEffect(callback) {
|
|
@@ -136,7 +136,7 @@ function createValueEffect(callback) {
|
|
|
136
136
|
if (typeof out == "function")
|
|
137
137
|
unSet = out;
|
|
138
138
|
else
|
|
139
|
-
throw Oops$b.
|
|
139
|
+
throw Oops$b.BadCallback();
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -158,7 +158,16 @@ class Model {
|
|
|
158
158
|
constructor() {
|
|
159
159
|
define(this, CONTROL, new Controller(this));
|
|
160
160
|
define(this, "get", this);
|
|
161
|
-
define(this, "
|
|
161
|
+
define(this, "is", this);
|
|
162
|
+
defineLazy(this, "set", () => {
|
|
163
|
+
const controller = control(this);
|
|
164
|
+
const assign = (key, value) => {
|
|
165
|
+
controller.update(key, value);
|
|
166
|
+
};
|
|
167
|
+
for (const key of getOwnPropertyNames(controller.proxy))
|
|
168
|
+
define(assign, key, controller.ref(key));
|
|
169
|
+
return assign;
|
|
170
|
+
});
|
|
162
171
|
}
|
|
163
172
|
get [STATE]() {
|
|
164
173
|
return this[CONTROL].state;
|
|
@@ -295,10 +304,7 @@ class Model {
|
|
|
295
304
|
return (typeof maybe == "function" &&
|
|
296
305
|
maybe.prototype instanceof this);
|
|
297
306
|
}
|
|
298
|
-
}
|
|
299
|
-
defineLazy(Model, CONTROL, function () {
|
|
300
|
-
return new Controller(this);
|
|
301
|
-
});
|
|
307
|
+
}
|
|
302
308
|
|
|
303
309
|
class Subscriber {
|
|
304
310
|
constructor(target, onUpdate) {
|
|
@@ -347,10 +353,10 @@ class Subscriber {
|
|
|
347
353
|
}
|
|
348
354
|
|
|
349
355
|
const Oops$a = issues({
|
|
350
|
-
|
|
356
|
+
BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
351
357
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
352
|
-
|
|
353
|
-
|
|
358
|
+
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
359
|
+
Early: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
354
360
|
});
|
|
355
361
|
const INIT = new WeakSet();
|
|
356
362
|
const INFO = new WeakMap();
|
|
@@ -377,7 +383,7 @@ function from(source, arg1, arg2) {
|
|
|
377
383
|
}
|
|
378
384
|
// Regular function is too ambiguous so not allowed.
|
|
379
385
|
else
|
|
380
|
-
throw Oops$a.
|
|
386
|
+
throw Oops$a.BadSource(subject, key, source);
|
|
381
387
|
let sub;
|
|
382
388
|
const setter = arg1;
|
|
383
389
|
const info = { key, parent, priority: 1 };
|
|
@@ -392,7 +398,7 @@ function from(source, arg1, arg2) {
|
|
|
392
398
|
return setter.call(sub.proxy, sub.proxy);
|
|
393
399
|
}
|
|
394
400
|
catch (err) {
|
|
395
|
-
Oops$a.
|
|
401
|
+
Oops$a.Failed(subject, key, !!initial).warn();
|
|
396
402
|
throw err;
|
|
397
403
|
}
|
|
398
404
|
}
|
|
@@ -433,7 +439,7 @@ function from(source, arg1, arg2) {
|
|
|
433
439
|
}
|
|
434
440
|
catch (e) {
|
|
435
441
|
if (early)
|
|
436
|
-
Oops$a.
|
|
442
|
+
Oops$a.Early(key).warn();
|
|
437
443
|
throw e;
|
|
438
444
|
}
|
|
439
445
|
finally {
|
|
@@ -500,26 +506,28 @@ class Controller {
|
|
|
500
506
|
this.proxy = Object.create(subject);
|
|
501
507
|
}
|
|
502
508
|
start() {
|
|
503
|
-
|
|
504
|
-
|
|
509
|
+
READY.add(this);
|
|
510
|
+
for (const key in this.subject) {
|
|
511
|
+
const { value: entry } = getOwnPropertyDescriptor(this.subject, key);
|
|
512
|
+
if (typeof entry == "function")
|
|
513
|
+
continue;
|
|
514
|
+
if (typeof entry == "symbol") {
|
|
515
|
+
const instruction = PENDING.get(entry);
|
|
516
|
+
if (instruction)
|
|
517
|
+
instruction.call(this, key, this);
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
this.manage(key, entry);
|
|
521
|
+
}
|
|
505
522
|
this.emit([]);
|
|
506
523
|
}
|
|
507
524
|
stop() {
|
|
508
525
|
this.followers.clear();
|
|
509
526
|
this.onDestroy.forEach(x => x());
|
|
510
527
|
}
|
|
511
|
-
manage(key) {
|
|
528
|
+
manage(key, value) {
|
|
512
529
|
const { proxy, state, subject } = this;
|
|
513
|
-
|
|
514
|
-
if (typeof entry == "function")
|
|
515
|
-
return;
|
|
516
|
-
if (typeof entry == "symbol") {
|
|
517
|
-
const instruction = PENDING.get(entry);
|
|
518
|
-
if (instruction)
|
|
519
|
-
instruction.call(this, key, this);
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
state[key] = entry;
|
|
530
|
+
state[key] = value;
|
|
523
531
|
const set = this.ref(key);
|
|
524
532
|
defineProperty(subject, key, {
|
|
525
533
|
enumerable: false,
|
|
@@ -611,26 +619,20 @@ class Controller {
|
|
|
611
619
|
}
|
|
612
620
|
function control(subject, cb) {
|
|
613
621
|
let control = subject[CONTROL];
|
|
614
|
-
const ready = READY.has(control);
|
|
615
622
|
if (!control) {
|
|
616
623
|
control = new Controller(subject);
|
|
617
624
|
define(subject, CONTROL, control);
|
|
618
625
|
}
|
|
619
|
-
|
|
620
|
-
if (!ready) {
|
|
621
|
-
READY.add(control);
|
|
622
|
-
control.start();
|
|
623
|
-
}
|
|
624
|
-
return control;
|
|
625
|
-
}
|
|
626
|
+
const ready = READY.has(control);
|
|
626
627
|
if (!ready) {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
done = cb(control);
|
|
630
|
-
|
|
631
|
-
|
|
628
|
+
if (cb) {
|
|
629
|
+
let done;
|
|
630
|
+
control.requestUpdate(() => done = cb(control));
|
|
631
|
+
return () => done && done();
|
|
632
|
+
}
|
|
633
|
+
control.start();
|
|
632
634
|
}
|
|
633
|
-
return cb(control);
|
|
635
|
+
return cb ? cb(control) : control;
|
|
634
636
|
}
|
|
635
637
|
|
|
636
638
|
function apply(fn, label) {
|
|
@@ -718,14 +720,14 @@ function forSubscriber(fn) {
|
|
|
718
720
|
}
|
|
719
721
|
|
|
720
722
|
const Oops$8 = issues({
|
|
721
|
-
|
|
723
|
+
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
722
724
|
});
|
|
723
725
|
function act(task) {
|
|
724
726
|
return apply(function act(key) {
|
|
725
727
|
let pending = false;
|
|
726
728
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
727
729
|
if (pending)
|
|
728
|
-
return Promise.reject(Oops$8.
|
|
730
|
+
return Promise.reject(Oops$8.DuplicatePending(key));
|
|
729
731
|
pending = true;
|
|
730
732
|
this.update(key);
|
|
731
733
|
try {
|
|
@@ -831,8 +833,8 @@ function createRef(key, cb) {
|
|
|
831
833
|
const Oops$7 = issues({
|
|
832
834
|
NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
|
|
833
835
|
BadFactory: () => `Set instruction can only accept a factory or undefined.`,
|
|
834
|
-
|
|
835
|
-
|
|
836
|
+
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
837
|
+
Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
836
838
|
});
|
|
837
839
|
function set(factory, argument) {
|
|
838
840
|
return apply(function set(key) {
|
|
@@ -883,7 +885,7 @@ function pendingFactory(parent, key, fn, required) {
|
|
|
883
885
|
const suspend = () => {
|
|
884
886
|
if (required === false)
|
|
885
887
|
return undefined;
|
|
886
|
-
const issue = Oops$7.
|
|
888
|
+
const issue = Oops$7.NotReady(subject, key);
|
|
887
889
|
Object.assign(pending, {
|
|
888
890
|
message: issue.message,
|
|
889
891
|
stack: issue.stack
|
|
@@ -895,7 +897,7 @@ function pendingFactory(parent, key, fn, required) {
|
|
|
895
897
|
init();
|
|
896
898
|
}
|
|
897
899
|
catch (err) {
|
|
898
|
-
Oops$7.
|
|
900
|
+
Oops$7.Failed(subject, key).warn();
|
|
899
901
|
throw err;
|
|
900
902
|
}
|
|
901
903
|
return () => {
|
|
@@ -914,8 +916,8 @@ function pendingFactory(parent, key, fn, required) {
|
|
|
914
916
|
|
|
915
917
|
const Parent = new WeakMap();
|
|
916
918
|
const Oops$6 = issues({
|
|
917
|
-
|
|
918
|
-
|
|
919
|
+
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
920
|
+
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
919
921
|
});
|
|
920
922
|
function parent(Expects, required) {
|
|
921
923
|
return apply(function parent() {
|
|
@@ -924,10 +926,10 @@ function parent(Expects, required) {
|
|
|
924
926
|
const expected = Expects.name;
|
|
925
927
|
if (!value) {
|
|
926
928
|
if (required !== false)
|
|
927
|
-
throw Oops$6.
|
|
929
|
+
throw Oops$6.Required(expected, child);
|
|
928
930
|
}
|
|
929
931
|
else if (!(value instanceof Expects))
|
|
930
|
-
throw Oops$6.
|
|
932
|
+
throw Oops$6.Unexpected(expected, child, value);
|
|
931
933
|
return { value };
|
|
932
934
|
});
|
|
933
935
|
}
|
|
@@ -1032,19 +1034,19 @@ class Lookup {
|
|
|
1032
1034
|
const LookupContext = React__default["default"].createContext(new Lookup());
|
|
1033
1035
|
const useLookup = () => React__default["default"].useContext(LookupContext);
|
|
1034
1036
|
const Oops$4 = issues({
|
|
1035
|
-
|
|
1037
|
+
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1036
1038
|
});
|
|
1037
|
-
function
|
|
1039
|
+
function useLocal(Type, arg) {
|
|
1038
1040
|
const instance = useLookup().get(Type);
|
|
1039
1041
|
if (!instance && arg !== false)
|
|
1040
|
-
throw Oops$4.
|
|
1042
|
+
throw Oops$4.NotFound(Type.name);
|
|
1041
1043
|
return typeof arg == "string" ?
|
|
1042
1044
|
instance[arg] :
|
|
1043
1045
|
instance;
|
|
1044
1046
|
}
|
|
1045
1047
|
|
|
1046
1048
|
const Oops$3 = issues({
|
|
1047
|
-
|
|
1049
|
+
NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
1048
1050
|
AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
|
|
1049
1051
|
});
|
|
1050
1052
|
const PendingContext = new WeakMap();
|
|
@@ -1058,7 +1060,7 @@ function tap(type, argument) {
|
|
|
1058
1060
|
};
|
|
1059
1061
|
const { subject } = this;
|
|
1060
1062
|
if ("set" in subject.constructor)
|
|
1061
|
-
throw Oops$3.
|
|
1063
|
+
throw Oops$3.NotAllowed(subject, type.name);
|
|
1062
1064
|
getPending(subject).push(context => {
|
|
1063
1065
|
let instance = context.get(type);
|
|
1064
1066
|
if (typeof argument == "function") {
|
|
@@ -1202,7 +1204,7 @@ function useTap(source, path, expect) {
|
|
|
1202
1204
|
if ("get" in source)
|
|
1203
1205
|
return () => source.get();
|
|
1204
1206
|
if ("prototype" in source)
|
|
1205
|
-
return () =>
|
|
1207
|
+
return () => useLocal(source);
|
|
1206
1208
|
else
|
|
1207
1209
|
return source;
|
|
1208
1210
|
}, [])();
|
|
@@ -1237,7 +1239,7 @@ class MVC extends Model {
|
|
|
1237
1239
|
return useModel(this, arg, callback);
|
|
1238
1240
|
}
|
|
1239
1241
|
static get(required) {
|
|
1240
|
-
return
|
|
1242
|
+
return useLocal(this, required);
|
|
1241
1243
|
}
|
|
1242
1244
|
static tap(key, expect) {
|
|
1243
1245
|
return useTap(this, key, expect);
|
|
@@ -1283,25 +1285,28 @@ class MVC extends Model {
|
|
|
1283
1285
|
}
|
|
1284
1286
|
|
|
1285
1287
|
const Oops$2 = issues({
|
|
1286
|
-
|
|
1288
|
+
BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
1287
1289
|
});
|
|
1288
1290
|
function Consumer(props) {
|
|
1289
|
-
const { get, has, children,
|
|
1291
|
+
const { get, has, children, for: type } = props;
|
|
1290
1292
|
if (typeof children == "function")
|
|
1291
|
-
return children(useTap(
|
|
1293
|
+
return children(useTap(type));
|
|
1292
1294
|
const callback = has || get;
|
|
1293
1295
|
if (typeof callback == "function")
|
|
1294
|
-
callback(
|
|
1296
|
+
callback(useLocal(type, !!has));
|
|
1295
1297
|
else
|
|
1296
|
-
throw Oops$2.
|
|
1298
|
+
throw Oops$2.BadProps();
|
|
1297
1299
|
return null;
|
|
1298
1300
|
}
|
|
1299
1301
|
|
|
1300
1302
|
const Oops$1 = issues({
|
|
1301
|
-
|
|
1303
|
+
NoType: () => "Provider 'of' prop must be Model, typeof Model or a collection of them.",
|
|
1304
|
+
PropDeprecated: () => "Provider `of` prop is deprecated, use `for` instead."
|
|
1302
1305
|
});
|
|
1303
1306
|
function Provider(props) {
|
|
1304
|
-
|
|
1307
|
+
if ("of" in props)
|
|
1308
|
+
throw Oops$1.PropDeprecated();
|
|
1309
|
+
const context = useNewContext(props.for);
|
|
1305
1310
|
const render = props.children;
|
|
1306
1311
|
useAppliedProps(context, props);
|
|
1307
1312
|
React__default["default"].useLayoutEffect(() => () => context.pop(), []);
|
|
@@ -1313,7 +1318,7 @@ function useNewContext(inject) {
|
|
|
1313
1318
|
const from = useLookup();
|
|
1314
1319
|
return React__default["default"].useMemo(() => {
|
|
1315
1320
|
if (!inject)
|
|
1316
|
-
throw Oops$1.
|
|
1321
|
+
throw Oops$1.NoType();
|
|
1317
1322
|
const context = from.push(inject);
|
|
1318
1323
|
for (const instance of context.local)
|
|
1319
1324
|
if (instance)
|
|
@@ -1327,7 +1332,7 @@ function useAppliedProps(within, props) {
|
|
|
1327
1332
|
const targets = within.local;
|
|
1328
1333
|
return function integrate(props) {
|
|
1329
1334
|
for (const [key, value] of entries(props))
|
|
1330
|
-
if (
|
|
1335
|
+
if (["of", "for", "children"].indexOf(key) < 0)
|
|
1331
1336
|
for (const into of targets)
|
|
1332
1337
|
if (into && key in into)
|
|
1333
1338
|
into[key] = value;
|
|
@@ -1348,15 +1353,15 @@ function RenderFunction(props) {
|
|
|
1348
1353
|
}
|
|
1349
1354
|
|
|
1350
1355
|
const Oops = issues({
|
|
1351
|
-
|
|
1352
|
-
|
|
1356
|
+
DoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.create() before attempting to access, or consider using ${name}.use() instead.`,
|
|
1357
|
+
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1353
1358
|
});
|
|
1354
1359
|
const Active = new WeakMap();
|
|
1355
1360
|
class Global extends MVC {
|
|
1356
1361
|
static create(...args) {
|
|
1357
1362
|
const Type = this;
|
|
1358
1363
|
if (Active.has(Type))
|
|
1359
|
-
throw Oops.
|
|
1364
|
+
throw Oops.AlreadyExists(this.name);
|
|
1360
1365
|
const instance = super.create(...args);
|
|
1361
1366
|
Active.set(Type, instance);
|
|
1362
1367
|
return instance;
|
|
@@ -1374,7 +1379,7 @@ class Global extends MVC {
|
|
|
1374
1379
|
static get(arg) {
|
|
1375
1380
|
const instance = Active.get(this);
|
|
1376
1381
|
if (!instance && arg !== false)
|
|
1377
|
-
throw Oops.
|
|
1382
|
+
throw Oops.DoesNotExist(this.name);
|
|
1378
1383
|
return (typeof arg == "string" ?
|
|
1379
1384
|
instance[arg] :
|
|
1380
1385
|
instance);
|
|
@@ -1410,7 +1415,7 @@ exports.set = set;
|
|
|
1410
1415
|
exports.tap = tap;
|
|
1411
1416
|
exports.use = use$1;
|
|
1412
1417
|
exports.useFrom = useFrom;
|
|
1413
|
-
exports.
|
|
1418
|
+
exports.useLocal = useLocal;
|
|
1414
1419
|
exports.useModel = useModel;
|
|
1415
1420
|
exports.useTap = useTap;
|
|
1416
1421
|
//# sourceMappingURL=index.js.map
|