-
Notifications
You must be signed in to change notification settings - Fork 1
/
build-worker.ts
160 lines (143 loc) · 6.22 KB
/
build-worker.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import * as fsp from "fs/promises";
import { glob } from "glob";
import * as path from "path";
import { Path, PathScurry } from "path-scurry";
import ts from "typescript";
import * as tstl from "typescript-to-lua";
export type Job = {
entryPathFromSrc: string;
};
export async function transpile(job: Job) {
// Create a virtual project that includes the entry point file.
const { entryPathFromSrc } = job;
const entryFile = new PathScurry("./src").cwd.resolve(entryPathFromSrc);
const bundleFiles = await globBundleFiles();
const virtualProject = Object.fromEntries(await Promise.all([entryFile, ...bundleFiles].map(readVirtualFile)));
// Call TypeScriptToLua.
const bundleFile = (entryFile.parent ?? entryFile).resolve(path.basename(entryFile.name, ".ts") + ".lua");
const result = tstl.transpileVirtualProject(virtualProject, {
...readCompilerOptions(),
types: ["lua-types/5.0", "@typescript-to-lua/language-extensions"], // Drop the jest types.
luaTarget: tstl.LuaTarget.Lua50,
sourceMapTraceback: false,
luaBundle: bundleFile.relative(),
luaBundleEntry: entryFile.relative(),
});
printDiagnostics(result.diagnostics);
// Write the result.
for (const tf of result.transpiledFiles) {
if (!tf.lua) continue;
const luaPath = path.join("./dist", path.relative("./mod", tf.outPath));
const dirPath = path.dirname(luaPath);
const outPath = path.join(dirPath, path.basename(luaPath, ".lua") + ".out");
const outText = await injectPaywareScripts(tf.lua);
await fsp.mkdir(dirPath, { recursive: true });
await fsp.writeFile(outPath, outText);
// Make multiple copies of the final output if needed.
await copyOutput(path.relative("./dist", outPath));
}
}
export async function globBundleFiles() {
return [
...(await glob(
[
"node_modules/lua-types/5.0.d.ts",
"node_modules/lua-types/core/index-5.0.d.ts",
"node_modules/lua-types/core/coroutine.d.ts",
"node_modules/lua-types/core/5.0/*",
"node_modules/lua-types/special/5.0.d.ts",
],
{ withFileTypes: true }
)),
...(await glob(["build.json", "@types/**/*", "lib/**/*.ts"], { cwd: "./src", withFileTypes: true })),
];
}
process.on("message", async m => {
if (process.send === undefined) return;
await transpile(m as Job);
// Signal completion to the parent.
process.send("done");
});
async function readVirtualFile(file: Path) {
const contents = await fsp.readFile(file.fullpath(), { encoding: "utf-8" });
return [file.relative(), contents] as [string, string];
}
function readCompilerOptions() {
const configJson = ts.readConfigFile("./src/tsconfig.json", ts.sys.readFile);
return ts.parseJsonConfigFileContent(configJson.config, ts.sys, ".").options;
}
function printDiagnostics(diagnostics: ts.Diagnostic[]) {
if (diagnostics.length > 0) {
console.log(
ts.formatDiagnosticsWithColorAndContext(diagnostics, {
getCurrentDirectory: () => ts.sys.getCurrentDirectory(),
getCanonicalFileName: f => f,
getNewLine: () => "\n",
})
);
}
}
async function injectPaywareScripts(lua: string) {
if (process.env.CI === "true") return lua;
const pathMap = new Map<string, string>([
["REPPO_AEM7_ENGINESCRIPT", "./payware/Assets/Reppo/AEM7/RailVehicles/Scripts/AEM7_EngineScript.out"],
["REPPO_E60_ENGINESCRIPT", "./payware/Assets/Reppo/E60CP/RailVehicles/Scripts/E60_EngineScript.out"],
]);
for (const [constant, path] of pathMap.entries()) {
if (lua.includes(constant)) {
lua = lua.replaceAll(constant, embedLuaBytecode(await fsp.readFile(path)));
}
}
return lua;
}
function embedLuaBytecode(bytes: Buffer) {
var str = '"';
for (const n of bytes) {
str += "\\" + n;
}
str += '"';
return str;
}
async function copyOutput(relativeOutPath: string) {
const copyTargets: [string, string[]][] = [
[
"Assets/RSC/NorthEastCorridor/RailVehicles/Electric/AEM7/Default/Engine/RailVehicle_EngineScript.out",
["Assets/RSC/NorthEastCorridor/RailVehicles/Electric/AEM7/Default/Engine/EngineScript.out"],
],
[
"Assets/RSC/NewYorkNewHaven/RailVehicles/Electric/ACS-64/Default/CommonScripts/EngineScript.out",
["Assets/DTG/WashingtonBaltimore/RailVehicles/Electric/ACS-64/Default/CommonScripts/EngineScript.out"],
],
[
"Assets/RSC/AcelaPack01/RailVehicles/Electric/Acela/Default/CommonScripts/PowerCar_EngineScript.out",
[
"Assets/DTG/WashingtonBaltimore/RailVehicles/Electric/Acela/Default/CommonScripts/PowerCar_EngineScript.out",
],
],
[
"Assets/RSC/P32Pack01/RailVehicles/Passengers/Shoreliner/Driving Trailer/CommonScripts/CabCarEngineScript.out",
[
"Assets/DTG/HudsonLine/RailVehicles/Passengers/Shoreliner/Driving Trailer/CommonScripts/CabCarEngineScript.out",
],
],
[
"Assets/DTG/NorthJerseyCoast/RailVehicles/Passengers/Comet/Driving Trailer/CommonScripts/CometCab_EngineScript.out",
[
"Assets/DTG/NJT-Alp46/RailVehicles/Passengers/Comet/Driving Trailer/CommonScripts/CometCab_EngineScript.out",
"Assets/DTG/GP40PHPack01/RailVehicles/Passengers/Comet/Driving Trailer/CommonScripts/CometCab_EngineScript.out",
"Assets/DTG/F40PH2Pack01/RailVehicles/Passengers/Comet/Driving Trailer/CommonScripts/CometCab_EngineScript.out",
],
],
];
const copyMap = new Map<string, string[]>(
copyTargets.map(([source, destinations]) => [
path.normalize(source),
destinations.map(relative => path.normalize(path.join("./dist", relative))),
])
);
const destinations = copyMap.get(path.normalize(relativeOutPath)) ?? [];
for (const destination of destinations) {
await fsp.mkdir(path.dirname(destination), { recursive: true });
await fsp.copyFile(path.join("./dist", relativeOutPath), destination);
}
}