Skip to content

Commit 113cd29

Browse files
committed
Add in-memory resolution testing util setup
1 parent a5597b6 commit 113cd29

8 files changed

Lines changed: 83 additions & 26 deletions

File tree

package-lock.json

Lines changed: 15 additions & 0 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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"jest": "^26.0.1",
5959
"jest-circus": "^25.1.0",
6060
"lua-types": "^2.8.0",
61+
"memfs": "^3.2.0",
6162
"prettier": "^2.0.5",
6263
"ts-jest": "^26.0.0",
6364
"ts-node": "^8.6.2"

src/transpilation/diagnostics.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as ts from "typescript";
2+
import { escapeString } from "../LuaPrinter";
23
import { createSerialDiagnosticFactory } from "../utils";
34

45
const createDiagnosticFactory = <TArgs extends any[]>(getMessage: (...args: TArgs) => string) =>
@@ -41,3 +42,16 @@ export const usingLuaBundleWithInlineMightGenerateDuplicateCode = createSerialDi
4142
export const unresolvableRequirePath = createDiagnosticFactory(
4243
(path: string) => `Cannot create require path. Module '${path}' does not exist within --rootDir.`
4344
);
45+
46+
const sourceFileStub = ts.createSourceFile("", "", ts.ScriptTarget.ES3);
47+
export const createResolutionErrorDiagnostic = createSerialDiagnosticFactory(
48+
(messageText: string, request: string, fileName: string) => {
49+
const text = `__TS__Resolve(${escapeString(request)})`;
50+
return {
51+
messageText,
52+
file: { ...sourceFileStub, fileName, text },
53+
start: 0,
54+
length: text.length,
55+
};
56+
}
57+
);

src/transpilation/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,19 @@ const libCache: { [key: string]: ts.SourceFile } = {};
4343

