Skip to content

Commit

Permalink
feat: new reset method (#218) (#271)
Browse files Browse the repository at this point in the history
  • Loading branch information
KermanX authored Feb 5, 2024
1 parent 61f16f8 commit 3dc21e2
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/Chunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ export default class Chunk {
this.intro = content + this.intro;
}

reset() {
this.intro = '';
this.outro = '';
if (this.edited) {
this.content = this.original;
this.storeName = false;
this.edited = false;
}
}

split(index) {
const sliceIndex = index - this.start;

Expand Down
26 changes: 26 additions & 0 deletions src/MagicString.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,32 @@ export default class MagicString {
return this;
}

reset(start, end) {
while (start < 0) start += this.original.length;
while (end < 0) end += this.original.length;

if (start === end) return this;

if (start < 0 || end > this.original.length) throw new Error('Character is out of bounds');
if (start > end) throw new Error('end must be greater than start');

if (DEBUG) this.stats.time('reset');

this._split(start);
this._split(end);

let chunk = this.byStart[start];

while (chunk) {
chunk.reset();

chunk = end > chunk.end ? this.byStart[chunk.end] : null;
}

if (DEBUG) this.stats.timeEnd('reset');
return this;
}

lastChar() {
if (this.outro.length) return this.outro[this.outro.length - 1];
let chunk = this.lastChunk;
Expand Down
4 changes: 4 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ export default class MagicString {
* Removing the same content twice, or making removals that partially overlap, will cause an error.
*/
remove(start: number, end: number): MagicString;
/**
* Reset the modified characters from `start` to `end` (of the original string, **not** the generated string).
*/
reset(start: number, end: number): MagicString;
/**
* Returns the content of the generated string that corresponds to the slice between `start` and `end` of the original string.
* Throws error if the indices are for characters that were already removed.
Expand Down
125 changes: 125 additions & 0 deletions test/MagicString.js
Original file line number Diff line number Diff line change
Expand Up @@ -1199,6 +1199,131 @@ describe('MagicString', () => {
});
});

describe('reset', () => {
it('should reset moved characters from the original string', () => {
const s = new MagicString('abcdefghijkl');

s.remove(1, 5);
s.reset(2, 4);
assert.equal(s.toString(), 'acdfghijkl');

s.reset(4, 5);
assert.equal(s.toString(), 'acdefghijkl');
});

it('should reset from the start', () => {
const s = new MagicString('abcdefghijkl');

s.remove(0, 6);
s.reset(0, 3);
assert.equal(s.toString(), 'abcghijkl');
});

it('should reset from the end', () => {
const s = new MagicString('abcdefghijkl');

s.remove(6, 12);
s.reset(10, 12);
assert.equal(s.toString(), 'abcdefkl');
});

it('should treat zero-length resets as a no-op', () => {
const s = new MagicString('abcdefghijkl');

s.remove(3, 5);
s.reset(0, 0).reset(6, 6).reset(9, -3);
assert.equal(s.toString(), 'abcfghijkl');
});

it('should treat not modified resets as a no-op', () => {
const s = new MagicString('abcdefghijkl');

s.reset(3, 5);
assert.equal(s.toString(), 'abcdefghijkl');
});

it('should reset overlapping ranges', () => {
const s1 = new MagicString('abcdefghijkl');

s1.remove(0, 10);
s1.reset(1, 7).reset(5, 9);
assert.equal(s1.toString(), 'bcdefghikl');

const s2 = new MagicString('abcdefghijkl');

s2.remove(0, 10);
s2.reset(3, 7).reset(4, 6);
assert.equal(s2.toString(), 'defgkl');
});

it('should reset overlapping ranges, redux', () => {
const s = new MagicString('abccde');

s.remove(0, 6);
s.reset(2, 3); // c
s.reset(1, 3); // bc
assert.equal(s.toString(), 'bc');
});

it('should reset modified ranges', () => {
const s = new MagicString('abcdefghi');

s.overwrite(3, 6, 'DEF');
s.remove(1, 8); // bcDEFgh
s.reset(2, 7); // cDEFg
assert.equal(s.slice(1, 8), 'cdefg');
assert.equal(s.toString(), 'acdefgi');
});

it('should reset modified ranges, redux', () => {
const s = new MagicString('abcdefghi');

s.remove(1, 8);
s.appendLeft(2, 'W');
s.appendRight(2, 'X');
s.prependLeft(3, 'Y');
s.prependRight(5, 'Z');
s.reset(2, 7);
assert.equal(s.toString(), 'aWcdefgi');
});

it('should not reset content inserted after the end of range', () => {
const s = new MagicString('ab.c;');

s.prependRight(0, '(');
s.prependRight(4, ')');
s.remove(1, 4);
s.reset(2, 4);
assert.equal(s.toString(), '(a.c);');
});

it('should provide a useful error when illegal removals are attempted', () => {
const s = new MagicString('abcdefghijkl');

s.remove(4, 8);

s.overwrite(5, 7, 'XX');

assert.throws(() => s.reset(4, 6), /Cannot split a chunk that has already been edited/);
});

it('should return this', () => {
const s = new MagicString('abcdefghijkl');
s.remove(2, 5);
assert.strictEqual(s.reset(3, 4), s);
});

it('removes across moved content', () => {
const s = new MagicString('abcdefghijkl');

s.remove(5, 8);
s.move(6, 9, 3);
s.reset(7, 8);

assert.equal(s.toString(), 'abchidejkl');
});
});

describe('slice', () => {
it('should return the generated content between the specified original characters', () => {
const s = new MagicString('abcdefghijkl');
Expand Down

0 comments on commit 3dc21e2

Please sign in to comment.