<commit_before>/* Contains code for handling plugin loading/removing and status management. */

export interface PluginData {
    [key: string]: any;
}

/* Each plugin is associated with an entry which stores the plugin code. */
export class PluginEntry {

    public _enabled: boolean;
    public _type: string;
    public _data: PluginData;
    public _name: string;
    public _description: string;
    public _status: string;
    public _errorMsg: string;

    public _onLoad: () => void;
    public _onRemove: () => void;

    constructor(json) {
        this._enabled = false;
        this._type = json.type;
        this._data = json.data;
        this._name = json.name;
        this._description = json.description;
        this._status = 'UNLOADED';
        this._errorMsg = '';

        this._onLoad = json.onLoad;
        this._onRemove = json.onRemove;
    }

    public getData() {return this._data;}

    public hasError() {
        return (/ERROR/).test(this._status);
    }

    public getErrorMsg() {
        return this._errorMsg;
    }

    public disable() {
        if (this._enabled) {
            if (typeof this._onRemove === 'function') {
                try {
                    this._onRemove();
                    this._status = 'UNLOADED';
                    this._errorMsg = '';
                }
                catch (e) {
                    this._errorMsg = e.message;
                    this._status = 'REMOVE ERROR';
                }
            }
            this._enabled = false;
        }
    }

    public enable() {
        if (!this._enabled) {
            if (typeof this._onLoad === 'function') {
                try {
                    this._onLoad();
                    this._status = 'LOADED';
                    this._errorMsg = '';
                }
                catch (e) {
                    this._errorMsg = e.message;
                    this._status = 'LOAD ERROR';
                }
            }
            this._enabled = true;
        }
    }

    public getName() {
        return this._name;
    }

    public isEnabled() {
        return this._enabled;
    }

}

/* Manager contains list of plugins that have been loaded. */
export default class PluginManager {
    public _plugins: PluginEntry[];
    public _errorMsg: string;

    constructor() {
        this._plugins = [];
        this._errorMsg = '';
    }

    public readJSON(json) {
        const entry = new PluginEntry(json);
        this._plugins.push(entry);
        return entry;
    }

    /* Returns true if any of the plugins are enabled. */
    public anyPluginsEnabled() {
        for (let i = 0; i < this._plugins.length; i++) {
            if (this._plugins[i].isEnabled()) {
                return true;
            }
        }
        return false;
    }

    public findPlugin(name) {
        return this._plugins.find(p => p._name === name);
    }

    public getPlugins() {
        return this._plugins.slice();
    }

    public getPluginNames() {
        return this._plugins.map(p => p._name);
    }

    public addPlugin(pluginData) {
        const entry = new PluginEntry(pluginData);
        this._plugins.push(entry);
        return entry;
    }

    public deletePlugin(name) {
        const index = this._plugins.findIndex(p => p.getName() === name);
        if (index >= 0) {
            this._plugins[index].disable();
            this._plugins.splice(index, 1);
        }
    }

    public disablePlugin(name) {
        const plugin = this.findPlugin(name);
        if (plugin) {
            plugin.disable();
        }
    }

    public enablePlugin(name) {
        const plugin = this.findPlugin(name);
        if (plugin) {
            plugin.enable();
        }
    }

    /* Loads a script using eval. */
    public loadScript(text) {
        try {
            /* eslint-disable */
            const pluginData = null;
            eval(text); // EVIL!!
            if (pluginData) {
                pluginData.data = text;
                this.addPlugin(pluginData);
                this._errorMsg = '';
            }
            else {
                this._errorMsg = 'no pluginData specified in the script';
            }
            /* eslint-enable */
        }
        catch (e) {
            this._errorMsg = e.message;
        }
    }
}<commit_msg>Added from/toJSON().<commit_after>/* Contains code for handling plugin loading/removing and status management. */

import RG from '../src/rg';
import {ObjectShell} from '../src/objectshellparser';

import * as AllCode from '../src/battles';

export interface PluginData {
    [key: string]: any;
}

/* Each plugin is associated with an entry which stores the plugin code. */
export class PluginEntry {

