lib/utils/Diff.js
function(diff) {
	var ret = [];

	diff.push({ value: '', lines: [] });  // Append an empty value to make cleanup easier

	// Formats a given set of lines for printing as context lines in a patch
	function contextLines(lines) {
		return lines.map(function(entry) { return ' ' + entry; });
	}

	var oldRangeStart = 0;
	var newRangeStart = 0;
	var curRange = [];
	var oldLine = 1;
	var newLine = 1;

	for (var i = 0; i < diff.length; i++) {
		var current = diff[i];
		var lines = current.lines || current.value.replace(/\n$/, '').split('\n');
		current.lines = lines;

		if (current.added || current.removed) {
			// If we have previous context, start with that
			if (!oldRangeStart) {
				var prev = diff[i - 1];
				oldRangeStart = oldLine;
				newRangeStart = newLine;

				if (prev) {
					curRange = contextLines(prev.lines.slice(-4));
					oldRangeStart -= curRange.length;
					newRangeStart -= curRange.length;
				}
			}

			// Output our changes
			curRange.push.apply(curRange, lines.map(function(entry) {
				return (current.added ? '+' : '-') + entry;
			}));

			// Track the updated file position
			if (current.added) {
				newLine += lines.length;
			} else {
				oldLine += lines.length;
			}
		} else {
			// Identical context lines. Track line changes
			if (oldRangeStart) {
				// Close out any changes that have been output (or join overlapping)
				if (lines.length <= 8 && i < diff.length - 2) {
					// Overlapping
					curRange.push.apply(curRange, contextLines(lines));
				} else {
					// end the range and output
					var contextSize = Math.min(lines.length, 4);
					ret.push(
						'@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize)
						+ ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize)
						+ ' @@');
					ret.push.apply(ret, curRange);
					ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));

					oldRangeStart = 0;
					newRangeStart = 0;
					curRange = [];
				}
			}
			oldLine += lines.length;
			newLine += lines.length;
		}
	}

	return ret.join('\n') + '\n';
}
function(diff) {
	var ret = [];

	diff.push({ value: '', lines: [] });  // Append an empty value to make cleanup easier

	// Formats a given set of lines for printing as context lines in a patch
	function contextLines(lines) {
		return lines.map(function(entry) { return ' ' + entry; });
	}

	var oldRangeStart = 0;
	var newRangeStart = 0;
	var curRange = [];
	var oldLine = 1;
	var newLine = 1;

	for (var i = 0; i < diff.length; i++) {
		var current = diff[i];
		var lines = current.lines || current.value.replace(/\n$/, '').split('\n');
		current.lines = lines;

		if (current.added || current.removed) {
			// If we have previous context, start with that
			if (!oldRangeStart) {
				var prev = diff[i - 1];
				oldRangeStart = oldLine;
				newRangeStart = newLine;

				if (prev) {
					curRange = contextLines(prev.lines.slice(-4));
					oldRangeStart -= curRange.length;
					newRangeStart -= curRange.length;
				}
			}

			// Output our changes
			curRange.push.apply(curRange, lines.map(function(entry) {
				return (current.added ? '+' : '-') + entry;
			}));

			// Track the updated file position
			if (current.added) {
				newLine += lines.length;
			} else {
				oldLine += lines.length;
			}
		} else {
			// Identical context lines. Track line changes
			if (oldRangeStart) {
				// Close out any changes that have been output (or join overlapping)
				if (lines.length <= 8 && i < diff.length - 2) {
					// Overlapping
					curRange.push.apply(curRange, contextLines(lines));
				} else {
					// end the range and output
					var contextSize = Math.min(lines.length, 4);
					ret.push(
						'@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize)
						+ ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize)
						+ ' @@');
					ret.push.apply(ret, curRange);
					ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));

					oldRangeStart = 0;
					newRangeStart = 0;
					curRange = [];
				}
			}
			oldLine += lines.length;
			newLine += lines.length;
		}
	}

	return ret.join('\n') + '\n';
}
function ( diff ) { var ret = [ ] ; diff . push ( { value : '' , lines : [ ] } ) ; // Append an empty value to make cleanup easier // Formats a given set of lines for printing as context lines in a patch function contextLines ( lines ) { return lines . map ( function ( entry ) { return ' ' + entry ; } ) ; } var oldRangeStart = 0 ; var newRangeStart = 0 ; var curRange = [ ] ; var oldLine = 1 ; var newLine = 1 ; for ( var i = 0 ; i < diff . length ; i ++ ) { var current = diff [ i ] ; var lines = current . lines || current . value . replace ( / \n$ / , '' ) . split ( '\n' ) ; current . lines = lines ; if ( current . added || current . removed ) { // If we have previous context, start with that if ( ! oldRangeStart ) { var prev = diff [ i - 1 ] ; oldRangeStart = oldLine ; newRangeStart = newLine ; if ( prev ) { curRange = contextLines ( prev . lines . slice ( - 4 ) ) ; oldRangeStart -= curRange . length ; newRangeStart -= curRange . length ; } } // Output our changes curRange . push . apply ( curRange , lines . map ( function ( entry ) { return ( current . added ? '+' : '-' ) + entry ; } ) ) ; // Track the updated file position if ( current . added ) { newLine += lines . length ; } else { oldLine += lines . length ; } } else { // Identical context lines. Track line changes if ( oldRangeStart ) { // Close out any changes that have been output (or join overlapping) if ( lines . length <= 8 && i < diff . length - 2 ) { // Overlapping curRange . push . apply ( curRange , contextLines ( lines ) ) ; } else { // end the range and output var contextSize = Math . min ( lines . length , 4 ) ; ret . push ( '@@ -' + oldRangeStart + ',' + ( oldLine - oldRangeStart + contextSize ) + ' +' + newRangeStart + ',' + ( newLine - newRangeStart + contextSize ) + ' @@' ) ; ret . push . apply ( ret , curRange ) ; ret . push . apply ( ret , contextLines ( lines . slice ( 0 , contextSize ) ) ) ; oldRangeStart = 0 ; newRangeStart = 0 ; curRange = [ ] ; } } oldLine += lines . length ; newLine += lines . length ; } } return ret . join ( '\n' ) + '\n' ; }
This is essentially lifted from jsDiff@1.4.0, but using our diff and
without the header and no newline warning.
@private
This is essentially lifted from jsDiff