cluaupp 1.5.0 → 1.5.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.
- package/CHANGELOG.md +47 -0
- package/README.md +10 -5
- package/api/CHANGELOG.md +3 -0
- package/api/chat.js +74 -0
- package/api/fixtures/roblox/README.md +6 -0
- package/api/fixtures/roblox/aux/sample.d.luau +6 -0
- package/api/fixtures/roblox/mini/Mini-API-Dump.json +72 -0
- package/api/generated/bench-latest.json +39 -0
- package/api/generated/capability-profile.json +76 -0
- package/api/generated/lsp-index.json +1 -0
- package/api/generated/luau/classes.d.luau +11221 -0
- package/api/generated/luau/datatypes.d.luau +327 -0
- package/api/generated/luau/enums.d.luau +4918 -0
- package/api/generated/luau/globals.d.luau +12 -0
- package/api/manifests/roblox-target.manifest.json +22 -0
- package/api/normalized/roblox-target.profile.json +237461 -0
- package/api/overrides/classes.json +8 -0
- package/api/overrides/compatibility.json +9 -0
- package/api/overrides/datatypes.json +1579 -0
- package/api/overrides/enums.json +8 -0
- package/api/overrides/globals.json +8 -0
- package/api/overrides/type-mappings.json +9 -0
- package/api/roblox-api.lock.json +9 -0
- package/data/Mini-API-Dump.json +1 -0
- package/editors/vscode/README.md +12 -10
- package/editors/vscode/extension.js +82 -0
- package/editors/vscode/icons/axiom.svg +4 -0
- package/editors/vscode/icons/bloom.svg +5 -0
- package/editors/vscode/icons/helm.svg +4 -0
- package/editors/vscode/icons/hive.svg +5 -0
- package/editors/vscode/icons/mint.svg +4 -0
- package/editors/vscode/icons/shift.svg +6 -0
- package/editors/vscode/language-configuration-schema.json +24 -0
- package/editors/vscode/package.json +172 -12
- package/editors/vscode/snippets/axiom.json +12 -0
- package/editors/vscode/snippets/bloom.json +12 -0
- package/editors/vscode/snippets/helm.json +12 -0
- package/editors/vscode/snippets/hive.json +12 -0
- package/editors/vscode/snippets/mint.json +12 -0
- package/editors/vscode/snippets/shift.json +17 -0
- package/editors/vscode/syntaxes/axiom.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/bloom.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/helm.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/hive.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/mint.tmLanguage.json +5 -0
- package/editors/vscode/syntaxes/schema.tmLanguage.json +89 -0
- package/editors/vscode/syntaxes/shift.tmLanguage.json +5 -0
- package/examples/game/.cluaupp/compile-cache/ReplicatedStorage__Shared__Constants__Datas__TemplateData.clh.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Boot__DataBoot.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Configuration__ServerConfig.clp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__Guard.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/ServerScriptService__Handlers__PlayerHandler.server.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterCharacterScripts__Character__CharacterReady.client.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/StarterPlayer__StarterPlayerScripts__Controllers__DataController.client.clpp.json +1 -0
- package/examples/game/.cluaupp/compile-cache/index.json +12 -0
- package/examples/game/.cluaupp/datamodel-profile.json +94 -0
- package/examples/game/.vscode/settings.json +12 -1
- package/examples/game/include/clpp/datatypes.clh +337 -373
- package/examples/game/include/clpp/generated/datamodel.clh +25 -0
- package/examples/game/include/clpp/generated/enums.clh +1 -1
- package/examples/game/include/clpp/generated/instances.clh +41135 -41064
- package/examples/game/include/clpp/libs/axiom.clh +1 -1
- package/examples/game/include/clpp/libs/math.clh +14 -0
- package/examples/game/include/clpp/libs/spring.clh +17 -0
- package/examples/game/include/clpp/libs/ward.clh +1 -0
- package/examples/game/include/clpp/roblox.clh +3 -4
- package/examples/game/libs/ArrayIndexer/init.luau +209 -0
- package/examples/game/libs/Axiom/init.luau +608 -0
- package/examples/game/libs/Bloom/init.luau +433 -0
- package/examples/game/libs/Coil/init.luau +215 -0
- package/examples/game/libs/Crest/init.luau +426 -0
- package/examples/game/libs/Echo/init.luau +417 -0
- package/examples/game/libs/Ember/init.luau +365 -0
- package/examples/game/libs/Flare/init.luau +717 -0
- package/examples/game/libs/Gleam/init.luau +729 -0
- package/examples/game/libs/Guide/init.luau +215 -0
- package/examples/game/libs/Helm/init.luau +377 -0
- package/examples/game/libs/Hive/init.luau +241 -0
- package/examples/game/libs/Keep/Client.luau +114 -0
- package/examples/game/libs/Keep/Data.luau +883 -0
- package/examples/game/libs/Keep/Engine.luau +211 -0
- package/examples/game/libs/Keep/Enum.luau +6 -0
- package/examples/game/libs/Keep/Enums.luau +10 -0
- package/examples/game/libs/Keep/Path.luau +236 -0
- package/examples/game/libs/Keep/Replicator.luau +298 -0
- package/examples/game/libs/Keep/Server.luau +251 -0
- package/examples/game/libs/Keep/Store.luau +652 -0
- package/examples/game/libs/Keep/Trade.luau +455 -0
- package/examples/game/libs/Keep/init.luau +205 -0
- package/examples/game/libs/Lens/init.luau +609 -0
- package/examples/game/libs/Mint/init.luau +279 -0
- package/examples/game/libs/Net/init.luau +156 -0
- package/examples/game/libs/Net/src/codec.luau +224 -0
- package/examples/game/libs/Occlude/init.luau +117 -0
- package/examples/game/libs/Pin/init.luau +309 -0
- package/examples/game/libs/Promise/LICENSE +21 -0
- package/examples/game/libs/Promise/_impl/LICENSE +21 -0
- package/examples/game/libs/Promise/_impl/init.lua +1991 -0
- package/examples/game/libs/Promise/init.lua +1990 -0
- package/examples/game/libs/Promise/init.luau +13 -0
- package/examples/game/libs/Promise/types.luau +46 -0
- package/examples/game/libs/Roster/init.luau +686 -0
- package/examples/game/libs/SOURCES.md +31 -0
- package/examples/game/libs/Shift/init.luau +238 -0
- package/examples/game/libs/Spark/init.luau +487 -0
- package/examples/game/libs/Stage/init.luau +178 -0
- package/examples/game/libs/Sweep/init.luau +259 -0
- package/examples/game/libs/Trace/init.luau +213 -0
- package/examples/game/libs/Ward/init.luau +211 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +29 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +13 -0
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +83 -0
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +18 -0
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +14 -0
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +15 -0
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +50 -0
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +12 -0
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +16 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +13 -0
- package/examples/game/src/ReplicatedStorage/Shared/Net/Net.clh +26 -0
- package/examples/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
- package/examples/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
- package/examples/game/stylua.toml +9 -0
- package/generated/api/build-profile.js +115 -0
- package/generated/api/cache.js +44 -0
- package/generated/api/coverage.js +32 -0
- package/generated/api/diff.js +125 -0
- package/generated/api/generators/clpp-headers.js +353 -0
- package/generated/api/generators/docs-reference.js +7 -0
- package/generated/api/generators/lsp-index.js +81 -0
- package/generated/api/generators/luau-defs.js +94 -0
- package/generated/api/ide.js +76 -0
- package/generated/api/identifier.js +47 -0
- package/generated/api/index.js +324 -0
- package/generated/api/loader.js +57 -0
- package/generated/api/merge.js +88 -0
- package/generated/api/model.js +5 -0
- package/generated/api/normalize.js +231 -0
- package/generated/api/overrides-validate.js +58 -0
- package/generated/api/perf.js +12 -0
- package/generated/api/registry.js +136 -0
- package/generated/api/release.js +44 -0
- package/generated/api/resolver.js +250 -0
- package/generated/api/sources/aux-types-diff.js +75 -0
- package/generated/api/sources/client-tracker.js +11 -0
- package/generated/api/sources/creator-docs.js +42 -0
- package/generated/api/sources/luau-types.js +34 -0
- package/generated/api/sources/mini-dump.js +17 -0
- package/generated/api/sources/studio-api.js +8 -0
- package/generated/api/sources/studio-apiv2.js +11 -0
- package/generated/api/sources/studio-full-api.js +8 -0
- package/generated/api/studio-smoke.js +80 -0
- package/generated/api/type-parse.js +49 -0
- package/generated/api/understander.js +51 -0
- package/generated/api/validate.js +135 -0
- package/generated/api-cli.js +421 -0
- package/generated/cli.js +16 -5
- package/generated/clpp/contract.js +3 -3
- package/generated/clpp/format-luau.js +236 -0
- package/generated/clpp/index.js +13 -1
- package/generated/clpp/modules.js +227 -0
- package/generated/clpp/postprocess.js +86 -5
- package/generated/clpp/rewrite-janitor.js +145 -0
- package/generated/clpp/runner.js +14 -2
- package/generated/compile.js +82 -0
- package/generated/flare/parse.js +12 -1
- package/generated/intellisense.js +57 -1
- package/generated/native/index.js +217 -16
- package/generated/target/authority-check.js +136 -0
- package/generated/target/authority-graph.js +74 -0
- package/generated/target/build-cache.js +112 -0
- package/generated/target/capabilities.js +89 -0
- package/generated/target/capability-profile.js +30 -0
- package/generated/target/component-contracts.js +60 -0
- package/generated/target/context-check.js +160 -0
- package/generated/target/datamodel-check.js +170 -0
- package/generated/target/datamodel-generate.js +74 -0
- package/generated/target/datamodel.js +233 -0
- package/generated/target/diagnostics.js +63 -0
- package/generated/target/doctor.js +152 -0
- package/generated/target/flare-version.js +58 -0
- package/generated/target/get-service.js +69 -0
- package/generated/target/lifetime-check.js +47 -0
- package/generated/target/luau-stamp.js +39 -0
- package/generated/target/optimizer-advise.js +88 -0
- package/generated/target/optimizer-apply.js +44 -0
- package/generated/target/optimizer-soa.js +254 -0
- package/generated/target/parallel-check.js +136 -0
- package/generated/target/pgo.js +148 -0
- package/generated/target/project-docs.js +69 -0
- package/generated/target/project-graph.js +71 -0
- package/generated/target/roblox.js +63 -0
- package/generated/target/security-check.js +41 -0
- package/generated/target/source-map.js +25 -0
- package/generated/target/studio-bridge.js +112 -0
- package/generated/utils/project.js +178 -8
- package/generated/utils/rojo-mapper.js +11 -3
- package/include/clpp/datatypes.clh +337 -373
- package/include/clpp/generated/enums.clh +1 -1
- package/include/clpp/generated/instances.clh +41135 -41064
- package/include/clpp/libs/axiom.clh +1 -1
- package/include/clpp/libs/hive.clh +1 -0
- package/include/clpp/libs/keep.clh +2 -0
- package/include/clpp/libs/math.clh +14 -0
- package/include/clpp/libs/spring.clh +17 -0
- package/include/clpp/libs/ward.clh +1 -0
- package/include/clpp/roblox.clh +3 -4
- package/package.json +10 -3
- package/plugins/CluauppNav/Plugin.luau +207 -0
- package/plugins/CluauppNav/ProfileLogger.luau +27 -0
- package/plugins/CluauppNav/README.md +24 -0
- package/runtime/Axiom/init.luau +10 -7
- package/runtime/Coil/init.luau +8 -2
- package/runtime/Crest/init.luau +1 -0
- package/runtime/Flare/init.luau +2 -1
- package/runtime/Gleam/init.luau +15 -4
- package/runtime/Hive/init.luau +36 -14
- package/runtime/Pin/init.luau +5 -2
- package/runtime/Roster/init.luau +2 -0
- package/runtime/Spark/init.luau +3 -0
- package/runtime/Sweep/init.luau +2 -0
- package/runtime/Trace/init.luau +3 -0
- package/runtime/Ward/init.luau +38 -5
- package/scripts/postinstall-editor.js +17 -0
- package/skills/README.md +13 -0
- package/skills/clpp-hive-flare/SKILL.md +79 -0
- package/skills/clpp-language/SKILL.md +123 -0
- package/skills/clpp-language/compiler.md +89 -0
- package/skills/clpp-style/SKILL.md +95 -0
- package/src/api/build-profile.ts +138 -0
- package/src/api/cache.ts +45 -0
- package/src/api/coverage.ts +46 -0
- package/src/api/diff.ts +143 -0
- package/src/api/generators/clpp-headers.ts +377 -0
- package/src/api/generators/docs-reference.ts +11 -0
- package/src/api/generators/lsp-index.ts +106 -0
- package/src/api/generators/luau-defs.ts +98 -0
- package/src/api/ide.ts +87 -0
- package/src/api/identifier.ts +47 -0
- package/src/api/index.ts +269 -0
- package/src/api/loader.ts +60 -0
- package/src/api/merge.ts +126 -0
- package/src/api/model.ts +283 -0
- package/src/api/normalize.ts +257 -0
- package/src/api/overrides-validate.ts +58 -0
- package/src/api/perf.ts +15 -0
- package/src/api/registry.ts +162 -0
- package/src/api/release.ts +47 -0
- package/src/api/resolver.ts +255 -0
- package/src/api/sources/aux-types-diff.ts +81 -0
- package/src/api/sources/client-tracker.ts +10 -0
- package/src/api/sources/creator-docs.ts +37 -0
- package/src/api/sources/luau-types.ts +30 -0
- package/src/api/sources/mini-dump.ts +50 -0
- package/src/api/sources/studio-api.ts +7 -0
- package/src/api/sources/studio-apiv2.ts +10 -0
- package/src/api/sources/studio-full-api.ts +7 -0
- package/src/api/studio-smoke.ts +82 -0
- package/src/api/type-parse.ts +48 -0
- package/src/api/understander.ts +72 -0
- package/src/api/validate.ts +160 -0
- package/src/api-cli.ts +493 -0
- package/src/api.generated.js +37 -22
- package/src/cli.ts +21 -6
- package/src/clpp/contract.ts +34 -3
- package/src/clpp/format-luau.ts +262 -0
- package/src/clpp/index.ts +13 -2
- package/src/clpp/modules.ts +252 -0
- package/src/clpp/postprocess.ts +100 -5
- package/src/clpp/rewrite-janitor.ts +156 -0
- package/src/clpp/runner.ts +14 -2
- package/src/compile.ts +87 -0
- package/src/flare/parse.ts +14 -1
- package/src/flare/types.ts +2 -0
- package/src/intellisense.ts +58 -1
- package/src/native/index.ts +225 -16
- package/src/target/authority-check.ts +162 -0
- package/src/target/authority-graph.ts +80 -0
- package/src/target/build-cache.ts +129 -0
- package/src/target/capabilities.ts +115 -0
- package/src/target/capability-profile.ts +25 -0
- package/src/target/component-contracts.ts +64 -0
- package/src/target/context-check.ts +177 -0
- package/src/target/datamodel-check.ts +188 -0
- package/src/target/datamodel-generate.ts +78 -0
- package/src/target/datamodel.ts +261 -0
- package/src/target/diagnostics.ts +67 -0
- package/src/target/doctor.ts +171 -0
- package/src/target/flare-version.ts +61 -0
- package/src/target/get-service.ts +85 -0
- package/src/target/lifetime-check.ts +45 -0
- package/src/target/luau-stamp.ts +33 -0
- package/src/target/optimizer-advise.ts +93 -0
- package/src/target/optimizer-apply.ts +63 -0
- package/src/target/optimizer-soa.ts +270 -0
- package/src/target/parallel-check.ts +135 -0
- package/src/target/pgo.ts +157 -0
- package/src/target/project-docs.ts +68 -0
- package/src/target/project-graph.ts +75 -0
- package/src/target/roblox.ts +78 -0
- package/src/target/security-check.ts +40 -0
- package/src/target/source-map.ts +36 -0
- package/src/target/studio-bridge.ts +140 -0
- package/src/types.ts +14 -0
- package/src/utils/project.ts +183 -9
- package/src/utils/rojo-mapper.ts +12 -3
- package/stylua.toml +9 -0
- package/templates/game/.vscode/settings.json +7 -1
- package/templates/game/include/clpp/datatypes.clh +337 -373
- package/templates/game/include/clpp/generated/enums.clh +1 -1
- package/templates/game/include/clpp/generated/instances.clh +41135 -41064
- package/templates/game/include/clpp/libs/axiom.clh +1 -1
- package/templates/game/include/clpp/libs/ward.clh +1 -0
- package/templates/game/include/clpp/roblox.clh +3 -4
- package/templates/game/src/ServerScriptService/Boot/DataBoot.server.clpp +1 -1
- package/templates/game/src/ServerScriptService/Handlers/PlayerHandler.server.clpp +1 -1
- package/templates/game/stylua.toml +9 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generate project documentation from DataModel + graph + Flare + advice.
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.generateProjectDocs = generateProjectDocs;
|
|
10
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const datamodel_js_1 = require("./datamodel.js");
|
|
13
|
+
const project_graph_js_1 = require("./project-graph.js");
|
|
14
|
+
const flare_version_js_1 = require("./flare-version.js");
|
|
15
|
+
const paths_js_1 = require("../clpp/paths.js");
|
|
16
|
+
const optimizer_advise_js_1 = require("./optimizer-advise.js");
|
|
17
|
+
function generateProjectDocs(projectRoot, rootDir = "src") {
|
|
18
|
+
const dm = (0, datamodel_js_1.buildDatamodelProfile)(projectRoot);
|
|
19
|
+
const graph = (0, project_graph_js_1.buildProjectGraph)(projectRoot, rootDir);
|
|
20
|
+
const flare = (0, flare_version_js_1.checkFlareVersions)(projectRoot, rootDir);
|
|
21
|
+
const srcDir = node_path_1.default.join(projectRoot, rootDir);
|
|
22
|
+
const files = node_fs_1.default.existsSync(srcDir) ? (0, paths_js_1.collectSources)(srcDir) : [];
|
|
23
|
+
const advice = [];
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const rel = node_path_1.default.relative(projectRoot, file).replace(/\\/g, "/");
|
|
26
|
+
for (const a of (0, optimizer_advise_js_1.adviseOptimizer)(node_fs_1.default.readFileSync(file, "utf8"), rel)) {
|
|
27
|
+
advice.push(`- **${a.target}** (${a.kind}): ${a.message}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const paths = dm
|
|
31
|
+
? Object.keys(dm.byPath)
|
|
32
|
+
.filter((p) => p !== "DataModel")
|
|
33
|
+
.sort()
|
|
34
|
+
.map((p) => `- \`${p}\` — ${dm.byPath[p].className}`)
|
|
35
|
+
.join("\n")
|
|
36
|
+
: "_no default.project.json_";
|
|
37
|
+
const markdown = [
|
|
38
|
+
`# Cluaupp project docs`,
|
|
39
|
+
``,
|
|
40
|
+
`Generated: ${new Date().toISOString()}`,
|
|
41
|
+
``,
|
|
42
|
+
`## DataModel`,
|
|
43
|
+
``,
|
|
44
|
+
paths,
|
|
45
|
+
``,
|
|
46
|
+
`## Modules (${graph.nodes.length})`,
|
|
47
|
+
``,
|
|
48
|
+
graph.nodes.map((n) => `- \`${n}\``).join("\n") || "_none_",
|
|
49
|
+
``,
|
|
50
|
+
`## Dependencies`,
|
|
51
|
+
``,
|
|
52
|
+
graph.edges.map((e) => `- \`${e.from}\` → \`${e.to}\``).join("\n") || "_none_",
|
|
53
|
+
``,
|
|
54
|
+
graph.cycles.length ? `### Cycles\n\n${graph.cycles.map((c) => `- ${c.join(" → ")}`).join("\n")}\n` : "",
|
|
55
|
+
`## Flare contracts`,
|
|
56
|
+
``,
|
|
57
|
+
flare.files.map((f) => `- \`${f.file}\` name=\`${f.name}\` version=${f.version ?? "unset"}`).join("\n") || "_none_",
|
|
58
|
+
``,
|
|
59
|
+
`## Optimizer advice`,
|
|
60
|
+
``,
|
|
61
|
+
advice.slice(0, 40).join("\n") || "_none_",
|
|
62
|
+
``,
|
|
63
|
+
].join("\n");
|
|
64
|
+
const outDir = node_path_1.default.join(projectRoot, ".cluaupp");
|
|
65
|
+
node_fs_1.default.mkdirSync(outDir, { recursive: true });
|
|
66
|
+
const outPath = node_path_1.default.join(outDir, "PROJECT.md");
|
|
67
|
+
node_fs_1.default.writeFileSync(outPath, markdown, "utf8");
|
|
68
|
+
return { outPath, markdown };
|
|
69
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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.buildProjectGraph = buildProjectGraph;
|
|
7
|
+
/** Project include/import/require graph + circular dependency detection. */
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const modules_js_1 = require("../clpp/modules.js");
|
|
11
|
+
const paths_js_1 = require("../clpp/paths.js");
|
|
12
|
+
function findCycles(nodes, edges) {
|
|
13
|
+
const adj = new Map();
|
|
14
|
+
for (const n of nodes)
|
|
15
|
+
adj.set(n, []);
|
|
16
|
+
for (const e of edges) {
|
|
17
|
+
if (!adj.has(e.from))
|
|
18
|
+
adj.set(e.from, []);
|
|
19
|
+
adj.get(e.from).push(e.to);
|
|
20
|
+
}
|
|
21
|
+
const cycles = [];
|
|
22
|
+
const visiting = new Set();
|
|
23
|
+
const visited = new Set();
|
|
24
|
+
const stack = [];
|
|
25
|
+
function dfs(n) {
|
|
26
|
+
if (visiting.has(n)) {
|
|
27
|
+
const i = stack.indexOf(n);
|
|
28
|
+
if (i >= 0)
|
|
29
|
+
cycles.push(stack.slice(i).concat(n));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (visited.has(n))
|
|
33
|
+
return;
|
|
34
|
+
visiting.add(n);
|
|
35
|
+
stack.push(n);
|
|
36
|
+
for (const to of adj.get(n) || [])
|
|
37
|
+
dfs(to);
|
|
38
|
+
stack.pop();
|
|
39
|
+
visiting.delete(n);
|
|
40
|
+
visited.add(n);
|
|
41
|
+
}
|
|
42
|
+
for (const n of nodes)
|
|
43
|
+
dfs(n);
|
|
44
|
+
return cycles;
|
|
45
|
+
}
|
|
46
|
+
function buildProjectGraph(projectRoot, rootDir = "src") {
|
|
47
|
+
const srcDir = node_path_1.default.join(projectRoot, rootDir);
|
|
48
|
+
const files = node_fs_1.default.existsSync(srcDir) ? (0, paths_js_1.collectSources)(srcDir) : [];
|
|
49
|
+
const nodes = [];
|
|
50
|
+
const edges = [];
|
|
51
|
+
const byAbs = new Map();
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
const rel = node_path_1.default.relative(projectRoot, file).replace(/\\/g, "/");
|
|
54
|
+
nodes.push(rel);
|
|
55
|
+
byAbs.set(node_path_1.default.resolve(file), rel);
|
|
56
|
+
}
|
|
57
|
+
for (const file of files) {
|
|
58
|
+
const rel = node_path_1.default.relative(projectRoot, file).replace(/\\/g, "/");
|
|
59
|
+
const source = node_fs_1.default.readFileSync(file, "utf8");
|
|
60
|
+
for (const mod of (0, modules_js_1.collectLanguageModulePaths)(source)) {
|
|
61
|
+
const resolved = (0, modules_js_1.resolveModuleFile)(mod, file, srcDir);
|
|
62
|
+
if (!resolved)
|
|
63
|
+
continue;
|
|
64
|
+
const hit = byAbs.get(node_path_1.default.resolve(resolved));
|
|
65
|
+
if (hit && hit !== rel) {
|
|
66
|
+
edges.push({ from: rel, to: hit });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { nodes, edges, cycles: findCycles(nodes, edges) };
|
|
71
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FILE_TAG_TO_CONTEXT = void 0;
|
|
4
|
+
exports.runContextFromFileName = runContextFromFileName;
|
|
5
|
+
exports.defaultRobloxProject = defaultRobloxProject;
|
|
6
|
+
exports.resolveGetServiceType = resolveGetServiceType;
|
|
7
|
+
exports.isRegisteredService = isRegisteredService;
|
|
8
|
+
exports.targetProfileSummary = targetProfileSummary;
|
|
9
|
+
const model_js_1 = require("../api/model.js");
|
|
10
|
+
const build_profile_js_1 = require("../api/build-profile.js");
|
|
11
|
+
exports.FILE_TAG_TO_CONTEXT = {
|
|
12
|
+
".server": "Server",
|
|
13
|
+
".client": "Client",
|
|
14
|
+
".plugin": "Plugin",
|
|
15
|
+
};
|
|
16
|
+
function runContextFromFileName(fileName) {
|
|
17
|
+
const lower = fileName.toLowerCase();
|
|
18
|
+
if (lower.includes(".server.")) {
|
|
19
|
+
return "Server";
|
|
20
|
+
}
|
|
21
|
+
if (lower.includes(".client.")) {
|
|
22
|
+
return "Client";
|
|
23
|
+
}
|
|
24
|
+
if (lower.includes(".plugin.")) {
|
|
25
|
+
return "Plugin";
|
|
26
|
+
}
|
|
27
|
+
return "Shared";
|
|
28
|
+
}
|
|
29
|
+
function defaultRobloxProject() {
|
|
30
|
+
return {
|
|
31
|
+
kind: "roblox",
|
|
32
|
+
libsFolderName: "CluauppLibs",
|
|
33
|
+
legacyLibsAlias: "ClppLibs",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Target-side GetService\<T\> — **Cluaupp Roblox Target feature**, not a CL++ language rule.
|
|
38
|
+
* CL++ only provides generic-call syntax (`GetService<Players>()`); Cluaupp maps T via the
|
|
39
|
+
* Canonical Registry, Context Safety, and headers under `#include <clpp/roblox.clh>`.
|
|
40
|
+
*/
|
|
41
|
+
function resolveGetServiceType(typeName, profile) {
|
|
42
|
+
const p = profile || (0, build_profile_js_1.buildRobloxTargetProfile)({ skipValidate: true });
|
|
43
|
+
if (p.services[typeName]) {
|
|
44
|
+
return typeName;
|
|
45
|
+
}
|
|
46
|
+
if (p.classes[typeName]?.service || p.classes[typeName]?.creation.service) {
|
|
47
|
+
return typeName;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
/** True when `name` is a registered Roblox service class. */
|
|
52
|
+
function isRegisteredService(name, profile) {
|
|
53
|
+
return resolveGetServiceType(name, profile) != null;
|
|
54
|
+
}
|
|
55
|
+
function targetProfileSummary() {
|
|
56
|
+
const profile = (0, build_profile_js_1.buildRobloxTargetProfile)({ skipValidate: true });
|
|
57
|
+
return {
|
|
58
|
+
schemaVersion: model_js_1.ROBLOX_TARGET_SCHEMA_VERSION,
|
|
59
|
+
target: "roblox",
|
|
60
|
+
classes: Object.keys(profile.classes).length,
|
|
61
|
+
services: Object.keys(profile.services).length,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkSecurity = checkSecurity;
|
|
4
|
+
/** Static security patterns (CLUAU-SEC*) — not a runtime anti-cheat. */
|
|
5
|
+
const roblox_js_1 = require("./roblox.js");
|
|
6
|
+
const diagnostics_js_1 = require("./diagnostics.js");
|
|
7
|
+
const CLIENT_PATTERNS = [
|
|
8
|
+
{ code: "CLUAU_SEC001", re: /\bCoins\s*=/, message: "Client appears to assign Coins — server must own currency" },
|
|
9
|
+
{ code: "CLUAU_SEC002", re: /\bDamage\s*=\s*[^=]/, message: "Client appears to set Damage — prefer server authority" },
|
|
10
|
+
{ code: "CLUAU_SEC003", re: /FireServer\s*\([^)]*Instance/, message: "Remote may accept unrestricted Instance from client" },
|
|
11
|
+
{ code: "CLUAU_SEC004", re: /Inventory.*=.*FireServer|FireServer.*Inventory/, message: "Client-supplied inventory result smell" },
|
|
12
|
+
];
|
|
13
|
+
const SERVER_PATTERNS = [
|
|
14
|
+
{ code: "CLUAU_SEC010", re: /FireServer/, message: "Server calling FireServer is inverted authority" },
|
|
15
|
+
{
|
|
16
|
+
code: "CLUAU_SEC011",
|
|
17
|
+
re: /\.Position\b[^\n]*player|player[^\n]*\.Position/,
|
|
18
|
+
message: "Server may be trusting client Position — validate or ignore client transform",
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
function checkSecurity(source, fileName) {
|
|
22
|
+
const ctx = (0, roblox_js_1.runContextFromFileName)(fileName);
|
|
23
|
+
const clean = (0, diagnostics_js_1.stripCommentsKeepStrings)(source);
|
|
24
|
+
const out = [];
|
|
25
|
+
const list = ctx === "Client" ? CLIENT_PATTERNS : ctx === "Server" ? SERVER_PATTERNS : [];
|
|
26
|
+
for (const p of list) {
|
|
27
|
+
const m = p.re.exec(clean);
|
|
28
|
+
if (!m)
|
|
29
|
+
continue;
|
|
30
|
+
const { line, column } = (0, diagnostics_js_1.lineColAt)(clean, m.index);
|
|
31
|
+
out.push({
|
|
32
|
+
code: p.code,
|
|
33
|
+
message: p.message,
|
|
34
|
+
line,
|
|
35
|
+
column,
|
|
36
|
+
severity: "warning",
|
|
37
|
+
file: fileName,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
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.writeSourceMap = writeSourceMap;
|
|
7
|
+
/** Minimal source map: CL++ path ↔ emitted Luau (1:1 file mapping for v1). */
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
function writeSourceMap(opts) {
|
|
11
|
+
const map = {
|
|
12
|
+
version: 1,
|
|
13
|
+
file: node_path_1.default.basename(opts.outLuauPath),
|
|
14
|
+
sourceRoot: opts.projectRoot.replace(/\\/g, "/"),
|
|
15
|
+
sources: [opts.sourceClppRel.replace(/\\/g, "/")],
|
|
16
|
+
mappings: "AAAA", // identity stub — refine when clpp emits VLQ maps
|
|
17
|
+
cluaupp: {
|
|
18
|
+
source: opts.sourceClppRel.replace(/\\/g, "/"),
|
|
19
|
+
generated: node_path_1.default.relative(opts.projectRoot, opts.outLuauPath).replace(/\\/g, "/"),
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const mapPath = opts.outLuauPath + ".map.json";
|
|
23
|
+
node_fs_1.default.writeFileSync(mapPath, JSON.stringify(map, null, "\t") + "\n", "utf8");
|
|
24
|
+
return mapPath;
|
|
25
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Local HTTP bridge: Studio plugin ↔ IDE (VS Code / Cursor).
|
|
4
|
+
* Default port 3847. Studio POSTs open requests; IDE polls /events.
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.BRIDGE_DEFAULT_PORT = void 0;
|
|
11
|
+
exports.startStudioBridge = startStudioBridge;
|
|
12
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
13
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
15
|
+
const node_events_1 = require("node:events");
|
|
16
|
+
exports.BRIDGE_DEFAULT_PORT = 3847;
|
|
17
|
+
function startStudioBridge(opts = {}) {
|
|
18
|
+
const port = opts.port ?? exports.BRIDGE_DEFAULT_PORT;
|
|
19
|
+
const bus = new node_events_1.EventEmitter();
|
|
20
|
+
const events = [];
|
|
21
|
+
let nextId = 1;
|
|
22
|
+
const push = (partial) => {
|
|
23
|
+
const ev = {
|
|
24
|
+
id: nextId++,
|
|
25
|
+
at: new Date().toISOString(),
|
|
26
|
+
...partial,
|
|
27
|
+
};
|
|
28
|
+
events.push(ev);
|
|
29
|
+
if (events.length > 200)
|
|
30
|
+
events.shift();
|
|
31
|
+
bus.emit("event", ev);
|
|
32
|
+
opts.onEvent?.(ev);
|
|
33
|
+
return ev;
|
|
34
|
+
};
|
|
35
|
+
const server = node_http_1.default.createServer((req, res) => {
|
|
36
|
+
const url = new URL(req.url || "/", `http://127.0.0.1:${port}`);
|
|
37
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
38
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
39
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
40
|
+
if (req.method === "OPTIONS") {
|
|
41
|
+
res.writeHead(204);
|
|
42
|
+
res.end();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (req.method === "GET" && url.pathname === "/health") {
|
|
46
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
47
|
+
res.end(JSON.stringify({ ok: true, service: "cluaupp-bridge", port }));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (req.method === "GET" && url.pathname === "/events") {
|
|
51
|
+
const since = Number(url.searchParams.get("since") || "0");
|
|
52
|
+
const batch = events.filter((e) => e.id > since);
|
|
53
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54
|
+
res.end(JSON.stringify({ events: batch }));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (req.method === "POST" && url.pathname === "/open") {
|
|
58
|
+
let body = "";
|
|
59
|
+
req.on("data", (c) => {
|
|
60
|
+
body += c;
|
|
61
|
+
if (body.length > 1_000_000)
|
|
62
|
+
req.destroy();
|
|
63
|
+
});
|
|
64
|
+
req.on("end", () => {
|
|
65
|
+
try {
|
|
66
|
+
const data = JSON.parse(body || "{}");
|
|
67
|
+
const rel = (data.path || "").replace(/\\/g, "/");
|
|
68
|
+
if (opts.projectRoot && rel && !rel.includes("..")) {
|
|
69
|
+
const abs = node_path_1.default.resolve(opts.projectRoot, rel);
|
|
70
|
+
if (!abs.startsWith(node_path_1.default.resolve(opts.projectRoot))) {
|
|
71
|
+
res.writeHead(400);
|
|
72
|
+
res.end("bad path");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!node_fs_1.default.existsSync(abs) && !rel.endsWith(".clpp") && !rel.endsWith(".clh")) {
|
|
76
|
+
/* still emit — file may be unsaved emit path */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const ev = push({
|
|
80
|
+
type: data.type || "open",
|
|
81
|
+
path: rel || undefined,
|
|
82
|
+
line: data.line,
|
|
83
|
+
instancePath: data.instancePath,
|
|
84
|
+
message: data.message,
|
|
85
|
+
});
|
|
86
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
87
|
+
res.end(JSON.stringify({ ok: true, id: ev.id }));
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
res.writeHead(400);
|
|
91
|
+
res.end(String(err instanceof Error ? err.message : err));
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
res.writeHead(404);
|
|
97
|
+
res.end("not found");
|
|
98
|
+
});
|
|
99
|
+
server.listen(port, "127.0.0.1");
|
|
100
|
+
return {
|
|
101
|
+
port,
|
|
102
|
+
close: () => {
|
|
103
|
+
server.close();
|
|
104
|
+
bus.removeAllListeners();
|
|
105
|
+
},
|
|
106
|
+
onEvent: (fn) => {
|
|
107
|
+
bus.on("event", fn);
|
|
108
|
+
return () => bus.off("event", fn);
|
|
109
|
+
},
|
|
110
|
+
getEventsSince: (id) => events.filter((e) => e.id > id),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -13,6 +13,7 @@ exports.watch = watch;
|
|
|
13
13
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
15
15
|
const package_info_js_1 = require("../package-info.js");
|
|
16
|
+
const postprocess_js_1 = require("../clpp/postprocess.js");
|
|
16
17
|
const paths_js_1 = require("../clpp/paths.js");
|
|
17
18
|
const index_js_1 = require("../flare/index.js");
|
|
18
19
|
const index_js_2 = require("../native/index.js");
|
|
@@ -21,6 +22,16 @@ const process_orchestrator_js_1 = require("./process-orchestrator.js");
|
|
|
21
22
|
const rojo_mapper_js_1 = require("./rojo-mapper.js");
|
|
22
23
|
const transpile_js_1 = require("../transpile.js");
|
|
23
24
|
const safe_paths_js_1 = require("./safe-paths.js");
|
|
25
|
+
const source_map_js_1 = require("../target/source-map.js");
|
|
26
|
+
const luau_stamp_js_1 = require("../target/luau-stamp.js");
|
|
27
|
+
const optimizer_soa_js_1 = require("../target/optimizer-soa.js");
|
|
28
|
+
const index_js_3 = require("../api/index.js");
|
|
29
|
+
const flare_version_js_1 = require("../target/flare-version.js");
|
|
30
|
+
const component_contracts_js_1 = require("../target/component-contracts.js");
|
|
31
|
+
const authority_check_js_1 = require("../target/authority-check.js");
|
|
32
|
+
const datamodel_js_1 = require("../target/datamodel.js");
|
|
33
|
+
const build_cache_js_1 = require("../target/build-cache.js");
|
|
34
|
+
const modules_js_1 = require("../clpp/modules.js");
|
|
24
35
|
function readProjectConfig(file) {
|
|
25
36
|
const raw = JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
|
|
26
37
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
@@ -40,6 +51,12 @@ function readProjectConfig(file) {
|
|
|
40
51
|
if (typeof data.architecture === "boolean") {
|
|
41
52
|
parsed.architecture = data.architecture;
|
|
42
53
|
}
|
|
54
|
+
if (data.rules && typeof data.rules === "object") {
|
|
55
|
+
parsed.rules = data.rules;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(data.components)) {
|
|
58
|
+
parsed.components = data.components;
|
|
59
|
+
}
|
|
43
60
|
return parsed;
|
|
44
61
|
}
|
|
45
62
|
function loadConfig(root) {
|
|
@@ -356,41 +373,128 @@ function compileFlareJobs(root, config, srcDir) {
|
|
|
356
373
|
}
|
|
357
374
|
return { jobs, errors };
|
|
358
375
|
}
|
|
359
|
-
function
|
|
376
|
+
function configFingerprint(config) {
|
|
377
|
+
return JSON.stringify({
|
|
378
|
+
strict: config.strict === true,
|
|
379
|
+
architecture: config.architecture === true,
|
|
380
|
+
rootDir: config.rootDir,
|
|
381
|
+
outDir: config.outDir,
|
|
382
|
+
v: package_info_js_1.pkg.version,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
function compileProject(root, config, mapper, options = {}) {
|
|
360
386
|
const srcDir = node_path_1.default.join(root, config.rootDir);
|
|
361
387
|
const schema = compileSchemaJobs(root, config, srcDir);
|
|
362
388
|
const files = (0, paths_js_1.collectSources)(srcDir);
|
|
363
389
|
const jobs = [...schema.jobs];
|
|
364
390
|
const errors = [...schema.errors];
|
|
391
|
+
const incremental = options.incremental !== false;
|
|
392
|
+
const cfgKey = configFingerprint(config);
|
|
393
|
+
let cacheHits = 0;
|
|
365
394
|
for (const file of files) {
|
|
366
395
|
const source = node_fs_1.default.readFileSync(file, "utf8");
|
|
367
396
|
const rel = posixRel(srcDir, file);
|
|
397
|
+
const sourceHash = (0, modules_js_1.fingerprintSourceWithDeps)(source, file, cfgKey, srcDir, build_cache_js_1.hashText);
|
|
368
398
|
try {
|
|
399
|
+
if (incremental) {
|
|
400
|
+
const cached = (0, build_cache_js_1.readCachedJob)(root, rel, sourceHash);
|
|
401
|
+
if (cached) {
|
|
402
|
+
jobs.push({ rel, files: cached.files, stale: cached.stale || [] });
|
|
403
|
+
cacheHits++;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
369
407
|
const result = (0, transpile_js_1.transpileSource)(source, rel, compileOptions(root, config, file, rel), mapper);
|
|
370
408
|
jobs.push({ rel, files: result.files, stale: result.stale || [] });
|
|
409
|
+
if (incremental) {
|
|
410
|
+
(0, build_cache_js_1.writeCachedJob)(root, {
|
|
411
|
+
rel,
|
|
412
|
+
sourceHash,
|
|
413
|
+
files: result.files,
|
|
414
|
+
stale: result.stale || [],
|
|
415
|
+
});
|
|
416
|
+
}
|
|
371
417
|
}
|
|
372
418
|
catch (err) {
|
|
373
419
|
errors.push({ rel, prefixes: sourcePrefixes(rel), message: err.message });
|
|
374
420
|
}
|
|
375
421
|
}
|
|
422
|
+
if (cacheHits > 0) {
|
|
423
|
+
console.log(`cluaupp: incremental cache hit ${cacheHits}/${files.length}`);
|
|
424
|
+
}
|
|
376
425
|
return { files, jobs, errors };
|
|
377
426
|
}
|
|
378
|
-
async function compileProjectAsync(root, config, mapper) {
|
|
427
|
+
async function compileProjectAsync(root, config, mapper, options = {}) {
|
|
379
428
|
const srcDir = node_path_1.default.join(root, config.rootDir);
|
|
380
429
|
const schema = compileSchemaJobs(root, config, srcDir);
|
|
381
430
|
const files = (0, paths_js_1.collectSources)(srcDir);
|
|
382
431
|
const jobs = [...schema.jobs];
|
|
383
432
|
const errors = [...schema.errors];
|
|
384
|
-
|
|
433
|
+
const incremental = options.incremental !== false;
|
|
434
|
+
const cfgKey = configFingerprint(config);
|
|
435
|
+
const concurrency = options.jobs ?? (0, build_cache_js_1.defaultJobCount)();
|
|
436
|
+
let cacheHits = 0;
|
|
437
|
+
const compiled = await (0, build_cache_js_1.mapPool)(files, concurrency, async (file) => {
|
|
385
438
|
const source = node_fs_1.default.readFileSync(file, "utf8");
|
|
386
439
|
const rel = posixRel(srcDir, file);
|
|
440
|
+
const sourceHash = (0, modules_js_1.fingerprintSourceWithDeps)(source, file, cfgKey, srcDir, build_cache_js_1.hashText);
|
|
387
441
|
try {
|
|
442
|
+
if (incremental) {
|
|
443
|
+
const cached = (0, build_cache_js_1.readCachedJob)(root, rel, sourceHash);
|
|
444
|
+
if (cached) {
|
|
445
|
+
return {
|
|
446
|
+
ok: true,
|
|
447
|
+
rel,
|
|
448
|
+
files: cached.files,
|
|
449
|
+
stale: cached.stale || [],
|
|
450
|
+
cached: true,
|
|
451
|
+
sourceHash,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
}
|
|
388
455
|
const result = await (0, transpile_js_1.transpileSourceAsync)(source, rel, compileOptions(root, config, file, rel), mapper);
|
|
389
|
-
|
|
456
|
+
return {
|
|
457
|
+
ok: true,
|
|
458
|
+
rel,
|
|
459
|
+
files: result.files,
|
|
460
|
+
stale: result.stale || [],
|
|
461
|
+
cached: false,
|
|
462
|
+
sourceHash,
|
|
463
|
+
};
|
|
390
464
|
}
|
|
391
465
|
catch (err) {
|
|
392
|
-
|
|
466
|
+
return {
|
|
467
|
+
ok: false,
|
|
468
|
+
rel,
|
|
469
|
+
prefixes: sourcePrefixes(rel),
|
|
470
|
+
message: err.message,
|
|
471
|
+
};
|
|
393
472
|
}
|
|
473
|
+
});
|
|
474
|
+
for (const item of compiled) {
|
|
475
|
+
if (item.ok) {
|
|
476
|
+
jobs.push({ rel: item.rel, files: item.files, stale: item.stale });
|
|
477
|
+
if (item.cached) {
|
|
478
|
+
cacheHits++;
|
|
479
|
+
}
|
|
480
|
+
else if (incremental) {
|
|
481
|
+
(0, build_cache_js_1.writeCachedJob)(root, {
|
|
482
|
+
rel: item.rel,
|
|
483
|
+
sourceHash: item.sourceHash,
|
|
484
|
+
files: item.files,
|
|
485
|
+
stale: item.stale,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
errors.push({ rel: item.rel, prefixes: item.prefixes, message: item.message });
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
if (cacheHits > 0) {
|
|
494
|
+
console.log(`cluaupp: incremental cache hit ${cacheHits}/${files.length} (jobs=${concurrency})`);
|
|
495
|
+
}
|
|
496
|
+
else if (files.length > 1 && concurrency > 1) {
|
|
497
|
+
console.log(`cluaupp: parallel compile jobs=${concurrency}`);
|
|
394
498
|
}
|
|
395
499
|
return { files, jobs, errors };
|
|
396
500
|
}
|
|
@@ -424,11 +528,25 @@ function writeJobs(root, config, jobs, format) {
|
|
|
424
528
|
if (!dest) {
|
|
425
529
|
continue;
|
|
426
530
|
}
|
|
427
|
-
|
|
531
|
+
let contents = artifact.contents;
|
|
532
|
+
if (/\.luau$/i.test(dest)) {
|
|
533
|
+
const srcFile = node_path_1.default.join(root, config.rootDir, job.rel);
|
|
534
|
+
const clppSource = node_fs_1.default.existsSync(srcFile) ? node_fs_1.default.readFileSync(srcFile, "utf8") : undefined;
|
|
535
|
+
contents = (0, luau_stamp_js_1.stampLuauFromClpp)((0, postprocess_js_1.rewriteClppEmit)(contents), job.rel, clppSource);
|
|
536
|
+
}
|
|
537
|
+
const changed = writeTextIfChanged(dest, contents);
|
|
428
538
|
written.add(resolveKey(dest));
|
|
429
539
|
if (changed) {
|
|
430
540
|
console.log("cluaupp:", job.rel, "→", node_path_1.default.relative(root, dest));
|
|
431
541
|
}
|
|
542
|
+
if (/\.luau$/i.test(dest)) {
|
|
543
|
+
const mapPath = (0, source_map_js_1.writeSourceMap)({
|
|
544
|
+
outLuauPath: dest,
|
|
545
|
+
sourceClppRel: job.rel,
|
|
546
|
+
projectRoot: root,
|
|
547
|
+
});
|
|
548
|
+
written.add(resolveKey(mapPath));
|
|
549
|
+
}
|
|
432
550
|
if (format && /\.luau$/i.test(dest)) {
|
|
433
551
|
process_orchestrator_js_1.ProcessOrchestrator.formatWithStyLuaSync(dest);
|
|
434
552
|
}
|
|
@@ -468,6 +586,18 @@ function finishBuild(root, config, compiled, options) {
|
|
|
468
586
|
}
|
|
469
587
|
}
|
|
470
588
|
const written = writeJobs(root, config, compiled.jobs, format);
|
|
589
|
+
try {
|
|
590
|
+
const soaPlans = (0, optimizer_soa_js_1.collectSoaPlansFromProject)(root, config.rootDir);
|
|
591
|
+
if (soaPlans.length) {
|
|
592
|
+
const files = (0, optimizer_soa_js_1.writeSoaArtifacts)(root, soaPlans, { useBuffer: false });
|
|
593
|
+
for (const f of files) {
|
|
594
|
+
console.log("cluaupp: SoA", node_path_1.default.relative(root, f));
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
catch (err) {
|
|
599
|
+
console.error("cluaupp: SoA emit failed", err.message);
|
|
600
|
+
}
|
|
471
601
|
const failedPrefixes = compiled.errors.flatMap((err) => err.prefixes);
|
|
472
602
|
pruneOut(root, config, written, failedPrefixes);
|
|
473
603
|
try {
|
|
@@ -514,20 +644,49 @@ function prepareBuild(root, options) {
|
|
|
514
644
|
}
|
|
515
645
|
return { config, mapper: createMapper(root, config, options.rojo) };
|
|
516
646
|
}
|
|
647
|
+
function enforceFrozen(root, config) {
|
|
648
|
+
const lock = (0, index_js_3.verifyLock)();
|
|
649
|
+
if (!lock.ok) {
|
|
650
|
+
throw new Error(`cluaupp build --frozen: API lock failed\n${lock.messages.join("\n")}`);
|
|
651
|
+
}
|
|
652
|
+
const flare = (0, flare_version_js_1.checkFlareVersions)(root, config.rootDir);
|
|
653
|
+
if (flare.conflicts.length) {
|
|
654
|
+
throw new Error(`cluaupp build --frozen: Flare version conflicts\n${flare.conflicts.map((c) => c.message).join("\n")}`);
|
|
655
|
+
}
|
|
656
|
+
const policy = (0, authority_check_js_1.loadPlatformPolicy)(root);
|
|
657
|
+
const components = config.components || policy.components || [];
|
|
658
|
+
if (components.length) {
|
|
659
|
+
const dm = (0, datamodel_js_1.buildDatamodelProfile)(root);
|
|
660
|
+
if (dm) {
|
|
661
|
+
const bad = (0, component_contracts_js_1.checkComponentContracts)(dm, components).filter((d) => d.severity === "error");
|
|
662
|
+
if (bad.length) {
|
|
663
|
+
throw new Error(`cluaupp build --frozen: component contracts\n${bad.map((b) => b.message).join("\n")}`);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
517
668
|
function build(root, options = {}) {
|
|
669
|
+
if (options.frozen) {
|
|
670
|
+
const config = loadConfig(root);
|
|
671
|
+
enforceFrozen(root, config);
|
|
672
|
+
}
|
|
518
673
|
const prepared = prepareBuild(root, options);
|
|
519
674
|
if (!prepared) {
|
|
520
675
|
return { failed: 0, written: new Set() };
|
|
521
676
|
}
|
|
522
|
-
const compiled = compileProject(root, prepared.config, prepared.mapper);
|
|
677
|
+
const compiled = compileProject(root, prepared.config, prepared.mapper, options);
|
|
523
678
|
return finishBuild(root, prepared.config, compiled, options);
|
|
524
679
|
}
|
|
525
680
|
async function buildAsync(root, options = {}) {
|
|
681
|
+
if (options.frozen) {
|
|
682
|
+
const config = loadConfig(root);
|
|
683
|
+
enforceFrozen(root, config);
|
|
684
|
+
}
|
|
526
685
|
const prepared = prepareBuild(root, options);
|
|
527
686
|
if (!prepared) {
|
|
528
687
|
return { failed: 0, written: new Set() };
|
|
529
688
|
}
|
|
530
|
-
const compiled = await compileProjectAsync(root, prepared.config, prepared.mapper);
|
|
689
|
+
const compiled = await compileProjectAsync(root, prepared.config, prepared.mapper, options);
|
|
531
690
|
return finishBuild(root, prepared.config, compiled, options);
|
|
532
691
|
}
|
|
533
692
|
async function init(dest) {
|
|
@@ -536,10 +695,21 @@ async function init(dest) {
|
|
|
536
695
|
const include = node_path_1.default.join(__dirname, "..", "..", "include");
|
|
537
696
|
copyDir(template, target);
|
|
538
697
|
copyDir(include, node_path_1.default.join(target, "include"));
|
|
698
|
+
const skills = node_path_1.default.join(__dirname, "..", "..", "skills");
|
|
699
|
+
if (node_fs_1.default.existsSync(skills)) {
|
|
700
|
+
copyDir(skills, node_path_1.default.join(target, ".cursor", "skills"));
|
|
701
|
+
}
|
|
539
702
|
copyRuntime(target);
|
|
540
703
|
(0, intellisense_js_1.syncEditorSupport)(target);
|
|
704
|
+
try {
|
|
705
|
+
(0, intellisense_js_1.installEditorExtension)();
|
|
706
|
+
}
|
|
707
|
+
catch {
|
|
708
|
+
// editor homes may be missing in CI
|
|
709
|
+
}
|
|
541
710
|
console.log("Cluaupp ready in", target);
|
|
542
711
|
console.log(" clpp install (CL++ highlighting + IntelliSense)");
|
|
712
|
+
console.log(" cluaupp intellisense (schema .flare .hive .mint .bloom .helm .shift .axiom)");
|
|
543
713
|
console.log(" rokit install");
|
|
544
714
|
console.log(" cluaupp build");
|
|
545
715
|
console.log(" rojo serve");
|