UNPKG

bedrock-development

Version:

APIs for creating and editing files related to Minecraft Bedrock development.

223 lines (222 loc) 8.86 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 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) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import * as fs from 'fs'; import * as path from 'path'; import { globSync } from 'glob'; import { chalk } from './utils.js'; import { exec } from "child_process"; import { fileURLToPath } from 'url'; import * as archiver from 'archiver'; /** * @remarks A global class for getting and setting workspace paths. */ export class Directories { static get PACKAGE_PATH() { return this.package_path; } /** * @remarks The path to the module's /src */ static get SOURCE_PATH() { return this.source_path + '/'; } /** * @remarks The path to the vanilla behavior pack samples packaged with the module. */ static get VANILLA_BEHAVIOR_PATH() { return Directories.SOURCE_PATH + 'vanilla/behavior_pack/'; } /** * @remarks The path to the vanilla resource pack samples packaged with the module. */ static get VANILLA_RESOURCE_PATH() { return Directories.SOURCE_PATH + 'vanilla/resource_pack/'; } /** * @remarks The behavior pack in the workspace. */ static get BEHAVIOR_PATH() { try { return globSync(this.behavior_path)[0].replace(/\/|\\+/g, '/') + '/'; } catch (error) { throw chalk.red("Cannot Find Behavior Path"); } } /** * @remarks The resource pack in the workspace. */ static get RESOURCE_PATH() { try { return globSync(this.resource_path)[0].replace(/\/|\\+/g, '/') + '/'; } catch (error) { throw chalk.red("Cannot Find Resource Path"); } } /** * @remarks The addon subpath <team>/<project> or an empty string if unspecified. */ static get ADDON_PATH() { return Directories.addon_path; } static set BEHAVIOR_PATH(v) { if (fs.existsSync(v)) { this.behavior_path = v; } else { console.warn(`${chalk.yellow(`Created directory ${v} and assigned to behavior path`)}`); fs.mkdirSync(v, { recursive: true }); this.behavior_path = v; } } static set RESOURCE_PATH(v) { if (fs.existsSync(v)) { this.resource_path = v; } else { console.warn(`${chalk.yellow(`Created directory ${v} and assigned to resource path`)}`); fs.mkdirSync(v, { recursive: true }); this.resource_path = v; } } static set ADDON_PATH(v) { Directories.addon_path = v + "/"; } } Directories.behavior_path = '**/behavior_packs/*bp/'; Directories.resource_path = '**/resource_packs/*rp/'; Directories.addon_path = ''; Directories.source_path = path.join(path.resolve(path.dirname(fileURLToPath(import.meta.url))), 'src'); Directories.package_path = path.join(path.resolve(path.dirname(path.dirname(path.dirname(fileURLToPath(import.meta.url))))), 'package.json'); /** * @remarks Gets files matching a glob pattern. * @param globPattern The glob pattern to use to find files. * @returns An array of {@link File}s matching the pattern. * @example * ```typescript * let files = getFiles(Directories.RESOURCE_PATH + 'texts/*.lang'); * ``` */ export function getFiles(globPattern) { globPattern = globPattern.replace(/\/|\\+/g, '/'); return globSync(globPattern).filter(file => fs.lstatSync(file).isFile()).map(file => { return { filePath: file, fileContents: String(fs.readFileSync(file)) }; }); } /** * @remarks Writes an array of files. * @param files The array of {@link File}s to write. * @example * ```typescript * let files = getFiles(Directories.RESOURCE_PATH + 'texts/*.lang'); * files.forEach(file => file.fileContents = ':)'); * setFiles(files); * ``` */ export function setFiles(files) { files.forEach(file => { if (!fs.existsSync(path.dirname(file.filePath))) { fs.mkdirSync(path.dirname(file.filePath), { recursive: true }); console.log(`${chalk.green(`Creating directory at ${path.dirname(file.filePath)}`)}`); } if (fs.existsSync(file.filePath)) { switch (file.handleExisting) { case 'overwrite': console.log(`${chalk.green(`Overwriting file at ${file.filePath}`)}`); fs.writeFileSync(file.filePath, file.fileContents); return; case 'overwrite_silent': fs.writeFileSync(file.filePath, file.fileContents); return; default: console.warn(`${chalk.yellow(`Won't overwrite file at ${file.filePath}`)}`); return; } } console.log(`${chalk.green(`Writing file at ${file.filePath}`)}`); fs.writeFileSync(file.filePath, file.fileContents); }); } /** * @remarks Copies a source file from this module to a destination. * @param sourceFile The filepath to a source file within this module's src. * @param targetPath The filepath to the destination the file should be copied to. * @param handleExisting How to handle existing files. Undefined will not overwrite, 'overwite' replaces the file with this object, * 'overwrite_silent' does the same with no terminal log. */ export function copySourceFile(sourceFile, targetPath, handleExisting) { if (!fs.existsSync(path.dirname(targetPath))) { fs.mkdirSync(path.dirname(targetPath), { recursive: true }); console.log(`${chalk.green(`Creating directory at ${path.dirname(targetPath)}`)}`); } if (fs.existsSync(targetPath)) { switch (handleExisting) { case 'overwrite': console.log(`${chalk.green(`Overwriting file at ${targetPath}`)}`); fs.copyFileSync(path.join(Directories.SOURCE_PATH, sourceFile), targetPath); return; case 'overwrite_silent': fs.copyFileSync(path.join(Directories.SOURCE_PATH, sourceFile), targetPath); return; default: console.warn(`${chalk.yellow(`Won't overwrite file at ${targetPath}`)}`); return; } } console.log(`${chalk.green(`Writing file at ${targetPath}`)}`); fs.copyFileSync(path.join(Directories.SOURCE_PATH, sourceFile), targetPath); } /** * @remarks Copies a source directory from this module to a destination. * @param src The path to a source directory within this module's src. * @param dest The filepath to the destination where the directory should be copied to. */ export function copySourceDirectory(src, dest) { fs.mkdirSync(dest, { recursive: true }); let entries = fs.readdirSync(src, { withFileTypes: true }); for (let entry of entries) { let srcPath = path.join(src, entry.name); let destPath = path.join(dest, entry.name); entry.isDirectory() ? copySourceDirectory(srcPath, destPath) : fs.copyFileSync(srcPath, destPath); } } /** * @remarks Archives a directory, compressing to a .zip or .mcworld for example. * @param dir The directory to archive. * @param zipPath The path the directory should be archived to. * @param callback A callback to run when the directory finishes archiving. */ export function archiveDirectory(dir, zipPath, callback) { let output = fs.createWriteStream(zipPath); let archive = archiver.default('zip', { zlib: { level: 9 } }); output.on('close', () => __awaiter(this, void 0, void 0, function* () { yield callback(); fs.rmSync(dir, { recursive: true, force: true }); })); archive.pipe(output); archive.directory(dir, ''); archive.finalize(); } /** * @remarks Creates a temporary file, opening it in Notepad. The contents of the file will be returned when Notepad is closed. * @returns A promise to a string. */ export function getStringFromTemporaryFile() { const filename = 'temp-' + Date.now() + '.txt'; fs.writeFileSync(filename, ''); return new Promise(resolve => { exec(`Notepad ${filename}`).on("close", () => { const contents = String(fs.readFileSync(filename)); fs.rmSync(filename); resolve(contents); }); }); }