cluaupp 1.5.2 → 2.0.0-beta.2

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 (210) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +29 -41
  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/README.md +1 -1
  12. package/editors/vscode/package.json +50 -15
  13. package/editors/vscode/snippets/flare.json +1 -1
  14. package/editors/vscode/snippets/hive.json +1 -1
  15. package/editors/vscode/syntaxes/clpp.tmLanguage.json +211 -0
  16. package/examples/README.md +9 -9
  17. package/examples/game/cluaupp.config.json +2 -2
  18. package/examples/game/default.project.json +4 -15
  19. package/examples/game/out/ReplicatedStorage/Shared/GameInfo.luau +8 -0
  20. package/examples/game/out/ReplicatedStorage/Shared/GameInfo.luau.map.json +13 -0
  21. package/examples/game/out/ServerScriptService/Leaderstats.server.luau +26 -0
  22. package/examples/game/out/ServerScriptService/Leaderstats.server.luau.map.json +13 -0
  23. package/examples/game/out/ServerScriptService/Main.server.luau +15 -0
  24. package/examples/game/out/ServerScriptService/Main.server.luau.map.json +13 -0
  25. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Main.client.luau +10 -0
  26. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Main.client.luau.map.json +13 -0
  27. package/examples/game/src/ReplicatedStorage/Shared/GameInfo.clp +1 -0
  28. package/examples/game/src/ServerScriptService/Leaderstats.server.clp +18 -0
  29. package/examples/game/src/ServerScriptService/Main.server.clp +9 -0
  30. package/examples/game/src/StarterPlayer/StarterPlayerScripts/Main.client.clp +4 -0
  31. package/generated/api/build-profile.js +1 -1
  32. package/generated/api/loader.js +2 -2
  33. package/generated/api/surface/build.js +328 -0
  34. package/generated/api/surface/luau-defs.js +595 -0
  35. package/generated/api/surface/model.js +8 -0
  36. package/generated/api-cli.js +2 -2
  37. package/generated/cli.js +18 -17
  38. package/generated/clpp/contract.js +6 -3
  39. package/generated/clpp/handshake.js +36 -0
  40. package/generated/clpp/modules.js +20 -9
  41. package/generated/clpp/runner.js +62 -31
  42. package/generated/compile.js +18 -1
  43. package/generated/compiler/ast.js +3 -0
  44. package/generated/compiler/checker/calls.js +999 -0
  45. package/generated/compiler/checker/checker.js +1215 -0
  46. package/generated/compiler/checker/exprs.js +791 -0
  47. package/generated/compiler/checker/flow.js +168 -0
  48. package/generated/compiler/checker/members.js +763 -0
  49. package/generated/compiler/checker/statements.js +792 -0
  50. package/generated/compiler/checker/symbols.js +90 -0
  51. package/generated/compiler/checker/typeops.js +348 -0
  52. package/generated/compiler/checker/yields.js +115 -0
  53. package/generated/compiler/diagnostics.js +138 -0
  54. package/generated/compiler/emit/emitter.js +2356 -0
  55. package/generated/compiler/emit/luau-types.js +137 -0
  56. package/generated/compiler/emit/names.js +130 -0
  57. package/generated/compiler/emit/runtime.js +432 -0
  58. package/generated/compiler/lexer.js +403 -0
  59. package/generated/compiler/parser.js +1881 -0
  60. package/generated/compiler/project.js +332 -0
  61. package/generated/compiler/roblox/api.js +388 -0
  62. package/generated/compiler/roblox/context.js +100 -0
  63. package/generated/compiler/source.js +59 -0
  64. package/generated/compiler/stdlib.js +232 -0
  65. package/generated/compiler/types.js +250 -0
  66. package/generated/intellisense.js +1 -15
  67. package/generated/lsp.js +1 -1
  68. package/generated/target/build-cache.js +4 -4
  69. package/generated/target/datamodel-generate.js +12 -0
  70. package/generated/target/gen-rojo-tree.js +15 -0
  71. package/generated/target/source-map.js +61 -8
  72. package/generated/target/studio-bridge.js +1 -0
  73. package/generated/utils/project.js +104 -31
  74. package/include/README.md +5 -0
  75. package/native/bin/.gitkeep +1 -0
  76. package/package.json +17 -6
  77. package/plugins/CluauppNav/Plugin.luau +28 -4
  78. package/rust/cluaupp/Cargo.lock +795 -0
  79. package/rust/cluaupp/Cargo.toml +17 -0
  80. package/rust/cluaupp/src/main.rs +717 -0
  81. package/scripts/postinstall-native.js +56 -0
  82. package/skills/README.md +3 -3
  83. package/skills/clpp-hive-flare/SKILL.md +30 -26
  84. package/skills/clpp-language/SKILL.md +67 -74
  85. package/skills/clpp-language/compiler.md +24 -36
  86. package/skills/clpp-style/SKILL.md +31 -44
  87. package/src/api/build-profile.ts +1 -1
  88. package/src/api/loader.ts +2 -2
  89. package/src/api/surface/build.ts +374 -0
  90. package/src/api/surface/luau-defs.ts +635 -0
  91. package/src/api/surface/model.ts +96 -0
  92. package/src/api-cli.ts +2 -2
  93. package/src/cli.ts +19 -18
  94. package/src/clpp/contract.ts +20 -3
  95. package/src/clpp/handshake.ts +25 -0
  96. package/src/clpp/modules.ts +17 -10
  97. package/src/clpp/runner.ts +52 -34
  98. package/src/compile.ts +20 -2
  99. package/src/compiler/ast.ts +336 -0
  100. package/src/compiler/checker/calls.ts +1025 -0
  101. package/src/compiler/checker/checker.ts +1352 -0
  102. package/src/compiler/checker/exprs.ts +805 -0
  103. package/src/compiler/checker/flow.ts +174 -0
  104. package/src/compiler/checker/members.ts +793 -0
  105. package/src/compiler/checker/statements.ts +802 -0
  106. package/src/compiler/checker/symbols.ts +219 -0
  107. package/src/compiler/checker/typeops.ts +355 -0
  108. package/src/compiler/checker/yields.ts +120 -0
  109. package/src/compiler/diagnostics.ts +163 -0
  110. package/src/compiler/emit/emitter.ts +2486 -0
  111. package/src/compiler/emit/luau-types.ts +143 -0
  112. package/src/compiler/emit/names.ts +130 -0
  113. package/src/compiler/emit/runtime.ts +438 -0
  114. package/src/compiler/lexer.ts +444 -0
  115. package/src/compiler/parser.ts +1943 -0
  116. package/src/compiler/project.ts +354 -0
  117. package/src/compiler/roblox/api.ts +408 -0
  118. package/src/compiler/roblox/context.ts +108 -0
  119. package/src/compiler/source.ts +67 -0
  120. package/src/compiler/stdlib.ts +256 -0
  121. package/src/compiler/types.ts +313 -0
  122. package/src/intellisense.ts +1 -13
  123. package/src/lsp.ts +1 -1
  124. package/src/target/build-cache.ts +5 -8
  125. package/src/target/datamodel-generate.ts +12 -1
  126. package/src/target/gen-rojo-tree.ts +15 -0
  127. package/src/target/source-map.ts +65 -27
  128. package/src/target/studio-bridge.ts +3 -0
  129. package/src/types.ts +3 -0
  130. package/src/utils/project.ts +99 -37
  131. package/templates/README.md +7 -0
  132. package/templates/{game → game-modern}/cluaupp.config.json +2 -2
  133. package/templates/{game → game-modern}/package.json +1 -2
  134. package/templates/game-modern/rokit.toml +2 -0
  135. package/templates/game-modern/src/ReplicatedStorage/Shared/GameInfo.clp +1 -0
  136. package/templates/game-modern/src/ServerScriptService/Handlers/Guard.server.clp +4 -0
  137. package/templates/game-modern/src/ServerScriptService/Main.server.clp +8 -0
  138. package/templates/game-modern/src/StarterPlayer/StarterPlayerScripts/Main.client.clp +4 -0
  139. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +0 -29
  140. package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +0 -13
  141. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +0 -83
  142. package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +0 -13
  143. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +0 -18
  144. package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +0 -13
  145. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +0 -14
  146. package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +0 -13
  147. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +0 -15
  148. package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +0 -13
  149. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +0 -50
  150. package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +0 -13
  151. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +0 -12
  152. package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +0 -13
  153. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +0 -16
  154. package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +0 -13
  155. package/examples/game/src/Client/Controllers/DataController.client.clpp +0 -7
  156. package/examples/game/src/Client/Main.client.clpp +0 -4
  157. package/examples/game/src/Declarations/Net.flare +0 -5
  158. package/examples/game/src/Include/GameTypes.clh +0 -40
  159. package/examples/game/src/Modules/Core/Guard.server.clpp +0 -7
  160. package/examples/game/src/Modules/Core/PlayerHandler.server.clpp +0 -23
  161. package/examples/game/src/Server/Boot/DataBoot.server.clpp +0 -13
  162. package/examples/game/src/Server/Main.server.clpp +0 -4
  163. package/templates/game/.clangd +0 -25
  164. package/templates/game/.vscode/extensions.json +0 -8
  165. package/templates/game/.vscode/settings.json +0 -17
  166. package/templates/game/Packages/.gitkeep +0 -0
  167. package/templates/game/compile_flags.txt +0 -6
  168. package/templates/game/default.project.json +0 -41
  169. package/templates/game/include/clpp/datatypes.clh +0 -575
  170. package/templates/game/include/clpp/generated/enums.clh +0 -4920
  171. package/templates/game/include/clpp/generated/instances.clh +0 -87182
  172. package/templates/game/include/clpp/libs/arrayindexer.clh +0 -12
  173. package/templates/game/include/clpp/libs/axiom.clh +0 -154
  174. package/templates/game/include/clpp/libs/bloom.clh +0 -58
  175. package/templates/game/include/clpp/libs/coil.clh +0 -37
  176. package/templates/game/include/clpp/libs/crest.clh +0 -22
  177. package/templates/game/include/clpp/libs/echo.clh +0 -52
  178. package/templates/game/include/clpp/libs/ember.clh +0 -17
  179. package/templates/game/include/clpp/libs/flare.clh +0 -65
  180. package/templates/game/include/clpp/libs/gleam.clh +0 -111
  181. package/templates/game/include/clpp/libs/guide.clh +0 -42
  182. package/templates/game/include/clpp/libs/helm.clh +0 -31
  183. package/templates/game/include/clpp/libs/hive.clh +0 -20
  184. package/templates/game/include/clpp/libs/keep.clh +0 -158
  185. package/templates/game/include/clpp/libs/lens.clh +0 -24
  186. package/templates/game/include/clpp/libs/mint.clh +0 -28
  187. package/templates/game/include/clpp/libs/net.clh +0 -31
  188. package/templates/game/include/clpp/libs/occlude.clh +0 -15
  189. package/templates/game/include/clpp/libs/pin.clh +0 -28
  190. package/templates/game/include/clpp/libs/promise.clh +0 -24
  191. package/templates/game/include/clpp/libs/roster.clh +0 -123
  192. package/templates/game/include/clpp/libs/shift.clh +0 -22
  193. package/templates/game/include/clpp/libs/spark.clh +0 -28
  194. package/templates/game/include/clpp/libs/stage.clh +0 -23
  195. package/templates/game/include/clpp/libs/sweep.clh +0 -23
  196. package/templates/game/include/clpp/libs/trace.clh +0 -18
  197. package/templates/game/include/clpp/libs/ward.clh +0 -19
  198. package/templates/game/include/clpp/libs.clh +0 -31
  199. package/templates/game/include/clpp/roblox.clh +0 -41
  200. package/templates/game/rokit.toml +0 -5
  201. package/templates/game/src/Client/Controllers/DataController.client.clpp +0 -7
  202. package/templates/game/src/Client/Main.client.clpp +0 -4
  203. package/templates/game/src/Declarations/Net.flare +0 -5
  204. package/templates/game/src/Include/GameTypes.clh +0 -40
  205. package/templates/game/src/Modules/Core/Guard.server.clpp +0 -7
  206. package/templates/game/src/Modules/Core/PlayerHandler.server.clpp +0 -24
  207. package/templates/game/src/Server/Boot/DataBoot.server.clpp +0 -13
  208. package/templates/game/src/Server/Main.server.clpp +0 -4
  209. package/templates/game/stylua.toml +0 -9
  210. package/templates/game/wally.toml +0 -12
