@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 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
+ }