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
@@ -1,36 +1,74 @@
1
- /** Minimal source map: CL++ path ↔ emitted Luau (1:1 file mapping for v1). */
1
+ /** Compiler coordinates are retained only for lines that survive host transformations. */
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
+ import type { SourceMapLine } from "../clpp/contract.js";
4
5
 
5
6
  export interface CluauppSourceMap {
6
- version: 1;
7
- file: string;
8
- sourceRoot: string;
9
- sources: string[];
10
- mappings: string;
11
- cluaupp: {
12
- source: string;
13
- generated: string;
14
- };
7
+ version: 1;
8
+ file: string;
9
+ sourceRoot: string;
10
+ sources: string[];
11
+ cluaupp: { source: string; generated: string; lines: SourceMapLine[] };
12
+ }
13
+
14
+ /** LCS alignment: inserted headers and removed lines never become fake source locations. */
15
+ export function remapSourceLines(original: string, generated: string, mappings: SourceMapLine[] = []): SourceMapLine[] {
16
+ const a = original.split(/\r?\n/);
17
+ const b = generated.split(/\r?\n/);
18
+ if (original === generated) return mappings.map(m => ({...m}));
19
+ // Avoid unbounded memory for generated bundles. An absent map is safer than a wrong one.
20
+ if (a.length * b.length > 4_000_000) return [];
21
+ const widths = b.length + 1;
22
+ const dp = new Uint32Array((a.length + 1) * widths);
23
+ for (let i = a.length - 1; i >= 0; i--) for (let j = b.length - 1; j >= 0; j--) {
24
+ dp[i * widths + j] = a[i].trim() === b[j].trim() ? 1 + dp[(i+1)*widths+j+1] : Math.max(dp[(i+1)*widths+j], dp[i*widths+j+1]);
25
+ }
26
+ const translated = new Map<number, number>();
27
+ let i = 0, j = 0;
28
+ while (i < a.length && j < b.length) {
29
+ if (a[i].trim() === b[j].trim()) {translated.set(i+1, j+1); i++; j++;}
30
+ else if (dp[(i+1)*widths+j] >= dp[i*widths+j+1]) i++;
31
+ else j++;
32
+ }
33
+ return mappings.flatMap(m => {
34
+ const line = translated.get(m.luauLine);
35
+ if (!line || !Number.isInteger(m.clppLine) || m.clppLine < 1) return [];
36
+ // Formatting can move columns; do not invent a column in that case.
37
+ const exact = a[m.luauLine-1] === b[line-1];
38
+ const {luauColumn, ...rest} = m;
39
+ return [{...rest, luauLine: line, ...(exact && luauColumn ? {luauColumn} : {})}];
40
+ });
41
+ }
42
+
43
+ export function embedSourceMap(luau: string, lines: SourceMapLine[]): { contents: string; lines: SourceMapLine[] } {
44
+ if (!lines.length) return {contents: luau, lines: []};
45
+ const shifted = lines.map(m => ({...m, luauLine: m.luauLine+1}));
46
+ // Preserve Luau directives at the start of the file.
47
+ const parts = luau.split(/\r?\n/);
48
+ let index = 0;
49
+ while (index < parts.length && parts[index].startsWith("--!")) index++;
50
+ const adjusted = shifted.map((m, i) => ({...m, luauLine: lines[i].luauLine > index ? m.luauLine : lines[i].luauLine}));
51
+ parts.splice(index, 0, "-- cluaupp-map: " + JSON.stringify(adjusted));
52
+ return {contents: parts.join("\n"), lines: adjusted};
15
53
  }
16
54
 