@@ -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. */
@@ -11,36 +11,68 @@ exports.compileViaClppAsync = compileViaClppAsync;
11
11
  exports.clppManifest = clppManifest;
12
12
  exports.clppVersion = clppVersion;
13
13
  exports.clppInstalls = clppInstalls;
14
+ exports.clppCacheIdentity = clppCacheIdentity;
14
15
  const node_child_process_1 = require("node:child_process");
15
16
  const node_fs_1 = __importDefault(require("node:fs"));
16
17
  const node_os_1 = __importDefault(require("node:os"));
17
18
  const node_path_1 = __importDefault(require("node:path"));
18
19
  const contract_js_1 = require("./contract.js");
20
+ const handshake_js_1 = require("./handshake.js");
19
21
  const MISSING_CLPP = `cluaupp: clpp not found. ${contract_js_1.CLPP_INSTALL_HINT}`;
20
22
  let cachedBin;
23
+ let cachedSelectionKey = "";
24
+ const contractSupport = new Map();
25
+ function binaryKey(bin) {
26
+ const stat = node_fs_1.default.statSync(bin);
27
+ return JSON.stringify([bin, stat.size, stat.mtimeMs]);
28
+ }
21
29
  function parseSemver(text) {
22
- const match = String(text).match(/(\d+)\.(\d+)\.(\d+)/);
30
+ const match = String(text).match(/(\d+)\.(\d+)(?:\.(\d+))?/);
23
31
  if (!match) {
24
32
  return null;
25
33
  }
26
- return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) };
34
+ return { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3] || 0) };
27
35
  }
