Commit d9e77f60 authored by Romain Courteaud's avatar Romain Courteaud

Drop not used code.

parent 1581dc4a
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global exports, deepClone, jsonDeepClone */
/**
* A class to manipulate metadata
*
* @class Metadata
* @constructor
*/
function Metadata(metadata) {
if (arguments.length > 0) {
if (metadata === null || typeof metadata !== 'object' ||
Array.isArray(metadata)) {
throw new TypeError("Metadata(): Optional argument 1 is not an object");
}
this._dict = metadata;
} else {
this._dict = {};
}
}
Metadata.prototype.format = function () {
return this.update(this._dict);
};
Metadata.prototype.check = function () {
var k;
for (k in this._dict) {
if (this._dict.hasOwnProperty(k)) {
if (k[0] !== '_') {
if (!Metadata.checkValue(this._dict[k])) {
return false;
}
}
}
}
return true;
};
Metadata.prototype.update = function (metadata) {
var k;
for (k in metadata) {
if (metadata.hasOwnProperty(k)) {
if (k[0] === '_') {
this._dict[k] = jsonDeepClone(metadata[k]);
} else {
this._dict[k] = Metadata.normalizeValue(metadata[k]);
}
if (this._dict[k] === undefined) {
delete this._dict[k];
}
}
}
return this;
};
Metadata.prototype.get = function (key) {
return this._dict[key];
};
Metadata.prototype.add = function (key, value) {
var i;
if (key[0] === '_') {
return this;
}
if (this._dict[key] === undefined) {
this._dict[key] = Metadata.normalizeValue(value);
if (this._dict[key] === undefined) {
delete this._dict[key];
}
return this;
}
if (!Array.isArray(this._dict[key])) {
this._dict[key] = [this._dict[key]];
}
value = Metadata.normalizeValue(value);
if (value === undefined) {
return this;
}
if (!Array.isArray(value)) {
value = [value];
}
for (i = 0; i < value.length; i += 1) {
this._dict[key][this._dict[key].length] = value[i];
}
return this;
};
Metadata.prototype.set = function (key, value) {
if (key[0] === '_') {
this._dict[key] = JSON.parse(JSON.stringify(value));
} else {
this._dict[key] = Metadata.normalizeValue(value);
}
if (this._dict[key] === undefined) {
delete this._dict[key];
}
return this;
};
Metadata.prototype.remove = function (key) {
delete this._dict[key];
return this;
};
Metadata.prototype.forEach = function (key, fun) {
var k, i, value, that = this;
if (typeof key === 'function') {
fun = key;
key = undefined;
}
function forEach(key, fun) {
value = that._dict[key];
if (!Array.isArray(that._dict[key])) {
value = [value];
}
for (i = 0; i < value.length; i += 1) {
if (typeof value[i] === 'object') {
fun.call(that, key, deepClone(value[i]), i);
} else {
fun.call(that, key, {'content': value[i]}, i);
}
}
}
if (key === undefined) {
for (k in this._dict) {
if (this._dict.hasOwnProperty(k)) {
forEach(k, fun);
}
}
} else {
forEach(key, fun);
}
return this;
};
Metadata.prototype.toFullDict = function () {
var dict = {};
this.forEach(function (key, value, index) {
dict[key] = dict[key] || [];
dict[key][index] = value;
});
return dict;
};
Metadata.asJsonableValue = function (value) {
switch (typeof value) {
case 'string':
case 'boolean':
return value;
case 'number':
if (isFinite(value)) {
return value;
}
return null;
case 'object':
if (value === null) {
return null;
}
if (value instanceof Date) {
// XXX this block is to enable phantomjs and browsers compatibility with
// Date.prototype.toJSON when it is a invalid date. In phantomjs, it
// returns `"Invalid Date"` but in browsers it returns `null`. Here, the
// result will always be `null`.
if (isNaN(value.getTime())) {
return null;
}
}
if (typeof value.toJSON === 'function') {
return Metadata.asJsonableValue(value.toJSON());
}
return value; // dict, array
// case 'undefined':
default:
return null;
}
};
Metadata.isDict = function (o) {
return typeof o === 'object' &&
Object.getPrototypeOf(o || []) === Object.prototype;
};
Metadata.isContent = function (c) {
return typeof c === 'string' ||
(typeof c === 'number' && isFinite(c)) ||
typeof c === 'boolean';
};
Metadata.contentValue = function (value) {
if (Array.isArray(value)) {
return Metadata.contentValue(value[0]);
}
if (Metadata.isDict(value)) {
return value.content;
}
return value;
};
Metadata.normalizeArray = function (value) {
var i;
value = value.slice();
i = 0;
while (i < value.length) {
value[i] = Metadata.asJsonableValue(value[i]);
if (Metadata.isDict(value[i])) {
value[i] = Metadata.normalizeObject(value[i]);
if (value[i] === undefined) {
value.splice(i, 1);
} else {
i += 1;
}
} else if (Metadata.isContent(value[i])) {
i += 1;
} else {
value.splice(i, 1);
}
}
if (value.length === 0) {
return;
}
if (value.length === 1) {
return value[0];
}
return value;
};
Metadata.normalizeObject = function (value) {
var i, count = 0, ok = false, new_value = {};
for (i in value) {
if (value.hasOwnProperty(i)) {
value[i] = Metadata.asJsonableValue(value[i]);
if (Metadata.isContent(value[i])) {
new_value[i] = value[i];
if (new_value[i] === undefined) {
delete new_value[i];
}
count += 1;
if (i === 'content') {
ok = true;
}
}
}
}
if (ok === false) {
return;
}
if (count === 1) {
return new_value.content;
}
return new_value;
};
Metadata.normalizeValue = function (value) {
value = Metadata.asJsonableValue(value);
if (Metadata.isContent(value)) {
return value;
}
if (Array.isArray(value)) {
return Metadata.normalizeArray(value);
}
if (Metadata.isDict(value)) {
return Metadata.normalizeObject(value);
}
};
Metadata.checkArray = function (value) {
var i;
for (i = 0; i < value.length; i += 1) {
if (Metadata.isDict(value[i])) {
if (!Metadata.checkObject(value[i])) {
return false;
}
} else if (!Metadata.isContent(value[i])) {
return false;
}
}
return true;
};
Metadata.checkObject = function (value) {
var i, ok = false;
for (i in value) {
if (value.hasOwnProperty(i)) {
if (Metadata.isContent(value[i])) {
if (i === 'content') {
ok = true;
}
} else {
return false;
}
}
}
if (ok === false) {
return false;
}
return true;
};
Metadata.checkValue = function (value) {
if (Metadata.isContent(value)) {
return true;
}
if (Array.isArray(value)) {
return Metadata.checkArray(value);
}
if (Metadata.isDict(value)) {
return Metadata.checkObject(value);
}
return false;
};
exports.Metadata = Metadata;
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global uniqueJSONStringify, methodType */
var defaults = {}, constants = {};
defaults.storage_types = {};
constants.dcmi_types = {
'Collection': 'Collection',
'Dataset': 'Dataset',
'Event': 'Event',
'Image': 'Image',
'InteractiveResource': 'InteractiveResource',
'MovingImage': 'MovingImage',
'PhysicalObject': 'PhysicalObject',
'Service': 'Service',
'Software': 'Software',
'Sound': 'Sound',
'StillImage': 'StillImage',
'Text': 'Text'
};
// if (dcmi_types.Collection === 'Collection') { is a DCMI type }
// if (typeof dcmi_types[name] === 'string') { is a DCMI type }
constants.http_status_text = {
"0": "Unknown",
"550": "Internal JIO Error",
"551": "Internal Storage Error",
"555": "Cancelled",
"Unknown": "Unknown",
"Internal JIO Error": "Internal JIO Error",
"Internal Storage Error": "Internal Storage Error",
"Cancelled": "Cancelled",
"unknown": "Unknown",
"internal_jio_error": "Internal JIO Error",
"internal_storage_error": "Internal Storage Error",
"cancelled": "Cancelled",
"200": "Ok",
"201": "Created",
"204": "No Content",
"205": "Reset Content",
"206": "Partial Content",
"304": "Not Modified",
"400": "Bad Request",
"401": "Unauthorized",
"402": "Payment Required",
"403": "Forbidden",
"404": "Not Found",
"405": "Method Not Allowed",
"406": "Not Acceptable",
"407": "Proxy Authentication Required",
"408": "Request Timeout",
"409": "Conflict",
"410": "Gone",
"411": "Length Required",
"412": "Precondition Failed",
"413": "Request Entity Too Large",
"414": "Request-URI Too Long",
"415": "Unsupported Media Type",
"416": "Requested Range Not Satisfiable",
"417": "Expectation Failed",
"418": "I'm a teapot",
"419": "Authentication Timeout",
"500": "Internal Server Error",
"501": "Not Implemented",
"502": "Bad Gateway",
"503": "Service Unavailable",
"504": "Gateway Timeout",
"507": "Insufficient Storage",
"Ok": "Ok",
"OK": "Ok",
"Created": "Created",
"No Content": "No Content",
"Reset Content": "Reset Content",
"Partial Content": "Partial Content",
"Not Modified": "Not Modified",
"Bad Request": "Bad Request",
"Unauthorized": "Unauthorized",
"Payment Required": "Payment Required",
"Forbidden": "Forbidden",
"Not Found": "Not Found",
"Method Not Allowed": "Method Not Allowed",
"Not Acceptable": "Not Acceptable",
"Proxy Authentication Required": "Proxy Authentication Required",
"Request Timeout": "Request Timeout",
"Conflict": "Conflict",
"Gone": "Gone",
"Length Required": "Length Required",
"Precondition Failed": "Precondition Failed",
"Request Entity Too Large": "Request Entity Too Large",
"Request-URI Too Long": "Request-URI Too Long",
"Unsupported Media Type": "Unsupported Media Type",
"Requested Range Not Satisfiable": "Requested Range Not Satisfiable",
"Expectation Failed": "Expectation Failed",
"I'm a teapot": "I'm a teapot",
"Authentication Timeout": "Authentication Timeout",
"Internal Server Error": "Internal Server Error",
"Not Implemented": "Not Implemented",
"Bad Gateway": "Bad Gateway",
"Service Unavailable": "Service Unavailable",
"Gateway Timeout": "Gateway Timeout",
"Insufficient Storage": "Insufficient Storage",
"ok": "Ok",
"created": "Created",
"no_content": "No Content",
"reset_content": "Reset Content",
"partial_content": "Partial Content",
"not_modified": "Not Modified",
"bad_request": "Bad Request",
"unauthorized": "Unauthorized",
"payment_required": "Payment Required",
"forbidden": "Forbidden",
"not_found": "Not Found",
"method_not_allowed": "Method Not Allowed",
"not_acceptable": "Not Acceptable",
"proxy_authentication_required": "Proxy Authentication Required",
"request_timeout": "Request Timeout",
"conflict": "Conflict",
"gone": "Gone",
"length_required": "Length Required",
"precondition_failed": "Precondition Failed",
"request_entity_too_large": "Request Entity Too Large",
"request-uri_too_long": "Request-URI Too Long",
"unsupported_media_type": "Unsupported Media Type",
"requested_range_not_satisfiable": "Requested Range Not Satisfiable",
"expectation_failed": "Expectation Failed",
"im_a_teapot": "I'm a teapot",
"authentication_timeout": "Authentication Timeout",
"internal_server_error": "Internal Server Error",
"not_implemented": "Not Implemented",
"bad_gateway": "Bad Gateway",
"service_unavailable": "Service Unavailable",
"gateway_timeout": "Gateway Timeout",
"insufficient_storage": "Insufficient Storage"
};
constants.http_status = {
"0": 0,
"550": 550,
"551": 551,
"555": 555,
"Unknown": 0,
"Internal JIO Error": 550,
"Internal Storage Error": 551,
"Cancelled": 555,
"unknown": 0,
"internal_jio_error": 550,
"internal_storage_error": 551,
"cancelled": 555,
"200": 200,
"201": 201,
"204": 204,
"205": 205,
"206": 206,
"304": 304,
"400": 400,
"401": 401,
"402": 402,
"403": 403,
"404": 404,
"405": 405,
"406": 406,
"407": 407,
"408": 408,
"409": 409,
"410": 410,
"411": 411,
"412": 412,
"413": 413,
"414": 414,
"415": 415,
"416": 416,
"417": 417,
"418": 418,
"419": 419,
"500": 500,
"501": 501,
"502": 502,
"503": 503,
"504": 504,
"507": 507,
"Ok": 200,
"OK": 200,
"Created": 201,
"No Content": 204,
"Reset Content": 205,
"Partial Content": 206,
"Not Modified": 304,
"Bad Request": 400,
"Unauthorized": 401,
"Payment Required": 402,
"Forbidden": 403,
"Not Found": 404,
"Method Not Allowed": 405,
"Not Acceptable": 406,
"Proxy Authentication Required": 407,
"Request Timeout": 408,
"Conflict": 409,
"Gone": 410,
"Length Required": 411,
"Precondition Failed": 412,
"Request Entity Too Large": 413,
"Request-URI Too Long": 414,
"Unsupported Media Type": 415,
"Requested Range Not Satisfiable": 416,
"Expectation Failed": 417,
"I'm a teapot": 418,
"Authentication Timeout": 419,
"Internal Server Error": 500,
"Not Implemented": 501,
"Bad Gateway": 502,
"Service Unavailable": 503,
"Gateway Timeout": 504,
"Insufficient Storage": 507,
"ok": 200,
"created": 201,
"no_content": 204,
"reset_content": 205,
"partial_content": 206,
"not_modified": 304,
"bad_request": 400,
"unauthorized": 401,
"payment_required": 402,
"forbidden": 403,
"not_found": 404,
"method_not_allowed": 405,
"not_acceptable": 406,
"proxy_authentication_required": 407,
"request_timeout": 408,
"conflict": 409,
"gone": 410,
"length_required": 411,
"precondition_failed": 412,
"request_entity_too_large": 413,
"request-uri_too_long": 414,
"unsupported_media_type": 415,
"requested_range_not_satisfiable": 416,
"expectation_failed": 417,
"im_a_teapot": 418,
"authentication_timeout": 419,
"internal_server_error": 500,
"not_implemented": 501,
"bad_gateway": 502,
"service_unavailable": 503,
"gateway_timeout": 504,
"insufficient_storage": 507
};
constants.http_action = {
"0": "error",
"550": "error",
"551": "error",
"555": "error",
"Unknown": "error",
"Internal JIO Error": "error",
"Internal Storage Error": "error",
"Cancelled": "error",
"unknown": "error",
"internal_jio_error": "error",
"internal_storage_error": "error",
"cancelled": "error",
"200": "success",
"201": "success",
"204": "success",
"205": "success",
"206": "success",
"304": "success",
"400": "error",
"401": "error",
"402": "error",
"403": "error",
"404": "error",
"405": "error",
"406": "error",
"407": "error",
"408": "error",
"409": "error",
"410": "error",
"411": "error",
"412": "error",
"413": "error",
"414": "error",
"415": "error",
"416": "error",
"417": "error",
"418": "error",
"419": "retry",
"500": "retry",
"501": "error",
"502": "error",
"503": "retry",
"504": "retry",
"507": "error",
"Ok": "success",
"OK": "success",
"Created": "success",
"No Content": "success",
"Reset Content": "success",
"Partial Content": "success",
"Not Modified": "success",
"Bad Request": "error",
"Unauthorized": "error",
"Payment Required": "error",
"Forbidden": "error",
"Not Found": "error",
"Method Not Allowed": "error",
"Not Acceptable": "error",
"Proxy Authentication Required": "error",
"Request Timeout": "error",
"Conflict": "error",
"Gone": "error",
"Length Required": "error",
"Precondition Failed": "error",
"Request Entity Too Large": "error",
"Request-URI Too Long": "error",
"Unsupported Media Type": "error",
"Requested Range Not Satisfiable": "error",
"Expectation Failed": "error",
"I'm a teapot": "error",
"Authentication Timeout": "retry",
"Internal Server Error": "retry",
"Not Implemented": "error",
"Bad Gateway": "error",
"Service Unavailable": "retry",
"Gateway Timeout": "retry",
"Insufficient Storage": "error",
"ok": "success",
"created": "success",
"no_content": "success",
"reset_content": "success",
"partial_content": "success",
"not_modified": "success",
"bad_request": "error",
"unauthorized": "error",
"payment_required": "error",
"forbidden": "error",
"not_found": "error",
"method_not_allowed": "error",
"not_acceptable": "error",
"proxy_authentication_required": "error",
"request_timeout": "error",
"conflict": "error",
"gone": "error",
"length_required": "error",
"precondition_failed": "error",
"request_entity_too_large": "error",
"request-uri_too_long": "error",
"unsupported_media_type": "error",
"requested_range_not_satisfiable": "error",
"expectation_failed": "error",
"im_a_teapot": "error",
"authentication_timeout": "retry",
"internal_server_error": "retry",
"not_implemented": "error",
"bad_gateway": "error",
"service_unavailable": "retry",
"gateway_timeout": "retry",
"insufficient_storage": "error"
};
constants.content_type_re =
/^([a-z]+\/[a-zA-Z0-9\+\-\.]+)(?:\s*;\s*charset\s*=\s*([a-zA-Z0-9\-]+))?$/;
/**
* Function that does nothing
*/
constants.emptyFunction = function () {
return;
};
defaults.job_rule_conditions = {};
/**
* Adds some job rule conditions
*/
(function () {
/**
* Compare two jobs and test if they use the same storage description
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function sameStorageDescription(a, b) {
return uniqueJSONStringify(a.storage_spec) ===
uniqueJSONStringify(b.storage_spec);
}
/**
* Compare two jobs and test if they are writers
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function areWriters(a, b) {
return methodType(a.method) === 'writer' &&
methodType(b.method) === 'writer';
}
/**
* Compare two jobs and test if they use metadata only
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function useMetadataOnly(a, b) {
if (['post', 'put', 'get', 'remove', 'allDocs'].indexOf(a.method) === -1) {
return false;
}
if (['post', 'put', 'get', 'remove', 'allDocs'].indexOf(b.method) === -1) {
return false;
}
return true;
}
/**
* Compare two jobs and test if they are readers
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function areReaders(a, b) {
return methodType(a.method) === 'reader' &&
methodType(b.method) === 'reader';
}
/**
* Compare two jobs and test if their methods are the same
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function sameMethod(a, b) {
return a.method === b.method;
}
/**
* Compare two jobs and test if their document ids are the same
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function sameDocumentId(a, b) {
return a.kwargs._id === b.kwargs._id;
}
/**
* Test if the jobs have a document id.
*
* @param {Object} a The first job to test
* @param {Object} b The second job to test
* @return {Boolean} True if ids exist, else false
*/
function haveDocumentIds(a, b) {
if (typeof a.kwargs._id !== "string" || a.kwargs._id === "") {
return false;
}
if (typeof b.kwargs._id !== "string" || b.kwargs._id === "") {
return false;
}
return true;
}
/**
* Compare two jobs and test if their kwargs are equal
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function sameParameters(a, b) {
return uniqueJSONStringify(a.kwargs) ===
uniqueJSONStringify(b.kwargs);
}
/**
* Compare two jobs and test if their options are equal
*
* @param {Object} a The first job to compare
* @param {Object} b The second job to compare
* @return {Boolean} True if equal, else false
*/
function sameOptions(a, b) {
return uniqueJSONStringify(a.options) ===
uniqueJSONStringify(b.options);
}
defaults.job_rule_conditions = {
"sameStorageDescription": sameStorageDescription,
"areWriters": areWriters,
"areReaders": areReaders,
"useMetadataOnly": useMetadataOnly,
"sameMethod": sameMethod,
"sameDocumentId": sameDocumentId,
"sameParameters": sameParameters,
"sameOptions": sameOptions,
"haveDocumentIds": haveDocumentIds
};
}());
/*jslint indent: 2, maxlen: 80, nomen: true, sloppy: true */
/*global exports, Blob, FileReader, RSVP, hex_sha256, XMLHttpRequest,
constants, console */
/**
* Do not exports these tools unless they are not writable, not configurable.
*/
exports.util = {};
/**
* Inherits the prototype methods from one constructor into another. The
* prototype of `constructor` will be set to a new object created from
* `superConstructor`.
*
* @param {Function} constructor The constructor which inherits the super
* one
* @param {Function} superConstructor The super constructor
*/
function inherits(constructor, superConstructor) {
constructor.super_ = superConstructor;
constructor.prototype = Object.create(superConstructor.prototype, {
"constructor": {
"configurable": true,
"enumerable": false,
"writable": true,
"value": constructor
}
});
}
/**
* Clones jsonable object in depth
*
* @param {A} object The jsonable object to clone
* @return {A} The cloned object
*/
function jsonDeepClone(object) {
var tmp = JSON.stringify(object);
if (tmp === undefined) {
return undefined;
}
return JSON.parse(tmp);
}
exports.util.jsonDeepClone = jsonDeepClone;
/**
* Update a dictionary by adding/replacing key values from another dict.
* Enumerable values equal to undefined are also used.
*
* @param {Object} original The dict to update
* @param {Object} other The other dict
* @return {Object} The updated original dict
*/
function dictUpdate(original, other) {
var k;
for (k in other) {
if (other.hasOwnProperty(k)) {
original[k] = other[k];
}
}
return original;
}
exports.util.dictUpdate = dictUpdate;
/**
* Like 'dict.clear()' in python. Delete all dict entries.
*
* @method dictClear
* @param {Object} self The dict to clear
*/
function dictClear(dict) {
var i;
for (i in dict) {
if (dict.hasOwnProperty(i)) {
delete dict[i];
// dictClear(dict);
// break;
}
}
}
exports.util.dictClear = dictClear;
/**
* Filter a dict to keep only values which keys are in `keys` list.
*
* @param {Object} dict The dict to filter
* @param {Array} keys The key list to keep
*/
function dictFilter(dict, keys) {
var i, buffer = [];
for (i = 0; i < keys.length; i += 1) {
buffer[i] = dict[keys[i]];
}
dictClear(dict);
for (i = 0; i < buffer.length; i += 1) {
dict[keys[i]] = buffer[i];
}
}
exports.util.dictFilter = dictFilter;
/**
* Gets all elements of an array and classifies them in a dict of array.
* Dict keys are element types, and values are list of element of type 'key'.
*
* @param {Array} array The array of elements to pop
* @return {Object} The type dict
*/
function arrayValuesToTypeDict(array) {
var i, l, type_object = {}, type, v;
for (i = 0, l = array.length; i < l; i += 1) {
v = array[i];
type = Array.isArray(v) ? "array" : typeof v;
/*jslint ass: true */
(type_object[type] = type_object[type] || []).push(v);
}
return type_object;
}
/**
* Concatenate a `string` `n` times.
*
* @param {String} string The string to concat
* @param {Number} n The number of time to concat
* @return {String} The concatenated string
*/
function concatStringNTimes(string, n) {
/*jslint plusplus: true */
var res = "";
while (--n >= 0) { res += string; }
return res;
}
/**
* JSON stringify a value. Object keys are sorted in order to make a kind of
* deepEqual thanks to a simple string comparison.
*
* JSON.stringify({"a": "b", "c": "d"}) ===
* JSON.stringify({"c": "d", "a": "b"}) // false
*
* deepEqual({"a": "b", "c": "d"}, {"c": "d", "a": "b"}); // true
*
* uniqueJSONStringify({"a": "b", "c": "d"}) ===
* uniqueJSONStringify({"c": "d", "a": "b"}) // true
*
* @param {Any} value The value to stringify
* @param {Function,Array} [replacer] A function to replace values during parse
* @param {String,Number} [space] Causes the result to be pretty-printed
* @return {String} The unique JSON stringified value
*/
function uniqueJSONStringify(value, replacer, space) {
var indent, key_value_space = "";
if (typeof space === "string") {
if (space !== "") {
indent = space;
key_value_space = " ";
}
} else if (typeof space === "number") {
if (isFinite(space) && space > 0) {
indent = concatStringNTimes(" ", space);
key_value_space = " ";
}
}
function uniqueJSONStringifyRec(key, value, deep) {
var i, l, res, my_space;
if (value && typeof value.toJSON === "function") {
value = value.toJSON();
}
if (typeof replacer === "function") {
value = replacer(key, value);
}
if (indent) {
my_space = concatStringNTimes(indent, deep);
}
if (Array.isArray(value)) {
res = [];
for (i = 0; i < value.length; i += 1) {
res[res.length] = uniqueJSONStringifyRec(i, value[i], deep + 1);
if (res[res.length - 1] === undefined) {
res[res.length - 1] = "null";
}
}
if (res.length === 0) { return "[]"; }
if (indent) {
return "[\n" + my_space + indent +
res.join(",\n" + my_space + indent) +
"\n" + my_space + "]";
}
return "[" + res.join(",") + "]";
}
if (typeof value === "object" && value !== null) {
if (Array.isArray(replacer)) {
res = replacer.reduce(function (p, c) {
p.push(c);
return p;
}, []);
} else {
res = Object.keys(value);
}
res.sort();
for (i = 0, l = res.length; i < l; i += 1) {
key = res[i];
res[i] = uniqueJSONStringifyRec(key, value[key], deep + 1);
if (res[i] !== undefined) {
res[i] = JSON.stringify(key) + ":" + key_value_space + res[i];
} else {
res.splice(i, 1);
l -= 1;
i -= 1;
}
}
if (res.length === 0) { return "{}"; }
if (indent) {
return "{\n" + my_space + indent +
res.join(",\n" + my_space + indent) +
"\n" + my_space + "}";
}
return "{" + res.join(",") + "}";
}
return JSON.stringify(value);
}
return uniqueJSONStringifyRec("", value, 0);
}
exports.util.uniqueJSONStringify = uniqueJSONStringify;
function makeBinaryStringDigest(string) {
return 'sha256-' + hex_sha256(string);
}
exports.util.makeBinaryStringDigest = makeBinaryStringDigest;
/**
* Acts like `Array.prototype.concat` but does not create a copy of the original
* array. It extends the original array and return it.
*
* @param {Array} array The array to extend
* @param {Any} [args]* Values to add in the array
* @return {Array} The original array
*/
function arrayExtend(array) { // args*
var i, j;
for (i = 1; i < arguments.length; i += 1) {
if (Array.isArray(arguments[i])) {
for (j = 0; j < arguments[i].length; j += 1) {
array[array.length] = arguments[i][j];
}
} else {
array[array.length] = arguments[i];
}
}
return array;
}
exports.util.arrayExtend = arrayExtend;
/**
* Acts like `Array.prototype.concat` but does not create a copy of the original
* array. It extends the original array from a specific position and return it.
*
* @param {Array} array The array to extend
* @param {Number} position The position where to extend
* @param {Any} [args]* Values to add in the array
* @return {Array} The original array
*/
function arrayInsert(array, position) { // args*
var array_part = array.splice(position, array.length - position);
arrayExtend.apply(null, arrayExtend([
], [array], Array.prototype.slice.call(arguments, 2)));
return arrayExtend(array, array_part);
}
exports.util.arrayInsert = arrayInsert;
/**
* Guess if the method is a writer or a reader.
*
* @param {String} method The method name
* @return {String} "writer", "reader" or "unknown"
*/
function methodType(method) {
switch (method) {
case "post":
case "put":
case "putAttachment":
case "remove":
case "removeAttachment":
case "repair":
return 'writer';
case "get":
case "getAttachment":
case "allDocs":
case "check":
return 'reader';
default:
return 'unknown';
}
}
/**
* forEach(array, callback[, thisArg]): Promise
*
* It executes the provided `callback` once for each element of the array with
* an assigned value asynchronously. If the `callback` returns a promise, then
* the function will wait for its fulfillment before executing the next
* iteration.
*
* `callback` is invoked with three arguments:
*
* - the element value
* - the element index
* - the array being traversed
*
* If a `thisArg` parameter is provided to `forEach`, it will be passed to
* `callback` when invoked, for use as its `this` value. Otherwise, the value
* `undefined` will be passed for use as its `this` value.
*
* Unlike `Array.prototype.forEach`, you can stop the iteration by throwing
* something, or by doing a `cancel` to the returned promise if it is
* cancellable promise.
*
* Inspired by `Array.prototype.forEach` from Mozilla Developer Network.
*
* @param {Array} array The array to parse
* @param {Function} callback Function to execute for each element.
* @param {Any} [thisArg] Value to use as `this` when executing `callback`.
* @param {Promise} A new promise.
*/
function forEach(array, fn, thisArg) {
if (arguments.length === 0) {
throw new TypeError("missing argument 0 when calling function forEach");
}
if (!Array.isArray(array)) {
throw new TypeError(array + " is not an array");
}
if (arguments.length === 1) {
throw new TypeError("missing argument 1 when calling function forEach");
}
if (typeof fn !== "function") {
throw new TypeError(fn + " is not a function");
}
var cancelled, current_promise = RSVP.resolve();
return new RSVP.Promise(function (done, fail, notify) {
var i = 0;
function next() {
if (cancelled) {
fail(new Error("Cancelled"));
return;
}
if (i < array.length) {
current_promise =
current_promise.then(fn.bind(thisArg, array[i], i, array));
current_promise.then(next, fail, notify);
i += 1;
return;
}
done();
}
next();
}, function () {
cancelled = true;
if (typeof current_promise.cancel === "function") {
current_promise.cancel();
}
});
}
exports.util.forEach = forEach;
/**
* range(stop, callback): Promise
* range(start, stop[, step], callback): Promise
*
* It executes the provided `callback` once for each step between `start` and
* `stop`. If the `callback` returns a promise, then the function will wait
* for its fulfillment before executing the next iteration.
*
* `callback` is invoked with one argument:
*
* - the index of the step
*
* `start`, `stop` and `step` must be finite numbers. If `step` is not
* provided, then the default step will be `1`. If `start` and `step` are not
* provided, `start` will be `0` and `step` will be `1`.
*
* Inspired by `range()` from Python 3 built-in functions.
*
* range(10, function (index) {
* return notifyIndex(index);
* }).then(onDone, onError, onNotify);
*
* @param {Number} [start=0] The start index
* @param {Number} stop The stop index
* @param {Number} [step=1] One step
* @param {Function} callback Function to execute on each iteration.
* @param {Promise} A new promise with no fulfillment value.
*/
function range(start, stop, step, callback) {
var type_object, cancelled, current_promise;
type_object = arrayValuesToTypeDict([start, stop, step, callback]);
if (type_object["function"].length !== 1) {
throw new TypeError("range(): only one callback is needed");
}
start = type_object.number.length;
if (start < 1) {
throw new TypeError("range(): 1, 2 or 3 numbers are needed");
}
if (start > 3) {
throw new TypeError("range(): only 1, 2 or 3 numbers are needed");
}
callback = type_object["function"][0];
if (start === 1) {
start = 0;
stop = type_object.number[0];
step = 1;
}
if (start === 2) {
start = type_object.number[0];
stop = type_object.number[1];
step = 1;
}
if (start === 3) {
start = type_object.number[0];
stop = type_object.number[1];
step = type_object.number[2];
if (step === 0) {
throw new TypeError("range(): step must not be zero");
}
}
type_object = undefined;
current_promise = RSVP.resolve();
return new RSVP.Promise(function (done, fail, notify) {
var i = start, test;
function next() {
if (cancelled) {
fail(new Error("Cancelled"));
return;
}
test = step > 0 ? i < stop : i > stop;
if (test) {
current_promise = current_promise.then(callback.bind(null, i));
current_promise.then(next, fail, notify);
i += step;
return;
}
done();
}
next();
}, function () {
cancelled = true;
if (typeof current_promise.cancel === "function") {
current_promise.cancel();
}
});
}
exports.util.range = range;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment