UNPKG

greybel-js

Version:

Transpiler/Interpreter for GreyScript. (GreyHack)

211 lines 8.24 kB
import fs from 'fs/promises'; import path from 'path'; import { generateAutoCompileCode } from '../helper/auto-compile-helper.js'; import { createBasePath } from '../helper/create-base-path.js'; import { escapeMSString } from '../helper/escape-ms-string.js'; class InstallerFile { maxChars; rootDirectory; items; buffer; previous; constructor(options) { this.rootDirectory = options.rootDirectory; this.maxChars = options.maxChars; this.buffer = options.contentHeader; this.items = []; this.previous = options.previous ?? null; } insert(item) { const isNew = !this.previous?.items.includes(item); const remaining = this.getRemainingSpace(); const filePath = `${this.rootDirectory}${item.ingameFilepath}`; let line = `m("${filePath}","${item.content}",${isNew ? '1' : '0'});d`; if (remaining > line.length) { this.buffer += line.slice(0, -1); this.items.push(item); item.content = ''; return true; } let diff = item.content.length + (remaining - line.length); if (diff <= 0) { return false; } let content = item.content.slice(0, diff); const endingQuotes = content.match(/"+$/)?.[0]; if (endingQuotes && endingQuotes.length % 2 === 1) { content = item.content.slice(0, --diff); } line = `m("${filePath}","${content}",${isNew ? '1' : '0'});d`; this.buffer += line; this.items.push(item); item.content = item.content.slice(diff); return false; } appendCode(content) { const remaining = this.getRemainingSpace(); if (remaining > content.length) { this.buffer += content; return true; } return false; } getCode() { return this.buffer; } getRemainingSpace() { return this.maxChars - this.buffer.length; } } class Installer { importList; rootDir; rootPaths; ingameDirectory; buildPath; maxChars; files; createdFiles; autoCompile; constructor(options) { this.rootDir = options.rootDir; this.buildPath = options.buildPath; this.rootPaths = options.rootPaths; this.ingameDirectory = options.ingameDirectory.trim().replace(/\/$/i, ''); this.maxChars = options.maxChars; this.autoCompile = options.autoCompile; this.files = []; this.importList = this.createImportList(options.rootDir, options.result); this.createdFiles = []; this.autoCompile = options.autoCompile; } getCreatedFiles() { return this.createdFiles; } async createInstallerFiles() { await Promise.all(this.files.map(async (file, index) => { const target = path.resolve(this.buildPath, 'installer' + index + '.src'); this.createdFiles.push(target); await fs.writeFile(target, file.getCode(), { encoding: 'utf-8' }); })); } createImportList(rootDir, parseResult) { const imports = Object.entries(parseResult).map(([target, code]) => { const ingameFilepath = createBasePath(rootDir, target, ''); return { filepath: target, ingameFilepath, content: escapeMSString(code).replace(/import_code\(/gi, 'import"+"_"+"code(') }; }); return imports; } createContentHeader() { return [ 's = get_shell', 'c = s.host_computer', 'm = function(filePath, content, isNew)', ' segments = filePath.split("/")[1 : ]', ' fileName = segments.pop', ' for segment in segments', ' parentPath = "/" + segments[ : __segment_idx].join("/")', ' folderName = segment', ' if parentPath == "/" then', ' folderPath = "/" + folderName', ' else', ' folderPath = parentPath + "/" + folderName', ' end if', ' folderHandle = c.File(folderPath)', ' if folderHandle == null then', ' result = c.create_folder(parentPath, folderName) == 1', ' if result != 1 then exit("Could not create folder in """ + folderPath + """ due to: " + result)', ' print("New folder """ + folderPath + """ got created.")', ' folderHandle = c.File(folderPath)', ' end if', ' if not folderHandle.is_folder then exit("Entity at """ + folderPath + """ is not a folder. Installation got aborted.")', ' end for', ' parentPath = "/" + segments.join("/")', ' fileEntity = c.File(filePath)', ' if fileEntity == null then', ' result = c.touch(parentPath, fileName)', ' if result != 1 then exit("Could not create file in """ + filePath + """ due to: " + result)', ' fileEntity = c.File(filePath)', ' end if', ' if fileEntity == null then exit("Unable to get file at """ + filePath + """. Installation got aborted.")', ' if fileEntity.is_folder then exit("File at """ + filePath + """ is a folder but should be a source file. Installation got aborted.")', ' if fileEntity.is_binary then exit("File at """ + filePath + """ is a binary but should be a source file. Installation got aborted.")', ' if isNew then', ' fileEntity.set_content(content)', ' print("New file """ + filePath + """ got created.")', ' else', ' fileEntity.set_content(fileEntity.get_content + content)', ' print("Content got appended to """ + filePath + """.")', ' end if', 'end function', 'd = function', ' c.File(program_path).delete', 'end function', '' ] .map((line) => line.trim()) .join(';'); } createContentFooterAutoCompile() { if (this.autoCompile.enabled) { const rootImports = this.rootPaths.map((it) => { return this.importList.find((item) => item.filepath === it); }); return generateAutoCompileCode({ rootDirectory: this.ingameDirectory, rootFilePaths: rootImports.map((it) => it.ingameFilepath), importPaths: this.importList.map((it) => it.ingameFilepath), purge: this.autoCompile.purge, allowImport: this.autoCompile.allowImport }).split(';'); } return []; } createContentFooter() { return ['d', ...this.createContentFooterAutoCompile(), ''].join(';'); } async build() { let file = new InstallerFile({ rootDirectory: this.ingameDirectory, contentHeader: this.createContentHeader(), maxChars: this.maxChars }); this.files.push(file); for (const item of this.importList) { let done = false; while (!done) { done = file.insert(item); if (!done) { file = new InstallerFile({ rootDirectory: this.ingameDirectory, contentHeader: this.createContentHeader(), maxChars: this.maxChars, previous: file }); this.files.push(file); } } } const contentFooter = this.createContentFooter(); if (!file.appendCode(contentFooter)) { file = new InstallerFile({ rootDirectory: this.ingameDirectory, contentHeader: contentFooter, maxChars: this.maxChars, previous: file }); this.files.push(file); } await this.createInstallerFiles(); } } export const createInstaller = async (options) => { const installer = new Installer(options); await installer.build(); return installer.getCreatedFiles(); }; //# sourceMappingURL=installer.js.map