11cb0ef41Sopenharmony_ciconst parseJSON = require('json-parse-even-better-errors') 21cb0ef41Sopenharmony_ciconst { diff } = require('just-diff') 31cb0ef41Sopenharmony_ciconst { diffApply } = require('just-diff-apply') 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciconst globalObjectProperties = Object.getOwnPropertyNames(Object.prototype) 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ciconst stripBOM = content => { 81cb0ef41Sopenharmony_ci content = content.toString() 91cb0ef41Sopenharmony_ci // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) 101cb0ef41Sopenharmony_ci // because the buffer-to-string conversion in `fs.readFileSync()` 111cb0ef41Sopenharmony_ci // translates it to FEFF, the UTF-16 BOM. 121cb0ef41Sopenharmony_ci if (content.charCodeAt(0) === 0xFEFF) { 131cb0ef41Sopenharmony_ci content = content.slice(1) 141cb0ef41Sopenharmony_ci } 151cb0ef41Sopenharmony_ci return content 161cb0ef41Sopenharmony_ci} 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciconst PARENT_RE = /\|{7,}/g 191cb0ef41Sopenharmony_ciconst OURS_RE = /<{7,}/g 201cb0ef41Sopenharmony_ciconst THEIRS_RE = /={7,}/g 211cb0ef41Sopenharmony_ciconst END_RE = />{7,}/g 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ciconst isDiff = str => 241cb0ef41Sopenharmony_ci str.match(OURS_RE) && str.match(THEIRS_RE) && str.match(END_RE) 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciconst parseConflictJSON = (str, reviver, prefer) => { 271cb0ef41Sopenharmony_ci prefer = prefer || 'ours' 281cb0ef41Sopenharmony_ci if (prefer !== 'theirs' && prefer !== 'ours') { 291cb0ef41Sopenharmony_ci throw new TypeError('prefer param must be "ours" or "theirs" if set') 301cb0ef41Sopenharmony_ci } 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ci str = stripBOM(str) 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ci if (!isDiff(str)) { 351cb0ef41Sopenharmony_ci return parseJSON(str) 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci const pieces = str.split(/[\n\r]+/g).reduce((acc, line) => { 391cb0ef41Sopenharmony_ci if (line.match(PARENT_RE)) { 401cb0ef41Sopenharmony_ci acc.state = 'parent' 411cb0ef41Sopenharmony_ci } else if (line.match(OURS_RE)) { 421cb0ef41Sopenharmony_ci acc.state = 'ours' 431cb0ef41Sopenharmony_ci } else if (line.match(THEIRS_RE)) { 441cb0ef41Sopenharmony_ci acc.state = 'theirs' 451cb0ef41Sopenharmony_ci } else if (line.match(END_RE)) { 461cb0ef41Sopenharmony_ci acc.state = 'top' 471cb0ef41Sopenharmony_ci } else { 481cb0ef41Sopenharmony_ci if (acc.state === 'top' || acc.state === 'ours') { 491cb0ef41Sopenharmony_ci acc.ours += line 501cb0ef41Sopenharmony_ci } 511cb0ef41Sopenharmony_ci if (acc.state === 'top' || acc.state === 'theirs') { 521cb0ef41Sopenharmony_ci acc.theirs += line 531cb0ef41Sopenharmony_ci } 541cb0ef41Sopenharmony_ci if (acc.state === 'top' || acc.state === 'parent') { 551cb0ef41Sopenharmony_ci acc.parent += line 561cb0ef41Sopenharmony_ci } 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci return acc 591cb0ef41Sopenharmony_ci }, { 601cb0ef41Sopenharmony_ci state: 'top', 611cb0ef41Sopenharmony_ci ours: '', 621cb0ef41Sopenharmony_ci theirs: '', 631cb0ef41Sopenharmony_ci parent: '', 641cb0ef41Sopenharmony_ci }) 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci // this will throw if either piece is not valid JSON, that's intended 671cb0ef41Sopenharmony_ci const parent = parseJSON(pieces.parent, reviver) 681cb0ef41Sopenharmony_ci const ours = parseJSON(pieces.ours, reviver) 691cb0ef41Sopenharmony_ci const theirs = parseJSON(pieces.theirs, reviver) 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci return prefer === 'ours' 721cb0ef41Sopenharmony_ci ? resolve(parent, ours, theirs) 731cb0ef41Sopenharmony_ci : resolve(parent, theirs, ours) 741cb0ef41Sopenharmony_ci} 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ciconst isObj = obj => obj && typeof obj === 'object' 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ciconst copyPath = (to, from, path, i) => { 791cb0ef41Sopenharmony_ci const p = path[i] 801cb0ef41Sopenharmony_ci if (isObj(to[p]) && isObj(from[p]) && 811cb0ef41Sopenharmony_ci Array.isArray(to[p]) === Array.isArray(from[p])) { 821cb0ef41Sopenharmony_ci return copyPath(to[p], from[p], path, i + 1) 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci to[p] = from[p] 851cb0ef41Sopenharmony_ci} 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci// get the diff from parent->ours and applying our changes on top of theirs. 881cb0ef41Sopenharmony_ci// If they turned an object into a non-object, then put it back. 891cb0ef41Sopenharmony_ciconst resolve = (parent, ours, theirs) => { 901cb0ef41Sopenharmony_ci const dours = diff(parent, ours) 911cb0ef41Sopenharmony_ci for (let i = 0; i < dours.length; i++) { 921cb0ef41Sopenharmony_ci if (globalObjectProperties.find(prop => dours[i].path.includes(prop))) { 931cb0ef41Sopenharmony_ci continue 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci try { 961cb0ef41Sopenharmony_ci diffApply(theirs, [dours[i]]) 971cb0ef41Sopenharmony_ci } catch (e) { 981cb0ef41Sopenharmony_ci copyPath(theirs, ours, dours[i].path, 0) 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci return theirs 1021cb0ef41Sopenharmony_ci} 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_cimodule.exports = Object.assign(parseConflictJSON, { isDiff }) 105