Source: lib/store.js

/*
 *  MIPS-Simulator : store.js [Stores content into file]
 *  Copyright (C)  2017  Progyan Bhattacharya, Bytes Club
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

"use strict";

const fs = require("fs");

/** class: Store
 * @desc Store Parse Trre Object into File Passed as Parameter
 * @param {string}      file       - Destination File Path
 * @param {Object}      flag       - Configuration Object
 * @prop  {boolean}     isSilent   - Omit Error Message to Standard Error
 * @prop  {boolean}     showWarn   - Display Warning instead of Error/Log
 * @prop  {boolean}     showDetail - Display Details of The Error Message
 * @prop  {FileStream}  store      - FileStream Module of Node.JS for File IO
 * @prop  {string}      target     - Path to Destination File
 * @prop  {boolean}     hasError   - True iff Any Error has Occured
 * @prop  {string}      errorText  - The Error Message
 * @prop  {string}      error      - Details of The Error
 * @prop  {string}      content    - Parse Tree Object
 */
class Store extends Object {
    constructor({ file, flag }) {
        super();

        // House-keeping
        if (typeof file === "undefined" || file === null) {
            const err = "No file parameter passed. Expected one!";
            throw err;
        }

        // Member variables
        const flagDefined = typeof flag !== "undefined";
        this.isSilent     = flagDefined && typeof flag.silent === "boolean" ?
                            flag.silent :
                            false;
        this.showWarn     = flagDefined && typeof flag.warning === "boolean" ?
                            flag.warning :
                            true;
        this.showDetail   = flagDefined && typeof flag.details === "boolean" ?
                            flag.details :
                            false;
        this.store        = fs;
        this.target       = file;
        this.hasError     = false;
        this.errorText    = null;
        this.error        = null;
        this.content      = null;
        this.save         = this.save.bind(this);
        this.getError     = this.getError.bind(this);
    }

    /** method: save
     * @desc Save Contents into Output File Specified
     * @prop {FileStream} store  - File Loader for IO
     * @prop {string}     file   - Target File Path
    */
    save(content) {
        const { store, target: file } = this;

        // Check if file exist on path
        if (store.existsSync(file)) {
            console.log(`${file} already exists, trying to overwrite the` +
                " content.");
            store.truncateSync(file);

            // Check write permission on the file
            try {
                store.accessSync(file, store.constants.W_OK);
            } catch (e) {
                this.hasError = true;
                this.errorText = `Fatal Error: Cannot write to file ${file}.` +
                    " Make sure you have WRITE permission on it.";
                this.error = e.toString();
                return this.getError();
            }
        }

        // Read file content
        try {
            const data = JSON.stringify(content);
            store.writeFileSync(file, data, "utf8");
        } catch (e) {
            this.hasError = true;
            this.errorText = `Fatal Error: Failed to store into ${file}.` +
                " Make sure the file is not corrupted.";
            this.error = e.toString();
            return this.getError();
        }
    }

    /** method: getError
     * @desc Display Error Information if any
     * @prop {boolean} hasError   - True iff Any Error has Occured
     * @prop {boolean} isSilent   - Omit Error Message to Standard Error
     * @prop {boolean} showWarn   - Display Warning instead of Error/Log
     * @prop {boolean} showDetail - Display Details of The Error Message
     * @prop {string}  errorText  - The Error Message
     * @prop {string}  error      - Details of The Error
     */
    getError() {
        const
        { hasError, isSilent, showWarn, showDetail, error, errorText } = this;

        // If error occured
        if (hasError) {
            let errorMsg = errorText;
            if (showDetail && error) {
                errorMsg = `${errorMsg}\n${error}`;
            }
            if (isSilent) {
                if (showWarn) {
                    console.warn(errorMsg);
                } else {
                    console.log(errorMsg);
                }
            } else {
                console.error(errorMsg);
            }
        }
    }
}

module.exports = Store;