Skip to content

Commit b6682de

Browse files
committed
Actually kinda works
1 parent 1001207 commit b6682de

File tree

10 files changed

+113
-59
lines changed

10 files changed

+113
-59
lines changed

src/transformation/utils/import.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as ts from "typescript";
2+
import * as lua from "../../LuaAST";
3+
4+
export function createImportsIdentifier(): lua.Identifier {
5+
return lua.createIdentifier("____imports");
6+
}
7+
8+
export function isSymbolImported(symbol: ts.Symbol): boolean {
9+
return symbol.declarations?.some(d => ts.isImportSpecifier(d) || ts.isNamespaceImport(d)) ?? false;
10+
}
11+
12+
export function createImportedIdentifier(luaIdentifier: lua.Identifier, node: ts.Node): lua.AssignmentLeftHandSideExpression {
13+
const importsTable = lua.createIdentifier("____imports");
14+
return lua.createTableIndexExpression(importsTable, lua.createStringLiteral(luaIdentifier.text), node);
15+
}

src/transformation/visitors/identifier.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import { isStandardLibraryType } from "../utils/typescript";
1212
import { getExtensionKindForNode, getExtensionKindForSymbol } from "../utils/language-extensions";
1313
import { callExtensions } from "./language-extensions/call-extension";
1414
import { isIdentifierExtensionValue, reportInvalidExtensionValue } from "./language-extensions/identifier";
15+
import { createImportedIdentifier, isSymbolImported } from "../utils/import";
1516

