@quenty/observablecollection 12.39.0 → 12.41.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,16 @@
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
+ # [12.41.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@12.40.0...@quenty/observablecollection@12.41.0) (2026-07-18)
7
+
8
+ ### Bug Fixes
9
+
10
+ - pin translation behavior with tests and fix camelCase key generation ([#737](https://github.com/Quenty/NevermoreEngine/issues/737)) ([1b7a536](https://github.com/Quenty/NevermoreEngine/commit/1b7a536dde7e124f8432e57612ec8138dd835d75))
11
+
12
+ # [12.40.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@12.39.0...@quenty/observablecollection@12.40.0) (2026-07-18)
13
+
14
+ **Note:** Version bump only for package @quenty/observablecollection
15
+
6
16
  # [12.39.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/observablecollection@12.38.1...@quenty/observablecollection@12.39.0) (2026-07-14)
7
17
 
8
18
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/observablecollection",
3
- "version": "12.39.0",
3
+ "version": "12.41.0",
4
4
  "description": "A set of observable collections, such as sets, maps, sorted lists, and more.",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -30,28 +30,28 @@
30
30
  "Quenty"
31
31
  ],
32
32
  "dependencies": {
33
- "@quenty/baseobject": "10.13.0",
33
+ "@quenty/baseobject": "10.14.0",
34
34
  "@quenty/binarysearch": "2.4.0",
35
- "@quenty/brio": "14.30.1",
35
+ "@quenty/brio": "14.32.0",
36
36
  "@quenty/ducktype": "5.11.0",
37
- "@quenty/instanceutils": "13.30.1",
37
+ "@quenty/instanceutils": "13.32.0",
38
38
  "@quenty/loader": "10.11.0",
39
- "@quenty/maid": "3.9.0",
39
+ "@quenty/maid": "3.10.0",
40
40
  "@quenty/nevermore-test-runner": "1.4.0",
41
- "@quenty/promise": "10.18.1",
42
- "@quenty/rx": "13.28.3",
41
+ "@quenty/promise": "10.20.0",
42
+ "@quenty/rx": "13.30.0",
43
43
  "@quenty/signal": "7.13.1",
44
44
  "@quenty/steputils": "3.6.3",
45
45
  "@quenty/symbol": "3.5.2",
46
46
  "@quenty/table": "3.9.2",
47
- "@quenty/valueobject": "13.31.1",
47
+ "@quenty/valueobject": "13.33.0",
48
48
  "@quentystudios/jest-lua": "3.10.0-quenty.2"
49
49
  },
50
50
  "devDependencies": {
51
- "@quenty/blend": "12.37.0"
51
+ "@quenty/blend": "12.39.0"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"
55
55
  },
56
- "gitHead": "13f0162f4971a77378e55e9b7236aea94f0dd3a8"
56
+ "gitHead": "647acfad93dca41c38f59cda247d2bfc0fff36d4"
57
57
  }
