X Tutup
Skip to content

Commit a3bfc2d

Browse files
authored
Fix export all bug and add NamespaceExport support (#937)
* Fix export all bug #927 * Support NamespaceExport #928 * Update snapshots * Add unsafe Lua name NamespaceExport test * Add comments to transformExportAll and add export default if NamespaceExport
1 parent 0d61965 commit a3bfc2d

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

src/transformation/visitors/modules/export.ts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,34 +36,72 @@ export const transformExportAssignment: FunctionVisitor<ts.ExportAssignment> = (
3636
}
3737
};
3838

39-
function transformExportAllFrom(context: TransformationContext, node: ts.ExportDeclaration): lua.Statement | undefined {
39+
function transformExportAll(context: TransformationContext, node: ts.ExportDeclaration): lua.Statement | undefined {
4040
assert(node.moduleSpecifier);
4141

4242
if (!context.resolver.moduleExportsSomeValue(node.moduleSpecifier)) {
4343
return undefined;
4444
}
4545

4646
const moduleRequire = createModuleRequire(context, node.moduleSpecifier);
47-
const tempModuleIdentifier = lua.createIdentifier("____export");
4847

48+
// export * as ns from "...";
49+
// exports.ns = require(...)
50+
if (node.exportClause && ts.isNamespaceExport(node.exportClause)) {
51+
const assignToExports = lua.createAssignmentStatement(
52+
lua.createTableIndexExpression(
53+
createExportsIdentifier(),
54+
lua.createStringLiteral(node.exportClause.name.text)
55+
),
56+
moduleRequire
57+
);
58+
return assignToExports;
59+
}
60+
61+
// export * from "...";
62+
// exports all values EXCEPT "default" from "..."
63+
const result: lua.Statement[] = [];
64+
65+
// local ____export = require(...)
66+
const tempModuleIdentifier = lua.createIdentifier("____export");
4967
const declaration = lua.createVariableDeclarationStatement(tempModuleIdentifier, moduleRequire);
68+
result.push(declaration);
5069

70+
// ____exports[____exportKey] = ____exportValue
5171
const forKey = lua.createIdentifier("____exportKey");
5272
const forValue = lua.createIdentifier("____exportValue");
73+
const leftAssignment = lua.createAssignmentStatement(
74+
lua.createTableIndexExpression(createExportsIdentifier(), forKey),
75+
forValue
76+
);
5377

54-
const body = lua.createBlock([
55-
lua.createAssignmentStatement(lua.createTableIndexExpression(createExportsIdentifier(), forKey), forValue),
56-
]);
78+
// if key ~= "default" then
79+
// -- export the value, do not export "default" values
80+
// end
81+
const ifBody = lua.createBlock([leftAssignment]);
82+
const ifStatement = lua.createIfStatement(
83+
lua.createBinaryExpression(
84+
lua.cloneIdentifier(forKey),
85+
lua.createStringLiteral("default"),
86+
lua.SyntaxKind.InequalityOperator
87+
),
88+
ifBody
89+
);
5790

91+
// for ____exportKey, ____exportValue in ____export do
92+
// -- export ____exportValue, unless ____exportKey is "default"
93+
// end
5894
const pairsIdentifier = lua.createIdentifier("pairs");
5995
const forIn = lua.createForInStatement(
60-
body,
96+
lua.createBlock([ifStatement]),
6197
[lua.cloneIdentifier(forKey), lua.cloneIdentifier(forValue)],
6298
[lua.createCallExpression(pairsIdentifier, [lua.cloneIdentifier(tempModuleIdentifier)])]
6399
);
64100

101+
result.push(forIn);
102+
65103
// Wrap this in a DoStatement to prevent polluting the scope.
66-
return lua.createDoStatement([declaration, forIn], node);
104+
return lua.createDoStatement(result, node);
67105
}
68106

69107
const isDefaultExportSpecifier = (node: ts.ExportSpecifier) =>
@@ -127,7 +165,7 @@ export const getExported = (context: TransformationContext, exportSpecifiers: ts
127165
export const transformExportDeclaration: FunctionVisitor<ts.ExportDeclaration> = (node, context) => {
128166
if (!node.exportClause) {
129167
// export * from "...";
130-
return transformExportAllFrom(context, node);
168+
return transformExportAll(context, node);
131169
}
132170

133171
if (!context.resolver.isValueAliasDeclaration(node)) {
@@ -136,7 +174,7 @@ export const transformExportDeclaration: FunctionVisitor<ts.ExportDeclaration> =
136174

137175
if (ts.isNamespaceExport(node.exportClause)) {
138176
// export * as ns from "...";
139-
throw new Error("NamespaceExport is not supported");
177+
return transformExportAll(context, node);
140178
}
141179

142180
const exportSpecifiers = getExported(context, node.exportClause);

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ ____exports.uwv = xyz
6464
do
6565
local ____export = require(\\"xyz\\")
6666
for ____exportKey, ____exportValue in pairs(____export) do
67-
____exports[____exportKey] = ____exportValue
67+
if ____exportKey ~= \\"default\\" then
68+
____exports[____exportKey] = ____exportValue
69+
end
6870
end
6971
end
7072
do

test/unit/modules/modules.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,3 +275,32 @@ test("export default function with future reference", () => {
275275
.setReturnExport("result")
276276
.expectToMatchJsResult();
277277
});
278+
279+
const moduleFile = `
280+
export default true;
281+
export const foo = "bar";
282+
`;
283+
284+
test("export all does not include default", () => {
285+
util.testBundle`
286+
export * from "./module";
287+
`
288+
.addExtraFile("module.ts", moduleFile)
289+
.expectToEqual({ foo: "bar" });
290+
});
291+
292+
test("namespace export does not include default", () => {
293+
util.testBundle`
294+
export * as result from "./module";
295+
`
296+
.addExtraFile("module.ts", moduleFile)
297+
.expectToEqual({ result: { default: true, foo: "bar" } });
298+
});
299+
300+
test("namespace export with unsafe Lua name", () => {
301+
util.testBundle`
302+
export * as $$$ from "./module";
303+
`
304+
.addExtraFile("module.ts", moduleFile)
305+
.expectToEqual({ $$$: { default: true, foo: "bar" } });
306+
});

0 commit comments

Comments
 (0)
X Tutup