diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..50d0002 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["node6", "react"], +} \ No newline at end of file diff --git a/package.json b/package.json index 4555339..941fc75 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "start": "npm run copy-css && webpack --progress --colors --watch", "serve": "node src/server/babel.index.js", "webpack-stats": "webpack --profile --json > stats.json", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha --watch --compilers js:babel-register" + }, "author": "", "license": "BSD-2-Clause", @@ -39,7 +40,10 @@ "babel-preset-es2015-native-modules": "^6.9.4", "babel-preset-node6": "^11.0.0", "babel-preset-react": "^6.3.13", + "babel-register": "^6.18.0", + "chai": "^3.5.0", "copyfiles": "^0.2.2", + "mocha": "^3.2.0", "piping": "^1.0.0-rc.4", "webpack": "^2.1.0-beta.27" } diff --git a/src/common/util/dubdiff.js b/src/common/util/dubdiff.js index 7ed2b3c..f94e98e 100644 --- a/src/common/util/dubdiff.js +++ b/src/common/util/dubdiff.js @@ -6,6 +6,8 @@ import * as JsDiff from 'diff' // the diff would use a custom compare function that would disregard the spaces // alternately, the text could be split with the spaces included in the array and then compared with a // custom diff function that would treat the space elements as null/ignored + +//the current mechanism for adding and removing spaces is fragile and broken export function plaintextDiff(original, final) { let arrOriginal = plaintextSplit(original) let arrFinal = plaintextSplit(final) @@ -27,22 +29,29 @@ export function markdownDiff(original, final) { return diff } - -export function diffToLogString(diff) { +// returns a string version of the diff, with "{+ ... +}" and "[- ... -]" +// representing ins and del blocks +export function diffToString(diff) { return diff.map(({added, removed, value}) => { - let sym = added ? "+" : removed ? '-' : '/' - return sym+value+sym - }) + let start = added ? '{+' : removed ? '[-' : '' + let end = added ? '+}' : removed ? '-]' : '' + let string = value + if (Array.isArray(value)) + string = value.join('') + + return start+string+end + }).join(' ') } let plaintextSplit = text =>text.split(/[ ]|(\n)/) + function plaintextRestoreSpaces (diff) { return diff.map(({added, removed, value}) => ({ added, removed, value:value.map((str, idx, arr) => ( (str!='\n' && (idx { - + previousBlockType = currentBlockType previousBlockWasMultiline = currentBlockIsMultiline - currentBlockType = (currentBlock.added ? B_ADD : (currentBlock.removed ? B_REMOVED : B_SAME)) + currentBlockType = (currentBlock.added ? B_ADDED : (currentBlock.removed ? B_REMOVED : B_SAME)) currentBlockIsMultiline = isMultilineDiffBlock(currentBlock) //transform rule 1 applys when: // the previous block was a del and had multiple lines // the current block is an ins - if (previousBlockType == B_REM && currentBlockType == B_INS && previousBlockWasMultiline) { + if (previousBlockType == B_REMOVED && currentBlockType == B_ADDED && previousBlockWasMultiline) { + console.log('trigger rule 1') + //split the first line from the current block let currentBlockSplit = splitMultilineDiffBlock(currentBlock) @@ -104,13 +115,14 @@ function applyTransformationRule1(diff) { let previousBlock = transformedDiff.pop() //split the first line from the previous block - let previousBlockSplit = splitMultilineDiffBlock(currentBlock) + let previousBlockSplit = splitMultilineDiffBlock(previousBlock) + + console.log({currentBlock, currentBlockSplit, previousBlock, previousBlockSplit}) //now add the blocks back, interleaving del and ins blocks for (let i=0; i str=='\n') + + splits.push(value.length) //create a range from each index const ranges = splits.reduce( //the accumulator is a structure with the last index and the list of ranges //the ranges are a {start, end} structure - ({last, ranges}, i) => {i, ranges.concat([{start:last, end:i}])}, + ({last, ranges}, i) => { + ranges = ranges.concat([{start:last, end:i}]) + return {last:i, ranges} + }, //start with the zero index and an empty array {last: 0, ranges:[]} ).ranges + //map the ranges into blocks const blocks = ranges.map( //each block is the same as the given original block, but with the values split at newlines - ({start, end}) => {added, removed, value.slice(start, end)} + ({start, end}) => ({added, removed, value:value.slice(start, end)}) ) + console.log({value, splits, ranges, blocks}) + return blocks } diff --git a/test/dubdiffMarkdown.js b/test/dubdiffMarkdown.js new file mode 100644 index 0000000..a3715fa --- /dev/null +++ b/test/dubdiffMarkdown.js @@ -0,0 +1,48 @@ +/*eslint-env node, mocha */ +/*global expect */ +/*eslint no-console: 0*/ +'use strict'; + +import chai from 'chai' + +import {markdownDiff, diffToString} from '../src/common/util/dubdiff' + +let diff = (a,b) => diffToString(markdownDiff(a,b)) + +const expect = chai.expect + +describe('dubdiff', () => { + let db; + + beforeEach(() => { + }); + + it('plaintext diffs consecutive words', ()=>{ + expect(diff( + 'This is a smlb sentnce with no errors.', + 'This is a simple sentence with no errors.' + )).to.equal('This is a [-smlb sentnce-] {+simple sentence+} with no errors.') + }) + + it('plaintext diffs with word deletion', ()=>{ + expect(diff( + 'Gonna delete a word.', + 'Gonna delete word.' + )).to.equal('Gonna delete [-a-] word.') + }) + + it('plaintext diffs with word insertion', ()=>{ + expect(diff( + 'Gonna delete word.', + 'Gonna delete a word.' + )).to.equal('Gonna delete {+a+} word.') + }) + + it('reorganizes insertions after multiline deletions', ()=>{ + expect(diff( +`# Title +other`, +`# Subtitle` + )).to.equal('# [-Title-] {+Subtitle+}[-\nother-]') + }) +}) \ No newline at end of file diff --git a/test/dubdiffPlaintext.js b/test/dubdiffPlaintext.js new file mode 100644 index 0000000..d8d3333 --- /dev/null +++ b/test/dubdiffPlaintext.js @@ -0,0 +1,63 @@ +/*eslint-env node, mocha */ +/*global expect */ +/*eslint no-console: 0*/ +'use strict'; + +import chai from 'chai' + +import {plaintextDiff, diffToString} from '../src/common/util/dubdiff' + +let diff = (a,b) => diffToString(plaintextDiff(a,b)) + +const expect = chai.expect + +describe('dubdiff', () => { + + beforeEach(() => { + }); + + it('diffs single words', ()=>{ + expect(diff( + 'This is a smlb sentence.', + 'This is a simple sentence.' + )).to.equal('This is a [-smlb-] {+simple+} sentence.') + }) + + it('diffs consecutive words', ()=>{ + expect(diff( + 'This is a smlb sentnce with no errors.', + 'This is a simple sentence with no errors.' + )).to.equal('This is a [-smlb sentnce-] {+simple sentence+} with no errors.') + }) + + it('diffs with word deletion', ()=>{ + expect(diff( + 'Gonna delete a word.', + 'Gonna delete word.' + )).to.equal('Gonna delete [-a-] word.') + }) + it('diffs with word insertion', ()=>{ + expect(diff( + 'Gonna delete word.', + 'Gonna delete a word.' + )).to.equal('Gonna delete {+a+} word.') + }) + it('diffs accross newline without weird spaces', () => { + expect(diff( + 'This is a flawed\ncomment', + 'This is a corrected\nitem' + )).to.equal('This is a [-flawed-] {+corrected+}\n[-comment-] {+item+}') + }) + it('doesn\'t add spaces after newline', () => { + expect(diff( + '\nhere', + '\nhere' + )).to.equal('\nhere') + }) + it('doesn\'t add spaces before newline', () => { + expect(diff( + 'there\n', + 'there\n' + )).to.equal('there\n') + }) +}) \ No newline at end of file