bufferedEditor.js

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("highland");
const lineStream_1 = require("./lineStream");
const bind_1 = require("./bind");
const files_1 = require("./files");
/** @class */
/** @implements {Editor} */
class BufferedEditor {
    constructor(filename) {
        this.filename = filename;
        this.writeBuffer = [];
        bind_1.default(this);
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * sets a `line` at a given line number `N`
     *
     * @method
     * set
     * @param {string} line
     * @param {number} n
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .set(1, line)
     *  .set(10, anotherline)
     *  .save();
     */
    set(i, line) {
        const pos = i - 1;
        if (pos > this.writeBuffer.length) {
            const ext = Array(pos - this.writeBuffer.length).fill('\n');
            this.writeBuffer = this.writeBuffer.concat(ext);
        }
        this.writeBuffer[pos] = `${line}\n`;
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Prepends a given `line` to a file
     *
     * @method
     * prepend
     * @param {string} line
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .prepend(line)
     *  .save();
     */
    prepend(line) {
        this.writeBuffer.unshift(`${line}\n`);
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Appends a given `line` to a file
     *
     * @method
     * append
     * @param {string} line
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .append(line)
     *  .save();
     */
    append(line) {
        this.writeBuffer.push(`${line}\n`);
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * replaces a given string or regex for every line
     *
     * @method
     * replace
     * @param {string|RegExp} source
     * @param {string} replacement
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .replace('x', 'y')
     *  .replace(/x/, 'y')
     *  .save();
     */
    replace(x, y) {
        this.writeBuffer = this.writeBuffer.map((line) => {
            return line.replace(x, y);
        });
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Maps each line using a given function
     *
     * @method
     * map
     * @param {function} fn
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .map((line) => {
     *      return line.toLowerCase() < 10;
     *  })
     *  .save();
     */
    map(fn) {
        this.writeBuffer = this.writeBuffer.map(fn);
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Filters the file contents using a given function
     *
     * @method
     * filter
     * @param {function} fn
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .filter((line) => {
     *      return line.length < 10;
     *  })
     *  .save();
     */
    filter(fn) {
        this.writeBuffer = this.writeBuffer.filter(fn);
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Deletes line by line number
     *
     * @method
     * delete
     * @param {function} fn
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .delete(10)
     *  .save(); // delete line 10
     */
    delete(n) {
        const pos = n - 1;
        this.writeBuffer.splice(pos, 1);
        return this;
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Writes any modifications to the file
     *
     * @method
     * save
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .set(1, line)
     *  .filter(fn)
     *  .map(fn)
     *  .save();
     */
    save() {
        return __awaiter(this, void 0, void 0, function* () {
            yield files_1.overwrite(this.modify, this.filename);
        });
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Writes any modifications to a given file
     *
     * @method
     * saveAs
     * @param {string} filename
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .set(1, line)
     *  .filter(fn)
     *  .map(fn)
     *  .saveAs('myFile');
     */
    saveAs(file) {
        return __awaiter(this, void 0, void 0, function* () {
            yield files_1.save(this.filename, file, this.modify);
        });
    }
    // tslint:disable-next-line:valid-jsdoc
    /**
     * Writes changes to stdout without modifying the source file. Useful for testing changes.
     *
     * @method
     * preview
     * @return Editor
     * @example
     * import FileSurgeon from 'FileSurgeon';
     *
     * const contents = FileSurgeon.edit(filename)
     *  .set(1, line)
     *  .filter(fn)
     *  .map(fn)
     *  .preview(); // writes changes to stdout
     */
    preview() {
        return __awaiter(this, void 0, void 0, function* () {
            let source;
            const dest = process.stdout;
            try {
                source = this.createSourceStream();
                yield this.modify(dest);
            }
            finally {
                source.destroy();
            }
        });
    }
    createSourceStream() {
        const source = lineStream_1.createStream(this.filename);
        return source;
    }
    modify(destination) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve) => {
                if (this.writeBuffer.length === 0)
                    resolve();
                _(this.writeBuffer).pipe(destination);
                destination.on('finish', () => {
                    resolve();
                });
            });
        });
    }
}
exports.BufferedEditor = BufferedEditor;