| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 | 
							- 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;
 
 
  |