mirror of
https://github.com/littensy/charm.git
synced 2026-10-21 03:36:11 +00:00
feat: add toRaw()
This commit is contained in:
parent
f082956ed9
commit
9f66803f04
13 changed files with 297 additions and 198 deletions
|
|
@ -5,7 +5,7 @@ local suite = require("../../../../test/suite")
|
|||
local test = suite.test
|
||||
local afterEach = suite.afterEach
|
||||
|
||||
local function mockArraySerdes(object: { [any]: any }): { [any]: any }
|
||||
local function mockArraySerdes(object: {}): {}
|
||||
if object[1] then
|
||||
local copy = {}
|
||||
for index = 1, #object do
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ local Charm = require("../Charm")
|
|||
local patch = require("./patch")
|
||||
local types = require("./types")
|
||||
|
||||
type ReactiveProxy<T = {}> = Charm.ReactiveProxy<T>
|
||||
type SyncPayload = types.SyncPayload
|
||||
|
||||
type SignalSetter<T = any> = (update: ((T) -> T) | T) -> ()
|
||||
|
||||
type ReactiveSetter<T = any> = (update: ((T) -> ()) | T) -> ()
|
||||
|
||||
type Reactive<T = any> = typeof(setmetatable({}, {} :: { setValue: ReactiveSetter<T> }))
|
||||
type SignalSetter<T = any> = (T | (T) -> T) -> ()
|
||||
type ReactiveSetter<T = any> = (T | (T) -> ()) -> ()
|
||||
|
||||
local trackedSignals: { [string]: SignalSetter } = {}
|
||||
local trackedReactives: { [string]: ReactiveSetter } = {}
|
||||
|
|
@ -24,12 +22,12 @@ local trackedReactives: { [string]: ReactiveSetter } = {}
|
|||
|
||||
@param signals A map of setter functions to sync with the server.
|
||||
]]
|
||||
local function addSignals(signals: { [string]: SignalSetter | { [any]: any } })
|
||||
local function addSignals(signals: { [string]: SignalSetter | {} })
|
||||
for key, signal in signals do
|
||||
if type(signal) == "function" then
|
||||
trackedSignals[key] = signal
|
||||
else
|
||||
trackedReactives[key] = getmetatable((signal :: any) :: Reactive).setValue
|
||||
trackedReactives[key] = getmetatable(signal :: ReactiveProxy).set
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ end
|
|||
long as the target array is not sparse. This function ensures that the diff
|
||||
function produces a patch that can be correctly applied.
|
||||
]]
|
||||
local function stringifySparseArray(object: { any }): { [string | number]: any }
|
||||
local function stringifySparseArray(object: {}): { [string | number]: any }
|
||||
local maxn = table.maxn(object)
|
||||
|
||||
if maxn == 0 or maxn == #object then
|
||||
|
|
@ -65,7 +65,7 @@ local function diff(oldState: any, newState: any): any
|
|||
return newState
|
||||
end
|
||||
|
||||
local diffs: { [any]: any } = table.clone(newState)
|
||||
local diffs = table.clone(newState)
|
||||
|
||||
for key, oldValue in oldState do
|
||||
diffs[key] = diff(oldValue, newState[key])
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ local patch = require("./patch")
|
|||
local types = require("./types")
|
||||
local utils = require("./utils")
|
||||
|
||||
type ReactiveProxy<T = {}> = Charm.ReactiveProxy<T>
|
||||
type SyncPayload = types.SyncPayload
|
||||
|
||||
type SyncStatus = number
|
||||
|
||||
type ClientKeys = { [string]: SyncStatus }
|
||||
|
||||
type Reactive<T> = typeof(setmetatable({}, {} :: { initialValue: T, track: () -> () }))
|
||||
|
||||
type TrackedState<T = any> = {
|
||||
target: any,
|
||||
currentValue: T,
|
||||
lastSyncedValue: T,
|
||||
dispose: () -> (),
|
||||
isReactive: boolean?,
|
||||
dispose: () -> (),
|
||||
}
|
||||
|
||||
type StateUpdate = {
|
||||
|
|
@ -68,21 +67,21 @@ local function trackSignal<T>(key: string, getter: () -> T)
|
|||
trackedStates[key] = trackedState
|
||||
end
|
||||
|
||||
local function trackReactive<T>(key: string, reactive: Reactive<T>)
|
||||
local function trackReactive<T>(key: string, proxy: ReactiveProxy<T>)
|
||||
if trackedStates[key] then
|
||||
if trackedStates[key].target ~= reactive then
|
||||
if trackedStates[key].target ~= proxy then
|
||||
warn("[Charm] Attempted to sync different states with the same key:", key)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local meta = getmetatable(reactive)
|
||||
local snapshot = utils.deepCopy(meta.initialValue)
|
||||
local meta = getmetatable(proxy)
|
||||
local snapshot = utils.deepCopy(meta.value)
|
||||
local firstRun = true
|
||||
|
||||
local trackedState = {
|
||||
target = reactive,
|
||||
currentValue = meta.initialValue,
|
||||
target = proxy,
|
||||
currentValue = meta.value,
|
||||
lastSyncedValue = snapshot,
|
||||
isReactive = true,
|
||||
}
|
||||
|
|
@ -93,7 +92,7 @@ local function trackReactive<T>(key: string, reactive: Reactive<T>)
|
|||
firstRun = false
|
||||
else
|
||||
local oldSnapshot = snapshot
|
||||
snapshot = utils.deepCopy(meta.initialValue)
|
||||
snapshot = utils.deepCopy(meta.value)
|
||||
table.insert(globalUpdates, {
|
||||
key = key,
|
||||
newValue = snapshot,
|
||||
|
|
@ -258,7 +257,7 @@ end
|
|||
@param client The client receiving state updates.
|
||||
@param signals A map of getter functions to sync with the client.
|
||||
]]
|
||||
local function addSignalsToClient(client: any, signals: { [string]: { [any]: any } | () -> any })
|
||||
local function addSignalsToClient(client: any, signals: { [string]: {} | () -> any })
|
||||
if not clients[client] then
|
||||
clients[client] = {}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@ type NestedTable = {
|
|||
[any]: NestedTable | any,
|
||||
}
|
||||
|
||||
type FlattenedTable = {
|
||||
[any]: any,
|
||||
}
|
||||
|
||||
--[[
|
||||
Flattens a nested table into a single table with slash-separated keys.
|
||||
Useful for recursively collecting atoms returned by modules.
|
||||
|
|
@ -17,15 +13,15 @@ type FlattenedTable = {
|
|||
@param input A nested table.
|
||||
@return A flattened table with slash-separated keys.
|
||||
]]
|
||||
local function flatten(input: NestedTable): FlattenedTable
|
||||
local result: FlattenedTable = {}
|
||||
local function flatten<Flattened>(input: {}): Flattened
|
||||
local result = {}
|
||||
|
||||
local function visit(node: NestedTable, path: string)
|
||||
local function visit(node: {}, path: string)
|
||||
for key, value in node do
|
||||
local location = if path == "" then key else path .. "/" .. key
|
||||
local location = if path == "" then tostring(key) else path .. "/" .. tostring(key)
|
||||
|
||||
if type(value) == "table" then
|
||||
visit(value :: NestedTable, location)
|
||||
visit(value :: {}, location)
|
||||
else
|
||||
result[location] = value
|
||||
end
|
||||
|
|
@ -34,7 +30,7 @@ local function flatten(input: NestedTable): FlattenedTable
|
|||
|
||||
visit(input, "")
|
||||
|
||||
return result
|
||||
return result :: any
|
||||
end
|
||||
|
||||
--[[
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
local function isTableUnsafe(object: { [any]: any })
|
||||
local function isTableUnsafe(object: {})
|
||||
local key = next(object)
|
||||
|
||||
if key == nil then
|
||||
|
|
@ -12,7 +12,7 @@ local function isTableUnsafe(object: { [any]: any })
|
|||
for key in object do
|
||||
if type(key) ~= keyType then
|
||||
return true
|
||||
elseif keyType == "number" and key > maxKey then
|
||||
elseif type(key) == "number" and key > maxKey then
|
||||
maxKey = key
|
||||
end
|
||||
end
|
||||
|
|
@ -33,7 +33,7 @@ end
|
|||
@param value The table value.
|
||||
@param key The key of the value.
|
||||
]]
|
||||
local function validate(value: { [any]: any })
|
||||
local function validate(value: {})
|
||||
if isTableUnsafe(value) then
|
||||
warn(
|
||||
`Cannot sync tables unsupported by remote events! See the table below for more info.\n\n`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue