json-merge-resolver
Version:
A rules-based JSON conflict resolver that parses Git conflict markers, reconstructs ours/theirs, and merges with deterministic strategies — beyond line-based merges.
2 lines (1 loc) • 4.2 kB
JavaScript
import{a as h,b as r,c as i}from"./chunk-WFDJ25NC.mjs";import{a as g}from"./chunk-JD45QQDD.mjs";import"./chunk-NHG7C4LQ.mjs";import{a as m,c,d as f,e as y,f as b}from"./chunk-HB6Q755Y.mjs";import{a as p,b as o,g as t,h as n}from"./chunk-WP4ACXPN.mjs";import"./chunk-76CZ6Z7T.mjs";var u={debug:n.fn(),info:n.fn(),warn:n.fn(),error:n.fn(),flush:n.fn()};n.mock("./strategy-resolver",()=>({resolveStrategies:n.fn(()=>["ours","theirs","merge"])}));var l=()=>({config:{debug:!1},strategies:{},_strategyCache:new Map});p("statusToString",()=>{o("maps known statuses",()=>{t(h(c)).toBe("OK"),t(h(f)).toBe("CONTINUE"),t(h(y)).toBe("FAIL"),t(h(b)).toBe("SKIP"),t(h(999)).toMatch(/UNKNOWN/)})});p("BuiltInStrategies",()=>{let s={ours:1,theirs:2,base:0,path:"x",ctx:l(),conflicts:[],logger:u};o("ours returns ours",()=>{let e=r.ours(s);t(e).toEqual({status:c,value:1})}),o("theirs returns theirs",()=>{let e=r.theirs(s);t(e).toEqual({status:c,value:2})}),o("base returns base",()=>{let e=r.base(s);t(e).toEqual({status:c,value:0})}),o("drop returns DROP symbol",()=>{let e=r.drop(s);t(e.value).toBe(m)}),o("skip returns SKIP",()=>{let e=r.skip(s);t(e.status).toBe(b),t(e.reason).toMatch(/Skip/)}),o("non-empty prefers ours \u2192 theirs \u2192 base",()=>{t(r["non-empty"]({...s,ours:"ours"}).value).toBe("ours"),t(r["non-empty"]({...s,ours:"",theirs:"theirs"}).value).toBe("theirs"),t(r["non-empty"]({...s,ours:"",theirs:"",base:"base"}).value).toBe("base"),t(r["non-empty"]({...s,ours:"",theirs:"",base:""}).status).toBe(f)}),o("update keeps theirs if ours defined",()=>{t(r.update({...s,ours:"x",theirs:"y"}).value).toBe("y")}),o("update drops if ours undefined",()=>{t(r.update({...s,ours:void 0,theirs:"y"}).value).toBe(m)}),o("concat arrays",()=>{let e=r.concat({...s,ours:[1],theirs:[2]});t(e).toEqual({status:c,value:[1,2]})}),o("concat non-arrays \u2192 CONTINUE",()=>{let e=r.concat({...s,ours:"a",theirs:"b"});t(e.status).toBe(f)}),o("unique arrays",()=>{let e=r.unique({...s,ours:[1,2],theirs:[2,3]});t(e).toEqual({status:c,value:[1,2,3]})}),o("unique non-arrays \u2192 CONTINUE",()=>{let e=r.unique({...s,ours:"a",theirs:"b"});t(e.status).toBe(f)}),o("merge plain objects recurses",async()=>{let e={...s,ours:{a:1},theirs:{a:2},base:{a:0},path:"obj",logger:u},d=await r.merge(e);t(d.status).toBe(c),t(d.value).toEqual({a:1})}),o("merge unmergeable types \u2192 CONTINUE",async()=>{let e=await r.merge({...s,ours:1,theirs:"str"});t(e.status).toBe(f)})});p("mergeObject",()=>{o("returns ours if equal",async()=>{let a=l(),s=[],e=await i({ours:1,theirs:1,base:0,path:"x",ctx:a,conflicts:s,logger:u});t(e).toBe(1),t(s).toHaveLength(0)}),o("applies strategy OK result",async()=>{g.mockReturnValueOnce(["theirs"]);let a=l(),e=await i({ours:1,theirs:2,path:"p",ctx:a,conflicts:[],logger:u});t(e).toBe(2)}),o("records SKIP as conflict",async()=>{g.mockReturnValueOnce(["skip"]);let a=l(),s=[],e=await i({ours:"a",theirs:"b",path:"p",ctx:a,conflicts:s,logger:u});t(e).toBeUndefined(),t(s[0].reason).toMatch(/Skip/)}),o("adds conflict if all CONTINUE",async()=>{g.mockReturnValueOnce(["concat"]);let a=l(),s=[],e=await i({ours:"a",theirs:"b",base:"",path:"p",ctx:a,conflicts:s,logger:u});t(e).toBeUndefined(),t(s[0]).toMatchObject({path:"p",reason:t.stringContaining("All strategies failed")})}),o("uses custom strategy from ctx.strategies",async()=>{g.mockReturnValueOnce(["custom"]);let a=l();a.strategies.custom=n.fn(()=>({status:c,value:"custom-result"}));let e=await i({ours:"a",theirs:"b",path:"p",ctx:a,conflicts:[],logger:u});t(e).toBe("custom-result"),t(a.strategies.custom).toHaveBeenCalled()}),o("throws on FAIL status",async()=>{g.mockReturnValueOnce(["fail-strategy"]);let a=l();a.strategies["fail-strategy"]=n.fn(()=>({status:y,reason:"test fail"}));let s=[];await t(i({ours:"a",theirs:"b",path:"p",ctx:a,conflicts:s,logger:u})).rejects.toThrow("Merge failed at p: test fail"),t(s[0].reason).toBe("test fail")}),o("enriches conflict with debug info when debug enabled",async()=>{g.mockReturnValueOnce(["concat"]);let a=l();a.config.debug=!0;let s=[];await i({ours:"a",theirs:"b",base:"c",path:"p",ctx:a,conflicts:s,logger:u}),t(s[0]).toMatchObject({path:"p",ours:"a",theirs:"b",base:"c"})})});