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.
Files changed (91) hide show
  1. package/dist/data/index.js.map +1 -1
  2. package/dist/eslint-plugin/index.js +2 -1
  3. package/dist/eslint-plugin/index.js.map +1 -1
  4. package/dist/internal/index.d.ts +128 -85
  5. package/dist/internal/index.d.ts.map +1 -1
  6. package/dist/internal/index.js +429 -286
  7. package/dist/internal/index.js.map +1 -1
  8. package/dist/introspection/index.d.ts.map +1 -1
  9. package/dist/introspection/index.js.map +1 -1
  10. package/dist/json/index.d.ts.map +1 -1
  11. package/dist/json/index.js.map +1 -1
  12. package/dist/main/index.d.ts +45 -35
  13. package/dist/main/index.d.ts.map +1 -1
  14. package/dist/main/index.js.map +1 -1
  15. package/dist/react/index.d.ts.map +1 -1
  16. package/dist/react/index.js +43 -2
  17. package/dist/react/index.js.map +1 -1
  18. package/dist/react-devtools/index.d.ts.map +1 -1
  19. package/dist/react-devtools/index.js +4 -5
  20. package/dist/react-devtools/index.js.map +1 -1
  21. package/dist/realtime/index.d.ts.map +1 -1
  22. package/dist/realtime/index.js.map +1 -1
  23. package/dist/realtime-client/index.js +5 -5
  24. package/dist/realtime-client/index.js.map +1 -1
  25. package/dist/realtime-react/index.js.map +1 -1
  26. package/dist/realtime-server/index.d.ts.map +1 -1
  27. package/dist/realtime-server/index.js +4 -4
  28. package/dist/realtime-server/index.js.map +1 -1
  29. package/dist/realtime-testing/index.d.ts.map +1 -1
  30. package/dist/realtime-testing/index.js.map +1 -1
  31. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  32. package/dist/transceivers/set-rtx/index.js.map +1 -1
  33. package/dist/web/index.js.map +1 -1
  34. package/package.json +10 -11
  35. package/src/internal/atom/create-regular-atom.ts +2 -6
  36. package/src/internal/caching.ts +2 -4
  37. package/src/internal/{ingest-updates → events}/ingest-atom-update.ts +4 -5
  38. package/src/internal/{ingest-updates → events}/ingest-creation-disposal.ts +37 -37
  39. package/src/internal/{ingest-updates → events}/ingest-selector-update.ts +5 -5
  40. package/src/internal/events/ingest-transaction-update.ts +45 -0
  41. package/src/internal/families/create-readonly-held-selector-family.ts +1 -1
  42. package/src/internal/families/create-readonly-pure-selector-family.ts +1 -1
  43. package/src/internal/families/create-regular-atom-family.ts +4 -3
  44. package/src/internal/families/create-writable-held-selector-family.ts +1 -1
  45. package/src/internal/families/create-writable-pure-selector-family.ts +1 -1
  46. package/src/internal/families/find-in-store.ts +2 -2
  47. package/src/internal/families/get-family-of-token.ts +1 -0
  48. package/src/internal/families/index.ts +0 -1
  49. package/src/internal/families/mint-in-store.ts +30 -64
  50. package/src/internal/get-state/get-from-store.ts +2 -3
  51. package/src/internal/get-state/read-or-compute-value.ts +6 -15
  52. package/src/internal/get-state/reduce-reference.ts +52 -11
  53. package/src/internal/index.ts +2 -2
  54. package/src/internal/is-fn.ts +9 -0
  55. package/src/internal/junction.ts +177 -133
  56. package/src/internal/mutable/create-mutable-atom-family.ts +1 -1
  57. package/src/internal/overlays/index.ts +3 -0
  58. package/src/internal/overlays/map-overlay.ts +86 -0
  59. package/src/internal/{lazy-map.ts → overlays/relations-overlay.ts} +6 -6
  60. package/src/internal/overlays/set-overlay.ts +55 -0
  61. package/src/internal/selector/create-readonly-held-selector.ts +8 -11
  62. package/src/internal/selector/create-readonly-pure-selector.ts +8 -10
  63. package/src/internal/selector/create-writable-held-selector.ts +6 -6
  64. package/src/internal/selector/create-writable-pure-selector.ts +2 -2
  65. package/src/internal/selector/register-selector.ts +3 -4
  66. package/src/internal/set-state/become.ts +11 -6
  67. package/src/internal/set-state/dispatch-state-update.ts +47 -12
  68. package/src/internal/set-state/operate-on-store.ts +10 -8
  69. package/src/internal/set-state/reset-atom-or-selector.ts +7 -7
  70. package/src/internal/set-state/set-atom-or-selector.ts +3 -2
  71. package/src/internal/set-state/set-atom.ts +5 -4
  72. package/src/internal/set-state/set-selector.ts +9 -8
  73. package/src/internal/store/withdraw.ts +4 -4
  74. package/src/internal/timeline/time-travel.ts +11 -11
  75. package/src/internal/transaction/apply-transaction.ts +5 -5
  76. package/src/internal/transaction/build-transaction.ts +17 -26
  77. package/src/internal/transaction/create-transaction.ts +1 -1
  78. package/src/internal/transaction/is-root-store.ts +2 -2
  79. package/src/main/events.ts +14 -3
  80. package/src/main/logger.ts +43 -32
  81. package/src/react-devtools/json-editor/editors-by-type/array-editor.tsx +1 -1
  82. package/src/react-devtools/json-editor/editors-by-type/object-editor.tsx +2 -3
  83. package/src/react-devtools/json-editor/editors-by-type/utilities/array-elements.ts +1 -1
  84. package/src/react-devtools/json-editor/editors-by-type/utilities/object-properties.ts +1 -1
  85. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +5 -5
  86. package/src/realtime-server/continuity/subscribe-to-continuity-perpectives.ts +4 -4
  87. package/dist/use-o-DXPncKmZ.js +0 -47
  88. package/dist/use-o-DXPncKmZ.js.map +0 -1
  89. package/src/internal/families/init-family-member.ts +0 -33
  90. package/src/internal/ingest-updates/ingest-transaction-update.ts +0 -47
  91. /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
