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.
- package/README.md +122 -0
- package/commands/setup-game.md +108 -0
- package/commands/sync-check.md +53 -0
- package/core/roblox-core.md +93 -0
- package/dist/server.js +167 -0
- package/package.json +35 -0
- package/skills/roblox-analytics/SKILL.md +277 -0
- package/skills/roblox-analytics/references/event-batcher.luau +75 -0
- package/skills/roblox-animation-vfx/SKILL.md +1325 -0
- package/skills/roblox-architecture/SKILL.md +863 -0
- package/skills/roblox-architecture/references/combat-systems.md +1381 -0
- package/skills/roblox-code-review/SKILL.md +687 -0
- package/skills/roblox-data/SKILL.md +889 -0
- package/skills/roblox-data/references/inventory-systems.md +1729 -0
- package/skills/roblox-debug/SKILL.md +99 -0
- package/skills/roblox-gui/SKILL.md +1103 -0
- package/skills/roblox-gui-fusion/SKILL.md +150 -0
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
- package/skills/roblox-gui-fusion/references/shop.luau +411 -0
- package/skills/roblox-luau-mastery/SKILL.md +1519 -0
- package/skills/roblox-monetization/SKILL.md +1084 -0
- package/skills/roblox-monetization/references/process-receipt.luau +131 -0
- package/skills/roblox-networking/SKILL.md +669 -0
- package/skills/roblox-networking/references/remote-validator.luau +193 -0
- package/skills/roblox-publish-checklist/SKILL.md +128 -0
- package/skills/roblox-runtime/SKILL.md +753 -0
- package/skills/roblox-sharp-edges/SKILL.md +295 -0
- package/skills/roblox-sync/SKILL.md +126 -0
- package/skills/roblox-testing/SKILL.md +943 -0
- package/skills/roblox-tooling/SKILL.md +150 -0
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
- package/vendor/LICENSES/promise-LICENSE +21 -0
- package/vendor/LICENSES/t-LICENSE +21 -0
- package/vendor/LICENSES/testez-LICENSE +201 -0
- package/vendor/README.md +84 -0
- package/vendor/fusion/Animation/ExternalTime.luau +84 -0
- package/vendor/fusion/Animation/Spring.luau +322 -0
- package/vendor/fusion/Animation/Stopwatch.luau +128 -0
- package/vendor/fusion/Animation/Tween.luau +187 -0
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
- package/vendor/fusion/Animation/lerpType.luau +164 -0
- package/vendor/fusion/Animation/packType.luau +100 -0
- package/vendor/fusion/Animation/springCoefficients.luau +80 -0
- package/vendor/fusion/Animation/unpackType.luau +103 -0
- package/vendor/fusion/Colour/Oklab.luau +70 -0
- package/vendor/fusion/Colour/sRGB.luau +55 -0
- package/vendor/fusion/External.luau +168 -0
- package/vendor/fusion/ExternalDebug.luau +70 -0
- package/vendor/fusion/Graph/Observer.luau +114 -0
- package/vendor/fusion/Graph/castToGraph.luau +29 -0
- package/vendor/fusion/Graph/change.luau +81 -0
- package/vendor/fusion/Graph/depend.luau +33 -0
- package/vendor/fusion/Graph/evaluate.luau +56 -0
- package/vendor/fusion/Instances/Attribute.luau +58 -0
- package/vendor/fusion/Instances/AttributeChange.luau +47 -0
- package/vendor/fusion/Instances/AttributeOut.luau +63 -0
- package/vendor/fusion/Instances/Child.luau +21 -0
- package/vendor/fusion/Instances/Children.luau +148 -0
- package/vendor/fusion/Instances/Hydrate.luau +33 -0
- package/vendor/fusion/Instances/New.luau +53 -0
- package/vendor/fusion/Instances/OnChange.luau +50 -0
- package/vendor/fusion/Instances/OnEvent.luau +54 -0
- package/vendor/fusion/Instances/Out.luau +69 -0
- package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
- package/vendor/fusion/Instances/defaultProps.luau +194 -0
- package/vendor/fusion/LICENSE +21 -0
- package/vendor/fusion/Logging/formatError.luau +49 -0
- package/vendor/fusion/Logging/messages.luau +52 -0
- package/vendor/fusion/Logging/parseError.luau +25 -0
- package/vendor/fusion/Memory/checkLifetime.luau +134 -0
- package/vendor/fusion/Memory/deriveScope.luau +24 -0
- package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
- package/vendor/fusion/Memory/doCleanup.luau +79 -0
- package/vendor/fusion/Memory/innerScope.luau +34 -0
- package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
- package/vendor/fusion/Memory/needsDestruction.luau +17 -0
- package/vendor/fusion/Memory/poisonScope.luau +34 -0
- package/vendor/fusion/Memory/scopePool.luau +55 -0
- package/vendor/fusion/Memory/scoped.luau +27 -0
- package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
- package/vendor/fusion/RobloxExternal.luau +98 -0
- package/vendor/fusion/State/Computed.luau +139 -0
- package/vendor/fusion/State/For/Disassembly.luau +211 -0
- package/vendor/fusion/State/For/ForTypes.luau +30 -0
- package/vendor/fusion/State/For/init.luau +110 -0
- package/vendor/fusion/State/ForKeys.luau +94 -0
- package/vendor/fusion/State/ForPairs.luau +97 -0
- package/vendor/fusion/State/ForValues.luau +94 -0
- package/vendor/fusion/State/Value.luau +88 -0
- package/vendor/fusion/State/castToState.luau +26 -0
- package/vendor/fusion/State/peek.luau +31 -0
- package/vendor/fusion/State/updateAll.luau +1 -0
- package/vendor/fusion/Types.luau +314 -0
- package/vendor/fusion/Utility/Contextual.luau +91 -0
- package/vendor/fusion/Utility/Safe.luau +23 -0
- package/vendor/fusion/Utility/isSimilar.luau +29 -0
- package/vendor/fusion/Utility/merge.luau +35 -0
- package/vendor/fusion/Utility/nameOf.luau +35 -0
- package/vendor/fusion/Utility/never.luau +14 -0
- package/vendor/fusion/Utility/nicknames.luau +11 -0
- package/vendor/fusion/Utility/xtypeof.luau +27 -0
- package/vendor/fusion/init.luau +82 -0
- package/vendor/profilestore/init.luau +2243 -0
- package/vendor/promise/init.luau +1982 -0
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
- package/vendor/rbxutil/buffer-util/Types.luau +60 -0
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
- package/vendor/rbxutil/buffer-util/init.luau +41 -0
- package/vendor/rbxutil/buffer-util/package.json +16 -0
- package/vendor/rbxutil/buffer-util/wally.toml +9 -0
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
- package/vendor/rbxutil/comm/Client/init.luau +135 -0
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
- package/vendor/rbxutil/comm/Server/init.luau +140 -0
- package/vendor/rbxutil/comm/Types.luau +18 -0
- package/vendor/rbxutil/comm/Util.luau +27 -0
- package/vendor/rbxutil/comm/init.luau +35 -0
- package/vendor/rbxutil/comm/wally.toml +13 -0
- package/vendor/rbxutil/component/init.luau +759 -0
- package/vendor/rbxutil/component/init.test.luau +311 -0
- package/vendor/rbxutil/component/wally.toml +14 -0
- package/vendor/rbxutil/concur/init.luau +542 -0
- package/vendor/rbxutil/concur/init.test.luau +364 -0
- package/vendor/rbxutil/concur/wally.toml +8 -0
- package/vendor/rbxutil/enum-list/init.luau +101 -0
- package/vendor/rbxutil/enum-list/init.test.luau +91 -0
- package/vendor/rbxutil/enum-list/wally.toml +8 -0
- package/vendor/rbxutil/find/index.d.ts +20 -0
- package/vendor/rbxutil/find/init.luau +44 -0
- package/vendor/rbxutil/find/package.json +17 -0
- package/vendor/rbxutil/find/wally.toml +8 -0
- package/vendor/rbxutil/input/Gamepad.luau +559 -0
- package/vendor/rbxutil/input/Keyboard.luau +124 -0
- package/vendor/rbxutil/input/Mouse.luau +278 -0
- package/vendor/rbxutil/input/PreferredInput.luau +91 -0
- package/vendor/rbxutil/input/Touch.luau +120 -0
- package/vendor/rbxutil/input/init.luau +33 -0
- package/vendor/rbxutil/input/wally.toml +12 -0
- package/vendor/rbxutil/loader/index.d.ts +15 -0
- package/vendor/rbxutil/loader/init.luau +137 -0
- package/vendor/rbxutil/loader/wally.toml +8 -0
- package/vendor/rbxutil/log/index.d.ts +38 -0
- package/vendor/rbxutil/log/init.luau +746 -0
- package/vendor/rbxutil/log/wally.toml +8 -0
- package/vendor/rbxutil/net/init.luau +190 -0
- package/vendor/rbxutil/net/wally.toml +8 -0
- package/vendor/rbxutil/option/index.d.ts +44 -0
- package/vendor/rbxutil/option/init.luau +489 -0
- package/vendor/rbxutil/option/init.test.luau +342 -0
- package/vendor/rbxutil/option/wally.toml +8 -0
- package/vendor/rbxutil/pid/index.d.ts +53 -0
- package/vendor/rbxutil/pid/init.luau +195 -0
- package/vendor/rbxutil/pid/package.json +16 -0
- package/vendor/rbxutil/pid/wally.toml +9 -0
- package/vendor/rbxutil/quaternion/index.d.ts +117 -0
- package/vendor/rbxutil/quaternion/init.luau +570 -0
- package/vendor/rbxutil/quaternion/package.json +16 -0
- package/vendor/rbxutil/quaternion/wally.toml +9 -0
- package/vendor/rbxutil/query/index.d.ts +43 -0
- package/vendor/rbxutil/query/init.luau +117 -0
- package/vendor/rbxutil/query/package.json +18 -0
- package/vendor/rbxutil/query/wally.toml +9 -0
- package/vendor/rbxutil/sequent/index.d.ts +28 -0
- package/vendor/rbxutil/sequent/init.luau +340 -0
- package/vendor/rbxutil/sequent/package.json +16 -0
- package/vendor/rbxutil/sequent/wally.toml +9 -0
- package/vendor/rbxutil/ser/init.luau +175 -0
- package/vendor/rbxutil/ser/init.test.luau +50 -0
- package/vendor/rbxutil/ser/wally.toml +11 -0
- package/vendor/rbxutil/shake/index.d.ts +36 -0
- package/vendor/rbxutil/shake/init.luau +532 -0
- package/vendor/rbxutil/shake/init.test.luau +267 -0
- package/vendor/rbxutil/shake/package.json +16 -0
- package/vendor/rbxutil/shake/wally.toml +9 -0
- package/vendor/rbxutil/signal/index.d.ts +100 -0
- package/vendor/rbxutil/signal/init.luau +432 -0
- package/vendor/rbxutil/signal/init.test.luau +190 -0
- package/vendor/rbxutil/signal/package.json +17 -0
- package/vendor/rbxutil/signal/wally.toml +9 -0
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
- package/vendor/rbxutil/silo/Util.luau +55 -0
- package/vendor/rbxutil/silo/init.luau +338 -0
- package/vendor/rbxutil/silo/init.test.luau +215 -0
- package/vendor/rbxutil/silo/wally.toml +8 -0
- package/vendor/rbxutil/spring/index.d.ts +40 -0
- package/vendor/rbxutil/spring/init.luau +97 -0
- package/vendor/rbxutil/spring/package.json +17 -0
- package/vendor/rbxutil/spring/wally.toml +8 -0
- package/vendor/rbxutil/stream/index.d.ts +88 -0
- package/vendor/rbxutil/stream/init.luau +597 -0
- package/vendor/rbxutil/stream/package.json +18 -0
- package/vendor/rbxutil/stream/wally.toml +9 -0
- package/vendor/rbxutil/streamable/Streamable.luau +202 -0
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
- package/vendor/rbxutil/streamable/init.luau +8 -0
- package/vendor/rbxutil/streamable/wally.toml +12 -0
- package/vendor/rbxutil/symbol/init.luau +56 -0
- package/vendor/rbxutil/symbol/init.test.luau +37 -0
- package/vendor/rbxutil/symbol/wally.toml +8 -0
- package/vendor/rbxutil/table-util/init.luau +938 -0
- package/vendor/rbxutil/table-util/init.test.luau +439 -0
- package/vendor/rbxutil/table-util/wally.toml +8 -0
- package/vendor/rbxutil/task-queue/index.d.ts +27 -0
- package/vendor/rbxutil/task-queue/init.luau +97 -0
- package/vendor/rbxutil/task-queue/wally.toml +8 -0
- package/vendor/rbxutil/timer/index.d.ts +81 -0
- package/vendor/rbxutil/timer/init.luau +249 -0
- package/vendor/rbxutil/timer/init.test.luau +73 -0
- package/vendor/rbxutil/timer/wally.toml +11 -0
- package/vendor/rbxutil/tree/index.d.ts +15 -0
- package/vendor/rbxutil/tree/init.luau +137 -0
- package/vendor/rbxutil/tree/wally.toml +8 -0
- package/vendor/rbxutil/trove/index.d.ts +46 -0
- package/vendor/rbxutil/trove/init.luau +787 -0
- package/vendor/rbxutil/trove/init.test.luau +203 -0
- package/vendor/rbxutil/trove/wally.toml +8 -0
- package/vendor/rbxutil/typed-remote/init.luau +196 -0
- package/vendor/rbxutil/typed-remote/wally.toml +8 -0
- package/vendor/rbxutil/wait-for/index.d.ts +17 -0
- package/vendor/rbxutil/wait-for/init.luau +257 -0
- package/vendor/rbxutil/wait-for/init.test.luau +182 -0
- package/vendor/rbxutil/wait-for/wally.toml +11 -0
- package/vendor/t/t.lua +1350 -0
- package/vendor/testez/Context.lua +26 -0
- package/vendor/testez/Expectation.lua +311 -0
- package/vendor/testez/ExpectationContext.lua +38 -0
- package/vendor/testez/LifecycleHooks.lua +89 -0
- package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
- package/vendor/testez/Reporters/TextReporter.lua +106 -0
- package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
- package/vendor/testez/TestBootstrap.lua +147 -0
- package/vendor/testez/TestEnum.lua +28 -0
- package/vendor/testez/TestPlan.lua +304 -0
- package/vendor/testez/TestPlanner.lua +40 -0
- package/vendor/testez/TestResults.lua +112 -0
- package/vendor/testez/TestRunner.lua +188 -0
- package/vendor/testez/TestSession.lua +243 -0
- 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,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,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
|
+
}
|