roblox-opencode 1.0.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.
Files changed (248) hide show
  1. package/README.md +122 -0
  2. package/commands/setup-game.md +108 -0
  3. package/commands/sync-check.md +53 -0
  4. package/core/roblox-core.md +93 -0
  5. package/dist/server.js +167 -0
  6. package/package.json +35 -0
  7. package/skills/roblox-analytics/SKILL.md +277 -0
  8. package/skills/roblox-analytics/references/event-batcher.luau +75 -0
  9. package/skills/roblox-animation-vfx/SKILL.md +1325 -0
  10. package/skills/roblox-architecture/SKILL.md +863 -0
  11. package/skills/roblox-architecture/references/combat-systems.md +1381 -0
  12. package/skills/roblox-code-review/SKILL.md +687 -0
  13. package/skills/roblox-data/SKILL.md +889 -0
  14. package/skills/roblox-data/references/inventory-systems.md +1729 -0
  15. package/skills/roblox-debug/SKILL.md +99 -0
  16. package/skills/roblox-gui/SKILL.md +1103 -0
  17. package/skills/roblox-gui-fusion/SKILL.md +150 -0
  18. package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
  19. package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
  20. package/skills/roblox-gui-fusion/references/shop.luau +411 -0
  21. package/skills/roblox-luau-mastery/SKILL.md +1519 -0
  22. package/skills/roblox-monetization/SKILL.md +1084 -0
  23. package/skills/roblox-monetization/references/process-receipt.luau +131 -0
  24. package/skills/roblox-networking/SKILL.md +669 -0
  25. package/skills/roblox-networking/references/remote-validator.luau +193 -0
  26. package/skills/roblox-publish-checklist/SKILL.md +128 -0
  27. package/skills/roblox-runtime/SKILL.md +753 -0
  28. package/skills/roblox-sharp-edges/SKILL.md +295 -0
  29. package/skills/roblox-sync/SKILL.md +126 -0
  30. package/skills/roblox-testing/SKILL.md +943 -0
  31. package/skills/roblox-tooling/SKILL.md +150 -0
  32. package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
  33. package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
  34. package/vendor/LICENSES/promise-LICENSE +21 -0
  35. package/vendor/LICENSES/t-LICENSE +21 -0
  36. package/vendor/LICENSES/testez-LICENSE +201 -0
  37. package/vendor/README.md +84 -0
  38. package/vendor/fusion/Animation/ExternalTime.luau +84 -0
  39. package/vendor/fusion/Animation/Spring.luau +322 -0
  40. package/vendor/fusion/Animation/Stopwatch.luau +128 -0
  41. package/vendor/fusion/Animation/Tween.luau +187 -0
  42. package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
  43. package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
  44. package/vendor/fusion/Animation/lerpType.luau +164 -0
  45. package/vendor/fusion/Animation/packType.luau +100 -0
  46. package/vendor/fusion/Animation/springCoefficients.luau +80 -0
  47. package/vendor/fusion/Animation/unpackType.luau +103 -0
  48. package/vendor/fusion/Colour/Oklab.luau +70 -0
  49. package/vendor/fusion/Colour/sRGB.luau +55 -0
  50. package/vendor/fusion/External.luau +168 -0
  51. package/vendor/fusion/ExternalDebug.luau +70 -0
  52. package/vendor/fusion/Graph/Observer.luau +114 -0
  53. package/vendor/fusion/Graph/castToGraph.luau +29 -0
  54. package/vendor/fusion/Graph/change.luau +81 -0
  55. package/vendor/fusion/Graph/depend.luau +33 -0
  56. package/vendor/fusion/Graph/evaluate.luau +56 -0
  57. package/vendor/fusion/Instances/Attribute.luau +58 -0
  58. package/vendor/fusion/Instances/AttributeChange.luau +47 -0
  59. package/vendor/fusion/Instances/AttributeOut.luau +63 -0
  60. package/vendor/fusion/Instances/Child.luau +21 -0
  61. package/vendor/fusion/Instances/Children.luau +148 -0
  62. package/vendor/fusion/Instances/Hydrate.luau +33 -0
  63. package/vendor/fusion/Instances/New.luau +53 -0
  64. package/vendor/fusion/Instances/OnChange.luau +50 -0
  65. package/vendor/fusion/Instances/OnEvent.luau +54 -0
  66. package/vendor/fusion/Instances/Out.luau +69 -0
  67. package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
  68. package/vendor/fusion/Instances/defaultProps.luau +194 -0
  69. package/vendor/fusion/LICENSE +21 -0
  70. package/vendor/fusion/Logging/formatError.luau +49 -0
  71. package/vendor/fusion/Logging/messages.luau +52 -0
  72. package/vendor/fusion/Logging/parseError.luau +25 -0
  73. package/vendor/fusion/Memory/checkLifetime.luau +134 -0
  74. package/vendor/fusion/Memory/deriveScope.luau +24 -0
  75. package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
  76. package/vendor/fusion/Memory/doCleanup.luau +79 -0
  77. package/vendor/fusion/Memory/innerScope.luau +34 -0
  78. package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
  79. package/vendor/fusion/Memory/needsDestruction.luau +17 -0
  80. package/vendor/fusion/Memory/poisonScope.luau +34 -0
  81. package/vendor/fusion/Memory/scopePool.luau +55 -0
  82. package/vendor/fusion/Memory/scoped.luau +27 -0
  83. package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
  84. package/vendor/fusion/RobloxExternal.luau +98 -0
  85. package/vendor/fusion/State/Computed.luau +139 -0
  86. package/vendor/fusion/State/For/Disassembly.luau +211 -0
  87. package/vendor/fusion/State/For/ForTypes.luau +30 -0
  88. package/vendor/fusion/State/For/init.luau +110 -0
  89. package/vendor/fusion/State/ForKeys.luau +94 -0
  90. package/vendor/fusion/State/ForPairs.luau +97 -0
  91. package/vendor/fusion/State/ForValues.luau +94 -0
  92. package/vendor/fusion/State/Value.luau +88 -0
  93. package/vendor/fusion/State/castToState.luau +26 -0
  94. package/vendor/fusion/State/peek.luau +31 -0
  95. package/vendor/fusion/State/updateAll.luau +1 -0
  96. package/vendor/fusion/Types.luau +314 -0
  97. package/vendor/fusion/Utility/Contextual.luau +91 -0
  98. package/vendor/fusion/Utility/Safe.luau +23 -0
  99. package/vendor/fusion/Utility/isSimilar.luau +29 -0
  100. package/vendor/fusion/Utility/merge.luau +35 -0
  101. package/vendor/fusion/Utility/nameOf.luau +35 -0
  102. package/vendor/fusion/Utility/never.luau +14 -0
  103. package/vendor/fusion/Utility/nicknames.luau +11 -0
  104. package/vendor/fusion/Utility/xtypeof.luau +27 -0
  105. package/vendor/fusion/init.luau +82 -0
  106. package/vendor/profilestore/init.luau +2243 -0
  107. package/vendor/promise/init.luau +1982 -0
  108. package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
  109. package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
  110. package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
  111. package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
  112. package/vendor/rbxutil/buffer-util/Types.luau +60 -0
  113. package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
  114. package/vendor/rbxutil/buffer-util/init.luau +41 -0
  115. package/vendor/rbxutil/buffer-util/package.json +16 -0
  116. package/vendor/rbxutil/buffer-util/wally.toml +9 -0
  117. package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
  118. package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
  119. package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
  120. package/vendor/rbxutil/comm/Client/init.luau +135 -0
  121. package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
  122. package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
  123. package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
  124. package/vendor/rbxutil/comm/Server/init.luau +140 -0
  125. package/vendor/rbxutil/comm/Types.luau +18 -0
  126. package/vendor/rbxutil/comm/Util.luau +27 -0
  127. package/vendor/rbxutil/comm/init.luau +35 -0
  128. package/vendor/rbxutil/comm/wally.toml +13 -0
  129. package/vendor/rbxutil/component/init.luau +759 -0
  130. package/vendor/rbxutil/component/init.test.luau +311 -0
  131. package/vendor/rbxutil/component/wally.toml +14 -0
  132. package/vendor/rbxutil/concur/init.luau +542 -0
  133. package/vendor/rbxutil/concur/init.test.luau +364 -0
  134. package/vendor/rbxutil/concur/wally.toml +8 -0
  135. package/vendor/rbxutil/enum-list/init.luau +101 -0
  136. package/vendor/rbxutil/enum-list/init.test.luau +91 -0
  137. package/vendor/rbxutil/enum-list/wally.toml +8 -0
  138. package/vendor/rbxutil/find/index.d.ts +20 -0
  139. package/vendor/rbxutil/find/init.luau +44 -0
  140. package/vendor/rbxutil/find/package.json +17 -0
  141. package/vendor/rbxutil/find/wally.toml +8 -0
  142. package/vendor/rbxutil/input/Gamepad.luau +559 -0
  143. package/vendor/rbxutil/input/Keyboard.luau +124 -0
  144. package/vendor/rbxutil/input/Mouse.luau +278 -0
  145. package/vendor/rbxutil/input/PreferredInput.luau +91 -0
  146. package/vendor/rbxutil/input/Touch.luau +120 -0
  147. package/vendor/rbxutil/input/init.luau +33 -0
  148. package/vendor/rbxutil/input/wally.toml +12 -0
  149. package/vendor/rbxutil/loader/index.d.ts +15 -0
  150. package/vendor/rbxutil/loader/init.luau +137 -0
  151. package/vendor/rbxutil/loader/wally.toml +8 -0
  152. package/vendor/rbxutil/log/index.d.ts +38 -0
  153. package/vendor/rbxutil/log/init.luau +746 -0
  154. package/vendor/rbxutil/log/wally.toml +8 -0
  155. package/vendor/rbxutil/net/init.luau +190 -0
  156. package/vendor/rbxutil/net/wally.toml +8 -0
  157. package/vendor/rbxutil/option/index.d.ts +44 -0
  158. package/vendor/rbxutil/option/init.luau +489 -0
  159. package/vendor/rbxutil/option/init.test.luau +342 -0
  160. package/vendor/rbxutil/option/wally.toml +8 -0
  161. package/vendor/rbxutil/pid/index.d.ts +53 -0
  162. package/vendor/rbxutil/pid/init.luau +195 -0
  163. package/vendor/rbxutil/pid/package.json +16 -0
  164. package/vendor/rbxutil/pid/wally.toml +9 -0
  165. package/vendor/rbxutil/quaternion/index.d.ts +117 -0
  166. package/vendor/rbxutil/quaternion/init.luau +570 -0
  167. package/vendor/rbxutil/quaternion/package.json +16 -0
  168. package/vendor/rbxutil/quaternion/wally.toml +9 -0
  169. package/vendor/rbxutil/query/index.d.ts +43 -0
  170. package/vendor/rbxutil/query/init.luau +117 -0
  171. package/vendor/rbxutil/query/package.json +18 -0
  172. package/vendor/rbxutil/query/wally.toml +9 -0
  173. package/vendor/rbxutil/sequent/index.d.ts +28 -0
  174. package/vendor/rbxutil/sequent/init.luau +340 -0
  175. package/vendor/rbxutil/sequent/package.json +16 -0
  176. package/vendor/rbxutil/sequent/wally.toml +9 -0
  177. package/vendor/rbxutil/ser/init.luau +175 -0
  178. package/vendor/rbxutil/ser/init.test.luau +50 -0
  179. package/vendor/rbxutil/ser/wally.toml +11 -0
  180. package/vendor/rbxutil/shake/index.d.ts +36 -0
  181. package/vendor/rbxutil/shake/init.luau +532 -0
  182. package/vendor/rbxutil/shake/init.test.luau +267 -0
  183. package/vendor/rbxutil/shake/package.json +16 -0
  184. package/vendor/rbxutil/shake/wally.toml +9 -0
  185. package/vendor/rbxutil/signal/index.d.ts +100 -0
  186. package/vendor/rbxutil/signal/init.luau +432 -0
  187. package/vendor/rbxutil/signal/init.test.luau +190 -0
  188. package/vendor/rbxutil/signal/package.json +17 -0
  189. package/vendor/rbxutil/signal/wally.toml +9 -0
  190. package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
  191. package/vendor/rbxutil/silo/Util.luau +55 -0
  192. package/vendor/rbxutil/silo/init.luau +338 -0
  193. package/vendor/rbxutil/silo/init.test.luau +215 -0
  194. package/vendor/rbxutil/silo/wally.toml +8 -0
  195. package/vendor/rbxutil/spring/index.d.ts +40 -0
  196. package/vendor/rbxutil/spring/init.luau +97 -0
  197. package/vendor/rbxutil/spring/package.json +17 -0
  198. package/vendor/rbxutil/spring/wally.toml +8 -0
  199. package/vendor/rbxutil/stream/index.d.ts +88 -0
  200. package/vendor/rbxutil/stream/init.luau +597 -0
  201. package/vendor/rbxutil/stream/package.json +18 -0
  202. package/vendor/rbxutil/stream/wally.toml +9 -0
  203. package/vendor/rbxutil/streamable/Streamable.luau +202 -0
  204. package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
  205. package/vendor/rbxutil/streamable/init.luau +8 -0
  206. package/vendor/rbxutil/streamable/wally.toml +12 -0
  207. package/vendor/rbxutil/symbol/init.luau +56 -0
  208. package/vendor/rbxutil/symbol/init.test.luau +37 -0
  209. package/vendor/rbxutil/symbol/wally.toml +8 -0
  210. package/vendor/rbxutil/table-util/init.luau +938 -0
  211. package/vendor/rbxutil/table-util/init.test.luau +439 -0
  212. package/vendor/rbxutil/table-util/wally.toml +8 -0
  213. package/vendor/rbxutil/task-queue/index.d.ts +27 -0
  214. package/vendor/rbxutil/task-queue/init.luau +97 -0
  215. package/vendor/rbxutil/task-queue/wally.toml +8 -0
  216. package/vendor/rbxutil/timer/index.d.ts +81 -0
  217. package/vendor/rbxutil/timer/init.luau +249 -0
  218. package/vendor/rbxutil/timer/init.test.luau +73 -0
  219. package/vendor/rbxutil/timer/wally.toml +11 -0
  220. package/vendor/rbxutil/tree/index.d.ts +15 -0
  221. package/vendor/rbxutil/tree/init.luau +137 -0
  222. package/vendor/rbxutil/tree/wally.toml +8 -0
  223. package/vendor/rbxutil/trove/index.d.ts +46 -0
  224. package/vendor/rbxutil/trove/init.luau +787 -0
  225. package/vendor/rbxutil/trove/init.test.luau +203 -0
  226. package/vendor/rbxutil/trove/wally.toml +8 -0
  227. package/vendor/rbxutil/typed-remote/init.luau +196 -0
  228. package/vendor/rbxutil/typed-remote/wally.toml +8 -0
  229. package/vendor/rbxutil/wait-for/index.d.ts +17 -0
  230. package/vendor/rbxutil/wait-for/init.luau +257 -0
  231. package/vendor/rbxutil/wait-for/init.test.luau +182 -0
  232. package/vendor/rbxutil/wait-for/wally.toml +11 -0
  233. package/vendor/t/t.lua +1350 -0
  234. package/vendor/testez/Context.lua +26 -0
  235. package/vendor/testez/Expectation.lua +311 -0
  236. package/vendor/testez/ExpectationContext.lua +38 -0
  237. package/vendor/testez/LifecycleHooks.lua +89 -0
  238. package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
  239. package/vendor/testez/Reporters/TextReporter.lua +106 -0
  240. package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
  241. package/vendor/testez/TestBootstrap.lua +147 -0
  242. package/vendor/testez/TestEnum.lua +28 -0
  243. package/vendor/testez/TestPlan.lua +304 -0
  244. package/vendor/testez/TestPlanner.lua +40 -0
  245. package/vendor/testez/TestResults.lua +112 -0
  246. package/vendor/testez/TestRunner.lua +188 -0
  247. package/vendor/testez/TestSession.lua +243 -0
  248. package/vendor/testez/init.lua +40 -0