17
55
  export function writeSourceMap(opts: {
18
- outLuauPath: string;
19
- sourceClppRel: string;
20
- projectRoot: string;
56
+ outLuauPath: string;
57
+ sourceClppRel: string;
58
+ projectRoot: string;
59
+ lines?: SourceMapLine[];
21
60
  }): string {
22
- const map: CluauppSourceMap = {
23
- version: 1,
24
- file: path.basename(opts.outLuauPath),
25
- sourceRoot: opts.projectRoot.replace(/\\/g, "/"),
26
- sources: [opts.sourceClppRel.replace(/\\/g, "/")],
27
- mappings: "AAAA", // identity stub — refine when clpp emits VLQ maps
28
- cluaupp: {
29
- source: opts.sourceClppRel.replace(/\\/g, "/"),
30
- generated: path.relative(opts.projectRoot, opts.outLuauPath).replace(/\\/g, "/"),
31
- },
32
- };
33
- const mapPath = opts.outLuauPath + ".map.json";
34
- fs.writeFileSync(mapPath, JSON.stringify(map, null, "\t") + "\n", "utf8");
35
- return mapPath;
61
+ const lines = opts.lines || [];
62
+ const source = opts.sourceClppRel.replace(/\\/g, "/");
63
+ const map: CluauppSourceMap = {
64
+ version: 1,
65
+ file: path.basename(opts.outLuauPath),
66
+ sourceRoot: opts.projectRoot.replace(/\\/g, "/"),
67
+ sources: [...new Set([source, ...lines.map(m => m.file)])],
68
+ cluaupp: { source, generated: path.relative(opts.projectRoot, opts.outLuauPath).replace(/\\/g, "/"), lines },
69
+ };
70
+ const mapPath = opts.outLuauPath + ".map.json";
71
+ const contents = JSON.stringify(map, null, "\t") + "\n";
72
+ if (!fs.existsSync(mapPath) || fs.readFileSync(mapPath, "utf8") !== contents) fs.writeFileSync(mapPath, contents, "utf8");
73
+ return mapPath;
36
74
  }
@@ -16,6 +16,7 @@ export interface BridgeEvent {
16
16
  type: "open" | "select" | "error" | "ping";
17
17
  path?: string;
18
18
  line?: number;
19
+ column?: number;
19
20
  message?: string;
20
21
  instancePath?: string;
21
22
  }
