mirror of
https://github.com/nodejs/node.git
synced 2025-05-13 01:44:38 +00:00

PR-URL: https://github.com/nodejs/node/pull/41127 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
105 lines
2.9 KiB
JavaScript
105 lines
2.9 KiB
JavaScript
const parseJSON = require('json-parse-even-better-errors')
|
|
const { diff } = require('just-diff')
|
|
const { diffApply } = require('just-diff-apply')
|
|
|
|
const globalObjectProperties = Object.getOwnPropertyNames(Object.prototype)
|
|
|
|
const stripBOM = content => {
|
|
content = content.toString()
|
|
// Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
|
|
// because the buffer-to-string conversion in `fs.readFileSync()`
|
|
// translates it to FEFF, the UTF-16 BOM.
|
|
if (content.charCodeAt(0) === 0xFEFF) {
|
|
content = content.slice(1)
|
|
}
|
|
return content
|
|
}
|
|
|
|
const PARENT_RE = /\|{7,}/g
|
|
const OURS_RE = /<{7,}/g
|
|
const THEIRS_RE = /={7,}/g
|
|
const END_RE = />{7,}/g
|
|
|
|
const isDiff = str =>
|
|
str.match(OURS_RE) && str.match(THEIRS_RE) && str.match(END_RE)
|
|
|
|
const parseConflictJSON = (str, reviver, prefer) => {
|
|
prefer = prefer || 'ours'
|
|
if (prefer !== 'theirs' && prefer !== 'ours') {
|
|
throw new TypeError('prefer param must be "ours" or "theirs" if set')
|
|
}
|
|
|
|
str = stripBOM(str)
|
|
|
|
if (!isDiff(str)) {
|
|
return parseJSON(str)
|
|
}
|
|
|
|
const pieces = str.split(/[\n\r]+/g).reduce((acc, line) => {
|
|
if (line.match(PARENT_RE)) {
|
|
acc.state = 'parent'
|
|
} else if (line.match(OURS_RE)) {
|
|
acc.state = 'ours'
|
|
} else if (line.match(THEIRS_RE)) {
|
|
acc.state = 'theirs'
|
|
} else if (line.match(END_RE)) {
|
|
acc.state = 'top'
|
|
} else {
|
|
if (acc.state === 'top' || acc.state === 'ours') {
|
|
acc.ours += line
|
|
}
|
|
if (acc.state === 'top' || acc.state === 'theirs') {
|
|
acc.theirs += line
|
|
}
|
|
if (acc.state === 'top' || acc.state === 'parent') {
|
|
acc.parent += line
|
|
}
|
|
}
|
|
return acc
|
|
}, {
|
|
state: 'top',
|
|
ours: '',
|
|
theirs: '',
|
|
parent: '',
|
|
})
|
|
|
|
// this will throw if either piece is not valid JSON, that's intended
|
|
const parent = parseJSON(pieces.parent, reviver)
|
|
const ours = parseJSON(pieces.ours, reviver)
|
|
const theirs = parseJSON(pieces.theirs, reviver)
|
|
|
|
return prefer === 'ours'
|
|
? resolve(parent, ours, theirs)
|
|
: resolve(parent, theirs, ours)
|
|
}
|
|
|
|
const isObj = obj => obj && typeof obj === 'object'
|
|
|
|
const copyPath = (to, from, path, i) => {
|
|
const p = path[i]
|
|
if (isObj(to[p]) && isObj(from[p]) &&
|
|
Array.isArray(to[p]) === Array.isArray(from[p])) {
|
|
return copyPath(to[p], from[p], path, i + 1)
|
|
}
|
|
to[p] = from[p]
|
|
}
|
|
|
|
// get the diff from parent->ours and applying our changes on top of theirs.
|
|
// If they turned an object into a non-object, then put it back.
|
|
const resolve = (parent, ours, theirs) => {
|
|
const dours = diff(parent, ours)
|
|
for (let i = 0; i < dours.length; i++) {
|
|
if (globalObjectProperties.find(prop => dours[i].path.includes(prop))) {
|
|
continue
|
|
}
|
|
try {
|
|
diffApply(theirs, [dours[i]])
|
|
} catch (e) {
|
|
copyPath(theirs, ours, dours[i].path, 0)
|
|
}
|
|
}
|
|
return theirs
|
|
}
|
|
|
|
module.exports = Object.assign(parseConflictJSON, { isDiff })
|