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,90 @@
1
+ "use strict";
2
+ /** Symbols, scopes and the per-module declaration registries shared by checker and emitter. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.Scope = void 0;
5
+ exports.emptyExports = emptyExports;
6
+ class Scope {
7
+ parent;
8
+ kind;
9
+ depth;
10
+ values = new Map();
11
+ types = new Map();
12
+ /** Narrowed types for paths (`sym#3`, `sym#3.Character`). */
13
+ narrowed = new Map();
14
+ constructor(parent, kind, depth) {
15
+ this.parent = parent;
16
+ this.kind = kind;
17
+ this.depth = depth;
18
+ }
19
+ lookup(name) {
20
+ let cur = this;
21
+ while (cur) {
22
+ const s = cur.values.get(name);
23
+ if (s) {
24
+ return s;
25
+ }
26
+ cur = cur.parent;
27
+ }
28
+ return undefined;
29
+ }
30
+ lookupType(name) {
31
+ let cur = this;
32
+ while (cur) {
33
+ const s = cur.types.get(name);
34
+ if (s) {
35
+ return s;
36
+ }
37
+ cur = cur.parent;
38
+ }
39
+ return undefined;
40
+ }
41
+ narrowedType(key) {
42
+ let cur = this;
43
+ while (cur) {
44
+ if (cur.narrowed.has(key)) {
45
+ return cur.narrowed.get(key);
46
+ }
47
+ cur = cur.parent;
48
+ }
49
+ return undefined;
50
+ }
51
+ /** Drop narrowings of a path and everything below it (after an assignment). */
52
+ invalidate(prefix) {
53
+ let cur = this;
54
+ while (cur) {
55
+ for (const key of [...cur.narrowed.keys()]) {
56
+ if (key === prefix || key.startsWith(`${prefix}.`)) {
57
+ cur.narrowed.delete(key);
58
+ }
59
+ }
60
+ cur = cur.parent;
61
+ }
62
+ // Mark as explicitly unknown at this level so outer narrowings stop applying.
63
+ }
64
+ allValueNames() {
65
+ const out = [];
66
+ let cur = this;
67
+ while (cur) {
68
+ out.push(...cur.values.keys());
69
+ cur = cur.parent;
70
+ }
71
+ return out;
72
+ }
73
+ }
74
+ exports.Scope = Scope;
75
+ function emptyExports(moduleId, file, kind, context) {
76
+ return {
77
+ moduleId,
78
+ file,
79
+ kind,
80
+ context,
81
+ funcs: new Map(),
82
+ structs: new Map(),
83
+ enums: new Map(),
84
+ variants: new Map(),
85
+ aliases: new Map(),
86
+ consts: new Map(),
87
+ namespaces: new Map(),
88
+ dmPath: null,
89
+ };
90
+ }
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+ /** Assignability, joins and member lookups that do not need checker state. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.assignable = assignable;
5
+ exports.structExtends = structExtends;
6
+ exports.join = join;
7
+ exports.substitute = substitute;
8
+ exports.bindGenerics = bindGenerics;
9
+ const types_js_1 = require("../types.js");
10
+ /**
11
+ * Can a value of type `from` be stored where `to` is expected?
12
+ * "nullable": only differs by a possible null (`Part?` into `Part`) — error in strict, warning otherwise.
13
+ * "narrowing": float into int — always an error (would lose the fraction).
14
+ */
15
+ function assignable(env, to, from) {
16
+ const a = (0, types_js_1.prune)(to);
17
+ const b = (0, types_js_1.prune)(from);
18
+ if (a === b || (0, types_js_1.isDynamic)(a) || (0, types_js_1.isDynamic)(b) || b.k === "never") {
19
+ return "ok";
20
+ }
21
+ if (a.k === "infer") {
22
+ a.resolved = b;
23
+ return "ok";
24
+ }
25
+ if (a.k === "param" || b.k === "param") {
26
+ return "ok";
27
+ }
28
+ if (b.k === "union") {
29
+ let worst = "ok";
30
+ for (const m of b.members) {
31
+ const r = assignable(env, a, m);
32
+ if (r === "no") {
33
+ return "no";
34
+ }
35
+ if (r !== "ok") {
36
+ worst = r;
37
+ }
38
+ }
39
+ return worst;
40
+ }
41
+ switch (a.k) {
42
+ case "void":
43
+ return b.k === "void" ? "ok" : "no";
44
+ case "null":
45
+ return b.k === "null" ? "ok" : "no";
46
+ case "option": {
47
+ if (b.k === "null") {
48
+ return "ok";
49
+ }
50
+ if (b.k === "option") {
51
+ return assignable(env, a.inner, b.inner) === "no" ? "no" : assignable(env, a.inner, b.inner);
52
+ }
53
+ return assignable(env, a.inner, b);
54
+ }
55
+ case "union": {
56
+ let best = "no";
57
+ for (const m of a.members) {
58
+ const r = assignable(env, m, b);
59
+ if (r === "ok") {
60
+ return "ok";
61
+ }
62
+ if (r !== "no") {
63
+ best = r;
64
+ }
65
+ }
66
+ if (b.k === "null" && a.members.some((m) => (0, types_js_1.prune)(m).k === "null")) {
67
+ return "ok";
68
+ }
69
+ return best;
70
+ }
71
+ case "float":
72
+ return b.k === "float" || b.k === "int" || (b.k === "lit" && typeof b.value === "number") ? "ok" : nullableOr(env, a, b);
73
+ case "int":
74
+ if (b.k === "int" || (b.k === "lit" && typeof b.value === "number" && Number.isInteger(b.value))) {
75
+ return "ok";
76
+ }
77
+ if (b.k === "float" || (b.k === "lit" && typeof b.value === "number")) {
78
+ return "narrowing";
79
+ }
80
+ if (b.k === "enum") {
81
+ return "ok";
82
+ }
83
+ return nullableOr(env, a, b);
84
+ case "bool":
85
+ return b.k === "bool" || (b.k === "lit" && typeof b.value === "boolean") ? "ok" : nullableOr(env, a, b);
86
+ case "string":
87
+ return b.k === "string" || (b.k === "lit" && typeof b.value === "string") ? "ok" : nullableOr(env, a, b);
88
+ case "lit":
89
+ return b.k === "lit" && b.value === a.value ? "ok" : nullableOr(env, a, b);
90
+ case "list":
91
+ if (b.k === "list") {
92
+ if (!a.typed || !b.typed) {
93
+ return "ok";
94
+ }
95
+ const r = assignable(env, a.elem, b.elem);
96
+ return r === "ok" || r === "nullable" ? r : "no";
97
+ }
98
+ if (b.k === "tuple") {
99
+ return b.elems.every((e) => assignable(env, a.elem, e) === "ok") ? "ok" : "no";
100
+ }
101
+ return nullableOr(env, a, b);
102
+ case "dict":
103
+ if (b.k === "dict") {
104
+ return assignable(env, a.key, b.key) !== "no" && assignable(env, a.value, b.value) !== "no" ? "ok" : "no";
105
+ }
106
+ if (b.k === "table") {
107
+ return Object.values(b.fields).every((f) => assignable(env, a.value, f) !== "no") ? "ok" : "no";
108
+ }
109
+ return nullableOr(env, a, b);
110
+ case "table":
111
+ if (b.k === "table") {
112
+ for (const [k, v] of Object.entries(a.fields)) {
113
+ const bf = b.fields[k];
114
+ if (!bf) {
115
+ if ((0, types_js_1.prune)(v).k !== "option") {
116
+ return "no";
117
+ }
118
+ continue;
119
+ }
120
+ if (assignable(env, v, bf) === "no") {
121
+ return "no";
122
+ }
123
+ }
124
+ return "ok";
125
+ }
126
+ if (b.k === "dict") {
127
+ return "ok";
128
+ }
129
+ return nullableOr(env, a, b);
130
+ case "struct":
131
+ if (b.k === "struct") {
132
+ if (a.id === b.id) {
133
+ return a.args.length === 0 || b.args.length === 0 || a.args.every((x, i) => (0, types_js_1.sameType)(x, b.args[i] ?? types_js_1.T.any)) ? "ok" : "no";
134
+ }
135
+ return structExtends(env, b.id, a.id) ? "ok" : "no";
136
+ }
137
+ return nullableOr(env, a, b);
138
+ case "enum":
139
+ case "variant":
140
+ if (b.k === a.k && b.id === a.id) {
141
+ return "ok";
142
+ }
143
+ if (a.k === "variant") {
144
+ return a.alternatives.some((alt) => assignable(env, alt, b) === "ok") ? "ok" : nullableOr(env, a, b);
145
+ }
146
+ return nullableOr(env, a, b);
147
+ case "result":
148
+ if (b.k === "result") {
149
+ const ok = assignable(env, a.ok, b.ok);
150
+ const err = assignable(env, a.err, b.err);
151
+ return ok !== "no" && err !== "no" ? "ok" : "no";
152
+ }
153
+ return nullableOr(env, a, b);
154
+ case "task":
155
+ return b.k === "task" ? "ok" : nullableOr(env, a, b);
156
+ case "func":
157
+ if (b.k === "func") {
158
+ return "ok";
159
+ }
160
+ return nullableOr(env, a, b);
161
+ case "instance":
162
+ if (b.k === "instance") {
163
+ return b.cls === a.cls || env.api.isA(b.cls, a.cls) ? "ok" : "no";
164
+ }
165
+ return nullableOr(env, a, b);
166
+ case "datatype":
167
+ if (b.k === "datatype") {
168
+ return b.name === a.name ? "ok" : "no";
169
+ }
170
+ return nullableOr(env, a, b);
171
+ case "rbxEnumItem":
172
+ if (b.k === "rbxEnumItem") {
173
+ return a.enumName === "*" || b.enumName === a.enumName || b.enumName === "*" ? "ok" : "no";
174
+ }
175
+ return nullableOr(env, a, b);
176
+ case "rbxEnum":
177
+ return b.k === "rbxEnum" && (a.enumName === "*" || a.enumName === b.enumName) ? "ok" : "no";
178
+ case "rbxSignal":
179
+ return b.k === "rbxSignal" ? "ok" : "no";
180
+ case "tuple":
181
+ return b.k === "tuple" && b.elems.length >= a.elems.length ? "ok" : "no";
182
+ case "thread":
183
+ case "buffer":
184
+ return b.k === a.k ? "ok" : nullableOr(env, a, b);
185
+ default:
186
+ return (0, types_js_1.sameType)(a, b) ? "ok" : "no";
187
+ }
188
+ }
189
+ function nullableOr(env, to, from) {
190
+ if (from.k === "option") {
191
+ return assignable(env, to, from.inner) === "ok" ? "nullable" : "no";
192
+ }
193
+ if (from.k === "null") {
194
+ return "nullable";
195
+ }
196
+ return "no";
197
+ }
198
+ function structExtends(env, childId, baseId) {
199
+ const seen = new Set();
200
+ const stack = [childId];
201
+ while (stack.length) {
202
+ const id = stack.pop();
203
+ if (id === baseId) {
204
+ return true;
205
+ }
206
+ if (seen.has(id)) {
207
+ continue;
208
+ }
209
+ seen.add(id);
210
+ const info = env.struct(id);
211
+ if (info) {
212
+ stack.push(...info.bases);
213
+ }
214
+ }
215
+ return false;
216
+ }
217
+ /** Least upper bound used for ternaries, list literals and inferred returns. */
218
+ function join(env, a, b) {
219
+ const x = (0, types_js_1.prune)(a);
220
+ const y = (0, types_js_1.prune)(b);
221
+ if ((0, types_js_1.isDynamic)(x)) {
222
+ return y;
223
+ }
224
+ if ((0, types_js_1.isDynamic)(y)) {
225
+ return x;
226
+ }
227
+ if (x.k === "never") {
228
+ return y;
229
+ }
230
+ if (y.k === "never") {
231
+ return x;
232
+ }
233
+ if ((0, types_js_1.sameType)(x, y)) {
234
+ return x;
235
+ }
236
+ if (x.k === "null") {
237
+ return types_js_1.T.option(y);
238
+ }
239
+ if (y.k === "null") {
240
+ return types_js_1.T.option(x);
241
+ }
242
+ if (x.k === "option" || y.k === "option") {
243
+ const inner = join(env, x.k === "option" ? x.inner : x, y.k === "option" ? y.inner : y);
244
+ return types_js_1.T.option(inner);
245
+ }
246
+ const numeric = (t) => t.k === "int" || t.k === "float" || (t.k === "lit" && typeof t.value === "number");
247
+ if (numeric(x) && numeric(y)) {
248
+ const isInt = (t) => t.k === "int" || (t.k === "lit" && Number.isInteger(t.value));
249
+ return isInt(x) && isInt(y) ? types_js_1.T.int : types_js_1.T.float;
250
+ }
251
+ if (x.k === "lit" && y.k === "lit" && typeof x.value === typeof y.value) {
252
+ return typeof x.value === "string" ? types_js_1.T.string : typeof x.value === "boolean" ? types_js_1.T.bool : types_js_1.T.float;
253
+ }
254
+ if ((x.k === "lit" && typeof x.value === "string" && y.k === "string") || (y.k === "lit" && typeof y.value === "string" && x.k === "string")) {
255
+ return types_js_1.T.string;
256
+ }
257
+ if (x.k === "instance" && y.k === "instance") {
258
+ return types_js_1.T.instance(commonClass(env, x.cls, y.cls));
259
+ }
260
+ if (x.k === "struct" && y.k === "struct") {
261
+ if (structExtends(env, x.id, y.id)) {
262
+ return y;
263
+ }
264
+ if (structExtends(env, y.id, x.id)) {
265
+ return x;
266
+ }
267
+ }
268
+ if (x.k === "list" && y.k === "list") {
269
+ return types_js_1.T.list(join(env, x.elem, y.elem), x.typed && y.typed);
270
+ }
271
+ return { k: "union", members: [x, y] };
272
+ }
273
+ function commonClass(env, a, b) {
274
+ const chain = new Set();
275
+ let cur = a;
276
+ while (cur) {
277
+ chain.add(cur);
278
+ cur = env.api.classes[cur]?.superclass ?? null;
279
+ }
280
+ cur = b;
281
+ while (cur) {
282
+ if (chain.has(cur)) {
283
+ return cur;
284
+ }
285
+ cur = env.api.classes[cur]?.superclass ?? null;
286
+ }
287
+ return "Instance";
288
+ }
289
+ /** Replace generic parameters by their bindings. */
290
+ function substitute(t, bindings) {
291
+ if (bindings.size === 0) {
292
+ return t;
293
+ }
294
+ const p = (0, types_js_1.prune)(t);
295
+ switch (p.k) {
296
+ case "param":
297
+ return bindings.get(p.name) ?? p;
298
+ case "list":
299
+ return types_js_1.T.list(substitute(p.elem, bindings), p.typed);
300
+ case "dict":
301
+ return types_js_1.T.dict(substitute(p.key, bindings), substitute(p.value, bindings));
302
+ case "option":
303
+ return types_js_1.T.option(substitute(p.inner, bindings));
304
+ case "result":
305
+ return { k: "result", ok: substitute(p.ok, bindings), err: substitute(p.err, bindings) };
306
+ case "task":
307
+ return { k: "task", result: substitute(p.result, bindings) };
308
+ case "struct":
309
+ return p.args.length ? { ...p, args: p.args.map((x) => substitute(x, bindings)) } : p;
310
+ case "func":
311
+ return {
312
+ ...p,
313
+ params: p.params.map((x) => ({ ...x, type: substitute(x.type, bindings) })),
314
+ ret: substitute(p.ret, bindings),
315
+ variadic: p.variadic ? substitute(p.variadic, bindings) : null,
316
+ };
317
+ case "union":
318
+ return { k: "union", members: p.members.map((m) => substitute(m, bindings)) };
319
+ case "tuple":
320
+ return { k: "tuple", elems: p.elems.map((m) => substitute(m, bindings)) };
321
+ default:
322
+ return p;
323
+ }
324
+ }
325
+ /** Bind generic parameters by matching a declared type against an argument type. */
326
+ function bindGenerics(declared, actual, bindings) {
327
+ const d = (0, types_js_1.prune)(declared);
328
+ const a = (0, types_js_1.prune)(actual);
329
+ if (d.k === "param") {
330
+ if (!bindings.has(d.name) && !(0, types_js_1.isDynamic)(a)) {
331
+ bindings.set(d.name, a.k === "lit" ? (typeof a.value === "string" ? types_js_1.T.string : typeof a.value === "boolean" ? types_js_1.T.bool : Number.isInteger(a.value) ? types_js_1.T.int : types_js_1.T.float) : a);
332
+ }
333
+ return;
334
+ }
335
+ if (d.k === "list" && a.k === "list") {
336
+ bindGenerics(d.elem, a.elem, bindings);
337
+ }
338
+ else if (d.k === "option") {
339
+ bindGenerics(d.inner, a.k === "option" ? a.inner : a, bindings);
340
+ }
341
+ else if (d.k === "dict" && a.k === "dict") {
342
+ bindGenerics(d.key, a.key, bindings);
343
+ bindGenerics(d.value, a.value, bindings);
344
+ }
345
+ else if (d.k === "struct" && a.k === "struct") {
346
+ d.args.forEach((x, i) => a.args[i] && bindGenerics(x, a.args[i], bindings));
347
+ }
348
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ /** Can executing these statements yield the current thread (task.wait, WaitForChild, *Async, :Wait())? */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.mayYield = mayYield;
5
+ const types_js_1 = require("../types.js");
6
+ const YIELDING_GLOBALS = new Set(["wait", "Wait"]);
7
+ const YIELDING_LIBRARY = new Set(["task.wait", "coroutine.yield"]);
8
+ function mayYield(c, body) {
9
+ let found = false;
10
+ const visitExpr = (e) => {
11
+ if (!e || found) {
12
+ return;
13
+ }
14
+ if (exprYields(c, e)) {
15
+ found = true;
16
+ return;
17
+ }
18
+ for (const [key, value] of Object.entries(e)) {
19
+ if (key === "ty" || key === "res" || key === "span" || key === "narrowedFrom") {
20
+ continue;
21
+ }
22
+ if (key === "body" && e.kind === "Function") {
23
+ continue; // a closure's body runs later
24
+ }
25
+ walk(value);
26
+ }
27
+ };
28
+ const walk = (node) => {
29
+ if (found || !node || typeof node !== "object") {
30
+ return;
31
+ }
32
+ if (Array.isArray(node)) {
33
+ for (const n of node) {
34
+ walk(n);
35
+ }
36
+ return;
37
+ }
38
+ const rec = node;
39
+ if (rec.kind && isExprKind(rec.kind)) {
40
+ visitExpr(node);
41
+ return;
42
+ }
43
+ for (const [key, value] of Object.entries(node)) {
44
+ if (key === "ty" || key === "res" || key === "span" || key === "sym") {
45
+ continue;
46
+ }
47
+ walk(value);
48
+ }
49
+ };
50
+ walk(body);
51
+ return found;
52
+ }
53
+ const EXPR_KINDS = new Set([
54
+ "Number", "String", "Template", "Bool", "Null", "Name", "SelfField", "Member", "Scope", "Index", "Call", "New", "Unary",
55
+ "Binary", "Ternary", "Function", "Spawn", "Await", "Thread", "Join", "Move", "PCall", "Parallel", "Update", "Cast", "Error",
56
+ ]);
57
+ function isExprKind(kind) {
58
+ return EXPR_KINDS.has(kind);
59
+ }
60
+ function exprYields(c, e) {
61
+ if (e.kind === "Await" || e.kind === "Join" || e.kind === "Parallel") {
62
+ return true;
63
+ }
64
+ if (e.kind !== "Call") {
65
+ return false;
66
+ }
67
+ const callee = e.callee;
68
+ const res = callee.res;
69
+ if (!res) {
70
+ return true;
71
+ }
72
+ switch (res.kind) {
73
+ case "rbxMethod": {
74
+ const name = callee.kind === "Member" || callee.kind === "Scope" ? callee.name : "";
75
+ const hit = c.api.member(res.owner, name);
76
+ return Boolean(hit?.member.yields) || name === "WaitForChild" || /Async$/.test(name);
77
+ }
78
+ case "datatypeMember":
79
+ return res.datatype === "RBXScriptSignal" && res.member === "Wait";
80
+ case "global":
81
+ return YIELDING_GLOBALS.has(res.luau);
82
+ case "library":
83
+ return YIELDING_LIBRARY.has(`${res.lib}.${res.member}`);
84
+ case "func":
85
+ case "local": {
86
+ const decl = res.sym.decl;
87
+ if (decl) {
88
+ return decl.fn?.mayYield ?? true;
89
+ }
90
+ const t = (0, types_js_1.prune)(callee.ty ?? { k: "any" });
91
+ return t.k !== "func";
92
+ }
93
+ case "method": {
94
+ const info = c.structs.get(res.struct);
95
+ const m = info?.methods.get(res.name);
96
+ return m?.decl.fn?.mayYield ?? true;
97
+ }
98
+ case "moduleMember":
99
+ return true;
100
+ case "builtin":
101
+ case "stdlib":
102
+ case "datatypeStatic":
103
+ case "rbxProperty":
104
+ case "rbxEvent":
105
+ case "enumCase":
106
+ case "struct":
107
+ case "signal":
108
+ return false;
109
+ case "dynamic":
110
+ case "luauMethod":
111
+ return true;
112
+ default:
113
+ return false;
114
+ }
115
+ }
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DiagnosticBag = void 0;
4
+ exports.hasErrors = hasErrors;
5
+ exports.sortDiagnostics = sortDiagnostics;
6
+ exports.formatDiagnostic = formatDiagnostic;
7
+ exports.editDistance = editDistance;
8
+ exports.suggest = suggest;
9
+ class DiagnosticBag {
10
+ source;
11
+ items = [];
12
+ seen = new Set();
13
+ constructor(source) {
14
+ this.source = source;
15
+ }
16
+ add(code, severity, span, message, notes, fix) {
17
+ const start = this.source.position(span.start);
18
+ const end = this.source.position(Math.max(span.start, span.end));
19
+ const diagnostic = {
20
+ code,
21
+ severity,
22
+ message,
23
+ file: this.source.path,
24
+ span,
25
+ line: start.line,
26
+ column: start.column,
27
+ endLine: end.line,
28
+ endColumn: end.column,
29
+ };
30
+ if (notes && notes.length > 0) {
31
+ diagnostic.notes = notes;
32
+ }
33
+ if (fix) {
34
+ diagnostic.fix = fix;
35
+ }
36
+ const key = `${code}:${span.start}:${span.end}:${message}`;
37
+ if (!this.seen.has(key)) {
38
+ this.seen.add(key);
39
+ this.items.push(diagnostic);
40
+ }
41
+ return diagnostic;
42
+ }
43
+ error(code, span, message, notes, fix) {
44
+ return this.add(code, "error", span, message, notes, fix);
45
+ }
46
+ warning(code, span, message, notes, fix) {
47
+ return this.add(code, "warning", span, message, notes, fix);
48
+ }
49
+ info(code, span, message, notes) {
50
+ return this.add(code, "info", span, message, notes);
51
+ }
52
+ get errorCount() {
53
+ let n = 0;
54
+ for (const d of this.items) {
55
+ if (d.severity === "error") {
56
+ n++;
57
+ }
58
+ }
59
+ return n;
60
+ }
61
+ }
62
+ exports.DiagnosticBag = DiagnosticBag;
63
+ function hasErrors(diagnostics) {
64
+ return diagnostics.some((d) => d.severity === "error");
65
+ }
66
+ function sortDiagnostics(diagnostics) {
67
+ return diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.span.start - b.span.start || a.code.localeCompare(b.code));
68
+ }
69
+ /** `file:line:col: error[CL3001]: message` plus a caret excerpt, like rustc/clang. */
70
+ function formatDiagnostic(d, source, color = false) {
71
+ const paint = (code, text) => (color ? `\x1b[${code}m${text}\x1b[0m` : text);
72
+ const label = d.severity === "error" ? paint("1;31", "error") : d.severity === "warning" ? paint("1;33", "warning") : paint("1;36", d.severity);
73
+ const lines = [`${d.file}:${d.line}:${d.column}: ${label}[${d.code}]: ${d.message}`];
74
+ if (source) {
75
+ const text = source.lineText(d.line).replace(/\t/g, " ");
76
+ const raw = source.lineText(d.line);
77
+ const prefix = raw.slice(0, d.column - 1).replace(/\t/g, " ");
78
+ const width = d.endLine === d.line ? Math.max(1, d.endColumn - d.column) : Math.max(1, raw.length - (d.column - 1));
79
+ const gutter = String(d.line).length;
80
+ lines.push(`${" ".repeat(gutter)} |`);
81
+ lines.push(`${d.line} | ${text}`);
82
+ lines.push(`${" ".repeat(gutter)} | ${" ".repeat(prefix.length)}${paint(d.severity === "error" ? "1;31" : "1;33", "^".repeat(Math.min(width, Math.max(1, text.length - prefix.length))))}`);
83
+ }
84
+ for (const note of d.notes || []) {
85
+ lines.push(` = ${note}`);
86
+ }
87
+ return lines.join("\n");
88
+ }
89
+ /** Damerau-free Levenshtein, capped; used for "did you mean" suggestions. */
90
+ function editDistance(a, b, cap = 4) {
91
+ if (Math.abs(a.length - b.length) > cap) {
92
+ return cap + 1;
93
+ }
94
+ const prev = new Array(b.length + 1);
95
+ const cur = new Array(b.length + 1);
96
+ for (let j = 0; j <= b.length; j++) {
97
+ prev[j] = j;
98
+ }
99
+ for (let i = 1; i <= a.length; i++) {
100
+ cur[0] = i;
101
+ let rowMin = cur[0];
102
+ const ca = a.charCodeAt(i - 1);
103
+ for (let j = 1; j <= b.length; j++) {
104
+ const cost = ca === b.charCodeAt(j - 1) ? 0 : 1;
105
+ cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
106
+ if (cur[j] < rowMin) {
107
+ rowMin = cur[j];
108
+ }
109
+ }
110
+ if (rowMin > cap) {
111
+ return cap + 1;
112
+ }
113
+ for (let j = 0; j <= b.length; j++) {
114
+ prev[j] = cur[j];
115
+ }
116
+ }
117
+ return prev[b.length];
118
+ }
119
+ function suggest(name, candidates, max = 2) {
120
+ let best = null;
121
+ let bestScore = Infinity;
122
+ const lower = name.toLowerCase();
123
+ for (const candidate of candidates) {
124
+ if (candidate === name) {
125
+ continue;
126
+ }
127
+ if (candidate.toLowerCase() === lower) {
128
+ return candidate;
129
+ }
130
+ const limit = Math.min(max, Math.max(1, Math.floor(name.length / 3)));
131
+ const score = editDistance(lower, candidate.toLowerCase(), limit);
132
+ if (score <= limit && score < bestScore) {
133
+ best = candidate;
134
+ bestScore = score;
135
+ }
136
+ }
137
+ return best;
138
+ }