103 lines
2.9 KiB
TypeScript
103 lines
2.9 KiB
TypeScript
import fs from 'fs';
|
|
import MagicString from 'magic-string';
|
|
|
|
export class MagicFile extends MagicString {
|
|
private filePath: string;
|
|
|
|
constructor(filePath: string) {
|
|
if (!fs.existsSync(filePath)) throw new Error('File not found');
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
super(content);
|
|
this.filePath = filePath;
|
|
}
|
|
|
|
saveFile() {
|
|
fs.writeFileSync(this.filePath, this.toString(), 'utf-8');
|
|
}
|
|
|
|
private getLineOffset(lineNumber: number) {
|
|
const lines = this.original.split('\n');
|
|
if (lineNumber < 0 || lineNumber >= lines.length) {
|
|
throw new Error('Line number out of range');
|
|
}
|
|
|
|
return lines
|
|
.slice(0, lineNumber)
|
|
.reduce((offset, line) => offset + line.length + 1, 0); // +1 for the newline character
|
|
}
|
|
|
|
/**
|
|
* Set the MagicString offset by the first line that includes the search.
|
|
*
|
|
* @param search Search string or RegEx
|
|
* @param offsetLineNumber Line number after which to start searching (0-based index)
|
|
* @returns MagicString instance
|
|
*/
|
|
findOffsetLine(search: string | RegExp, offsetLineNumber: number = 0) {
|
|
const lines = this.original.split('\n');
|
|
if (offsetLineNumber < 0 || offsetLineNumber >= lines.length) {
|
|
throw new Error('Offset line number out of range');
|
|
}
|
|
|
|
const lineIndex = lines
|
|
.slice(offsetLineNumber + 1)
|
|
.findIndex((line) =>
|
|
typeof search === 'string' ? line.includes(search) : search.test(line)
|
|
);
|
|
|
|
if (lineIndex === -1) {
|
|
throw new Error('Content not found');
|
|
}
|
|
|
|
const adjustedLineIndex = offsetLineNumber + 1 + lineIndex;
|
|
|
|
this.offset = this.getLineOffset(adjustedLineIndex);
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set the MagicString offset by line index. (Lines start at 1.)
|
|
*
|
|
* @param {number} lineNumber
|
|
* @returns MagicString instance
|
|
*/
|
|
offsetLine(lineNumber: number) {
|
|
const lines = this.original.split('\n');
|
|
if (lineNumber <= 0 || lineNumber > lines.length) {
|
|
throw new Error('Line number out of range');
|
|
}
|
|
|
|
this.offset = this.getLineOffset(lineNumber - 1);
|
|
|
|
return this;
|
|
}
|
|
|
|
private getEndOfLineIndex() {
|
|
const lineEndIndex = this.original.indexOf('\n', this.offset);
|
|
const endIndex =
|
|
lineEndIndex === -1 ? this.original.length : lineEndIndex - this.offset;
|
|
return endIndex;
|
|
}
|
|
|
|
appendToLine(content: string) {
|
|
const endOfLineIndex = this.getEndOfLineIndex();
|
|
return this.appendRight(endOfLineIndex, content);
|
|
}
|
|
|
|
replaceLine(content: string) {
|
|
const endOfLineIndex = this.getEndOfLineIndex();
|
|
return this.overwrite(this.offset, endOfLineIndex, content);
|
|
}
|
|
|
|
prependToLine(content: string) {
|
|
return this.appendLeft(0, content);
|
|
}
|
|
|
|
locations(search: string) {
|
|
const start = this.original.indexOf(search);
|
|
if (start === -1) throw new Error('Search string not found');
|
|
const end = start + search.length;
|
|
return { start, end };
|
|
}
|
|
}
|