/*global ace, define, exports*/ /*jshint laxbreak: true*/ var diffview = function diffview_(options) { "use strict"; (function diffview__options() { options.context = ((/^([0-9]+)$/).test(options.context) === true) ? Number(options.context) : -1; options.crlf = (options.crlf === true || options.crlf === "true"); options.diff = (typeof options.diff === "string") ? options .diff .replace(/\u0000|\u0001|\u0002|\u0003|\u0004|\u0005|\u0006|\u0007|\u0008|\u000b|\u000c|\u000e|\u000f|\u0010|\u0011|\u0012|\u0013|\u0014|\u0015|\u0016|\u0017|\u0018|\u0019|\u001a|\u001b|\u001c|\u001d|\u001e|\u001f|\u007f|\u0080|\u0081|\u0082|\u0083|\u0084|\u0085|\u0086|\u0087|\u0088|\u0089|\u008a|\u008b|\u008c|\u008d|\u008e|\u008f|\u0090|\u0091|\u0092|\u0093|\u0094|\u0095|\u0096|\u0097|\u0098|\u0099|\u009a|\u009b|\u009c|\u009d|\u009e|\u009f/g, "") .replace(/\r\n/g, "\n") .replace(/\r/g, "\n") : ""; options.diffcli = (options.diffcli === true || options.diffcli === "true"); options.difflabel = (typeof options.difflabel === "string") ? options .difflabel .replace(/&/g, "&") .replace(//g, ">") : "New Source"; options.diffspaceignore = (options.diffspaceignore === true || options.diffspaceignore === "true"); options.diffview = (options.diffview === "inline") ? "inline" : "sidebyside"; options.inline = (options.inline === true || options.inline === "true" || options.inline === "inline" || options.diffview === "inline"); options.inchar = (typeof options.inchar === "string") ? options.inchar : " "; options.insize = ((/^([0-9]+)$/).test(options.insize)) ? Number(options.insize) : 4; options.source = (typeof options.source === "string") ? options .source .replace(/\u0000|\u0001|\u0002|\u0003|\u0004|\u0005|\u0006|\u0007|\u0008|\u000b|\u000c|\u000e|\u000f|\u0010|\u0011|\u0012|\u0013|\u0014|\u0015|\u0016|\u0017|\u0018|\u0019|\u001a|\u001b|\u001c|\u001d|\u001e|\u001f|\u007f|\u0080|\u0081|\u0082|\u0083|\u0084|\u0085|\u0086|\u0087|\u0088|\u0089|\u008a|\u008b|\u008c|\u008d|\u008e|\u008f|\u0090|\u0091|\u0092|\u0093|\u0094|\u0095|\u0096|\u0097|\u0098|\u0099|\u009a|\u009b|\u009c|\u009d|\u009e|\u009f/g, "") .replace(/\r\n/g, "\n") .replace(/\r/g, "\n") : ""; options.sourcelabel = (typeof options.sourcelabel === "string") ? options .sourcelabel .replace(/&/g, "&") .replace(//g, ">") : "Base Source"; //old non-standard API if (typeof options.baseTextLines === "string") { options.source = options .baseTextLines .replace(/\u0000|\u0001|\u0002|\u0003|\u0004|\u0005|\u0006|\u0007|\u0008|\u000b|\u000c|\u000e|\u000f|\u0010|\u0011|\u0012|\u0013|\u0014|\u0015|\u0016|\u0017|\u0018|\u0019|\u001a|\u001b|\u001c|\u001d|\u001e|\u001f|\u007f|\u0080|\u0081|\u0082|\u0083|\u0084|\u0085|\u0086|\u0087|\u0088|\u0089|\u008a|\u008b|\u008c|\u008d|\u008e|\u008f|\u0090|\u0091|\u0092|\u0093|\u0094|\u0095|\u0096|\u0097|\u0098|\u0099|\u009a|\u009b|\u009c|\u009d|\u009e|\u009f/g, "") .replace(/\r\n/g, "\n") .replace(/\r/g, "\n"); } if (typeof options.baseTextName === "string") { options.sourcelabel = options .baseTextName .replace(/&/g, "&") .replace(//g, ">"); } if (typeof options.newTextLines === "string") { options.diff = options .newTextLines .replace(/\u0000|\u0001|\u0002|\u0003|\u0004|\u0005|\u0006|\u0007|\u0008|\u000b|\u000c|\u000e|\u000f|\u0010|\u0011|\u0012|\u0013|\u0014|\u0015|\u0016|\u0017|\u0018|\u0019|\u001a|\u001b|\u001c|\u001d|\u001e|\u001f|\u007f|\u0080|\u0081|\u0082|\u0083|\u0084|\u0085|\u0086|\u0087|\u0088|\u0089|\u008a|\u008b|\u008c|\u008d|\u008e|\u008f|\u0090|\u0091|\u0092|\u0093|\u0094|\u0095|\u0096|\u0097|\u0098|\u0099|\u009a|\u009b|\u009c|\u009d|\u009e|\u009f/g, "") .replace(/\r\n/g, "\n") .replace(/\r/g, "\n"); } if (typeof options.newTextName === "string") { options.difflabel = options .newTextName .replace(/&/g, "&") .replace(//g, ">"); } if ((/^([0-9]+)$/).test(options.contextSize) === true) { options.context = Number(options.contextSize); } if (typeof options.tchar === "string") { options.inchar = options.tchar; } if ((/^([0-9]+)$/).test(options.tsize) === true) { options.insize = Number(options.tsize); } }()); //diffview application contains three primary parts //1. opcodes - performs the 'largest common subsequence' // calculation to determine which lines are different. I // did not write this logic. I have rewritten it for // performance, but original logic is still intact. //2. charcomp - performs the 'largest common subsequence' upon // characters of two compared lines. //3. The construction of the output into the 'node' array //errorout is a count of differences var errorout = 0, //diffline is a count of lines that are not equal diffline = 0, lf = (options.crlf === true) ? "\r\n" : "\n", //tab is a construct of a standard indentation for code tab = (function diffview__tab() { var a = 0, output = []; if (options.inchar === "") { return ""; } for (a = 0; a < options.insize; a += 1) { output.push(options.inchar); } return output.join(""); }()), //array representation of base source linesBase = (options.diffcli === true) ? options.source.split(lf) : options.source .replace(/&/g, "&") .replace(/&#lt;/g, "$#lt;") .replace(/&#gt;/g, "$#gt;") .replace(//g, "$#gt;") .split(lf), //array representation of new source linesNew = (options.diffcli === true) ? options.diff.split(lf) : options.diff .replace(/&/g, "&") .replace(/&#lt;/g, "$#lt;") .replace(/&#gt;/g, "$#gt;") .replace(//g, "$#gt;") .split(lf), //the core algorithm. This logic is not mine even though I //have largely rewritten it for performance. It determines //the largest common subsequence calculations between lines //of code opcodes = (function diffview__opcodes() { var a = 0, codes = [], lb = 0, ln = 0, aa = 0, bb = 0, match = 0, end = 0, same = function diffview__opcodes_initSame() { return; }, diff = function diffview__opcodes_initDiff() { return; }, diffeval = function diffview__opcodes_diffeval(type) { if (type === "delete") { codes.push(["delete", lb, (lb + (bb - a)), ln, ln]); lb += (bb - a); aa = bb - a; do { linesNew.unshift(""); aa -= 1; } while (aa > 0); a = bb; if (bb === end) { return; } return same(); } if (type === "insert") { codes.push(["insert", lb, lb, ln, (ln + (bb - a))]); ln += (bb - a); aa = bb - a; do { linesBase.unshift(""); aa -= 1; } while (aa > 0); a = bb; return; if (bb === end) { return; } return same(); } if (type === "replace") { codes.push(["replace", lb, (lb + (bb - aa)), ln, (ln + (bb - aa))]); lb += (bb - aa); ln += (bb - aa); a = bb; if (bb === end) { return; } return same(); } }; same = function diffview__opcodes_sames() { var xx = 0; end = Math.min(linesBase.length, linesNew.length); for (xx = a + 1; xx < end; xx += 1) { if (linesBase[xx] !== linesNew[xx]) { codes.push(["equal", lb, (lb + (xx - a)), ln, (ln + (xx - a))]); lb += (xx - a); ln += (xx - a); a = xx; return diff(); } } codes.push(["equal", lb, (lb + (aa - a)), ln, (ln + (aa - a))]); }; diff = function diffview__opcodes_diff() { match = 0; for (aa = a; aa < end; aa += 1) { for (bb = aa + 1; bb < end; bb += 1) { if (linesBase[bb] === linesNew[aa]) { return diffeval("delete"); } if (linesBase[bb] === linesNew[aa]) { if (match === 0) { match = bb - aa; } else { if (match <= bb - aa) { if (match === bb - aa) { bb = aa + match - 1; } else { bb = aa + match; } return diffeval("delete"); } return diffeval("insert"); } } else if (linesBase[aa] === linesNew[bb]) { if (match === 0) { match = bb - aa; } else { if (match <= bb - aa) { if (match === bb - aa) { bb = aa + match - 1; } else { bb = aa + match; } return diffeval("insert"); } return diffeval("delete"); } } else if (linesBase[bb] === linesNew[bb] && match > 0 && match > bb - aa) { return diffeval("replace"); } } } }; if (linesBase[0] === linesNew[0]) { same(); } else { Math.min(linesBase.length, linesNew.length); diff(); } if (linesBase[0] === "") { a = 0; do { a += 1; } while (linesBase[a] === ""); linesBase = linesBase.slice(a); } if (linesNew[0] === "") { a = 0; do { a += 1; } while (linesNew[a] === ""); linesNew = linesNew.slice(a); } return codes; }()); //after the opcodes generate the other two core pieces of logic //are quaranteened into an anonymous function. return (function diffview__report() { var a = 0, i = 0, node = ["
"], data = (options.diffcli === true) ? [ [], [], [], [], [], [] ] : [ [], [], [], [] ], rowcnt = 0, rowItem = -1, rcount = 0, foldcount = 0, foldstart = -1, jump = 0, finaldoc = "", tabFix = (tab === "") ? "" : new RegExp("^((" + tab.replace(/\\/g, "\\") + ")+)"), noTab = function diffview__report_noTab(str) { var b = 0, strLen = str.length, output = []; for (b = 0; b < strLen; b += 1) { output.push(str[b].replace(tabFix, "")); } return output; }, baseTab = (tab === "") ? [] : noTab(linesBase), newTab = (tab === "") ? [] : noTab(linesNew), opcodesLength = opcodes.length, btest = false, ntest = false, repeat = false, ctest = true, bs = 0, be = 0, ns = 0, ne = 0, change = "", charcompOutput = [], //this is the character comparison logic that performs //the 'largest common subsequence' between two lines of //code charcomp = function diffview__report_charcomp(lineA, lineB) { var b = 0, dataA = [], dataB = [], cleanedA = (options.diffcli === true) ? lineA : lineA .replace(/ /g, " ") .replace(/ /g, " ") .replace(/</g, "<") .replace(/>/g, ">") .replace(/\$#lt;/g, "<") .replace(/\$#gt;/g, ">") .replace(/&/g, "&"), cleanedB = (options.diffcli === true) ? lineB : lineB .replace(/ /g, " ") .replace(/ /g, " ") .replace(/</g, "<") .replace(/>/g, ">") .replace(/\$#lt;/g, "<") .replace(/\$#gt;/g, ">") .replace(/&/g, "&"), dataMinLength = 0, currentdiff = [], regStart = (/_pdiffdiff\u005f/g), regEnd = (/_epdiffdiff\u005f/g), strStart = "_pdiffdiff\u005f", strEnd = "_epdiffdiff\u005f", tabdiff = (function diffview__report_charcomp_tabdiff() { var tabMatchA = "", tabMatchB = "", splitA = "", splitB = "", analysis = [], matchListA = cleanedA.match(tabFix), matchListB = cleanedB.match(tabFix); if (matchListA === null || matchListB === null || (matchListA[0] === "" && matchListA.length === 1) || (matchListB[0] === "" && matchListB.length === 1)) { return ["", "", cleanedA, cleanedB]; } tabMatchA = matchListA[0]; tabMatchB = matchListB[0]; splitA = cleanedA.split(tabMatchA)[1]; splitB = cleanedB.split(tabMatchB)[1]; if (tabMatchA.length > tabMatchB.length) { analysis = tabMatchA.split(tabMatchB); tabMatchA = tabMatchB + strStart + analysis[1] + strEnd; tabMatchB = tabMatchB + strStart + strEnd; } else { analysis = tabMatchB.split(tabMatchA); tabMatchB = tabMatchA + strStart + analysis[1] + strEnd; tabMatchA = tabMatchA + strStart + strEnd; } return [tabMatchA, tabMatchB, splitA, splitB]; }()), //compare is the fuzzy string comparison algorithm compare = function diffview__report_charcomp_compare(start) { var x = 0, y = 0, max = Math.max(dataA.length, dataB.length), store = [], sorta = function diffview__report_charcomp_compare_sorta(a, b) { if (a[1] - a[0] < b[1] - b[0]) { return 1; } return -1; }, sortb = function diffview__report_charcomp_compare_sortb(a, b) { if (a[0] + a[1] > b[0] + b[1]) { return 1; } return -1; }, whitetest = (/^(\s+)$/), whitespace = false, wordtest = false; //first gather a list of all matching indexes into an array for (x = start; x < dataMinLength; x += 1) { for (y = start; y < max; y += 1) { if (dataA[x] === dataB[y] || dataB[x] === dataA[y]) { store.push([x, y]); if (dataA[y] === dataB[x] && dataA[y + 1] === dataB[x + 1] && whitetest.test(dataB[x - 1]) === true) { wordtest = true; store = [[x, y]]; } if (dataA[x] === dataB[y] && dataA[x + 1] === dataB[y + 1] && whitetest.test(dataB[y - 1]) === true) { wordtest = true; store = [[x, y]]; } break; } } if (wordtest === true) { break; } } //if there are no character matches then quit out if (store.length === 0) { return [dataMinLength, max, 0, whitespace]; } //take the list of matches and sort it //first sort by size of change with shortest up front //second sort by sum of change start and end //the second sort results in the smallest change from the earliest point store.sort(sorta); if (dataMinLength - start < 5000) { store.sort(sortb); } //x should always be the shorter index (change start) if (store[0][0] < store[0][1]) { x = store[0][0]; y = store[0][1]; } else { y = store[0][0]; x = store[0][1]; } if (options.diffspaceignore === true) { if (whitetest.test(dataA.join("").slice(b, x)) === true || whitetest.test(dataB.join("").slice(b, x)) === true) { whitespace = true; } } //package the output if (dataA[y] === dataB[x]) { if (dataA[y - 1] === dataB[x - 1] && x !== start) { x -= 1; y -= 1; } return [x, y, 0, whitespace]; } if (dataA[x] === dataB[y]) { if (dataA[x - 1] === dataB[y - 1] && x !== start) { x -= 1; y -= 1; } return [x, y, 1, whitespace]; } }; //if same after accounting for character entities then exit if (cleanedA === cleanedB) { return [lineA, lineB]; } //prevent extra error counting that occurred before entering this function errorout -= 1; //diff for tabs if (tabFix !== "" && cleanedA.length !== cleanedB.length && cleanedA.replace(tabFix, "") === cleanedB.replace(tabFix, "") && options.diffspaceignore === false) { errorout += 1; if (options.diffcli === true) { tabdiff[0] = tabdiff[0] + tabdiff[2]; tabdiff[0] = tabdiff[0] .replace(regStart, "") .replace(regEnd, ""); tabdiff[1] = tabdiff[1] + tabdiff[3]; tabdiff[1] = tabdiff[1] .replace(regStart, "") .replace(regEnd, ""); return [tabdiff[0], tabdiff[1]]; } tabdiff[0] = tabdiff[0] + tabdiff[2]; tabdiff[0] = tabdiff[0] .replace(/&/g, "&") .replace(//g, ">") .replace(regStart, "") .replace(regEnd, ""); tabdiff[1] = tabdiff[1] + tabdiff[3]; tabdiff[1] = tabdiff[1] .replace(/&/g, "&") .replace(//g, ">") .replace(regStart, "") .replace(regEnd, ""); return [tabdiff[0], tabdiff[1]]; } //turn the pruned input into arrays dataA = cleanedA.split(""); dataB = cleanedB.split(""); //the length of the shortest array dataMinLength = Math.min(dataA.length, dataB.length); for (b = 0; b < dataMinLength; b += 1) { //if undefined break the loop if (dataA[b] === undefined || dataB[b] === undefined) { break; } //iterate until the arrays are not the same if (dataA[b] !== dataB[b]) { //fuzzy string comparison returns an array with these indexes //0 - shorter ending index of difference //1 - longer ending index of difference //2 - 0 if index 2 is for dataA or 1 for dataB //3 - whether the difference is only whitespace currentdiff = compare(b); //supply the difference start indicator if (currentdiff[3] === false) { //count each difference errorout += 1; if (b > 0) { dataA[b - 1] = dataA[b - 1] + strStart; dataB[b - 1] = dataB[b - 1] + strStart; } else { dataA[b] = strStart + dataA[b]; dataB[b] = strStart + dataB[b]; } //complex decision tree on how to supply difference end indicator if (currentdiff[2] === 1) { if (currentdiff[0] === 0) { dataA[0] = dataA[0].replace(regStart, strStart + strEnd); } else if (currentdiff[0] === dataMinLength) { if (dataB.length === dataMinLength) { dataA[dataA.length - 1] = dataA[dataA.length - 1] + strEnd; } else { dataA[currentdiff[0] - 1] = dataA[currentdiff[0] - 1] + strEnd; } } else { if (dataA[currentdiff[0]].indexOf(strStart) > -1) { dataA[currentdiff[0]] = dataA[currentdiff[0]] + strEnd; } else { dataA[currentdiff[0]] = strEnd + dataA[currentdiff[0]]; } } if (currentdiff[1] > dataB.length - 1 || currentdiff[0] === dataMinLength) { dataB[dataB.length - 1] = dataB[dataB.length - 1] + strEnd; } else { dataB[currentdiff[1]] = strEnd + dataB[currentdiff[1]]; } } else { if (currentdiff[0] === 0) { dataB[0] = dataB[0].replace(regStart, strStart + strEnd); } else if (currentdiff[0] === dataMinLength) { if (dataA.length === dataMinLength) { dataB[dataB.length - 1] = dataB[dataB.length - 1] + strEnd; } else { dataB[currentdiff[0] - 1] = dataB[currentdiff[0] - 1] + strEnd; } } else { if (dataB[currentdiff[0]].indexOf(strStart) > -1) { dataB[currentdiff[0]] = dataB[currentdiff[0]] + strEnd; } else { dataB[currentdiff[0]] = strEnd + dataB[currentdiff[0]]; } } if (currentdiff[1] > dataA.length - 1 || currentdiff[0] === dataMinLength) { dataA[dataA.length - 1] = dataA[dataA.length - 1] + strEnd; } else { dataA[currentdiff[1]] = strEnd + dataA[currentdiff[1]]; } } } //we must rebase the array with the shorter difference //so that the end of the current difference is on the //same index. This provides a common baseline by which //to find the next unmatching index if (currentdiff[1] > currentdiff[0] && currentdiff[1] - currentdiff[0] < 1000) { if (currentdiff[2] === 1) { do { dataA.unshift(""); currentdiff[0] += 1; } while (currentdiff[1] > currentdiff[0]); } else { do { dataB.unshift(""); currentdiff[0] += 1; } while (currentdiff[1] > currentdiff[0]); } } //since the previous logic will grow the shorter array //we have to redefine the shortest length dataMinLength = Math.min(dataA.length, dataB.length); //assign the incrementer to the end of the longer difference b = currentdiff[1]; } } //if one array is longer than the other and not identified as different //then identify this difference in length if (dataA.length > dataB.length && dataB[dataB.length - 1] !== undefined && dataB[dataB.length - 1].indexOf(strEnd) < 0) { dataB.push(strStart + strEnd); dataA[dataB.length - 1] = strStart + dataA[dataB.length - 1]; dataA[dataA.length - 1] = dataA[dataA.length - 1] + strEnd; errorout += 1; } if (dataB.length > dataA.length && dataA[dataA.length - 1] !== undefined && dataA[dataA.length - 1].indexOf(strEnd) < 0) { dataA.push(strStart + strEnd); dataB[dataA.length - 1] = strStart + dataB[dataA.length - 1]; dataB[dataB.length - 1] = dataB[dataB.length - 1] + strEnd; errorout += 1; } //options.diffcli output doesn't need XML protected characters //to be escaped because its output is the command line if (options.diffcli === true) { return [ dataA .join("") .replace(regStart, "") .replace(regEnd, ""), dataB .join("") .replace(regStart, "") .replace(regEnd, "") ]; } return [ dataA .join("") .replace(/&/g, "&") .replace(//g, ">") .replace(regStart, "") .replace(regEnd, ""), dataB .join("") .replace(/&/g, "&") .replace(//g, ">") .replace(regStart, "") .replace(regEnd, "") ]; }; if (options.diffcli === false) { if (options.inline === true) { node.push("

"); node.push(options.sourcelabel); node.push(" vs. "); node.push(options.difflabel); node.push("

    "); } else { data[0].push("

    "); data[0].push(options.sourcelabel); data[0].push("

      "); data[2].push("

      "); data[2].push(options.difflabel); data[2].push("

        "); } } for (a = 0; a < opcodesLength; a += 1) { change = opcodes[a][0]; bs = opcodes[a][1]; be = opcodes[a][2]; ns = opcodes[a][3]; ne = opcodes[a][4]; rowcnt = Math.max(be - bs, ne - ns); ctest = true; for (i = 0; i < rowcnt; i += 1) { //apply options.context collapsing for the output, if needed if (options.context > -1 && opcodesLength > 1 && ((a > 0 && i === options.context) || (a === 0 && i === 0)) && change === "equal") { ctest = false; jump = rowcnt - ((a === 0 ? 1 : 2) * options.context); if (jump > 1) { bs += jump; ns += jump; i += jump - 1; if (options.diffcli === true) { data[5].push([bs, ns]); } else { data[0].push("
      1. ...
      2. "); if (options.inline === false) { data[1].push(""); } data[2].push("
      3. ...
      4. "); data[3].push(""); } if (a + 1 === opcodes.length) { break; } } } else if (change !== "equal") { diffline += 1; } foldcount += 1; if (linesBase[bs] !== linesNew[ns] && change === "equal") { change = "replace"; } //this is a check against false positives incurred //by increasing or reducing of nesting. At this //time it only checks one level deep. if (tab !== "") { if (btest === false && linesBase[be] !== linesNew[ne] && typeof linesBase[bs + 1] === "string" && typeof linesNew[ns] === "string" && baseTab[bs + 1] === newTab[ns] && baseTab[bs] !== newTab[ns] && (typeof linesNew[ns - 1] !== "string" || baseTab[bs] !== newTab[ns - 1])) { btest = true; } else if (ntest === false && linesBase[be] !== linesNew[ne] && typeof linesNew[ns + 1] === "string" && typeof linesBase[bs] === "string" && newTab[ns + 1] === baseTab[bs] && newTab[ns] !== baseTab[bs] && (typeof linesBase[bs - 1] !== "string" || newTab[ns] !== baseTab[bs - 1])) { ntest = true; } } if (options.diffcli === true) { if (options.diffspaceignore === true && change === "replace" && linesBase[bs].replace(/\s+/g, "") === linesNew[ns].replace(/\s+/g, "")) { change = "equal"; errorout -= 1; } else { //data array schema: //0 - base line number //1 - base code line //2 - new line number //3 - new code line //4 - [0] (change) //5 - index of options.context (not parallel) if (ntest === true || change === "insert") { if (options.diffspaceignore === false || (/^(\s+)$/g).test(linesNew[ns]) === false) { data[0].push(0); data[1].push(""); data[2].push(ns + 1); data[3].push(linesNew[ns]); data[4].push("insert"); errorout += 1; } } else if (btest === true || change === "delete") { if (options.diffspaceignore === false || (/^(\s+)$/g).test(linesBase[bs]) === false) { data[0].push(bs + 1); data[1].push(linesBase[bs]); data[2].push(0); data[3].push(""); data[4].push("delete"); errorout += 1; } } else if (change === "replace") { if (linesBase[bs] !== linesNew[ns]) { if (linesBase[bs] === "") { charcompOutput = ["", linesNew[ns]]; } else if (linesNew[ns] === "") { charcompOutput = [linesBase[bs], ""]; } else if (bs < be && ns < ne) { charcompOutput = charcomp(linesBase[bs], linesNew[ns]); errorout += 1; } } if (bs < be) { data[0].push(bs + 1); if (ns < ne) { data[1].push(charcompOutput[0]); } else { data[1].push(linesBase[bs]); } data[2].push(0); data[3].push(""); data[4].push("delete"); } if (ns < ne) { data[0].push(0); data[1].push(""); data[2].push(ns + 1); if (bs < be) { data[3].push(charcompOutput[1]); } else { data[3].push(linesNew[ns]); } data[4].push("insert"); } } else if (bs < be || ns < ne) { if (options.diffspaceignore === false || linesBase[bs].replace(/\s+/g, "") !== linesNew[ns].replace(/\s+/g, "")) { data[0].push(bs + 1); data[1].push(linesBase[bs]); data[2].push(ns + 1); data[3].push(linesNew[ns]); data[4].push(change); if (change !== "equal") { errorout += 1; } } } if (btest === true) { bs += 1; btest = false; } else if (ntest === true) { ns += 1; ntest = false; } else { bs += 1; ns += 1; } } //this is the final of the three primary components //this is where the output is built } else if (options.inline === true) { if (options.diffspaceignore === true && change === "replace" && linesBase[bs].replace(/\s+/g, "") === linesNew[ns].replace(/\s+/g, "")) { change = "equal"; errorout -= 1; } if (options.context < 0 && rowItem < a) { rowItem = a; if (foldstart > -1) { if (data[0][foldstart + 1] === foldcount - 1) { data[0][foldstart] = "
      5. " + data[0][foldstart].slice(data[0][foldstart].indexOf("line xxx'>- ") + 12); } else { data[0][foldstart] = data[0][foldstart].replace("xxx", (foldcount - 1 + rcount)); } } if (change !== "replace") { data[0].push("
      6. - "); foldstart = data[0].length - 1; if (ntest === true || change === "insert") { data[0].push(" "); } else { data[0].push(bs + 1); } data[0].push("
      7. "); } else { rcount += 1; } } else if (change !== "replace") { data[0].push("
      8. "); if (ntest === true || change === "insert") { data[0].push(" "); } else { data[0].push(bs + 1); } data[0].push("
      9. "); } else if (change === "replace") { rcount += 1; } if (ntest === true || change === "insert") { data[2].push("
      10. "); data[2].push(ns + 1); data[2].push("
      11. "); if (options.diffspaceignore === true && linesNew[ns].replace(/\s+/g, "") === "") { data[3].push("
      12. "); diffline -= 1; } else { data[3].push("
      13. "); } data[3].push(linesNew[ns]); data[3].push("
      14. "); } else if (btest === true || change === "delete") { data[2].push("
      15. "); if (options.diffspaceignore === true && linesBase[bs].replace(/\s+/g, "") === "") { data[3].push("
      16. "); diffline -= 1; } else { data[3].push("
      17. "); } data[3].push(linesBase[bs]); data[3].push("
      18. "); } else if (change === "replace") { if (linesBase[bs] !== linesNew[ns]) { if (linesBase[bs] === "") { charcompOutput = ["", linesNew[ns]]; } else if (linesNew[ns] === "") { charcompOutput = [linesBase[bs], ""]; } else if (bs < be && ns < ne) { charcompOutput = charcomp(linesBase[bs], linesNew[ns]); } } if (bs < be) { data[0].push("
      19. "+ (bs + 1) + "
      20. "); data[2].push("
      21. "); if (options.diffspaceignore === true && linesBase[bs].replace(/\s+/g, "") === "") { data[3].push("
      22. "); diffline -= 1; } else { data[3].push("
      23. "); } if (ns < ne) { data[3].push(charcompOutput[0]); } else { data[3].push(linesBase[bs]); } data[3].push("
      24. "); } if (ns < ne) { data[0].push("
      25. "); data[2].push("
      26. "); data[2].push(ns + 1); data[2].push("
      27. "); if (options.diffspaceignore === true && linesNew[ns].replace(/\s+/g, "") === "") { data[3].push("
      28. "); diffline -= 1; } else { data[3].push("
      29. "); } if (bs < be) { data[3].push(charcompOutput[1]); } else { data[3].push(linesNew[ns]); } data[3].push("
      30. "); } } else if (bs < be || ns < ne) { data[2].push("
      31. "); data[2].push(ns + 1); data[2].push("
      32. "); data[3].push("
      33. "); data[3].push(linesBase[bs]); data[3].push("
      34. "); } if (btest === true) { bs += 1; btest = false; } else if (ntest === true) { ns += 1; ntest = false; } else { bs += 1; ns += 1; } } else { if (btest === false && ntest === false && typeof linesBase[bs] === "string" && typeof linesNew[ns] === "string") { if (linesBase[bs] === "" && linesNew[ns] !== "") { change = "insert"; } if (linesNew[ns] === "" && linesBase[bs] !== "") { change = "delete"; } if (change === "replace" && bs < be && ns < ne && linesBase[bs] !== linesNew[ns]) { if (options.diffspaceignore === true && linesBase[bs].replace(/\s+/g, "") === linesNew[ns].replace(/\s+/g, "")) { change = "equal"; charcompOutput = [linesBase[bs], linesNew[ns]]; } else { charcompOutput = charcomp(linesBase[bs], linesNew[ns]); } } else { charcompOutput = [linesBase[bs], linesNew[ns]]; } if (bs === Number(data[0][data[0].length - 1].substring(data[0][data[0].length - 1].indexOf(">") + 1, data[0][data[0].length - 1].lastIndexOf("<"))) - 1 || ns === Number(data[2][data[2].length - 1].substring(data[2][data[2].length - 1].indexOf(">") + 1, data[2][data[2].length - 1].lastIndexOf("<"))) - 1) { repeat = true; } if (repeat === false) { if (bs < be) { if (options.context < 0 && rowItem < a) { rowItem = a; if (foldstart > -1) { data[0][foldstart] = data[0][foldstart].replace("xxx", (foldcount - 1)); } data[0].push("
      35. - " + (bs + 1) + "
      36. "); foldstart = data[0].length - 1; } else { data[0].push("
      37. " + (bs + 1) + "
      38. "); } data[1].push("
      39. "); data[1].push(charcompOutput[0]); data[1].push("
      40. "); } else if (ctest === true) { if (options.context < 0 && rowItem < a) { rowItem = a; if (foldstart > -1) { data[0][foldstart] = data[0][foldstart].replace("xxx", (foldcount - 1)); } data[0].push("
      41. -
      42. "); foldstart = data[0].length - 1; } else { data[0].push("
      43. "); } data[1].push("
      44. "); } if (ns < ne) { data[2].push("
      45. " + (ns + 1) + "
      46. "); data[3].push("
      47. "); data[3].push(charcompOutput[1]); data[3].push("
      48. "); } else if (ctest === true) { data[2].push("
      49. "); data[3].push("
      50. "); } } else { repeat = false; } if (bs < be) { bs += 1; } if (ns < ne) { ns += 1; } } else if (btest === true || (typeof linesBase[bs] === "string" && typeof linesNew[ns] !== "string")) { if (bs !== Number(data[0][data[0].length - 1].substring(data[0][data[0].length - 1].indexOf(">") + 1, data[0][data[0].length - 1].lastIndexOf("<"))) - 1) { data[0].push("
      51. " + (bs + 1) + "
      52. "); data[1].push("
      53. "); data[1].push(linesBase[bs]); data[1].push("
      54. "); data[2].push("
      55. "); data[3].push("
      56. "); } btest = false; bs += 1; } else if (ntest === true || (typeof linesBase[bs] !== "string" && typeof linesNew[ns] === "string")) { if (ns !== Number(data[2][data[2].length - 1].substring(data[2][data[2].length - 1].indexOf(">") + 1, data[2][data[2].length - 1].lastIndexOf("<"))) - 1) { data[0].push("
      57. "); data[1].push("
      58. "); data[2].push("
      59. " + (ns + 1) + "
      60. "); data[3].push("
      61. "); data[3].push(linesNew[ns]); data[3].push("
      62. "); } ntest = false; ns += 1; } } } } if (foldstart > -1) { data[0][foldstart] = data[0][foldstart].replace("xxx", foldcount + rcount); } if (options.diffcli === true) { data.push(errorout); return data; } node.push(data[0].join("")); node.push("
        "); } else { node.push("'data'>"); node.push(data[1].join("")); node.push("
      "); } node.push(data[2].join("")); node.push("
      "); node.push(data[3].join("")); if (options.inline === true) { node.push("
    "); } else { node.push("
"); } node.push("

Diff view written by Pretty D" + "iff.

"); finaldoc = node.join(""); return [ finaldoc .replace(/li\ class='equal'><\/li/g, "li class='equal'>