shelving 1.68.2 → 1.68.5
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/feedback/Feedback.js +2 -2
- package/firestore/client/FirestoreClientProvider.d.ts +1 -1
- package/firestore/client/FirestoreClientProvider.js +13 -9
- package/firestore/lite/FirestoreLiteProvider.js +12 -8
- package/firestore/server/FirestoreServerProvider.d.ts +1 -1
- package/firestore/server/FirestoreServerProvider.js +7 -3
- package/markup/rules.js +18 -13
- package/observe/Observable.d.ts +4 -0
- package/observe/Observable.js +0 -3
- package/observe/Observer.d.ts +4 -4
- package/observe/Subject.d.ts +4 -4
- package/observe/Subject.js +23 -17
- package/package.json +1 -1
- package/provider/DebugProvider.js +29 -29
- package/provider/ThroughProvider.d.ts +4 -2
- package/provider/ThroughProvider.js +11 -3
- package/provider/ValidationProvider.js +2 -3
- package/react/useDocument.js +3 -3
- package/react/useQuery.js +3 -3
- package/react/useSubscribe.js +8 -1
- package/schema/AllowSchema.js +4 -4
- package/schema/ArraySchema.js +3 -3
- package/schema/DateSchema.js +4 -4
- package/schema/NumberSchema.js +2 -2
- package/schema/SlugSchema.js +2 -2
- package/schema/ThroughSchema.d.ts +4 -2
- package/schema/ThroughSchema.js +10 -4
- package/update/ArrayUpdate.d.ts +2 -1
- package/update/ArrayUpdate.js +22 -3
- package/update/DataUpdate.d.ts +3 -2
- package/update/DataUpdate.js +42 -2
- package/update/Delete.d.ts +11 -0
- package/update/Delete.js +15 -0
- package/update/Increment.d.ts +5 -5
- package/update/Increment.js +5 -5
- package/update/ObjectUpdate.d.ts +8 -8
- package/update/ObjectUpdate.js +38 -18
- package/update/Update.d.ts +4 -1
- package/update/Update.js +6 -0
- package/update/hydrations.js +3 -1
- package/update/index.d.ts +2 -2
- package/update/index.js +2 -2
- package/util/color.d.ts +6 -2
- package/util/color.js +17 -11
- package/util/constants.d.ts +0 -2
- package/util/constants.js +0 -2
- package/util/data.d.ts +6 -6
- package/util/data.js +3 -3
- package/util/date.d.ts +5 -5
- package/util/date.js +19 -19
- package/util/jsx.d.ts +1 -0
- package/util/number.d.ts +3 -3
- package/util/number.js +5 -5
- package/util/search.js +2 -2
- package/util/string.d.ts +4 -4
- package/util/string.js +7 -7
- package/util/transform.js +2 -2
- package/util/validate.d.ts +9 -0
- package/util/validate.js +13 -2
- package/update/util.d.ts +0 -7
- package/update/util.js +0 -44
package/feedback/Feedback.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { debug } from "../util/debug.js";
|
|
2
|
-
import {
|
|
2
|
+
import { getTitle } from "../util/string.js";
|
|
3
3
|
/**
|
|
4
4
|
* The `Feedback` class represents a feedback message that should be shown to the user.
|
|
5
5
|
* - Basic `Feedback` is neither good nor bad, `SuccessFeedback` indicates good news, and `ErrorFeedback` indicates bad news.
|
|
@@ -27,7 +27,7 @@ export class Feedback {
|
|
|
27
27
|
if (v instanceof Feedback)
|
|
28
28
|
messages[k] = v.feedback;
|
|
29
29
|
else
|
|
30
|
-
messages[k] =
|
|
30
|
+
messages[k] = getTitle(v);
|
|
31
31
|
}
|
|
32
32
|
return messages;
|
|
33
33
|
}
|
|
@@ -2,9 +2,9 @@ import type { Firestore } from "firebase/firestore";
|
|
|
2
2
|
import type { DocumentReference, QueryReference } from "../../db/Reference.js";
|
|
3
3
|
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
4
4
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
5
|
+
import { Observer } from "../../observe/Observer.js";
|
|
5
6
|
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
6
7
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
7
|
-
import { Observer } from "../../observe/Observer.js";
|
|
8
8
|
/**
|
|
9
9
|
* Firestore client database provider.
|
|
10
10
|
* - Works with the Firebase JS SDK.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { orderBy as firestoreOrderBy, where as firestoreWhere, limit as firestoreLimit, increment as firestoreIncrement, arrayUnion as firestoreArrayUnion, arrayRemove as firestoreArrayRemove, deleteField as firestoreDeleteField, collection as firestoreCollection, doc as firestoreDocument, query as firestoreQuery, onSnapshot, addDoc, setDoc, updateDoc, deleteDoc, getDoc, getDocs, } from "firebase/firestore";
|
|
2
|
+
import { dispatchError, dispatchNext } from "../../observe/Observer.js";
|
|
2
3
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
4
|
import { Provider } from "../../provider/Provider.js";
|
|
4
5
|
import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
5
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
7
|
import { Increment } from "../../update/Increment.js";
|
|
7
8
|
import { ObjectUpdate } from "../../update/ObjectUpdate.js";
|
|
8
|
-
import {
|
|
9
|
+
import { Delete } from "../../update/Delete.js";
|
|
10
|
+
import { Update } from "../../update/Update.js";
|
|
9
11
|
// Constants.
|
|
10
12
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
11
13
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -36,15 +38,15 @@ function getCollection(firestore, { collection }) {
|
|
|
36
38
|
}
|
|
37
39
|
/** Create a corresponding `QueryReference` from a Query. */
|
|
38
40
|
function getQuery(firestore, ref) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
return firestoreQuery(getCollection(firestore, ref), ...yieldQueryConstraints(ref));
|
|
42
|
+
}
|
|
43
|
+
function* yieldQueryConstraints({ sorts, filters, limit }) {
|
|
41
44
|
for (const { key, direction } of sorts)
|
|
42
|
-
|
|
45
|
+
yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
|
|
43
46
|
for (const { operator, key, value } of filters)
|
|
44
|
-
|
|
47
|
+
yield firestoreWhere(key === "id" ? ID : key, OPERATORS[operator], value);
|
|
45
48
|
if (typeof limit === "number")
|
|
46
|
-
|
|
47
|
-
return firestoreQuery(getCollection(firestore, ref), ...constraints);
|
|
49
|
+
yield firestoreLimit(limit);
|
|
48
50
|
}
|
|
49
51
|
function getEntities(snapshot) {
|
|
50
52
|
return snapshot.docs.map(getEntity);
|
|
@@ -60,7 +62,9 @@ function getOptionalEntity(snapshot) {
|
|
|
60
62
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
61
63
|
function* yieldFieldValues(updates, prefix = "") {
|
|
62
64
|
for (const [key, update] of updates) {
|
|
63
|
-
if (update
|
|
65
|
+
if (!(update instanceof Update))
|
|
66
|
+
yield [`${prefix}${key}`, update];
|
|
67
|
+
else if (update instanceof Delete)
|
|
64
68
|
yield [`${prefix}${key}`, firestoreDeleteField()];
|
|
65
69
|
else if (update instanceof Increment)
|
|
66
70
|
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
@@ -75,7 +79,7 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
75
79
|
yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
|
|
76
80
|
}
|
|
77
81
|
else
|
|
78
|
-
yield [`${prefix}${key}`, update];
|
|
82
|
+
yield [`${prefix}${key}`, update.transform()];
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
/**
|
|
@@ -5,6 +5,8 @@ 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 { Update } from "../../update/Update.js";
|
|
9
|
+
import { Delete } from "../../update/Delete.js";
|
|
8
10
|
// Constants.
|
|
9
11
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
10
12
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -35,15 +37,15 @@ function getCollection(firestore, { collection }) {
|
|
|
35
37
|
}
|
|
36
38
|
/** Create a corresponding `QueryReference` from a Query. */
|
|
37
39
|
function getQuery(firestore, ref) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
return firestoreQuery(getCollection(firestore, ref), ...yieldQueryConstraints(ref));
|
|
41
|
+
}
|
|
42
|
+
function* yieldQueryConstraints({ sorts, filters, limit }) {
|
|
40
43
|
for (const { key, direction } of sorts)
|
|
41
|
-
|
|
44
|
+
yield firestoreOrderBy(key === "id" ? ID : key, DIRECTIONS[direction]);
|
|
42
45
|
for (const { operator, key, value } of filters)
|
|
43
|
-
|
|
46
|
+
yield firestoreWhere(key === "id" ? ID : key, OPERATORS[operator], value);
|
|
44
47
|
if (typeof limit === "number")
|
|
45
|
-
|
|
46
|
-
return firestoreQuery(getCollection(firestore, ref), ...constraints);
|
|
48
|
+
yield firestoreLimit(limit);
|
|
47
49
|
}
|
|
48
50
|
function getEntities(snapshot) {
|
|
49
51
|
return snapshot.docs.map(getEntity);
|
|
@@ -59,7 +61,9 @@ function getOptionalData(snapshot) {
|
|
|
59
61
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
60
62
|
function* yieldFieldValues(updates, prefix = "") {
|
|
61
63
|
for (const [key, update] of updates) {
|
|
62
|
-
if (update
|
|
64
|
+
if (!(update instanceof Update))
|
|
65
|
+
yield [`${prefix}${key}`, update];
|
|
66
|
+
else if (update instanceof Delete)
|
|
63
67
|
yield [`${prefix}${key}`, firestoreDeleteField()];
|
|
64
68
|
else if (update instanceof Increment)
|
|
65
69
|
yield [`${prefix}${key}`, firestoreIncrement(update.amount)];
|
|
@@ -74,7 +78,7 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
74
78
|
yield [`${prefix}${key}`, firestoreArrayRemove(...update.deletes)];
|
|
75
79
|
}
|
|
76
80
|
else
|
|
77
|
-
yield [`${prefix}${key}`, update];
|
|
81
|
+
yield [`${prefix}${key}`, update.transform()];
|
|
78
82
|
}
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
@@ -2,9 +2,9 @@ import { Firestore } from "@google-cloud/firestore";
|
|
|
2
2
|
import type { DocumentReference, QueryReference } from "../../db/Reference.js";
|
|
3
3
|
import type { Data, Entities, OptionalEntity } from "../../util/data.js";
|
|
4
4
|
import type { Unsubscribe } from "../../observe/Observable.js";
|
|
5
|
+
import { Observer } from "../../observe/Observer.js";
|
|
5
6
|
import { AsynchronousProvider, Provider } from "../../provider/Provider.js";
|
|
6
7
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
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
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Firestore, FieldValue } from "@google-cloud/firestore";
|
|
2
|
+
import { dispatchError, dispatchNext } from "../../observe/Observer.js";
|
|
2
3
|
import { UnsupportedError } from "../../error/UnsupportedError.js";
|
|
3
4
|
import { Provider } from "../../provider/Provider.js";
|
|
4
5
|
import { ArrayUpdate } from "../../update/ArrayUpdate.js";
|
|
5
6
|
import { DataUpdate } from "../../update/DataUpdate.js";
|
|
6
7
|
import { Increment } from "../../update/Increment.js";
|
|
7
8
|
import { ObjectUpdate } from "../../update/ObjectUpdate.js";
|
|
8
|
-
import {
|
|
9
|
+
import { Delete } from "../../update/Delete.js";
|
|
10
|
+
import { Update } from "../../update/Update.js";
|
|
9
11
|
// Constants.
|
|
10
12
|
// const ID = "__name__"; // DH: `__name__` is the entire path of the document. `__id__` is just ID.
|
|
11
13
|
const ID = "__id__"; // Internal way Firestore Queries can reference the ID of the current document.
|
|
@@ -60,7 +62,9 @@ function getOptionalEntity(snapshot) {
|
|
|
60
62
|
/** Convert `Update` instances into corresponding Firestore `FieldValue` instances. */
|
|
61
63
|
function* yieldFieldValues(updates, prefix = "") {
|
|
62
64
|
for (const [key, update] of updates) {
|
|
63
|
-
if (update
|
|
65
|
+
if (!(update instanceof Update))
|
|
66
|
+
yield [`${prefix}${key}`, update];
|
|
67
|
+
else if (update instanceof Delete)
|
|
64
68
|
yield [`${prefix}${key}`, FieldValue.delete()];
|
|
65
69
|
else if (update instanceof Increment)
|
|
66
70
|
yield [`${prefix}${key}`, FieldValue.increment(update.amount)];
|
|
@@ -75,7 +79,7 @@ function* yieldFieldValues(updates, prefix = "") {
|
|
|
75
79
|
yield [`${prefix}${key}`, FieldValue.arrayRemove(...update.deletes)];
|
|
76
80
|
}
|
|
77
81
|
else
|
|
78
|
-
yield [`${prefix}${key}`, update];
|
|
82
|
+
yield [`${prefix}${key}`, update.transform()];
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
/**
|
package/markup/rules.js
CHANGED
|
@@ -12,7 +12,7 @@ const MATCH_INDENT = /^ {1,2}/gm;
|
|
|
12
12
|
*/
|
|
13
13
|
export const HEADING_RULE = {
|
|
14
14
|
regexp: getLineRegExp(`(#{1,6}) +(${MATCH_LINE.source})`),
|
|
15
|
-
render: ([, prefix = "", children = ""]) => ({ type: `h${prefix.length}`, key: null, props: { children } }),
|
|
15
|
+
render: ([, prefix = "", children = ""]) => ({ type: `h${prefix.length}`, key: null, ref: null, props: { children } }),
|
|
16
16
|
contexts: ["block"],
|
|
17
17
|
childContext: "inline",
|
|
18
18
|
};
|
|
@@ -25,7 +25,7 @@ export const HEADING_RULE = {
|
|
|
25
25
|
*/
|
|
26
26
|
export const HORIZONTAL_RULE = {
|
|
27
27
|
regexp: getLineRegExp(`([${BULLETS}])(?: *\\1){2,}`),
|
|
28
|
-
render: () => ({ type: "hr", key: null, props: {} }),
|
|
28
|
+
render: () => ({ type: "hr", key: null, ref: null, props: {} }),
|
|
29
29
|
contexts: ["block"],
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
@@ -40,7 +40,7 @@ export const UNORDERED_LIST_RULE = {
|
|
|
40
40
|
regexp: getBlockRegExp(`${UNORDERED}(${MATCH_BLOCK.source})`),
|
|
41
41
|
render: ([, list = ""]) => {
|
|
42
42
|
const children = list.split(SPLIT_UL_ITEMS).map(_mapUnorderedItem);
|
|
43
|
-
return { type: "ul", key: null, props: { children } };
|
|
43
|
+
return { type: "ul", key: null, ref: null, props: { children } };
|
|
44
44
|
},
|
|
45
45
|
contexts: ["block", "list"],
|
|
46
46
|
childContext: "list",
|
|
@@ -48,7 +48,7 @@ export const UNORDERED_LIST_RULE = {
|
|
|
48
48
|
const SPLIT_UL_ITEMS = new RegExp(`\\n+${UNORDERED}`, "g");
|
|
49
49
|
const _mapUnorderedItem = (item, key) => {
|
|
50
50
|
const children = item.replace(MATCH_INDENT, "");
|
|
51
|
-
return { type: "li", key, props: { children } };
|
|
51
|
+
return { type: "li", key, ref: null, props: { children } };
|
|
52
52
|
};
|
|
53
53
|
/**
|
|
54
54
|
* Ordered list.
|
|
@@ -60,7 +60,7 @@ export const ORDERED_LIST_RULE = {
|
|
|
60
60
|
regexp: getBlockRegExp(`(${ORDERED}${MATCH_BLOCK.source})`),
|
|
61
61
|
render: ([, list = ""]) => {
|
|
62
62
|
const children = list.split(SPLIT_OL_ITEMS).map(_mapOrderedItem);
|
|
63
|
-
return { type: "ol", key: null, props: { children } };
|
|
63
|
+
return { type: "ol", key: null, ref: null, props: { children } };
|
|
64
64
|
},
|
|
65
65
|
contexts: ["block", "list"],
|
|
66
66
|
childContext: "list",
|
|
@@ -73,7 +73,7 @@ const _mapOrderedItem = (item, key) => {
|
|
|
73
73
|
.slice(firstSpace + 1)
|
|
74
74
|
.trimStart()
|
|
75
75
|
.replace(MATCH_INDENT, "");
|
|
76
|
-
return { type: "li", key, props: { value, children } };
|
|
76
|
+
return { type: "li", key, ref: null, props: { value, children } };
|
|
77
77
|
};
|
|
78
78
|
/**
|
|
79
79
|
* Blockquote block.
|
|
@@ -86,6 +86,7 @@ export const BLOCKQUOTE_RULE = {
|
|
|
86
86
|
render: ([, quote = ""]) => ({
|
|
87
87
|
type: "blockquote",
|
|
88
88
|
key: null,
|
|
89
|
+
ref: null,
|
|
89
90
|
props: { children: quote.replace(BLOCKQUOTE_LINES, "") },
|
|
90
91
|
}),
|
|
91
92
|
contexts: ["block", "list"],
|
|
@@ -105,10 +106,12 @@ export const FENCED_CODE_RULE = {
|
|
|
105
106
|
render: ([, , file, children]) => ({
|
|
106
107
|
type: "pre",
|
|
107
108
|
key: null,
|
|
109
|
+
ref: null,
|
|
108
110
|
props: {
|
|
109
111
|
children: {
|
|
110
112
|
type: "code",
|
|
111
113
|
key: null,
|
|
114
|
+
ref: null,
|
|
112
115
|
props: { "data-file": file || undefined, children },
|
|
113
116
|
},
|
|
114
117
|
},
|
|
@@ -121,7 +124,7 @@ export const FENCED_CODE_RULE = {
|
|
|
121
124
|
*/
|
|
122
125
|
export const PARAGRAPH_RULE = {
|
|
123
126
|
regexp: getBlockRegExp(` *(${MATCH_BLOCK.source})`),
|
|
124
|
-
render: ([, children]) => ({ type: `p`, key: null, props: { children } }),
|
|
127
|
+
render: ([, children]) => ({ type: `p`, key: null, ref: null, props: { children } }),
|
|
125
128
|
contexts: ["block"],
|
|
126
129
|
childContext: "inline",
|
|
127
130
|
priority: -10, // Lower precedence than other blocks so it matches last and paragraphs can be broken by other blocks.
|
|
@@ -152,6 +155,7 @@ export const LINK_RULE = {
|
|
|
152
155
|
render: ([, title, href = ""], { rel }) => ({
|
|
153
156
|
type: "a",
|
|
154
157
|
key: null,
|
|
158
|
+
ref: null,
|
|
155
159
|
props: { children: title || formatUrl(href), href, rel },
|
|
156
160
|
}),
|
|
157
161
|
contexts: ["inline", "list"],
|
|
@@ -182,6 +186,7 @@ export const AUTOLINK_RULE = {
|
|
|
182
186
|
render: ([, href = "", title], { rel }) => ({
|
|
183
187
|
type: "a",
|
|
184
188
|
key: null,
|
|
189
|
+
ref: null,
|
|
185
190
|
props: { children: title || formatUrl(href), href, rel },
|
|
186
191
|
}),
|
|
187
192
|
contexts: ["inline", "list"],
|
|
@@ -196,7 +201,7 @@ export const AUTOLINK_RULE = {
|
|
|
196
201
|
*/
|
|
197
202
|
export const CODE_RULE = {
|
|
198
203
|
regexp: getWrapRegExp("`+", MATCH_BLOCK.source),
|
|
199
|
-
render: ([, , children]) => ({ type: "code", key: null, props: { children } }),
|
|
204
|
+
render: ([, , children]) => ({ type: "code", key: null, ref: null, props: { children } }),
|
|
200
205
|
contexts: ["inline", "list"],
|
|
201
206
|
priority: 10, // Higher priority than other inlines so it matches first before e.g. `strong` or `em` (from CommonMark spec: "Code span backticks have higher precedence than any other inline constructs except HTML tags and autolinks.")
|
|
202
207
|
};
|
|
@@ -210,7 +215,7 @@ export const CODE_RULE = {
|
|
|
210
215
|
*/
|
|
211
216
|
export const STRONG_RULE = {
|
|
212
217
|
regexp: getWrapRegExp("\\*+"),
|
|
213
|
-
render: ([, , children]) => ({ type: "strong", key: null, props: { children } }),
|
|
218
|
+
render: ([, , children]) => ({ type: "strong", key: null, ref: null, props: { children } }),
|
|
214
219
|
contexts: ["inline", "list", "link"],
|
|
215
220
|
childContext: "inline",
|
|
216
221
|
};
|
|
@@ -224,7 +229,7 @@ export const STRONG_RULE = {
|
|
|
224
229
|
*/
|
|
225
230
|
export const EMPHASIS_RULE = {
|
|
226
231
|
regexp: getWrapRegExp("_+"),
|
|
227
|
-
render: ([, , children]) => ({ type: "em", key: null, props: { children } }),
|
|
232
|
+
render: ([, , children]) => ({ type: "em", key: null, ref: null, props: { children } }),
|
|
228
233
|
contexts: ["inline", "list", "link"],
|
|
229
234
|
childContext: "inline",
|
|
230
235
|
};
|
|
@@ -238,7 +243,7 @@ export const EMPHASIS_RULE = {
|
|
|
238
243
|
*/
|
|
239
244
|
export const INSERT_RULE = {
|
|
240
245
|
regexp: getWrapRegExp("\\+\\++"),
|
|
241
|
-
render: ([, , children]) => ({ type: "ins", key: null, props: { children } }),
|
|
246
|
+
render: ([, , children]) => ({ type: "ins", key: null, ref: null, props: { children } }),
|
|
242
247
|
contexts: ["inline", "list", "link"],
|
|
243
248
|
childContext: "inline",
|
|
244
249
|
};
|
|
@@ -252,7 +257,7 @@ export const INSERT_RULE = {
|
|
|
252
257
|
*/
|
|
253
258
|
export const DELETE_RULE = {
|
|
254
259
|
regexp: getWrapRegExp("--+|~~+"),
|
|
255
|
-
render: ([, , children]) => ({ type: "del", key: null, props: { children } }),
|
|
260
|
+
render: ([, , children]) => ({ type: "del", key: null, ref: null, props: { children } }),
|
|
256
261
|
contexts: ["inline", "list", "link"],
|
|
257
262
|
childContext: "inline",
|
|
258
263
|
};
|
|
@@ -266,7 +271,7 @@ export const DELETE_RULE = {
|
|
|
266
271
|
*/
|
|
267
272
|
export const LINEBREAK_RULE = {
|
|
268
273
|
regexp: /\n/,
|
|
269
|
-
render: () => ({ type: "br", key: null, props: {} }),
|
|
274
|
+
render: () => ({ type: "br", key: null, ref: null, props: {} }),
|
|
270
275
|
contexts: ["inline", "list", "link"],
|
|
271
276
|
childContext: "inline",
|
|
272
277
|
};
|
package/observe/Observable.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare type Unsubscribe = () => void;
|
|
|
6
6
|
export interface Observable<T> {
|
|
7
7
|
/** Subscribe an observer to this observable. */
|
|
8
8
|
subscribe(observer: PartialObserver<T> | Dispatch<[T]>): Unsubscribe;
|
|
9
|
+
/** Is this observable closed? */
|
|
10
|
+
readonly closed?: boolean;
|
|
9
11
|
}
|
|
10
12
|
/** Subscribe function is a function that initiates a subscription to an observer. */
|
|
11
13
|
export declare type Subscribe<T> = (observer: PartialObserver<T>) => Unsubscribe;
|
|
@@ -17,4 +19,6 @@ export declare function subscribe<T>(source: Subscribable<T>, target: PartialObs
|
|
|
17
19
|
export interface Connectable<T> {
|
|
18
20
|
/** Subscribe this entity to a subscribable. */
|
|
19
21
|
connect(subscribable: Subscribable<T>): Unsubscribe;
|
|
22
|
+
/** Is this observable closed? */
|
|
23
|
+
readonly closed?: boolean;
|
|
20
24
|
}
|
package/observe/Observable.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { ConditionError } from "../error/ConditionError.js";
|
|
2
1
|
/** Start a subscription to a `Subscribable` and return the `Unsubscriber` function. */
|
|
3
2
|
export function subscribe(source, target) {
|
|
4
|
-
if (target.closed)
|
|
5
|
-
throw new ConditionError("Target is closed");
|
|
6
3
|
return typeof source === "function" ? source(target) : source.subscribe(target);
|
|
7
4
|
}
|
package/observe/Observer.d.ts
CHANGED
|
@@ -8,13 +8,13 @@ import type { Connectable } from "./Observable.js";
|
|
|
8
8
|
* - Compatible with https://github.com/tc39/proposal-observable/
|
|
9
9
|
*/
|
|
10
10
|
export interface Observer<T> {
|
|
11
|
-
/** Send the next value to this
|
|
11
|
+
/** Send the next value to this observer. */
|
|
12
12
|
readonly next: Dispatch<[T]>;
|
|
13
|
-
/** End this
|
|
13
|
+
/** End this observer with an error. */
|
|
14
14
|
readonly error: Handler;
|
|
15
|
-
/** End this
|
|
15
|
+
/** End this observer with success. */
|
|
16
16
|
readonly complete: Dispatch;
|
|
17
|
-
/** Is this
|
|
17
|
+
/** Is this observer closed? */
|
|
18
18
|
readonly closed?: boolean;
|
|
19
19
|
}
|
|
20
20
|
/** Partial observer is an observer missing one or more of its callbacks. */
|
package/observe/Subject.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Observable, Subscribable, Unsubscribe } from "./Observable.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export declare class Subject<T> implements Observable<T>, ConnectableObserver<T> {
|
|
11
11
|
/** List of sources this subject is subscribed to. */
|
|
12
|
-
protected readonly
|
|
12
|
+
protected readonly _connections: Set<Unsubscribe>;
|
|
13
13
|
/** List of subscribed observers that values are forwarded to. */
|
|
14
14
|
protected readonly _subscribers: Set<Partial<import("./Observer.js").Observer<T>>>;
|
|
15
15
|
/** Get the number of current subscribers. */
|
|
@@ -25,16 +25,16 @@ export declare class Subject<T> implements Observable<T>, ConnectableObserver<T>
|
|
|
25
25
|
complete(): void;
|
|
26
26
|
/** Close this subject (called by `error()` and `complete()`). */
|
|
27
27
|
private _close;
|
|
28
|
-
/** Connect this
|
|
28
|
+
/** Connect this subject to a source. */
|
|
29
29
|
connect(source: Subscribable<T>): Unsubscribe;
|
|
30
30
|
/** Disconnect this subject from all sources. */
|
|
31
31
|
disconnect(): void;
|
|
32
32
|
/**
|
|
33
33
|
* Subscribe to this subject and return an unsubscriber function.
|
|
34
|
-
* - Allows either an `Observer` object or separate `next()
|
|
34
|
+
* - Allows either an `Observer` object or separate `next()", `error()` and `complete()` functions.
|
|
35
35
|
* - Implements `Observable`
|
|
36
36
|
*/
|
|
37
|
-
subscribe(
|
|
37
|
+
subscribe(target: PartialObserver<T> | Dispatch<[T]>): Unsubscribe;
|
|
38
38
|
/** Add an observer (called by `subscribe()`). */
|
|
39
39
|
protected _addObserver(observer: PartialObserver<T>): void;
|
|
40
40
|
/** Called after adding the first observer. */
|
package/observe/Subject.js
CHANGED
|
@@ -11,7 +11,7 @@ import { subscribe } from "./Observable.js";
|
|
|
11
11
|
export class Subject {
|
|
12
12
|
constructor() {
|
|
13
13
|
/** List of sources this subject is subscribed to. */
|
|
14
|
-
this.
|
|
14
|
+
this._connections = new Set();
|
|
15
15
|
/** List of subscribed observers that values are forwarded to. */
|
|
16
16
|
this._subscribers = new Set();
|
|
17
17
|
/** Is this subject open or closed (i.e. `error()` or `complete()` have been called. */
|
|
@@ -19,7 +19,7 @@ export class Subject {
|
|
|
19
19
|
}
|
|
20
20
|
/** Get the number of current subscribers. */
|
|
21
21
|
get connections() {
|
|
22
|
-
return this.
|
|
22
|
+
return this._connections.size;
|
|
23
23
|
}
|
|
24
24
|
/** Get the number of current subscribers. */
|
|
25
25
|
get subscribers() {
|
|
@@ -27,7 +27,7 @@ export class Subject {
|
|
|
27
27
|
}
|
|
28
28
|
next(value) {
|
|
29
29
|
if (this.closed)
|
|
30
|
-
throw new ConditionError(
|
|
30
|
+
throw new ConditionError(`Observer is closed`);
|
|
31
31
|
this._dispatch(value);
|
|
32
32
|
}
|
|
33
33
|
/** Call `next()` on the subscribers. */
|
|
@@ -37,7 +37,7 @@ export class Subject {
|
|
|
37
37
|
}
|
|
38
38
|
error(reason) {
|
|
39
39
|
if (this.closed)
|
|
40
|
-
throw new ConditionError(
|
|
40
|
+
throw new ConditionError(`Observer is closed`);
|
|
41
41
|
this._close();
|
|
42
42
|
for (const subscriber of this._subscribers) {
|
|
43
43
|
this._subscribers.delete(subscriber);
|
|
@@ -46,7 +46,7 @@ export class Subject {
|
|
|
46
46
|
}
|
|
47
47
|
complete() {
|
|
48
48
|
if (this.closed)
|
|
49
|
-
throw new ConditionError(
|
|
49
|
+
throw new ConditionError(`Observer is closed`);
|
|
50
50
|
this._close();
|
|
51
51
|
for (const subscriber of this._subscribers) {
|
|
52
52
|
this._subscribers.delete(subscriber);
|
|
@@ -58,38 +58,43 @@ export class Subject {
|
|
|
58
58
|
this.closed = true;
|
|
59
59
|
this.disconnect();
|
|
60
60
|
}
|
|
61
|
-
/** Connect this
|
|
61
|
+
/** Connect this subject to a source. */
|
|
62
62
|
connect(source) {
|
|
63
63
|
if (this.closed)
|
|
64
|
-
throw new ConditionError(
|
|
64
|
+
throw new ConditionError(`Connectable is closed`);
|
|
65
65
|
const unsubscribe = subscribe(source, this);
|
|
66
66
|
const cleanup = () => {
|
|
67
|
-
this.
|
|
67
|
+
this._connections.delete(cleanup);
|
|
68
68
|
dispatch(unsubscribe);
|
|
69
69
|
};
|
|
70
|
-
this.
|
|
70
|
+
this._connections.add(cleanup);
|
|
71
71
|
return cleanup;
|
|
72
72
|
}
|
|
73
73
|
/** Disconnect this subject from all sources. */
|
|
74
74
|
disconnect() {
|
|
75
|
-
for (const cleanup of this.
|
|
75
|
+
for (const cleanup of this._connections)
|
|
76
76
|
dispatch(cleanup); // Cleanups are self-cleaning.
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
79
79
|
* Subscribe to this subject and return an unsubscriber function.
|
|
80
|
-
* - Allows either an `Observer` object or separate `next()
|
|
80
|
+
* - Allows either an `Observer` object or separate `next()", `error()` and `complete()` functions.
|
|
81
81
|
* - Implements `Observable`
|
|
82
82
|
*/
|
|
83
|
-
subscribe(
|
|
84
|
-
|
|
83
|
+
subscribe(target) {
|
|
84
|
+
if (this.closed)
|
|
85
|
+
throw new ConditionError(`Observable is closed`);
|
|
86
|
+
const observer = typeof target === `function` ? { next: target } : target;
|
|
87
|
+
if (observer.closed)
|
|
88
|
+
throw new ConditionError("Target is closed");
|
|
85
89
|
this._addObserver(observer);
|
|
86
90
|
return this._removeObserver.bind(this, observer);
|
|
87
91
|
}
|
|
88
92
|
/** Add an observer (called by `subscribe()`). */
|
|
89
93
|
_addObserver(observer) {
|
|
90
|
-
const
|
|
94
|
+
const sizeBefore = this._subscribers.size;
|
|
91
95
|
this._subscribers.add(observer);
|
|
92
|
-
|
|
96
|
+
const sizeAfter = this._subscribers.size;
|
|
97
|
+
if (!sizeBefore && sizeAfter)
|
|
93
98
|
this._addFirstObserver();
|
|
94
99
|
}
|
|
95
100
|
/** Called after adding the first observer. */
|
|
@@ -98,9 +103,10 @@ export class Subject {
|
|
|
98
103
|
}
|
|
99
104
|
/** Remove an observer. */
|
|
100
105
|
_removeObserver(observer) {
|
|
101
|
-
const
|
|
106
|
+
const sizeBefore = this._subscribers.size;
|
|
102
107
|
this._subscribers.delete(observer);
|
|
103
|
-
|
|
108
|
+
const sizeAfter = this._subscribers.size;
|
|
109
|
+
if (sizeBefore && !sizeAfter)
|
|
104
110
|
this._removeLastObserver();
|
|
105
111
|
}
|
|
106
112
|
/** Called after adding the first observer. */
|