From 7152f21129917853da5f388269712581d89f722f Mon Sep 17 00:00:00 2001 From: Richard Date: Fri, 25 Oct 2024 19:13:06 -0700 Subject: [PATCH] refactor: replace all references to molecules --- src/charm-sync/src/index.d.ts | 29 +++++++++++++++++------------ src/charm/src/index.d.ts | 8 ++++++++ src/charm/src/init.luau | 2 +- src/charm/src/observe.luau | 6 +++--- src/charm/src/store.luau | 14 +++++++------- src/charm/src/subscribe.luau | 24 ++++++++++++------------ src/react/src/index.d.ts | 10 +++++----- src/react/src/init.luau | 14 +++++++------- src/vide/src/index.d.ts | 6 +++--- src/vide/src/init.luau | 8 ++++---- tests/react/useAtom.spec.luau | 2 +- tests/vide/useAtom.spec.luau | 2 +- 12 files changed, 69 insertions(+), 56 deletions(-) diff --git a/src/charm-sync/src/index.d.ts b/src/charm-sync/src/index.d.ts index ef2b8d3..33168dd 100644 --- a/src/charm-sync/src/index.d.ts +++ b/src/charm-sync/src/index.d.ts @@ -1,4 +1,4 @@ -import { Atom, Molecule } from "@rbxts/charm"; +import { Atom, Selector } from "@rbxts/charm"; export = CharmSync; export as namespace CharmSync; @@ -8,13 +8,18 @@ type Cleanup = () => void; declare namespace CharmSync { type AtomMap = Record>; - type MoleculeMap = Record>; + /** + * @deprecated Use `SelectorMap` instead. + */ + type MoleculeMap = Record>; + + type SelectorMap = Record>; /** - * Recursively infers the type of the state produced by a map of molecules. + * Infers the type of the return values produced by a map of functions. */ type StateOfMap = { - [P in keyof T]: T[P] extends Molecule ? State : never; + [P in keyof T]: T[P] extends Selector ? State : never; }; /** @@ -45,7 +50,7 @@ declare namespace CharmSync { * @param options The atoms to synchronize with the client. * @returns A `ServerSyncer` object. */ - function server(options: ServerOptions): ServerSyncer; + function server(options: ServerOptions): ServerSyncer; /** * Checks whether a value is `None`. If `true`, the value is scheduled to be @@ -90,9 +95,9 @@ declare namespace CharmSync { * A payload that can be sent from the server to the client to synchronize * state between the two. */ - type SyncPayload = - | { type: "init"; data: StateOfMap } - | { type: "patch"; data: SyncPatch> }; + type SyncPayload = + | { type: "init"; data: StateOfMap } + | { type: "patch"; data: SyncPatch> }; interface ClientOptions { /** @@ -106,11 +111,11 @@ declare namespace CharmSync { ignoreUnhydrated?: boolean; } - interface ServerOptions { + interface ServerOptions { /** * The atoms to synchronize with the client. */ - atoms: Molecules; + atoms: Selectors; /** * The interval at which to send patches to the client, in seconds. * Defaults to `0` (patches are sent up to once per frame). Set to a @@ -139,7 +144,7 @@ declare namespace CharmSync { sync(...payloads: SyncPayload[]): void; } - interface ServerSyncer { + interface ServerSyncer { /** * Sets up a subscription to each atom that schedules a patch to be sent to * the client whenever the state changes. When a change occurs, the `callback` @@ -151,7 +156,7 @@ declare namespace CharmSync { * @param callback The function to call when the state changes. * @returns A cleanup function that unsubscribes all listeners. */ - connect(callback: (player: Player, ...payloads: SyncPayload[]) => void): Cleanup; + connect(callback: (player: Player, ...payloads: SyncPayload[]) => void): Cleanup; /** * Hydrates the client's state with the server's state. This should be * called when a player joins the game and requires the server's state. diff --git a/src/charm/src/index.d.ts b/src/charm/src/index.d.ts index d70057a..69a9ca6 100644 --- a/src/charm/src/index.d.ts +++ b/src/charm/src/index.d.ts @@ -37,6 +37,14 @@ declare namespace Charm { */ type Selector = () => State; + /** + * A function that depends on one or more atoms and produces a value. Can be + * used to derive state from atoms. + * + * @returns The current state. + */ + type Molecule = Selector; + /** * Infers the type of the state produced by the given function. */ diff --git a/src/charm/src/init.luau b/src/charm/src/init.luau index cf144e3..4bc1a8c 100644 --- a/src/charm/src/init.luau +++ b/src/charm/src/init.luau @@ -8,8 +8,8 @@ local subscribe = require(script.subscribe) local types = require(script.types) export type Atom = types.Atom -export type Molecule = types.Selector export type Selector = types.Selector +export type Molecule = types.Selector export type SyncPayload = types.SyncPayload return { diff --git a/src/charm/src/observe.luau b/src/charm/src/observe.luau index d2cfeb4..5bb0296 100644 --- a/src/charm/src/observe.luau +++ b/src/charm/src/observe.luau @@ -9,15 +9,15 @@ local function noop() end cleans up the instance when the item is removed. Returns a cleanup function that unsubscribes all instances. - @param molecule The atom or molecule to observe. + @param callback The atom or selector to observe. @param factory The function that tracks the lifecycle of each item. @return A function that unsubscribes all instances. ]=] -local function observe(molecule: Selector<{ [K]: V }>, factory: (value: V, key: K) -> (() -> ())?): () -> () +local function observe(callback: Selector<{ [K]: V }>, factory: (value: V, key: K) -> (() -> ())?): () -> () local connections: { [K]: () -> () } = {} local unsubscribe = effect(function() - local state = molecule() + local state = callback() for key, disconnect in next, connections do if state[key] == nil then diff --git a/src/charm/src/store.luau b/src/charm/src/store.luau index 68bea45..488ae11 100644 --- a/src/charm/src/store.luau +++ b/src/charm/src/store.luau @@ -100,8 +100,8 @@ end Returns the result of the function without subscribing to changes. If a non-function value is provided, it is returned as is. - @param molecule The atom or molecule to get the state of. - @param args Arguments to pass to the molecule. + @param callback The atom or selector to get the state of. + @param args Arguments to pass to the function. @return The current state. ]=] local function peek(callback: ((U...) -> T) | T, ...: U...): T @@ -128,12 +128,12 @@ end Captures all atoms that are read during the function call and returns them along with the result of the function. Useful for tracking dependencies. - @param molecule The function to run. + @param callback The function to run. @return A tuple containing the captured atoms and the result of the function. ]=] -local function capture(molecule: () -> T): (Set>, T) - if listeners[molecule] then - return { [molecule] = true }, peek(molecule) +local function capture(callback: () -> T): (Set>, T) + if listeners[callback] then + return { [callback] = true }, peek(callback) end local dependencies: Set> = {} @@ -141,7 +141,7 @@ local function capture(molecule: () -> T): (Set>, T) capturing.index += 1 capturing.stack[capturing.index] = dependencies - local result = try(molecule, function() + local result = try(callback, function() capturing.stack[capturing.index] = nil capturing.index -= 1 end) diff --git a/src/charm/src/subscribe.luau b/src/charm/src/subscribe.luau index d34df22..0286d68 100644 --- a/src/charm/src/subscribe.luau +++ b/src/charm/src/subscribe.luau @@ -3,39 +3,39 @@ local types = require(script.Parent.types) type Selector = types.Selector --[=[ - Subscribes to changes in the given atom or molecule. The callback is + Subscribes to changes in the given atom or selector. The callback is called with the current state and the previous state immediately after a change occurs. - @param molecule The atom or molecule to subscribe to. - @param callback The function to call when the state changes. + @param callback The atom or selector to subscribe to. + @param listener The function to call when the state changes. @return A function that unsubscribes the callback. ]=] -local function subscribe(molecule: Selector, callback: (state: T, prev: T) -> ()): () -> () - local dependencies, state = store.capture(molecule) +local function subscribe(callback: Selector, listener: (state: T, prev: T) -> ()): () -> () + local dependencies, state = store.capture(callback) local disconnected = false - local function listener() + local function handler() local prevState = state - store.disconnect(dependencies, listener) - dependencies, state = store.capture(molecule) + store.disconnect(dependencies, handler) + dependencies, state = store.capture(callback) if not disconnected then - store.connect(dependencies, listener) + store.connect(dependencies, handler) end if state ~= prevState then - callback(state, prevState) + listener(state, prevState) end end - store.connect(dependencies, listener) + store.connect(dependencies, handler) return function() if not disconnected then disconnected = true - store.disconnect(dependencies, listener) + store.disconnect(dependencies, handler) end end end diff --git a/src/react/src/index.d.ts b/src/react/src/index.d.ts index abf0fb3..e3eb917 100644 --- a/src/react/src/index.d.ts +++ b/src/react/src/index.d.ts @@ -1,15 +1,15 @@ -import { Molecule } from "@rbxts/charm"; +import { Selector } from "@rbxts/charm"; /** - * A hook that subscribes to changes in the given atom or molecule. The + * A hook that subscribes to changes in the given atom or selector. The * component is re-rendered whenever the state changes. * * If the `dependencies` array is provided, the subscription to the atom or - * molecule is re-created whenever the dependencies change. Otherwise, the + * selector is re-created whenever the dependencies change. Otherwise, the * subscription is created once when the component is mounted. * - * @param molecule The atom or molecule to subscribe to. + * @param callback The atom or selector to subscribe to. * @param dependencies An array of values that the subscription depends on. * @returns The current state. */ -export function useAtom(molecule: Molecule, dependencies?: unknown[]): State; +export function useAtom(callback: Selector, dependencies?: unknown[]): State; diff --git a/src/react/src/init.luau b/src/react/src/init.luau index 5bcafba..e200551 100644 --- a/src/react/src/init.luau +++ b/src/react/src/init.luau @@ -4,23 +4,23 @@ local React = if script.Parent:FindFirstChild("react") else require(script.Parent.React) --[=[ - A hook that subscribes to changes in the given atom or molecule. The + A hook that subscribes to changes in the given atom or selector. The component is re-rendered whenever the state changes. If the `dependencies` array is provided, the subscription to the atom or - molecule is re-created whenever the dependencies change. Otherwise, the + selector is re-created whenever the dependencies change. Otherwise, the subscription is created once when the component is mounted. - @param molecule The atom or molecule to subscribe to. + @param callback The atom or selector to subscribe to. @param dependencies An array of values that the subscription depends on. @return The current state. ]=] -local function useAtom(molecule: Charm.Molecule, dependencies: { any }?): State - local state, setState = React.useState(molecule) +local function useAtom(callback: Charm.Selector, dependencies: { any }?): State + local state, setState = React.useState(callback) React.useEffect(function() - setState(molecule()) - return Charm.subscribe(molecule, setState) + setState(callback()) + return Charm.subscribe(callback, setState) end, dependencies or {}) return state diff --git a/src/vide/src/index.d.ts b/src/vide/src/index.d.ts index 77e8612..21ace65 100644 --- a/src/vide/src/index.d.ts +++ b/src/vide/src/index.d.ts @@ -1,9 +1,9 @@ -import { Molecule } from "@rbxts/charm"; +import { Selector } from "@rbxts/charm"; /** * Subscribes to the state of an atom and returns a Vide source. * - * @param molecule The atom or molecule to subscribe to. + * @param callback The atom or selector to subscribe to. * @returns The reactive source. */ -export function useAtom(atom: Molecule): () => T; +export function useAtom(callback: Selector): () => T; diff --git a/src/vide/src/init.luau b/src/vide/src/init.luau index d311ce6..605fdd8 100644 --- a/src/vide/src/init.luau +++ b/src/vide/src/init.luau @@ -6,12 +6,12 @@ local Vide = if script.Parent:FindFirstChild("vide") --[=[ Subscribes to the state of an atom and returns a Vide source. - @param molecule The atom or molecule to subscribe to. + @param callback The atom or selector to subscribe to. @return The reactive source. ]=] -local function useAtom(molecule: () -> State): State - local state = Vide.source(molecule()) - local unsubscribe = Charm.subscribe(molecule, function(value) +local function useAtom(callback: () -> State): State + local state = Vide.source(callback()) + local unsubscribe = Charm.subscribe(callback, function(value) task.spawn(state, value) end) diff --git a/tests/react/useAtom.spec.luau b/tests/react/useAtom.spec.luau index bb94715..5476f28 100644 --- a/tests/react/useAtom.spec.luau +++ b/tests/react/useAtom.spec.luau @@ -17,7 +17,7 @@ return function() expect(hook.result).to.equal(1) end) - it("accepts a molecule", function() + it("accepts a selector", function() local state = atom(0) local hook = renderHook(function() return useAtom(function() diff --git a/tests/vide/useAtom.spec.luau b/tests/vide/useAtom.spec.luau index 6b8c66a..cc4dd40 100644 --- a/tests/vide/useAtom.spec.luau +++ b/tests/vide/useAtom.spec.luau @@ -20,7 +20,7 @@ return function() cleanup() end) - it("accepts a molecule", function() + it("accepts a selector", function() local state = atom(0) local source local cleanup = root(function()