cluaupp 1.5.0 → 1.5.1

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 (323) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +10 -5
  3. package/api/CHANGELOG.md +3 -0
  4. package/api/chat.js +74 -0
  5. package/api/fixtures/roblox/README.md +6 -0
  6. package/api/fixtures/roblox/aux/sample.d.luau +6 -0
  7. package/api/fixtures/roblox/mini/Mini-API-Dump.json +72 -0
  8. package/api/generated/bench-latest.json +39 -0
  9. package/api/generated/capability-profile.json +76 -0
  10. package/api/generated/lsp-index.json +1 -0
  11. package/api/generated/luau/classes.d.luau +11221 -0
  12. package/api/generated/luau/datatypes.d.luau +327 -0
  13. package/api/generated/luau/enums.d.luau +4918 -0
  14. package/api/generated/luau/globals.d.luau +12 -0
  15. package/api/manifests/roblox-target.manifest.json +22 -0
  16. package/api/normalized/roblox-target.profile.json +237461 -0
  17. package/api/overrides/classes.json +8 -0
  18. package/api/overrides/compatibility.json +9 -0
  19. package/api/overrides/datatypes.json +1579 -0
  20. package/api/overrides/enums.json +8 -0
  21. package/api/overrides/globals.json +8 -0
  22. package/api/overrides/type-mappings.json +9 -0
  23. package/api/roblox-api.lock.json +9 -0
  24. package/data/Mini-API-Dump.json +1 -0
  25. package/editors/vscode/README.md +12 -10
  26. package/editors/vscode/extension.js +82 -0
  27. package/editors/vscode/icons/axiom.svg +4 -0
  28. package/editors/vscode/icons/bloom.svg +5 -0
  29. package/editors/vscode/icons/helm.svg +4 -0
  30. package/editors/vscode/icons/hive.svg +5 -0
  31. package/editors/vscode/icons/mint.svg +4 -0
  32. package/editors/vscode/icons/shift.svg +6 -0
  33. package/editors/vscode/language-configuration-schema.json +24 -0
  34. package/editors/vscode/package.json +172 -12
  35. package/editors/vscode/snippets/axiom.json +12 -0
  36. package/editors/vscode/snippets/bloom.json +12 -0
  37. package/editors/vscode/snippets/helm.json +12 -0
  38. package/editors/vscode/snippets/hive.json +12 -0
  39. package/editors/vscode/snippets/mint.json +12 -0
  40. package/editors/vscode/snippets/shift.json +17 -0
  41. package/editors/vscode/syntaxes/axiom.tmLanguage.json +5 -0
  42. package/editors/vscode/syntaxes/bloom.tmLanguage.json +5 -0
  43. package/editors/vscode/syntaxes/helm.tmLanguage.json +5 -0
  44. package/editors/vscode/syntaxes/hive.tmLanguage.json +5 -0
  45. package/editors/vscode/syntaxes/mint.tmLanguage.json +5 -0
  46. package/editors/vscode/syntaxes/schema.tmLanguage.json +89 -0
  47. package/editors/vscode/syntaxes/shift.tmLanguage.json +5 -0
  48. package/examples/game/.cluaupp/compile-cache/ReplicatedStorage__Shared__Constants__Datas__TemplateData.clh.json +1 -0
  49. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Boot__DataBoot.server.clpp.json +1 -0
  50. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Configuration__ServerConfig.clp.json +1 -0
  51. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__Guard.server.clpp.json +1 -0
  52. package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__PlayerHandler.server.clpp.json +1 -0
  53. package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterCharacterScripts__Character__CharacterReady.client.clpp.json +1 -0
  54. package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterPlayerScripts__Controllers__DataController.client.clpp.json +1 -0
  55. package/examples/game/.cluaupp/compile-cache/index.json +12 -0
  56. package/examples/game/.cluaupp/datamodel-profile.json +94 -0
  57. package/examples/game/.vscode/settings.json +12 -1
  58. package/examples/game/include/clpp/datatypes.clh +337 -373
  59. package/examples/game/include/clpp/generated/datamodel.clh +25 -0
  60. package/examples/game/include/clpp/generated/enums.clh +1 -1
  61. package/examples/game/include/clpp/generated/instances.clh +41135 -41064
  62. package/examples/game/include/clpp/libs/axiom.clh +1 -1
  63. package/examples/game/include/clpp/libs/math.clh +14 -0
  64. package/examples/game/include/clpp/libs/spring.clh +17 -0
  65. package/examples/game/include/clpp/libs/ward.clh +1 -0
  66. package/examples/game/include/clpp/roblox.clh +3 -4
  67. package/examples/game/libs/ArrayIndexer/init.luau +209 -0
  68. package/examples/game/libs/Axiom/init.luau +608 -0
  69. package/examples/game/libs/Bloom/init.luau +433 -0
  70. package/examples/game/libs/Coil/init.luau +215 -0
  71. package/examples/game/libs/Crest/init.luau +426 -0
  72. package/examples/game/libs/Echo/init.luau +417 -0
  73. package/examples/game/libs/Ember/init.luau +365 -0
  74. package/examples/game/libs/Flare/init.luau +717 -0
  75. package/examples/game/libs/Gleam/init.luau +729 -0
  76. package/examples/game/libs/Guide/init.luau +215 -0
  77. package/examples/game/libs/Helm/init.luau +377 -0
  78. package/examples/game/libs/Hive/init.luau +241 -0
  79. package/examples/game/libs/Keep/Client.luau +114 -0
  80. package/examples/game/libs/Keep/Data.luau +883 -0
  81. package/examples/game/libs/Keep/Engine.luau +211 -0
  82. package/examples/game/libs/Keep/Enum.luau +6 -0
  83. package/examples/game/libs/Keep/Enums.luau +10 -0
  84. package/examples/game/libs/Keep/Path.luau +236 -0
  85. package/examples/game/libs/Keep/Replicator.luau +298 -0
  86. package/examples/game/libs/Keep/Server.luau +251 -0
  87. package/examples/game/libs/Keep/Store.luau +652 -0
  88. package/examples/game/libs/Keep/Trade.luau +455 -0
  89. package/examples/game/libs/Keep/init.luau +205 -0
  90. package/examples/game/libs/Lens/init.luau +609 -0
  91. package/examples/game/libs/Mint/init.luau +279 -0
  92. package/examples/game/libs/Net/init.luau +156 -0
  93. package/examples/game/libs/Net/src/codec.luau +224 -0
  94. package/examples/game/libs/Occlude/init.luau +117 -0
  95. package/examples/game/libs/Pin/init.luau +309 -0
  96. package/examples/game/libs/Promise/LICENSE +21 -0
  97. package/examples/game/libs/Promise/_impl/LICENSE +21 -0
  98. package/examples/game/libs/Promise/_impl/init.lua +1991 -0
  99. package/examples/game/libs/Promise/init.lua +1990 -0
  100. package/examples/game/libs/Promise/init.luau +13 -0
  101. package/examples/game/libs/Promise/types.luau +46 -0
  102. package/examples/game/libs/Roster/init.luau +686 -0
  103. package/examples/game/libs/SOURCES.md +31 -0
  104. package/examples/game/libs/Shift/init.luau +238 -0
  105. package/examples/game/libs/Spark/init.luau +487 -0
  106. package/examples/game/libs/Stage/init.luau +178 -0
  107. package/examples/game/libs/Sweep/init.luau +259 -0
  108. package/examples/game/libs/Trace/init.luau +213 -0
  109. package/examples/game/libs/Ward/init.luau +211 -0
  110. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +29 -0
  111. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +13 -0
  112. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +83 -0
  113. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +13 -0
  114. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +18 -0
  115. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +13 -0
  116. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +14 -0
  117. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +13 -0
  118. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +15 -0
  119. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +13 -0
  120. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +50 -0
  121. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +13 -0
  122. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +12 -0
  123. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +13 -0
  124. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +16 -0
  125. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +13 -0
  126. package/examples/game/src/ReplicatedStorage/Shared/Net/Net.clh +26 -0
  127. package/examples/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
  128. package/examples/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
  129. package/examples/game/stylua.toml +9 -0
  130. package/generated/api/build-profile.js +115 -0
  131. package/generated/api/cache.js +44 -0
  132. package/generated/api/coverage.js +32 -0
  133. package/generated/api/diff.js +125 -0
  134. package/generated/api/generators/clpp-headers.js +353 -0
  135. package/generated/api/generators/docs-reference.js +7 -0
  136. package/generated/api/generators/lsp-index.js +81 -0
  137. package/generated/api/generators/luau-defs.js +94 -0
  138. package/generated/api/ide.js +76 -0
  139. package/generated/api/identifier.js +47 -0
  140. package/generated/api/index.js +324 -0
  141. package/generated/api/loader.js +57 -0
  142. package/generated/api/merge.js +88 -0
  143. package/generated/api/model.js +5 -0
  144. package/generated/api/normalize.js +231 -0
  145. package/generated/api/overrides-validate.js +58 -0
  146. package/generated/api/perf.js +12 -0
  147. package/generated/api/registry.js +136 -0
  148. package/generated/api/release.js +44 -0
  149. package/generated/api/resolver.js +250 -0
  150. package/generated/api/sources/aux-types-diff.js +75 -0
  151. package/generated/api/sources/client-tracker.js +11 -0
  152. package/generated/api/sources/creator-docs.js +42 -0
  153. package/generated/api/sources/luau-types.js +34 -0
  154. package/generated/api/sources/mini-dump.js +17 -0
  155. package/generated/api/sources/studio-api.js +8 -0
  156. package/generated/api/sources/studio-apiv2.js +11 -0
  157. package/generated/api/sources/studio-full-api.js +8 -0
  158. package/generated/api/studio-smoke.js +80 -0
  159. package/generated/api/type-parse.js +49 -0
  160. package/generated/api/understander.js +51 -0
  161. package/generated/api/validate.js +135 -0
  162. package/generated/api-cli.js +421 -0
  163. package/generated/cli.js +16 -5
  164. package/generated/clpp/contract.js +3 -3
  165. package/generated/clpp/format-luau.js +236 -0
  166. package/generated/clpp/index.js +13 -1
  167. package/generated/clpp/modules.js +227 -0
  168. package/generated/clpp/postprocess.js +86 -5
  169. package/generated/clpp/rewrite-janitor.js +145 -0
  170. package/generated/clpp/runner.js +14 -2
  171. package/generated/compile.js +82 -0
  172. package/generated/flare/parse.js +12 -1
  173. package/generated/intellisense.js +57 -1
  174. package/generated/native/index.js +217 -16
  175. package/generated/target/authority-check.js +136 -0
  176. package/generated/target/authority-graph.js +74 -0
  177. package/generated/target/build-cache.js +112 -0
  178. package/generated/target/capabilities.js +89 -0
  179. package/generated/target/capability-profile.js +30 -0
  180. package/generated/target/component-contracts.js +60 -0
  181. package/generated/target/context-check.js +160 -0
  182. package/generated/target/datamodel-check.js +170 -0
  183. package/generated/target/datamodel-generate.js +74 -0
  184. package/generated/target/datamodel.js +233 -0
  185. package/generated/target/diagnostics.js +63 -0
  186. package/generated/target/doctor.js +152 -0
  187. package/generated/target/flare-version.js +58 -0
  188. package/generated/target/get-service.js +69 -0
  189. package/generated/target/lifetime-check.js +47 -0
  190. package/generated/target/luau-stamp.js +39 -0
  191. package/generated/target/optimizer-advise.js +88 -0
  192. package/generated/target/optimizer-apply.js +44 -0
  193. package/generated/target/optimizer-soa.js +254 -0
  194. package/generated/target/parallel-check.js +136 -0
  195. package/generated/target/pgo.js +148 -0
  196. package/generated/target/project-docs.js +69 -0
  197. package/generated/target/project-graph.js +71 -0
  198. package/generated/target/roblox.js +63 -0
  199. package/generated/target/security-check.js +41 -0
  200. package/generated/target/source-map.js +25 -0
  201. package/generated/target/studio-bridge.js +112 -0
  202. package/generated/utils/project.js +178 -8
  203. package/generated/utils/rojo-mapper.js +11 -3
  204. package/include/clpp/datatypes.clh +337 -373
  205. package/include/clpp/generated/enums.clh +1 -1
  206. package/include/clpp/generated/instances.clh +41135 -41064
  207. package/include/clpp/libs/axiom.clh +1 -1
  208. package/include/clpp/libs/hive.clh +1 -0
  209. package/include/clpp/libs/keep.clh +2 -0
  210. package/include/clpp/libs/math.clh +14 -0
  211. package/include/clpp/libs/spring.clh +17 -0
  212. package/include/clpp/libs/ward.clh +1 -0
  213. package/include/clpp/roblox.clh +3 -4
  214. package/package.json +10 -3
  215. package/plugins/CluauppNav/Plugin.luau +207 -0
  216. package/plugins/CluauppNav/ProfileLogger.luau +27 -0
  217. package/plugins/CluauppNav/README.md +24 -0
  218. package/runtime/Axiom/init.luau +10 -7
  219. package/runtime/Coil/init.luau +8 -2
  220. package/runtime/Crest/init.luau +1 -0
  221. package/runtime/Flare/init.luau +2 -1
  222. package/runtime/Gleam/init.luau +15 -4
  223. package/runtime/Hive/init.luau +36 -14
  224. package/runtime/Pin/init.luau +5 -2
  225. package/runtime/Roster/init.luau +2 -0
  226. package/runtime/Spark/init.luau +3 -0
  227. package/runtime/Sweep/init.luau +2 -0
  228. package/runtime/Trace/init.luau +3 -0
  229. package/runtime/Ward/init.luau +38 -5
  230. package/scripts/postinstall-editor.js +17 -0
  231. package/skills/README.md +13 -0
  232. package/skills/clpp-hive-flare/SKILL.md +79 -0
  233. package/skills/clpp-language/SKILL.md +123 -0
  234. package/skills/clpp-language/compiler.md +89 -0
  235. package/skills/clpp-style/SKILL.md +95 -0
  236. package/src/api/build-profile.ts +138 -0
  237. package/src/api/cache.ts +45 -0
  238. package/src/api/coverage.ts +46 -0
  239. package/src/api/diff.ts +143 -0
  240. package/src/api/generators/clpp-headers.ts +377 -0
  241. package/src/api/generators/docs-reference.ts +11 -0
  242. package/src/api/generators/lsp-index.ts +106 -0
  243. package/src/api/generators/luau-defs.ts +98 -0
  244. package/src/api/ide.ts +87 -0
  245. package/src/api/identifier.ts +47 -0
  246. package/src/api/index.ts +269 -0
  247. package/src/api/loader.ts +60 -0
  248. package/src/api/merge.ts +126 -0
  249. package/src/api/model.ts +283 -0
  250. package/src/api/normalize.ts +257 -0
  251. package/src/api/overrides-validate.ts +58 -0
  252. package/src/api/perf.ts +15 -0
  253. package/src/api/registry.ts +162 -0
  254. package/src/api/release.ts +47 -0
  255. package/src/api/resolver.ts +255 -0
  256. package/src/api/sources/aux-types-diff.ts +81 -0
  257. package/src/api/sources/client-tracker.ts +10 -0
  258. package/src/api/sources/creator-docs.ts +37 -0
  259. package/src/api/sources/luau-types.ts +30 -0
  260. package/src/api/sources/mini-dump.ts +50 -0
  261. package/src/api/sources/studio-api.ts +7 -0
  262. package/src/api/sources/studio-apiv2.ts +10 -0
  263. package/src/api/sources/studio-full-api.ts +7 -0
  264. package/src/api/studio-smoke.ts +82 -0
  265. package/src/api/type-parse.ts +48 -0
  266. package/src/api/understander.ts +72 -0
  267. package/src/api/validate.ts +160 -0
  268. package/src/api-cli.ts +493 -0
  269. package/src/api.generated.js +37 -22
  270. package/src/cli.ts +21 -6
  271. package/src/clpp/contract.ts +34 -3
  272. package/src/clpp/format-luau.ts +262 -0
  273. package/src/clpp/index.ts +13 -2
  274. package/src/clpp/modules.ts +252 -0
  275. package/src/clpp/postprocess.ts +100 -5
  276. package/src/clpp/rewrite-janitor.ts +156 -0
  277. package/src/clpp/runner.ts +14 -2
  278. package/src/compile.ts +87 -0
  279. package/src/flare/parse.ts +14 -1
  280. package/src/flare/types.ts +2 -0
  281. package/src/intellisense.ts +58 -1
  282. package/src/native/index.ts +225 -16
  283. package/src/target/authority-check.ts +162 -0
  284. package/src/target/authority-graph.ts +80 -0
  285. package/src/target/build-cache.ts +129 -0
  286. package/src/target/capabilities.ts +115 -0
  287. package/src/target/capability-profile.ts +25 -0
  288. package/src/target/component-contracts.ts +64 -0
  289. package/src/target/context-check.ts +177 -0
  290. package/src/target/datamodel-check.ts +188 -0
  291. package/src/target/datamodel-generate.ts +78 -0
  292. package/src/target/datamodel.ts +261 -0
  293. package/src/target/diagnostics.ts +67 -0
  294. package/src/target/doctor.ts +171 -0
  295. package/src/target/flare-version.ts +61 -0
  296. package/src/target/get-service.ts +85 -0
  297. package/src/target/lifetime-check.ts +45 -0
  298. package/src/target/luau-stamp.ts +33 -0
  299. package/src/target/optimizer-advise.ts +93 -0
  300. package/src/target/optimizer-apply.ts +63 -0
  301. package/src/target/optimizer-soa.ts +270 -0
  302. package/src/target/parallel-check.ts +135 -0
  303. package/src/target/pgo.ts +157 -0
  304. package/src/target/project-docs.ts +68 -0
  305. package/src/target/project-graph.ts +75 -0
  306. package/src/target/roblox.ts +78 -0
  307. package/src/target/security-check.ts +40 -0
  308. package/src/target/source-map.ts +36 -0
  309. package/src/target/studio-bridge.ts +140 -0
  310. package/src/types.ts +14 -0
  311. package/src/utils/project.ts +183 -9
  312. package/src/utils/rojo-mapper.ts +12 -3
  313. package/stylua.toml +9 -0
  314. package/templates/game/.vscode/settings.json +7 -1
  315. package/templates/game/include/clpp/datatypes.clh +337 -373
  316. package/templates/game/include/clpp/generated/enums.clh +1 -1
  317. package/templates/game/include/clpp/generated/instances.clh +41135 -41064
  318. package/templates/game/include/clpp/libs/axiom.clh +1 -1
  319. package/templates/game/include/clpp/libs/ward.clh +1 -0
  320. package/templates/game/include/clpp/roblox.clh +3 -4
  321. package/templates/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
  322. package/templates/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
  323. package/templates/game/stylua.toml +9 -0
