UNPKG

json-conflict-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.88 kB
import{b as n}from"./chunk-Q4E7EFS7.mjs";import{c}from"./chunk-NHG7C4LQ.mjs";import{a as r,b as a,g as e,h as o}from"./chunk-WP4ACXPN.mjs";import"./chunk-76CZ6Z7T.mjs";r("normalizeConfig",()=>{a("uses default strategy = merge when not provided",async()=>{let t=await n({});e(t.rules.default).toEqual([{name:"merge",important:!1},{name:"ours",important:!1}])}),a("accepts single default strategy",async()=>{let t=await n({defaultStrategy:"theirs"});e(t.rules.default).toEqual([{name:"theirs",important:!1}])}),a("accepts multiple default strategies",async()=>{let t=await n({defaultStrategy:["merge","theirs"]});e(t.rules.default).toEqual([{name:"merge",important:!1},{name:"theirs",important:!1}])}),a("classifies rules from byStrategy into exactFields",async()=>{let s=await n({byStrategy:{theirs:["foo","bar!"]}});e(s.rules.exactFields.foo[0].strategies).toEqual([{name:"theirs",important:!1}]),e(s.rules.exactFields.bar[0].strategies[0].important).toBe(!0)}),a("classifies dotted keys as exact",async()=>{let s=await n({byStrategy:{merge:["a.b.c"]}});e(s.rules.exact["a.b.c"]).toHaveLength(1)}),a("classifies wildcard keys as patterns",async()=>{let s=await n({byStrategy:{merge:["foo.*.bar"]}});e(s.rules.patterns["foo.*.bar"]).toHaveLength(1)}),a("classifies bracket keys into patterns",async()=>{let s=await n({byStrategy:{merge:["[id]"]}});e(s.rules.patterns["**.id.**"]).toHaveLength(1)}),a("throws on invalid bracket key",async()=>{let t={byStrategy:{merge:["[a.b]"]}};await e(()=>n(t)).rejects.toThrow(/Invalid bracket form/)}),a("throws on empty rule key",async()=>{let t={byStrategy:{merge:["!"]}};await e(()=>n(t)).rejects.toThrow(/Invalid rule key/)}),a("expands rules tree into exact entries",async()=>{let s=await n({rules:{user:{name:["theirs"],profile:{age:["merge"]}}}});e(s.rules.exact["user.name"][0].strategies).toEqual([{name:"theirs",important:!1}]),e(s.rules.exact["user.profile.age"][0].strategies).toEqual([{name:"merge",important:!1}])}),a("uses basicMatcher by default",async()=>{let t=await n({});e(t.matcher).toBe(c)}),a("accepts custom matcher instance",async()=>{let t={isMatch:()=>!0},s=await n({matcher:t});e(s.matcher).toBe(t)}),a("throws if strategy name ends with '!'",async()=>{await e(n({byStrategy:{"merge!!":["foo"]}})).rejects.toThrow(/must not end with "!"/)}),a("throws on empty rule key '!'",async()=>{await e(n({byStrategy:{merge:["!"]}})).rejects.toThrow(/Invalid rule key/)}),a("marks important from byStrategy rule with '!'",async()=>{let s=await n({byStrategy:{theirs:["foo!"]}});e(s.rules.exactFields.foo[0].strategies[0].important).toBe(!0)}),a("marks important from rules tree key with '!'",async()=>{let s=await n({rules:{user:{"id!":["theirs"]}}});e(s.rules.exact["user.id"][0].strategies[0].important).toBe(!0)}),a("throws on invalid bracket form with dot",async()=>{await e(n({byStrategy:{merge:["[a.b]"]}})).rejects.toThrow(/Invalid bracket form/)}),a("throws on empty bracket form",async()=>{await e(n({byStrategy:{merge:["[]"]}})).rejects.toThrow(/Invalid bracket form/)}),a("throws on invalid escaped dot in bracket form",async()=>{await e(n({byStrategy:{merge:["[a.b]"]}})).rejects.toThrow(/Invalid bracket form/)}),a("expands deeply nested rule tree",async()=>{let s=await n({rules:{root:{child:{leaf:["merge"]}}}});e(s.rules.exact["root.child.leaf"][0].strategies).toEqual([{name:"merge",important:!1}])}),a("push appends to same key",async()=>{let s=await n({byStrategy:{merge:["dup"],theirs:["dup"]}});e(s.rules.exactFields.dup.map(i=>i.strategies[0])).toEqual([{name:"merge",important:!1},{name:"theirs",important:!1}])}),a("merges customStrategies with plugin strategies",async()=>{let t=o.fn(),i=await n({customStrategies:{"custom-strategy":t}});e(i.customStrategies["custom-strategy"]).toBe(t)}),a("returns empty strategies when no plugins provided",async()=>{let t=await n({});e(t.customStrategies).toEqual({})}),a("loads plugin strategies when plugins provided",async()=>{let t={strategies:{"plugin-strategy":o.fn()}};o.doMock("test-plugin",()=>({default:t}));let i=await n({plugins:["test-plugin"]});e(i.customStrategies["plugin-strategy"]).toBe(t.strategies["plugin-strategy"]),o.doUnmock("test-plugin")}),a("calls plugin init with config",async()=>{let t=o.fn(),s={strategies:{"test-strategy":o.fn()},init:t};o.doMock("test-plugin",()=>({default:s})),await n({plugins:["test-plugin"],pluginConfig:{"test-plugin":{option:"value"}}}),e(t).toHaveBeenCalledWith({option:"value"}),o.doUnmock("test-plugin")}),a("throws error when plugin has no strategies",async()=>{let t={};o.doMock("bad-plugin",()=>({default:t})),await e(n({plugins:["bad-plugin"]})).rejects.toThrow('Plugin "bad-plugin" does not export strategies'),o.doUnmock("bad-plugin")}),a("throws error when plugin import fails",async()=>{await e(n({plugins:["non-existent-plugin"]})).rejects.toThrow('Failed to load plugin "non-existent-plugin"')})});