@rbxts/evxryy-collect 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/index.d.ts +48 -0
- package/out/init.luau +312 -0
- package/package.json +40 -0
package/out/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
type Executable = CallbackLike | ConnectionLike | MetatableLike | Instance | thread;
|
|
2
|
+
type CallbackLike = () => void;
|
|
3
|
+
type ConnectionLike = RBXScriptConnection;
|
|
4
|
+
type CleanupMethods = {
|
|
5
|
+
Destroy?: () => void;
|
|
6
|
+
Clean?: () => void;
|
|
7
|
+
DoCleaning?: () => void;
|
|
8
|
+
Cleaning?: () => void;
|
|
9
|
+
Disconnect?: () => void;
|
|
10
|
+
DisconnectAll?: () => void;
|
|
11
|
+
};
|
|
12
|
+
type MetatableLike = Record<string, unknown> & CleanupMethods;
|
|
13
|
+
declare namespace Collect {
|
|
14
|
+
interface CollectConstructor {
|
|
15
|
+
new (): Collect;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
interface Collect {
|
|
19
|
+
Add(object: Executable): void;
|
|
20
|
+
Remove(object: Executable, clean?: boolean): void;
|
|
21
|
+
RemoveAll(clean?: boolean, ...args: unknown[]): void;
|
|
22
|
+
Find(object: Executable): Executable | null;
|
|
23
|
+
Construct<T extends Executable, A extends unknown[]>(ctor: {
|
|
24
|
+
new (...args: A): T;
|
|
25
|
+
} | {
|
|
26
|
+
new: (...args: A) => T;
|
|
27
|
+
} | ((...args: A) => T), ...args: A): T | undefined;
|
|
28
|
+
Extend(): Collect;
|
|
29
|
+
Merge(objectComponent: Collect): void;
|
|
30
|
+
LinkToInstance(object: Instance): Collect;
|
|
31
|
+
IsEmpty(): boolean;
|
|
32
|
+
Clean(): void;
|
|
33
|
+
WrapClean(): () => void;
|
|
34
|
+
add: Collect["Add"];
|
|
35
|
+
remove: Collect["Remove"];
|
|
36
|
+
removeAll: Collect["RemoveAll"];
|
|
37
|
+
find: Collect["Find"];
|
|
38
|
+
construct: Collect["Construct"];
|
|
39
|
+
extend: Collect["Extend"];
|
|
40
|
+
merge: Collect["Merge"];
|
|
41
|
+
destroy: Collect["Clean"];
|
|
42
|
+
link: Collect["LinkToInstance"];
|
|
43
|
+
isEmpty: Collect["IsEmpty"];
|
|
44
|
+
clean: Collect["Clean"];
|
|
45
|
+
wrapClean: Collect["WrapClean"];
|
|
46
|
+
}
|
|
47
|
+
declare const Collect: Collect.CollectConstructor;
|
|
48
|
+
export = Collect;
|
package/out/init.luau
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
--[[
|
|
2
|
+
Author : evxry_ll
|
|
3
|
+
|
|
4
|
+
-- Collect: A garbage collection/cleanup utility module
|
|
5
|
+
-- Manages and cleans up various types of resources (connections, instances, threads, etc.)
|
|
6
|
+
]]
|
|
7
|
+
|
|
8
|
+
-- Type definitions for items that can be cleaned up
|
|
9
|
+
export type ExecutableList = {
|
|
10
|
+
Item : Executable,
|
|
11
|
+
CleanupMethod : string?, -- Optional cleanup method name for objects
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
-- Union type of all cleanable resource types
|
|
15
|
+
type Executable = CallbackLike
|
|
16
|
+
| ConnectionLike
|
|
17
|
+
| MetatableLike
|
|
18
|
+
| Instance
|
|
19
|
+
| thread
|
|
20
|
+
|
|
21
|
+
-- Simple callback function type
|
|
22
|
+
type CallbackLike = () -> ()
|
|
23
|
+
|
|
24
|
+
-- Connection type (like RBXScriptConnection)
|
|
25
|
+
type ConnectionLike = {
|
|
26
|
+
Disconnect : () -> (),
|
|
27
|
+
Connected : boolean,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
-- Type for objects with metatables (custom classes)
|
|
31
|
+
type MetatableLike = typeof(setmetatable({} :: {
|
|
32
|
+
__index : MetatableLike,
|
|
33
|
+
},{} :: {any}))
|
|
34
|
+
|
|
35
|
+
-- Generic Cleanup Methods - common method names used for cleanup
|
|
36
|
+
local GCM = table.freeze(
|
|
37
|
+
{"Destroy","Clean","DoCleaning","Cleaning","DisconnectAll","Disconnect"}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
-- Detects which cleanup method an object has
|
|
41
|
+
-- @param t: Object to check
|
|
42
|
+
-- @return: Name of cleanup method or "Not-Found"
|
|
43
|
+
local function GCM_Detection(t : MetatableLike) : "Destroy" | "Clean" | "DoCleaning" | "Cleaning" | "Not-Found"
|
|
44
|
+
for _,callbackName in pairs(GCM) do
|
|
45
|
+
if(t[callbackName]) then
|
|
46
|
+
return callbackName
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
return "Not-Found"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
-- Constructor table for creating new CollectComponent instances
|
|
53
|
+
local Constructor = {}
|
|
54
|
+
Constructor.__index = Constructor
|
|
55
|
+
|
|
56
|
+
-- Component prototype with all methods
|
|
57
|
+
local Component = {}
|
|
58
|
+
Component.__index = Component
|
|
59
|
+
|
|
60
|
+
-- Type definition for CollectComponent instances
|
|
61
|
+
export type CollectComponent<T...> = typeof(setmetatable({} :: {
|
|
62
|
+
_task : {ExecutableList}, -- Array of tracked items
|
|
63
|
+
_cleaning : boolean, -- Flag to prevent operations during cleanup
|
|
64
|
+
},Component))
|
|
65
|
+
|
|
66
|
+
-- Creates a new CollectComponent instance
|
|
67
|
+
-- @return: New CollectComponent for managing cleanup tasks
|
|
68
|
+
function Constructor.new<T...>() : CollectComponent<T...>
|
|
69
|
+
local self = setmetatable({
|
|
70
|
+
_task = {},
|
|
71
|
+
_cleaning = false,
|
|
72
|
+
},Component)
|
|
73
|
+
return self
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
-- Operator overload: Allows using + to add items
|
|
77
|
+
-- Example: component + connection
|
|
78
|
+
function Component.__add<T...>(self : CollectComponent<T...>,object : Executable)
|
|
79
|
+
self:Add(object)
|
|
80
|
+
return self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
-- Operator overload: Allows using - to remove items
|
|
84
|
+
-- Example: component - connection
|
|
85
|
+
function Component.__sub<T...>(self : CollectComponent<T...>,object : Executable)
|
|
86
|
+
self:Remove(object,true)
|
|
87
|
+
return self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
-- String representation of the component
|
|
91
|
+
-- Returns: "CollectComponent(n)" where n is the number of tracked items
|
|
92
|
+
function Component.__tostring<T...>(self : CollectComponent<T...>)
|
|
93
|
+
return "CollectComponent("..#self._task..")"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
-- Length operator overload
|
|
97
|
+
-- Returns: Number of tracked items
|
|
98
|
+
function Component.__len<T...>(self : CollectComponent<T...>)
|
|
99
|
+
return #self._task
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
-- Adds an item to be tracked and cleaned up later
|
|
103
|
+
-- @param object: Item to track (function, connection, instance, thread, or table with cleanup method)
|
|
104
|
+
function Component.Add<T...>(self : CollectComponent<T...>,object : Executable)
|
|
105
|
+
if(self._cleaning) then return end -- Prevent adding during cleanup
|
|
106
|
+
-- Validate input type
|
|
107
|
+
assert(
|
|
108
|
+
typeof(object) == "function" or
|
|
109
|
+
typeof(object) == "RBXScriptConnection" or
|
|
110
|
+
typeof(object) == "table" or
|
|
111
|
+
typeof(object) == "Instance" or
|
|
112
|
+
typeof(object) == "thread"
|
|
113
|
+
,"\"object\" argument is not a \"Executable\"")
|
|
114
|
+
|
|
115
|
+
local pointer : ExecutableList = {Item = nil}
|
|
116
|
+
-- For tables and instances, detect cleanup method
|
|
117
|
+
if(typeof(object) == "table" or typeof(object) == "Instance") then
|
|
118
|
+
local gcMethod = GCM_Detection(object :: any)
|
|
119
|
+
if(gcMethod == "Not-Found") then
|
|
120
|
+
error("Current object does not have any cleanup method.")
|
|
121
|
+
end
|
|
122
|
+
pointer = {
|
|
123
|
+
Item = object,
|
|
124
|
+
CleanupMethod = gcMethod,
|
|
125
|
+
}
|
|
126
|
+
else
|
|
127
|
+
pointer = {Item = object,}
|
|
128
|
+
end
|
|
129
|
+
table.insert(self._task,pointer)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
-- Removes a specific item from tracking
|
|
133
|
+
-- @param object: Item to remove
|
|
134
|
+
-- @param clean: If true, calls cleanup on the item
|
|
135
|
+
function Component.Remove<T...>(self : CollectComponent<T...>,object : Executable,clean : boolean?)
|
|
136
|
+
if(self._cleaning) then return end
|
|
137
|
+
local tasks = self._task
|
|
138
|
+
-- Find and remove the item
|
|
139
|
+
for index,value : ExecutableList in pairs(tasks) do
|
|
140
|
+
if(value.Item == object) then
|
|
141
|
+
table.remove(tasks,index)
|
|
142
|
+
-- Clean up if requested
|
|
143
|
+
if(clean or type(clean) == "nil") then
|
|
144
|
+
if(value.CleanupMethod) then
|
|
145
|
+
-- Call the object's cleanup method
|
|
146
|
+
(value.Item :: any)[value.CleanupMethod](value.Item)
|
|
147
|
+
else
|
|
148
|
+
-- Handle threads and functions
|
|
149
|
+
if(typeof(value.Item) == "thread") then
|
|
150
|
+
task.cancel((value.Item :: thread))
|
|
151
|
+
elseif(typeof(value.Item) == "RBXScriptConnection") then
|
|
152
|
+
(value.Item :: RBXScriptConnection):Disconnect()
|
|
153
|
+
else
|
|
154
|
+
(value.Item :: any)()
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
break
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
-- Finds an item in the tracked list
|
|
164
|
+
-- @param object: Item to find
|
|
165
|
+
-- @return: The item if found, nil otherwise
|
|
166
|
+
function Component.Find<T...>(self : CollectComponent<T...>,object : Executable) : Executable?
|
|
167
|
+
local tasks = self._task
|
|
168
|
+
for index,value in pairs(tasks) do
|
|
169
|
+
if(value.Item == object) then
|
|
170
|
+
return value.Item
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
return nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
-- Removes all tracked items
|
|
177
|
+
-- @param clean: If true, calls cleanup on all items
|
|
178
|
+
-- @param ...: Additional arguments passed to cleanup methods
|
|
179
|
+
function Component.RemoveAll<R,T...>(self : CollectComponent<T...>,clean : boolean?,... : R)
|
|
180
|
+
if(self._cleaning) then return end
|
|
181
|
+
local tasks = self._task
|
|
182
|
+
if #tasks == 0 then return end
|
|
183
|
+
-- Clean up each item if requested
|
|
184
|
+
for i = 1, #tasks do
|
|
185
|
+
local value = tasks[i]
|
|
186
|
+
if(clean or type(clean) == "nil") then
|
|
187
|
+
if value.CleanupMethod then
|
|
188
|
+
-- Call object's cleanup method with additional args
|
|
189
|
+
(value.Item :: any)[value.CleanupMethod](value.Item, ...)
|
|
190
|
+
else
|
|
191
|
+
-- Handle threads and functions
|
|
192
|
+
if typeof(value.Item) == "thread" then
|
|
193
|
+
task.cancel((value.Item :: thread))
|
|
194
|
+
elseif(typeof(value.Item) == "RBXScriptConnection") then
|
|
195
|
+
(value.Item :: any):Disconnect()
|
|
196
|
+
else
|
|
197
|
+
(value.Item :: any)(...)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
table.clear(tasks)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
-- Creates a new object and adds it to tracking
|
|
206
|
+
-- @param class: Class constructor (table with .new or function)
|
|
207
|
+
-- @param ...: Arguments for constructor
|
|
208
|
+
-- @return: The created object
|
|
209
|
+
function Component.Construct<R,T...>(self : CollectComponent<T...>,class : MetatableLike & {new : (...any) -> ...any}, ... : any) : R?
|
|
210
|
+
if(self._cleaning) then return end
|
|
211
|
+
local object = nil
|
|
212
|
+
local t = type(class)
|
|
213
|
+
-- Call constructor based on type
|
|
214
|
+
if t == "table" then
|
|
215
|
+
object = (class :: any).new(...)
|
|
216
|
+
elseif t == "function" then
|
|
217
|
+
object = (class :: any)(...)
|
|
218
|
+
end
|
|
219
|
+
self:Add(object)
|
|
220
|
+
return self:Find(object)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
-- Creates a new CollectComponent as a child of this one
|
|
224
|
+
-- @return: New CollectComponent that will be cleaned with parent
|
|
225
|
+
function Component.Extend<T...>(self : CollectComponent<T...>) : CollectComponent<T...>?
|
|
226
|
+
if(self._cleaning) then return end
|
|
227
|
+
return self:Construct(Constructor)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
-- Merges another CollectComponent into this one, taking ownership of all its tracked items
|
|
231
|
+
-- The source component is destroyed after merging
|
|
232
|
+
-- @param self: Target CollectComponent that will receive the items
|
|
233
|
+
-- @param CollectComponent: Source CollectComponent to merge from (will be destroyed)
|
|
234
|
+
function Component.Merge<T...,K...>(self : CollectComponent<T...>, CollectComponent : CollectComponent<K...>)
|
|
235
|
+
-- Prevent merging if this component is being cleaned up
|
|
236
|
+
if(self._cleaning) then return end
|
|
237
|
+
-- Get all tasks from the source component
|
|
238
|
+
local tasks = CollectComponent._task
|
|
239
|
+
-- Transfer all tasks to this component
|
|
240
|
+
if(#tasks > 0) then
|
|
241
|
+
for i = 1,#tasks do
|
|
242
|
+
table.insert(self._task,tasks[i])
|
|
243
|
+
end
|
|
244
|
+
-- Clear the source component's tasks without cleaning them
|
|
245
|
+
-- (ownership has been transferred to this component)
|
|
246
|
+
CollectComponent:RemoveAll()
|
|
247
|
+
end
|
|
248
|
+
-- Destroy the source component completely
|
|
249
|
+
table.clear(CollectComponent :: any)
|
|
250
|
+
setmetatable(CollectComponent :: any,nil)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
--[[
|
|
254
|
+
Transfer the current life cycle of the component to the new object.
|
|
255
|
+
for example if the object is destroyed the component will also be destroyed.
|
|
256
|
+
]]
|
|
257
|
+
function Component.LinkToInstance<T...>(self : CollectComponent<T...>, object : Instance) : CollectComponent<T...>
|
|
258
|
+
assert(typeof(object) == "Instance","object must be a typeof Instance")
|
|
259
|
+
-- Create a new task to monitor the instance's ancestry
|
|
260
|
+
object.Destroying:Once(function()
|
|
261
|
+
self:Clean() -- Clean up this component if the instance is destroyed
|
|
262
|
+
end)
|
|
263
|
+
return self
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
--[[
|
|
267
|
+
Check if current list of tasks is empty
|
|
268
|
+
@return: True if the component has no tasks, false otherwise
|
|
269
|
+
]]
|
|
270
|
+
function Component.IsEmpty<T...>(self : CollectComponent<T...>) : boolean
|
|
271
|
+
return next(self._task) == nil
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
-- Cleans up all tracked items and destroys the component
|
|
275
|
+
-- This is the main cleanup method - call when done with the component
|
|
276
|
+
function Component.Clean<T...>(self : CollectComponent<T...>)
|
|
277
|
+
if(self._cleaning) then return end -- Prevent double cleanup
|
|
278
|
+
self:RemoveAll(true) -- Clean all tracked items
|
|
279
|
+
self._cleaning = true -- Mark as cleaning
|
|
280
|
+
table.clear(self :: any) -- Clear all data
|
|
281
|
+
setmetatable(self :: any,nil) -- Remove metatable
|
|
282
|
+
self = nil :: any -- Clear reference
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
-- Returns a function that cleans this component when called
|
|
286
|
+
-- Useful for passing cleanup to other systems
|
|
287
|
+
-- @return: Function that calls Clean()
|
|
288
|
+
function Component.WrapClean<T...>(self : CollectComponent<T...>) : () -> ()
|
|
289
|
+
return function()
|
|
290
|
+
self:Clean()
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
-- Create alias for Constructor methods
|
|
295
|
+
Constructor.New = Constructor.new
|
|
296
|
+
|
|
297
|
+
-- Create alias for Component methods
|
|
298
|
+
Component.add = Component.Add
|
|
299
|
+
Component.remove = Component.Remove
|
|
300
|
+
Component.removeAll = Component.RemoveAll
|
|
301
|
+
Component.find = Component.Find
|
|
302
|
+
Component.construct = Component.Construct
|
|
303
|
+
Component.extend = Component.Extend
|
|
304
|
+
Component.merge = Component.Merge
|
|
305
|
+
Component.clean = Component.Clean
|
|
306
|
+
Component.destroy = Component.Clean
|
|
307
|
+
Component.Destroy = Component.Clean
|
|
308
|
+
Component.wrapClean = Component.WrapClean
|
|
309
|
+
Component.isEmpty = Component.IsEmpty
|
|
310
|
+
Component.link = Component.LinkToInstance
|
|
311
|
+
|
|
312
|
+
return Constructor
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rbxts/evxryy-collect",
|
|
3
|
+
"version": "1.3.2",
|
|
4
|
+
"description": "Garbage collection/cleanup utility module",
|
|
5
|
+
"main": "out/init.lua",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "rbxtsc",
|
|
8
|
+
"watch": "rbxtsc -w",
|
|
9
|
+
"prepublishOnly": "npm run build"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"url": "https://github.com/evxryyy/OpenEvxEngine/tree/main/Collect"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "evxryyy",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"type": "commonjs",
|
|
18
|
+
"types": "out/index.d.ts",
|
|
19
|
+
"typings": "out/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"out",
|
|
22
|
+
"!**/*.tsbuildinfo"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@rbxts/compiler-types": "^3.0.0-types.0",
|
|
29
|
+
"@rbxts/types": "^1.0.914",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^8.58.0",
|
|
31
|
+
"@typescript-eslint/parser": "^8.58.0",
|
|
32
|
+
"eslint": "^10.2.0",
|
|
33
|
+
"eslint-config-prettier": "^10.1.8",
|
|
34
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
35
|
+
"eslint-plugin-roblox-ts": "^1.4.0",
|
|
36
|
+
"prettier": "^3.8.1",
|
|
37
|
+
"roblox-ts": "^3.0.0",
|
|
38
|
+
"typescript": "^5.9.3"
|
|
39
|
+
}
|
|
40
|
+
}
|