@quenty/binder 14.19.0 → 14.19.1
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/CHANGELOG.md +11 -0
- package/package.json +12 -12
- package/src/Shared/Binder.lua +163 -70
- package/src/Shared/BinderGroup.lua +2 -2
- package/src/Shared/BinderGroupProvider.lua +2 -2
- package/src/Shared/BinderProvider.lua +10 -8
- package/src/Shared/BinderUtils.lua +13 -9
- package/src/Shared/Collection/BoundChildCollection.lua +3 -3
- package/src/Shared/Promise/promiseBoundClass.lua +14 -43
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [14.19.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/binder@14.19.0...@quenty/binder@14.19.1) (2025-04-05)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Add types to packages ([2374fb2](https://github.com/Quenty/NevermoreEngine/commit/2374fb2b043cfbe0e9b507b3316eec46a4e353a0))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [14.19.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/binder@14.18.2...@quenty/binder@14.19.0) (2025-04-02)
|
|
7
18
|
|
|
8
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/binder",
|
|
3
|
-
"version": "14.19.
|
|
3
|
+
"version": "14.19.1",
|
|
4
4
|
"description": "Utility object to Bind a class to Roblox object, and associated helper methods",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -25,19 +25,19 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/baseobject": "^10.8.
|
|
29
|
-
"@quenty/brio": "^14.17.
|
|
30
|
-
"@quenty/instanceutils": "^13.17.
|
|
31
|
-
"@quenty/linkutils": "^13.17.
|
|
32
|
-
"@quenty/loader": "^10.8.
|
|
33
|
-
"@quenty/maid": "^3.4.
|
|
34
|
-
"@quenty/promise": "^10.10.
|
|
35
|
-
"@quenty/rx": "^13.17.
|
|
36
|
-
"@quenty/signal": "^7.10.
|
|
37
|
-
"@quenty/valueobject": "^13.17.
|
|
28
|
+
"@quenty/baseobject": "^10.8.1",
|
|
29
|
+
"@quenty/brio": "^14.17.1",
|
|
30
|
+
"@quenty/instanceutils": "^13.17.1",
|
|
31
|
+
"@quenty/linkutils": "^13.17.1",
|
|
32
|
+
"@quenty/loader": "^10.8.1",
|
|
33
|
+
"@quenty/maid": "^3.4.1",
|
|
34
|
+
"@quenty/promise": "^10.10.2",
|
|
35
|
+
"@quenty/rx": "^13.17.1",
|
|
36
|
+
"@quenty/signal": "^7.10.1",
|
|
37
|
+
"@quenty/valueobject": "^13.17.1"
|
|
38
38
|
},
|
|
39
39
|
"publishConfig": {
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "78c3ac0ab08dd18085b6e6e6e4f745e76ed99f68"
|
|
43
43
|
}
|
package/src/Shared/Binder.lua
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Bind class to Roblox Instance
|
|
3
4
|
|
|
@@ -29,17 +30,53 @@ local require = require(script.Parent.loader).load(script)
|
|
|
29
30
|
local RunService = game:GetService("RunService")
|
|
30
31
|
local CollectionService = game:GetService("CollectionService")
|
|
31
32
|
|
|
33
|
+
local Brio = require("Brio")
|
|
32
34
|
local Maid = require("Maid")
|
|
33
35
|
local MaidTaskUtils = require("MaidTaskUtils")
|
|
34
36
|
local Observable = require("Observable")
|
|
35
|
-
local
|
|
37
|
+
local Promise = require("Promise")
|
|
36
38
|
local Signal = require("Signal")
|
|
37
|
-
local
|
|
39
|
+
local _CancelToken = require("CancelToken")
|
|
38
40
|
|
|
39
41
|
local Binder = {}
|
|
40
42
|
Binder.__index = Binder
|
|
41
43
|
Binder.ClassName = "Binder"
|
|
42
44
|
|
|
45
|
+
export type ConstructorCallback<T> = (Instance) -> T
|
|
46
|
+
|
|
47
|
+
export type ClassDefinition<T> = {
|
|
48
|
+
new: ConstructorCallback<T>,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type ProviderDefition<T> = {
|
|
52
|
+
Create: ConstructorCallback<T>,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type BinderConstructor<T> = ClassDefinition<T> | ProviderDefition<T> | ConstructorCallback<T>
|
|
56
|
+
|
|
57
|
+
export type Binder<T> = typeof(setmetatable(
|
|
58
|
+
{} :: {
|
|
59
|
+
ServiceName: string,
|
|
60
|
+
|
|
61
|
+
_tagName: string,
|
|
62
|
+
_defaultClassType: string,
|
|
63
|
+
_args: { any },
|
|
64
|
+
_constructor: BinderConstructor<T>,
|
|
65
|
+
|
|
66
|
+
_started: boolean,
|
|
67
|
+
_initialized: boolean,
|
|
68
|
+
_pendingInstSet: { [Instance]: true },
|
|
69
|
+
_instToClass: { [Instance]: T },
|
|
70
|
+
_allClassSet: { [T]: true },
|
|
71
|
+
_maid: Maid.Maid,
|
|
72
|
+
_listeners: { [Instance]: { [any]: true } },
|
|
73
|
+
_classAddedSignal: Signal.Signal<T, Instance>?,
|
|
74
|
+
_classRemovingSignal: Signal.Signal<T, Instance>?,
|
|
75
|
+
_classRemovedSignal: Signal.Signal<T, Instance>?,
|
|
76
|
+
},
|
|
77
|
+
Binder
|
|
78
|
+
))
|
|
79
|
+
|
|
43
80
|
--[=[
|
|
44
81
|
Constructor for a binder
|
|
45
82
|
@type BinderContructor (Instance, ...: any) -> T | { new: (Instance, ...: any) } | { Create(self, Instance, ...: any) }
|
|
@@ -66,7 +103,7 @@ Binder.ClassName = "Binder"
|
|
|
66
103
|
@param ... any -- Variable arguments that will be passed into the constructor
|
|
67
104
|
@return Binder<T>
|
|
68
105
|
]=]
|
|
69
|
-
function Binder.new(tagName, constructor
|
|
106
|
+
function Binder.new<T>(tagName: string, constructor: BinderConstructor<T>, ...): Binder<T>
|
|
70
107
|
assert(type(tagName) == "string", "Bad tagName")
|
|
71
108
|
|
|
72
109
|
local self = setmetatable({}, Binder)
|
|
@@ -84,7 +121,7 @@ function Binder.new(tagName, constructor, ...)
|
|
|
84
121
|
self._args = { ... }
|
|
85
122
|
end
|
|
86
123
|
|
|
87
|
-
return self
|
|
124
|
+
return self :: Binder<T>
|
|
88
125
|
end
|
|
89
126
|
|
|
90
127
|
--[=[
|
|
@@ -93,7 +130,7 @@ end
|
|
|
93
130
|
@param value any
|
|
94
131
|
@return boolean true or false, whether or not it is a value
|
|
95
132
|
]=]
|
|
96
|
-
function Binder.isBinder(value)
|
|
133
|
+
function Binder.isBinder(value: any): boolean
|
|
97
134
|
return type(value) == "table"
|
|
98
135
|
and type(value.Start) == "function"
|
|
99
136
|
and type(value.GetTag) == "function"
|
|
@@ -134,7 +171,7 @@ function Binder:Init(...)
|
|
|
134
171
|
|
|
135
172
|
if select("#", ...) > 0 then
|
|
136
173
|
if not self._args then
|
|
137
|
-
self._args = {...}
|
|
174
|
+
self._args = { ... }
|
|
138
175
|
elseif not self:_argsMatch(...) then
|
|
139
176
|
warn("[Binder.Init] - Non-matching args from :Init() and .new()")
|
|
140
177
|
end
|
|
@@ -153,7 +190,7 @@ function Binder:_argsMatch(...)
|
|
|
153
190
|
return false
|
|
154
191
|
end
|
|
155
192
|
|
|
156
|
-
for index, value in
|
|
193
|
+
for index, value in { ... } do
|
|
157
194
|
if self._args[index] ~= value then
|
|
158
195
|
return false
|
|
159
196
|
end
|
|
@@ -165,7 +202,7 @@ end
|
|
|
165
202
|
--[=[
|
|
166
203
|
Listens for new instances and connects to the GetInstanceAddedSignal() and removed signal!
|
|
167
204
|
]=]
|
|
168
|
-
function Binder
|
|
205
|
+
function Binder.Start<T>(self: Binder<T>)
|
|
169
206
|
if not self._initialized then
|
|
170
207
|
self:Init()
|
|
171
208
|
end
|
|
@@ -176,7 +213,7 @@ function Binder:Start()
|
|
|
176
213
|
self._maid._warning = nil
|
|
177
214
|
self._started = true
|
|
178
215
|
|
|
179
|
-
for _, inst in
|
|
216
|
+
for _, inst in CollectionService:GetTagged(self._tagName) do
|
|
180
217
|
task.spawn(self._add, self, inst)
|
|
181
218
|
end
|
|
182
219
|
|
|
@@ -192,7 +229,7 @@ end
|
|
|
192
229
|
Returns the tag name that the binder has.
|
|
193
230
|
@return string
|
|
194
231
|
]=]
|
|
195
|
-
function Binder
|
|
232
|
+
function Binder.GetTag<T>(self: Binder<T>): string
|
|
196
233
|
return self._tagName
|
|
197
234
|
end
|
|
198
235
|
|
|
@@ -202,7 +239,7 @@ end
|
|
|
202
239
|
|
|
203
240
|
@return BinderContructor
|
|
204
241
|
]=]
|
|
205
|
-
function Binder
|
|
242
|
+
function Binder.GetConstructor<T>(self: Binder<T>): BinderConstructor<T>
|
|
206
243
|
return self._constructor
|
|
207
244
|
end
|
|
208
245
|
|
|
@@ -210,9 +247,9 @@ end
|
|
|
210
247
|
Observes the current value of the instance
|
|
211
248
|
|
|
212
249
|
@param instance Instance
|
|
213
|
-
@return Observable<T
|
|
250
|
+
@return Observable<T?>
|
|
214
251
|
]=]
|
|
215
|
-
function Binder:Observe(instance)
|
|
252
|
+
function Binder:Observe(instance: Instance)
|
|
216
253
|
assert(typeof(instance) == "Instance", "Bad instance")
|
|
217
254
|
|
|
218
255
|
return Observable.new(function(sub)
|
|
@@ -232,20 +269,20 @@ end
|
|
|
232
269
|
|
|
233
270
|
@return Observable<Brio<T>>
|
|
234
271
|
]=]
|
|
235
|
-
function Binder
|
|
272
|
+
function Binder.ObserveAllBrio<T>(self: Binder<T>): Observable.Observable<Brio.Brio<T>>
|
|
236
273
|
return Observable.new(function(sub)
|
|
237
274
|
local maid = Maid.new()
|
|
238
275
|
|
|
239
|
-
local function handleNewClass(class)
|
|
276
|
+
local function handleNewClass(class: T)
|
|
240
277
|
local brio = Brio.new(class)
|
|
241
|
-
maid[class] = brio
|
|
278
|
+
maid[class :: any] = brio
|
|
242
279
|
|
|
243
280
|
sub:Fire(brio)
|
|
244
281
|
end
|
|
245
282
|
|
|
246
283
|
maid:GiveTask(self:GetClassAddedSignal():Connect(handleNewClass))
|
|
247
284
|
|
|
248
|
-
for _, item in
|
|
285
|
+
for _, item in self:GetAll() do
|
|
249
286
|
if not sub:IsPending() then
|
|
250
287
|
break
|
|
251
288
|
end
|
|
@@ -255,12 +292,12 @@ function Binder:ObserveAllBrio()
|
|
|
255
292
|
|
|
256
293
|
if sub:IsPending() then
|
|
257
294
|
maid:GiveTask(self:GetClassRemovingSignal():Connect(function(class)
|
|
258
|
-
maid[class] = nil
|
|
295
|
+
maid[class :: any] = nil
|
|
259
296
|
end))
|
|
260
297
|
end
|
|
261
298
|
|
|
262
299
|
return maid
|
|
263
|
-
end)
|
|
300
|
+
end) :: any
|
|
264
301
|
end
|
|
265
302
|
|
|
266
303
|
--[=[
|
|
@@ -269,7 +306,7 @@ end
|
|
|
269
306
|
@param instance Instance
|
|
270
307
|
@return Observable<Brio<T>>
|
|
271
308
|
]=]
|
|
272
|
-
function Binder
|
|
309
|
+
function Binder.ObserveBrio<T>(self: Binder<T>, instance: Instance): Observable.Observable<Brio.Brio<T>>
|
|
273
310
|
assert(typeof(instance) == "Instance", "Bad instance")
|
|
274
311
|
|
|
275
312
|
return Observable.new(function(sub)
|
|
@@ -290,7 +327,7 @@ function Binder:ObserveBrio(instance)
|
|
|
290
327
|
handleClassChanged(self:Get(instance))
|
|
291
328
|
|
|
292
329
|
return maid
|
|
293
|
-
end)
|
|
330
|
+
end) :: any
|
|
294
331
|
end
|
|
295
332
|
|
|
296
333
|
--[=[
|
|
@@ -305,7 +342,7 @@ end
|
|
|
305
342
|
@param callback function
|
|
306
343
|
@return function -- Cleanup function
|
|
307
344
|
]=]
|
|
308
|
-
function Binder
|
|
345
|
+
function Binder.ObserveInstance<T>(self: Binder<T>, inst: Instance, callback: (T?) -> ()): () -> ()
|
|
309
346
|
assert(typeof(inst) == "Instance", "Bad inst")
|
|
310
347
|
assert(type(callback) == "function", "Bad callback")
|
|
311
348
|
|
|
@@ -340,14 +377,14 @@ end
|
|
|
340
377
|
|
|
341
378
|
@return Signal<T>
|
|
342
379
|
]=]
|
|
343
|
-
function Binder
|
|
380
|
+
function Binder.GetClassAddedSignal<T>(self: Binder<T>): Signal.Signal<T, Instance>
|
|
344
381
|
if self._classAddedSignal then
|
|
345
382
|
return self._classAddedSignal
|
|
346
383
|
end
|
|
347
384
|
|
|
348
|
-
self._classAddedSignal = self._maid:Add(Signal.new()) -- :fire(class, inst)
|
|
385
|
+
self._classAddedSignal = self._maid:Add(Signal.new() :: any) -- :fire(class, inst)
|
|
349
386
|
|
|
350
|
-
return self._classAddedSignal
|
|
387
|
+
return self._classAddedSignal :: any
|
|
351
388
|
end
|
|
352
389
|
|
|
353
390
|
--[=[
|
|
@@ -355,14 +392,14 @@ end
|
|
|
355
392
|
|
|
356
393
|
@return Signal<T>
|
|
357
394
|
]=]
|
|
358
|
-
function Binder
|
|
395
|
+
function Binder.GetClassRemovingSignal<T>(self: Binder<T>): Signal.Signal<T, Instance>
|
|
359
396
|
if self._classRemovingSignal then
|
|
360
397
|
return self._classRemovingSignal
|
|
361
398
|
end
|
|
362
399
|
|
|
363
|
-
self._classRemovingSignal = self._maid:Add(Signal.new()) -- :fire(class, inst)
|
|
400
|
+
self._classRemovingSignal = self._maid:Add(Signal.new() :: any) -- :fire(class, inst)
|
|
364
401
|
|
|
365
|
-
return self._classRemovingSignal
|
|
402
|
+
return self._classRemovingSignal :: any
|
|
366
403
|
end
|
|
367
404
|
|
|
368
405
|
--[=[
|
|
@@ -370,14 +407,14 @@ end
|
|
|
370
407
|
|
|
371
408
|
@return Signal<T>
|
|
372
409
|
]=]
|
|
373
|
-
function Binder
|
|
410
|
+
function Binder.GetClassRemovedSignal<T>(self: Binder<T>): Signal.Signal<T, Instance>
|
|
374
411
|
if self._classRemovedSignal then
|
|
375
412
|
return self._classRemovedSignal
|
|
376
413
|
end
|
|
377
414
|
|
|
378
|
-
self._classRemovedSignal = self._maid:Add(Signal.new()) -- :fire(class, inst)
|
|
415
|
+
self._classRemovedSignal = self._maid:Add(Signal.new() :: any) -- :fire(class, inst)
|
|
379
416
|
|
|
380
|
-
return self._classRemovedSignal
|
|
417
|
+
return self._classRemovedSignal :: any
|
|
381
418
|
end
|
|
382
419
|
|
|
383
420
|
--[=[
|
|
@@ -388,7 +425,7 @@ end
|
|
|
388
425
|
|
|
389
426
|
-- Update every bird every frame
|
|
390
427
|
RunService.Stepped:Connect(function()
|
|
391
|
-
for _, bird in
|
|
428
|
+
for _, bird in birdBinder:GetAll() do
|
|
392
429
|
bird:Update()
|
|
393
430
|
end
|
|
394
431
|
end)
|
|
@@ -398,15 +435,14 @@ end
|
|
|
398
435
|
|
|
399
436
|
@return {T}
|
|
400
437
|
]=]
|
|
401
|
-
function Binder
|
|
438
|
+
function Binder.GetAll<T>(self: Binder<T>): { T }
|
|
402
439
|
local all = {}
|
|
403
|
-
for class, _ in
|
|
404
|
-
all[#all+1] = class
|
|
440
|
+
for class, _ in self._allClassSet do
|
|
441
|
+
all[#all + 1] = class
|
|
405
442
|
end
|
|
406
443
|
return all
|
|
407
444
|
end
|
|
408
445
|
|
|
409
|
-
|
|
410
446
|
--[=[
|
|
411
447
|
Faster method to get all items in a binder
|
|
412
448
|
|
|
@@ -427,9 +463,9 @@ end
|
|
|
427
463
|
Do not mutate this set directly
|
|
428
464
|
:::
|
|
429
465
|
|
|
430
|
-
@return { [T]:
|
|
466
|
+
@return { [T]: true }
|
|
431
467
|
]=]
|
|
432
|
-
function Binder
|
|
468
|
+
function Binder.GetAllSet<T>(self: Binder<T>): { [T]: true }
|
|
433
469
|
return self._allClassSet
|
|
434
470
|
end
|
|
435
471
|
|
|
@@ -446,9 +482,15 @@ end
|
|
|
446
482
|
@param inst Instance -- Instance to check
|
|
447
483
|
@return T? -- Bound class
|
|
448
484
|
]=]
|
|
449
|
-
function Binder
|
|
485
|
+
function Binder.Bind<T>(self: Binder<T>, inst: Instance): T?
|
|
450
486
|
if RunService:IsClient() then
|
|
451
|
-
warn(
|
|
487
|
+
warn(
|
|
488
|
+
string.format(
|
|
489
|
+
"[Binder.Bind] - Bindings '%s' done on the client! Will be disrupted upon server replication! %s",
|
|
490
|
+
self._tagName,
|
|
491
|
+
debug.traceback()
|
|
492
|
+
)
|
|
493
|
+
)
|
|
452
494
|
end
|
|
453
495
|
|
|
454
496
|
CollectionService:AddTag(inst, self._tagName)
|
|
@@ -460,7 +502,7 @@ end
|
|
|
460
502
|
|
|
461
503
|
@param inst Instance
|
|
462
504
|
]=]
|
|
463
|
-
function Binder
|
|
505
|
+
function Binder.Tag<T>(self: Binder<T>, inst: Instance)
|
|
464
506
|
assert(typeof(inst) == "Instance", "Bad inst")
|
|
465
507
|
|
|
466
508
|
CollectionService:AddTag(inst, self._tagName)
|
|
@@ -471,7 +513,7 @@ end
|
|
|
471
513
|
|
|
472
514
|
@param inst Instance
|
|
473
515
|
]=]
|
|
474
|
-
function Binder
|
|
516
|
+
function Binder.HasTag<T>(self: Binder<T>, inst: Instance): boolean
|
|
475
517
|
assert(typeof(inst) == "Instance", "Bad inst")
|
|
476
518
|
|
|
477
519
|
return CollectionService:HasTag(inst, self._tagName)
|
|
@@ -482,7 +524,7 @@ end
|
|
|
482
524
|
|
|
483
525
|
@param inst Instance
|
|
484
526
|
]=]
|
|
485
|
-
function Binder
|
|
527
|
+
function Binder.Untag<T>(self: Binder<T>, inst: Instance)
|
|
486
528
|
assert(typeof(inst) == "Instance", "Bad inst")
|
|
487
529
|
|
|
488
530
|
CollectionService:RemoveTag(inst, self._tagName)
|
|
@@ -494,11 +536,17 @@ end
|
|
|
494
536
|
@server
|
|
495
537
|
@param inst Instance -- Instance to unbind
|
|
496
538
|
]=]
|
|
497
|
-
function Binder
|
|
539
|
+
function Binder.Unbind<T>(self: Binder<T>, inst: Instance)
|
|
498
540
|
assert(typeof(inst) == "Instance", "Bad inst'")
|
|
499
541
|
|
|
500
542
|
if RunService:IsClient() then
|
|
501
|
-
warn(
|
|
543
|
+
warn(
|
|
544
|
+
string.format(
|
|
545
|
+
"[Binder.Bind] - Unbinding '%s' done on the client! Might be disrupted upon server replication! %s",
|
|
546
|
+
self._tagName,
|
|
547
|
+
debug.traceback()
|
|
548
|
+
)
|
|
549
|
+
)
|
|
502
550
|
end
|
|
503
551
|
|
|
504
552
|
CollectionService:RemoveTag(inst, self._tagName)
|
|
@@ -514,9 +562,11 @@ end
|
|
|
514
562
|
@param inst Instance -- Instance to bind
|
|
515
563
|
@return T? -- Bound class (potentially)
|
|
516
564
|
]=]
|
|
517
|
-
function Binder
|
|
565
|
+
function Binder.BindClient<T>(self: Binder<T>, inst: Instance)
|
|
518
566
|
if not RunService:IsClient() then
|
|
519
|
-
warn(
|
|
567
|
+
warn(
|
|
568
|
+
string.format("[Binder.BindClient] - Bindings '%s' done on the server! Will be replicated!", self._tagName)
|
|
569
|
+
)
|
|
520
570
|
end
|
|
521
571
|
|
|
522
572
|
CollectionService:AddTag(inst, self._tagName)
|
|
@@ -529,7 +579,7 @@ end
|
|
|
529
579
|
@client
|
|
530
580
|
@param inst Instance -- Instance to unbind
|
|
531
581
|
]=]
|
|
532
|
-
function Binder
|
|
582
|
+
function Binder.UnbindClient<T>(self: Binder<T>, inst: Instance)
|
|
533
583
|
assert(typeof(inst) == "Instance", "Bad inst")
|
|
534
584
|
CollectionService:RemoveTag(inst, self._tagName)
|
|
535
585
|
end
|
|
@@ -540,7 +590,7 @@ end
|
|
|
540
590
|
@param inst Instance -- Instance to check
|
|
541
591
|
@return T?
|
|
542
592
|
]=]
|
|
543
|
-
function Binder
|
|
593
|
+
function Binder.Get<T>(self: Binder<T>, inst: Instance): T?
|
|
544
594
|
assert(typeof(inst) == "Instance", "Argument 'inst' is not an Instance")
|
|
545
595
|
return self._instToClass[inst]
|
|
546
596
|
end
|
|
@@ -549,21 +599,59 @@ end
|
|
|
549
599
|
Returns a promise which will resolve when the instance is bound.
|
|
550
600
|
|
|
551
601
|
@param inst Instance -- Instance to check
|
|
552
|
-
@param cancelToken
|
|
602
|
+
@param cancelToken CancelToken?
|
|
553
603
|
@return Promise<T>
|
|
554
604
|
]=]
|
|
555
|
-
function Binder
|
|
605
|
+
function Binder.Promise<T>(self: Binder<T>, inst: Instance, cancelToken: _CancelToken.CancelToken?): Promise.Promise<T>
|
|
556
606
|
assert(typeof(inst) == "Instance", "Argument 'inst' is not an Instance")
|
|
557
|
-
|
|
607
|
+
|
|
608
|
+
local class = self:Get(inst)
|
|
609
|
+
if class then
|
|
610
|
+
return Promise.resolved(class)
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
local maid = Maid.new()
|
|
614
|
+
local promise = Promise.new()
|
|
615
|
+
|
|
616
|
+
if cancelToken then
|
|
617
|
+
cancelToken:ErrorIfCancelled()
|
|
618
|
+
maid:GivePromise(cancelToken.PromiseCancelled):Then(function()
|
|
619
|
+
promise:Reject()
|
|
620
|
+
end)
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
maid:GiveTask(self:ObserveInstance(inst, function(classAdded)
|
|
624
|
+
if classAdded then
|
|
625
|
+
promise:Resolve(classAdded)
|
|
626
|
+
end
|
|
627
|
+
end))
|
|
628
|
+
|
|
629
|
+
task.delay(5, function()
|
|
630
|
+
if promise:IsPending() then
|
|
631
|
+
warn(
|
|
632
|
+
string.format(
|
|
633
|
+
"[promiseBoundClass] - Infinite yield possible on %q for binder %q\n",
|
|
634
|
+
inst:GetFullName(),
|
|
635
|
+
self:GetTag()
|
|
636
|
+
)
|
|
637
|
+
)
|
|
638
|
+
end
|
|
639
|
+
end)
|
|
640
|
+
|
|
641
|
+
promise:Finally(function()
|
|
642
|
+
maid:Destroy()
|
|
643
|
+
end)
|
|
644
|
+
|
|
645
|
+
return promise
|
|
558
646
|
end
|
|
559
647
|
|
|
560
648
|
--[=[
|
|
561
649
|
Creates a new class tagged with this binder's instance
|
|
562
650
|
|
|
563
|
-
@param className string
|
|
651
|
+
@param className string?
|
|
564
652
|
@return Instance
|
|
565
653
|
]=]
|
|
566
|
-
function Binder
|
|
654
|
+
function Binder.Create<T>(self: Binder<T>, className: string): Instance
|
|
567
655
|
assert(type(className) == "string" or className == nil, "Bad className")
|
|
568
656
|
|
|
569
657
|
local instance = Instance.new(className or self._defaultClassType)
|
|
@@ -575,7 +663,7 @@ function Binder:Create(className)
|
|
|
575
663
|
return instance
|
|
576
664
|
end
|
|
577
665
|
|
|
578
|
-
function Binder
|
|
666
|
+
function Binder._add<T>(self: Binder<T>, inst: Instance)
|
|
579
667
|
assert(typeof(inst) == "Instance", "Argument 'inst' is not an Instance")
|
|
580
668
|
|
|
581
669
|
if self._instToClass[inst] then
|
|
@@ -590,28 +678,33 @@ function Binder:_add(inst)
|
|
|
590
678
|
|
|
591
679
|
self._pendingInstSet[inst] = true
|
|
592
680
|
|
|
593
|
-
local
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
681
|
+
local constructor: any = self._constructor
|
|
682
|
+
local class: T
|
|
683
|
+
if type(constructor) == "function" then
|
|
684
|
+
class = constructor(inst, unpack(self._args))
|
|
685
|
+
elseif constructor.Create then
|
|
686
|
+
class = constructor:Create(inst, unpack(self._args))
|
|
598
687
|
else
|
|
599
|
-
class =
|
|
688
|
+
class = constructor.new(inst, unpack(self._args))
|
|
600
689
|
end
|
|
601
690
|
|
|
602
691
|
if self._pendingInstSet[inst] ~= true then
|
|
603
692
|
-- Got GCed in the process of loading?!
|
|
604
693
|
-- Constructor probably yields. Yikes.
|
|
605
|
-
warn(
|
|
694
|
+
warn(
|
|
695
|
+
string.format(
|
|
696
|
+
"[Binder._add] - Failed to load instance %q of %q, removed while loading!",
|
|
606
697
|
inst:GetFullName(),
|
|
607
|
-
tostring(type(
|
|
698
|
+
tostring(type(constructor) == "table" and constructor.ClassName or constructor)
|
|
699
|
+
)
|
|
700
|
+
)
|
|
608
701
|
return
|
|
609
702
|
end
|
|
610
703
|
|
|
611
704
|
self._pendingInstSet[inst] = nil
|
|
612
705
|
assert(self._instToClass[inst] == nil, "Overwrote")
|
|
613
706
|
|
|
614
|
-
class = class or {}
|
|
707
|
+
class = class or {} :: any
|
|
615
708
|
|
|
616
709
|
-- Add to state
|
|
617
710
|
self._allClassSet[class] = true
|
|
@@ -620,7 +713,7 @@ function Binder:_add(inst)
|
|
|
620
713
|
-- Fire events
|
|
621
714
|
local listeners = self._listeners[inst]
|
|
622
715
|
if listeners then
|
|
623
|
-
for callback, _ in
|
|
716
|
+
for callback, _ in listeners do
|
|
624
717
|
task.spawn(callback, class)
|
|
625
718
|
end
|
|
626
719
|
end
|
|
@@ -630,7 +723,7 @@ function Binder:_add(inst)
|
|
|
630
723
|
end
|
|
631
724
|
end
|
|
632
725
|
|
|
633
|
-
function Binder
|
|
726
|
+
function Binder._remove<T>(self: Binder<T>, inst: Instance)
|
|
634
727
|
self._pendingInstSet[inst] = nil
|
|
635
728
|
|
|
636
729
|
local class = self._instToClass[inst]
|
|
@@ -650,7 +743,7 @@ function Binder:_remove(inst)
|
|
|
650
743
|
-- Fire listener here
|
|
651
744
|
local listeners = self._listeners[inst]
|
|
652
745
|
if listeners then
|
|
653
|
-
for callback, _ in
|
|
746
|
+
for callback, _ in listeners do
|
|
654
747
|
task.spawn(callback, nil)
|
|
655
748
|
end
|
|
656
749
|
end
|
|
@@ -668,9 +761,9 @@ end
|
|
|
668
761
|
--[=[
|
|
669
762
|
Cleans up all bound classes, and disconnects all events.
|
|
670
763
|
]=]
|
|
671
|
-
function Binder
|
|
764
|
+
function Binder.Destroy<T>(self: Binder<T>)
|
|
672
765
|
local inst, class = next(self._instToClass)
|
|
673
|
-
while class ~= nil do
|
|
766
|
+
while class ~= nil and inst ~= nil do
|
|
674
767
|
task.spawn(self._remove, self, inst)
|
|
675
768
|
inst, class = next(self._instToClass)
|
|
676
769
|
end
|
|
@@ -679,4 +772,4 @@ function Binder:Destroy()
|
|
|
679
772
|
self._maid:DoCleaning()
|
|
680
773
|
end
|
|
681
774
|
|
|
682
|
-
return Binder
|
|
775
|
+
return Binder
|
|
@@ -44,12 +44,12 @@ end
|
|
|
44
44
|
|
|
45
45
|
@param binders { Binder<T> }
|
|
46
46
|
]=]
|
|
47
|
-
function BinderGroup:AddList(binders)
|
|
47
|
+
function BinderGroup:AddList(binders: { any })
|
|
48
48
|
assert(type(binders) == "table", "Bad binders")
|
|
49
49
|
|
|
50
50
|
-- Assume to be using osyris's typechecking library,
|
|
51
51
|
-- we have an optional constructor to validate binder classes.
|
|
52
|
-
for _, binder in
|
|
52
|
+
for _, binder in binders do
|
|
53
53
|
self:Add(binder)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
@@ -71,8 +71,8 @@ end
|
|
|
71
71
|
@param groupName string
|
|
72
72
|
@return BinderGroup?
|
|
73
73
|
]=]
|
|
74
|
-
function BinderGroupProvider:Get(groupName)
|
|
75
|
-
assert(type(groupName) == "string", "groupName
|
|
74
|
+
function BinderGroupProvider:Get(groupName: string)
|
|
75
|
+
assert(type(groupName) == "string", "Bad groupName")
|
|
76
76
|
return rawget(self, groupName)
|
|
77
77
|
end
|
|
78
78
|
|
|
@@ -40,7 +40,7 @@ BinderProvider.__index = BinderProvider
|
|
|
40
40
|
@param initMethod (self, serviceBag: ServiceBag)
|
|
41
41
|
@return BinderProvider
|
|
42
42
|
]=]
|
|
43
|
-
function BinderProvider.new(serviceName, initMethod)
|
|
43
|
+
function BinderProvider.new(serviceName: string, initMethod)
|
|
44
44
|
local self = setmetatable({}, BinderProvider)
|
|
45
45
|
|
|
46
46
|
if type(serviceName) == "string" then
|
|
@@ -48,7 +48,9 @@ function BinderProvider.new(serviceName, initMethod)
|
|
|
48
48
|
else
|
|
49
49
|
-- Backwords compatibility (for now)
|
|
50
50
|
if type(serviceName) == "function" and initMethod == nil then
|
|
51
|
-
warn(
|
|
51
|
+
warn(
|
|
52
|
+
"[BinderProvider] - Missing serviceName for binder provider. Please pass in a service name as the first argument."
|
|
53
|
+
)
|
|
52
54
|
initMethod = serviceName
|
|
53
55
|
else
|
|
54
56
|
error("Bad serviceName")
|
|
@@ -68,7 +70,7 @@ end
|
|
|
68
70
|
@param value any
|
|
69
71
|
@return boolean -- True if it is a binder provider
|
|
70
72
|
]=]
|
|
71
|
-
function BinderProvider.isBinderProvider(value)
|
|
73
|
+
function BinderProvider.isBinderProvider(value: any): boolean
|
|
72
74
|
return type(value) == "table" and value.ClassName == "BinderProvider"
|
|
73
75
|
end
|
|
74
76
|
|
|
@@ -118,7 +120,7 @@ function BinderProvider:Init(...)
|
|
|
118
120
|
|
|
119
121
|
self._initMethod(self, ...)
|
|
120
122
|
|
|
121
|
-
for _, binder in
|
|
123
|
+
for _, binder in self._binders do
|
|
122
124
|
binder:Init(...)
|
|
123
125
|
end
|
|
124
126
|
|
|
@@ -151,7 +153,7 @@ function BinderProvider:Start()
|
|
|
151
153
|
assert(not self._started, "Already started")
|
|
152
154
|
|
|
153
155
|
self._started = true
|
|
154
|
-
for _, binder in
|
|
156
|
+
for _, binder in self._binders do
|
|
155
157
|
binder:Start()
|
|
156
158
|
end
|
|
157
159
|
|
|
@@ -176,8 +178,8 @@ end
|
|
|
176
178
|
@param tagName string
|
|
177
179
|
@return Binder<T>?
|
|
178
180
|
]=]
|
|
179
|
-
function BinderProvider:Get(tagName)
|
|
180
|
-
assert(type(tagName) == "string", "tagName
|
|
181
|
+
function BinderProvider:Get(tagName: string)
|
|
182
|
+
assert(type(tagName) == "string", "Bad tagName")
|
|
181
183
|
return rawget(self, tagName)
|
|
182
184
|
end
|
|
183
185
|
|
|
@@ -199,7 +201,7 @@ end
|
|
|
199
201
|
function BinderProvider:Destroy()
|
|
200
202
|
self._destroyed = true
|
|
201
203
|
|
|
202
|
-
for _, item in
|
|
204
|
+
for _, item in self._binders do
|
|
203
205
|
rawset(self, item:GetTag(), nil)
|
|
204
206
|
end
|
|
205
207
|
|
|
@@ -42,7 +42,7 @@ function BinderUtils.findFirstChild(binder, parent)
|
|
|
42
42
|
assert(type(binder) == "table", "Binder must be binder")
|
|
43
43
|
assert(typeof(parent) == "Instance", "Parent parameter must be instance")
|
|
44
44
|
|
|
45
|
-
for _, child in
|
|
45
|
+
for _, child in parent:GetChildren() do
|
|
46
46
|
local class = binder:Get(child)
|
|
47
47
|
if class then
|
|
48
48
|
return class
|
|
@@ -64,7 +64,7 @@ function BinderUtils.getChildren(binder, parent)
|
|
|
64
64
|
assert(typeof(parent) == "Instance", "Parent parameter must be instance")
|
|
65
65
|
|
|
66
66
|
local objects = {}
|
|
67
|
-
for _, item in
|
|
67
|
+
for _, item in parent:GetChildren() do
|
|
68
68
|
local obj = binder:Get(item)
|
|
69
69
|
if obj then
|
|
70
70
|
table.insert(objects, obj)
|
|
@@ -73,7 +73,6 @@ function BinderUtils.getChildren(binder, parent)
|
|
|
73
73
|
return objects
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
|
|
77
76
|
--[=[
|
|
78
77
|
Maps a list of binders into a look up table where the keys are
|
|
79
78
|
tags and the value is the binder.
|
|
@@ -87,7 +86,7 @@ function BinderUtils.mapBinderListToTable(bindersList)
|
|
|
87
86
|
assert(type(bindersList) == "table", "bindersList must be a table of binders")
|
|
88
87
|
|
|
89
88
|
local tags = {}
|
|
90
|
-
for _, binder in
|
|
89
|
+
for _, binder in bindersList do
|
|
91
90
|
tags[binder:GetTag()] = binder
|
|
92
91
|
end
|
|
93
92
|
return tags
|
|
@@ -109,8 +108,8 @@ end
|
|
|
109
108
|
function BinderUtils.getMappedFromList(tagsMap, instanceList)
|
|
110
109
|
local objects = {}
|
|
111
110
|
|
|
112
|
-
for _, instance in
|
|
113
|
-
for _, tag in
|
|
111
|
+
for _, instance in instanceList do
|
|
112
|
+
for _, tag in CollectionService:GetTags(instance) do
|
|
114
113
|
local binder = tagsMap[tag]
|
|
115
114
|
if binder then
|
|
116
115
|
local obj = binder:Get(instance)
|
|
@@ -150,7 +149,7 @@ end
|
|
|
150
149
|
function BinderUtils.getLinkedChildren(binder, linkName, parent)
|
|
151
150
|
local seen = {}
|
|
152
151
|
local objects = {}
|
|
153
|
-
for _, item in
|
|
152
|
+
for _, item in parent:GetChildren() do
|
|
154
153
|
if item.Name == linkName and item:IsA("ObjectValue") and item.Value then
|
|
155
154
|
local obj = binder:Get(item.Value)
|
|
156
155
|
if obj then
|
|
@@ -158,7 +157,12 @@ function BinderUtils.getLinkedChildren(binder, linkName, parent)
|
|
|
158
157
|
seen[obj] = true
|
|
159
158
|
table.insert(objects, obj)
|
|
160
159
|
else
|
|
161
|
-
warn(
|
|
160
|
+
warn(
|
|
161
|
+
string.format(
|
|
162
|
+
"[BinderUtils.getLinkedChildren] - Double linked children at %q",
|
|
163
|
+
item:GetFullName()
|
|
164
|
+
)
|
|
165
|
+
)
|
|
162
166
|
end
|
|
163
167
|
end
|
|
164
168
|
end
|
|
@@ -178,7 +182,7 @@ function BinderUtils.getDescendants(binder, parent)
|
|
|
178
182
|
assert(typeof(parent) == "Instance", "Parent parameter must be instance")
|
|
179
183
|
|
|
180
184
|
local objects = {}
|
|
181
|
-
for _, item in
|
|
185
|
+
for _, item in parent:GetDescendants() do
|
|
182
186
|
local obj = binder:Get(item)
|
|
183
187
|
if obj then
|
|
184
188
|
table.insert(objects, obj)
|
|
@@ -18,7 +18,7 @@ BoundChildCollection.__index = BoundChildCollection
|
|
|
18
18
|
@param parent Instance
|
|
19
19
|
@return BoundChildCollection<T>
|
|
20
20
|
]=]
|
|
21
|
-
function BoundChildCollection.new(binder, parent)
|
|
21
|
+
function BoundChildCollection.new(binder, parent: Instance)
|
|
22
22
|
local self = setmetatable(BaseObject.new(), BoundChildCollection)
|
|
23
23
|
|
|
24
24
|
self._binder = binder or error("No binder")
|
|
@@ -89,7 +89,7 @@ end
|
|
|
89
89
|
]=]
|
|
90
90
|
function BoundChildCollection:GetClasses()
|
|
91
91
|
local list = {}
|
|
92
|
-
for class, _ in
|
|
92
|
+
for class, _ in self._classes do
|
|
93
93
|
table.insert(list, class)
|
|
94
94
|
end
|
|
95
95
|
return list
|
|
@@ -104,7 +104,7 @@ function BoundChildCollection:_startTracking()
|
|
|
104
104
|
self:_removeChild(child)
|
|
105
105
|
end))
|
|
106
106
|
|
|
107
|
-
for _, child in
|
|
107
|
+
for _, child in self._parent:GetChildren() do
|
|
108
108
|
-- Specifically do not fire on init because nothing is listening
|
|
109
109
|
self:_addChild(child, true)
|
|
110
110
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Utility function to promise a bound class on an object
|
|
3
4
|
@class promiseBoundClass
|
|
@@ -5,52 +6,22 @@
|
|
|
5
6
|
|
|
6
7
|
local require = require(script.Parent.loader).load(script)
|
|
7
8
|
|
|
8
|
-
local
|
|
9
|
-
local
|
|
9
|
+
local Binder = require("Binder")
|
|
10
|
+
local _Promise = require("Promise")
|
|
11
|
+
local _CancelToken = require("CancelToken")
|
|
10
12
|
|
|
11
13
|
--[=[
|
|
12
|
-
Returns a promise that resolves when the class is bound to the instance.
|
|
13
|
-
@param binder Binder<T>
|
|
14
|
-
@param inst Instance
|
|
15
|
-
@param cancelToken CancelToken
|
|
16
|
-
@return Promise<T>
|
|
17
|
-
@function promiseBoundClass
|
|
18
|
-
@within promiseBoundClass
|
|
14
|
+
Returns a promise that resolves when the class is bound to the instance.
|
|
15
|
+
@param binder Binder<T>
|
|
16
|
+
@param inst Instance
|
|
17
|
+
@param cancelToken CancelToken
|
|
18
|
+
@return Promise<T>
|
|
19
|
+
@function promiseBoundClass
|
|
20
|
+
@within promiseBoundClass
|
|
19
21
|
]=]
|
|
20
|
-
return function(binder
|
|
21
|
-
assert(
|
|
22
|
+
return function<T>(binder: Binder.Binder<T>, inst: Instance, cancelToken: _CancelToken.CancelToken?): _Promise.Promise<T>
|
|
23
|
+
assert(Binder.isBinder(binder), "'binder' must be table")
|
|
22
24
|
assert(typeof(inst) == "Instance", "'inst' must be instance")
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
if class then
|
|
26
|
-
return Promise.resolved(class)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
local maid = Maid.new()
|
|
30
|
-
local promise = Promise.new()
|
|
31
|
-
|
|
32
|
-
if cancelToken then
|
|
33
|
-
cancelToken:ErrorIfCancelled()
|
|
34
|
-
maid:GivePromise(cancelToken.PromiseCancelled):Then(function()
|
|
35
|
-
promise:Reject()
|
|
36
|
-
end)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
maid:GiveTask(binder:ObserveInstance(inst, function(classAdded)
|
|
40
|
-
if classAdded then
|
|
41
|
-
promise:Resolve(classAdded)
|
|
42
|
-
end
|
|
43
|
-
end))
|
|
44
|
-
|
|
45
|
-
task.delay(5, function()
|
|
46
|
-
if promise:IsPending() then
|
|
47
|
-
warn(string.format("[promiseBoundClass] - Infinite yield possible on %q for binder %q\n", inst:GetFullName(), binder:GetTag()))
|
|
48
|
-
end
|
|
49
|
-
end)
|
|
50
|
-
|
|
51
|
-
promise:Finally(function()
|
|
52
|
-
maid:Destroy()
|
|
53
|
-
end)
|
|
54
|
-
|
|
55
|
-
return promise
|
|
26
|
+
return binder:Promise(inst, cancelToken)
|
|
56
27
|
end
|