Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions src/LuaTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface Scope {
export interface EmitResolver {
isValueAliasDeclaration(node: ts.Node): boolean;
isReferencedAliasDeclaration(node: ts.Node, checkChildren?: boolean): boolean;
isTopLevelValueImportEqualsWithEntityName(node: ts.ImportEqualsDeclaration): boolean;
moduleExportsSomeValue(moduleReferenceExpression: ts.Expression): boolean;
}

Expand Down Expand Up @@ -462,21 +463,38 @@ export class LuaTransformer {

public transformImportEqualsDeclaration(declaration: ts.ImportEqualsDeclaration): StatementVisitResult {
const name = this.transformIdentifier(declaration.name);
const expression = ts.isExternalModuleReference(declaration.moduleReference)
? this.transformExternalModuleReference(declaration.moduleReference)
: this.transformEntityName(declaration.moduleReference);
let expression: tstl.Expression;
if (ts.isExternalModuleReference(declaration.moduleReference)) {
if (!this.resolver.isReferencedAliasDeclaration(declaration)) {
return undefined;
}

expression = this.transformExternalModuleReference(declaration.moduleReference);
} else {
if (this.currentSourceFile === undefined) {
throw TSTLErrors.MissingSourceFile();
}

const shouldEmit =
this.resolver.isReferencedAliasDeclaration(declaration) ||
(!ts.isExternalModule(this.currentSourceFile) &&
this.resolver.isTopLevelValueImportEqualsWithEntityName(declaration));

if (!shouldEmit) {
return undefined;
}

expression = this.transformEntityName(declaration.moduleReference);
}

return this.createHoistableVariableDeclarationStatement(name, expression, declaration);
}

public transformExternalModuleReference(
externalModuleReference: ts.ExternalModuleReference
): ExpressionVisitResult {
return tstl.createCallExpression(
tstl.createIdentifier("require"),
[this.transformExpression(externalModuleReference.expression)],
externalModuleReference
);
// TODO: Should `externalModuleReference` be original node?
return this.createModuleRequire(externalModuleReference.expression as ts.StringLiteral);
}

private transformEntityName(entityName: ts.EntityName): ExpressionVisitResult {
Expand Down
15 changes: 4 additions & 11 deletions test/unit/declarations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ test("ImportEquals declaration", () => {
export function func() { return "foo" }
}
};

import importedFunc = outerNamespace.innerNamespace.func;
`;

Expand All @@ -117,12 +117,12 @@ test("ImportEquals declaration ambient", () => {
function func(): string;
}
};

import importedFunc = outerNamespace.innerNamespace.func;
`;

const luaHeader = `outerNamespace = {
innerNamespace = {
const luaHeader = `outerNamespace = {
innerNamespace = {
func = function() return "foo" end
}
}
Expand All @@ -133,10 +133,3 @@ test("ImportEquals declaration ambient", () => {
const result = util.transpileAndExecute(execution, undefined, luaHeader, header);
expect(result).toEqual("foo");
});

test("ImportEquals declaration require", () => {
const source = `import foo = require("bar");`;

const result = util.transpileString(source);
expect(result.includes(`local foo = require("bar")`)).toBeTruthy();
});
14 changes: 13 additions & 1 deletion test/unit/modules.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as ts from "typescript";
import * as tstl from "../../src";
import { TSTLErrors } from "../../src/TSTLErrors";
import * as util from "../util";
Expand All @@ -11,7 +12,11 @@ describe("module import/export elision", () => {
`;

const expectToElideImport = (code: string) => {
const lua = util.transpileString({ "module.d.ts": moduleDeclaration, "main.ts": code }, undefined, false);
const lua = util.transpileString(
{ "module.d.ts": moduleDeclaration, "main.ts": code },
{ module: ts.ModuleKind.CommonJS },
false
);

expect(() => util.executeLua(lua)).not.toThrow();
};
Expand All @@ -37,6 +42,13 @@ describe("module import/export elision", () => {
`);
});

test("should elide `import =` declarations", () => {
expectToElideImport(`
import module = require("module");
const foo: module.Type = "bar";
`);
});

test("should elide type exports", () => {
const code = `
declare const _G: any;
Expand Down
19 changes: 15 additions & 4 deletions test/unit/require.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import * as ts from "typescript";
import * as util from "../util";

const requireRegex = /require\("(.*?)"\)/;

test.each([
{
filePath: "main.ts",
Expand Down Expand Up @@ -79,8 +82,7 @@ test.each([
expect(() => util.transpileString(input, options)).toThrow();
} else {
const lua = util.transpileString(input, options);
const regex = /require\("(.*?)"\)/;
const match = regex.exec(lua);
const match = requireRegex.exec(lua);

if (util.expectToBeDefined(match)) {
expect(match[1]).toBe(expectedPath);
Expand All @@ -96,11 +98,20 @@ test.each([{ comment: "", expectedPath: "src.fake" }, { comment: "/** @noResolut
"src/main.ts": `import * as fake from "fake"; fake;`,
"module.d.ts": `${comment} declare module "fake" {}`,
});
const regex = /require\("(.*?)"\)/;
const match = regex.exec(lua);
const match = requireRegex.exec(lua);

if (util.expectToBeDefined(match)) {
expect(match[1]).toBe(expectedPath);
}
}
);

test("ImportEquals declaration require", () => {
const input = `import foo = require("./foo/bar"); foo;`;

const lua = util.transpileString(input, { module: ts.ModuleKind.CommonJS });
const match = requireRegex.exec(lua);
if (util.expectToBeDefined(match)) {
expect(match[1]).toBe("foo.bar");
}
});