"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;