Skip to content

Commit 19d47de

Browse files
committed
New emit pipeline and API/CLI refactor
1 parent 683e43a commit 19d47de

33 files changed

+767
-604
lines changed

build_lualib.ts

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,29 @@
11
import * as fs from "fs";
22
import * as glob from "glob";
3-
import { compile } from "./src/Compiler";
4-
import { LuaLib as luaLib, LuaLibFeature } from "./src/LuaLib";
3+
import * as path from "path";
4+
import * as tstl from "./src";
5+
import { LuaLib } from "./src/LuaLib";
56

6-
const bundlePath = "./dist/lualib/lualib_bundle.lua";
7+
const options: tstl.CompilerOptions = {
8+
skipLibCheck: true,
9+
types: [],
10+
luaLibImport: tstl.LuaLibImportKind.None,
11+
luaTarget: tstl.LuaTarget.Lua51,
12+
noHeader: true,
13+
outDir: path.join(__dirname, "./dist/lualib"),
14+
rootDir: path.join(__dirname, "./src/lualib"),
15+
};
716

8-
compile([
9-
"--skipLibCheck",
10-
"--types",
11-
"node",
12-
"--luaLibImport",
13-
"none",
14-
"--luaTarget",
15-
"5.1",
16-
"--noHeader",
17-
"--outDir",
18-
"./dist/lualib",
19-
"--rootDir",
20-
"./src/lualib",
21-
"--noHeader",
22-
"true",
23-
...glob.sync("./src/lualib/**/*.ts"),
24-
]);
17+
// TODO: Check diagnostics
18+
const { transpiledFiles } = tstl.transpileFiles(glob.sync("./src/lualib/**/*.ts"), options);
19+
tstl.emitTranspiledFiles(options, transpiledFiles);
2520

21+
const bundlePath = path.join(__dirname, "./dist/lualib/lualib_bundle.lua");
2622
if (fs.existsSync(bundlePath)) {
2723
fs.unlinkSync(bundlePath);
2824
}
2925

30-
const bundle = luaLib.loadFeatures(Object.keys(LuaLibFeature).map(lib => LuaLibFeature[lib]));
31-
fs.writeFileSync(bundlePath, bundle);
26+
fs.writeFileSync(
27+
bundlePath,
28+
LuaLib.loadFeatures(Object.keys(tstl.LuaLibFeature).map(lib => tstl.LuaLibFeature[lib])),
29+
);

