UNPKG

rbxts-transformer-t

Version:

TypeScript transformer which converts TypeScript types to t entities

342 lines (341 loc) 15.1 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildType = exports.is_t_ImportDeclaration = exports.MARCO_NAME = exports.OBJECT_NAME = void 0; var typescript_1 = __importStar(require("typescript")); var get_installed_path_1 = require("get-installed-path"); var path_1 = __importDefault(require("path")); var fs_1 = __importDefault(require("fs")); var utility = __importStar(require("./utility")); exports.OBJECT_NAME = "t"; exports.MARCO_NAME = "$terrify"; var typePath = (0, get_installed_path_1.getInstalledPathSync)("@rbxts/types", { local: true }); var instanceDefType = path_1.default.normalize(path_1.default.join(typePath, "include", "generated", "None.d.ts")); function get_t_Path() { try { return (0, get_installed_path_1.getInstalledPathSync)("@rbxts/t", { local: true }); } catch (_a) { throw "[rbxts-transformer-t ERROR]: @rbxts/t must be installed for rbxts-transformer-t to work."; } } var ROBLOX_TYPES = [ "Axes", "BrickColor", "CFrame", "Color3", "ColorSequence", "ColorSequenceKeypoint", "DockWidgetPluginGuiInfo", "Faces", "Instance", "NumberRange", "NumberSequence", "NumberSequenceKeypoint", "PathWaypoint", "PhysicalProperties", "Random", "Ray", "Rect", "Region3", "Region3int16", "TweenInfo", "UDim", "UDim2", "Vector2", "Vector3", "Vector3int16", "RBXScriptSignal", "RBXScriptConnection", "Enum", "EnumItem", ]; function createPropertyAccess(propertyName) { return typescript_1.factory.createPropertyAccessExpression(typescript_1.factory.createIdentifier(exports.OBJECT_NAME), typescript_1.factory.createIdentifier(propertyName)); } function createMethodCall(methodName, params) { return typescript_1.factory.createCallExpression(createPropertyAccess(methodName), undefined, params); } function createLiteral(literal) { return createMethodCall("literal", [literal]); } function createLiteralExpression(type, typeChecker) { var stringType = typeChecker.typeToString(type); if (stringType === "true" || stringType === "false") { return stringType === "true" ? typescript_1.factory.createTrue() : typescript_1.factory.createFalse(); } if (type.isStringLiteral()) return typescript_1.factory.createStringLiteral(type.value); if (type.isNumberLiteral()) return typescript_1.factory.createNumericLiteral(type.value.toString()); } function convertTypesArray(types, typeChecker) { var transformNextType = function (types, result) { if (types.length === 0) return result; var _a = __read(types), head = _a[0], tail = _a.slice(1); var res = buildType(head, typeChecker); return transformNextType(tail, __spreadArray(__spreadArray([], __read(result), false), [res], false)); }; return transformNextType(types, []); } /** * Converts ts.UnionType to a ts.Expression */ function convertUnionType(type, typeChecker) { var _a; var nodes = (_a = type.aliasSymbol) === null || _a === void 0 ? void 0 : _a.declarations; var types = nodes !== undefined && nodes.length !== 0 ? nodes[0].type.types.map(typeChecker.getTypeFromTypeNode) : type.types; var _b = __read(utility.separateArray(types, utility.isLiteral(typeChecker)), 2), literalTypes = _b[0], notLiteralTypes = _b[1]; var literalExpression = literalTypes.length === 0 ? undefined : typescript_1.factory.createCallExpression(createPropertyAccess("literal"), undefined, literalTypes.map(function (type) { return createLiteralExpression(type, typeChecker); })); var result = convertTypesArray(notLiteralTypes, typeChecker); if (result.length === 0 && literalExpression) return literalExpression; if (literalExpression) result.push(literalExpression); return createMethodCall("union", result); } /** * Converts ts.TupleType to a ts.Expression */ function convertTupleType(type, typeChecker) { var result = convertTypesArray(type.resolvedTypeArguments, typeChecker); return createMethodCall("strictArray", result); } /** * Converts Array type to a ts.Expression */ function convertArrayType(type, typeChecker) { var args = type.typeArguments; if (args === undefined || args.length === 0) throw new Error("Array must have type arguments"); var result = buildType(args[0], typeChecker); return createMethodCall("array", [result]); } /** * Converts Map type to a ts.Expression */ function convertMapType(type, typeChecker) { var args = type.typeArguments; if (args === undefined) throw new Error("Map must have type arguments"); var result = convertTypesArray(args, typeChecker); return createMethodCall("map", result); } /** * Converts Array of object properties to t.interface Expression. If there are * optional properties, they will be built as separate objects * and mixed to main object using t.intersection function */ function convertObjectType(props, typeChecker) { if (props.length === 0) return createMethodCall("interface", [typescript_1.factory.createObjectLiteralExpression([])]); var preparedProps = props.map(function (prop) { var origin = prop.syntheticOrigin; return origin !== undefined ? origin : prop; }); // separate properties by weither // property is optional or not // and get 2 property lists var _a = __read(utility.separateArray(preparedProps, utility.isOptionalPropertyDeclaration), 2), optionalProps = _a[0], nonOptionalProps = _a[1]; // Builds t.interface entity by property list var handlePropList = function (props, isOptional) { var handledProps = props.map(function (prop) { return utility.extractProperty(prop, typeChecker); }); var types = handledProps.map(function (prop) { return prop.type; }); var result = convertTypesArray(types, typeChecker); var properties = result.map(function (p, i) { return typescript_1.factory.createPropertyAssignment(utility.buildPropertyName(handledProps[i].name), isOptional ? createMethodCall("optional", [p]) : p); }); return createMethodCall("interface", [typescript_1.factory.createObjectLiteralExpression(properties)]); }; // Build 2 or 1 objects for each optional props object and add them to the result array var result = []; if (optionalProps.length !== 0) result.push(handlePropList(optionalProps, true)); if (nonOptionalProps.length !== 0) result.push(handlePropList(nonOptionalProps)); return result.length === 1 ? result[0] : createMethodCall("intersection", result); } /** * Converts interface type to to ts.Expression */ function convertInterfaceType(type, typeChecker) { var _a; var props = (_a = type.declaredProperties) !== null && _a !== void 0 ? _a : []; var object = convertObjectType(props, typeChecker); var parents = type.symbol.declarations // TODO .map(function (d) { return d.heritageClauses; }) .filter(Boolean) .reduce(utility.mergeArrays, []) .map(function (clause) { return clause.types; }) .reduce(utility.mergeArrays, []) .map(typeChecker.getTypeFromTypeNode); if (parents.length === 0) return object; var parentsTransformed = convertTypesArray(parents, typeChecker); var nodesArray = __spreadArray([object], __read(parentsTransformed), false); return createMethodCall("intersection", nodesArray); } function convertEnumType(type, typeChecker) { var e_1, _a; var enumDeclaration = type.symbol.valueDeclaration; var result = []; try { for (var _b = __values(enumDeclaration.members), _c = _b.next(); !_c.done; _c = _b.next()) { var member = _c.value; var value = typeChecker.getConstantValue(member); if (typeof value === "string") result.push(typescript_1.factory.createStringLiteral(value)); else if (typeof value === "number") result.push(typescript_1.factory.createNumericLiteral(value)); else throw "Unsupported!"; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return createMethodCall("literal", result); } var tTypeDefinitions = fs_1.default.readFileSync(path_1.default.join(get_t_Path(), "lib", "t.d.ts"), "utf8"); function is_t_ImportDeclaration(program) { return function (node) { if (!typescript_1.default.isImportDeclaration(node)) return false; if (!node.importClause) return false; var namedBindings = node.importClause.namedBindings; if (!node.importClause.name && !namedBindings) return false; var importSymbol = program.getTypeChecker().getSymbolAtLocation(node.moduleSpecifier); if (!importSymbol || importSymbol.valueDeclaration.getSourceFile().text !== tTypeDefinitions) // TODO return false; return true; }; } exports.is_t_ImportDeclaration = is_t_ImportDeclaration; function buildType(type, typeChecker) { var _a, _b, _c, _d; var stringType = typeChecker.typeToString(type); // Checking for error cases if (stringType === "never") throw new Error("Never type transformation is not supported"); if (type.isClass()) throw new Error("Transformation of classes is not supported"); // Basic types transformation if (["null", "undefined", "void", "unknown"].includes(stringType)) return createPropertyAccess("none"); if (ROBLOX_TYPES.includes(stringType)) return createPropertyAccess(stringType); var fileName = (_d = (_c = (_b = (_a = type.symbol) === null || _a === void 0 ? void 0 : _a.declarations) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.getSourceFile()) === null || _d === void 0 ? void 0 : _d.fileName; if (fileName && path_1.default.normalize(fileName) === instanceDefType) { return createMethodCall("instanceIsA", [typescript_1.factory.createStringLiteral(stringType)]); } if (utility.isBrickColorType(type)) return createPropertyAccess("BrickColor"); if (utility.isEnum(type)) return createMethodCall("enum", [typescript_1.factory.createPropertyAccessExpression(typescript_1.factory.createIdentifier("Enum"), stringType)]); if (stringType === "true" || stringType === "false") { var literal = stringType === "true" ? typescript_1.factory.createTrue() : typescript_1.factory.createFalse(); return createLiteral(literal); } if (type.isStringLiteral()) return createLiteral(typescript_1.factory.createStringLiteral(type.value)); if (type.isNumberLiteral()) return createLiteral(typescript_1.factory.createNumericLiteral(type.value.toString())); if (["string", "number", "boolean", "any", "thread"].includes(stringType)) return createPropertyAccess(stringType); if (utility.isFunctionType(type)) return createPropertyAccess("callback"); // Complex types transformation try { if (utility.isCustomEnum(type)) return convertEnumType(type, typeChecker); if (utility.isMapType(type)) return convertMapType(type, typeChecker); if (type.isUnion()) return convertUnionType(type, typeChecker); else if (utility.isTupleType(type, typeChecker)) return convertTupleType(type, typeChecker); else if (utility.isArrayType(type, typeChecker)) return convertArrayType(type, typeChecker); else if (utility.isObjectType(type) || type.isIntersection()) return convertObjectType(type.getProperties(), typeChecker); else if (type.isClassOrInterface()) return convertInterfaceType(type, typeChecker); } catch (err) { throw "[t-ts-transformer ERROR]: Failed to build type ".concat(stringType, "\n").concat(err); } throw "Cannot build type ".concat(stringType); } exports.buildType = buildType;