atom.io 0.18.1 → 0.18.3
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/data/dist/index.cjs +0 -2
- package/data/dist/index.js +2 -4
- package/dist/{chunk-JDUNWJFB.js → chunk-BWWVY5O5.js} +1 -3
- package/dist/{chunk-NYCVSXQB.js → chunk-CVBEVTM5.js} +0 -2
- package/dist/chunk-O47EQUM6.js +29 -0
- package/dist/{chunk-PZLG2HP3.js → chunk-U2IICNHQ.js} +0 -2
- package/dist/{chunk-XACXFU3B.js → chunk-VAE5OCKN.js} +0 -2
- package/dist/{chunk-NYTGCPHB.js → chunk-WX2NCOZR.js} +0 -2
- package/dist/{chunk-IZHOMSXA.js → chunk-YDOGCZ53.js} +0 -2
- package/dist/index.cjs +0 -2
- package/dist/index.js +1 -3
- package/internal/dist/index.cjs +46 -102
- package/internal/dist/index.d.ts +23 -23
- package/internal/dist/index.js +48 -104
- package/internal/src/families/create-regular-atom-family.ts +4 -4
- package/internal/src/get-state/get-from-store.ts +2 -5
- package/internal/src/mutable/create-mutable-atom-family.ts +4 -4
- package/internal/src/selector/register-selector.ts +3 -14
- package/internal/src/set-state/set-into-store.ts +2 -5
- package/internal/src/store/withdraw-new-family-member.ts +38 -28
- package/internal/src/store/withdraw.ts +20 -23
- package/internal/src/subscribe/subscribe-to-state.ts +2 -3
- package/internal/src/subscribe/subscribe-to-timeline.ts +0 -5
- package/internal/src/subscribe/subscribe-to-transaction.ts +0 -5
- package/internal/src/timeline/add-atom-to-timeline.ts +6 -15
- package/internal/src/timeline/create-timeline.ts +0 -27
- package/introspection/dist/index.cjs +0 -2
- package/introspection/dist/index.js +1 -3
- package/json/dist/index.cjs +0 -2
- package/json/dist/index.js +3 -5
- package/package.json +6 -5
- package/react/dist/index.cjs +2 -5
- package/react/dist/index.js +3 -6
- package/react/src/use-tl.ts +2 -2
- package/react-devtools/dist/index.cjs +1 -3
- package/react-devtools/dist/index.css +0 -1
- package/react-devtools/dist/index.js +4 -6
- package/realtime/dist/index.cjs +0 -2
- package/realtime/dist/index.js +1 -3
- package/realtime-client/dist/index.cjs +1 -3
- package/realtime-client/dist/index.js +15 -41
- package/realtime-react/dist/index.cjs +0 -2
- package/realtime-react/dist/index.js +2 -4
- package/realtime-server/dist/index.cjs +3 -5
- package/realtime-server/dist/index.js +4 -6
- package/realtime-server/src/ipc-sockets/parent-socket.ts +4 -3
- package/realtime-testing/dist/index.cjs +43 -7
- package/realtime-testing/dist/index.js +6 -9
- package/realtime-testing/src/setup-realtime-test.tsx +3 -5
- package/transceivers/set-rtx/dist/index.cjs +0 -2
- package/transceivers/set-rtx/dist/index.js +1 -3
- package/data/dist/index.cjs.map +0 -1
- package/data/dist/index.js.map +0 -1
- package/dist/chunk-IZHOMSXA.js.map +0 -1
- package/dist/chunk-JDUNWJFB.js.map +0 -1
- package/dist/chunk-NYCVSXQB.js.map +0 -1
- package/dist/chunk-NYTGCPHB.js.map +0 -1
- package/dist/chunk-PZLG2HP3.js.map +0 -1
- package/dist/chunk-XACXFU3B.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/internal/dist/index.cjs.map +0 -1
- package/internal/dist/index.js.map +0 -1
- package/introspection/dist/index.cjs.map +0 -1
- package/introspection/dist/index.js.map +0 -1
- package/json/dist/index.cjs.map +0 -1
- package/json/dist/index.js.map +0 -1
- package/react/dist/index.cjs.map +0 -1
- package/react/dist/index.js.map +0 -1
- package/react-devtools/dist/index.cjs.map +0 -1
- package/react-devtools/dist/index.css.map +0 -1
- package/react-devtools/dist/index.js.map +0 -1
- package/realtime/dist/index.cjs.map +0 -1
- package/realtime/dist/index.js.map +0 -1
- package/realtime-client/dist/index.cjs.map +0 -1
- package/realtime-client/dist/index.js.map +0 -1
- package/realtime-react/dist/index.cjs.map +0 -1
- package/realtime-react/dist/index.js.map +0 -1
- package/realtime-server/dist/index.cjs.map +0 -1
- package/realtime-server/dist/index.js.map +0 -1
- package/realtime-testing/dist/index.cjs.map +0 -1
- package/realtime-testing/dist/index.js.map +0 -1
- package/transceivers/set-rtx/dist/index.cjs.map +0 -1
- package/transceivers/set-rtx/dist/index.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx","../../../anvl/src/object/entries.ts"],"names":["usersOfSockets","clients"],"mappings":"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","sourcesContent":["import * as http from \"http\"\n\nimport { prettyDOM, render } from \"@testing-library/react\"\nimport type { RenderResult } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport {\n\tIMPLICIT,\n\tclearStore,\n\tfindInStore,\n\tgetFromStore,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport * as AR from \"atom.io/react\"\nimport * as RT from \"atom.io/realtime\"\nimport * as RTR from \"atom.io/realtime-react\"\nimport * as RTS from \"atom.io/realtime-server\"\nimport * as Happy from \"happy-dom\"\nimport * as React from \"react\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nimport { recordToEntries } from \"~/packages/anvl/src/object\"\n\nlet testNumber = 0\n\nexport type TestSetupOptions = {\n\tport: number\n\tserver: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\tsocket: ClientSocket\n}\nexport type RealtimeTestClientBuilder = {\n\tdispose: () => void\n\tinit: () => RealtimeTestClient\n}\n\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tdispose: () => void\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => void\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClientBuilder\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClientBuilder>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\t++testNumber\n\tconst silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE)\n\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen(options.port).address()\n\tconst port =\n\t\ttypeof address === `string` ? null : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\n\tconst server = new SocketIO.Server(httpServer).use((socket, next) => {\n\t\tconst { token, username } = socket.handshake.auth\n\t\tif (token === `test` && socket.id) {\n\t\t\tconst socketState = findInStore(RTS.socketAtoms, socket.id, silo.store)\n\t\t\tsetIntoStore(socketState, socket, silo.store)\n\t\t\tconst usersOfSockets = RTS.usersOfSockets.in(silo.store)\n\t\t\tusersOfSockets.relations.set(socket.id, username)\n\t\t\tsetIntoStore(RTS.userIndex, (index) => index.add(username), silo.store)\n\t\t\tsetIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store)\n\t\t\tconsole.log(`${username} connected on ${socket.id}`)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\toptions.server({ socket, silo })\n\t})\n\n\tconst dispose = () => {\n\t\tserver.close()\n\t\tconst roomKeys = getFromStore(RT.roomIndex, silo.store)\n\t\tfor (const roomKey of roomKeys) {\n\t\t\tconst roomState = findInStore(RTS.roomSelectors, roomKey, silo.store)\n\t\t\tconst room = getFromStore(roomState, silo.store)\n\t\t\tif (room && !(room instanceof Promise)) {\n\t\t\t\troom.process.kill()\n\t\t\t}\n\t\t}\n\t\tsilo.store.valueMap.clear()\n\t}\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClientBuilder => {\n\tconst testClient = { dispose: () => {} }\n\tconst init = () => {\n\t\tconst socket: ClientSocket = io(`http://localhost:${port}/`, {\n\t\t\tauth: { token: `test`, username: `${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(name, IMPLICIT.STORE)\n\t\tfor (const [key, value] of silo.store.valueMap.entries()) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tsilo.store.valueMap.set(key, [...value])\n\t\t\t}\n\t\t}\n\n\t\tconst { document } = new Happy.Window()\n\t\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\t\tconst renderResult = render(\n\t\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t\t<RTR.RealtimeProvider socket={socket}>\n\t\t\t\t\t<options.client />\n\t\t\t\t</RTR.RealtimeProvider>\n\t\t\t</AR.StoreProvider>,\n\t\t\t{\n\t\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t\t},\n\t\t)\n\n\t\tconst prettyPrint = () => console.log(prettyDOM(renderResult.container))\n\n\t\tconst dispose = () => {\n\t\t\trenderResult.unmount()\n\t\t\tsocket.disconnect()\n\t\t\tclearStore(silo.store)\n\t\t}\n\t\ttestClient.dispose = dispose\n\n\t\treturn {\n\t\t\tname,\n\t\t\tsilo,\n\t\t\tsocket,\n\t\t\trenderResult,\n\t\t\tprettyPrint,\n\t\t}\n\t}\n\treturn Object.assign(testClient, { init })\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(\n\t\toptions,\n\t\t`CLIENT-${testNumber}`,\n\t\tserver.port,\n\t)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tserver.dispose()\n\t\t\tclient.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = recordToEntries(options.clients).reduce(\n\t\t(clients, [name, client]) => {\n\t\t\tclients[name] = setupRealtimeTestClient(\n\t\t\t\t{ ...options, client },\n\t\t\t\tname,\n\t\t\t\tserver.port,\n\t\t\t)\n\t\t\treturn clients\n\t\t},\n\t\t{} as Record<ClientNames, RealtimeTestClientBuilder>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tserver.dispose()\n\t\t\tfor (const [, client] of recordToEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t},\n\t}\n}\n","export type Entries<K extends keyof any, V> = [key: K, value: V][]\n\nexport const recordToEntries = <K extends keyof any, V>(\n\tobj: Record<K, V>,\n): Entries<K, V> => Object.entries(obj) as Entries<K, V>\n\nexport const entriesToRecord = <K extends keyof any, V>(\n\tentries: Entries<K, V>,\n): Record<K, V> => Object.fromEntries(entries) as Record<K, V>\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx"],"names":["usersOfSockets","clients"],"mappings":"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","sourcesContent":["import * as http from \"http\"\n\nimport { prettyDOM, render } from \"@testing-library/react\"\nimport type { RenderResult } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport {\n\tIMPLICIT,\n\tclearStore,\n\tfindInStore,\n\tgetFromStore,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport * as AR from \"atom.io/react\"\nimport * as RT from \"atom.io/realtime\"\nimport * as RTR from \"atom.io/realtime-react\"\nimport * as RTS from \"atom.io/realtime-server\"\nimport * as Happy from \"happy-dom\"\nimport * as React from \"react\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nimport { recordToEntries } from \"~/packages/anvl/src/object\"\n\nlet testNumber = 0\n\nexport type TestSetupOptions = {\n\tport: number\n\tserver: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\tsocket: ClientSocket\n}\nexport type RealtimeTestClientBuilder = {\n\tdispose: () => void\n\tinit: () => RealtimeTestClient\n}\n\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tdispose: () => void\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => void\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClientBuilder\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClientBuilder>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\t++testNumber\n\tconst silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE)\n\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen(options.port).address()\n\tconst port =\n\t\ttypeof address === `string` ? null : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\n\tconst server = new SocketIO.Server(httpServer).use((socket, next) => {\n\t\tconst { token, username } = socket.handshake.auth\n\t\tif (token === `test` && socket.id) {\n\t\t\tconst socketState = findInStore(RTS.socketAtoms, socket.id, silo.store)\n\t\t\tsetIntoStore(socketState, socket, silo.store)\n\t\t\tconst usersOfSockets = RTS.usersOfSockets.in(silo.store)\n\t\t\tusersOfSockets.relations.set(socket.id, username)\n\t\t\tsetIntoStore(RTS.userIndex, (index) => index.add(username), silo.store)\n\t\t\tsetIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store)\n\t\t\tconsole.log(`${username} connected on ${socket.id}`)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\toptions.server({ socket, silo })\n\t})\n\n\tconst dispose = () => {\n\t\tserver.close()\n\t\tconst roomKeys = getFromStore(RT.roomIndex, silo.store)\n\t\tfor (const roomKey of roomKeys) {\n\t\t\tconst roomState = findInStore(RTS.roomSelectors, roomKey, silo.store)\n\t\t\tconst room = getFromStore(roomState, silo.store)\n\t\t\tif (room && !(room instanceof Promise)) {\n\t\t\t\troom.process.kill()\n\t\t\t}\n\t\t}\n\t\tsilo.store.valueMap.clear()\n\t}\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClientBuilder => {\n\tconst testClient = { dispose: () => {} }\n\tconst init = () => {\n\t\tconst socket: ClientSocket = io(`http://localhost:${port}/`, {\n\t\t\tauth: { token: `test`, username: `${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(name, IMPLICIT.STORE)\n\t\tfor (const [key, value] of silo.store.valueMap.entries()) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tsilo.store.valueMap.set(key, [...value])\n\t\t\t}\n\t\t}\n\n\t\tconst { document } = new Happy.Window()\n\t\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\t\tconst renderResult = render(\n\t\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t\t<RTR.RealtimeProvider socket={socket}>\n\t\t\t\t\t<options.client />\n\t\t\t\t</RTR.RealtimeProvider>\n\t\t\t</AR.StoreProvider>,\n\t\t\t{\n\t\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t\t},\n\t\t)\n\n\t\tconst prettyPrint = () => console.log(prettyDOM(renderResult.container))\n\n\t\tconst dispose = () => {\n\t\t\trenderResult.unmount()\n\t\t\tsocket.disconnect()\n\t\t\tclearStore(silo.store)\n\t\t}\n\t\ttestClient.dispose = dispose\n\n\t\treturn {\n\t\t\tname,\n\t\t\tsilo,\n\t\t\tsocket,\n\t\t\trenderResult,\n\t\t\tprettyPrint,\n\t\t}\n\t}\n\treturn Object.assign(testClient, { init })\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(\n\t\toptions,\n\t\t`CLIENT-${testNumber}`,\n\t\tserver.port,\n\t)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tserver.dispose()\n\t\t\tclient.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = recordToEntries(options.clients).reduce(\n\t\t(clients, [name, client]) => {\n\t\t\tclients[name] = setupRealtimeTestClient(\n\t\t\t\t{ ...options, client },\n\t\t\t\tname,\n\t\t\t\tserver.port,\n\t\t\t)\n\t\t\treturn clients\n\t\t},\n\t\t{} as Record<ClientNames, RealtimeTestClientBuilder>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tserver.dispose()\n\t\t\tfor (const [, client] of recordToEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t},\n\t}\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/set-rtx.ts"],"names":["update","value"],"mappings":"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","sourcesContent":["import type { Lineage, Transceiver, TransceiverMode } from \"atom.io/internal\"\nimport { Subject } from \"atom.io/internal\"\nimport type { Json, Stringified, primitive } from \"atom.io/json\"\nimport { parseJson, stringifyJson } from \"atom.io/json\"\n\nexport type SetUpdate =\n\t| `add:${string}`\n\t| `clear:${string}`\n\t| `del:${string}`\n\t| `tx:${string}`\nexport type NumberedSetUpdate = `${number}=${SetUpdate}`\n\nexport interface SetRTXJson<P extends primitive> extends Json.Object {\n\tmembers: P[]\n\tcache: (NumberedSetUpdate | null)[]\n\tcacheLimit: number\n\tcacheIdx: number\n\tcacheUpdateNumber: number\n}\nexport class SetRTX<P extends primitive>\n\textends Set<P>\n\timplements Transceiver<NumberedSetUpdate>, Lineage\n{\n\tpublic mode: TransceiverMode = `record`\n\tpublic readonly subject = new Subject<SetUpdate>()\n\tpublic cacheLimit = 0\n\tpublic cache: (NumberedSetUpdate | null)[] = []\n\tpublic cacheIdx = -1\n\tpublic cacheUpdateNumber = -1\n\n\tpublic constructor(values?: Iterable<P>, cacheLimit = 0) {\n\t\tsuper(values)\n\t\tif (values instanceof SetRTX) {\n\t\t\tthis.parent = values\n\t\t\tthis.cacheUpdateNumber = values.cacheUpdateNumber\n\t\t}\n\t\tif (cacheLimit) {\n\t\t\tthis.cacheLimit = cacheLimit\n\t\t\tthis.cache = new Array(cacheLimit)\n\t\t\tthis.subscribe(`auto cache`, (update) => {\n\t\t\t\tthis.cacheIdx++\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tthis.cache[this.cacheIdx] = update\n\t\t\t})\n\t\t}\n\t}\n\n\tpublic toJSON(): SetRTXJson<P> {\n\t\treturn {\n\t\t\tmembers: [...this],\n\t\t\tcache: this.cache,\n\t\t\tcacheLimit: this.cacheLimit,\n\t\t\tcacheIdx: this.cacheIdx,\n\t\t\tcacheUpdateNumber: this.cacheUpdateNumber,\n\t\t}\n\t}\n\n\tpublic static fromJSON<P extends primitive>(json: SetRTXJson<P>): SetRTX<P> {\n\t\tconst set = new SetRTX<P>(json.members, json.cacheLimit)\n\t\tset.cache = json.cache\n\t\tset.cacheIdx = json.cacheIdx\n\t\tset.cacheUpdateNumber = json.cacheUpdateNumber\n\t\treturn set\n\t}\n\n\tpublic add(value: P): this {\n\t\tconst result = super.add(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`add:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic clear(): void {\n\t\tconst capturedContents = this.mode === `record` ? [...this] : null\n\t\tsuper.clear()\n\t\tif (capturedContents) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`clear:${JSON.stringify(capturedContents)}`)\n\t\t}\n\t}\n\n\tpublic delete(value: P): boolean {\n\t\tconst result = super.delete(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`del:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic readonly parent: SetRTX<P> | null\n\tpublic child: SetRTX<P> | null = null\n\tpublic transactionUpdates: SetUpdate[] | null = null\n\tpublic transaction(run: (child: SetRTX<P>) => boolean): void {\n\t\tthis.mode = `transaction`\n\t\tthis.transactionUpdates = []\n\t\tthis.child = new SetRTX(this)\n\t\tconst unsubscribe = this.child._subscribe(`transaction`, (update) => {\n\t\t\tthis.transactionUpdates?.push(update)\n\t\t})\n\t\ttry {\n\t\t\tconst shouldCommit = run(this.child)\n\t\t\tif (shouldCommit) {\n\t\t\t\tfor (const update of this.transactionUpdates) {\n\t\t\t\t\tthis.doStep(update)\n\t\t\t\t}\n\t\t\t\tthis.cacheUpdateNumber++\n\t\t\t\tthis.emit(`tx:${this.transactionUpdates.join(`;`)}`)\n\t\t\t}\n\t\t} catch (thrown) {\n\t\t\tconsole.error(`Failed to apply transaction to SetRTX: ${thrown}`)\n\t\t\tthrow thrown\n\t\t} finally {\n\t\t\tunsubscribe()\n\t\t\tthis.child = null\n\t\t\tthis.transactionUpdates = null\n\t\t\tthis.mode = `record`\n\t\t}\n\t}\n\n\tprotected _subscribe(\n\t\tkey: string,\n\t\tfn: (update: SetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, fn)\n\t}\n\tpublic subscribe(\n\t\tkey: string,\n\t\tfn: (update: NumberedSetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, (update) =>\n\t\t\tfn(`${this.cacheUpdateNumber}=${update}`),\n\t\t)\n\t}\n\n\tpublic emit(update: SetUpdate): void {\n\t\tthis.subject.next(update)\n\t}\n\n\tprivate doStep(update: SetUpdate): void {\n\t\tconst typeValueBreak = update.indexOf(`:`)\n\t\tconst type = update.substring(0, typeValueBreak)\n\t\tconst value = update.substring(typeValueBreak + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.add(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `clear`:\n\t\t\t\tthis.clear()\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.delete(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `tx`:\n\t\t\t\tfor (const update of value.split(`;`)) {\n\t\t\t\t\tthis.doStep(update as SetUpdate)\n\t\t\t\t}\n\t\t}\n\t}\n\n\tpublic getUpdateNumber(update: NumberedSetUpdate): number {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\treturn Number(update.substring(0, breakpoint))\n\t}\n\n\tpublic do(update: NumberedSetUpdate): number | `OUT_OF_RANGE` | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tconst eventOffset = updateNumber - this.cacheUpdateNumber\n\t\tconst isFuture = eventOffset > 0\n\t\tif (isFuture) {\n\t\t\tif (eventOffset === 1) {\n\t\t\t\tthis.mode = `playback`\n\t\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\t\tthis.doStep(innerUpdate)\n\t\t\t\tthis.mode = `record`\n\t\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.cacheUpdateNumber + 1\n\t\t}\n\t\tif (Math.abs(eventOffset) < this.cacheLimit) {\n\t\t\tconst eventIdx = this.cacheIdx + eventOffset\n\t\t\tconst cachedUpdate = this.cache[eventIdx]\n\t\t\tif (cachedUpdate === update) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tthis.mode = `playback`\n\t\t\tlet done = false\n\t\t\twhile (!done) {\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tconst update = this.cache[this.cacheIdx]\n\t\t\t\tthis.cacheIdx--\n\t\t\t\tif (!update) {\n\t\t\t\t\treturn `OUT_OF_RANGE`\n\t\t\t\t}\n\t\t\t\tthis.undo(update)\n\t\t\t\tdone = this.cacheIdx === eventIdx - 1\n\t\t\t}\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.doStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\treturn null\n\t\t}\n\t\treturn `OUT_OF_RANGE`\n\t}\n\n\tpublic undoStep(update: SetUpdate): void {\n\t\tconst breakpoint = update.indexOf(`:`)\n\t\tconst type = update.substring(0, breakpoint)\n\t\tconst value = update.substring(breakpoint + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.delete(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.add(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `clear`: {\n\t\t\t\tconst values = JSON.parse(value) as P[]\n\t\t\t\tfor (const value of values) this.add(value)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase `tx`: {\n\t\t\t\tconst updates = value.split(`;`) as SetUpdate[]\n\t\t\t\tfor (let i = updates.length - 1; i >= 0; i--) {\n\t\t\t\t\tthis.undoStep(updates[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic undo(update: NumberedSetUpdate): number | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tif (updateNumber === this.cacheUpdateNumber) {\n\t\t\tthis.mode = `playback`\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.undoStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber--\n\t\t\treturn null\n\t\t}\n\t\treturn this.cacheUpdateNumber\n\t}\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/set-rtx.ts"],"names":["update","value"],"mappings":"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","sourcesContent":["import type { Lineage, Transceiver, TransceiverMode } from \"atom.io/internal\"\nimport { Subject } from \"atom.io/internal\"\nimport type { Json, Stringified, primitive } from \"atom.io/json\"\nimport { parseJson, stringifyJson } from \"atom.io/json\"\n\nexport type SetUpdate =\n\t| `add:${string}`\n\t| `clear:${string}`\n\t| `del:${string}`\n\t| `tx:${string}`\nexport type NumberedSetUpdate = `${number}=${SetUpdate}`\n\nexport interface SetRTXJson<P extends primitive> extends Json.Object {\n\tmembers: P[]\n\tcache: (NumberedSetUpdate | null)[]\n\tcacheLimit: number\n\tcacheIdx: number\n\tcacheUpdateNumber: number\n}\nexport class SetRTX<P extends primitive>\n\textends Set<P>\n\timplements Transceiver<NumberedSetUpdate>, Lineage\n{\n\tpublic mode: TransceiverMode = `record`\n\tpublic readonly subject = new Subject<SetUpdate>()\n\tpublic cacheLimit = 0\n\tpublic cache: (NumberedSetUpdate | null)[] = []\n\tpublic cacheIdx = -1\n\tpublic cacheUpdateNumber = -1\n\n\tpublic constructor(values?: Iterable<P>, cacheLimit = 0) {\n\t\tsuper(values)\n\t\tif (values instanceof SetRTX) {\n\t\t\tthis.parent = values\n\t\t\tthis.cacheUpdateNumber = values.cacheUpdateNumber\n\t\t}\n\t\tif (cacheLimit) {\n\t\t\tthis.cacheLimit = cacheLimit\n\t\t\tthis.cache = new Array(cacheLimit)\n\t\t\tthis.subscribe(`auto cache`, (update) => {\n\t\t\t\tthis.cacheIdx++\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tthis.cache[this.cacheIdx] = update\n\t\t\t})\n\t\t}\n\t}\n\n\tpublic toJSON(): SetRTXJson<P> {\n\t\treturn {\n\t\t\tmembers: [...this],\n\t\t\tcache: this.cache,\n\t\t\tcacheLimit: this.cacheLimit,\n\t\t\tcacheIdx: this.cacheIdx,\n\t\t\tcacheUpdateNumber: this.cacheUpdateNumber,\n\t\t}\n\t}\n\n\tpublic static fromJSON<P extends primitive>(json: SetRTXJson<P>): SetRTX<P> {\n\t\tconst set = new SetRTX<P>(json.members, json.cacheLimit)\n\t\tset.cache = json.cache\n\t\tset.cacheIdx = json.cacheIdx\n\t\tset.cacheUpdateNumber = json.cacheUpdateNumber\n\t\treturn set\n\t}\n\n\tpublic add(value: P): this {\n\t\tconst result = super.add(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`add:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic clear(): void {\n\t\tconst capturedContents = this.mode === `record` ? [...this] : null\n\t\tsuper.clear()\n\t\tif (capturedContents) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`clear:${JSON.stringify(capturedContents)}`)\n\t\t}\n\t}\n\n\tpublic delete(value: P): boolean {\n\t\tconst result = super.delete(value)\n\t\tif (this.mode === `record`) {\n\t\t\tthis.cacheUpdateNumber++\n\t\t\tthis.emit(`del:${stringifyJson<P>(value)}`)\n\t\t}\n\t\treturn result\n\t}\n\n\tpublic readonly parent: SetRTX<P> | null\n\tpublic child: SetRTX<P> | null = null\n\tpublic transactionUpdates: SetUpdate[] | null = null\n\tpublic transaction(run: (child: SetRTX<P>) => boolean): void {\n\t\tthis.mode = `transaction`\n\t\tthis.transactionUpdates = []\n\t\tthis.child = new SetRTX(this)\n\t\tconst unsubscribe = this.child._subscribe(`transaction`, (update) => {\n\t\t\tthis.transactionUpdates?.push(update)\n\t\t})\n\t\ttry {\n\t\t\tconst shouldCommit = run(this.child)\n\t\t\tif (shouldCommit) {\n\t\t\t\tfor (const update of this.transactionUpdates) {\n\t\t\t\t\tthis.doStep(update)\n\t\t\t\t}\n\t\t\t\tthis.cacheUpdateNumber++\n\t\t\t\tthis.emit(`tx:${this.transactionUpdates.join(`;`)}`)\n\t\t\t}\n\t\t} catch (thrown) {\n\t\t\tconsole.error(`Failed to apply transaction to SetRTX: ${thrown}`)\n\t\t\tthrow thrown\n\t\t} finally {\n\t\t\tunsubscribe()\n\t\t\tthis.child = null\n\t\t\tthis.transactionUpdates = null\n\t\t\tthis.mode = `record`\n\t\t}\n\t}\n\n\tprotected _subscribe(\n\t\tkey: string,\n\t\tfn: (update: SetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, fn)\n\t}\n\tpublic subscribe(\n\t\tkey: string,\n\t\tfn: (update: NumberedSetUpdate) => void,\n\t): () => void {\n\t\treturn this.subject.subscribe(key, (update) =>\n\t\t\tfn(`${this.cacheUpdateNumber}=${update}`),\n\t\t)\n\t}\n\n\tpublic emit(update: SetUpdate): void {\n\t\tthis.subject.next(update)\n\t}\n\n\tprivate doStep(update: SetUpdate): void {\n\t\tconst typeValueBreak = update.indexOf(`:`)\n\t\tconst type = update.substring(0, typeValueBreak)\n\t\tconst value = update.substring(typeValueBreak + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.add(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `clear`:\n\t\t\t\tthis.clear()\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.delete(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `tx`:\n\t\t\t\tfor (const update of value.split(`;`)) {\n\t\t\t\t\tthis.doStep(update as SetUpdate)\n\t\t\t\t}\n\t\t}\n\t}\n\n\tpublic getUpdateNumber(update: NumberedSetUpdate): number {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\treturn Number(update.substring(0, breakpoint))\n\t}\n\n\tpublic do(update: NumberedSetUpdate): number | `OUT_OF_RANGE` | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tconst eventOffset = updateNumber - this.cacheUpdateNumber\n\t\tconst isFuture = eventOffset > 0\n\t\tif (isFuture) {\n\t\t\tif (eventOffset === 1) {\n\t\t\t\tthis.mode = `playback`\n\t\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\t\tthis.doStep(innerUpdate)\n\t\t\t\tthis.mode = `record`\n\t\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.cacheUpdateNumber + 1\n\t\t}\n\t\tif (Math.abs(eventOffset) < this.cacheLimit) {\n\t\t\tconst eventIdx = this.cacheIdx + eventOffset\n\t\t\tconst cachedUpdate = this.cache[eventIdx]\n\t\t\tif (cachedUpdate === update) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tthis.mode = `playback`\n\t\t\tlet done = false\n\t\t\twhile (!done) {\n\t\t\t\tthis.cacheIdx %= this.cacheLimit\n\t\t\t\tconst update = this.cache[this.cacheIdx]\n\t\t\t\tthis.cacheIdx--\n\t\t\t\tif (!update) {\n\t\t\t\t\treturn `OUT_OF_RANGE`\n\t\t\t\t}\n\t\t\t\tthis.undo(update)\n\t\t\t\tdone = this.cacheIdx === eventIdx - 1\n\t\t\t}\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.doStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber = updateNumber\n\t\t\treturn null\n\t\t}\n\t\treturn `OUT_OF_RANGE`\n\t}\n\n\tpublic undoStep(update: SetUpdate): void {\n\t\tconst breakpoint = update.indexOf(`:`)\n\t\tconst type = update.substring(0, breakpoint)\n\t\tconst value = update.substring(breakpoint + 1)\n\t\tswitch (type) {\n\t\t\tcase `add`:\n\t\t\t\tthis.delete(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `del`:\n\t\t\t\tthis.add(parseJson(value as Stringified<P>))\n\t\t\t\tbreak\n\t\t\tcase `clear`: {\n\t\t\t\tconst values = JSON.parse(value) as P[]\n\t\t\t\tfor (const value of values) this.add(value)\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase `tx`: {\n\t\t\t\tconst updates = value.split(`;`) as SetUpdate[]\n\t\t\t\tfor (let i = updates.length - 1; i >= 0; i--) {\n\t\t\t\t\tthis.undoStep(updates[i])\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic undo(update: NumberedSetUpdate): number | null {\n\t\tconst breakpoint = update.indexOf(`=`)\n\t\tconst updateNumber = Number(update.substring(0, breakpoint))\n\t\tif (updateNumber === this.cacheUpdateNumber) {\n\t\t\tthis.mode = `playback`\n\t\t\tconst innerUpdate = update.substring(breakpoint + 1) as SetUpdate\n\t\t\tthis.undoStep(innerUpdate)\n\t\t\tthis.mode = `record`\n\t\t\tthis.cacheUpdateNumber--\n\t\t\treturn null\n\t\t}\n\t\treturn this.cacheUpdateNumber\n\t}\n}\n"]}
|