chore: bump deps

This commit is contained in:
littensy 2026-01-12 17:24:36 -08:00
parent 28872264a2
commit 41d59cdfad
4 changed files with 58 additions and 94 deletions

View file

@ -1,51 +1,7 @@
local fs = require("@std/fs") local fs = require("@std/fs")
local json = require("@std/json")
local net = require("@lute/net") local net = require("@lute/net")
local process = require("@lute/process") local process = require("@lute/process")
local CURRENT_FFLAGS = "https://clientsettingscdn.roblox.com/v1/settings/application?applicationName=PCStudioApp"
local FFLAG_KINDS = { "FFlag", "FInt" }
local function analyze()
local args = {
"luau-lsp",
"analyze",
"--sourcemap=sourcemap.json",
"--ignore=**/node_modules/**",
"--base-luaurc=.luaurc",
"--definitions=roblox.d.luau",
"--no-flags-enabled",
}
local response = net.request(CURRENT_FFLAGS, { method = "GET" })
local data: any = json.deserialize(response.body)
for name, value in data.applicationSettings do
if type(name) ~= "string" then
continue
end
for _, kind in FFLAG_KINDS do
if string.find(name, `^{kind}Luau`) then
table.insert(args, `--flag:{string.sub(name, #kind + 1)}={value}`)
end
end
end
table.insert(args, "packages")
table.insert(args, "tests")
table.insert(args, "benches")
local result = process.run(args)
local stderr = string.gsub(result.stderr, "Unknown FFlag[^\n]+\n", "")
print(stderr)
if result.exitcode == 1 then
process.exit(1)
end
end
process.run({ "rojo", "sourcemap", "--output=sourcemap.json" }, { stdio = "inherit" }) process.run({ "rojo", "sourcemap", "--output=sourcemap.json" }, { stdio = "inherit" })
fs.writestringtofile( fs.writestringtofile(
@ -53,24 +9,26 @@ fs.writestringtofile(
net.request("https://luau-lsp.pages.dev/globalTypes.None.d.luau", { method = "GET" }).body net.request("https://luau-lsp.pages.dev/globalTypes.None.d.luau", { method = "GET" }).body
) )
analyze() local analyze = process.run({
"luau-lsp",
-- process.run({ "analyze",
-- "luau-lsp", "--sourcemap=sourcemap.json",
-- "analyze", "--ignore=**/node_modules/**",
-- "--sourcemap=sourcemap.json", "--base-luaurc=.luaurc",
-- "--ignore=**/node_modules/**", "--definitions=roblox.d.luau",
-- "--base-luaurc=.luaurc", "packages",
-- "--defs=roblox.d.luau", "tests",
-- "packages", "benches",
-- "tests", }, { stdio = "inherit" })
-- "benches",
-- }, { stdio = "inherit" })
fs.remove("roblox.d.luau") fs.remove("roblox.d.luau")
process.run({ "selene", "packages", "tests", "benches" }, { stdio = "inherit" }) local selene = process.run({ "selene", "packages", "tests", "benches" }, { stdio = "inherit" })
process.run({ "stylua", "--check", "packages", "tests", "benches" }, { stdio = "inherit" }) local stylua = process.run({ "stylua", "--check", "packages", "tests", "benches" }, { stdio = "inherit" })
process.run({ "pnpm", "eslint", "packages" }, { stdio = "inherit" }) local eslint = process.run({ "pnpm", "eslint", "packages" }, { stdio = "inherit" })
if not (analyze.ok and selene.ok and stylua.ok and eslint.ok) then
process.exit(1)
end

View file

@ -233,10 +233,9 @@ Effects are fundamental to reactivity, allowing you to react to signal updates.
```luau ```luau
local getCounter, setCounter = signal(0) local getCounter, setCounter = signal(0)
-- Count is 0
effect(function() effect(function()
print(`Count is {getCounter()}`) print(`Count is {getCounter()}`)
end) end) -- Count is 0
setCounter(1) -- Count is 1 setCounter(1) -- Count is 1
``` ```
@ -257,22 +256,33 @@ setCounter(1) -- Cleanup 0
dispose() -- Cleanup 1 dispose() -- Cleanup 1
``` ```
Effects can be nested and they will clean up automatically when the parent effect re-runs or gets disposed. This means you don't have to manually clean up inner effects, and this applies to functions like `subscribe()` and `observe()`. ### Nested Effects
Effects can be nested inside other effects. When the outer effect re-runs, inner effects from the previous run are automatically cleaned up, and new inner effects are created if needed. The system ensures proper execution order; outer effects always run before their inner effects:
```luau ```luau
local getCounter, setCounter = signal(0) local getShow, setShow = signal(true)
local getCount, setCount = signal(1)
effect(function() effect(function()
print(`Outer: {getCounter()}`) if getShow() then
-- This inner effect is created when show() is true
effect(function() effect(function()
print(`Inner: {getcounter()}`) print(`Count is: {getCount()}`)
end)
end) end)
end
end) -- Output: Count is: 1
setCounter(1) -- Outer: 1, Inner: 1 setCount(2) -- Count is: 2
setCounter(2) -- Outer: 2, Inner: 2
-- When show becomes false, the inner effect is cleaned up
setShow(false) -- No output
setCount(3) -- No output (inner effect no longer exists)
``` ```
Nested effect cleanup also applies to every reaction API (`subscribe()`, `listen()`, `observe()`) because they are built upon effects.
> [!NOTE] > [!NOTE]
> To run code that is "detached" from the parent effect or scope, use `untracked()` or a detached effect scope. If you suspect that the new nested effect behavior is causing issues with migration, try disabling the `flags.trackInnerEffects` flag to assist with debugging. > To run code that is "detached" from the parent effect or scope, use `untracked()` or a detached effect scope. If you suspect that the new nested effect behavior is causing issues with migration, try disabling the `flags.trackInnerEffects` flag to assist with debugging.
@ -289,17 +299,15 @@ local users, setUsers = reactive({
{ name = "John", surname = "Doe" }, { name = "John", surname = "Doe" },
}) })
-- Output: John Doe
effect(function() effect(function()
print(`{users[1].name} {users[1].surname}`) print(`{users[1].name} {users[1].surname}`)
end) end) -- Output: John Doe
-- Output: Jane Smith
setUsers(function(state) setUsers(function(state)
state[1].name = "Jane" state[1].name = "Jane"
state[1].surname = "Smith" state[1].surname = "Smith"
table.insert(state, { name = "Steve", surname = "Doe" }) table.insert(state, { name = "Steve", surname = "Doe" })
end) end) -- Output: Jane Smith
-- You can also mutate the reactive proxy directly: -- You can also mutate the reactive proxy directly:
users[1].name = "John" -- John Smith users[1].name = "John" -- John Smith
@ -327,10 +335,9 @@ In case you want to opt-out of dependency tracking in an effect, you can use `un
local getTracked, setTracked = signal(0) local getTracked, setTracked = signal(0)
local getUntracked, setUntracked = signal(0) local getUntracked, setUntracked = signal(0)
-- Tracked: 0, Untracked: 0
effect(function() effect(function()
print(`Tracked: {getTracked()}, Untracked: {untracked(getUntracked)}`) print(`Tracked: {getTracked()}, Untracked: {untracked(getUntracked)}`)
end) end) -- Output: Tracked: 0, Untracked: 0
setTracked(1) -- Tracked: 1, Untracked: 0 setTracked(1) -- Tracked: 1, Untracked: 0
setUntracked(1) -- No output setUntracked(1) -- No output
@ -364,10 +371,9 @@ Similar to `untracked()`, but does not prevent the parent effect from tracking n
```luau ```luau
local getCounter, setCounter = signal(0) local getCounter, setCounter = signal(0)
-- Count is 0
local disposeOuter = effect(function() local disposeOuter = effect(function()
print(`Count is {peek(getCounter)}`) print(`Count is {peek(getCounter)}`)
end) end) -- Output: Count is 0
setCounter(1) -- No output; count was accessed in peek() setCounter(1) -- No output; count was accessed in peek()
``` ```
@ -430,7 +436,7 @@ The callback also receives the previous value, or `nil` when running for the fir
```luau ```luau
local getCounter, setCounter = signal(0) local getCounter, setCounter = signal(0)
-- Count is 0 (was nil) -- Output: Count is 0 (was nil)
listen(getCounter, function(count, prevCount) listen(getCounter, function(count, prevCount)
print(`Count is {count} (was {prevCount})`) print(`Count is {count} (was {prevCount})`)
end) end)
@ -595,9 +601,7 @@ effect(function()
setCounter(function(count) setCounter(function(count)
return math.min(count + 1, 3) return math.min(count + 1, 3)
end) end)
end) end) -- Output: 0, 1, 2, 3
-- Output: 0, 1, 2, 3
``` ```
--- ---
@ -931,7 +935,7 @@ This means nilable values may be replaced with `None` in patches, and code worki
Charm v0.11 introduces _a lot_ of breaking changes, so below are some tips that might help you migrate from an older version. Charm v0.11 introduces _a lot_ of breaking changes, so below are some tips that might help you migrate from an older version.
<details> <details>
<summary><b>Terminology changes</b></summary> <summary><b>Terminology</b></summary>
- Signal: A state container with one function to get the state, and another to update it - Signal: A state container with one function to get the state, and another to update it
- Atom: A signal with the getter and setter combined into one function - Atom: A signal with the getter and setter combined into one function

View file

@ -191,7 +191,9 @@ local function runCleanups(cleanups: { () -> () })
for key, cleanup in cleanups do for key, cleanup in cleanups do
cleanups[key] = nil cleanups[key] = nil
local prevSub = setActiveSub(nil) local prevSub = setActiveSub(nil)
xpcall(cleanup, warn or print) xpcall(cleanup, function(err)
warn("Error occurred during effect cleanup:", debug.traceback(tostring(err), 2))
end)
activeSub = prevSub activeSub = prevSub
end end
end end
@ -799,14 +801,14 @@ local function batch<Args..., Results...>(fn: (Args...) -> Results..., ...: Args
end end
--[[ --[[
Converts a non-signal into a computed signal. If the function is already a Wraps a function in a computed signal if it is not already a reactive
signal, it is returned as-is. Useful for memoizing a getter function signal. Useful for memoizing a getter function without creating unnecessary
without creating unnecessary nested signals. nested signals.
@param fn A signal or function that accesses signals @param fn A signal or function that accesses signals
@return Computed signal if `fn` is not already a signal @return `fn` wrapped in a computed signal if needed
]] ]]
local function toSignal<T>(fn: () -> T): () -> T local function toComputed<T>(fn: () -> T): () -> T
local name = debug.info(fn, "n") local name = debug.info(fn, "n")
return if name == "readSignal" or name == "readComputed" or name == "atomOper" then fn else computed(fn) return if name == "readSignal" or name == "readComputed" or name == "atomOper" then fn else computed(fn)
end end
@ -825,7 +827,7 @@ end
@see https://github.com/littensy/charm?tab=readme-ov-file#listengetter-callback @see https://github.com/littensy/charm?tab=readme-ov-file#listengetter-callback
]] ]]
local function listen<T>(getter: () -> T, fn: (state: T, previous: T?) -> ()): () -> () local function listen<T>(getter: () -> T, fn: (state: T, previous: T?) -> ()): () -> ()
local tracked = toSignal(getter) local tracked = toComputed(getter)
local current: T local current: T
return effect(function() return effect(function()
@ -849,7 +851,7 @@ end
@see https://github.com/littensy/charm?tab=readme-ov-file#subscribegetter-callback @see https://github.com/littensy/charm?tab=readme-ov-file#subscribegetter-callback
]] ]]
local function subscribe<T>(getter: () -> T, fn: (state: T, lastState: T) -> ()): () -> () local function subscribe<T>(getter: () -> T, fn: (state: T, lastState: T) -> ()): () -> ()
local tracked = toSignal(getter) local tracked = toComputed(getter)
local current: T local current: T
local firstRun = true local firstRun = true

View file

@ -3,5 +3,5 @@ wally = "UpliftGames/wally@0.3.2"
rojo = "rojo-rbx/rojo@7.6.1" rojo = "rojo-rbx/rojo@7.6.1"
stylua = "johnnymorganz/stylua@2.3.1" stylua = "johnnymorganz/stylua@2.3.1"
selene = "Kampfkarren/selene@0.29.0" selene = "Kampfkarren/selene@0.29.0"
luau-lsp = "johnnymorganz/luau-lsp@1.57.1" luau-lsp = "johnnymorganz/luau-lsp@1.60.0"
lute = "luau-lang/lute@0.1.0-nightly.20251213" lute = "luau-lang/lute@0.1.0-nightly.20260112"