typescript-to-lua
Version:
A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!
89 lines • 5.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformModuleDeclaration = void 0;
exports.createModuleLocalName = createModuleLocalName;
exports.createModuleLocalNameIdentifier = createModuleLocalNameIdentifier;
const ts = require("typescript");
const lua = require("../../LuaAST");
const export_1 = require("../utils/export");
const lua_ast_1 = require("../utils/lua-ast");
const safe_names_1 = require("../utils/safe-names");
const scope_1 = require("../utils/scope");
const symbols_1 = require("../utils/symbols");
const identifier_1 = require("./identifier");
function createModuleLocalName(context, module) {
if (!ts.isSourceFile(module.parent) && ts.isModuleDeclaration(module.parent)) {
const parentDeclaration = createModuleLocalName(context, module.parent);
const name = createModuleLocalNameIdentifier(context, module);
return lua.createTableIndexExpression(parentDeclaration, lua.createStringLiteral(name.text), module.name);
}
return createModuleLocalNameIdentifier(context, module);
}
function createModuleLocalNameIdentifier(context, declaration) {
const moduleSymbol = context.checker.getSymbolAtLocation(declaration.name);
if (moduleSymbol !== undefined && (0, safe_names_1.isUnsafeName)(moduleSymbol.name, context.options)) {
return lua.createIdentifier((0, safe_names_1.createSafeName)(declaration.name.text), declaration.name, moduleSymbol && (0, symbols_1.getSymbolIdOfSymbol)(context, moduleSymbol), declaration.name.text);
}
return (0, identifier_1.transformIdentifier)(context, declaration.name);
}
// TODO: Do it based on transform result?
function moduleHasEmittedBody(node) {
if (node.body) {
if (ts.isModuleBlock(node.body)) {
// Ignore if body has no emitted statements
return node.body.statements.some(s => !ts.isInterfaceDeclaration(s) && !ts.isTypeAliasDeclaration(s));
}
else if (ts.isModuleDeclaration(node.body)) {
return true;
}
}
return false;
}
const transformModuleDeclaration = (node, context) => {
var _a, _b;
const currentNamespace = context.currentNamespaces;
const result = [];
const symbol = context.checker.getSymbolAtLocation(node.name);
const hasExports = symbol !== undefined && context.checker.getExportsOfModule(symbol).length > 0;
const nameIdentifier = (0, identifier_1.transformIdentifier)(context, node.name);
const exportScope = (0, export_1.getIdentifierExportScope)(context, nameIdentifier);
// Non-module namespace could be merged if:
// - is top level
// - is nested and exported
const isNonModuleMergeable = !context.isModule && (!currentNamespace || exportScope);
// This is NOT the first declaration if:
// - declared as a module before this (ignore interfaces with same name)
// - declared as a class or function at all (TS requires these to be before module, unless module is empty)
const isFirstDeclaration = symbol === undefined ||
(!((_a = symbol.declarations) === null || _a === void 0 ? void 0 : _a.some(d => ts.isClassLike(d) || ts.isFunctionDeclaration(d))) &&
ts.getOriginalNode(node) === ((_b = symbol.declarations) === null || _b === void 0 ? void 0 : _b.find(ts.isModuleDeclaration)));
if (isNonModuleMergeable) {
// 'local NS = NS or {}' or 'exportTable.NS = exportTable.NS or {}'
const localDeclaration = (0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, nameIdentifier, lua.createBinaryExpression((0, export_1.addExportToIdentifier)(context, nameIdentifier), lua.createTableExpression(), lua.SyntaxKind.OrOperator));
result.push(...localDeclaration);
}
else if (isFirstDeclaration) {
// local NS = {} or exportTable.NS = {}
const localDeclaration = (0, lua_ast_1.createLocalOrExportedOrGlobalDeclaration)(context, nameIdentifier, lua.createTableExpression());
result.push(...localDeclaration);
}
if ((isNonModuleMergeable || isFirstDeclaration) && exportScope && hasExports && moduleHasEmittedBody(node)) {
// local NS = exportTable.NS
const localDeclaration = (0, lua_ast_1.createHoistableVariableDeclarationStatement)(context, createModuleLocalNameIdentifier(context, node), (0, export_1.createExportedIdentifier)(context, nameIdentifier, exportScope));
result.push(localDeclaration);
}
// Set current namespace for nested NS
// Keep previous namespace to reset after block transpilation
context.currentNamespaces = node;
// Transform moduleblock to block and visit it
if (moduleHasEmittedBody(node)) {
context.pushScope(scope_1.ScopeType.Block, node);
const statements = (0, scope_1.performHoisting)(context, context.transformStatements(ts.isModuleBlock(node.body) ? node.body.statements : node.body));
context.popScope();
result.push(lua.createDoStatement(statements));
}
context.currentNamespaces = currentNamespace;
return result;
};
exports.transformModuleDeclaration = transformModuleDeclaration;
//# sourceMappingURL=namespace.js.map