unidiff
Version:
diff with unified diff format handling
109 lines (95 loc) • 3.56 kB
JavaScript
let jdiff = require('diff')
let hunk = require('./hunk')
// return a change type code for the change (returned from diff.diffLines())
function changeType (change) {
if (change.added) {
return hunk.ADDED
} else if (change.removed) {
return hunk.REMOVED
} else {
return hunk.UNMODIFIED
}
}
// Given changes from a call to diff.diffLines(), assign each change a type code and
// check that no two of same type occur in a row
function checkAndAssignTypes (changes) {
if (changes.length === 0) { return [] }
changes[0].type = changeType(changes[0])
return changes.reduce(function (a, b, i) {
b.type = changeType(b)
if (a.type === b.type) {
throw Error('repeating change types are not handled: ' + a.type + ' (at ' + (i-1) + ' and ' + i + ')')
}
return b
})
}
// convert an array of results from diff.diffLines() into text in unified diff format.
// return empty string if there are no changes.
function formatLines (changes, opt) {
checkAndAssignTypes(changes)
opt = opt || {}
opt.aname = opt.aname || 'a'
opt.bname = opt.bname || 'b'
let context = (opt.context || opt.context === 0) ? opt.context : 0
opt.pre_context = (opt.pre_context || opt.pre_context === 0) ? opt.pre_context : context
opt.post_context = (opt.post_context || opt.post_context === 0) ? opt.post_context : context
let hunks = hunk.makeHunks(changes, opt.pre_context, opt.post_context)
if (hunks.length) {
let ret = []
ret.push('--- ' + opt.aname)
ret.push('+++ ' + opt.bname)
hunks.forEach(function (h) {
ret.push(h.unified())
})
return ret.join('\n')
} else {
return ''
}
}
// same as jsdiff.diffLines, but returns empty array when there are no changes (instead of an array with a single
// unmodified change object)
function diffLines (a, b, cb) {
a = Array.isArray(a) ? a.join('\n') + '\n' : a
b = Array.isArray(b) ? b.join('\n') + '\n' : b
let ret = jdiff.diffLines(a, b, cb)
if (ret.length === 1 && !ret[0].added && !ret[0].removed) {
return []
} else {
return ret
}
}
function diffAsText (a, b, opt) {
return formatLines(diffLines(a, b), opt)
}
// handy assertion function that asserts that two arrays or two multi-line strings are the same and reports
// differences to console.log in unified format if there are differences.
//
// actual - array or multi-line string to compare
// expected - array or multi-line string to compare
// label - label to clarify output if there are differences
// okFn - function like tape.ok that takes two arguments:
// expression - true if OK, false if failed test
// msg - a one-line message that prints upon failure
// logFn - function to call with diff output when there are differences (defaults to console.log)
//
function assertEqual (actual, expected, okFn, label, logFn) {
logFn = logFn || console.log
okFn = okFn.ok || okFn
let diff = diffAsText(actual, expected, {context: 3, aname: label + " (actual)", bname: label + ' (expected)'})
okFn(!diff, label)
if (diff) {
diff.split('\n').forEach(function (line) {
logFn(' ' + line)
})
}
}
exports.assertEqual = assertEqual
exports.diffAsText = diffAsText
exports.formatLines = formatLines
exports.diffLines = diffLines
Object.keys(jdiff).forEach(function (k) {
if (!exports[k]) {
exports[k] = jdiff[k]
}
})