mirror of
https://github.com/littensy/charm.git
synced 2026-10-22 12:41:37 +00:00
refactor: rename Source to Molecule
This commit is contained in:
parent
f2ec300204
commit
0046af5598
11 changed files with 60 additions and 50 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
local store = require(script.Parent.store)
|
local store = require(script.Parent.store)
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
|
local unwrap = require(script.Parent.unwrap)
|
||||||
type Atom<T> = types.Atom<T>
|
type Atom<T> = types.Atom<T>
|
||||||
type AtomOptions<T> = types.AtomOptions<T>
|
type AtomOptions<T> = types.AtomOptions<T>
|
||||||
|
|
||||||
|
|
@ -15,7 +16,14 @@ local function atom<T>(state: T, options: AtomOptions<T>?): Atom<T>
|
||||||
return state
|
return state
|
||||||
end
|
end
|
||||||
|
|
||||||
local nextState = if type(...) == "function" then (...)(state) else ...
|
local nextState = ...
|
||||||
|
|
||||||
|
if type(nextState) == "function" then
|
||||||
|
-- Atoms called in a function should not be included as dependencies
|
||||||
|
nextState = unwrap(function()
|
||||||
|
return nextState(state)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
if state ~= nextState and not (equals and equals(state, nextState)) then
|
if state ~= nextState and not (equals and equals(state, nextState)) then
|
||||||
state = nextState
|
state = nextState
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
local store = require(script.Parent.store)
|
local store = require(script.Parent.store)
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
type Atom<T> = types.Atom<T>
|
type Atom<T> = types.Atom<T>
|
||||||
type Source<T> = types.Source<T>
|
type Molecule<T> = types.Molecule<T>
|
||||||
|
|
||||||
local function capture<T>(source: Source<T>): ({ [Atom<any>]: true }, T)
|
local function capture<T>(molecule: Molecule<T>): ({ [Atom<any>]: true }, T)
|
||||||
if store.listeners[source] then
|
if store.listeners[molecule] then
|
||||||
return { [source] = true }, source()
|
return { [molecule] = true }, molecule()
|
||||||
end
|
end
|
||||||
|
|
||||||
store.setCapturing(true)
|
store.setCapturing(true)
|
||||||
local success, result = pcall(source)
|
local success, result = pcall(molecule)
|
||||||
store.setCapturing(false)
|
store.setCapturing(false)
|
||||||
|
|
||||||
local dependencies = table.clone(store.captured)
|
local dependencies = table.clone(store.captured)
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,16 @@ local store = require(script.Parent.store)
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
type Atom<T> = types.Atom<T>
|
type Atom<T> = types.Atom<T>
|
||||||
type AtomOptions<T> = types.AtomOptions<T>
|
type AtomOptions<T> = types.AtomOptions<T>
|
||||||
type Source<T> = types.Source<T>
|
type Molecule<T> = types.Molecule<T>
|
||||||
|
|
||||||
local function derive<T>(source: Source<T>, options: AtomOptions<T>?): Source<T>
|
local function derive<T>(molecule: Molecule<T>, options: AtomOptions<T>?): Molecule<T>
|
||||||
local atoms, state = capture(source)
|
local atoms, state = capture(molecule)
|
||||||
local derived = atom(state, options)
|
local derived = atom(state, options)
|
||||||
local derivedRef = setmetatable({ current = derived }, { __mode = "v" })
|
local derivedRef = setmetatable({ current = derived }, { __mode = "v" })
|
||||||
|
|
||||||
local function listener()
|
local function listener()
|
||||||
if derivedRef.current then
|
if derivedRef.current then
|
||||||
derivedRef.current(source())
|
derivedRef.current(molecule())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
local capture = require(script.Parent.capture)
|
local capture = require(script.Parent.capture)
|
||||||
local store = require(script.Parent.store)
|
local store = require(script.Parent.store)
|
||||||
|
|
||||||
local function effect(source: () -> nil): () -> ()
|
local function effect(molecule: () -> nil): () -> ()
|
||||||
local atoms = capture(source)
|
local atoms = capture(molecule)
|
||||||
|
|
||||||
local function listener()
|
local function listener()
|
||||||
source()
|
molecule()
|
||||||
end
|
end
|
||||||
|
|
||||||
for atom in atoms do
|
for atom in atoms do
|
||||||
|
|
|
||||||
43
src/index.d.ts
vendored
43
src/index.d.ts
vendored
|
|
@ -9,12 +9,12 @@ type AnyMap<K, V> =
|
||||||
| (K extends string | number | symbol ? { readonly [Key in K]: V } : never);
|
| (K extends string | number | symbol ? { readonly [Key in K]: V } : never);
|
||||||
|
|
||||||
declare namespace Charm {
|
declare namespace Charm {
|
||||||
interface Atom<T> extends Source<T> {
|
interface Atom<State> extends Molecule<State> {
|
||||||
readonly __nominal: unique symbol;
|
readonly __nominal: unique symbol;
|
||||||
(state: T | ((prev: T) => T)): void;
|
(state: State | ((prev: State) => State)): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Source<T> = () => T;
|
type Molecule<State> = () => State;
|
||||||
|
|
||||||
interface AtomOptions<State> {
|
interface AtomOptions<State> {
|
||||||
equals?: (prev: State, next: State) => boolean;
|
equals?: (prev: State, next: State) => boolean;
|
||||||
|
|
@ -24,52 +24,55 @@ declare namespace Charm {
|
||||||
|
|
||||||
function isAtom(value: unknown): value is Atom<any>;
|
function isAtom(value: unknown): value is Atom<any>;
|
||||||
|
|
||||||
function derive<State>(atom: Source<State>, options?: AtomOptions<State>): Source<State>;
|
function derive<State>(molecule: Molecule<State>, options?: AtomOptions<State>): Molecule<State>;
|
||||||
|
|
||||||
function subscribe<State>(atom: Source<State>, callback: (state: State, prev: State) => void): Cleanup;
|
function subscribe<State>(molecule: Molecule<State>, callback: (state: State, prev: State) => void): Cleanup;
|
||||||
|
|
||||||
function effect(callback: Source<void>): Cleanup;
|
function effect(callback: Molecule<void>): Cleanup;
|
||||||
|
|
||||||
function unwrap<State>(atom: State | Source<State>): State;
|
function unwrap<State>(molecule: State | Molecule<State>): State;
|
||||||
|
|
||||||
function capture<State>(atom: Source<State>): LuaTuple<[captured: Set<Atom<unknown>>, state: State]>;
|
function capture<State>(molecule: Molecule<State>): LuaTuple<[captured: Set<Atom<unknown>>, state: State]>;
|
||||||
|
|
||||||
function observe<Item>(
|
function observe<Item>(
|
||||||
atom: Source<readonly Item[]>,
|
molecule: Molecule<readonly Item[]>,
|
||||||
factory: (item: Item, index: number) => Cleanup | void,
|
factory: (item: Item, index: number) => Cleanup | void,
|
||||||
): Cleanup;
|
): Cleanup;
|
||||||
|
|
||||||
function observe<Key, Item>(
|
function observe<Key, Item>(
|
||||||
atom: Source<AnyMap<Key, Item>>,
|
molecule: Molecule<AnyMap<Key, Item>>,
|
||||||
factory: (item: Item, key: Key) => Cleanup | void,
|
factory: (item: Item, key: Key) => Cleanup | void,
|
||||||
): Cleanup;
|
): Cleanup;
|
||||||
|
|
||||||
function map<V0, K1, V1>(
|
function map<V0, K1, V1>(
|
||||||
atom: Source<readonly V0[]>,
|
molecule: Molecule<readonly V0[]>,
|
||||||
mapper: (value: V0, index: number) => LuaTuple<[value: V1 | undefined, key: K1]>,
|
mapper: (value: V0, index: number) => LuaTuple<[value: V1 | undefined, key: K1]>,
|
||||||
): Source<ReadonlyMap<K1, V1>>;
|
): Molecule<ReadonlyMap<K1, V1>>;
|
||||||
|
|
||||||
function map<V0, V1>(atom: Source<readonly V0[]>, mapper: (value: V0, index: number) => V1): Source<readonly V1[]>;
|
function map<V0, V1>(
|
||||||
|
molecule: Molecule<readonly V0[]>,
|
||||||
|
mapper: (value: V0, index: number) => V1,
|
||||||
|
): Molecule<readonly V1[]>;
|
||||||
|
|
||||||
function map<K0, V0, K1 = K0, V1 = V0>(
|
function map<K0, V0, K1 = K0, V1 = V0>(
|
||||||
atom: Source<AnyMap<K0, V0>>,
|
molecule: Molecule<AnyMap<K0, V0>>,
|
||||||
mapper: (value: V0, key: K0) => LuaTuple<[value: V1 | undefined, key: K1]> | V1,
|
mapper: (value: V0, key: K0) => LuaTuple<[value: V1 | undefined, key: K1]> | V1,
|
||||||
): Source<ReadonlyMap<K1, V1>>;
|
): Molecule<ReadonlyMap<K1, V1>>;
|
||||||
|
|
||||||
// React
|
// React
|
||||||
|
|
||||||
function useAtomState<State>(atom: Source<State>): State;
|
function useAtomState<State>(molecule: Molecule<State>): State;
|
||||||
|
|
||||||
function useAtomState<State, Result>(atom: Source<State>, selector: (state: State) => Result): Result;
|
function useAtomState<State, Result>(molecule: Molecule<State>, selector: (state: State) => Result): Result;
|
||||||
|
|
||||||
function useSetAtom<State>(atom: Source<State>): (state: State | ((prev: State) => State)) => void;
|
function useSetAtom<State>(molecule: Molecule<State>): (state: State | ((prev: State) => State)) => void;
|
||||||
|
|
||||||
function useAtom<State>(
|
function useAtom<State>(
|
||||||
atom: Source<State>,
|
molecule: Molecule<State>,
|
||||||
): LuaTuple<[state: State, setState: (state: State | ((prev: State) => State)) => void]>;
|
): LuaTuple<[state: State, setState: (state: State | ((prev: State) => State)) => void]>;
|
||||||
|
|
||||||
function useAtom<State, Result>(
|
function useAtom<State, Result>(
|
||||||
atom: Source<State>,
|
molecule: Molecule<State>,
|
||||||
selector: (state: State) => Result,
|
selector: (state: State) => Result,
|
||||||
): LuaTuple<[state: Result, setState: (state: Result | ((prev: Result) => Result)) => void]>;
|
): LuaTuple<[state: Result, setState: (state: Result | ((prev: Result) => Result)) => void]>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ local types = require(script.types)
|
||||||
local unwrap = require(script.unwrap)
|
local unwrap = require(script.unwrap)
|
||||||
|
|
||||||
export type Atom<State> = types.Atom<State>
|
export type Atom<State> = types.Atom<State>
|
||||||
export type Source<State> = types.Source<State>
|
export type Molecule<State> = types.Molecule<State>
|
||||||
export type SyncPayload = types.SyncPayload
|
export type SyncPayload = types.SyncPayload
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
14
src/map.luau
14
src/map.luau
|
|
@ -2,14 +2,14 @@ local atom = require(script.Parent.atom)
|
||||||
local subscribe = require(script.Parent.subscribe)
|
local subscribe = require(script.Parent.subscribe)
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
type Atom<T> = types.Atom<T>
|
type Atom<T> = types.Atom<T>
|
||||||
type Source<T> = types.Source<T>
|
type Molecule<T> = types.Molecule<T>
|
||||||
|
|
||||||
type Map =
|
type Map =
|
||||||
(<K0, V0, K1, V1>(atom: Source<{ [K0]: V0 }>, mapper: (V0, K0) -> (V1?, K1)) -> Source<{ [K1]: V1 }>)
|
(<K0, V0, K1, V1>(fn: Molecule<{ [K0]: V0 }>, mapper: (V0, K0) -> (V1?, K1)) -> Molecule<{ [K1]: V1 }>)
|
||||||
& (<K0, V0, V1>(atom: Source<{ [K0]: V0 }>, mapper: (V0, K0) -> V1?) -> Source<{ [K0]: V1 }>)
|
& (<K0, V0, V1>(fn: Molecule<{ [K0]: V0 }>, mapper: (V0, K0) -> V1?) -> Molecule<{ [K0]: V1 }>)
|
||||||
& (<K0, V0, K1, V1>(atom: Source<{ [K0]: V0 }>, mapper: (V0, K0) -> (V1?, K1?)) -> Source<{ [K1]: V1 }>)
|
& (<K0, V0, K1, V1>(fn: Molecule<{ [K0]: V0 }>, mapper: (V0, K0) -> (V1?, K1?)) -> Molecule<{ [K1]: V1 }>)
|
||||||
|
|
||||||
local function map<K0, V0, K1, V1>(itemsAtom: Source<{ [K0]: V0 }>, mapper: (V0, K0) -> (V1?, K1?)): Source<{ [K1]: V1 }>
|
local function map<K0, V0, K1, V1>(getItems: Molecule<{ [K0]: V0 }>, mapper: (V0, K0) -> (V1?, K1?)): Molecule<{ [K1]: V1 }>
|
||||||
local mappedAtom = atom({})
|
local mappedAtom = atom({})
|
||||||
local mappedAtomRef = setmetatable({ current = mappedAtom }, { __mode = "v" })
|
local mappedAtomRef = setmetatable({ current = mappedAtom }, { __mode = "v" })
|
||||||
local prevMappedItems: { [K1]: V1 } = {}
|
local prevMappedItems: { [K1]: V1 } = {}
|
||||||
|
|
@ -45,8 +45,8 @@ local function map<K0, V0, K1, V1>(itemsAtom: Source<{ [K0]: V0 }>, mapper: (V0,
|
||||||
mappedAtom(mappedItems)
|
mappedAtom(mappedItems)
|
||||||
end
|
end
|
||||||
|
|
||||||
unsubscribe = subscribe(itemsAtom, listener)
|
unsubscribe = subscribe(getItems, listener)
|
||||||
listener(itemsAtom())
|
listener(getItems())
|
||||||
|
|
||||||
return mappedAtom
|
return mappedAtom
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
local effect = require(script.Parent.effect)
|
local effect = require(script.Parent.effect)
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
type Source<T> = types.Source<T>
|
type Molecule<T> = types.Molecule<T>
|
||||||
|
|
||||||
local function observe<K, V>(source: Source<{ [K]: V }>, factory: (value: V, key: K) -> () -> ()): () -> ()
|
local function observe<K, V>(molecule: Molecule<{ [K]: V }>, factory: (value: V, key: K) -> () -> ()): () -> ()
|
||||||
local connections: { [K]: () -> () } = {}
|
local connections: { [K]: () -> () } = {}
|
||||||
|
|
||||||
local unsubscribe = effect(function()
|
local unsubscribe = effect(function()
|
||||||
local state = source()
|
local state = molecule()
|
||||||
|
|
||||||
for key, disconnect in connections do
|
for key, disconnect in connections do
|
||||||
if state[key] == nil then
|
if state[key] == nil then
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
type Atom<T> = types.Atom<T>
|
type Atom<T> = types.Atom<T>
|
||||||
type Source<T> = types.Source<T>
|
|
||||||
type WeakMap<K, V> = types.WeakMap<K, V>
|
type WeakMap<K, V> = types.WeakMap<K, V>
|
||||||
|
|
||||||
local listeners: WeakMap<Atom<any>, WeakMap<() -> (), unknown>> = setmetatable({}, { __mode = "k" })
|
local listeners: WeakMap<Atom<any>, WeakMap<() -> (), unknown>> = setmetatable({}, { __mode = "k" })
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
local capture = require(script.Parent.capture)
|
local capture = require(script.Parent.capture)
|
||||||
local store = require(script.Parent.store)
|
local store = require(script.Parent.store)
|
||||||
local types = require(script.Parent.types)
|
local types = require(script.Parent.types)
|
||||||
type Source<T> = types.Source<T>
|
type Molecule<T> = types.Molecule<T>
|
||||||
|
|
||||||
local function subscribe<T>(source: Source<T>, callback: (state: T, prev: T) -> ()): () -> ()
|
local function subscribe<T>(molecule: Molecule<T>, callback: (state: T, prev: T) -> ()): () -> ()
|
||||||
local atoms, state = capture(source)
|
local atoms, state = capture(molecule)
|
||||||
|
|
||||||
local function listener()
|
local function listener()
|
||||||
local prevState = state
|
local prevState = state
|
||||||
state = source()
|
state = molecule()
|
||||||
callback(state, prevState)
|
callback(state, prevState)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ export type WeakMap<K, V> = typeof(setmetatable({} :: { [K]: V }, { __mode = "k"
|
||||||
|
|
||||||
export type Atom<T> = (() -> T) & (state: T | (T) -> T) -> T
|
export type Atom<T> = (() -> T) & (state: T | (T) -> T) -> T
|
||||||
|
|
||||||
export type Source<T> = () -> T
|
export type Molecule<T> = () -> T
|
||||||
|
|
||||||
export type AtomOptions<T> = {
|
export type AtomOptions<T> = {
|
||||||
equals: (prev: T, next: T) -> boolean,
|
equals: (prev: T, next: T) -> boolean,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue