forked from TypeScriptToLua/TypeScriptToLua
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbundle.ts
More file actions
97 lines (79 loc) · 3.57 KB
/
bundle.ts
File metadata and controls
97 lines (79 loc) · 3.57 KB
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
import * as path from "path";
import { SourceNode } from "source-map";
import * as ts from "typescript";
import { CompilerOptions } from "../CompilerOptions";
import { escapeString, tstlHeader } from "../LuaPrinter";
import { cast, formatPathToLuaPath, isNonNull, normalizeSlashes, trimExtension } from "../utils";
import { couldNotFindBundleEntryPoint } from "./diagnostics";
import { getEmitOutDir, getEmitPathRelativeToOutDir, getSourceDir } from "./transpiler";
import { EmitFile, ProcessedFile } from "./utils";
const createModulePath = (pathToResolve: string, program: ts.Program) =>
escapeString(formatPathToLuaPath(trimExtension(getEmitPathRelativeToOutDir(pathToResolve, program))));
// Override `require` to read from ____modules table.
const requireOverride = `
local ____modules = {}
local ____moduleCache = {}
local ____originalRequire = require
local function require(file)
if ____moduleCache[file] then
return ____moduleCache[file]
end
if ____modules[file] then
____moduleCache[file] = ____modules[file]()
return ____moduleCache[file]
else
if ____originalRequire then
return ____originalRequire(file)
else
error("module '" .. file .. "' not found")
end
end
end
`;
export function getBundleResult(program: ts.Program, files: ProcessedFile[]): [ts.Diagnostic[], EmitFile] {
const diagnostics: ts.Diagnostic[] = [];
const options = program.getCompilerOptions() as CompilerOptions;
const bundleFile = cast(options.luaBundle, isNonNull);
const entryModule = cast(options.luaBundleEntry, isNonNull);
// Resolve project settings relative to project file.
const resolvedEntryModule = path.resolve(getSourceDir(program), entryModule);
const outputPath = normalizeSlashes(path.resolve(getEmitOutDir(program), bundleFile));
if (program.getSourceFile(resolvedEntryModule) === undefined && program.getSourceFile(entryModule) === undefined) {
diagnostics.push(couldNotFindBundleEntryPoint(entryModule));
}
// For each file: ["<module path>"] = function() <lua content> end,
const moduleTableEntries = files.map(f => moduleSourceNode(f, createModulePath(f.fileName, program)));
// Create ____modules table containing all entries from moduleTableEntries
const moduleTable = createModuleTableNode(moduleTableEntries);
// return require("<entry module path>")
const entryPoint = `return require(${createModulePath(entryModule, program)})\n`;
const sourceChunks = [requireOverride, moduleTable, entryPoint];
if (!options.noHeader) {
sourceChunks.unshift(tstlHeader);
}
const bundleNode = joinSourceChunks(sourceChunks);
const { code, map } = bundleNode.toStringWithSourceMap();
return [
diagnostics,
{
outputPath,
code,
sourceMap: map.toString(),
sourceFiles: files.flatMap(x => x.sourceFiles ?? []),
},
];
}
function moduleSourceNode({ code, sourceMapNode }: ProcessedFile, modulePath: string): SourceNode {
const tableEntryHead = `[${modulePath}] = function() `;
const tableEntryTail = " end,\n";
return joinSourceChunks([tableEntryHead, sourceMapNode ?? code, tableEntryTail]);
}
function createModuleTableNode(fileChunks: SourceChunk[]): SourceNode {
const tableHead = "____modules = {\n";
const tableEnd = "}\n";
return joinSourceChunks([tableHead, ...fileChunks, tableEnd]);
}
type SourceChunk = string | SourceNode;
function joinSourceChunks(chunks: SourceChunk[]): SourceNode {
return new SourceNode(null, null, null, chunks);
}