diff --git a/package-lock.json b/package-lock.json index 3d005c1..147e274 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1320,6 +1320,12 @@ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" }, + "lodash.partition": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.partition/-/lodash.partition-4.6.0.tgz", + "integrity": "sha1-o45GtzRp4EILDaEhLmbUFL42S6Q=", + "dev": true + }, "log-driver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", diff --git a/package.json b/package.json index 83bed43..542902f 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "eslint-plugin-prettier": "^3.1.2", "istanbul": "~0.4.5", "jasmine": "^3.5.0", + "lodash.partition": "^4.6.0", "prettier": "^2.0.4", "typescript": "^3.8.3" }, @@ -34,7 +35,7 @@ "build": "tsc", "prepare": "npm run build", "lint": "eslint 'src/**/*.ts'", - "test": "npm run build; jasmine test/*.js test/**/*.js", + "test": "npm run build & jasmine test/*.js test/**/*.js", "test:coverage": "istanbul cover jasmine test/*.js test/**/*.js", "test:coverage:report": "cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" }, diff --git a/src/Delta.ts b/src/Delta.ts index 31ef73d..42cb4c0 100644 --- a/src/Delta.ts +++ b/src/Delta.ts @@ -6,6 +6,41 @@ import Op from './Op'; const NULL_CHARACTER = String.fromCharCode(0); // Placeholder char for embed in diff() +function addMetaData( + op: Op, + thisOrOther: boolean, + replaces?: string | null, + original?: string | null, +): Op { + const clone = cloneDeep(op); + const attr = clone.attributes || {}; + attr.meta = { thisOrOther }; + if (typeof replaces !== 'undefined') { + attr.meta.replaces = replaces; + } + if (typeof original !== 'undefined') { + attr.meta.original = original; + } + clone.attributes = attr; + return clone; +} + +function addMetaDataAttribute( + attributes: AttributeMap | undefined = {}, + thisOrOther: boolean, + replaces?: string | null, + original?: string | null, +): AttributeMap { + attributes = { ...attributes, meta: { thisOrOther } }; + if (typeof replaces !== 'undefined') { + attributes.meta.replaces = replaces; + } + if (typeof original !== 'undefined') { + attributes.meta.original = original; + } + return attributes; +} + class Delta { static Op = Op; static AttributeMap = AttributeMap; @@ -186,6 +221,13 @@ class Delta { compose(other: Delta): Delta { const thisIter = Op.iterator(this.ops); const otherIter = Op.iterator(other.ops); + + let runningCursor = 0; + const attributeMarker: { + [id: string]: { start: number; end: number }; + } = {}; + const toRemove: { [id: string]: { this: boolean; other: boolean } } = {}; + const ops = []; const firstOther = otherIter.peek(); if ( @@ -198,8 +240,32 @@ class Delta { thisIter.peekType() === 'insert' && thisIter.peekLength() <= firstLeft ) { - firstLeft -= thisIter.peekLength(); - ops.push(thisIter.next()); + const length = thisIter.peekLength(); + firstLeft -= length; + const op = thisIter.next(); + if (op.attributes?.detectionId) { + if ( + toRemove[op.attributes.detectionId] && + toRemove[op.attributes.detectionId].this && + toRemove[op.attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = attributeMarker[op.attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[op.attributes.detectionId] = { this: true, other: true }; + delete attributeMarker[op.attributes.detectionId]; + } else { + attributeMarker[op.attributes.detectionId] = thisEntry; + } + } + } + ops.push(op.attributes?.detectionId ? addMetaData(op, true) : op); + runningCursor += length; } if (firstOther.retain - firstLeft > 0) { otherIter.next(firstOther.retain - firstLeft); @@ -208,7 +274,31 @@ class Delta { const delta = new Delta(ops); while (thisIter.hasNext() || otherIter.hasNext()) { if (otherIter.peekType() === 'insert') { - delta.push(otherIter.next()); + const op = otherIter.next(); + const length = Op.length(op); + if (op.attributes?.detectionId) { + if ( + toRemove[op.attributes.detectionId] && + toRemove[op.attributes.detectionId].this && + toRemove[op.attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = attributeMarker[op.attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[op.attributes.detectionId] = { this: true, other: true }; + delete attributeMarker[op.attributes.detectionId]; + } else { + attributeMarker[op.attributes.detectionId] = thisEntry; + } + } + } + delta.push(op.attributes?.detectionId ? addMetaData(op, false) : op); + runningCursor += length; } else if (thisIter.peekType() === 'delete') { delta.push(thisIter.next()); } else { @@ -231,7 +321,85 @@ class Delta { if (attributes) { newOp.attributes = attributes; } - delta.push(newOp); + if (attributes?.detectionId) { + if ( + toRemove[attributes.detectionId] && + toRemove[attributes.detectionId].this && + toRemove[attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = attributeMarker[attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[attributes.detectionId] = { this: true, other: true }; + delete attributeMarker[attributes.detectionId]; + } else { + attributeMarker[attributes.detectionId] = thisEntry; + } + } + + // One detectionId got erased!!! + if ( + thisOp.attributes?.detectionId && + otherOp.attributes?.detectionId + ) { + const thisOrOther = + thisOp.attributes.detectionId !== attributes.detectionId + ? 'this' + : 'other'; + const detId = + thisOrOther === 'this' + ? thisOp.attributes.detectionId + : otherOp.attributes.detectionId; + + const removalStatus = toRemove[detId] || { + this: false, + other: false, + }; + toRemove[detId] = { ...removalStatus, [thisOrOther]: true }; + if ( + toRemove[detId] && + toRemove[detId].this && + toRemove[detId].other + ) { + delete attributeMarker[detId]; + } + } + } else if ( + thisOp.attributes?.detectionId && + otherOp.attributes?.detectionId === null + ) { + const removalStatus = toRemove[thisOp.attributes.detectionId] || { + this: false, + other: false, + }; + toRemove[thisOp.attributes.detectionId] = { + ...removalStatus, + this: true, + }; + if ( + toRemove[thisOp.attributes.detectionId] && + toRemove[thisOp.attributes.detectionId].this && + toRemove[thisOp.attributes.detectionId].other + ) { + delete attributeMarker[thisOp.attributes.detectionId]; + } + } + + delta.push( + typeof attributes?.detectionId !== 'undefined' + ? addMetaData( + newOp, + thisOp.attributes?.detectionId === attributes?.detectionId, + ) + : newOp, + ); + + runningCursor += length; // Optimization if rest of other is just retain if ( @@ -239,7 +407,66 @@ class Delta { isEqual(delta.ops[delta.ops.length - 1], newOp) ) { const rest = new Delta(thisIter.rest()); - return delta.concat(rest).chop(); + + const validatedRest = cloneDeep(rest.ops).map((op) => { + if ( + op.attributes?.detectionId && + toRemove[op.attributes.detectionId] && + toRemove[op.attributes.detectionId].this + ) { + const newOp = cloneDeep(op); + let newAttributes = newOp.attributes; + if (op.retain) { + newAttributes = { ...newAttributes, detectionId: null }; + } else if (newAttributes) { + delete newAttributes['detectionId']; + } + if (newAttributes && Object.keys(newAttributes).length === 0) { + delete newOp['attributes']; + return newOp; + } + return { ...newOp, attributes: newAttributes }; + } else { + return op; + } + }); + + const newDelta = new Delta(); + cloneDeep(delta.ops).forEach((op) => { + let attributes = op.attributes; + if (attributes?.detectionId) { + if (typeof attributes.meta === 'undefined') { + throw Error( + 'if an attribute has a detection it should have meta info', + ); + } + const thisOrOther = attributes.meta.thisOrOther + ? 'this' + : 'other'; + const shouldDelete = + toRemove[attributes.detectionId] && + toRemove[attributes.detectionId][thisOrOther]; + + if (shouldDelete) { + if (typeof op.retain === 'number') { + attributes = { ...op.attributes, detectionId: null }; + } else { + delete attributes['detectionId']; + } + } + } + if (attributes) { + delete attributes['meta']; + } + if (!attributes || Object.keys(attributes).length === 0) { + delete op['attributes']; + newDelta.push({ ...op }); + } else { + newDelta.push({ ...op, attributes }); + } + }); + + return newDelta.concat(new Delta(validatedRest)).chop(); } // Other op should be delete, we could be an insert or retain @@ -248,11 +475,77 @@ class Delta { typeof otherOp.delete === 'number' && typeof thisOp.retain === 'number' ) { + if (thisOp.attributes?.detectionId) { + const removalStatus = toRemove[thisOp.attributes.detectionId] || { + this: false, + other: false, + }; + toRemove[thisOp.attributes.detectionId] = { + ...removalStatus, + this: true, + }; + if ( + toRemove[thisOp.attributes.detectionId] && + toRemove[thisOp.attributes.detectionId].this && + toRemove[thisOp.attributes.detectionId].other + ) { + delete attributeMarker[thisOp.attributes.detectionId]; + } + } delta.push(otherOp); + } else { + if (thisOp.attributes?.detectionId) { + const removalStatus = toRemove[thisOp.attributes.detectionId] || { + this: false, + other: false, + }; + toRemove[thisOp.attributes.detectionId] = { + ...removalStatus, + this: true, + }; + if ( + toRemove[thisOp.attributes.detectionId] && + toRemove[thisOp.attributes.detectionId].this && + toRemove[thisOp.attributes.detectionId].other + ) { + delete attributeMarker[thisOp.attributes.detectionId]; + } + } } } } - return delta.chop(); + + const newDelta = new Delta(); + cloneDeep(delta.ops).forEach((op) => { + let attributes = op.attributes; + if ( + attributes?.detectionId && + typeof attributes.meta.thisOrOther !== 'undefined' + ) { + const thisOrOther = attributes.meta.thisOrOther ? 'this' : 'other'; + const shouldDelete = + toRemove[attributes.detectionId] && + toRemove[attributes.detectionId][thisOrOther]; + + if (shouldDelete) { + if (typeof op.retain === 'number') { + attributes = { ...op.attributes, detectionId: null }; + } else { + delete attributes['detectionId']; + } + } + } + if (attributes) { + delete attributes['meta']; + } + if (!attributes || Object.keys(attributes).length === 0) { + delete op['attributes']; + newDelta.push({ ...op }); + } else { + newDelta.push({ ...op, attributes }); + } + }); + return newDelta.chop(); } concat(other: Delta): Delta { @@ -398,37 +691,291 @@ class Delta { const thisIter = Op.iterator(this.ops); const otherIter = Op.iterator(other.ops); const delta = new Delta(); + + let runningCursor = 0; + const attributeMarker: { + [id: string]: { start: number; end: number }; + } = {}; + const toRemove: { [id: string]: { this: boolean; other: boolean } } = {}; + while (thisIter.hasNext() || otherIter.hasNext()) { if ( thisIter.peekType() === 'insert' && (priority || otherIter.peekType() !== 'insert') ) { - delta.retain(Op.length(thisIter.next())); + const op = thisIter.next(); + const length = Op.length(op); + + if (op.attributes?.detectionId) { + if ( + toRemove[op.attributes.detectionId] && + toRemove[op.attributes.detectionId].this && + toRemove[op.attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = attributeMarker[op.attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[op.attributes.detectionId] = { this: true, other: true }; + delete attributeMarker[op.attributes.detectionId]; + } else { + attributeMarker[op.attributes.detectionId] = thisEntry; + } + } + } + + delta.retain( + length, + addMetaDataAttribute( + undefined, + true, + undefined, + op.attributes?.detectionId, + ), + ); + + runningCursor += length; } else if (otherIter.peekType() === 'insert') { - delta.push(otherIter.next()); + const op = otherIter.next(); + const length = Op.length(op); + + if (op.attributes?.detectionId) { + if ( + toRemove[op.attributes.detectionId] && + toRemove[op.attributes.detectionId].this && + toRemove[op.attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = attributeMarker[op.attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[op.attributes.detectionId] = { this: true, other: true }; + delete attributeMarker[op.attributes.detectionId]; + } else { + attributeMarker[op.attributes.detectionId] = thisEntry; + } + } + } + + delta.push(op.attributes?.detectionId ? addMetaData(op, false) : op); + + runningCursor += length; } else { const length = Math.min(thisIter.peekLength(), otherIter.peekLength()); const thisOp = thisIter.next(length); const otherOp = otherIter.next(length); + if (thisOp.delete) { + if (otherOp.attributes?.detectionId) { + const removalStatus = toRemove[otherOp.attributes.detectionId] || { + this: false, + other: false, + }; + toRemove[otherOp.attributes.detectionId] = { + ...removalStatus, + other: true, + }; + if ( + toRemove[otherOp.attributes.detectionId] && + toRemove[otherOp.attributes.detectionId].this && + toRemove[otherOp.attributes.detectionId].other + ) { + delete attributeMarker[otherOp.attributes.detectionId]; + } + } + // Our delete either makes their delete redundant or removes their retain continue; } else if (otherOp.delete) { + if (thisOp.attributes?.detectionId) { + const removalStatus = toRemove[thisOp.attributes.detectionId] || { + this: false, + other: false, + }; + toRemove[thisOp.attributes.detectionId] = { + ...removalStatus, + this: true, + }; + if ( + toRemove[thisOp.attributes.detectionId] && + toRemove[thisOp.attributes.detectionId].this && + toRemove[thisOp.attributes.detectionId].other + ) { + delete attributeMarker[thisOp.attributes.detectionId]; + } + } + delta.push(otherOp); } else { // We retain either their retain or insert - delta.retain( - length, - AttributeMap.transform( - thisOp.attributes, - otherOp.attributes, - priority, - ), + let attributes = AttributeMap.transform( + thisOp.attributes, + otherOp.attributes, + priority, ); + + if (typeof attributes?.detectionId === 'undefined') { + if (typeof thisOp.attributes?.detectionId !== 'undefined') { + if ( + toRemove[thisOp.attributes.detectionId] && + toRemove[thisOp.attributes.detectionId].this && + toRemove[thisOp.attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = + attributeMarker[thisOp.attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[thisOp.attributes.detectionId] = { + this: true, + other: true, + }; + delete attributeMarker[thisOp.attributes.detectionId]; + } else { + attributeMarker[thisOp.attributes.detectionId] = thisEntry; + } + } + + if (otherOp.attributes?.detectionId) { + const removalStatus = toRemove[ + otherOp.attributes.detectionId + ] || { + this: false, + other: false, + }; + toRemove[otherOp.attributes.detectionId] = { + ...removalStatus, + other: true, + }; + if ( + toRemove[otherOp.attributes.detectionId] && + toRemove[otherOp.attributes.detectionId].this && + toRemove[otherOp.attributes.detectionId].other + ) { + delete attributeMarker[otherOp.attributes.detectionId]; + } + } + + attributes = addMetaDataAttribute( + attributes, + true, + otherOp.attributes?.detectionId, + thisOp.attributes?.detectionId, + ); + } else { + /// doest have a detection + } + } else { + // detection from other + if (otherOp.attributes?.detectionId) { + if ( + toRemove[otherOp.attributes.detectionId] && + toRemove[otherOp.attributes.detectionId].this && + toRemove[otherOp.attributes.detectionId].other + ) { + // do nothing... + } else { + const thisEntry = { + start: runningCursor, + end: runningCursor + length, + }; + const lastEntry = + attributeMarker[otherOp.attributes.detectionId]; + if (lastEntry && lastEntry.end < thisEntry.start) { + toRemove[otherOp.attributes.detectionId] = { + this: true, + other: true, + }; + delete attributeMarker[otherOp.attributes.detectionId]; + } else { + attributeMarker[otherOp.attributes.detectionId] = thisEntry; + } + } + } + + if (thisOp.attributes?.detectionId) { + const removalStatus = toRemove[thisOp.attributes.detectionId] || { + this: false, + other: false, + }; + toRemove[thisOp.attributes.detectionId] = { + ...removalStatus, + this: true, + }; + if ( + toRemove[thisOp.attributes.detectionId] && + toRemove[thisOp.attributes.detectionId].this && + toRemove[thisOp.attributes.detectionId].other + ) { + delete attributeMarker[thisOp.attributes.detectionId]; + } + } + + attributes = addMetaDataAttribute( + attributes, + false, + thisOp.attributes?.detectionId, + ); + } + + delta.retain(length, attributes); + + runningCursor += length; } } } - return delta.chop(); + + const newDelta = new Delta(); + cloneDeep(delta.ops).forEach((op) => { + let attributes = op.attributes; + const detectionId = attributes?.detectionId || attributes?.meta?.original; + + if (detectionId) { + if (typeof attributes?.meta === 'undefined') { + throw Error( + 'if an attribute has a detection it should have meta info', + ); + } + const thisOrOther = attributes.meta.thisOrOther ? 'this' : 'other'; + const shouldDelete = + toRemove[detectionId] && toRemove[detectionId][thisOrOther]; + if (shouldDelete) { + const shouldNull = + thisOrOther === 'other' && + typeof attributes.meta.replaces === 'string'; + if (shouldNull) { + attributes = { ...op.attributes, detectionId: null }; + } else { + delete attributes['detectionId']; + } + } + } + + if (attributes) { + delete attributes['meta']; + } + + if (!attributes || Object.keys(attributes).length === 0) { + delete op['attributes']; + newDelta.push({ ...op }); + } else { + newDelta.push({ ...op, attributes }); + } + }); + + return newDelta.chop(); } transformPosition(index: number, priority = false): number { diff --git a/test/delta/compose.js b/test/delta/compose.js index d74f697..ddef3af 100644 --- a/test/delta/compose.js +++ b/test/delta/compose.js @@ -1,151 +1,333 @@ -var Delta = require('../../dist/Delta'); +const Delta = require('../../dist/Delta'); -describe('compose()', function() { - it('insert + insert', function() { - var a = new Delta().insert('A'); - var b = new Delta().insert('B'); - var expected = new Delta().insert('B').insert('A'); +describe('compose()', function () { + it('insert + insert', function () { + const a = new Delta().insert('A'); + const b = new Delta().insert('B'); + const expected = new Delta().insert('B').insert('A'); expect(a.compose(b)).toEqual(expected); }); - it('insert + retain', function() { - var a = new Delta().insert('A'); - var b = new Delta().retain(1, { bold: true, color: 'red', font: null }); - var expected = new Delta().insert('A', { bold: true, color: 'red' }); + it('insert + insert (detectionId)', function () { + const a = new Delta().insert('A', { detectionId: '123' }); + const b = new Delta().insert('B', { detectionId: '234' }); + const expected = new Delta() + .insert('B', { detectionId: '234' }) + .insert('A', { detectionId: '123' }); expect(a.compose(b)).toEqual(expected); }); - it('insert + delete', function() { - var a = new Delta().insert('A'); - var b = new Delta().delete(1); - var expected = new Delta(); + it('insert + retain', function () { + const a = new Delta().insert('A'); + const b = new Delta().retain(1, { bold: true, color: 'red', font: null }); + const expected = new Delta().insert('A', { bold: true, color: 'red' }); expect(a.compose(b)).toEqual(expected); }); - it('delete + insert', function() { - var a = new Delta().delete(1); - var b = new Delta().insert('B'); - var expected = new Delta().insert('B').delete(1); + it('insert + retain (detectionId)', function () { + const a = new Delta().insert('A'); + const b = new Delta().retain(1, { + bold: true, + color: 'red', + font: null, + detectionId: '123', + }); + const expected = new Delta().insert('A', { + bold: true, + color: 'red', + detectionId: '123', + }); + expect(a.compose(b)).toEqual(expected); + }); + + it('insert + delete', function () { + const a = new Delta().insert('A'); + const b = new Delta().delete(1); + const expected = new Delta(); + expect(a.compose(b)).toEqual(expected); + }); + + it('insert + delete (detectionId)', function () { + const a = new Delta().insert('A', { detectionId: '123' }); + const b = new Delta().delete(1); + const expected = new Delta(); + expect(a.compose(b)).toEqual(expected); + }); + + it('insert + delete (detectionId) - clears detection', function () { + const a = new Delta().insert('AB', { detectionId: '123' }); + const b = new Delta().delete(1); + const expected = new Delta().insert('B'); expect(a.compose(b)).toEqual(expected); }); - it('delete + retain', function() { - var a = new Delta().delete(1); - var b = new Delta().retain(1, { bold: true, color: 'red' }); - var expected = new Delta() + it('delete + insert', function () { + const a = new Delta().delete(1); + const b = new Delta().insert('B'); + const expected = new Delta().insert('B').delete(1); + expect(a.compose(b)).toEqual(expected); + }); + + it('delete + insert (detectionId)', function () { + const a = new Delta().delete(1); + const b = new Delta().insert('B', { detectionId: '123' }); + const expected = new Delta().insert('B', { detectionId: '123' }).delete(1); + expect(a.compose(b)).toEqual(expected); + }); + + it('delete + retain', function () { + const a = new Delta().delete(1); + const b = new Delta().retain(1, { bold: true, color: 'red' }); + const expected = new Delta() .delete(1) .retain(1, { bold: true, color: 'red' }); expect(a.compose(b)).toEqual(expected); }); - it('delete + delete', function() { - var a = new Delta().delete(1); - var b = new Delta().delete(1); - var expected = new Delta().delete(2); + it('delete + retain (detectionId)', function () { + const a = new Delta().delete(1); + const b = new Delta().retain(1, { + bold: true, + color: 'red', + detectionId: '123', + }); + const expected = new Delta() + .delete(1) + .retain(1, { bold: true, color: 'red', detectionId: '123' }); + expect(a.compose(b)).toEqual(expected); + }); + + it('delete + delete', function () { + const a = new Delta().delete(1); + const b = new Delta().delete(1); + const expected = new Delta().delete(2); + expect(a.compose(b)).toEqual(expected); + }); + + it('retain + insert', function () { + const a = new Delta().retain(1, { color: 'blue' }); + const b = new Delta().insert('B'); + const expected = new Delta().insert('B').retain(1, { color: 'blue' }); + expect(a.compose(b)).toEqual(expected); + }); + + it('retain + insert (detectionId)', function () { + const a = new Delta().retain(1, { color: 'blue', detectionId: '123' }); + const b = new Delta().insert('B'); + const expected = new Delta() + .insert('B') + .retain(1, { color: 'blue', detectionId: '123' }); expect(a.compose(b)).toEqual(expected); }); - it('retain + insert', function() { - var a = new Delta().retain(1, { color: 'blue' }); - var b = new Delta().insert('B'); - var expected = new Delta().insert('B').retain(1, { color: 'blue' }); + it('retain + retain', function () { + const a = new Delta().retain(1, { color: 'blue' }); + const b = new Delta().retain(1, { bold: true, color: 'red', font: null }); + const expected = new Delta().retain(1, { + bold: true, + color: 'red', + font: null, + }); expect(a.compose(b)).toEqual(expected); }); - it('retain + retain', function() { - var a = new Delta().retain(1, { color: 'blue' }); - var b = new Delta().retain(1, { bold: true, color: 'red', font: null }); - var expected = new Delta().retain(1, { + it('retain + retain (detectionId)', function () { + const a = new Delta().retain(1, { color: 'blue', detectionId: '123' }); + const b = new Delta().retain(1, { + bold: true, + color: 'red', + font: null, + detectionId: '234', + }); + const expected = new Delta().retain(1, { bold: true, color: 'red', font: null, + detectionId: '234', }); expect(a.compose(b)).toEqual(expected); }); - it('retain + delete', function() { - var a = new Delta().retain(1, { color: 'blue' }); - var b = new Delta().delete(1); - var expected = new Delta().delete(1); + it('retain + delete', function () { + const a = new Delta().retain(1, { color: 'blue' }); + const b = new Delta().delete(1); + const expected = new Delta().delete(1); expect(a.compose(b)).toEqual(expected); }); - it('insert in middle of text', function() { - var a = new Delta().insert('Hello'); - var b = new Delta().retain(3).insert('X'); - var expected = new Delta().insert('HelXlo'); + it('retain + delete (detectionId)', function () { + const a = new Delta().retain(1, { color: 'blue', detectionId: '123' }); + const b = new Delta().delete(1); + const expected = new Delta().delete(1); expect(a.compose(b)).toEqual(expected); }); - it('insert and delete ordering', function() { - var a = new Delta().insert('Hello'); - var b = new Delta().insert('Hello'); - var insertFirst = new Delta() - .retain(3) - .insert('X') - .delete(1); - var deleteFirst = new Delta() - .retain(3) + it('retain + delete (detectionId) - clears detection', function () { + const a = new Delta().retain(2, { color: 'blue', detectionId: '123' }); + const b = new Delta().delete(1); + const expected = new Delta() .delete(1) - .insert('X'); - var expected = new Delta().insert('HelXo'); + .retain(1, { color: 'blue', detectionId: null }); + expect(a.compose(b)).toEqual(expected); + }); + + it('insert in middle of text', function () { + const a = new Delta().insert('Hello'); + const b = new Delta().retain(3).insert('X'); + const expected = new Delta().insert('HelXlo'); + expect(a.compose(b)).toEqual(expected); + }); + + it('insert in middle of detection (clears detection)', function () { + const a = new Delta().insert('Hello', { detectionId: '123' }); + const b = new Delta().retain(3).insert('X'); + const expected = new Delta().insert('HelXlo'); + expect(a.compose(b)).toEqual(expected); + }); + + it('delete in middle of detection (clears detection)', function () { + const a = new Delta().insert('Hello', { detectionId: '123' }); + const b = new Delta().retain(3).delete(1); + const expected = new Delta().insert('Helo'); + expect(a.compose(b)).toEqual(expected); + }); + + it('insert and delete ordering', function () { + const a = new Delta().insert('Hello'); + const b = new Delta().insert('Hello'); + const insertFirst = new Delta().retain(3).insert('X').delete(1); + const deleteFirst = new Delta().retain(3).delete(1).insert('X'); + const expected = new Delta().insert('HelXo'); expect(a.compose(insertFirst)).toEqual(expected); expect(b.compose(deleteFirst)).toEqual(expected); }); - it('insert embed', function() { - var a = new Delta().insert(1, { src: 'http://quilljs.com/image.png' }); - var b = new Delta().retain(1, { alt: 'logo' }); - var expected = new Delta().insert(1, { + it('insert and delete ordering with detection (clears detection)', function () { + const a = new Delta().insert('Hello', { detectionId: '123' }); + const b = new Delta().insert('Hello', { detectionId: '123' }); + const insertFirst = new Delta().retain(3).insert('X').delete(1); + const deleteFirst = new Delta().retain(3).delete(1).insert('X'); + const expected = new Delta().insert('HelXo'); + expect(a.compose(insertFirst)).toEqual(expected); + expect(b.compose(deleteFirst)).toEqual(expected); + }); + + it('insert embed', function () { + const a = new Delta().insert(1, { src: 'http://quilljs.com/image.png' }); + const b = new Delta().retain(1, { alt: 'logo' }); + const expected = new Delta().insert(1, { src: 'http://quilljs.com/image.png', alt: 'logo', }); expect(a.compose(b)).toEqual(expected); }); - it('delete entire text', function() { - var a = new Delta().retain(4).insert('Hello'); - var b = new Delta().delete(9); - var expected = new Delta().delete(4); + it('delete entire text', function () { + const a = new Delta().retain(4).insert('Hello'); + const b = new Delta().delete(9); + const expected = new Delta().delete(4); + expect(a.compose(b)).toEqual(expected); + }); + + it('delete entire text (detectionId)', function () { + const a = new Delta().retain(4).insert('Hello', { detectionId: '123' }); + const b = new Delta().delete(9); + const expected = new Delta().delete(4); + expect(a.compose(b)).toEqual(expected); + }); + + it('retain more than length of text', function () { + const a = new Delta().insert('Hello'); + const b = new Delta().retain(10); + const expected = new Delta().insert('Hello'); + expect(a.compose(b)).toEqual(expected); + }); + + it('retain empty embed', function () { + const a = new Delta().insert(1); + const b = new Delta().retain(1); + const expected = new Delta().insert(1); expect(a.compose(b)).toEqual(expected); }); - it('retain more than length of text', function() { - var a = new Delta().insert('Hello'); - var b = new Delta().retain(10); - var expected = new Delta().insert('Hello'); + it('remove all attributes', function () { + const a = new Delta().insert('A', { bold: true }); + const b = new Delta().retain(1, { bold: null }); + const expected = new Delta().insert('A'); expect(a.compose(b)).toEqual(expected); }); - it('retain empty embed', function() { - var a = new Delta().insert(1); - var b = new Delta().retain(1); - var expected = new Delta().insert(1); + it('remove all attributes (detectionId)', function () { + const a = new Delta().insert('A', { detectionId: '123' }); + const b = new Delta().retain(1, { detectionId: null }); + const expected = new Delta().insert('A'); expect(a.compose(b)).toEqual(expected); }); - it('remove all attributes', function() { - var a = new Delta().insert('A', { bold: true }); - var b = new Delta().retain(1, { bold: null }); - var expected = new Delta().insert('A'); + it('remove all embed attributes', function () { + const a = new Delta().insert(2, { bold: true }); + const b = new Delta().retain(1, { bold: null }); + const expected = new Delta().insert(2); expect(a.compose(b)).toEqual(expected); }); - it('remove all embed attributes', function() { - var a = new Delta().insert(2, { bold: true }); - var b = new Delta().retain(1, { bold: null }); - var expected = new Delta().insert(2); + it('remove all detection attributes (like embeds)', function () { + const a = new Delta().insert('AB', { detectionId: '123' }); + const b = new Delta().retain(1, { detectionId: null }); + const expected = new Delta().insert('AB'); expect(a.compose(b)).toEqual(expected); }); - it('immutability', function() { - var attr1 = { bold: true }; - var attr2 = { bold: true }; - var a1 = new Delta().insert('Test', attr1); - var a2 = new Delta().insert('Test', attr1); - var b1 = new Delta().retain(1, { color: 'red' }).delete(2); - var b2 = new Delta().retain(1, { color: 'red' }).delete(2); - var expected = new Delta() + it('remove all detection attributes (like embeds) 2', function () { + const a = new Delta() + .insert( + { url: 'http://quilljs.com' }, + { + italic: true, + detectionId: '21b9c1e8-d8f9-43ea-8f91-c3890e25a2aa', + }, + ) + .insert('k', { + italic: true, + detectionId: '21b9c1e8-d8f9-43ea-8f91-c3890e25a2aa', + color: 'red', + }); + const b = new Delta().retain(1).retain(1, { detectionId: null }); + const expected = new Delta() + .insert({ url: 'http://quilljs.com' }, { italic: true }) + .insert('k', { + italic: true, + color: 'red', + }); + expect(a.compose(b)).toEqual(expected); + }); + + it('replace detectionId (clear detection)', function () { + const a = new Delta().insert('AB', { detectionId: '123' }); + const b = new Delta().retain(1, { detectionId: '234' }); + const expected = new Delta() + .insert('A', { detectionId: '234' }) + .insert('B'); + expect(a.compose(b)).toEqual(expected); + }); + + it('replace detectionId (clear detection) 2', function () { + const a = new Delta().insert('AB').insert('CD', { detectionId: '123' }); + const b = new Delta().retain(1).retain(3, { detectionId: '234' }); + const expected = new Delta() + .insert('A') + .insert('BCD', { detectionId: '234' }); + expect(a.compose(b)).toEqual(expected); + }); + + it('immutability', function () { + const attr1 = { bold: true }; + const attr2 = { bold: true }; + const a1 = new Delta().insert('Test', attr1); + const a2 = new Delta().insert('Test', attr1); + const b1 = new Delta().retain(1, { color: 'red' }).delete(2); + const b2 = new Delta().retain(1, { color: 'red' }).delete(2); + const expected = new Delta() .insert('T', { color: 'red', bold: true }) .insert('t', attr1); expect(a1.compose(b1)).toEqual(expected); @@ -154,14 +336,14 @@ describe('compose()', function() { expect(attr1).toEqual(attr2); }); - it('retain start optimization', function() { - var a = new Delta() + it('retain start optimization', function () { + const a = new Delta() .insert('A', { bold: true }) .insert('B') .insert('C', { bold: true }) .delete(1); - var b = new Delta().retain(3).insert('D'); - var expected = new Delta() + const b = new Delta().retain(3).insert('D'); + const expected = new Delta() .insert('A', { bold: true }) .insert('B') .insert('C', { bold: true }) @@ -170,15 +352,15 @@ describe('compose()', function() { expect(a.compose(b)).toEqual(expected); }); - it('retain start optimization split', function() { - var a = new Delta() + it('retain start optimization split', function () { + const a = new Delta() .insert('A', { bold: true }) .insert('B') .insert('C', { bold: true }) .retain(5) .delete(1); - var b = new Delta().retain(4).insert('D'); - var expected = new Delta() + const b = new Delta().retain(4).insert('D'); + const expected = new Delta() .insert('A', { bold: true }) .insert('B') .insert('C', { bold: true }) @@ -189,30 +371,2386 @@ describe('compose()', function() { expect(a.compose(b)).toEqual(expected); }); - it('retain end optimization', function() { - var a = new Delta() + it('retain end optimization', function () { + const a = new Delta() .insert('A', { bold: true }) .insert('B') .insert('C', { bold: true }); - var b = new Delta().delete(1); - var expected = new Delta().insert('B').insert('C', { bold: true }); + const b = new Delta().delete(1); + const expected = new Delta().insert('B').insert('C', { bold: true }); expect(a.compose(b)).toEqual(expected); }); - it('retain end optimization join', function() { - var a = new Delta() + it('retain end optimization join', function () { + const a = new Delta() .insert('A', { bold: true }) .insert('B') .insert('C', { bold: true }) .insert('D') .insert('E', { bold: true }) .insert('F'); - var b = new Delta().retain(1).delete(1); - var expected = new Delta() + const b = new Delta().retain(1).delete(1); + const expected = new Delta() .insert('AC', { bold: true }) .insert('D') .insert('E', { bold: true }) .insert('F'); expect(a.compose(b)).toEqual(expected); }); + + it('a', function () { + const list = [ + new Delta([ + { + insert: 'outgrabe', + attributes: { color: 'purple', detectionId: '0' }, + }, + ]), + new Delta([ + { retain: 1 }, + { insert: 'blade' }, + { retain: 5 }, + { + retain: 2, + attributes: { bold: true, italic: null, detectionId: '1' }, + }, + ]), + new Delta([{ retain: 3 }, { delete: 4 }]), + new Delta([ + { retain: 4 }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { font: 'serif', italic: true, detectionId: '2' }, + }, + { retain: 1 }, + { delete: 1 }, + { retain: 3 }, + ]), + new Delta([ + { retain: 1, attributes: { color: 'orange', detectionId: null } }, + ]), + new Delta([{ retain: 3 }, { insert: 'in' }]), + ]; + + const expected = [ + new Delta([]), + new Delta([ + { + insert: 'outgrabe', + attributes: { color: 'purple', detectionId: '0' }, + }, + ]), + new Delta([ + { insert: 'o', attributes: { color: 'purple' } }, + { insert: 'blade' }, + { insert: 'utgra', attributes: { color: 'purple' } }, + { + insert: 'be', + attributes: { bold: true, color: 'purple', detectionId: '1' }, + }, + ]), + new Delta([ + { insert: 'o', attributes: { color: 'purple' } }, + { insert: 'bl' }, + { insert: 'tgra', attributes: { color: 'purple' } }, + { + insert: 'be', + attributes: { bold: true, color: 'purple', detectionId: '1' }, + }, + ]), + new Delta([ + { insert: 'o', attributes: { color: 'purple' } }, + { insert: 'bl' }, + { insert: 't', attributes: { color: 'purple' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { font: 'serif', italic: true, detectionId: '2' }, + }, + { insert: 'ga', attributes: { color: 'purple' } }, + { + insert: 'be', + attributes: { bold: true, color: 'purple', detectionId: '1' }, + }, + ]), + new Delta([ + { insert: 'o', attributes: { color: 'orange' } }, + { insert: 'bl' }, + { insert: 't', attributes: { color: 'purple' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { font: 'serif', italic: true, detectionId: '2' }, + }, + { insert: 'ga', attributes: { color: 'purple' } }, + { + insert: 'be', + attributes: { bold: true, color: 'purple', detectionId: '1' }, + }, + ]), + new Delta([ + { insert: 'o', attributes: { color: 'orange' } }, + { insert: 'blin' }, + { insert: 't', attributes: { color: 'purple' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { font: 'serif', italic: true, detectionId: '2' }, + }, + { insert: 'ga', attributes: { color: 'purple' } }, + { + insert: 'be', + attributes: { bold: true, color: 'purple', detectionId: '1' }, + }, + ]), + ]; + + for (let i = 0; i < expected.length - 1; i++) { + const initialDoc = expected[i]; + const op = list[i]; + const expectedDoc = expected[i + 1]; + expect(initialDoc.compose(op)).toEqual(expectedDoc); + } + }); + + it('inserts take precedence over deletes if there are at the same index', () => { + const thisOp = new Delta([ + { retain: 2, attributes: { color: 'purple', font: null } }, + { + retain: 1, + attributes: { font: 'serif', detectionId: null, color: 'purple' }, + }, + { retain: 1, attributes: { color: 'purple', font: null } }, + { delete: 1 }, + { retain: 1 }, + { + retain: 2, + attributes: { color: 'purple', font: 'serif', italic: null }, + }, + { insert: 'his' }, + { retain: 1 }, + { + attributes: { detectionId: 'c2e6a141-8092-4e65-97ed-3bef0d5eced2' }, + insert: 'took', + }, + { + attributes: { + color: 'purple', + detectionId: '4dd308e1-e022-4806-b071-8152976018c4', + }, + insert: 'that', + }, + ]); + const otherOp = new Delta([ + { retain: 2 }, + { retain: 4, attributes: { bold: null, italic: null } }, + { retain: 2 }, + { delete: 3 }, + { retain: 2 }, + { delete: 4 }, + ]); + thisOp.compose(otherOp); + }); + + it('b', () => { + const ops = [ + new Delta([ + { retain: 3 }, + { retain: 3, attributes: { color: 'green', italic: true } }, + ]), + new Delta([ + { retain: 3 }, + { retain: 4, attributes: { color: 'orange', bold: null } }, + ]), + new Delta([ + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { retain: 5 }, + { insert: 'the', attributes: { italic: true, detectionId: '7' } }, + ]), + new Delta([ + { insert: 'it', attributes: { font: 'serif', detectionId: '8' } }, + ]), + new Delta([ + { retain: 1 }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'blue', detectionId: '9' }, + }, + ]), + ]; + const expected = [ + new Delta([ + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { italic: true, color: 'yellow', detectionId: '6' }, + }, + { insert: 'thrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { color: 'green', italic: true, detectionId: '6' }, + }, + { insert: 'th', attributes: { color: 'green', italic: true } }, + { insert: 'rtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { color: 'orange', italic: true, detectionId: '6' }, + }, + { insert: 'th', attributes: { color: 'orange', italic: true } }, + { insert: 'r', attributes: { color: 'orange' } }, + { insert: 'theough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { color: 'orange', italic: true, detectionId: '6' }, + }, + { insert: 't', attributes: { color: 'orange', italic: true } }, + { insert: 'the', attributes: { italic: true, detectionId: '7' } }, + { insert: 'h', attributes: { color: 'orange', italic: true } }, + { insert: 'r', attributes: { color: 'orange' } }, + { insert: 'theough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'it', attributes: { font: 'serif', detectionId: '8' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { color: 'orange', italic: true, detectionId: '6' }, + }, + { insert: 't', attributes: { color: 'orange', italic: true } }, + { insert: 'the', attributes: { italic: true, detectionId: '7' } }, + { insert: 'h', attributes: { color: 'orange', italic: true } }, + { insert: 'r', attributes: { color: 'orange' } }, + { insert: 'theough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'i', attributes: { font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'blue', detectionId: '9' }, + }, + { insert: 't', attributes: { font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { color: 'orange', italic: true, detectionId: '6' }, + }, + { insert: 't', attributes: { color: 'orange', italic: true } }, + { insert: 'the', attributes: { italic: true, detectionId: '7' } }, + { insert: 'h', attributes: { color: 'orange', italic: true } }, + { insert: 'r', attributes: { color: 'orange' } }, + { insert: 'theough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + ]; + for (let i = 0; i < expected.length - 1; i++) { + const initialDoc = expected[i]; + const op = ops[i]; + const expectedDoc = expected[i + 1]; + expect(initialDoc.compose(op)).toEqual(expectedDoc); + } + }); + + it('c', () => { + const ops = [ + new Delta([ + { retain: 3 }, + { insert: 'toves', attributes: { color: 'purple' } }, + ]), + new Delta([ + { retain: 1 }, + { + insert: 'He', + attributes: { font: 'sans-serif', italic: true, detectionId: '6' }, + }, + ]), + new Delta([ + { retain: 3 }, + { retain: 1, attributes: { bold: true, detectionId: '7' } }, + ]), + new Delta([ + { retain: 1 }, + { + retain: 1, + attributes: { color: 'red', font: null, bold: null }, + }, + { retain: 3 }, + { retain: 2, attributes: { bold: null } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { retain: 3 }, + { retain: 2, attributes: { bold: true, italic: null } }, + { insert: 'snack' }, + ]), + new Delta([{ retain: 5 }, { insert: 'wood' }]), + ]; + const expected = [ + new Delta([ + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { italic: true, color: 'yellow', detectionId: '6' }, + }, + { insert: 'thrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + }, + }, + { insert: 'toves', attributes: { color: 'purple' } }, + { + insert: 'x', + attributes: { italic: true, color: 'yellow' }, + }, + { insert: 'thrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'He', + attributes: { font: 'sans-serif', italic: true, detectionId: '6' }, + }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + }, + }, + { insert: 'toves', attributes: { color: 'purple' } }, + { + insert: 'x', + attributes: { italic: true, color: 'yellow' }, + }, + { insert: 'thrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'He', + attributes: { font: 'sans-serif', italic: true, detectionId: '6' }, + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: '7', + }, + }, + { + insert: 'n', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + }, + }, + { insert: 'toves', attributes: { color: 'purple' } }, + { + insert: 'x', + attributes: { italic: true, color: 'yellow' }, + }, + { insert: 'thrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { italic: true, detectionId: '6', color: 'red' }, + }, + { + insert: 'e', + attributes: { font: 'sans-serif', italic: true, detectionId: '6' }, + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: '7', + }, + }, + { + insert: 'n', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + }, + }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { + insert: 'x', + attributes: { color: 'yellow', bold: true }, + }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { italic: true, detectionId: '6', color: 'red' }, + }, + { + insert: 'e', + attributes: { font: 'sans-serif', italic: true, detectionId: '6' }, + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: '7', + }, + }, + { + insert: 'n', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + }, + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { + insert: 'x', + attributes: { color: 'yellow', bold: true }, + }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]), + ]; + + for (let i = 0; i < expected.length - 1; i++) { + const initialDoc = expected[i]; + const op = ops[i]; + const expectedDoc = expected[i + 1]; + expect(initialDoc.compose(op)).toEqual(expectedDoc); + } + }); + + it('e', () => { + const initialDoc = new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6', + color: 'red', + }, + }, + { + insert: 'e', + attributes: { + font: 'sans-serif', + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6', + }, + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: 'ee1c76bc-ecda-4fa3-8166-6cf5aac85104', + }, + }, + { + insert: 'n', + attributes: { italic: true, font: 'monospace', color: 'yellow' }, + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + const ops = [ + new Delta([ + { retain: 3 }, + { + insert: 2, + attributes: { + font: 'sans-serif', + italic: true, + detectionId: 'a33725f5-8c7d-42fc-9eef-5bc4f55b1dfa', + }, + }, + ]), + new Delta([ + { retain: 3 }, + { + insert: 1, + attributes: { + color: 'green', + bold: true, + italic: true, + detectionId: 'c7fb3482-3235-40e1-9cda-9e80877cc020', + }, + }, + ]), + new Delta([ + { retain: 3 }, + { insert: 'Jubjub' }, + { retain: 3 }, + { delete: 1 }, + ]), + new Delta([ + { retain: 5 }, + { insert: 'dead' }, + { retain: 5 }, + { insert: 'rested' }, + ]), + new Delta([{ retain: 5 }, { delete: 1 }]), + ]; + + const finalDoc = new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6', + color: 'red', + }, + }, + { + insert: 'e', + attributes: { + font: 'sans-serif', + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6', + }, + }, + { insert: 'Jueadbjub' }, + { + insert: 1, + attributes: { + color: 'green', + bold: true, + italic: true, + detectionId: 'c7fb3482-3235-40e1-9cda-9e80877cc020', + }, + }, + { insert: 'rested' }, + { + insert: 2, + attributes: { + font: 'sans-serif', + italic: true, + detectionId: 'a33725f5-8c7d-42fc-9eef-5bc4f55b1dfa', + }, + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: 'ee1c76bc-ecda-4fa3-8166-6cf5aac85104', + }, + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + let s = initialDoc; + ops.forEach((op) => { + s = new Delta(s).compose(new Delta(op)); + }); + expect(s).toEqual(finalDoc); + }); + + it('asdasdasd', () => { + const doc = new Delta([ + { insert: 'rmi' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow', font: 'sans-serif' }, + }, + { insert: 'ms' }, + { + insert: 'y', + attributes: { + font: 'serif', + italic: true, + detectionId: '977848c0-defb-437b-ae7d-9f60e0c93aa0', + }, + }, + { + insert: 'o', + attributes: { + font: 'serif', + italic: true, + detectionId: '977848c0-defb-437b-ae7d-9f60e0c93aa0', + color: 'red', + }, + }, + { insert: 'ug', attributes: { color: 'red', italic: true } }, + { insert: 'h' }, + { insert: 2, attributes: { bold: true } }, + { insert: 'e' }, + { insert: 'ab', attributes: { color: 'green' } }, + { insert: 'thoue' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + const ops = [ + new Delta([ + { + insert: 'Jabberwock', + attributes: { color: 'red', font: 'serif', italic: true }, + }, + { delete: 4 }, + { retain: 5 }, + { + retain: 1, + attributes: { + color: 'yellow', + bold: true, + detectionId: '0b2ecb5a-a7c7-4b16-855a-fda3a9e66d3b', + }, + }, + { delete: 1 }, + ]), + new Delta([ + { retain: 3 }, + { + insert: 2, + attributes: { font: 'serif', bold: true, italic: true }, + }, + ]), + new Delta([ + { insert: 'in', attributes: { bold: true } }, + { retain: 4 }, + { delete: 1 }, + ]), + new Delta([ + { retain: 2 }, + { insert: 2, attributes: { color: 'purple' } }, + ]), + new Delta([ + { retain: 2 }, + { + retain: 3, + attributes: { + color: null, + detectionId: 'a5294df6-b261-4455-86a1-e7a01f78c584', + }, + }, + { retain: 4 }, + { + retain: 2, + attributes: { + color: 'blue', + detectionId: '1c5a9144-8610-4f86-a419-fb2ac04572cb', + }, + }, + { + retain: 4, + attributes: { + bold: true, + detectionId: '210ea74d-f4f9-443b-8c5b-af89ea1615c9', + }, + }, + { retain: 4 }, + { insert: 'the' }, + ]), + ]; + + const res = new Delta([ + { insert: 'in', attributes: { bold: true } }, + { + insert: 2, + attributes: { detectionId: 'a5294df6-b261-4455-86a1-e7a01f78c584' }, + }, + { + insert: 'Ja', + attributes: { + font: 'serif', + italic: true, + detectionId: 'a5294df6-b261-4455-86a1-e7a01f78c584', + }, + }, + { + insert: 'b', + attributes: { color: 'red', font: 'serif', italic: true }, + }, + { + insert: 2, + attributes: { font: 'serif', bold: true, italic: true }, + }, + { + insert: 'er', + attributes: { color: 'red', font: 'serif', italic: true }, + }, + { + insert: 'wo', + attributes: { + color: 'blue', + font: 'serif', + italic: true, + detectionId: '1c5a9144-8610-4f86-a419-fb2ac04572cb', + }, + }, + { + insert: 'ck', + attributes: { + color: 'red', + font: 'serif', + italic: true, + bold: true, + detectionId: '210ea74d-f4f9-443b-8c5b-af89ea1615c9', + }, + }, + { + insert: 'ms', + attributes: { + bold: true, + detectionId: '210ea74d-f4f9-443b-8c5b-af89ea1615c9', + }, + }, + { + insert: 'y', + attributes: { + font: 'serif', + italic: true, + detectionId: '977848c0-defb-437b-ae7d-9f60e0c93aa0', + }, + }, + { + insert: 'o', + attributes: { + font: 'serif', + italic: true, + detectionId: '977848c0-defb-437b-ae7d-9f60e0c93aa0', + color: 'red', + }, + }, + { insert: 'u', attributes: { color: 'red', italic: true } }, + { + insert: 'g', + attributes: { + color: 'yellow', + italic: true, + bold: true, + detectionId: '0b2ecb5a-a7c7-4b16-855a-fda3a9e66d3b', + }, + }, + { insert: 'the' }, + { insert: 2, attributes: { bold: true } }, + { insert: 'e' }, + { insert: 'ab', attributes: { color: 'green' } }, + { insert: 'thoue' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + const composed = ops.reduce((acc, op) => acc.compose(op)); + expect(doc.compose(composed)).toEqual(res); + }); + + it('f', () => { + const doc = new Delta([ + { insert: 'and' }, + { + insert: 2, + attributes: { color: 'red', font: 'serif', italic: true }, + }, + { + insert: 1, + attributes: { + color: 'red', + font: 'monospace', + detectionId: 'a5496ec4-8e5c-4da6-a0a9-2ff2ce55de1f', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow', font: 'sans-serif' }, + }, + { insert: 'awhile' }, + { insert: 'gyre', attributes: { bold: true, italic: true } }, + { insert: 'w' }, + { insert: 2, attributes: { font: 'sans-serif', italic: true } }, + { insert: 'u', attributes: { italic: true } }, + { insert: 'ff' }, + { insert: 'ish', attributes: { italic: true } }, + { insert: 'h' }, + { insert: 'i', attributes: { color: 'green', italic: true } }, + { insert: 'ffl' }, + { + insert: 'ng', + attributes: { + bold: true, + detectionId: '50bd9de5-de2e-4c12-9ce8-e5d154c56156', + }, + }, + { insert: 'm', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'So' }, + { insert: 'y', attributes: { font: 'serif', italic: true } }, + { + insert: 2, + attributes: { + color: 'purple', + font: 'monospace', + detectionId: '0e8c5efc-d4be-4514-843e-c5515e126f4a', + }, + }, + { + insert: 'o', + attributes: { font: 'serif', italic: true, color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', color: 'orange' }, + }, + { insert: 'y', attributes: { italic: true, color: 'orange' } }, + { insert: 're', attributes: { italic: true } }, + { insert: 'h', attributes: { bold: true } }, + { insert: 2, attributes: { bold: true } }, + { insert: 'houe' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + const ops = [ + new Delta([ + { retain: 4 }, + { delete: 2 }, + { retain: 5 }, + { insert: 'wabe' }, + { retain: 3 }, + { delete: 3 }, + ]), + new Delta([ + { retain: 1 }, + { delete: 1 }, + { retain: 4 }, + { delete: 2 }, + { retain: 4 }, + { + retain: 1, + attributes: { detectionId: 'aebfa4cc-d65c-4050-846e-a26518764f4f' }, + }, + { delete: 1 }, + { retain: 4 }, + { delete: 1 }, + { retain: 3 }, + { delete: 2 }, + ]), + new Delta([ + { retain: 5 }, + { delete: 3 }, + { retain: 2 }, + { insert: 'Long' }, + { retain: 2 }, + { + retain: 4, + attributes: { + font: null, + italic: null, + detectionId: '777afdc4-8446-4c60-a59e-2e6a751097ce', + }, + }, + { retain: 2 }, + { delete: 2 }, + { retain: 1 }, + { + retain: 2, + attributes: { + color: 'green', + font: 'monospace', + bold: null, + italic: null, + }, + }, + ]), + new Delta([ + { retain: 1 }, + { delete: 4 }, + { retain: 1 }, + { + insert: 'day', + attributes: { color: 'yellow', font: 'sans-serif' }, + }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { font: 'sans-serif', italic: true }, + }, + ]), + new Delta([{ retain: 1 }, { retain: 4, attributes: { font: 'serif' } }]), + ]; + + const res = new Delta([ + { insert: 'a' }, + { insert: 'b', attributes: { font: 'serif' } }, + { insert: 'day', attributes: { color: 'yellow', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { font: 'sans-serif', italic: true }, + }, + { + insert: 'e', + attributes: { detectionId: 'aebfa4cc-d65c-4050-846e-a26518764f4f' }, + }, + { insert: 'Long' }, + { insert: 'gy', attributes: { bold: true, italic: true } }, + { + insert: 2, + attributes: { detectionId: '777afdc4-8446-4c60-a59e-2e6a751097ce' }, + }, + { + insert: 'ufi', + attributes: { detectionId: '777afdc4-8446-4c60-a59e-2e6a751097ce' }, + }, + { insert: 's', attributes: { italic: true } }, + { insert: 'i', attributes: { color: 'green', italic: true } }, + { insert: 'l' }, + { + insert: 'ng', + attributes: { + detectionId: '50bd9de5-de2e-4c12-9ce8-e5d154c56156', + color: 'green', + font: 'monospace', + }, + }, + { insert: 'm', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'So' }, + { insert: 'y', attributes: { font: 'serif', italic: true } }, + { + insert: 2, + attributes: { + color: 'purple', + font: 'monospace', + detectionId: '0e8c5efc-d4be-4514-843e-c5515e126f4a', + }, + }, + { + insert: 'o', + attributes: { font: 'serif', italic: true, color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', color: 'orange' }, + }, + { insert: 'y', attributes: { italic: true, color: 'orange' } }, + { insert: 're', attributes: { italic: true } }, + { insert: 'h', attributes: { bold: true } }, + { insert: 2, attributes: { bold: true } }, + { insert: 'houe' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + const composed = ops.reduce((acc, op) => acc.compose(op)); + + expect(doc.compose(composed)).toEqual(res); + }); + + it('g', () => { + const doc = new Delta([ + { + insert: 1, + attributes: { + bold: true, + detectionId: '4fff9e92-e14f-4cfe-8e9a-6f0e0c1eb9f9', + }, + }, + { + insert: 2, + attributes: { color: 'green', font: 'sans-serif', italic: true }, + }, + { + insert: 'e', + attributes: { detectionId: '1548ffc2-299d-4727-b47f-bf77f5d3e0a1' }, + }, + { + insert: 'T', + attributes: { italic: true, color: 'blue', font: 'serif' }, + }, + { insert: 'ra' }, + { insert: 't', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'ca', attributes: { color: 'blue' } }, + { insert: 'he', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'sh', attributes: { italic: true } }, + { insert: 'h' }, + { insert: 'i', attributes: { color: 'green', italic: true } }, + { insert: 'ffl' }, + { + insert: 'ng', + attributes: { + bold: true, + detectionId: '50bd9de5-de2e-4c12-9ce8-e5d154c56156', + }, + }, + { insert: 'm', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'So' }, + { insert: 'y', attributes: { font: 'serif', italic: true } }, + { + insert: 2, + attributes: { + color: 'purple', + font: 'monospace', + detectionId: '0e8c5efc-d4be-4514-843e-c5515e126f4a', + }, + }, + { + insert: 'o', + attributes: { font: 'serif', italic: true, color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', color: 'orange' }, + }, + { insert: 'y', attributes: { italic: true, color: 'orange' } }, + { insert: 're', attributes: { italic: true } }, + { insert: 'h', attributes: { bold: true } }, + { insert: 2, attributes: { bold: true } }, + { insert: 'houe' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + const res = new Delta([ + { + insert: 1, + attributes: { + bold: true, + detectionId: '4fff9e92-e14f-4cfe-8e9a-6f0e0c1eb9f9', + }, + }, + { + insert: 2, + attributes: { color: 'green', font: 'sans-serif', italic: true }, + }, + { + insert: 'e', + attributes: { detectionId: '1548ffc2-299d-4727-b47f-bf77f5d3e0a1' }, + }, + { insert: 'h', attributes: { color: 'yellow' } }, + { insert: 'The' }, + { insert: 'i', attributes: { color: 'yellow' } }, + { + insert: 'st', + attributes: { + font: 'sans-serif', + bold: true, + color: 'blue', + italic: true, + detectionId: 'e8df1807-830b-435e-812a-5510d870488d', + }, + }, + { insert: 'c', attributes: { color: 'blue' } }, + { insert: 'borogoves', attributes: { italic: true } }, + { insert: 'iandts' }, + { insert: 'a', attributes: { color: 'blue' } }, + { insert: 'he', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'i', attributes: { color: 'green', italic: true } }, + { insert: 'f' }, + { + insert: 'fl', + attributes: { + color: 'orange', + detectionId: '5823be0b-20b1-42c2-bde4-5447595cfe1e', + }, + }, + { + insert: 'n', + attributes: { + bold: true, + detectionId: '5823be0b-20b1-42c2-bde4-5447595cfe1e', + color: 'orange', + }, + }, + { insert: 'g', attributes: { bold: true } }, + { insert: 'm', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'So' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { + font: 'monospace', + detectionId: '063c0801-19e3-4b08-acab-245510f766ab', + }, + }, + { insert: 'y', attributes: { font: 'serif', italic: true } }, + { + insert: 2, + attributes: { + color: 'purple', + font: 'monospace', + detectionId: '0e8c5efc-d4be-4514-843e-c5515e126f4a', + }, + }, + { + insert: 'o', + attributes: { font: 'serif', italic: true, color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'orange' }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', color: 'orange' }, + }, + { insert: 'y', attributes: { italic: true, color: 'orange' } }, + { insert: 're', attributes: { italic: true } }, + { insert: 'h', attributes: { bold: true } }, + { insert: 2, attributes: { bold: true } }, + { insert: 'houe' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + const ops = [ + new Delta([ + { retain: 3 }, + { insert: 'his', attributes: { color: 'yellow' } }, + { delete: 3 }, + { retain: 2 }, + { insert: 'its' }, + ]), + new Delta([ + { retain: 5 }, + { + retain: 2, + attributes: { + color: 'blue', + font: 'sans-serif', + bold: true, + italic: true, + detectionId: 'e8df1807-830b-435e-812a-5510d870488d', + }, + }, + { retain: 1 }, + { insert: 'borogoves', attributes: { italic: true } }, + { retain: 1 }, + { insert: 'and' }, + { retain: 5 }, + { delete: 3 }, + { retain: 2 }, + { + retain: 3, + attributes: { + color: 'orange', + detectionId: '5823be0b-20b1-42c2-bde4-5447595cfe1e', + }, + }, + { retain: 4 }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { + font: 'monospace', + detectionId: '063c0801-19e3-4b08-acab-245510f766ab', + }, + }, + ]), + new Delta([{ retain: 4 }, { insert: 'The' }]), + ]; + + const composed = ops.reduce((acc, op) => acc.compose(op)); + expect(doc.compose(composed)).toEqual(res); + }); + + xit('1', () => { + const doc = new Delta([ + { insert: 'm' }, + { + attributes: { color: 'red', italic: true, detectionId: '0' }, + insert: 'H', + }, + { + attributes: { font: 'sans-serif', italic: true, detectionId: '0' }, + insert: 'e', + }, + { + attributes: { + bold: true, + detectionId: '1', + italic: true, + font: 'monospace', + color: 'yellow', + }, + insert: 'a', + }, + { + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + insert: 'n', + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { attributes: { color: 'purple', font: 'serif' }, insert: 2 }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { + insert: 'x', + attributes: { bold: true, color: 'yellow', detectionId: '6' }, + }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]); + + const op1 = new Delta([ + { retain: 3 }, + { insert: 'toves', attributes: { color: 'purple' } }, + ]); + + const op2 = new Delta([ + { retain: 1 }, + { + insert: 'He', + attributes: { font: 'sans-serif', italic: true, detectionId: '0' }, + }, + ]); + + const op3 = new Delta([ + { retain: 3 }, + { retain: 1, attributes: { bold: true, detectionId: '1' } }, + ]); + + const op4 = new Delta([ + { retain: 1 }, + { retain: 1, attributes: { color: 'red', font: null, bold: null } }, + { retain: 3 }, + { retain: 2, attributes: { bold: null } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { retain: 3 }, + { retain: 2, attributes: { bold: true, italic: null } }, + { insert: 'snack' }, + ]); + + const op5 = new Delta([{ retain: 5 }, { insert: 'wood' }]); + + const expected = new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { italic: true, detectionId: '0', color: 'red' }, + }, + { + insert: 'e', + attributes: { font: 'sans-serif', italic: true, detectionId: '0' }, + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: '1', + }, + }, + { + insert: 'n', + attributes: { italic: true, font: 'monospace', color: 'yellow' }, + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]); + + expect( + doc.compose(op1).compose(op2).compose(op3).compose(op4).compose(op5), + ).toEqual(expected); + }); + + xit('2', () => { + const doc = new Delta([ + { insert: 'i', attributes: { font: 'serif' } }, + { + attributes: { color: 'blue', detectionId: '2' }, + insert: { url: 'http://quilljs.com' }, + }, + { insert: 't', attributes: { font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { color: 'orange', italic: true, detectionId: '6' }, + }, + { insert: 't', attributes: { color: 'orange', italic: true } }, + { attributes: { italic: true, detectionId: '0' }, insert: 'the' }, + { insert: 'h', attributes: { color: 'orange', italic: true } }, + { insert: 'r', attributes: { color: 'orange' } }, + { insert: 'theough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]); + + const list = [ + new Delta([ + { retain: 3 }, + { retain: 3, attributes: { color: 'green', italic: true } }, + ]), + new Delta([ + { retain: 3 }, + { retain: 4, attributes: { color: 'orange', bold: null } }, + ]), + new Delta([ + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { retain: 5 }, + { insert: 'the', attributes: { italic: true, detectionId: '0' } }, + ]), + new Delta([ + { insert: 'it', attributes: { font: 'serif', detectionId: '1' } }, + ]), + new Delta([ + { retain: 1 }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'blue', detectionId: '2' }, + }, + ]), + ]; + + const expected = new Delta([ + { insert: 'i', attributes: { font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'blue', detectionId: '2' }, + }, + { insert: 't', attributes: { font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'yellow', italic: true }, + }, + { insert: 'm' }, + { + insert: 'an', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + detectionId: '6', + }, + }, + { + insert: 'x', + attributes: { italic: true, color: 'orange', detectionId: '6' }, + }, + { insert: 't', attributes: { color: 'orange', italic: true } }, + { insert: 'the', attributes: { italic: true, detectionId: '0' } }, + { insert: 'h', attributes: { color: 'orange', italic: true } }, + { insert: 'r', attributes: { color: 'orange' } }, + { insert: 'theough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: '5', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { insert: 'Cal', attributes: { bold: true } }, + { insert: 'looh' }, + ]); + + let s = doc; + list.forEach((delta) => { + s = s.compose(delta); + }); + expect(s).toEqual(expected); + }); }); diff --git a/test/delta/diff.js b/test/delta/diff.js index 0ebf7cb..a6cb35f 100644 --- a/test/delta/diff.js +++ b/test/delta/diff.js @@ -157,4 +157,174 @@ describe('diff()', function() { a.diff(b); }).toThrow(new Error('diff() called on non-document')); }); + + it('asdasd', function() { + const initialDoc = new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6', + color: 'red' + } + }, + { + insert: 'e', + attributes: { + font: 'sans-serif', + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6' + } + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: 'ee1c76bc-ecda-4fa3-8166-6cf5aac85104' + } + }, + { + insert: 'n', + attributes: { italic: true, font: 'monospace', color: 'yellow' } + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' } + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0' + } + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' } + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true } + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181' + } + }, + { insert: 'looh' } + ]) + + const resultDoc = new Delta([ + { insert: 'm' }, + { + insert: 'H', + attributes: { + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6', + color: 'red' + } + }, + { + insert: 'e', + attributes: { + font: 'sans-serif', + italic: true, + detectionId: '609abe0d-8f37-4d7d-813a-a7b35ef60cc6' + } + }, + { insert: 'Jueadbjub' }, + { + insert: 1, + attributes: { + color: 'green', + bold: true, + italic: true, + detectionId: '03832101-1a22-4751-920d-713e188de4c8' + } + }, + { insert: 'rested' }, + { + insert: 2, + attributes: { + font: 'sans-serif', + italic: true, + detectionId: '97976429-abe8-4699-af34-84e1d258c46e' + } + }, + { + insert: 'a', + attributes: { + italic: true, + font: 'monospace', + color: 'yellow', + bold: true, + detectionId: 'ee1c76bc-ecda-4fa3-8166-6cf5aac85104' + } + }, + { insert: 'wood' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'purple', font: 'serif' } }, + { insert: { url: 'http://quilljs.com' } }, + { insert: 'ves', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' } + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0' + } + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' } + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true } + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181' + } + }, + { insert: 'looh' } + ]) + + const diff = initialDoc.diff(resultDoc) + const actual = initialDoc.compose(diff) + }) }); diff --git a/test/delta/transform-detections.js b/test/delta/transform-detections.js new file mode 100644 index 0000000..79b52e0 --- /dev/null +++ b/test/delta/transform-detections.js @@ -0,0 +1,697 @@ +/* eslint-disable @typescript-eslint/camelcase */ +const Delta = require('../../dist/Delta'); + +/** + * NOTE: Assumes compose() works as intended... + * - when adding a new detection, it "removed" any overlapping detections first + * - gets rid of any partially deleted detectionIds (either through "null" or "delete") + * - get rid of any detections that have been split by an insert + */ + +function transformX(left, right) { + return [right.transform(left, true), left.transform(right, false)]; +} + +describe('validated detections', function () { + describe('insert inside of detection retain', function () { + const a = new Delta().retain(1).insert('X'); + const b = new Delta().retain(2, { detectionId: '123' }); + const a_ = new Delta().retain(1).insert('X'); // original + // var b_ = new Delta().retain(1, { detectionId: '123' }).retain(1).retain(1, { detectionId: '123' }); // original + // var b_ = new Delta().retain(3); // modified - we dont need to specifcally "null" anything + const b_ = new Delta(); // chop + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_); + expect(b.transform(a, true)).toEqual(a_); + expect(a.transform(b, false)).toEqual(b_); + expect(b.transform(a, false)).toEqual(a_); + }); + + it('compose + transform', function () { + const doc = new Delta().insert('ABC'); + const final = new Delta().insert('AXBC'); + expect(doc.compose(a).compose(b_, true)).toEqual(final); + expect(doc.compose(b).compose(a_, false)).toEqual(final); + expect(doc.compose(a).compose(b_, false)).toEqual(final); + expect(doc.compose(b).compose(a_, true)).toEqual(final); + }); + }); + + describe('det insert & delete [not modified]', function () { + const a = new Delta().insert('X', { detectionId: '123' }); + const b = new Delta().delete(1); + const a_ = new Delta().insert('X', { detectionId: '123' }); + const b_ = new Delta().retain(1).delete(1); + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_); + expect(b.transform(a, true)).toEqual(a_); + expect(a.transform(b, false)).toEqual(b_); + expect(b.transform(a, false)).toEqual(a_); + }); + + it('compose + transform', function () { + const doc = new Delta().insert('ABC', { detectionId: '234' }); + const final = new Delta() + .insert('X', { detectionId: '123' }) + .insert('BC'); + expect(doc.compose(a).compose(b_, true)).toEqual(final); + expect(doc.compose(b).compose(a_, false)).toEqual(final); + expect(doc.compose(a).compose(b_, false)).toEqual(final); + expect(doc.compose(b).compose(a_, true)).toEqual(final); + }); + }); + + describe('det retain & delete', function () { + const a = new Delta().retain(2, { detectionId: '123' }); + const b = new Delta().delete(1); + // var a_ = new Delta().retain(1, { detectionId: '123' }); // original + // var a_ = new Delta().retain(1); // modified + const a_ = new Delta(); // chop + const b_ = new Delta().delete(1); // same as original + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_); + expect(b.transform(a, true)).toEqual(a_); + expect(a.transform(b, false)).toEqual(b_); + expect(b.transform(a, false)).toEqual(a_); + }); + + it('compose + transform', function () { + const doc = new Delta().insert('ABC'); + const final = new Delta().insert('BC'); + expect(doc.compose(a).compose(b_, true)).toEqual(final); + expect(doc.compose(b).compose(a_, false)).toEqual(final); + expect(doc.compose(a).compose(b_, false)).toEqual(final); + expect(doc.compose(b).compose(a_, true)).toEqual(final); + }); + }); + + describe('detection retain & detection retain (always ignore one of them)', function () { + const a = new Delta().retain(2).retain(2, { detectionId: '123' }); + const b = new Delta().retain(3, { detectionId: '234' }); + + const a_a = new Delta().retain(2).retain(2, { detectionId: '123' }); + // var a_b = new Delta().retain(3).retain(1, { detectionId: '123' }); // original + // var a_b = new Delta().retain(3).retain(1); // modified + const a_b = new Delta(); // chop + + const b_b = new Delta().retain(3, { detectionId: '234' }); + // var b_a = new Delta().retain(2, { detectionId: '234' }); // original + // var b_a = new Delta().retain(2); // modified + const b_a = new Delta(); // chop + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_a); + expect(b.transform(a, true)).toEqual(a_b); + expect(a.transform(b, false)).toEqual(b_b); + expect(b.transform(a, false)).toEqual(a_a); + }); + + it('compose + transform with A priority', function () { + const doc = new Delta().insert('ABCD'); + const final = new Delta() + .insert('AB') + .insert('CD', { detectionId: '123' }); + expect(doc.compose(a).compose(b_a)).toEqual(final); + expect(doc.compose(b).compose(a_a)).toEqual(final); + }); + + it('compose + transform with B Priority', function () { + const doc = new Delta().insert('ABCD'); + const final = new Delta() + .insert('ABC', { detectionId: '234' }) + .insert('D'); + expect(doc.compose(a).compose(b_b)).toEqual(final); + expect(doc.compose(b).compose(a_b)).toEqual(final); + }); + }); + + describe('detection null + retain detection', function () { + const a = new Delta().retain(3, { detectionId: null }); + const b = new Delta().retain(1).retain(4, { detectionId: '123' }); + + const a_a = new Delta().retain(3, { detectionId: null }); + const a_b = new Delta().retain(1, { detectionId: null }); + + const b_b = new Delta().retain(1).retain(4, { detectionId: '123' }); + // var b_a = new Delta().retain(3).retain(1, { detectionId: '123' }); // original + // var b_a = new Delta().retain(3).retain(1); // modified + const b_a = new Delta(); // chop + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_a); + expect(b.transform(a, true)).toEqual(a_b); + expect(a.transform(b, false)).toEqual(b_b); + expect(b.transform(a, false)).toEqual(a_a); + }); + + it('compose + transform with A priority', function () { + const doc = new Delta() + .insert('ABC', { detectionId: '234' }) + .insert('DE'); + const final = new Delta().insert('ABCDE'); + expect(doc.compose(a).compose(b_a)).toEqual(final); + expect(doc.compose(b).compose(a_a)).toEqual(final); + }); + + it('compose + transform with B Priority', function () { + const doc = new Delta() + .insert('ABC', { detectionId: '234' }) + .insert('DE'); + const final = new Delta() + .insert('A') + .insert('BCDE', { detectionId: '123' }); + expect(doc.compose(a).compose(b_b)).toEqual(final); + expect(doc.compose(b).compose(a_b)).toEqual(final); + }); + }); + + describe('detection null + delete [not modified]', function () { + const a = new Delta().retain(3, { detectionId: null }); + const b = new Delta().delete(1); + + const a_ = new Delta().retain(2, { detectionId: null }); + const b_ = new Delta().delete(1); + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_); + expect(b.transform(a, true)).toEqual(a_); + expect(a.transform(b, false)).toEqual(b_); + expect(b.transform(a, false)).toEqual(a_); + }); + + it('compose + transform', function () { + const doc = new Delta().insert('ABC', { detectionId: '123' }); + const final = new Delta().insert('BC'); + expect(doc.compose(a).compose(b_, true)).toEqual(final); + expect(doc.compose(b).compose(a_, false)).toEqual(final); + expect(doc.compose(a).compose(b_, false)).toEqual(final); + expect(doc.compose(b).compose(a_, true)).toEqual(final); + }); + }); + + describe('detection null + insert [not modified]', function () { + const a = new Delta().retain(3, { detectionId: null }); + const b = new Delta().insert('X'); + + const a_ = new Delta().retain(1).retain(3, { detectionId: null }); + const b_ = new Delta().insert('X'); + + it('transforms', function () { + expect(a.transform(b, true)).toEqual(b_); + expect(b.transform(a, true)).toEqual(a_); + expect(a.transform(b, false)).toEqual(b_); + expect(b.transform(a, false)).toEqual(a_); + }); + + it('compose + transform', function () { + const doc = new Delta().insert('ABC', { detectionId: '123' }); + const final = new Delta().insert('XABC'); + expect(doc.compose(a).compose(b_, true)).toEqual(final); + expect(doc.compose(b).compose(a_, false)).toEqual(final); + expect(doc.compose(a).compose(b_, false)).toEqual(final); + expect(doc.compose(b).compose(a_, true)).toEqual(final); + }); + }); + + describe('retain + retain & delete (need to null)', function () { + const a = new Delta() + .retain(1, { detectionId: '123' }) + .delete(1) + .retain(1, { detectionId: '123' }); + const b = new Delta().retain(4, { detectionId: '234' }); + + const a_a = new Delta() + .retain(1, { detectionId: '123' }) + .delete(1) + .retain(1, { detectionId: '123' }); + const a_b = new Delta().retain(1).delete(1); + + // var b_b = new Delta().retain(4, { detectionId: '234' }); // original + // var b_b = new Delta().retain(2, { detectionId: null }).retain(2); // modified + const b_b = new Delta().retain(2, { detectionId: null }); // chop + const b_a = new Delta(); + + it('transforms', function () { + // expect(a.transform(b, true)).toEqual(b_a); + // expect(b.transform(a, true)).toEqual(a_b); + expect(a.transform(b, false)).toEqual(b_b); + // expect(b.transform(a, false)).toEqual(a_a); + }); + + it('compose + transform with A priority', function () { + const doc = new Delta().insert('ABCDE'); + const final = new Delta() + .insert('AC', { detectionId: '123' }) + .insert('DE'); + expect(doc.compose(a).compose(b_a)).toEqual(final); + expect(doc.compose(b).compose(a_a)).toEqual(final); + }); + + it('compose + transform with B Priority', function () { + const doc = new Delta().insert('ABCDE'); + const final = new Delta().insert('ACDE'); + expect(doc.compose(a).compose(b_b)).toEqual(final); + expect(doc.compose(b).compose(a_b)).toEqual(final); + }); + }); + + it('sdasd', function () { + const sop = new Delta([ + { insert: 'He' }, + { retain: 3 }, + { attributes: { italic: true }, insert: 1 }, + { retain: 2 }, + { delete: 3 }, + { + retain: 2, + attributes: { color: 'purple', bold: null, italic: true }, + }, + ]); + + const cop = new Delta([ + { retain: 1, attributes: { italic: null, detectionId: null } }, + { + retain: 3, + attributes: { + color: 'yellow', + bold: null, + italic: true, + detectionId: '6', + }, + }, + { insert: 'thrtheough' }, + ]); + + expect(cop.transform(sop)).toEqual( + new Delta([ + { insert: 'He' }, + { retain: 3 }, + { attributes: { italic: true }, insert: 1 }, + { retain: 12 }, + { delete: 3 }, + { + retain: 2, + attributes: { color: 'purple', bold: null, italic: true }, + }, + ]), + ); + expect(sop.transform(cop)).toEqual( + new Delta([ + { retain: 2 }, + { attributes: { italic: null, detectionId: null }, retain: 1 }, + { + retain: 2, + attributes: { color: 'yellow', bold: null, italic: true }, + }, + { retain: 1 }, + { + retain: 1, + attributes: { color: 'yellow', bold: null, italic: true }, + }, + { insert: 'thrtheough' }, + ]), + ); + }); + + it('a', function () { + const original = new Delta([ + { + insert: 'a', + attributes: { font: 'serif', bold: true, italic: true }, + }, + { insert: 'w' }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { + color: 'orange', + detectionId: '16f19f4b-aeb3-44d6-8987-f272bc061b06', + }, + }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { bold: true }, + }, + { + insert: 2, + attributes: { detectionId: '9c4180de-2297-4eca-8553-e0d606a05e50' }, + }, + { insert: 'k', attributes: { color: 'red', italic: true } }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', italic: true }, + }, + { insert: 'Tr' }, + { insert: 'est', attributes: { font: 'monospace', bold: true } }, + { insert: 'ehedcame' }, + { + insert: 'with', + attributes: { detectionId: 'ea0a9f6a-cae7-497f-bfab-ff3749719b95' }, + }, + { insert: 'as' }, + { insert: 'sh', attributes: { italic: true } }, + { insert: 'h' }, + { + insert: 'iff', + attributes: { + font: 'monospace', + bold: true, + italic: true, + detectionId: '4ca892f7-383f-44a6-a6fc-87846767d526', + }, + }, + { + insert: 'l', + attributes: { detectionId: '1d05b61c-6c19-4280-9967-8d83638fb6d2' }, + }, + { + insert: 'ng', + attributes: { + bold: true, + detectionId: '50bd9de5-de2e-4c12-9ce8-e5d154c56156', + }, + }, + { insert: 'm', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'So' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', color: 'orange' }, + }, + { insert: 'y', attributes: { italic: true, color: 'orange' } }, + { insert: 're', attributes: { italic: true } }, + { insert: 'h', attributes: { bold: true } }, + { insert: 2, attributes: { bold: true } }, + { insert: 'houe' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + const serverComposed = new Delta([ + { retain: 3 }, + { + attributes: { + font: 'monospace', + bold: true, + detectionId: '2c6811ab-46f5-4672-84ec-bc3a9bd9a74d', + }, + insert: { image: 'http://quilljs.com' }, + }, + { + attributes: { + color: 'purple', + detectionId: '8b2585d4-bbd7-4de8-a18c-23fdd915c00f', + }, + insert: 'mome', + }, + { + retain: 1, + attributes: { + bold: null, + italic: true, + detectionId: '21b9c1e8-d8f9-43ea-8f91-c3890e25a2aa', + }, + }, + { delete: 1 }, + { + retain: 1, + attributes: { + bold: null, + italic: true, + detectionId: '21b9c1e8-d8f9-43ea-8f91-c3890e25a2aa', + }, + }, + { delete: 6 }, + { retain: 1, attributes: { detectionId: null } }, + { retain: 3 }, + { insert: { image: 'http://quilljs.com' } }, + { retain: 1 }, + { delete: 3 }, + { retain: 4 }, + { delete: 3 }, + ]); + + const clientComposed = new Delta([ + { retain: 5 }, + { + retain: 4, + attributes: { detectionId: '6df775a6-b82c-4cc3-ba7c-7740679f0e97' }, + }, + ]); + + const [server_, client_] = transformX(serverComposed, clientComposed); + + expect(original.compose(serverComposed).compose(client_)).toEqual( + original.compose(clientComposed).compose(server_), + ); + }); + + it('b', function () { + const original = new Delta([ + { insert: 'th', attributes: { font: 'sans-serif' } }, + { insert: 'my' }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'purple' }, + }, + { insert: 'n', attributes: { font: 'monospace' } }, + { + insert: 2, + attributes: { detectionId: '4594e1ac-7bd4-444b-8f56-fe17bd7ab80f' }, + }, + { insert: 'a', attributes: { bold: true } }, + { insert: 'hu' }, + { insert: 'r', attributes: { italic: true } }, + { + insert: 're', + attributes: { font: 'sans-serif', bold: true, italic: true }, + }, + { + insert: 2, + attributes: { detectionId: '0e1b8a1c-d104-4158-af79-605c635949bf' }, + }, + { + insert: 'in', + attributes: { detectionId: '625b1cc7-0ad5-428a-be69-d5ab80b7a4f6' }, + }, + { + insert: 2, + attributes: { + color: 'green', + detectionId: '710547c8-072b-46ae-ad81-2190e68bfd23', + }, + }, + { + insert: 'n', + attributes: { + bold: true, + font: 'sans-serif', + italic: true, + detectionId: '41641b9d-b0a8-45e1-b7fd-2f7ee9e1740b', + }, + }, + { + insert: 'a', + attributes: { + color: 'orange', + font: 'sans-serif', + bold: true, + italic: true, + detectionId: '41641b9d-b0a8-45e1-b7fd-2f7ee9e1740b', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { + italic: true, + detectionId: '41641b9d-b0a8-45e1-b7fd-2f7ee9e1740b', + bold: true, + }, + }, + { + insert: 'nd', + attributes: { color: 'orange', font: 'serif', bold: true }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { font: 'serif', color: 'orange' }, + }, + { insert: 'd' }, + { insert: 'y', attributes: { italic: true, color: 'orange' } }, + { insert: 're', attributes: { italic: true } }, + { insert: 'h', attributes: { bold: true } }, + { insert: 2, attributes: { bold: true } }, + { insert: 'houe' }, + { insert: 'e', attributes: { font: 'sans-serif', italic: true } }, + { insert: 'vo', attributes: { font: 'sans-serif', bold: true } }, + { insert: 'rpal', attributes: { font: 'serif' } }, + { insert: 'h', attributes: { color: 'red' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { italic: true }, + }, + { insert: 'a', attributes: { color: 'red' } }, + { insert: 'nthed' }, + { + insert: 'oo', + attributes: { + color: 'purple', + detectionId: '2dcaf529-e262-431d-bd02-824e252e164b', + }, + }, + { insert: 'd' }, + { insert: 'to', attributes: { color: 'purple' } }, + { insert: 2, attributes: { color: 'orange', font: 'serif' } }, + { + insert: { url: 'http://quilljs.com' }, + attributes: { color: 'orange', font: 'serif' }, + }, + { insert: 've', attributes: { color: 'orange', font: 'serif' } }, + { insert: 's', attributes: { color: 'purple' } }, + { insert: 'x', attributes: { color: 'yellow', bold: true } }, + { insert: 't', attributes: { bold: true } }, + { insert: 'snackhrtheough' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'yellow' }, + }, + { insert: 'g' }, + { + insert: 'to', + attributes: { + color: 'yellow', + font: 'monospace', + bold: true, + detectionId: 'aa4f15f3-27a7-4ed5-8634-459f8442c1e0', + }, + }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red' }, + }, + { insert: 'imble' }, + { insert: 'e', attributes: { italic: true } }, + { insert: 'as' }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { color: 'red', bold: true }, + }, + { + insert: 'Cal', + attributes: { + bold: true, + detectionId: '0119fa75-1136-4023-8ac3-69e932839181', + }, + }, + { insert: 'looh' }, + ]); + + const serverComposed = new Delta([ + { insert: 'i', attributes: { color: 'blue' } }, + { insert: 'le', attributes: { color: 'purple', font: 'serif' } }, + { delete: 1 }, + { + retain: 1, + attributes: { color: 'purple', font: 'serif', bold: null }, + }, + { retain: 1 }, + { insert: 'bite' }, + { retain: 3 }, + { delete: 2 }, + { retain: 2 }, + { delete: 4 }, + ]); + + const clientComposed = new Delta([ + { delete: 1 }, + { retain: 3 }, + { delete: 2 }, + { retain: 1 }, + { + insert: { image: 'http://quilljs.com' }, + attributes: { + font: 'sans-serif', + detectionId: 'd56a565c-cf5d-47f8-b834-67de19ed46ae', + }, + }, + { insert: 'ome', attributes: { color: 'orange', italic: true } }, + { delete: 4 }, + { + retain: 4, + attributes: { + color: 'blue', + detectionId: '5c1c9624-527a-4870-90f8-8a92d2db2218', + }, + }, + { retain: 4 }, + { insert: 'that' }, + ]); + + const [server_, client_] = transformX(serverComposed, clientComposed); + + expect(original.compose(serverComposed).compose(client_)).toEqual( + original.compose(clientComposed).compose(server_), + ); + }); +}); diff --git a/test/delta/transform.js b/test/delta/transform.js index b559298..bcce2f4 100644 --- a/test/delta/transform.js +++ b/test/delta/transform.js @@ -1,7 +1,7 @@ var Delta = require('../../dist/Delta'); -describe('transform()', function() { - it('insert + insert', function() { +describe('transform()', function () { + it('insert + insert', function () { var a1 = new Delta().insert('A'); var b1 = new Delta().insert('B'); var a2 = new Delta(a1); @@ -12,7 +12,7 @@ describe('transform()', function() { expect(a2.transform(b2, false)).toEqual(expected2); }); - it('insert + retain', function() { + it('insert + retain', function () { var a = new Delta().insert('A'); var b = new Delta().retain(1, { bold: true, color: 'red' }); var expected = new Delta() @@ -21,42 +21,42 @@ describe('transform()', function() { expect(a.transform(b, true)).toEqual(expected); }); - it('insert + delete', function() { + it('insert + delete', function () { var a = new Delta().insert('A'); var b = new Delta().delete(1); var expected = new Delta().retain(1).delete(1); expect(a.transform(b, true)).toEqual(expected); }); - it('delete + insert', function() { + it('delete + insert', function () { var a = new Delta().delete(1); var b = new Delta().insert('B'); var expected = new Delta().insert('B'); expect(a.transform(b, true)).toEqual(expected); }); - it('delete + retain', function() { + it('delete + retain', function () { var a = new Delta().delete(1); var b = new Delta().retain(1, { bold: true, color: 'red' }); var expected = new Delta(); expect(a.transform(b, true)).toEqual(expected); }); - it('delete + delete', function() { + it('delete + delete', function () { var a = new Delta().delete(1); var b = new Delta().delete(1); var expected = new Delta(); expect(a.transform(b, true)).toEqual(expected); }); - it('retain + insert', function() { + it('retain + insert', function () { var a = new Delta().retain(1, { color: 'blue' }); var b = new Delta().insert('B'); var expected = new Delta().insert('B'); expect(a.transform(b, true)).toEqual(expected); }); - it('retain + retain', function() { + it('retain + retain', function () { var a1 = new Delta().retain(1, { color: 'blue' }); var b1 = new Delta().retain(1, { bold: true, color: 'red' }); var a2 = new Delta().retain(1, { color: 'blue' }); @@ -67,7 +67,7 @@ describe('transform()', function() { expect(b2.transform(a2, true)).toEqual(expected2); }); - it('retain + retain without priority', function() { + it('retain + retain without priority', function () { var a1 = new Delta().retain(1, { color: 'blue' }); var b1 = new Delta().retain(1, { bold: true, color: 'red' }); var a2 = new Delta().retain(1, { color: 'blue' }); @@ -78,24 +78,16 @@ describe('transform()', function() { expect(b2.transform(a2, false)).toEqual(expected2); }); - it('retain + delete', function() { + it('retain + delete', function () { var a = new Delta().retain(1, { color: 'blue' }); var b = new Delta().delete(1); var expected = new Delta().delete(1); expect(a.transform(b, true)).toEqual(expected); }); - it('alternating edits', function() { - var a1 = new Delta() - .retain(2) - .insert('si') - .delete(5); - var b1 = new Delta() - .retain(1) - .insert('e') - .delete(5) - .retain(1) - .insert('ow'); + it('alternating edits', function () { + var a1 = new Delta().retain(2).insert('si').delete(5); + var b1 = new Delta().retain(1).insert('e').delete(5).retain(1).insert('ow'); var a2 = new Delta(a1); var b2 = new Delta(b1); var expected1 = new Delta() @@ -104,15 +96,12 @@ describe('transform()', function() { .delete(1) .retain(2) .insert('ow'); - var expected2 = new Delta() - .retain(2) - .insert('si') - .delete(1); + var expected2 = new Delta().retain(2).insert('si').delete(1); expect(a1.transform(b1, false)).toEqual(expected1); expect(b2.transform(a2, false)).toEqual(expected2); }); - it('conflicting appends', function() { + it('conflicting appends', function () { var a1 = new Delta().retain(3).insert('aa'); var b1 = new Delta().retain(3).insert('bb'); var a2 = new Delta(a1); @@ -123,7 +112,7 @@ describe('transform()', function() { expect(b2.transform(a2, false)).toEqual(expected2); }); - it('prepend + append', function() { + it('prepend + append', function () { var a1 = new Delta().insert('aa'); var b1 = new Delta().retain(3).insert('bb'); var expected1 = new Delta().retain(5).insert('bb'); @@ -134,7 +123,7 @@ describe('transform()', function() { expect(b2.transform(a2, false)).toEqual(expected2); }); - it('trailing deletes with differing lengths', function() { + it('trailing deletes with differing lengths', function () { var a1 = new Delta().retain(2).delete(1); var b1 = new Delta().delete(3); var expected1 = new Delta().delete(2); @@ -145,7 +134,7 @@ describe('transform()', function() { expect(b2.transform(a2, false)).toEqual(expected2); }); - it('immutability', function() { + it('immutability', function () { var a1 = new Delta().insert('A'); var a2 = new Delta().insert('A'); var b1 = new Delta().insert('B');