    public _enabled: boolean;
    public _type: string;
    public _data: PluginData;
    public _name: string;
    public _description: string;
    public _status: string;
    public _errorMsg: string;
    public _fileType: string;

    public _onLoad: () => void;
    public _onRemove: () => void;

    constructor(json) {
        this._enabled = false;
        this._type = json.type;
        this._data = json.data;
        this._name = json.name;
        this._description = json.description;
        this._fileType = json.fileType;
        this._status = 'UNLOADED';
        this._errorMsg = '';

        this._onLoad = json.onLoad;
        this._onRemove = json.onRemove;
    }

    public getData(): PluginData {return this._data;}

    public hasError() {
        return (/ERROR/).test(this._status);
    }

    public getErrorMsg() {
        return this._errorMsg;
    }

    public disable(): void {
        if (this._enabled) {
            if (typeof this._onRemove === 'function') {
                try {
                    this._onRemove();
                    this._status = 'UNLOADED';
                    this._errorMsg = '';
                }
                catch (e) {
                    this._errorMsg = e.message;
                    this._status = 'UNLOAD ERROR';
                }
            }
            this._enabled = false;
        }
    }

    public enable(): void {
        if (!this._enabled) {
            if (typeof this._onLoad === 'function') {
                try {
                    this._onLoad();
                    this._status = 'LOADED';
                    this._errorMsg = '';
                }
                catch (e) {
                    this._errorMsg = e.message;
                    this._status = 'LOAD ERROR';
                }
            }
            this._enabled = true;
        }
    }

    public getName(): string {
        return this._name;
    }

    public getType(): string {
        return this._type;
    }

    public isEnabled() {
        return this._enabled;
    }

    public toJSON() {
        return {
            type: this._type,
            fileType: this._fileType,
            name: this._name,
            data: this._data,
            description: this._description
        };
    }

}

/* Manager contains list of plugins that have been loaded. */
export class PluginManager {

    /* Returns a plugin manager from json. */
    public static fromJSON(jsonArr): PluginManager {
        const pm = new PluginManager();
        jsonArr.forEach(plugin => {
            if (plugin.fileType === 'json') {
                pm.readJSON(plugin);
            }
            else {
                pm.loadScript(plugin.data);
            }
        });
        pm.enableAll();
        /* TODO */
        return pm;
    }

    private _plugins: PluginEntry[];
    private _errorMsg: string;
    private _readCallbacks: {[key: string]: (entry: PluginEntry) => void};
    private _globalRefsWereSet: boolean;

    constructor() {
        this._plugins = [];
        this._errorMsg = '';
        this._readCallbacks = {
            [RG.TYPE_ACTOR]: this.parseShellsOnRead,
            [RG.TYPE_ITEM]: this.parseShellsOnRead,
            [RG.TYPE_ELEM]: this.parseShellsOnRead
        };
        this._globalRefsWereSet = false;
    }

    /* Loads plugin data in JSON format. */
    public readJSON(json): PluginEntry {
        json.fileType = 'json';
        const entry = this.addPlugin(json);
        const type = entry.getType();

        if (this._readCallbacks[type]) {
            this._readCallbacks[type](entry);
        }
        return entry;
    }

    /* Loads a script using eval. */
    public loadScript(text: string): PluginEntry {
        let entry: PluginEntry = null;
        try {
            this.setGlobalRefs();
            /* tslint:disable */
            let pluginData = null;
            // Note that eval'ed text must set the pluginData
            eval(text);
            /* tslint:enable */
            if (pluginData) {
                pluginData.data = text;
                pluginData.fileType = 'script';
                entry = this.addPlugin(pluginData);
                this._errorMsg = '';
            }
            else {
                this._errorMsg = 'no pluginData specified in the script';
            }

            if (this._globalRefsWereSet) {
                this.unsetGlobalRefs();
            }
            /* eslint-enable */
        }
        catch (e) {
            this._errorMsg = e.message;
            if (this._globalRefsWereSet) {
                this.unsetGlobalRefs();
            }
            throw e;
        }
        return entry;
    }

