@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 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.0",
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.0",
29
- "@quenty/brio": "^14.17.0",
30
- "@quenty/instanceutils": "^13.17.0",
31
- "@quenty/linkutils": "^13.17.0",
32
- "@quenty/loader": "^10.8.0",
33
- "@quenty/maid": "^3.4.0",
34
- "@quenty/promise": "^10.10.1",
35
- "@quenty/rx": "^13.17.0",
36
- "@quenty/signal": "^7.10.0",
37
- "@quenty/valueobject": "^13.17.0"
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": "e8ea56930e65322fcffc05a1556d5df988068f0b"
42
+ "gitHead": "78c3ac0ab08dd18085b6e6e6e4f745e76ed99f68"
43
43
  }
@@ -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 promiseBoundClass = require("promiseBoundClass")
37
+ local Promise = require("Promise")
36
38
  local Signal = require("Signal")
37
- local Brio = require("Brio")
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 pairs({...}) do
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:Start()
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 pairs(CollectionService:GetTagged(self._tagName)) do
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:GetTag()
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:GetConstructor()
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 | nil>
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:ObserveAllBrio()
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 pairs(self:GetAll()) do
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:ObserveBrio(instance)
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:ObserveInstance(inst, callback)
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:GetClassAddedSignal()
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:GetClassRemovingSignal()
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:GetClassRemovedSignal()
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 pairs(birdBinder:GetAll()) do
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:GetAll()
438
+ function Binder.GetAll<T>(self: Binder<T>): { T }
402
439
  local all = {}
403
- for class, _ in pairs(self._allClassSet) do
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]: boolean }
466
+ @return { [T]: true }
431
467
  ]=]
432
- function Binder:GetAllSet()
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:Bind(inst)
485
+ function Binder.Bind<T>(self: Binder<T>, inst: Instance): T?
450
486
  if RunService:IsClient() then
451
- warn(string.format("[Binder.Bind] - Bindings '%s' done on the client! Will be disrupted upon server replication! %s", self._tagName, debug.traceback()))
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:Tag(inst)
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:HasTag(inst)
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:Untag(inst)
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:Unbind(inst)
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(string.format("[Binder.Bind] - Unbinding '%s' done on the client! Might be disrupted upon server replication! %s", self._tagName, debug.traceback()))
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:BindClient(inst)
565
+ function Binder.BindClient<T>(self: Binder<T>, inst: Instance)
518
566
  if not RunService:IsClient() then
519
- warn(string.format("[Binder.BindClient] - Bindings '%s' done on the server! Will be replicated!", self._tagName))
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:UnbindClient(inst)
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:Get(inst)
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? CancelToken
602
+ @param cancelToken CancelToken?
553
603
  @return Promise<T>
554
604
  ]=]
555
- function Binder:Promise(inst, cancelToken)
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
- return promiseBoundClass(self, inst, cancelToken)
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 | nil
651
+ @param className string?
564
652
  @return Instance
565
653
  ]=]
566
- function Binder:Create(className)
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:_add(inst)
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 class
594
- if type(self._constructor) == "function" then
595
- class = self._constructor(inst, unpack(self._args))
596
- elseif self._constructor.Create then
597
- class = self._constructor:Create(inst, unpack(self._args))
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 = self._constructor.new(inst, unpack(self._args))
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(string.format("[Binder._add] - Failed to load instance %q of %q, removed while loading!",
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(self._constructor) == "table" and self._constructor.ClassName or self._constructor)))
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 pairs(listeners) do
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:_remove(inst)
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 pairs(listeners) do
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:Destroy()
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 pairs(binders) do
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 must be a string")
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("[BinderProvider] - Missing serviceName for binder provider. Please pass in a service name as the first argument.")
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 pairs(self._binders) do
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 pairs(self._binders) do
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 must be a string")
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 pairs(self._binders) do
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 pairs(parent:GetChildren()) do
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 pairs(parent:GetChildren()) do
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 pairs(bindersList) do
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 pairs(instanceList) do
113
- for _, tag in pairs(CollectionService:GetTags(instance)) do
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 pairs(parent:GetChildren()) do
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(string.format("[BinderUtils.getLinkedChildren] - Double linked children at %q", item:GetFullName()))
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 pairs(parent:GetDescendants()) do
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 pairs(self._classes) do
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 pairs(self._parent:GetChildren()) do
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 Promise = require("Promise")
9
- local Maid = require("Maid")
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, inst, cancelToken)
21
- assert(type(binder) == "table", "'binder' must be table")
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
- local class = binder:Get(inst)
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