From 29c7bfade8e7d91391c89cf913d65de84b19c3e9 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Sun, 3 Mar 2024 22:57:46 +0100 Subject: [PATCH] fix: handle last empty line correctly when using update/overwrite (#274) --- src/utils/Mappings.js | 5 ++++- test/MagicString.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/utils/Mappings.js b/src/utils/Mappings.js index 7a26bfc..7838644 100644 --- a/src/utils/Mappings.js +++ b/src/utils/Mappings.js @@ -12,9 +12,12 @@ export default class Mappings { addEdit(sourceIndex, content, loc, nameIndex) { if (content.length) { + const contentLengthMinusOne = content.length - 1; let contentLineEnd = content.indexOf('\n', 0); let previousContentLineEnd = -1; - while (contentLineEnd >= 0) { + // Loop through each line in the content and add a segment, but stop if the last line is empty, + // else code afterwards would fill one line too many + while (contentLineEnd >= 0 && contentLengthMinusOne > contentLineEnd) { const segment = [this.generatedCodeColumn, sourceIndex, loc.line, loc.column]; if (nameIndex >= 0) { segment.push(nameIndex); diff --git a/test/MagicString.js b/test/MagicString.js index 4298ea4..190cab9 100644 --- a/test/MagicString.js +++ b/test/MagicString.js @@ -491,6 +491,43 @@ describe('MagicString', () => { assert.equal(loc4.line, 1); assert.equal(loc4.column, 4); }); + + it('generates a correct source map with update using content ending with a new line', () => { + const s = new MagicString('foobar'); + s.update(2, 3, 'od\n'); + s.update(4, 5, 'a\nnd\n'); + assert.equal(s.toString(), 'food\nba\nnd\nr'); + + const map = s.generateMap({ hires: true }); + const smc = new SourceMapConsumer(map); + + // od\n + const loc = smc.originalPositionFor({ line: 1, column: 3 }); + assert.equal(loc.line, 1); + assert.equal(loc.column, 2); + const loc2 = smc.originalPositionFor({ line: 1, column: 4 }); + assert.equal(loc2.line, 1); + assert.equal(loc2.column, 2); + const loc3 = smc.originalPositionFor({ line: 2, column: 0 }); + assert.equal(loc3.line, 1); + assert.equal(loc3.column, 3); + const loc4 = smc.originalPositionFor({ line: 2, column: 1 }); + assert.equal(loc4.line, 1); + assert.equal(loc4.column, 4); + // a\nnd\n + const loc5 = smc.originalPositionFor({ line: 2, column: 2 }); + assert.equal(loc5.line, 1); + assert.equal(loc5.column, 4); + const loc6 = smc.originalPositionFor({ line: 2, column: 3 }); + assert.equal(loc6.line, 1); + assert.equal(loc6.column, 4); + const loc7 = smc.originalPositionFor({ line: 3, column: 0 }); + assert.equal(loc7.line, 1); + assert.equal(loc7.column, 4); + const loc8 = smc.originalPositionFor({ line: 4, column: 0 }); + assert.equal(loc8.line, 1); + assert.equal(loc8.column, 5); + }); }); describe('getIndentString', () => {