From 478f0419c61e7272940450b6221d549a11a24292 Mon Sep 17 00:00:00 2001 From: "L.D. Gerrits" <99460608+LDGerrits@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:21:27 +0100 Subject: [PATCH] scope should invoke :disconnect() and :Disconnect methods --- .../api-reference/memory/members/docleanup.md | 2 ++ docs/api-reference/memory/types/task.md | 2 ++ docs/tutorials/fundamentals/scopes.md | 1 + src/Memory/doCleanup.luau | 19 ++++++++++++- src/Types.luau | 2 ++ test/Spec/Memory/doCleanup.spec.luau | 28 +++++++++++++++++++ 6 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/api-reference/memory/members/docleanup.md b/docs/api-reference/memory/members/docleanup.md index 99946798e..ffef29529 100644 --- a/docs/api-reference/memory/members/docleanup.md +++ b/docs/api-reference/memory/members/docleanup.md @@ -42,6 +42,8 @@ to determine what should happen. - if `function`, it is called - ...else if `{destroy: (self) -> ()}`, `:destroy()` is called - ...else if `{Destroy: (self) -> ()}`, `:Destroy()` is called +- ...else if `{disconnect: (self) -> ()}`, `:disconnect()` is called +- ...else if `{Disconnect: (self) -> ()}`, `:Disconnect()` is called - ...else if `{any}`, `doCleanup` is called on all members When Fusion is running inside of Roblox: diff --git a/docs/api-reference/memory/types/task.md b/docs/api-reference/memory/types/task.md index 3e34c1785..a5bcc9fe4 100644 --- a/docs/api-reference/memory/types/task.md +++ b/docs/api-reference/memory/types/task.md @@ -16,6 +16,8 @@ export type Task = | () -> () | {destroy: (self) -> ()} | {Destroy: (self) -> ()} + | {disconnect: (self) -> ()} + | {Disconnect: (self) -> ()} | {Task} ``` Types which [`doCleanup`](../../members/docleanup) has defined behaviour for. diff --git a/docs/tutorials/fundamentals/scopes.md b/docs/tutorials/fundamentals/scopes.md index 45e235584..6dfcfb916 100644 --- a/docs/tutorials/fundamentals/scopes.md +++ b/docs/tutorials/fundamentals/scopes.md @@ -77,6 +77,7 @@ Scopes passed to `doCleanup` can contain: - Roblox instances to destroy - Roblox event connections to disconnect - Your own objects with `:destroy()` or `:Destroy()` methods to be called +- Your own objects with `:disconnect()` or `:Disconnect()` methods to be called - Other nested scopes to be cleaned up You can add these manually using `table.insert` if you need custom behaviour, diff --git a/src/Memory/doCleanup.luau b/src/Memory/doCleanup.luau index 1dfb9f86e..6a29d1f7f 100644 --- a/src/Memory/doCleanup.luau +++ b/src/Memory/doCleanup.luau @@ -41,7 +41,14 @@ local function doCleanup( task() elseif typeof(task) == "table" then - local task = (task :: any) :: {Destroy: (...unknown) -> (...unknown)?, destroy: (...unknown) -> (...unknown)?} + local task = ( + task :: any + ) :: { + Destroy: (...unknown) -> ...unknown?, + destroy: (...unknown) -> ...unknown?, + Disconnect: (...unknown) -> ...unknown?, + disconnect: (...unknown) -> ...unknown?, + } -- case 4: destroy() function if typeof(task.destroy) == "function" then @@ -65,6 +72,16 @@ local function doCleanup( end ExternalDebug.untrackScope(task) + + -- case 7: Disconnect() function + elseif typeof(task.Disconnect) == "function" then + local task = (task :: any) :: { Disconnect: (...unknown) -> ...unknown } + task:Disconnect() + + -- case 8: disconnect() function + elseif typeof(task.disconnect) == "function" then + local task = (task :: any) :: { disconnect: (...unknown) -> ...unknown } + task:disconnect() end end diff --git a/src/Types.luau b/src/Types.luau index 4377acd0b..75b61fba4 100644 --- a/src/Types.luau +++ b/src/Types.luau @@ -43,6 +43,8 @@ export type Task = () -> () | {destroy: (unknown) -> ()} | {Destroy: (unknown) -> ()} | + {disconnect: (unknown) -> ()} | + {Disconnect: (unknown) -> ()} | {Task} -- A scope of tasks to clean up. diff --git a/test/Spec/Memory/doCleanup.spec.luau b/test/Spec/Memory/doCleanup.spec.luau index 0df2ceb73..883b16497 100644 --- a/test/Spec/Memory/doCleanup.spec.luau +++ b/test/Spec/Memory/doCleanup.spec.luau @@ -74,6 +74,34 @@ return function() expect(didRun).to.equal(true) end) + it("should invoke :disconnect() methods", function() + local expect = getfenv().expect + + local didRun = false + + doCleanup({ + disconnect = function() + didRun = true + end + }) + + expect(didRun).to.equal(true) + end) + + it("should invoke :Disconnect() methods", function() + local expect = getfenv().expect + + local didRun = false + + doCleanup({ + Disconnect = function() + didRun = true + end + }) + + expect(didRun).to.equal(true) + end) + it("should clean up contents of arrays", function() local expect = getfenv().expect