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.
Files changed (129) hide show
  1. package/CHANGELOG.md +14 -75
  2. package/README.md +42 -88
  3. package/docs/README.md +25 -21
  4. package/docs/architecture.md +13 -76
  5. package/docs/cli.md +12 -64
  6. package/docs/comparison.md +6 -24
  7. package/docs/config.md +6 -7
  8. package/docs/cpp-advanced.md +6 -3
  9. package/docs/cpp-types.md +2 -0
  10. package/docs/examples/combat.md +19 -227
  11. package/docs/examples/hud.md +13 -81
  12. package/docs/examples/index.md +9 -16
  13. package/docs/examples/leaderstats.md +44 -115
  14. package/docs/getting-started.md +20 -135
  15. package/docs/intellisense.md +5 -42
  16. package/docs/intro.md +16 -15
  17. package/docs/libraries/dataservice.md +4 -1
  18. package/docs/libraries/index.md +2 -1
  19. package/docs/libraries/more.md +3 -1
  20. package/docs/libraries/ui.md +76 -0
  21. package/docs/migration.md +38 -0
  22. package/docs/oop/file-tags.md +12 -36
  23. package/docs/oop/index.md +18 -11
  24. package/docs/roblox-api.md +4 -56
  25. package/docs/syntax.md +54 -179
  26. package/editors/vscode/extension.js +1 -1
  27. package/editors/vscode/package.json +4 -4
  28. package/examples/README.md +5 -7
  29. package/examples/game/.vscode/extensions.json +2 -2
  30. package/examples/game/.vscode/settings.json +6 -23
  31. package/examples/game/src/client/hud.client.clpp +54 -0
  32. package/examples/game/src/client/init.client.clpp +6 -0
  33. package/examples/game/src/server/combat.server.clpp +85 -0
  34. package/examples/game/src/server/leaderstats.server.clpp +28 -0
  35. package/examples/game/src/shared/PlayerData.clh +20 -0
  36. package/examples/game/src/shared/config.clp +6 -0
  37. package/examples/game/src/shared/features.clp +88 -0
  38. package/generated/api.js +15 -1
  39. package/generated/cli.js +40 -24
  40. package/generated/clpp/contract.js +5 -0
  41. package/generated/clpp/index.js +27 -0
  42. package/generated/clpp/paths.js +121 -0
  43. package/generated/clpp/postprocess.js +78 -0
  44. package/generated/clpp/runner.js +102 -0
  45. package/generated/compile.js +26 -138
  46. package/generated/emit.js +79 -3
  47. package/generated/intellisense.js +83 -207
  48. package/generated/lex.js +3 -0
  49. package/generated/libs.js +1 -1
  50. package/generated/lsp.js +1 -8
  51. package/generated/parse.js +119 -24
  52. package/generated/preprocess.js +8 -179
  53. package/generated/system-understander.js +1 -1
  54. package/generated/transpile.js +3 -50
  55. package/generated/utils/project.js +13 -28
  56. package/include/{cluaupp/datatypes.hpp → clpp/datatypes.clh} +5 -1
  57. package/include/{cluaupp/generated/instances.hpp → clpp/generated/instances.clh} +1 -1
  58. package/include/{cluaupp/libs/chrono.hpp → clpp/libs/chrono.clh} +9 -9
  59. package/include/{cluaupp/libs/cmdr.hpp → clpp/libs/cmdr.clh} +4 -4
  60. package/include/{cluaupp/libs/dataservice.hpp → clpp/libs/dataservice.clh} +8 -15
  61. package/include/{cluaupp/libs/display.hpp → clpp/libs/display.clh} +1 -2
  62. package/include/{cluaupp/libs/ezvisual.hpp → clpp/libs/ezvisual.clh} +1 -3
  63. package/include/{cluaupp/libs/formatnumber.hpp → clpp/libs/formatnumber.clh} +2 -3
  64. package/include/{cluaupp/libs/fusion.hpp → clpp/libs/fusion.clh} +5 -5
  65. package/include/{cluaupp/libs/iris.hpp → clpp/libs/iris.clh} +2 -2
  66. package/include/{cluaupp/libs/janitor.hpp → clpp/libs/janitor.clh} +1 -2
  67. package/include/{cluaupp/libs/module3d.hpp → clpp/libs/module3d.clh} +2 -4
  68. package/include/{cluaupp/libs/net.hpp → clpp/libs/net.clh} +2 -4
  69. package/include/{cluaupp/libs/promise.hpp → clpp/libs/promise.clh} +1 -4
  70. package/include/{cluaupp/libs/spring.hpp → clpp/libs/spring.clh} +1 -2
  71. package/include/{cluaupp/libs/statemachine.hpp → clpp/libs/statemachine.clh} +2 -3
  72. package/include/{cluaupp/libs/stickybillboard.hpp → clpp/libs/stickybillboard.clh} +1 -2
  73. package/include/{cluaupp/libs/topbarplus.hpp → clpp/libs/topbarplus.clh} +3 -4
  74. package/include/clpp/libs.clh +24 -0
  75. package/include/clpp/roblox.clh +31 -0
  76. package/package.json +20 -16
  77. package/src/api.ts +15 -1
  78. package/src/cli.ts +39 -25
  79. package/src/clpp/contract.ts +39 -0
  80. package/src/clpp/index.ts +18 -0
  81. package/src/clpp/paths.ts +117 -0
  82. package/src/clpp/postprocess.ts +93 -0
  83. package/src/clpp/runner.ts +102 -0
  84. package/src/compile.ts +26 -149
  85. package/src/intellisense.ts +82 -211
  86. package/src/libs.ts +1 -1
  87. package/src/lsp.ts +1 -5
  88. package/src/preprocess.ts +8 -180
  89. package/src/system-understander.ts +1 -1
  90. package/src/transpile.ts +9 -52
  91. package/src/utils/project.ts +12 -28
  92. package/templates/game/.vscode/extensions.json +2 -2
  93. package/templates/game/.vscode/settings.json +6 -23
  94. package/templates/game/src/client/init.client.clpp +6 -0
  95. package/templates/game/src/server/leaderstats.server.clpp +29 -0
  96. package/templates/game/src/shared/config.clp +6 -0
  97. package/examples/game/.clangd +0 -25
  98. package/examples/game/.vscode/c_cpp_properties.json +0 -27
  99. package/examples/game/compile_flags.txt +0 -6
  100. package/examples/game/src/client/hud.client.cpp +0 -12
  101. package/examples/game/src/client/init.client.cpp +0 -6
  102. package/examples/game/src/server/combat.server.cpp +0 -23
  103. package/examples/game/src/server/leaderstats.server.cpp +0 -29
  104. package/examples/game/src/shared/config.cpp +0 -5
  105. package/examples/game/src/shared/config.h +0 -5
  106. package/include/cluaupp/libs.hpp +0 -25
  107. package/include/cluaupp/roblox.hpp +0 -47
  108. package/src/architecture.ts +0 -500
  109. package/src/ast.ts +0 -37
  110. package/src/emit.ts +0 -531
  111. package/src/emitter/luau-codegen.ts +0 -187
  112. package/src/emitter/translators.ts +0 -168
  113. package/src/headers.ts +0 -233
  114. package/src/layout.ts +0 -114
  115. package/src/lex.ts +0 -155
  116. package/src/parse.ts +0 -630
  117. package/src/parser/collector.ts +0 -148
  118. package/src/parser/index.ts +0 -27
  119. package/src/tree-sitter-cpp.d.ts +0 -4
  120. package/src/understand.ts +0 -322
  121. package/templates/game/.vscode/c_cpp_properties.json +0 -27
  122. package/templates/game/src/client/init.client.cpp +0 -6
  123. package/templates/game/src/server/leaderstats.server.cpp +0 -29
  124. package/templates/game/src/shared/config.cpp +0 -5
  125. package/templates/game/src/shared/config.h +0 -5
  126. /package/include/{cluaupp/generated/enums.hpp → clpp/generated/enums.clh} +0 -0
  127. /package/include/{cluaupp/libs/math.hpp → clpp/libs/math.clh} +0 -0
  128. /package/include/{cluaupp/libs/twinkle.hpp → clpp/libs/twinkle.clh} +0 -0
  129. /package/include/{cluaupp/libs/vfx.hpp → clpp/libs/vfx.clh} +0 -0
