UNPKG

roblox-ts

Version:

A TypeScript-to-Luau Compiler for Roblox

171 lines 8.93 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.transformSourceFile = transformSourceFile; const luau_ast_1 = __importDefault(require("@roblox-ts/luau-ast")); const rojo_resolver_1 = require("@roblox-ts/rojo-resolver"); const constants_1 = require("../../Shared/constants"); const assert_1 = require("../../Shared/util/assert"); const transformIdentifier_1 = require("./expressions/transformIdentifier"); const transformStatementList_1 = require("./transformStatementList"); const getOriginalSymbolOfNode_1 = require("../util/getOriginalSymbolOfNode"); const isSymbolMutable_1 = require("../util/isSymbolMutable"); const isSymbolOfValue_1 = require("../util/isSymbolOfValue"); const traversal_1 = require("../util/traversal"); const typescript_1 = __importDefault(require("typescript")); function getExportPair(state, exportSymbol) { var _a, _b; const declaration = (_a = exportSymbol.getDeclarations()) === null || _a === void 0 ? void 0 : _a[0]; if (declaration && typescript_1.default.isExportSpecifier(declaration)) { return [declaration.name.text, (0, transformIdentifier_1.transformIdentifierDefined)(state, (_b = declaration.propertyName) !== null && _b !== void 0 ? _b : declaration.name)]; } else { let name = exportSymbol.name; if (exportSymbol.name === "default" && declaration && (typescript_1.default.isFunctionDeclaration(declaration) || typescript_1.default.isClassDeclaration(declaration)) && declaration.name) { name = declaration.name.text; } return [exportSymbol.name, luau_ast_1.default.id(name)]; } } function isExportSymbolFromExportFrom(exportSymbol) { if (exportSymbol.declarations) { for (const exportSpecifier of exportSymbol.declarations) { if (typescript_1.default.isExportSpecifier(exportSpecifier)) { const exportDec = exportSpecifier.parent.parent; if (typescript_1.default.isExportDeclaration(exportDec) && exportDec.moduleSpecifier) { return true; } } } } return false; } function getIgnoredExportSymbols(state, sourceFile) { const ignoredSymbols = new Set(); for (const statement of sourceFile.statements) { if (typescript_1.default.isExportDeclaration(statement) && statement.moduleSpecifier) { if (!statement.exportClause) { const moduleSymbol = (0, getOriginalSymbolOfNode_1.getOriginalSymbolOfNode)(state.typeChecker, statement.moduleSpecifier); if (moduleSymbol) { state.getModuleExports(moduleSymbol).forEach(v => ignoredSymbols.add(v)); } } else if (typescript_1.default.isNamespaceExport(statement.exportClause)) { const idSymbol = state.typeChecker.getSymbolAtLocation(statement.exportClause.name); if (idSymbol) { ignoredSymbols.add(idSymbol); } } } } return ignoredSymbols; } function isExportSymbolOnlyFromDeclare(exportSymbol) { var _a, _b; return ((_b = (_a = exportSymbol.declarations) === null || _a === void 0 ? void 0 : _a.every(declaration => { const statement = (0, traversal_1.getAncestor)(declaration, typescript_1.default.isStatement); const modifiers = statement && typescript_1.default.canHaveModifiers(statement) ? typescript_1.default.getModifiers(statement) : undefined; return modifiers === null || modifiers === void 0 ? void 0 : modifiers.some(v => v.kind === typescript_1.default.SyntaxKind.DeclareKeyword); })) !== null && _b !== void 0 ? _b : false); } function handleExports(state, sourceFile, symbol, statements) { const ignoredExportSymbols = getIgnoredExportSymbols(state, sourceFile); let mustPushExports = state.hasExportFrom; const exportPairs = new Array(); if (!state.hasExportEquals) { for (const exportSymbol of state.getModuleExports(symbol)) { if (ignoredExportSymbols.has(exportSymbol)) continue; if (!!(exportSymbol.flags & typescript_1.default.SymbolFlags.Prototype)) continue; if (isExportSymbolFromExportFrom(exportSymbol)) continue; const originalSymbol = typescript_1.default.skipAlias(exportSymbol, state.typeChecker); if (!(0, isSymbolOfValue_1.isSymbolOfValue)(originalSymbol)) continue; if ((0, isSymbolMutable_1.isSymbolMutable)(state, originalSymbol)) { mustPushExports = true; continue; } if (isExportSymbolOnlyFromDeclare(exportSymbol)) continue; exportPairs.push(getExportPair(state, exportSymbol)); } } if (state.hasExportEquals) { const finalStatement = sourceFile.statements[sourceFile.statements.length - 1]; if (!(typescript_1.default.isExportAssignment(finalStatement) && finalStatement.isExportEquals)) { luau_ast_1.default.list.push(statements, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ReturnStatement, { expression: luau_ast_1.default.globals.exports, })); } } else if (mustPushExports) { luau_ast_1.default.list.unshift(statements, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.VariableDeclaration, { left: luau_ast_1.default.globals.exports, right: luau_ast_1.default.map(), })); for (const [exportKey, exportId] of exportPairs) { luau_ast_1.default.list.push(statements, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Assignment, { left: luau_ast_1.default.property(luau_ast_1.default.globals.exports, exportKey), operator: "=", right: exportId, })); } luau_ast_1.default.list.push(statements, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ReturnStatement, { expression: luau_ast_1.default.globals.exports, })); } else if (exportPairs.length > 0) { const fields = luau_ast_1.default.list.make(); for (const [exportKey, exportId] of exportPairs) { luau_ast_1.default.list.push(fields, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.MapField, { index: luau_ast_1.default.string(exportKey), value: exportId, })); } luau_ast_1.default.list.push(statements, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ReturnStatement, { expression: luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.Map, { fields, }), })); } } function getLastNonCommentStatement(listNode) { while (listNode && luau_ast_1.default.isComment(listNode.value)) { listNode = listNode.prev; } return listNode; } function transformSourceFile(state, node) { const symbol = state.typeChecker.getSymbolAtLocation(node); (0, assert_1.assert)(symbol); state.setModuleIdBySymbol(symbol, luau_ast_1.default.globals.exports); const statements = (0, transformStatementList_1.transformStatementList)(state, node, node.statements, undefined); handleExports(state, node, symbol, statements); const lastStatement = getLastNonCommentStatement(statements.tail); if (!lastStatement || !luau_ast_1.default.isReturnStatement(lastStatement.value)) { const outputPath = state.pathTranslator.getOutputPath(node.fileName); if (state.rojoResolver.getRbxTypeFromFilePath(outputPath) === rojo_resolver_1.RbxType.ModuleScript) { luau_ast_1.default.list.push(statements, luau_ast_1.default.create(luau_ast_1.default.SyntaxKind.ReturnStatement, { expression: luau_ast_1.default.nil() })); } } const headerStatements = luau_ast_1.default.list.make(); luau_ast_1.default.list.push(headerStatements, luau_ast_1.default.comment(` Compiled with roblox-ts v${constants_1.COMPILER_VERSION}`)); if (state.usesRuntimeLib) { luau_ast_1.default.list.push(headerStatements, state.createRuntimeLibImport(node)); } const directiveComments = luau_ast_1.default.list.make(); while (statements.head && luau_ast_1.default.isComment(statements.head.value) && statements.head.value.text.startsWith("!")) { luau_ast_1.default.list.push(directiveComments, luau_ast_1.default.list.shift(statements)); } luau_ast_1.default.list.unshiftList(statements, headerStatements); luau_ast_1.default.list.unshiftList(statements, directiveComments); return statements; } //# sourceMappingURL=transformSourceFile.js.map