Skip to content

Commit ae52da3

Browse files
committed
Extract Transpilation class into its own file
1 parent f405f67 commit ae52da3

3 files changed

Lines changed: 115 additions & 111 deletions

File tree

src/transpilation/chunk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { escapeString } from "../LuaPrinter";
66
import { assert, normalizeSlashes } from "../utils";
77
import { couldNotFindBundleEntryPoint } from "./diagnostics";
88
import { Module } from "./module";
9-
import { Transpilation } from "./transpiler";
9+
import { Transpilation } from "./transpilation";
1010
import { getConfigDirectory } from "./utils";
1111

1212
export interface Chunk {

src/transpilation/transpilation.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { Resolver, ResolverFactory } from "enhanced-resolve";
2+
import * as fs from "fs";
3+
import * as path from "path";
4+
import * as ts from "typescript";
5+
import { CompilerOptions, isBundleEnabled, LuaTarget } from "../CompilerOptions";
6+
import { getLuaLibBundle } from "../LuaLib";
7+
import { assert, cast, isNonNull, normalizeSlashes, trimExtension } from "../utils";
8+
import { Chunk, modulesToBundleChunks, modulesToChunks } from "./chunk";
9+
import { createResolutionErrorDiagnostic } from "./diagnostics";
10+
import { buildModule, Module } from "./module";
11+
import { Transpiler } from "./transpiler";
12+
import { EmitHost } from "./utils";
13+
14+
export class Transpilation {
15+
public readonly diagnostics: ts.Diagnostic[] = [];
16+
private modules: Module[] = [];
17+
18+
public options = this.program.getCompilerOptions() as CompilerOptions;
19+
public rootDir: string;
20+
public outDir: string;
21+
public emitHost: EmitHost;
22+
23+
private readonly implicitScriptExtensions = [".ts", ".tsx", ".js", ".jsx"] as const;
24+
protected resolver: Resolver;
25+
26+
constructor(public transpiler: Transpiler, public program: ts.Program) {
27+
this.emitHost = transpiler.emitHost;
28+
29+
const { rootDir } = program.getCompilerOptions();
30+
this.rootDir =
31+
// getCommonSourceDirectory ignores provided rootDir when TS6059 is emitted
32+
rootDir == null
33+
? program.getCommonSourceDirectory()
34+
: ts.getNormalizedAbsolutePath(rootDir, this.emitHost.getCurrentDirectory());
35+
36+
this.outDir = this.options.outDir ?? this.rootDir;
37+
38+
this.resolver = ResolverFactory.createResolver({
39+
extensions: [".lua", ...this.implicitScriptExtensions],
40+
conditionNames: ["lua", `lua:${this.options.luaTarget ?? LuaTarget.Universal}`],
41+
fileSystem: this.emitHost.resolutionFileSystem ?? fs,
42+
useSyncFileSystemCalls: true,
43+
});
44+
}
45+
46+
public emit(programModules: Module[]): Chunk[] {
47+
programModules.forEach(module => this.modules.push(module));
48+
programModules.forEach(module => this.buildModule(module));
49+
50+
const lualibRequired = this.modules.some(m => m.code.toString().includes('require("lualib_bundle")'));
51+
if (lualibRequired) {
52+
const fileName = normalizeSlashes(path.resolve(this.rootDir, "lualib_bundle.lua"));
53+
this.modules.unshift({ request: fileName, code: getLuaLibBundle(this.emitHost), isBuilt: true });
54+
}
55+
56+
return this.mapModulesToChunks(this.modules);
57+
}
58+
59+
private buildModule(module: Module) {
60+
buildModule(module, request => {
61+
let resolvedModule: Module;
62+
try {
63+
resolvedModule = this.resolveRequestToModule(module.request, request);
64+
} catch (error) {
65+
this.diagnostics.push(createResolutionErrorDiagnostic(error.message, request, module.request));
66+
return { error: error.message };
67+
}
68+
69+
return this.getModuleId(resolvedModule);
70+
});
71+
}
72+
73+
private resolveRequestToModule(issuer: string, request: string) {
74+
const resolvedPath = this.resolver.resolveSync({}, path.dirname(issuer), request);
75+
assert(typeof resolvedPath === "string", `Invalid resolution result: ${resolvedPath}`);
76+
77+
let module = this.modules.find(m => m.request === resolvedPath);
78+
if (!module) {
79+
if (
80+
this.implicitScriptExtensions.some(extension => resolvedPath.endsWith(extension)) ||
81+
resolvedPath.endsWith(".json")
82+
) {
83+
throw new Error(`Resolved source file '${resolvedPath}' is not a part of the project.`);
84+
}
85+
86+
// TODO: Load source map files
87+
module = {
88+
request: resolvedPath,
89+
code: cast(this.emitHost.readFile(resolvedPath), isNonNull),
90+
isBuilt: false,
91+
};
92+
93+
this.modules.push(module);
94+
this.buildModule(module);
95+
}
96+
97+
return module;
98+
}
99+
100+
public getModuleId(module: Module) {
101+
const result = path.relative(this.rootDir, trimExtension(module.request));
102+
// TODO: handle files on other drives
103+
assert(!path.isAbsolute(result), `Invalid path: ${result}`);
104+
return result
105+
.replace(/\.\.[/\\]/g, "_/")
106+
.replace(/\./g, "__")
107+
.replace(/[/\\]/g, ".");
108+
}
109+
110+
private mapModulesToChunks(modules: Module[]): Chunk[] {
111+
return isBundleEnabled(this.options) ? modulesToBundleChunks(this, modules) : modulesToChunks(this, modules);
112+
}
113+
}

src/transpilation/transpiler.ts

Lines changed: 1 addition & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
1-
import { Resolver, ResolverFactory } from "enhanced-resolve";
2-
import * as fs from "fs";
3-
import * as path from "path";
41
import * as ts from "typescript";
5-
import { CompilerOptions, isBundleEnabled, LuaTarget } from "../CompilerOptions";
6-
import { getLuaLibBundle } from "../LuaLib";
7-
import { assert, cast, isNonNull, normalizeSlashes, trimExtension } from "../utils";
8-
import { Chunk, modulesToBundleChunks, modulesToChunks } from "./chunk";
9-
import { createResolutionErrorDiagnostic } from "./diagnostics";
10-
import { buildModule, Module } from "./module";
2+
import { Transpilation } from "./transpilation";
113
import { emitProgramModules, TranspileOptions } from "./transpile";
124
import { EmitHost } from "./utils";
135

@@ -49,104 +41,3 @@ export class Transpiler {
4941
return { diagnostics, emitSkipped: emitPlan.length === 0 };
5042
}
5143
}
52-
53-
export class Transpilation {
54-
public readonly diagnostics: ts.Diagnostic[] = [];
55-
private modules: Module[] = [];
56-
57-
public options = this.program.getCompilerOptions() as CompilerOptions;
58-
public rootDir: string;
59-
public outDir: string;
60-
public emitHost: EmitHost;
61-
62-
private readonly implicitScriptExtensions = [".ts", ".tsx", ".js", ".jsx"] as const;
63-
protected resolver: Resolver;
64-
65-
constructor(public transpiler: Transpiler, public program: ts.Program) {
66-
this.emitHost = transpiler.emitHost;
67-
68-
const { rootDir } = program.getCompilerOptions();
69-
this.rootDir =
70-
// getCommonSourceDirectory ignores provided rootDir when TS6059 is emitted
71-
rootDir == null
72-
? program.getCommonSourceDirectory()
73-
: ts.getNormalizedAbsolutePath(rootDir, this.emitHost.getCurrentDirectory());
74-
75-
this.outDir = this.options.outDir ?? this.rootDir;
76-
77-
this.resolver = ResolverFactory.createResolver({
78-
extensions: [".lua", ...this.implicitScriptExtensions],
79-
conditionNames: ["lua", `lua:${this.options.luaTarget ?? LuaTarget.Universal}`],
80-
fileSystem: this.emitHost.resolutionFileSystem ?? fs,
81-
useSyncFileSystemCalls: true,
82-
});
83-
}
84-
85-
public emit(programModules: Module[]): Chunk[] {
86-
programModules.forEach(module => this.modules.push(module));
87-
programModules.forEach(module => this.buildModule(module));
88-
89-
const lualibRequired = this.modules.some(m => m.code.toString().includes('require("lualib_bundle")'));
90-
if (lualibRequired) {
91-
const fileName = normalizeSlashes(path.resolve(this.rootDir, "lualib_bundle.lua"));
92-
this.modules.unshift({ request: fileName, code: getLuaLibBundle(this.emitHost), isBuilt: true });
93-
}
94-
95-
return this.mapModulesToChunks(this.modules);
96-
}
97-
98-
private buildModule(module: Module) {
99-
buildModule(module, request => {
100-
let resolvedModule: Module;
101-
try {
102-
resolvedModule = this.resolveRequestToModule(module.request, request);
103-
} catch (error) {
104-
this.diagnostics.push(createResolutionErrorDiagnostic(error.message, request, module.request));
105-
return { error: error.message };
106-
}
107-
108-
return this.getModuleId(resolvedModule);
109-
});
110-
}
111-
112-
private resolveRequestToModule(issuer: string, request: string) {
113-
const resolvedPath = this.resolver.resolveSync({}, path.dirname(issuer), request);
114-
assert(typeof resolvedPath === "string", `Invalid resolution result: ${resolvedPath}`);
115-
116-
let module = this.modules.find(m => m.request === resolvedPath);
117-
if (!module) {
118-
if (
119-
this.implicitScriptExtensions.some(extension => resolvedPath.endsWith(extension)) ||
120-
resolvedPath.endsWith(".json")
121-
) {
122-
throw new Error(`Resolved source file '${resolvedPath}' is not a part of the project.`);
123-
}
124-
125-
// TODO: Load source map files
126-
module = {
127-
request: resolvedPath,
128-
code: cast(this.emitHost.readFile(resolvedPath), isNonNull),
129-
isBuilt: false,
130-
};
131-
132-
this.modules.push(module);
133-
this.buildModule(module);
134-
}
135-
136-
return module;
137-
}
138-
139-
public getModuleId(module: Module) {
140-
const result = path.relative(this.rootDir, trimExtension(module.request));
141-
// TODO: handle files on other drives
142-
assert(!path.isAbsolute(result), `Invalid path: ${result}`);
143-
return result
144-
.replace(/\.\.[/\\]/g, "_/")
145-
.replace(/\./g, "__")
146-
.replace(/[/\\]/g, ".");
147-
}
148-
149-
private mapModulesToChunks(modules: Module[]): Chunk[] {
150-
return isBundleEnabled(this.options) ? modulesToBundleChunks(this, modules) : modulesToChunks(this, modules);
151-
}
152-
}

0 commit comments

Comments
 (0)