@expressive/mvc 0.1.0 → 0.2.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/lib/index.d.ts +37 -7
- package/lib/index.esm.js +102 -107
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +102 -107
- 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
|
|
|
@@ -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,19 @@ 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
|
-
function
|
|
1034
|
+
function useLocal(Type, arg) {
|
|
1043
1035
|
const instance = useLookup().get(Type);
|
|
1044
1036
|
if (!instance && arg !== false)
|
|
1045
|
-
throw Oops$4.
|
|
1037
|
+
throw Oops$4.NotFound(Type.name);
|
|
1046
1038
|
return typeof arg == "string" ?
|
|
1047
1039
|
instance[arg] :
|
|
1048
1040
|
instance;
|
|
1049
1041
|
}
|
|
1050
1042
|
|
|
1051
1043
|
const Oops$3 = issues({
|
|
1052
|
-
|
|
1044
|
+
NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
1053
1045
|
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
1046
|
});
|
|
1055
1047
|
const PendingContext = new WeakMap();
|
|
@@ -1063,7 +1055,7 @@ function tap(type, argument) {
|
|
|
1063
1055
|
};
|
|
1064
1056
|
const { subject } = this;
|
|
1065
1057
|
if ("set" in subject.constructor)
|
|
1066
|
-
throw Oops$3.
|
|
1058
|
+
throw Oops$3.NotAllowed(subject, type.name);
|
|
1067
1059
|
getPending(subject).push(context => {
|
|
1068
1060
|
let instance = context.get(type);
|
|
1069
1061
|
if (typeof argument == "function") {
|
|
@@ -1207,7 +1199,7 @@ function useTap(source, path, expect) {
|
|
|
1207
1199
|
if ("get" in source)
|
|
1208
1200
|
return () => source.get();
|
|
1209
1201
|
if ("prototype" in source)
|
|
1210
|
-
return () =>
|
|
1202
|
+
return () => useLocal(source);
|
|
1211
1203
|
else
|
|
1212
1204
|
return source;
|
|
1213
1205
|
}, [])();
|
|
@@ -1242,7 +1234,7 @@ class MVC extends Model {
|
|
|
1242
1234
|
return useModel(this, arg, callback);
|
|
1243
1235
|
}
|
|
1244
1236
|
static get(required) {
|
|
1245
|
-
return
|
|
1237
|
+
return useLocal(this, required);
|
|
1246
1238
|
}
|
|
1247
1239
|
static tap(key, expect) {
|
|
1248
1240
|
return useTap(this, key, expect);
|
|
@@ -1288,25 +1280,28 @@ class MVC extends Model {
|
|
|
1288
1280
|
}
|
|
1289
1281
|
|
|
1290
1282
|
const Oops$2 = issues({
|
|
1291
|
-
|
|
1283
|
+
BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
1292
1284
|
});
|
|
1293
1285
|
function Consumer(props) {
|
|
1294
|
-
const { get, has, children,
|
|
1286
|
+
const { get, has, children, for: type } = props;
|
|
1295
1287
|
if (typeof children == "function")
|
|
1296
|
-
return children(useTap(
|
|
1288
|
+
return children(useTap(type));
|
|
1297
1289
|
const callback = has || get;
|
|
1298
1290
|
if (typeof callback == "function")
|
|
1299
|
-
callback(
|
|
1291
|
+
callback(useLocal(type, !!has));
|
|
1300
1292
|
else
|
|
1301
|
-
throw Oops$2.
|
|
1293
|
+
throw Oops$2.BadProps();
|
|
1302
1294
|
return null;
|
|
1303
1295
|
}
|
|
1304
1296
|
|
|
1305
1297
|
const Oops$1 = issues({
|
|
1306
|
-
|
|
1298
|
+
NoType: () => "Provider 'of' prop must be Model, typeof Model or a collection of them.",
|
|
1299
|
+
PropDeprecated: () => "Provider `of` prop is deprecated, use `for` instead."
|
|
1307
1300
|
});
|
|
1308
1301
|
function Provider(props) {
|
|
1309
|
-
|
|
1302
|
+
if ("of" in props)
|
|
1303
|
+
throw Oops$1.PropDeprecated();
|
|
1304
|
+
const context = useNewContext(props.for);
|
|
1310
1305
|
const render = props.children;
|
|
1311
1306
|
useAppliedProps(context, props);
|
|
1312
1307
|
React__default["default"].useLayoutEffect(() => () => context.pop(), []);
|
|
@@ -1318,7 +1313,7 @@ function useNewContext(inject) {
|
|
|
1318
1313
|
const from = useLookup();
|
|
1319
1314
|
return React__default["default"].useMemo(() => {
|
|
1320
1315
|
if (!inject)
|
|
1321
|
-
throw Oops$1.
|
|
1316
|
+
throw Oops$1.NoType();
|
|
1322
1317
|
const context = from.push(inject);
|
|
1323
1318
|
for (const instance of context.local)
|
|
1324
1319
|
if (instance)
|
|
@@ -1332,7 +1327,7 @@ function useAppliedProps(within, props) {
|
|
|
1332
1327
|
const targets = within.local;
|
|
1333
1328
|
return function integrate(props) {
|
|
1334
1329
|
for (const [key, value] of entries(props))
|
|
1335
|
-
if (
|
|
1330
|
+
if (["of", "for", "children"].indexOf(key) < 0)
|
|
1336
1331
|
for (const into of targets)
|
|
1337
1332
|
if (into && key in into)
|
|
1338
1333
|
into[key] = value;
|
|
@@ -1353,15 +1348,15 @@ function RenderFunction(props) {
|
|
|
1353
1348
|
}
|
|
1354
1349
|
|
|
1355
1350
|
const Oops = issues({
|
|
1356
|
-
|
|
1357
|
-
|
|
1351
|
+
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.`,
|
|
1352
|
+
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1358
1353
|
});
|
|
1359
1354
|
const Active = new WeakMap();
|
|
1360
1355
|
class Global extends MVC {
|
|
1361
1356
|
static create(...args) {
|
|
1362
1357
|
const Type = this;
|
|
1363
1358
|
if (Active.has(Type))
|
|
1364
|
-
throw Oops.
|
|
1359
|
+
throw Oops.AlreadyExists(this.name);
|
|
1365
1360
|
const instance = super.create(...args);
|
|
1366
1361
|
Active.set(Type, instance);
|
|
1367
1362
|
return instance;
|
|
@@ -1379,7 +1374,7 @@ class Global extends MVC {
|
|
|
1379
1374
|
static get(arg) {
|
|
1380
1375
|
const instance = Active.get(this);
|
|
1381
1376
|
if (!instance && arg !== false)
|
|
1382
|
-
throw Oops.
|
|
1377
|
+
throw Oops.DoesNotExist(this.name);
|
|
1383
1378
|
return (typeof arg == "string" ?
|
|
1384
1379
|
instance[arg] :
|
|
1385
1380
|
instance);
|
|
@@ -1415,7 +1410,7 @@ exports.set = set;
|
|
|
1415
1410
|
exports.tap = tap;
|
|
1416
1411
|
exports.use = use$1;
|
|
1417
1412
|
exports.useFrom = useFrom;
|
|
1418
|
-
exports.
|
|
1413
|
+
exports.useLocal = useLocal;
|
|
1419
1414
|
exports.useModel = useModel;
|
|
1420
1415
|
exports.useTap = useTap;
|
|
1421
1416
|
//# sourceMappingURL=index.js.map
|