UNPKG

roblox-ts

Version:

<div align="center"><img width=25% src="https://i.imgur.com/yCjHmng.png"></div> <h1 align="center"><a href="https://roblox-ts.github.io/">roblox-ts</a></h1> <div align="center">A TypeScript-to-Lua Compiler for Roblox</div> <br> <div align="center"> <a hr

494 lines 18.1 kB
"use strict"; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const ts = __importStar(require("ts-morph")); const compiler_1 = require("./compiler"); const utility_1 = require("./utility"); exports.RBX_SERVICES = [ "AssetService", "BadgeService", "Chat", "CollectionService", "ContentProvider", "ContextActionService", "DataStoreService", "Debris", "GamePassService", "GroupService", "GuiService", "HapticService", "HttpService", "InsertService", "KeyframeSequenceProvider", "Lighting", "LocalizationService", "LogService", "MarketplaceService", "PathfindingService", "PhysicsService", "Players", "PointsService", "ReplicatedFirst", "ReplicatedStorage", "RunService", "ScriptContext", "Selection", "ServerScriptService", "ServerStorage", "SoundService", "StarterGui", "StarterPlayer", "Stats", "Teams", "TeleportService", "TestService", "TextService", "TweenService", "UserInputService", "VRService", "Workspace", ]; function isRbxService(name) { return exports.RBX_SERVICES.indexOf(name) !== -1; } exports.isRbxService = isRbxService; function isTypeStatement(node) { return (ts.TypeGuards.isEmptyStatement(node) || ts.TypeGuards.isTypeReferenceNode(node) || ts.TypeGuards.isTypeAliasDeclaration(node) || ts.TypeGuards.isInterfaceDeclaration(node) || (ts.TypeGuards.isAmbientableNode(node) && node.hasDeclareKeyword())); } exports.isTypeStatement = isTypeStatement; function isImport(node) { return (ts.TypeGuards.isImportSpecifier(node) || ts.TypeGuards.isImportClause(node) || ts.TypeGuards.isImportEqualsDeclaration(node)); } function isExport(node) { return ts.TypeGuards.isExportAssignment(node) || ts.TypeGuards.isExportSpecifier(node); } function isType(node) { if (ts.TypeGuards.isIdentifier(node)) { return isType(node.getParent()); } return (node.getKindName() === "TypeQuery" || ts.TypeGuards.isEmptyStatement(node) || ts.TypeGuards.isTypeReferenceNode(node) || ts.TypeGuards.isTypeAliasDeclaration(node) || ts.TypeGuards.isInterfaceDeclaration(node) || isImport(node) || isExport(node) || (ts.TypeGuards.isAmbientableNode(node) && node.hasDeclareKeyword())); } exports.isType = isType; function isUsedAsType(node) { try { for (const refSymbol of node.findReferences()) { for (const refEntry of refSymbol.getReferences()) { if (refEntry.getSourceFile() === node.getSourceFile()) { const ref = utility_1.skipNodesDownwards(refEntry.getNode()); if (!isType(ref)) { return false; } if (isExport(ref.getParent()) && ts.TypeGuards.isIdentifier(ref) && ref.getDefinitionNodes().some(n => !isType(n))) { return false; } } } } } catch (e) { // https://github.com/dsherret/ts-morph/issues/650 return false; } return true; } exports.isUsedAsType = isUsedAsType; function inheritsFrom(type, className) { const symbol = type.getSymbol(); if (symbol) { if (symbol.getName() === className) { return true; } const declarations = symbol.getDeclarations(); for (const declaration of declarations) { if (!ts.TypeGuards.isSourceFile(declaration)) { const decType = getType(declaration); const decBaseTypes = decType.getBaseTypes(); for (const baseType of decBaseTypes) { if (inheritsFrom(baseType, className)) { return true; } } } } } return false; } exports.inheritsFrom = inheritsFrom; function isTypeOnlyNamespace(node) { const statements = node.getStatements(); for (const statement of statements) { if (!ts.TypeGuards.isNamespaceDeclaration(statement) && !isType(statement)) { return false; } } for (const statement of statements) { if (ts.TypeGuards.isNamespaceDeclaration(statement) && !isTypeOnlyNamespace(statement)) { return false; } } return true; } exports.isTypeOnlyNamespace = isTypeOnlyNamespace; function typeConstraint(type, cb) { if (type.isUnion()) { return type.getUnionTypes().every(t => typeConstraint(t, cb)); } else if (type.isIntersection()) { return type.getIntersectionTypes().some(t => typeConstraint(t, cb)); } else { return cb(type); } } exports.typeConstraint = typeConstraint; function laxTypeConstraint(type, cb) { if (type.isUnion()) { return type.getUnionTypes().some(t => strictTypeConstraint(t, cb)); } else if (type.isIntersection()) { return type.getIntersectionTypes().some(t => strictTypeConstraint(t, cb)); } else { return cb(type); } } exports.laxTypeConstraint = laxTypeConstraint; function strictTypeConstraint(type, cb) { if (type.isUnion()) { return type.getUnionTypes().every(t => strictTypeConstraint(t, cb)); } else if (type.isIntersection()) { return type.getIntersectionTypes().every(t => strictTypeConstraint(t, cb)); } else { return cb(type); } } exports.strictTypeConstraint = strictTypeConstraint; function isSomeType(type, typeConstraintChecker, cb) { if (typeConstraintChecker(type, cb)) { return true; } else { if (type.isTypeParameter()) { const constraint = type.getConstraint(); if (constraint) { return typeConstraintChecker(constraint, cb); } } } return false; } const check = (t, c) => c(t); function isAnyType(type) { return isSomeType(type, check, t => t.getText() === "any"); } exports.isAnyType = isAnyType; function isNullableType(type) { return isSomeType(type, laxTypeConstraint, t => t.isNullable() || t.isUndefined()); } exports.isNullableType = isNullableType; function isBooleanType(type) { return isSomeType(type, typeConstraint, t => t.isBoolean() || t.isBooleanLiteral()); } exports.isBooleanType = isBooleanType; function isNumberType(type) { return isSomeType(type, typeConstraint, t => t.isNumber() || t.isNumberLiteral()); } exports.isNumberType = isNumberType; function isNumberTypeStrict(type) { return isSomeType(type, strictTypeConstraint, t => t.isNumber() || t.isNumberLiteral()); } exports.isNumberTypeStrict = isNumberTypeStrict; function isStringType(type) { return isSomeType(type, typeConstraint, t => t.isString() || t.isStringLiteral()); } exports.isStringType = isStringType; function isObjectType(type) { return isSomeType(type, typeConstraint, t => t.isObject()); } exports.isObjectType = isObjectType; function isEnumType(type) { return isSomeType(type, typeConstraint, t => { const symbol = t.getSymbol(); return symbol !== undefined && symbol.getDeclarations().some(d => ts.TypeGuards.isEnumDeclaration(d)); }); } exports.isEnumType = isEnumType; function isIterableIterator(type, node) { return isSomeType(type, typeConstraint, t => { const symbol = t.getSymbol(); return symbol ? symbol.getEscapedName() === "IterableIterator" : false; }); } exports.isIterableIterator = isIterableIterator; function isIterableFunction(type) { return isSomeType(type, check, t => { const symbol = t.getAliasSymbol(); return symbol ? symbol.getEscapedName() === "IterableFunction" : false; }); } exports.isIterableFunction = isIterableFunction; function getCompilerDirectiveHelper(type, directive, orCallback, t) { const symbol = t.getSymbol(); if ((symbol !== undefined && compiler_1.getCompilerDirective(symbol, [directive]) === directive) || orCallback(t)) { return true; } else { if (type.isTypeParameter()) { const constraint = type.getConstraint(); if (constraint) { return getCompilerDirectiveWithConstraint(constraint, directive, orCallback); } } return false; } } function getCompilerDirectiveWithConstraint(type, directive, orCallback = (t) => false) { return typeConstraint(type, t => getCompilerDirectiveHelper(type, directive, orCallback, t)); } exports.getCompilerDirectiveWithConstraint = getCompilerDirectiveWithConstraint; function getCompilerDirectiveWithStrictConstraint(type, directive, orCallback = (t) => false) { return strictTypeConstraint(type, t => getCompilerDirectiveHelper(type, directive, orCallback, t)); } exports.getCompilerDirectiveWithStrictConstraint = getCompilerDirectiveWithStrictConstraint; function getCompilerDirectiveWithLaxConstraint(type, directive, orCallback = (t) => false) { return laxTypeConstraint(type, t => getCompilerDirectiveHelper(type, directive, orCallback, t)); } exports.getCompilerDirectiveWithLaxConstraint = getCompilerDirectiveWithLaxConstraint; function superExpressionClassInheritsFromSetOrMap(node) { for (const constructSignature of getType(node).getConstructSignatures()) { const returnType = constructSignature.getReturnType(); if (getCompilerDirectiveWithConstraint(returnType, "set" /* Set */) || getCompilerDirectiveWithConstraint(returnType, "map" /* Map */)) { return true; } } return false; } exports.superExpressionClassInheritsFromSetOrMap = superExpressionClassInheritsFromSetOrMap; function superExpressionClassInheritsFromArray(node, recursive = true) { const type = getType(node); for (const constructSignature of type.getConstructSignatures()) { if (getCompilerDirectiveWithConstraint(constructSignature.getReturnType(), "array" /* Array */, t => t.isArray() || t.isTuple())) { return true; } } return recursive && inheritsFromArray(type); } exports.superExpressionClassInheritsFromArray = superExpressionClassInheritsFromArray; function classDeclarationInheritsFromArray(classExp, recursive = true) { const extendsExp = classExp.getExtends(); return extendsExp ? superExpressionClassInheritsFromArray(extendsExp.getExpression(), recursive) : false; } exports.classDeclarationInheritsFromArray = classDeclarationInheritsFromArray; function inheritsFromArray(type) { const symbol = type.getSymbol(); if (symbol) { for (const declaration of symbol.getDeclarations()) { if (ts.TypeGuards.isClassDeclaration(declaration) && classDeclarationInheritsFromArray(declaration)) { return true; } } } return false; } function isArrayTypeLax(type) { return getCompilerDirectiveWithLaxConstraint(type, "array" /* Array */, t => t.isArray() || t.isTuple() || inheritsFromArray(type)); } exports.isArrayTypeLax = isArrayTypeLax; function isStringMethodType(type) { return getCompilerDirectiveWithConstraint(type, "string" /* String */); } exports.isStringMethodType = isStringMethodType; function isArrayType(type) { return getCompilerDirectiveWithConstraint(type, "array" /* Array */, t => t.isArray() || t.isTuple() || inheritsFromArray(type)); } exports.isArrayType = isArrayType; function isMapType(type) { return getCompilerDirectiveWithConstraint(type, "map" /* Map */); } exports.isMapType = isMapType; function isSetType(type) { return getCompilerDirectiveWithConstraint(type, "set" /* Set */); } exports.isSetType = isSetType; function isMethodType(type) { return type.getCallSignatures().length > 0; } exports.isMethodType = isMethodType; function isArrayMethodType(type) { return isMethodType(type) && getCompilerDirectiveWithConstraint(type, "array" /* Array */); } exports.isArrayMethodType = isArrayMethodType; function isMapMethodType(type) { return isMethodType(type) && getCompilerDirectiveWithConstraint(type, "map" /* Map */); } exports.isMapMethodType = isMapMethodType; function isSetMethodType(type) { return isMethodType(type) && getCompilerDirectiveWithConstraint(type, "set" /* Set */); } exports.isSetMethodType = isSetMethodType; const LUA_TUPLE_REGEX = /^LuaTuple<[^]+>$/; function isTupleType(node) { return LUA_TUPLE_REGEX.test(node.getText()); } exports.isTupleType = isTupleType; function isTupleReturnType(node) { const returnTypeNode = node.getReturnTypeNode(); return returnTypeNode ? isTupleType(returnTypeNode) : false; } exports.isTupleReturnType = isTupleReturnType; function isTupleReturnTypeCall(node) { const expr = node.getExpression(); if (ts.TypeGuards.isIdentifier(expr)) { const definitions = expr.getDefinitions(); if ( // I don't think a case like this could ever occur, but I also don't want to be blamed if it does. definitions.length > 0 && definitions.every(def => { const declarationNode = def.getDeclarationNode(); return declarationNode && ts.TypeGuards.isFunctionDeclaration(declarationNode) ? isTupleReturnType(declarationNode) : false; })) { return true; } } const symbol = expr.getSymbol(); if (symbol) { const valDec = symbol.getValueDeclaration(); return valDec && ts.TypeGuards.isReturnTypedNode(valDec) ? isTupleReturnType(valDec) : false; } else { return false; } } exports.isTupleReturnTypeCall = isTupleReturnTypeCall; function isAncestorOf(ancestor, descendant) { while (descendant) { if (ancestor === descendant) { return true; } descendant = descendant.getParent(); } return false; } function shouldHoist(ancestor, id, checkAncestor = true) { if (ts.TypeGuards.isForStatement(ancestor)) { return false; } const refs = new Array(); for (const refSymbol of id.findReferences()) { for (const refEntry of refSymbol.getReferences()) { if (refEntry.getSourceFile() === id.getSourceFile()) { let refNode = refEntry.getNode(); if (ts.TypeGuards.isVariableDeclaration(refNode)) { refNode = refNode.getNameNode(); } refs.push(refNode); } } } const ancestorParent = ancestor.getParent(); const ancestorChildIndex = ancestor.getChildIndex(); const checkCallback = (ref) => { // if ever ref is in front if (ref === id) { return true; } if (checkAncestor && isAncestorOf(ancestor, ref)) { return false; } else { let refAncestor = ref; while (refAncestor && refAncestor.getParent() !== ancestorParent) { refAncestor = refAncestor.getParent(); } if (refAncestor && refAncestor.getChildIndex() >= ancestorChildIndex) { return true; } } return false; }; if (checkAncestor ? refs.every(checkCallback) : !refs.some(checkCallback)) { return false; } else { const caseClauseAncestor = ancestor.getFirstAncestorByKind(ts.SyntaxKind.CaseClause); if (caseClauseAncestor) { return shouldHoist(caseClauseAncestor, id, false); } return true; } } exports.shouldHoist = shouldHoist; function shouldPushToPrecedingStatement(arg, argStr, argContext) { return !argContext.isPushed && !isConstantExpression(arg); } exports.shouldPushToPrecedingStatement = shouldPushToPrecedingStatement; /** Returns whether or not the given expression is an expression containing only: * - constants * - numeric/string literals * - unary/binary/ternary expressions */ function isConstantExpression(node, maxDepth = Number.MAX_VALUE) { if (maxDepth >= 0) { if (ts.TypeGuards.isStringLiteral(node)) { return true; } else if (ts.TypeGuards.isNumericLiteral(node)) { return true; } else if (ts.TypeGuards.isIdentifier(node) && compiler_1.isIdentifierDefinedInConst(node)) { return true; } else if (ts.TypeGuards.isThisExpression(node) || ts.TypeGuards.isSuperExpression(node)) { return true; } else if (ts.TypeGuards.isBinaryExpression(node) && isConstantExpression(utility_1.skipNodesDownwards(node.getLeft()), maxDepth - 1) && isConstantExpression(utility_1.skipNodesDownwards(node.getRight()), maxDepth - 1)) { return true; } else if ((ts.TypeGuards.isPrefixUnaryExpression(node) || ts.TypeGuards.isPostfixUnaryExpression(node)) && isConstantExpression(utility_1.skipNodesDownwards(node.getOperand()), maxDepth)) { return true; } else if (ts.TypeGuards.isConditionalExpression(node) && isConstantExpression(utility_1.skipNodesDownwards(node.getCondition()), maxDepth - 1) && isConstantExpression(utility_1.skipNodesDownwards(node.getWhenTrue()), maxDepth - 1) && isConstantExpression(utility_1.skipNodesDownwards(node.getWhenFalse()), maxDepth - 1)) { return true; } } return false; } exports.isConstantExpression = isConstantExpression; /** Calls skipNodesUpwards and returns getType() */ function getType(node) { return utility_1.skipNodesUpwards(node).getType(); } exports.getType = getType; //# sourceMappingURL=typeUtilities.js.map