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,211 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Breaks down an input table into reactive sub-objects for each pair.
8
+ ]]
9
+
10
+ local Package = script.Parent.Parent.Parent
11
+ local Types = require(Package.Types)
12
+ local External = require(Package.External)
13
+ -- Graph
14
+ local depend = require(Package.Graph.depend)
15
+ -- State
16
+ local peek = require(Package.State.peek)
17
+ local castToState = require(Package.State.castToState)
18
+ local ForTypes = require(Package.State.For.ForTypes)
19
+ -- Memory
20
+ local doCleanup = require(Package.Memory.doCleanup)
21
+ local deriveScope = require(Package.Memory.deriveScope)
22
+ local scopePool = require(Package.Memory.scopePool)
23
+ -- Utility
24
+ local nameOf = require(Package.Utility.nameOf)
25
+ local nicknames = require(Package.Utility.nicknames)
26
+
27
+ type Self<S, KI, KO, VI, VO> = ForTypes.Disassembly<S, KI, KO, VI, KO> & {
28
+ scope: (S & Types.Scope<unknown>)?,
29
+ _inputTable: Types.UsedAs<{[KI]: VI}>,
30
+ _constructor: (
31
+ Types.Scope<S>,
32
+ initialKey: KI,
33
+ initialValue: VI
34
+ ) -> ForTypes.SubObject<S, KI, KO, VI, VO>,
35
+ _subObjects: {[ForTypes.SubObject<S, KI, KO, VI, VO>]: true}
36
+ }
37
+
38
+
39
+ local class = {}
40
+ class.type = "Graph"
41
+ class.kind = "For.Disassembly"
42
+ class.timeliness = "lazy"
43
+
44
+ local METATABLE = table.freeze {__index = class}
45
+
46
+ local function Disassembly<S, KI, KO, VI, VO>(
47
+ scope: S & Types.Scope<unknown>,
48
+ inputTable: Types.UsedAs<{[KI]: VI}>,
49
+ constructor: (
50
+ Types.Scope<S>,
51
+ initialKey: KI,
52
+ initialValue: VI
53
+ ) -> ForTypes.SubObject<S, KI, KO, VI, VO>
54
+ ): ForTypes.Disassembly<S, KI, KO, VI, KO>
55
+ local createdAt = os.clock()
56
+ local self = setmetatable(
57
+ {
58
+ createdAt = createdAt,
59
+ dependencySet = {},
60
+ dependentSet = {},
61
+ scope = scope,
62
+ validity = "invalid",
63
+ _inputTable = inputTable,
64
+ _constructor = constructor,
65
+ _subObjects = {}
66
+ },
67
+ METATABLE
68
+ ) :: any
69
+
70
+ local destroy = function()
71
+ self.scope = nil
72
+ for dependency in pairs(self.dependencySet) do
73
+ dependency.dependentSet[self] = nil
74
+ end
75
+ for subObject in self._subObjects do
76
+ if subObject.maybeScope ~= nil then
77
+ doCleanup(subObject.maybeScope)
78
+ subObject.maybeScope = nil
79
+ end
80
+ end
81
+ end
82
+ self.oldestTask = destroy
83
+ nicknames[self.oldestTask] = "For (internal disassembler)"
84
+ table.insert(scope, destroy)
85
+
86
+ return self
87
+ end
88
+
89
+ function class.populate<S, KI, KO, VI, VO>(
90
+ self: Self<S, KI, KO, VI, VO>,
91
+ use: Types.Use,
92
+ output: {[KO]: VO}
93
+ ): ()
94
+ local minArrayIndex = math.huge
95
+ local maxArrayIndex = -math.huge
96
+ local hasHoles = false
97
+ for subObject in self._subObjects do
98
+ local outputKey, outputValue = subObject:useOutputPair(use)
99
+ if outputKey == nil or outputValue == nil then
100
+ hasHoles = true
101
+ continue
102
+ elseif output[outputKey] ~= nil then
103
+ External.logErrorNonFatal("forKeyCollision", nil, tostring(outputKey))
104
+ continue
105
+ end
106
+ output[outputKey] = outputValue
107
+ if typeof(outputKey) == "number" then
108
+ minArrayIndex = math.min(minArrayIndex, outputKey)
109
+ maxArrayIndex = math.max(maxArrayIndex, outputKey)
110
+ end
111
+ end
112
+ -- Be careful of NaN here
113
+ if hasHoles and maxArrayIndex > minArrayIndex then
114
+ local output: {[number]: VO} = output :: any
115
+ local moveToIndex = minArrayIndex
116
+ for moveFromIndex = minArrayIndex, maxArrayIndex do
117
+ local outputValue = output[moveFromIndex]
118
+ if outputValue == nil then
119
+ continue
120
+ end
121
+ -- The ordering is important in case the indices are the same
122
+ output[moveFromIndex] = nil
123
+ output[moveToIndex] = outputValue
124
+ moveToIndex += 1
125
+ end
126
+ end
127
+ end
128
+
129
+ function class._evaluate<S, KI, KO, VI, VO>(
130
+ self: Self<S, KI, KO, VI, VO>
131
+ ): boolean
132
+ local outerScope = self.scope :: S & Types.Scope<unknown>
133
+ local inputState = castToState(self._inputTable)
134
+ if inputState ~= nil then
135
+ if inputState.scope == nil then
136
+ External.logError(
137
+ "useAfterDestroy",
138
+ nil,
139
+ `The input {nameOf(inputState, "table")}`,
140
+ `the For object that is watching it`
141
+ )
142
+ end
143
+ depend(self, inputState)
144
+ end
145
+
146
+ local pendingPairs = {} :: {[KI]: VI}
147
+ for key, value in peek(self._inputTable) do
148
+ pendingPairs[key] = value
149
+ end
150
+
151
+ local newSubObjects = {} :: typeof(self._subObjects)
152
+
153
+ for subObject in self._subObjects do
154
+ local reused = false
155
+ local oldInputKey = subObject.inputKey
156
+ local oldInputValue = subObject.inputValue
157
+ local newInputKey: KI
158
+ -- Reuse when the keys are identical.
159
+ if not subObject.roamKeys and pendingPairs[oldInputKey] ~= nil then
160
+ reused = true
161
+ newInputKey = oldInputKey
162
+ else -- Try and reuse some other pair instead.
163
+ for pendingKey, pendingValue in pendingPairs do
164
+ reused = true
165
+ newInputKey = pendingKey
166
+ if subObject.roamValues then
167
+ break
168
+ end
169
+ if pendingValue == oldInputValue then
170
+ -- If the values are the same, then no need to update those,
171
+ -- so prefer this choice to any other.
172
+ break
173
+ end
174
+ end
175
+ end
176
+ if reused then
177
+ local newInputValue = pendingPairs[newInputKey]
178
+ newSubObjects[subObject] = true
179
+ if newInputKey ~= oldInputKey then
180
+ subObject.inputKey = newInputKey
181
+ subObject:invalidateInputKey()
182
+ end
183
+ if newInputValue ~= oldInputValue then
184
+ subObject.inputValue = newInputValue
185
+ subObject:invalidateInputValue()
186
+ end
187
+ pendingPairs[newInputKey] = nil
188
+ else -- Too many sub objects for the number of pairs.
189
+ if subObject.maybeScope ~= nil then
190
+ doCleanup(subObject.maybeScope)
191
+ subObject.maybeScope = nil
192
+ end
193
+ end
194
+ end
195
+
196
+ -- Generate new objects if needed to cover the remaining pending pairs.
197
+ for pendingKey, pendingValue in pendingPairs do
198
+ local subObject = self._constructor(deriveScope(outerScope), pendingKey, pendingValue)
199
+ if subObject.maybeScope ~= nil then
200
+ subObject.maybeScope = scopePool.giveIfEmpty(subObject.maybeScope)
201
+ end
202
+ newSubObjects[subObject] = true
203
+ end
204
+
205
+ self._subObjects = newSubObjects
206
+
207
+ return true
208
+ end
209
+
210
+ table.freeze(class)
211
+ return Disassembly
@@ -0,0 +1,30 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Stores types that are commonly used between For objects.
8
+ ]]
9
+
10
+ local Package = script.Parent.Parent.Parent
11
+ local Types = require(Package.Types)
12
+
13
+ export type SubObject<S, KI, KO, VI, VO> = {
14
+ -- Not all sub objects need to store a scope, for example if the scope
15
+ -- remains empty, it'll be given back to the scope pool.
16
+ maybeScope: Types.Scope<S>?,
17
+ inputKey: KI,
18
+ inputValue: VI,
19
+ roamKeys: boolean,
20
+ roamValues: boolean,
21
+ invalidateInputKey: (SubObject<S, KI, KO, VI, VO>) -> (),
22
+ invalidateInputValue: (SubObject<S, KI, KO, VI, VO>) -> (),
23
+ useOutputPair: (SubObject<S, KI, KO, VI, VO>, Types.Use) -> (KO?, VO?)
24
+ }
25
+
26
+ export type Disassembly<S, KI, KO, VI, VO> = Types.GraphObject & {
27
+ populate: (Disassembly<S, KI, KO, VI, VO>, Types.Use, output: {[KO]: VO}) -> ()
28
+ }
29
+
30
+ return nil
@@ -0,0 +1,110 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ The generic implementation for all `For` objects.
8
+ ]]
9
+
10
+ local Package = script.Parent.Parent
11
+ local Types = require(Package.Types)
12
+ local External = require(Package.External)
13
+ -- Graph
14
+ local depend = require(Package.Graph.depend)
15
+ -- State
16
+ local peek = require(Package.State.peek)
17
+ local castToState = require(Package.State.castToState)
18
+ local ForTypes = require(Package.State.For.ForTypes)
19
+ -- Utility
20
+ local never = require(Package.Utility.never)
21
+ local nicknames = require(Package.Utility.nicknames)
22
+
23
+ local Disassembly = require(Package.State.For.Disassembly)
24
+
25
+ type Self<S, KI, KO, VI, VO> = Types.For<KO, VO> & {
26
+ _disassembly: ForTypes.Disassembly<S, KI, KO, VI, VO>
27
+ }
28
+
29
+ local class = {}
30
+ class.type = "State"
31
+ class.kind = "For"
32
+ class.timeliness = "lazy"
33
+
34
+ local METATABLE = table.freeze {__index = class}
35
+
36
+ local function For<S, KI, KO, VI, VO>(
37
+ scope: Types.Scope<S>,
38
+ inputTable: Types.UsedAs<{[KI]: VI}>,
39
+ constructor: (
40
+ Types.Scope<S>,
41
+ initialKey: KI,
42
+ initialValue: VI
43
+ ) -> ForTypes.SubObject<S, KI, KO, VI, VO>
44
+ ): Types.For<KO, VO>
45
+ local createdAt = os.clock()
46
+ local self: Self<S, KI, KO, VI, VO> = setmetatable(
47
+ {
48
+ createdAt = createdAt,
49
+ dependencySet = {},
50
+ dependentSet = {},
51
+ scope = scope,
52
+ validity = "invalid",
53
+ _EXTREMELY_DANGEROUS_usedAsValue = {},
54
+ _disassembly = Disassembly(
55
+ scope,
56
+ inputTable,
57
+ constructor
58
+ )
59
+ },
60
+ METATABLE
61
+ ) :: any
62
+
63
+ local destroy = function()
64
+ self.scope = nil
65
+ for dependency in pairs(self.dependencySet) do
66
+ dependency.dependentSet[self] = nil
67
+ end
68
+ end
69
+ self.oldestTask = destroy
70
+ nicknames[self.oldestTask] = "For"
71
+ table.insert(scope, destroy)
72
+
73
+ return self
74
+ end
75
+
76
+ function class.get<S, KI, KO, VI, VO>(
77
+ _self: Self<S, KI, KO, VI, VO>
78
+ ): never
79
+ External.logError("stateGetWasRemoved")
80
+ return never()
81
+ end
82
+
83
+ function class._evaluate<S, KI, KO, VI, VO>(
84
+ self: Self<S, KI, KO, VI, VO>
85
+ ): boolean
86
+ if self.scope == nil then
87
+ return false
88
+ end
89
+ local outerScope = self.scope :: S & Types.Scope<unknown>
90
+
91
+ depend(self, self._disassembly)
92
+ table.clear(self._EXTREMELY_DANGEROUS_usedAsValue)
93
+ self._disassembly:populate(
94
+ function<T>(
95
+ maybeState: Types.UsedAs<T>
96
+ ): T
97
+ local state = castToState(maybeState)
98
+ if state ~= nil then
99
+ depend(self, state)
100
+ end
101
+ return peek(maybeState)
102
+ end,
103
+ self._EXTREMELY_DANGEROUS_usedAsValue
104
+ )
105
+
106
+ return true
107
+ end
108
+
109
+ table.freeze(class)
110
+ return For
@@ -0,0 +1,94 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Constructs and returns a new For state object which processes keys and
8
+ preserves values.
9
+
10
+ https://elttob.uk/Fusion/0.3/api-reference/state/members/forkeys/
11
+
12
+ TODO: the sub objects constructed here can be more efficiently implemented
13
+ as a dedicated state object.
14
+ ]]
15
+
16
+ local Package = script.Parent.Parent
17
+ local Types = require(Package.Types)
18
+ local External = require(Package.External)
19
+ -- Memory
20
+ local doCleanup = require(Package.Memory.doCleanup)
21
+ -- State
22
+ local For = require(Package.State.For)
23
+ local Value = require(Package.State.Value)
24
+ local Computed = require(Package.State.Computed)
25
+ local ForTypes = require(Package.State.For.ForTypes)
26
+ -- Logging
27
+ local parseError = require(Package.Logging.parseError)
28
+
29
+ local SUB_OBJECT_META = {
30
+ __index = {
31
+ roamKeys = false,
32
+ roamValues = true,
33
+ invalidateInputKey = function(self): ()
34
+ self._inputKeyState:set(self.inputKey)
35
+ end,
36
+ invalidateInputValue = function(self): ()
37
+ -- do nothing
38
+ end,
39
+ useOutputPair = function(self, use)
40
+ return use(self._outputKeyState), self.inputValue
41
+ end
42
+ }
43
+ }
44
+
45
+ local function SubObject<KI, KO, V, S>(
46
+ scope: Types.Scope<S>,
47
+ initialKey: KI,
48
+ initialValue: V,
49
+ processor: (Types.Use, Types.Scope<S>, KI) -> KO
50
+ ): ForTypes.SubObject<S, KI, KO, V, V>
51
+ local self = {}
52
+ self.maybeScope = scope
53
+ self.inputKey = initialKey
54
+ self.inputValue = initialValue
55
+ self._inputKeyState = Value(scope, initialKey)
56
+ self._processor = processor
57
+ self._outputKeyState = Computed(scope, function(use, scope): KO?
58
+ local inputKey = use(self._inputKeyState)
59
+ local ok, outputKey = xpcall(self._processor, parseError, use, scope, inputKey)
60
+ if ok then
61
+ return outputKey
62
+ else
63
+ local error: Types.Error = outputKey :: any
64
+ error.context = `while processing key {tostring(inputKey)}`
65
+ External.logErrorNonFatal("callbackError", error)
66
+ doCleanup(scope)
67
+ table.clear(scope)
68
+ return nil
69
+ end
70
+ end)
71
+ return setmetatable(self, SUB_OBJECT_META) :: any
72
+ end
73
+
74
+ local function ForKeys<KI, KO, V, S>(
75
+ scope: Types.Scope<S>,
76
+ inputTable: Types.UsedAs<{[KI]: V}>,
77
+ processor: (Types.Use, Types.Scope<S>, KI) -> KO,
78
+ destructor: unknown?
79
+ ): Types.For<KO, V>
80
+ if typeof(inputTable) == "function" then
81
+ External.logError("scopeMissing", nil, "ForKeys", "myScope:ForKeys(inputTable, function(scope, use, key) ... end)")
82
+ elseif destructor ~= nil then
83
+ External.logWarn("destructorRedundant", "ForKeys")
84
+ end
85
+ return For(
86
+ scope,
87
+ inputTable,
88
+ function(scope, initialKey, initialValue)
89
+ return SubObject(scope, initialKey, initialValue, processor)
90
+ end
91
+ )
92
+ end
93
+
94
+ return ForKeys :: Types.ForKeysConstructor
@@ -0,0 +1,97 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Constructs and returns a new For state object which processes keys and
8
+ values in pairs.
9
+
10
+ https://elttob.uk/Fusion/0.3/api-reference/state/members/forpairs/
11
+
12
+ TODO: the sub objects constructed here can be more efficiently implemented
13
+ as a dedicated state object.
14
+ ]]
15
+
16
+ local Package = script.Parent.Parent
17
+ local Types = require(Package.Types)
18
+ local External = require(Package.External)
19
+ -- State
20
+ local For = require(Package.State.For)
21
+ local Value = require(Package.State.Value)
22
+ local Computed = require(Package.State.Computed)
23
+ local ForTypes = require(Package.State.For.ForTypes)
24
+ -- Logging
25
+ local parseError = require(Package.Logging.parseError)
26
+ -- Memory
27
+ local doCleanup = require(Package.Memory.doCleanup)
28
+
29
+ local SUB_OBJECT_META = {
30
+ __index = {
31
+ roamKeys = false,
32
+ roamValues = false,
33
+ invalidateInputKey = function(self): ()
34
+ self._inputKeyState:set(self.inputKey)
35
+ end,
36
+ invalidateInputValue = function(self): ()
37
+ self._inputValueState:set(self.inputValue)
38
+ end,
39
+ useOutputPair = function(self, use)
40
+ local pair = use(self._outputPairState)
41
+ return pair.key, pair.value
42
+ end
43
+ }
44
+ }
45
+
46
+ local function SubObject<KI, KO, VI, VO, S>(
47
+ scope: Types.Scope<S>,
48
+ initialKey: KI,
49
+ initialValue: VI,
50
+ processor: (Types.Use, Types.Scope<S>, KI, VI) -> (KO, VO)
51
+ ): ForTypes.SubObject<S, KI, KO, VI, VO>
52
+ local self = {}
53
+ self.maybeScope = scope
54
+ self.inputKey = initialKey
55
+ self.inputValue = initialValue
56
+ self._inputKeyState = Value(scope, initialKey)
57
+ self._inputValueState = Value(scope, initialValue)
58
+ self._processor = processor
59
+ self._outputPairState = Computed(scope, function(use, scope): {key: KO?, value: VO?}
60
+ local inputKey = use(self._inputKeyState)
61
+ local inputValue = use(self._inputValueState)
62
+ local ok, outputKey, outputValue = xpcall(self._processor, parseError, use, scope, inputKey, inputValue)
63
+ if ok then
64
+ return {key = outputKey, value = outputValue}
65
+ else
66
+ local error: Types.Error = outputKey :: any
67
+ error.context = `while processing key {tostring(inputValue)} and value {tostring(inputValue)}`
68
+ External.logErrorNonFatal("callbackError", error)
69
+ doCleanup(scope)
70
+ table.clear(scope)
71
+ return {key = nil, value = nil}
72
+ end
73
+ end)
74
+ return setmetatable(self, SUB_OBJECT_META) :: any
75
+ end
76
+
77
+ local function ForPairs<KI, KO, VI, VO, S>(
78
+ scope: Types.Scope<S>,
79
+ inputTable: Types.UsedAs<{[KI]: VI}>,
80
+ processor: (Types.Use, Types.Scope<S>, KI, VI) -> (KO, VO),
81
+ destructor: unknown?
82
+ ): Types.For<KO, VO>
83
+ if typeof(inputTable) == "function" then
84
+ External.logError("scopeMissing", nil, "ForPairs", "myScope:ForPairs(inputTable, function(scope, use, key, value) ... end)")
85
+ elseif destructor ~= nil then
86
+ External.logWarn("destructorRedundant", "ForPairs")
87
+ end
88
+ return For(
89
+ scope,
90
+ inputTable,
91
+ function(scope, initialKey, initialValue)
92
+ return SubObject(scope, initialKey, initialValue, processor)
93
+ end
94
+ )
95
+ end
96
+
97
+ return ForPairs :: Types.ForPairsConstructor
@@ -0,0 +1,94 @@
1
+ --!strict
2
+ --!nolint LocalUnused
3
+ --!nolint LocalShadow
4
+ local task = nil -- Disable usage of Roblox's task scheduler
5
+
6
+ --[[
7
+ Constructs and returns a new For state object which processes values and
8
+ preserves keys.
9
+
10
+ https://elttob.uk/Fusion/0.3/api-reference/state/members/forvalues/
11
+
12
+ TODO: the sub objects constructed here can be more efficiently implemented
13
+ as a dedicated state object.
14
+ ]]
15
+
16
+ local Package = script.Parent.Parent
17
+ local Types = require(Package.Types)
18
+ local External = require(Package.External)
19
+ -- State
20
+ local For = require(Package.State.For)
21
+ local Value = require(Package.State.Value)
22
+ local Computed = require(Package.State.Computed)
23
+ local ForTypes = require(Package.State.For.ForTypes)
24
+ -- Logging
25
+ local parseError = require(Package.Logging.parseError)
26
+ -- Memory
27
+ local doCleanup = require(Package.Memory.doCleanup)
28
+
29
+ local SUB_OBJECT_META = {
30
+ __index = {
31
+ roamKeys = true,
32
+ roamValues = false,
33
+ invalidateInputKey = function(self): ()
34
+ -- do nothing
35
+ end,
36
+ invalidateInputValue = function(self): ()
37
+ self._inputValueState:set(self.inputValue)
38
+ end,
39
+ useOutputPair = function(self, use)
40
+ return self.inputKey, use(self._outputValueState)
41
+ end
42
+ }
43
+ }
44
+
45
+ local function SubObject<K, VI, VO, S>(
46
+ scope: Types.Scope<S>,
47
+ initialKey: K,
48
+ initialValue: VI,
49
+ processor: (Types.Use, Types.Scope<S>, VI) -> VO
50
+ ): ForTypes.SubObject<S, K, K, VI, VO>
51
+ local self = {}
52
+ self.maybeScope = scope
53
+ self.inputKey = initialKey
54
+ self.inputValue = initialValue
55
+ self._inputValueState = Value(scope, initialValue)
56
+ self._processor = processor
57
+ self._outputValueState = Computed(scope, function(use, scope): VO?
58
+ local inputValue = use(self._inputValueState)
59
+ local ok, outputValue = xpcall(self._processor, parseError, use, scope, inputValue)
60
+ if ok then
61
+ return outputValue
62
+ else
63
+ local error: Types.Error = outputValue :: any
64
+ error.context = `while processing value {tostring(inputValue)}`
65
+ External.logErrorNonFatal("callbackError", error)
66
+ doCleanup(scope)
67
+ table.clear(scope)
68
+ return nil
69
+ end
70
+ end)
71
+ return setmetatable(self, SUB_OBJECT_META) :: any
72
+ end
73
+
74
+ local function ForValues<K, VI, VO, S>(
75
+ scope: Types.Scope<S>,
76
+ inputTable: Types.UsedAs<{[K]: VI}>,
77
+ processor: (Types.Use, Types.Scope<S>, VI) -> VO,
78
+ destructor: unknown?
79
+ ): Types.For<K, VO>
80
+ if typeof(inputTable) == "function" then
81
+ External.logError("scopeMissing", nil, "ForValues", "myScope:ForValues(inputTable, function(scope, use, value) ... end)")
82
+ elseif destructor ~= nil then
83
+ External.logWarn("destructorRedundant", "ForValues")
84
+ end
85
+ return For(
86
+ scope,
87
+ inputTable,
88
+ function(scope, initialKey, initialValue)
89
+ return SubObject(scope, initialKey, initialValue, processor)
90
+ end
91
+ )
92
+ end
93
+
94
+ return ForValues :: Types.ForValuesConstructor