apply-multi-diff
Version:
A zero-dependency library to apply unified diffs and search-and-replace patches, with support for fuzzy matching.
38 lines (32 loc) • 4.34 kB
JavaScript
var constants=require('../constants'),error=require('../utils/error'),string=require('../utils/string');const y=e=>`apply_diff Tool: Standard Diff Format
Applies unified diff to a file. Supports fuzzy matching and hunk splitting.
Parameters:
:file_path: Path to file relative to ${e}
:diff_content: Unified diff format with ---\` headers, followed by one or more \`@@ ... @@\` hunk headers.
- Lines starting with \` \` (a space) are context and must match the original file.
- Lines starting with \`-\` will be removed.
- Lines starting with \`+\` will be added.
Example:
<apply_diff file_path="src/component.tsx">
\`\`\`diff
--- a/src/component.tsx
+++ b/src/component.tsx
@@ -10,7 +10,8 @@
function MyComponent() {
- const [count, setCount] = useState(0);
+ const [count, setCount] = useState(1);
+ const [name, setName] = useState('');
return (
<div>
\`\`\`
</apply_diff>`,k=e=>{const l=e.split(`
`),i=[];let t=null;const o=/^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@/,a=/^@@ .* @@/;for(const s of l){if(s.startsWith("---")||s.startsWith("+++"))continue;let r=s.match(o);r?(t&&i.push(t),t={originalStartLine:parseInt(r[1]??"0",10),originalLineCount:r[3]?parseInt(r[3],10):1,newStartLine:parseInt(r[4]??"0",10),newLineCount:r[6]?parseInt(r[6],10):1,lines:[]}):a.test(s)?(t&&i.push(t),t={originalStartLine:1,originalLineCount:1,newStartLine:1,newLineCount:1,lines:[]}):t&&(s.startsWith(" ")||s.startsWith("+")||s.startsWith("-"))&&t.lines.push(s);}return t&&i.push(t),i.length>0?i:null},g=(e,l,i)=>{const t=[...e.slice(0,i)];let o=i;for(const a of l.lines){const s=a.substring(1);if(a.startsWith("+")){t.push(s);continue}let r=-1;const u=Math.min(o+10,e.length);for(let n=o;n<u;n++)if(e[n]===s){r=n;break}if(r!==-1){for(let n=o;n<r;n++){const c=e[n];c!==void 0&&t.push(c);}if(a.startsWith(" ")){const n=e[r];n!==void 0&&t.push(n);}o=r+1;}else {if(a.startsWith(" ")){const n=e[o];n!==void 0&&t.push(n);}o++;}}return t.push(...e.slice(o)),t},m=(e,l)=>{const i=l.lines.filter(n=>n.startsWith(" ")||n.startsWith("-")).map(n=>n.substring(1));if(i.length===0){const n=l.originalStartLine,c=[...e],f=l.lines.filter(h=>h.startsWith("+")).map(h=>h.substring(1));return c.splice(n,0,...f),{success:true,newLines:c}}const t=l.originalStartLine-1;if(t>=0&&t+i.length<=e.length&&e.slice(t,t+i.length).join(`
`)===i.join(`
`))return {success:true,newLines:g(e,l,t)};if(l.lines.filter(n=>n.startsWith(" ")).length===0&&i.length>0)return {success:false};let a=-1,s=1/0;const r=i.join(`
`),u=Math.floor(r.length*.3);for(let n=0;n<=e.length-i.length;n++){const c=e.slice(n,n+i.length).join(`
`),f=string.levenshtein(r,c);if(f<s&&(s=f,a=n),f===0)break}return a!==-1&&s<=u?{success:true,newLines:g(e,l,a)}:{success:false}},x=e=>{const l=[];let t=0;for(;t<e.lines.length;){for(;t<e.lines.length&&e.lines[t]?.startsWith(" ");)t++;if(t===e.lines.length)break;const o=t;for(;t<e.lines.length&&!e.lines[t]?.startsWith(" ");)t++;const a=t,s=Math.max(0,o-2),r=Math.min(e.lines.length,a+2),u=e.lines.slice(s,r);l.push({...e,lines:u});}return l},L=(e,l)=>{const i=k(l);if(!i)return error.createErrorResult(constants.ERROR_CODES.INVALID_DIFF_FORMAT,"Invalid diff format. Could not parse any hunks.");for(let s=0;s<i.length;s++)for(let r=s+1;r<i.length;r++){const u=i[s],n=i[r];if(!u||!n)continue;const c=u.originalStartLine+u.originalLineCount;if(Math.max(u.originalStartLine,n.originalStartLine)<Math.min(c,n.originalStartLine+n.originalLineCount))return error.createErrorResult(constants.ERROR_CODES.OVERLAPPING_HUNKS,"Hunks overlap, which is not supported.")}let t=e.split(`
`),o=true;for(const s of i){const r=m(t,s);if(r.success)t=r.newLines;else {const u=x(s);if(u.length<=1){o=false;break}let n=true;for(const c of u){const f=m(t,c);if(f.success)t=f.newLines;else {n=false;break}}if(!n){o=false;break}}}if(!o)return error.createErrorResult(constants.ERROR_CODES.CONTEXT_MISMATCH,"Could not apply modification. A hunk could not be matched, even with fuzzy search and hunk splitting fallbacks.");let a=t.join(`
`);return !e.endsWith(`
`)&&l.includes("+line 2")&&(a+=`
`),{success:true,content:a}};exports._findAndApplyHunk_for_debug=m;exports._parseHunks_for_debug=k;exports._splitHunk_for_debug=x;exports.applyDiff=L;exports.getToolDescription=y;//# sourceMappingURL=standard-diff.cjs.map
//# sourceMappingURL=standard-diff.cjs.map
;