@@ -1,500 +0,0 @@
1
- // @ts-nocheck
2
- import path from "node:path";
3
- import { emit } from "./emit.js";
4
- import { requireCluauppLib } from "./libs.js";
5
- import { organizeDecls, janitorNames, emitSection, joinBlocks, SECTION, ENTRY_FN } from "./layout.js";
6
- import {
7
- VALUE_CLASSES,
8
- analyze,
9
- toPascalServiceName,
10
- legacyOutName,
11
- modernScriptOutName,
12
- } from "./understand.js";
13
- import { implOutName } from "./preprocess.js";
14
-
15
- function header(plan) {
16
- const lines = [];
17
- if (plan && plan.strict) {
18
- lines.push("--!strict");
19
- }
20
- lines.push("-- Compiled by Cluaupp — C++ × Luau");
21
- if (plan && plan.reasoning) {
22
- for (const line of plan.reasoning) {
23
- lines.push(`-- ${line}`);
24
- }
25
- }
26
- lines.push("");
27
- return lines.join("\n");
28
- }
29
-
30
- function cluauppLib(name) {
31
- return requireCluauppLib(name);
32
- }
33
-
34
- function emitTypes(plan) {
35
- const lines = [header(plan).trimEnd(), ""];
36
- lines.push('const ReplicatedStorage = game:GetService("ReplicatedStorage")');
37
- lines.push(`const Occlude = ${cluauppLib("Occlude")}`);
38
- lines.push(`const ArrayIndexer = ${cluauppLib("ArrayIndexer")}`);
39
- lines.push("");
40
-
41
- if (plan.stats.length > 0) {
42
- const union = plan.stats.map((stat) => `"${stat.name}"`).join(" | ");
43
- lines.push(`export type StatName = ${union}`);
44
- lines.push("");
45
- lines.push(`export type ${plan.serviceName}Data = {`);
46
- for (const stat of plan.stats) {
47
- lines.push(` ${stat.name}: ${stat.luau},`);
48
- }
49
- lines.push("}");
50
- lines.push("");
51
- }
52
-
53
- if (plan.roles.cache) {
54
- lines.push("export type PlayerCache = {");
55
- lines.push(" Folder: Folder,");
56
- for (const stat of plan.stats) {
57
- lines.push(` ${stat.name}: ${stat.instance},`);
58
- }
59
- lines.push("}");
60
- lines.push("");
61
- }
62
-
63
- const manifest = [];
64
- if (plan.roles.cache) {
65
- manifest.push(" CacheController: {");
66
- manifest.push(" Get: (player: Player) -> PlayerCache?,");
67
- manifest.push(" Ensure: (player: Player) -> PlayerCache,");
68
- manifest.push(" Clear: (player: Player) -> (),");
69
- manifest.push(" ClearAll: () -> (),");
70
- manifest.push(" },");
71
- }
72
- if (plan.roles.players) {
73
- manifest.push(" PlayersManager: {");
74
- manifest.push(" Start: (onPlayer: (player: Player) -> (), onLeave: ((player: Player) -> ())?) -> (),");
75
- manifest.push(" Stop: () -> (),");
76
- manifest.push(" },");
77
- }
78
- if (plan.roles.domain) {
79
- manifest.push(` ${plan.roles.domain}: {`);
80
- manifest.push(" Start: () -> (),");
81
- manifest.push(" Stop: () -> (),");
82
- manifest.push(" },");
83
- }
84
- lines.push("export type ServiceManifest = {");
85
- if (manifest.length === 0) {
86
- lines.push(" Main: { Start: () -> (), Stop: () -> () },");
87
- } else {
88
- lines.push(...manifest);
89
- }
90
- lines.push("}");
91
- lines.push("");
92
- if (plan.roles.cache) {
93
- lines.push('export type CacheService = ArrayIndexer.Table<ServiceManifest, "CacheController">');
94
- } else if (plan.roles.domain) {
95
- lines.push(`export type DomainService = ArrayIndexer.Table<ServiceManifest, "${plan.roles.domain}">`);
96
- } else {
97
- lines.push('export type MainService = ArrayIndexer.Table<ServiceManifest, "Main">');
98
- }
99
- if (plan.stats.length > 1) {
100
- const hide = plan.stats[plan.stats.length - 1].name;
101
- lines.push(`export type HudData = Occlude.Keys<${plan.serviceName}Data, "${hide}">`);
102
- }
103
- lines.push("");
104
- lines.push("return {}");
105
- lines.push("");
106
- return lines.join("\n");
107
- }
108
-
109
- function emitPlayersManager(plan) {
110
- return `${header(plan).trimEnd()}
111
-
112
- const Players = game:GetService("Players")
113
- const ReplicatedStorage = game:GetService("ReplicatedStorage")
114
- const Janitor = ${cluauppLib("Janitor")}
115
-
116
- type Janitor = Janitor.Janitor
117
- export type PlayerHandler = (player: Player) -> ()
118
-
119
- local PlayersManager = {}
120
- local lifetime: Janitor? = nil
121
- local leaveHandler: PlayerHandler? = nil
122
-
123
- function PlayersManager.Start(onPlayer: PlayerHandler, onLeave: PlayerHandler?)
124
- PlayersManager.Stop()
125
- local janitor = Janitor.new()
126
- lifetime = janitor
127
- leaveHandler = onLeave
128
-
129
- const function accept(player: Player)
130
- onPlayer(player)
131
- end
132
-
133
- for _, player in Players:GetPlayers() do
134
- accept(player)
135
- end
136
-
137
- janitor:Add(Players.PlayerAdded:Connect(accept), "Disconnect", "PlayerAdded")
138
- if onLeave then
139
- janitor:Add(Players.PlayerRemoving:Connect(onLeave), "Disconnect", "PlayerRemoving")
140
- end
141
- end
142
-
143
- function PlayersManager.Stop()
144
- if lifetime == nil then
145
- return
146
- end
147
- local onLeave = leaveHandler
148
- leaveHandler = nil
149
- if onLeave then
150
- for _, player in Players:GetPlayers() do
151
- onLeave(player)
152
- end
153
- end
154
- lifetime:Cleanup()
155
- lifetime = nil
156
- end
157
-
158
- return PlayersManager
159
- `;
160
- }
161
-
162
- function emitCacheController(plan) {
163
- const types = plan.typesName;
164
- const folder = plan.folderName || "leaderstats";
165
- const lines = [header(plan).trimEnd(), ""];
166
- lines.push(`const Types = require(script.Parent.${types})`);
167
- lines.push("");
168
- lines.push(`const FOLDER_NAME = "${folder}"`);
169
- lines.push("");
170
- lines.push("local cache: { [Player]: Types.PlayerCache } = {}");
171
- lines.push("local CacheController = {}");
172
- lines.push("");
173
- lines.push("function CacheController.Get(player: Player): Types.PlayerCache?");
174
- lines.push(" return cache[player]");
175
- lines.push("end");
176
- lines.push("");
177
- lines.push("function CacheController.Ensure(player: Player): Types.PlayerCache");
178
- lines.push(" local existing = cache[player]");
179
- lines.push(" if existing then");
180
- lines.push(" return existing");
181
- lines.push(" end");
182
- lines.push("");
183
- lines.push(" local folderInstance = player:FindFirstChild(FOLDER_NAME)");
184
- lines.push(" local folder: Folder");
185
- lines.push(' if folderInstance and folderInstance:IsA("Folder") then');
186
- lines.push(" folder = folderInstance");
187
- lines.push(" else");
188
- lines.push(' folder = Instance.new("Folder")');
189
- lines.push(" folder.Name = FOLDER_NAME");
190
- lines.push(" folder.Parent = player");
191
- lines.push(" end");
192
- lines.push("");
193
- for (const stat of plan.stats) {
194
- const ident = stat.name;
195
- lines.push(` local existing${ident} = folder:FindFirstChild("${stat.name}")`);
196
- lines.push(` local ${ident}: ${stat.instance}`);
197
- lines.push(` if existing${ident} and existing${ident}:IsA("${stat.instance}") then`);
198
- lines.push(` ${ident} = existing${ident}`);
199
- lines.push(" else");
200
- lines.push(` ${ident} = Instance.new("${stat.instance}")`);
201
- lines.push(` ${ident}.Name = "${stat.name}"`);
202
- lines.push(` ${ident}.Value = ${stat.defaultValue}`);
203
- lines.push(` ${ident}.Parent = folder`);
204
- lines.push(" end");
205
- lines.push("");
206
- }
207
- lines.push(" local record: Types.PlayerCache = {");
208
- lines.push(" Folder = folder,");
209
- for (const stat of plan.stats) {
210
- lines.push(` ${stat.name} = ${stat.name},`);
211
- }
212
- lines.push(" }");
213
- lines.push(" cache[player] = record");
214
- lines.push(" return record");
215
- lines.push("end");
216
- lines.push("");
217
- lines.push("function CacheController.Clear(player: Player)");
218
- lines.push(" cache[player] = nil");
219
- lines.push("end");
220
- lines.push("");
221
- lines.push("function CacheController.ClearAll()");
222
- lines.push(" table.clear(cache)");
223
- lines.push("end");
224
- lines.push("");
225
- lines.push("return CacheController");
226
- lines.push("");
227
- return lines.join("\n");
228
- }
229
-
230
- function emitMain(plan) {
231
- const lines = [header(plan).trimEnd(), ""];
232
- if (plan.roles.players) {
233
- lines.push("const PlayersManager = require(script.Parent.PlayersManager)");
234
- }
235
- if (plan.roles.cache) {
236
- lines.push("const CacheController = require(script.Parent.CacheController)");
237
- }
238
- if (plan.roles.domain) {
239
- lines.push(`const ${plan.roles.domain} = require(script.Parent.${plan.roles.domain})`);
240
- }
241
- lines.push("");
242
- lines.push("local Main = {}");
243
- lines.push("");
244
- lines.push("function Main.Start()");
245
- if (plan.roles.players && plan.roles.cache) {
246
- lines.push(" PlayersManager.Start(function(player: Player)");
247
- lines.push(" CacheController.Ensure(player)");
248
- lines.push(" end, function(player: Player)");
249
- lines.push(" CacheController.Clear(player)");
250
- lines.push(" end)");
251
- } else if (plan.roles.players) {
252
- lines.push(" PlayersManager.Start(function(_player: Player) end)");
253
- }
254
- if (plan.roles.domain) {
255
- lines.push(` ${plan.roles.domain}.Start()`);
256
- }
257
- if (!plan.roles.players && !plan.roles.domain) {
258
- lines.push(" return");
259
- }
260
- lines.push("end");
261
- lines.push("");
262
- lines.push("function Main.Stop()");
263
- if (plan.roles.domain) {
264
- lines.push(` ${plan.roles.domain}.Stop()`);
265
- }
266
- if (plan.roles.cache) {
267
- lines.push(" CacheController.ClearAll()");
268
- }
269
- if (plan.roles.players) {
270
- lines.push(" PlayersManager.Stop()");
271
- }
272
- if (!plan.roles.domain && !plan.roles.cache && !plan.roles.players) {
273
- lines.push(" return");
274
- }
275
- lines.push("end");
276
- lines.push("");
277
- lines.push("return Main");
278
- lines.push("");
279
- return lines.join("\n");
280
- }
281
-
282
- function emitBootstrap(plan) {
283
- return `${header(plan)}require(script.Main):Start()
284
- `;
285
- }
286
-
287
- function emitConfig(plan, ast, options) {
288
- const owned = (ast.body || []).some((decl) => decl.owner);
289
- if (owned) {
290
- return `${header(plan).trimEnd()}\n\n${emit(ast, { ...options, skipHeader: true, skipInit: true }).trimEnd()}\n`;
291
- }
292
- const lines = [];
293
- if (plan.onlyConsts) {
294
- lines.push(header(plan).trimEnd());
295
- lines.push("");
296
- for (const item of plan.consts) {
297
- lines.push(`const ${item.name}: ${item.luau} = ${item.value}`);
298
- }
299
- } else {
300
- lines.push(header(plan).trimEnd());
301
- lines.push("");
302
- lines.push(emit(ast, { ...options, skipHeader: true, skipInit: true }).trimEnd());
303
- }
304
- lines.push("");
305
- lines.push("return {");
306
- for (const item of plan.consts) {
307
- lines.push(` ${item.name} = ${item.name},`);
308
- }
309
- for (const decl of ast.body || []) {
310
- if (decl.type === "function" && decl.name !== "init") {
311
- lines.push(` ${decl.name} = ${decl.name},`);
312
- }
313
- }
314
- if ((ast.body || []).some((decl) => decl.type === "function" && decl.name === "init")) {
315
- lines.push(" Start = init,");
316
- lines.push(" Init = init,");
317
- lines.push(" init = init,");
318
- }
319
- lines.push("}");
320
- lines.push("");
321
- return lines.join("\n");
322
- }
323
-
324
- function emitDecls(decls, options) {
325
- if (!decls || decls.length === 0) {
326
- return "";
327
- }
328
- return emit({ type: "program", body: decls }, { ...options, skipHeader: true, skipInit: true }).trimEnd();
329
- }
330
-
331
- function emitDomainController(plan, ast, options) {
332
- const keep = (ast.body || []).filter((decl) => {
333
- return decl.type === "decl" || decl.type === "proto" || decl.type === "function" || decl.type === "expr";
334
- });
335
- const groups = organizeDecls(keep);
336
- const name = plan.roles.domain;
337
- const entry = keep.find((decl) => decl.type === "function" && ENTRY_FN.test(decl.name || ""));
338
- const bootExprs = keep.filter((decl) => decl.type === "expr");
339
- const janitors = janitorNames(keep);
340
- const closer = keep.find((decl) => decl.type === "function" && /^(OnClose|Cleanup|Shutdown)$/i.test(decl.name));
341
- const stopLines = [];
342
- if (janitors.length > 0) {
343
- for (const janitor of janitors) {
344
- stopLines.push(` ${janitor}:Cleanup()`);
345
- }
346
- } else if (closer) {
347
- stopLines.push(` ${closer.name}()`);
348
- } else {
349
- stopLines.push(" return");
350
- }
351
- const boot = entry
352
- ? ` ${entry.name}()`
353
- : bootExprs.length
354
- ? emitDecls(bootExprs, options)
355
- .split("\n")
356
- .map((line) => (line ? `\t${line}` : line))
357
- .join("\n")
358
- : " return";
359
- const startFn = `function ${name}.Start()\n ${name}.Stop()\n${boot}\nend`;
360
- const stopFn = `function ${name}.Stop()\n${stopLines.join("\n")}\nend`;
361
- 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}`)}`;
362
- return body;
363
- }
364
-
365
- function emitModule(plan, ast, options) {
366
- return emitConfig(plan, ast, options);
367
- }
368
-
369
- function emitScriptMeta(runContext) {
370
- return `${JSON.stringify(
371
- {
372
- properties: {
373
- RunContext: `Enum.RunContext.${runContext}`,
374
- },
375
- },
376
- null,
377
- "\t",
378
- )}\n`;
379
- }
380
-
381
- function serviceBootName(plan) {
382
- if (plan.isClient) {
383
- return "init.client.luau";
384
- }
385
- return "init.server.luau";
386
- }
387
-
388
- function serviceFiles(plan, ast, options, dir) {
389
- const folder = `${dir}/${plan.serviceName}`;
390
- const boot = serviceBootName(plan);
391
- const files = [{ name: `${folder}/${boot}`, contents: emitBootstrap(plan) }];
392
- if (!plan.isClient && plan.runContext) {
393
- files.push({ name: `${folder}/init.meta.json`, contents: emitScriptMeta(plan.runContext) });
394
- }
395
- files.push({ name: `${folder}/Main.luau`, contents: emitMain(plan) });
396
- if (plan.roles.players) {
397
- files.push({ name: `${folder}/PlayersManager.luau`, contents: emitPlayersManager(plan) });
398
- }
399
- if (plan.roles.cache) {
400
- files.push({ name: `${folder}/CacheController.luau`, contents: emitCacheController(plan) });
401
- }
402
- if (plan.roles.domain) {
403
- files.push({ name: `${folder}/${plan.roles.domain}.luau`, contents: emitDomainController(plan, ast, options) });
404
- }
405
- files.push({ name: `${folder}/${plan.typesName}.luau`, contents: emitTypes(plan) });
406
- return files;
407
- }
408
-
409
- function serviceFolderStale(plan, rel) {
410
- const dir = path.posix.dirname(rel).replace(/^\.$/, "");
411
- const serviceDir = dir && dir !== "." ? dir : plan.isClient ? "client" : "server";
412
- const folder = `${serviceDir}/${plan.serviceName}`;
413
- return [
414
- folder,
415
- `${folder}/init.luau`,
416
- `${folder}/init.server.luau`,
417
- `${folder}/init.client.luau`,
418
- `${folder}/init.meta.json`,
419
- `${folder}/Main.luau`,
420
- `${folder}/PlayersManager.luau`,
421
- `${folder}/CacheController.luau`,
422
- `${folder}/${plan.typesName}.luau`,
423
- plan.roles && plan.roles.domain ? `${folder}/${plan.roles.domain}.luau` : null,
424
- ].filter(Boolean);
425
- }
426
-
427
- function planOutput(ast, fileName, options = {}) {
428
- const plan = analyze(ast, fileName);
429
- plan.strict = options.strict === true;
430
- const rel = (options.relativeName || fileName).replace(/\\/g, "/");
431
- const dir = path.dirname(rel).replace(/^\.$/, "");
432
- const outDir = dir && dir !== "." ? dir : "";
433
- const prefix = outDir ? `${outDir}/` : "";
434
- const stale = serviceFolderStale(plan, rel);
435
-
436
- if (options.siblingHeader) {
437
- return {
438
- kind: "module",
439
- plan,
440
- files: [{ name: implOutName(rel), contents: emitModule(plan, ast, { ...options, skipInit: true }) }],
441
- stale: [],
442
- };
443
- }
444
-
445
- if (options.architecture === true) {
446
- if (plan.kind === "legacy") {
447
- return { kind: "legacy", plan, files: null, stale: [], outName: legacyOutName(rel) };
448
- }
449
-
450
- if (plan.kind === "service") {
451
- const serviceDir = outDir || (plan.isClient ? "client" : "server");
452
- const folder = `${serviceDir}/${plan.serviceName}`;
453
- const serviceStale = plan.isClient
454
- ? [`${folder}/init.luau`, `${folder}/init.server.luau`, `${folder}/init.meta.json`]
455
- : [`${folder}/init.luau`, `${folder}/init.client.luau`];
456
- return {
457
- kind: "service",
458
- plan,
459
- files: serviceFiles(plan, ast, options, serviceDir),
460
- stale: serviceStale,
461
- };
462
- }
463
-
464
- if (plan.kind === "config" || plan.kind === "module") {
465
- return {
466
- kind: plan.kind,
467
- plan,
468
- files: [{ name: `${prefix}${plan.serviceName}.luau`, contents: emitModule(plan, ast, options) }],
469
- stale: [rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau")],
470
- };
471
- }
472
-
473
- return { kind: "flat", plan, files: null, stale: [], outName: modernScriptOutName(rel) };
474
- }
475
-
476
- if (plan.kind === "legacy") {
477
- return { kind: "legacy", plan, files: null, stale, outName: legacyOutName(rel) };
478
- }
479
-
480
- if (plan.kind === "config" || plan.kind === "module") {
481
- return {
482
- kind: plan.kind,
483
- plan,
484
- files: [{ name: `${prefix}${plan.serviceName}.luau`, contents: emitModule(plan, ast, options) }],
485
- stale: [rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau"), ...stale],
486
- };
487
- }
488
-
489
- const outName = modernScriptOutName(rel);
490
- const stripped = rel.replace(/\.(server|client|plugin)\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau");
491
- const extraStale = stripped !== outName ? [stripped] : [];
492
- return { kind: "flat", plan, files: null, stale: [...stale, ...extraStale], outName };
493
- }
494
-
495
- export {
496
- analyze,
497
- planOutput,
498
- toPascalServiceName,
499
- VALUE_CLASSES,
500
- };
package/src/ast.ts DELETED
@@ -1,37 +0,0 @@
1
- import type { CompileOptions } from "./types.js";
2
-
3
- export type Token = {
4
- type: string;
5
- value: string;
6
- line: number;
7
- col: number;
8
- start: number;
9
- end: number;
10
- };
11
-
12
- export type AstNode = {
13
- type: string;
14
- [key: string]: any;
15
- };
16
-
17
- export type AstProgram = {
18
- type: string;
19
- body: AstNode[];
20
- fileName: string;
21
- };
22
-
23
- export type ModuleInclude = {
24
- name: string;
25
- outRel: string;
26
- header?: string;
27
- impl?: string | null;
28
- exports?: { consts?: string[]; structs?: string[]; hasProtos?: boolean };
29
- };
30
-
31
- export type PreprocessOptions = CompileOptions & {
32
- pragmaResolved?: boolean;
33
- seen?: Set<string>;
34
- moduleIncludes?: ModuleInclude[];
35
- siblingHeader?: string | null;
36
- source?: string;
37
- };