refactor: use new type solver

This commit is contained in:
littensy 2026-04-02 06:49:54 -07:00
parent 748dbc5014
commit 22b440e35f
32 changed files with 169 additions and 155 deletions

View file

@ -3,7 +3,7 @@ local patch = require("./patch")
local types = require("./types")
type SyncPayload = types.SyncPayload
type ReactiveProxy<T = {}> = types.ReactiveProxy<T>
type ReactiveProxy<T = { [any]: any }> = types.ReactiveProxy<T>
local trackedSignals: { [string]: (any) -> any } = {}
local trackedReactives: { [string]: ReactiveProxy } = {}

View file

@ -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: {}): { [string | number]: any }
local function stringifySparseArray(object: { [any]: any }): { [string | number]: any }
local maxn = table.maxn(object)
if maxn == 0 or maxn == #object then

View file

@ -39,8 +39,9 @@ local syncCallback: ((client: any, payloads: { SyncPayload }) -> ())?
support custom implementations of reactive proxies.
]]
local function toRaw<T>(value: T): T
local value: any = value
if type(value) == "table" and type(value.__target) == "table" and type(value.__track) == "function" then
value.__track()
(value.__track :: () -> ())()
return toRaw(value.__target)
end
return value
@ -153,15 +154,17 @@ local function selectFromGlobalPatchList(client: any, globalPatches: { any }): {
local status = clientKeys[key]
if status == LISTENING_FOR_CHANGES then
table.insert(payloads, {
local payload: SyncPayload = {
type = "patch",
data = { [key] = patchData },
})
}
table.insert(payloads, payload)
elseif status == PENDING_INITIAL_STATE then
table.insert(payloads, {
local payload: SyncPayload = {
type = "init",
data = { [key] = update.newValue },
})
}
table.insert(payloads, payload)
clientKeys[key] = LISTENING_FOR_CHANGES
end
end
@ -228,11 +231,19 @@ local function selectFromGlobalPatch(client: any, globalPatch: { [string]: any }
end
if next(initData) ~= nil then
table.insert(payloads, { type = "init", data = initData })
local payload: SyncPayload = {
type = "init",
data = initData,
}
table.insert(payloads, payload)
end
if next(patchData) ~= nil then
table.insert(payloads, { type = "patch", data = patchData })
local payload: SyncPayload = {
type = "patch",
data = patchData,
}
table.insert(payloads, payload)
end
return payloads

View file

@ -2,10 +2,6 @@ local Charm = require("../Charm")
type Atom<T> = Charm.Atom<T>
type NestedTable = {
[any]: NestedTable | any,
}
--[[
Flattens a nested table into a single table with slash-separated keys.
Useful for recursively collecting atoms returned by modules.
@ -13,15 +9,15 @@ type NestedTable = {
@param input A nested table.
@return A flattened table with slash-separated keys.
]]
local function flatten<Flattened>(input: {}): Flattened
local function flatten<Flattened>(input: { [any]: any }): Flattened
local result = {}
local function visit(node: {}, path: string)
local function visit(node: { [any]: any }, path: string)
for key, value in node do
local location = if path == "" then tostring(key) else path .. "/" .. tostring(key)
if type(value) == "table" then
visit(value :: {}, location)
visit(value, location)
else
result[location] = value
end

View file

@ -1,4 +1,4 @@
local function isTableUnsafe(object: {})
local function isTableUnsafe(object: { [any]: any })
local key = next(object)
if key == nil then
@ -31,9 +31,8 @@ end
with remote argument limitations, such as sparse arrays or mixed tables.
@param value The table value.
@param key The key of the value.
]]
local function validate(value: {})
local function validate(value: { [any]: any })
if isTableUnsafe(value) then
warn(
`Cannot sync tables unsupported by remote events! See the table below for more info.\n\n`

View file

@ -2,7 +2,7 @@ local config = require("../src/config")
local patch = require("../src/patch")
local test = require("../../../tests/test")
local function mockArraySerdes(object: {}): {}
local function mockArraySerdes(object: { [any]: any }): { [any]: any }
if object[1] then
local copy = {}
for index = 1, #object do

View file

@ -4,6 +4,7 @@ local config = require("../src/config")
local patch = require("../src/patch")
local server = require("../src/server")
local test = require("../../../tests/test")
local types = require("../src/types")
test.afterEach(function()
server.reset()
@ -14,7 +15,7 @@ test("should replicate state changes", function()
local a = Charm.atom(0)
local b = Charm.atom(0)
local c = Charm.atom(0)
local target, payloads
local target: unknown, payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a, b = b, c = c })
server.connect(function(...)
@ -41,7 +42,7 @@ test("should replicate partial state patches", function()
local client = {}
local a = Charm.atom({ x = 0, y = 0 })
local b = Charm.atom(0 :: number?)
local target, payloads
local target: unknown, payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a, b = b })
server.connect(function(...)
@ -68,7 +69,7 @@ end)
test("should replicate partial state patches (reactive)", function()
local client = {}
local a = DeepCharm.reactive({ x = { y = 0 }, z = 0 :: number? })
local target, payloads
local target: unknown, payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a })
server.connect(function(...)
@ -118,7 +119,7 @@ test("should init new clients", function()
local clientA = {}
local clientB = {}
local a = Charm.atom(0)
local payloadsA, payloadsB
local payloadsA: { types.SyncPayload }, payloadsB: { types.SyncPayload }
server.addSignalsToClient(clientA, { a = a })
server.connect(function(target, payloads)
@ -147,7 +148,7 @@ test("should init new atoms", function()
local client = {}
local a = Charm.atom(0)
local b = Charm.atom(0)
local target, payloads
local target: unknown, payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a })
server.connect(function(...)
@ -172,7 +173,7 @@ test("should only replicate to synced clients", function()
local clientB = {}
local a = Charm.atom(0)
local b = Charm.atom(0)
local payloadsA, payloadsB
local payloadsA: { types.SyncPayload }, payloadsB: { types.SyncPayload }
server.addSignalsToClient(clientA, { a = a })
server.addSignalsToClient(clientB, { b = b })
@ -214,7 +215,7 @@ end)
test("should serialize state", function()
local client = {}
local a = Charm.atom({ 1, 2, 3, 4, 5 })
local payloads
local payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a })
server.connect(function(_, p)
@ -231,7 +232,7 @@ end)
test("should not send unchanged state", function()
local client = {}
local a = Charm.atom(0)
local payloads
local payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a })
server.connect(function(_, p)
@ -262,7 +263,7 @@ test.describe("historical", function()
local a = Charm.atom(0)
local b = Charm.atom(0)
local c = Charm.atom(0)
local target, payloads
local target: unknown, payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a, b = b, c = c })
server.connect(function(...)
@ -292,7 +293,7 @@ test.describe("historical", function()
local a = DeepCharm.reactive({ value = 0 })
local b = DeepCharm.reactive({ value = 0 })
local c = DeepCharm.reactive({ value = 0 })
local target, payloads
local target: unknown, payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a, b = b, c = c })
server.connect(function(...)
@ -321,7 +322,7 @@ test.describe("historical", function()
local clientA = {}
local clientB = {}
local a = Charm.atom(0)
local payloadsA, payloadsB
local payloadsA: { types.SyncPayload }, payloadsB: { types.SyncPayload }
server.addSignalsToClient(clientA, { a = a })
server.connect(function(target, payloads)
@ -357,7 +358,7 @@ test.describe("historical", function()
local client = {}
local a = Charm.atom(0)
local b = Charm.atom(0)
local payloads
local payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a })
server.connect(function(_, ...)
@ -386,7 +387,7 @@ test.describe("historical", function()
test("should not send unchanged state", function()
local client = {}
local a = Charm.atom(0)
local payloads
local payloads: { types.SyncPayload }
server.addSignalsToClient(client, { a = a })
server.connect(function(_, p)

View file

@ -8,7 +8,8 @@ test("should flatten functions", function()
b = { c = Charm.atom(0) },
d = { e = { f = utils.signalToAtom(Charm.signal(0)) } },
}
local result = utils.flatten(input)
local result = utils.flatten<<{ [string]: Charm.Atom<number> }>>(input)
assert(result.a == input.a, "should flatten the first level")
assert(result["b/c"] == input.b.c, "should flatten the second level")