@@ -86,6 +87,7 @@ export function startStudioBridge(opts: {
86
87
  const data = JSON.parse(body || "{}") as {
87
88
  path?: string;
88
89
  line?: number;
90
+ column?: number;
89
91
  instancePath?: string;
90
92
  type?: BridgeEvent["type"];
91
93
  message?: string;
@@ -106,6 +108,7 @@ export function startStudioBridge(opts: {
106
108
  type: data.type || "open",
107
109
  path: rel || undefined,
108
110
  line: data.line,
111
+ column: data.column,
109
112
  instancePath: data.instancePath,
110
113
  message: data.message,
111
114
  });
package/src/types.ts CHANGED
@@ -78,6 +78,9 @@ export interface BuildResult {
78
78
  export interface CompiledArtifact {
79
79
  name: string;
80
80
  contents: string;
81
+ /** Compiler coordinates before host output transforms. */
82
+ sourceMap?: import("./clpp/contract.js").SourceMapLine[];
83
+ generatedSource?: string;
81
84
  }
82
85
 
83
86
  export interface CompileServiceResult {
@@ -1,17 +1,19 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import type { BuildOptions, BuildResult, ProjectConfig } from "../types.js";
4
- import { pkg } from "../package-info.js";
4
+ import { pkg, projectRoot as toolRoot } from "../package-info.js";
5
+ import { clppCacheIdentity } from "../clpp/runner.js";
6
+ import type { CompiledArtifact } from "../types.js";
5
7
  import { rewriteClppEmit } from "../clpp/postprocess.js";
6
8
  import { collectSources, toLuauPath } from "../clpp/paths.js";
7
9
  import { collectFlareFiles, compileFlareFile } from "../flare/index.js";
8
10
  import { collectNativeSchemaFiles, compileNativeSchemaFile } from "../native/index.js";
9
- import { installEditorExtension, syncEditorSupport } from "../intellisense.js";
11
+ import { syncEditorSupport } from "../intellisense.js";
10
12
  import { ProcessOrchestrator } from "./process-orchestrator.js";
11
13
  import { RojoMapper } from "./rojo-mapper.js";
12
14
  import { transpileSource, transpileSourceAsync } from "../transpile.js";
13
15
  import { assertInitDest, assertInside, isInside, safeProjectSubdir, safeRelPath } from "./safe-paths.js";
14
- import { writeSourceMap } from "../target/source-map.js";
16
+ import { writeSourceMap, remapSourceLines, embedSourceMap } from "../target/source-map.js";
15
17
  import { stampLuauFromClpp } from "../target/luau-stamp.js";
16
18
  import { collectSoaPlansFromProject, writeSoaArtifacts } from "../target/optimizer-soa.js";
17
19
  import { verifyLock } from "../api/index.js";
@@ -28,6 +30,8 @@ import {
28
30
  writeCachedJob,
29
31
  } from "../target/build-cache.js";
30
32
  import { fingerprintSourceWithDeps } from "../clpp/modules.js";
33
+ import { ProjectCompiler } from "../compiler/project.js";
34
+ import { formatDiagnostic } from "../compiler/diagnostics.js";
31
35
 
32
36
  function readProjectConfig(file: string): Partial<ProjectConfig> {
33
37
  const raw = JSON.parse(fs.readFileSync(file, "utf8"));
@@ -335,7 +339,7 @@ function compileOptions(root: string, config: ProjectConfig, file: string, rel:
335
339
  }
336
340
 
337
341
  function compileSchemaJobs(root: string, config: ProjectConfig, srcDir: string) {
338
- const jobs: Array<{ rel: string; files: Array<{ name: string; contents: string }>; stale: string[] }> = [];
342
+ const jobs: Array<{ rel: string; files: CompiledArtifact[]; stale: string[] }> = [];
339
343
  const errors: Array<{ rel: string; prefixes: string[]; message: string }> = [];
340
344
  const flare = compileFlareJobs(root, config, srcDir);
341
345
  jobs.push(...flare.jobs);
@@ -366,7 +370,7 @@ function compileSchemaJobs(root: string, config: ProjectConfig, srcDir: string)
366
370
  }
367
371
 
368
372
  function compileFlareJobs(root: string, config: ProjectConfig, srcDir: string) {
369
- const jobs: Array<{ rel: string; files: Array<{ name: string; contents: string }>; stale: string[] }> = [];
373
+ const jobs: Array<{ rel: string; files: CompiledArtifact[]; stale: string[] }> = [];
370
374
  const errors: Array<{ rel: string; prefixes: string[]; message: string }> = [];
371
375
  for (const file of collectFlareFiles(srcDir)) {
372
376
  const rel = posixRel(srcDir, file);
@@ -389,27 +393,58 @@ function compileFlareJobs(root: string, config: ProjectConfig, srcDir: string) {
389
393
  return { jobs, errors };
390
394
  }
391
395
 
392
- function configFingerprint(config: ProjectConfig): string {
396
+ function configFingerprint(root: string, config: ProjectConfig, rojoPath?: string): string {
397
+ const inputs = [path.resolve(root, rojoPath || "default.project.json"), path.join(root, "cluaupp.platform.json"), path.join(root, "cluaupp.profile.json"), path.join(toolRoot, "api", "normalized", "roblox-target.profile.json"), path.join(toolRoot, "api", "generated", "capability-profile.json"), path.join(toolRoot, "api", "roblox-api.lock.json")];
393
398
  return JSON.stringify({
394
399
  strict: config.strict === true,
395
400
  architecture: config.architecture === true,
396
401
  rootDir: config.rootDir,
397
402
  outDir: config.outDir,
398
403
  v: pkg.version,
404
+ rules: config.rules,
405
+ components: config.components,
406
+ inputs: inputs.map(file => [file, fs.existsSync(file) ? hashText(fs.readFileSync(file, "utf8")) : null]),
399
407
  });
400
408
  }
401
409
 
410
+ function compileClpJobs(root: string, config: ProjectConfig, srcDir: string) {
411
+ const compiler = new ProjectCompiler({ root, srcDir, strict: config.strict === true, version: pkg.version });
412
+ const jobs: Array<{ rel: string; files: CompiledArtifact[]; stale: string[] }> = [];
413
+ const errors: Array<{ rel: string; prefixes: string[]; message: string }> = [];
414
+ for (const result of compiler.compileAll()) {
415
+ if (result.luau === null) {
416
+ const diagnostics = result.diagnostics.filter((d) => d.severity === "error");
417
+ errors.push({
418
+ rel: result.rel,
419
+ prefixes: sourcePrefixes(result.rel),
420
+ message: diagnostics.map((d) => formatDiagnostic(d, result.source)).join("\n") || `${result.rel}: Luau emission failed`,
421
+ });
422
+ continue;
423
+ }
424
+ jobs.push({ rel: result.rel, files: [{ name: result.outRel, contents: result.luau, sourceMap: result.sourceMap, generatedSource: result.luau }], stale: [] });
425
+ }
426
+ return { jobs, errors };
427
+ }
428
+
402
429
  function compileProject(root: string, config: ProjectConfig, mapper: RojoMapper, options: BuildOptions = {}) {
403
430
  const srcDir = path.join(root, config.rootDir);
404
431
  const schema = compileSchemaJobs(root, config, srcDir);
405
432
  const files = collectSources(srcDir);
406
- const jobs = [...schema.jobs];
407
- const errors = [...schema.errors];
433
+ const legacyFiles = files.filter((file) => !file.toLowerCase().endsWith(".clp"));
434
+ const clp = compileClpJobs(root, config, srcDir);
435
+ const jobs = [...schema.jobs, ...clp.jobs];
436
+ const errors = [...schema.errors, ...clp.errors];
408
437
  const incremental = options.incremental !== false;
409
- const cfgKey = configFingerprint(config);
438
+ let cfgKey = configFingerprint(root, config, options.rojo);
439
+ if (legacyFiles.length) {
440
+ try {cfgKey += clppCacheIdentity();} catch (err) {
441
+ for (const file of legacyFiles) {const rel = posixRel(srcDir, file); errors.push({rel, prefixes: sourcePrefixes(rel), message: (err as Error).message});}
442
+ return {files, jobs, errors};
443
+ }
444
+ }
410
445
  let cacheHits = 0;
411
446
 
412
- for (const file of files) {
447
+ for (const file of legacyFiles) {
413
448
  const source = fs.readFileSync(file, "utf8");
414
449
  const rel = posixRel(srcDir, file);
415
450
  const sourceHash = fingerprintSourceWithDeps(source, file, cfgKey, srcDir, hashText);
@@ -438,7 +473,7 @@ function compileProject(root: string, config: ProjectConfig, mapper: RojoMapper,
438
473
  }
439
474
 
440
475
  if (cacheHits > 0) {
441
- console.log(`cluaupp: incremental cache hit ${cacheHits}/${files.length}`);
476
+ console.log(`cluaupp: incremental cache hit ${cacheHits}/${legacyFiles.length}`);
442
477
  }
443
478
  return { files, jobs, errors };
444
479
  }
@@ -447,14 +482,22 @@ async function compileProjectAsync(root: string, config: ProjectConfig, mapper:
447
482
  const srcDir = path.join(root, config.rootDir);
448
483
  const schema = compileSchemaJobs(root, config, srcDir);
449
484
  const files = collectSources(srcDir);
450
- const jobs = [...schema.jobs];
451
- const errors = [...schema.errors];
485
+ const legacyFiles = files.filter((file) => !file.toLowerCase().endsWith(".clp"));
486
+ const clp = compileClpJobs(root, config, srcDir);
487
+ const jobs = [...schema.jobs, ...clp.jobs];
488
+ const errors = [...schema.errors, ...clp.errors];
452
489
  const incremental = options.incremental !== false;
453
- const cfgKey = configFingerprint(config);
490
+ let cfgKey = configFingerprint(root, config, options.rojo);
491
+ if (legacyFiles.length) {
492
+ try {cfgKey += clppCacheIdentity();} catch (err) {
493
+ for (const file of legacyFiles) {const rel = posixRel(srcDir, file); errors.push({rel, prefixes: sourcePrefixes(rel), message: (err as Error).message});}
494
+ return {files, jobs, errors};
495
+ }
496
+ }
454
497
  const concurrency = options.jobs ?? defaultJobCount();
455
498
  let cacheHits = 0;
456
499
 
457
- const compiled = await mapPool(files, concurrency, async (file) => {
500
+ const compiled = await mapPool(legacyFiles, concurrency, async (file) => {
458
501
  const source = fs.readFileSync(file, "utf8");
459
502
  const rel = posixRel(srcDir, file);
460
503
  const sourceHash = fingerprintSourceWithDeps(source, file, cfgKey, srcDir, hashText);
@@ -510,8 +553,8 @@ async function compileProjectAsync(root: string, config: ProjectConfig, mapper:
510
553
  }
511
554
 
512
555
  if (cacheHits > 0) {
513
- console.log(`cluaupp: incremental cache hit ${cacheHits}/${files.length} (jobs=${concurrency})`);
514
- } else if (files.length > 1 && concurrency > 1) {
556
+ console.log(`cluaupp: incremental cache hit ${cacheHits}/${legacyFiles.length} (jobs=${concurrency})`);
557
+ } else if (legacyFiles.length > 1 && concurrency > 1) {
515
558
  console.log(`cluaupp: parallel compile jobs=${concurrency}`);
516
559
  }
517
560
  return { files, jobs, errors };
@@ -541,7 +584,7 @@ function outDest(root: string, config: ProjectConfig, rel: string): string | nul
541
584
  return dest;
542
585
  }
543
586
 
544
- function writeJobs(root: string, config: ProjectConfig, jobs: Array<{ rel: string; files: Array<{ name: string; contents: string }>; stale: string[] }>, format: boolean): Set<string> {
587
+ function writeJobs(root: string, config: ProjectConfig, jobs: Array<{ rel: string; files: CompiledArtifact[]; stale: string[] }>, format: boolean): Set<string> {
545
588
  const written = new Set<string>();
546
589
  for (const job of jobs) {
547
590
  for (const artifact of job.files) {
@@ -553,7 +596,18 @@ function writeJobs(root: string, config: ProjectConfig, jobs: Array<{ rel: strin
553
596
  if (/\.luau$/i.test(dest)) {
554
597
  const srcFile = path.join(root, config.rootDir, job.rel);
555
598
  const clppSource = fs.existsSync(srcFile) ? fs.readFileSync(srcFile, "utf8") : undefined;
556
- contents = stampLuauFromClpp(rewriteClppEmit(contents), job.rel, clppSource);
599
+ contents = stampLuauFromClpp(/\.clp$/i.test(job.rel) ? contents : rewriteClppEmit(contents), posixRel(root, srcFile), clppSource);
600
+ }
601
+ let lines = (artifact.sourceMap || []).map(m => ({...m, file: path.isAbsolute(m.file) ? posixRel(root, m.file) : path.posix.join(config.rootDir.replace(/\\/g, "/"), m.file)}));
602
+ if (format && /\.luau$/i.test(dest)) {
603
+ writeTextIfChanged(dest, contents);
604
+ ProcessOrchestrator.formatWithStyLuaSync(dest);
605
+ contents = fs.readFileSync(dest, "utf8");
606
+ }
607
+ if (/\.luau$/i.test(dest)) {
608
+ lines = remapSourceLines(artifact.generatedSource || artifact.contents, contents, lines);
609
+ const embedded = embedSourceMap(contents, lines);
610
+ contents = embedded.contents; lines = embedded.lines;
557
611
  }
558
612
  const changed = writeTextIfChanged(dest, contents);
559
613
  written.add(resolveKey(dest));
@@ -563,14 +617,12 @@ function writeJobs(root: string, config: ProjectConfig, jobs: Array<{ rel: strin
563
617
  if (/\.luau$/i.test(dest)) {
564
618
  const mapPath = writeSourceMap({
565
619
  outLuauPath: dest,
566
- sourceClppRel: job.rel,
620
+ sourceClppRel: path.posix.join(config.rootDir.replace(/\\/g, "/"), job.rel),
567
621
  projectRoot: root,
622
+ lines,
568
623
  });
569
624
  written.add(resolveKey(mapPath));
570
625
  }
571
- if (format && /\.luau$/i.test(dest)) {
572
- ProcessOrchestrator.formatWithStyLuaSync(dest);
573
- }
574
626
  }
575
627
  for (const stale of job.stale || []) {
576
628
  const dest = outDest(root, config, stale);
@@ -592,7 +644,7 @@ function ensureVendor(root: string): void {
592
644
  function finishBuild(
593
645
  root: string,
594
646
  config: ProjectConfig,
595
- compiled: { jobs: Array<{ rel: string; files: Array<{ name: string; contents: string }>; stale: string[] }>; errors: Array<{ rel: string; prefixes: string[]; message: string }> },
647
+ compiled: { jobs: Array<{ rel: string; files: CompiledArtifact[]; stale: string[] }>; errors: Array<{ rel: string; prefixes: string[]; message: string }> },
596
648
  options: BuildOptions,
597
649
  ): BuildResult {
598
650
  const exitOnError = options.exitOnError !== false;
@@ -726,7 +778,7 @@ export async function buildAsync(root: string, options: BuildOptions = {}): Prom
726
778
 
727
779
  export async function init(dest: string): Promise<void> {
728
780
  const target = assertInitDest(dest);
729
- const template = path.join(__dirname, "..", "..", "templates", "game");
781
+ const template = path.join(__dirname, "..", "..", "templates", "game-modern");
730
782
  const include = path.join(__dirname, "..", "..", "include");
731
783
  copyDir(template, target);
732
784
  copyDir(include, path.join(target, "include"));
@@ -738,13 +790,9 @@ export async function init(dest: string): Promise<void> {
738
790
  const initConfig = loadConfig(target);
739
791
  syncRojoTree(target, initConfig);
740
792
  syncEditorSupport(target);
741
- try {
742
- installEditorExtension();
743
- } catch {
744
- // editor homes may be missing in CI
745
- }
793
+ // CL++ 0.10 owns its editor extension; project init only writes associations.
746
794
  console.log("Cluaupp ready in", target);
747
- console.log(" clpp install (CL++ highlighting + IntelliSense)");
795
+ console.log(" CL++ 0.10 editor extension provides syntax highlighting; Cluaupp compiles Roblox .clp files");
748
796
  console.log(" cluaupp intellisense (schema .flare .hive .mint .bloom .helm .shift .axiom)");
749
797
  console.log(" rokit install");
750
798
  console.log(" cluaupp build");
@@ -0,0 +1,7 @@
1
+ # Project templates
2
+
3
+ | Template | Use |
4
+ | --- | --- |
5
+ | [`game-modern/`](game-modern/) | **`cluaupp init`** — CL++ 0.10 Roblox target: `src/`, `.clp`, `link`, top-level scripts |
6
+
7
+ Legacy `.clpp` / `Src/` / `#include` layouts are not scaffolded anymore. For migration, see [migration](https://kartzrbx.github.io/Cluaupp/migration/). Integration tests keep a frozen copy under [`test/fixtures/legacy-clpp-game/`](../test/fixtures/legacy-clpp-game/).
@@ -1,6 +1,6 @@
1
1
  {
2
- "rootDir": "Src",
2
+ "rootDir": "src",
3
3
  "outDir": "out",
4
- "strict": false,
4
+ "strict": true,
5
5
  "architecture": false
6
6
  }
@@ -3,7 +3,6 @@
3
3
  "private": true,
4
4
  "scripts": {
5
5
  "build": "cluaupp build",
6
- "watch": "cluaupp watch",
7
- "dev": "cluaupp watch"
6
+ "watch": "cluaupp watch"
8
7
  }
9
8
  }
@@ -0,0 +1,2 @@
1
+ [tools]
2
+ rojo = "rojo-rbx/rojo@7.7.0"
@@ -0,0 +1 @@
1
+ const GAME_NAME = "My CL++ game";
@@ -0,0 +1,4 @@
1
+ link @clpp.roblox;
2
+ link @clpp.libs.ward as Ward;
3
+
4
+ Ward.Start();
@@ -0,0 +1,8 @@
1
+ link @clpp.roblox;
2
+ link @ReplicatedStorage.Shared.GameInfo as GameInfo;
3
+
4
+ Players players = GetService<Players>();
5
+ post(GameInfo.GAME_NAME .: " server ready");
6
+ players.PlayerAdded ~> func (Player player) {
7
+ post(player.Name .: " joined");
8
+ };
@@ -0,0 +1,4 @@
1
+ link @clpp.roblox;
2
+ link @ReplicatedStorage.Shared.GameInfo as GameInfo;
3
+
4
+ post(GameInfo.GAME_NAME .: " client ready");
@@ -1,29 +0,0 @@
1
- --!nonstrict
2
- -- cluaupp-source: ReplicatedStorage/Shared/Constants/Datas/TemplateData.clh
3
- -- Compiled by CL++ — C++ × Luau
4
-
5
- -- cluaupp: Roster.new / GetService ReplicatedStorage / self.janitor
6
-
7
- export type PlayerTemplate = {
8
- Currencies: Currencies,
9
- Rebirths: number,
10
- Rank: number,
11
- Inventory: PlayerInventory,
12
- Trade: PlayerTrade,
13
- Settings: PlayerSettings,
14
- Codes: PlayerCodes,
15
- }
16
-
17
- const function PlayerTemplate()
18
- return {
19
- Currencies = { Coins = 0, Gems = 0 },
20
- Rebirths = 0,
21
- Rank = 0,
22
- Inventory = { Slots = 20 },
23
- Trade = { DayKey = nil, TradesToday = 0, LastTradeAt = 0, ActiveTradeId = nil },
24
- Settings = { GameMusic = 100, Effects = 100 },
25
- Codes = { RedeemedCount = 0 },
26
- }
27
- end
28
-
29
- return PlayerTemplate
@@ -1,13 +0,0 @@
1
- {
2
- "version": 1,
3
- "file": "TemplateData.luau",
4
- "sourceRoot": "C:/Users/gtofr/OneDrive/Documentos/GitHub/Cluaupp/examples/game",
5
- "sources": [
6
- "ReplicatedStorage/Shared/Constants/Datas/TemplateData.clh"
7
- ],
8
- "mappings": "AAAA",
9
- "cluaupp": {
10
- "source": "ReplicatedStorage/Shared/Constants/Datas/TemplateData.clh",
11
- "generated": "out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau"
12
- }
13
- }
@@ -1,83 +0,0 @@
1
- --!native
2
- --!optimize 2
3
- --!strict
4
- -- cluaupp-source: ReplicatedStorage/Shared/Net/Net.flare
5
- -- Generated by Cluaupp Flare from ReplicatedStorage/Shared/Net/Net.flare
6
- -- Do not edit. Change the .flare schema and run cluaupp build.
7
-
8
- -- cluaupp: Roster.new / GetService ReplicatedStorage / self.janitor
9
-
10
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
11
- local Flare = require(ReplicatedStorage.CluauppLibs.Flare)
12
-
13
- local session = Flare.open(script)
14
-
15
- -- packet Ready (#1)
16
- local function writeReady(cursor)
17
- return cursor
18
- end
19
-
20
- local function readReady(cursor)
21
- return
22
- end
23
-
24
- local Ready = session.packet({
25
- id = 1,
26
- from = "client",
27
- reliable = true,
28
- write = writeReady,
29
- read = readReady,
30
- })
31
-
32
- -- packet Welcome (#2)
33
- local function writeWelcome(cursor, userId, clock)
34
- Flare.writei32(cursor, userId)
35
- Flare.writef64(cursor, clock)
36
- return cursor
37
- end
38
-
39
- local function readWelcome(cursor)
40
- local userId = Flare.readi32(cursor)
41
- local clock = Flare.readf64(cursor)
42
- return userId, clock
43
- end
44
-
45
- local Welcome = session.packet({
46
- id = 2,
47
- from = "server",
48
- reliable = true,
49
- write = writeWelcome,
50
- read = readWelcome,
51
- })
52
-
53
- -- query Session (#1)
54
- local function writeSessionReq(cursor)
55
- return cursor
56
- end
57
-
58
- local function readSessionReq(cursor)
59
- return
60
- end
61
-
62
- local function writeSessionRes(cursor, value)
63
- Flare.writei32(cursor, value)
64
- return cursor
65
- end
66
-
67
- local function readSessionRes(cursor)
68
- return Flare.readi32(cursor)
69
- end
70
-
71
- local Session = session.query({
72
- id = 1,
73
- writeReq = writeSessionReq,
74
- readReq = readSessionReq,
75
- writeRes = writeSessionRes,
76
- readRes = readSessionRes,
77
- })
78
-
79
- return {
80
- Ready = Ready,
81
- Welcome = Welcome,
82
- Session = Session,
83
- }
@@ -1,13 +0,0 @@
1
- {
2
- "version": 1,
3
- "file": "Net.luau",
4
- "sourceRoot": "C:/Users/gtofr/OneDrive/Documentos/GitHub/Cluaupp/examples/game",
5
- "sources": [
6
- "ReplicatedStorage/Shared/Net/Net.flare"
7
- ],
8
- "mappings": "AAAA",
9
- "cluaupp": {
10
- "source": "ReplicatedStorage/Shared/Net/Net.flare",
11
- "generated": "out/ReplicatedStorage/Shared/Net/Net.luau"
12
- }
13
- }
@@ -1,18 +0,0 @@
1
- --!nonstrict
2
- -- cluaupp-source: ServerScriptService/Boot/DataBoot.server.clpp
3
- -- Compiled by CL++ — C++ × Luau
4
-
5
- -- cluaupp: Roster.new / GetService ReplicatedStorage / self.janitor
6
-
7
- const ReplicatedStorage = game:GetService("ReplicatedStorage")
8
-
9
- const Keep = require(ReplicatedStorage.CluauppLibs.Keep)
10
- const TemplateData = require(ReplicatedStorage.Shared.Constants.Datas.TemplateData)
11
-
12
- -- DataBoot.server.clpp:6
13
- const function init()
14
- local playerData: PlayerTemplate = TemplateData()
15
- Keep.Server:Init({ Template = playerData, StoreName = "PlayerData", UseMock = true })
16
- end
17
-
18
- init()
@@ -1,13 +0,0 @@
1
- {
2
- "version": 1,
3
- "file": "DataBoot.server.luau",
4
- "sourceRoot": "C:/Users/gtofr/OneDrive/Documentos/GitHub/Cluaupp/examples/game",
5
- "sources": [
6
- "ServerScriptService/Boot/DataBoot.server.clpp"
7
- ],
8
- "mappings": "AAAA",
9
- "cluaupp": {
10
- "source": "ServerScriptService/Boot/DataBoot.server.clpp",
11
- "generated": "out/ServerScriptService/Boot/DataBoot.server.luau"
12
- }
13
- }
@@ -1,14 +0,0 @@
1
- --!nonstrict
2
- -- cluaupp-source: ServerScriptService/Configuration/ServerConfig.clp
3
- -- Compiled by CL++ — C++ × Luau
4
-
5
- -- cluaupp: Roster.new / GetService ReplicatedStorage / self.janitor
6
-
7
- const STORE_NAME: string = "PlayerData"
8
-
9
- const USE_MOCK_IN_STUDIO: boolean = true
10
-
11
- return {
12
- STORE_NAME = STORE_NAME,
13
- USE_MOCK_IN_STUDIO = USE_MOCK_IN_STUDIO,
14
- }
@@ -1,13 +0,0 @@
1
- {
2
- "version": 1,
3
- "file": "ServerConfig.luau",
4
- "sourceRoot": "C:/Users/gtofr/OneDrive/Documentos/GitHub/Cluaupp/examples/game",
5
- "sources": [
6
- "ServerScriptService/Configuration/ServerConfig.clp"
7
- ],
8
- "mappings": "AAAA",
9
- "cluaupp": {
10
- "source": "ServerScriptService/Configuration/ServerConfig.clp",
11
- "generated": "out/ServerScriptService/Configuration/ServerConfig.luau"
12
- }
13
- }
@@ -1,15 +0,0 @@
1
- --!nonstrict
2
- -- cluaupp-source: ServerScriptService/Handlers/Guard.server.clpp
3
- -- Compiled by CL++ — C++ × Luau
4
-
5
- const ReplicatedStorage = game:GetService("ReplicatedStorage")
6
- const Ward = require(ReplicatedStorage.CluauppLibs.Ward)
7
-
8
- -- cluaupp: Roster.new / GetService ReplicatedStorage / self.janitor
9
-
10
- -- Guard.server.clpp:5
11
- const function init()
12
- Ward.Start()
13
- end
14
-
15
- init()