@@ -0,0 +1,364 @@
1
+ local ServerScriptService = game:GetService("ServerScriptService")
2
+
3
+ local Test = require(ServerScriptService.TestRunner.Test)
4
+
5
+ return function(ctx: Test.TestContext)
6
+ local Concur = require(script.Parent)
7
+
8
+ local function Awaiter(timeout: number)
9
+ local awaiter = {}
10
+ local thread
11
+ local delayThread
12
+ function awaiter.Resume(...)
13
+ if coroutine.running() ~= delayThread then
14
+ task.cancel(delayThread)
15
+ end
16
+ task.spawn(thread, ...)
17
+ end
18
+ function awaiter.Yield()
19
+ thread = coroutine.running()
20
+ delayThread = task.delay(timeout, function()
21
+ awaiter.Resume()
22
+ end)
23
+ return coroutine.yield()
24
+ end
25
+ return awaiter
26
+ end
27
+
28
+ local bindableEvent
29
+ ctx:BeforeEach(function()
30
+ bindableEvent = Instance.new("BindableEvent")
31
+ end)
32
+ ctx:AfterEach(function()
33
+ bindableEvent:Destroy()
34
+ bindableEvent = nil
35
+ end)
36
+
37
+ ctx:Describe("Single", function()
38
+ ctx:Test("should spawn a new concur instance", function()
39
+ local value = nil
40
+ ctx:Expect(function()
41
+ Concur.spawn(function()
42
+ value = 10
43
+ end)
44
+ end)
45
+ :Not()
46
+ :ToThrow()
47
+ ctx:Expect(value):ToBe(10)
48
+ end)
49
+
50
+ ctx:Test("should defer a new concur instance", function()
51
+ local awaiter = Awaiter(1)
52
+ ctx:Expect(function()
53
+ Concur.defer(function()
54
+ awaiter.Resume(10)
55
+ end)
56
+ end)
57
+ :Not()
58
+ :ToThrow()
59
+ local value = awaiter.Yield()
60
+ ctx:Expect(value):ToBe(10)
61
+ end)
62
+
63
+ ctx:Test("should delay a new concur instance", function()
64
+ local awaiter = Awaiter(1)
65
+ ctx:Expect(function()
66
+ Concur.delay(0.1, function()
67
+ awaiter.Resume(10)
68
+ end)
69
+ end)
70
+ :Not()
71
+ :ToThrow()
72
+ local value = awaiter.Yield()
73
+ ctx:Expect(value):ToBe(10)
74
+ end)
75
+
76
+ ctx:Test("should create an immediate value concur instance", function()
77
+ local c
78
+ ctx:Expect(function()
79
+ c = Concur.value(10)
80
+ end)
81
+ :Not()
82
+ :ToThrow()
83
+ ctx:Expect(c):ToBeOk()
84
+ ctx:Expect(c:IsCompleted()):ToBe(true)
85
+ local err, val = c:Await()
86
+ ctx:Expect(err):ToBeNil()
87
+ ctx:Expect(val):ToBe(10)
88
+ end)
89
+
90
+ ctx:Test("should create a concur instance to watch an event with no predicate", function()
91
+ local c
92
+ ctx:Expect(function()
93
+ c = Concur.event(bindableEvent.Event)
94
+ end)
95
+ :Not()
96
+ :ToThrow()
97
+ ctx:Expect(c:IsCompleted()):ToBe(false)
98
+ bindableEvent:Fire(10)
99
+ local err, val = c:Await(1)
100
+ ctx:Expect(err):ToBeNil()
101
+ ctx:Expect(val):ToBe(10)
102
+ end)
103
+
104
+ ctx:Test("should create a concur instance to watch an event with a predicate", function()
105
+ local c
106
+ ctx:Expect(function()
107
+ c = Concur.event(bindableEvent.Event, function(v)
108
+ return v < 10
109
+ end)
110
+ end)
111
+ :Not()
112
+ :ToThrow()
113
+ ctx:Expect(c:IsCompleted()):ToBe(false)
114
+ bindableEvent:Fire(10)
115
+ bindableEvent:Fire(5)
116
+ local err, val = c:Await(1)
117
+ ctx:Expect(err):ToBeNil()
118
+ ctx:Expect(val):ToBe(5)
119
+ end)
120
+ end)
121
+
122
+ ctx:Describe("Multi", function()
123
+ ctx:Test("should complete all concur instances", function()
124
+ local c1 = Concur.spawn(function()
125
+ return 10
126
+ end)
127
+ local c2 = Concur.defer(function()
128
+ return 20
129
+ end)
130
+ local c3 = Concur.delay(0, function()
131
+ return 30
132
+ end)
133
+ local c4 = Concur.spawn(function()
134
+ error("fail")
135
+ end)
136
+ local c5 = Concur.event(bindableEvent.Event)
137
+ local c = Concur.all({ c1, c2, c3, c4, c5 })
138
+ ctx:Expect(c:IsCompleted()):ToBe(false)
139
+ bindableEvent:Fire(40)
140
+ local err, res = c:Await(1)
141
+ ctx:Expect(err):ToBeNil()
142
+ ctx:Expect(res[1][1]):ToBeNil()
143
+ ctx:Expect(res[1][2]):ToBe(10)
144
+ ctx:Expect(res[2][1]):ToBeNil()
145
+ ctx:Expect(res[2][2]):ToBe(20)
146
+ ctx:Expect(res[3][1]):ToBeNil()
147
+ ctx:Expect(res[3][2]):ToBe(30)
148
+ ctx:Expect(res[4][1]):ToBeOk()
149
+ ctx:Expect(res[4][2]):ToBeNil()
150
+ ctx:Expect(res[5][1]):ToBeNil()
151
+ ctx:Expect(res[5][2]):ToBe(40)
152
+ end)
153
+
154
+ ctx:Test("should complete the first concur instance", function()
155
+ local c1 = Concur.defer(function()
156
+ return 10
157
+ end)
158
+ local c2 = Concur.spawn(function()
159
+ return 20
160
+ end)
161
+ local c = Concur.first({ c1, c2 })
162
+ local err, res = c:Await(1)
163
+ ctx:Expect(err):ToBeNil()
164
+ ctx:Expect(res):ToBe(20)
165
+ end)
166
+ end)
167
+
168
+ ctx:Describe("Stop", function()
169
+ ctx:Test("should stop a single concur", function()
170
+ local c1 = Concur.defer(function()
171
+ return 10
172
+ end)
173
+ ctx:Expect(c1:IsCompleted()):ToBe(false)
174
+ c1:Stop()
175
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
176
+ local err, val = c1:Await()
177
+ ctx:Expect(err):ToBe(Concur.Errors.Stopped)
178
+ ctx:Expect(val):ToBeNil()
179
+ end)
180
+
181
+ ctx:Test("should stop multiple concurs", function()
182
+ local c1 = Concur.defer(function() end)
183
+ local c2 = Concur.delay(1, function() end)
184
+ local c3 = Concur.event(bindableEvent.Event)
185
+ local c = Concur.all({ c1, c2, c3 })
186
+ c:Stop()
187
+ local err, val = c:Await()
188
+ ctx:Expect(err):ToBe(Concur.Errors.Stopped)
189
+ ctx:Expect(val):ToBeNil()
190
+ end)
191
+
192
+ ctx:Test("should not stop an already completed concur", function()
193
+ local c1 = Concur.spawn(function()
194
+ return 10
195
+ end)
196
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
197
+ c1:Stop()
198
+ local err, val = c1:Await()
199
+ ctx:Expect(err):ToBeNil()
200
+ ctx:Expect(val):ToBe(10)
201
+ end)
202
+ end)
203
+
204
+ ctx:Describe("IsCompleted", function()
205
+ ctx:Test("should correctly check if a concur instance is completed", function()
206
+ local c1 = Concur.defer(function() end)
207
+ ctx:Expect(c1:IsCompleted()):ToBe(false)
208
+ local err = c1:Await()
209
+ ctx:Expect(err):ToBeNil()
210
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
211
+ end)
212
+
213
+ ctx:Test("should be marked as completed if error", function()
214
+ local c1 = Concur.spawn(function()
215
+ error("err")
216
+ end)
217
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
218
+ end)
219
+
220
+ ctx:Test("should be marked as completed if stopped", function()
221
+ local c1 = Concur.defer(function() end)
222
+ c1:Stop()
223
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
224
+ end)
225
+ end)
226
+
227
+ ctx:Describe("Await", function()
228
+ ctx:Test("should await concur to be completed", function()
229
+ local c1 = Concur.defer(function()
230
+ return 10
231
+ end)
232
+ local err, val = c1:Await(1)
233
+ ctx:Expect(err):ToBeNil()
234
+ ctx:Expect(val):ToBe(10)
235
+ end)
236
+
237
+ ctx:Test("should await concur to be completed even if error", function()
238
+ local c1 = Concur.defer(function()
239
+ return error("err")
240
+ end)
241
+ local err, val = c1:Await(1)
242
+ ctx:Expect(err):ToBeOk()
243
+ ctx:Expect(val):ToBeNil()
244
+ end)
245
+
246
+ ctx:Test("should await concur to be completed even if stopped", function()
247
+ local c1 = Concur.delay(0.1, function()
248
+ return 10
249
+ end)
250
+ task.defer(function()
251
+ c1:Stop()
252
+ end)
253
+ local err, val = c1:Await(1)
254
+ ctx:Expect(err):ToBe(Concur.Errors.Stopped)
255
+ ctx:Expect(val):ToBeNil()
256
+ end)
257
+
258
+ ctx:Test("should return completed values immediately if already completed", function()
259
+ local c1 = Concur.spawn(function()
260
+ return 10
261
+ end)
262
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
263
+ local err, val = c1:Await()
264
+ ctx:Expect(err):ToBeNil()
265
+ ctx:Expect(val):ToBe(10)
266
+ end)
267
+
268
+ ctx:Test("should timeout", function()
269
+ local c1 = Concur.delay(0.2, function()
270
+ return 10
271
+ end)
272
+ local err, val = c1:Await(0.1)
273
+ ctx:Expect(err):ToBe(Concur.Errors.Timeout)
274
+ ctx:Expect(val):ToBeNil()
275
+ err, val = c1:Await()
276
+ ctx:Expect(err):ToBeNil()
277
+ ctx:Expect(val):ToBe(10)
278
+ end)
279
+ end)
280
+
281
+ ctx:Describe("OnCompleted", function()
282
+ ctx:Test("should fire function once completed", function()
283
+ local awaiter = Awaiter(0.1)
284
+ local c1 = Concur.defer(function()
285
+ return 10
286
+ end)
287
+ ctx:Expect(c1:IsCompleted()):ToBe(false)
288
+ c1:OnCompleted(function(err, val)
289
+ awaiter.Resume(err, val)
290
+ end)
291
+ local err, val = awaiter.Yield()
292
+ ctx:Expect(err):ToBeNil()
293
+ ctx:Expect(val):ToBe(10)
294
+ end)
295
+
296
+ ctx:Test("should fire function even if already completed", function()
297
+ local c1 = Concur.spawn(function()
298
+ return 10
299
+ end)
300
+ ctx:Expect(c1:IsCompleted()):ToBe(true)
301
+ local err, val
302
+ c1:OnCompleted(function(e, v)
303
+ err, val = e, v
304
+ end)
305
+ ctx:Expect(err):ToBeNil()
306
+ ctx:Expect(val):ToBe(10)
307
+ end)
308
+
309
+ ctx:Test("should fire function even if error", function()
310
+ local awaiter = Awaiter(0.1)
311
+ local c1 = Concur.defer(function()
312
+ error("err")
313
+ end)
314
+ c1:OnCompleted(function(err, val)
315
+ awaiter.Resume(err, val)
316
+ end)
317
+ local err, val = awaiter.Yield()
318
+ ctx:Expect(err):ToBeOk()
319
+ ctx:Expect(val):ToBeNil()
320
+ end)
321
+
322
+ ctx:Test("should fire function even if stopped", function()
323
+ local awaiter = Awaiter(0.2)
324
+ local c1 = Concur.delay(0.1, function()
325
+ error("err")
326
+ end)
327
+ c1:OnCompleted(function(err, val)
328
+ awaiter.Resume(err, val)
329
+ end)
330
+ task.defer(function()
331
+ c1:Stop()
332
+ end)
333
+ local err, val = awaiter.Yield()
334
+ ctx:Expect(err):ToBe(Concur.Errors.Stopped)
335
+ ctx:Expect(val):ToBeNil()
336
+ end)
337
+
338
+ ctx:Test("should fire function even if timeout", function()
339
+ local awaiter = Awaiter(0.5)
340
+ local c1 = Concur.delay(0.2, function()
341
+ error("err")
342
+ end)
343
+ c1:OnCompleted(function(err, val)
344
+ awaiter.Resume(err, val)
345
+ end, 0.1)
346
+ local err, val = awaiter.Yield()
347
+ ctx:Expect(err):ToBe(Concur.Errors.Timeout)
348
+ ctx:Expect(val):ToBeNil()
349
+ end)
350
+
351
+ ctx:Test("should unbind function", function()
352
+ local c1 = Concur.defer(function() end)
353
+ local val = nil
354
+ local unbind = c1:OnCompleted(function()
355
+ val = 10
356
+ end)
357
+ unbind()
358
+ local err = c1:Await()
359
+ ctx:Expect(err):ToBeNil()
360
+ task.wait()
361
+ ctx:Expect(val):ToBeNil()
362
+ end)
363
+ end)
364
+ end
@@ -0,0 +1,8 @@
1
+ [package]
2
+ name = "sleitnick/concur"
3
+ description = "Concurrent task handler"
4
+ version = "0.1.2"
5
+ license = "MIT"
6
+ authors = ["Stephen Leitnick"]
7
+ registry = "https://github.com/UpliftGames/wally-index"
8
+ realm = "shared"
@@ -0,0 +1,101 @@
1
+ -- EnumList
2
+ -- Stephen Leitnick
3
+ -- January 08, 2021
4
+
5
+ type EnumNames = { string }
6
+
7
+ --[=[
8
+ @interface EnumItem
9
+ .Name string
10
+ .Value number
11
+ .EnumType EnumList
12
+ @within EnumList
13
+ ]=]
14
+ export type EnumItem = {
15
+ Name: string,
16
+ Value: number,
17
+ EnumType: any,
18
+ }
19
+
20
+ local LIST_KEY = newproxy()
21
+ local NAME_KEY = newproxy()
22
+
23
+ local function CreateEnumItem(name: string, value: number, enum: any): EnumItem
24
+ local enumItem = {
25
+ Name = name,
26
+ Value = value,
27
+ EnumType = enum,
28
+ }
29
+ table.freeze(enumItem)
30
+ return enumItem
31
+ end
32
+
33
+ --[=[
34
+ @class EnumList
35
+ Defines a new Enum.
36
+ ]=]
37
+ local EnumList = {}
38
+ EnumList.__index = EnumList
39
+
40
+ --[=[
41
+ @param name string
42
+ @param enums {string}
43
+ @return EnumList
44
+ Constructs a new EnumList.
45
+
46
+ ```lua
47
+ local directions = EnumList.new("Directions", {
48
+ "Up",
49
+ "Down",
50
+ "Left",
51
+ "Right",
52
+ })
53
+
54
+ local direction = directions.Up
55
+ ```
56
+ ]=]
57
+ function EnumList.new(name: string, enums: EnumNames)
58
+ assert(type(name) == "string", "Name string required")
59
+ assert(type(enums) == "table", "Enums table required")
60
+ local self = {}
61
+ self[LIST_KEY] = {}
62
+ self[NAME_KEY] = name
63
+ for i, enumName in ipairs(enums) do
64
+ assert(type(enumName) == "string", "Enum name must be a string")
65
+ local enumItem = CreateEnumItem(enumName, i, self)
66
+ self[enumName] = enumItem
67
+ table.insert(self[LIST_KEY], enumItem)
68
+ end
69
+ return table.freeze(setmetatable(self, EnumList))
70
+ end
71
+
72
+ --[=[
73
+ @param obj any
74
+ @return boolean
75
+ Returns `true` if `obj` belongs to the EnumList.
76
+ ]=]
77
+ function EnumList:BelongsTo(obj: any): boolean
78
+ return type(obj) == "table" and obj.EnumType == self
79
+ end
80
+
81
+ --[=[
82
+ Returns an array of all enum items.
83
+ @return {EnumItem}
84
+ @since v2.0.0
85
+ ]=]
86
+ function EnumList:GetEnumItems()
87
+ return self[LIST_KEY]
88
+ end
89
+
90
+ --[=[
91
+ Get the name of the enum.
92
+ @return string
93
+ @since v2.0.0
94
+ ]=]
95
+ function EnumList:GetName()
96
+ return self[NAME_KEY]
97
+ end
98
+
99
+ export type EnumList = typeof(EnumList.new(...))
100
+
101
+ return EnumList
@@ -0,0 +1,91 @@
1
+ local ServerScriptService = game:GetService("ServerScriptService")
2
+
3
+ local Test = require(ServerScriptService.TestRunner.Test)
4
+
5
+ return function(ctx: Test.TestContext)
6
+ local EnumList = require(script.Parent)
7
+
8
+ ctx:Describe("Constructor", function()
9
+ ctx:Test("should create a new enumlist", function()
10
+ ctx:Expect(function()
11
+ EnumList.new("Test", { "ABC", "XYZ" })
12
+ end)
13
+ :Not()
14
+ :ToThrow()
15
+ end)
16
+
17
+ ctx:Test("should fail to create a new enumlist with no name", function()
18
+ ctx:Expect(function()
19
+ EnumList.new(nil, { "ABC", "XYZ" })
20
+ end):ToThrow()
21
+ end)
22
+
23
+ ctx:Test("should fail to create a new enumlist with no enums", function()
24
+ ctx:Expect(function()
25
+ EnumList.new("Test")
26
+ end):ToThrow()
27
+ end)
28
+
29
+ ctx:Test("should fail to create a new enumlist with non string enums", function()
30
+ ctx:Expect(function()
31
+ EnumList.new("Test", { true, false, 32, "ABC" })
32
+ end):ToThrow()
33
+ end)
34
+ end)
35
+
36
+ ctx:Describe("Access", function()
37
+ ctx:Test("should be able to access enum items", function()
38
+ local test = EnumList.new("Test", { "ABC", "XYZ" })
39
+ ctx:Expect(function()
40
+ local _item = test.ABC
41
+ end)
42
+ :Not()
43
+ :ToThrow()
44
+ ctx:Expect(test:BelongsTo(test.ABC)):ToBe(true)
45
+ end)
46
+
47
+ ctx:Test("should throw if trying to modify the enumlist", function()
48
+ local test = EnumList.new("Test", { "ABC", "XYZ" })
49
+ ctx:Expect(function()
50
+ test.Hello = 32
51
+ end):ToThrow()
52
+ ctx:Expect(function()
53
+ test.ABC = 32
54
+ end):ToThrow()
55
+ end)
56
+
57
+ ctx:Test("should throw if trying to modify an enumitem", function()
58
+ local test = EnumList.new("Test", { "ABC", "XYZ" })
59
+ ctx:Expect(function()
60
+ local abc = test.ABC
61
+ abc.XYZ = 32
62
+ end):ToThrow()
63
+ ctx:Expect(function()
64
+ local abc = test.ABC
65
+ abc.Name = "NewName"
66
+ end):ToThrow()
67
+ end)
68
+
69
+ ctx:Test("should get the name", function()
70
+ local test = EnumList.new("Test", { "ABC", "XYZ" })
71
+ local name = test:GetName()
72
+ ctx:Expect(name):ToBe("Test")
73
+ end)
74
+ end)
75
+
76
+ ctx:Describe("Get Items", function()
77
+ ctx:Test("should be able to get all enum items", function()
78
+ local test = EnumList.new("Test", { "ABC", "XYZ" })
79
+ local items = test:GetEnumItems()
80
+ ctx:Expect(items):ToBeA("table")
81
+ ctx:Expect(#items):ToBe(2)
82
+ for i, enumItem in ipairs(items) do
83
+ ctx:Expect(enumItem):ToBeA("table")
84
+ ctx:Expect(enumItem.Name):ToBeA("string")
85
+ ctx:Expect(enumItem.Value):ToBeA("number")
86
+ ctx:Expect(enumItem.Value):ToBe(i)
87
+ ctx:Expect(enumItem.EnumType):ToBe(test)
88
+ end
89
+ end)
90
+ end)
91
+ end
@@ -0,0 +1,8 @@
1
+ [package]
2
+ name = "sleitnick/enum-list"
3
+ description = "Enum List class"
4
+ version = "2.1.0"
5
+ license = "MIT"
6
+ authors = ["Stephen Leitnick"]
7
+ registry = "https://github.com/UpliftGames/wally-index"
8
+ realm = "shared"
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Find an instance in the data model hierarchy, otherwise throw an error.
3
+ *
4
+ * ```ts
5
+ * const part = find<BasePart>(Workspace, "Some", "Model", "Part");
6
+ * ```
7
+ *
8
+ * Note that the generic type is not a runtime-enforced type-check. A custom
9
+ * assertion is needed if you desire to enforce the type:
10
+ * ```ts
11
+ * const folder = find<Folder>(ReplicatedStorage, "Somewhere", "MyFolder");
12
+ * assert(folder.IsA("Folder"));
13
+ * ```
14
+ *
15
+ * @param parent The parent where the search begins.
16
+ * @param path The name of each instance, where the last one is the returned instance.
17
+ */
18
+ declare function find<T extends Instance = Instance>(parent: Instance, ...path: string[]): T;
19
+
20
+ export = find;
@@ -0,0 +1,44 @@
1
+ --!strict
2
+
3
+ --[=[
4
+ @class Find
5
+
6
+ A utility function for finding objects in the data model hierarchy.
7
+
8
+ Similar to `FindFirstChild`, except it explicitly errors if any object
9
+ is not found, as well as a more helpful message as to what wasn't found.
10
+
11
+ ```lua
12
+ local find = require(ReplicatedStorage.Packages.find)
13
+
14
+ -- Find instance "workspace.Some.Folder.Here.Item":
15
+ local item = find(workspace, "Some", "Folder", "Here", "Item")
16
+ ```
17
+
18
+ In the above example, if "Folder" didn't exist, the function would throw an error with the message: `failed to find instance "Folder" within "Workspace.Some"`.
19
+
20
+ The return type is simply `Instance`. Any type-checking should be done on the return value:
21
+ ```lua
22
+ local part = find(workspace, "SomePart") :: BasePart -- Blindly assume and type this as a BasePart
23
+ assert(part:IsA("BasePart")) -- Extra optional precaution to ensure type
24
+ ```
25
+ ]=]
26
+
27
+ local function find(parent: Instance, ...: string): Instance
28
+ local instance = parent
29
+
30
+ for i = 1, select("#", ...) do
31
+ local name = (select(i, ...))
32
+
33
+ local inst = instance:FindFirstChild(name)
34
+ if inst == nil then
35
+ error(`failed to find instance "{name}" within {instance:GetFullName()}`, 2)
36
+ end
37
+
38
+ instance = inst
39
+ end
40
+
41
+ return instance
42
+ end
43
+
44
+ return find
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@rbxutil/find",
3
+ "version": "1.0.0",
4
+ "main": "init.luau",
5
+ "repository": "github:Sleitnick/RbxUtil",
6
+ "license": "MIT",
7
+ "types": "index.d.ts",
8
+ "files": [
9
+ "./*",
10
+ "!*.toml",
11
+ "!*.json",
12
+ "!*.test.luau"
13
+ ],
14
+ "publishConfig": {
15
+ "access": "public"
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ [package]
2
+ name = "sleitnick/find"
3
+ description = "Utility function for finding an in the data model hierarchy"
4
+ version = "1.0.0"
5
+ license = "MIT"
6
+ authors = ["Stephen Leitnick"]
7
+ registry = "https://github.com/UpliftGames/wally-index"
8
+ realm = "shared"