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,938 @@
1
+ --!strict
2
+
3
+ -- TableUtil
4
+ -- Stephen Leitnick
5
+ -- September 13, 2017
6
+
7
+ --[=[
8
+ @class TableUtil
9
+
10
+ A collection of helpful table utility functions. Many of these functions are carried over from JavaScript or
11
+ Python that are not present in Lua.
12
+
13
+ Tables that only work specifically with arrays or dictionaries are marked as such in the documentation.
14
+
15
+ :::info Immutability
16
+ All functions (_except_ `SwapRemove`, `SwapRemoveFirstValue`, and `Lock`) treat tables as immutable and will return
17
+ copies of the given table(s) with the operations performed on the copies.
18
+ :::
19
+ ]=]
20
+ local TableUtil = {}
21
+
22
+ local HttpService = game:GetService("HttpService")
23
+ local rng = Random.new()
24
+
25
+ --[=[
26
+ @within TableUtil
27
+ @function Copy
28
+ @param tbl table -- Table to copy
29
+ @param deep boolean? -- Whether or not to perform a deep copy
30
+ @return table
31
+
32
+ Creates a copy of the given table. By default, a shallow copy is
33
+ performed. For deep copies, a second boolean argument must be
34
+ passed to the function.
35
+
36
+ :::caution No cyclical references
37
+ Deep copies are _not_ protected against cyclical references. Passing
38
+ a table with cyclical references _and_ the `deep` parameter set to
39
+ `true` will result in a stack-overflow.
40
+ :::
41
+ ]=]
42
+ local function Copy<T>(t: T, deep: boolean?): T
43
+ if not deep then
44
+ return (table.clone(t :: any) :: any) :: T
45
+ end
46
+ local function DeepCopy(tbl: { any })
47
+ local tCopy = table.clone(tbl)
48
+ for k, v in tCopy do
49
+ if type(v) == "table" then
50
+ tCopy[k] = DeepCopy(v)
51
+ end
52
+ end
53
+ return tCopy
54
+ end
55
+ return DeepCopy(t :: any) :: T
56
+ end
57
+
58
+ --[=[
59
+ @within TableUtil
60
+ @function Sync
61
+ @param srcTbl table -- Source table
62
+ @param templateTbl table -- Template table
63
+ @return table
64
+
65
+ Synchronizes the `srcTbl` based on the `templateTbl`. This will make
66
+ sure that `srcTbl` has all of the same keys as `templateTbl`, including
67
+ removing keys in `srcTbl` that are not present in `templateTbl`. This
68
+ is a _deep_ operation, so any nested tables will be synchronized as
69
+ well.
70
+
71
+ ```lua
72
+ local template = {kills = 0, deaths = 0, xp = 0}
73
+ local data = {kills = 10, experience = 12}
74
+ data = TableUtil.Sync(data, template)
75
+ print(data) --> {kills = 10, deaths = 0, xp = 0}
76
+ ```
77
+
78
+ :::caution Data Loss Warning
79
+ This is a two-way sync, so the source table will have data
80
+ _removed_ that isn't found in the template table. This can
81
+ be problematic if used for player data, where there might
82
+ be dynamic data added that isn't in the template.
83
+
84
+ For player data, use `TableUtil.Reconcile` instead.
85
+ :::
86
+ ]=]
87
+ local function Sync<S, T>(srcTbl: S, templateTbl: T): T
88
+ assert(type(srcTbl) == "table", "First argument must be a table")
89
+ assert(type(templateTbl) == "table", "Second argument must be a table")
90
+
91
+ local tbl = table.clone(srcTbl)
92
+
93
+ -- If 'tbl' has something 'templateTbl' doesn't, then remove it from 'tbl'
94
+ -- If 'tbl' has something of a different type than 'templateTbl', copy from 'templateTbl'
95
+ -- If 'templateTbl' has something 'tbl' doesn't, then add it to 'tbl'
96
+ for k, v in pairs(tbl) do
97
+ local vTemplate = templateTbl[k]
98
+
99
+ -- Remove keys not within template:
100
+ if vTemplate == nil then
101
+ tbl[k] = nil
102
+
103
+ -- Synchronize data types:
104
+ elseif type(v) ~= type(vTemplate) then
105
+ if type(vTemplate) == "table" then
106
+ tbl[k] = Copy(vTemplate, true)
107
+ else
108
+ tbl[k] = vTemplate
109
+ end
110
+
111
+ -- Synchronize sub-tables:
112
+ elseif type(v) == "table" then
113
+ tbl[k] = Sync(v, vTemplate)
114
+ end
115
+ end
116
+
117
+ -- Add any missing keys:
118
+ for k, vTemplate in pairs(templateTbl) do
119
+ local v = tbl[k]
120
+
121
+ if v == nil then
122
+ if type(vTemplate) == "table" then
123
+ tbl[k] = Copy(vTemplate, true)
124
+ else
125
+ tbl[k] = vTemplate
126
+ end
127
+ end
128
+ end
129
+
130
+ return (tbl :: any) :: T
131
+ end
132
+
133
+ --[=[
134
+ @within TableUtil
135
+ @function Reconcile
136
+ @param source table
137
+ @param template table
138
+ @return table
139
+
140
+ Performs a one-way sync on the `source` table against the
141
+ `template` table. Any keys found in `template` that are
142
+ not found in `source` will be added to `source`. This is
143
+ useful for syncing player data against data template tables
144
+ to ensure players have all the necessary keys, while
145
+ maintaining existing keys that may no longer be in the
146
+ template.
147
+
148
+ This is a deep operation, so nested tables will also be
149
+ properly reconciled.
150
+
151
+ ```lua
152
+ local template = {kills = 0, deaths = 0, xp = 0}
153
+ local data = {kills = 10, abc = 20}
154
+ local correctedData = TableUtil.Reconcile(data, template)
155
+
156
+ print(correctedData) --> {kills = 10, deaths = 0, xp = 0, abc = 20}
157
+ ```
158
+ ]=]
159
+ local function Reconcile<S, T>(src: S, template: T): S & T
160
+ assert(type(src) == "table", "First argument must be a table")
161
+ assert(type(template) == "table", "Second argument must be a table")
162
+
163
+ local tbl = table.clone(src)
164
+
165
+ for k, v in template do
166
+ local sv = src[k]
167
+ if sv == nil then
168
+ if type(v) == "table" then
169
+ tbl[k] = Copy(v, true)
170
+ else
171
+ tbl[k] = v
172
+ end
173
+ elseif type(sv) == "table" then
174
+ if type(v) == "table" then
175
+ tbl[k] = Reconcile(sv, v)
176
+ else
177
+ tbl[k] = Copy(sv, true)
178
+ end
179
+ end
180
+ end
181
+
182
+ return (tbl :: any) :: S & T
183
+ end
184
+
185
+ --[=[
186
+ @within TableUtil
187
+ @function SwapRemove
188
+ @param tbl table -- Array
189
+ @param i number -- Index
190
+
191
+ Removes index `i` in the table by swapping the value at `i` with
192
+ the last value in the array, and then trimming off the last
193
+ value from the array.
194
+
195
+ This allows removal of the value at `i` in `O(1)` time, but does
196
+ not preserve array ordering. If a value needs to be removed from
197
+ an array, but ordering of the array does not matter, using
198
+ `SwapRemove` is always preferred over `table.remove`.
199
+
200
+ In the following example, we remove "B" at index 2. SwapRemove does
201
+ this by moving the last value "E" over top of "B", and then trimming
202
+ off "E" at the end of the array:
203
+ ```lua
204
+ local t = {"A", "B", "C", "D", "E"}
205
+ TableUtil.SwapRemove(t, 2) -- Remove "B"
206
+ print(t) --> {"A", "E", "C", "D"}
207
+ ```
208
+
209
+ :::note Arrays only
210
+ This function works on arrays, but not dictionaries.
211
+ :::
212
+ ]=]
213
+ local function SwapRemove<T>(t: { T }, i: number)
214
+ local n = #t
215
+ t[i] = t[n]
216
+ t[n] = nil
217
+ end
218
+
219
+ --[=[
220
+ @within TableUtil
221
+ @function SwapRemoveFirstValue
222
+ @param tbl table -- Array
223
+ @param v any -- Value to find
224
+ @return number?
225
+
226
+ Performs `table.find(tbl, v)` to find the index of the given
227
+ value, and then performs `TableUtil.SwapRemove` on that index.
228
+
229
+ ```lua
230
+ local t = {"A", "B", "C", "D", "E"}
231
+ TableUtil.SwapRemoveFirstValue(t, "C")
232
+ print(t) --> {"A", "B", "E", "D"}
233
+ ```
234
+
235
+ :::note Arrays only
236
+ This function works on arrays, but not dictionaries.
237
+ :::
238
+ ]=]
239
+ local function SwapRemoveFirstValue<T>(t: { T }, v: T): number?
240
+ local index: number? = table.find(t, v)
241
+ if index then
242
+ SwapRemove(t, index)
243
+ end
244
+ return index
245
+ end
246
+
247
+ --[=[
248
+ @within TableUtil
249
+ @function Map
250
+ @param tbl table
251
+ @param predicate (value: any, key: any, tbl: table) -> newValue: any
252
+ @return table
253
+
254
+ Performs a map operation against the given table, which can be used to
255
+ map new values based on the old values at given keys/indices.
256
+
257
+ For example:
258
+
259
+ ```lua
260
+ local t = {A = 10, B = 20, C = 30}
261
+ local t2 = TableUtil.Map(t, function(value)
262
+ return value * 2
263
+ end)
264
+ print(t2) --> {A = 20, B = 40, C = 60}
265
+ ```
266
+ ]=]
267
+ local function Map<T, M>(t: { T }, f: (T, number, { T }) -> M): { M }
268
+ assert(type(t) == "table", "First argument must be a table")
269
+ assert(type(f) == "function", "Second argument must be a function")
270
+ local newT = table.create(#t)
271
+ for k, v in t do
272
+ newT[k] = f(v, k, t)
273
+ end
274
+ return newT
275
+ end
276
+
277
+ --[=[
278
+ @within TableUtil
279
+ @function Filter
280
+ @param tbl table
281
+ @param predicate (value: any, key: any, tbl: table) -> keep: boolean
282
+ @return table
283
+
284
+ Performs a filter operation against the given table, which can be used to
285
+ filter out unwanted values from the table.
286
+
287
+ For example:
288
+
289
+ ```lua
290
+ local t = {A = 10, B = 20, C = 30}
291
+ local t2 = TableUtil.Filter(t, function(value, key)
292
+ return value > 15
293
+ end)
294
+ print(t2) --> {B = 40, C = 60}
295
+ ```
296
+ ]=]
297
+ local function Filter<T>(t: { T }, predicate: (T, any, { T }) -> boolean): { T }
298
+ assert(type(t) == "table", "First argument must be a table")
299
+ assert(type(predicate) == "function", "Second argument must be a function")
300
+ local newT = table.create(#t)
301
+ if #t > 0 then
302
+ local n = 0
303
+ for i, v in t do
304
+ if predicate(v, i, t) then
305
+ n += 1
306
+ newT[n] = v
307
+ end
308
+ end
309
+ else
310
+ for k, v in t do
311
+ if predicate(v, k, t) then
312
+ newT[k] = v
313
+ end
314
+ end
315
+ end
316
+ return newT
317
+ end
318
+
319
+ --[=[
320
+ @within TableUtil
321
+ @function Reduce
322
+ @param tbl table
323
+ @param predicate (accumulator: any, value: any, index: any, tbl: table) -> result: any
324
+ @return table
325
+
326
+ Performs a reduce operation against the given table, which can be used to
327
+ reduce the table into a single value. This could be used to sum up a table
328
+ or transform all the values into a compound value of any kind.
329
+
330
+ For example:
331
+
332
+ ```lua
333
+ local t = {10, 20, 30, 40}
334
+ local result = TableUtil.Reduce(t, function(accum, value)
335
+ return accum + value
336
+ end)
337
+ print(result) --> 100
338
+ ```
339
+ ]=]
340
+ local function Reduce<T, R>(t: { T }, predicate: (R, T, any, { T }) -> R, init: R): R
341
+ assert(type(t) == "table", "First argument must be a table")
342
+ assert(type(predicate) == "function", "Second argument must be a function")
343
+ local result = init :: R
344
+ if #t > 0 then
345
+ local start = 1
346
+ if init == nil then
347
+ result = (t[1] :: any) :: R
348
+ start = 2
349
+ end
350
+ for i = start, #t do
351
+ result = predicate(result, t[i], i, t)
352
+ end
353
+ else
354
+ local start = nil
355
+ if init == nil then
356
+ result = (next(t) :: any) :: R
357
+ start = result
358
+ end
359
+ for k, v in next, t, start :: any? do
360
+ result = predicate(result, v, k, t)
361
+ end
362
+ end
363
+ return result
364
+ end
365
+
366
+ --[=[
367
+ @within TableUtil
368
+ @function Assign
369
+ @param target table
370
+ @param ... table
371
+ @return table
372
+
373
+ Copies all values of the given tables into the `target` table.
374
+
375
+ ```lua
376
+ local t = {A = 10}
377
+ local t2 = {B = 20}
378
+ local t3 = {C = 30, D = 40}
379
+ local newT = TableUtil.Assign(t, t2, t3)
380
+ print(newT) --> {A = 10, B = 20, C = 30, D = 40}
381
+ ```
382
+ ]=]
383
+ local function Assign<T>(target: { T }, ...: { any }): { T } & { any }
384
+ local tbl = table.clone(target)
385
+ for _, src in { ... } do
386
+ for k, v in src do
387
+ tbl[k] = v
388
+ end
389
+ end
390
+ return tbl
391
+ end
392
+
393
+ --[=[
394
+ @within TableUtil
395
+ @function Extend
396
+ @param target table
397
+ @param extension table
398
+ @return table
399
+
400
+ Extends the target array with the extension array.
401
+
402
+ ```lua
403
+ local t = {10, 20, 30}
404
+ local t2 = {30, 40, 50}
405
+ local tNew = TableUtil.Extend(t, t2)
406
+ print(tNew) --> {10, 20, 30, 30, 40, 50}
407
+ ```
408
+
409
+ :::note Arrays only
410
+ This function works on arrays, but not dictionaries.
411
+ :::
412
+ ]=]
413
+ local function Extend<T, E>(target: { T }, extension: { E }): { T } & { E }
414
+ local tbl = table.clone(target) :: { any }
415
+ for _, v in extension do
416
+ table.insert(tbl, v)
417
+ end
418
+ return tbl
419
+ end
420
+
421
+ --[=[
422
+ @within TableUtil
423
+ @function Reverse
424
+ @param tbl table
425
+ @return table
426
+
427
+ Reverses the array.
428
+
429
+ ```lua
430
+ local t = {1, 5, 10}
431
+ local tReverse = TableUtil.Reverse(t)
432
+ print(tReverse) --> {10, 5, 1}
433
+ ```
434
+
435
+ :::note Arrays only
436
+ This function works on arrays, but not dictionaries.
437
+ :::
438
+ ]=]
439
+ local function Reverse<T>(tbl: { T }): { T }
440
+ local n = #tbl
441
+ local tblRev = table.create(n)
442
+ for i = 1, n do
443
+ tblRev[i] = tbl[n - i + 1]
444
+ end
445
+ return tblRev
446
+ end
447
+
448
+ --[=[
449
+ @within TableUtil
450
+ @function Shuffle
451
+ @param tbl table
452
+ @param rngOverride Random?
453
+ @return table
454
+
455
+ Shuffles the table.
456
+
457
+ ```lua
458
+ local t = {1, 2, 3, 4, 5, 6, 7, 8, 9}
459
+ local shuffled = TableUtil.Shuffle(t)
460
+ print(shuffled) --> e.g. {9, 4, 6, 7, 3, 1, 5, 8, 2}
461
+ ```
462
+
463
+ :::note Arrays only
464
+ This function works on arrays, but not dictionaries.
465
+ :::
466
+ ]=]
467
+ local function Shuffle<T>(tbl: { T }, rngOverride: Random?): { T }
468
+ assert(type(tbl) == "table", "First argument must be a table")
469
+ local shuffled = table.clone(tbl)
470
+ local random = if typeof(rngOverride) == "Random" then rngOverride else rng
471
+ for i = #tbl, 2, -1 do
472
+ local j = random:NextInteger(1, i)
473
+ shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
474
+ end
475
+ return shuffled
476
+ end
477
+
478
+ --[=[
479
+ @within TableUtil
480
+ @function Sample
481
+ @param tbl table
482
+ @param sampleSize number
483
+ @param rngOverride Random?
484
+ @return table
485
+
486
+ Returns a random sample of the table.
487
+
488
+ ```lua
489
+ local t = {1, 2, 3, 4, 5, 6, 7, 8, 9}
490
+ local sample = TableUtil.Sample(t, 3)
491
+ print(sample) --> e.g. {6, 2, 5}
492
+ ```
493
+
494
+ :::note Arrays only
495
+ This function works on arrays, but not dictionaries.
496
+ :::
497
+ ]=]
498
+ local function Sample<T>(tbl: { T }, size: number, rngOverride: Random?): { T }
499
+ assert(type(tbl) == "table", "First argument must be a table")
500
+ assert(type(size) == "number", "Second argument must be a number")
501
+
502
+ -- If given table is empty, just return a new empty table:
503
+ local len = #tbl
504
+ if len == 0 then
505
+ return {}
506
+ end
507
+
508
+ local shuffled = table.clone(tbl)
509
+ local sample = table.create(size)
510
+ local random = if typeof(rngOverride) == "Random" then rngOverride else rng
511
+
512
+ -- Clamp sample size to be no larger than the given table size:
513
+ size = math.clamp(size, 1, len)
514
+
515
+ for i = 1, size do
516
+ local j = random:NextInteger(i, len)
517
+ shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
518
+ end
519
+
520
+ table.move(shuffled, 1, size, 1, sample)
521
+
522
+ return sample
523
+ end
524
+
525
+ --[=[
526
+ @within TableUtil
527
+ @function Flat
528
+ @param tbl table
529
+ @param depth number?
530
+ @return table
531
+
532
+ Returns a new table where all sub-arrays have been
533
+ bubbled up to the top. The depth at which the scan
534
+ is performed is dictated by the `depth` parameter,
535
+ which is set to `1` by default.
536
+
537
+ ```lua
538
+ local t = {{10, 20}, {90, 100}, {30, 15}}
539
+ local flat = TableUtil.Flat(t)
540
+ print(flat) --> {10, 20, 90, 100, 30, 15}
541
+ ```
542
+
543
+ :::note Arrays only
544
+ This function works on arrays, but not dictionaries.
545
+ :::
546
+ ]=]
547
+ local function Flat<T>(tbl: { T }, depth: number?): { T }
548
+ local maxDepth: number = if type(depth) == "number" then depth else 1
549
+ local flatTbl = table.create(#tbl)
550
+ local function Scan(t: { any }, d: number)
551
+ for _, v in t do
552
+ if type(v) == "table" and d < maxDepth then
553
+ Scan(v, d + 1)
554
+ else
555
+ table.insert(flatTbl, v)
556
+ end
557
+ end
558
+ end
559
+ Scan(tbl, 0)
560
+ return flatTbl
561
+ end
562
+
563
+ --[=[
564
+ @within TableUtil
565
+ @function FlatMap
566
+ @param tbl table
567
+ @param predicate (key: any, value: any, tbl: table) -> newValue: any
568
+ @return table
569
+
570
+ Calls `TableUtil.Map` on the given table and predicate, and then
571
+ calls `TableUtil.Flat` on the result from the map operation.
572
+
573
+ ```lua
574
+ local t = {10, 20, 30}
575
+ local result = TableUtil.FlatMap(t, function(value)
576
+ return {value, value * 2}
577
+ end)
578
+ print(result) --> {10, 20, 20, 40, 30, 60}
579
+ ```
580
+
581
+ :::note Arrays only
582
+ This function works on arrays, but not dictionaries.
583
+ :::
584
+ ]=]
585
+ local function FlatMap<T, M>(tbl: { T }, callback: (T, number, { T }) -> M): { M }
586
+ return Flat(Map(tbl, callback))
587
+ end
588
+
589
+ --[=[
590
+ @within TableUtil
591
+ @function Keys
592
+ @param tbl table
593
+ @return table
594
+
595
+ Returns an array with all the keys in the table.
596
+
597
+ ```lua
598
+ local t = {A = 10, B = 20, C = 30}
599
+ local keys = TableUtil.Keys(t)
600
+ print(keys) --> {"A", "B", "C"}
601
+ ```
602
+
603
+ :::caution Ordering
604
+ The ordering of the keys is never guaranteed. If order is imperative, call
605
+ `table.sort` on the resulting `keys` array.
606
+ ```lua
607
+ local keys = TableUtil.Keys(t)
608
+ table.sort(keys)
609
+ ```
610
+ :::
611
+ ]=]
612
+ local function Keys<K, V>(tbl: { [K]: V }): { K }
613
+ local keys = table.create(#tbl)
614
+ for k in tbl do
615
+ table.insert(keys, k)
616
+ end
617
+ return keys
618
+ end
619
+
620
+ --[=[
621
+ @within TableUtil
622
+ @function Values
623
+ @param tbl table
624
+ @return table
625
+
626
+ Returns an array with all the values in the table.
627
+
628
+ ```lua
629
+ local t = {A = 10, B = 20, C = 30}
630
+ local values = TableUtil.Values(t)
631
+ print(values) --> {10, 20, 30}
632
+ ```
633
+
634
+ :::caution Ordering
635
+ The ordering of the values is never guaranteed. If order is imperative, call
636
+ `table.sort` on the resulting `values` array.
637
+ ```lua
638
+ local values = TableUtil.Values(t)
639
+ table.sort(values)
640
+ ```
641
+ :::
642
+ ]=]
643
+ local function Values<K, V>(tbl: { [K]: V }): { V }
644
+ local values = table.create(#tbl)
645
+ for _, v in tbl do
646
+ table.insert(values, v)
647
+ end
648
+ return values
649
+ end
650
+
651
+ --[=[
652
+ @within TableUtil
653
+ @function Find
654
+ @param tbl table
655
+ @param callback (value: any, index: any, tbl: table) -> boolean
656
+ @return (value: any?, key: any?)
657
+
658
+ Performs a linear scan across the table and calls `callback` on
659
+ each item in the array. Returns the value and key of the first
660
+ pair in which the callback returns `true`.
661
+
662
+ ```lua
663
+ local t = {
664
+ {Name = "Bob", Age = 20};
665
+ {Name = "Jill", Age = 30};
666
+ {Name = "Ann", Age = 25};
667
+ }
668
+
669
+ -- Find first person who has a name starting with J:
670
+ local firstPersonWithJ = TableUtil.Find(t, function(person)
671
+ return person.Name:sub(1, 1):lower() == "j"
672
+ end)
673
+
674
+ print(firstPersonWithJ) --> {Name = "Jill", Age = 30}
675
+ ```
676
+
677
+ :::caution Dictionary Ordering
678
+ While `Find` can also be used with dictionaries, dictionary ordering is never
679
+ guaranteed, and thus the result could be different if there are more
680
+ than one possible matches given the data and callback function.
681
+ :::
682
+ ]=]
683
+ local function Find<K, V>(tbl: { [K]: V }, callback: (V, K, { [K]: V }) -> boolean): (V?, K?)
684
+ for k, v in tbl do
685
+ if callback(v, k, tbl) then
686
+ return v, k
687
+ end
688
+ end
689
+ return nil, nil
690
+ end
691
+
692
+ --[=[
693
+ @within TableUtil
694
+ @function Every
695
+ @param tbl table
696
+ @param callback (value: any, index: any, tbl: table) -> boolean
697
+ @return boolean
698
+
699
+ Returns `true` if the `callback` also returns `true` for _every_
700
+ item in the table.
701
+
702
+ ```lua
703
+ local t = {10, 20, 40, 50, 60}
704
+
705
+ local allAboveZero = TableUtil.Every(t, function(value)
706
+ return value > 0
707
+ end)
708
+
709
+ print("All above zero:", allAboveZero) --> All above zero: true
710
+ ```
711
+ ]=]
712
+ local function Every<K, V>(tbl: { [K]: V }, callback: (V, K, { [K]: V }) -> boolean): boolean
713
+ for k, v in tbl do
714
+ if not callback(v, k, tbl) then
715
+ return false
716
+ end
717
+ end
718
+ return true
719
+ end
720
+
721
+ --[=[
722
+ @within TableUtil
723
+ @function Some
724
+ @param tbl table
725
+ @param callback (value: any, index: any, tbl: table) -> boolean
726
+ @return boolean
727
+
728
+ Returns `true` if the `callback` also returns `true` for _at least
729
+ one_ of the items in the table.
730
+
731
+ ```lua
732
+ local t = {10, 20, 40, 50, 60}
733
+
734
+ local someBelowTwenty = TableUtil.Some(t, function(value)
735
+ return value < 20
736
+ end)
737
+
738
+ print("Some below twenty:", someBelowTwenty) --> Some below twenty: true
739
+ ```
740
+ ]=]
741
+ local function Some<K, V>(tbl: { [K]: V }, callback: (V, K, { [K]: V }) -> boolean): boolean
742
+ for k, v in tbl do
743
+ if callback(v, k, tbl) then
744
+ return true
745
+ end
746
+ end
747
+ return false
748
+ end
749
+
750
+ --[=[
751
+ @within TableUtil
752
+ @function Truncate
753
+ @param tbl table
754
+ @param length number
755
+ @return table
756
+
757
+ Returns a new table truncated to the length of `length`. Any length
758
+ equal or greater than the current length will simply return a
759
+ shallow copy of the table.
760
+
761
+ ```lua
762
+ local t = {10, 20, 30, 40, 50, 60, 70, 80}
763
+ local tTruncated = TableUtil.Truncate(t, 3)
764
+ print(tTruncated) --> {10, 20, 30}
765
+ ```
766
+ ]=]
767
+ local function Truncate<T>(tbl: { T }, len: number): { T }
768
+ local n = #tbl
769
+ len = math.clamp(len, 1, n)
770
+ return if len == n then table.clone(tbl) else table.move(tbl, 1, len, 1, table.create(len))
771
+ end
772
+
773
+ --[=[
774
+ @within TableUtil
775
+ @function Zip
776
+ @param ... table
777
+ @return (iter: (t: table, k: any) -> (key: any?, values: table?), tbl: table, startIndex: any?)
778
+
779
+ Returns an iterator that can scan through multiple tables at the same time side-by-side, matching
780
+ against shared keys/indices.
781
+
782
+ ```lua
783
+ local t1 = {10, 20, 30, 40, 50}
784
+ local t2 = {60, 70, 80, 90, 100}
785
+
786
+ for key,values in TableUtil.Zip(t1, t2) do
787
+ print(key, values)
788
+ end
789
+
790
+ --[[
791
+ Outputs:
792
+ 1 {10, 60}
793
+ 2 {20, 70}
794
+ 3 {30, 80}
795
+ 4 {40, 90}
796
+ 5 {50, 100}
797
+ --]]
798
+ ```
799
+ ]=]
800
+ local function Zip(...: { [any]: any }): ((t: { any }, k: any) -> (any, any), { any }, any)
801
+ assert(select("#", ...) > 0, "Must supply at least 1 table")
802
+ local function ZipIteratorArray(all: { any }, k: number): (number?, { any }?)
803
+ k += 1
804
+ local values = {}
805
+ for i, t in all do
806
+ local v = t[k]
807
+ if v ~= nil then
808
+ values[i] = v
809
+ else
810
+ return nil, nil
811
+ end
812
+ end
813
+ return k, values
814
+ end
815
+ local function ZipIteratorMap(all: { [any]: any }, k: any): (number?, { any }?)
816
+ local values = {}
817
+ for i, t in all do
818
+ local v = next(t, k)
819
+ if v ~= nil then
820
+ values[i] = v
821
+ else
822
+ return nil, nil
823
+ end
824
+ end
825
+ return k, values
826
+ end
827
+ local all = { ... }
828
+ if #all[1] > 0 then
829
+ return ZipIteratorArray, all, 0
830
+ else
831
+ return ZipIteratorMap, all, nil
832
+ end
833
+ end
834
+
835
+ --[=[
836
+ @within TableUtil
837
+ @function Lock
838
+ @param tbl table
839
+ @return table
840
+
841
+ Locks the table using `table.freeze`, as well as any
842
+ nested tables within the given table. This will lock
843
+ the whole deep structure of the table, disallowing any
844
+ further modifications.
845
+
846
+ ```lua
847
+ local tbl = {xyz = {abc = 32}}
848
+ tbl.xyz.abc = 28 -- Works fine
849
+ TableUtil.Lock(tbl)
850
+ tbl.xyz.abc = 64 -- Will throw an error (cannot modify readonly table)
851
+ ```
852
+ ]=]
853
+ local function Lock<T>(tbl: T): T
854
+ local function Freeze(t: { [any]: any })
855
+ for k, v in pairs(t) do
856
+ if type(v) == "table" then
857
+ t[k] = Freeze(v)
858
+ end
859
+ end
860
+ return table.freeze(t)
861
+ end
862
+ return Freeze(tbl :: any)
863
+ end
864
+
865
+ --[=[
866
+ @within TableUtil
867
+ @function IsEmpty
868
+ @param tbl table
869
+ @return boolean
870
+
871
+ Returns `true` if the given table is empty. This is
872
+ simply performed by checking if `next(tbl)` is `nil`
873
+ and works for both arrays and dictionaries. This is
874
+ useful when needing to check if a table is empty but
875
+ not knowing if it is an array or dictionary.
876
+
877
+ ```lua
878
+ TableUtil.IsEmpty({}) -- true
879
+ TableUtil.IsEmpty({"abc"}) -- false
880
+ TableUtil.IsEmpty({abc = 32}) -- false
881
+ ```
882
+ ]=]
883
+ local function IsEmpty(tbl: { any }): boolean
884
+ return next(tbl) == nil
885
+ end
886
+
887
+ --[=[
888
+ @within TableUtil
889
+ @function EncodeJSON
890
+ @param value any
891
+ @return string
892
+
893
+ Proxy for [`HttpService:JSONEncode`](https://developer.roblox.com/en-us/api-reference/function/HttpService/JSONEncode).
894
+ ]=]
895
+ local function EncodeJSON(value: any): string
896
+ return HttpService:JSONEncode(value)
897
+ end
898
+
899
+ --[=[
900
+ @within TableUtil
901
+ @function DecodeJSON
902
+ @param value any
903
+ @return string
904
+
905
+ Proxy for [`HttpService:JSONDecode`](https://developer.roblox.com/en-us/api-reference/function/HttpService/JSONDecode).
906
+ ]=]
907
+ local function DecodeJSON(str: string): any
908
+ return HttpService:JSONDecode(str)
909
+ end
910
+
911
+ TableUtil.Copy = Copy
912
+ TableUtil.Sync = Sync
913
+ TableUtil.Reconcile = Reconcile
914
+ TableUtil.SwapRemove = SwapRemove
915
+ TableUtil.SwapRemoveFirstValue = SwapRemoveFirstValue
916
+ TableUtil.Map = Map
917
+ TableUtil.Filter = Filter
918
+ TableUtil.Reduce = Reduce
919
+ TableUtil.Assign = Assign
920
+ TableUtil.Extend = Extend
921
+ TableUtil.Reverse = Reverse
922
+ TableUtil.Shuffle = Shuffle
923
+ TableUtil.Sample = Sample
924
+ TableUtil.Flat = Flat
925
+ TableUtil.FlatMap = FlatMap
926
+ TableUtil.Keys = Keys
927
+ TableUtil.Values = Values
928
+ TableUtil.Find = Find
929
+ TableUtil.Every = Every
930
+ TableUtil.Some = Some
931
+ TableUtil.Truncate = Truncate
932
+ TableUtil.Zip = Zip
933
+ TableUtil.Lock = Lock
934
+ TableUtil.IsEmpty = IsEmpty
935
+ TableUtil.EncodeJSON = EncodeJSON
936
+ TableUtil.DecodeJSON = DecodeJSON
937
+
938
+ return TableUtil