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,88 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ A state object which allows regular Luau code to control its value.
8
+
9
+ https://elttob.uk/Fusion/0.3/api-reference/state/types/value/
10
+ ]]
11
+
12
+ local Package = script.Parent.Parent
13
+ local Types = require(Package.Types)
14
+ local External = require(Package.External)
15
+ -- Graph
16
+ local change = require(Package.Graph.change)
17
+ -- Utility
18
+ local isSimilar = require(Package.Utility.isSimilar)
19
+ local never = require(Package.Utility.never)
20
+ local nicknames = require(Package.Utility.nicknames)
21
+
22
+ type Self<T, S> = Types.Value<T, S>
23
+
24
+ local class = {}
25
+ class.type = "State"
26
+ class.kind = "Value"
27
+ class.timeliness = "lazy"
28
+ class.dependencySet = table.freeze {}
29
+
30
+ local METATABLE = table.freeze {__index = class}
31
+
32
+ local function Value<T>(
33
+ scope: Types.Scope<unknown>,
34
+ initialValue: T
35
+ ): Types.Value<T, any>
36
+ local createdAt = os.clock()
37
+ if initialValue == nil and (typeof(scope) ~= "table" or (scope[1] == nil and next(scope) ~= nil)) then
38
+ External.logError("scopeMissing", nil, "Value", "myScope:Value(initialValue)")
39
+ end
40
+ local self: Self<T, any> = setmetatable(
41
+ {
42
+ createdAt = createdAt,
43
+ dependentSet = {},
44
+ lastChange = os.clock(),
45
+ scope = scope,
46
+ validity = "valid",
47
+ _EXTREMELY_DANGEROUS_usedAsValue = initialValue
48
+ },
49
+ METATABLE
50
+ ) :: any
51
+ local destroy = function()
52
+ self.scope = nil
53
+ end
54
+ self.oldestTask = destroy
55
+ nicknames[self.oldestTask] = "Value"
56
+ table.insert(scope, destroy)
57
+ return self
58
+ end
59
+
60
+ function class:get<T, S>(
61
+ _self: Self<T, S>
62
+ ): never
63
+ External.logError("stateGetWasRemoved")
64
+ return never()
65
+ end
66
+
67
+ function class.set<T, S>(
68
+ self: Self<T, S>,
69
+ newValue: S
70
+ ): S
71
+ local oldValue = self._EXTREMELY_DANGEROUS_usedAsValue
72
+ if not isSimilar(oldValue, newValue) then
73
+ self._EXTREMELY_DANGEROUS_usedAsValue = newValue :: any
74
+ change(self)
75
+ end
76
+ return newValue
77
+ end
78
+
79
+ function class._evaluate<T, S>(
80
+ _self: Self<T, S>
81
+ ): boolean
82
+ -- The similarity test is done in advance when the value is set, so this
83
+ -- should be fine.
84
+ return true
85
+ end
86
+
87
+ table.freeze(class)
88
+ return Value :: Types.ValueConstructor
@@ -0,0 +1,26 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Returns the input *only* if it is a state object.
8
+ ]]
9
+
10
+ local Package = script.Parent.Parent
11
+ local Types = require(Package.Types)
12
+
13
+ local function castToState<T>(
14
+ target: Types.UsedAs<T>
15
+ ): Types.StateObject<T>?
16
+ if
17
+ typeof(target) == "table" and
18
+ target.type == "State"
19
+ then
20
+ return target
21
+ else
22
+ return nil
23
+ end
24
+ end
25
+
26
+ return castToState
@@ -0,0 +1,31 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Extracts a value of type T from its input.
8
+
9
+ https://elttob.uk/Fusion/0.3/api-reference/state/members/peek/
10
+ ]]
11
+
12
+ local Package = script.Parent.Parent
13
+ local Types = require(Package.Types)
14
+ -- State
15
+ local castToState = require(Package.State.castToState)
16
+ -- Graph
17
+ local evaluate = require(Package.Graph.evaluate)
18
+
19
+ local function peek<T>(
20
+ target: Types.UsedAs<T>
21
+ ): T
22
+ local targetState = castToState(target)
23
+ if targetState ~= nil then
24
+ evaluate(targetState, false)
25
+ return targetState._EXTREMELY_DANGEROUS_usedAsValue :: T
26
+ else
27
+ return target :: T
28
+ end
29
+ end
30
+
31
+ return peek
@@ -0,0 +1 @@
1
+ return nil -- dummy file so I can write tests
@@ -0,0 +1,314 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Stores common public-facing type information for Fusion APIs.
8
+ ]]
9
+
10
+ export type Error = {
11
+ type: "Error",
12
+ raw: string,
13
+ message: string,
14
+ trace: string,
15
+ context: string?
16
+ }
17
+
18
+ -- Types that can be expressed as vectors of numbers, and so can be animated.
19
+ export type Animatable =
20
+ number |
21
+ CFrame |
22
+ Color3 |
23
+ ColorSequenceKeypoint |
24
+ DateTime |
25
+ NumberRange |
26
+ NumberSequenceKeypoint |
27
+ PhysicalProperties |
28
+ Ray |
29
+ Rect |
30
+ Region3 |
31
+ Region3int16 |
32
+ UDim |
33
+ UDim2 |
34
+ Vector2 |
35
+ Vector2int16 |
36
+ Vector3 |
37
+ Vector3int16
38
+
39
+ -- A task which can be accepted for cleanup.
40
+ export type Task =
41
+ Instance |
42
+ RBXScriptConnection |
43
+ () -> () |
44
+ {destroy: (unknown) -> ()} |
45
+ {Destroy: (unknown) -> ()} |
46
+ {Task}
47
+
48
+ -- A scope of tasks to clean up.
49
+ export type Scope<Constructors = any> = {Task} & Constructors
50
+
51
+ -- An object which uses a scope to dictate how long it lives.
52
+ export type ScopedObject = {
53
+ scope: Scope<unknown>?,
54
+ oldestTask: unknown
55
+ }
56
+
57
+ -- Script-readable version information.
58
+ export type Version = {
59
+ major: number,
60
+ minor: number,
61
+ isRelease: boolean
62
+ }
63
+
64
+ -- An object which stores a value scoped in time.
65
+ export type Contextual<T> = {
66
+ type: "Contextual",
67
+ now: (Contextual<T>) -> T,
68
+ is: (Contextual<T>, T) -> ContextualIsMethods
69
+ }
70
+
71
+ type ContextualIsMethods = {
72
+ during: <R, A...>(ContextualIsMethods, (A...) -> R, A...) -> R
73
+ }
74
+
75
+ -- A graph object which can have dependencies and dependencies.
76
+ export type GraphObject = ScopedObject & {
77
+ createdAt: number,
78
+ dependencySet: {[GraphObject]: unknown},
79
+ dependentSet: {[GraphObject]: unknown},
80
+ lastChange: number?,
81
+ timeliness: "lazy" | "eager",
82
+ validity: "valid" | "invalid" | "busy",
83
+ _evaluate: (GraphObject) -> boolean
84
+ }
85
+
86
+ -- An object which stores a piece of reactive state.
87
+ export type StateObject<T> = GraphObject & {
88
+ type: "State",
89
+ kind: string,
90
+ _EXTREMELY_DANGEROUS_usedAsValue: T
91
+ }
92
+
93
+ -- Passing values of this type to `Use` returns `T`.
94
+ export type UsedAs<T> = StateObject<T> | T
95
+
96
+ -- Function signature for use callbacks.
97
+ export type Use = <T>(target: UsedAs<T>) -> T
98
+
99
+ -- A state object whose value can be set at any time by the user.
100
+ export type Value<T, S = T> = StateObject<T> & {
101
+ kind: "State",
102
+ timeliness: "lazy",
103
+ set: (Value<T, S>, newValue: S, force: boolean?) -> S,
104
+ ____phantom_setType: (never) -> S -- phantom data so this contains S
105
+ }
106
+ export type ValueConstructor = <T>(
107
+ scope: Scope<unknown>,
108
+ initialValue: T
109
+ ) -> Value<T, any>
110
+
111
+ -- A state object whose value is derived from other objects using a callback.
112
+ export type Computed<T> = StateObject<T> & {
113
+ kind: "Computed",
114
+ timeliness: "lazy"
115
+ }
116
+ export type ComputedConstructor = <T, S>(
117
+ scope: S & Scope<unknown>,
118
+ callback: (Use, S) -> T
119
+ ) -> Computed<T>
120
+
121
+ -- A state object which maps over keys and/or values in another table.
122
+ export type For<KO, VO> = StateObject<{[KO]: VO}> & {
123
+ kind: "For"
124
+ }
125
+ export type ForPairsConstructor = <KI, KO, VI, VO, S>(
126
+ scope: S & Scope<unknown>,
127
+ inputTable: UsedAs<{[KI]: VI}>,
128
+ processor: (Use, S, key: KI, value: VI) -> (KO, VO)
129
+ ) -> For<KO, VO>
130
+ export type ForKeysConstructor = <KI, KO, V, S>(
131
+ scope: S & Scope<unknown>,
132
+ inputTable: UsedAs<{[KI]: V}>,
133
+ processor: (Use, S, key: KI) -> KO
134
+ ) -> For<KO, V>
135
+ export type ForValuesConstructor = <K, VI, VO, S>(
136
+ scope: S & Scope<unknown>,
137
+ inputTable: UsedAs<{[K]: VI}>,
138
+ processor: (Use, S, value: VI) -> VO
139
+ ) -> For<K, VO>
140
+
141
+ -- An object which can listen for updates on another state object.
142
+ export type Observer = GraphObject & {
143
+ type: "Observer",
144
+ timeliness: "eager",
145
+ onChange: (Observer, callback: () -> ()) -> (() -> ()),
146
+ onBind: (Observer, callback: () -> ()) -> (() -> ())
147
+ }
148
+ export type ObserverConstructor = (
149
+ scope: Scope<unknown>,
150
+ watching: unknown
151
+ ) -> Observer
152
+
153
+ -- A state object which follows another state object using tweens.
154
+ export type Tween<T> = StateObject<T> & {
155
+ kind: "Tween"
156
+ }
157
+ export type TweenConstructor = <T>(
158
+ scope: Scope<unknown>,
159
+ goalState: UsedAs<T>,
160
+ tweenInfo: UsedAs<TweenInfo>?
161
+ ) -> Tween<T>
162
+
163
+ -- A state object which follows another state object using spring simulation.
164
+ export type Spring<T> = StateObject<T> & {
165
+ kind: "Spring",
166
+ setPosition: (Spring<T>, newPosition: T) -> (),
167
+ setVelocity: (Spring<T>, newVelocity: T) -> (),
168
+ addVelocity: (Spring<T>, deltaVelocity: T) -> ()
169
+ }
170
+ export type SpringConstructor = <T>(
171
+ scope: Scope<unknown>,
172
+ goalState: UsedAs<T>,
173
+ speed: UsedAs<number>?,
174
+ damping: UsedAs<number>?
175
+ ) -> Spring<T>
176
+
177
+ -- Denotes children instances in an instance or component's property table.
178
+ export type SpecialKey = {
179
+ type: "SpecialKey",
180
+ kind: string,
181
+ stage: "self" | "descendants" | "ancestor" | "observer",
182
+ apply: (
183
+ self: SpecialKey,
184
+ scope: Scope<unknown>,
185
+ value: unknown,
186
+ applyTo: Instance
187
+ ) -> ()
188
+ }
189
+
190
+ -- A collection of instances that may be parented to another instance.
191
+ export type Child = Instance | StateObject<Child> | {[unknown]: Child}
192
+
193
+ -- A table that defines an instance's properties, handlers and children.
194
+ export type PropertyTable = {[string | SpecialKey]: unknown}
195
+
196
+ export type NewConstructor = (
197
+ scope: Scope<unknown>,
198
+ className: string
199
+ ) -> (propertyTable: PropertyTable) -> Instance
200
+
201
+ export type HydrateConstructor = (
202
+ scope: Scope<unknown>,
203
+ target: Instance
204
+ ) -> (propertyTable: PropertyTable) -> Instance
205
+
206
+ -- Is there a sane way to write out this type?
207
+ -- ... I sure hope so.
208
+
209
+ export type DeriveScopeConstructor = (<S>(Scope<S>) -> Scope<S>)
210
+ & (<S, A>(Scope<S>, A & {}) -> Scope<S & A>)
211
+ & (<S, A, B>(Scope<S>, A & {}, B & {}) -> Scope<S & A & B>)
212
+ & (<S, A, B, C>(Scope<S>, A & {}, B & {}, C & {}) -> Scope<S & A & B & C>)
213
+ & (<S, A, B, C, D>(Scope<S>, A & {}, B & {}, C & {}, D & {}) -> Scope<S & A & B & C & D>)
214
+ & (<S, A, B, C, D, E>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}) -> Scope<S & A & B & C & D & E>)
215
+ & (<S, A, B, C, D, E, F>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}) -> Scope<S & A & B & C & D & E & F>)
216
+ & (<S, A, B, C, D, E, F, G>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}) -> Scope<S & A & B & C & D & E & F & G>)
217
+ & (<S, A, B, C, D, E, F, G, H>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}) -> Scope<S & A & B & C & D & E & F & G & H>)
218
+ & (<S, A, B, C, D, E, F, G, H, I>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}) -> Scope<S & A & B & C & D & E & F & G & H & I>)
219
+ & (<S, A, B, C, D, E, F, G, H, I, J>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}) -> Scope<S & A & B & C & D & E & F & G & H & I & J>)
220
+ & (<S, A, B, C, D, E, F, G, H, I, J, K>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}) -> Scope<S & A & B & C & D & E & F & G & H & I & J & K>)
221
+ & (<S, A, B, C, D, E, F, G, H, I, J, K, L>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}, L & {}) -> Scope<S & A & B & C & D & E & F & G & H & I & J & K & L>)
222
+
223
+ export type ScopedConstructor = (() -> Scope<{}>)
224
+ & (<A>(A & {}) -> Scope<A>)
225
+ & (<A, B>(A & {}, B & {}) -> Scope<A & B>)
226
+ & (<A, B, C>(A & {}, B & {}, C & {}) -> Scope<A & B & C>)
227
+ & (<A, B, C, D>(A & {}, B & {}, C & {}, D & {}) -> Scope<A & B & C & D>)
228
+ & (<A, B, C, D, E>(A & {}, B & {}, C & {}, D & {}, E & {}) -> Scope<A & B & C & D & E>)
229
+ & (<A, B, C, D, E, F>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}) -> Scope<A & B & C & D & E & F>)
230
+ & (<A, B, C, D, E, F, G>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}) -> Scope<A & B & C & D & E & F & G>)
231
+ & (<A, B, C, D, E, F, G, H>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}) -> Scope<A & B & C & D & E & F & G & H>)
232
+ & (<A, B, C, D, E, F, G, H, I>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}) -> Scope<A & B & C & D & E & F & G & H & I>)
233
+ & (<A, B, C, D, E, F, G, H, I, J>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}) -> Scope<A & B & C & D & E & F & G & H & I & J>)
234
+ & (<A, B, C, D, E, F, G, H, I, J, K>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}) -> Scope<A & B & C & D & E & F & G & H & I & J & K>)
235
+ & (<A, B, C, D, E, F, G, H, I, J, K, L>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}, L & {}) -> Scope<A & B & C & D & E & F & G & H & I & J & K & L>)
236
+
237
+ export type ContextualConstructor = <T>(defaultValue: T) -> Contextual<T>
238
+
239
+ export type Safe = <Success, Fail>(
240
+ callbacks: {
241
+ try: () -> Success,
242
+ fallback: (err: unknown) -> Fail
243
+ }
244
+ ) -> Success | Fail
245
+
246
+ export type Fusion = {
247
+ version: Version,
248
+ Contextual: ContextualConstructor,
249
+ Safe: Safe,
250
+
251
+ doCleanup: (Task) -> (),
252
+ scoped: ScopedConstructor,
253
+ deriveScope: DeriveScopeConstructor,
254
+ innerScope: DeriveScopeConstructor,
255
+
256
+ peek: Use,
257
+ Value: ValueConstructor,
258
+ Computed: ComputedConstructor,
259
+ ForPairs: ForPairsConstructor,
260
+ ForKeys: ForKeysConstructor,
261
+ ForValues: ForValuesConstructor,
262
+ Observer: ObserverConstructor,
263
+
264
+ Tween: TweenConstructor,
265
+ Spring: SpringConstructor,
266
+
267
+ New: NewConstructor,
268
+ Hydrate: HydrateConstructor,
269
+
270
+ Child: ({Child}) -> Child,
271
+ Children: SpecialKey,
272
+ Out: (propertyName: string) -> SpecialKey,
273
+ OnEvent: (eventName: string) -> SpecialKey,
274
+ OnChange: (propertyName: string) -> SpecialKey,
275
+ Attribute: (attributeName: string) -> SpecialKey,
276
+ AttributeChange: (attributeName: string) -> SpecialKey,
277
+ AttributeOut: (attributeName: string) -> SpecialKey,
278
+ }
279
+
280
+ export type ExternalProvider = {
281
+ policies: {
282
+ allowWebLinks: boolean
283
+ },
284
+
285
+ logErrorNonFatal: (
286
+ errorString: string
287
+ ) -> (),
288
+ logWarn: (
289
+ errorString: string
290
+ ) -> (),
291
+
292
+ doTaskImmediate: (
293
+ resume: () -> ()
294
+ ) -> (),
295
+ doTaskDeferred: (
296
+ resume: () -> ()
297
+ ) -> (),
298
+ startScheduler: () -> (),
299
+ stopScheduler: () -> ()
300
+ }
301
+
302
+ export type ExternalDebugger = {
303
+ startDebugging: () -> (),
304
+ stopDebugging: () -> (),
305
+
306
+ trackScope: (
307
+ scope: Scope<unknown>
308
+ ) -> (),
309
+ untrackScope: (
310
+ scope: Scope<unknown>
311
+ ) -> ()
312
+ }
313
+
314
+ return nil
@@ -0,0 +1,91 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Time-based contextual values, to allow for transparently passing values down
8
+ the call stack.
9
+ ]]
10
+
11
+ local Package = script.Parent.Parent
12
+ local Types = require(Package.Types)
13
+ local External = require(Package.External)
14
+ -- Logging
15
+ local parseError = require(Package.Logging.parseError)
16
+
17
+ export type Self<T> = Types.Contextual<T> & {
18
+ _valuesNow: {[thread]: {value: T}},
19
+ _defaultValue: T
20
+ }
21
+
22
+ local class = {}
23
+ class.type = "Contextual"
24
+
25
+ local METATABLE = table.freeze {__index = class}
26
+ local WEAK_KEYS_METATABLE = table.freeze {__mode = "k"}
27
+
28
+ local function Contextual<T>(
29
+ defaultValue: T
30
+ ): Types.Contextual<T>
31
+ local self: Self<T> = setmetatable(
32
+ {
33
+ -- if we held strong references to threads here, then if a thread was
34
+ -- killed before this contextual had a chance to finish executing its
35
+ -- callback, it would be held strongly in this table forever
36
+ _valuesNow = setmetatable({}, WEAK_KEYS_METATABLE),
37
+ _defaultValue = defaultValue
38
+ },
39
+ METATABLE
40
+ ) :: any
41
+
42
+ return self
43
+ end
44
+
45
+ --[[
46
+ Returns the current value of this contextual.
47
+ ]]
48
+ function class.now<T>(
49
+ self: Self<T>
50
+ ): T
51
+ local thread = coroutine.running()
52
+ local value = self._valuesNow[thread]
53
+ if typeof(value) ~= "table" then
54
+ return self._defaultValue
55
+ else
56
+ return value.value
57
+ end
58
+ end
59
+
60
+ --[[
61
+ Temporarily assigns a value to this contextual.
62
+ ]]
63
+ function class.is<T>(
64
+ self: Self<T>,
65
+ newValue: T
66
+ )
67
+ local methods = {}
68
+
69
+ function methods.during<T, A...>(
70
+ _: any, -- during is called with colon syntax but we don't care
71
+ callback: (A...) -> T,
72
+ ...: A...
73
+ ): T
74
+ local thread = coroutine.running()
75
+ local prevValue = self._valuesNow[thread]
76
+ -- Storing the value in this format allows us to distinguish storing
77
+ -- `nil` from not calling `:during()` at all.
78
+ self._valuesNow[thread] = { value = newValue }
79
+ local ok, value = xpcall(callback, parseError, ...)
80
+ self._valuesNow[thread] = prevValue
81
+ if not ok then
82
+ External.logError("callbackError", value :: any)
83
+ end
84
+ return value
85
+ end
86
+
87
+ return methods
88
+ end
89
+
90
+ table.freeze(class)
91
+ return Contextual
@@ -0,0 +1,23 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ A variant of xpcall() designed for inline usage, letting you define fallback
8
+ values based on caught errors.
9
+ ]]
10
+
11
+ local Package = script.Parent.Parent
12
+
13
+ local function Safe<Success, Fail>(
14
+ callbacks: {
15
+ try: () -> Success,
16
+ fallback: (err: unknown) -> Fail
17
+ }
18
+ ): Success | Fail
19
+ local _, value = xpcall(callbacks.try, callbacks.fallback)
20
+ return value
21
+ end
22
+
23
+ return Safe
@@ -0,0 +1,29 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Implements the 'similarity test' used to determine whether two values have
8
+ a meaningful difference.
9
+
10
+ https://elttob.uk/Fusion/0.3/tutorials/best-practices/optimisation/#similarity
11
+ ]]
12
+
13
+ local function isSimilar(
14
+ a: unknown,
15
+ b: unknown
16
+ ): boolean
17
+ local typeA = typeof(a)
18
+ local isTable = typeA == "table"
19
+ local isUserdata = typeA == "userdata"
20
+ return
21
+ if not (isTable or isUserdata) then
22
+ a == b or a ~= a and b ~= b
23
+ elseif typeA == typeof(b) and (isUserdata or table.isfrozen(a :: any) or getmetatable(a :: any) ~= nil) then
24
+ a == b
25
+ else
26
+ false
27
+ end
28
+
29
+ return isSimilar
@@ -0,0 +1,35 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Attempts to merge a variadic number of tables together.
8
+ ]]
9
+
10
+ local Package = script.Parent.Parent
11
+ local External = require(Package.External)
12
+
13
+ local function merge(
14
+ overwrite: boolean,
15
+ into: {[unknown]: unknown},
16
+ ...: {[unknown]: unknown}
17
+ ): {[unknown]: unknown}
18
+ local fromTables = {...}
19
+ if #fromTables < 1 then
20
+ return into
21
+ else
22
+ for _, fromTable in fromTables do
23
+ for key, value in fromTable do
24
+ if into[key] == nil then
25
+ into[key] = value
26
+ elseif not overwrite then
27
+ External.logError("mergeConflict", nil, tostring(key))
28
+ end
29
+ end
30
+ end
31
+ return into
32
+ end
33
+ end
34
+
35
+ return merge
@@ -0,0 +1,35 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Returns the most specific custom name for the given object.
8
+ ]]
9
+
10
+ local Package = script.Parent.Parent
11
+ -- Utility
12
+ local nicknames = require(Package.Utility.nicknames)
13
+
14
+ local function nameOf(
15
+ x: unknown,
16
+ defaultName: string
17
+ ): string
18
+ local nickname = nicknames[x]
19
+ if typeof(nickname) == "string" then
20
+ return nickname
21
+ end
22
+ if typeof(x) == "table" then
23
+ local x = x :: {[any]: any}
24
+ if typeof(x.name) == "string" then
25
+ return x.name
26
+ elseif typeof(x.kind) == "string" then
27
+ return x.kind
28
+ elseif typeof(x.type) == "string" then
29
+ return x.type
30
+ end
31
+ end
32
+ return defaultName
33
+ end
34
+
35
+ return nameOf
@@ -0,0 +1,14 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Never returns.
8
+ ]]
9
+
10
+ local function never(): never
11
+ error("This codepath should not be reachable")
12
+ end
13
+
14
+ return never