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
243 lines • 9.62 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ajv_1 = __importDefault(require("ajv"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const ajv = new ajv_1.default();
class RojoProjectError extends Error {
}
exports.RojoProjectError = RojoProjectError;
const ROJO_METADATA_REGEX = /^\$/;
const LUA_EXT = ".lua";
const FOLDER_EXT = "";
const SUB_EXT_TYPE_MAP = new Map([
["", "ModuleScript"],
[".server", "Script"],
[".client", "LocalScript"],
]);
const DEFAULT_ISOLATED_CONTAINERS = [
["StarterPack"],
["StarterGui"],
["StarterPlayer", "StarterPlayerScripts"],
["StarterPlayer", "StarterCharacterScripts"],
["StarterPlayer", "StarterCharacter"],
];
const CLIENT_CONTAINERS = [["StarterPack"], ["StarterGui"], ["StarterPlayer"]];
const SERVER_CONTAINERS = [["ServerStorage"], ["ServerScriptService"]];
function stripExts(filePath) {
const ext = path_1.default.extname(filePath);
filePath = filePath.slice(0, -ext.length);
const subext = path_1.default.extname(filePath);
if (subext.length > 0) {
filePath = filePath.slice(0, -subext.length);
}
return filePath;
}
function arrayStartsWith(a, b) {
const minLength = Math.min(a.length, b.length);
for (let i = 0; i < minLength; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
var FileRelation;
(function (FileRelation) {
FileRelation[FileRelation["OutToOut"] = 0] = "OutToOut";
FileRelation[FileRelation["OutToIn"] = 1] = "OutToIn";
FileRelation[FileRelation["InToOut"] = 2] = "InToOut";
FileRelation[FileRelation["InToIn"] = 3] = "InToIn";
})(FileRelation = exports.FileRelation || (exports.FileRelation = {}));
var NetworkType;
(function (NetworkType) {
NetworkType[NetworkType["Unknown"] = 0] = "Unknown";
NetworkType[NetworkType["Client"] = 1] = "Client";
NetworkType[NetworkType["Server"] = 2] = "Server";
})(NetworkType = exports.NetworkType || (exports.NetworkType = {}));
class RojoProject {
constructor(basePath, config) {
this.partitions = new Array();
this.isolatedContainers = [...DEFAULT_ISOLATED_CONTAINERS];
this.basePath = basePath;
this.tree = config.tree;
this.parseTree(config.tree, []);
}
parseTree(tree, rbxPath) {
if (tree.$path) {
const ext = path_1.default.extname(tree.$path);
if (ext === LUA_EXT || ext === FOLDER_EXT) {
this.partitions.push({
base: [...rbxPath],
fsPath: path_1.default.resolve(this.basePath, tree.$path),
isFile: ext === LUA_EXT,
});
}
}
if (tree.$isolated === true) {
this.isolatedContainers.push([...rbxPath]);
}
for (const childName of Object.keys(tree).filter(v => !ROJO_METADATA_REGEX.test(v))) {
rbxPath.push(childName);
this.parseTree(tree[childName], rbxPath);
rbxPath.pop();
}
}
static fromPath(rojoPath) {
return __awaiter(this, void 0, void 0, function* () {
if (!path_1.default.isAbsolute(rojoPath)) {
rojoPath = path_1.default.resolve(rojoPath);
}
if (yield fs_extra_1.default.pathExists(rojoPath)) {
if (!this.validateRojo) {
this.validateRojo = ajv.compile(JSON.parse((yield fs_extra_1.default.readFile(path_1.default.join(__dirname, "..", "rojo-schema.json"))).toString()));
}
const objectJson = JSON.parse((yield fs_extra_1.default.readFile(rojoPath)).toString());
if (this.validateRojo(objectJson)) {
return new RojoProject(path_1.default.resolve(rojoPath, ".."), objectJson);
}
else {
throw new RojoProjectError("Invalid Rojo configuration!\n" + JSON.stringify(this.validateRojo.errors));
}
}
else {
throw new RojoProjectError(`${rojoPath} is not a valid path!`);
}
});
}
static fromPathSync(rojoPath) {
if (!path_1.default.isAbsolute(rojoPath)) {
rojoPath = path_1.default.resolve(rojoPath);
}
if (fs_extra_1.default.pathExistsSync(rojoPath)) {
if (!this.validateRojo) {
this.validateRojo = ajv.compile(JSON.parse(fs_extra_1.default.readFileSync(path_1.default.join(__dirname, "..", "rojo-schema.json")).toString()));
}
const objectJson = JSON.parse(fs_extra_1.default.readFileSync(rojoPath).toString());
if (this.validateRojo(objectJson)) {
return new RojoProject(path_1.default.resolve(rojoPath, ".."), objectJson);
}
else {
throw new RojoProjectError("Invalid Rojo configuration!\n" + JSON.stringify(this.validateRojo.errors));
}
}
else {
throw new RojoProjectError(`${rojoPath} is not a valid path!`);
}
}
static cwd() {
return __awaiter(this, void 0, void 0, function* () {
return this.fromPath(process.cwd());
});
}
getRbxPathFromFile(filePath) {
if (!path_1.default.isAbsolute(filePath)) {
filePath = path_1.default.resolve(this.basePath, filePath);
}
for (const partition of this.partitions) {
if (partition.isFile) {
if (partition.fsPath === filePath) {
return [...partition.base];
}
}
else {
if (filePath.startsWith(partition.fsPath)) {
const relative = path_1.default.relative(partition.fsPath, stripExts(filePath)).split(path_1.default.sep);
if (relative[relative.length - 1] === "init") {
relative.pop();
}
return partition.base.concat(relative);
}
}
}
}
getRbxFromFile(filePath) {
const subext = path_1.default.extname(path_1.default.basename(filePath, path_1.default.extname(filePath)));
return {
path: this.getRbxPathFromFile(filePath),
type: SUB_EXT_TYPE_MAP.get(subext) || "Unknown",
};
}
isGame() {
return this.tree.$className === "DataModel";
}
getContainer(from, rbxPath) {
if (this.isGame()) {
if (rbxPath) {
for (const container of from) {
if (arrayStartsWith(rbxPath, container)) {
return container;
}
}
}
}
}
getFileRelation(filePath, modulePath) {
const fileContainer = this.getContainer(this.isolatedContainers, this.getRbxPathFromFile(filePath));
const moduleContainer = this.getContainer(this.isolatedContainers, this.getRbxPathFromFile(modulePath));
if (fileContainer && moduleContainer) {
if (fileContainer === moduleContainer) {
return FileRelation.InToIn;
}
else {
return FileRelation.OutToIn;
}
}
else if (fileContainer && !moduleContainer) {
return FileRelation.InToOut;
}
else if (!fileContainer && moduleContainer) {
return FileRelation.OutToIn;
}
else {
// !fileContainer && !moduleContainer
return FileRelation.OutToOut;
}
}
isIsolated(filePath) {
return this.getContainer(this.isolatedContainers, this.getRbxPathFromFile(filePath)) !== undefined;
}
getNetworkType(filePath) {
const rbxPath = this.getRbxPathFromFile(filePath);
if (this.getContainer(SERVER_CONTAINERS, rbxPath)) {
return NetworkType.Server;
}
if (this.getContainer(CLIENT_CONTAINERS, rbxPath)) {
return NetworkType.Client;
}
return NetworkType.Unknown;
}
static relative(rbxFrom, rbxTo) {
const maxLength = Math.max(rbxFrom.length, rbxTo.length);
let diffIndex = maxLength;
for (let i = 0; i < maxLength; i++) {
if (rbxFrom[i] !== rbxTo[i]) {
diffIndex = i;
break;
}
}
const result = new Array();
if (diffIndex < rbxFrom.length) {
for (let i = 0; i < rbxFrom.length - diffIndex; i++) {
result.push("..");
}
}
for (let i = diffIndex; i < rbxTo.length; i++) {
result.push(rbxTo[i]);
}
return result;
}
}
exports.RojoProject = RojoProject;
//# sourceMappingURL=RojoProject.js.map