Skip to content

Commit 1ff2963

Browse files
committed
Move high-level API to managed.ts
1 parent e1a3dfd commit 1ff2963

4 files changed

Lines changed: 116 additions & 114 deletions

File tree

src/transpilation/index.ts

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,4 @@
1-
import * as fs from "fs";
2-
import * as path from "path";
3-
import * as ts from "typescript";
4-
import { parseConfigFileWithSystem } from "../cli/tsconfig";
5-
import { CompilerOptions } from "../CompilerOptions";
6-
import { createEmitOutputCollector, TranspiledFile } from "./output-collector";
7-
import { EmitResult, Transpiler } from "./transpiler";
8-
1+
export * from "./managed";
92
export * from "./transpile";
103
export * from "./transpiler";
114
export { EmitHost } from "./utils";
12-
export { TranspiledFile };
13-
14-
export function transpileFiles(
15-
rootNames: string[],
16-
options: CompilerOptions = {},
17-
writeFile?: ts.WriteFileCallback
18-
): EmitResult {
19-
const program = ts.createProgram(rootNames, options);
20-
const { diagnostics: transpileDiagnostics, emitSkipped } = new Transpiler().emit({ program, writeFile });
21-
const diagnostics = ts.sortAndDeduplicateDiagnostics([
22-
...ts.getPreEmitDiagnostics(program),
23-
...transpileDiagnostics,
24-
]);
25-
26-
return { diagnostics: [...diagnostics], emitSkipped };
27-
}
28-
29-
export function transpileProject(
30-
configFileName: string,
31-
optionsToExtend?: CompilerOptions,
32-
writeFile?: ts.WriteFileCallback
33-
): EmitResult {
34-
const parseResult = parseConfigFileWithSystem(configFileName, optionsToExtend);
35-
if (parseResult.errors.length > 0) {
36-
return { diagnostics: parseResult.errors, emitSkipped: true };
37-
}
38-
39-
return transpileFiles(parseResult.fileNames, parseResult.options, writeFile);
40-
}
41-
42-
const libCache: { [key: string]: ts.SourceFile } = {};
43-
44-
/** @internal */
45-
export function createVirtualProgram(input: Record<string, string>, options: CompilerOptions = {}): ts.Program {
46-
function notImplemented(): never {
47-
throw new Error("Not implemented");
48-
}
49-
50-
const getFileFromInput = (fileName: string) =>
51-
input[fileName] ?? (fileName.startsWith("/") ? input[fileName.slice(1)] : undefined);
52-
53-
const compilerHost: ts.CompilerHost = {
54-
useCaseSensitiveFileNames: () => false,
55-
getCanonicalFileName: fileName => fileName,
56-
getCurrentDirectory: () => "/",
57-
fileExists: fileName => fileName.startsWith("lib.") || getFileFromInput(fileName) !== undefined,
58-
readFile: notImplemented,
59-
writeFile: notImplemented,
60-
getDefaultLibFileName: ts.getDefaultLibFileName,
61-
getNewLine: () => "\n",
62-
63-
getSourceFile(fileName) {
64-
const fileFromInput = getFileFromInput(fileName);
65-
if (fileFromInput !== undefined) {
66-
return ts.createSourceFile(fileName, fileFromInput, ts.ScriptTarget.Latest, false);
67-
}
68-
69-
if (fileName.startsWith("lib.")) {
70-
if (libCache[fileName]) return libCache[fileName];
71-
const typeScriptDir = path.dirname(require.resolve("typescript"));
72-
const filePath = path.join(typeScriptDir, fileName);
73-
const content = fs.readFileSync(filePath, "utf8");
74-
75-
libCache[fileName] = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, false);
76-
77-
return libCache[fileName];
78-
}
79-
},
80-
};
81-
82-
return ts.createProgram(Object.keys(input), options, compilerHost);
83-
}
84-
85-
export interface TranspileVirtualProjectResult {
86-
diagnostics: ts.Diagnostic[];
87-
transpiledFiles: TranspiledFile[];
88-
}
89-
90-
export function transpileVirtualProject(
91-
files: Record<string, string>,
92-
options: CompilerOptions = {}
93-
): TranspileVirtualProjectResult {
94-
const program = createVirtualProgram(files, options);
95-
const collector = createEmitOutputCollector();
96-
const { diagnostics: transpileDiagnostics } = new Transpiler().emit({ program, writeFile: collector.writeFile });
97-
const diagnostics = ts.sortAndDeduplicateDiagnostics([
98-
...ts.getPreEmitDiagnostics(program),
99-
...transpileDiagnostics,
100-
]);
101-
102-
return { diagnostics: [...diagnostics], transpiledFiles: collector.files };
103-
}
104-
105-
export interface TranspileStringResult {
106-
diagnostics: ts.Diagnostic[];
107-
file?: TranspiledFile;
108-
}
109-
110-
export function transpileString(main: string, options: CompilerOptions = {}): TranspileStringResult {
111-
const { diagnostics, transpiledFiles } = transpileVirtualProject({ "main.ts": main }, options);
112-
return {
113-
diagnostics,
114-
file: transpiledFiles.find(({ sourceFiles }) => sourceFiles.some(f => f.fileName === "main.ts")),
115-
};
116-
}

