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,489 @@
|
|
|
1
|
+
-- Option
|
|
2
|
+
-- Stephen Leitnick
|
|
3
|
+
-- August 28, 2020
|
|
4
|
+
|
|
5
|
+
--[[
|
|
6
|
+
|
|
7
|
+
MatchTable {
|
|
8
|
+
Some: (value: any) -> any
|
|
9
|
+
None: () -> any
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
CONSTRUCTORS:
|
|
13
|
+
|
|
14
|
+
Option.Some(anyNonNilValue): Option<any>
|
|
15
|
+
Option.Wrap(anyValue): Option<any>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
STATIC FIELDS:
|
|
19
|
+
|
|
20
|
+
Option.None: Option<None>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
STATIC METHODS:
|
|
24
|
+
|
|
25
|
+
Option.Is(obj): boolean
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
METHODS:
|
|
29
|
+
|
|
30
|
+
opt:Match(): (matches: MatchTable) -> any
|
|
31
|
+
opt:IsSome(): boolean
|
|
32
|
+
opt:IsNone(): boolean
|
|
33
|
+
opt:Unwrap(): any
|
|
34
|
+
opt:Expect(errMsg: string): any
|
|
35
|
+
opt:ExpectNone(errMsg: string): void
|
|
36
|
+
opt:UnwrapOr(default: any): any
|
|
37
|
+
opt:UnwrapOrElse(default: () -> any): any
|
|
38
|
+
opt:And(opt2: Option<any>): Option<any>
|
|
39
|
+
opt:AndThen(predicate: (unwrapped: any) -> Option<any>): Option<any>
|
|
40
|
+
opt:Or(opt2: Option<any>): Option<any>
|
|
41
|
+
opt:OrElse(orElseFunc: () -> Option<any>): Option<any>
|
|
42
|
+
opt:XOr(opt2: Option<any>): Option<any>
|
|
43
|
+
opt:Contains(value: any): boolean
|
|
44
|
+
|
|
45
|
+
--------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
Options are useful for handling nil-value cases. Any time that an
|
|
48
|
+
operation might return nil, it is useful to instead return an
|
|
49
|
+
Option, which will indicate that the value might be nil, and should
|
|
50
|
+
be explicitly checked before using the value. This will help
|
|
51
|
+
prevent common bugs caused by nil values that can fail silently.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
Example:
|
|
55
|
+
|
|
56
|
+
local result1 = Option.Some(32)
|
|
57
|
+
local result2 = Option.Some(nil)
|
|
58
|
+
local result3 = Option.Some("Hi")
|
|
59
|
+
local result4 = Option.Some(nil)
|
|
60
|
+
local result5 = Option.None
|
|
61
|
+
|
|
62
|
+
-- Use 'Match' to match if the value is Some or None:
|
|
63
|
+
result1:Match {
|
|
64
|
+
Some = function(value) print(value) end;
|
|
65
|
+
None = function() print("No value") end;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
-- Raw check:
|
|
69
|
+
if result2:IsSome() then
|
|
70
|
+
local value = result2:Unwrap() -- Explicitly call Unwrap
|
|
71
|
+
print("Value of result2:", value)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if result3:IsNone() then
|
|
75
|
+
print("No result for result3")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
-- Bad, will throw error bc result4 is none:
|
|
79
|
+
local value = result4:Unwrap()
|
|
80
|
+
|
|
81
|
+
--]]
|
|
82
|
+
|
|
83
|
+
export type MatchTable<T> = {
|
|
84
|
+
Some: (value: T) -> any,
|
|
85
|
+
None: () -> any,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type MatchFn<T> = (matches: MatchTable<T>) -> any
|
|
89
|
+
|
|
90
|
+
export type DefaultFn<T> = () -> T
|
|
91
|
+
|
|
92
|
+
export type AndThenFn<T> = (value: T) -> Option<T>
|
|
93
|
+
|
|
94
|
+
export type OrElseFn<T> = () -> Option<T>
|
|
95
|
+
|
|
96
|
+
export type Option<T> = typeof(setmetatable(
|
|
97
|
+
{} :: {
|
|
98
|
+
Match: (self: Option<T>) -> MatchFn<T>,
|
|
99
|
+
IsSome: (self: Option<T>) -> boolean,
|
|
100
|
+
IsNone: (self: Option<T>) -> boolean,
|
|
101
|
+
Contains: (self: Option<T>, value: T) -> boolean,
|
|
102
|
+
Unwrap: (self: Option<T>) -> T,
|
|
103
|
+
Expect: (self: Option<T>, errMsg: string) -> T,
|
|
104
|
+
ExpectNone: (self: Option<T>, errMsg: string) -> nil,
|
|
105
|
+
UnwrapOr: (self: Option<T>, default: T) -> T,
|
|
106
|
+
UnwrapOrElse: (self: Option<T>, defaultFn: DefaultFn<T>) -> T,
|
|
107
|
+
And: (self: Option<T>, opt2: Option<T>) -> Option<T>,
|
|
108
|
+
AndThen: (self: Option<T>, predicate: AndThenFn<T>) -> Option<T>,
|
|
109
|
+
Or: (self: Option<T>, opt2: Option<T>) -> Option<T>,
|
|
110
|
+
OrElse: (self: Option<T>, orElseFunc: OrElseFn<T>) -> Option<T>,
|
|
111
|
+
XOr: (self: Option<T>, opt2: Option<T>) -> Option<T>,
|
|
112
|
+
},
|
|
113
|
+
{} :: {
|
|
114
|
+
__index: Option<T>,
|
|
115
|
+
}
|
|
116
|
+
))
|
|
117
|
+
|
|
118
|
+
local CLASSNAME = "Option"
|
|
119
|
+
|
|
120
|
+
--[=[
|
|
121
|
+
@class Option
|
|
122
|
+
|
|
123
|
+
Represents an optional value in Lua. This is useful to avoid `nil` bugs, which can
|
|
124
|
+
go silently undetected within code and cause hidden or hard-to-find bugs.
|
|
125
|
+
]=]
|
|
126
|
+
local Option = {}
|
|
127
|
+
Option.__index = Option
|
|
128
|
+
|
|
129
|
+
function Option._new(value)
|
|
130
|
+
local self = setmetatable({
|
|
131
|
+
ClassName = CLASSNAME,
|
|
132
|
+
_v = value,
|
|
133
|
+
_s = (value ~= nil),
|
|
134
|
+
}, Option)
|
|
135
|
+
return self
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
--[=[
|
|
139
|
+
@param value T
|
|
140
|
+
@return Option<T>
|
|
141
|
+
|
|
142
|
+
Creates an Option instance with the given value. Throws an error
|
|
143
|
+
if the given value is `nil`.
|
|
144
|
+
]=]
|
|
145
|
+
function Option.Some(value)
|
|
146
|
+
assert(value ~= nil, "Option.Some() value cannot be nil")
|
|
147
|
+
return Option._new(value)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
--[=[
|
|
151
|
+
@param value T
|
|
152
|
+
@return Option<T> | Option<None>
|
|
153
|
+
|
|
154
|
+
Safely wraps the given value as an option. If the
|
|
155
|
+
value is `nil`, returns `Option.None`, otherwise
|
|
156
|
+
returns `Option.Some(value)`.
|
|
157
|
+
]=]
|
|
158
|
+
function Option.Wrap(value)
|
|
159
|
+
if value == nil then
|
|
160
|
+
return Option.None
|
|
161
|
+
else
|
|
162
|
+
return Option.Some(value)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
--[=[
|
|
167
|
+
@param obj any
|
|
168
|
+
@return boolean
|
|
169
|
+
Returns `true` if `obj` is an Option.
|
|
170
|
+
]=]
|
|
171
|
+
function Option.Is(obj)
|
|
172
|
+
return type(obj) == "table" and getmetatable(obj) == Option
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
--[=[
|
|
176
|
+
@param obj any
|
|
177
|
+
Throws an error if `obj` is not an Option.
|
|
178
|
+
]=]
|
|
179
|
+
function Option.Assert(obj)
|
|
180
|
+
assert(Option.Is(obj), "Result was not of type Option")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
--[=[
|
|
184
|
+
@param data table
|
|
185
|
+
@return Option
|
|
186
|
+
Deserializes the data into an Option. This data should have come from
|
|
187
|
+
the `option:Serialize()` method.
|
|
188
|
+
]=]
|
|
189
|
+
function Option.Deserialize(data) -- type data = {ClassName: string, Value: any}
|
|
190
|
+
assert(type(data) == "table" and data.ClassName == CLASSNAME, "Invalid data for deserializing Option")
|
|
191
|
+
return data.Value == nil and Option.None or Option.Some(data.Value)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
--[=[
|
|
195
|
+
@return table
|
|
196
|
+
Returns a serialized version of the option.
|
|
197
|
+
]=]
|
|
198
|
+
function Option:Serialize()
|
|
199
|
+
return {
|
|
200
|
+
ClassName = self.ClassName,
|
|
201
|
+
Value = self._v,
|
|
202
|
+
}
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
--[=[
|
|
206
|
+
@param matches {Some: (value: any) -> any, None: () -> any}
|
|
207
|
+
@return any
|
|
208
|
+
|
|
209
|
+
Matches against the option.
|
|
210
|
+
|
|
211
|
+
```lua
|
|
212
|
+
local opt = Option.Some(32)
|
|
213
|
+
opt:Match {
|
|
214
|
+
Some = function(num) print("Number", num) end,
|
|
215
|
+
None = function() print("No value") end,
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
]=]
|
|
219
|
+
function Option:Match(matches)
|
|
220
|
+
local onSome = matches.Some
|
|
221
|
+
local onNone = matches.None
|
|
222
|
+
assert(type(onSome) == "function", "Missing 'Some' match")
|
|
223
|
+
assert(type(onNone) == "function", "Missing 'None' match")
|
|
224
|
+
if self:IsSome() then
|
|
225
|
+
return onSome(self:Unwrap())
|
|
226
|
+
else
|
|
227
|
+
return onNone()
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
--[=[
|
|
232
|
+
@return boolean
|
|
233
|
+
Returns `true` if the option has a value.
|
|
234
|
+
]=]
|
|
235
|
+
function Option:IsSome()
|
|
236
|
+
return self._s
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
--[=[
|
|
240
|
+
@return boolean
|
|
241
|
+
Returns `true` if the option is None.
|
|
242
|
+
]=]
|
|
243
|
+
function Option:IsNone()
|
|
244
|
+
return not self._s
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
--[=[
|
|
248
|
+
@param msg string
|
|
249
|
+
@return value: any
|
|
250
|
+
Unwraps the value in the option, otherwise throws an error with `msg` as the error message.
|
|
251
|
+
```lua
|
|
252
|
+
local opt = Option.Some(10)
|
|
253
|
+
print(opt:Expect("No number")) -> 10
|
|
254
|
+
print(Option.None:Expect("No number")) -- Throws an error "No number"
|
|
255
|
+
```
|
|
256
|
+
]=]
|
|
257
|
+
function Option:Expect(msg)
|
|
258
|
+
assert(self:IsSome(), msg)
|
|
259
|
+
return self._v
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
--[=[
|
|
263
|
+
@param msg string
|
|
264
|
+
Throws an error with `msg` as the error message if the value is _not_ None.
|
|
265
|
+
]=]
|
|
266
|
+
function Option:ExpectNone(msg)
|
|
267
|
+
assert(self:IsNone(), msg)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
--[=[
|
|
271
|
+
@return value: any
|
|
272
|
+
Returns the value in the option, or throws an error if the option is None.
|
|
273
|
+
]=]
|
|
274
|
+
function Option:Unwrap()
|
|
275
|
+
return self:Expect("Cannot unwrap option of None type")
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
--[=[
|
|
279
|
+
@param default any
|
|
280
|
+
@return value: any
|
|
281
|
+
If the option holds a value, returns the value. Otherwise, returns `default`.
|
|
282
|
+
]=]
|
|
283
|
+
function Option:UnwrapOr(default)
|
|
284
|
+
if self:IsSome() then
|
|
285
|
+
return self:Unwrap()
|
|
286
|
+
else
|
|
287
|
+
return default
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
--[=[
|
|
292
|
+
@param defaultFn () -> any
|
|
293
|
+
@return value: any
|
|
294
|
+
If the option holds a value, returns the value. Otherwise, returns the
|
|
295
|
+
result of the `defaultFn` function.
|
|
296
|
+
]=]
|
|
297
|
+
function Option:UnwrapOrElse(defaultFn)
|
|
298
|
+
if self:IsSome() then
|
|
299
|
+
return self:Unwrap()
|
|
300
|
+
else
|
|
301
|
+
return defaultFn()
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
--[=[
|
|
306
|
+
@param optionB Option
|
|
307
|
+
@return Option
|
|
308
|
+
Returns `optionB` if the calling option has a value,
|
|
309
|
+
otherwise returns None.
|
|
310
|
+
|
|
311
|
+
```lua
|
|
312
|
+
local optionA = Option.Some(32)
|
|
313
|
+
local optionB = Option.Some(64)
|
|
314
|
+
local opt = optionA:And(optionB)
|
|
315
|
+
-- opt == optionB
|
|
316
|
+
|
|
317
|
+
local optionA = Option.None
|
|
318
|
+
local optionB = Option.Some(64)
|
|
319
|
+
local opt = optionA:And(optionB)
|
|
320
|
+
-- opt == Option.None
|
|
321
|
+
```
|
|
322
|
+
]=]
|
|
323
|
+
function Option:And(optionB)
|
|
324
|
+
if self:IsSome() then
|
|
325
|
+
return optionB
|
|
326
|
+
else
|
|
327
|
+
return Option.None
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
--[=[
|
|
332
|
+
@param andThenFn (value: any) -> Option
|
|
333
|
+
@return value: Option
|
|
334
|
+
If the option holds a value, then the `andThenFn`
|
|
335
|
+
function is called with the held value of the option,
|
|
336
|
+
and then the resultant Option returned by the `andThenFn`
|
|
337
|
+
is returned. Otherwise, None is returned.
|
|
338
|
+
|
|
339
|
+
```lua
|
|
340
|
+
local optA = Option.Some(32)
|
|
341
|
+
local optB = optA:AndThen(function(num)
|
|
342
|
+
return Option.Some(num * 2)
|
|
343
|
+
end)
|
|
344
|
+
print(optB:Expect("Expected number")) --> 64
|
|
345
|
+
```
|
|
346
|
+
]=]
|
|
347
|
+
function Option:AndThen(andThenFn)
|
|
348
|
+
if self:IsSome() then
|
|
349
|
+
local result = andThenFn(self:Unwrap())
|
|
350
|
+
Option.Assert(result)
|
|
351
|
+
return result
|
|
352
|
+
else
|
|
353
|
+
return Option.None
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
--[=[
|
|
358
|
+
@param optionB Option
|
|
359
|
+
@return Option
|
|
360
|
+
If caller has a value, returns itself. Otherwise, returns `optionB`.
|
|
361
|
+
]=]
|
|
362
|
+
function Option:Or(optionB)
|
|
363
|
+
if self:IsSome() then
|
|
364
|
+
return self
|
|
365
|
+
else
|
|
366
|
+
return optionB
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
--[=[
|
|
371
|
+
@param orElseFn () -> Option
|
|
372
|
+
@return Option
|
|
373
|
+
If caller has a value, returns itself. Otherwise, returns the
|
|
374
|
+
option generated by the `orElseFn` function.
|
|
375
|
+
]=]
|
|
376
|
+
function Option:OrElse(orElseFn)
|
|
377
|
+
if self:IsSome() then
|
|
378
|
+
return self
|
|
379
|
+
else
|
|
380
|
+
local result = orElseFn()
|
|
381
|
+
Option.Assert(result)
|
|
382
|
+
return result
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
--[=[
|
|
387
|
+
@param optionB Option
|
|
388
|
+
@return Option
|
|
389
|
+
If both `self` and `optionB` have values _or_ both don't have a value,
|
|
390
|
+
then this returns None. Otherwise, it returns the option that does have
|
|
391
|
+
a value.
|
|
392
|
+
]=]
|
|
393
|
+
function Option:XOr(optionB)
|
|
394
|
+
local someOptA = self:IsSome()
|
|
395
|
+
local someOptB = optionB:IsSome()
|
|
396
|
+
if someOptA == someOptB then
|
|
397
|
+
return Option.None
|
|
398
|
+
elseif someOptA then
|
|
399
|
+
return self
|
|
400
|
+
else
|
|
401
|
+
return optionB
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
--[=[
|
|
406
|
+
@param predicate (value: any) -> boolean
|
|
407
|
+
@return Option
|
|
408
|
+
Returns `self` if this option has a value and the predicate returns `true.
|
|
409
|
+
Otherwise, returns None.
|
|
410
|
+
]=]
|
|
411
|
+
function Option:Filter(predicate)
|
|
412
|
+
if self:IsNone() or not predicate(self._v) then
|
|
413
|
+
return Option.None
|
|
414
|
+
else
|
|
415
|
+
return self
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
--[=[
|
|
420
|
+
@param value any
|
|
421
|
+
@return boolean
|
|
422
|
+
Returns `true` if this option contains `value`.
|
|
423
|
+
]=]
|
|
424
|
+
function Option:Contains(value)
|
|
425
|
+
return self:IsSome() and self._v == value
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
--[=[
|
|
429
|
+
@return string
|
|
430
|
+
Metamethod to transform the option into a string.
|
|
431
|
+
```lua
|
|
432
|
+
local optA = Option.Some(64)
|
|
433
|
+
local optB = Option.None
|
|
434
|
+
print(optA) --> Option<number>
|
|
435
|
+
print(optB) --> Option<None>
|
|
436
|
+
```
|
|
437
|
+
]=]
|
|
438
|
+
function Option:__tostring()
|
|
439
|
+
if self:IsSome() then
|
|
440
|
+
return ("Option<" .. typeof(self._v) .. ">")
|
|
441
|
+
else
|
|
442
|
+
return "Option<None>"
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
--[=[
|
|
447
|
+
@return boolean
|
|
448
|
+
@param opt Option
|
|
449
|
+
Metamethod to check equality between two options. Returns `true` if both
|
|
450
|
+
options hold the same value _or_ both options are None.
|
|
451
|
+
```lua
|
|
452
|
+
local o1 = Option.Some(32)
|
|
453
|
+
local o2 = Option.Some(32)
|
|
454
|
+
local o3 = Option.Some(64)
|
|
455
|
+
local o4 = Option.None
|
|
456
|
+
local o5 = Option.None
|
|
457
|
+
|
|
458
|
+
print(o1 == o2) --> true
|
|
459
|
+
print(o1 == o3) --> false
|
|
460
|
+
print(o1 == o4) --> false
|
|
461
|
+
print(o4 == o5) --> true
|
|
462
|
+
```
|
|
463
|
+
]=]
|
|
464
|
+
function Option:__eq(opt)
|
|
465
|
+
if Option.Is(opt) then
|
|
466
|
+
if self:IsSome() and opt:IsSome() then
|
|
467
|
+
return (self:Unwrap() == opt:Unwrap())
|
|
468
|
+
elseif self:IsNone() and opt:IsNone() then
|
|
469
|
+
return true
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
return false
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
--[=[
|
|
476
|
+
@prop None Option<None>
|
|
477
|
+
@within Option
|
|
478
|
+
Represents no value.
|
|
479
|
+
]=]
|
|
480
|
+
Option.None = Option._new()
|
|
481
|
+
|
|
482
|
+
return (Option :: any) :: {
|
|
483
|
+
Some: <T>(value: T) -> Option<T>,
|
|
484
|
+
Wrap: <T>(value: T?) -> Option<T>,
|
|
485
|
+
|
|
486
|
+
Is: (obj: any) -> boolean,
|
|
487
|
+
|
|
488
|
+
None: Option<any>,
|
|
489
|
+
}
|