@skipruntime/core 0.0.12 → 0.0.14
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/skiplang-json/index.d.ts +0 -3
- package/dist/skiplang-json/index.d.ts.map +1 -1
- package/dist/skiplang-json/index.js +5 -8
- package/dist/skiplang-json/index.js.map +1 -1
- package/dist/src/api.d.ts +36 -21
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/binding.d.ts +0 -5
- package/dist/src/binding.d.ts.map +1 -1
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +105 -63
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api.ts +28 -21
- package/src/binding.ts +0 -19
- package/src/index.ts +125 -100
package/src/index.ts
CHANGED
|
@@ -13,8 +13,7 @@ import type {
|
|
|
13
13
|
JsonObject,
|
|
14
14
|
} from "../skiplang-json/index.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
isSkManaged,
|
|
16
|
+
deepFreeze,
|
|
18
17
|
SkManaged,
|
|
19
18
|
checkOrCloneParam,
|
|
20
19
|
} from "../skiplang-json/index.js";
|
|
@@ -54,13 +53,28 @@ import {
|
|
|
54
53
|
type FromBinding,
|
|
55
54
|
} from "./binding.js";
|
|
56
55
|
|
|
57
|
-
export { sk_freeze, isSkManaged };
|
|
58
56
|
export * from "./api.js";
|
|
59
57
|
export * from "./errors.js";
|
|
60
58
|
|
|
61
59
|
export type JSONMapper = Mapper<Json, Json, Json, Json>;
|
|
62
60
|
export type JSONLazyCompute = LazyCompute<Json, Json>;
|
|
63
61
|
|
|
62
|
+
function instantiateUserObject<Params extends DepSafe[], Result extends object>(
|
|
63
|
+
what: string,
|
|
64
|
+
ctor: new (...params: Params) => Result,
|
|
65
|
+
params: Params,
|
|
66
|
+
): Result {
|
|
67
|
+
const checkedParams = params.map(checkOrCloneParam) as Params;
|
|
68
|
+
const obj = new ctor(...checkedParams);
|
|
69
|
+
Object.freeze(obj);
|
|
70
|
+
if (!obj.constructor.name) {
|
|
71
|
+
throw new SkipClassNameError(
|
|
72
|
+
`${what} classes must be defined at top-level.`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return obj;
|
|
76
|
+
}
|
|
77
|
+
|
|
64
78
|
class Handles {
|
|
65
79
|
private nextID: number = 1;
|
|
66
80
|
private readonly objects: any[] = [];
|
|
@@ -138,15 +152,18 @@ class LazyCollectionImpl<K extends Json, V extends Json>
|
|
|
138
152
|
) as (V & DepSafe)[];
|
|
139
153
|
}
|
|
140
154
|
|
|
141
|
-
getUnique(key: K): V & DepSafe {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
getUnique(key: K, _default?: { ifNone?: V; ifMany?: V }): V & DepSafe {
|
|
156
|
+
const values = this.getArray(key);
|
|
157
|
+
switch (values.length) {
|
|
158
|
+
case 1:
|
|
159
|
+
return values[0]!;
|
|
160
|
+
case 0:
|
|
161
|
+
if (_default?.ifNone !== undefined) return deepFreeze(_default.ifNone);
|
|
162
|
+
throw new SkipNonUniqueValueError();
|
|
163
|
+
default:
|
|
164
|
+
if (_default?.ifMany !== undefined) return deepFreeze(_default.ifMany);
|
|
165
|
+
throw new SkipNonUniqueValueError();
|
|
166
|
+
}
|
|
150
167
|
}
|
|
151
168
|
}
|
|
152
169
|
|
|
@@ -171,15 +188,18 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
171
188
|
) as (V & DepSafe)[];
|
|
172
189
|
}
|
|
173
190
|
|
|
174
|
-
getUnique(key: K): V & DepSafe {
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
getUnique(key: K, _default?: { ifNone?: V; ifMany?: V }): V & DepSafe {
|
|
192
|
+
const values = this.getArray(key);
|
|
193
|
+
switch (values.length) {
|
|
194
|
+
case 1:
|
|
195
|
+
return values[0]!;
|
|
196
|
+
case 0:
|
|
197
|
+
if (_default?.ifNone !== undefined) return deepFreeze(_default.ifNone);
|
|
198
|
+
throw new SkipNonUniqueValueError();
|
|
199
|
+
default:
|
|
200
|
+
if (_default?.ifMany !== undefined) return deepFreeze(_default.ifMany);
|
|
201
|
+
throw new SkipNonUniqueValueError();
|
|
202
|
+
}
|
|
183
203
|
}
|
|
184
204
|
|
|
185
205
|
size = () => {
|
|
@@ -212,14 +232,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
212
232
|
mapper: new (...params: Params) => Mapper<K, V, K2, V2>,
|
|
213
233
|
...params: Params
|
|
214
234
|
): EagerCollection<K2, V2> {
|
|
215
|
-
const
|
|
216
|
-
const mapperObj = new mapper(...mapperParams);
|
|
217
|
-
Object.freeze(mapperObj);
|
|
218
|
-
if (!mapperObj.constructor.name) {
|
|
219
|
-
throw new SkipClassNameError(
|
|
220
|
-
"Mapper classes must be defined at top-level.",
|
|
221
|
-
);
|
|
222
|
-
}
|
|
235
|
+
const mapperObj = instantiateUserObject("Mapper", mapper, params);
|
|
223
236
|
const skmapper = this.refs.binding.SkipRuntime_createMapper(
|
|
224
237
|
this.refs.handles.register(mapperObj),
|
|
225
238
|
);
|
|
@@ -238,25 +251,12 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
238
251
|
reducer: new (...params: ReducerParams) => Reducer<V2, Accum>,
|
|
239
252
|
...reducerParams: ReducerParams
|
|
240
253
|
) => {
|
|
241
|
-
const
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
Object.freeze(mapperObj);
|
|
248
|
-
Object.freeze(reducerObj);
|
|
249
|
-
|
|
250
|
-
if (!mapperObj.constructor.name) {
|
|
251
|
-
throw new SkipClassNameError(
|
|
252
|
-
"Mapper classes must be defined at top-level.",
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
if (!reducerObj.constructor.name) {
|
|
256
|
-
throw new SkipClassNameError(
|
|
257
|
-
"Reducer classes must be defined at top-level.",
|
|
258
|
-
);
|
|
259
|
-
}
|
|
254
|
+
const mapperObj = instantiateUserObject("Mapper", mapper, mapperParams);
|
|
255
|
+
const reducerObj = instantiateUserObject(
|
|
256
|
+
"Reducer",
|
|
257
|
+
reducer,
|
|
258
|
+
reducerParams,
|
|
259
|
+
);
|
|
260
260
|
|
|
261
261
|
const skmapper = this.refs.binding.SkipRuntime_createMapper(
|
|
262
262
|
this.refs.handles.register(mapperObj),
|
|
@@ -290,14 +290,7 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
290
290
|
reducer: new (...params: Params) => Reducer<V, Accum>,
|
|
291
291
|
...params: Params
|
|
292
292
|
): EagerCollection<K, Accum> {
|
|
293
|
-
const
|
|
294
|
-
const reducerObj = new reducer(...reducerParams);
|
|
295
|
-
Object.freeze(reducerObj);
|
|
296
|
-
if (!reducerObj.constructor.name) {
|
|
297
|
-
throw new SkipClassNameError(
|
|
298
|
-
"Reducer classes must be defined at top-level.",
|
|
299
|
-
);
|
|
300
|
-
}
|
|
293
|
+
const reducerObj = instantiateUserObject("Reducer", reducer, params);
|
|
301
294
|
if (sknative in reducerObj && typeof reducerObj[sknative] == "string") {
|
|
302
295
|
return this.derive<K, Accum>(
|
|
303
296
|
this.refs.binding.SkipRuntime_Collection__nativeReduce(
|
|
@@ -320,8 +313,8 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
320
313
|
}
|
|
321
314
|
|
|
322
315
|
merge(...others: EagerCollection<K, V>[]): EagerCollection<K, V> {
|
|
323
|
-
const otherNames = others.map(
|
|
324
|
-
(other)
|
|
316
|
+
const otherNames = others.map((other) =>
|
|
317
|
+
EagerCollectionImpl.getName(other),
|
|
325
318
|
);
|
|
326
319
|
const mapped = this.refs.binding.SkipRuntime_Collection__merge(
|
|
327
320
|
this.collection,
|
|
@@ -335,6 +328,12 @@ class EagerCollectionImpl<K extends Json, V extends Json>
|
|
|
335
328
|
): EagerCollection<K2, V2> {
|
|
336
329
|
return new EagerCollectionImpl<K2, V2>(collection, this.refs);
|
|
337
330
|
}
|
|
331
|
+
|
|
332
|
+
static getName<K extends Json, V extends Json>(
|
|
333
|
+
coll: EagerCollection<K, V>,
|
|
334
|
+
): string {
|
|
335
|
+
return (coll as EagerCollectionImpl<K, V>).collection;
|
|
336
|
+
}
|
|
338
337
|
}
|
|
339
338
|
|
|
340
339
|
class CollectionWriter<K extends Json, V extends Json> {
|
|
@@ -398,14 +397,7 @@ class ContextImpl extends SkManaged implements Context {
|
|
|
398
397
|
compute: new (...params: Params) => LazyCompute<K, V>,
|
|
399
398
|
...params: Params
|
|
400
399
|
): LazyCollection<K, V> {
|
|
401
|
-
const
|
|
402
|
-
const computeObj = new compute(...mapperParams);
|
|
403
|
-
Object.freeze(computeObj);
|
|
404
|
-
if (!computeObj.constructor.name) {
|
|
405
|
-
throw new SkipClassNameError(
|
|
406
|
-
"LazyCompute classes must be defined at top-level.",
|
|
407
|
-
);
|
|
408
|
-
}
|
|
400
|
+
const computeObj = instantiateUserObject("LazyCompute", compute, params);
|
|
409
401
|
const skcompute = this.refs.binding.SkipRuntime_createLazyCompute(
|
|
410
402
|
this.refs.handles.register(computeObj),
|
|
411
403
|
);
|
|
@@ -728,47 +720,74 @@ export class ServiceInstance {
|
|
|
728
720
|
}
|
|
729
721
|
|
|
730
722
|
class ValuesImpl<T> implements Values<T> {
|
|
723
|
+
/* Lazy Iterable/Sequence: values are generated from
|
|
724
|
+
the Iterator pointer and stored in materialized.
|
|
725
|
+
Once finished the pointer is nullified. */
|
|
726
|
+
private readonly materialized: (T & DepSafe)[] = [];
|
|
727
|
+
|
|
731
728
|
constructor(
|
|
732
729
|
private readonly skjson: JsonConverter,
|
|
733
730
|
private readonly binding: FromBinding,
|
|
734
|
-
private
|
|
731
|
+
private pointer: Pointer<Internal.NonEmptyIterator> | null,
|
|
735
732
|
) {
|
|
736
|
-
this.skjson = skjson;
|
|
737
|
-
this.binding = binding;
|
|
738
733
|
this.pointer = pointer;
|
|
739
734
|
}
|
|
740
735
|
|
|
741
|
-
next(): Nullable<T & DepSafe> {
|
|
742
|
-
|
|
736
|
+
private next(): Nullable<T & DepSafe> {
|
|
737
|
+
if (this.pointer === null) {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const v = this.skjson.importOptJSON(
|
|
743
742
|
this.binding.SkipRuntime_NonEmptyIterator__next(this.pointer),
|
|
744
743
|
) as Nullable<T & DepSafe>;
|
|
744
|
+
|
|
745
|
+
if (v === null) {
|
|
746
|
+
this.pointer = null;
|
|
747
|
+
} else {
|
|
748
|
+
this.materialized.push(v);
|
|
749
|
+
}
|
|
750
|
+
return v;
|
|
745
751
|
}
|
|
746
752
|
|
|
747
|
-
getUnique(): T & DepSafe {
|
|
748
|
-
|
|
749
|
-
this.
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
+
getUnique(_default?: { ifMany?: T }): T & DepSafe {
|
|
754
|
+
if (this.materialized.length < 1) {
|
|
755
|
+
this.next();
|
|
756
|
+
}
|
|
757
|
+
const first = this.materialized[0];
|
|
758
|
+
if (
|
|
759
|
+
first === undefined /* i.e. this.materialized.length == 0 */ ||
|
|
760
|
+
this.materialized.length >= 2 ||
|
|
761
|
+
this.next() !== null
|
|
762
|
+
) {
|
|
763
|
+
if (_default?.ifMany !== undefined) return deepFreeze(_default.ifMany);
|
|
764
|
+
throw new SkipNonUniqueValueError();
|
|
765
|
+
}
|
|
766
|
+
return first;
|
|
753
767
|
}
|
|
754
768
|
|
|
755
|
-
toArray
|
|
756
|
-
|
|
757
|
-
|
|
769
|
+
toArray(): (T & DepSafe)[] {
|
|
770
|
+
while (this.next() !== null);
|
|
771
|
+
return this.materialized;
|
|
772
|
+
}
|
|
758
773
|
|
|
759
774
|
[Symbol.iterator](): Iterator<T & DepSafe> {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
this.
|
|
763
|
-
this.
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
}
|
|
775
|
+
let i = 0;
|
|
776
|
+
const next = (): IteratorResult<T & DepSafe> => {
|
|
777
|
+
// Invariant: this.materialized.length >= i
|
|
778
|
+
let value = this.materialized[i];
|
|
779
|
+
if (value === undefined /* i.e. this.materialized.length == i */) {
|
|
780
|
+
const next = this.next();
|
|
781
|
+
if (next === null) {
|
|
782
|
+
return { value: null, done: true };
|
|
783
|
+
}
|
|
784
|
+
value = next;
|
|
785
|
+
}
|
|
786
|
+
i++;
|
|
787
|
+
return { value };
|
|
771
788
|
};
|
|
789
|
+
|
|
790
|
+
return { next };
|
|
772
791
|
}
|
|
773
792
|
}
|
|
774
793
|
|
|
@@ -820,11 +839,19 @@ export class ToBinding {
|
|
|
820
839
|
): Pointer<Internal.CJArray> {
|
|
821
840
|
const skjson = this.getJsonConverter();
|
|
822
841
|
const mapper = this.handles.get(skmapper);
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
842
|
+
const context = new ContextImpl(this.refs());
|
|
843
|
+
try {
|
|
844
|
+
const result = mapper.mapEntry(
|
|
845
|
+
skjson.importJSON(key) as Json,
|
|
846
|
+
new ValuesImpl<Json>(skjson, this.binding, values),
|
|
847
|
+
context,
|
|
848
|
+
);
|
|
849
|
+
return skjson.exportJSON(Array.from(result));
|
|
850
|
+
} catch (e: unknown) {
|
|
851
|
+
console.error("Uncaught error during Skip runtime reactive update: ", e);
|
|
852
|
+
// Exception in async context will be dropped -- this `throw` is just to appease typechecker
|
|
853
|
+
throw e;
|
|
854
|
+
}
|
|
828
855
|
}
|
|
829
856
|
|
|
830
857
|
SkipRuntime_deleteMapper(mapper: Handle<JSONMapper>): void {
|
|
@@ -868,7 +895,7 @@ export class ToBinding {
|
|
|
868
895
|
collections[key] = new EagerCollectionImpl<Json, Json>(name, refs);
|
|
869
896
|
}
|
|
870
897
|
const collection = resource.instantiate(collections, new ContextImpl(refs));
|
|
871
|
-
return (collection
|
|
898
|
+
return EagerCollectionImpl.getName(collection);
|
|
872
899
|
}
|
|
873
900
|
|
|
874
901
|
SkipRuntime_deleteResource(resource: Handle<Resource>): void {
|
|
@@ -912,9 +939,7 @@ export class ToBinding {
|
|
|
912
939
|
const result = service.createGraph(collections, new ContextImpl(refs));
|
|
913
940
|
const collectionsNames: { [name: string]: string } = {};
|
|
914
941
|
for (const [name, collection] of Object.entries(result)) {
|
|
915
|
-
collectionsNames[name] = (
|
|
916
|
-
collection as EagerCollectionImpl<Json, Json>
|
|
917
|
-
).collection;
|
|
942
|
+
collectionsNames[name] = EagerCollectionImpl.getName(collection);
|
|
918
943
|
}
|
|
919
944
|
return skjson.exportJSON(collectionsNames);
|
|
920
945
|
}
|