UNPKG

greybel-js

Version:

Transpiler/Interpreter for GreyScript. (GreyHack)

176 lines (175 loc) 6.2 kB
import fs from 'fs/promises'; import path from 'path'; import { generateAutoCompileCode } from './scripts/auto-compile-helper.js'; import { createBasePath } from '../helper/create-base-path.js'; import { escapeMSString } from '../helper/escape-ms-string.js'; import { generateContentHeader } from './scripts/installer-content-header.js'; class InstallerFile { maxChars; destination; items; buffer; previous; constructor(options) { this.destination = options.destination; 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.destination}${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; resourceDirectory; 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.resourceDirectory = options.resourceDirectory.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; } getDestination() { return this.autoCompile ? this.resourceDirectory : this.ingameDirectory; } 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 [ `BUILD_DESTINATION="${this.ingameDirectory}"`, `BUILD_RESOURCE_DESTINATION="${this.resourceDirectory}"`, `BUILD_AUTO_COMPILE=${this.autoCompile ? '1' : '0'}`, generateContentHeader(), '' ] .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({ rootFilePaths: rootImports.map((it) => it.ingameFilepath), importPaths: this.importList.map((it) => it.ingameFilepath), allowImport: this.autoCompile.allowImport }).split(';'); } return []; } createContentFooter() { return ['d', ...this.createContentFooterAutoCompile(), ''].join(';'); } async build() { let file = new InstallerFile({ destination: this.getDestination(), 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({ destination: this.getDestination(), contentHeader: this.createContentHeader(), maxChars: this.maxChars, previous: file }); this.files.push(file); } } } const contentFooter = this.createContentFooter(); if (!file.appendCode(contentFooter)) { file = new InstallerFile({ destination: this.getDestination(), 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(); };