+ }
@@ -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
- AType extends string,
7
- BType extends string,
7
+ A extends string,
8
+ B extends string,
8
9
  Content extends Json.Object | null,
9
10
  > = {
10
- readonly relations: ([AType, BType[]] | [BType, AType[]])[]
11
+ readonly relations: ([A, B[]] | [B, A[]])[]
11
12
  readonly contents: [string, Content][]
12
13
  }
13
14
  export interface JunctionEntries<
14
- AType extends string,
15
- BType extends string,
15
+ A extends string,
16
+ B extends string,
16
17
  Content extends Json.Object | null,
17
18
  > extends Json.Object,
18
- JunctionEntriesBase<AType, BType, Content> {}
19
+ JunctionEntriesBase<A, B, Content> {}
19
20
 
20
- export type JunctionSchemaBase<ASide extends string, BSide extends string> = {
21
+ export type JunctionSchemaBase<AName extends string, BName extends string> = {
21
22
  /** Description of the relationship between the two sides */
22
- readonly between: [a: ASide, b: BSide]
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
- AType extends string,
59
- BType extends string,
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, AType>
65
- isBType?: Refinement<string, BType>
67
+ isAType?: Refinement<string, A>
68
+ isBType?: Refinement<string, B>
66
69
  isContent?: Refinement<unknown, Content>
67
- makeContentKey?: (a: AType, b: BType) => string
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
- ASide extends string,
72
- AType extends string,
73
- BSide extends string,
74
- BType extends string,
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<AType, BType, Content> & JunctionSchema<ASide, BSide>
80
+ > = JunctionEntries<A, B, Content> & JunctionSchema<AName, BName>
77
81
 
78
82
  export class Junction<
79
- const ASide extends string,
80
- const AType extends string,
81
- const BSide extends string,
82
- const BType extends string,
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: ASide
86
- public readonly b: BSide
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<AType | BType, Set<AType> | Set<BType>> =
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, AType> | null
93
- public isBType?: Refinement<string, BType> | null
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: AType, b: BType): string => `${a}:${b}`
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: AType): Set<BType> | undefined
100
- public getRelatedKeys(key: BType): Set<AType> | undefined
101
- public getRelatedKeys(key: AType | BType): Set<AType> | Set<BType> | undefined
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: AType, b: BType): void {
108
- let aRelations = this.relations.get(a) as Set<BType> | undefined
109
- let bRelations = this.relations.get(b) as Set<AType> | undefined
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: AType, b: BType): void {
124
- const aRelations = this.relations.get(a) as Set<BType> | undefined
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<AType> | undefined
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: AType, bs: BType[]): void
141
- protected replaceRelationsUnsafely(b: BType, as: AType[]): void
142
- protected replaceRelationsUnsafely(
143
- x: AType | BType,
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<AType>().add(x as AType)
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: AType, bs: BType[]): void
153
- protected replaceRelationsSafely(b: BType, as: AType[]): void
150
+ protected replaceRelationsSafely(a: A, bs: B[]): void
151
+ protected replaceRelationsSafely(b: B, as: A[]): void
154
152
  protected replaceRelationsSafely<
