!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.pouchCollate=e():"undefined"!=typeof global?global.pouchCollate=e():"undefined"!=typeof self&&(self.pouchCollate=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1, 1 // 1 -> 1, 2 // 2 -> 2, 2 return key .replace(/\u0002/g, '\u0002\u0002') .replace(/\u0001/g, '\u0001\u0002') .replace(/\u0000/g, '\u0001\u0001'); case 'object': var isArray = Array.isArray(key); var arr = isArray ? key : Object.keys(key); var i = -1; var len = arr.length; var result = ''; if (isArray) { while (++i < len) { result += exports.toIndexableString(arr[i]); } } else { while (++i < len) { var objKey = arr[i]; result += exports.toIndexableString(objKey) + exports.toIndexableString(key[objKey]); } } return result; } } return ''; } // convert the given key to a string that would be appropriate // for lexical sorting, e.g. within a database, where the // sorting is the same given by the collate() function. exports.toIndexableString = function (key) { var zero = '\u0000'; key = exports.normalizeKey(key); return collationIndex(key) + SEP + indexify(key) + zero; }; function parseNumber(str, i) { var originalIdx = i; var num; var zero = str[i] === '1'; if (zero) { num = 0; i++; } else { var neg = str[i] === '0'; i++; var numAsString = ''; var magAsString = str.substring(i, i + MAGNITUDE_DIGITS); var magnitude = parseInt(magAsString, 10) + MIN_MAGNITUDE; if (neg) { magnitude = -magnitude; } i += MAGNITUDE_DIGITS; while (true) { var ch = str[i]; if (ch === '\u0000') { break; } else { numAsString += ch; } i++; } numAsString = numAsString.split('.'); if (numAsString.length === 1) { num = parseInt(numAsString, 10); } else { num = parseFloat(numAsString[0] + '.' + numAsString[1]); } if (neg) { num = num - 10; } if (magnitude !== 0) { // parseFloat is more reliable than pow due to rounding errors // e.g. Number.MAX_VALUE would return Infinity if we did // num * Math.pow(10, magnitude); num = parseFloat(num + 'e' + magnitude); } } return {num: num, length : i - originalIdx}; } // move up the stack while parsing // this function moved outside of parseIndexableString for performance function pop(stack, metaStack) { var obj = stack.pop(); if (metaStack.length) { var lastMetaElement = metaStack[metaStack.length - 1]; if (obj === lastMetaElement.element) { // popping a meta-element, e.g. an object whose value is another object metaStack.pop(); lastMetaElement = metaStack[metaStack.length - 1]; } var element = lastMetaElement.element; var lastElementIndex = lastMetaElement.index; if (Array.isArray(element)) { element.push(obj); } else if (lastElementIndex === stack.length - 2) { // obj with key+value var key = stack.pop(); element[key] = obj; } else { stack.push(obj); // obj with key only } } } exports.parseIndexableString = function (str) { var stack = []; var metaStack = []; // stack for arrays and objects var i = 0; while (true) { var collationIndex = str[i++]; if (collationIndex === '\u0000') { if (stack.length === 1) { return stack.pop(); } else { pop(stack, metaStack); continue; } } switch (collationIndex) { case '1': stack.push(null); break; case '2': stack.push(str[i] === '1'); i++; break; case '3': var parsedNum = parseNumber(str, i); stack.push(parsedNum.num); i += parsedNum.length; break; case '4': var parsedStr = ''; while (true) { var ch = str[i]; if (ch === '\u0000') { break; } parsedStr += ch; i++; } // perform the reverse of the order-preserving replacement // algorithm (see above) parsedStr = parsedStr.replace(/\u0001\u0001/g, '\u0000') .replace(/\u0001\u0002/g, '\u0001') .replace(/\u0002\u0002/g, '\u0002'); stack.push(parsedStr); break; case '5': var arrayElement = { element: [], index: stack.length }; stack.push(arrayElement.element); metaStack.push(arrayElement); break; case '6': var objElement = { element: {}, index: stack.length }; stack.push(objElement.element); metaStack.push(objElement); break; default: throw new Error( 'bad collationIndex or unexpectedly reached end of input: ' + collationIndex); } } }; function arrayCollate(a, b) { var len = Math.min(a.length, b.length); for (var i = 0; i < len; i++) { var sort = exports.collate(a[i], b[i]); if (sort !== 0) { return sort; } } return (a.length === b.length) ? 0 : (a.length > b.length) ? 1 : -1; } function stringCollate(a, b) { // See: https://github.com/daleharvey/pouchdb/issues/40 // This is incompatible with the CouchDB implementation, but its the // best we can do for now return (a === b) ? 0 : ((a > b) ? 1 : -1); } function objectCollate(a, b) { var ak = Object.keys(a), bk = Object.keys(b); var len = Math.min(ak.length, bk.length); for (var i = 0; i < len; i++) { // First sort the keys var sort = exports.collate(ak[i], bk[i]); if (sort !== 0) { return sort; } // if the keys are equal sort the values sort = exports.collate(a[ak[i]], b[bk[i]]); if (sort !== 0) { return sort; } } return (ak.length === bk.length) ? 0 : (ak.length > bk.length) ? 1 : -1; } // The collation is defined by erlangs ordered terms // the atoms null, true, false come first, then numbers, strings, // arrays, then objects // null/undefined/NaN/Infinity/-Infinity are all considered null function collationIndex(x) { var id = ['boolean', 'number', 'string', 'object']; var idx = id.indexOf(typeof x); //false if -1 otherwise true, but fast!!!!1 if (~idx) { if (x === null) { return 1; } if (Array.isArray(x)) { return 5; } return idx < 3 ? (idx + 2) : (idx + 3); } if (Array.isArray(x)) { return 5; } } // conversion: // x yyy zz...zz // x = 0 for negative, 1 for 0, 2 for positive // y = exponent (for negative numbers negated) moved so that it's >= 0 // z = mantisse function numToIndexableString(num) { if (num === 0) { return '1'; } // convert number to exponential format for easier and // more succinct string sorting var expFormat = num.toExponential().split(/e\+?/); var magnitude = parseInt(expFormat[1], 10); var neg = num < 0; var result = neg ? '0' : '2'; // first sort by magnitude // it's easier if all magnitudes are positive var magForComparison = ((neg ? -magnitude : magnitude) - MIN_MAGNITUDE); var magString = utils.padLeft((magForComparison).toString(), '0', MAGNITUDE_DIGITS); result += SEP + magString; // then sort by the factor var factor = Math.abs(parseFloat(expFormat[0])); // [1..10) if (neg) { // for negative reverse ordering factor = 10 - factor; } var factorStr = factor.toFixed(20); // strip zeros from the end factorStr = factorStr.replace(/\.?0+$/, ''); result += SEP + factorStr; return result; } },{"./utils":2}],2:[function(require,module,exports){ 'use strict'; function pad(str, padWith, upToLength) { var padding = ''; var targetLength = upToLength - str.length; while (padding.length < targetLength) { padding += padWith; } return padding; } exports.padLeft = function (str, padWith, upToLength) { var padding = pad(str, padWith, upToLength); return padding + str; }; exports.padRight = function (str, padWith, upToLength) { var padding = pad(str, padWith, upToLength); return str + padding; }; exports.stringLexCompare = function (a, b) { var aLen = a.length; var bLen = b.length; var i; for (i = 0; i < aLen; i++) { if (i === bLen) { // b is shorter substring of a return 1; } var aChar = a.charAt(i); var bChar = b.charAt(i); if (aChar !== bChar) { return aChar < bChar ? -1 : 1; } } if (aLen < bLen) { // a is shorter substring of b return -1; } return 0; }; /* * returns the decimal form for the given integer, i.e. writes * out all the digits (in base-10) instead of using scientific notation */ exports.intToDecimalForm = function (int) { var isNeg = int < 0; var result = ''; do { var remainder = isNeg ? -Math.ceil(int % 10) : Math.floor(int % 10); result = remainder + result; int = isNeg ? Math.ceil(int / 10) : Math.floor(int / 10); } while (int); if (isNeg && result !== '0') { result = '-' + result; } return result; }; },{}]},{},[1]) (1) }); ;