cluaupp 1.5.2 → 2.0.0-beta.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 (195) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +27 -40
  3. package/api/generated/bench-latest.json +43 -21
  4. package/api/generated/lsp-index.json +1 -1
  5. package/api/manifests/roblox-target.manifest.json +5 -5
  6. package/api/normalized/roblox-target.profile.json +8729 -267
  7. package/api/roblox/luau-builtins.d.luau +185 -0
  8. package/api/roblox/surface.json +1 -0
  9. package/api/roblox-api.lock.json +11 -2
  10. package/bin/cluaupp.js +38 -0
  11. package/editors/vscode/syntaxes/clpp.tmLanguage.json +211 -0
  12. package/examples/README.md +9 -9
  13. package/examples/game/cluaupp.config.json +2 -2
  14. package/examples/game/default.project.json +4 -15
  15. package/examples/game/out/ReplicatedStorage/Shared/GameInfo.luau +8 -0
  16. package/examples/game/out/ReplicatedStorage/Shared/GameInfo.luau.map.json +13 -0
  17. package/examples/game/out/ServerScriptService/Leaderstats.server.luau +26 -0
  18. package/examples/game/out/ServerScriptService/Leaderstats.server.luau.map.json +13 -0
  19. package/examples/game/out/ServerScriptService/Main.server.luau +15 -0
  20. package/examples/game/out/ServerScriptService/Main.server.luau.map.json +13 -0
  21. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Main.client.luau +10 -0
  22. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Main.client.luau.map.json +13 -0
  23. package/examples/game/src/ReplicatedStorage/Shared/GameInfo.clp +1 -0
  24. package/examples/game/src/ServerScriptService/Leaderstats.server.clp +18 -0
  25. package/examples/game/src/ServerScriptService/Main.server.clp +9 -0
  26. package/examples/game/src/StarterPlayer/StarterPlayerScripts/Main.client.clp +4 -0
  27. package/generated/api/build-profile.js +1 -1
  28. package/generated/api/loader.js +2 -2
  29. package/generated/api/surface/build.js +328 -0
  30. package/generated/api/surface/luau-defs.js +595 -0
  31. package/generated/api/surface/model.js +8 -0
  32. package/generated/clpp/contract.js +6 -3
  33. package/generated/clpp/handshake.js +36 -0
  34. package/generated/clpp/modules.js +20 -9
  35. package/generated/clpp/runner.js +62 -31
  36. package/generated/compile.js +18 -1
  37. package/generated/compiler/ast.js +3 -0
  38. package/generated/compiler/checker/calls.js +999 -0
  39. package/generated/compiler/checker/checker.js +1215 -0
  40. package/generated/compiler/checker/exprs.js +791 -0
  41. package/generated/compiler/checker/flow.js +168 -0
  42. package/generated/compiler/checker/members.js +763 -0
  43. package/generated/compiler/checker/statements.js +792 -0
  44. package/generated/compiler/checker/symbols.js +90 -0
  45. package/generated/compiler/checker/typeops.js +348 -0
  46. package/generated/compiler/checker/yields.js +115 -0
  47. package/generated/compiler/diagnostics.js +138 -0
  48. package/generated/compiler/emit/emitter.js +2356 -0
  49. package/generated/compiler/emit/luau-types.js +137 -0
  50. package/generated/compiler/emit/names.js +130 -0
  51. package/generated/compiler/emit/runtime.js +432 -0
  52. package/generated/compiler/lexer.js +403 -0
  53. package/generated/compiler/parser.js +1881 -0
  54. package/generated/compiler/project.js +332 -0
  55. package/generated/compiler/roblox/api.js +388 -0
  56. package/generated/compiler/roblox/context.js +100 -0
  57. package/generated/compiler/source.js +59 -0
  58. package/generated/compiler/stdlib.js +232 -0
  59. package/generated/compiler/types.js +250 -0
  60. package/generated/target/build-cache.js +4 -4
  61. package/generated/target/gen-rojo-tree.js +15 -0
  62. package/generated/target/source-map.js +61 -8
  63. package/generated/target/studio-bridge.js +1 -0
  64. package/generated/utils/project.js +83 -25
  65. package/native/bin/.gitkeep +1 -0
  66. package/package.json +17 -6
  67. package/plugins/CluauppNav/Plugin.luau +28 -4
  68. package/rust/cluaupp/Cargo.lock +795 -0
  69. package/rust/cluaupp/Cargo.toml +17 -0
  70. package/rust/cluaupp/src/main.rs +717 -0
  71. package/scripts/postinstall-native.js +56 -0
  72. package/skills/README.md +3 -3
  73. package/skills/clpp-hive-flare/SKILL.md +30 -26
  74. package/skills/clpp-language/SKILL.md +67 -74
  75. package/skills/clpp-language/compiler.md +24 -36
  76. package/skills/clpp-style/SKILL.md +31 -44
  77. package/src/api/build-profile.ts +1 -1
  78. package/src/api/loader.ts +2 -2
  79. package/src/api/surface/build.ts +374 -0
  80. package/src/api/surface/luau-defs.ts +635 -0
  81. package/src/api/surface/model.ts +96 -0
  82. package/src/clpp/contract.ts +20 -3
  83. package/src/clpp/handshake.ts +25 -0
  84. package/src/clpp/modules.ts +17 -10
  85. package/src/clpp/runner.ts +52 -34
  86. package/src/compile.ts +20 -2
  87. package/src/compiler/ast.ts +336 -0
  88. package/src/compiler/checker/calls.ts +1025 -0
  89. package/src/compiler/checker/checker.ts +1352 -0
  90. package/src/compiler/checker/exprs.ts +805 -0
  91. package/src/compiler/checker/flow.ts +174 -0
  92. package/src/compiler/checker/members.ts +793 -0
  93. package/src/compiler/checker/statements.ts +802 -0
  94. package/src/compiler/checker/symbols.ts +219 -0
  95. package/src/compiler/checker/typeops.ts +355 -0
  96. package/src/compiler/checker/yields.ts +120 -0
  97. package/src/compiler/diagnostics.ts +163 -0
  98. package/src/compiler/emit/emitter.ts +2486 -0
  99. package/src/compiler/emit/luau-types.ts +143 -0
  100. package/src/compiler/emit/names.ts +130 -0
  101. package/src/compiler/emit/runtime.ts +438 -0
  102. package/src/compiler/lexer.ts +444 -0
  103. package/src/compiler/parser.ts +1943 -0
  104. package/src/compiler/project.ts +354 -0
  105. package/src/compiler/roblox/api.ts +408 -0
  106. package/src/compiler/roblox/context.ts +108 -0
  107. package/src/compiler/source.ts +67 -0
  108. package/src/compiler/stdlib.ts +256 -0
  109. package/src/compiler/types.ts +313 -0
  110. package/src/target/build-cache.ts +5 -8
  111. package/src/target/gen-rojo-tree.ts +15 -0
  112. package/src/target/source-map.ts +65 -27
  113. package/src/target/studio-bridge.ts +3 -0
  114. package/src/types.ts +3 -0
  115. package/src/utils/project.ts +79 -31
  116. package/templates/README.md +7 -0
  117. package/templates/{game → game-modern}/cluaupp.config.json +2 -2
  118. package/templates/{game → game-modern}/package.json +1 -2
  119. package/templates/game-modern/rokit.toml +2 -0
  120. package/templates/game-modern/src/ReplicatedStorage/Shared/GameInfo.clp +1 -0
  121. package/templates/game-modern/src/ServerScriptService/Handlers/Guard.server.clp +4 -0
  122. package/templates/game-modern/src/ServerScriptService/Main.server.clp +8 -0
  123. package/templates/game-modern/src/StarterPlayer/StarterPlayerScripts/Main.client.clp +4 -0
  124. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +0 -29
  125. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +0 -13
  126. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +0 -83
  127. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +0 -13
  128. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +0 -18
  129. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +0 -13
  130. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +0 -14
  131. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +0 -13
  132. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +0 -15
  133. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +0 -13
  134. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +0 -50
  135. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +0 -13
  136. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +0 -12
  137. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +0 -13
  138. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +0 -16
  139. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +0 -13
  140. package/examples/game/src/Client/Controllers/DataController.client.clpp +0 -7
  141. package/examples/game/src/Client/Main.client.clpp +0 -4
  142. package/examples/game/src/Declarations/Net.flare +0 -5
  143. package/examples/game/src/Include/GameTypes.clh +0 -40
  144. package/examples/game/src/Modules/Core/Guard.server.clpp +0 -7
  145. package/examples/game/src/Modules/Core/PlayerHandler.server.clpp +0 -23
  146. package/examples/game/src/Server/Boot/DataBoot.server.clpp +0 -13
  147. package/examples/game/src/Server/Main.server.clpp +0 -4
  148. package/templates/game/.clangd +0 -25
  149. package/templates/game/.vscode/extensions.json +0 -8
  150. package/templates/game/.vscode/settings.json +0 -17
  151. package/templates/game/Packages/.gitkeep +0 -0
  152. package/templates/game/compile_flags.txt +0 -6
  153. package/templates/game/default.project.json +0 -41
  154. package/templates/game/include/clpp/datatypes.clh +0 -575
  155. package/templates/game/include/clpp/generated/enums.clh +0 -4920
  156. package/templates/game/include/clpp/generated/instances.clh +0 -87182
  157. package/templates/game/include/clpp/libs/arrayindexer.clh +0 -12
  158. package/templates/game/include/clpp/libs/axiom.clh +0 -154
  159. package/templates/game/include/clpp/libs/bloom.clh +0 -58
  160. package/templates/game/include/clpp/libs/coil.clh +0 -37
  161. package/templates/game/include/clpp/libs/crest.clh +0 -22
  162. package/templates/game/include/clpp/libs/echo.clh +0 -52
  163. package/templates/game/include/clpp/libs/ember.clh +0 -17
  164. package/templates/game/include/clpp/libs/flare.clh +0 -65
  165. package/templates/game/include/clpp/libs/gleam.clh +0 -111
  166. package/templates/game/include/clpp/libs/guide.clh +0 -42
  167. package/templates/game/include/clpp/libs/helm.clh +0 -31
  168. package/templates/game/include/clpp/libs/hive.clh +0 -20
  169. package/templates/game/include/clpp/libs/keep.clh +0 -158
  170. package/templates/game/include/clpp/libs/lens.clh +0 -24
  171. package/templates/game/include/clpp/libs/mint.clh +0 -28
  172. package/templates/game/include/clpp/libs/net.clh +0 -31
  173. package/templates/game/include/clpp/libs/occlude.clh +0 -15
  174. package/templates/game/include/clpp/libs/pin.clh +0 -28
  175. package/templates/game/include/clpp/libs/promise.clh +0 -24
  176. package/templates/game/include/clpp/libs/roster.clh +0 -123
  177. package/templates/game/include/clpp/libs/shift.clh +0 -22
  178. package/templates/game/include/clpp/libs/spark.clh +0 -28
  179. package/templates/game/include/clpp/libs/stage.clh +0 -23
  180. package/templates/game/include/clpp/libs/sweep.clh +0 -23
  181. package/templates/game/include/clpp/libs/trace.clh +0 -18
  182. package/templates/game/include/clpp/libs/ward.clh +0 -19
  183. package/templates/game/include/clpp/libs.clh +0 -31
  184. package/templates/game/include/clpp/roblox.clh +0 -41
  185. package/templates/game/rokit.toml +0 -5
  186. package/templates/game/src/Client/Controllers/DataController.client.clpp +0 -7
  187. package/templates/game/src/Client/Main.client.clpp +0 -4
  188. package/templates/game/src/Declarations/Net.flare +0 -5
  189. package/templates/game/src/Include/GameTypes.clh +0 -40
  190. package/templates/game/src/Modules/Core/Guard.server.clpp +0 -7
  191. package/templates/game/src/Modules/Core/PlayerHandler.server.clpp +0 -24
  192. package/templates/game/src/Server/Boot/DataBoot.server.clpp +0 -13
  193. package/templates/game/src/Server/Main.server.clpp +0 -4
  194. package/templates/game/stylua.toml +0 -9
  195. package/templates/game/wally.toml +0 -12
