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

233 lines 7.86 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 CompilerError_1 = require("../errors/CompilerError"); const typeUtilities_1 = require("../typeUtilities"); const utility_1 = require("../utility"); const LUA_RESERVED_KEYWORDS = [ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", ]; const LUA_RESERVED_METAMETHODS = [ "__index", "__newindex", "__add", "__sub", "__mul", "__div", "__mod", "__pow", "__unm", "__eq", "__lt", "__le", "__call", "__concat", "__tostring", "__len", "__metatable", "__mode", ]; const LUA_RESERVED_NAMESPACES = [ "ipairs", "os", "type", "select", "math", "_G", "shared", "string", "require", "debug", "tonumber", "next", "_VERSION", "pairs", "pcall", "rawset", "error", "utf8", "setmetatable", "setfenv", "xpcall", "ypcall", "tostring", "print", "collectgarbage", "rawequal", "assert", "table", "coroutine", "rawget", "getmetatable", "getfenv", "tick", "wait", "delay", "spawn", "warn", "newproxy", "Random", "Axes", "BrickColor", "CFrame", "Color3", "ColorSequence", "ColorSequenceKeypoint", "Faces", "NumberRange", "NumberSequence", "NumberSequenceKeypoint", "Rect", "Region3", "Region3int16", "string", "UDim", "UDim2", "Vector2", "Vector3", "Ray", ]; const TS_RESERVED_KEYWORDS = ["_exports", "undefined", "TS", "globalThis", "table"]; function checkReserved(name, node, checkNamespace = false) { if (LUA_RESERVED_KEYWORDS.indexOf(name) !== -1) { throw new CompilerError_1.CompilerError(`Cannot use '${name}' as identifier (reserved Lua keyword)`, node, CompilerError_1.CompilerErrorType.ReservedKeyword); } else if (!name.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) { throw new CompilerError_1.CompilerError(`Cannot use '${name}' as identifier (doesn't match Lua's identifier rules)`, node, CompilerError_1.CompilerErrorType.InvalidIdentifier); } else if (TS_RESERVED_KEYWORDS.indexOf(name) !== -1 || name.match(/^_[0-9]+$/)) { throw new CompilerError_1.CompilerError(`Cannot use '${name}' as identifier (reserved for Roblox-ts)`, node, CompilerError_1.CompilerErrorType.RobloxTSReservedIdentifier); } else if (checkNamespace && LUA_RESERVED_NAMESPACES.indexOf(name) !== -1) { throw new CompilerError_1.CompilerError(`Cannot use '${name}' as identifier (reserved Lua namespace)`, node, CompilerError_1.CompilerErrorType.ReservedNamespace); } } exports.checkReserved = checkReserved; function checkMethodReserved(name, node) { checkReserved(name, node); if (LUA_RESERVED_METAMETHODS.indexOf(name) !== -1) { throw new CompilerError_1.CompilerError(`Cannot use '${name}' as a method name (reserved Lua metamethod)`, node, CompilerError_1.CompilerErrorType.ReservedMethodName); } } exports.checkMethodReserved = checkMethodReserved; const COMPILER_DIRECTIVE_TAG = "rbxts"; function getCompilerDirectiveFromDeclaration(node, directives) { if (ts.TypeGuards.isJSDocableNode(node)) { for (const jsDoc of node.getJsDocs()) { for (const jsTag of jsDoc.getTags()) { if (jsTag.getTagName() === COMPILER_DIRECTIVE_TAG) { const comment = jsTag.getComment(); if (comment) { for (const word of comment.split(" ")) { for (const directive of directives) { if (word === directive) { return directive; } } } } } } } } const parent = node.getParent(); if (parent) { const result = getCompilerDirectiveFromDeclaration(parent, directives); if (result !== undefined) { return result; } } } /** * Searches `node` recursively for directives. Returns either the first directive from the given list that it finds. * If it cannot find a directive from the list, it returns `undefined`. * Search is: * - left -> right * - inner -> outer * @param node JSDocable node to search * @param directives list of directives to search for */ function getCompilerDirective(symbol, directives) { for (const node of symbol.getDeclarations()) { const result = getCompilerDirectiveFromDeclaration(node, directives); if (result !== undefined) { return result; } } } exports.getCompilerDirective = getCompilerDirective; function checkApiAccess(state, node) { const symbol = node.getSymbol(); if (!symbol) { return; } if (state.scriptContext === utility_1.ScriptContext.Server) { if (getCompilerDirective(symbol, ["client" /* Client */, "server" /* Server */]) === "client" /* Client */) { throw new CompilerError_1.CompilerError("Server script attempted to access a client-only API!", node, CompilerError_1.CompilerErrorType.InvalidClientOnlyAPIAccess); } } else if (state.scriptContext === utility_1.ScriptContext.Client) { if (getCompilerDirective(symbol, ["client" /* Client */, "server" /* Server */]) === "server" /* Server */) { throw new CompilerError_1.CompilerError("Client script attempted to access a server-only API!", node, CompilerError_1.CompilerErrorType.InvalidServerOnlyAPIAccess); } } } exports.checkApiAccess = checkApiAccess; function checkNonAny(node, checkArrayType = false) { const isInCatch = node.getFirstAncestorByKind(ts.SyntaxKind.CatchClause) !== undefined; let type = typeUtilities_1.getType(node); if (checkArrayType && type.isArray()) { const arrayType = type.getArrayElementType(); if (arrayType) { type = arrayType; } } if (!isInCatch && typeUtilities_1.isAnyType(type)) { const parent = node.getParent(); if (parent) { throw new CompilerError_1.CompilerError(`${utility_1.yellow(node.getText())} in ${utility_1.yellow(parent.getText())} is of type ${utility_1.bold("any")} which is not supported! Use type ${utility_1.bold("unknown")} instead.`, node, CompilerError_1.CompilerErrorType.NoAny); } else { throw new CompilerError_1.CompilerError(`${utility_1.yellow(node.getText())} is of type ${utility_1.bold("any")} which is not supported! Use type ${utility_1.bold("unknown")} instead.`, node, CompilerError_1.CompilerErrorType.NoAny); } } return node; } exports.checkNonAny = checkNonAny; function checkReturnsNonAny(node) { const isInCatch = node.getFirstAncestorByKind(ts.SyntaxKind.CatchClause) !== undefined; if (!isInCatch && typeUtilities_1.isAnyType(node.getReturnType())) { throw new CompilerError_1.CompilerError(`Functions with a return type of type ${utility_1.bold("any")} are unsupported! Use type ${utility_1.bold("unknown")} instead!`, node, CompilerError_1.CompilerErrorType.NoAny); } } exports.checkReturnsNonAny = checkReturnsNonAny; //# sourceMappingURL=security.js.map