cluaupp 0.1.2 → 0.1.5
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 +29 -1
- package/README.md +10 -13
- package/docs/README.md +13 -10
- package/docs/architecture.md +30 -73
- package/docs/cli.md +5 -6
- package/docs/comparison.md +3 -3
- package/docs/config.md +6 -6
- package/docs/cpp-advanced.md +10 -6
- package/docs/cpp-organization.md +4 -2
- package/docs/cpp-safety.md +11 -7
- package/docs/cpp-types.md +1 -1
- package/docs/examples/_category_.json +5 -0
- package/docs/examples/combat.md +239 -0
- package/docs/examples/data-boot.md +98 -0
- package/docs/examples/hud.md +96 -0
- package/docs/examples/index.md +43 -0
- package/docs/examples/leaderstats.md +140 -0
- package/docs/examples/shop.md +122 -0
- package/docs/examples/sword.md +108 -0
- package/docs/getting-started.md +14 -7
- package/docs/intellisense.md +31 -0
- package/docs/intro.md +3 -3
- package/docs/libraries/_category_.json +5 -0
- package/docs/libraries/dataservice.md +104 -0
- package/docs/libraries/index.md +22 -0
- package/docs/libraries/janitor.md +65 -0
- package/docs/libraries/more.md +79 -0
- package/docs/libraries/net.md +35 -0
- package/docs/libraries/promise.md +27 -0
- package/docs/oop/_category_.json +5 -0
- package/docs/oop/file-tags.md +48 -0
- package/docs/oop/index.md +22 -0
- package/docs/oop/modules.md +88 -0
- package/docs/oop/services.md +76 -0
- package/docs/print-cout.md +91 -0
- package/docs/syntax.md +63 -8
- package/editors/vscode/extension.js +146 -0
- package/editors/vscode/package.json +25 -0
- package/include/cluaupp/libs/janitor.hpp +7 -3
- package/include/cluaupp/roblox.hpp +19 -0
- package/package.json +66 -65
- package/runtime/Janitor/init.luau +4 -34
- package/src/architecture.js +174 -66
- package/src/cli.js +88 -21
- package/src/client/init.client.cpp +5 -0
- package/src/compile.js +77 -7
- package/src/editor-install.js +218 -0
- package/src/emit.js +321 -9
- package/src/headers.js +234 -0
- package/src/intellisense.js +1368 -0
- package/src/layout.js +129 -0
- package/src/lex.js +17 -9
- package/src/libs.js +165 -18
- package/src/lsp.js +227 -0
- package/src/parse.js +187 -6
- package/src/preprocess.js +118 -3
- package/src/server/leaderstats.server.cpp +28 -0
- package/src/shared/config.cpp +5 -0
- package/src/shared/config.h +3 -0
- package/src/understand.js +66 -6
- package/templates/game/.clangd +11 -0
- package/templates/game/.vscode/c_cpp_properties.json +6 -2
- package/templates/game/.vscode/extensions.json +6 -0
- package/templates/game/.vscode/settings.json +16 -2
- package/templates/game/cluaupp.config.json +2 -2
- package/templates/game/compile_flags.txt +2 -0
- package/templates/game/src/client/init.client.cpp +1 -0
- package/templates/game/src/server/leaderstats.server.cpp +1 -0
- package/docs/libraries.md +0 -80
package/package.json
CHANGED
|
@@ -1,65 +1,66 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cluaupp",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Cluaupp — the definitive merge of C++ and modern Luau. Source-to-source transpiler with first-class Roblox APIs.",
|
|
5
|
-
"author": "KartzDev",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"bin": {
|
|
8
|
-
"cluaupp": "bin/cluaupp.js",
|
|
9
|
-
"cluau": "bin/cluaupp.js"
|
|
10
|
-
},
|
|
11
|
-
"main": "src/compile.js",
|
|
12
|
-
"exports": {
|
|
13
|
-
".": "./src/compile.js",
|
|
14
|
-
"./package.json": "./package.json"
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"bin",
|
|
18
|
-
"src",
|
|
19
|
-
"include",
|
|
20
|
-
"templates",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"docs
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "cluaupp",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Cluaupp — the definitive merge of C++ and modern Luau. Source-to-source transpiler with first-class Roblox APIs.",
|
|
5
|
+
"author": "KartzDev",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cluaupp": "bin/cluaupp.js",
|
|
9
|
+
"cluau": "bin/cluaupp.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "src/compile.js",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/compile.js",
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin",
|
|
18
|
+
"src",
|
|
19
|
+
"include",
|
|
20
|
+
"templates",
|
|
21
|
+
"editors",
|
|
22
|
+
"runtime",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"docs"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"cluaupp": "node bin/cluaupp.js",
|
|
30
|
+
"cluau": "node bin/cluaupp.js",
|
|
31
|
+
"build": "node bin/cluaupp.js build",
|
|
32
|
+
"watch": "node bin/cluaupp.js watch",
|
|
33
|
+
"test": "node test/leaderstats.test.js && node test/understand.test.js && node test/datatypes.test.js && node test/headers.test.js && node test/libs.test.js && node test/runtime-libs.test.js && node test/intellisense.test.js && node test/intellisense-complete.test.js && node test/dataservice.test.js && node test/datacontroller-signal.test.js && node test/cout.test.js && node test/prune.test.js && node test/hold.test.js && node test/vendor-stable.test.js && node test/switch.test.js && node test/qualified.test.js && node test/module-require.test.js",
|
|
34
|
+
"generate-api": "node scripts/generate-api.js",
|
|
35
|
+
"check-highlight": "node scripts/check-highlight.js",
|
|
36
|
+
"vendor-libs": "node scripts/vendor-libs.js",
|
|
37
|
+
"docs": "moonwave dev",
|
|
38
|
+
"docs:build": "moonwave build",
|
|
39
|
+
"site": "node scripts/generate-api.js && node scripts/check-highlight.js",
|
|
40
|
+
"dev": "node scripts/dev.js",
|
|
41
|
+
"stop": "node scripts/stop.js",
|
|
42
|
+
"prepublishOnly": "npm test"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"luau",
|
|
49
|
+
"roblox",
|
|
50
|
+
"cpp",
|
|
51
|
+
"c++",
|
|
52
|
+
"transpiler",
|
|
53
|
+
"compiler",
|
|
54
|
+
"rojo",
|
|
55
|
+
"cluaupp",
|
|
56
|
+
"cluau"
|
|
57
|
+
],
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/KartzRbx/Cluaupp.git"
|
|
61
|
+
},
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/KartzRbx/Cluaupp/issues"
|
|
64
|
+
},
|
|
65
|
+
"homepage": "https://github.com/KartzRbx/Cluaupp#readme"
|
|
66
|
+
}
|
|
@@ -1,45 +1,15 @@
|
|
|
1
1
|
--!strict
|
|
2
2
|
-- Cluaupp Janitor — typed border. Engine: howmanysmall/Janitor (_impl).
|
|
3
|
-
--
|
|
3
|
+
-- Public type and return value are the implementation. Promise is required
|
|
4
|
+
-- inside _impl as CluauppLibs.Promise (`script.Parent.Parent.Promise`).
|
|
4
5
|
|
|
5
6
|
--[=[
|
|
6
7
|
@class Janitor
|
|
7
8
|
Cleans up connections, instances, promises, and threads.
|
|
8
9
|
]=]
|
|
9
10
|
|
|
10
|
-
local PromiseMod = require(script.Parent.Promise)
|
|
11
|
-
type Promise<T...> = PromiseMod.Promise<T...>
|
|
12
|
-
|
|
13
11
|
local Impl = require(script._impl)
|
|
14
12
|
|
|
15
|
-
export type Janitor =
|
|
16
|
-
CurrentlyCleaning: boolean,
|
|
17
|
-
SuppressInstanceReDestroy: boolean,
|
|
18
|
-
UnsafeThreadCleanup: boolean,
|
|
19
|
-
Add: <T>(self: Janitor, object: T, methodName: (boolean | string)?, index: string?) -> T,
|
|
20
|
-
AddObject: <T, A...>(
|
|
21
|
-
self: Janitor,
|
|
22
|
-
constructor: { new: (A...) -> T },
|
|
23
|
-
methodName: (boolean | string)?,
|
|
24
|
-
index: string?,
|
|
25
|
-
A...
|
|
26
|
-
) -> T,
|
|
27
|
-
AddPromise: <T...>(self: Janitor, promiseObject: Promise<T...>, index: string?) -> Promise<T...>,
|
|
28
|
-
Remove: (self: Janitor, index: string) -> Janitor,
|
|
29
|
-
RemoveNoClean: (self: Janitor, index: string) -> Janitor,
|
|
30
|
-
RemoveList: (self: Janitor, ...string) -> Janitor,
|
|
31
|
-
Get: <T>(self: Janitor, index: string) -> T?,
|
|
32
|
-
GetAll: (self: Janitor) -> { [string]: unknown },
|
|
33
|
-
Has: (self: Janitor, index: string) -> boolean,
|
|
34
|
-
Cleanup: (self: Janitor) -> (),
|
|
35
|
-
Destroy: (self: Janitor) -> (),
|
|
36
|
-
LinkToInstance: (self: Janitor, object: Instance, allowMultiple: boolean?) -> RBXScriptConnection,
|
|
37
|
-
LinkToInstances: (self: Janitor, ...Instance) -> Janitor,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
type JanitorStatic = {
|
|
41
|
-
new: () -> Janitor,
|
|
42
|
-
Is: (value: unknown) -> boolean,
|
|
43
|
-
}
|
|
13
|
+
export type Janitor = Impl.Janitor
|
|
44
14
|
|
|
45
|
-
return Impl
|
|
15
|
+
return Impl
|
package/src/architecture.js
CHANGED
|
@@ -2,16 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const { emit } = require("./emit");
|
|
5
|
-
const {
|
|
5
|
+
const { requireCluauppLib } = require("./libs");
|
|
6
|
+
const { organizeDecls, janitorNames, emitSection, joinBlocks, SECTION, ENTRY_FN } = require("./layout");
|
|
6
7
|
const {
|
|
7
8
|
VALUE_CLASSES,
|
|
8
9
|
analyze,
|
|
9
10
|
toPascalServiceName,
|
|
10
11
|
legacyOutName,
|
|
12
|
+
modernScriptOutName,
|
|
11
13
|
} = require("./understand");
|
|
14
|
+
const { implOutName } = require("./preprocess");
|
|
12
15
|
|
|
13
16
|
function header(plan) {
|
|
14
|
-
const lines = [
|
|
17
|
+
const lines = [];
|
|
18
|
+
if (plan && plan.strict) {
|
|
19
|
+
lines.push("--!strict");
|
|
20
|
+
}
|
|
21
|
+
lines.push("-- Compiled by Cluaupp — C++ × Luau");
|
|
15
22
|
if (plan && plan.reasoning) {
|
|
16
23
|
for (const line of plan.reasoning) {
|
|
17
24
|
lines.push(`-- ${line}`);
|
|
@@ -27,9 +34,9 @@ function cluauppLib(name) {
|
|
|
27
34
|
|
|
28
35
|
function emitTypes(plan) {
|
|
29
36
|
const lines = [header(plan).trimEnd(), ""];
|
|
30
|
-
lines.push('
|
|
31
|
-
lines.push(`
|
|
32
|
-
lines.push(`
|
|
37
|
+
lines.push('const ReplicatedStorage = game:GetService("ReplicatedStorage")');
|
|
38
|
+
lines.push(`const Occlude = ${cluauppLib("Occlude")}`);
|
|
39
|
+
lines.push(`const ArrayIndexer = ${cluauppLib("ArrayIndexer")}`);
|
|
33
40
|
lines.push("");
|
|
34
41
|
|
|
35
42
|
if (plan.stats.length > 0) {
|
|
@@ -60,6 +67,7 @@ function emitTypes(plan) {
|
|
|
60
67
|
manifest.push(" Get: (player: Player) -> PlayerCache?,");
|
|
61
68
|
manifest.push(" Ensure: (player: Player) -> PlayerCache,");
|
|
62
69
|
manifest.push(" Clear: (player: Player) -> (),");
|
|
70
|
+
manifest.push(" ClearAll: () -> (),");
|
|
63
71
|
manifest.push(" },");
|
|
64
72
|
}
|
|
65
73
|
if (plan.roles.players) {
|
|
@@ -100,23 +108,26 @@ function emitTypes(plan) {
|
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
function emitPlayersManager(plan) {
|
|
103
|
-
return `${header(plan)}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
return `${header(plan).trimEnd()}
|
|
112
|
+
|
|
113
|
+
const Players = game:GetService("Players")
|
|
114
|
+
const ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
115
|
+
const Janitor = ${cluauppLib("Janitor")}
|
|
108
116
|
|
|
117
|
+
type Janitor = Janitor.Janitor
|
|
109
118
|
export type PlayerHandler = (player: Player) -> ()
|
|
110
119
|
|
|
111
120
|
local PlayersManager = {}
|
|
112
121
|
local lifetime: Janitor? = nil
|
|
122
|
+
local leaveHandler: PlayerHandler? = nil
|
|
113
123
|
|
|
114
124
|
function PlayersManager.Start(onPlayer: PlayerHandler, onLeave: PlayerHandler?)
|
|
115
125
|
PlayersManager.Stop()
|
|
116
126
|
local janitor = Janitor.new()
|
|
117
127
|
lifetime = janitor
|
|
128
|
+
leaveHandler = onLeave
|
|
118
129
|
|
|
119
|
-
|
|
130
|
+
const function accept(player: Player)
|
|
120
131
|
onPlayer(player)
|
|
121
132
|
end
|
|
122
133
|
|
|
@@ -134,6 +145,13 @@ function PlayersManager.Stop()
|
|
|
134
145
|
if lifetime == nil then
|
|
135
146
|
return
|
|
136
147
|
end
|
|
148
|
+
local onLeave = leaveHandler
|
|
149
|
+
leaveHandler = nil
|
|
150
|
+
if onLeave then
|
|
151
|
+
for _, player in Players:GetPlayers() do
|
|
152
|
+
onLeave(player)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
137
155
|
lifetime:Cleanup()
|
|
138
156
|
lifetime = nil
|
|
139
157
|
end
|
|
@@ -146,11 +164,11 @@ function emitCacheController(plan) {
|
|
|
146
164
|
const types = plan.typesName;
|
|
147
165
|
const folder = plan.folderName || "leaderstats";
|
|
148
166
|
const lines = [header(plan).trimEnd(), ""];
|
|
149
|
-
lines.push(`
|
|
167
|
+
lines.push(`const Types = require(script.Parent.${types})`);
|
|
150
168
|
lines.push("");
|
|
151
|
-
lines.push(`
|
|
152
|
-
lines.push("local cache: { [Player]: Types.PlayerCache } = {}");
|
|
169
|
+
lines.push(`const FOLDER_NAME = "${folder}"`);
|
|
153
170
|
lines.push("");
|
|
171
|
+
lines.push("local cache: { [Player]: Types.PlayerCache } = {}");
|
|
154
172
|
lines.push("local CacheController = {}");
|
|
155
173
|
lines.push("");
|
|
156
174
|
lines.push("function CacheController.Get(player: Player): Types.PlayerCache?");
|
|
@@ -201,6 +219,10 @@ function emitCacheController(plan) {
|
|
|
201
219
|
lines.push(" cache[player] = nil");
|
|
202
220
|
lines.push("end");
|
|
203
221
|
lines.push("");
|
|
222
|
+
lines.push("function CacheController.ClearAll()");
|
|
223
|
+
lines.push(" table.clear(cache)");
|
|
224
|
+
lines.push("end");
|
|
225
|
+
lines.push("");
|
|
204
226
|
lines.push("return CacheController");
|
|
205
227
|
lines.push("");
|
|
206
228
|
return lines.join("\n");
|
|
@@ -209,13 +231,13 @@ function emitCacheController(plan) {
|
|
|
209
231
|
function emitMain(plan) {
|
|
210
232
|
const lines = [header(plan).trimEnd(), ""];
|
|
211
233
|
if (plan.roles.players) {
|
|
212
|
-
lines.push("
|
|
234
|
+
lines.push("const PlayersManager = require(script.Parent.PlayersManager)");
|
|
213
235
|
}
|
|
214
236
|
if (plan.roles.cache) {
|
|
215
|
-
lines.push("
|
|
237
|
+
lines.push("const CacheController = require(script.Parent.CacheController)");
|
|
216
238
|
}
|
|
217
239
|
if (plan.roles.domain) {
|
|
218
|
-
lines.push(`
|
|
240
|
+
lines.push(`const ${plan.roles.domain} = require(script.Parent.${plan.roles.domain})`);
|
|
219
241
|
}
|
|
220
242
|
lines.push("");
|
|
221
243
|
lines.push("local Main = {}");
|
|
@@ -242,9 +264,15 @@ function emitMain(plan) {
|
|
|
242
264
|
if (plan.roles.domain) {
|
|
243
265
|
lines.push(` ${plan.roles.domain}.Stop()`);
|
|
244
266
|
}
|
|
267
|
+
if (plan.roles.cache) {
|
|
268
|
+
lines.push(" CacheController.ClearAll()");
|
|
269
|
+
}
|
|
245
270
|
if (plan.roles.players) {
|
|
246
271
|
lines.push(" PlayersManager.Stop()");
|
|
247
272
|
}
|
|
273
|
+
if (!plan.roles.domain && !plan.roles.cache && !plan.roles.players) {
|
|
274
|
+
lines.push(" return");
|
|
275
|
+
}
|
|
248
276
|
lines.push("end");
|
|
249
277
|
lines.push("");
|
|
250
278
|
lines.push("return Main");
|
|
@@ -258,6 +286,10 @@ function emitBootstrap(plan) {
|
|
|
258
286
|
}
|
|
259
287
|
|
|
260
288
|
function emitConfig(plan, ast, options) {
|
|
289
|
+
const owned = (ast.body || []).some((decl) => decl.owner);
|
|
290
|
+
if (owned) {
|
|
291
|
+
return `${header(plan).trimEnd()}\n\n${emit(ast, { ...options, skipHeader: true, skipInit: true }).trimEnd()}\n`;
|
|
292
|
+
}
|
|
261
293
|
const lines = [];
|
|
262
294
|
if (plan.onlyConsts) {
|
|
263
295
|
lines.push(header(plan).trimEnd());
|
|
@@ -282,59 +314,86 @@ function emitConfig(plan, ast, options) {
|
|
|
282
314
|
}
|
|
283
315
|
if ((ast.body || []).some((decl) => decl.type === "function" && decl.name === "init")) {
|
|
284
316
|
lines.push(" Start = init,");
|
|
317
|
+
lines.push(" Init = init,");
|
|
318
|
+
lines.push(" init = init,");
|
|
285
319
|
}
|
|
286
320
|
lines.push("}");
|
|
287
321
|
lines.push("");
|
|
288
322
|
return lines.join("\n");
|
|
289
323
|
}
|
|
290
324
|
|
|
325
|
+
function emitDecls(decls, options) {
|
|
326
|
+
if (!decls || decls.length === 0) {
|
|
327
|
+
return "";
|
|
328
|
+
}
|
|
329
|
+
return emit({ type: "program", body: decls }, { ...options, skipHeader: true, skipInit: true }).trimEnd();
|
|
330
|
+
}
|
|
331
|
+
|
|
291
332
|
function emitDomainController(plan, ast, options) {
|
|
292
|
-
const absorbCache = plan.roles.cache;
|
|
293
333
|
const keep = (ast.body || []).filter((decl) => {
|
|
294
|
-
|
|
295
|
-
return true;
|
|
296
|
-
}
|
|
297
|
-
if (decl.type !== "function") {
|
|
298
|
-
return false;
|
|
299
|
-
}
|
|
300
|
-
if (decl.name === "init") {
|
|
301
|
-
return true;
|
|
302
|
-
}
|
|
303
|
-
const classified = plan.functions.find((item) => item.name === decl.name);
|
|
304
|
-
if (absorbCache && classified && classified.absorb === "cache") {
|
|
305
|
-
return false;
|
|
306
|
-
}
|
|
307
|
-
return true;
|
|
334
|
+
return decl.type === "decl" || decl.type === "proto" || decl.type === "function" || decl.type === "expr";
|
|
308
335
|
});
|
|
309
|
-
const
|
|
310
|
-
const code = emit(subset, { ...options, skipHeader: true, skipInit: true }).trimEnd();
|
|
336
|
+
const groups = organizeDecls(keep);
|
|
311
337
|
const name = plan.roles.domain;
|
|
312
|
-
const
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
338
|
+
const entry = keep.find((decl) => decl.type === "function" && ENTRY_FN.test(decl.name || ""));
|
|
339
|
+
const bootExprs = keep.filter((decl) => decl.type === "expr");
|
|
340
|
+
const janitors = janitorNames(keep);
|
|
341
|
+
const closer = keep.find((decl) => decl.type === "function" && /^(OnClose|Cleanup|Shutdown)$/i.test(decl.name));
|
|
342
|
+
const stopLines = [];
|
|
343
|
+
if (janitors.length > 0) {
|
|
344
|
+
for (const janitor of janitors) {
|
|
345
|
+
stopLines.push(` ${janitor}:Cleanup()`);
|
|
346
|
+
}
|
|
347
|
+
} else if (closer) {
|
|
348
|
+
stopLines.push(` ${closer.name}()`);
|
|
349
|
+
} else {
|
|
350
|
+
stopLines.push(" return");
|
|
351
|
+
}
|
|
352
|
+
const boot = entry
|
|
353
|
+
? ` ${entry.name}()`
|
|
354
|
+
: bootExprs.length
|
|
355
|
+
? emitDecls(bootExprs, options)
|
|
356
|
+
.split("\n")
|
|
357
|
+
.map((line) => (line ? `\t${line}` : line))
|
|
358
|
+
.join("\n")
|
|
359
|
+
: " return";
|
|
360
|
+
const startFn = `function ${name}.Start()\n ${name}.Stop()\n${boot}\nend`;
|
|
361
|
+
const stopFn = `function ${name}.Stop()\n${stopLines.join("\n")}\nend`;
|
|
362
|
+
const body = `${header(plan).trimEnd()}\n\n${emitSection(SECTION.api, emitDecls(groups.api, options))}${emitSection(SECTION.constants, emitDecls(groups.constants, options))}${emitSection(SECTION.variables, joinBlocks([emitDecls(groups.variables, options), `local ${name} = {}`]))}${emitSection(SECTION.support, emitDecls(groups.support, options))}${emitSection(SECTION.principal, joinBlocks([emitDecls(groups.principal, options), startFn]))}${emitSection(SECTION.cleanup, joinBlocks([emitDecls(groups.cleanup, options), stopFn]))}${emitSection(SECTION.returns, `return ${name}`)}`;
|
|
363
|
+
return body;
|
|
328
364
|
}
|
|
329
365
|
|
|
330
366
|
function emitModule(plan, ast, options) {
|
|
331
367
|
return emitConfig(plan, ast, options);
|
|
332
368
|
}
|
|
333
369
|
|
|
370
|
+
function emitScriptMeta(runContext) {
|
|
371
|
+
return `${JSON.stringify(
|
|
372
|
+
{
|
|
373
|
+
properties: {
|
|
374
|
+
RunContext: `Enum.RunContext.${runContext}`,
|
|
375
|
+
},
|
|
376
|
+
},
|
|
377
|
+
null,
|
|
378
|
+
"\t",
|
|
379
|
+
)}\n`;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function serviceBootName(plan) {
|
|
383
|
+
if (plan.isClient) {
|
|
384
|
+
return "init.client.luau";
|
|
385
|
+
}
|
|
386
|
+
return "init.server.luau";
|
|
387
|
+
}
|
|
388
|
+
|
|
334
389
|
function serviceFiles(plan, ast, options, dir) {
|
|
335
390
|
const folder = `${dir}/${plan.serviceName}`;
|
|
336
|
-
const boot = plan
|
|
337
|
-
const files = [{ name: `${folder}/${boot}`, contents: emitBootstrap(plan) }
|
|
391
|
+
const boot = serviceBootName(plan);
|
|
392
|
+
const files = [{ name: `${folder}/${boot}`, contents: emitBootstrap(plan) }];
|
|
393
|
+
if (!plan.isClient && plan.runContext) {
|
|
394
|
+
files.push({ name: `${folder}/init.meta.json`, contents: emitScriptMeta(plan.runContext) });
|
|
395
|
+
}
|
|
396
|
+
files.push({ name: `${folder}/Main.luau`, contents: emitMain(plan) });
|
|
338
397
|
if (plan.roles.players) {
|
|
339
398
|
files.push({ name: `${folder}/PlayersManager.luau`, contents: emitPlayersManager(plan) });
|
|
340
399
|
}
|
|
@@ -348,29 +407,75 @@ function serviceFiles(plan, ast, options, dir) {
|
|
|
348
407
|
return files;
|
|
349
408
|
}
|
|
350
409
|
|
|
410
|
+
function serviceFolderStale(plan, rel) {
|
|
411
|
+
const dir = path.posix.dirname(rel).replace(/^\.$/, "");
|
|
412
|
+
const serviceDir = dir && dir !== "." ? dir : plan.isClient ? "client" : "server";
|
|
413
|
+
const folder = `${serviceDir}/${plan.serviceName}`;
|
|
414
|
+
return [
|
|
415
|
+
folder,
|
|
416
|
+
`${folder}/init.luau`,
|
|
417
|
+
`${folder}/init.server.luau`,
|
|
418
|
+
`${folder}/init.client.luau`,
|
|
419
|
+
`${folder}/init.meta.json`,
|
|
420
|
+
`${folder}/Main.luau`,
|
|
421
|
+
`${folder}/PlayersManager.luau`,
|
|
422
|
+
`${folder}/CacheController.luau`,
|
|
423
|
+
`${folder}/${plan.typesName}.luau`,
|
|
424
|
+
plan.roles && plan.roles.domain ? `${folder}/${plan.roles.domain}.luau` : null,
|
|
425
|
+
].filter(Boolean);
|
|
426
|
+
}
|
|
427
|
+
|
|
351
428
|
function planOutput(ast, fileName, options = {}) {
|
|
352
429
|
const plan = analyze(ast, fileName);
|
|
430
|
+
plan.strict = options.strict === true;
|
|
353
431
|
const rel = (options.relativeName || fileName).replace(/\\/g, "/");
|
|
354
432
|
const dir = path.dirname(rel).replace(/^\.$/, "");
|
|
355
433
|
const outDir = dir && dir !== "." ? dir : "";
|
|
356
434
|
const prefix = outDir ? `${outDir}/` : "";
|
|
435
|
+
const stale = serviceFolderStale(plan, rel);
|
|
357
436
|
|
|
358
|
-
if (options.
|
|
359
|
-
return {
|
|
437
|
+
if (options.siblingHeader) {
|
|
438
|
+
return {
|
|
439
|
+
kind: "module",
|
|
440
|
+
plan,
|
|
441
|
+
files: [{ name: implOutName(rel), contents: emitModule(plan, ast, { ...options, skipInit: true }) }],
|
|
442
|
+
stale: [],
|
|
443
|
+
};
|
|
360
444
|
}
|
|
361
445
|
|
|
362
|
-
if (
|
|
363
|
-
|
|
446
|
+
if (options.architecture === true) {
|
|
447
|
+
if (plan.kind === "legacy") {
|
|
448
|
+
return { kind: "legacy", plan, files: null, stale: [], outName: legacyOutName(rel) };
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (plan.kind === "service") {
|
|
452
|
+
const serviceDir = outDir || (plan.isClient ? "client" : "server");
|
|
453
|
+
const folder = `${serviceDir}/${plan.serviceName}`;
|
|
454
|
+
const serviceStale = plan.isClient
|
|
455
|
+
? [`${folder}/init.luau`, `${folder}/init.server.luau`, `${folder}/init.meta.json`]
|
|
456
|
+
: [`${folder}/init.luau`, `${folder}/init.client.luau`];
|
|
457
|
+
return {
|
|
458
|
+
kind: "service",
|
|
459
|
+
plan,
|
|
460
|
+
files: serviceFiles(plan, ast, options, serviceDir),
|
|
461
|
+
stale: serviceStale,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (plan.kind === "config" || plan.kind === "module") {
|
|
466
|
+
return {
|
|
467
|
+
kind: plan.kind,
|
|
468
|
+
plan,
|
|
469
|
+
files: [{ name: `${prefix}${plan.serviceName}.luau`, contents: emitModule(plan, ast, options) }],
|
|
470
|
+
stale: [rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau")],
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return { kind: "flat", plan, files: null, stale: [], outName: modernScriptOutName(rel) };
|
|
364
475
|
}
|
|
365
476
|
|
|
366
|
-
if (plan.kind === "
|
|
367
|
-
|
|
368
|
-
return {
|
|
369
|
-
kind: "service",
|
|
370
|
-
plan,
|
|
371
|
-
files: serviceFiles(plan, ast, options, serviceDir),
|
|
372
|
-
stale: [rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau")],
|
|
373
|
-
};
|
|
477
|
+
if (plan.kind === "legacy") {
|
|
478
|
+
return { kind: "legacy", plan, files: null, stale, outName: legacyOutName(rel) };
|
|
374
479
|
}
|
|
375
480
|
|
|
376
481
|
if (plan.kind === "config" || plan.kind === "module") {
|
|
@@ -378,11 +483,14 @@ function planOutput(ast, fileName, options = {}) {
|
|
|
378
483
|
kind: plan.kind,
|
|
379
484
|
plan,
|
|
380
485
|
files: [{ name: `${prefix}${plan.serviceName}.luau`, contents: emitModule(plan, ast, options) }],
|
|
381
|
-
stale: [rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau")],
|
|
486
|
+
stale: [rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau"), ...stale],
|
|
382
487
|
};
|
|
383
488
|
}
|
|
384
489
|
|
|
385
|
-
|
|
490
|
+
const outName = modernScriptOutName(rel);
|
|
491
|
+
const stripped = rel.replace(/\.(server|client|plugin)\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau");
|
|
492
|
+
const extraStale = stripped !== outName ? [stripped] : [];
|
|
493
|
+
return { kind: "flat", plan, files: null, stale: [...stale, ...extraStale], outName };
|
|
386
494
|
}
|
|
387
495
|
|
|
388
496
|
module.exports = {
|