jest.config.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ const isCI = require("is-ci");
33
/** @type {Partial<import("@jest/types").Config.DefaultOptions>} */
44
module.exports = {
55
testMatch: ["**/test/**/*.spec.ts"],
6-
collectCoverageFrom: ["<rootDir>/src/**/*", "!<rootDir>/src/lualib/**/*"],
6+
collectCoverageFrom: [
7+
"<rootDir>/src/**/*",
8+
"!<rootDir>/src/lualib/**/*",
9+
// https://github.com/facebook/jest/issues/5274
10+
"!<rootDir>/src/tstl.ts",
11+
],
712
watchPathIgnorePatterns: ["/watch\\.ts$"],
813

914
testEnvironment: "node",

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"devDependencies": {
4646
"@types/glob": "^5.0.35",
4747
"@types/jest": "^24.0.11",
48-
"@types/node": "^9.6.23",
48+
"@types/node": "^11.13.0",
4949
"fengari": "^0.1.2",
5050
"glob": "^7.1.2",
5151
"jest": "^24.5.0",

src/API.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
import * as ts from "typescript";
4+
import { parseConfigFileContent } from "./CommandLineParser";
5+
import { CompilerOptions } from "./CompilerOptions";
6+
import { getTranspileOutput, TranspiledFile, TranspilationResult } from "./Transpile";
7+
8+
export function transpileFiles(
9+
rootNames: string[],
10+
options: CompilerOptions = {}
11+
): TranspilationResult {
12+
const program = ts.createProgram(rootNames, options);
13+
const { diagnostics, transpiledFiles } = getTranspileOutput({ program, options });
14+
15+
const allDiagnostics = ts.sortAndDeduplicateDiagnostics([
16+
...ts.getPreEmitDiagnostics(program),
17+
...diagnostics,
18+
]);
19+
20+
return { transpiledFiles, diagnostics: [...allDiagnostics] };
21+
}
22+
23+
export function transpileProject(
24+
fileName: string,
25+
options?: CompilerOptions
26+
): TranspilationResult {
27+
const parseResult = parseConfigFileContent(
28+
fs.readFileSync(fileName, "utf8"),
29+
fileName,
30+
options
31+
);
32+
if (parseResult.isValid === false) {
33+
// TODO: Return diagnostics
34+
throw new Error(parseResult.errorMessage);
35+
}
36+
37+
return transpileFiles(parseResult.result.fileNames, parseResult.result.options);
38+
}
39+
40+
const libCache: { [key: string]: ts.SourceFile } = {};
41+
export function createVirtualProgram(
42+
input: Record<string, string>,
43+
options?: CompilerOptions
44+
): ts.Program {
45+
const compilerHost: ts.CompilerHost = {
46+
fileExists: () => true,
47+
getCanonicalFileName: fileName => fileName,
48+
getCurrentDirectory: () => "",
49+
getDefaultLibFileName: ts.getDefaultLibFileName,
50+
readFile: () => "",
51+
getNewLine: () => "\n",
52+
useCaseSensitiveFileNames: () => false,
53+
writeFile: () => {},
54+
55+
getSourceFile: filename => {
56+
if (filename in input) {
57+
return ts.createSourceFile(
58+
filename,
59+
input[filename],
60+
ts.ScriptTarget.Latest,
61+
false
62+
);
63+
}
64+
65+
if (filename.startsWith("lib.")) {
66+
if (libCache[filename]) return libCache[filename];
67+
const typeScriptDir = path.dirname(require.resolve("typescript"));
68+
const filePath = path.join(typeScriptDir, filename);
69+
const content = fs.readFileSync(filePath, "utf8");
70+
71+
libCache[filename] = ts.createSourceFile(
72+
filename,
73+
content,
74+
ts.ScriptTarget.Latest,
75+
false
76+
);
77+
78+
return libCache[filename];
79+
}
80+
},
81+
};
82+
83+
return ts.createProgram(Object.keys(input), options, compilerHost);
84+
}
85+
86+
export interface TranspileStringResult {
87+
file: TranspiledFile;
88+
diagnostics: ts.Diagnostic[];
89+
}
90+
91+
export function transpileString(
92+
input: string | Record<string, string>,
93+
options: CompilerOptions = {}
94+
): TranspileStringResult {
95+
const programFiles = typeof input === "object" ? input : { "main.ts": input };
96+
const mainFileName =
97+
typeof input === "string"
98+
? "main.ts"
99+
: Object.keys(input).find(x => /\bmain\.[a-z]+$/.test(x));
100+
if (mainFileName === undefined) throw new Error('Input should have a file named "main"');
101+
102+
const program = createVirtualProgram(programFiles, options);
103+
const { diagnostics, transpiledFiles } = getTranspileOutput({ program, options });
104+
105+
const allDiagnostics = ts.sortAndDeduplicateDiagnostics([
106+
...ts.getPreEmitDiagnostics(program),
107+
...diagnostics,
108+
]);
109+
110+
return { file: transpiledFiles.get(mainFileName), diagnostics: [...allDiagnostics] };
111+
}

src/CommandLineParser.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type ArgumentParseResult<T> =
1313
{ isValid: true; result: T; increment?: number }
1414
| { isValid: false, errorMessage: string };
1515

16-
interface ParsedCommandLine extends ts.ParsedCommandLine {
16+
export interface ParsedCommandLine extends ts.ParsedCommandLine {
1717
options: CompilerOptions;
1818
}
1919

@@ -161,19 +161,13 @@ function readTsConfig(parsedCommandLine: ts.ParsedCommandLine): CLIParseResult
161161
}
162162

163163
const configPath = options.project;
164-
const parsedJsonConfig = parseTsConfigFile(configPath, options);
165-
166-
return parsedJsonConfig;
164+
const configContent = fs.readFileSync(configPath, "utf8");
165+
return parseConfigFileContent(configContent, configPath, options);
167166
}
168167
return { isValid: true, result: parsedCommandLine };
169168
}
170169

171-
export function parseTsConfigFile(filePath: string, existingOptions?: ts.CompilerOptions): CLIParseResult {
172-
const configContents = fs.readFileSync(filePath).toString();
173-
return parseTsConfigString(configContents, filePath, existingOptions);
174-
}
175-
176-
export function parseTsConfigString(
170+
export function parseConfigFileContent(
177171
tsConfigString: string,
178172
configPath: string,
179173
existingOptions?: ts.CompilerOptions
@@ -183,7 +177,8 @@ export function parseTsConfigString(
183177
configJson.config,
184178
ts.sys,
185179
path.dirname(configPath),
186-
existingOptions
180+
existingOptions,
181+
configPath
187182
);
188183

189184
for (const key in parsedJsonConfig.raw) {

0 commit comments

Comments
 (0)