cluaupp 0.2.2 → 1.0.0
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.
- package/CHANGELOG.md +14 -75
- package/README.md +42 -88
- package/docs/README.md +25 -21
- package/docs/architecture.md +13 -76
- package/docs/cli.md +12 -64
- package/docs/comparison.md +6 -24
- package/docs/config.md +6 -7
- package/docs/cpp-advanced.md +6 -3
- package/docs/cpp-types.md +2 -0
- package/docs/examples/combat.md +19 -227
- package/docs/examples/hud.md +13 -81
- package/docs/examples/index.md +9 -16
- package/docs/examples/leaderstats.md +44 -115
- package/docs/getting-started.md +20 -135
- package/docs/intellisense.md +5 -42
- package/docs/intro.md +16 -15
- package/docs/libraries/dataservice.md +4 -1
- package/docs/libraries/index.md +2 -1
- package/docs/libraries/more.md +3 -1
- package/docs/libraries/ui.md +76 -0
- package/docs/migration.md +38 -0
- package/docs/oop/file-tags.md +12 -36
- package/docs/oop/index.md +18 -11
- package/docs/roblox-api.md +4 -56
- package/docs/syntax.md +54 -179
- package/editors/vscode/extension.js +1 -1
- package/editors/vscode/package.json +4 -4
- package/examples/README.md +5 -7
- package/examples/game/.vscode/extensions.json +2 -2
- package/examples/game/.vscode/settings.json +6 -23
- package/examples/game/src/client/hud.client.clpp +54 -0
- package/examples/game/src/client/init.client.clpp +6 -0
- package/examples/game/src/server/combat.server.clpp +85 -0
- package/examples/game/src/server/leaderstats.server.clpp +28 -0
- package/examples/game/src/shared/PlayerData.clh +20 -0
- package/examples/game/src/shared/config.clp +6 -0
- package/examples/game/src/shared/features.clp +88 -0
- package/generated/api.js +15 -1
- package/generated/cli.js +40 -24
- package/generated/clpp/contract.js +5 -0
- package/generated/clpp/index.js +27 -0
- package/generated/clpp/paths.js +121 -0
- package/generated/clpp/postprocess.js +78 -0
- package/generated/clpp/runner.js +102 -0
- package/generated/compile.js +26 -138
- package/generated/emit.js +79 -3
- package/generated/intellisense.js +83 -207
- package/generated/lex.js +3 -0
- package/generated/libs.js +1 -1
- package/generated/lsp.js +1 -8
- package/generated/parse.js +119 -24
- package/generated/preprocess.js +8 -179
- package/generated/system-understander.js +1 -1
- package/generated/transpile.js +3 -50
- package/generated/utils/project.js +13 -28
- package/include/{cluaupp/datatypes.hpp → clpp/datatypes.clh} +5 -1
- package/include/{cluaupp/generated/instances.hpp → clpp/generated/instances.clh} +1 -1
- package/include/{cluaupp/libs/chrono.hpp → clpp/libs/chrono.clh} +9 -9
- package/include/{cluaupp/libs/cmdr.hpp → clpp/libs/cmdr.clh} +4 -4
- package/include/{cluaupp/libs/dataservice.hpp → clpp/libs/dataservice.clh} +8 -15
- package/include/{cluaupp/libs/display.hpp → clpp/libs/display.clh} +1 -2
- package/include/{cluaupp/libs/ezvisual.hpp → clpp/libs/ezvisual.clh} +1 -3
- package/include/{cluaupp/libs/formatnumber.hpp → clpp/libs/formatnumber.clh} +2 -3
- package/include/{cluaupp/libs/fusion.hpp → clpp/libs/fusion.clh} +5 -5
- package/include/{cluaupp/libs/iris.hpp → clpp/libs/iris.clh} +2 -2
- package/include/{cluaupp/libs/janitor.hpp → clpp/libs/janitor.clh} +1 -2
- package/include/{cluaupp/libs/module3d.hpp → clpp/libs/module3d.clh} +2 -4
- package/include/{cluaupp/libs/net.hpp → clpp/libs/net.clh} +2 -4
- package/include/{cluaupp/libs/promise.hpp → clpp/libs/promise.clh} +1 -4
- package/include/{cluaupp/libs/spring.hpp → clpp/libs/spring.clh} +1 -2
- package/include/{cluaupp/libs/statemachine.hpp → clpp/libs/statemachine.clh} +2 -3
- package/include/{cluaupp/libs/stickybillboard.hpp → clpp/libs/stickybillboard.clh} +1 -2
- package/include/{cluaupp/libs/topbarplus.hpp → clpp/libs/topbarplus.clh} +3 -4
- package/include/clpp/libs.clh +24 -0
- package/include/clpp/roblox.clh +31 -0
- package/package.json +20 -16
- package/src/api.ts +15 -1
- package/src/cli.ts +39 -25
- package/src/clpp/contract.ts +39 -0
- package/src/clpp/index.ts +18 -0
- package/src/clpp/paths.ts +117 -0
- package/src/clpp/postprocess.ts +93 -0
- package/src/clpp/runner.ts +102 -0
- package/src/compile.ts +26 -149
- package/src/intellisense.ts +82 -211
- package/src/libs.ts +1 -1
- package/src/lsp.ts +1 -5
- package/src/preprocess.ts +8 -180
- package/src/system-understander.ts +1 -1
- package/src/transpile.ts +9 -52
- package/src/utils/project.ts +12 -28
- package/templates/game/.vscode/extensions.json +2 -2
- package/templates/game/.vscode/settings.json +6 -23
- package/templates/game/src/client/init.client.clpp +6 -0
- package/templates/game/src/server/leaderstats.server.clpp +29 -0
- package/templates/game/src/shared/config.clp +6 -0
- package/examples/game/.clangd +0 -25
- package/examples/game/.vscode/c_cpp_properties.json +0 -27
- package/examples/game/compile_flags.txt +0 -6
- package/examples/game/src/client/hud.client.cpp +0 -12
- package/examples/game/src/client/init.client.cpp +0 -6
- package/examples/game/src/server/combat.server.cpp +0 -23
- package/examples/game/src/server/leaderstats.server.cpp +0 -29
- package/examples/game/src/shared/config.cpp +0 -5
- package/examples/game/src/shared/config.h +0 -5
- package/include/cluaupp/libs.hpp +0 -25
- package/include/cluaupp/roblox.hpp +0 -47
- package/src/architecture.ts +0 -500
- package/src/ast.ts +0 -37
- package/src/emit.ts +0 -531
- package/src/emitter/luau-codegen.ts +0 -187
- package/src/emitter/translators.ts +0 -168
- package/src/headers.ts +0 -233
- package/src/layout.ts +0 -114
- package/src/lex.ts +0 -155
- package/src/parse.ts +0 -630
- package/src/parser/collector.ts +0 -148
- package/src/parser/index.ts +0 -27
- package/src/tree-sitter-cpp.d.ts +0 -4
- package/src/understand.ts +0 -322
- package/templates/game/.vscode/c_cpp_properties.json +0 -27
- package/templates/game/src/client/init.client.cpp +0 -6
- package/templates/game/src/server/leaderstats.server.cpp +0 -29
- package/templates/game/src/shared/config.cpp +0 -5
- package/templates/game/src/shared/config.h +0 -5
- /package/include/{cluaupp/generated/enums.hpp → clpp/generated/enums.clh} +0 -0
- /package/include/{cluaupp/libs/math.hpp → clpp/libs/math.clh} +0 -0
- /package/include/{cluaupp/libs/twinkle.hpp → clpp/libs/twinkle.clh} +0 -0
- /package/include/{cluaupp/libs/vfx.hpp → clpp/libs/vfx.clh} +0 -0
package/generated/api.js
CHANGED
|
@@ -43,9 +43,23 @@ function luauType(name) {
|
|
|
43
43
|
if (!name) {
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
|
-
const cleaned = String(name)
|
|
46
|
+
const cleaned = String(name)
|
|
47
|
+
.replace(/\*+$/, "")
|
|
48
|
+
.replace(/^const\s+/, "")
|
|
49
|
+
.replace(/^Enum::/, "Enum.")
|
|
50
|
+
.replace(/\s+/g, " ")
|
|
51
|
+
.trim();
|
|
47
52
|
if (cleaned in LUAU_TYPES) {
|
|
48
53
|
return LUAU_TYPES[cleaned];
|
|
49
54
|
}
|
|
55
|
+
const generic = cleaned.match(/^(?:std::)?(?:vector|array|span|LuaArray)\s*<\s*([^>]+)\s*>$/);
|
|
56
|
+
if (generic) {
|
|
57
|
+
const inner = luauType(generic[1]) || generic[1];
|
|
58
|
+
return `{${inner}}`;
|
|
59
|
+
}
|
|
60
|
+
const optional = cleaned.match(/^(?:std::)?optional\s*<\s*([^>]+)\s*>$/);
|
|
61
|
+
if (optional) {
|
|
62
|
+
return `${luauType(optional[1]) || optional[1]}?`;
|
|
63
|
+
}
|
|
50
64
|
return cleaned;
|
|
51
65
|
}
|
package/generated/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.program = exports.init = exports.watch = void 0;
|
|
6
|
+
exports.hasClpp = exports.program = exports.init = exports.watch = void 0;
|
|
7
7
|
exports.build = build;
|
|
8
8
|
exports.dispatch = dispatch;
|
|
9
9
|
const commander_1 = require("commander");
|
|
@@ -11,7 +11,10 @@ const promises_1 = __importDefault(require("node:fs/promises"));
|
|
|
11
11
|
const node_path_1 = __importDefault(require("node:path"));
|
|
12
12
|
const package_info_js_1 = require("./package-info.js");
|
|
13
13
|
const lsp_js_1 = require("./lsp.js");
|
|
14
|
-
const
|
|
14
|
+
const paths_js_1 = require("./clpp/paths.js");
|
|
15
|
+
const contract_js_1 = require("./clpp/contract.js");
|
|
16
|
+
const runner_js_1 = require("./clpp/runner.js");
|
|
17
|
+
Object.defineProperty(exports, "hasClpp", { enumerable: true, get: function () { return runner_js_1.hasClpp; } });
|
|
15
18
|
const intellisense_js_1 = require("./intellisense.js");
|
|
16
19
|
const rojo_mapper_js_1 = require("./utils/rojo-mapper.js");
|
|
17
20
|
const process_orchestrator_js_1 = require("./utils/process-orchestrator.js");
|
|
@@ -23,7 +26,7 @@ const program = new commander_1.Command();
|
|
|
23
26
|
exports.program = program;
|
|
24
27
|
program
|
|
25
28
|
.name("cluaupp")
|
|
26
|
-
.description("
|
|
29
|
+
.description("Cluaupp toolchain — compile CL++ to Luau, Rojo, and CluauppLibs")
|
|
27
30
|
.version(package_info_js_1.pkg.version, "-v, --version", "print version")
|
|
28
31
|
.showHelpAfterError()
|
|
29
32
|
.action(() => {
|
|
@@ -44,14 +47,14 @@ program
|
|
|
44
47
|
});
|
|
45
48
|
program
|
|
46
49
|
.command("build")
|
|
47
|
-
.description("
|
|
50
|
+
.description("Compile a CL++ file, directory, or project to Luau")
|
|
48
51
|
.argument("[folder]", "project folder", ".")
|
|
49
|
-
.option("-i, --input <path>", "
|
|
50
|
-
.option("-o, --output <path>", "
|
|
51
|
-
.option("-r, --rojo <path>", "
|
|
52
|
-
.option("--strict", "
|
|
53
|
-
.option("--format", "
|
|
54
|
-
.option("--analyze", "
|
|
52
|
+
.option("-i, --input <path>", "CL++ file or directory")
|
|
53
|
+
.option("-o, --output <path>", "Luau file or directory")
|
|
54
|
+
.option("-r, --rojo <path>", "Path to Rojo default.project.json", "./default.project.json")
|
|
55
|
+
.option("--strict", "Emit --!strict")
|
|
56
|
+
.option("--format", "Run StyLua on output")
|
|
57
|
+
.option("--analyze", "Run luau-analyze on output")
|
|
55
58
|
.action(async (folder, options) => {
|
|
56
59
|
if (options.input) {
|
|
57
60
|
await buildInput(options);
|
|
@@ -73,8 +76,8 @@ program
|
|
|
73
76
|
.command("watch")
|
|
74
77
|
.description("rebuild on save")
|
|
75
78
|
.argument("[folder]", "project folder", ".")
|
|
76
|
-
.option("-r, --rojo <path>", "
|
|
77
|
-
.option("--format", "
|
|
79
|
+
.option("-r, --rojo <path>", "Path to Rojo default.project.json", "./default.project.json")
|
|
80
|
+
.option("--format", "Run StyLua on output")
|
|
78
81
|
.action((folder, options) => {
|
|
79
82
|
try {
|
|
80
83
|
(0, project_js_1.watch)(node_path_1.default.resolve(process.cwd(), folder), {
|
|
@@ -89,7 +92,7 @@ program
|
|
|
89
92
|
});
|
|
90
93
|
program
|
|
91
94
|
.command("lsp")
|
|
92
|
-
.description("
|
|
95
|
+
.description("Language server stdio (JSON-RPC). Use `clpp install` for CL++ IntelliSense.")
|
|
93
96
|
.argument("[folder]", "project folder", ".")
|
|
94
97
|
.action((folder) => {
|
|
95
98
|
(0, lsp_js_1.start)({ projectRoot: node_path_1.default.resolve(process.cwd(), folder) });
|
|
@@ -97,18 +100,32 @@ program
|
|
|
97
100
|
program
|
|
98
101
|
.command("intellisense")
|
|
99
102
|
.alias("intelisense")
|
|
100
|
-
.description("
|
|
103
|
+
.description("Point the editor at CL++ (`clpp install`)")
|
|
101
104
|
.argument("[folder]", "project folder", ".")
|
|
102
105
|
.action(async (folder) => {
|
|
103
106
|
try {
|
|
104
107
|
const root = node_path_1.default.resolve(process.cwd(), folder);
|
|
105
108
|
(0, intellisense_js_1.syncEditorSupport)(root, (0, project_js_1.loadConfig)(root));
|
|
106
|
-
|
|
107
|
-
console.log("cluaupp:
|
|
108
|
-
console.log("cluaupp:
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
await (0, intellisense_js_1.installEditorSupport)();
|
|
110
|
+
console.log("cluaupp: editor associations written in", root);
|
|
111
|
+
console.log("cluaupp:", contract_js_1.CLPP_INSTALL_HINT);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error(err instanceof Error ? err.message : err);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
program
|
|
119
|
+
.command("language")
|
|
120
|
+
.description("CL++ manifest (`clpp api manifest`)")
|
|
121
|
+
.action(() => {
|
|
122
|
+
try {
|
|
123
|
+
(0, runner_js_1.resolveClppBinary)();
|
|
124
|
+
const version = (0, runner_js_1.clppVersion)();
|
|
125
|
+
if (version) {
|
|
126
|
+
console.log("clpp", version);
|
|
111
127
|
}
|
|
128
|
+
console.log(JSON.stringify((0, runner_js_1.clppManifest)(), null, "\t"));
|
|
112
129
|
}
|
|
113
130
|
catch (err) {
|
|
114
131
|
console.error(err instanceof Error ? err.message : err);
|
|
@@ -129,14 +146,13 @@ async function buildInput(options) {
|
|
|
129
146
|
console.error(`[Erro] O caminho de entrada especificado não existe: ${inputPath}`);
|
|
130
147
|
process.exit(1);
|
|
131
148
|
}
|
|
132
|
-
console.log("🏁 Inicializando Pipeline do Compilador Cluaupp V2...");
|
|
133
149
|
const mapper = new rojo_mapper_js_1.RojoMapper(node_path_1.default.resolve(options.rojo), node_path_1.default.dirname(inputPath));
|
|
134
150
|
await mapper.load();
|
|
135
151
|
const inputs = (await promises_1.default.stat(inputPath)).isDirectory()
|
|
136
|
-
? (0,
|
|
152
|
+
? (0, paths_js_1.collectSources)(inputPath)
|
|
137
153
|
: [inputPath];
|
|
138
154
|
if (inputs.length === 0) {
|
|
139
|
-
console.error("no .
|
|
155
|
+
console.error("no .clpp/.clp/.clh files in", inputPath);
|
|
140
156
|
process.exit(1);
|
|
141
157
|
}
|
|
142
158
|
const outputIsFile = /\.luau$/i.test(outputPath);
|
|
@@ -154,7 +170,7 @@ async function buildInput(options) {
|
|
|
154
170
|
srcDir: node_path_1.default.dirname(file),
|
|
155
171
|
includeDirs: [node_path_1.default.dirname(file)],
|
|
156
172
|
}, mapper);
|
|
157
|
-
const dest = outputIsFile ? outputPath : node_path_1.default.join(outputPath, node_path_1.default.basename((0,
|
|
173
|
+
const dest = outputIsFile ? outputPath : node_path_1.default.join(outputPath, node_path_1.default.basename((0, paths_js_1.toLuauPath)(rel)));
|
|
158
174
|
await promises_1.default.mkdir(node_path_1.default.dirname(dest), { recursive: true });
|
|
159
175
|
const luau = compiled.files[0]?.contents ?? "";
|
|
160
176
|
await promises_1.default.writeFile(dest, luau, "utf8");
|
|
@@ -167,7 +183,7 @@ async function buildInput(options) {
|
|
|
167
183
|
console.log("\nRelatório de Análise Estática do Luau:\n", analysisReport);
|
|
168
184
|
}
|
|
169
185
|
}
|
|
170
|
-
console.log(`
|
|
186
|
+
console.log(`Compiled ${file} → ${dest}`);
|
|
171
187
|
}
|
|
172
188
|
}
|
|
173
189
|
function build(root, options = {}) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Stable CL++ ↔ Cluaupp contract. Cluaupp invokes the `clpp` binary. */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.CLPP_INSTALL_HINT = void 0;
|
|
5
|
+
exports.CLPP_INSTALL_HINT = "Install CL++ and put `clpp` on PATH: https://github.com/KartzRbx/CLPP (`cargo install --path .` then `clpp install`). Override with CLPP_PATH.";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.toLuauPath = exports.siblingHeader = exports.scriptKind = exports.isTaggedScript = exports.isSourceFile = exports.isImplFile = exports.isHeaderFile = exports.isEngineStub = exports.fileStem = exports.emitKind = exports.collectSources = exports.SOURCE_EXTS = exports.shouldSkipInit = exports.clppLuauToGame = exports.resolveClppBinary = exports.hasClpp = exports.clppVersion = exports.clppManifest = exports.compileViaClpp = exports.CLPP_INSTALL_HINT = void 0;
|
|
4
|
+
var contract_js_1 = require("./contract.js");
|
|
5
|
+
Object.defineProperty(exports, "CLPP_INSTALL_HINT", { enumerable: true, get: function () { return contract_js_1.CLPP_INSTALL_HINT; } });
|
|
6
|
+
var runner_js_1 = require("./runner.js");
|
|
7
|
+
Object.defineProperty(exports, "compileViaClpp", { enumerable: true, get: function () { return runner_js_1.compileViaClpp; } });
|
|
8
|
+
Object.defineProperty(exports, "clppManifest", { enumerable: true, get: function () { return runner_js_1.clppManifest; } });
|
|
9
|
+
Object.defineProperty(exports, "clppVersion", { enumerable: true, get: function () { return runner_js_1.clppVersion; } });
|
|
10
|
+
Object.defineProperty(exports, "hasClpp", { enumerable: true, get: function () { return runner_js_1.hasClpp; } });
|
|
11
|
+
Object.defineProperty(exports, "resolveClppBinary", { enumerable: true, get: function () { return runner_js_1.resolveClppBinary; } });
|
|
12
|
+
var postprocess_js_1 = require("./postprocess.js");
|
|
13
|
+
Object.defineProperty(exports, "clppLuauToGame", { enumerable: true, get: function () { return postprocess_js_1.clppLuauToGame; } });
|
|
14
|
+
Object.defineProperty(exports, "shouldSkipInit", { enumerable: true, get: function () { return postprocess_js_1.shouldSkipInit; } });
|
|
15
|
+
var paths_js_1 = require("./paths.js");
|
|
16
|
+
Object.defineProperty(exports, "SOURCE_EXTS", { enumerable: true, get: function () { return paths_js_1.SOURCE_EXTS; } });
|
|
17
|
+
Object.defineProperty(exports, "collectSources", { enumerable: true, get: function () { return paths_js_1.collectSources; } });
|
|
18
|
+
Object.defineProperty(exports, "emitKind", { enumerable: true, get: function () { return paths_js_1.emitKind; } });
|
|
19
|
+
Object.defineProperty(exports, "fileStem", { enumerable: true, get: function () { return paths_js_1.fileStem; } });
|
|
20
|
+
Object.defineProperty(exports, "isEngineStub", { enumerable: true, get: function () { return paths_js_1.isEngineStub; } });
|
|
21
|
+
Object.defineProperty(exports, "isHeaderFile", { enumerable: true, get: function () { return paths_js_1.isHeaderFile; } });
|
|
22
|
+
Object.defineProperty(exports, "isImplFile", { enumerable: true, get: function () { return paths_js_1.isImplFile; } });
|
|
23
|
+
Object.defineProperty(exports, "isSourceFile", { enumerable: true, get: function () { return paths_js_1.isSourceFile; } });
|
|
24
|
+
Object.defineProperty(exports, "isTaggedScript", { enumerable: true, get: function () { return paths_js_1.isTaggedScript; } });
|
|
25
|
+
Object.defineProperty(exports, "scriptKind", { enumerable: true, get: function () { return paths_js_1.scriptKind; } });
|
|
26
|
+
Object.defineProperty(exports, "siblingHeader", { enumerable: true, get: function () { return paths_js_1.siblingHeader; } });
|
|
27
|
+
Object.defineProperty(exports, "toLuauPath", { enumerable: true, get: function () { return paths_js_1.toLuauPath; } });
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SOURCE_EXTS = void 0;
|
|
7
|
+
exports.isSourceFile = isSourceFile;
|
|
8
|
+
exports.isEngineStub = isEngineStub;
|
|
9
|
+
exports.isHeaderFile = isHeaderFile;
|
|
10
|
+
exports.isImplFile = isImplFile;
|
|
11
|
+
exports.toLuauPath = toLuauPath;
|
|
12
|
+
exports.fileStem = fileStem;
|
|
13
|
+
exports.scriptKind = scriptKind;
|
|
14
|
+
exports.emitKind = emitKind;
|
|
15
|
+
exports.isTaggedScript = isTaggedScript;
|
|
16
|
+
exports.siblingHeader = siblingHeader;
|
|
17
|
+
exports.collectSources = collectSources;
|
|
18
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
19
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
+
exports.SOURCE_EXTS = [".clpp", ".clp", ".clh"];
|
|
21
|
+
function isSourceFile(fileName) {
|
|
22
|
+
return exports.SOURCE_EXTS.includes(node_path_1.default.extname(fileName).toLowerCase());
|
|
23
|
+
}
|
|
24
|
+
function isEngineStub(filePath) {
|
|
25
|
+
const normalized = filePath.replace(/\\/g, "/").toLowerCase();
|
|
26
|
+
return (normalized.includes("/include/cluaupp/") ||
|
|
27
|
+
normalized.includes("/include/clpp/") ||
|
|
28
|
+
normalized.includes("/include/cluau/") ||
|
|
29
|
+
normalized.includes("/stdlib/") ||
|
|
30
|
+
normalized.endsWith("/roblox.hpp") ||
|
|
31
|
+
normalized.endsWith("/roblox.h") ||
|
|
32
|
+
normalized.endsWith("/roblox.clh"));
|
|
33
|
+
}
|
|
34
|
+
function isHeaderFile(fileName) {
|
|
35
|
+
return node_path_1.default.extname(fileName).toLowerCase() === ".clh";
|
|
36
|
+
}
|
|
37
|
+
function isImplFile(fileName) {
|
|
38
|
+
const ext = node_path_1.default.extname(fileName).toLowerCase();
|
|
39
|
+
return ext === ".clp" || ext === ".clpp";
|
|
40
|
+
}
|
|
41
|
+
function toLuauPath(filePath) {
|
|
42
|
+
return String(filePath).replace(/\.(clpp|clp|clh)$/i, ".luau");
|
|
43
|
+
}
|
|
44
|
+
function fileStem(fileName) {
|
|
45
|
+
let name = node_path_1.default.basename(fileName);
|
|
46
|
+
const lower = name.toLowerCase();
|
|
47
|
+
for (const ext of [".clpp", ".clp", ".clh"]) {
|
|
48
|
+
if (lower.endsWith(ext)) {
|
|
49
|
+
name = name.slice(0, -ext.length);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const tagged = name.toLowerCase();
|
|
54
|
+
for (const tag of [".legacy.server", ".legacy.client", ".legacy", ".server", ".client", ".plugin"]) {
|
|
55
|
+
if (tagged.endsWith(tag)) {
|
|
56
|
+
name = name.slice(0, -tag.length);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return name;
|
|
61
|
+
}
|
|
62
|
+
function scriptKind(fileName) {
|
|
63
|
+
const name = node_path_1.default.basename(fileName).toLowerCase();
|
|
64
|
+
if (name.endsWith(".clh")) {
|
|
65
|
+
return "header";
|
|
66
|
+
}
|
|
67
|
+
if (name.includes(".legacy.")) {
|
|
68
|
+
return "legacy";
|
|
69
|
+
}
|
|
70
|
+
if (name.includes(".server.")) {
|
|
71
|
+
return "server";
|
|
72
|
+
}
|
|
73
|
+
if (name.includes(".client.")) {
|
|
74
|
+
return "client";
|
|
75
|
+
}
|
|
76
|
+
if (name.includes(".plugin.")) {
|
|
77
|
+
return "plugin";
|
|
78
|
+
}
|
|
79
|
+
return "module";
|
|
80
|
+
}
|
|
81
|
+
function emitKind(fileName) {
|
|
82
|
+
const kind = scriptKind(fileName);
|
|
83
|
+
if (kind === "legacy") {
|
|
84
|
+
return "legacy";
|
|
85
|
+
}
|
|
86
|
+
if (kind === "module" || kind === "header") {
|
|
87
|
+
return "module";
|
|
88
|
+
}
|
|
89
|
+
return "flat";
|
|
90
|
+
}
|
|
91
|
+
function isTaggedScript(fileName) {
|
|
92
|
+
const kind = scriptKind(fileName);
|
|
93
|
+
return kind === "server" || kind === "client" || kind === "plugin" || kind === "legacy";
|
|
94
|
+
}
|
|
95
|
+
function siblingHeader(implPath) {
|
|
96
|
+
if (!implPath || isHeaderFile(implPath)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const dir = node_path_1.default.dirname(implPath);
|
|
100
|
+
const stem = fileStem(implPath);
|
|
101
|
+
const candidate = node_path_1.default.join(dir, `${stem}.clh`);
|
|
102
|
+
if (node_fs_1.default.existsSync(candidate)) {
|
|
103
|
+
return candidate;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function collectSources(dir, files = []) {
|
|
108
|
+
if (!node_fs_1.default.existsSync(dir)) {
|
|
109
|
+
return files;
|
|
110
|
+
}
|
|
111
|
+
for (const entry of node_fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
112
|
+
const full = node_path_1.default.join(dir, entry.name);
|
|
113
|
+
if (entry.isDirectory()) {
|
|
114
|
+
collectSources(full, files);
|
|
115
|
+
}
|
|
116
|
+
else if (isSourceFile(entry.name)) {
|
|
117
|
+
files.push(full);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return files;
|
|
121
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shouldSkipInit = shouldSkipInit;
|
|
4
|
+
exports.clppLuauToGame = clppLuauToGame;
|
|
5
|
+
const libs_js_1 = require("../libs.js");
|
|
6
|
+
const paths_js_1 = require("./paths.js");
|
|
7
|
+
function insertAfterHeader(luau, block) {
|
|
8
|
+
const match = String(luau).match(/^(?:--[^\n]*\n)+/);
|
|
9
|
+
if (!match) {
|
|
10
|
+
return `${block}\n${luau}`;
|
|
11
|
+
}
|
|
12
|
+
const insertAt = match[0].length;
|
|
13
|
+
const rest = luau.slice(insertAt).replace(/^\n*/, "\n");
|
|
14
|
+
return `${luau.slice(0, insertAt)}\n${block}\n${rest}`;
|
|
15
|
+
}
|
|
16
|
+
function rewriteClppLibs(luau) {
|
|
17
|
+
return String(luau).replace(/require\(\s*ClppLibs\.([A-Za-z0-9_]+)\s*\)/g, (_all, name) => {
|
|
18
|
+
return (0, libs_js_1.requireCluauppLib)(name);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function ensureReplicatedStorage(luau) {
|
|
22
|
+
if (!luau.includes("CluauppLibs")) {
|
|
23
|
+
return luau;
|
|
24
|
+
}
|
|
25
|
+
if (/GetService\(\s*"ReplicatedStorage"\s*\)/.test(luau)) {
|
|
26
|
+
return luau;
|
|
27
|
+
}
|
|
28
|
+
return insertAfterHeader(luau, 'const ReplicatedStorage = game:GetService("ReplicatedStorage")');
|
|
29
|
+
}
|
|
30
|
+
function stripInitCall(luau) {
|
|
31
|
+
return String(luau).replace(/\ninit\(\)\s*\n?$/m, "\n");
|
|
32
|
+
}
|
|
33
|
+
function ensureStrict(luau, strict) {
|
|
34
|
+
if (!strict || /^\s*--!strict\b/m.test(luau)) {
|
|
35
|
+
return luau;
|
|
36
|
+
}
|
|
37
|
+
if (luau.startsWith("--")) {
|
|
38
|
+
return `--!strict\n${luau}`;
|
|
39
|
+
}
|
|
40
|
+
return `--!strict\n${luau}`;
|
|
41
|
+
}
|
|
42
|
+
function librarySpecs(names) {
|
|
43
|
+
const specs = [];
|
|
44
|
+
const seen = new Set();
|
|
45
|
+
for (const name of names || []) {
|
|
46
|
+
const spec = libs_js_1.MODULES[name];
|
|
47
|
+
if (!spec || seen.has(spec.bind)) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
seen.add(spec.bind);
|
|
51
|
+
specs.push(spec);
|
|
52
|
+
}
|
|
53
|
+
return specs;
|
|
54
|
+
}
|
|
55
|
+
function missingLibraries(luau, names) {
|
|
56
|
+
return librarySpecs(names).filter((spec) => {
|
|
57
|
+
return !luau.includes(`CluauppLibs.${spec.file}`) && !new RegExp(`\\bconst ${spec.bind}\\b`).test(luau);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function shouldSkipInit(fileName, hasSiblingHeader) {
|
|
61
|
+
if (!hasSiblingHeader) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
return !(0, paths_js_1.isTaggedScript)(fileName);
|
|
65
|
+
}
|
|
66
|
+
function clppLuauToGame(artifact, options) {
|
|
67
|
+
let luau = rewriteClppLibs(artifact.luau || "");
|
|
68
|
+
luau = ensureReplicatedStorage(luau);
|
|
69
|
+
if (options.skipInit) {
|
|
70
|
+
luau = stripInitCall(luau);
|
|
71
|
+
}
|
|
72
|
+
luau = ensureStrict(luau, options.strict);
|
|
73
|
+
const missing = missingLibraries(luau, artifact.libraries);
|
|
74
|
+
if (missing.length > 0) {
|
|
75
|
+
luau = (0, libs_js_1.insertPreamble)(luau, [], missing, options.outName);
|
|
76
|
+
}
|
|
77
|
+
return luau;
|
|
78
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasClpp = hasClpp;
|
|
4
|
+
exports.resolveClppBinary = resolveClppBinary;
|
|
5
|
+
exports.compileViaClpp = compileViaClpp;
|
|
6
|
+
exports.clppManifest = clppManifest;
|
|
7
|
+
exports.clppVersion = clppVersion;
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const contract_js_1 = require("./contract.js");
|
|
10
|
+
const MISSING_CLPP = `cluaupp: clpp not found. ${contract_js_1.CLPP_INSTALL_HINT}`;
|
|
11
|
+
function whichClpp() {
|
|
12
|
+
if (process.env.CLPP_PATH) {
|
|
13
|
+
return process.env.CLPP_PATH;
|
|
14
|
+
}
|
|
15
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
16
|
+
const found = (0, node_child_process_1.spawnSync)(finder, ["clpp"], { encoding: "utf8", windowsHide: true });
|
|
17
|
+
if (found.status !== 0) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const line = String(found.stdout || "")
|
|
21
|
+
.split(/\r?\n/)
|
|
22
|
+
.map((item) => item.trim())
|
|
23
|
+
.find((item) => item.length > 0);
|
|
24
|
+
return line || "clpp";
|
|
25
|
+
}
|
|
26
|
+
function hasClpp() {
|
|
27
|
+
return Boolean(whichClpp());
|
|
28
|
+
}
|
|
29
|
+
function resolveClppBinary() {
|
|
30
|
+
const bin = whichClpp();
|
|
31
|
+
if (!bin) {
|
|
32
|
+
throw new Error(MISSING_CLPP);
|
|
33
|
+
}
|
|
34
|
+
return bin;
|
|
35
|
+
}
|
|
36
|
+
function parseArtifact(stdout, fileName, fallbackError) {
|
|
37
|
+
const text = String(stdout || "").trim();
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(text);
|
|
40
|
+
if (parsed && typeof parsed === "object") {
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// fall through
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
ok: false,
|
|
49
|
+
luau: "",
|
|
50
|
+
fileName,
|
|
51
|
+
outputHint: "",
|
|
52
|
+
scriptKind: null,
|
|
53
|
+
isScript: false,
|
|
54
|
+
isHeader: false,
|
|
55
|
+
rojoClass: "ModuleScript",
|
|
56
|
+
libraries: [],
|
|
57
|
+
error: fallbackError || "clpp returned invalid JSON",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function compileViaClpp(request) {
|
|
61
|
+
const bin = resolveClppBinary();
|
|
62
|
+
const payload = JSON.stringify({
|
|
63
|
+
source: request.source,
|
|
64
|
+
fileName: request.fileName,
|
|
65
|
+
strict: request.strict,
|
|
66
|
+
});
|
|
67
|
+
const result = (0, node_child_process_1.spawnSync)(bin, ["api", "compile"], {
|
|
68
|
+
input: payload,
|
|
69
|
+
encoding: "utf8",
|
|
70
|
+
cwd: request.cwd,
|
|
71
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
72
|
+
windowsHide: true,
|
|
73
|
+
});
|
|
74
|
+
const stderr = String(result.stderr || "").trim();
|
|
75
|
+
const artifact = parseArtifact(result.stdout, request.fileName, stderr || result.error?.message || "clpp api compile failed");
|
|
76
|
+
if (!artifact.ok) {
|
|
77
|
+
throw new Error(artifact.error || stderr || `clpp failed (${result.status})`);
|
|
78
|
+
}
|
|
79
|
+
return artifact;
|
|
80
|
+
}
|
|
81
|
+
function clppManifest() {
|
|
82
|
+
const bin = resolveClppBinary();
|
|
83
|
+
const result = (0, node_child_process_1.spawnSync)(bin, ["api", "manifest"], {
|
|
84
|
+
encoding: "utf8",
|
|
85
|
+
windowsHide: true,
|
|
86
|
+
});
|
|
87
|
+
if (result.status !== 0) {
|
|
88
|
+
throw new Error(String(result.stderr || result.error?.message || "clpp api manifest failed"));
|
|
89
|
+
}
|
|
90
|
+
return JSON.parse(result.stdout);
|
|
91
|
+
}
|
|
92
|
+
function clppVersion() {
|
|
93
|
+
const bin = whichClpp();
|
|
94
|
+
if (!bin) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const result = (0, node_child_process_1.spawnSync)(bin, ["--version"], { encoding: "utf8", windowsHide: true });
|
|
98
|
+
if (result.status !== 0) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return String(result.stdout || "").trim() || null;
|
|
102
|
+
}
|