4444
/** @internal */
4545
export function createVirtualProgram(input: Record<string, string>, options: CompilerOptions = {}): ts.Program {
46+
function notImplemented(): never {
47+
throw new Error("Not implemented");
48+
}
49+
4650
const compilerHost: ts.CompilerHost = {
47-
fileExists: () => true,
51+
useCaseSensitiveFileNames: () => false,
4852
getCanonicalFileName: fileName => fileName,
4953
getCurrentDirectory: () => "",
54+
fileExists: fileName => fileName.startsWith("lib.") || fileName in input,
55+
readFile: notImplemented,
56+
writeFile: notImplemented,
5057
getDefaultLibFileName: ts.getDefaultLibFileName,
51-
readFile: () => "",
5258
getNewLine: () => "\n",
53-
useCaseSensitiveFileNames: () => false,
54-
writeFile() {},
5559

5660
getSourceFile(fileName) {
5761
if (fileName in input) {

src/transpilation/transpile/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function getProgramTranspileResult(
7272
if (!options.noEmit && !options.emitDeclarationOnly) {
7373
const printResult = printer(program, emitHost, sourceFile.fileName, luaAst, luaLibFeatures);
7474
const sourceRootDir = program.getCommonSourceDirectory();
75-
const fileName = path.resolve(sourceRootDir, sourceFile.fileName);
75+
const fileName = path.join(sourceRootDir, sourceFile.fileName);
7676
transpiledFiles.push({ sourceFiles: [sourceFile], fileName, luaAst, ...printResult });
7777
}
7878
};

src/transpilation/transpiler.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { CompilerOptions, isBundleEnabled, LuaTarget } from "../CompilerOptions"
66
import { getLuaLibBundle } from "../LuaLib";
77
import { assert, cast, isNonNull, normalizeSlashes, trimExtension } from "../utils";
88
import { getBundleResult } from "./bundle";
9+
import { createResolutionErrorDiagnostic } from "./diagnostics";
910
import { replaceResolveMacroInSource, replaceResolveMacroSourceNodes, ResolveMacroReplacer } from "./macro";
1011
import { getProgramTranspileResult, TranspileOptions } from "./transpile";
1112
import { EmitFile, EmitHost, ProcessedFile } from "./utils";
@@ -92,18 +93,15 @@ class Transpilation {
9293

9394
private handleProcessedFile(file: ProcessedFile) {
9495
const replacer: ResolveMacroReplacer = (request: string) => {
96+
let basedir = path.dirname(file.fileName);
97+
if (basedir === ".") basedir = this.emitHost.getCurrentDirectory();
9598
let resolvedPath: string;
9699
try {
97-
resolvedPath = this.resolveRequest(request, file.fileName);
100+
const result = this.resolver.resolveSync({}, basedir, request);
101+
assert(typeof result === "string");
102+
resolvedPath = result;
98103
} catch (error) {
99-
this.diagnostics.push({
100-
category: ts.DiagnosticCategory.Error,
101-
code: -1,
102-
file: ts.createSourceFile(file.fileName, "", ts.ScriptTarget.ES3),
103-
start: undefined,
104-
length: undefined,
105-
messageText: error.message,
106-
});
104+
this.diagnostics.push(createResolutionErrorDiagnostic(error.message, request, file.fileName));
107105
return { error: error.message };
108106
}
109107

@@ -131,16 +129,10 @@ class Transpilation {
131129
protected resolver = ResolverFactory.createResolver({
132130
extensions: [".lua", ".ts", ".tsx", ".js", ".jsx"],
133131
conditionNames: ["lua", `lua:${this.options.luaTarget ?? LuaTarget.Universal}`],
134-
fileSystem: this.emitHost.fileSystem ?? fs,
132+
fileSystem: this.emitHost.resolutionFileSystem ?? fs,
135133
useSyncFileSystemCalls: true,
136134
});
137135

138-
protected resolveRequest(request: string, issuer: string) {
139-
const result = this.resolver.resolveSync({}, path.dirname(issuer), request);
140-
assert(typeof result === "string");
141-
return result;
142-
}
143-
144136
protected toGeneratedFileName(fileName: string) {
145137
const result = path.relative(this.rootDir, trimExtension(fileName));
146138
// TODO: handle files on other drives

src/transpilation/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as fs from "fs";
1+
import { FileSystem } from "enhanced-resolve";
22
import * as path from "path";
33
import * as resolve from "resolve";
44
import { SourceNode } from "source-map";
@@ -9,7 +9,7 @@ import * as lua from "../LuaAST";
99
import * as diagnosticFactories from "./diagnostics";
1010

1111
export interface EmitHost extends Pick<ts.System, "getCurrentDirectory" | "readFile" | "writeFile"> {
12-
fileSystem?: typeof fs;
12+
resolutionFileSystem?: FileSystem;
1313
}
1414

1515
interface BaseFile {

test/util.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as nativeAssert from "assert";
33
import { lauxlib, lua, lualib, to_jsstring, to_luastring } from "fengari";
44
import * as fs from "fs";
55
import { stringify } from "javascript-stringify";
6+
import { Volume } from "memfs";
67
import * as path from "path";
78
import * as prettyFormat from "pretty-format";
89
import * as ts from "typescript";
@@ -176,6 +177,13 @@ export abstract class TestBuilder {
176177
return this;
177178
}
178179

180+
private nativeFileSystem = false;
181+
public useNativeFileSystem() {
182+
expect(this.hasProgram).toBe(false);
183+
this.nativeFileSystem = true;
184+
return this;
185+
}
186+
179187
private options: tstl.CompilerOptions = {
180188
luaTarget: tstl.LuaTarget.Lua53,
181189
noHeader: true,
@@ -207,6 +215,17 @@ export abstract class TestBuilder {
207215
return this;
208216
}
209217

218+
protected getSourceFiles() {
219+
return { ...this.extraFiles, [this.mainFileName]: this.getTsCode() };
220+
}
221+
222+
private extraRawFiles: Record<string, string> = {};
223+
public addRawFile(fileName: string, content: string): this {
224+
expect(this.hasProgram).toBe(false);
225+
this.extraRawFiles[fileName] = content;
226+
return this;
227+
}
228+
210229
private customTransformers?: ts.CustomTransformers;
211230
public setCustomTransformers(customTransformers?: ts.CustomTransformers): this {
212231
expect(this.hasProgram).toBe(false);
@@ -224,14 +243,26 @@ export abstract class TestBuilder {
224243
@memoize
225244
public getProgram(): ts.Program {
226245
this.hasProgram = true;
227-
return tstl.createVirtualProgram({ ...this.extraFiles, [this.mainFileName]: this.getTsCode() }, this.options);
246+
return tstl.createVirtualProgram(this.getSourceFiles(), this.options);
228247
}
229248

230249
@memoize
231250
public getLuaResult(): tstl.TranspileVirtualProjectResult {
232-
const program = this.getProgram();
233251
const collector = createEmitOutputCollector();
234-
const { diagnostics: transpileDiagnostics } = new tstl.Transpiler().emit({
252+
const program = this.getProgram();
253+
254+
const emitHost: tstl.EmitHost = { ...ts.sys };
255+
if (!this.nativeFileSystem) {
256+
const virtualFS = Volume.fromJSON({ ...this.extraRawFiles, ...this.getSourceFiles() }, "/");
257+
emitHost.resolutionFileSystem = virtualFS;
258+
emitHost.getCurrentDirectory = () => "/";
259+
emitHost.readFile = (fileName, encoding = "utf8") =>
260+
fileName.endsWith("lualib_bundle.lua")
261+
? ts.sys.readFile(fileName, encoding)
262+
: (virtualFS.readFileSync(fileName, encoding) as string);
263+
}
264+
265+
const { diagnostics: transpileDiagnostics } = new tstl.Transpiler({ emitHost }).emit({
235266
program,
236267
customTransformers: this.customTransformers,
237268
writeFile: collector.writeFile,

0 commit comments

Comments
 (0)