shelving 1.63.0 → 1.65.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/api/Resource.js +2 -2
- package/db/Database.d.ts +2 -1
- package/db/Reference.d.ts +46 -39
- package/db/Reference.js +70 -73
- package/db/index.d.ts +0 -3
- package/db/index.js +0 -3
- package/error/ThroughError.d.ts +8 -0
- package/error/ThroughError.js +13 -0
- package/firestore/client/FirestoreClientProvider.d.ts +11 -11
- package/firestore/client/FirestoreClientProvider.js +21 -15
- package/firestore/lite/FirestoreLiteProvider.d.ts +10 -11
- package/firestore/lite/FirestoreLiteProvider.js +21 -16
- package/firestore/server/FirestoreServerProvider.d.ts +11 -11
- package/firestore/server/FirestoreServerProvider.js +23 -17
- package/index.d.ts +2 -1
- package/index.js +2 -1
- package/markup/rules.js +4 -4
- package/observe/AbstractObserver.d.ts +15 -0
- package/observe/AbstractObserver.js +42 -0
- package/observe/AsyncObserver.d.ts +5 -0
- package/observe/AsyncObserver.js +8 -0
- package/{stream/LastStream.d.ts → observe/LastSubject.d.ts} +2 -2
- package/observe/LastSubject.js +12 -0
- package/observe/MatchObserver.d.ts +9 -0
- package/observe/MatchObserver.js +12 -0
- package/observe/MatchableObserver.d.ts +7 -0
- package/observe/MatchableObserver.js +10 -0
- package/observe/Observable.d.ts +20 -0
- package/observe/Observable.js +7 -0
- package/observe/Observer.d.ts +31 -0
- package/observe/Observer.js +48 -0
- package/observe/OnceObserver.d.ts +5 -0
- package/observe/OnceObserver.js +8 -0
- package/observe/Subject.d.ts +46 -0
- package/observe/Subject.js +110 -0
- package/observe/ThroughObserver.d.ts +5 -0
- package/observe/ThroughObserver.js +8 -0
- package/observe/TransformObserver.d.ts +9 -0
- package/observe/TransformObserver.js +12 -0
- package/observe/TransformableObserver.d.ts +7 -0
- package/observe/TransformableObserver.js +8 -0
- package/observe/index.d.ts +13 -0
- package/observe/index.js +13 -0
- package/observe/util.d.ts +24 -0
- package/observe/util.js +34 -0
- package/package.json +3 -3
- package/provider/BatchProvider.d.ts +8 -8
- package/provider/BatchProvider.js +26 -31
- package/provider/CacheProvider.d.ts +12 -24
- package/provider/CacheProvider.js +40 -67
- package/provider/DebugProvider.d.ts +20 -0
- package/provider/DebugProvider.js +170 -0
- package/provider/MemoryProvider.d.ts +43 -14
- package/provider/MemoryProvider.js +148 -115
- package/provider/Provider.d.ts +23 -23
- package/provider/ThroughProvider.d.ts +20 -12
- package/provider/ThroughProvider.js +12 -12
- package/provider/ValidationProvider.d.ts +10 -10
- package/provider/ValidationProvider.js +69 -14
- package/provider/index.d.ts +1 -1
- package/provider/index.js +1 -1
- package/query/Filter.d.ts +8 -16
- package/query/Filter.js +8 -7
- package/query/Filters.d.ts +6 -11
- package/query/Filters.js +5 -5
- package/query/Query.d.ts +10 -13
- package/query/Query.js +10 -10
- package/query/Rule.d.ts +2 -3
- package/query/Sort.d.ts +7 -8
- package/query/Sort.js +5 -5
- package/query/Sorts.d.ts +3 -4
- package/query/Sorts.js +2 -2
- package/query/index.d.ts +0 -1
- package/query/index.js +0 -1
- package/react/index.d.ts +0 -6
- package/react/index.js +3 -6
- package/react/useDocument.d.ts +32 -39
- package/react/useDocument.js +71 -75
- package/react/useInstance.d.ts +4 -7
- package/react/useInstance.js +6 -9
- package/react/useLazy.d.ts +5 -9
- package/react/useQuery.d.ts +48 -46
- package/react/useQuery.js +116 -87
- package/react/useReduce.d.ts +8 -1
- package/react/useReduce.js +1 -3
- package/react/useSubscribe.d.ts +5 -6
- package/react/useSubscribe.js +10 -11
- package/schema/AllowSchema.d.ts +3 -4
- package/schema/AllowSchema.js +1 -1
- package/schema/MapSchema.js +2 -2
- package/schema/ObjectSchema.js +2 -2
- package/{stream → state}/ArrayState.d.ts +1 -1
- package/{stream → state}/ArrayState.js +8 -10
- package/{stream → state}/BooleanState.d.ts +1 -1
- package/{stream → state}/BooleanState.js +3 -5
- package/{stream → state}/DataState.d.ts +3 -3
- package/{stream → state}/DataState.js +6 -6
- package/{stream → state}/ObjectState.d.ts +1 -1
- package/{stream → state}/ObjectState.js +6 -8
- package/state/SelfClosingState.d.ts +18 -0
- package/state/SelfClosingState.js +34 -0
- package/state/State.d.ts +32 -0
- package/state/State.js +69 -0
- package/{stream → state}/index.d.ts +1 -4
- package/{stream → state}/index.js +1 -4
- package/test/basics.d.ts +12 -15
- package/test/basics.js +10 -20
- package/test/people.d.ts +9 -14
- package/test/people.js +6 -12
- package/test/util.d.ts +3 -3
- package/test/util.js +7 -7
- package/update/ArrayUpdate.d.ts +2 -1
- package/update/ArrayUpdate.js +4 -4
- package/update/DataUpdate.d.ts +2 -1
- package/update/DataUpdate.js +3 -2
- package/update/ObjectUpdate.d.ts +2 -1
- package/update/ObjectUpdate.js +14 -5
- package/update/Update.d.ts +2 -2
- package/update/util.d.ts +1 -4
- package/update/util.js +3 -3
- package/util/async.d.ts +4 -5
- package/util/async.js +3 -2
- package/util/clone.js +3 -3
- package/util/data.d.ts +42 -44
- package/util/data.js +32 -33
- package/util/entry.d.ts +15 -28
- package/util/entry.js +19 -13
- package/util/equal.d.ts +4 -5
- package/util/filter.d.ts +5 -46
- package/util/filter.js +5 -47
- package/util/function.d.ts +5 -5
- package/util/function.js +3 -3
- package/util/hydrate.d.ts +1 -1
- package/util/hydrate.js +7 -7
- package/util/index.d.ts +1 -1
- package/util/index.js +1 -1
- package/util/iterate.d.ts +15 -19
- package/util/iterate.js +7 -17
- package/util/match.d.ts +20 -0
- package/util/match.js +14 -0
- package/util/random.js +2 -3
- package/util/search.d.ts +1 -1
- package/util/sort.d.ts +4 -30
- package/util/sort.js +0 -38
- package/util/string.d.ts +1 -1
- package/util/string.js +2 -7
- package/util/template.js +2 -2
- package/util/timeout.d.ts +2 -0
- package/util/timeout.js +8 -1
- package/util/transform.d.ts +39 -44
- package/util/transform.js +21 -34
- package/util/validate.d.ts +26 -20
- package/util/validate.js +20 -22
- package/api/errors.d.ts +0 -8
- package/api/errors.js +0 -9
- package/db/PaginationState.d.ts +0 -31
- package/db/PaginationState.js +0 -67
- package/db/errors.d.ts +0 -25
- package/db/errors.js +0 -34
- package/db/util.d.ts +0 -37
- package/db/util.js +0 -54
- package/provider/ErrorProvider.d.ts +0 -32
- package/provider/ErrorProvider.js +0 -175
- package/query/util.d.ts +0 -8
- package/query/util.js +0 -8
- package/react/useCompare.d.ts +0 -3
- package/react/useCompare.js +0 -8
- package/react/useFetch.d.ts +0 -17
- package/react/useFetch.js +0 -41
- package/react/usePagination.d.ts +0 -8
- package/react/usePagination.js +0 -22
- package/react/usePureEffect.d.ts +0 -10
- package/react/usePureEffect.js +0 -17
- package/react/usePureState.d.ts +0 -11
- package/react/usePureState.js +0 -16
- package/react/useState.d.ts +0 -39
- package/react/useState.js +0 -65
- package/stream/LastStream.js +0 -12
- package/stream/LazyState.d.ts +0 -11
- package/stream/LazyState.js +0 -28
- package/stream/LazyStream.d.ts +0 -12
- package/stream/LazyStream.js +0 -28
- package/stream/State.d.ts +0 -46
- package/stream/State.js +0 -66
- package/stream/Stream.d.ts +0 -66
- package/stream/Stream.js +0 -122
- package/util/observe.d.ts +0 -111
- package/util/observe.js +0 -159
|
@@ -45,10 +45,16 @@ function getQuery(firestore, ref) {
|
|
|
45
45
|
constraints.push(firestoreLimit(limit));
|
|
46
46
|
return firestoreQuery(getCollection(firestore, ref), ...constraints);
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
function getEntities(snapshot) {
|
|
49
|
+
return snapshot.docs.map(getEntity);
|
|
50
|
+
}
|
|
51
|
+
function getEntity(snapshot) {
|
|
52
|
+
const data = snapshot.data();
|
|
53
|
+
return { ...data, id: snapshot.id };
|
|
54
|
+
}
|
|
55
|
+
function getOptionalData(snapshot) {
|
|
56
|
+
const data = snapshot.data();
|
|
57
|
+
return data ? { ...data, id: snapshot.id } : null;
|
|
52
58
|
}
|
|
53
59
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
54
60
|
function* yieldFieldValues(updates, prefix = "") {
|
|
@@ -82,32 +88,31 @@ export class FirestoreClientProvider extends Provider {
|
|
|
82
88
|
super();
|
|
83
89
|
this.firestore = firestore;
|
|
84
90
|
}
|
|
85
|
-
async
|
|
86
|
-
|
|
87
|
-
return snapshot.data() || null;
|
|
91
|
+
async getDocument(ref) {
|
|
92
|
+
return getOptionalData(await getDoc(getDocument(this.firestore, ref)));
|
|
88
93
|
}
|
|
89
|
-
|
|
90
|
-
throw new
|
|
94
|
+
subscribeDocument() {
|
|
95
|
+
throw new UnsupportedError("FirestoreLiteProvider does not support realtime subscriptions");
|
|
91
96
|
}
|
|
92
|
-
async
|
|
93
|
-
const reference = await addDoc(getCollection(this.firestore, ref), data);
|
|
97
|
+
async addDocument(ref, data) {
|
|
98
|
+
const reference = await addDoc(getCollection(this.firestore, ref), data);
|
|
94
99
|
return reference.id;
|
|
95
100
|
}
|
|
96
|
-
async
|
|
101
|
+
async setDocument(ref, data) {
|
|
97
102
|
await setDoc(getDocument(this.firestore, ref), data);
|
|
98
103
|
}
|
|
99
|
-
async
|
|
104
|
+
async updateDocument(ref, update) {
|
|
100
105
|
const fieldValues = Object.fromEntries(yieldFieldValues(update));
|
|
101
106
|
await updateDoc(getDocument(this.firestore, ref), fieldValues);
|
|
102
107
|
}
|
|
103
|
-
async
|
|
108
|
+
async deleteDocument(ref) {
|
|
104
109
|
await deleteDoc(getDocument(this.firestore, ref));
|
|
105
110
|
}
|
|
106
111
|
async getQuery(ref) {
|
|
107
|
-
return
|
|
112
|
+
return getEntities(await getDocs(getQuery(this.firestore, ref)));
|
|
108
113
|
}
|
|
109
114
|
subscribeQuery() {
|
|
110
|
-
throw new
|
|
115
|
+
throw new UnsupportedError("FirestoreLiteProvider does not support realtime subscriptions");
|
|
111
116
|
}
|
|
112
117
|
async setQuery(ref, data) {
|
|
113
118
|
const snapshot = await getDocs(getQuery(this.firestore, ref));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Firestore } from "@google-cloud/firestore";
|
|
2
2
|
import type { DocumentReference, QueryReference } from "../../db/Reference.js";
|
|
3
|
-
import type { Data,
|
|
4
|
-
import type {
|
|
3
|
+
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
4
|
+
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
5
5
|
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
6
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
|
-
import { Observer
|
|
7
|
+
import { Observer } from "../../observe/Observer.js";
|
|
8
8
|
/**
|
|
9
9
|
* Firestore server database provider.
|
|
10
10
|
* - Works with the Firebase Admin SDK for Node.JS
|
|
@@ -12,14 +12,14 @@ import { Observer, Unsubscriber } from "../../util/observe.js";
|
|
|
12
12
|
export declare class FirestoreServerProvider extends Provider implements AsynchronousProvider {
|
|
13
13
|
readonly firestore: Firestore;
|
|
14
14
|
constructor(firestore?: Firestore);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
getQuery<T extends Data>(ref: QueryReference<T>): Promise<
|
|
22
|
-
subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<
|
|
15
|
+
getDocument<T extends Data>(ref: DocumentReference<T>): Promise<OptionalEntity<T>>;
|
|
16
|
+
subscribeDocument<T extends Data>(ref: DocumentReference<T>, observer: Observer<OptionalEntity<T>>): Unsubscribe;
|
|
17
|
+
addDocument<T extends Data>(ref: QueryReference<T>, data: T): Promise<string>;
|
|
18
|
+
setDocument<T extends Data>(ref: DocumentReference<T>, data: T): Promise<void>;
|
|
19
|
+
updateDocument<T extends Data>(ref: DocumentReference<T>, update: DataUpdate<T>): Promise<void>;
|
|
20
|
+
deleteDocument<T extends Data>(ref: DocumentReference<T>): Promise<void>;
|
|
21
|
+
getQuery<T extends Data>(ref: QueryReference<T>): Promise<Entities<T>>;
|
|
22
|
+
subscribeQuery<T extends Data>(ref: QueryReference<T>, observer: Observer<Entities<T>>): Unsubscribe;
|
|
23
23
|
setQuery<T extends Data>(ref: QueryReference<T>, data: T): Promise<number>;
|
|
24
24
|
updateQuery<T extends Data>(ref: QueryReference<T>, update: DataUpdate<T>): Promise<number>;
|
|
25
25
|
deleteQuery<T extends Data>(ref: QueryReference<T>): Promise<number>;
|
|
@@ -5,7 +5,7 @@ import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
|
5
5
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
6
|
import { Increment } from "../../update/Increment.js";
|
|
7
7
|
import { ObjectUpdate } from "../../update/ObjectUpdate.js";
|
|
8
|
-
import { dispatchError, dispatchNext } from "../../
|
|
8
|
+
import { dispatchError, dispatchNext } from "../../observe/Observer.js";
|
|
9
9
|
// Constants.
|
|
10
10
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
11
11
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -46,10 +46,16 @@ function getQuery(firestore, ref) {
|
|
|
46
46
|
query = query.limit(limit);
|
|
47
47
|
return query;
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
function getEntities(snapshot) {
|
|
50
|
+
return snapshot.docs.map(getEntity);
|
|
51
|
+
}
|
|
52
|
+
function getEntity(snapshot) {
|
|
53
|
+
const data = snapshot.data();
|
|
54
|
+
return { ...data, id: snapshot.id };
|
|
55
|
+
}
|
|
56
|
+
function getOptionalEntity(snapshot) {
|
|
57
|
+
const data = snapshot.data();
|
|
58
|
+
return data ? { ...data, id: snapshot.id } : null;
|
|
53
59
|
}
|
|
54
60
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
55
61
|
function* yieldFieldValues(updates, prefix = "") {
|
|
@@ -81,36 +87,36 @@ export class FirestoreServerProvider extends Provider {
|
|
|
81
87
|
super();
|
|
82
88
|
this.firestore = firestore;
|
|
83
89
|
}
|
|
84
|
-
async
|
|
85
|
-
return (await getDocument(this.firestore, ref).get())
|
|
90
|
+
async getDocument(ref) {
|
|
91
|
+
return getOptionalEntity(await getDocument(this.firestore, ref).get());
|
|
86
92
|
}
|
|
87
|
-
|
|
88
|
-
return getDocument(this.firestore, ref).onSnapshot(snapshot => dispatchNext(observer, snapshot
|
|
93
|
+
subscribeDocument(ref, observer) {
|
|
94
|
+
return getDocument(this.firestore, ref).onSnapshot(snapshot => dispatchNext(observer, getOptionalEntity(snapshot)), thrown => dispatchError(observer, thrown));
|
|
89
95
|
}
|
|
90
|
-
async
|
|
96
|
+
async addDocument(ref, data) {
|
|
91
97
|
return (await getCollection(this.firestore, ref).add(data)).id;
|
|
92
98
|
}
|
|
93
|
-
async
|
|
99
|
+
async setDocument(ref, data) {
|
|
94
100
|
await getDocument(this.firestore, ref).set(data);
|
|
95
101
|
}
|
|
96
|
-
async
|
|
97
|
-
const fieldValues = Object.fromEntries(yieldFieldValues(update));
|
|
102
|
+
async updateDocument(ref, update) {
|
|
103
|
+
const fieldValues = Object.fromEntries(yieldFieldValues(update));
|
|
98
104
|
await getDocument(this.firestore, ref).update(fieldValues);
|
|
99
105
|
}
|
|
100
|
-
async
|
|
106
|
+
async deleteDocument(ref) {
|
|
101
107
|
await getDocument(this.firestore, ref).delete();
|
|
102
108
|
}
|
|
103
109
|
async getQuery(ref) {
|
|
104
|
-
return
|
|
110
|
+
return getEntities(await getQuery(this.firestore, ref).get());
|
|
105
111
|
}
|
|
106
112
|
subscribeQuery(ref, observer) {
|
|
107
|
-
return getQuery(this.firestore, ref).onSnapshot(snapshot => dispatchNext(observer,
|
|
113
|
+
return getQuery(this.firestore, ref).onSnapshot(snapshot => dispatchNext(observer, getEntities(snapshot)), thrown => dispatchError(observer, thrown));
|
|
108
114
|
}
|
|
109
115
|
async setQuery(ref, data) {
|
|
110
116
|
return await bulkWrite(this.firestore, ref, (w, s) => void w.set(s.ref, data));
|
|
111
117
|
}
|
|
112
118
|
async updateQuery(ref, update) {
|
|
113
|
-
const fieldValues = Object.fromEntries(yieldFieldValues(update));
|
|
119
|
+
const fieldValues = Object.fromEntries(yieldFieldValues(update));
|
|
114
120
|
return await bulkWrite(this.firestore, ref, (w, s) => void w.update(s.ref, fieldValues));
|
|
115
121
|
}
|
|
116
122
|
async deleteQuery(ref) {
|
package/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./api/index.js";
|
|
|
11
11
|
export * from "./error/index.js";
|
|
12
12
|
export * from "./feedback/index.js";
|
|
13
13
|
export * from "./markup/index.js";
|
|
14
|
-
export * from "./
|
|
14
|
+
export * from "./observe/index.js";
|
|
15
|
+
export * from "./state/index.js";
|
|
15
16
|
export * from "./update/index.js";
|
|
16
17
|
export * from "./util/index.js";
|
package/index.js
CHANGED
|
@@ -13,7 +13,8 @@ export * from "./api/index.js";
|
|
|
13
13
|
export * from "./error/index.js";
|
|
14
14
|
export * from "./feedback/index.js";
|
|
15
15
|
export * from "./markup/index.js";
|
|
16
|
-
export * from "./
|
|
16
|
+
export * from "./observe/index.js";
|
|
17
|
+
export * from "./state/index.js";
|
|
17
18
|
export * from "./update/index.js";
|
|
18
19
|
export * from "./util/index.js";
|
|
19
20
|
// Integrations.
|
package/markup/rules.js
CHANGED
|
@@ -39,14 +39,14 @@ const UNORDERED = `[${BULLETS}] +`; // Anything that can be a bullet (used for u
|
|
|
39
39
|
export const UNORDERED_LIST_RULE = {
|
|
40
40
|
regexp: getBlockRegExp(`${UNORDERED}(${MATCH_BLOCK.source})`),
|
|
41
41
|
render: ([, list = ""]) => {
|
|
42
|
-
const children = list.split(SPLIT_UL_ITEMS).map(
|
|
42
|
+
const children = list.split(SPLIT_UL_ITEMS).map(_mapUnorderedItem);
|
|
43
43
|
return { type: "ul", key: null, props: { children } };
|
|
44
44
|
},
|
|
45
45
|
contexts: ["block", "list"],
|
|
46
46
|
childContext: "list",
|
|
47
47
|
};
|
|
48
48
|
const SPLIT_UL_ITEMS = new RegExp(`\\n+${UNORDERED}`, "g");
|
|
49
|
-
const
|
|
49
|
+
const _mapUnorderedItem = (item, key) => {
|
|
50
50
|
const children = item.replace(MATCH_INDENT, "");
|
|
51
51
|
return { type: "li", key, props: { children } };
|
|
52
52
|
};
|
|
@@ -59,14 +59,14 @@ const ORDERED = "[0-9]+[.):] +"; // Number for a numbered list (e.g. `1.` or `2)
|
|
|
59
59
|
export const ORDERED_LIST_RULE = {
|
|
60
60
|
regexp: getBlockRegExp(`(${ORDERED}${MATCH_BLOCK.source})`),
|
|
61
61
|
render: ([, list = ""]) => {
|
|
62
|
-
const children = list.split(SPLIT_OL_ITEMS).map(
|
|
62
|
+
const children = list.split(SPLIT_OL_ITEMS).map(_mapOrderedItem);
|
|
63
63
|
return { type: "ol", key: null, props: { children } };
|
|
64
64
|
},
|
|
65
65
|
contexts: ["block", "list"],
|
|
66
66
|
childContext: "list",
|
|
67
67
|
};
|
|
68
68
|
const SPLIT_OL_ITEMS = new RegExp(`\\n+(?=${ORDERED})`, "g");
|
|
69
|
-
const
|
|
69
|
+
const _mapOrderedItem = (item, key) => {
|
|
70
70
|
const firstSpace = item.indexOf(" ");
|
|
71
71
|
const value = parseInt(item.slice(0, firstSpace), 10);
|
|
72
72
|
const children = item
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Subscribable, Unsubscribe } from "./Observable.js";
|
|
2
|
+
import { PartialObserver, ConnectableObserver } from "./Observer.js";
|
|
3
|
+
/** Abstract observer designed to pass values through to an observer. */
|
|
4
|
+
export declare abstract class AbstractObserver<I, O> implements ConnectableObserver<I> {
|
|
5
|
+
private _target;
|
|
6
|
+
private _cleanup;
|
|
7
|
+
get closed(): boolean;
|
|
8
|
+
get target(): PartialObserver<O>;
|
|
9
|
+
constructor(target: PartialObserver<O>);
|
|
10
|
+
connect(subscribable: Subscribable<I>): Unsubscribe;
|
|
11
|
+
disconnect(): void;
|
|
12
|
+
abstract next(value: I): void;
|
|
13
|
+
error(reason: Error | unknown): void;
|
|
14
|
+
complete(): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { dispatch } from "../util/function.js";
|
|
2
|
+
import { ConditionError } from "../error/ConditionError.js";
|
|
3
|
+
import { subscribe } from "./Observable.js";
|
|
4
|
+
import { dispatchError, dispatchComplete } from "./Observer.js";
|
|
5
|
+
/** Abstract observer designed to pass values through to an observer. */
|
|
6
|
+
export class AbstractObserver {
|
|
7
|
+
constructor(target) {
|
|
8
|
+
this._target = target;
|
|
9
|
+
}
|
|
10
|
+
get closed() {
|
|
11
|
+
return !this._target;
|
|
12
|
+
}
|
|
13
|
+
get target() {
|
|
14
|
+
if (!this._target)
|
|
15
|
+
throw new ConditionError("Observer is closed");
|
|
16
|
+
return this._target;
|
|
17
|
+
}
|
|
18
|
+
connect(subscribable) {
|
|
19
|
+
if (!this._target)
|
|
20
|
+
throw new ConditionError("Observer is closed");
|
|
21
|
+
if (this._cleanup)
|
|
22
|
+
throw new ConditionError("Observer already connected");
|
|
23
|
+
this._cleanup = subscribe(subscribable, this);
|
|
24
|
+
return this.disconnect.bind(this);
|
|
25
|
+
}
|
|
26
|
+
disconnect() {
|
|
27
|
+
if (this._cleanup)
|
|
28
|
+
this._cleanup = void dispatch(this._cleanup);
|
|
29
|
+
}
|
|
30
|
+
error(reason) {
|
|
31
|
+
const target = this.target;
|
|
32
|
+
this._target = undefined; // Close this observer.
|
|
33
|
+
this.disconnect();
|
|
34
|
+
dispatchError(target, reason);
|
|
35
|
+
}
|
|
36
|
+
complete() {
|
|
37
|
+
const target = this.target;
|
|
38
|
+
this._target = undefined; // Close this observer.
|
|
39
|
+
this.disconnect();
|
|
40
|
+
dispatchComplete(target);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AbstractObserver } from "./AbstractObserver.js";
|
|
2
|
+
import { dispatchAsyncNext } from "./Observer.js";
|
|
3
|
+
/** Observer that allows promised values to be passed to `next()`. */
|
|
4
|
+
export class AsyncObserver extends AbstractObserver {
|
|
5
|
+
next(value) {
|
|
6
|
+
dispatchAsyncNext(this.target, value);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Subject } from "./Subject.js";
|
|
2
2
|
/** Stream that only calls its most recently added subscriber. */
|
|
3
|
-
export declare class
|
|
3
|
+
export declare class LastSubject<T> extends Subject<T> {
|
|
4
4
|
protected _dispatch(value: T): void;
|
|
5
5
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getLastItem } from "../util/array.js";
|
|
2
|
+
import { dispatchNext } from "./Observer.js";
|
|
3
|
+
import { Subject } from "./Subject.js";
|
|
4
|
+
/** Stream that only calls its most recently added subscriber. */
|
|
5
|
+
export class LastSubject extends Subject {
|
|
6
|
+
// Override to dispatch only to a slice of the subscribers.
|
|
7
|
+
_dispatch(value) {
|
|
8
|
+
const observer = getLastItem(this._subscribers);
|
|
9
|
+
if (observer)
|
|
10
|
+
dispatchNext(observer, value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Matcher } from "../util/match.js";
|
|
2
|
+
import { MatchableObserver } from "./MatchableObserver.js";
|
|
3
|
+
import { PartialObserver } from "./Observer.js";
|
|
4
|
+
/** Observer that filters is next value with a matcher. */
|
|
5
|
+
export declare class MatchObserver<T> extends MatchableObserver<T> {
|
|
6
|
+
protected _matcher: Matcher<T, void>;
|
|
7
|
+
constructor(matcher: Matcher<T, void>, target: PartialObserver<T>);
|
|
8
|
+
match(value: T): boolean;
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { match } from "../util/match.js";
|
|
2
|
+
import { MatchableObserver } from "./MatchableObserver.js";
|
|
3
|
+
/** Observer that filters is next value with a matcher. */
|
|
4
|
+
export class MatchObserver extends MatchableObserver {
|
|
5
|
+
constructor(matcher, target) {
|
|
6
|
+
super(target);
|
|
7
|
+
this._matcher = matcher;
|
|
8
|
+
}
|
|
9
|
+
match(value) {
|
|
10
|
+
return match(value, this._matcher);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Matchable } from "../util/match.js";
|
|
2
|
+
import { AbstractObserver } from "./AbstractObserver.js";
|
|
3
|
+
/** Observer implementing `Matchable` that implements a `match()` property that is called filter the next value before dispatching it. */
|
|
4
|
+
export declare abstract class MatchableObserver<T> extends AbstractObserver<T, T> implements Matchable<T, void> {
|
|
5
|
+
next(value: T): void;
|
|
6
|
+
abstract match(value: T): boolean;
|
|
7
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AbstractObserver } from "./AbstractObserver.js";
|
|
2
|
+
import { dispatchNext } from "./Observer.js";
|
|
3
|
+
/** Observer implementing `Matchable` that implements a `match()` property that is called filter the next value before dispatching it. */
|
|
4
|
+
export class MatchableObserver extends AbstractObserver {
|
|
5
|
+
next(value) {
|
|
6
|
+
const target = this.target;
|
|
7
|
+
if (this.match(value))
|
|
8
|
+
dispatchNext(target, value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Dispatch } from "../util/function.js";
|
|
2
|
+
import type { PartialObserver } from "./Observer.js";
|
|
3
|
+
/** Function that ends a subscription. */
|
|
4
|
+
export declare type Unsubscribe = () => void;
|
|
5
|
+
/** An object that can subscribed to. */
|
|
6
|
+
export interface Observable<T> {
|
|
7
|
+
/** Subscribe an observer to this observable. */
|
|
8
|
+
subscribe(observer: PartialObserver<T> | Dispatch<[T]>): Unsubscribe;
|
|
9
|
+
}
|
|
10
|
+
/** Subscribe function is a function that initiates a subscription to an observer. */
|
|
11
|
+
export declare type Subscribe<T> = (observer: PartialObserver<T>) => Unsubscribe;
|
|
12
|
+
/** Subscribable is either an observable object or a subscribe function. */
|
|
13
|
+
export declare type Subscribable<T> = Observable<T> | Subscribe<T>;
|
|
14
|
+
/** Start a subscription to a `Subscribable` and return the `Unsubscriber` function. */
|
|
15
|
+
export declare function subscribe<T>(source: Subscribable<T>, target: PartialObserver<T>): Unsubscribe;
|
|
16
|
+
/** An object that can be connected to a subscribable. */
|
|
17
|
+
export interface Connectable<T> {
|
|
18
|
+
/** Subscribe this entity to a subscribable. */
|
|
19
|
+
connect(subscribable: Subscribable<T>): Unsubscribe;
|
|
20
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ConditionError } from "../error/ConditionError.js";
|
|
2
|
+
/** Start a subscription to a `Subscribable` and return the `Unsubscriber` function. */
|
|
3
|
+
export function subscribe(source, target) {
|
|
4
|
+
if (target.closed)
|
|
5
|
+
throw new ConditionError("Target is closed");
|
|
6
|
+
return typeof source === "function" ? source(target) : source.subscribe(target);
|
|
7
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Dispatch } from "../util/function.js";
|
|
2
|
+
import { Handler } from "../util/error.js";
|
|
3
|
+
import type { Connectable } from "./Observable.js";
|
|
4
|
+
/**
|
|
5
|
+
* Observer
|
|
6
|
+
* - An Observer is used to receive data from an Observable, and is supplied as an argument to subscribe.
|
|
7
|
+
* - All methods are optional.
|
|
8
|
+
* - Compatible with https://github.com/tc39/proposal-observable/
|
|
9
|
+
*/
|
|
10
|
+
export interface Observer<T> {
|
|
11
|
+
/** Send the next value to this object. */
|
|
12
|
+
readonly next: Dispatch<[T]>;
|
|
13
|
+
/** End this object with an error. */
|
|
14
|
+
readonly error: Handler;
|
|
15
|
+
/** End this object with success. */
|
|
16
|
+
readonly complete: Dispatch;
|
|
17
|
+
/** Is this object closed? */
|
|
18
|
+
readonly closed?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Partial observer is an observer missing one or more of its callbacks. */
|
|
21
|
+
export declare type PartialObserver<T> = Partial<Observer<T>>;
|
|
22
|
+
/** Connectable observer is an observer that can connect to a subscribable source. */
|
|
23
|
+
export declare type ConnectableObserver<T> = Observer<T> & Connectable<T>;
|
|
24
|
+
/** Dispatch the next value to an observer (and if the next value errors log the error). */
|
|
25
|
+
export declare function dispatchNext<T>(observer: PartialObserver<T>, value: T): void;
|
|
26
|
+
/** Dispatch the next value to an observer (and if the next value errors log the error). */
|
|
27
|
+
export declare function dispatchAsyncNext<T>(observer: PartialObserver<T>, value: PromiseLike<T>): void;
|
|
28
|
+
/** Dispatch a complete call an observer (and if the next value errors log the error). */
|
|
29
|
+
export declare function dispatchComplete<T>(observer: PartialObserver<T>): void;
|
|
30
|
+
/** Dispatch an error value to an observer. */
|
|
31
|
+
export declare function dispatchError<T>(observer: PartialObserver<T>, reason: Error | unknown): void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { logError } from "../util/error.js";
|
|
2
|
+
/** Dispatch the next value to an observer (and if the next value errors log the error). */
|
|
3
|
+
export function dispatchNext(observer, value) {
|
|
4
|
+
if (!observer.next)
|
|
5
|
+
return;
|
|
6
|
+
try {
|
|
7
|
+
observer.next(value);
|
|
8
|
+
}
|
|
9
|
+
catch (thrown) {
|
|
10
|
+
logError(thrown);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Dispatch the next value to an observer (and if the next value errors log the error). */
|
|
14
|
+
export function dispatchAsyncNext(observer, value) {
|
|
15
|
+
if (!observer.next)
|
|
16
|
+
return;
|
|
17
|
+
void _dispatchAsyncNext(observer, value);
|
|
18
|
+
}
|
|
19
|
+
async function _dispatchAsyncNext(observer, value) {
|
|
20
|
+
try {
|
|
21
|
+
dispatchNext(observer, await value);
|
|
22
|
+
}
|
|
23
|
+
catch (reason) {
|
|
24
|
+
dispatchError(observer, reason);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Dispatch a complete call an observer (and if the next value errors log the error). */
|
|
28
|
+
export function dispatchComplete(observer) {
|
|
29
|
+
if (!observer.complete)
|
|
30
|
+
return;
|
|
31
|
+
try {
|
|
32
|
+
observer.complete();
|
|
33
|
+
}
|
|
34
|
+
catch (thrown) {
|
|
35
|
+
logError(thrown);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Dispatch an error value to an observer. */
|
|
39
|
+
export function dispatchError(observer, reason) {
|
|
40
|
+
if (!observer.error)
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
observer.error(reason);
|
|
44
|
+
}
|
|
45
|
+
catch (thrown) {
|
|
46
|
+
logError(thrown);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Dispatch } from "../util/function.js";
|
|
2
|
+
import { ConnectableObserver, PartialObserver } from "./Observer.js";
|
|
3
|
+
import { Observable, Subscribable, Unsubscribe } from "./Observable.js";
|
|
4
|
+
/**
|
|
5
|
+
* Simple subject
|
|
6
|
+
* - Subject combines `Observer` and `Observable`.
|
|
7
|
+
* - Multiple observers can subscribe and values are multicase to all of them.
|
|
8
|
+
* - Does no deriving (input and output types are the same).
|
|
9
|
+
*/
|
|
10
|
+
export declare class Subject<T> implements Observable<T>, ConnectableObserver<T> {
|
|
11
|
+
/** List of sources this subject is subscribed to. */
|
|
12
|
+
protected readonly _cleanups: Set<Unsubscribe>;
|
|
13
|
+
/** List of subscribed observers that values are forwarded to. */
|
|
14
|
+
protected readonly _subscribers: Set<Partial<import("./Observer.js").Observer<T>>>;
|
|
15
|
+
/** Get the number of current subscribers. */
|
|
16
|
+
get connections(): number;
|
|
17
|
+
/** Get the number of current subscribers. */
|
|
18
|
+
get subscribers(): number;
|
|
19
|
+
/** Is this subject open or closed (i.e. `error()` or `complete()` have been called. */
|
|
20
|
+
readonly closed: boolean;
|
|
21
|
+
next(value: T): void;
|
|
22
|
+
/** Call `next()` on the subscribers. */
|
|
23
|
+
protected _dispatch(value: T): void;
|
|
24
|
+
error(reason: Error | unknown): void;
|
|
25
|
+
complete(): void;
|
|
26
|
+
/** Close this subject (called by `error()` and `complete()`). */
|
|
27
|
+
private _close;
|
|
28
|
+
/** Connect this subjet to a source. */
|
|
29
|
+
connect(source: Subscribable<T>): Unsubscribe;
|
|
30
|
+
/** Disconnect this subject from all sources. */
|
|
31
|
+
disconnect(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Subscribe to this subject and return an unsubscriber function.
|
|
34
|
+
* - Allows either an `Observer` object or separate `next()`, `error()` and `complete()` functions.
|
|
35
|
+
* - Implements `Observable`
|
|
36
|
+
*/
|
|
37
|
+
subscribe(next: PartialObserver<T> | Dispatch<[T]>): Unsubscribe;
|
|
38
|
+
/** Add an observer (called by `subscribe()`). */
|
|
39
|
+
protected _addObserver(observer: PartialObserver<T>): void;
|
|
40
|
+
/** Called after adding the first observer. */
|
|
41
|
+
protected _addFirstObserver(): void;
|
|
42
|
+
/** Remove an observer. */
|
|
43
|
+
protected _removeObserver(observer: PartialObserver<T>): void;
|
|
44
|
+
/** Called after adding the first observer. */
|
|
45
|
+
protected _removeLastObserver(): void;
|
|
46
|
+
}
|