From 4cf7754e655b069b05e30ee7255456b0babf3a65 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Sat, 8 Mar 2025 17:24:34 -0500 Subject: [PATCH] Strip BOM when applying diffs --- jest.config.js | 3 ++- package-lock.json | 22 ++++++++++++++++----- package.json | 3 ++- src/__mocks__/strip-bom.js | 13 ++++++++++++ src/integrations/editor/DiffViewProvider.ts | 9 +++++++-- 5 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 src/__mocks__/strip-bom.js diff --git a/jest.config.js b/jest.config.js index dbe5ee54eb..c18b6e9eff 100644 --- a/jest.config.js +++ b/jest.config.js @@ -30,9 +30,10 @@ module.exports = { "^strip-ansi$": "/src/__mocks__/strip-ansi.js", "^default-shell$": "/src/__mocks__/default-shell.js", "^os-name$": "/src/__mocks__/os-name.js", + "^strip-bom$": "/src/__mocks__/strip-bom.js", }, transformIgnorePatterns: [ - "node_modules/(?!(@modelcontextprotocol|delay|p-wait-for|globby|serialize-error|strip-ansi|default-shell|os-name)/)", + "node_modules/(?!(@modelcontextprotocol|delay|p-wait-for|globby|serialize-error|strip-ansi|default-shell|os-name|strip-bom)/)", ], roots: ["/src", "/webview-ui/src"], modulePathIgnorePatterns: [".vscode-test"], diff --git a/package-lock.json b/package-lock.json index 3b8f47c2e2..7c8935b791 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,6 +51,7 @@ "sound-play": "^1.1.0", "string-similarity": "^4.0.4", "strip-ansi": "^7.1.0", + "strip-bom": "^5.0.0", "tmp": "^0.2.3", "tree-sitter-wasms": "^0.1.11", "turndown": "^7.2.0", @@ -10782,6 +10783,15 @@ "node": ">=8" } }, + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-simple-dot-reporter": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/jest-simple-dot-reporter/-/jest-simple-dot-reporter-1.0.5.tgz", @@ -14170,12 +14180,14 @@ } }, "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", + "integrity": "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-final-newline": { diff --git a/package.json b/package.json index 5ddd9320f1..926218b21c 100644 --- a/package.json +++ b/package.json @@ -265,8 +265,8 @@ "@anthropic-ai/sdk": "^0.37.0", "@anthropic-ai/vertex-sdk": "^0.7.0", "@aws-sdk/client-bedrock-runtime": "^3.706.0", - "@google/generative-ai": "^0.18.0", "@google-cloud/vertexai": "^1.9.3", + "@google/generative-ai": "^0.18.0", "@mistralai/mistralai": "^1.3.6", "@modelcontextprotocol/sdk": "^1.0.1", "@types/clone-deep": "^4.0.4", @@ -304,6 +304,7 @@ "sound-play": "^1.1.0", "string-similarity": "^4.0.4", "strip-ansi": "^7.1.0", + "strip-bom": "^5.0.0", "tmp": "^0.2.3", "tree-sitter-wasms": "^0.1.11", "turndown": "^7.2.0", diff --git a/src/__mocks__/strip-bom.js b/src/__mocks__/strip-bom.js new file mode 100644 index 0000000000..64bb0dac4f --- /dev/null +++ b/src/__mocks__/strip-bom.js @@ -0,0 +1,13 @@ +// Mock implementation of strip-bom +module.exports = function stripBom(string) { + if (typeof string !== "string") { + throw new TypeError("Expected a string") + } + + // Removes UTF-8 BOM + if (string.charCodeAt(0) === 0xfeff) { + return string.slice(1) + } + + return string +} diff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts index ee24d7db4e..5058ca0252 100644 --- a/src/integrations/editor/DiffViewProvider.ts +++ b/src/integrations/editor/DiffViewProvider.ts @@ -7,6 +7,7 @@ import { formatResponse } from "../../core/prompts/responses" import { DecorationController } from "./DecorationController" import * as diff from "diff" import { diagnosticsToProblemsString, getNewDiagnostics } from "../diagnostics" +import stripBom from "strip-bom" export const DIFF_VIEW_URI_SCHEME = "cline-diff" @@ -104,7 +105,7 @@ export class DiffViewProvider { const edit = new vscode.WorkspaceEdit() const rangeToReplace = new vscode.Range(0, 0, endLine + 1, 0) const contentToReplace = accumulatedLines.slice(0, endLine + 1).join("\n") + "\n" - edit.replace(document.uri, rangeToReplace, contentToReplace) + edit.replace(document.uri, rangeToReplace, stripBom(stripBom(contentToReplace))) await vscode.workspace.applyEdit(edit) // Update decorations this.activeLineController.setActiveLine(endLine) @@ -128,7 +129,11 @@ export class DiffViewProvider { } // Apply the final content const finalEdit = new vscode.WorkspaceEdit() - finalEdit.replace(document.uri, new vscode.Range(0, 0, document.lineCount, 0), accumulatedContent) + finalEdit.replace( + document.uri, + new vscode.Range(0, 0, document.lineCount, 0), + stripBom(stripBom(accumulatedContent)), + ) await vscode.workspace.applyEdit(finalEdit) // Clear all decorations at the end (after applying final edit) this.fadedOverlayController.clear()