@quenty/binder 8.17.0 → 8.18.0

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
+ # [8.18.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/binder@8.17.0...@quenty/binder@8.18.0) (2023-06-17)
7
+
8
+
9
+ ### Features
10
+
11
+ * Binders can be initialized by the ServiceBag directly instead of requireing a BinderProvider ([28ce17f](https://github.com/Quenty/NevermoreEngine/commit/28ce17fe254b7fdce115132244ca1a6e8693d24b))
12
+
13
+
14
+
15
+
16
+
6
17
  # [8.17.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/binder@8.16.0...@quenty/binder@8.17.0) (2023-06-05)
7
18
 
8
19
  **Note:** Version bump only for package @quenty/binder
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/binder",
3
- "version": "8.17.0",
3
+ "version": "8.18.0",
4
4
  "description": "Utility object to Bind a class to Roblox object, and associated helper methods",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -26,17 +26,18 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@quenty/baseobject": "^6.2.1",
29
- "@quenty/brio": "^8.13.0",
30
- "@quenty/instanceutils": "^7.14.0",
31
- "@quenty/linkutils": "^7.14.0",
29
+ "@quenty/brio": "^8.14.0",
30
+ "@quenty/instanceutils": "^7.15.0",
31
+ "@quenty/linkutils": "^7.15.0",
32
32
  "@quenty/loader": "^6.2.1",
33
33
  "@quenty/maid": "^2.5.0",
34
- "@quenty/promise": "^6.5.0",
34
+ "@quenty/promise": "^6.6.0",
35
+ "@quenty/rx": "^7.12.0",
35
36
  "@quenty/signal": "^2.4.0",
36
- "@quenty/valueobject": "^7.15.0"
37
+ "@quenty/valueobject": "^7.16.0"
37
38
  },
38
39
  "publishConfig": {
39
40
  "access": "public"
40
41
  },
41
- "gitHead": "d8ad8f8567843d3867b6c06c8c57ec4493672335"
42
+ "gitHead": "dc77d6de09e9eb9d3fd6dafd790c052d8393d38f"
42
43
  }
@@ -31,8 +31,10 @@ local CollectionService = game:GetService("CollectionService")
31
31
 
32
32
  local Maid = require("Maid")
33
33
  local MaidTaskUtils = require("MaidTaskUtils")
34
- local Signal = require("Signal")
34
+ local Observable = require("Observable")
35
35
  local promiseBoundClass = require("promiseBoundClass")
36
+ local Signal = require("Signal")
37
+ local Brio = require("Brio")
36
38
 
37
39
  local Binder = {}
38
40
  Binder.__index = Binder
@@ -65,22 +67,17 @@ Binder.ClassName = "Binder"
65
67
  @return Binder<T>
66
68
  ]=]
67
69
  function Binder.new(tagName, constructor, ...)
68
- local self = setmetatable({}, Binder)
70
+ assert(type(tagName) == "string", "Bad tagName")
69
71
 
70
- self._maid = Maid.new()
71
- self._tagName = tagName or error("Bad argument 'tagName', expected string")
72
- self._constructor = constructor or error("Bad argument 'constructor', expected table or function")
73
-
74
- self._instToClass = {} -- [inst] = class
75
- self._allClassSet = {} -- [class] = true
76
- self._pendingInstSet = {} -- [inst] = true
72
+ local self = setmetatable({}, Binder)
77
73
 
78
- self._listeners = {} -- [inst] = callback
79
- self._args = {...}
74
+ self._tagName = assert(tagName, "Bad argument 'tagName', expected string")
75
+ self._constructor = assert(constructor, "Bad argument 'constructor', expected table or function")
76
+ self.ServiceName = self._tagName .. "Binder"
80
77
 
81
- self._maid._warning = task.delay(5, function()
82
- warn(("Binder %q is not loaded. Call :Start() on it!"):format(self._tagName))
83
- end)
78
+ if select("#", ...) > 0 then
79
+ self._args = { ... }
80
+ end
84
81
 
85
82
  return self
86
83
  end
@@ -111,10 +108,60 @@ function Binder.isBinder(value)
111
108
  and type(value.Destroy) == "function"
112
109
  end
113
110
 
