Skip to content

Commit

Permalink
feat(text): deleteBlock, deleteEveryBlock
Browse files Browse the repository at this point in the history
  • Loading branch information
seb-cr committed May 7, 2023
1 parent 881702c commit 3fda8fd
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
65 changes: 65 additions & 0 deletions src/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,69 @@ export class Text {
});
this.content = lines.join('\n');
}

/**
* Deletes the first group of lines that match `block`, or throws if no lines
* match.
*
* @param block Strings or RegExps that identify the lines.
*/
deleteBlock(block: (string | RegExp)[]) {
if (block.length === 0) {
return;
}

const lines = this.lines();
const patterns = block.map((it) => regex(it));
const maxIndex = lines.length - block.length;
const row = lines.findIndex((
(_, index) => index <= maxIndex && patterns.every((
(pattern, offset) => lines[index + offset].match(pattern)
))
));
if (row === -1) {
throw new Error(`No block found matching\n\n${patterns.join('\n')}`);
}
lines.splice(row, block.length);
this.content = lines.join('\n');
}

/**
* Deletes every group of lines that matches `block`.
*
* @param block Strings or RegExps that identify the lines.
*/
deleteEveryBlock(block: (string | RegExp)[]) {
if (block.length === 0) {
return;
}

const lines = this.lines();
const patterns = block.map((it) => regex(it));
const rows: number[] = [];
let matchRow = -1;
let matches = 0;
lines.forEach((line, index) => {
if (line.match(patterns[matches])) {
if (matches === 0) {
matchRow = index;
}
matches += 1;
if (matches === block.length) {
rows.push(matchRow);
matches = 0;
}
} else if (matches > 0) {
if (line.match(patterns[0])) {
matches = 1;
} else {
matches = 0;
}
}
});
rows.forEach((row, index) => {
lines.splice(row - index * block.length, block.length);
});
this.content = lines.join('\n');
}
}
41 changes: 41 additions & 0 deletions tests/text.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,45 @@ describe('Text', () => {
expect(text.content).to.equal('one');
});
});

describe('deleteBlock', () => {
it('should delete the first matching block (strings)', () => {
const text = new Text('one\ntwo\n\none\nthree\n\none\ntwo');
text.deleteBlock(['one', 'two']);
expect(text.content).to.equal('\none\nthree\n\none\ntwo');
});

it('should delete the first matching block (regexps)', () => {
const text = new Text('one\ntwo\n\none\nthree\n\none\ntwo');
text.deleteBlock([/one/, /two/]);
expect(text.content).to.equal('\none\nthree\n\none\ntwo');
});

it('should throw if no block matches', () => {
const text = new Text('one');
expect(
() => text.deleteBlock(['one', 'two']),
).to.throw('No block found matching\n\n/one/\n/two/');
});
});

describe('deleteEveryBlock', () => {
it('should delete all matching blocks (strings)', () => {
const text = new Text('one\ntwo\n\none\nthree\n\none\ntwo');
text.deleteEveryBlock(['one', 'two']);
expect(text.content).to.equal('\none\nthree\n');
});

it('should delete all matching blocks (regexps)', () => {
const text = new Text('one\ntwo\n\none\nthree\n\none\ntwo');
text.deleteEveryBlock([/one/, /two/]);
expect(text.content).to.equal('\none\nthree\n');
});

it('should not consider lines overlapping in blocks that match', () => {
const text = new Text('one\none\none\ntwo');
text.deleteEveryBlock(['one', 'one']);
expect(text.content).to.equal('one\ntwo');
});
});
});

0 comments on commit 3fda8fd

Please sign in to comment.