    /* Returns true if any of the plugins are enabled. */
    public anyPluginsEnabled(): boolean {
        for (let i = 0; i < this._plugins.length; i++) {
            if (this._plugins[i].isEnabled()) {
                return true;
            }
        }
        return false;
    }

    public findPlugin(name): PluginEntry | null {
        return this._plugins.find(p => p._name === name);
    }

    public getPlugins(): PluginEntry[] {
        return this._plugins.slice();
    }

    public getPluginNames(): string[] {
        return this._plugins.map(p => p._name);
    }

    public addPlugin(pluginData): PluginEntry {
        this.validateType(pluginData);
        const entry = new PluginEntry(pluginData);
        this._plugins.push(entry);
        return entry;
    }

    public deletePlugin(name: string): void {
        const index = this._plugins.findIndex(p => p.getName() === name);
        if (index >= 0) {
            this._plugins[index].disable();
            this._plugins.splice(index, 1);
        }
    }

    public disablePlugin(name: string): void {
        const plugin: PluginData = this.findPlugin(name);
        if (plugin) {
            this.setGlobalRefs();
            plugin.disable();
            this.unsetGlobalRefs();
        }
    }

    public enablePlugin(name: string): void {
        const plugin: PluginData = this.findPlugin(name);
        if (plugin) {
            this.setGlobalRefs();
            plugin.enable();
            this.unsetGlobalRefs();
        }
    }

    public enableAll(): void {
        this.setGlobalRefs();
        this._plugins.forEach(plugin => {
            plugin.enable();
        });
        this.unsetGlobalRefs();
    }

    public disableAll(): void {
        this.setGlobalRefs();
        this._plugins.forEach(plugin => {
            plugin.disable();
        });
        this.unsetGlobalRefs();
    }

    public getError(): string {
        return this._errorMsg;
    }


    /* Serialize the plugin manager. */
    public toJSON(): any {
        return this._plugins.map(p => p.toJSON());
    }

    protected setGlobalRefs(): void {
        if (typeof window !== 'undefined') {
            if (!(window as any).RG) {
                console.log('SETTING GLOBAL REFS');
                this._globalRefsWereSet = true;
                (window as any).RG = AllCode;
            }
        }
        else if (typeof global !== 'undefined') {
            if (!(global as any).RG) {
                this._globalRefsWereSet = true;
                (global as any).RG = AllCode;
            }
        }
    }

    protected unsetGlobalRefs(): void {
        this._globalRefsWereSet = false;
        if (typeof window !== 'undefined') {
            (window as any).RG = undefined;
        }
        else if (typeof global !== 'undefined') {
            (global as any).RG = undefined;
        }
    }

    protected withGlobalRefs(cb: () => void): void {
        this.setGlobalRefs();
        cb();
        this.unsetGlobalRefs();
    }

    protected parseShellsOnRead = (entry: PluginEntry): void => {
        const data = entry.getData();
        const type = entry.getType();
        const types = [RG.TYPE_ACTOR, RG.TYPE_ITEM, RG.TYPE_ELEM];
        types.forEach(propType => {
            if (type === propType) {
                const parser = ObjectShell.getParser();
                parser.parseShellCateg(propType, data);
            }
        });
    }

    protected validateType(pluginData): void {
        const types = [
            'plugin', 'items', 'actors', 'elements', 'system'
        ];
        if (!pluginData.type) {
            throw new Error('pluginData must have type specified');
        }
        const index = types.indexOf(pluginData.type);
        if (index < 0) {
            let msg = 'type must be any of the following: ';
            msg += JSON.stringify(types);
            msg += ` but got |${pluginData.type}|`;
            throw new Error(msg);
        }
    }


}
{'fraction_non_alphanumeric': 0.11585547924753657, 'fraction_numerical': 0.0005225440429979098, 'mean_word_length': 1.5263058646049406, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2333506', 'n_tokens_mistral': 3735, 'n_tokens_neox': 3568, 'n_words': 867}