src/transpilation/managed.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as ts from "typescript";
2+
import { parseConfigFileWithSystem } from "../cli/tsconfig";
3+
import { CompilerOptions } from "../CompilerOptions";
4+
import { createEmitOutputCollector, TranspiledFile } from "./output-collector";
5+
import { EmitResult, Transpiler } from "./transpiler";
6+
import { createVirtualProgram } from "./utils";
7+
8+
export { TranspiledFile };
9+
10+
export function transpileFiles(
11+
rootNames: string[],
12+
options: CompilerOptions = {},
13+
writeFile?: ts.WriteFileCallback
14+
): EmitResult {
15+
const program = ts.createProgram(rootNames, options);
16+
const { diagnostics: transpileDiagnostics, emitSkipped } = new Transpiler().emit({ program, writeFile });
17+
const diagnostics = ts.sortAndDeduplicateDiagnostics([
18+
...ts.getPreEmitDiagnostics(program),
19+
...transpileDiagnostics,
20+
]);
21+
22+
return { diagnostics: [...diagnostics], emitSkipped };
23+
}
24+
25+
export function transpileProject(
26+
configFileName: string,
27+
optionsToExtend?: CompilerOptions,
28+
writeFile?: ts.WriteFileCallback
29+
): EmitResult {
30+
const parseResult = parseConfigFileWithSystem(configFileName, optionsToExtend);
31+
if (parseResult.errors.length > 0) {
32+
return { diagnostics: parseResult.errors, emitSkipped: true };
33+
}
34+
35+
return transpileFiles(parseResult.fileNames, parseResult.options, writeFile);
36+
}
37+
38+
export interface TranspileVirtualProjectResult {
39+
diagnostics: ts.Diagnostic[];
40+
transpiledFiles: TranspiledFile[];
41+
}
42+
43+
export function transpileVirtualProject(
44+
files: Record<string, string>,
45+
options: CompilerOptions = {}
46+
): TranspileVirtualProjectResult {
47+
const program = createVirtualProgram(files, options);
48+
const collector = createEmitOutputCollector();
49+
const { diagnostics: transpileDiagnostics } = new Transpiler().emit({ program, writeFile: collector.writeFile });
50+
const diagnostics = ts.sortAndDeduplicateDiagnostics([
51+
...ts.getPreEmitDiagnostics(program),
52+
...transpileDiagnostics,
53+
]);
54+
55+
return { diagnostics: [...diagnostics], transpiledFiles: collector.files };
56+
}
57+
58+
export interface TranspileStringResult {
59+
diagnostics: ts.Diagnostic[];
60+
file?: TranspiledFile;
61+
}
62+
63+
export function transpileString(main: string, options: CompilerOptions = {}): TranspileStringResult {
64+
const { diagnostics, transpiledFiles } = transpileVirtualProject({ "main.ts": main }, options);
65+
return {
66+
diagnostics,
67+
file: transpiledFiles.find(({ sourceFiles }) => sourceFiles.some(f => f.fileName === "main.ts")),
68+
};
69+
}

src/transpilation/utils.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { FileSystem } from "enhanced-resolve";
2+
import * as fs from "fs";
23
import * as path from "path";
34
import * as resolve from "resolve";
45
import { SourceNode } from "source-map";
56
import * as ts from "typescript";
67
// TODO: Don't depend on CLI?
78
import * as cliDiagnostics from "../cli/diagnostics";
9+
import { CompilerOptions } from "../CompilerOptions";
810
import * as lua from "../LuaAST";
911
import * as diagnosticFactories from "./diagnostics";
1012

@@ -74,3 +76,45 @@ export function resolvePlugin(
7476

7577
return { result };
7678
}
79+
80+
const libCache = new Map<string, ts.SourceFile>();
81+
export function createVirtualProgram(input: Record<string, string>, options: CompilerOptions = {}): ts.Program {
82+
function notImplemented(): never {
83+
throw new Error("Not implemented");
84+
}
85+
86+
const getFileFromInput = (fileName: string) =>
87+
input[fileName] ?? (fileName.startsWith("/") ? input[fileName.slice(1)] : undefined);
88+
89+
const compilerHost: ts.CompilerHost = {
90+
useCaseSensitiveFileNames: () => false,
91+
getCanonicalFileName: fileName => fileName,
92+
getCurrentDirectory: () => "/",
93+
fileExists: fileName => fileName.startsWith("lib.") || getFileFromInput(fileName) !== undefined,
94+
readFile: notImplemented,
95+
writeFile: notImplemented,
96+
getDefaultLibFileName: ts.getDefaultLibFileName,
97+
getNewLine: () => "\n",
98+
99+
getSourceFile(fileName) {
100+
const fileFromInput = getFileFromInput(fileName);
101+
if (fileFromInput !== undefined) {
102+
return ts.createSourceFile(fileName, fileFromInput, ts.ScriptTarget.Latest, false);
103+
}
104+
105+
if (libCache.has(fileName)) return libCache.get(fileName)!;
106+
107+
if (fileName.startsWith("lib.")) {
108+
const typeScriptDir = path.dirname(require.resolve("typescript"));
109+
const filePath = path.join(typeScriptDir, fileName);
110+
const content = fs.readFileSync(filePath, "utf8");
111+
112+
const sourceFile = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, false);
113+
libCache.set(fileName, sourceFile);
114+
return sourceFile;
115+
}
116+
},
117+
};
118+
119+
return ts.createProgram(Object.keys(input), options, compilerHost);
120+
}

test/util.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as ts from "typescript";
1010
import * as vm from "vm";
1111
import * as tstl from "../src";
1212
import { createEmitOutputCollector } from "../src/transpilation/output-collector";
13+
import { createVirtualProgram } from "../src/transpilation/utils";
1314

1415
export * from "./legacy-utils";
1516

@@ -243,7 +244,7 @@ export abstract class TestBuilder {
243244
@memoize
244245
public getProgram(): ts.Program {
245246
this.hasProgram = true;
246-
return tstl.createVirtualProgram(this.getSourceFiles(), this.options);
247+
return createVirtualProgram(this.getSourceFiles(), this.options);
247248
}
248249

249250
@memoize

0 commit comments

Comments
 (0)