atom.io 0.38.2 → 0.39.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/dist/data/index.js.map +1 -1
- package/dist/eslint-plugin/index.js +2 -1
- package/dist/eslint-plugin/index.js.map +1 -1
- package/dist/internal/index.d.ts +128 -85
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +429 -286
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.d.ts.map +1 -1
- package/dist/introspection/index.js.map +1 -1
- package/dist/json/index.d.ts.map +1 -1
- package/dist/json/index.js.map +1 -1
- package/dist/main/index.d.ts +45 -35
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js.map +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +43 -2
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.d.ts.map +1 -1
- package/dist/react-devtools/index.js +4 -5
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.js +5 -5
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-react/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/dist/realtime-server/index.js +4 -4
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.d.ts.map +1 -1
- package/dist/realtime-testing/index.js.map +1 -1
- package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
- package/dist/transceivers/set-rtx/index.js.map +1 -1
- package/dist/web/index.js.map +1 -1
- package/package.json +10 -11
- package/src/internal/atom/create-regular-atom.ts +2 -6
- package/src/internal/caching.ts +2 -4
- package/src/internal/{ingest-updates → events}/ingest-atom-update.ts +4 -5
- package/src/internal/{ingest-updates → events}/ingest-creation-disposal.ts +37 -37
- package/src/internal/{ingest-updates → events}/ingest-selector-update.ts +5 -5
- package/src/internal/events/ingest-transaction-update.ts +45 -0
- package/src/internal/families/create-readonly-held-selector-family.ts +1 -1
- package/src/internal/families/create-readonly-pure-selector-family.ts +1 -1
- package/src/internal/families/create-regular-atom-family.ts +4 -3
- package/src/internal/families/create-writable-held-selector-family.ts +1 -1
- package/src/internal/families/create-writable-pure-selector-family.ts +1 -1
- package/src/internal/families/find-in-store.ts +2 -2
- package/src/internal/families/get-family-of-token.ts +1 -0
- package/src/internal/families/index.ts +0 -1
- package/src/internal/families/mint-in-store.ts +30 -64
- package/src/internal/get-state/get-from-store.ts +2 -3
- package/src/internal/get-state/read-or-compute-value.ts +6 -15
- package/src/internal/get-state/reduce-reference.ts +52 -11
- package/src/internal/index.ts +2 -2
- package/src/internal/is-fn.ts +9 -0
- package/src/internal/junction.ts +177 -133
- package/src/internal/mutable/create-mutable-atom-family.ts +1 -1
- package/src/internal/overlays/index.ts +3 -0
- package/src/internal/overlays/map-overlay.ts +86 -0
- package/src/internal/{lazy-map.ts → overlays/relations-overlay.ts} +6 -6
- package/src/internal/overlays/set-overlay.ts +55 -0
- package/src/internal/selector/create-readonly-held-selector.ts +8 -11
- package/src/internal/selector/create-readonly-pure-selector.ts +8 -10
- package/src/internal/selector/create-writable-held-selector.ts +6 -6
- package/src/internal/selector/create-writable-pure-selector.ts +2 -2
- package/src/internal/selector/register-selector.ts +3 -4
- package/src/internal/set-state/become.ts +11 -6
- package/src/internal/set-state/dispatch-state-update.ts +47 -12
- package/src/internal/set-state/operate-on-store.ts +10 -8
- package/src/internal/set-state/reset-atom-or-selector.ts +7 -7
- package/src/internal/set-state/set-atom-or-selector.ts +3 -2
- package/src/internal/set-state/set-atom.ts +5 -4
- package/src/internal/set-state/set-selector.ts +9 -8
- package/src/internal/store/withdraw.ts +4 -4
- package/src/internal/timeline/time-travel.ts +11 -11
- package/src/internal/transaction/apply-transaction.ts +5 -5
- package/src/internal/transaction/build-transaction.ts +17 -26
- package/src/internal/transaction/create-transaction.ts +1 -1
- package/src/internal/transaction/is-root-store.ts +2 -2
- package/src/main/events.ts +14 -3
- package/src/main/logger.ts +43 -32
- package/src/react-devtools/json-editor/editors-by-type/array-editor.tsx +1 -1
- package/src/react-devtools/json-editor/editors-by-type/object-editor.tsx +2 -3
- package/src/react-devtools/json-editor/editors-by-type/utilities/array-elements.ts +1 -1
- package/src/react-devtools/json-editor/editors-by-type/utilities/object-properties.ts +1 -1
- package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +5 -5
- package/src/realtime-server/continuity/subscribe-to-continuity-perpectives.ts +4 -4
- package/dist/use-o-DXPncKmZ.js +0 -47
- package/dist/use-o-DXPncKmZ.js.map +0 -1
- package/src/internal/families/init-family-member.ts +0 -33
- package/src/internal/ingest-updates/ingest-transaction-update.ts +0 -47
- /package/src/internal/{ingest-updates → events}/index.ts +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Fn } from "./utility-types"
|
|
2
|
+
|
|
3
|
+
const NON_CTOR_FN_REGEX =
|
|
4
|
+
/^\[object (?:Async|Generator|AsyncGenerator)?Function\]$/
|
|
5
|
+
|
|
6
|
+
export function isFn(input: unknown): input is Fn {
|
|
7
|
+
const protoString = Object.prototype.toString.call(input)
|
|
8
|
+
return NON_CTOR_FN_REGEX.test(protoString)
|
|
9
|
+
}
|
package/src/internal/junction.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import type { Json } from "atom.io/json"
|
|
2
2
|
|
|
3
|
+
import { MapOverlay, RelationsOverlay, SetOverlay } from "./overlays"
|
|
3
4
|
import type { Refinement } from "./utility-types"
|
|
4
5
|
|
|
5
6
|
export type JunctionEntriesBase<
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
A extends string,
|
|
8
|
+
B extends string,
|
|
8
9
|
Content extends Json.Object | null,
|
|
9
10
|
> = {
|
|
10
|
-
readonly relations: ([
|
|
11
|
+
readonly relations: ([A, B[]] | [B, A[]])[]
|
|
11
12
|
readonly contents: [string, Content][]
|
|
12
13
|
}
|
|
13
14
|
export interface JunctionEntries<
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
A extends string,
|
|
16
|
+
B extends string,
|
|
16
17
|
Content extends Json.Object | null,
|
|
17
18
|
> extends Json.Object,
|
|
18
|
-
JunctionEntriesBase<
|
|
19
|
+
JunctionEntriesBase<A, B, Content> {}
|
|
19
20
|
|
|
20
|
-
export type JunctionSchemaBase<
|
|
21
|
+
export type JunctionSchemaBase<AName extends string, BName extends string> = {
|
|
21
22
|
/** Description of the relationship between the two sides */
|
|
22
|
-
readonly between: [a:
|
|
23
|
+
readonly between: [a: AName, b: BName]
|
|
23
24
|
/** How many relations are allowed in each direction? */
|
|
24
25
|
readonly cardinality: `1:1` | `1:n` | `n:n`
|
|
25
26
|
}
|
|
@@ -55,58 +56,58 @@ export type ExternalStoreConfiguration<Content extends Json.Object | null> =
|
|
|
55
56
|
Empty<ExternalStoreWithContentConfiguration<Json.Object>>
|
|
56
57
|
|
|
57
58
|
export type JunctionAdvancedConfiguration<
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
AName extends string,
|
|
60
|
+
A extends string,
|
|
61
|
+
BName extends string,
|
|
62
|
+
B extends string,
|
|
60
63
|
Content extends Json.Object | null,
|
|
61
64
|
> = {
|
|
62
65
|
warn?: (...args: any[]) => void
|
|
63
66
|
externalStore?: ExternalStoreConfiguration<Content>
|
|
64
|
-
isAType?: Refinement<string,
|
|
65
|
-
isBType?: Refinement<string,
|
|
67
|
+
isAType?: Refinement<string, A>
|
|
68
|
+
isBType?: Refinement<string, B>
|
|
66
69
|
isContent?: Refinement<unknown, Content>
|
|
67
|
-
makeContentKey?: (a:
|
|
70
|
+
makeContentKey?: (a: A, b: B) => string
|
|
71
|
+
source?: Junction<AName, A, BName, B, Content>
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
export type JunctionJSON<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
AName extends string,
|
|
76
|
+
A extends string,
|
|
77
|
+
BName extends string,
|
|
78
|
+
B extends string,
|
|
75
79
|
Content extends Json.Object | null,
|
|
76
|
-
> = JunctionEntries<
|
|
80
|
+
> = JunctionEntries<A, B, Content> & JunctionSchema<AName, BName>
|
|
77
81
|
|
|
78
82
|
export class Junction<
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
+
const AName extends string,
|
|
84
|
+
const A extends string,
|
|
85
|
+
const BName extends string,
|
|
86
|
+
const B extends string,
|
|
83
87
|
const Content extends Json.Object | null = null,
|
|
84
88
|
> {
|
|
85
|
-
public readonly a:
|
|
86
|
-
public readonly b:
|
|
89
|
+
public readonly a: AName
|
|
90
|
+
public readonly b: BName
|
|
87
91
|
public readonly cardinality: `1:1` | `1:n` | `n:n`
|
|
88
|
-
public readonly relations: Map<
|
|
89
|
-
new Map()
|
|
92
|
+
public readonly relations: Map<A | B, Set<A> | Set<B>> = new Map()
|
|
90
93
|
public readonly contents: Map<string, Content> = new Map()
|
|
91
94
|
|
|
92
|
-
public isAType?: Refinement<string,
|
|
93
|
-
public isBType?: Refinement<string,
|
|
95
|
+
public isAType?: Refinement<string, A> | null
|
|
96
|
+
public isBType?: Refinement<string, B> | null
|
|
94
97
|
public isContent: Refinement<unknown, Content> | null
|
|
95
|
-
public makeContentKey = (a:
|
|
98
|
+
public makeContentKey = (a: A, b: B): string => `${a}:${b}`
|
|
96
99
|
|
|
97
100
|
public warn?: (...args: any[]) => void
|
|
98
101
|
|
|
99
|
-
public getRelatedKeys(key:
|
|
100
|
-
public getRelatedKeys(key:
|
|
101
|
-
public getRelatedKeys(key:
|
|
102
|
-
public getRelatedKeys(
|
|
103
|
-
key: AType | BType,
|
|
104
|
-
): Set<AType> | Set<BType> | undefined {
|
|
102
|
+
public getRelatedKeys(key: A): Set<B> | undefined
|
|
103
|
+
public getRelatedKeys(key: B): Set<A> | undefined
|
|
104
|
+
public getRelatedKeys(key: A | B): Set<A> | Set<B> | undefined
|
|
105
|
+
public getRelatedKeys(key: A | B): Set<A> | Set<B> | undefined {
|
|
105
106
|
return this.relations.get(key)
|
|
106
107
|
}
|
|
107
|
-
protected addRelation(a:
|
|
108
|
-
let aRelations = this.relations.get(a) as Set<
|
|
109
|
-
let bRelations = this.relations.get(b) as Set<
|
|
108
|
+
protected addRelation(a: A, b: B): void {
|
|
109
|
+
let aRelations = this.relations.get(a) as Set<B> | undefined
|
|
110
|
+
let bRelations = this.relations.get(b) as Set<A> | undefined
|
|
110
111
|
if (aRelations) {
|
|
111
112
|
aRelations.add(b)
|
|
112
113
|
} else {
|
|
@@ -120,14 +121,14 @@ export class Junction<
|
|
|
120
121
|
this.relations.set(b, bRelations)
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
|
-
protected deleteRelation(a:
|
|
124
|
-
const aRelations = this.relations.get(a) as Set<
|
|
124
|
+
protected deleteRelation(a: A, b: B): void {
|
|
125
|
+
const aRelations = this.relations.get(a) as Set<B> | undefined
|
|
125
126
|
if (aRelations) {
|
|
126
127
|
aRelations.delete(b)
|
|
127
128
|
if (aRelations.size === 0) {
|
|
128
129
|
this.relations.delete(a)
|
|
129
130
|
}
|
|
130
|
-
const bRelations = this.relations.get(b) as Set<
|
|
131
|
+
const bRelations = this.relations.get(b) as Set<A> | undefined
|
|
131
132
|
if (bRelations) {
|
|
132
133
|
bRelations.delete(a)
|
|
133
134
|
if (bRelations.size === 0) {
|
|
@@ -137,31 +138,28 @@ export class Junction<
|
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
protected replaceRelationsUnsafely(a:
|
|
141
|
-
protected replaceRelationsUnsafely(b:
|
|
142
|
-
protected replaceRelationsUnsafely(
|
|
143
|
-
x
|
|
144
|
-
ys: AType[] | BType[],
|
|
145
|
-
): void {
|
|
146
|
-
this.relations.set(x as AType, new Set(ys as BType[]))
|
|
141
|
+
protected replaceRelationsUnsafely(a: A, bs: B[]): void
|
|
142
|
+
protected replaceRelationsUnsafely(b: B, as: A[]): void
|
|
143
|
+
protected replaceRelationsUnsafely(x: A | B, ys: A[] | B[]): void {
|
|
144
|
+
this.relations.set(x as A, new Set(ys as B[]))
|
|
147
145
|
for (const y of ys) {
|
|
148
|
-
const yRelations = new Set<
|
|
146
|
+
const yRelations = new Set<A>().add(x as A)
|
|
149
147
|
this.relations.set(y, yRelations)
|
|
150
148
|
}
|
|
151
149
|
}
|
|
152
|
-
protected replaceRelationsSafely(a:
|
|
153
|
-
protected replaceRelationsSafely(b:
|
|
150
|
+
protected replaceRelationsSafely(a: A, bs: B[]): void
|
|
151
|
+
protected replaceRelationsSafely(b: B, as: A[]): void
|
|
154
152
|
protected replaceRelationsSafely<
|
|
155
|
-
XType extends
|
|
156
|
-
YType extends XType extends
|
|
153
|
+
XType extends A | B,
|
|
154
|
+
YType extends XType extends A ? B : A,
|
|
157
155
|
>(x: XType, ys: YType[]): void {
|
|
158
156
|
const xRelationsPrev = this.relations.get(x)
|
|
159
|
-
let a:
|
|
160
|
-
let b:
|
|
157
|
+
let a: A | undefined = this.isAType?.(x) ? x : undefined
|
|
158
|
+
let b: B | undefined = a === undefined ? (x as B) : undefined
|
|
161
159
|
if (xRelationsPrev) {
|
|
162
160
|
for (const y of xRelationsPrev) {
|
|
163
|
-
a ??= y as
|
|
164
|
-
b ??= y as
|
|
161
|
+
a ??= y as A
|
|
162
|
+
b ??= y as B
|
|
165
163
|
const yRelations = this.relations.get(y) as Set<XType> | undefined
|
|
166
164
|
if (yRelations) {
|
|
167
165
|
if (yRelations.size === 1) {
|
|
@@ -196,26 +194,34 @@ export class Junction<
|
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
public constructor(
|
|
199
|
-
data: JunctionSchema<
|
|
200
|
-
Partial<JunctionEntries<NoInfer<
|
|
201
|
-
config?: JunctionAdvancedConfiguration<
|
|
197
|
+
data: JunctionSchema<AName, BName> &
|
|
198
|
+
Partial<JunctionEntries<NoInfer<A>, NoInfer<B>, Content>>,
|
|
199
|
+
config?: JunctionAdvancedConfiguration<AName, A, BName, B, Content>,
|
|
202
200
|
) {
|
|
203
201
|
this.a = data.between[0]
|
|
204
202
|
this.b = data.between[1]
|
|
205
203
|
|
|
206
204
|
this.cardinality = data.cardinality
|
|
207
|
-
|
|
208
|
-
this.relations = new Map(
|
|
209
|
-
data.relations?.map(([x, ys]) => [x, new Set(ys as AType[])]),
|
|
210
|
-
)
|
|
211
|
-
this.contents = new Map(data.contents)
|
|
212
|
-
}
|
|
205
|
+
|
|
213
206
|
this.isAType = config?.isAType ?? null
|
|
214
207
|
this.isBType = config?.isBType ?? null
|
|
215
208
|
this.isContent = config?.isContent ?? null
|
|
216
209
|
if (config?.makeContentKey) {
|
|
217
210
|
this.makeContentKey = config.makeContentKey
|
|
218
211
|
}
|
|
212
|
+
if (!config?.externalStore) {
|
|
213
|
+
const source = config?.source
|
|
214
|
+
if (source === undefined) {
|
|
215
|
+
this.relations = new Map(
|
|
216
|
+
data.relations?.map(([x, ys]) => [x, new Set(ys as A[])]),
|
|
217
|
+
)
|
|
218
|
+
this.contents = new Map(data.contents)
|
|
219
|
+
}
|
|
220
|
+
if (source) {
|
|
221
|
+
this.relations = new RelationsOverlay(source.relations)
|
|
222
|
+
this.contents = new MapOverlay(source.contents)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
219
225
|
if (config?.externalStore) {
|
|
220
226
|
const externalStore = config.externalStore
|
|
221
227
|
this.has = (a, b) => externalStore.has(a, b)
|
|
@@ -248,10 +254,10 @@ export class Junction<
|
|
|
248
254
|
}
|
|
249
255
|
for (const [x, ys] of data.relations ?? []) {
|
|
250
256
|
let a = this.isAType?.(x) ? x : undefined
|
|
251
|
-
let b = a === undefined ? (x as
|
|
257
|
+
let b = a === undefined ? (x as B) : undefined
|
|
252
258
|
for (const y of ys) {
|
|
253
|
-
a ??= y as
|
|
254
|
-
b ??= y as
|
|
259
|
+
a ??= y as A
|
|
260
|
+
b ??= y as B
|
|
255
261
|
this.addRelation(a, b)
|
|
256
262
|
}
|
|
257
263
|
}
|
|
@@ -263,54 +269,41 @@ export class Junction<
|
|
|
263
269
|
this.warn = config.warn
|
|
264
270
|
}
|
|
265
271
|
}
|
|
266
|
-
public toJSON(): JunctionJSON<
|
|
272
|
+
public toJSON(): JunctionJSON<AName, A, BName, B, Content> {
|
|
267
273
|
return {
|
|
268
274
|
between: [this.a, this.b],
|
|
269
275
|
cardinality: this.cardinality,
|
|
270
276
|
relations: [...this.relations.entries()].map(
|
|
271
|
-
([a, b]) => [a, [...b]] as [
|
|
277
|
+
([a, b]) => [a, [...b]] as [A, B[]],
|
|
272
278
|
),
|
|
273
279
|
contents: [...this.contents.entries()],
|
|
274
280
|
}
|
|
275
281
|
}
|
|
276
282
|
|
|
277
283
|
public set(
|
|
278
|
-
a:
|
|
279
|
-
...rest: Content extends null ? [b:
|
|
284
|
+
a: A,
|
|
285
|
+
...rest: Content extends null ? [b: B] : [b: B, content: Content]
|
|
280
286
|
): this
|
|
281
287
|
public set(
|
|
282
|
-
relation: { [Key in
|
|
288
|
+
relation: { [Key in AName]: A } & { [Key in BName]: B },
|
|
283
289
|
...rest: Content extends null ? [] | [void?: undefined] : [content: Content]
|
|
284
290
|
): this
|
|
285
291
|
public set(
|
|
286
|
-
// a: AType | ({ [Key in ASide]: AType } & { [Key in BSide]: BType }),
|
|
287
|
-
// ...rest: Content extends null
|
|
288
|
-
// ? [] | [b?: BType | undefined]
|
|
289
|
-
// : [b: BType, content: Content] | [content: Content]
|
|
290
292
|
...params:
|
|
291
293
|
| [
|
|
292
|
-
|
|
293
|
-
...rest: Content extends null
|
|
294
|
-
? [b: BType]
|
|
295
|
-
: [b: BType, content: Content],
|
|
296
|
-
]
|
|
297
|
-
| [
|
|
298
|
-
relation: { [Key in ASide]: AType } & { [Key in BSide]: BType },
|
|
294
|
+
relation: { [Key in AName]: A } & { [Key in BName]: B },
|
|
299
295
|
...rest: Content extends null
|
|
300
296
|
? [] | [void?: undefined]
|
|
301
297
|
: [content: Content],
|
|
302
298
|
]
|
|
303
|
-
|
|
304
|
-
// | [{ [Key in ASide]: AType } & { [Key in BSide]: BType }]
|
|
305
|
-
// | [a: AType, b: BType, content: Content]
|
|
306
|
-
// | [a: AType, b: BType]
|
|
299
|
+
| [a: A, ...rest: Content extends null ? [b: B] : [b: B, content: Content]]
|
|
307
300
|
): this {
|
|
308
|
-
let a:
|
|
309
|
-
let b:
|
|
301
|
+
let a: A
|
|
302
|
+
let b: B
|
|
310
303
|
let content: Content | undefined
|
|
311
304
|
switch (params.length) {
|
|
312
305
|
case 1: {
|
|
313
|
-
const relation = params[0] as Record<
|
|
306
|
+
const relation = params[0] as Record<AName, A> & Record<BName, B>
|
|
314
307
|
a = relation[this.a]
|
|
315
308
|
b = relation[this.b]
|
|
316
309
|
content = undefined
|
|
@@ -319,7 +312,7 @@ export class Junction<
|
|
|
319
312
|
case 2: {
|
|
320
313
|
const zeroth = params[0]
|
|
321
314
|
if (typeof zeroth === `string`) {
|
|
322
|
-
;[a, b] = params as unknown as [
|
|
315
|
+
;[a, b] = params as unknown as [A, B]
|
|
323
316
|
} else {
|
|
324
317
|
a = zeroth[this.a]
|
|
325
318
|
b = zeroth[this.b]
|
|
@@ -328,8 +321,8 @@ export class Junction<
|
|
|
328
321
|
break
|
|
329
322
|
}
|
|
330
323
|
default: {
|
|
331
|
-
a = params[0] as
|
|
332
|
-
b = params[1] as
|
|
324
|
+
a = params[0] as A
|
|
325
|
+
b = params[1] as B
|
|
333
326
|
content = params[2] as Content
|
|
334
327
|
break
|
|
335
328
|
}
|
|
@@ -356,47 +349,45 @@ export class Junction<
|
|
|
356
349
|
return this
|
|
357
350
|
}
|
|
358
351
|
|
|
359
|
-
public delete(a:
|
|
360
|
-
public delete(b:
|
|
352
|
+
public delete(a: A, b?: B): this
|
|
353
|
+
public delete(b: B, a?: A): this
|
|
361
354
|
public delete(
|
|
362
355
|
relation:
|
|
363
|
-
| { [Key in
|
|
364
|
-
| { [Key in
|
|
365
|
-
| ({ [Key in
|
|
356
|
+
| { [Key in AName]: A }
|
|
357
|
+
| { [Key in BName]: B }
|
|
358
|
+
| ({ [Key in AName]: A } & { [Key in BName]: B }),
|
|
366
359
|
b?: undefined,
|
|
367
360
|
): this
|
|
368
361
|
public delete(
|
|
369
362
|
x:
|
|
370
|
-
|
|
|
371
|
-
|
|
|
372
|
-
| Record<
|
|
373
|
-
| Record<
|
|
374
|
-
| Record<
|
|
375
|
-
b?:
|
|
363
|
+
| A
|
|
364
|
+
| B
|
|
365
|
+
| Record<AName | BName, string>
|
|
366
|
+
| Record<AName, string>
|
|
367
|
+
| Record<BName, string>,
|
|
368
|
+
b?: A | B,
|
|
376
369
|
): this {
|
|
377
370
|
// @ts-expect-error we deduce that this.b may index x
|
|
378
|
-
b = typeof b === `string` ? (b as
|
|
371
|
+
b = typeof b === `string` ? (b as B) : (x[this.b] as B | undefined)
|
|
379
372
|
const a =
|
|
380
373
|
// @ts-expect-error we deduce that this.a may index x
|
|
381
|
-
typeof x === `string` ? (x as
|
|
374
|
+
typeof x === `string` ? (x as A) : (x[this.a] as A | undefined)
|
|
382
375
|
|
|
383
376
|
if (a === undefined && typeof b === `string`) {
|
|
384
|
-
const bRelations = this.getRelatedKeys(b) as Set<
|
|
377
|
+
const bRelations = this.getRelatedKeys(b) as Set<A>
|
|
385
378
|
if (bRelations) {
|
|
386
379
|
for (const bRelation of bRelations) {
|
|
387
380
|
this.delete(bRelation, b)
|
|
388
381
|
}
|
|
389
382
|
}
|
|
390
|
-
}
|
|
391
|
-
if (typeof a === `string` && b === undefined) {
|
|
383
|
+
} else if (typeof a === `string` && b === undefined) {
|
|
392
384
|
const aRelations = this.getRelatedKeys(a)
|
|
393
385
|
if (aRelations) {
|
|
394
386
|
for (const aRelation of aRelations) {
|
|
395
387
|
this.delete(a, aRelation)
|
|
396
388
|
}
|
|
397
389
|
}
|
|
398
|
-
}
|
|
399
|
-
if (typeof a === `string` && typeof b === `string`) {
|
|
390
|
+
} else if (typeof a === `string` && typeof b === `string`) {
|
|
400
391
|
this.deleteRelation(a, b)
|
|
401
392
|
const contentKey = this.makeContentKey(a, b)
|
|
402
393
|
this.deleteContent(contentKey)
|
|
@@ -404,9 +395,9 @@ export class Junction<
|
|
|
404
395
|
return this
|
|
405
396
|
}
|
|
406
397
|
|
|
407
|
-
public getRelatedKey(key:
|
|
408
|
-
public getRelatedKey(key:
|
|
409
|
-
public getRelatedKey(key:
|
|
398
|
+
public getRelatedKey(key: A): B | undefined
|
|
399
|
+
public getRelatedKey(key: B): A | undefined
|
|
400
|
+
public getRelatedKey(key: A | B): A | B | undefined {
|
|
410
401
|
const relations = this.getRelatedKeys(key)
|
|
411
402
|
if (relations) {
|
|
412
403
|
if (relations.size > 1) {
|
|
@@ -418,7 +409,7 @@ export class Junction<
|
|
|
418
409
|
.join(`, `)}). Only one related key was expected.`,
|
|
419
410
|
)
|
|
420
411
|
}
|
|
421
|
-
let singleRelation:
|
|
412
|
+
let singleRelation: A | B | undefined
|
|
422
413
|
for (const relation of relations) {
|
|
423
414
|
singleRelation = relation
|
|
424
415
|
break
|
|
@@ -428,18 +419,18 @@ export class Junction<
|
|
|
428
419
|
}
|
|
429
420
|
|
|
430
421
|
public replaceRelations(
|
|
431
|
-
a:
|
|
432
|
-
relations: Content extends null ?
|
|
422
|
+
a: A,
|
|
423
|
+
relations: Content extends null ? B[] : Record<B, Content>,
|
|
433
424
|
config?: { reckless: boolean },
|
|
434
425
|
): this
|
|
435
426
|
public replaceRelations(
|
|
436
|
-
b:
|
|
437
|
-
relations: Content extends null ?
|
|
427
|
+
b: B,
|
|
428
|
+
relations: Content extends null ? A[] : Record<A, Content>,
|
|
438
429
|
config?: { reckless: boolean },
|
|
439
430
|
): this
|
|
440
431
|
public replaceRelations<
|
|
441
|
-
XType extends
|
|
442
|
-
YType extends XType extends
|
|
432
|
+
XType extends A | B,
|
|
433
|
+
YType extends XType extends A ? B : A,
|
|
443
434
|
>(
|
|
444
435
|
x: XType,
|
|
445
436
|
relations: Content extends null ? YType[] : Record<YType, Content>,
|
|
@@ -462,18 +453,18 @@ export class Junction<
|
|
|
462
453
|
return this
|
|
463
454
|
}
|
|
464
455
|
|
|
465
|
-
public getContent(a:
|
|
456
|
+
public getContent(a: A, b: B): Content | undefined {
|
|
466
457
|
const contentKey = this.makeContentKey(a, b)
|
|
467
458
|
return this.getContentInternal(contentKey)
|
|
468
459
|
}
|
|
469
460
|
|
|
470
|
-
public getRelationEntries(input: Record<
|
|
471
|
-
public getRelationEntries(input: Record<
|
|
461
|
+
public getRelationEntries(input: Record<AName, A>): [B, Content][]
|
|
462
|
+
public getRelationEntries(input: Record<BName, B>): [A, Content][]
|
|
472
463
|
public getRelationEntries(
|
|
473
|
-
input: Record<
|
|
474
|
-
): [
|
|
475
|
-
const a:
|
|
476
|
-
const b:
|
|
464
|
+
input: Record<AName, A> | Record<BName, B>,
|
|
465
|
+
): [A | B, Content][] {
|
|
466
|
+
const a: A | undefined = (input as any)[this.a]
|
|
467
|
+
const b: B | undefined = (input as any)[this.b]
|
|
477
468
|
if (a !== undefined && b === undefined) {
|
|
478
469
|
const aRelations = this.getRelatedKeys(a)
|
|
479
470
|
if (aRelations) {
|
|
@@ -493,13 +484,66 @@ export class Junction<
|
|
|
493
484
|
return []
|
|
494
485
|
}
|
|
495
486
|
|
|
496
|
-
public has(a:
|
|
497
|
-
public has(b:
|
|
498
|
-
public has(a:
|
|
487
|
+
public has(a: A, b?: B): boolean
|
|
488
|
+
public has(b: B, a?: A): boolean
|
|
489
|
+
public has(a: A | B, b?: A | B): boolean {
|
|
499
490
|
if (b) {
|
|
500
491
|
const setA = this.getRelatedKeys(a)
|
|
501
492
|
return setA?.has(b as any) ?? false
|
|
502
493
|
}
|
|
503
494
|
return this.relations.has(a)
|
|
504
495
|
}
|
|
496
|
+
public overlay(): JunctionOverlay<AName, A, BName, B, Content> {
|
|
497
|
+
const config: JunctionAdvancedConfiguration<AName, A, BName, B, Content> = {
|
|
498
|
+
source: this,
|
|
499
|
+
makeContentKey: this.makeContentKey,
|
|
500
|
+
}
|
|
501
|
+
if (this.isAType) config.isAType = this.isAType
|
|
502
|
+
if (this.isBType) config.isBType = this.isBType
|
|
503
|
+
if (this.isContent) config.isContent = this.isContent
|
|
504
|
+
if (this.warn) config.warn = this.warn
|
|
505
|
+
|
|
506
|
+
return new Junction(
|
|
507
|
+
{
|
|
508
|
+
between: [this.a, this.b],
|
|
509
|
+
cardinality: this.cardinality,
|
|
510
|
+
},
|
|
511
|
+
config,
|
|
512
|
+
) as JunctionOverlay<AName, A, BName, B, Content>
|
|
513
|
+
}
|
|
514
|
+
public incorporate(
|
|
515
|
+
overlay: JunctionOverlay<AName, A, BName, B, Content>,
|
|
516
|
+
): void {
|
|
517
|
+
const { relations, contents } = overlay
|
|
518
|
+
for (const [key, value] of relations) {
|
|
519
|
+
if (value instanceof SetOverlay) {
|
|
520
|
+
const { source } = value
|
|
521
|
+
for (const keyAdded of value.iterateOwn()) {
|
|
522
|
+
source.add(keyAdded)
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
this.relations.set(key, value)
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
for (const key of relations.deleted) {
|
|
529
|
+
this.relations.delete(key)
|
|
530
|
+
}
|
|
531
|
+
for (const [key, value] of contents) {
|
|
532
|
+
this.contents.set(key, value)
|
|
533
|
+
}
|
|
534
|
+
for (const key of contents.deleted) {
|
|
535
|
+
this.contents.delete(key)
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export type JunctionOverlay<
|
|
541
|
+
AName extends string,
|
|
542
|
+
A extends string,
|
|
543
|
+
BName extends string,
|
|
544
|
+
B extends string,
|
|
545
|
+
Content extends Json.Object | null = null,
|
|
546
|
+
> = Junction<AName, A, BName, B, Content> & {
|
|
547
|
+
relations: MapOverlay<A | B, Set<A> | Set<B>>
|
|
548
|
+
contents: MapOverlay<string, Content>
|
|
505
549
|
}
|
|
@@ -60,7 +60,7 @@ export function createMutableAtomFamily<
|
|
|
60
60
|
|
|
61
61
|
const token = createMutableAtom(target, individualOptions, family)
|
|
62
62
|
|
|
63
|
-
subject.next({ type: `state_creation`, token, timestamp: Date.now() })
|
|
63
|
+
// subject.next({ type: `state_creation`, token, timestamp: Date.now() })
|
|
64
64
|
return token
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export class MapOverlay<K, V> extends Map<K, V> {
|
|
2
|
+
public deleted: Set<K> = new Set()
|
|
3
|
+
public changed: Set<K> = new Set()
|
|
4
|
+
protected readonly source: Map<K, V>
|
|
5
|
+
|
|
6
|
+
public constructor(source: Map<K, V>) {
|
|
7
|
+
super()
|
|
8
|
+
this.source = source
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public get(key: K): V | undefined {
|
|
12
|
+
const has = super.has(key)
|
|
13
|
+
if (has) {
|
|
14
|
+
return super.get(key)
|
|
15
|
+
}
|
|
16
|
+
if (!this.deleted.has(key) && this.source.has(key)) {
|
|
17
|
+
const value = this.source.get(key)
|
|
18
|
+
return value
|
|
19
|
+
}
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public set(key: K, value: V): this {
|
|
24
|
+
this.deleted.delete(key)
|
|
25
|
+
if (this.source.has(key)) {
|
|
26
|
+
this.changed.add(key)
|
|
27
|
+
}
|
|
28
|
+
return super.set(key, value)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public hasOwn(key: K): boolean {
|
|
32
|
+
return super.has(key)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public has(key: K): boolean {
|
|
36
|
+
return !this.deleted.has(key) && (super.has(key) || this.source.has(key))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public delete(key: K): boolean {
|
|
40
|
+
if (this.source.has(key)) {
|
|
41
|
+
this.deleted.add(key)
|
|
42
|
+
this.changed.delete(key)
|
|
43
|
+
}
|
|
44
|
+
return super.delete(key)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public clear(): void {
|
|
48
|
+
this.deleted = new Set(this.source.keys())
|
|
49
|
+
this.changed.clear()
|
|
50
|
+
super.clear()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public *[Symbol.iterator](): MapIterator<[K, V]> {
|
|
54
|
+
yield* super[Symbol.iterator]()
|
|
55
|
+
for (const [key, value] of this.source) {
|
|
56
|
+
if (!this.deleted.has(key) && !this.changed.has(key)) {
|
|
57
|
+
yield [key, value]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
public *entries(): MapIterator<[K, V]> {
|
|
62
|
+
yield* this[Symbol.iterator]()
|
|
63
|
+
}
|
|
64
|
+
public *keys(): MapIterator<K> {
|
|
65
|
+
yield* super.keys()
|
|
66
|
+
for (const key of this.source.keys()) {
|
|
67
|
+
if (!this.deleted.has(key) && !this.changed.has(key)) {
|
|
68
|
+
yield key
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
public *values(): MapIterator<V> {
|
|
73
|
+
for (const [, value] of this[Symbol.iterator]()) {
|
|
74
|
+
yield value
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
public forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void): void {
|
|
78
|
+
for (const [key, value] of this[Symbol.iterator]()) {
|
|
79
|
+
callbackfn(value, key, this)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public get size(): number {
|
|
84
|
+
return super.size + this.source.size - this.changed.size - this.deleted.size
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { SetOverlay } from "./set-overlay"
|
|
2
|
+
|
|
3
|
+
export class RelationsOverlay<K, V extends Set<any>> extends Map<K, V> {
|
|
2
4
|
public deleted: Set<K> = new Set()
|
|
3
5
|
protected readonly source: Map<K, V>
|
|
4
6
|
|
|
@@ -14,7 +16,9 @@ export class LazyMap<K, V> extends Map<K, V> {
|
|
|
14
16
|
}
|
|
15
17
|
if (!this.deleted.has(key) && this.source.has(key)) {
|
|
16
18
|
const value = this.source.get(key)
|
|
17
|
-
|
|
19
|
+
const valueOverlay = new SetOverlay(value as V) as unknown as V
|
|
20
|
+
super.set(key, valueOverlay)
|
|
21
|
+
return valueOverlay
|
|
18
22
|
}
|
|
19
23
|
return undefined
|
|
20
24
|
}
|
|
@@ -24,10 +28,6 @@ export class LazyMap<K, V> extends Map<K, V> {
|
|
|
24
28
|
return super.set(key, value)
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
public hasOwn(key: K): boolean {
|
|
28
|
-
return super.has(key)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
31
|
public has(key: K): boolean {
|
|
32
32
|
return !this.deleted.has(key) && (super.has(key) || this.source.has(key))
|
|
33
33
|
}
|