You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							155 lines
						
					
					
						
							4.1 KiB
						
					
					
				
			
		
		
	
	
							155 lines
						
					
					
						
							4.1 KiB
						
					
					
				var equal = require('deep-equal'); | 
						|
var extend = require('extend'); | 
						|
 | 
						|
 | 
						|
var lib = { | 
						|
  attributes: { | 
						|
    compose: function (a, b, keepNull) { | 
						|
      if (typeof a !== 'object') a = {}; | 
						|
      if (typeof b !== 'object') b = {}; | 
						|
      var attributes = extend(true, {}, b); | 
						|
      if (!keepNull) { | 
						|
        attributes = Object.keys(attributes).reduce(function (copy, key) { | 
						|
          if (attributes[key] != null) { | 
						|
            copy[key] = attributes[key]; | 
						|
          } | 
						|
          return copy; | 
						|
        }, {}); | 
						|
      } | 
						|
      for (var key in a) { | 
						|
        if (a[key] !== undefined && b[key] === undefined) { | 
						|
          attributes[key] = a[key]; | 
						|
        } | 
						|
      } | 
						|
      return Object.keys(attributes).length > 0 ? attributes : undefined; | 
						|
    }, | 
						|
 | 
						|
    diff: function(a, b) { | 
						|
      if (typeof a !== 'object') a = {}; | 
						|
      if (typeof b !== 'object') b = {}; | 
						|
      var attributes = Object.keys(a).concat(Object.keys(b)).reduce(function (attributes, key) { | 
						|
        if (!equal(a[key], b[key])) { | 
						|
          attributes[key] = b[key] === undefined ? null : b[key]; | 
						|
        } | 
						|
        return attributes; | 
						|
      }, {}); | 
						|
      return Object.keys(attributes).length > 0 ? attributes : undefined; | 
						|
    }, | 
						|
 | 
						|
    transform: function (a, b, priority) { | 
						|
      if (typeof a !== 'object') return b; | 
						|
      if (typeof b !== 'object') return undefined; | 
						|
      if (!priority) return b;  // b simply overwrites us without priority | 
						|
      var attributes = Object.keys(b).reduce(function (attributes, key) { | 
						|
        if (a[key] === undefined) attributes[key] = b[key];  // null is a valid value | 
						|
        return attributes; | 
						|
      }, {}); | 
						|
      return Object.keys(attributes).length > 0 ? attributes : undefined; | 
						|
    } | 
						|
  }, | 
						|
 | 
						|
  iterator: function (ops) { | 
						|
    return new Iterator(ops); | 
						|
  }, | 
						|
 | 
						|
  length: function (op) { | 
						|
    if (typeof op['delete'] === 'number') { | 
						|
      return op['delete']; | 
						|
    } else if (typeof op.retain === 'number') { | 
						|
      return op.retain; | 
						|
    } else { | 
						|
      return typeof op.insert === 'string' ? op.insert.length : 1; | 
						|
    } | 
						|
  } | 
						|
}; | 
						|
 | 
						|
 | 
						|
function Iterator(ops) { | 
						|
  this.ops = ops; | 
						|
  this.index = 0; | 
						|
  this.offset = 0; | 
						|
}; | 
						|
 | 
						|
Iterator.prototype.hasNext = function () { | 
						|
  return this.peekLength() < Infinity; | 
						|
}; | 
						|
 | 
						|
Iterator.prototype.next = function (length) { | 
						|
  if (!length) length = Infinity; | 
						|
  var nextOp = this.ops[this.index]; | 
						|
  if (nextOp) { | 
						|
    var offset = this.offset; | 
						|
    var opLength = lib.length(nextOp) | 
						|
    if (length >= opLength - offset) { | 
						|
      length = opLength - offset; | 
						|
      this.index += 1; | 
						|
      this.offset = 0; | 
						|
    } else { | 
						|
      this.offset += length; | 
						|
    } | 
						|
    if (typeof nextOp['delete'] === 'number') { | 
						|
      return { 'delete': length }; | 
						|
    } else { | 
						|
      var retOp = {}; | 
						|
      if (nextOp.attributes) { | 
						|
        retOp.attributes = nextOp.attributes; | 
						|
      } | 
						|
      if (typeof nextOp.retain === 'number') { | 
						|
        retOp.retain = length; | 
						|
      } else if (typeof nextOp.insert === 'string') { | 
						|
        retOp.insert = nextOp.insert.substr(offset, length); | 
						|
      } else { | 
						|
        // offset should === 0, length should === 1 | 
						|
        retOp.insert = nextOp.insert; | 
						|
      } | 
						|
      return retOp; | 
						|
    } | 
						|
  } else { | 
						|
    return { retain: Infinity }; | 
						|
  } | 
						|
}; | 
						|
 | 
						|
Iterator.prototype.peek = function () { | 
						|
  return this.ops[this.index]; | 
						|
}; | 
						|
 | 
						|
Iterator.prototype.peekLength = function () { | 
						|
  if (this.ops[this.index]) { | 
						|
    // Should never return 0 if our index is being managed correctly | 
						|
    return lib.length(this.ops[this.index]) - this.offset; | 
						|
  } else { | 
						|
    return Infinity; | 
						|
  } | 
						|
}; | 
						|
 | 
						|
Iterator.prototype.peekType = function () { | 
						|
  if (this.ops[this.index]) { | 
						|
    if (typeof this.ops[this.index]['delete'] === 'number') { | 
						|
      return 'delete'; | 
						|
    } else if (typeof this.ops[this.index].retain === 'number') { | 
						|
      return 'retain'; | 
						|
    } else { | 
						|
      return 'insert'; | 
						|
    } | 
						|
  } | 
						|
  return 'retain'; | 
						|
}; | 
						|
 | 
						|
Iterator.prototype.rest = function () { | 
						|
  if (!this.hasNext()) { | 
						|
    return []; | 
						|
  } else if (this.offset === 0) { | 
						|
    return this.ops.slice(this.index); | 
						|
  } else { | 
						|
    var offset = this.offset; | 
						|
    var index = this.index; | 
						|
    var next = this.next(); | 
						|
    var rest = this.ops.slice(this.index); | 
						|
    this.offset = offset; | 
						|
    this.index = index; | 
						|
    return [next].concat(rest); | 
						|
  } | 
						|
}; | 
						|
 | 
						|
 | 
						|
module.exports = lib;
 | 
						|
 |