155
- XType extends AType | BType,
156
- YType extends XType extends AType ? BType : AType,
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: AType | undefined = this.isAType?.(x) ? x : undefined
160
- let b: BType | undefined = a === undefined ? (x as BType) : undefined
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 AType
164
- b ??= y as BType
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<ASide, BSide> &
200
- Partial<JunctionEntries<NoInfer<AType>, NoInfer<BType>, Content>>,
201
- config?: JunctionAdvancedConfiguration<AType, BType, Content>,
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
- if (!config?.externalStore) {
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 BType) : undefined
257
+ let b = a === undefined ? (x as B) : undefined
252
258
  for (const y of ys) {
253
- a ??= y as AType
254
- b ??= y as BType
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<ASide, AType, BSide, BType, Content> {
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 [AType, BType[]],
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: AType,
279
- ...rest: Content extends null ? [b: BType] : [b: BType, content: Content]
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 ASide]: AType } & { [Key in BSide]: BType },
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
- a: AType,
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
- // | [{ [Key in ASide]: AType } & { [Key in BSide]: BType }, content: Content]
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: AType
309
- let b: BType
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<ASide, AType> & Record<BSide, BType>
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 [AType, BType]
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 AType
332
- b = params[1] as BType
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: AType, b?: BType): this
360
- public delete(b: BType, a?: AType): this
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 ASide]: AType }
364
- | { [Key in BSide]: BType }
365
- | ({ [Key in ASide]: AType } & { [Key in BSide]: BType }),
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
- | AType
371
- | BType
372
- | Record<ASide | BSide, string>
373
- | Record<ASide, string>
374
- | Record<BSide, string>,
375
- b?: AType | BType,
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 BType) : (x[this.b] as BType | undefined)
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 AType) : (x[this.a] as AType | undefined)
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<AType>
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: AType): BType | undefined
408
- public getRelatedKey(key: BType): AType | undefined
409
- public getRelatedKey(key: AType | BType): AType | BType | undefined {
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: AType | BType | undefined
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: AType,
432
- relations: Content extends null ? BType[] : Record<BType, Content>,
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: BType,
437
- relations: Content extends null ? AType[] : Record<AType, Content>,
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 AType | BType,
442
- YType extends XType extends AType ? BType : AType,
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: AType, b: BType): Content | undefined {
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<ASide, AType>): [BType, Content][]
471
- public getRelationEntries(input: Record<BSide, BType>): [AType, Content][]
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<ASide, AType> | Record<BSide, BType>,
474
- ): [AType | BType, Content][] {
475
- const a: AType | undefined = (input as any)[this.a]
476
- const b: BType | undefined = (input as any)[this.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: AType, b?: BType): boolean
497
- public has(b: BType, a?: AType): boolean
498
- public has(a: AType | BType, b?: AType | BType): boolean {
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,3 @@
1
+ export * from "./map-overlay"
2
+ export * from "./relations-overlay"
3
+ export * from "./set-overlay"
@@ -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
- export class LazyMap<K, V> extends Map<K, V> {
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
- return value
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
  }