28
36
  function cmpSemver(a, b) {
29
37
  return a.major - b.major || a.minor - b.minor || a.patch - b.patch;
30
38
  }
31
- function minClpp() {
32
- return parseSemver(contract_js_1.MIN_CLPP_VERSION) || { major: 0, minor: 8, patch: 0 };
33
- }
34
- function tooOldMessage(bin, version) {
35
- return `cluaupp: clpp ${version || "unknown"} is too old (${bin}). Need CL++ ${contract_js_1.MIN_CLPP_VERSION}+. Install https://github.com/KartzRbx/CLPP/releases or set CLPP / CLPP_PATH.`;
36
- }
37
39
  function probeVersion(bin) {
38
- const result = (0, node_child_process_1.spawnSync)(bin, ["--version"], { encoding: "utf8", windowsHide: true });
40
+ const result = (0, node_child_process_1.spawnSync)(bin, ["--version"], { encoding: "utf8", windowsHide: true, timeout: 10_000 });
39
41
  if (result.status !== 0) {
40
42
  return null;
41
43
  }
42
44
  return String(result.stdout || result.stderr || "").trim() || null;
43
45
  }
46
+ function handshake(bin) {
47
+ const key = binaryKey(bin);
48
+ const cached = contractSupport.get(key);
49
+ if (cached)
50
+ return cached;
51
+ const version = probeVersion(bin) || "";
52
+ let manifest;
53
+ // Reject the VM before asking it to compile or interpret any input.
54
+ if ((0, handshake_js_1.acceptsCompilerVersion)(version)) {
55
+ const result = (0, node_child_process_1.spawnSync)(bin, ["api", "manifest"], { encoding: "utf8", windowsHide: true, timeout: 10_000 });
56
+ if (result.status === 0) {
57
+ try {
58
+ manifest = JSON.parse(String(result.stdout || ""));
59
+ }
60
+ catch { }
61
+ }
62
+ }
63
+ const validated = (0, handshake_js_1.validateCompilerHandshake)(version, manifest);
64
+ contractSupport.set(key, validated);
65
+ return validated;
66
+ }
67
+ function supportsLuauContract(bin) {
68
+ try {
69
+ handshake(bin);
70
+ return true;
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
44
76
  function pushCandidate(out, seen, item) {
45
77
  const value = String(item || "").trim();
46
78
  if (!value) {
@@ -66,9 +98,12 @@ function listClppCandidates() {
66
98
  const override = [];
67
99
  pushCandidate(override, seen, process.env.CLPP);
68
100
  pushCandidate(override, seen, process.env.CLPP_PATH);
69
- const overrideExisting = override.filter(existsBin);
70
- if (overrideExisting.length > 0) {
71
- return overrideExisting;
101
+ if (override.length > 0) {
102
+ for (const bin of override) {
103
+ if (!existsBin(bin))
104
+ throw new Error(`cluaupp: explicit CLPP/CLPP_PATH does not exist: ${bin}`);
105
+ }
106
+ return override;
72
107
  }
73
108
  const out = [];
74
109
  const finder = process.platform === "win32" ? "where" : "which";
@@ -97,7 +132,7 @@ function pickClppBinary() {
97
132
  if (!fallback) {
98
133
  fallback = bin;
99
134
  }
100
- if (!parsed) {
135
+ if (!parsed || !supportsLuauContract(bin)) {
101
136
  continue;
102
137
  }
103
138
  if (!best || cmpSemver(parsed, best.parsed) > 0) {
@@ -107,9 +142,11 @@ function pickClppBinary() {
107
142
  return best?.bin || fallback;
108
143
  }
109
144
  function whichClpp() {
110
- if (cachedBin !== undefined) {
145
+ const selectionKey = JSON.stringify([process.env.CLPP, process.env.CLPP_PATH, process.env.PATH]);
146
+ if (cachedBin !== undefined && selectionKey === cachedSelectionKey) {
111
147
  return cachedBin;
112
148
  }
149
+ cachedSelectionKey = selectionKey;
113
150
  cachedBin = pickClppBinary();
114
151
  return cachedBin;
115
152
  }
@@ -121,18 +158,14 @@ function resolveClppBinary() {
121
158
  if (!bin) {
122
159
  throw new Error(MISSING_CLPP);
123
160
  }
124
- const version = probeVersion(bin);
125
- const parsed = parseSemver(version || "");
126
- if (!parsed || cmpSemver(parsed, minClpp()) < 0) {
127
- throw new Error(tooOldMessage(bin, version));
128
- }
161
+ handshake(bin);
129
162
  return bin;
130
163
  }
131
164
  function parseArtifact(stdout, fileName, fallbackError) {
132
165
  const text = String(stdout || "").trim();
133
166
  try {
134
167
  const parsed = JSON.parse(text);
135
- if (parsed && typeof parsed === "object") {
168
+ if (parsed && typeof parsed === "object" && typeof parsed.ok === "boolean" && typeof parsed.luau === "string" && typeof parsed.fileName === "string") {
136
169
  return parsed;
137
170
  }
138
171
  }
@@ -158,7 +191,7 @@ function formatClppFailure(artifact, fallback) {
158
191
  return diags
159
192
  .map((d) => {
160
193
  const where = `${artifact.fileName || "clpp"}:${d.line}:${d.column}`;
161
- return `${where}: ${d.message}`;
194
+ return `${where}: ${d.severity}${d.code ? " [" + d.code + "]" : ""}: ${d.message}${d.help ? "\n " + d.help : ""}`;
162
195
  })
163
196
  .join("\n");
164
197
  }
@@ -186,7 +219,7 @@ function compileViaClpp(request) {
186
219
  });
187
220
  const stderr = String(result.stderr || "").trim();
188
221
  const artifact = parseArtifact(result.stdout, request.fileName, stderr || result.error?.message || "clpp api compile failed");
189
- if (!artifact.ok) {
222
+ if (result.status !== 0 || result.error || !artifact.ok) {
190
223
  throw new Error(formatClppFailure(artifact, stderr || result.error?.message || `clpp failed (${result.status})`));
191
224
  }
192
225
  return artifact;
@@ -218,7 +251,7 @@ function compileViaClppAsync(request) {
218
251
  child.on("error", reject);
219
252
  child.on("close", (code) => {
220
253
  const artifact = parseArtifact(stdout, request.fileName, stderr.trim() || `clpp api compile failed (${code})`);
221
- if (!artifact.ok) {
254
+ if (code !== 0 || !artifact.ok) {
222
255
  reject(new Error(formatClppFailure(artifact, stderr.trim() || `clpp failed (${code})`)));
223
256
  return;
224
257
  }
@@ -239,14 +272,7 @@ function compileViaClppAsync(request) {
239
272
  }
240
273
  function clppManifest() {
241
274
  const bin = resolveClppBinary();
242
- const result = (0, node_child_process_1.spawnSync)(bin, ["api", "manifest"], {
243
- encoding: "utf8",
244
- windowsHide: true,
245
- });
246
- if (result.status !== 0) {
247
- throw new Error(String(result.stderr || result.error?.message || "clpp api manifest failed"));
248
- }
249
- return JSON.parse(result.stdout);
275
+ return handshake(bin);
250
276
  }
251
277
  function clppVersion() {
252
278
  const bin = whichClpp();
@@ -263,3 +289,8 @@ function clppInstalls() {
263
289
  selected: bin === selected,
264
290
  }));
265
291
  }
292
+ /** Include the actual binary and handshake in incremental fingerprints. */
293
+ function clppCacheIdentity() {
294
+ const bin = resolveClppBinary();
295
+ return JSON.stringify([binaryKey(bin), handshake(bin)]);
296
+ }
@@ -21,6 +21,8 @@ const datamodel_generate_js_1 = require("./target/datamodel-generate.js");
21
21
  const parallel_check_js_1 = require("./target/parallel-check.js");
22
22
  const authority_check_js_1 = require("./target/authority-check.js");
23
23
  const get_service_js_1 = require("./target/get-service.js");
24
+ const project_js_1 = require("./compiler/project.js");
25
+ const diagnostics_js_1 = require("./compiler/diagnostics.js");
24
26
  function defaultTargetProfilePath() {
25
27
  const cached = node_path_1.default.join(package_info_js_1.projectRoot, "api", "normalized", "roblox-target.profile.json");
26
28
  if (node_fs_1.default.existsSync(cached)) {
@@ -122,7 +124,7 @@ function finishArtifact(artifact, relative, outName, options, skipInit, source)
122
124
  return {
123
125
  kind: (0, paths_js_1.emitKind)(relative),
124
126
  plan: { kind: (0, paths_js_1.emitKind)(relative), strict: options.strict === true },
125
- files: [{ name: outName, contents: luau }],
127
+ files: [{ name: outName, contents: luau, sourceMap: artifact.sourceMap, generatedSource: artifact.luau }],
126
128
  stale: [],
127
129
  };
128
130
  }
@@ -130,14 +132,29 @@ function compileSource(source, fileName, options = {}) {
130
132
  return compileService(source, fileName, options).files[0]?.contents ?? "";
131
133
  }
132
134
  function compileService(source, fileName, options = {}) {
135
+ if (/\.clp$/i.test(options.relativeName || fileName || "")) {
136
+ return compileModernSource(source, fileName, options);
137
+ }
133
138
  const args = compileArgs(source, fileName, options);
134
139
  enforcePlatform(source, args.relative, args);
135
140
  const artifact = (0, runner_js_1.compileViaClpp)(args.request);
136
141
  return finishArtifact(artifact, args.relative, args.outName, args.options, args.skipInit, source);
137
142
  }
138
143
  async function compileServiceAsync(source, fileName, options = {}) {
144
+ if (/\.clp$/i.test(options.relativeName || fileName || "")) {
145
+ return compileModernSource(source, fileName, options);
146
+ }
139
147
  const args = compileArgs(source, fileName, options);
140
148
  enforcePlatform(source, args.relative, args);
141
149
  const artifact = await (0, runner_js_1.compileViaClppAsync)(args.request);
142
150
  return finishArtifact(artifact, args.relative, args.outName, args.options, args.skipInit, source);
143
151
  }
152
+ function compileModernSource(source, fileName, options) {
153
+ const relative = (options.relativeName || fileName || "input.clp").replace(/\\/g, "/");
154
+ const srcDir = options.srcDir || (options.filePath ? node_path_1.default.dirname(node_path_1.default.resolve(options.filePath)) : process.cwd());
155
+ const result = (0, project_js_1.compileSource)(source, relative, { srcDir, strict: options.strict === true, version: package_info_js_1.pkg.version });
156
+ if (result.luau === null) {
157
+ throw new Error(result.diagnostics.filter((d) => d.severity === "error").map((d) => (0, diagnostics_js_1.formatDiagnostic)(d, result.source)).join("\n") || `${relative}: Luau emission failed`);
158
+ }
159
+ return { kind: (0, paths_js_1.emitKind)(relative), files: [{ name: options.outName || (0, paths_js_1.toLuauPath)(relative), contents: result.luau, sourceMap: result.sourceMap, generatedSource: result.luau }], stale: [] };
160
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ /** CL++ syntax tree. The checker annotates nodes in place (`ty`, `res`, `sym`). */
3
+ Object.defineProperty(exports, "__esModule", { value: true });