@fishan/myers-core-diff
Version:
A high-performance core diff engine based on Myers' algorithm, with plugin support for custom strategies (e.g., Patience, Preserve Structure).
8 lines (7 loc) • 3.1 kB
JavaScript
/**
* @license
* Copyright (c) 2025, Internal Implementation
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/import{DiffOperation as b}from"./myers_core_diff.js";const l=!1,P={minMatchLength:2,quickDiffThreshold:16,hugeDiffThreshold:64,jumpStep:1,huntChunkSize:2,minAnchorConfidence:.7,useAnchors:!0};function w(r,i,a,t,c,u){const o=new Set(r.subarray(i,a));if(o.size===0)return!1;for(let n=c;n<u;n++)if(o.has(t[n]))return!0;return!1}function x(r,i,a,t,c,u,o,n,p,e){const m=t-a,s=o-u,f=m+s;if(f===0)return[];if(!w(i,a,t,c,u,o))return r._guidedCalculateDiff(i,a,t,c,u,o,n,p,e);if(f>=p.quickDiffThreshold/2){const g={...p,...P},y=r._findAnchors(i,a,t,c,u,o,g,e),D=r._mergeAndFilterAnchors(y,g,e);if(D.length>0){const L=[];let R=a,$=u;for(const d of D){if(d.oldPos>R||d.newPos>$){const I=x(r,i,R,d.oldPos,c,$,d.newPos,n,p,e);L.push(...I)}for(let I=0;I<d.length;I++)L.push([b.EQUAL,n[i[d.oldPos+I]]]);R=d.oldPos+d.length,$=d.newPos+d.length}if(R<t||$<o){const d=x(r,i,R,t,c,$,o,n,p,e);L.push(...d)}return L}}return r._guidedCalculateDiff(i,a,t,c,u,o,n,p,e)}function C(r,i,a,t,c,u,o,n,p,e){const m=[];let s=a,f=u;for(;s<t&&f<o;){const h=r._findNextLocalAnchor(i,s,t,c,f,o,p.localLookahead||50,e),A=h?.oldPos??t,g=h?.newPos??o;if(A>s||g>f){const y=x(r,i,s,A,c,f,g,n,p,e);m.push(...y)}h?(m.push([b.EQUAL,n[i[h.oldPos]]]),s=h.oldPos+1,f=h.newPos+1):(s=t,f=o)}if(s<t)for(let h=s;h<t;h++)m.push([b.REMOVE,n[i[h]]]);if(f<o)for(let h=f;h<o;h++)m.push([b.ADD,n[c[h]]]);return m}function M(r,i,a,t,c,u){const o=new Map,n=new Map;for(let s=i;s<a;s++){const f=r[s];o.set(f,(o.get(f)||0)+1),o.get(f)===1?n.set(f,s):n.delete(f)}const p=new Map,e=new Map;for(let s=c;s<u;s++){const f=t[s];p.set(f,(p.get(f)||0)+1),p.get(f)===1?e.set(f,s):e.delete(f)}const m=new Map;for(const[s,f]of n.entries())o.get(s)===1&&e.has(s)&&p.get(e.get(s))===1&&m.set(s,{oldIndex:f,newIndex:e.get(s)});return m}function U(r){if(!r||r.length===0)return[];r.sort((n,p)=>n.oldIndex-p.oldIndex);const i=r.length,a=new Array(i).fill(0),t=new Array(i).fill(-1);let c=0;for(let n=0;n<i;n++){const p=r[n].newIndex;let e=0,m=c;for(;e<m;){const s=Math.floor((e+m)/2);r[a[s]].newIndex<p?e=s+1:m=s}a[e]=n,e>0&&(t[n]=a[e-1]),e===c&&c++}const u=[];let o=a[c-1];for(;o!==-1;)u.push(r[o]),o=t[o];return u.reverse(),u}function _(r,i,a,t,c,u,o,n,p,e,m=0){if(a>=t&&u>=o)return[];if(a>=t)return r._createAdditions(c,u,o,n,!1);if(u>=o)return r._createDeletions(i,a,t,n,!1);const s=M(i,a,t,c,u,o),f=Array.from(s.entries()).map(([A,g])=>({tokenId:A,oldIndex:g.oldIndex,newIndex:g.newIndex})),h=U(f);if(l&&e&&h.length>0,h.length===0)return C(r,i,a,t,c,u,o,n,p,e);{const A=[];let g=a,y=u;for(const D of h){if(D.oldIndex>g||D.newIndex>y){const L=_(r,i,g,D.oldIndex,c,y,D.newIndex,n,p,e,m+1);A.push(...L)}A.push([b.EQUAL,n[D.tokenId]]),g=D.oldIndex+1,y=D.newIndex+1}if(t>g||o>y){const D=_(r,i,g,t,c,y,o,n,p,e,m+1);A.push(...D)}return A}}const O=(r,i,a,t,c,u,o,n,p,e)=>_(r,i,a,t,c,u,o,n,p,e,0);function S(r){r.registerStrategy("patienceDiff",O)}export{S as registerPatienceDiffStrategy};