refactor: reorganize repo, create deep-charm

This commit is contained in:
littensy 2026-02-24 19:49:34 -08:00
parent d741640d28
commit 89478f679c
64 changed files with 913 additions and 744 deletions

View file

@ -5,6 +5,5 @@ end
local Charm = require(script.Parent.Parent.charm.src)
export type Atom<T = any> = Charm.Atom<T>
export type ReactiveProxy<T = any> = Charm.ReactiveProxy<T>
return Charm

View file

@ -11,14 +11,14 @@
"!wally.toml",
"!wally.lock",
"!default.project.json",
"!**/__tests__"
"!test"
],
"repository": {
"type": "git",
"url": "git+https://github.com/littensy/charm.git"
},
"scripts": {
"prepare": "cp ../../LICENSE.md . && cp ../../README.md .",
"prepare": "cp ../../LICENSE . && cp ../../README.md .",
"publish:wally": "wally publish"
},
"dependencies": {

View file

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

View file

@ -4,8 +4,6 @@ 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
@ -36,9 +34,21 @@ local clients: { [any]: ClientKeys } = {}
local connection: RBXScriptConnection?
local syncCallback: ((client: any, payloads: { SyncPayload }) -> ())?
--[[
Manually converts a reactive proxy to its raw representation to potentially
support custom implementations of reactive proxies.
]]
local function toRaw<T>(value: T): T
if type(value) == "table" and type(value.__target) == "table" and type(value.__track) == "function" then
value.__track()
return toRaw(value.__target)
end
return value
end
local function trackSignal<T>(key: string, getter: () -> T, identifier: unknown)
if trackedStates[key] then
-- Ignore duplicates, but warn against name collisions
-- Warn against name collisions with conflicting signals or proxies
if trackedStates[key].identifier ~= identifier then
warn("[Charm] Attempted to sync different states with the same key:", key)
end
@ -47,12 +57,12 @@ local function trackSignal<T>(key: string, getter: () -> T, identifier: unknown)
local trackedState: TrackedState<T>
local initialValue = getter()
local rawInitialValue = Charm.toRaw(initialValue)
local rawInitialValue = toRaw(initialValue)
local snapshot = if initialValue ~= rawInitialValue then utils.deepCopy(rawInitialValue) else initialValue
local dispose = Charm.effect(function()
local newValue = getter()
local rawValue = Charm.toRaw(newValue)
local rawValue = toRaw(newValue)
local isReactive = newValue ~= rawValue
if not trackedState then

View file

@ -18,4 +18,13 @@ export type SyncPayload =
]]
export type None = { __none: "__none" }
export type ReactiveProxy<T = any> = typeof(setmetatable(
{} :: {
__track: () -> (),
__target: T,
__signals: { [unknown]: () -> unknown },
},
{} :: { __index: T }
))
return {}

View file

@ -1,4 +1,5 @@
local Charm = require("../Charm")
local DeepCharm = require("../../deep-charm/src")
local client = require("../src/client")
local test = require("../../../tests/test")
@ -38,7 +39,7 @@ test("should merge patch", function()
end)
test("should merge patch (reactive)", function()
local a = Charm.reactive({ b = 1, c = 2 })
local a = DeepCharm.reactive({ b = 1, c = 2 })
local runs = 0
Charm.effect(function()

View file

@ -1,4 +1,5 @@
local Charm = require("../Charm")
local DeepCharm = require("../../deep-charm/src")
local client = require("../src/client")
local config = require("../src/config")
local server = require("../src/server")
@ -13,9 +14,9 @@ end)
test("should replicate server state to client", function()
local target = {}
local serverA = Charm.atom({ count = 0 })
local serverB = Charm.reactive({ count = 0 })
local serverB = DeepCharm.reactive({ count = 0 })
local clientA = Charm.atom({ count = -1 })
local clientB = Charm.reactive({ count = -1 })
local clientB = DeepCharm.reactive({ count = -1 })
client.addSignals({ a = clientA, b = clientB })
server.addSignalsToClient(target, { a = serverA, b = serverB })
@ -50,9 +51,9 @@ end)
test("should replicate historical server state to client", function()
local target = {}
local serverA = Charm.atom({ count = 0 })
local serverB = Charm.reactive({ count = 0 })
local serverB = DeepCharm.reactive({ count = 0 })
local clientA = Charm.atom({ count = -1 })
local clientB = Charm.reactive({ count = -1 })
local clientB = DeepCharm.reactive({ count = -1 })
config.preserveHistory = true

View file

@ -1,4 +1,5 @@
local Charm = require("../Charm")
local DeepCharm = require("../../deep-charm/src")
local config = require("../src/config")
local patch = require("../src/patch")
local server = require("../src/server")
@ -66,7 +67,7 @@ end)
test("should replicate partial state patches (reactive)", function()
local client = {}
local a = Charm.reactive({ x = { y = 0 }, z = 0 :: number? })
local a = DeepCharm.reactive({ x = { y = 0 }, z = 0 :: number? })
local target, payloads
server.addSignalsToClient(client, { a = a })
@ -99,7 +100,7 @@ end)
test("should handle nested proxies", function()
local client = {}
local src = Charm.reactive({ (Charm.reactive({})) })
local src = DeepCharm.reactive({ (DeepCharm.reactive({})) })
local payloads: {}? = nil
server.addSignalsToClient(client, { src = src })
@ -288,9 +289,9 @@ test.describe("historical", function()
test("should replicate granular state changes (reactive)", function()
local client = {}
local a = Charm.reactive({ value = 0 })
local b = Charm.reactive({ value = 0 })
local c = Charm.reactive({ value = 0 })
local a = DeepCharm.reactive({ value = 0 })
local b = DeepCharm.reactive({ value = 0 })
local c = DeepCharm.reactive({ value = 0 })
local target, payloads
server.addSignalsToClient(client, { a = a, b = b, c = c })

View file

@ -5,7 +5,7 @@ registry = "https://github.com/UpliftGames/wally-index"
realm = "shared"
exclude = [
"node_modules",
"__tests__",
"test",
"src/index.d.ts",
"package.json",
"Charm.luau",