111
+ --[=[
112
+ Initializes the Binder. Designed to be done via ServiceBag.
113
+
114
+ @param ... any
115
+ ]=]
116
+ function Binder:Init(...)
117
+ if self._initialized then
118
+ return
119
+ end
120
+
121
+ self._initialized = true
122
+ self._maid = Maid.new()
123
+
124
+ self._instToClass = {} -- [inst] = class
125
+ self._allClassSet = {} -- [class] = true
126
+ self._pendingInstSet = {} -- [inst] = true
127
+
128
+ self._listeners = {} -- [inst] = callback
129
+
130
+ if select("#", ...) > 0 then
131
+ if not self._args then
132
+ self._args = {...}
133
+ elseif not self:_argsMatch(...) then
134
+ warn("[Binder.Init] - Non-matching args from :Init() and .new()")
135
+ end
136
+ end
137
+
138
+ self._maid._warning = task.delay(5, function()
139
+ warn(("Binder %q is not loaded. Call :Start() on it!"):format(self._tagName))
140
+ end)
141
+ end
142
+
143
+ function Binder:_argsMatch(...)
144
+ if #self._args ~= select("#", ...) then
145
+ return false
146
+ end
147
+
148
+ for index, value in pairs({...}) do
149
+ if self._args[index] ~= value then
150
+ return false
151
+ end
152
+ end
153
+
154
+ return true
155
+ end
156
+
114
157
  --[=[
115
158
  Listens for new instances and connects to the GetInstanceAddedSignal() and removed signal!
116
159
  ]=]
117
160
  function Binder:Start()
161
+ if not self._initialized then
162
+ self:Init()
163
+ end
164
+
118
165
  if self._loaded then
119
166
  return
120
167
  end
@@ -151,9 +198,65 @@ function Binder:GetConstructor()
151
198
  return self._constructor
152
199
  end
153
200
 
201
+ --[=[
202
+ Observes the current value of the instance
203
+
204
+ @param instance Instance
205
+ @return Observable<T | nil>
206
+ ]=]
207
+ function Binder:Observe(instance)
208
+ assert(typeof(instance) == "Instance", "Bad instance")
209
+
210
+ return Observable.new(function(sub)
211
+ local maid = Maid.new()
212
+
213
+ maid:GiveTask(self:ObserveInstance(instance, function(...)
214
+ sub:Fire(...)
215
+ end))
216
+ sub:Fire(self:Get(instance))
217
+
218
+ return maid
219
+ end)
220
+ end
221
+
222
+ --[=[
223
+ Observes a bound class on a given instance.
224
+
225
+ @param instance Instance
226
+ @return Observable<Brio<T>>
227
+ ]=]
228
+ function Binder:ObserveBrio(instance)
229
+ assert(typeof(instance) == "Instance", "Bad instance")
230
+
231
+ return Observable.new(function(sub)
232
+ local maid = Maid.new()
233
+
234
+ local function handleClassChanged(class)
235
+ if class then
236
+ local brio = Brio.new(class)
237
+ maid._lastBrio = brio
238
+
239
+ sub:Fire(brio)
240
+ else
241
+ maid._lastBrio = nil
242
+ end
243
+ end
244
+
245
+ maid:GiveTask(self:ObserveInstance(instance, handleClassChanged))
246
+ handleClassChanged(self:Get(instance))
247
+
248
+ return maid
249
+ end)
250
+ end
251
+
154
252
  --[=[
155
253
  Fired when added, and then after removal, but before destroy!
156
254
 
255
+ ```info
256
+ This is before [Rx] so it doesn't follow the same Rx pattern. See [Binder.Observe] for
257
+ an [Rx] compatible interface.
258
+ ```
259
+
157
260
  @param inst Instance
158
261
  @param callback function
159
262
  @return function -- Cleanup function
@@ -308,6 +411,28 @@ function Binder:Bind(inst)
308
411
  return self:Get(inst)
309
412
  end
310
413
 
414
+ --[=[
415
+ Tags the instance with the tag for the binder
416
+
417
+ @param inst Instance
418
+ ]=]
419
+ function Binder:Tag(inst)
420
+ assert(typeof(inst) == "Instance", "Bad inst")
421
+
422
+ CollectionService:AddTag(inst, self._tagName)
423
+ end
424
+
425
+ --[=[
426
+ Untags the instance with the tag for the binder
427
+
428
+ @param inst Instance
429
+ ]=]
430
+ function Binder:Untag(inst)
431
+ assert(typeof(inst) == "Instance", "Bad inst")
432
+
433
+ CollectionService:RemoveTag(inst, self._tagName)
434
+ end
435
+
311
436
  --[=[
312
437
  Unbinds the instance by removing the tag.
313
438
 
@@ -117,6 +117,10 @@ function BinderProvider:Init(...)
117
117
 
118
118
  self._initMethod(self, ...)
119
119
 
120
+ for _, binder in pairs(self._binders) do
121
+ binder:Init(...)
122
+ end
123
+
120
124
  self._bindersAddedPromise:Resolve()
121
125
  end
122
126