@@ -1,11 +1,9 @@
1
- --!nonstrict
1
+ --!strict
2
2
  --[[
3
3
  @class ObservableCountingMap.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local ObservableCountingMap = require("ObservableCountingMap")
@@ -1,11 +1,9 @@
1
- --!nonstrict
1
+ --!strict
2
2
  --[[
3
3
  @class ObservableList.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local ObservableList = require("ObservableList")
@@ -37,7 +35,7 @@ describe("ObservableList.new()", function()
37
35
 
38
36
  it("should allow false as a value", function()
39
37
  expect(observableList:Get(2)).toEqual(nil)
40
- observableList:Add(false)
38
+ observableList:Add(false :: any)
41
39
  expect(observableList:Get(2)).toEqual(false)
42
40
  end)
43
41
 
@@ -1,11 +1,9 @@
1
- --!nonstrict
1
+ --!strict
2
2
  --[[
3
3
  @class ObservableMap.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local ObservableMap = require("ObservableMap")
@@ -39,9 +37,9 @@ describe("ObservableMap.new()", function()
39
37
  end)
40
38
 
41
39
  it("should allow false as a key", function()
42
- expect(observableMap:Get(false)).toEqual(nil)
43
- observableMap:Set(false, "Hello")
44
- expect(observableMap:Get(false)).toEqual("Hello")
40
+ expect(observableMap:Get(false :: any)).toEqual(nil)
41
+ observableMap:Set(false :: any, "Hello")
42
+ expect(observableMap:Get(false :: any)).toEqual("Hello")
45
43
  end)
46
44
 
47
45
  it("should fire off events for a specific key", function()
@@ -1,11 +1,9 @@
1
- --!nonstrict
1
+ --!strict
2
2
  --[[
3
3
  @class ObservableMapList.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local ObservableMapList = require("ObservableMapList")
@@ -3,9 +3,7 @@
3
3
  @class ObservableSortedList.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Brio = require("Brio")
11
9
  local Jest = require("Jest")
@@ -59,8 +57,9 @@ describe("ObservableSortedList", function()
59
57
  it("should accept an observable as sort value", function()
60
58
  local maid = Maid.new()
61
59
  local list = maid:Add(ObservableSortedList.new())
62
- list:Add("b", Rx.of(2))
63
- list:Add("a", Rx.of(1))
60
+ -- Cast: the recursive Observable type does not unify structurally inside Add's union.
61
+ list:Add("b", Rx.of(2) :: any)
62
+ list:Add("a", Rx.of(1) :: any)
64
63
 
65
64
  expect(list:Get(1)).toEqual("a")
66
65
  expect(list:Get(2)).toEqual("b")
@@ -332,7 +331,7 @@ describe("ObservableSortedList", function()
332
331
  local removeA = list:Add("a", 1)
333
332
  list:_testForceFireEvents()
334
333
 
335
- local seenBrios: { Brio.Brio<string> } = {}
334
+ local seenBrios: { Brio.Brio<string, any> } = {}
336
335
  local sub = list:ObserveItemsBrio():Subscribe(function(brio)
337
336
  table.insert(seenBrios, brio)
338
337
  end)
@@ -917,7 +916,7 @@ describe("ObservableSortedList", function()
917
916
  expect(list:GetList()).toEqual({ "a", "b", "c" })
918
917
 
919
918
  -- Emit nil - B should be removed from tree
920
- sortValue.Value = nil
919
+ sortValue.Value = nil :: any
921
920
  expect(list:GetList()).toEqual({ "a", "c" })
922
921
  expect(list:Contains("b")).toEqual(false)
923
922
 
@@ -943,7 +942,7 @@ describe("ObservableSortedList", function()
943
942
  expect(seenBrios[2]:IsDead()).toEqual(false)
944
943
 
945
944
  -- Emit nil - B's brio should die
946
- sortValue.Value = nil
945
+ sortValue.Value = nil :: any
947
946
  list:_testForceFireEvents()
948
947
 
949
948
  expect(seenBrios[2]:IsDead()).toEqual(true)
@@ -958,7 +957,7 @@ describe("ObservableSortedList", function()
958
957
  local list = maid:Add(ObservableSortedList.new())
959
958
 
960
959
  list:Add("a", 1)
961
- list:Add("b", Rx.EMPTY)
960
+ list:Add("b", Rx.EMPTY :: any)
962
961
  list:Add("c", 3)
963
962
 
964
963
  -- B should never enter the tree
@@ -989,7 +988,7 @@ describe("ObservableSortedList", function()
989
988
  expect(list:GetList()).toEqual({ "a", "b", "c" })
990
989
 
991
990
  -- Disappear
992
- sortValue.Value = nil
991
+ sortValue.Value = nil :: any
993
992
  expect(list:GetList()).toEqual({ "a", "c" })
994
993
 
995
994
  -- Reappear at different position
@@ -1012,7 +1011,7 @@ describe("ObservableSortedList", function()
1012
1011
  expect(list:GetList()).toEqual({ "a", "b", "c" })
1013
1012
 
1014
1013
  -- Go nil then come back in the same frame
1015
- sortValue.Value = nil
1014
+ sortValue.Value = nil :: any
1016
1015
  sortValue.Value = 2
1017
1016
 
1018
1017
  expect(list:GetList()).toEqual({ "a", "b", "c" })
@@ -1134,7 +1133,7 @@ describe("ObservableSortedList", function()
1134
1133
  expect(list:GetList()).toEqual({ "a", "b" })
1135
1134
 
1136
1135
  -- Set nil (removes from tree) then also call cleanup
1137
- sortValue.Value = nil
1136
+ sortValue.Value = nil :: any
1138
1137
  remove()
1139
1138
 
1140
1139
  expect(list:GetList()).toEqual({ "a" })
@@ -1248,7 +1247,7 @@ describe("ObservableSortedList", function()
1248
1247
  list:Add("b", sortValue:Observe())
1249
1248
  list:_testForceFireEvents()
1250
1249
 
1251
- local seenBrios: { Brio.Brio<string> } = {}
1250
+ local seenBrios: { Brio.Brio<string, any> } = {}
1252
1251
  local sub = list:ObserveItemsBrio():Subscribe(function(brio)
1253
1252
  table.insert(seenBrios, brio)
1254
1253
  end)
@@ -1256,7 +1255,7 @@ describe("ObservableSortedList", function()
1256
1255
  expect(#seenBrios).toEqual(2)
1257
1256
 
1258
1257
  -- Remove via nil
1259
- sortValue.Value = nil
1258
+ sortValue.Value = nil :: any
1260
1259
  list:_testForceFireEvents()
1261
1260
 
1262
1261
  expect(seenBrios[2]:IsDead()).toEqual(true)
@@ -3,9 +3,7 @@
3
3
  @class SortFunctionUtils.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local SortFunctionUtils = require("SortFunctionUtils")
@@ -59,7 +57,7 @@ describe("SortFunctionUtils", function()
59
57
  describe("emptyIterator", function()
60
58
  it("should return nothing", function()
61
59
  local count = 0
62
- for _ in SortFunctionUtils.emptyIterator do
60
+ for _ in SortFunctionUtils.emptyIterator :: any do
63
61
  count += 1
64
62
  end
65
63
  expect(count).toEqual(0)
@@ -3,9 +3,7 @@
3
3
  @class SortedNode.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local SortedNode = require("SortedNode")
@@ -70,6 +70,13 @@ function SortedNodeValue.__lt<T>(self: SortedNodeValue<T>, other: SortedNodeValu
70
70
  return self._compare(self._value, other._value) < 0
71
71
  end
72
72
 
73
+ function SortedNodeValue.__le<T>(self: SortedNodeValue<T>, other: SortedNodeValue<T>): boolean
74
+ assert(SortedNodeValue.isSortedNodeValue(other), "Bad other")
75
+ assert(other._compare == self._compare, "Bad compare")
76
+
77
+ return self._compare(self._value, other._value) <= 0
78
+ end
79
+
73
80
  function SortedNodeValue.__gt<T>(self: SortedNodeValue<T>, other: SortedNodeValue<T>): boolean
74
81
  assert(SortedNodeValue.isSortedNodeValue(other), "Bad other")
75
82
  assert(other._compare == self._compare, "Bad compare")
@@ -3,9 +3,7 @@
3
3
  @class SortedNodeValue.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local SortFunctionUtils = require("SortFunctionUtils")
@@ -3,9 +3,7 @@
3
3
  @class UnifiedChangedSpanTracker.spec.lua
4
4
  ]]
5
5
 
6
- local require = (require :: any)(
7
- game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent
8
- ).bootstrapStory(script) :: typeof(require(script.Parent.loader).load(script))
6
+ local require = require(script.Parent.loader).load(script)
9
7
 
10
8
  local Jest = require("Jest")
11
9
  local UnifiedChangedSpanTracker = require("UnifiedChangedSpanTracker")