bedrock-development
Version:
APIs for creating and editing files related to Minecraft Bedrock development.
196 lines (169 loc) • 5.77 kB
text/typescript
import {Chalk} from 'chalk';
import * as path from 'path';
import { Directories, getFiles, setFiles } from './file_manager.js';
/**
* @remarks A globally accessible instance of the {@link Chalk} class that provides colored text in the terminal.
*/
export const chalk = new Chalk();
/**
* @remarks The format version shared by all Minecraft Types.
*/
export const currentFormatVersion = '1.20.50';
/**
* @remarks A class for working with name data like identifiers.
*/
export class NameData {
private static teamName: string = '';
private static projectName: string = '';
/**
* @remarks The original source string, i.e. `subfolder/minecraft:test`.
*/
public original: string;
/**
* @remarks The full identifier of the source string, i.e. `minecraft:test`.
*/
public fullname: string;
/**
* @remarks The namespace of the source stirng, i.e. `minecraft:test`.
*/
public namespace: string;
/**
* @remarks The shortname of the source string, i.e. `test` from either `minecraft:test` or `geometry.test`.
*/
public shortname: string;
/**
* @remarks The display name of the source string as used in the lang, i.e. `Test`.
*/
public display: string;
/**
* @remarks The directory name of the source string, i.e. `subfolder/`.
*/
public directory: string;
/**
* @remarks The name of the development team.
*/
public static get TeamName() : string {
return NameData.teamName;
}
/**
* @remarks The name of the Project
*/
public static get ProjectName() : string {
return NameData.projectName;
}
/**
* @remarks Creates a namedata object from a source string.
* @param name The source string to create namedata from.
* @example
* ```typescript
* let name = new NameData("subfolder/minecraft:test");
* ```
*/
constructor(name: string) {
this.original = name;
this.fullname = path.basename(name);
this.namespace = this.fullname.split(/\.|:/)[1] ?? `${NameData.teamName}_${NameData.ProjectName}`;
this.shortname = this.fullname.split(/\.|:/).pop() ?? '';
if (!this.fullname.includes(this.namespace)) {
this.fullname = this.namespace + ':' + this.shortname;
}
this.directory = path.dirname(name) + '/';
if (this.directory === './') {
this.directory = '';
}
const words = this.splitWords(this.shortname);
for (let i = 0; i < words.length; i++) {
words[i] = words[i][0].toUpperCase() + words[i].substring(1);
}
this.display = words.join(' ');
}
private splitWords(name: string): string[] {
name = name.replace(/_/g, ' ');
return name.split(' ');
}
public static setAddonNamespace(namespace: string) {
NameData.teamName = namespace.split(/_/).shift() ?? '';
NameData.projectName = namespace.split(/_/).pop() ?? '';
}
}
/**
* @remarks Determines if a value is an object or a primitive.
* @param item The item to check.
* @returns True if the item is an object.
*/
export function isObject(item: any): boolean {
return item && typeof item === "object" && !Array.isArray(item);
}
/**
* @remarks Performs a deep merge between two objects.
* @param target The target object to merge with.
* @param source The source object to merge with the target.
* @returns An object with the properties of the source and target merged deeply.
* @example
* ```typescript
* mergeDeep({subProperty: {targetKey: 1}}, {subProperty: {sourceKey: 2}});
* // Returns {subProperty: {targetKey: 1, sourceKey: 2}};
* ```
*/
export function mergeDeep(target: any, source: any) {
let output = Object.assign({}, target);
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach((key) => {
if (isObject(source[key])) {
if (!(key in target)) Object.assign(output, { [key]: source[key] });
else output[key] = mergeDeep(target[key], source[key]);
} else if (Array.isArray(source[key])) {
if (!(key in target)) Object.assign(output, { [key]: source[key] });
else Object.assign(output, { [key]: target[key].concat(source[key]) });
} else {
Object.assign(output, { [key]: source[key] });
}
});
}
return output;
}
/**
* @remarks The format of the bedrock.config.json file.
*/
export interface IConfigData {
addon_namespace: string;
}
/**
* @remarks Gets the config data from the working directory.
*/
export function getConfig(): IConfigData|undefined {
const config = getFiles('bedrock.config.json')[0];
if (config) {
return JSON.parse(config.fileContents) as any;
}
}
export function implementConfig() {
const config = getConfig();
if (config) {
setAddonName(config.addon_namespace);
console.log(`${chalk.green(`Got addon namespace (${config.addon_namespace}) from config file`)}`);
}
}
/**
* @remarks Sets the bedrock.config.json file contents.
* @param config The config data to write.
*/
export function setConfig(config: IConfigData) {
const files = getFiles('bedrock.config.json');
if (!files.length) {
files.push({filePath: 'bedrock.config.json', fileContents: ''});
}
files.forEach(file => {
file.fileContents = JSON.stringify(config, null, '\t');
file.handleExisting = 'overwrite';
});
setFiles(files);
}
/**
* @remarks Sets the global addon data from the addon namespace.
* @param addon The addon name as <team_name>_<project_name>.
*/
export function setAddonName(addon: string) {
Directories.ADDON_PATH = addon.replace(/_/, '/');
NameData.setAddonNamespace(addon);
}