cluaupp 0.1.5 → 0.2.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 (101) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +6 -1
  3. package/bin/cluau.js +1 -1
  4. package/bin/cluaupp.js +1 -1
  5. package/docs/architecture.md +26 -1
  6. package/docs/cli.md +27 -6
  7. package/docs/examples/index.md +2 -0
  8. package/docs/getting-started.md +5 -4
  9. package/docs/intellisense.md +49 -31
  10. package/docs/intro.md +1 -1
  11. package/editors/vscode/extension.js +97 -146
  12. package/editors/vscode/package.json +6 -6
  13. package/examples/README.md +18 -0
  14. package/examples/game/.clangd +25 -0
  15. package/examples/game/.vscode/c_cpp_properties.json +27 -0
  16. package/examples/game/.vscode/extensions.json +5 -0
  17. package/examples/game/.vscode/settings.json +27 -0
  18. package/examples/game/Packages/.gitkeep +0 -0
  19. package/examples/game/cluaupp.config.json +6 -0
  20. package/examples/game/compile_flags.txt +6 -0
  21. package/examples/game/default.project.json +39 -0
  22. package/examples/game/package.json +9 -0
  23. package/examples/game/rokit.toml +5 -0
  24. package/examples/game/src/client/hud.client.cpp +12 -0
  25. package/{src → examples/game/src}/client/init.client.cpp +1 -0
  26. package/examples/game/src/server/combat.server.cpp +23 -0
  27. package/{src → examples/game/src}/server/leaderstats.server.cpp +1 -0
  28. package/examples/game/wally.toml +11 -0
  29. package/generated/api.js +51 -0
  30. package/generated/architecture.js +473 -0
  31. package/generated/ast.js +2 -0
  32. package/generated/cli.js +191 -0
  33. package/generated/compile.js +115 -0
  34. package/generated/editor-install.js +170 -0
  35. package/generated/emit.js +503 -0
  36. package/generated/emitter/luau-codegen.js +167 -0
  37. package/generated/emitter/translators.js +164 -0
  38. package/generated/headers.js +220 -0
  39. package/generated/index.html +49 -0
  40. package/generated/intellisense.js +277 -0
  41. package/generated/layout.js +112 -0
  42. package/generated/lex.js +146 -0
  43. package/generated/libs.js +484 -0
  44. package/generated/lsp.js +55 -0
  45. package/generated/package-info.js +11 -0
  46. package/generated/parse.js +607 -0
  47. package/generated/parser/collector.js +100 -0
  48. package/generated/parser/index.js +30 -0
  49. package/generated/preprocess.js +181 -0
  50. package/generated/system-understander.js +443 -0
  51. package/generated/transpile.js +66 -0
  52. package/generated/types.js +2 -0
  53. package/generated/understand.js +298 -0
  54. package/generated/utils/process-orchestrator.js +63 -0
  55. package/generated/utils/project.js +491 -0
  56. package/generated/utils/rojo-mapper.js +181 -0
  57. package/generated/utils/safe-paths.js +104 -0
  58. package/package.json +29 -8
  59. package/src/api.ts +53 -0
  60. package/src/{architecture.js → architecture.ts} +9 -10
  61. package/src/ast.ts +37 -0
  62. package/src/cli.ts +214 -0
  63. package/src/compile.ts +118 -0
  64. package/src/editor-install.ts +182 -0
  65. package/src/{emit.js → emit.ts} +4 -5
  66. package/src/emitter/luau-codegen.ts +187 -0
  67. package/src/emitter/translators.ts +168 -0
  68. package/src/{headers.js → headers.ts} +4 -5
  69. package/src/intellisense.ts +286 -0
  70. package/src/{layout.js → layout.ts} +114 -129
  71. package/src/{lex.js → lex.ts} +4 -6
  72. package/src/{libs.js → libs.ts} +9 -4
  73. package/src/lsp.ts +60 -0
  74. package/src/package-info.ts +7 -0
  75. package/src/{parse.js → parse.ts} +3 -4
  76. package/src/parser/collector.ts +115 -0
  77. package/src/parser/index.ts +27 -0
  78. package/src/{preprocess.js → preprocess.ts} +22 -37
  79. package/src/system-understander.ts +501 -0
  80. package/src/transpile.ts +64 -0
  81. package/src/tree-sitter-cpp.d.ts +4 -0
  82. package/src/types.ts +81 -0
  83. package/src/{understand.js → understand.ts} +19 -210
  84. package/src/utils/process-orchestrator.ts +72 -0
  85. package/src/utils/project.ts +506 -0
  86. package/src/utils/rojo-mapper.ts +190 -0
  87. package/src/utils/safe-paths.ts +98 -0
  88. package/templates/game/.clangd +9 -0
  89. package/templates/game/.vscode/c_cpp_properties.json +1 -1
  90. package/templates/game/.vscode/extensions.json +5 -6
  91. package/templates/game/.vscode/settings.json +7 -6
  92. package/templates/game/compile_flags.txt +1 -0
  93. package/templates/game/rokit.toml +5 -0
  94. package/src/api.js +0 -57
  95. package/src/cli.js +0 -473
  96. package/src/compile.js +0 -110
  97. package/src/editor-install.js +0 -218
  98. package/src/intellisense.js +0 -1368
  99. package/src/lsp.js +0 -227
  100. /package/{src → examples/game/src}/shared/config.cpp +0 -0
  101. /package/{src → examples/game/src}/shared/config.h +0 -0
