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,332 @@
1
+ "use strict";
2
+ /**
3
+ * Project compilation: maps `Src/` onto the Roblox DataModel, builds the typed `@game` tree,
4
+ * resolves `link`s into a module graph (each module checked once, cycles reported) and emits Luau.
5
+ *
6
+ * Layout — folders named like a service map onto that service:
7
+ * Src/ServerScriptService/… → game.ServerScriptService
8
+ * Src/ReplicatedStorage/Shared/… → game.ReplicatedStorage.Shared
9
+ * Src/StarterPlayer/StarterPlayerScripts → game.StarterPlayer.StarterPlayerScripts
10
+ * Legacy domain folders still work: Server → ServerScriptService, Client → StarterPlayerScripts,
11
+ * anything else → ReplicatedStorage/<folder>.
12
+ */
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.isIdentifier = exports.ProjectCompiler = exports.LIBS_FOLDER = exports.SOURCE_EXT = void 0;
18
+ exports.scriptStem = scriptStem;
19
+ exports.outputName = outputName;
20
+ exports.dataModelPath = dataModelPath;
21
+ exports.classForFile = classForFile;
22
+ exports.collectClp = collectClp;
23
+ exports.buildDataModel = buildDataModel;
24
+ exports.instancePath = instancePath;
25
+ exports.compileSource = compileSource;
26
+ const node_fs_1 = __importDefault(require("node:fs"));
27
+ const node_path_1 = __importDefault(require("node:path"));
28
+ const checker_js_1 = require("./checker/checker.js");
29
+ const diagnostics_js_1 = require("./diagnostics.js");
30
+ const emitter_js_1 = require("./emit/emitter.js");
31
+ const names_js_1 = require("./emit/names.js");
32
+ Object.defineProperty(exports, "isIdentifier", { enumerable: true, get: function () { return names_js_1.isIdentifier; } });
33
+ const parser_js_1 = require("./parser.js");
34
+ const api_js_1 = require("./roblox/api.js");
35
+ const context_js_1 = require("./roblox/context.js");
36
+ const source_js_1 = require("./source.js");
37
+ const stdlib_js_1 = require("./stdlib.js");
38
+ exports.SOURCE_EXT = ".clp";
39
+ exports.LIBS_FOLDER = ["ReplicatedStorage", "CluauppLibs"];
40
+ const LEGACY_FOLDERS = {
41
+ Server: ["ServerScriptService"],
42
+ Client: ["StarterPlayer", "StarterPlayerScripts"],
43
+ Character: ["StarterPlayer", "StarterCharacterScripts"],
44
+ Gui: ["StarterGui"],
45
+ };
46
+ const NESTED_SERVICES = {
47
+ StarterPlayerScripts: ["StarterPlayer", "StarterPlayerScripts"],
48
+ StarterCharacterScripts: ["StarterPlayer", "StarterCharacterScripts"],
49
+ };
50
+ function scriptStem(fileName) {
51
+ return node_path_1.default.basename(fileName).replace(/\.(server|client|plugin)?\.?clp$/i, "").replace(/\.clp$/i, "");
52
+ }
53
+ function outputName(rel) {
54
+ return rel.replace(/\.clp$/i, ".luau");
55
+ }
56
+ /** DataModel path of a source file, e.g. `ReplicatedStorage/Shared/Combat.clp` → ["ReplicatedStorage", "Shared", "Combat"]. */
57
+ function dataModelPath(api, rel) {
58
+ const parts = rel.replace(/\\/g, "/").split("/");
59
+ const file = parts.pop();
60
+ const stem = scriptStem(file);
61
+ const first = parts[0];
62
+ let base;
63
+ let rest;
64
+ if (!first) {
65
+ base = ["ReplicatedStorage"];
66
+ rest = [];
67
+ }
68
+ else if (NESTED_SERVICES[first]) {
69
+ base = NESTED_SERVICES[first];
70
+ rest = parts.slice(1);
71
+ }
72
+ else if (first === "StarterPlayer" && NESTED_SERVICES[parts[1]]) {
73
+ base = NESTED_SERVICES[parts[1]];
74
+ rest = parts.slice(2);
75
+ }
76
+ else if (api.isService(first)) {
77
+ base = [first];
78
+ rest = parts.slice(1);
79
+ }
80
+ else if (LEGACY_FOLDERS[first]) {
81
+ base = LEGACY_FOLDERS[first];
82
+ rest = parts.slice(1);
83
+ }
84
+ else {
85
+ base = ["ReplicatedStorage"];
86
+ rest = parts;
87
+ }
88
+ return [...base, ...rest, stem];
89
+ }
90
+ function classForFile(fileName) {
91
+ const ctx = (0, context_js_1.runContextOf)(fileName);
92
+ return ctx === "server" ? "Script" : ctx === "client" ? "LocalScript" : ctx === "plugin" ? "Script" : "ModuleScript";
93
+ }
94
+ function collectClp(dir, out = []) {
95
+ if (!node_fs_1.default.existsSync(dir)) {
96
+ return out;
97
+ }
98
+ for (const entry of node_fs_1.default.readdirSync(dir, { withFileTypes: true })) {
99
+ const full = node_path_1.default.join(dir, entry.name);
100
+ if (entry.isDirectory()) {
101
+ collectClp(full, out);
102
+ }
103
+ else if (entry.name.toLowerCase().endsWith(exports.SOURCE_EXT)) {
104
+ out.push(full);
105
+ }
106
+ }
107
+ return out;
108
+ }
109
+ /** Typed `game` tree: services → folders → scripts compiled from Src, plus CluauppLibs. */
110
+ function buildDataModel(api, srcDir, files, libs = []) {
111
+ const root = { name: "game", className: "DataModel", path: [], children: new Map() };
112
+ const ensure = (segments, leafClass, sourceFile) => {
113
+ let node = root;
114
+ segments.forEach((seg, i) => {
115
+ let child = node.children.get(seg);
116
+ const isLeaf = i === segments.length - 1;
117
+ if (!child) {
118
+ const cls = i === 0 && api.isService(seg) ? seg : isLeaf ? leafClass : i === 1 && segments[0] === "StarterPlayer" ? seg : "Folder";
119
+ child = { name: seg, className: cls, path: segments.slice(0, i + 1), children: new Map() };
120
+ node.children.set(seg, child);
121
+ }
122
+ if (isLeaf && sourceFile) {
123
+ child.className = leafClass;
124
+ child.sourceFile = sourceFile;
125
+ }
126
+ node = child;
127
+ });
128
+ };
129
+ for (const svc of ["Workspace", "Players", "ReplicatedStorage", "ReplicatedFirst", "ServerScriptService", "ServerStorage", "StarterGui", "StarterPack", "StarterPlayer", "Lighting", "SoundService", "Teams"]) {
130
+ ensure([svc], svc);
131
+ }
132
+ ensure(["StarterPlayer", "StarterPlayerScripts"], "StarterPlayerScripts");
133
+ ensure(["StarterPlayer", "StarterCharacterScripts"], "StarterCharacterScripts");
134
+ for (const file of files) {
135
+ const rel = node_path_1.default.relative(srcDir, file).replace(/\\/g, "/");
136
+ ensure(dataModelPath(api, rel), classForFile(file), node_path_1.default.resolve(file));
137
+ }
138
+ if (libs.length) {
139
+ ensure(exports.LIBS_FOLDER, "Folder");
140
+ for (const lib of libs) {
141
+ ensure([...exports.LIBS_FOLDER, lib], "ModuleScript");
142
+ }
143
+ }
144
+ return root;
145
+ }
146
+ /** Luau expression that reaches an Instance by its DataModel path, robust to replication order. */
147
+ function instancePath(dm, service, fromDm) {
148
+ if (fromDm && fromDm.length > 1 && dm.length > 1) {
149
+ const fromParent = fromDm.slice(0, -1);
150
+ const targetParent = dm.slice(0, -1);
151
+ if (fromParent.join("/") === targetParent.join("/")) {
152
+ return `script.Parent${childAccess(dm[dm.length - 1])}`;
153
+ }
154
+ }
155
+ const [first, ...rest] = dm;
156
+ let expr = first === "Workspace" ? "workspace" : service(first);
157
+ for (const seg of rest) {
158
+ expr += childAccess(seg);
159
+ }
160
+ return expr;
161
+ }
162
+ function childAccess(name) {
163
+ return `:WaitForChild(${(0, names_js_1.luauString)(name)})`;
164
+ }
165
+ class ProjectCompiler {
166
+ options;
167
+ api;
168
+ files;
169
+ dataModel;
170
+ results = new Map();
171
+ inProgress = [];
172
+ byDmPath = new Map();
173
+ libs;
174
+ constructor(options, libs = []) {
175
+ this.options = options;
176
+ this.api = options.api ?? (0, api_js_1.robloxApi)();
177
+ this.files = collectClp(options.srcDir).map((f) => node_path_1.default.resolve(f));
178
+ this.libs = libs;
179
+ this.dataModel = buildDataModel(this.api, options.srcDir, this.files, libs);
180
+ for (const f of this.files) {
181
+ this.byDmPath.set(this.dmOf(f).join("/"), f);
182
+ }
183
+ }
184
+ rel(file) {
185
+ return node_path_1.default.relative(this.options.srcDir, file).replace(/\\/g, "/");
186
+ }
187
+ dmOf(file) {
188
+ return dataModelPath(this.api, this.rel(file));
189
+ }
190
+ compileAll() {
191
+ return this.files.map((f) => this.compile(f));
192
+ }
193
+ compile(file, text) {
194
+ const key = node_path_1.default.resolve(file);
195
+ const cached = this.results.get(key);
196
+ if (cached && text === undefined) {
197
+ return cached;
198
+ }
199
+ const source = new source_js_1.SourceFile(this.rel(key), text ?? node_fs_1.default.readFileSync(key, "utf8"));
200
+ const diags = new diagnostics_js_1.DiagnosticBag(source);
201
+ const rel = this.rel(key);
202
+ const context = (0, context_js_1.runContextOf)(key);
203
+ const kind = context === "shared" ? "module" : "script";
204
+ this.inProgress.push(key);
205
+ const program = (0, parser_js_1.parse)(source, diags);
206
+ const dmPath = this.dmOf(key);
207
+ let info = null;
208
+ try {
209
+ info = new checker_js_1.Checker({
210
+ program,
211
+ source,
212
+ diags,
213
+ api: this.api,
214
+ moduleId: key,
215
+ kind,
216
+ context,
217
+ strict: this.options.strict,
218
+ resolveLink: (link) => this.resolveLink(link, key, diags),
219
+ dataModel: this.dataModel,
220
+ dmPath,
221
+ }).run();
222
+ }
223
+ finally {
224
+ this.inProgress.pop();
225
+ }
226
+ let luau = null;
227
+ let sourceMap = [];
228
+ if (diags.errorCount === 0) {
229
+ luau = (0, emitter_js_1.emitLuau)(program, info, this.api, {
230
+ sourceLabel: rel,
231
+ sourcePosition: offset => source.position(offset),
232
+ onSourceMap: lines => { sourceMap = lines; },
233
+ version: this.options.version,
234
+ requireTarget: (l, service) => this.requireTarget(l, dmPath, service),
235
+ libsRoot: (service) => instancePath(exports.LIBS_FOLDER, service, null),
236
+ });
237
+ }
238
+ const result = { file: key, rel, outRel: outputName(rel), luau, sourceMap, diagnostics: diags.items, source, info };
239
+ this.results.set(key, result);
240
+ return result;
241
+ }
242
+ resolveLink(link, fromFile, diags) {
243
+ const p = link.path;
244
+ if (link.isPackage) {
245
+ if (p === "@clpp.roblox" || p === "@roblox") {
246
+ return { kind: "roblox" };
247
+ }
248
+ const std = stdlib_js_1.STD_PATHS[p];
249
+ if (std && std !== "unsupported") {
250
+ return { kind: "std", module: std };
251
+ }
252
+ if (stdlib_js_1.DESKTOP_ONLY[p]) {
253
+ return { kind: "error", message: `${p} is a desktop module of the clpp VM and does not exist on Roblox`, notes: [stdlib_js_1.DESKTOP_ONLY[p]] };
254
+ }
255
+ const lib = /^@(?:clpp\.libs|cluaupp)\.([A-Za-z0-9_]+)$/.exec(p);
256
+ if (lib) {
257
+ const name = this.libs.find((l) => l.toLowerCase() === lib[1].toLowerCase());
258
+ if (!name && this.libs.length) {
259
+ return { kind: "error", message: `CluauppLibs has no library '${lib[1]}'`, notes: [`available: ${this.libs.join(", ")}`] };
260
+ }
261
+ const libName = name ?? lib[1][0].toUpperCase() + lib[1].slice(1);
262
+ return { kind: "luau", dmPath: [...exports.LIBS_FOLDER, libName], label: libName };
263
+ }
264
+ if (p.startsWith("@game.") || /^@[A-Z]/.test(p)) {
265
+ const shorthand = !p.startsWith("@game.");
266
+ const segments = p.slice(shorthand ? 1 : "@game.".length).split(".");
267
+ if (!this.api.isService(segments[0])) {
268
+ return { kind: "error", message: `'${segments[0]}' is not a Roblox service`, notes: ["link @ReplicatedStorage.Shared.Module as Module;"] };
269
+ }
270
+ const fileHit = this.byDmPath.get(segments.join("/"));
271
+ if (fileHit) {
272
+ return this.linkFile(fileHit, fromFile);
273
+ }
274
+ if (shorthand) {
275
+ return { kind: "error", message: `no .clp module at ${p}`, notes: [`create src/${segments.join("/")}.clp or use a relative link to the file`] };
276
+ }
277
+ return { kind: "luau", dmPath: segments, label: segments.join(".") };
278
+ }
279
+ return { kind: "error", message: `unknown module ${p}`, notes: ["@clpp.roblox, @clpp.axiom, @clpp.libs.<Lib>, @ReplicatedStorage.Shared.<Module>, @game.<Service>.<…>"] };
280
+ }
281
+ let target = node_path_1.default.resolve(node_path_1.default.dirname(fromFile), p);
282
+ if (!node_fs_1.default.existsSync(target) && node_fs_1.default.existsSync(`${target}.clp`)) {
283
+ target = `${target}.clp`;
284
+ }
285
+ if (!target.toLowerCase().endsWith(exports.SOURCE_EXT)) {
286
+ return { kind: "error", message: `cannot link '${p}': CL++ modules are .clp files`, notes: [/\.(clh|clpp)$/i.test(p) ? "CL++ 0.9 has no headers: rename the module to .clp" : "link \"./file.clp\" as Name;"] };
287
+ }
288
+ if (!node_fs_1.default.existsSync(target)) {
289
+ return { kind: "error", message: `cannot open module '${p}'` };
290
+ }
291
+ void diags;
292
+ return this.linkFile(target, fromFile);
293
+ }
294
+ linkFile(target, fromFile) {
295
+ const key = node_path_1.default.resolve(target);
296
+ if (this.inProgress.includes(key)) {
297
+ const cycle = [...this.inProgress.slice(this.inProgress.indexOf(key)), key].map((f) => this.rel(f));
298
+ return { kind: "error", message: "circular link", notes: [cycle.join(" → ")] };
299
+ }
300
+ if (key === node_path_1.default.resolve(fromFile)) {
301
+ return { kind: "error", message: "a module cannot link itself" };
302
+ }
303
+ const compiled = this.compile(key);
304
+ if (!compiled.info) {
305
+ return { kind: "error", message: `module ${this.rel(key)} failed to compile` };
306
+ }
307
+ if (compiled.diagnostics.some((d) => d.severity === "error")) {
308
+ const first = compiled.diagnostics.find((d) => d.severity === "error");
309
+ return { kind: "error", message: `module ${this.rel(key)} has errors`, notes: [`${first.file}:${first.line}:${first.column}: ${first.message}`] };
310
+ }
311
+ const exports = compiled.info.exports;
312
+ return { kind: "clp", exports, dmPath: this.dmOf(key), file: key };
313
+ }
314
+ requireTarget(link, fromDm, service) {
315
+ const t = link.target;
316
+ if (t.kind === "clp" && t.dmPath) {
317
+ return instancePath(t.dmPath, service, fromDm);
318
+ }
319
+ if (t.kind === "luau") {
320
+ return instancePath(t.dmPath, service, fromDm);
321
+ }
322
+ return null;
323
+ }
324
+ }
325
+ exports.ProjectCompiler = ProjectCompiler;
326
+ /** Compile one file with no project around it (tests, playground, `cluaupp check <file>`). */
327
+ function compileSource(text, fileName = "Main.server.clp", options = {}) {
328
+ const root = options.root ?? process.cwd();
329
+ const srcDir = options.srcDir ?? root;
330
+ const compiler = new ProjectCompiler({ root, srcDir, strict: options.strict ?? false, version: options.version ?? "dev", api: options.api });
331
+ return compiler.compile(node_path_1.default.resolve(srcDir, fileName), text);
332
+ }