Fix newline insertion bug in replace tool (#18595)

This commit is contained in:
Andrew Garrett
2026-02-09 17:37:53 +11:00
committed by GitHub
parent d45a45d565
commit 8cbe851339
2 changed files with 39 additions and 2 deletions

View File

@@ -372,6 +372,43 @@ describe('EditTool', () => {
expect(result.newContent).toBe(expectedContent);
expect(result.occurrences).toBe(1);
});
it('should NOT insert extra newlines when replacing a block preceded by a blank line (regression)', async () => {
const content = '\n function oldFunc() {\n // some code\n }';
const result = await calculateReplacement(mockConfig, {
params: {
file_path: 'test.js',
instruction: 'test',
old_string: 'function oldFunc() {\n // some code\n }', // Two spaces after function to trigger regex
new_string: 'function newFunc() {\n // new code\n}', // Unindented
},
currentContent: content,
abortSignal,
});
// The blank line at the start should be preserved as-is,
// and the discovered indentation (2 spaces) should be applied to each line.
const expectedContent = '\n function newFunc() {\n // new code\n }';
expect(result.newContent).toBe(expectedContent);
});
it('should NOT insert extra newlines in flexible replacement when old_string starts with a blank line (regression)', async () => {
const content = ' // some comment\n\n function oldFunc() {}';
const result = await calculateReplacement(mockConfig, {
params: {
file_path: 'test.js',
instruction: 'test',
old_string: '\nfunction oldFunc() {}',
new_string: '\n function newFunc() {}', // Include desired indentation
},
currentContent: content,
abortSignal,
});
// The blank line at the start is preserved, and the new block is inserted.
const expectedContent = ' // some comment\n\n function newFunc() {}';
expect(result.newContent).toBe(expectedContent);
});
});
describe('validateToolParams', () => {

View File

@@ -167,7 +167,7 @@ async function calculateFlexibleReplacement(
if (isMatch) {
flexibleOccurrences++;
const firstLineInMatch = window[0];
const indentationMatch = firstLineInMatch.match(/^(\s*)/);
const indentationMatch = firstLineInMatch.match(/^([ \t]*)/);
const indentation = indentationMatch ? indentationMatch[1] : '';
const newBlockWithIndent = replaceLines.map(
(line: string) => `${indentation}${line}`,
@@ -229,7 +229,7 @@ async function calculateRegexReplacement(
// The final pattern captures leading whitespace (indentation) and then matches the token pattern.
// 'm' flag enables multi-line mode, so '^' matches the start of any line.
const finalPattern = `^(\\s*)${pattern}`;
const finalPattern = `^([ \t]*)${pattern}`;
const flexibleRegex = new RegExp(finalPattern, 'm');
const match = flexibleRegex.exec(currentContent);