quill-delta
Advanced tools
Comparing version 4.2.2 to 5.0.0
interface AttributeMap { | ||
[key: string]: any; | ||
[key: string]: unknown; | ||
} | ||
declare namespace AttributeMap { | ||
function compose(a: AttributeMap | undefined, b: AttributeMap | undefined, keepNull: boolean): AttributeMap | undefined; | ||
function compose(a?: AttributeMap, b?: AttributeMap, keepNull?: boolean): AttributeMap | undefined; | ||
function diff(a?: AttributeMap, b?: AttributeMap): AttributeMap | undefined; | ||
@@ -7,0 +7,0 @@ function invert(attr?: AttributeMap, base?: AttributeMap): AttributeMap; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); | ||
var lodash_isequal_1 = __importDefault(require("lodash.isequal")); | ||
const cloneDeep = require("lodash.clonedeep"); | ||
const isEqual = require("lodash.isequal"); | ||
var AttributeMap; | ||
(function (AttributeMap) { | ||
function compose(a, b, keepNull) { | ||
if (a === void 0) { a = {}; } | ||
if (b === void 0) { b = {}; } | ||
function compose(a = {}, b = {}, keepNull = false) { | ||
if (typeof a !== 'object') { | ||
@@ -19,5 +14,5 @@ a = {}; | ||
} | ||
var attributes = lodash_clonedeep_1.default(b); | ||
let attributes = cloneDeep(b); | ||
if (!keepNull) { | ||
attributes = Object.keys(attributes).reduce(function (copy, key) { | ||
attributes = Object.keys(attributes).reduce((copy, key) => { | ||
if (attributes[key] != null) { | ||
@@ -29,3 +24,3 @@ copy[key] = attributes[key]; | ||
} | ||
for (var key in a) { | ||
for (const key in a) { | ||
if (a[key] !== undefined && b[key] === undefined) { | ||
@@ -38,5 +33,3 @@ attributes[key] = a[key]; | ||
AttributeMap.compose = compose; | ||
function diff(a, b) { | ||
if (a === void 0) { a = {}; } | ||
if (b === void 0) { b = {}; } | ||
function diff(a = {}, b = {}) { | ||
if (typeof a !== 'object') { | ||
@@ -48,6 +41,6 @@ a = {}; | ||
} | ||
var attributes = Object.keys(a) | ||
const attributes = Object.keys(a) | ||
.concat(Object.keys(b)) | ||
.reduce(function (attrs, key) { | ||
if (!lodash_isequal_1.default(a[key], b[key])) { | ||
.reduce((attrs, key) => { | ||
if (!isEqual(a[key], b[key])) { | ||
attrs[key] = b[key] === undefined ? null : b[key]; | ||
@@ -60,7 +53,5 @@ } | ||
AttributeMap.diff = diff; | ||
function invert(attr, base) { | ||
if (attr === void 0) { attr = {}; } | ||
if (base === void 0) { base = {}; } | ||
function invert(attr = {}, base = {}) { | ||
attr = attr || {}; | ||
var baseInverted = Object.keys(base).reduce(function (memo, key) { | ||
const baseInverted = Object.keys(base).reduce((memo, key) => { | ||
if (base[key] !== attr[key] && attr[key] !== undefined) { | ||
@@ -71,3 +62,3 @@ memo[key] = base[key]; | ||
}, {}); | ||
return Object.keys(attr).reduce(function (memo, key) { | ||
return Object.keys(attr).reduce((memo, key) => { | ||
if (attr[key] !== base[key] && base[key] === undefined) { | ||
@@ -80,4 +71,3 @@ memo[key] = null; | ||
AttributeMap.invert = invert; | ||
function transform(a, b, priority) { | ||
if (priority === void 0) { priority = false; } | ||
function transform(a, b, priority = false) { | ||
if (typeof a !== 'object') { | ||
@@ -92,3 +82,3 @@ return b; | ||
} | ||
var attributes = Object.keys(b).reduce(function (attrs, key) { | ||
const attributes = Object.keys(b).reduce((attrs, key) => { | ||
if (a[key] === undefined) { | ||
@@ -95,0 +85,0 @@ attrs[key] = b[key]; // null is a valid value |
@@ -1,7 +0,18 @@ | ||
import diff from 'fast-diff'; | ||
import * as diff from 'fast-diff'; | ||
import AttributeMap from './AttributeMap'; | ||
import Op from './Op'; | ||
import OpIterator from './OpIterator'; | ||
interface EmbedHandler<T> { | ||
compose(a: T, b: T, keepNull: boolean): T; | ||
invert(a: T, b: T): T; | ||
transform(a: T, b: T, priority: boolean): T; | ||
} | ||
declare class Delta { | ||
static Op: typeof Op; | ||
static OpIterator: typeof OpIterator; | ||
static AttributeMap: typeof AttributeMap; | ||
private static handlers; | ||
static registerEmbed<T>(embedType: string, handler: EmbedHandler<T>): void; | ||
static unregisterEmbed(embedType: string): void; | ||
private static getHandler; | ||
ops: Op[]; | ||
@@ -11,5 +22,5 @@ constructor(ops?: Op[] | { | ||
}); | ||
insert(arg: string | object, attributes?: AttributeMap): this; | ||
insert(arg: string | Record<string, unknown>, attributes?: AttributeMap | null): this; | ||
delete(length: number): this; | ||
retain(length: number, attributes?: AttributeMap): this; | ||
retain(length: number | Record<string, unknown>, attributes?: AttributeMap | null): this; | ||
push(newOp: Op): this; | ||
@@ -34,2 +45,3 @@ chop(): this; | ||
} | ||
export = Delta; | ||
export default Delta; | ||
export { Op, OpIterator, AttributeMap }; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.AttributeMap = exports.OpIterator = exports.Op = void 0; | ||
const diff = require("fast-diff"); | ||
const cloneDeep = require("lodash.clonedeep"); | ||
const isEqual = require("lodash.isequal"); | ||
const AttributeMap_1 = require("./AttributeMap"); | ||
exports.AttributeMap = AttributeMap_1.default; | ||
const Op_1 = require("./Op"); | ||
exports.Op = Op_1.default; | ||
const OpIterator_1 = require("./OpIterator"); | ||
exports.OpIterator = OpIterator_1.default; | ||
const NULL_CHARACTER = String.fromCharCode(0); // Placeholder char for embed in diff() | ||
const getEmbedTypeAndData = (a, b) => { | ||
if (typeof a !== 'object' || a === null) { | ||
throw new Error(`cannot retain a ${typeof a}`); | ||
} | ||
if (typeof b !== 'object' || b === null) { | ||
throw new Error(`cannot retain a ${typeof b}`); | ||
} | ||
const embedType = Object.keys(a)[0]; | ||
if (!embedType || embedType !== Object.keys(b)[0]) { | ||
throw new Error(`embed types not matched: ${embedType} != ${Object.keys(b)[0]}`); | ||
} | ||
return [embedType, a[embedType], b[embedType]]; | ||
}; | ||
var fast_diff_1 = __importDefault(require("fast-diff")); | ||
var lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); | ||
var lodash_isequal_1 = __importDefault(require("lodash.isequal")); | ||
var AttributeMap_1 = __importDefault(require("./AttributeMap")); | ||
var Op_1 = __importDefault(require("./Op")); | ||
var NULL_CHARACTER = String.fromCharCode(0); // Placeholder char for embed in diff() | ||
var Delta = /** @class */ (function () { | ||
function Delta(ops) { | ||
class Delta { | ||
constructor(ops) { | ||
// Assume we are given a well formed ops | ||
@@ -24,4 +40,17 @@ if (Array.isArray(ops)) { | ||
} | ||
Delta.prototype.insert = function (arg, attributes) { | ||
var newOp = {}; | ||
static registerEmbed(embedType, handler) { | ||
this.handlers[embedType] = handler; | ||
} | ||
static unregisterEmbed(embedType) { | ||
delete this.handlers[embedType]; | ||
} | ||
static getHandler(embedType) { | ||
const handler = this.handlers[embedType]; | ||
if (!handler) { | ||
throw new Error(`no handlers for embed type "${embedType}"`); | ||
} | ||
return handler; | ||
} | ||
insert(arg, attributes) { | ||
const newOp = {}; | ||
if (typeof arg === 'string' && arg.length === 0) { | ||
@@ -37,4 +66,4 @@ return this; | ||
return this.push(newOp); | ||
}; | ||
Delta.prototype.delete = function (length) { | ||
} | ||
delete(length) { | ||
if (length <= 0) { | ||
@@ -44,8 +73,8 @@ return this; | ||
return this.push({ delete: length }); | ||
}; | ||
Delta.prototype.retain = function (length, attributes) { | ||
if (length <= 0) { | ||
} | ||
retain(length, attributes) { | ||
if (typeof length === 'number' && length <= 0) { | ||
return this; | ||
} | ||
var newOp = { retain: length }; | ||
const newOp = { retain: length }; | ||
if (attributes != null && | ||
@@ -57,7 +86,7 @@ typeof attributes === 'object' && | ||
return this.push(newOp); | ||
}; | ||
Delta.prototype.push = function (newOp) { | ||
var index = this.ops.length; | ||
var lastOp = this.ops[index - 1]; | ||
newOp = lodash_clonedeep_1.default(newOp); | ||
} | ||
push(newOp) { | ||
let index = this.ops.length; | ||
let lastOp = this.ops[index - 1]; | ||
newOp = cloneDeep(newOp); | ||
if (typeof lastOp === 'object') { | ||
@@ -79,3 +108,3 @@ if (typeof newOp.delete === 'number' && | ||
} | ||
if (lodash_isequal_1.default(newOp.attributes, lastOp.attributes)) { | ||
if (isEqual(newOp.attributes, lastOp.attributes)) { | ||
if (typeof newOp.insert === 'string' && | ||
@@ -106,33 +135,33 @@ typeof lastOp.insert === 'string') { | ||
return this; | ||
}; | ||
Delta.prototype.chop = function () { | ||
var lastOp = this.ops[this.ops.length - 1]; | ||
if (lastOp && lastOp.retain && !lastOp.attributes) { | ||
} | ||
chop() { | ||
const lastOp = this.ops[this.ops.length - 1]; | ||
if (lastOp && typeof lastOp.retain === 'number' && !lastOp.attributes) { | ||
this.ops.pop(); | ||
} | ||
return this; | ||
}; | ||
Delta.prototype.filter = function (predicate) { | ||
} | ||
filter(predicate) { | ||
return this.ops.filter(predicate); | ||
}; | ||
Delta.prototype.forEach = function (predicate) { | ||
} | ||
forEach(predicate) { | ||
this.ops.forEach(predicate); | ||
}; | ||
Delta.prototype.map = function (predicate) { | ||
} | ||
map(predicate) { | ||
return this.ops.map(predicate); | ||
}; | ||
Delta.prototype.partition = function (predicate) { | ||
var passed = []; | ||
var failed = []; | ||
this.forEach(function (op) { | ||
var target = predicate(op) ? passed : failed; | ||
} | ||
partition(predicate) { | ||
const passed = []; | ||
const failed = []; | ||
this.forEach((op) => { | ||
const target = predicate(op) ? passed : failed; | ||
target.push(op); | ||
}); | ||
return [passed, failed]; | ||
}; | ||
Delta.prototype.reduce = function (predicate, initialValue) { | ||
} | ||
reduce(predicate, initialValue) { | ||
return this.ops.reduce(predicate, initialValue); | ||
}; | ||
Delta.prototype.changeLength = function () { | ||
return this.reduce(function (length, elem) { | ||
} | ||
changeLength() { | ||
return this.reduce((length, elem) => { | ||
if (elem.insert) { | ||
@@ -146,16 +175,14 @@ return length + Op_1.default.length(elem); | ||
}, 0); | ||
}; | ||
Delta.prototype.length = function () { | ||
return this.reduce(function (length, elem) { | ||
} | ||
length() { | ||
return this.reduce((length, elem) => { | ||
return length + Op_1.default.length(elem); | ||
}, 0); | ||
}; | ||
Delta.prototype.slice = function (start, end) { | ||
if (start === void 0) { start = 0; } | ||
if (end === void 0) { end = Infinity; } | ||
var ops = []; | ||
var iter = Op_1.default.iterator(this.ops); | ||
var index = 0; | ||
} | ||
slice(start = 0, end = Infinity) { | ||
const ops = []; | ||
const iter = new OpIterator_1.default(this.ops); | ||
let index = 0; | ||
while (index < end && iter.hasNext()) { | ||
var nextOp = void 0; | ||
let nextOp; | ||
if (index < start) { | ||
@@ -171,12 +198,12 @@ nextOp = iter.next(start - index); | ||
return new Delta(ops); | ||
}; | ||
Delta.prototype.compose = function (other) { | ||
var thisIter = Op_1.default.iterator(this.ops); | ||
var otherIter = Op_1.default.iterator(other.ops); | ||
var ops = []; | ||
var firstOther = otherIter.peek(); | ||
} | ||
compose(other) { | ||
const thisIter = new OpIterator_1.default(this.ops); | ||
const otherIter = new OpIterator_1.default(other.ops); | ||
const ops = []; | ||
const firstOther = otherIter.peek(); | ||
if (firstOther != null && | ||
typeof firstOther.retain === 'number' && | ||
firstOther.attributes == null) { | ||
var firstLeft = firstOther.retain; | ||
let firstLeft = firstOther.retain; | ||
while (thisIter.peekType() === 'insert' && | ||
@@ -191,3 +218,3 @@ thisIter.peekLength() <= firstLeft) { | ||
} | ||
var delta = new Delta(ops); | ||
const delta = new Delta(ops); | ||
while (thisIter.hasNext() || otherIter.hasNext()) { | ||
@@ -201,15 +228,31 @@ if (otherIter.peekType() === 'insert') { | ||
else { | ||
var length_1 = Math.min(thisIter.peekLength(), otherIter.peekLength()); | ||
var thisOp = thisIter.next(length_1); | ||
var otherOp = otherIter.next(length_1); | ||
if (typeof otherOp.retain === 'number') { | ||
var newOp = {}; | ||
const length = Math.min(thisIter.peekLength(), otherIter.peekLength()); | ||
const thisOp = thisIter.next(length); | ||
const otherOp = otherIter.next(length); | ||
if (otherOp.retain) { | ||
const newOp = {}; | ||
if (typeof thisOp.retain === 'number') { | ||
newOp.retain = length_1; | ||
newOp.retain = | ||
typeof otherOp.retain === 'number' ? length : otherOp.retain; | ||
} | ||
else { | ||
newOp.insert = thisOp.insert; | ||
if (typeof otherOp.retain === 'number') { | ||
if (thisOp.retain == null) { | ||
newOp.insert = thisOp.insert; | ||
} | ||
else { | ||
newOp.retain = thisOp.retain; | ||
} | ||
} | ||
else { | ||
const action = thisOp.retain == null ? 'insert' : 'retain'; | ||
const [embedType, thisData, otherData] = getEmbedTypeAndData(thisOp[action], otherOp.retain); | ||
const handler = Delta.getHandler(embedType); | ||
newOp[action] = { | ||
[embedType]: handler.compose(thisData, otherData, action === 'retain'), | ||
}; | ||
} | ||
} | ||
// Preserve null when composing with a retain, otherwise remove it for inserts | ||
var attributes = AttributeMap_1.default.compose(thisOp.attributes, otherOp.attributes, typeof thisOp.retain === 'number'); | ||
const attributes = AttributeMap_1.default.compose(thisOp.attributes, otherOp.attributes, typeof thisOp.retain === 'number'); | ||
if (attributes) { | ||
@@ -221,4 +264,4 @@ newOp.attributes = attributes; | ||
if (!otherIter.hasNext() && | ||
lodash_isequal_1.default(delta.ops[delta.ops.length - 1], newOp)) { | ||
var rest = new Delta(thisIter.rest()); | ||
isEqual(delta.ops[delta.ops.length - 1], newOp)) { | ||
const rest = new Delta(thisIter.rest()); | ||
return delta.concat(rest).chop(); | ||
@@ -230,3 +273,4 @@ } | ||
else if (typeof otherOp.delete === 'number' && | ||
typeof thisOp.retain === 'number') { | ||
(typeof thisOp.retain === 'number' || | ||
(typeof thisOp.retain === 'object' && thisOp.retain !== null))) { | ||
delta.push(otherOp); | ||
@@ -237,5 +281,5 @@ } | ||
return delta.chop(); | ||
}; | ||
Delta.prototype.concat = function (other) { | ||
var delta = new Delta(this.ops.slice()); | ||
} | ||
concat(other) { | ||
const delta = new Delta(this.ops.slice()); | ||
if (other.ops.length > 0) { | ||
@@ -246,14 +290,14 @@ delta.push(other.ops[0]); | ||
return delta; | ||
}; | ||
Delta.prototype.diff = function (other, cursor) { | ||
} | ||
diff(other, cursor) { | ||
if (this.ops === other.ops) { | ||
return new Delta(); | ||
} | ||
var strings = [this, other].map(function (delta) { | ||
const strings = [this, other].map((delta) => { | ||
return delta | ||
.map(function (op) { | ||
.map((op) => { | ||
if (op.insert != null) { | ||
return typeof op.insert === 'string' ? op.insert : NULL_CHARACTER; | ||
} | ||
var prep = delta === other ? 'on' : 'with'; | ||
const prep = delta === other ? 'on' : 'with'; | ||
throw new Error('diff() called ' + prep + ' non-document'); | ||
@@ -263,16 +307,16 @@ }) | ||
}); | ||
var retDelta = new Delta(); | ||
var diffResult = fast_diff_1.default(strings[0], strings[1], cursor); | ||
var thisIter = Op_1.default.iterator(this.ops); | ||
var otherIter = Op_1.default.iterator(other.ops); | ||
diffResult.forEach(function (component) { | ||
var length = component[1].length; | ||
const retDelta = new Delta(); | ||
const diffResult = diff(strings[0], strings[1], cursor); | ||
const thisIter = new OpIterator_1.default(this.ops); | ||
const otherIter = new OpIterator_1.default(other.ops); | ||
diffResult.forEach((component) => { | ||
let length = component[1].length; | ||
while (length > 0) { | ||
var opLength = 0; | ||
let opLength = 0; | ||
switch (component[0]) { | ||
case fast_diff_1.default.INSERT: | ||
case diff.INSERT: | ||
opLength = Math.min(otherIter.peekLength(), length); | ||
retDelta.push(otherIter.next(opLength)); | ||
break; | ||
case fast_diff_1.default.DELETE: | ||
case diff.DELETE: | ||
opLength = Math.min(length, thisIter.peekLength()); | ||
@@ -282,7 +326,7 @@ thisIter.next(opLength); | ||
break; | ||
case fast_diff_1.default.EQUAL: | ||
case diff.EQUAL: | ||
opLength = Math.min(thisIter.peekLength(), otherIter.peekLength(), length); | ||
var thisOp = thisIter.next(opLength); | ||
var otherOp = otherIter.next(opLength); | ||
if (lodash_isequal_1.default(thisOp.insert, otherOp.insert)) { | ||
const thisOp = thisIter.next(opLength); | ||
const otherOp = otherIter.next(opLength); | ||
if (isEqual(thisOp.insert, otherOp.insert)) { | ||
retDelta.retain(opLength, AttributeMap_1.default.diff(thisOp.attributes, otherOp.attributes)); | ||
@@ -299,8 +343,7 @@ } | ||
return retDelta.chop(); | ||
}; | ||
Delta.prototype.eachLine = function (predicate, newline) { | ||
if (newline === void 0) { newline = '\n'; } | ||
var iter = Op_1.default.iterator(this.ops); | ||
var line = new Delta(); | ||
var i = 0; | ||
} | ||
eachLine(predicate, newline = '\n') { | ||
const iter = new OpIterator_1.default(this.ops); | ||
let line = new Delta(); | ||
let i = 0; | ||
while (iter.hasNext()) { | ||
@@ -310,5 +353,5 @@ if (iter.peekType() !== 'insert') { | ||
} | ||
var thisOp = iter.peek(); | ||
var start = Op_1.default.length(thisOp) - iter.peekLength(); | ||
var index = typeof thisOp.insert === 'string' | ||
const thisOp = iter.peek(); | ||
const start = Op_1.default.length(thisOp) - iter.peekLength(); | ||
const index = typeof thisOp.insert === 'string' | ||
? thisOp.insert.indexOf(newline, start) - start | ||
@@ -333,17 +376,17 @@ : -1; | ||
} | ||
}; | ||
Delta.prototype.invert = function (base) { | ||
var inverted = new Delta(); | ||
this.reduce(function (baseIndex, op) { | ||
} | ||
invert(base) { | ||
const inverted = new Delta(); | ||
this.reduce((baseIndex, op) => { | ||
if (op.insert) { | ||
inverted.delete(Op_1.default.length(op)); | ||
} | ||
else if (op.retain && op.attributes == null) { | ||
else if (typeof op.retain === 'number' && op.attributes == null) { | ||
inverted.retain(op.retain); | ||
return baseIndex + op.retain; | ||
} | ||
else if (op.delete || (op.retain && op.attributes)) { | ||
var length_2 = (op.delete || op.retain); | ||
var slice = base.slice(baseIndex, baseIndex + length_2); | ||
slice.forEach(function (baseOp) { | ||
else if (op.delete || typeof op.retain === 'number') { | ||
const length = (op.delete || op.retain); | ||
const slice = base.slice(baseIndex, baseIndex + length); | ||
slice.forEach((baseOp) => { | ||
if (op.delete) { | ||
@@ -356,10 +399,17 @@ inverted.push(baseOp); | ||
}); | ||
return baseIndex + length_2; | ||
return baseIndex + length; | ||
} | ||
else if (typeof op.retain === 'object' && op.retain !== null) { | ||
const slice = base.slice(baseIndex, baseIndex + 1); | ||
const baseOp = new OpIterator_1.default(slice.ops).next(); | ||
const [embedType, opData, baseOpData] = getEmbedTypeAndData(op.retain, baseOp.insert); | ||
const handler = Delta.getHandler(embedType); | ||
inverted.retain({ [embedType]: handler.invert(opData, baseOpData) }, AttributeMap_1.default.invert(op.attributes, baseOp.attributes)); | ||
return baseIndex + 1; | ||
} | ||
return baseIndex; | ||
}, 0); | ||
return inverted.chop(); | ||
}; | ||
Delta.prototype.transform = function (arg, priority) { | ||
if (priority === void 0) { priority = false; } | ||
} | ||
transform(arg, priority = false) { | ||
priority = !!priority; | ||
@@ -369,6 +419,6 @@ if (typeof arg === 'number') { | ||
} | ||
var other = arg; | ||
var thisIter = Op_1.default.iterator(this.ops); | ||
var otherIter = Op_1.default.iterator(other.ops); | ||
var delta = new Delta(); | ||
const other = arg; | ||
const thisIter = new OpIterator_1.default(this.ops); | ||
const otherIter = new OpIterator_1.default(other.ops); | ||
const delta = new Delta(); | ||
while (thisIter.hasNext() || otherIter.hasNext()) { | ||
@@ -383,5 +433,5 @@ if (thisIter.peekType() === 'insert' && | ||
else { | ||
var length_3 = Math.min(thisIter.peekLength(), otherIter.peekLength()); | ||
var thisOp = thisIter.next(length_3); | ||
var otherOp = otherIter.next(length_3); | ||
const length = Math.min(thisIter.peekLength(), otherIter.peekLength()); | ||
const thisOp = thisIter.next(length); | ||
const otherOp = otherIter.next(length); | ||
if (thisOp.delete) { | ||
@@ -395,4 +445,23 @@ // Our delete either makes their delete redundant or removes their retain | ||
else { | ||
const thisData = thisOp.retain; | ||
const otherData = otherOp.retain; | ||
let transformedData = typeof otherData === 'object' && otherData !== null | ||
? otherData | ||
: length; | ||
if (typeof thisData === 'object' && | ||
thisData !== null && | ||
typeof otherData === 'object' && | ||
otherData !== null) { | ||
const embedType = Object.keys(thisData)[0]; | ||
if (embedType === Object.keys(otherData)[0]) { | ||
const handler = Delta.getHandler(embedType); | ||
if (handler) { | ||
transformedData = { | ||
[embedType]: handler.transform(thisData[embedType], otherData[embedType], priority), | ||
}; | ||
} | ||
} | ||
} | ||
// We retain either their retain or insert | ||
delta.retain(length_3, AttributeMap_1.default.transform(thisOp.attributes, otherOp.attributes, priority)); | ||
delta.retain(transformedData, AttributeMap_1.default.transform(thisOp.attributes, otherOp.attributes, priority)); | ||
} | ||
@@ -402,28 +471,32 @@ } | ||
return delta.chop(); | ||
}; | ||
Delta.prototype.transformPosition = function (index, priority) { | ||
if (priority === void 0) { priority = false; } | ||
} | ||
transformPosition(index, priority = false) { | ||
priority = !!priority; | ||
var thisIter = Op_1.default.iterator(this.ops); | ||
var offset = 0; | ||
const thisIter = new OpIterator_1.default(this.ops); | ||
let offset = 0; | ||
while (thisIter.hasNext() && offset <= index) { | ||
var length_4 = thisIter.peekLength(); | ||
var nextType = thisIter.peekType(); | ||
const length = thisIter.peekLength(); | ||
const nextType = thisIter.peekType(); | ||
thisIter.next(); | ||
if (nextType === 'delete') { | ||
index -= Math.min(length_4, index - offset); | ||
index -= Math.min(length, index - offset); | ||
continue; | ||
} | ||
else if (nextType === 'insert' && (offset < index || !priority)) { | ||
index += length_4; | ||
index += length; | ||
} | ||
offset += length_4; | ||
offset += length; | ||
} | ||
return index; | ||
}; | ||
Delta.Op = Op_1.default; | ||
Delta.AttributeMap = AttributeMap_1.default; | ||
return Delta; | ||
}()); | ||
module.exports = Delta; | ||
} | ||
} | ||
Delta.Op = Op_1.default; | ||
Delta.OpIterator = OpIterator_1.default; | ||
Delta.AttributeMap = AttributeMap_1.default; | ||
Delta.handlers = {}; | ||
exports.default = Delta; | ||
if (typeof module === 'object') { | ||
module.exports = Delta; | ||
module.exports.default = Delta; | ||
} | ||
//# sourceMappingURL=Delta.js.map |
import AttributeMap from './AttributeMap'; | ||
import Iterator from './Iterator'; | ||
interface Op { | ||
insert?: string | object; | ||
insert?: string | Record<string, unknown>; | ||
delete?: number; | ||
retain?: number; | ||
retain?: number | Record<string, unknown>; | ||
attributes?: AttributeMap; | ||
} | ||
declare namespace Op { | ||
function iterator(ops: Op[]): Iterator; | ||
function length(op: Op): number; | ||
} | ||
export default Op; |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Iterator_1 = __importDefault(require("./Iterator")); | ||
var Op; | ||
(function (Op) { | ||
function iterator(ops) { | ||
return new Iterator_1.default(ops); | ||
} | ||
Op.iterator = iterator; | ||
function length(op) { | ||
@@ -20,2 +12,5 @@ if (typeof op.delete === 'number') { | ||
} | ||
else if (typeof op.retain === 'object' && op.retain !== null) { | ||
return 1; | ||
} | ||
else { | ||
@@ -22,0 +17,0 @@ return typeof op.insert === 'string' ? op.insert.length : 1; |
{ | ||
"name": "quill-delta", | ||
"version": "4.2.2", | ||
"version": "5.0.0", | ||
"description": "Format for representing rich text documents and changes.", | ||
@@ -14,15 +14,20 @@ "author": "Jason Chen <jhchen7@gmail.com>", | ||
"devDependencies": { | ||
"@types/lodash.clonedeep": "^4.5.0", | ||
"@types/lodash.isequal": "^4.5.0", | ||
"@typescript-eslint/eslint-plugin": "^2.28.0", | ||
"@typescript-eslint/parser": "^2.28.0", | ||
"coveralls": "^3.0.11", | ||
"eslint": "^6.8.0", | ||
"eslint-config-prettier": "^6.10.1", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
"istanbul": "~0.4.5", | ||
"jasmine": "^3.5.0", | ||
"prettier": "^2.0.4", | ||
"typescript": "^3.8.3" | ||
"@types/jasmine": "^3.10.3", | ||
"@types/lodash.clonedeep": "^4.5.6", | ||
"@types/lodash.isequal": "^4.5.5", | ||
"@types/node": "^17.0.21", | ||
"@typescript-eslint/eslint-plugin": "^5.14.0", | ||
"@typescript-eslint/parser": "^5.14.0", | ||
"eslint": "^8.10.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"jasmine": "^4.0.2", | ||
"nyc": "^15.1.0", | ||
"prettier": "^2.5.1", | ||
"ts-node": "^10.7.0", | ||
"typescript": "^4.6.2" | ||
}, | ||
"engines": { | ||
"node": ">= 12.0.0" | ||
}, | ||
"files": [ | ||
@@ -38,5 +43,5 @@ "tsconfig.json", | ||
"lint": "eslint 'src/**/*.ts'", | ||
"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" | ||
"test": "jasmine --config=jasmine.json", | ||
"test:coverage": "nyc npm run test", | ||
"test:coverage:report": "nyc report --reporter=lcov" | ||
}, | ||
@@ -47,3 +52,2 @@ "eslintConfig": { | ||
"plugin:@typescript-eslint/recommended", | ||
"prettier/@typescript-eslint", | ||
"plugin:prettier/recommended" | ||
@@ -56,11 +60,3 @@ ], | ||
"rules": { | ||
"@typescript-eslint/ban-ts-ignore": "off", | ||
"@typescript-eslint/no-explicit-any": "off", | ||
"@typescript-eslint/no-namespace": "off", | ||
"@typescript-eslint/no-unused-vars": [ | ||
"error", | ||
{ | ||
"argsIgnorePattern": "^_" | ||
} | ||
] | ||
"@typescript-eslint/no-namespace": "off" | ||
} | ||
@@ -67,0 +63,0 @@ }, |
@@ -1,2 +0,2 @@ | ||
# Delta [![Build Status](https://travis-ci.org/quilljs/delta.svg?branch=master)](http://travis-ci.org/quilljs/delta) [![Coverage Status](https://img.shields.io/coveralls/quilljs/delta.svg)](https://coveralls.io/r/quilljs/delta) | ||
# Delta [![Build Status](https://github.com/quilljs/delta/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/quilljs/delta/actions?query=branch%3Amaster) [![Coverage Status](https://img.shields.io/coveralls/quilljs/delta.svg)](https://coveralls.io/r/quilljs/delta) | ||
@@ -22,12 +22,12 @@ Deltas are a simple, yet expressive format that can be used to describe contents and changes. The format is JSON based, and is human readable, yet easily parsible by machines. Deltas can describe any rich text document, includes all text and formatting information, without the ambiguity and complexity of HTML. | ||
// Change intended to be applied to above: | ||
// Keep the first 12 characters, delete the next 4, | ||
// and insert a white 'White' | ||
// Keep the first 12 characters, insert a white 'White' | ||
// and delete the next four characters ('Grey') | ||
const death = new Delta().retain(12) | ||
.delete(4) | ||
.insert('White', { color: '#fff' }); | ||
.insert('White', { color: '#fff' }) | ||
.delete(4); | ||
// { | ||
// ops: [ | ||
// { retain: 12 }, | ||
// { delete: 4 }, | ||
// { insert: 'White', attributes: { color: '#fff' } } | ||
// { insert: 'White', attributes: { color: '#fff' } }, | ||
// { delete: 4 } | ||
// ] | ||
@@ -40,4 +40,4 @@ // } | ||
// ops: [ | ||
// { insert: 'Gandalf ', attributes: { bold: true } }, | ||
// { insert: 'the ' }, | ||
// { insert: 'Gandalf', attributes: { bold: true } }, | ||
// { insert: ' the ' }, | ||
// { insert: 'White', attributes: { color: '#fff' } } | ||
@@ -377,3 +377,3 @@ // ] | ||
.insert('World'); | ||
const delta = new Delta().retain(6, { bold: true }).delete(5).insert('!'); | ||
const delta = new Delta().retain(6, { bold: true }).insert('!').delete(5); | ||
@@ -380,0 +380,0 @@ const inverted = delta.invert(base); // { ops: [ |
@@ -1,6 +0,6 @@ | ||
import cloneDeep from 'lodash.clonedeep'; | ||
import isEqual from 'lodash.isequal'; | ||
import cloneDeep = require('lodash.clonedeep'); | ||
import isEqual = require('lodash.isequal'); | ||
interface AttributeMap { | ||
[key: string]: any; | ||
[key: string]: unknown; | ||
} | ||
@@ -12,3 +12,3 @@ | ||
b: AttributeMap = {}, | ||
keepNull: boolean, | ||
keepNull = false, | ||
): AttributeMap | undefined { | ||
@@ -15,0 +15,0 @@ if (typeof a !== 'object') { |
167
src/Delta.ts
@@ -1,13 +0,57 @@ | ||
import diff from 'fast-diff'; | ||
import cloneDeep from 'lodash.clonedeep'; | ||
import isEqual from 'lodash.isequal'; | ||
import * as diff from 'fast-diff'; | ||
import cloneDeep = require('lodash.clonedeep'); | ||
import isEqual = require('lodash.isequal'); | ||
import AttributeMap from './AttributeMap'; | ||
import Op from './Op'; | ||
import OpIterator from './OpIterator'; | ||
const NULL_CHARACTER = String.fromCharCode(0); // Placeholder char for embed in diff() | ||
interface EmbedHandler<T> { | ||
compose(a: T, b: T, keepNull: boolean): T; | ||
invert(a: T, b: T): T; | ||
transform(a: T, b: T, priority: boolean): T; | ||
} | ||
const getEmbedTypeAndData = ( | ||
a: Op['insert'] | Op['retain'], | ||
b: Op['insert'], | ||
): [string, unknown, unknown] => { | ||
if (typeof a !== 'object' || a === null) { | ||
throw new Error(`cannot retain a ${typeof a}`); | ||
} | ||
if (typeof b !== 'object' || b === null) { | ||
throw new Error(`cannot retain a ${typeof b}`); | ||
} | ||
const embedType = Object.keys(a)[0]; | ||
if (!embedType || embedType !== Object.keys(b)[0]) { | ||
throw new Error( | ||
`embed types not matched: ${embedType} != ${Object.keys(b)[0]}`, | ||
); | ||
} | ||
return [embedType, a[embedType], b[embedType]]; | ||
}; | ||
class Delta { | ||
static Op = Op; | ||
static OpIterator = OpIterator; | ||
static AttributeMap = AttributeMap; | ||
private static handlers: { [embedType: string]: EmbedHandler<unknown> } = {}; | ||
static registerEmbed<T>(embedType: string, handler: EmbedHandler<T>): void { | ||
this.handlers[embedType] = handler; | ||
} | ||
static unregisterEmbed(embedType: string): void { | ||
delete this.handlers[embedType]; | ||
} | ||
private static getHandler(embedType: string): EmbedHandler<unknown> { | ||
const handler = this.handlers[embedType]; | ||
if (!handler) { | ||
throw new Error(`no handlers for embed type "${embedType}"`); | ||
} | ||
return handler; | ||
} | ||
ops: Op[]; | ||
@@ -25,3 +69,6 @@ constructor(ops?: Op[] | { ops: Op[] }) { | ||
insert(arg: string | object, attributes?: AttributeMap): this { | ||
insert( | ||
arg: string | Record<string, unknown>, | ||
attributes?: AttributeMap | null, | ||
): this { | ||
const newOp: Op = {}; | ||
@@ -49,4 +96,7 @@ if (typeof arg === 'string' && arg.length === 0) { | ||
retain(length: number, attributes?: AttributeMap): this { | ||
if (length <= 0) { | ||
retain( | ||
length: number | Record<string, unknown>, | ||
attributes?: AttributeMap | null, | ||
): this { | ||
if (typeof length === 'number' && length <= 0) { | ||
return this; | ||
@@ -119,3 +169,3 @@ } | ||
const lastOp = this.ops[this.ops.length - 1]; | ||
if (lastOp && lastOp.retain && !lastOp.attributes) { | ||
if (lastOp && typeof lastOp.retain === 'number' && !lastOp.attributes) { | ||
this.ops.pop(); | ||
@@ -174,3 +224,3 @@ } | ||
const ops = []; | ||
const iter = Op.iterator(this.ops); | ||
const iter = new OpIterator(this.ops); | ||
let index = 0; | ||
@@ -191,4 +241,4 @@ while (index < end && iter.hasNext()) { | ||
compose(other: Delta): Delta { | ||
const thisIter = Op.iterator(this.ops); | ||
const otherIter = Op.iterator(other.ops); | ||
const thisIter = new OpIterator(this.ops); | ||
const otherIter = new OpIterator(other.ops); | ||
const ops = []; | ||
@@ -223,8 +273,29 @@ const firstOther = otherIter.peek(); | ||
const otherOp = otherIter.next(length); | ||
if (typeof otherOp.retain === 'number') { | ||
if (otherOp.retain) { | ||
const newOp: Op = {}; | ||
if (typeof thisOp.retain === 'number') { | ||
newOp.retain = length; | ||
newOp.retain = | ||
typeof otherOp.retain === 'number' ? length : otherOp.retain; | ||
} else { | ||
newOp.insert = thisOp.insert; | ||
if (typeof otherOp.retain === 'number') { | ||
if (thisOp.retain == null) { | ||
newOp.insert = thisOp.insert; | ||
} else { | ||
newOp.retain = thisOp.retain; | ||
} | ||
} else { | ||
const action = thisOp.retain == null ? 'insert' : 'retain'; | ||
const [embedType, thisData, otherData] = getEmbedTypeAndData( | ||
thisOp[action], | ||
otherOp.retain, | ||
); | ||
const handler = Delta.getHandler(embedType); | ||
newOp[action] = { | ||
[embedType]: handler.compose( | ||
thisData, | ||
otherData, | ||
action === 'retain', | ||
), | ||
}; | ||
} | ||
} | ||
@@ -255,3 +326,4 @@ // Preserve null when composing with a retain, otherwise remove it for inserts | ||
typeof otherOp.delete === 'number' && | ||
typeof thisOp.retain === 'number' | ||
(typeof thisOp.retain === 'number' || | ||
(typeof thisOp.retain === 'object' && thisOp.retain !== null)) | ||
) { | ||
@@ -291,4 +363,4 @@ delta.push(otherOp); | ||
const diffResult = diff(strings[0], strings[1], cursor); | ||
const thisIter = Op.iterator(this.ops); | ||
const otherIter = Op.iterator(other.ops); | ||
const thisIter = new OpIterator(this.ops); | ||
const otherIter = new OpIterator(other.ops); | ||
diffResult.forEach((component: diff.Diff) => { | ||
@@ -340,3 +412,3 @@ let length = component[1].length; | ||
): void { | ||
const iter = Op.iterator(this.ops); | ||
const iter = new OpIterator(this.ops); | ||
let line = new Delta(); | ||
@@ -376,6 +448,6 @@ let i = 0; | ||
inverted.delete(Op.length(op)); | ||
} else if (op.retain && op.attributes == null) { | ||
} else if (typeof op.retain === 'number' && op.attributes == null) { | ||
inverted.retain(op.retain); | ||
return baseIndex + op.retain; | ||
} else if (op.delete || (op.retain && op.attributes)) { | ||
} else if (op.delete || typeof op.retain === 'number') { | ||
const length = (op.delete || op.retain) as number; | ||
@@ -394,2 +466,15 @@ const slice = base.slice(baseIndex, baseIndex + length); | ||
return baseIndex + length; | ||
} else if (typeof op.retain === 'object' && op.retain !== null) { | ||
const slice = base.slice(baseIndex, baseIndex + 1); | ||
const baseOp = new OpIterator(slice.ops).next(); | ||
const [embedType, opData, baseOpData] = getEmbedTypeAndData( | ||
op.retain, | ||
baseOp.insert, | ||
); | ||
const handler = Delta.getHandler(embedType); | ||
inverted.retain( | ||
{ [embedType]: handler.invert(opData, baseOpData) }, | ||
AttributeMap.invert(op.attributes, baseOp.attributes), | ||
); | ||
return baseIndex + 1; | ||
} | ||
@@ -409,4 +494,4 @@ return baseIndex; | ||
const other: Delta = arg; | ||
const thisIter = Op.iterator(this.ops); | ||
const otherIter = Op.iterator(other.ops); | ||
const thisIter = new OpIterator(this.ops); | ||
const otherIter = new OpIterator(other.ops); | ||
const delta = new Delta(); | ||
@@ -431,5 +516,32 @@ while (thisIter.hasNext() || otherIter.hasNext()) { | ||
} else { | ||
const thisData = thisOp.retain; | ||
const otherData = otherOp.retain; | ||
let transformedData: Op['retain'] = | ||
typeof otherData === 'object' && otherData !== null | ||
? otherData | ||
: length; | ||
if ( | ||
typeof thisData === 'object' && | ||
thisData !== null && | ||
typeof otherData === 'object' && | ||
otherData !== null | ||
) { | ||
const embedType = Object.keys(thisData)[0]; | ||
if (embedType === Object.keys(otherData)[0]) { | ||
const handler = Delta.getHandler(embedType); | ||
if (handler) { | ||
transformedData = { | ||
[embedType]: handler.transform( | ||
thisData[embedType], | ||
otherData[embedType], | ||
priority, | ||
), | ||
}; | ||
} | ||
} | ||
} | ||
// We retain either their retain or insert | ||
delta.retain( | ||
length, | ||
transformedData, | ||
AttributeMap.transform( | ||
@@ -449,3 +561,3 @@ thisOp.attributes, | ||
priority = !!priority; | ||
const thisIter = Op.iterator(this.ops); | ||
const thisIter = new OpIterator(this.ops); | ||
let offset = 0; | ||
@@ -468,2 +580,9 @@ while (thisIter.hasNext() && offset <= index) { | ||
export = Delta; | ||
export default Delta; | ||
export { Op, OpIterator, AttributeMap }; | ||
if (typeof module === 'object') { | ||
module.exports = Delta; | ||
module.exports.default = Delta; | ||
} |
import AttributeMap from './AttributeMap'; | ||
import Iterator from './Iterator'; | ||
interface Op { | ||
// only one property out of {insert, delete, retain} will be present | ||
insert?: string | object; | ||
insert?: string | Record<string, unknown>; | ||
delete?: number; | ||
retain?: number; | ||
retain?: number | Record<string, unknown>; | ||
@@ -14,6 +13,2 @@ attributes?: AttributeMap; | ||
namespace Op { | ||
export function iterator(ops: Op[]): Iterator { | ||
return new Iterator(ops); | ||
} | ||
export function length(op: Op): number { | ||
@@ -24,2 +19,4 @@ if (typeof op.delete === 'number') { | ||
return op.retain; | ||
} else if (typeof op.retain === 'object' && op.retain !== null) { | ||
return 1; | ||
} else { | ||
@@ -26,0 +23,0 @@ return typeof op.insert === 'string' ? op.insert.length : 1; |
@@ -7,4 +7,5 @@ { | ||
"strict": true, | ||
"target": "ES5", | ||
"esModuleInterop": true, | ||
"target": "ES2015", | ||
"module": "commonjs", | ||
"strictNullChecks": true, | ||
"noErrorTruncation": true, | ||
@@ -11,0 +12,0 @@ "noUnusedLocals": true, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
95300
1536
14
20
1
1