@quenty/valueobject 13.17.0 → 13.17.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 +9 -9
- package/src/Shared/ValueObject.lua +86 -61
- package/src/Shared/ValueObjectUtils.lua +7 -5
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
|
+
## [13.17.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/valueobject@13.17.0...@quenty/valueobject@13.17.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
|
# [13.17.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/valueobject@13.16.2...@quenty/valueobject@13.17.0) (2025-04-02)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/valueobject
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/valueobject",
|
|
3
|
-
"version": "13.17.
|
|
3
|
+
"version": "13.17.1",
|
|
4
4
|
"description": "To work like value objects in Roblox and track a single item with .Changed events",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -26,16 +26,16 @@
|
|
|
26
26
|
"Quenty"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@quenty/brio": "^14.17.
|
|
30
|
-
"@quenty/ducktype": "^5.8.
|
|
31
|
-
"@quenty/loader": "^10.8.
|
|
32
|
-
"@quenty/maid": "^3.4.
|
|
33
|
-
"@quenty/rx": "^13.17.
|
|
34
|
-
"@quenty/signal": "^7.10.
|
|
35
|
-
"@quenty/valuebaseutils": "^13.17.
|
|
29
|
+
"@quenty/brio": "^14.17.1",
|
|
30
|
+
"@quenty/ducktype": "^5.8.2",
|
|
31
|
+
"@quenty/loader": "^10.8.1",
|
|
32
|
+
"@quenty/maid": "^3.4.1",
|
|
33
|
+
"@quenty/rx": "^13.17.1",
|
|
34
|
+
"@quenty/signal": "^7.10.1",
|
|
35
|
+
"@quenty/valuebaseutils": "^13.17.1"
|
|
36
36
|
},
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "78c3ac0ab08dd18085b6e6e6e4f745e76ed99f68"
|
|
41
41
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
To work like value objects in Roblox and track a single item,
|
|
3
4
|
with `.Changed` events
|
|
@@ -14,23 +15,55 @@ local Observable = require("Observable")
|
|
|
14
15
|
local RxValueBaseUtils = require("RxValueBaseUtils")
|
|
15
16
|
local Signal = require("Signal")
|
|
16
17
|
local ValueBaseUtils = require("ValueBaseUtils")
|
|
18
|
+
local _Subscription = require("Subscription")
|
|
19
|
+
local _Rx = require("Rx")
|
|
17
20
|
|
|
18
21
|
local EMPTY_FUNCTION = function() end
|
|
19
22
|
|
|
20
23
|
local ValueObject = {}
|
|
21
24
|
ValueObject.ClassName = "ValueObject"
|
|
22
25
|
|
|
26
|
+
export type TypeChecker = (value: any) -> (boolean, string?)
|
|
27
|
+
|
|
28
|
+
export type ValueObjectTypeArg = string | TypeChecker
|
|
29
|
+
|
|
30
|
+
export type ValueObject<T> = typeof(setmetatable(
|
|
31
|
+
{} :: {
|
|
32
|
+
--[=[
|
|
33
|
+
The value of the ValueObject
|
|
34
|
+
@prop Value T
|
|
35
|
+
@within ValueObject
|
|
36
|
+
]=]
|
|
37
|
+
Value: T,
|
|
38
|
+
|
|
39
|
+
--[=[
|
|
40
|
+
Event fires when the value's object value change
|
|
41
|
+
@prop Changed Signal<T> -- fires with oldValue, newValue, ...
|
|
42
|
+
@within ValueObject
|
|
43
|
+
]=]
|
|
44
|
+
Changed: Signal.Signal<(T, T, ...any)>,
|
|
45
|
+
LastEventContext: { any },
|
|
46
|
+
|
|
47
|
+
_checkType: ValueObjectTypeArg?,
|
|
48
|
+
_value: T,
|
|
49
|
+
_default: T?,
|
|
50
|
+
_lastEventContext: { any }?,
|
|
51
|
+
_lastMountedSub: _Subscription.Subscription<(T, ...any)>?,
|
|
52
|
+
},
|
|
53
|
+
ValueObject
|
|
54
|
+
))
|
|
55
|
+
|
|
23
56
|
--[=[
|
|
24
57
|
Constructs a new value object
|
|
25
58
|
@param baseValue T
|
|
26
|
-
@param checkType string |
|
|
59
|
+
@param checkType string? | (value: T) -> (boolean, string?)
|
|
27
60
|
@return ValueObject
|
|
28
61
|
]=]
|
|
29
|
-
function ValueObject.new(baseValue
|
|
62
|
+
function ValueObject.new<T>(baseValue: T?, checkType: ValueObjectTypeArg?): ValueObject<T>
|
|
30
63
|
local self = setmetatable({
|
|
31
|
-
_value = baseValue
|
|
32
|
-
_default = baseValue
|
|
33
|
-
_checkType = checkType
|
|
64
|
+
_value = baseValue,
|
|
65
|
+
_default = baseValue,
|
|
66
|
+
_checkType = checkType,
|
|
34
67
|
}, ValueObject)
|
|
35
68
|
|
|
36
69
|
if type(checkType) == "string" then
|
|
@@ -41,22 +74,16 @@ function ValueObject.new(baseValue, checkType)
|
|
|
41
74
|
assert(checkType(baseValue))
|
|
42
75
|
end
|
|
43
76
|
|
|
44
|
-
return self
|
|
77
|
+
return self :: any
|
|
45
78
|
end
|
|
46
79
|
|
|
47
|
-
--[=[
|
|
48
|
-
Event fires when the value's object value change
|
|
49
|
-
@prop Changed Signal<T> -- fires with oldValue, newValue, ...
|
|
50
|
-
@within ValueObject
|
|
51
|
-
]=]
|
|
52
|
-
|
|
53
80
|
--[=[
|
|
54
81
|
Returns the current check type, if any
|
|
55
82
|
|
|
56
|
-
@return string |
|
|
83
|
+
@return string? | (value: T) -> (boolean, string)
|
|
57
84
|
]=]
|
|
58
|
-
function ValueObject
|
|
59
|
-
return rawget(self, "_checkType")
|
|
85
|
+
function ValueObject.GetCheckType<T>(self: ValueObject<T>): ValueObjectTypeArg?
|
|
86
|
+
return rawget(self :: any, "_checkType")
|
|
60
87
|
end
|
|
61
88
|
|
|
62
89
|
--[=[
|
|
@@ -64,7 +91,7 @@ end
|
|
|
64
91
|
@param observable Observable<T>
|
|
65
92
|
@return ValueObject<T>
|
|
66
93
|
]=]
|
|
67
|
-
function ValueObject.fromObservable(observable)
|
|
94
|
+
function ValueObject.fromObservable<T>(observable: Observable.Observable<T>): ValueObject<T>
|
|
68
95
|
local result = ValueObject.new()
|
|
69
96
|
|
|
70
97
|
result:Mount(observable)
|
|
@@ -77,11 +104,11 @@ end
|
|
|
77
104
|
@param value any
|
|
78
105
|
@return boolean
|
|
79
106
|
]=]
|
|
80
|
-
function ValueObject.isValueObject(value)
|
|
107
|
+
function ValueObject.isValueObject(value: any): boolean
|
|
81
108
|
return DuckTypeUtils.isImplementation(ValueObject, value)
|
|
82
109
|
end
|
|
83
110
|
|
|
84
|
-
function ValueObject
|
|
111
|
+
function ValueObject._toMountableObservable<T>(_self: ValueObject<T>, value: T | Observable.Observable<T> | ValueBase)
|
|
85
112
|
if Observable.isObservable(value) then
|
|
86
113
|
return value
|
|
87
114
|
elseif typeof(value) == "Instance" then
|
|
@@ -91,9 +118,9 @@ function ValueObject:_toMountableObservable(value)
|
|
|
91
118
|
end
|
|
92
119
|
elseif type(value) == "table" then
|
|
93
120
|
if ValueObject.isValueObject(value) then
|
|
94
|
-
return value:Observe()
|
|
95
|
-
|
|
96
|
-
|
|
121
|
+
return (value :: any):Observe()
|
|
122
|
+
-- elseif Promise.isPromise(value) then
|
|
123
|
+
-- return Rx.fromPromise(value)
|
|
97
124
|
end
|
|
98
125
|
end
|
|
99
126
|
|
|
@@ -106,7 +133,7 @@ end
|
|
|
106
133
|
@param value Observable | T
|
|
107
134
|
@return MaidTask
|
|
108
135
|
]=]
|
|
109
|
-
function ValueObject
|
|
136
|
+
function ValueObject.Mount<T>(self: ValueObject<T>, value: Observable.Observable<T> | T | ValueBase): () -> ()
|
|
110
137
|
local observable = self:_toMountableObservable(value)
|
|
111
138
|
if observable then
|
|
112
139
|
self:_cleanupLastMountedSub()
|
|
@@ -115,36 +142,36 @@ function ValueObject:Mount(value)
|
|
|
115
142
|
ValueObject._applyValue(self, ...)
|
|
116
143
|
end)
|
|
117
144
|
|
|
118
|
-
rawset(self, "_lastMountedSub", sub)
|
|
145
|
+
rawset(self :: any, "_lastMountedSub", sub)
|
|
119
146
|
|
|
120
147
|
return function()
|
|
121
|
-
if rawget(self, "_lastMountedSub") == sub then
|
|
148
|
+
if rawget(self :: any, "_lastMountedSub") == sub then
|
|
122
149
|
self:_cleanupLastMountedSub()
|
|
123
150
|
end
|
|
124
151
|
end
|
|
125
152
|
else
|
|
126
153
|
self:_cleanupLastMountedSub()
|
|
127
154
|
|
|
128
|
-
ValueObject._applyValue(self, value)
|
|
155
|
+
ValueObject._applyValue(self, value :: T)
|
|
129
156
|
|
|
130
157
|
return EMPTY_FUNCTION
|
|
131
158
|
end
|
|
132
159
|
end
|
|
133
160
|
|
|
134
|
-
function ValueObject
|
|
135
|
-
local lastSub = rawget(self, "_lastMountedSub")
|
|
161
|
+
function ValueObject._cleanupLastMountedSub<T>(self: ValueObject<T>)
|
|
162
|
+
local lastSub = rawget(self :: any, "_lastMountedSub")
|
|
136
163
|
if lastSub then
|
|
137
|
-
rawset(self, "_lastMountedSub", nil)
|
|
164
|
+
rawset(self :: any, "_lastMountedSub", nil)
|
|
138
165
|
MaidTaskUtils.doTask(lastSub)
|
|
139
166
|
end
|
|
140
167
|
end
|
|
141
168
|
|
|
142
169
|
--[=[
|
|
143
170
|
Observes the current value of the ValueObject
|
|
144
|
-
@return Observable<T
|
|
171
|
+
@return Observable<T?>
|
|
145
172
|
]=]
|
|
146
|
-
function ValueObject
|
|
147
|
-
local found = rawget(self, "_observable")
|
|
173
|
+
function ValueObject.Observe<T>(self: ValueObject<T>): Observable.Observable<T?>
|
|
174
|
+
local found = rawget(self :: any, "_observable")
|
|
148
175
|
if found then
|
|
149
176
|
return found
|
|
150
177
|
end
|
|
@@ -161,8 +188,8 @@ function ValueObject:Observe()
|
|
|
161
188
|
sub:Fire(newValue, ...)
|
|
162
189
|
end)
|
|
163
190
|
|
|
164
|
-
local args = rawget(self, "_lastEventContext")
|
|
165
|
-
local value = rawget(self, "_value")
|
|
191
|
+
local args = rawget(self :: any, "_lastEventContext")
|
|
192
|
+
local value = rawget(self :: any, "_value")
|
|
166
193
|
if args then
|
|
167
194
|
sub:Fire(value, table.unpack(args, 1, args.n))
|
|
168
195
|
else
|
|
@@ -173,7 +200,7 @@ function ValueObject:Observe()
|
|
|
173
200
|
end)
|
|
174
201
|
|
|
175
202
|
-- We use a lot of these so let's cache the result which reduces the number of tables we have here
|
|
176
|
-
rawset(self, "_observable", created)
|
|
203
|
+
rawset(self :: any, "_observable", created)
|
|
177
204
|
return created
|
|
178
205
|
end
|
|
179
206
|
|
|
@@ -183,7 +210,10 @@ end
|
|
|
183
210
|
@param condition function | nil -- optional
|
|
184
211
|
@return Observable<Brio<T>>
|
|
185
212
|
]=]
|
|
186
|
-
function ValueObject
|
|
213
|
+
function ValueObject.ObserveBrio<T>(
|
|
214
|
+
self: ValueObject<T>,
|
|
215
|
+
condition: _Rx.Predicate<T>?
|
|
216
|
+
): Observable.Observable<Brio.Brio<T>>
|
|
187
217
|
assert(type(condition) == "function" or condition == nil, "Bad condition")
|
|
188
218
|
|
|
189
219
|
return Observable.new(function(sub)
|
|
@@ -196,7 +226,7 @@ function ValueObject:ObserveBrio(condition)
|
|
|
196
226
|
|
|
197
227
|
local maid = Maid.new()
|
|
198
228
|
|
|
199
|
-
local function handleNewValue(newValue, ...)
|
|
229
|
+
local function handleNewValue(newValue: T, ...)
|
|
200
230
|
if not condition or condition(newValue) then
|
|
201
231
|
local brio = Brio.new(newValue, ...)
|
|
202
232
|
maid._current = brio
|
|
@@ -206,11 +236,11 @@ function ValueObject:ObserveBrio(condition)
|
|
|
206
236
|
end
|
|
207
237
|
end
|
|
208
238
|
|
|
209
|
-
maid:GiveTask(self.Changed:Connect(function(newValue,
|
|
239
|
+
maid:GiveTask(self.Changed:Connect(function(newValue, _previous, ...)
|
|
210
240
|
handleNewValue(newValue, ...)
|
|
211
241
|
end))
|
|
212
242
|
|
|
213
|
-
local args = rawget(self, "_lastEventContext")
|
|
243
|
+
local args = rawget(self :: any, "_lastEventContext")
|
|
214
244
|
if args then
|
|
215
245
|
handleNewValue(self.Value, table.unpack(args, 1, args.n))
|
|
216
246
|
else
|
|
@@ -218,7 +248,7 @@ function ValueObject:ObserveBrio(condition)
|
|
|
218
248
|
end
|
|
219
249
|
|
|
220
250
|
return maid
|
|
221
|
-
end)
|
|
251
|
+
end) :: any
|
|
222
252
|
end
|
|
223
253
|
|
|
224
254
|
--[=[
|
|
@@ -237,21 +267,21 @@ end
|
|
|
237
267
|
@param ... any -- Additional args. Can be used to pass event changing state args with value
|
|
238
268
|
@return () -> () -- Cleanup
|
|
239
269
|
]=]
|
|
240
|
-
function ValueObject
|
|
270
|
+
function ValueObject.SetValue<T>(self: ValueObject<T>, value: T, ...)
|
|
241
271
|
self:_cleanupLastMountedSub()
|
|
242
272
|
|
|
243
273
|
ValueObject._applyValue(self, value, ...)
|
|
244
274
|
|
|
245
275
|
return function()
|
|
246
|
-
if rawget(self, "_value") == value then
|
|
247
|
-
ValueObject._applyValue(self, rawget(self, "_default"))
|
|
276
|
+
if rawget(self :: any, "_value") == value then
|
|
277
|
+
ValueObject._applyValue(self, rawget(self :: any, "_default"))
|
|
248
278
|
end
|
|
249
279
|
end
|
|
250
280
|
end
|
|
251
281
|
|
|
252
|
-
function ValueObject
|
|
253
|
-
local previous = rawget(self, "_value")
|
|
254
|
-
local checkType = rawget(self, "_checkType")
|
|
282
|
+
function ValueObject._applyValue<T>(self: ValueObject<T>, value: T, ...)
|
|
283
|
+
local previous = rawget(self :: any, "_value")
|
|
284
|
+
local checkType = rawget(self :: any, "_checkType")
|
|
255
285
|
|
|
256
286
|
if type(checkType) == "string" then
|
|
257
287
|
if typeof(value) ~= checkType then
|
|
@@ -263,40 +293,35 @@ function ValueObject:_applyValue(value, ...)
|
|
|
263
293
|
|
|
264
294
|
if previous ~= value then
|
|
265
295
|
if select("#", ...) > 0 then
|
|
266
|
-
rawset(self, "_lastEventContext", table.pack(...))
|
|
296
|
+
rawset(self :: any, "_lastEventContext", table.pack(...))
|
|
267
297
|
else
|
|
268
|
-
rawset(self, "_lastEventContext", nil)
|
|
298
|
+
rawset(self :: any, "_lastEventContext", nil)
|
|
269
299
|
end
|
|
270
300
|
|
|
271
|
-
rawset(self, "_value", value)
|
|
272
|
-
local changed = rawget(self, "Changed")
|
|
301
|
+
rawset(self :: any, "_value", value)
|
|
302
|
+
local changed = rawget(self :: any, "Changed")
|
|
273
303
|
if changed then
|
|
274
304
|
changed:Fire(value, previous, ...)
|
|
275
305
|
end
|
|
276
306
|
end
|
|
277
307
|
end
|
|
278
308
|
|
|
279
|
-
--[=[
|
|
280
|
-
The value of the ValueObject
|
|
281
|
-
@prop Value T
|
|
282
|
-
@within ValueObject
|
|
283
|
-
]=]
|
|
284
309
|
function ValueObject:__index(index)
|
|
285
310
|
if ValueObject[index] then
|
|
286
311
|
return ValueObject[index]
|
|
287
312
|
elseif index == "Value" then
|
|
288
|
-
return self
|
|
313
|
+
return rawget(self :: any, "_value")
|
|
289
314
|
elseif index == "Changed" then
|
|
290
315
|
-- Defer construction of Changed event until something needs it, since a lot
|
|
291
316
|
-- of times we don't need it
|
|
292
317
|
|
|
293
318
|
local signal = Signal.new() -- :Fire(newValue, oldValue, ...)
|
|
294
319
|
|
|
295
|
-
rawset(self, "Changed", signal)
|
|
320
|
+
rawset(self :: any, "Changed", signal)
|
|
296
321
|
|
|
297
322
|
return signal
|
|
298
323
|
elseif index == "LastEventContext" then
|
|
299
|
-
local args = rawget(self, "_lastEventContext")
|
|
324
|
+
local args = rawget(self :: any, "_lastEventContext")
|
|
300
325
|
if args then
|
|
301
326
|
return table.unpack(args, 1, args.n)
|
|
302
327
|
else
|
|
@@ -325,18 +350,18 @@ end
|
|
|
325
350
|
|
|
326
351
|
Does not fire the event since 3.5.0
|
|
327
352
|
]=]
|
|
328
|
-
function ValueObject
|
|
329
|
-
rawset(self, "_value", nil)
|
|
353
|
+
function ValueObject.Destroy<T>(self: ValueObject<T>)
|
|
354
|
+
rawset(self :: any, "_value", nil)
|
|
330
355
|
|
|
331
356
|
self:_cleanupLastMountedSub()
|
|
332
357
|
|
|
333
358
|
-- Avoid using a maid here because we make a LOT of ValueObjects
|
|
334
|
-
local changed = rawget(self, "Changed")
|
|
359
|
+
local changed = rawget(self :: any, "Changed")
|
|
335
360
|
if changed then
|
|
336
361
|
changed:Destroy()
|
|
337
362
|
end
|
|
338
363
|
|
|
339
|
-
setmetatable(self, nil)
|
|
364
|
+
setmetatable(self :: any, nil)
|
|
340
365
|
end
|
|
341
366
|
|
|
342
367
|
return ValueObject
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
--!strict
|
|
1
2
|
--[=[
|
|
2
3
|
Utils that work with Roblox Value objects (and also ValueObject)
|
|
3
4
|
@class ValueObjectUtils
|
|
@@ -18,7 +19,7 @@ local ValueObjectUtils = {}
|
|
|
18
19
|
@param to ValueObject<T>
|
|
19
20
|
@return MaidTask
|
|
20
21
|
]=]
|
|
21
|
-
function ValueObjectUtils.syncValue(from
|
|
22
|
+
function ValueObjectUtils.syncValue<T>(from: ValueObject.ValueObject<T>, to: ValueObject.ValueObject<T>): Maid.Maid
|
|
22
23
|
local maid = Maid.new()
|
|
23
24
|
to.Value = from.Value
|
|
24
25
|
|
|
@@ -31,10 +32,12 @@ end
|
|
|
31
32
|
|
|
32
33
|
--[=[
|
|
33
34
|
Observes the current value of the ValueObject
|
|
35
|
+
|
|
36
|
+
@deprecated 13.18.0
|
|
34
37
|
@param valueObject ValueObject<T>
|
|
35
38
|
@return Observable<T>
|
|
36
39
|
]=]
|
|
37
|
-
function ValueObjectUtils.observeValue(valueObject)
|
|
40
|
+
function ValueObjectUtils.observeValue<T>(valueObject: ValueObject.ValueObject<T>): Observable.Observable<T>
|
|
38
41
|
assert(ValueObject.isValueObject(valueObject), "Bad valueObject")
|
|
39
42
|
|
|
40
43
|
return valueObject:Observe()
|
|
@@ -45,7 +48,7 @@ end
|
|
|
45
48
|
@param valueObject ValueObject<T>
|
|
46
49
|
@return Observable<Brio<T>>
|
|
47
50
|
]=]
|
|
48
|
-
function ValueObjectUtils.observeValueBrio(valueObject)
|
|
51
|
+
function ValueObjectUtils.observeValueBrio<T>(valueObject: ValueObject.ValueObject<T>): Observable.Observable<Brio.Brio<T>>
|
|
49
52
|
assert(valueObject, "Bad valueObject")
|
|
50
53
|
|
|
51
54
|
return Observable.new(function(sub)
|
|
@@ -62,8 +65,7 @@ function ValueObjectUtils.observeValueBrio(valueObject)
|
|
|
62
65
|
refire()
|
|
63
66
|
|
|
64
67
|
return maid
|
|
65
|
-
end)
|
|
68
|
+
end) :: any
|
|
66
69
|
end
|
|
67
70
|
|
|
68
|
-
|
|
69
71
|
return ValueObjectUtils
|