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