@expressive/mvc 0.1.1 → 0.2.2
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 +50 -10
- package/lib/index.esm.js +109 -109
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +108 -108
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
|
@@ -156,16 +156,16 @@ const LOCAL = Symbol("LOCAL");
|
|
|
156
156
|
const STATE = Symbol("STATE");
|
|
157
157
|
class Model {
|
|
158
158
|
constructor() {
|
|
159
|
-
|
|
160
|
-
define(this, CONTROL, control);
|
|
159
|
+
define(this, CONTROL, new Controller(this));
|
|
161
160
|
define(this, "get", this);
|
|
161
|
+
define(this, "is", this);
|
|
162
162
|
defineLazy(this, "set", () => {
|
|
163
|
+
const controller = control(this);
|
|
163
164
|
const assign = (key, value) => {
|
|
164
|
-
|
|
165
|
+
controller.update(key, value);
|
|
165
166
|
};
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
define(assign, key, control.ref(key));
|
|
167
|
+
for (const key of getOwnPropertyNames(controller.proxy))
|
|
168
|
+
define(assign, key, controller.ref(key));
|
|
169
169
|
return assign;
|
|
170
170
|
});
|
|
171
171
|
}
|
|
@@ -353,10 +353,10 @@ class Subscriber {
|
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
const Oops$a = issues({
|
|
356
|
-
|
|
356
|
+
BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
357
357
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
358
|
-
|
|
359
|
-
|
|
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.`
|
|
360
360
|
});
|
|
361
361
|
const INIT = new WeakSet();
|
|
362
362
|
const INFO = new WeakMap();
|
|
@@ -383,7 +383,7 @@ function from(source, arg1, arg2) {
|
|
|
383
383
|
}
|
|
384
384
|
// Regular function is too ambiguous so not allowed.
|
|
385
385
|
else
|
|
386
|
-
throw Oops$a.
|
|
386
|
+
throw Oops$a.BadSource(subject, key, source);
|
|
387
387
|
let sub;
|
|
388
388
|
const setter = arg1;
|
|
389
389
|
const info = { key, parent, priority: 1 };
|
|
@@ -398,7 +398,7 @@ function from(source, arg1, arg2) {
|
|
|
398
398
|
return setter.call(sub.proxy, sub.proxy);
|
|
399
399
|
}
|
|
400
400
|
catch (err) {
|
|
401
|
-
Oops$a.
|
|
401
|
+
Oops$a.Failed(subject, key, !!initial).warn();
|
|
402
402
|
throw err;
|
|
403
403
|
}
|
|
404
404
|
}
|
|
@@ -439,7 +439,7 @@ function from(source, arg1, arg2) {
|
|
|
439
439
|
}
|
|
440
440
|
catch (e) {
|
|
441
441
|
if (early)
|
|
442
|
-
Oops$a.
|
|
442
|
+
Oops$a.Early(key).warn();
|
|
443
443
|
throw e;
|
|
444
444
|
}
|
|
445
445
|
finally {
|
|
@@ -623,9 +623,6 @@ function control(subject, cb) {
|
|
|
623
623
|
control = new Controller(subject);
|
|
624
624
|
define(subject, CONTROL, control);
|
|
625
625
|
}
|
|
626
|
-
return ready(control, cb);
|
|
627
|
-
}
|
|
628
|
-
function ready(control, cb) {
|
|
629
626
|
const ready = READY.has(control);
|
|
630
627
|
if (!ready) {
|
|
631
628
|
if (cb) {
|
|
@@ -723,14 +720,14 @@ function forSubscriber(fn) {
|
|
|
723
720
|
}
|
|
724
721
|
|
|
725
722
|
const Oops$8 = issues({
|
|
726
|
-
|
|
723
|
+
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
727
724
|
});
|
|
728
725
|
function act(task) {
|
|
729
726
|
return apply(function act(key) {
|
|
730
727
|
let pending = false;
|
|
731
728
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
732
729
|
if (pending)
|
|
733
|
-
return Promise.reject(Oops$8.
|
|
730
|
+
return Promise.reject(Oops$8.DuplicatePending(key));
|
|
734
731
|
pending = true;
|
|
735
732
|
this.update(key);
|
|
736
733
|
try {
|
|
@@ -835,28 +832,74 @@ function createRef(key, cb) {
|
|
|
835
832
|
|
|
836
833
|
const Oops$7 = issues({
|
|
837
834
|
NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
835
|
+
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
836
|
+
Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
841
837
|
});
|
|
842
838
|
function set(factory, argument) {
|
|
843
839
|
return apply(function set(key) {
|
|
840
|
+
const { subject, state } = this;
|
|
841
|
+
const required = argument === true || argument === undefined;
|
|
844
842
|
let set;
|
|
845
843
|
let get;
|
|
846
844
|
let suspense;
|
|
847
|
-
const required = argument === true || argument === undefined;
|
|
848
845
|
if (factory === undefined)
|
|
849
846
|
suspense = true;
|
|
850
|
-
else
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
847
|
+
else {
|
|
848
|
+
let pending;
|
|
849
|
+
let error;
|
|
850
|
+
const init = () => {
|
|
851
|
+
const output = typeof factory == "function" ?
|
|
852
|
+
mayRetry(() => factory.call(subject, key, subject)) :
|
|
853
|
+
factory;
|
|
854
|
+
if (output instanceof Promise) {
|
|
855
|
+
pending = output
|
|
856
|
+
.catch(err => error = err)
|
|
857
|
+
.then(val => state[key] = val)
|
|
858
|
+
.finally(() => {
|
|
859
|
+
pending = undefined;
|
|
860
|
+
this.update(key);
|
|
861
|
+
});
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
return state[key] = output;
|
|
865
|
+
};
|
|
866
|
+
const suspend = () => {
|
|
867
|
+
if (required === false)
|
|
868
|
+
return undefined;
|
|
869
|
+
const issue = Oops$7.NotReady(subject, key);
|
|
870
|
+
Object.assign(pending, {
|
|
871
|
+
message: issue.message,
|
|
872
|
+
stack: issue.stack
|
|
873
|
+
});
|
|
874
|
+
throw pending;
|
|
875
|
+
};
|
|
876
|
+
if (required)
|
|
877
|
+
try {
|
|
878
|
+
init();
|
|
879
|
+
}
|
|
880
|
+
catch (err) {
|
|
881
|
+
Oops$7.Failed(subject, key).warn();
|
|
882
|
+
throw err;
|
|
883
|
+
}
|
|
884
|
+
get = () => {
|
|
885
|
+
if (pending)
|
|
886
|
+
return suspend();
|
|
887
|
+
if (error)
|
|
888
|
+
throw error;
|
|
889
|
+
if (key in state)
|
|
890
|
+
return state[key];
|
|
891
|
+
let output = init();
|
|
892
|
+
return pending
|
|
893
|
+
? suspend()
|
|
894
|
+
: output;
|
|
895
|
+
};
|
|
896
|
+
}
|
|
854
897
|
if (typeof argument == "function")
|
|
855
898
|
set = createValueEffect(argument);
|
|
856
899
|
else
|
|
857
900
|
set = (value) => {
|
|
858
901
|
if (value === undefined && required)
|
|
859
|
-
throw Oops$7.NonOptional(
|
|
902
|
+
throw Oops$7.NonOptional(subject, key);
|
|
860
903
|
};
|
|
861
904
|
return {
|
|
862
905
|
set,
|
|
@@ -864,63 +907,12 @@ function set(factory, argument) {
|
|
|
864
907
|
suspense
|
|
865
908
|
};
|
|
866
909
|
});
|
|
867
|
-
}
|
|
868
|
-
function pendingFactory(parent, key, fn, required) {
|
|
869
|
-
const { subject, state } = parent;
|
|
870
|
-
let pending;
|
|
871
|
-
let error;
|
|
872
|
-
const init = () => {
|
|
873
|
-
const output = mayRetry(() => {
|
|
874
|
-
return fn.call(subject, key, subject);
|
|
875
|
-
});
|
|
876
|
-
if (output instanceof Promise) {
|
|
877
|
-
pending = output
|
|
878
|
-
.catch(err => error = err)
|
|
879
|
-
.then(val => state[key] = val)
|
|
880
|
-
.finally(() => {
|
|
881
|
-
pending = undefined;
|
|
882
|
-
parent.update(key);
|
|
883
|
-
});
|
|
884
|
-
return;
|
|
885
|
-
}
|
|
886
|
-
return state[key] = output;
|
|
887
|
-
};
|
|
888
|
-
const suspend = () => {
|
|
889
|
-
if (required === false)
|
|
890
|
-
return undefined;
|
|
891
|
-
const issue = Oops$7.ValueNotReady(subject, key);
|
|
892
|
-
Object.assign(pending, {
|
|
893
|
-
message: issue.message,
|
|
894
|
-
stack: issue.stack
|
|
895
|
-
});
|
|
896
|
-
throw pending;
|
|
897
|
-
};
|
|
898
|
-
if (required)
|
|
899
|
-
try {
|
|
900
|
-
init();
|
|
901
|
-
}
|
|
902
|
-
catch (err) {
|
|
903
|
-
Oops$7.FactoryFailed(subject, key).warn();
|
|
904
|
-
throw err;
|
|
905
|
-
}
|
|
906
|
-
return () => {
|
|
907
|
-
if (pending)
|
|
908
|
-
return suspend();
|
|
909
|
-
if (error)
|
|
910
|
-
throw error;
|
|
911
|
-
if (key in state)
|
|
912
|
-
return state[key];
|
|
913
|
-
let output = init();
|
|
914
|
-
return pending
|
|
915
|
-
? suspend()
|
|
916
|
-
: output;
|
|
917
|
-
};
|
|
918
910
|
}
|
|
919
911
|
|
|
920
912
|
const Parent = new WeakMap();
|
|
921
913
|
const Oops$6 = issues({
|
|
922
|
-
|
|
923
|
-
|
|
914
|
+
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
915
|
+
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
924
916
|
});
|
|
925
917
|
function parent(Expects, required) {
|
|
926
918
|
return apply(function parent() {
|
|
@@ -929,10 +921,10 @@ function parent(Expects, required) {
|
|
|
929
921
|
const expected = Expects.name;
|
|
930
922
|
if (!value) {
|
|
931
923
|
if (required !== false)
|
|
932
|
-
throw Oops$6.
|
|
924
|
+
throw Oops$6.Required(expected, child);
|
|
933
925
|
}
|
|
934
926
|
else if (!(value instanceof Expects))
|
|
935
|
-
throw Oops$6.
|
|
927
|
+
throw Oops$6.Unexpected(expected, child, value);
|
|
936
928
|
return { value };
|
|
937
929
|
});
|
|
938
930
|
}
|
|
@@ -1037,19 +1029,24 @@ class Lookup {
|
|
|
1037
1029
|
const LookupContext = React__default["default"].createContext(new Lookup());
|
|
1038
1030
|
const useLookup = () => React__default["default"].useContext(LookupContext);
|
|
1039
1031
|
const Oops$4 = issues({
|
|
1040
|
-
|
|
1032
|
+
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1041
1033
|
});
|
|
1042
1034
|
function useLocal(Type, arg) {
|
|
1043
1035
|
const instance = useLookup().get(Type);
|
|
1044
1036
|
if (!instance && arg !== false)
|
|
1045
|
-
throw Oops$4.
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1037
|
+
throw Oops$4.NotFound(Type.name);
|
|
1038
|
+
switch (typeof arg) {
|
|
1039
|
+
case "string":
|
|
1040
|
+
return instance[arg];
|
|
1041
|
+
case "function":
|
|
1042
|
+
React.useLayoutEffect(() => arg(instance), []);
|
|
1043
|
+
default:
|
|
1044
|
+
return instance;
|
|
1045
|
+
}
|
|
1049
1046
|
}
|
|
1050
1047
|
|
|
1051
1048
|
const Oops$3 = issues({
|
|
1052
|
-
|
|
1049
|
+
NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
1053
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.`
|
|
1054
1051
|
});
|
|
1055
1052
|
const PendingContext = new WeakMap();
|
|
@@ -1063,7 +1060,7 @@ function tap(type, argument) {
|
|
|
1063
1060
|
};
|
|
1064
1061
|
const { subject } = this;
|
|
1065
1062
|
if ("set" in subject.constructor)
|
|
1066
|
-
throw Oops$3.
|
|
1063
|
+
throw Oops$3.NotAllowed(subject, type.name);
|
|
1067
1064
|
getPending(subject).push(context => {
|
|
1068
1065
|
let instance = context.get(type);
|
|
1069
1066
|
if (typeof argument == "function") {
|
|
@@ -1241,8 +1238,8 @@ class MVC extends Model {
|
|
|
1241
1238
|
use(arg, callback) {
|
|
1242
1239
|
return useModel(this, arg, callback);
|
|
1243
1240
|
}
|
|
1244
|
-
static get(
|
|
1245
|
-
return useLocal(this,
|
|
1241
|
+
static get(arg) {
|
|
1242
|
+
return useLocal(this, arg);
|
|
1246
1243
|
}
|
|
1247
1244
|
static tap(key, expect) {
|
|
1248
1245
|
return useTap(this, key, expect);
|
|
@@ -1288,25 +1285,28 @@ class MVC extends Model {
|
|
|
1288
1285
|
}
|
|
1289
1286
|
|
|
1290
1287
|
const Oops$2 = issues({
|
|
1291
|
-
|
|
1288
|
+
BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
1292
1289
|
});
|
|
1293
1290
|
function Consumer(props) {
|
|
1294
|
-
const { get, has, children,
|
|
1291
|
+
const { get, has, children, for: type } = props;
|
|
1295
1292
|
if (typeof children == "function")
|
|
1296
|
-
return children(useTap(
|
|
1293
|
+
return children(useTap(type));
|
|
1297
1294
|
const callback = has || get;
|
|
1298
1295
|
if (typeof callback == "function")
|
|
1299
|
-
callback(useLocal(
|
|
1296
|
+
callback(useLocal(type, !!has));
|
|
1300
1297
|
else
|
|
1301
|
-
throw Oops$2.
|
|
1298
|
+
throw Oops$2.BadProps();
|
|
1302
1299
|
return null;
|
|
1303
1300
|
}
|
|
1304
1301
|
|
|
1305
1302
|
const Oops$1 = issues({
|
|
1306
|
-
|
|
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."
|
|
1307
1305
|
});
|
|
1308
1306
|
function Provider(props) {
|
|
1309
|
-
|
|
1307
|
+
if ("of" in props)
|
|
1308
|
+
throw Oops$1.PropDeprecated();
|
|
1309
|
+
const context = useNewContext(props.for);
|
|
1310
1310
|
const render = props.children;
|
|
1311
1311
|
useAppliedProps(context, props);
|
|
1312
1312
|
React__default["default"].useLayoutEffect(() => () => context.pop(), []);
|
|
@@ -1318,7 +1318,7 @@ function useNewContext(inject) {
|
|
|
1318
1318
|
const from = useLookup();
|
|
1319
1319
|
return React__default["default"].useMemo(() => {
|
|
1320
1320
|
if (!inject)
|
|
1321
|
-
throw Oops$1.
|
|
1321
|
+
throw Oops$1.NoType();
|
|
1322
1322
|
const context = from.push(inject);
|
|
1323
1323
|
for (const instance of context.local)
|
|
1324
1324
|
if (instance)
|
|
@@ -1332,7 +1332,7 @@ function useAppliedProps(within, props) {
|
|
|
1332
1332
|
const targets = within.local;
|
|
1333
1333
|
return function integrate(props) {
|
|
1334
1334
|
for (const [key, value] of entries(props))
|
|
1335
|
-
if (
|
|
1335
|
+
if (["of", "for", "children"].indexOf(key) < 0)
|
|
1336
1336
|
for (const into of targets)
|
|
1337
1337
|
if (into && key in into)
|
|
1338
1338
|
into[key] = value;
|
|
@@ -1353,15 +1353,15 @@ function RenderFunction(props) {
|
|
|
1353
1353
|
}
|
|
1354
1354
|
|
|
1355
1355
|
const Oops = issues({
|
|
1356
|
-
|
|
1357
|
-
|
|
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.`
|
|
1358
1358
|
});
|
|
1359
1359
|
const Active = new WeakMap();
|
|
1360
1360
|
class Global extends MVC {
|
|
1361
1361
|
static create(...args) {
|
|
1362
1362
|
const Type = this;
|
|
1363
1363
|
if (Active.has(Type))
|
|
1364
|
-
throw Oops.
|
|
1364
|
+
throw Oops.AlreadyExists(this.name);
|
|
1365
1365
|
const instance = super.create(...args);
|
|
1366
1366
|
Active.set(Type, instance);
|
|
1367
1367
|
return instance;
|
|
@@ -1379,7 +1379,7 @@ class Global extends MVC {
|
|
|
1379
1379
|
static get(arg) {
|
|
1380
1380
|
const instance = Active.get(this);
|
|
1381
1381
|
if (!instance && arg !== false)
|
|
1382
|
-
throw Oops.
|
|
1382
|
+
throw Oops.DoesNotExist(this.name);
|
|
1383
1383
|
return (typeof arg == "string" ?
|
|
1384
1384
|
instance[arg] :
|
|
1385
1385
|
instance);
|