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
JavaScript
"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