package/src/cli.js DELETED
@@ -1,473 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require("fs");
4
- const path = require("path");
5
- const { compileService } = require("./compile");
6
- const { isSourceFile, toLuauPath } = require("./preprocess");
7
- const { syncEditorSupport, installEditorSupport } = require("./intellisense");
8
- const pkg = require("../package.json");
9
-
10
- function printHelp() {
11
- console.log(`Cluaupp ${pkg.version} — C++ × Luau
12
-
13
- Usage:
14
- cluaupp init [folder] create a game (src/server, src/client, src/shared)
15
- cluaupp build [folder] transpile src → out (one file per .cpp)
16
- cluaupp watch [folder] rebuild on save
17
- cluaupp lsp [folder] language server (stdio JSON-RPC)
18
- cluaupp intellisense install Cursor/VS Code IntelliSense
19
- cluaupp --version print version
20
- cluaupp --help this help
21
-
22
- Flow: cluaupp init → cluaupp build → rojo serve (plugin in Roblox Studio)
23
- Docs: https://github.com/kartzDev/cluaupp
24
- `);
25
- }
26
-
27
- function copyDir(from, to) {
28
- fs.mkdirSync(to, { recursive: true });
29
- for (const entry of fs.readdirSync(from, { withFileTypes: true })) {
30
- const src = path.join(from, entry.name);
31
- const dest = path.join(to, entry.name);
32
- if (entry.isDirectory()) {
33
- copyDir(src, dest);
34
- } else {
35
- fs.copyFileSync(src, dest);
36
- }
37
- }
38
- }
39
-
40
- function tryRm(target) {
41
- try {
42
- fs.rmSync(target, { recursive: true, force: true });
43
- return true;
44
- } catch (err) {
45
- if (err.code === "EPERM" || err.code === "EBUSY" || err.code === "ENOTEMPTY") {
46
- console.error("cluaupp: skip remove", target, `(${err.code})`);
47
- return false;
48
- }
49
- throw err;
50
- }
51
- }
52
-
53
- function copyFileIfChanged(src, dest, mode = "fill") {
54
- if (mode === "fill" && fs.existsSync(dest)) {
55
- return;
56
- }
57
- if (mode === "update" && fs.existsSync(dest)) {
58
- const from = fs.statSync(src);
59
- const to = fs.statSync(dest);
60
- if (from.size === to.size && from.mtimeMs <= to.mtimeMs) {
61
- return;
62
- }
63
- }
64
- fs.mkdirSync(path.dirname(dest), { recursive: true });
65
- try {
66
- fs.copyFileSync(src, dest);
67
- } catch (err) {
68
- if (err.code === "EPERM" || err.code === "EBUSY") {
69
- console.error("cluaupp: skip copy", dest, `(${err.code})`);
70
- return;
71
- }
72
- throw err;
73
- }
74
- }
75
-
76
- function syncDir(from, to, mode = "fill") {
77
- if (!fs.existsSync(from)) {
78
- return;
79
- }
80
- fs.mkdirSync(to, { recursive: true });
81
- for (const entry of fs.readdirSync(from, { withFileTypes: true })) {
82
- const src = path.join(from, entry.name);
83
- const dest = path.join(to, entry.name);
84
- if (entry.isDirectory()) {
85
- syncDir(src, dest, mode);
86
- } else {
87
- copyFileIfChanged(src, dest, mode);
88
- }
89
- }
90
- }
91
-
92
- function copyRuntime(dest) {
93
- const runtime = path.join(__dirname, "..", "runtime");
94
- if (!fs.existsSync(runtime)) {
95
- return;
96
- }
97
- syncDir(runtime, path.join(dest, "libs"));
98
- }
99
-
100
- function copyHeaders(dest) {
101
- const from = path.join(__dirname, "..", "include", "cluaupp");
102
- if (!fs.existsSync(from)) {
103
- return;
104
- }
105
- syncDir(from, path.join(dest, "include", "cluaupp"));
106
- }
107
-
108
- function loadConfig(root) {
109
- const configNames = ["cluaupp.config.json", "cluau.config.json"];
110
- for (const name of configNames) {
111
- const file = path.join(root, name);
112
- if (fs.existsSync(file)) {
113
- return { rootDir: "src", outDir: "out", strict: false, architecture: false, ...JSON.parse(fs.readFileSync(file, "utf8")) };
114
- }
115
- }
116
- return { rootDir: "src", outDir: "out", strict: false, architecture: false };
117
- }
118
-
119
- function collectCpp(dir, files = []) {
120
- if (!fs.existsSync(dir)) {
121
- return files;
122
- }
123
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
124
- const full = path.join(dir, entry.name);
125
- if (entry.isDirectory()) {
126
- collectCpp(full, files);
127
- } else if (isSourceFile(entry.name)) {
128
- files.push(full);
129
- }
130
- }
131
- return files;
132
- }
133
-
134
- function collectFiles(dir, files = []) {
135
- if (!fs.existsSync(dir)) {
136
- return files;
137
- }
138
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
139
- const full = path.join(dir, entry.name);
140
- if (entry.isDirectory()) {
141
- collectFiles(full, files);
142
- } else {
143
- files.push(full);
144
- }
145
- }
146
- return files;
147
- }
148
-
149
- function resolveKey(file) {
150
- const resolved = path.resolve(file);
151
- return process.platform === "win32" ? resolved.toLowerCase() : resolved;
152
- }
153
-
154
- function posixRel(from, file) {
155
- return path.relative(from, file).replace(/\\/g, "/");
156
- }
157
-
158
- function sourcePrefixes(rel) {
159
- const noExt = rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, "");
160
- const noTag = noExt.replace(/\.(server|client)$/i, "");
161
- return [...new Set([noExt, noTag, toLuauPath(rel).replace(/\\/g, "/")])];
162
- }
163
-
164
- function matchesPrefix(relOut, prefixes) {
165
- const n = relOut.replace(/\\/g, "/").toLowerCase();
166
- return prefixes.some((prefix) => {
167
- const k = prefix.replace(/\\/g, "/").toLowerCase();
168
- return n === k || n === `${k}.luau` || n.startsWith(`${k}/`) || n.startsWith(`${k}.`);
169
- });
170
- }
171
-
172
- function removeEmptyOutDirs(outDir, projectRoot) {
173
- if (!fs.existsSync(outDir)) {
174
- return;
175
- }
176
- const walk = (dir) => {
177
- if (resolveKey(dir) === resolveKey(outDir)) {
178
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
179
- if (entry.isDirectory()) {
180
- walk(path.join(dir, entry.name));
181
- }
182
- }
183
- return;
184
- }
185
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
186
- if (entry.isDirectory()) {
187
- walk(path.join(dir, entry.name));
188
- }
189
- }
190
- if (fs.existsSync(dir) && fs.readdirSync(dir).length === 0) {
191
- if (tryRm(dir)) {
192
- console.log("cluaupp: removed", path.relative(projectRoot, dir));
193
- }
194
- }
195
- };
196
- walk(outDir);
197
- }
198
-
199
- function pruneOut(root, config, written, failedPrefixes) {
200
- const outDir = path.join(root, config.outDir);
201
- if (!fs.existsSync(outDir)) {
202
- return;
203
- }
204
- for (const file of collectFiles(outDir)) {
205
- if (written.has(resolveKey(file))) {
206
- continue;
207
- }
208
- const rel = posixRel(outDir, file);
209
- if (matchesPrefix(rel, failedPrefixes)) {
210
- continue;
211
- }
212
- if (tryRm(file)) {
213
- console.log("cluaupp: removed", path.relative(root, file));
214
- }
215
- }
216
- removeEmptyOutDirs(outDir, root);
217
- }
218
-
219
- function compileProject(root, config) {
220
- const srcDir = path.join(root, config.rootDir);
221
- const files = collectCpp(srcDir);
222
- const jobs = [];
223
- const errors = [];
224
-
225
- for (const file of files) {
226
- const source = fs.readFileSync(file, "utf8");
227
- const rel = posixRel(srcDir, file);
228
- try {
229
- const result = compileService(source, rel, {
230
- ...config,
231
- filePath: file,
232
- relativeName: rel,
233
- outName: toLuauPath(rel),
234
- architecture: config.architecture === true,
235
- includeDirs: [path.dirname(file), srcDir, path.join(root, "include")],
236
- srcDir,
237
- });
238
- jobs.push({ rel, files: result.files, stale: result.stale || [] });
239
- } catch (err) {
240
- errors.push({ rel, prefixes: sourcePrefixes(rel), message: err.message });
241
- }
242
- }
243
-
244
- return { files, jobs, errors };
245
- }
246
-
247
- function writeTextIfChanged(dest, contents) {
248
- if (fs.existsSync(dest) && fs.readFileSync(dest, "utf8") === contents) {
249
- return false;
250
- }
251
- fs.mkdirSync(path.dirname(dest), { recursive: true });
252
- fs.writeFileSync(dest, contents, "utf8");
253
- return true;
254
- }
255
-
256
- function writeJobs(root, config, jobs) {
257
- const written = new Set();
258
- for (const job of jobs) {
259
- for (const artifact of job.files) {
260
- const dest = path.join(root, config.outDir, artifact.name);
261
- const changed = writeTextIfChanged(dest, artifact.contents);
262
- written.add(resolveKey(dest));
263
- if (changed) {
264
- console.log("cluaupp:", job.rel, "→", path.relative(root, dest));
265
- }
266
- }
267
- for (const stale of job.stale) {
268
- const dest = path.join(root, config.outDir, stale);
269
- if (fs.existsSync(dest) && !written.has(resolveKey(dest))) {
270
- if (tryRm(dest)) {
271
- console.log("cluaupp: removed", path.relative(root, dest));
272
- }
273
- }
274
- }
275
- }
276
- return written;
277
- }
278
-
279
- function libsPresent(root) {
280
- const libs = path.join(root, "libs");
281
- return fs.existsSync(libs) && fs.readdirSync(libs).length > 0;
282
- }
283
-
284
- function ensureVendor(root) {
285
- copyRuntime(root);
286
- copyHeaders(root);
287
- }
288
-
289
- function build(root, options = {}) {
290
- const exitOnError = options.exitOnError !== false;
291
- const holdOnError = options.holdOnError === true;
292
- const config = loadConfig(root);
293
- if (options.syncVendor !== false) {
294
- ensureVendor(root);
295
- }
296
- const srcDir = path.join(root, config.rootDir);
297
- if (!fs.existsSync(srcDir) || collectCpp(srcDir).length === 0) {
298
- console.error("no .cpp/.h/.hpp files in", config.rootDir);
299
- if (!holdOnError) {
300
- pruneOut(root, config, new Set(), []);
301
- }
302
- if (exitOnError) {
303
- process.exit(1);
304
- }
305
- return { failed: 0, written: new Set() };
306
- }
307
-
308
- const compiled = compileProject(root, config);
309
- if (compiled.errors.length > 0) {
310
- for (const err of compiled.errors) {
311
- console.error(err.message);
312
- }
313
- if (holdOnError) {
314
- console.error(`cluaupp: out not updated (${compiled.errors.length} compile error${compiled.errors.length === 1 ? "" : "s"})`);
315
- try {
316
- syncEditorSupport(root, config);
317
- } catch (err) {
318
- console.error("cluaupp: intellisense sync failed", err.message);
319
- }
320
- return { failed: compiled.errors.length, written: new Set() };
321
- }
322
- }
323
-
324
- const written = writeJobs(root, config, compiled.jobs);
325
- const failedPrefixes = compiled.errors.flatMap((err) => err.prefixes);
326
- pruneOut(root, config, written, failedPrefixes);
327
- try {
328
- syncEditorSupport(root, config);
329
- } catch (err) {
330
- console.error("cluaupp: intellisense sync failed", err.message);
331
- }
332
- if (compiled.errors.length > 0 && exitOnError) {
333
- process.exit(1);
334
- }
335
- return { failed: compiled.errors.length, written };
336
- }
337
-
338
- async function init(dest) {
339
- const template = path.join(__dirname, "..", "templates", "game");
340
- const include = path.join(__dirname, "..", "include");
341
- copyDir(template, dest);
342
- copyDir(include, path.join(dest, "include"));
343
- copyRuntime(dest);
344
- syncEditorSupport(dest);
345
- const installed = await installEditorSupport();
346
- console.log("Cluaupp ready in", dest);
347
- console.log(" cluaupp build");
348
- console.log(" rojo serve");
349
- if (installed.local.length || (installed.cpp && installed.cpp.status === "installed")) {
350
- console.log(" reload Cursor (Ctrl+Shift+P → Developer: Reload Window)");
351
- }
352
- }
353
-
354
- function pidAlive(pid) {
355
- try {
356
- process.kill(pid, 0);
357
- return true;
358
- } catch {
359
- return false;
360
- }
361
- }
362
-
363
- function acquireWatchLock(root) {
364
- const file = path.join(root, ".cluaupp-watch.lock");
365
- if (fs.existsSync(file)) {
366
- const pid = Number(fs.readFileSync(file, "utf8").trim());
367
- if (Number.isFinite(pid) && pid !== process.pid && pidAlive(pid)) {
368
- console.error(`cluaupp: watch already running (pid ${pid}). Stop it first — two watchers make Rojo crash on libs/.`);
369
- process.exit(1);
370
- }
371
- }
372
- fs.writeFileSync(file, String(process.pid), "utf8");
373
- const release = () => {
374
- try {
375
- if (fs.existsSync(file) && fs.readFileSync(file, "utf8").trim() === String(process.pid)) {
376
- fs.unlinkSync(file);
377
- }
378
- } catch {
379
- // ignore
380
- }
381
- };
382
- process.on("exit", release);
383
- process.on("SIGINT", () => {
384
- release();
385
- process.exit(0);
386
- });
387
- process.on("SIGTERM", () => {
388
- release();
389
- process.exit(0);
390
- });
391
- }
392
-
393
- function watch(root) {
394
- acquireWatchLock(root);
395
- build(root, { exitOnError: false, syncVendor: false, holdOnError: true });
396
- const config = loadConfig(root);
397
- const dir = path.join(root, config.rootDir);
398
- let timer = null;
399
- let running = false;
400
- let queued = false;
401
-
402
- const run = () => {
403
- if (running) {
404
- queued = true;
405
- return;
406
- }
407
- running = true;
408
- try {
409
- build(root, { exitOnError: false, syncVendor: false, holdOnError: true });
410
- } catch (err) {
411
- console.error(err.message);
412
- } finally {
413
- running = false;
414
- if (queued) {
415
- queued = false;
416
- run();
417
- }
418
- }
419
- };
420
-
421
- console.log("cluaupp", pkg.version, "watching", dir, "(libs untouched)");
422
- if (!fs.existsSync(dir)) {
423
- fs.mkdirSync(dir, { recursive: true });
424
- }
425
- fs.watch(dir, { recursive: true }, () => {
426
- clearTimeout(timer);
427
- timer = setTimeout(run, 400);
428
- });
429
- }
430
-
431
- function dispatch(args) {
432
- const cmd = args[0] || "help";
433
- const cwd = process.cwd();
434
- if (cmd === "init") {
435
- return init(path.resolve(cwd, args[1] || ".")).catch((err) => {
436
- console.error(err.message || err);
437
- process.exit(1);
438
- });
439
- } else if (cmd === "build") {
440
- build(path.resolve(cwd, args[1] || "."));
441
- } else if (cmd === "watch") {
442
- watch(path.resolve(cwd, args[1] || "."));
443
- } else if (cmd === "lsp") {
444
- const { start } = require("./lsp");
445
- start({ projectRoot: path.resolve(cwd, args[1] || ".") });
446
- } else if (cmd === "intellisense" || cmd === "intelisense") {
447
- const root = path.resolve(cwd, args[1] || ".");
448
- syncEditorSupport(root, loadConfig(root));
449
- return installEditorSupport().then((installed) => {
450
- console.log("cluaupp: compile_commands.json, .clangd, and .vscode updated in", root);
451
- if (installed.local.length) {
452
- for (const dest of installed.local) {
453
- console.log("cluaupp: Cluaupp IntelliSense", dest);
454
- }
455
- }
456
- }).catch((err) => {
457
- console.error(err.message || err);
458
- process.exit(1);
459
- });
460
- } else if (cmd === "--version" || cmd === "-v" || cmd === "version") {
461
- console.log(pkg.version);
462
- } else {
463
- printHelp();
464
- }
465
- }
466
-
467
- const launchedAsCli =
468
- require.main && ["cli.js", "cluaupp.js", "cluau.js"].includes(path.basename(require.main.filename));
469
- if (launchedAsCli) {
470
- dispatch(process.argv.slice(2));
471
- }
472
-
473
- module.exports = { build, watch, dispatch };
package/src/compile.js DELETED
@@ -1,110 +0,0 @@
1
- "use strict";
2
-
3
- const path = require("path");
4
- const { parse } = require("./parse");
5
- const { emit } = require("./emit");
6
- const { preprocess, isHeaderFile, toLuauPath, siblingImplementation, siblingHeader, implOutName } = require("./preprocess");
7
- const { collectLibraries, insertPreamble } = require("./libs");
8
- const { planOutput } = require("./architecture");
9
- const { emitHeaderModule, primaryHeaderName } = require("./headers");
10
-
11
- function shouldAttachRequires(name) {
12
- return !/\.(json)$/i.test(String(name || ""));
13
- }
14
-
15
- function attachRequires(contents, source, ast, options, outName) {
16
- if (!shouldAttachRequires(outName)) {
17
- return contents;
18
- }
19
- const libraries = String(contents).includes("CluauppLibs") ? [] : collectLibraries(source, ast);
20
- return insertPreamble(contents, options.moduleIncludes || [], libraries, outName);
21
- }
22
-
23
- function posixRel(from, file) {
24
- return path.relative(from, file).replace(/\\/g, "/");
25
- }
26
-
27
- function wireHeaderImpl(ast, fileName, options) {
28
- const headerPath = options.filePath || null;
29
- const impl = headerPath ? siblingImplementation(headerPath) : null;
30
- if (!impl) {
31
- return;
32
- }
33
- const typeName = primaryHeaderName(ast, options.relativeName || fileName);
34
- const implRel = options.srcDir ? posixRel(options.srcDir, impl) : path.basename(impl).replace(/\\/g, "/");
35
- const implOut = implOutName(implRel);
36
- options.headerImplName = `${typeName}Module`;
37
- options.moduleIncludes = options.moduleIncludes || [];
38
- if (!options.moduleIncludes.some((spec) => spec.name === options.headerImplName)) {
39
- options.moduleIncludes.push({
40
- name: options.headerImplName,
41
- outRel: implOut,
42
- exports: { consts: [], structs: [] },
43
- });
44
- }
45
- }
46
-
47
- function compileHeader(source, fileName, options, prepared, ast) {
48
- wireHeaderImpl(ast, fileName, options);
49
- const rel = (options.relativeName || fileName || "header.h").replace(/\\/g, "/");
50
- const outName = toLuauPath(rel);
51
- const luau = attachRequires(emitHeaderModule(ast, options), source, ast, options, outName);
52
- return {
53
- kind: "module",
54
- plan: { kind: "module", strict: options.strict === true },
55
- files: [{ name: outName, contents: luau }],
56
- stale: [],
57
- };
58
- }
59
-
60
- function compileSource(source, fileName, options = {}) {
61
- options.moduleIncludes = options.moduleIncludes || [];
62
- const prepared = preprocess(source, options.filePath || null, options);
63
- const ast = parse(prepared, fileName || "input.cpp");
64
- if (isHeaderFile(fileName) || isHeaderFile(options.filePath || "")) {
65
- return compileHeader(source, fileName, options, prepared, ast).files[0].contents;
66
- }
67
- const luau = emit(ast, options);
68
- return attachRequires(luau, source, ast, options, options.outName || fileName);
69
- }
70
-
71
- function compileService(source, fileName, options = {}) {
72
- options.moduleIncludes = options.moduleIncludes || [];
73
- const prepared = preprocess(source, options.filePath || null, options);
74
- const ast = parse(prepared, fileName || "input.cpp");
75
- if (isHeaderFile(fileName) || isHeaderFile(options.filePath || "") || isHeaderFile(options.relativeName || "")) {
76
- return compileHeader(source, fileName, options, prepared, ast);
77
- }
78
- const implHeader = options.filePath ? siblingHeader(options.filePath) : null;
79
- if (implHeader) {
80
- options.skipInit = true;
81
- }
82
- const planned = planOutput(ast, fileName || "input.cpp", {
83
- ...options,
84
- relativeName: options.relativeName || fileName,
85
- source: prepared,
86
- siblingHeader: implHeader,
87
- });
88
- if (planned.files) {
89
- return {
90
- ...planned,
91
- files: planned.files.map((file) => ({
92
- ...file,
93
- contents: attachRequires(file.contents, source, ast, options, file.name),
94
- })),
95
- };
96
- }
97
- const luau = attachRequires(emit(ast, options), source, ast, options, planned.outName || options.outName || fileName);
98
- const name =
99
- planned.outName ||
100
- options.outName ||
101
- String(fileName || "input.cpp").replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau");
102
- return {
103
- kind: planned.kind || "flat",
104
- plan: planned.plan,
105
- files: [{ name, contents: luau }],
106
- stale: planned.stale || [],
107
- };
108
- }
109
-
110
- module.exports = { compileSource, compileService };