@@ -0,0 +1,162 @@
1
+ import type {
2
+ ClassDefinition,
3
+ EventDefinition,
4
+ MethodDefinition,
5
+ PropertyDefinition,
6
+ RobloxTargetProfile,
7
+ ServiceDefinition,
8
+ } from "./model.js";
9
+
10
+ export interface ApiRegistry {
11
+ profile: RobloxTargetProfile;
12
+ classes: Map<string, ClassDefinition>;
13
+ services: Map<string, ServiceDefinition>;
14
+ enums: Map<string, RobloxTargetProfile["enums"][string]>;
15
+ datatypes: Map<string, RobloxTargetProfile["datatypes"][string]>;
16
+ members: Map<string, { owner: string; kind: string; name: string }>;
17
+ methods: Map<string, MethodDefinition[]>;
18
+ properties: Map<string, PropertyDefinition>;
19
+ events: Map<string, EventDefinition>;
20
+ ancestors: Map<string, string[]>;
21
+ }
22
+
23
+ export function buildRegistry(profile: RobloxTargetProfile): ApiRegistry {
24
+ const classes = new Map(Object.entries(profile.classes));
25
+ const services = new Map(Object.entries(profile.services));
26
+ const enums = new Map(Object.entries(profile.enums));
27
+ const datatypes = new Map(Object.entries(profile.datatypes));
28
+ const members = new Map<string, { owner: string; kind: string; name: string }>();
29
+ const methods = new Map<string, MethodDefinition[]>();
30
+ const properties = new Map<string, PropertyDefinition>();
31
+ const events = new Map<string, EventDefinition>();
32
+ const ancestors = new Map<string, string[]>();
33
+
34
+ for (const cls of classes.values()) {
35
+ ancestors.set(cls.name, collectAncestors(cls.name, profile.classes));
36
+ for (const prop of cls.properties) {
37
+ const key = `${cls.name}.${prop.name}`;
38
+ properties.set(key, prop);
39
+ members.set(key, { owner: cls.name, kind: "property", name: prop.name });
40
+ }
41
+ for (const method of cls.methods) {
42
+ const key = `${cls.name}.${method.name}`;
43
+ const list = methods.get(key) || [];
44
+ list.push(method);
45
+ methods.set(key, list);
46
+ members.set(key, { owner: cls.name, kind: "method", name: method.name });
47
+ }
48
+ for (const event of cls.events) {
49
+ const key = `${cls.name}.${event.name}`;
50
+ events.set(key, event);
51
+ members.set(key, { owner: cls.name, kind: "event", name: event.name });
52
+ }
53
+ for (const cb of cls.callbacks) {
54
+ members.set(`${cls.name}.${cb.name}`, { owner: cls.name, kind: "callback", name: cb.name });
55
+ }
56
+ }
57
+
58
+ return {
59
+ profile,
60
+ classes,
61
+ services,
62
+ enums,
63
+ datatypes,
64
+ members,
65
+ methods,
66
+ properties,
67
+ events,
68
+ ancestors,
69
+ };
70
+ }
71
+
72
+ function collectAncestors(name: string, classes: Record<string, ClassDefinition>): string[] {
73
+ const chain: string[] = [];
74
+ let current = classes[name]?.superclass || null;
75
+ const seen = new Set<string>();
76
+ while (current && !seen.has(current)) {
77
+ seen.add(current);
78
+ chain.push(current);
79
+ current = classes[current]?.superclass || null;
80
+ }
81
+ return chain;
82
+ }
83
+
84
+ /** Flattened IntelliSense view — does not mutate ClassGraph. */
85
+ export function flattenMembers(registry: ApiRegistry, className: string): {
86
+ properties: PropertyDefinition[];
87
+ methods: MethodDefinition[];
88
+ events: EventDefinition[];
89
+ } {
90
+ const order = [className, ...(registry.ancestors.get(className) || [])];
91
+ const properties: PropertyDefinition[] = [];
92
+ const methods: MethodDefinition[] = [];
93
+ const events: EventDefinition[] = [];
94
+ const seenProp = new Set<string>();
95
+ const seenMethod = new Set<string>();
96
+ const seenEvent = new Set<string>();
97
+ for (const name of order) {
98
+ const cls = registry.classes.get(name);
99
+ if (!cls) {
100
+ continue;
101
+ }
102
+ for (const p of cls.properties) {
103
+ if (!seenProp.has(p.name)) {
104
+ seenProp.add(p.name);
105
+ properties.push(p);
106
+ }
107
+ }
108
+ for (const m of cls.methods) {
109
+ const key = `${m.name}#${m.overloadIndex}`;
110
+ if (!seenMethod.has(key)) {
111
+ seenMethod.add(key);
112
+ methods.push(m);
113
+ }
114
+ }
115
+ for (const e of cls.events) {
116
+ if (!seenEvent.has(e.name)) {
117
+ seenEvent.add(e.name);
118
+ events.push(e);
119
+ }
120
+ }
121
+ }
122
+ return { properties, methods, events };
123
+ }
124
+
125
+ export function deriveServices(classes: Record<string, ClassDefinition>): Record<string, ServiceDefinition> {
126
+ const services: Record<string, ServiceDefinition> = {};
127
+ for (const cls of Object.values(classes)) {
128
+ if (!cls.service && !cls.creation.service) {
129
+ continue;
130
+ }
131
+ services[cls.name] = {
132
+ name: cls.name,
133
+ className: cls.name,
134
+ kind: "service",
135
+ accessor: "game:GetService",
136
+ singleton: true,
137
+ type: { kind: "Class", name: cls.name },
138
+ };
139
+ }
140
+ return services;
141
+ }
142
+
143
+ export function searchRegistry(registry: ApiRegistry, query: string, limit = 50): Array<{ kind: string; symbol: string }> {
144
+ const q = query.toLowerCase();
145
+ const hits: Array<{ kind: string; symbol: string }> = [];
146
+ for (const name of registry.classes.keys()) {
147
+ if (name.toLowerCase().includes(q)) {
148
+ hits.push({ kind: "class", symbol: name });
149
+ }
150
+ }
151
+ for (const name of registry.enums.keys()) {
152
+ if (name.toLowerCase().includes(q)) {
153
+ hits.push({ kind: "enum", symbol: name });
154
+ }
155
+ }
156
+ for (const [key] of registry.members) {
157
+ if (key.toLowerCase().includes(q)) {
158
+ hits.push({ kind: "member", symbol: key });
159
+ }
160
+ }
161
+ return hits.slice(0, limit);
162
+ }
@@ -0,0 +1,47 @@
1
+ /** Release / checksum helpers for Roblox Target artifacts. */
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { projectRoot } from "../package-info.js";
5
+ import { pkg } from "../package-info.js";
6
+ import { hashBuffer } from "./resolver.js";
7
+ import { ROBLOX_TARGET_SCHEMA_VERSION } from "./model.js";
8
+
9
+ export interface ReleaseChecklist {
10
+ schemaVersion: number;
11
+ generatorVersion: string;
12
+ lockPresent: boolean;
13
+ manifestPresent: boolean;
14
+ checksums: Record<string, string>;
15
+ }
16
+
17
+ export function buildReleaseChecklist(): ReleaseChecklist {
18
+ const lockPath = path.join(projectRoot, "api", "roblox-api.lock.json");
19
+ const manifestPath = path.join(projectRoot, "api", "manifests", "roblox-target.manifest.json");
20
+ const checksums: Record<string, string> = {};
21
+ for (const rel of [
22
+ "include/clpp/generated/enums.clh",
23
+ "include/clpp/datatypes.clh",
24
+ "include/clpp/generated/instances.clh",
25
+ "api/overrides/datatypes.json",
26
+ ]) {
27
+ const full = path.join(projectRoot, rel);
28
+ if (fs.existsSync(full)) {
29
+ checksums[rel] = hashBuffer(fs.readFileSync(full));
30
+ }
31
+ }
32
+ return {
33
+ schemaVersion: ROBLOX_TARGET_SCHEMA_VERSION,
34
+ generatorVersion: pkg.version,
35
+ lockPresent: fs.existsSync(lockPath),
36
+ manifestPresent: fs.existsSync(manifestPath),
37
+ checksums,
38
+ };
39
+ }
40
+
41
+ export function writeApiChangelog(entries: string[], outPath?: string): string {
42
+ const target = outPath || path.join(projectRoot, "api", "CHANGELOG.md");
43
+ const body = [`# Roblox API changelog`, ``, ...entries.map((e) => `- ${e}`), ``].join("\n");
44
+ fs.mkdirSync(path.dirname(target), { recursive: true });
45
+ fs.writeFileSync(target, body, "utf8");
46
+ return target;
47
+ }
@@ -0,0 +1,255 @@
1
+ import { createHash } from "node:crypto";
2
+ import type { CanonicalType, DefaultKind, ParameterDefinition } from "./model.js";
3
+
4
+ export type RobloxTypeRef = {
5
+ Category?: string;
6
+ Name?: string;
7
+ Optional?: boolean;
8
+ };
9
+
10
+ const PRIMITIVE_MAP: Record<string, string> = {
11
+ bool: "boolean",
12
+ boolean: "boolean",
13
+ int: "int",
14
+ int64: "int64",
15
+ float: "float",
16
+ double: "double",
17
+ number: "double",
18
+ string: "string",
19
+ null: "void",
20
+ void: "void",
21
+ nil: "void",
22
+ };
23
+
24
+ export function hashBuffer(data: string | Buffer): string {
25
+ return createHash("sha256").update(data).digest("hex");
26
+ }
27
+
28
+ export function mapRobloxType(ref: RobloxTypeRef | string | undefined | null): CanonicalType {
29
+ if (!ref) {
30
+ return { kind: "Unknown" };
31
+ }
32
+ if (typeof ref === "string") {
33
+ return mapNamedType(ref);
34
+ }
35
+ const category = String(ref.Category || "");
36
+ const name = String(ref.Name || "");
37
+ let mapped: CanonicalType;
38
+ switch (category) {
39
+ case "Primitive":
40
+ mapped = mapNamedType(name);
41
+ break;
42
+ case "Class":
43
+ mapped = { kind: "Class", name };
44
+ break;
45
+ case "Enum":
46
+ mapped = { kind: "Enum", name };
47
+ break;
48
+ case "DataType":
49
+ if (name === "Function") {
50
+ mapped = {
51
+ kind: "Function",
52
+ parameters: [{ kind: "Any" }],
53
+ returns: [{ kind: "Any" }],
54
+ variadic: true,
55
+ };
56
+ } else if (name === "buffer" || name === "Buffer") {
57
+ mapped = { kind: "Buffer" };
58
+ } else {
59
+ mapped = { kind: "Datatype", name };
60
+ }
61
+ break;
62
+ case "Group":
63
+ if (name === "Array") {
64
+ mapped = { kind: "Array", element: { kind: "Any" } };
65
+ } else if (name === "Dictionary" || name === "Map") {
66
+ mapped = {
67
+ kind: "Dictionary",
68
+ key: { kind: "Any" },
69
+ value: { kind: "Any" },
70
+ };
71
+ } else if (name === "Tuple") {
72
+ mapped = { kind: "Tuple", elements: [{ kind: "Any" }] };
73
+ } else if (name === "Variant") {
74
+ mapped = { kind: "Any" };
75
+ } else {
76
+ mapped = {
77
+ kind: "Unsupported",
78
+ raw: `${category}:${name}`,
79
+ reason: `Group type ${name} has no direct CL++ mapping yet`,
80
+ };
81
+ }
82
+ break;
83
+ default:
84
+ if (!name) {
85
+ mapped = { kind: "Unknown" };
86
+ } else {
87
+ mapped = mapNamedType(name);
88
+ }
89
+ }
90
+ if (ref.Optional || /\?$/.test(name)) {
91
+ return { kind: "Optional", inner: stripOptionalMarker(mapped) };
92
+ }
93
+ return mapped;
94
+ }
95
+
96
+ function stripOptionalMarker(type: CanonicalType): CanonicalType {
97
+ if (type.kind === "Class" || type.kind === "Enum" || type.kind === "Datatype" || type.kind === "Primitive") {
98
+ return { ...type, name: type.name.replace(/\?$/, "") };
99
+ }
100
+ return type;
101
+ }
102
+
103
+ function mapNamedType(rawName: string): CanonicalType {
104
+ const name = rawName.replace(/\?$/, "");
105
+ if (!name) {
106
+ return { kind: "Unknown" };
107
+ }
108
+ if (name === "any") {
109
+ return { kind: "Any" };
110
+ }
111
+ if (name === "unknown") {
112
+ return { kind: "Unknown" };
113
+ }
114
+ if (name === "never") {
115
+ return { kind: "Never" };
116
+ }
117
+ if (name === "buffer" || name === "Buffer") {
118
+ return { kind: "Buffer" };
119
+ }
120
+ if (PRIMITIVE_MAP[name]) {
121
+ return { kind: "Primitive", name: PRIMITIVE_MAP[name] };
122
+ }
123
+ if (/^[A-Z]/.test(name)) {
124
+ return { kind: "Class", name };
125
+ }
126
+ return { kind: "Primitive", name };
127
+ }
128
+
129
+ export function mapParameter(
130
+ param: { Name?: string; Type?: RobloxTypeRef; Default?: string },
131
+ index: number,
132
+ ): ParameterDefinition {
133
+ const name = param.Name || `arg${index}`;
134
+ const type = mapRobloxType(param.Type);
135
+ const optional = type.kind === "Optional" || param.Default !== undefined;
136
+ const def = classifyDefault(param.Default);
137
+ return {
138
+ name,
139
+ type: optional && type.kind !== "Optional" ? { kind: "Optional", inner: type } : type,
140
+ optional,
141
+ default: param.Default,
142
+ defaultKind: def,
143
+ };
144
+ }
145
+
146
+ function classifyDefault(value: string | undefined): DefaultKind | undefined {
147
+ if (value === undefined) {
148
+ return undefined;
149
+ }
150
+ if (value === "null" || value === "nil") {
151
+ return "Null";
152
+ }
153
+ if (value === "true" || value === "false") {
154
+ return "Boolean";
155
+ }
156
+ if (/^-?\d+(\.\d+)?$/.test(value)) {
157
+ return "Number";
158
+ }
159
+ if (/^Enum\./.test(value)) {
160
+ return "EnumItem";
161
+ }
162
+ if (/^['"`]/.test(value)) {
163
+ return "String";
164
+ }
165
+ return "Unknown";
166
+ }
167
+
168
+ export function typeToClpp(type: CanonicalType): string {
169
+ switch (type.kind) {
170
+ case "Primitive":
171
+ if (type.name === "boolean") {
172
+ return "bool";
173
+ }
174
+ if (type.name === "void") {
175
+ return "void";
176
+ }
177
+ return type.name;
178
+ case "Class":
179
+ case "Datatype":
180
+ return type.name;
181
+ case "Enum":
182
+ return `Enum::${type.name}`;
183
+ case "Optional":
184
+ return `${typeToClpp(type.inner)}?`;
185
+ case "Array":
186
+ return `array<${typeToClpp(type.element)}>`;
187
+ case "Dictionary":
188
+ case "Map":
189
+ return `dictionary<${typeToClpp(type.key)}, ${typeToClpp(type.value)}>`;
190
+ case "Tuple":
191
+ return `tuple<${type.elements.map(typeToClpp).join(", ")}>`;
192
+ case "Function":
193
+ return "func";
194
+ case "Union":
195
+ return type.members.map(typeToClpp).join(" | ");
196
+ case "Buffer":
197
+ return "buffer";
198
+ case "Any":
199
+ return "auto";
200
+ case "Unknown":
201
+ return "auto";
202
+ case "Never":
203
+ return "void";
204
+ case "Unsupported":
205
+ return "auto";
206
+ default:
207
+ return "auto";
208
+ }
209
+ }
210
+
211
+ export function typeToLuau(type: CanonicalType): string {
212
+ switch (type.kind) {
213
+ case "Primitive":
214
+ if (type.name === "int" || type.name === "int64" || type.name === "float" || type.name === "double") {
215
+ return "number";
216
+ }
217
+ if (type.name === "void") {
218
+ return "()";
219
+ }
220
+ return type.name;
221
+ case "Class":
222
+ case "Datatype":
223
+ return type.name;
224
+ case "Enum":
225
+ return `Enum.${type.name}`;
226
+ case "Optional":
227
+ return `${typeToLuau(type.inner)}?`;
228
+ case "Array":
229
+ return `{ ${typeToLuau(type.element)} }`;
230
+ case "Dictionary":
231
+ case "Map":
232
+ return `{ [${typeToLuau(type.key)}]: ${typeToLuau(type.value)} }`;
233
+ case "Buffer":
234
+ return "buffer";
235
+ case "Any":
236
+ return "any";
237
+ case "Unknown":
238
+ return "unknown";
239
+ case "Function":
240
+ return "(...any) -> ...any";
241
+ case "Unsupported":
242
+ return "any";
243
+ default:
244
+ return "any";
245
+ }
246
+ }
247
+
248
+ export function eventSignalType(parameters: ParameterDefinition[]): CanonicalType {
249
+ return {
250
+ kind: "Datatype",
251
+ name: parameters.length
252
+ ? `RBXScriptSignal/*(${parameters.map((p) => typeToClpp(p.type)).join(", ")})*/`
253
+ : "RBXScriptSignal",
254
+ };
255
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Optional coverage cross-check against @rbxts/types or LuauTypes.
3
+ * Never imported by the compile hot path.
4
+ */
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+
8
+ export interface AuxTypesDiff {
9
+ source: string;
10
+ auxSymbols: number;
11
+ registrySymbols: number;
12
+ onlyInAux: string[];
13
+ onlyInRegistry: string[];
14
+ }
15
+
16
+ function collectDeclareClasses(text: string): Set<string> {
17
+ const names = new Set<string>();
18
+ const re = /\b(?:declare\s+class|export\s+type|interface|type)\s+([A-Za-z_][\w]*)/g;
19
+ let match: RegExpExecArray | null;
20
+ while ((match = re.exec(text))) {
21
+ names.add(match[1]);
22
+ }
23
+ return names;
24
+ }
25
+
26
+ /**
27
+ * Diff registry class/datatype/enum names against a local types file or directory
28
+ * (e.g. node_modules/@rbxts/types or Studio LuauTypes.d.luau).
29
+ */
30
+ export function diffAgainstAuxTypes(
31
+ registryNames: string[],
32
+ auxPath: string,
33
+ ): AuxTypesDiff {
34
+ if (!fs.existsSync(auxPath)) {
35
+ throw new Error(`Aux types path not found: ${auxPath}`);
36
+ }
37
+ const stat = fs.statSync(auxPath);
38
+ let auxSet: Set<string>;
39
+ if (stat.isDirectory()) {
40
+ auxSet = new Set<string>();
41
+ const stack = [auxPath];
42
+ while (stack.length) {
43
+ const dir = stack.pop()!;
44
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
45
+ const full = path.join(dir, entry.name);
46
+ if (entry.isDirectory()) {
47
+ stack.push(full);
48
+ } else if (/\.(luau|ts|d\.ts)$/i.test(entry.name)) {
49
+ for (const name of collectDeclareClasses(fs.readFileSync(full, "utf8"))) {
50
+ auxSet.add(name);
51
+ }
52
+ }
53
+ }
54
+ }
55
+ } else {
56
+ auxSet = collectDeclareClasses(fs.readFileSync(auxPath, "utf8"));
57
+ }
58
+
59
+ const regSet = new Set(registryNames);
60
+ const onlyInAux: string[] = [];
61
+ const onlyInRegistry: string[] = [];
62
+ for (const name of auxSet) {
63
+ if (!regSet.has(name)) {
64
+ onlyInAux.push(name);
65
+ }
66
+ }
67
+ for (const name of regSet) {
68
+ if (!auxSet.has(name)) {
69
+ onlyInRegistry.push(name);
70
+ }
71
+ }
72
+ onlyInAux.sort();
73
+ onlyInRegistry.sort();
74
+ return {
75
+ source: auxPath,
76
+ auxSymbols: auxSet.size,
77
+ registrySymbols: regSet.size,
78
+ onlyInAux,
79
+ onlyInRegistry,
80
+ };
81
+ }
@@ -0,0 +1,10 @@
1
+ import type { LoadedSource } from "../loader.js";
2
+ import { loadJsonFile } from "../loader.js";
3
+
4
+ /**
5
+ * Optional Client Tracker adapter (non-authoritative early-diff source).
6
+ * Pass a local API-Dump.json / Full-API-Dump.json checkout path.
7
+ */
8
+ export function loadClientTrackerDump(filePath: string): LoadedSource<unknown> {
9
+ return loadJsonFile("client-tracker", filePath);
10
+ }
@@ -0,0 +1,37 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { hashBuffer } from "../resolver.js";
4
+ import type { LoadedSource } from "../loader.js";
5
+
6
+ /**
7
+ * Creator Docs engine reference walker.
8
+ * Expects a local clone of Roblox/creator-docs (or a fixture subtree).
9
+ */
10
+ export function loadCreatorDocs(rootDir: string): LoadedSource<{ pages: string[] }> {
11
+ if (!fs.existsSync(rootDir)) {
12
+ throw new Error(`Creator Docs root not found: ${rootDir}`);
13
+ }
14
+ const pages: string[] = [];
15
+ const stack = [rootDir];
16
+ while (stack.length) {
17
+ const dir = stack.pop()!;
18
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
19
+ const full = path.join(dir, entry.name);
20
+ if (entry.isDirectory()) {
21
+ stack.push(full);
22
+ } else if (/\.(md|mdx|yaml|yml)$/i.test(entry.name)) {
23
+ pages.push(path.relative(rootDir, full).replace(/\\/g, "/"));
24
+ }
25
+ }
26
+ }
27
+ pages.sort();
28
+ return {
29
+ meta: {
30
+ id: "creator-docs",
31
+ path: rootDir,
32
+ hash: hashBuffer(pages.join("\n")),
33
+ loadedAt: new Date().toISOString(),
34
+ },
35
+ data: { pages },
36
+ };
37
+ }
@@ -0,0 +1,30 @@
1
+ import fs from "node:fs";
2
+ import { hashBuffer } from "../resolver.js";
3
+ import type { LoadedSource } from "../loader.js";
4
+
5
+ /**
6
+ * Parse LuauTypes.d.luau into a lightweight symbol index.
7
+ * Full type AST is deferred; we extract declare/class/type names for cross-check.
8
+ */
9
+ export function loadLuauTypes(filePath: string): LoadedSource<{ symbols: string[]; textHash: string }> {
10
+ if (!fs.existsSync(filePath)) {
11
+ throw new Error(`LuauTypes file not found: ${filePath}`);
12
+ }
13
+ const raw = fs.readFileSync(filePath);
14
+ const text = raw.toString("utf8");
15
+ const symbols = new Set<string>();
16
+ const declareRe = /\b(?:declare|type|export type|class)\s+([A-Za-z_][\w.]*)/g;
17
+ let match: RegExpExecArray | null;
18
+ while ((match = declareRe.exec(text))) {
19
+ symbols.add(match[1].split(".")[0]);
20
+ }
21
+ return {
22
+ meta: {
23
+ id: "luau-types",
24
+ path: filePath,
25
+ hash: hashBuffer(raw),
26
+ loadedAt: new Date().toISOString(),
27
+ },
28
+ data: { symbols: [...symbols].sort(), textHash: hashBuffer(raw) },
29
+ };
30
+ }
@@ -0,0 +1,50 @@
1
+ import path from "node:path";
2
+ import { projectRoot } from "../../package-info.js";
3
+ import { loadJsonFile, type LoadedSource } from "../loader.js";
4
+
5
+ export interface MiniDumpParameter {
6
+ Name?: string;
7
+ Type?: { Category?: string; Name?: string; Optional?: boolean };
8
+ Default?: string;
9
+ }
10
+
11
+ export interface MiniDumpMember {
12
+ MemberType: string;
13
+ Name: string;
14
+ ValueType?: { Category?: string; Name?: string; Optional?: boolean };
15
+ ReturnType?: { Category?: string; Name?: string; Optional?: boolean };
16
+ Parameters?: MiniDumpParameter[];
17
+ Tags?: Array<string | Record<string, unknown>>;
18
+ Security?: string | { Read?: string; Write?: string };
19
+ ThreadSafety?: string;
20
+ Default?: string;
21
+ Category?: string;
22
+ }
23
+
24
+ export interface MiniDumpClass {
25
+ Name: string;
26
+ Superclass?: string;
27
+ Tags?: Array<string | Record<string, unknown>>;
28
+ Members?: MiniDumpMember[];
29
+ MemoryCategory?: string;
30
+ }
31
+
32
+ export interface MiniDumpEnum {
33
+ Name: string;
34
+ Items?: Array<{ Name: string; Value: number }>;
35
+ }
36
+
37
+ export interface MiniApiDump {
38
+ Classes: MiniDumpClass[];
39
+ Enums: MiniDumpEnum[];
40
+ Version?: number | string;
41
+ }
42
+
43
+ export function loadMiniDump(filePath?: string): LoadedSource<MiniApiDump> {
44
+ const target = filePath || path.join(projectRoot, "data", "Mini-API-Dump.json");
45
+ const loaded = loadJsonFile<MiniApiDump>("mini-api-dump", target);
46
+ if (!Array.isArray(loaded.data.Classes) || !Array.isArray(loaded.data.Enums)) {
47
+ throw new Error("Mini-API-Dump.json missing Classes/Enums arrays");
48
+ }
49
+ return loaded;
50
+ }
@@ -0,0 +1,7 @@
1
+ import type { LoadedSource } from "../loader.js";
2
+ import { loadJsonFile } from "../loader.js";
3
+
4
+ /** Studio --api JSON (same shape family as Mini dump when exported). */
5
+ export function loadStudioApi(filePath: string): LoadedSource<unknown> {
6
+ return loadJsonFile("studio-api", filePath);
7
+ }
@@ -0,0 +1,10 @@
1
+ import type { LoadedSource } from "../loader.js";
2
+ import { loadJsonFile } from "../loader.js";
3
+
4
+ /**
5
+ * Studio --apiV2 JSON export — preferred canonical schema when available.
6
+ * Until a fixture is checked in, callers may pass a local Studio dump path.
7
+ */
8
+ export function loadStudioApiV2(filePath: string): LoadedSource<unknown> {
9
+ return loadJsonFile("studio-api-v2", filePath);
10
+ }