1617
export function transformIdentifier(context: TransformationContext, identifier: ts.Identifier): lua.Identifier {
17-
return transformNonValueIdentifier(context, identifier, context.checker.getSymbolAtLocation(identifier));
18+
return transformNonValueIdentifier(context, identifier, context.checker.getSymbolAtLocation(identifier)) as lua.Identifier;
1819
}
1920
function transformNonValueIdentifier(
2021
context: TransformationContext,
2122
identifier: ts.Identifier,
2223
symbol: ts.Symbol | undefined
23-
) {
24+
): lua.Expression {
2425
if (isOptionalContinuation(identifier)) {
2526
return lua.createIdentifier(identifier.text, undefined, tempSymbolId);
2627
}
@@ -52,7 +53,9 @@ function transformNonValueIdentifier(
5253
: identifier.text;
5354

5455
const symbolId = getIdentifierSymbolId(context, identifier, symbol);
55-
return lua.createIdentifier(text, identifier, symbolId, identifier.text);
56+
const luaIdentifier = lua.createIdentifier(text, identifier, symbolId, identifier.text);
57+
58+
return symbol && isSymbolImported(symbol) ? createImportedIdentifier(luaIdentifier, identifier) : luaIdentifier;
5659
}
5760

5861
export function transformIdentifierWithSymbol(

src/transformation/visitors/modules/export.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as ts from "typescript";
22
import * as lua from "../../../LuaAST";
3-
import { assert } from "../../../utils";
3+
import { assert, cast } from "../../../utils";
44
import { FunctionVisitor, TransformationContext } from "../../context";
55
import {
66
createDefaultExportExpression,
@@ -145,20 +145,21 @@ function transformExportSpecifiersFrom(
145145

146146
// Wrap in block to prevent imports from hoisting out of `do` statement
147147
const [block] = transformScopeBlock(context, ts.factory.createBlock([importDeclaration]), ScopeType.Block);
148-
const result = block.statements;
148+
const [requireStatement, ...importAssignments] = block.statements;
149149

150150
// Now the module is imported, add the imports to the export table
151+
const assignments = [];
151152
for (const specifier of exportSpecifiers) {
152-
result.push(
153+
assignments.push(
153154
lua.createAssignmentStatement(
154155
createExportedIdentifier(context, transformIdentifier(context, specifier.name)),
155-
transformIdentifier(context, specifier.name)
156+
cast(importAssignments[assignments.length], lua.isAssignmentStatement).right
156157
)
157158
);
158159
}
159160

160161
// Wrap this in a DoStatement to prevent polluting the scope.
161-
return lua.createDoStatement(result, statement);
162+
return lua.createDoStatement([requireStatement, ...assignments], statement);
162163
}
163164

164165
export const getExported = (context: TransformationContext, exportSpecifiers: ts.NamedExports) =>

src/transformation/visitors/modules/import.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ function transformImportSpecifier(
4545
context: TransformationContext,
4646
importSpecifier: ts.ImportSpecifier,
4747
moduleTableName: lua.Identifier
48-
): lua.VariableDeclarationStatement {
48+
): lua.AssignmentStatement {
4949
const leftIdentifier = transformIdentifier(context, importSpecifier.name);
5050
const propertyName = transformPropertyName(
5151
context,
5252
importSpecifier.propertyName ? importSpecifier.propertyName : importSpecifier.name
5353
);
5454

55-
return lua.createVariableDeclarationStatement(
55+
return lua.createAssignmentStatement(
5656
leftIdentifier,
5757
lua.createTableIndexExpression(moduleTableName, propertyName),
5858
importSpecifier
@@ -93,7 +93,7 @@ export const transformImportDeclaration: FunctionVisitor<ts.ImportDeclaration> =
9393
if (statement.importClause.name) {
9494
if (shouldBeImported(context, statement.importClause)) {
9595
const propertyName = createDefaultExportStringLiteral(statement.importClause.name);
96-
const defaultImportAssignmentStatement = lua.createVariableDeclarationStatement(
96+
const defaultImportAssignmentStatement = lua.createAssignmentStatement(
9797
transformIdentifier(context, statement.importClause.name),
9898
lua.createTableIndexExpression(importUniqueName, propertyName),
9999
statement.importClause.name
@@ -108,7 +108,7 @@ export const transformImportDeclaration: FunctionVisitor<ts.ImportDeclaration> =
108108
// local module = require("module")
109109
if (statement.importClause.namedBindings && ts.isNamespaceImport(statement.importClause.namedBindings)) {
110110
if (context.resolver.isReferencedAliasDeclaration(statement.importClause.namedBindings)) {
111-
const requireStatement = lua.createVariableDeclarationStatement(
111+
const requireStatement = lua.createAssignmentStatement(
112112
transformIdentifier(context, statement.importClause.namedBindings.name),
113113
requireCall,
114114
statement

src/transformation/visitors/sourceFile.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export const transformSourceFileNode: FunctionVisitor<ts.SourceFile> = (node, co
2929
context.pushScope(ScopeType.File);
3030

3131
statements = performHoisting(context, context.transformStatements(node.statements));
32+
const hasImports = context.scopeStack[0].importStatements?.some(lua.isAssignmentStatement);
33+
3234
context.popScope();
3335

3436
if (context.isModule) {
@@ -40,6 +42,15 @@ export const transformSourceFileNode: FunctionVisitor<ts.SourceFile> = (node, co
4042
);
4143
}
4244

45+
if (hasImports) {
46+
statements.unshift(
47+
lua.createVariableDeclarationStatement(
48+
lua.createIdentifier("____imports"),
49+
lua.createTableExpression()
50+
)
51+
);
52+
}
53+
4354
// return ____exports
4455
statements.push(lua.createReturnStatement([createExportsIdentifier()]));
4556
}

test/translation/__snapshots__/transformation.spec.ts.snap

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,12 @@ do
3939
end
4040
do
4141
local ____xyz = require(\\"xyz\\")
42-
local abc = ____xyz.abc
43-
local def = ____xyz.def
44-
____exports.abc = abc
45-
____exports.def = def
42+
____exports.abc = ____xyz.abc
43+
____exports.def = ____xyz.def
4644
end
4745
do
4846
local ____xyz = require(\\"xyz\\")
49-
local def = ____xyz.abc
50-
____exports.def = def
47+
____exports.def = ____xyz.abc
5148
end
5249
return ____exports"
5350
`;
@@ -113,65 +110,70 @@ end"
113110
`;
114111

115112
exports[`Transformation (modulesImportAll) 1`] = `
116-
"local ____exports = {}
117-
local Test = require(\\"test\\")
118-
local ____ = Test
113+
"local ____imports = {}
114+
local ____exports = {}
115+
____imports.Test = require(\\"test\\")
116+
local ____ = ____imports.Test
119117
return ____exports"
120118
`;
121119

122120
exports[`Transformation (modulesImportNamed) 1`] = `
123-
"local ____exports = {}
121+
"local ____imports = {}
122+
local ____exports = {}
124123
local ____test = require(\\"test\\")
125-
local TestClass = ____test.TestClass
126-
local ____ = TestClass
124+
____imports.TestClass = ____test.TestClass
125+
local ____ = ____imports.TestClass
127126
return ____exports"
128127
`;
129128

130129
exports[`Transformation (modulesImportNamedSpecialChars) 1`] = `
131-
"local ____exports = {}
130+
"local ____imports = {}
131+
local ____exports = {}
132132
local ____kebab_2Dmodule = require(\\"kebab-module\\")
133-
local TestClass1 = ____kebab_2Dmodule.TestClass1
133+
____imports.TestClass1 = ____kebab_2Dmodule.TestClass1
134134
local ____dollar_24module = require(\\"dollar$module\\")
135-
local TestClass2 = ____dollar_24module.TestClass2
135+
____imports.TestClass2 = ____dollar_24module.TestClass2
136136
local ____singlequote_27module = require(\\"singlequote'module\\")
137-
local TestClass3 = ____singlequote_27module.TestClass3
137+
____imports.TestClass3 = ____singlequote_27module.TestClass3
138138
local ____hash_23module = require(\\"hash#module\\")
139-
local TestClass4 = ____hash_23module.TestClass4
139+
____imports.TestClass4 = ____hash_23module.TestClass4
140140
local ____space_20module = require(\\"space module\\")
141-
local TestClass5 = ____space_20module.TestClass5
142-
local ____ = TestClass1
143-
local ____ = TestClass2
144-
local ____ = TestClass3
145-
local ____ = TestClass4
146-
local ____ = TestClass5
141+
____imports.TestClass5 = ____space_20module.TestClass5
142+
local ____ = ____imports.TestClass1
143+
local ____ = ____imports.TestClass2
144+
local ____ = ____imports.TestClass3
145+
local ____ = ____imports.TestClass4
146+
local ____ = ____imports.TestClass5
147147
return ____exports"
148148
`;
149149

150150
exports[`Transformation (modulesImportRenamed) 1`] = `
151-
"local ____exports = {}
151+
"local ____imports = {}
152+
local ____exports = {}
152153
local ____test = require(\\"test\\")
153-
local RenamedClass = ____test.TestClass
154-
local ____ = RenamedClass
154+
____imports.RenamedClass = ____test.TestClass
155+
local ____ = ____imports.RenamedClass
155156
return ____exports"
156157
`;
157158

158159
exports[`Transformation (modulesImportRenamedSpecialChars) 1`] = `
159-
"local ____exports = {}
160+
"local ____imports = {}
161+
local ____exports = {}
160162
local ____kebab_2Dmodule = require(\\"kebab-module\\")
161-
local RenamedClass1 = ____kebab_2Dmodule.TestClass
163+
____imports.RenamedClass1 = ____kebab_2Dmodule.TestClass
162164
local ____dollar_24module = require(\\"dollar$module\\")
163-
local RenamedClass2 = ____dollar_24module.TestClass
165+
____imports.RenamedClass2 = ____dollar_24module.TestClass
164166
local ____singlequote_27module = require(\\"singlequote'module\\")
165-
local RenamedClass3 = ____singlequote_27module.TestClass
167+
____imports.RenamedClass3 = ____singlequote_27module.TestClass
166168
local ____hash_23module = require(\\"hash#module\\")
167-
local RenamedClass4 = ____hash_23module.TestClass
169+
____imports.RenamedClass4 = ____hash_23module.TestClass
168170
local ____space_20module = require(\\"space module\\")
169-
local RenamedClass5 = ____space_20module.TestClass
170-
local ____ = RenamedClass1
171-
local ____ = RenamedClass2
172-
local ____ = RenamedClass3
173-
local ____ = RenamedClass4
174-
local ____ = RenamedClass5
171+
____imports.RenamedClass5 = ____space_20module.TestClass
172+
local ____ = ____imports.RenamedClass1
173+
local ____ = ____imports.RenamedClass2
174+
local ____ = ____imports.RenamedClass3
175+
local ____ = ____imports.RenamedClass4
176+
local ____ = ____imports.RenamedClass5
175177
return ____exports"
176178
`;
177179

@@ -278,8 +280,9 @@ end"
278280
`;
279281

280282
exports[`Transformation (unusedDefaultWithNamespaceImport) 1`] = `
281-
"local ____exports = {}
282-
local x = require(\\"module\\")
283-
local ____ = x
283+
"local ____imports = {}
284+
local ____exports = {}
285+
____imports.x = require(\\"module\\")
286+
local ____ = ____imports.x
284287
return ____exports"
285288
`;

test/transpile/__snapshots__/project.spec.ts.snap

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ return ____exports
3333
},
3434
Object {
3535
"filePath": "index.lua",
36-
"lua": "local ____exports = {}
36+
"lua": "local ____imports = {}
37+
local ____exports = {}
3738
local ____otherFile = require(\\"otherFile\\")
38-
local getNumber = ____otherFile.getNumber
39-
local myNumber = getNumber(nil)
39+
____imports.getNumber = ____otherFile.getNumber
40+
local myNumber = ____imports.getNumber(nil)
4041
setAPIValue(myNumber * 5)
4142
return ____exports
4243
",

test/transpile/bundle.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ describe("bundle with source maps", () => {
9090
}> = [
9191
{
9292
file: "index",
93-
luaPattern: "____exports.myNumber = getNumber(",
93+
luaPattern: "____exports.myNumber = ____imports.getNumber(",
9494
typeScriptPattern: "const myNumber = getNumber(",
9595
},
9696
{

test/unit/modules/__snapshots__/resolution.spec.ts.snap

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`doesn't resolve paths out of root dir: code 1`] = `
4-
"local ____exports = {}
5-
local module = require(\\"module\\")
6-
local ____ = module
4+
"local ____imports = {}
5+
local ____exports = {}
6+
____imports.module = require(\\"module\\")
7+
local ____ = ____imports.module
78
return ____exports"
89
`;
910

test/unit/modules/modules.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,22 @@ test("import expression", () => {
291291
.setOptions({ module: ts.ModuleKind.ESNext })
292292
.expectToMatchJsResult();
293293
});
294+
295+
test("imports table", () => {
296+
util.testModule`
297+
import { var1, var2 } from "./otherFile";
298+
const var3 = var1 + var2;
299+
export { var1, var2, var3 }
300+
`
301+
.addExtraFile(
302+
"otherFile.ts",
303+
`
304+
export const var1 = 3;
305+
export const var2 = 5;`
306+
)
307+
.expectToEqual({
308+
var1: 3,
309+
var2: 5,
310+
var3: 8
311+
});
312+
});

0 commit comments

Comments
 (0)