@@ -0,0 +1,595 @@
1
+ "use strict";
2
+ /**
3
+ * Parser for Luau definition files (`*.d.luau`, the luau-lsp format):
4
+ * `declare extern type X [extends Y] with … end`, `declare name: Type`, `declare function f(…): R`,
5
+ * `type Alias = Type`, `export type Alias<T> = Type`, `@deprecated` / `@[deprecated {use = "…"}]`.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.parseDefinitions = parseDefinitions;
9
+ const OPS = ["...", "->", "::", "@[", "(", ")", "{", "}", "[", "]", "<", ">", ",", ":", ";", "?", "|", "&", "=", ".", "@"];
10
+ function lex(text) {
11
+ const out = [];
12
+ let i = 0;
13
+ let line = 1;
14
+ while (i < text.length) {
15
+ const c = text[i];
16
+ if (c === "\n") {
17
+ line++;
18
+ i++;
19
+ continue;
20
+ }
21
+ if (c === " " || c === "\t" || c === "\r") {
22
+ i++;
23
+ continue;
24
+ }
25
+ if (c === "-" && text[i + 1] === "-") {
26
+ if (text.startsWith("--[[", i) || text.startsWith("--[=[", i)) {
27
+ const close = text.indexOf("]]", i);
28
+ const chunk = text.slice(i, close < 0 ? text.length : close + 2);
29
+ line += chunk.split("\n").length - 1;
30
+ i = close < 0 ? text.length : close + 2;
31
+ continue;
32
+ }
33
+ while (i < text.length && text[i] !== "\n") {
34
+ i++;
35
+ }
36
+ continue;
37
+ }
38
+ if (/[A-Za-z_]/.test(c)) {
39
+ let j = i + 1;
40
+ while (j < text.length && /[A-Za-z0-9_]/.test(text[j])) {
41
+ j++;
42
+ }
43
+ out.push({ t: "name", v: text.slice(i, j), line });
44
+ i = j;
45
+ continue;
46
+ }
47
+ if (/[0-9]/.test(c)) {
48
+ let j = i + 1;
49
+ while (j < text.length && /[0-9.]/.test(text[j])) {
50
+ j++;
51
+ }
52
+ out.push({ t: "number", v: text.slice(i, j), line });
53
+ i = j;
54
+ continue;
55
+ }
56
+ if (c === '"' || c === "'") {
57
+ let j = i + 1;
58
+ while (j < text.length && text[j] !== c) {
59
+ if (text[j] === "\\") {
60
+ j++;
61
+ }
62
+ j++;
63
+ }
64
+ out.push({ t: "string", v: text.slice(i + 1, j), line });
65
+ i = j + 1;
66
+ continue;
67
+ }
68
+ const op = OPS.find((o) => text.startsWith(o, i));
69
+ if (op) {
70
+ out.push({ t: "op", v: op, line });
71
+ i += op.length;
72
+ continue;
73
+ }
74
+ i++;
75
+ }
76
+ out.push({ t: "eof", v: "", line });
77
+ return out;
78
+ }
79
+ class DefParser {
80
+ toks;
81
+ i = 0;
82
+ /** Defaults of the generic parameters read last (`<T = BasePart>`). */
83
+ lastDefaults = {};
84
+ constructor(toks) {
85
+ this.toks = toks;
86
+ }
87
+ peek(n = 0) {
88
+ return this.toks[Math.min(this.i + n, this.toks.length - 1)];
89
+ }
90
+ next() {
91
+ return this.toks[this.i++] ?? this.toks[this.toks.length - 1];
92
+ }
93
+ is(v, n = 0) {
94
+ const t = this.peek(n);
95
+ return (t.t === "op" || t.t === "name") && t.v === v;
96
+ }
97
+ eat(v) {
98
+ if (this.is(v)) {
99
+ this.i++;
100
+ return true;
101
+ }
102
+ return false;
103
+ }
104
+ expect(v) {
105
+ if (!this.eat(v)) {
106
+ const t = this.peek();
107
+ throw new Error(`definitions: expected '${v}' at line ${t.line}, found '${t.v}'`);
108
+ }
109
+ }
110
+ name() {
111
+ const t = this.next();
112
+ if (t.t !== "name") {
113
+ throw new Error(`definitions: expected name at line ${t.line}, found '${t.v}'`);
114
+ }
115
+ return t.v;
116
+ }
117
+ file() {
118
+ const out = { metadata: {}, externs: [], declares: [], aliases: {}, aliasParams: {} };
119
+ while (this.peek().t !== "eof") {
120
+ const deprecated = this.attributes();
121
+ if (this.is("declare")) {
122
+ this.next();
123
+ if (this.is("extern")) {
124
+ this.next();
125
+ this.expect("type");
126
+ out.externs.push(this.externType());
127
+ continue;
128
+ }
129
+ if (this.is("class")) {
130
+ this.next();
131
+ out.externs.push(this.externType(true));
132
+ continue;
133
+ }
134
+ if (this.is("function")) {
135
+ this.next();
136
+ const name = this.name();
137
+ const fn = this.funcSignature(false);
138
+ out.declares.push({ name, type: fn, ...(deprecated ? { deprecated } : {}) });
139
+ continue;
140
+ }
141
+ const name = this.name();
142
+ this.expect(":");
143
+ const type = this.type();
144
+ out.declares.push({ name, type, ...(deprecated ? { deprecated } : {}) });
145
+ continue;
146
+ }
147
+ if (this.is("export")) {
148
+ this.next();
149
+ }
150
+ if (this.is("type")) {
151
+ this.next();
152
+ const name = this.name();
153
+ this.lastDefaults = {};
154
+ const params = this.genericParamNames();
155
+ const defaults = this.lastDefaults;
156
+ this.expect("=");
157
+ out.aliases[name] = substituteNames(this.type(), defaults);
158
+ if (params.length) {
159
+ out.aliasParams[name] = params;
160
+ }
161
+ continue;
162
+ }
163
+ this.next();
164
+ }
165
+ return out;
166
+ }
167
+ /** `@deprecated`, `@[deprecated {use = "X"}]`, `@checked` … — returns the deprecation, if any. */
168
+ attributes() {
169
+ let deprecated;
170
+ for (;;) {
171
+ if (this.is("@[")) {
172
+ this.next();
173
+ let depth = 1;
174
+ let sawDeprecated = false;
175
+ while (depth > 0 && this.peek().t !== "eof") {
176
+ const t = this.next();
177
+ if (t.t === "op" && (t.v === "[" || t.v === "@[")) {
178
+ depth++;
179
+ }
180
+ else if (t.t === "op" && t.v === "]") {
181
+ depth--;
182
+ }
183
+ else if (t.t === "name" && t.v === "deprecated") {
184
+ sawDeprecated = true;
185
+ deprecated = true;
186
+ }
187
+ else if (sawDeprecated && t.t === "string") {
188
+ deprecated = t.v;
189
+ }
190
+ }
191
+ continue;
192
+ }
193
+ if (this.is("@")) {
194
+ this.next();
195
+ const word = this.name();
196
+ if (word === "deprecated") {
197
+ deprecated = true;
198
+ }
199
+ continue;
200
+ }
201
+ return deprecated;
202
+ }
203
+ }
204
+ genericParamNames() {
205
+ const names = [];
206
+ if (this.eat("<")) {
207
+ while (!this.is(">") && this.peek().t !== "eof") {
208
+ const t = this.next();
209
+ if (t.t === "name") {
210
+ names.push(t.v);
211
+ }
212
+ if (this.eat("=")) {
213
+ const def = this.type();
214
+ if (t.t === "name") {
215
+ this.lastDefaults[t.v] = def;
216
+ }
217
+ }
218
+ this.eat("...");
219
+ this.eat(",");
220
+ }
221
+ this.expect(">");
222
+ }
223
+ return names;
224
+ }
225
+ externType(isClass = false) {
226
+ const line = this.peek().line;
227
+ const name = this.name();
228
+ let ext = null;
229
+ if (this.eat("extends")) {
230
+ ext = this.name();
231
+ }
232
+ if (!isClass) {
233
+ this.expect("with");
234
+ }
235
+ const members = [];
236
+ while (!this.is("end") && this.peek().t !== "eof") {
237
+ const deprecated = this.attributes();
238
+ if (this.is("function")) {
239
+ this.next();
240
+ const mname = this.name();
241
+ const fn = this.funcSignature(true);
242
+ members.push({ name: mname, fn, ...(deprecated ? { deprecated } : {}) });
243
+ continue;
244
+ }
245
+ if (this.is("[")) {
246
+ // indexer `[string]: any`
247
+ this.next();
248
+ this.type();
249
+ this.expect("]");
250
+ this.expect(":");
251
+ this.type();
252
+ continue;
253
+ }
254
+ if (this.peek().t === "name" && (this.is(":", 1))) {
255
+ const mname = this.name();
256
+ this.expect(":");
257
+ const type = this.type();
258
+ members.push({ name: mname, type, ...(deprecated ? { deprecated } : {}) });
259
+ continue;
260
+ }
261
+ if (this.is("read") || this.is("write")) {
262
+ this.next();
263
+ continue;
264
+ }
265
+ this.next();
266
+ }
267
+ this.expect("end");
268
+ return { name, extends: ext, members, line };
269
+ }
270
+ /** `(self, a: T, b: U?, ...: V): R` after the function name. */
271
+ funcSignature(method) {
272
+ const generics = this.genericParamNames();
273
+ this.expect("(");
274
+ const params = [];
275
+ let variadic;
276
+ let first = true;
277
+ while (!this.is(")") && this.peek().t !== "eof") {
278
+ if (this.eat("...")) {
279
+ variadic = this.eat(":") ? this.type() : { k: "name", name: "any" };
280
+ this.eat(",");
281
+ continue;
282
+ }
283
+ const pname = this.name();
284
+ if (first && method && pname === "self") {
285
+ if (this.eat(":")) {
286
+ this.type();
287
+ }
288
+ first = false;
289
+ this.eat(",");
290
+ continue;
291
+ }
292
+ first = false;
293
+ let t = { k: "name", name: "any" };
294
+ if (this.eat(":")) {
295
+ t = this.type();
296
+ }
297
+ params.push({ name: pname, t });
298
+ this.eat(",");
299
+ }
300
+ this.expect(")");
301
+ const fn = { k: "fn", params, returns: [] };
302
+ if (variadic) {
303
+ fn.variadic = variadic;
304
+ }
305
+ if (generics.length) {
306
+ fn.generics = generics;
307
+ }
308
+ if (this.eat(":")) {
309
+ this.returnTypes(fn);
310
+ }
311
+ return fn;
312
+ }
313
+ returnTypes(fn) {
314
+ if (this.is("(")) {
315
+ // tuple `(A, B)` or a parenthesized function type `((a) -> b)`
316
+ const mark = this.i;
317
+ this.next();
318
+ if (this.eat(")")) {
319
+ if (this.is("->")) {
320
+ this.i = mark;
321
+ fn.returns = [this.type()];
322
+ }
323
+ return;
324
+ }
325
+ const list = [];
326
+ let tail;
327
+ while (!this.is(")") && this.peek().t !== "eof") {
328
+ if (this.eat("...")) {
329
+ tail = this.type();
330
+ }
331
+ else {
332
+ list.push(this.type());
333
+ }
334
+ this.eat(",");
335
+ }
336
+ this.expect(")");
337
+ if (this.is("->") || this.is("|") || this.is("?") || this.is("&")) {
338
+ this.i = mark;
339
+ fn.returns = [this.type()];
340
+ return;
341
+ }
342
+ fn.returns = list;
343
+ if (tail) {
344
+ fn.returnsVariadic = tail;
345
+ }
346
+ return;
347
+ }
348
+ if (this.eat("...")) {
349
+ fn.returnsVariadic = this.type();
350
+ return;
351
+ }
352
+ const t = this.type();
353
+ if (t.k === "name" && (t.name === "nil" || t.name === "()")) {
354
+ return;
355
+ }
356
+ fn.returns = [t];
357
+ }
358
+ type() {
359
+ this.eat("|");
360
+ const first = this.intersection();
361
+ if (!this.is("|")) {
362
+ return first;
363
+ }
364
+ const ts = [first];
365
+ while (this.eat("|")) {
366
+ ts.push(this.intersection());
367
+ }
368
+ return { k: "union", ts };
369
+ }
370
+ intersection() {
371
+ const first = this.postfix();
372
+ if (!this.is("&")) {
373
+ return first;
374
+ }
375
+ const ts = [first];
376
+ while (this.eat("&")) {
377
+ ts.push(this.postfix());
378
+ }
379
+ return { k: "inter", ts };
380
+ }
381
+ postfix() {
382
+ let t = this.primary();
383
+ while (this.eat("?")) {
384
+ t = { k: "opt", t };
385
+ }
386
+ return t;
387
+ }
388
+ primary() {
389
+ const tok = this.peek();
390
+ if (tok.t === "string") {
391
+ this.next();
392
+ return { k: "lit", value: tok.v };
393
+ }
394
+ if (this.is("typeof")) {
395
+ this.next();
396
+ this.expect("(");
397
+ let depth = 1;
398
+ while (depth > 0 && this.peek().t !== "eof") {
399
+ const t = this.next();
400
+ if (t.v === "(") {
401
+ depth++;
402
+ }
403
+ else if (t.v === ")") {
404
+ depth--;
405
+ }
406
+ }
407
+ return { k: "name", name: "any" };
408
+ }
409
+ if (this.is("{")) {
410
+ return this.table();
411
+ }
412
+ if (this.is("<")) {
413
+ // generic function type `<T>(a: T) -> T`
414
+ const generics = this.genericParamNames();
415
+ const fn = this.parenType();
416
+ if (fn.k === "fn" && generics.length) {
417
+ fn.generics = generics;
418
+ }
419
+ return fn;
420
+ }
421
+ if (this.is("(")) {
422
+ return this.parenType();
423
+ }
424
+ if (this.is("...")) {
425
+ this.next();
426
+ const inner = this.type();
427
+ return inner.k === "name" ? { k: "pack", name: inner.name } : inner;
428
+ }
429
+ if (tok.t === "name") {
430
+ this.next();
431
+ let name = tok.v;
432
+ while (this.is(".") && this.peek(1).t === "name") {
433
+ this.next();
434
+ name += `.${this.next().v}`;
435
+ }
436
+ if (name === "true" || name === "false") {
437
+ return { k: "lit", value: name === "true" };
438
+ }
439
+ if (this.eat("...")) {
440
+ return { k: "pack", name };
441
+ }
442
+ if (this.is("<")) {
443
+ this.next();
444
+ const args = [];
445
+ while (!this.is(">") && this.peek().t !== "eof") {
446
+ if (this.is("(") && this.is(")", 1)) {
447
+ this.next();
448
+ this.next();
449
+ args.push({ k: "name", name: "()" });
450
+ }
451
+ else {
452
+ const arg = this.type();
453
+ if (arg.k === "name" && arg.name === "__pack") {
454
+ args.push(...(arg.args || []));
455
+ }
456
+ else {
457
+ args.push(arg);
458
+ }
459
+ }
460
+ this.eat(",");
461
+ }
462
+ this.expect(">");
463
+ return { k: "name", name, args };
464
+ }
465
+ return { k: "name", name };
466
+ }
467
+ throw new Error(`definitions: unexpected '${tok.v}' at line ${tok.line}`);
468
+ }
469
+ /** `( … )` — a function type when followed by `->`, else grouping. */
470
+ parenType() {
471
+ this.expect("(");
472
+ const params = [];
473
+ let variadic;
474
+ while (!this.is(")") && this.peek().t !== "eof") {
475
+ if (this.eat("...")) {
476
+ variadic = this.is(",") || this.is(")") ? { k: "name", name: "any" } : this.type();
477
+ this.eat(",");
478
+ continue;
479
+ }
480
+ let pname;
481
+ if (this.peek().t === "name" && this.is(":", 1)) {
482
+ pname = this.next().v;
483
+ this.next();
484
+ }
485
+ const t = this.type();
486
+ if (t.k === "pack") {
487
+ variadic = { k: "name", name: "any" };
488
+ this.eat(",");
489
+ continue;
490
+ }
491
+ params.push(pname ? { name: pname, t } : { t });
492
+ this.eat(",");
493
+ }
494
+ this.expect(")");
495
+ if (this.eat("->")) {
496
+ const fn = { k: "fn", params, returns: [] };
497
+ if (variadic) {
498
+ fn.variadic = variadic;
499
+ }
500
+ this.returnTypes(fn);
501
+ return fn;
502
+ }
503
+ if (params.length === 1 && !variadic) {
504
+ return params[0].t;
505
+ }
506
+ if (params.length === 0) {
507
+ return { k: "name", name: "()" };
508
+ }
509
+ // a type pack `(A, B)`, as in RBXScriptSignal<(InputObject, boolean)>
510
+ return { k: "name", name: "__pack", args: params.map((p) => p.t) };
511
+ }
512
+ table() {
513
+ this.expect("{");
514
+ if (this.eat("}")) {
515
+ return { k: "table", fields: {} };
516
+ }
517
+ // `{ T }` array
518
+ const mark = this.i;
519
+ const isField = (this.peek().t === "name" && this.is(":", 1)) || this.is("[") || ((this.is("read") || this.is("write")) && this.peek(1).t === "name");
520
+ if (!isField) {
521
+ const elem = this.type();
522
+ if (this.eat("}")) {
523
+ return { k: "array", t: elem };
524
+ }
525
+ this.i = mark;
526
+ }
527
+ const fields = {};
528
+ let indexer;
529
+ while (!this.is("}") && this.peek().t !== "eof") {
530
+ if ((this.is("read") || this.is("write")) && this.peek(1).t === "name" && this.is(":", 2)) {
531
+ this.next();
532
+ }
533
+ if (this.eat("[")) {
534
+ const key = this.type();
535
+ this.expect("]");
536
+ this.expect(":");
537
+ indexer = [key, this.type()];
538
+ }
539
+ else {
540
+ const fname = this.name();
541
+ this.expect(":");
542
+ fields[fname] = this.type();
543
+ }
544
+ if (!this.eat(",")) {
545
+ this.eat(";");
546
+ }
547
+ }
548
+ this.expect("}");
549
+ if (indexer && Object.keys(fields).length === 0) {
550
+ return { k: "map", key: indexer[0], value: indexer[1] };
551
+ }
552
+ return { k: "table", fields };
553
+ }
554
+ }
555
+ /** Replace generic parameter names by their defaults (`RaycastResult<T = BasePart>` → BasePart). */
556
+ function substituteNames(t, map) {
557
+ if (Object.keys(map).length === 0) {
558
+ return t;
559
+ }
560
+ const sub = (x) => substituteNames(x, map);
561
+ switch (t.k) {
562
+ case "name":
563
+ return map[t.name] && !t.args ? map[t.name] : t.args ? { ...t, args: t.args.map(sub) } : t;
564
+ case "opt":
565
+ return { k: "opt", t: sub(t.t) };
566
+ case "union":
567
+ case "inter":
568
+ return { k: t.k, ts: t.ts.map(sub) };
569
+ case "array":
570
+ return { k: "array", t: sub(t.t) };
571
+ case "map":
572
+ return { k: "map", key: sub(t.key), value: sub(t.value) };
573
+ case "table":
574
+ return { k: "table", fields: Object.fromEntries(Object.entries(t.fields).map(([k, v]) => [k, sub(v)])) };
575
+ case "fn":
576
+ return { ...t, params: t.params.map((p) => ({ ...p, t: sub(p.t) })), returns: t.returns.map(sub) };
577
+ default:
578
+ return t;
579
+ }
580
+ }
581
+ function parseDefinitions(text) {
582
+ let metadata = {};
583
+ const first = text.split("\n", 1)[0];
584
+ if (first.startsWith("--#METADATA#")) {
585
+ try {
586
+ metadata = JSON.parse(first.slice("--#METADATA#".length));
587
+ }
588
+ catch {
589
+ metadata = {};
590
+ }
591
+ }
592
+ const file = new DefParser(lex(text)).file();
593
+ file.metadata = metadata;
594
+ return file;
595
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /**
3
+ * Roblox surface: the typed Roblox API the CL++ checker validates against.
4
+ * Built from luau-lsp's Roblox definitions (types, nullability, overloads, operators) merged with
5
+ * the Roblox API dump profile (security, read-only, creatable, services, int vs float).
6
+ * Stored as `api/roblox/surface.json` and loaded once per process.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
- /** Stable CL++ ↔ Cluaupp contract (CL++ 0.8.x). Cluaupp invokes the `clpp` binary. */
2
+ /** Legacy adapter policy for CL++ 0.8.x. Requires an upstream compiler implementing the handshake. */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.CLPP_INSTALL_HINT = exports.MIN_CLPP_VERSION = void 0;
4
+ exports.CLPP_INSTALL_HINT = exports.CLPP_CONTRACT_VERSION = exports.CLPP_VERSION_RANGE = exports.MAX_CLPP_VERSION_EXCLUSIVE = exports.MIN_CLPP_VERSION = void 0;
5
5
  exports.MIN_CLPP_VERSION = "0.8.0";
6
- exports.CLPP_INSTALL_HINT = "Install CL++ 0.8.0+ (`clpp` from https://github.com/KartzRbx/CLPP/releases). Put it on PATH. Prefer `import { Name } from \"./x.clh\"` for language modules; angle `#include <clpp/…>` stays for host prelude. Override with CLPP or CLPP_PATH.";
6
+ exports.MAX_CLPP_VERSION_EXCLUSIVE = "0.9.0";
7
+ exports.CLPP_VERSION_RANGE = ">=0.8.0 <0.9.0";
8
+ exports.CLPP_CONTRACT_VERSION = 1;
9
+ exports.CLPP_INSTALL_HINT = "Install the legacy Luau compiler >=0.8.0 <0.9.0 with contractVersion 1 (the CL++ VM is incompatible) (`clpp` from https://github.com/KartzRbx/CLPP/releases). Put it on PATH. Prefer `import { Name } from \"./x.clh\"` for language modules; angle `#include <clpp/…>` stays for host prelude. Override with CLPP or CLPP_PATH.";
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCompilerVersion = parseCompilerVersion;
4
+ exports.acceptsCompilerVersion = acceptsCompilerVersion;
5
+ exports.validateCompilerHandshake = validateCompilerHandshake;
6
+ const contract_js_1 = require("./contract.js");
7
+ function parseCompilerVersion(text) {
8
+ const m = /^(?:clpp\s+|CL\+\+\s+)?(\d+)\.(\d+)\.(\d+)(?:-[\w.-]+)?(?:\+[\w.-]+)?$/i.exec(text.trim());
9
+ return m ? m.slice(1, 4).map(Number) : null;
10
+ }
11
+ function compare(a, b) {
12
+ return a[0] - b[0] || a[1] - b[1] || a[2] - b[2];
13
+ }
14
+ function acceptsCompilerVersion(text) {
15
+ const v = parseCompilerVersion(text);
16
+ return !!v && compare(v, parseCompilerVersion(contract_js_1.MIN_CLPP_VERSION)) >= 0 && compare(v, parseCompilerVersion(contract_js_1.MAX_CLPP_VERSION_EXCLUSIVE)) < 0;
17
+ }
18
+ function validateCompilerHandshake(version, value) {
19
+ const fail = (reason) => { throw new Error(`cluaupp: incompatible clpp (${version || "unknown"}): ${reason}. Require Luau compiler ${contract_js_1.CLPP_VERSION_RANGE}, contractVersion ${contract_js_1.CLPP_CONTRACT_VERSION}. The clpp game VM cannot emit Roblox Luau. Set CLPP or CLPP_PATH to the Luau compiler.`); };
20
+ if (!acceptsCompilerVersion(version))
21
+ fail("unsupported version");
22
+ if (!value || typeof value !== "object")
23
+ fail("missing api manifest");
24
+ const m = value;
25
+ if (m.id !== "clpp" || m.name !== "CL++")
26
+ fail("wrong compiler identity");
27
+ if (m.contractVersion !== contract_js_1.CLPP_CONTRACT_VERSION)
28
+ fail("missing or unsupported contractVersion");
29
+ if (!acceptsCompilerVersion(m.version) || compare(parseCompilerVersion(version), parseCompilerVersion(m.version)) !== 0)
30
+ fail("binary and manifest versions disagree");
31
+ if (!Array.isArray(m.extensions) || ![".clpp", ".clp", ".clh"].every(x => m.extensions.includes(x)))
32
+ fail("missing source extensions");
33
+ if (!Array.isArray(m.tags) || ![["*.server.clpp", "server", "Script"], ["*.client.clpp", "client", "LocalScript"], ["*.clh", "header", "ModuleScript"]].every(([pattern, kind, cls]) => m.tags.some(t => t.pattern === pattern && t.scriptKind === kind && t.rojoClass === cls)))
34
+ fail("missing Roblox file tags");
35
+ return m;
36
+ }
@@ -135,19 +135,30 @@ function resolveLanguageDeps(source, fromFile, srcDir) {
135
135
  return out;
136
136
  }
137
137
  /**
138
- * Fingerprint source + one-hop language deps so import/include edits invalidate incremental cache.
138
+ * Fingerprint source + transitive language deps so import/include edits invalidate incremental cache.
139
139
  */
140
140
  function fingerprintSourceWithDeps(source, fromFile, configKey, srcDir, hashText) {
141
141
  const parts = [configKey, source];
142
- for (const dep of resolveLanguageDeps(source, fromFile, srcDir)) {
143
- try {
144
- parts.push(`\n//dep:${dep.replace(/\\/g, "/")}\n`);
145
- parts.push(node_fs_1.default.readFileSync(dep, "utf8"));
146
- }
147
- catch {
148
- parts.push(`\n//dep-missing:${dep.replace(/\\/g, "/")}\n`);
142
+ const seen = new Set([node_path_1.default.resolve(fromFile)]);
143
+ const visit = (text, file) => {
144
+ for (const ref of collectModuleRefs(text)) {
145
+ if (ref.angled)
146
+ continue;
147
+ const dep = resolveModuleFile(ref.modulePath, file, srcDir);
148
+ if (!dep) {
149
+ parts.push("\n//missing:" + file + ":" + ref.modulePath);
150
+ continue;
151
+ }
152
+ const key = node_path_1.default.resolve(dep);
153
+ if (seen.has(key))
154
+ continue;
155
+ seen.add(key);
156
+ const contents = node_fs_1.default.readFileSync(key, "utf8");
157
+ parts.push("\n//dep:" + key.replace(/\\/g, "/") + "\n", contents);
158
+ visit(contents, key);
149
159
  }
150
- }
160
+ };
161
+ visit(source, fromFile);
151
162
  return hashText(parts.join(""));
152
163
  }
153
164
  /** Rewrite CL++ `script.Parent…Service…` walks to game-rooted requires. */