www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit a35461e2fc6847d09e01467bddd3fc27a8b51131
parent 06825c4767fe5c16f52c2cfcebef7c92749933b2
Author: Simon Kornblith <simon@simonster.com>
Date:   Tue, 10 Jul 2012 15:27:38 -0400

Rename q.jsm to q.js, and use a version of q that's closer to the original and allows use in script tags as well

Diffstat:
Mchrome/content/zotero/xpcom/file.js | 2+-
Mchrome/content/zotero/xpcom/http.js | 2+-
Mchrome/content/zotero/xpcom/style.js | 2+-
Aresource/q.js | 1511+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dresource/q.jsm | 1499-------------------------------------------------------------------------------
5 files changed, 1514 insertions(+), 1502 deletions(-)

diff --git a/chrome/content/zotero/xpcom/file.js b/chrome/content/zotero/xpcom/file.js @@ -28,7 +28,7 @@ * @namespace */ Zotero.File = new function(){ - Components.utils.import("resource://zotero/q.jsm"); + Components.utils.import("resource://zotero/q.js"); Components.utils.import("resource://gre/modules/NetUtil.jsm"); Components.utils.import("resource://gre/modules/FileUtils.jsm"); diff --git a/chrome/content/zotero/xpcom/http.js b/chrome/content/zotero/xpcom/http.js @@ -3,7 +3,7 @@ * @namespace */ Zotero.HTTP = new function() { - Components.utils.import("resource://zotero/q.jsm"); + Components.utils.import("resource://zotero/q.js"); /** * Exception returned for unexpected status when promise* is used diff --git a/chrome/content/zotero/xpcom/style.js b/chrome/content/zotero/xpcom/style.js @@ -32,7 +32,7 @@ Zotero.Styles = new function() { var _initialized = false; var _styles, _visibleStyles, _cacheTranslatorData; - Components.utils.import("resource://zotero/q.jsm"); + Components.utils.import("resource://zotero/q.js"); Components.utils.import("resource://gre/modules/Services.jsm"); this.xsltProcessor = null; diff --git a/resource/q.js b/resource/q.js @@ -0,0 +1,1511 @@ +// vim:ts=4:sts=4:sw=4: +/*jshint browser: true, node: true, + curly: true, eqeqeq: true, noarg: true, nonew: true, trailing: true, + undef: true */ +/*global define: false, Q: true, msSetImmediate: false, setImmediate: false, + ReturnValue: false, cajaVM: false, ses: false */ +/*! + * + * Copyright 2009-2012 Kris Kowal under the terms of the MIT + * license found at http://github.com/kriskowal/q/raw/master/LICENSE + * + * With parts by Tyler Close + * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found + * at http://www.opensource.org/licenses/mit-license.html + * Forked at ref_send.js version: 2009-05-11 + * + * With parts by Mark Miller + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * With formatStackTrace and formatSourcePosition functions + * Copyright 2006-2008 the V8 project authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function (definition) { + // Turn off strict mode for this function so we can assign to global.Q + /*jshint strict: false*/ + + // This file will function properly as a <script> tag, or a module + // using CommonJS and NodeJS or RequireJS module formats. In + // Common/Node/RequireJS, the module exports the Q API and when + // executed as a simple <script>, it creates a Q global instead. + + // RequireJS + if (typeof define === "function") { + define(definition); + + // CommonJS + } else if (typeof exports === "object") { + definition(void 0, exports); + + // SES (Secure EcmaScript) + } else if (typeof ses !== "undefined") { + if (!ses.ok()) { + return; + } else { + ses.makeQ = function () { + var Q = {}; + return definition(void 0, Q); + }; + } + + // Mozilla JSM + } else if (~String(this).indexOf('BackstagePass')) { + EXPORTED_SYMBOLS = ["Q"]; + + // Q expects an implementation of setTimeout + setTimeout = new function() { + // We need to maintain references to running nsITimers. Otherwise, they can + // get garbage collected before they fire. + var _runningTimers = []; + + return function setTimeout(func, ms) { + var timer = Components.classes["@mozilla.org/timer;1"]. + createInstance(Components.interfaces.nsITimer); + timer.initWithCallback({"notify":function() { + // Remove timer from array so it can be garbage collected + _runningTimers.splice(_runningTimers.indexOf(timer), 1); + + // Execute callback function + try { + func(); + } catch(err) { + // Rethrow errors that occur so that they appear in the error + // console with the appropriate name and line numbers. While the + // the errors appear without this, the line numbers get eaten. + var scriptError = Components.classes["@mozilla.org/scripterror;1"] + .createInstance(Components.interfaces.nsIScriptError); + scriptError.init( + err.message || err.toString(), + err.fileName || err.filename || null, + null, + err.lineNumber || null, + null, + scriptError.errorFlag, + 'component javascript' + ); + Components.classes["@mozilla.org/consoleservice;1"] + .getService(Components.interfaces.nsIConsoleService) + .logMessage(scriptError); + } + }}, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT); + _runningTimers.push(timer); + } + }; + definition(void 0, Q = {}); + + // <script> + } else { + definition(void 0, Q = {}); + } + +})(function (require, exports) { +"use strict"; + +// shims + +// used for fallback "defend" and in "allResolved" +var noop = function () {}; + +// for the security conscious, defend may be a deep freeze as provided +// by cajaVM. Otherwise we try to provide a shallow freeze just to +// discourage promise changes that are not compatible with secure +// usage. If Object.freeze does not exist, fall back to doing nothing +// (no op). +var defend = Object.freeze || noop; +if (typeof cajaVM !== "undefined") { + defend = cajaVM.def; +} + +// use the fastest possible means to execute a task in a future turn +// of the event loop. +var nextTick; +if (typeof process !== "undefined") { + // node + nextTick = process.nextTick; +} else if (typeof msSetImmediate === "function") { + // IE 10 only, at the moment + // And yes, ``bind``ing to ``window`` is necessary O_o. + nextTick = msSetImmediate.bind(window); +} else if (typeof setImmediate === "function") { + // https://github.com/NobleJS/setImmediate + nextTick = setImmediate; +} else if (typeof MessageChannel !== "undefined") { + // modern browsers + // http://www.nonblocking.io/2011/06/windownexttick.html + var channel = new MessageChannel(); + // linked list of tasks (single, with head node) + var head = {}, tail = head; + channel.port1.onmessage = function () { + head = head.next; + var task = head.task; + delete head.task; + task(); + }; + nextTick = function (task) { + tail = tail.next = {task: task}; + channel.port2.postMessage(0); + }; +} else { + // old browsers + nextTick = function (task) { + setTimeout(task, 0); + }; +} + +// Attempt to make generics safe in the face of downstream +// modifications. +// There is no situation where this is necessary. +// If you need a security guarantee, these primordials need to be +// deeply frozen anyway, and if you don’t need a security guarantee, +// this is just plain paranoid. +// However, this does have the nice side-effect of reducing the size +// of the code by reducing x.call() to merely x(), eliminating many +// hard-to-minify characters. +// See Mark Miller’s explanation of what this does. +// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming +var uncurryThis; +// I have kept both variations because the first is theoretically +// faster, if bind is available. +if (Function.prototype.bind) { + var Function_bind = Function.prototype.bind; + uncurryThis = Function_bind.bind(Function_bind.call); +} else { + uncurryThis = function (f) { + return function (thisp) { + return f.call.apply(f, arguments); + }; + }; +} + +var array_slice = uncurryThis(Array.prototype.slice); + +var array_reduce = uncurryThis( + Array.prototype.reduce || function (callback, basis) { + var index = 0, + length = this.length; + // concerning the initial value, if one is not provided + if (arguments.length === 1) { + // seek to the first value in the array, accounting + // for the possibility that is is a sparse array + do { + if (index in this) { + basis = this[index++]; + break; + } + if (++index >= length) { + throw new TypeError(); + } + } while (1); + } + // reduce + for (; index < length; index++) { + // account for the possibility that the array is sparse + if (index in this) { + basis = callback(basis, this[index], index); + } + } + return basis; + } +); + +var array_indexOf = uncurryThis( + Array.prototype.indexOf || function (value) { + // not a very good shim, but good enough for our one use of it + for (var i = 0; i < this.length; i++) { + if (this[i] === value) { + return i; + } + } + return -1; + } +); + +var array_map = uncurryThis( + Array.prototype.map || function (callback, thisp) { + var self = this; + var collect = []; + array_reduce(self, function (undefined, value, index) { + collect.push(callback.call(thisp, value, index, self)); + }, void 0); + return collect; + } +); + +var object_create = Object.create || function (prototype) { + function Type() { } + Type.prototype = prototype; + return new Type(); +}; + +var object_keys = Object.keys || function (object) { + var keys = []; + for (var key in object) { + keys.push(key); + } + return keys; +}; + +var object_toString = Object.prototype.toString; + +// generator related shims + +function isStopIteration(exception) { + return ( + object_toString(exception) === "[object StopIteration]" || + exception instanceof QReturnValue + ); +} + +var QReturnValue; +if (typeof ReturnValue !== "undefined") { + QReturnValue = ReturnValue; +} else { + QReturnValue = function (value) { + this.value = value; + }; +} + +// long stack traces + +function formatStackTrace(error, frames) { + var lines = []; + try { + lines.push(error.toString()); + } catch (e) { + try { + lines.push("<error: " + e + ">"); + } catch (ee) { + lines.push("<error>"); + } + } + for (var i = 0; i < frames.length; i++) { + var frame = frames[i]; + var line; + + // <Inserted by @domenic> + if (typeof frame === "string") { + lines.push(frame); + // </Inserted by @domenic> + } else { + try { + line = formatSourcePosition(frame); + } catch (e) { + try { + line = "<error: " + e + ">"; + } catch (ee) { + // Any code that reaches this point is seriously nasty! + line = "<error>"; + } + } + lines.push(" at " + line); + } + } + return lines.join("\n"); +} + +function formatSourcePosition(frame) { + var fileLocation = ""; + if (frame.isNative()) { + fileLocation = "native"; + } else if (frame.isEval()) { + fileLocation = "eval at " + frame.getEvalOrigin(); + } else { + var fileName = frame.getFileName(); + if (fileName) { + fileLocation += fileName; + var lineNumber = frame.getLineNumber(); + if (lineNumber !== null) { + fileLocation += ":" + lineNumber; + var columnNumber = frame.getColumnNumber(); + if (columnNumber) { + fileLocation += ":" + columnNumber; + } + } + } + } + if (!fileLocation) { + fileLocation = "unknown source"; + } + var line = ""; + var functionName = frame.getFunction().name; + var addPrefix = true; + var isConstructor = frame.isConstructor(); + var isMethodCall = !(frame.isToplevel() || isConstructor); + if (isMethodCall) { + var methodName = frame.getMethodName(); + line += frame.getTypeName() + "."; + if (functionName) { + line += functionName; + if (methodName && (methodName !== functionName)) { + line += " [as " + methodName + "]"; + } + } else { + line += methodName || "<anonymous>"; + } + } else if (isConstructor) { + line += "new " + (functionName || "<anonymous>"); + } else if (functionName) { + line += functionName; + } else { + line += fileLocation; + addPrefix = false; + } + if (addPrefix) { + line += " (" + fileLocation + ")"; + } + return line; +} + +/* + * Retrieves an array of structured stack frames parsed from the ``stack`` + * property of a given object. + * + * @param objectWithStack {Object} an object with a ``stack`` property: usually + * an error or promise. + * + * @returns an array of stack frame objects. For more information, see + * [V8's JavaScript stack trace API documentation](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi). + */ +function getStackFrames(objectWithStack) { + var oldPrepareStackTrace = Error.prepareStackTrace; + + Error.prepareStackTrace = function (error, frames) { + // Filter out frames from the innards of Node and Q. + return frames.filter(function (frame) { + var fileName = frame.getFileName(); + return ( + fileName !== "module.js" && + fileName !== "node.js" && + fileName !== qFileName + ); + }); + }; + + var stack = objectWithStack.stack; + + Error.prepareStackTrace = oldPrepareStackTrace; + + return stack; +} + +// discover own file name for filtering stack traces +var qFileName; +if (Error.captureStackTrace) { + qFileName = (function () { + var fileName; + + var oldPrepareStackTrace = Error.prepareStackTrace; + + Error.prepareStackTrace = function (error, frames) { + fileName = frames[0].getFileName(); + }; + + // teases call of temporary prepareStackTrace + // JSHint and Closure Compiler generate known warnings here + /*jshint expr: true */ + new Error().stack; + + Error.prepareStackTrace = oldPrepareStackTrace; + + return fileName; + })(); +} + +function deprecate(fn, name, alternative){ + return function () { + if (typeof console !== "undefined" && typeof console.warn === "function"){ + console.warn(name + " is deprecated, use " + alternative + " instead."); + } + return fn.apply(fn,arguments); + }; +} + +// end of shims +// beginning of real work + +/** + * Performs a task in a future turn of the event loop. + * @param {Function} task + */ +exports.nextTick = nextTick; + +/** + * Constructs a {promise, resolve} object. + * + * The resolver is a callback to invoke with a more resolved value for the + * promise. To fulfill the promise, invoke the resolver with any value that is + * not a function. To reject the promise, invoke the resolver with a rejection + * object. To put the promise in the same state as another promise, invoke the + * resolver with that other promise. + */ +exports.defer = defer; +function defer() { + // if "pending" is an "Array", that indicates that the promise has not yet + // been resolved. If it is "undefined", it has been resolved. Each + // element of the pending array is itself an array of complete arguments to + // forward to the resolved promise. We coerce the resolution value to a + // promise using the ref promise because it handles both fully + // resolved values and other promises gracefully. + var pending = [], value; + + var deferred = object_create(defer.prototype); + var promise = object_create(makePromise.prototype); + + promise.promiseSend = function () { + var args = array_slice(arguments); + if (pending) { + pending.push(args); + } else { + nextTick(function () { + value.promiseSend.apply(value, args); + }); + } + }; + + promise.valueOf = function () { + if (pending) { + return promise; + } + return value.valueOf(); + }; + + if (Error.captureStackTrace) { + Error.captureStackTrace(promise, defer); + } + + function become(resolvedValue) { + if (!pending) { + return; + } + value = resolve(resolvedValue); + array_reduce(pending, function (undefined, pending) { + nextTick(function () { + value.promiseSend.apply(value, pending); + }); + }, void 0); + pending = void 0; + return value; + } + + defend(promise); + + deferred.promise = promise; + deferred.resolve = become; + deferred.reject = function (exception) { + return become(reject(exception)); + }; + + return deferred; +} + +/** + * Creates a Node-style callback that will resolve or reject the deferred + * promise. + * @returns a nodeback + */ +defer.prototype.makeNodeResolver = function () { + var self = this; + return function (error, value) { + if (error) { + self.reject(error); + } else if (arguments.length > 2) { + self.resolve(array_slice(arguments, 1)); + } else { + self.resolve(value); + } + }; +}; +// XXX deprecated +defer.prototype.node = deprecate(defer.prototype.makeNodeResolver, "node", "makeNodeResolver"); + +/** + * @param makePromise {Function} a function that returns nothing and accepts + * the resolve and reject functions for a deferred. + * @returns a promise that may be resolved with the given resolve and reject + * functions, or rejected by a thrown exception in makePromise + */ +exports.promise = promise; +function promise(makePromise) { + var deferred = defer(); + call( + makePromise, + void 0, + deferred.resolve, + deferred.reject + ).fail(deferred.reject); + return deferred.promise; +} + +/** + * Constructs a Promise with a promise descriptor object and optional fallback + * function. The descriptor contains methods like when(rejected), get(name), + * put(name, value), post(name, args), and delete(name), which all + * return either a value, a promise for a value, or a rejection. The fallback + * accepts the operation name, a resolver, and any further arguments that would + * have been forwarded to the appropriate method above had a method been + * provided with the proper name. The API makes no guarantees about the nature + * of the returned object, apart from that it is usable whereever promises are + * bought and sold. + */ +exports.makePromise = makePromise; +function makePromise(descriptor, fallback, valueOf, exception) { + if (fallback === void 0) { + fallback = function (op) { + return reject(new Error("Promise does not support operation: " + op)); + }; + } + + var promise = object_create(makePromise.prototype); + + promise.promiseSend = function (op, resolved /* ...args */) { + var args = array_slice(arguments, 2); + var result; + try { + if (descriptor[op]) { + result = descriptor[op].apply(promise, args); + } else { + result = fallback.apply(promise, [op].concat(args)); + } + } catch (exception) { + result = reject(exception); + } + resolved(result); + }; + + if (valueOf) { + promise.valueOf = valueOf; + } + + if (exception) { + promise.exception = exception; + } + + defend(promise); + + return promise; +} + +// provide thenables, CommonJS/Promises/A +makePromise.prototype.then = function (fulfilled, rejected) { + return when(this, fulfilled, rejected); +}; + +// Chainable methods +array_reduce( + [ + "isResolved", "isFulfilled", "isRejected", + "when", "spread", "send", + "get", "put", "del", + "post", "invoke", + "keys", + "apply", "call", "bind", + "fapply", "fcall", "fbind", + "all", "allResolved", + "view", "viewInfo", + "timeout", "delay", + "catch", "finally", "fail", "fin", "end" + ], + function (prev, name) { + makePromise.prototype[name] = function () { + return exports[name].apply( + exports, + [this].concat(array_slice(arguments)) + ); + }; + }, + void 0 +); + +makePromise.prototype.toSource = function () { + return this.toString(); +}; + +makePromise.prototype.toString = function () { + return "[object Promise]"; +}; + +defend(makePromise.prototype); + +/** + * If an object is not a promise, it is as "near" as possible. + * If a promise is rejected, it is as "near" as possible too. + * If it’s a fulfilled promise, the fulfillment value is nearer. + * If it’s a deferred promise and the deferred has been resolved, the + * resolution is "nearer". + * @param object + * @returns most resolved (nearest) form of the object + */ +exports.nearer = valueOf; +function valueOf(value) { + // if !Object.isObject(value) + // generates a known JSHint "constructor invocation without new" warning + // supposed to be fixed, but isn't? https://github.com/jshint/jshint/issues/392 + /*jshint newcap: false */ + if (Object(value) !== value) { + return value; + } else { + return value.valueOf(); + } +} + +/** + * @returns whether the given object is a promise. + * Otherwise it is a fulfilled value. + */ +exports.isPromise = isPromise; +function isPromise(object) { + return object && typeof object.promiseSend === "function"; +} + +/** + * @returns whether the given object is a resolved promise. + */ +exports.isResolved = isResolved; +function isResolved(object) { + return isFulfilled(object) || isRejected(object); +} + +/** + * @returns whether the given object is a value or fulfilled + * promise. + */ +exports.isFulfilled = isFulfilled; +function isFulfilled(object) { + return !isPromise(valueOf(object)); +} + +/** + * @returns whether the given object is a rejected promise. + */ +exports.isRejected = isRejected; +function isRejected(object) { + object = valueOf(object); + return isPromise(object) && 'exception' in object; +} + +var rejections = []; +var errors = []; +if (typeof window !== "undefined" && window.console) { + // This promise library consumes exceptions thrown in handlers so + // they can be handled by a subsequent promise. The rejected + // promises get added to this array when they are created, and + // removed when they are handled. + console.log("Should be empty:", errors); +} + +/** + * Constructs a rejected promise. + * @param exception value describing the failure + */ +exports.reject = reject; +function reject(exception) { + exception = exception || new Error(); + var rejection = makePromise({ + "when": function (rejected) { + // note that the error has been handled + if (rejected) { + var at = array_indexOf(rejections, this); + if (at !== -1) { + errors.splice(at, 1); + rejections.splice(at, 1); + } + } + return rejected ? rejected(exception) : reject(exception); + } + }, function fallback(op) { + return reject(exception); + }, function valueOf() { + return this; + }, exception); + // note that the error has not been handled + rejections.push(rejection); + errors.push(exception); + return rejection; +} + +/** + * Constructs a promise for an immediate reference. + * @param value immediate reference + */ +exports.begin = resolve; // XXX experimental +exports.resolve = resolve; +exports.ref = deprecate(resolve, "ref", "resolve"); // XXX deprecated, use resolve +function resolve(object) { + // If the object is already a Promise, return it directly. This enables + // the resolve function to both be used to created references from objects, + // but to tolerably coerce non-promises to promises. + if (isPromise(object)) { + return object; + } + // assimilate thenables, CommonJS/Promises/A + if (object && typeof object.then === "function") { + var result = defer(); + object.then(result.resolve, result.reject); + return result.promise; + } + return makePromise({ + "when": function (rejected) { + return object; + }, + "get": function (name) { + return object[name]; + }, + "put": function (name, value) { + return object[name] = value; + }, + "del": function (name) { + return delete object[name]; + }, + "post": function (name, value) { + return object[name].apply(object, value); + }, + "apply": function (self, args) { + return object.apply(self, args); + }, + "fapply": function (args) { + return object.apply(void 0, args); + }, + "viewInfo": function () { + var on = object; + var properties = {}; + + function fixFalsyProperty(name) { + if (!properties[name]) { + properties[name] = typeof on[name]; + } + } + + while (on) { + Object.getOwnPropertyNames(on).forEach(fixFalsyProperty); + on = Object.getPrototypeOf(on); + } + return { + "type": typeof object, + "properties": properties + }; + }, + "keys": function () { + return object_keys(object); + } + }, void 0, function valueOf() { + return object; + }); +} + +/** + * Annotates an object such that it will never be + * transferred away from this process over any promise + * communication channel. + * @param object + * @returns promise a wrapping of that object that + * additionally responds to the "isDef" message + * without a rejection. + */ +exports.master = master; +function master(object) { + return makePromise({ + "isDef": function () {} + }, function fallback(op) { + var args = array_slice(arguments); + return send.apply(void 0, [object].concat(args)); + }, function () { + return valueOf(object); + }); +} + +exports.viewInfo = viewInfo; +function viewInfo(object, info) { + object = resolve(object); + if (info) { + return makePromise({ + "viewInfo": function () { + return info; + } + }, function fallback(op) { + var args = array_slice(arguments); + return send.apply(void 0, [object].concat(args)); + }, function () { + return valueOf(object); + }); + } else { + return send(object, "viewInfo"); + } +} + +exports.view = view; +function view(object) { + return viewInfo(object).when(function (info) { + var view; + if (info.type === "function") { + view = function () { + return apply(object, void 0, arguments); + }; + } else { + view = {}; + } + var properties = info.properties || {}; + object_keys(properties).forEach(function (name) { + if (properties[name] === "function") { + view[name] = function () { + return post(object, name, arguments); + }; + } + }); + return resolve(view); + }); +} + +/** + * Registers an observer on a promise. + * + * Guarantees: + * + * 1. that fulfilled and rejected will be called only once. + * 2. that either the fulfilled callback or the rejected callback will be + * called, but not both. + * 3. that fulfilled and rejected will not be called in this turn. + * + * @param value promise or immediate reference to observe + * @param fulfilled function to be called with the fulfilled value + * @param rejected function to be called with the rejection exception + * @return promise for the return value from the invoked callback + */ +exports.when = when; +function when(value, fulfilled, rejected) { + var deferred = defer(); + var done = false; // ensure the untrusted promise makes at most a + // single call to one of the callbacks + + function _fulfilled(value) { + try { + return fulfilled ? fulfilled(value) : value; + } catch (exception) { + return reject(exception); + } + } + + function _rejected(exception) { + try { + return rejected ? rejected(exception) : reject(exception); + } catch (newException) { + return reject(newException); + } + } + + nextTick(function () { + resolve(value).promiseSend("when", function (value) { + if (done) { + return; + } + done = true; + resolve(value).promiseSend("when", function (value) { + deferred.resolve(_fulfilled(value)); + }, function (exception) { + deferred.resolve(_rejected(exception)); + }); + }, function (exception) { + if (done) { + return; + } + done = true; + deferred.resolve(_rejected(exception)); + }); + }); + + return deferred.promise; +} + +/** + * Spreads the values of a promised array of arguments into the + * fulfillment callback. + * @param fulfilled callback that receives variadic arguments from the + * promised array + * @param rejected callback that receives the exception if the promise + * is rejected. + * @returns a promise for the return value or thrown exception of + * either callback. + */ +exports.spread = spread; +function spread(promise, fulfilled, rejected) { + return when(promise, function (values) { + return fulfilled.apply(void 0, values); + }, rejected); +} + +/** + * The async function is a decorator for generator functions, turning + * them into asynchronous generators. This presently only works in + * Firefox/Spidermonkey, however, this code does not cause syntax + * errors in older engines. This code should continue to work and + * will in fact improve over time as the language improves. + * + * Decorates a generator function such that: + * - it may yield promises + * - execution will continue when that promise is fulfilled + * - the value of the yield expression will be the fulfilled value + * - it returns a promise for the return value (when the generator + * stops iterating) + * - the decorated function returns a promise for the return value + * of the generator or the first rejected promise among those + * yielded. + * - if an error is thrown in the generator, it propagates through + * every following yield until it is caught, or until it escapes + * the generator function altogether, and is translated into a + * rejection for the promise returned by the decorated generator. + * - in present implementations of generators, when a generator + * function is complete, it throws ``StopIteration``, ``return`` is + * a syntax error in the presence of ``yield``, so there is no + * observable return value. There is a proposal[1] to add support + * for ``return``, which would permit the value to be carried by a + * ``StopIteration`` instance, in which case it would fulfill the + * promise returned by the asynchronous generator. This can be + * emulated today by throwing StopIteration explicitly with a value + * property. + * + * [1]: http://wiki.ecmascript.org/doku.php?id=strawman:async_functions#reference_implementation + * + */ +exports.async = async; +function async(makeGenerator) { + return function () { + // when verb is "send", arg is a value + // when verb is "throw", arg is an exception + function continuer(verb, arg) { + var result; + try { + result = generator[verb](arg); + } catch (exception) { + if (isStopIteration(exception)) { + return exception.value; + } else { + return reject(exception); + } + } + return when(result, callback, errback); + } + var generator = makeGenerator.apply(this, arguments); + var callback = continuer.bind(continuer, "send"); + var errback = continuer.bind(continuer, "throw"); + return callback(); + }; +} + +/** + * Throws a ReturnValue exception to stop an asynchronous generator. + * Only useful presently in Firefox/SpiderMonkey since generators are + * implemented. + * @param value the return value for the surrounding generator + * @throws ReturnValue exception with the value. + * @example + * Q.async(function () { + * var foo = yield getFooPromise(); + * var bar = yield getBarPromise(); + * Q.return(foo + bar); + * }) + */ +exports['return'] = _return; +function _return(value) { + throw new QReturnValue(value); +} + +/** + * Constructs a promise method that can be used to safely observe resolution of + * a promise for an arbitrarily named method like "propfind" in a future turn. + */ +exports.sender = deprecate(sender, "sender", "dispatcher"); // XXX deprecated, use dispatcher +exports.Method = deprecate(sender, "Method", "dispatcher"); // XXX deprecated, use dispatcher +function sender(op) { + return function (object) { + var args = array_slice(arguments, 1); + return send.apply(void 0, [object, op].concat(args)); + }; +} + +/** + * sends a message to a value in a future turn + * @param object* the recipient + * @param op the name of the message operation, e.g., "when", + * @param ...args further arguments to be forwarded to the operation + * @returns result {Promise} a promise for the result of the operation + */ +exports.send = deprecate(send, "send", "dispatch"); // XXX deprecated, use dispatch +function send(object, op) { + var deferred = defer(); + var args = array_slice(arguments, 2); + object = resolve(object); + nextTick(function () { + object.promiseSend.apply( + object, + [op, deferred.resolve].concat(args) + ); + }); + return deferred.promise; +} + +/** + * sends a message to a value in a future turn + * @param object* the recipient + * @param op the name of the message operation, e.g., "when", + * @param args further arguments to be forwarded to the operation + * @returns result {Promise} a promise for the result of the operation + */ +exports.dispatch = dispatch; +function dispatch(object, op, args) { + var deferred = defer(); + object = resolve(object); + nextTick(function () { + object.promiseSend.apply( + object, + [op, deferred.resolve].concat(args) + ); + }); + return deferred.promise; +} + +/** + * Constructs a promise method that can be used to safely observe resolution of + * a promise for an arbitrarily named method like "propfind" in a future turn. + * + * "dispatcher" constructs methods like "get(promise, name)" and "put(promise)". + */ +exports.dispatcher = dispatcher; +function dispatcher(op) { + return function (object) { + var args = array_slice(arguments, 1); + return dispatch(object, op, args); + }; +} + +/** + * Gets the value of a property in a future turn. + * @param object promise or immediate reference for target object + * @param name name of property to get + * @return promise for the property value + */ +exports.get = dispatcher("get"); + +/** + * Sets the value of a property in a future turn. + * @param object promise or immediate reference for object object + * @param name name of property to set + * @param value new value of property + * @return promise for the return value + */ +exports.put = dispatcher("put"); + +/** + * Deletes a property in a future turn. + * @param object promise or immediate reference for target object + * @param name name of property to delete + * @return promise for the return value + */ +exports["delete"] = // XXX experimental +exports.del = dispatcher("del"); + +/** + * Invokes a method in a future turn. + * @param object promise or immediate reference for target object + * @param name name of method to invoke + * @param value a value to post, typically an array of + * invocation arguments for promises that + * are ultimately backed with `resolve` values, + * as opposed to those backed with URLs + * wherein the posted value can be any + * JSON serializable object. + * @return promise for the return value + */ +// bound locally because it is used by other methods +var post = exports.post = dispatcher("post"); + +/** + * Invokes a method in a future turn. + * @param object promise or immediate reference for target object + * @param name name of method to invoke + * @param ...args array of invocation arguments + * @return promise for the return value + */ +exports.invoke = function (value, name) { + var args = array_slice(arguments, 2); + return post(value, name, args); +}; + +/** + * Applies the promised function in a future turn. + * @param object promise or immediate reference for target function + * @param thisp the `this` object for the call + * @param args array of application arguments + */ +// XXX deprecated, use fapply +var apply = exports.apply = deprecate(dispatcher("apply"), "apply", "fapply"); + +/** + * Applies the promised function in a future turn. + * @param object promise or immediate reference for target function + * @param args array of application arguments + */ +var fapply = exports.fapply = dispatcher("fapply"); + +/** + * Calls the promised function in a future turn. + * @param object promise or immediate reference for target function + * @param thisp the `this` object for the call + * @param ...args array of application arguments + */ +// XXX deprecated, use fcall +exports.call = deprecate(call, "call", "fcall"); +function call(value, thisp) { + var args = array_slice(arguments, 2); + return apply(value, thisp, args); +} + +/** + * Calls the promised function in a future turn. + * @param object promise or immediate reference for target function + * @param ...args array of application arguments + */ +exports["try"] = fcall; // XXX experimental +exports.fcall = fcall; +function fcall(value) { + var args = array_slice(arguments, 1); + return fapply(value, args); +} + +/** + * Binds the promised function, transforming return values into a fulfilled + * promise and thrown errors into a rejected one. + * @param object promise or immediate reference for target function + * @param thisp the `this` object for the call + * @param ...args array of application arguments + */ +exports.bind = deprecate(bind, "bind", "fbind"); // XXX deprecated, use fbind +function bind(value, thisp) { + var args = array_slice(arguments, 2); + return function bound() { + var allArgs = args.concat(array_slice(arguments)); + return apply(value, thisp, allArgs); + }; +} + +/** + * Binds the promised function, transforming return values into a fulfilled + * promise and thrown errors into a rejected one. + * @param object promise or immediate reference for target function + * @param ...args array of application arguments + */ +exports.fbind = fbind; +function fbind(value) { + var args = array_slice(arguments, 1); + return function fbound() { + var allArgs = args.concat(array_slice(arguments)); + return fapply(value, allArgs); + }; +} + +/** + * Requests the names of the owned properties of a promised + * object in a future turn. + * @param object promise or immediate reference for target object + * @return promise for the keys of the eventually resolved object + */ +exports.keys = dispatcher("keys"); + +/** + * Turns an array of promises into a promise for an array. If any of + * the promises gets rejected, the whole array is rejected immediately. + * @param {Array*} an array (or promise for an array) of values (or + * promises for values) + * @returns a promise for an array of the corresponding values + */ +// By Mark Miller +// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled +exports.all = all; +function all(promises) { + return when(promises, function (promises) { + var countDown = promises.length; + if (countDown === 0) { + return resolve(promises); + } + var deferred = defer(); + array_reduce(promises, function (undefined, promise, index) { + when(promise, function (value) { + promises[index] = value; + if (--countDown === 0) { + deferred.resolve(promises); + } + }) + .fail(deferred.reject); + }, void 0); + return deferred.promise; + }); +} + +/** + * Waits for all promises to be resolved, either fulfilled or + * rejected. This is distinct from `all` since that would stop + * waiting at the first rejection. The promise returned by + * `allResolved` will never be rejected. + * @param promises a promise for an array (or an array) of promises + * (or values) + * @return a promise for an array of promises + */ +exports.allResolved = allResolved; +function allResolved(promises) { + return when(promises, function (promises) { + return when(all(array_map(promises, function (promise) { + return when(promise, noop, noop); + })), function () { + return array_map(promises, resolve); + }); + }); +} + +/** + * Captures the failure of a promise, giving an oportunity to recover + * with a callback. If the given promise is fulfilled, the returned + * promise is fulfilled. + * @param {Any*} promise for something + * @param {Function} callback to fulfill the returned promise if the + * given promise is rejected + * @returns a promise for the return value of the callback + */ +exports["catch"] = // XXX experimental +exports.fail = fail; +function fail(promise, rejected) { + return when(promise, void 0, rejected); +} + +/** + * Provides an opportunity to observe the rejection of a promise, + * regardless of whether the promise is fulfilled or rejected. Forwards + * the resolution to the returned promise when the callback is done. + * The callback can return a promise to defer completion. + * @param {Any*} promise + * @param {Function} callback to observe the resolution of the given + * promise, takes no arguments. + * @returns a promise for the resolution of the given promise when + * ``fin`` is done. + */ +exports["finally"] = // XXX experimental +exports.fin = fin; +function fin(promise, callback) { + return when(promise, function (value) { + return when(callback(), function () { + return value; + }); + }, function (exception) { + return when(callback(), function () { + return reject(exception); + }); + }); +} + +/** + * Terminates a chain of promises, forcing rejections to be + * thrown as exceptions. + * @param {Any*} promise at the end of a chain of promises + * @returns nothing + */ +exports.end = end; // XXX stopgap +function end(promise) { + when(promise, void 0, function (error) { + // forward to a future turn so that ``when`` + // does not catch it and turn it into a rejection. + nextTick(function () { + // If possible (that is, if in V8), transform the error stack + // trace by removing Node and Q cruft, then concatenating with + // the stack trace of the promise we are ``end``ing. See #57. + if (Error.captureStackTrace && typeof error === "object" && + "stack" in error) { + var errorStackFrames = getStackFrames(error); + var promiseStackFrames = getStackFrames(promise); + + var combinedStackFrames = errorStackFrames.concat( + "From previous event:", + promiseStackFrames + ); + error.stack = formatStackTrace(error, combinedStackFrames); + } + + throw error; + }); + }); +} + +/** + * Causes a promise to be rejected if it does not get fulfilled before + * some milliseconds time out. + * @param {Any*} promise + * @param {Number} milliseconds timeout + * @returns a promise for the resolution of the given promise if it is + * fulfilled before the timeout, otherwise rejected. + */ +exports.timeout = timeout; +function timeout(promise, ms) { + var deferred = defer(); + var timeoutId = setTimeout(function () { + deferred.reject(new Error("Timed out after " + ms + " ms")); + }, ms); + + when(promise, function (value) { + clearTimeout(timeoutId); + deferred.resolve(value); + }, deferred.reject); + return deferred.promise; +} + +/** + * Returns a promise for the given value (or promised value) after some + * milliseconds. + * @param {Any*} promise + * @param {Number} milliseconds + * @returns a promise for the resolution of the given promise after some + * time has elapsed. + */ +exports.delay = delay; +function delay(promise, timeout) { + if (timeout === void 0) { + timeout = promise; + promise = void 0; + } + var deferred = defer(); + setTimeout(function () { + deferred.resolve(promise); + }, timeout); + return deferred.promise; +} + +/** + * Passes a continuation to a Node function, which is called with a given + * `this` value and arguments provided as an array, and returns a promise. + * + * var FS = require("fs"); + * Q.napply(FS.readFile, FS, [__filename]) + * .then(function (content) { + * }) + * + */ +exports.napply = napply; +function napply(callback, thisp, args) { + return nbind(callback, thisp).apply(void 0, args); +} + +/** + * Passes a continuation to a Node function, which is called with a given + * `this` value and arguments provided individually, and returns a promise. + * + * var FS = require("fs"); + * Q.ncall(FS.readFile, FS, __filename) + * .then(function (content) { + * }) + * + */ +exports.ncall = ncall; +function ncall(callback, thisp /*, ...args*/) { + var args = array_slice(arguments, 2); + return napply(callback, thisp, args); +} + +/** + * Wraps a NodeJS continuation passing function and returns an equivalent + * version that returns a promise. + * + * Q.nbind(FS.readFile, FS)(__filename) + * .then(console.log) + * .end() + * + */ +exports.nbind = nbind; +function nbind(callback /* thisp, ...args*/) { + if (arguments.length > 1) { + var thisp = arguments[1]; + var args = array_slice(arguments, 2); + + var originalCallback = callback; + callback = function () { + var combinedArgs = args.concat(array_slice(arguments)); + return originalCallback.apply(thisp, combinedArgs); + }; + } + return function () { + var deferred = defer(); + var args = array_slice(arguments); + // add a continuation that resolves the promise + args.push(deferred.makeNodeResolver()); + // trap exceptions thrown by the callback + fapply(callback, args) + .fail(deferred.reject); + return deferred.promise; + }; +} + +/** + * Calls a method of a Node-style object that accepts a Node-style + * callback with a given array of arguments, plus a provided callback. + * @param object an object that has the named method + * @param {String} name name of the method of object + * @param {Array} args arguments to pass to the method; the callback + * will be provided by Q and appended to these arguments. + * @returns a promise for the value or error + */ +exports.npost = npost; +function npost(object, name, args) { + return napply(object[name], object, args); +} + +/** + * Calls a method of a Node-style object that accepts a Node-style + * callback, forwarding the given variadic arguments, plus a provided + * callback argument. + * @param object an object that has the named method + * @param {String} name name of the method of object + * @param ...args arguments to pass to the method; the callback will + * be provided by Q and appended to these arguments. + * @returns a promise for the value or error + */ +exports.ninvoke = ninvoke; +function ninvoke(object, name /*, ...args*/) { + var args = array_slice(arguments, 2); + return napply(object[name], object, args); +} + +defend(exports); + +}); diff --git a/resource/q.jsm b/resource/q.jsm @@ -1,1499 +0,0 @@ -// vim:ts=4:sts=4:sw=4: -/*jshint browser: true, node: true, - curly: true, eqeqeq: true, noarg: true, nonew: true, trailing: true, - undef: true */ -/*global define: false, Q: true, msSetImmediate: false, setImmediate: false, - ReturnValue: false, cajaVM: false, ses: false */ -/*! - * - * Copyright 2009-2012 Kris Kowal under the terms of the MIT - * license found at http://github.com/kriskowal/q/raw/master/LICENSE - * - * With parts by Tyler Close - * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found - * at http://www.opensource.org/licenses/mit-license.html - * Forked at ref_send.js version: 2009-05-11 - * - * With parts by Mark Miller - * Copyright (C) 2011 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * With formatStackTrace and formatSourcePosition functions - * Copyright 2006-2008 the V8 project authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -var EXPORTED_SYMBOLS = ["Q"]; -var setTimeout = new function() { - var _runningTimers = []; - return function setTimeout(func, ms) { - var timer = Components.classes["@mozilla.org/timer;1"]. - createInstance(Components.interfaces.nsITimer); - var timerCallback = {"notify":function() { - // remove timer from global scope, so it can be garbage collected - _runningTimers.splice(_runningTimers.indexOf(timer), 1); - // execute callback function - try { - func(); - } catch(err) { - var scriptError = Components.classes["@mozilla.org/scripterror;1"] - .createInstance(Components.interfaces.nsIScriptError); - scriptError.init( - err.message ? err.message : err.toString(), - err.fileName ? err.fileName : (err.filename ? err.filename : null), - null, - err.lineNumber ? err.lineNumber : null, - null, - scriptError['errorFlag'], - 'component javascript' - ); - Components.classes["@mozilla.org/consoleservice;1"] - .getService(Components.interfaces.nsIConsoleService) - .logMessage(scriptError); - } - }}; - timer.initWithCallback(timerCallback, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT); - } -}; - -(function (definition) { - // Turn off strict mode for this function so we can assign to global.Q - /*jshint strict: false*/ - - // This file will function properly as a <script> tag, or a module - // using CommonJS and NodeJS or RequireJS module formats. In - // Common/Node/RequireJS, the module exports the Q API and when - // executed as a simple <script>, it creates a Q global instead. - - // RequireJS - if (typeof define === "function") { - define(definition); - - // CommonJS - } else if (typeof exports === "object") { - definition(void 0, exports); - - // SES (Secure EcmaScript) - } else if (typeof ses !== "undefined") { - if (!ses.ok()) { - return; - } else { - ses.makeQ = function () { - var Q = {}; - return definition(void 0, Q); - }; - } - - // <script> - } else { - definition(void 0, Q = {}); - } - -})(function (require, exports) { -"use strict"; - -// shims - -// used for fallback "defend" and in "allResolved" -var noop = function () {}; - -// for the security conscious, defend may be a deep freeze as provided -// by cajaVM. Otherwise we try to provide a shallow freeze just to -// discourage promise changes that are not compatible with secure -// usage. If Object.freeze does not exist, fall back to doing nothing -// (no op). -var defend = Object.freeze || noop; -if (typeof cajaVM !== "undefined") { - defend = cajaVM.def; -} - -// use the fastest possible means to execute a task in a future turn -// of the event loop. -var nextTick; -if (typeof process !== "undefined") { - // node - nextTick = process.nextTick; -} else if (typeof msSetImmediate === "function") { - // IE 10 only, at the moment - // And yes, ``bind``ing to ``window`` is necessary O_o. - nextTick = msSetImmediate.bind(window); -} else if (typeof setImmediate === "function") { - // https://github.com/NobleJS/setImmediate - nextTick = setImmediate; -} else if (typeof MessageChannel !== "undefined") { - // modern browsers - // http://www.nonblocking.io/2011/06/windownexttick.html - var channel = new MessageChannel(); - // linked list of tasks (single, with head node) - var head = {}, tail = head; - channel.port1.onmessage = function () { - head = head.next; - var task = head.task; - delete head.task; - task(); - }; - nextTick = function (task) { - tail = tail.next = {task: task}; - channel.port2.postMessage(0); - }; -} else { - // old browsers - nextTick = function (task) { - setTimeout(task, 0); - }; -} - -// Attempt to make generics safe in the face of downstream -// modifications. -// There is no situation where this is necessary. -// If you need a security guarantee, these primordials need to be -// deeply frozen anyway, and if you don’t need a security guarantee, -// this is just plain paranoid. -// However, this does have the nice side-effect of reducing the size -// of the code by reducing x.call() to merely x(), eliminating many -// hard-to-minify characters. -// See Mark Miller’s explanation of what this does. -// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming -var uncurryThis; -// I have kept both variations because the first is theoretically -// faster, if bind is available. -if (Function.prototype.bind) { - var Function_bind = Function.prototype.bind; - uncurryThis = Function_bind.bind(Function_bind.call); -} else { - uncurryThis = function (f) { - return function (thisp) { - return f.call.apply(f, arguments); - }; - }; -} - -var array_slice = uncurryThis(Array.prototype.slice); - -var array_reduce = uncurryThis( - Array.prototype.reduce || function (callback, basis) { - var index = 0, - length = this.length; - // concerning the initial value, if one is not provided - if (arguments.length === 1) { - // seek to the first value in the array, accounting - // for the possibility that is is a sparse array - do { - if (index in this) { - basis = this[index++]; - break; - } - if (++index >= length) { - throw new TypeError(); - } - } while (1); - } - // reduce - for (; index < length; index++) { - // account for the possibility that the array is sparse - if (index in this) { - basis = callback(basis, this[index], index); - } - } - return basis; - } -); - -var array_indexOf = uncurryThis( - Array.prototype.indexOf || function (value) { - // not a very good shim, but good enough for our one use of it - for (var i = 0; i < this.length; i++) { - if (this[i] === value) { - return i; - } - } - return -1; - } -); - -var array_map = uncurryThis( - Array.prototype.map || function (callback, thisp) { - var self = this; - var collect = []; - array_reduce(self, function (undefined, value, index) { - collect.push(callback.call(thisp, value, index, self)); - }, void 0); - return collect; - } -); - -var object_create = Object.create || function (prototype) { - function Type() { } - Type.prototype = prototype; - return new Type(); -}; - -var object_keys = Object.keys || function (object) { - var keys = []; - for (var key in object) { - keys.push(key); - } - return keys; -}; - -var object_toString = Object.prototype.toString; - -// generator related shims - -function isStopIteration(exception) { - return ( - object_toString(exception) === "[object StopIteration]" || - exception instanceof QReturnValue - ); -} - -var QReturnValue; -if (typeof ReturnValue !== "undefined") { - QReturnValue = ReturnValue; -} else { - QReturnValue = function (value) { - this.value = value; - }; -} - -// long stack traces - -function formatStackTrace(error, frames) { - var lines = []; - try { - lines.push(error.toString()); - } catch (e) { - try { - lines.push("<error: " + e + ">"); - } catch (ee) { - lines.push("<error>"); - } - } - for (var i = 0; i < frames.length; i++) { - var frame = frames[i]; - var line; - - // <Inserted by @domenic> - if (typeof frame === "string") { - lines.push(frame); - // </Inserted by @domenic> - } else { - try { - line = formatSourcePosition(frame); - } catch (e) { - try { - line = "<error: " + e + ">"; - } catch (ee) { - // Any code that reaches this point is seriously nasty! - line = "<error>"; - } - } - lines.push(" at " + line); - } - } - return lines.join("\n"); -} - -function formatSourcePosition(frame) { - var fileLocation = ""; - if (frame.isNative()) { - fileLocation = "native"; - } else if (frame.isEval()) { - fileLocation = "eval at " + frame.getEvalOrigin(); - } else { - var fileName = frame.getFileName(); - if (fileName) { - fileLocation += fileName; - var lineNumber = frame.getLineNumber(); - if (lineNumber !== null) { - fileLocation += ":" + lineNumber; - var columnNumber = frame.getColumnNumber(); - if (columnNumber) { - fileLocation += ":" + columnNumber; - } - } - } - } - if (!fileLocation) { - fileLocation = "unknown source"; - } - var line = ""; - var functionName = frame.getFunction().name; - var addPrefix = true; - var isConstructor = frame.isConstructor(); - var isMethodCall = !(frame.isToplevel() || isConstructor); - if (isMethodCall) { - var methodName = frame.getMethodName(); - line += frame.getTypeName() + "."; - if (functionName) { - line += functionName; - if (methodName && (methodName !== functionName)) { - line += " [as " + methodName + "]"; - } - } else { - line += methodName || "<anonymous>"; - } - } else if (isConstructor) { - line += "new " + (functionName || "<anonymous>"); - } else if (functionName) { - line += functionName; - } else { - line += fileLocation; - addPrefix = false; - } - if (addPrefix) { - line += " (" + fileLocation + ")"; - } - return line; -} - -/* - * Retrieves an array of structured stack frames parsed from the ``stack`` - * property of a given object. - * - * @param objectWithStack {Object} an object with a ``stack`` property: usually - * an error or promise. - * - * @returns an array of stack frame objects. For more information, see - * [V8's JavaScript stack trace API documentation](http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi). - */ -function getStackFrames(objectWithStack) { - var oldPrepareStackTrace = Error.prepareStackTrace; - - Error.prepareStackTrace = function (error, frames) { - // Filter out frames from the innards of Node and Q. - return frames.filter(function (frame) { - var fileName = frame.getFileName(); - return ( - fileName !== "module.js" && - fileName !== "node.js" && - fileName !== qFileName - ); - }); - }; - - var stack = objectWithStack.stack; - - Error.prepareStackTrace = oldPrepareStackTrace; - - return stack; -} - -// discover own file name for filtering stack traces -var qFileName; -if (Error.captureStackTrace) { - qFileName = (function () { - var fileName; - - var oldPrepareStackTrace = Error.prepareStackTrace; - - Error.prepareStackTrace = function (error, frames) { - fileName = frames[0].getFileName(); - }; - - // teases call of temporary prepareStackTrace - // JSHint and Closure Compiler generate known warnings here - /*jshint expr: true */ - new Error().stack; - - Error.prepareStackTrace = oldPrepareStackTrace; - - return fileName; - })(); -} - -function deprecate(fn, name, alternative){ - return function () { - if (typeof console !== "undefined" && typeof console.warn === "function"){ - console.warn(name + " is deprecated, use " + alternative + " instead."); - } - return fn.apply(fn,arguments); - }; -} - -// end of shims -// beginning of real work - -/** - * Performs a task in a future turn of the event loop. - * @param {Function} task - */ -exports.nextTick = nextTick; - -/** - * Constructs a {promise, resolve} object. - * - * The resolver is a callback to invoke with a more resolved value for the - * promise. To fulfill the promise, invoke the resolver with any value that is - * not a function. To reject the promise, invoke the resolver with a rejection - * object. To put the promise in the same state as another promise, invoke the - * resolver with that other promise. - */ -exports.defer = defer; -function defer() { - // if "pending" is an "Array", that indicates that the promise has not yet - // been resolved. If it is "undefined", it has been resolved. Each - // element of the pending array is itself an array of complete arguments to - // forward to the resolved promise. We coerce the resolution value to a - // promise using the ref promise because it handles both fully - // resolved values and other promises gracefully. - var pending = [], value; - - var deferred = object_create(defer.prototype); - var promise = object_create(makePromise.prototype); - - promise.promiseSend = function () { - var args = array_slice(arguments); - if (pending) { - pending.push(args); - } else { - nextTick(function () { - value.promiseSend.apply(value, args); - }); - } - }; - - promise.valueOf = function () { - if (pending) { - return promise; - } - return value.valueOf(); - }; - - if (Error.captureStackTrace) { - Error.captureStackTrace(promise, defer); - } - - function become(resolvedValue) { - if (!pending) { - return; - } - value = resolve(resolvedValue); - array_reduce(pending, function (undefined, pending) { - nextTick(function () { - value.promiseSend.apply(value, pending); - }); - }, void 0); - pending = void 0; - return value; - } - - defend(promise); - - deferred.promise = promise; - deferred.resolve = become; - deferred.reject = function (exception) { - return become(reject(exception)); - }; - - return deferred; -} - -/** - * Creates a Node-style callback that will resolve or reject the deferred - * promise. - * @returns a nodeback - */ -defer.prototype.makeNodeResolver = function () { - var self = this; - return function (error, value) { - if (error) { - self.reject(error); - } else if (arguments.length > 2) { - self.resolve(array_slice(arguments, 1)); - } else { - self.resolve(value); - } - }; -}; -// XXX deprecated -defer.prototype.node = deprecate(defer.prototype.makeNodeResolver, "node", "makeNodeResolver"); - -/** - * @param makePromise {Function} a function that returns nothing and accepts - * the resolve and reject functions for a deferred. - * @returns a promise that may be resolved with the given resolve and reject - * functions, or rejected by a thrown exception in makePromise - */ -exports.promise = promise; -function promise(makePromise) { - var deferred = defer(); - call( - makePromise, - void 0, - deferred.resolve, - deferred.reject - ).fail(deferred.reject); - return deferred.promise; -} - -/** - * Constructs a Promise with a promise descriptor object and optional fallback - * function. The descriptor contains methods like when(rejected), get(name), - * put(name, value), post(name, args), and delete(name), which all - * return either a value, a promise for a value, or a rejection. The fallback - * accepts the operation name, a resolver, and any further arguments that would - * have been forwarded to the appropriate method above had a method been - * provided with the proper name. The API makes no guarantees about the nature - * of the returned object, apart from that it is usable whereever promises are - * bought and sold. - */ -exports.makePromise = makePromise; -function makePromise(descriptor, fallback, valueOf, exception) { - if (fallback === void 0) { - fallback = function (op) { - return reject(new Error("Promise does not support operation: " + op)); - }; - } - - var promise = object_create(makePromise.prototype); - - promise.promiseSend = function (op, resolved /* ...args */) { - var args = array_slice(arguments, 2); - var result; - try { - if (descriptor[op]) { - result = descriptor[op].apply(promise, args); - } else { - result = fallback.apply(promise, [op].concat(args)); - } - } catch (exception) { - result = reject(exception); - } - resolved(result); - }; - - if (valueOf) { - promise.valueOf = valueOf; - } - - if (exception) { - promise.exception = exception; - } - - defend(promise); - - return promise; -} - -// provide thenables, CommonJS/Promises/A -makePromise.prototype.then = function (fulfilled, rejected) { - return when(this, fulfilled, rejected); -}; - -// Chainable methods -array_reduce( - [ - "isResolved", "isFulfilled", "isRejected", - "when", "spread", "send", - "get", "put", "del", - "post", "invoke", - "keys", - "apply", "call", "bind", - "fapply", "fcall", "fbind", - "all", "allResolved", - "view", "viewInfo", - "timeout", "delay", - "catch", "finally", "fail", "fin", "end" - ], - function (prev, name) { - makePromise.prototype[name] = function () { - return exports[name].apply( - exports, - [this].concat(array_slice(arguments)) - ); - }; - }, - void 0 -); - -makePromise.prototype.toSource = function () { - return this.toString(); -}; - -makePromise.prototype.toString = function () { - return "[object Promise]"; -}; - -defend(makePromise.prototype); - -/** - * If an object is not a promise, it is as "near" as possible. - * If a promise is rejected, it is as "near" as possible too. - * If it’s a fulfilled promise, the fulfillment value is nearer. - * If it’s a deferred promise and the deferred has been resolved, the - * resolution is "nearer". - * @param object - * @returns most resolved (nearest) form of the object - */ -exports.nearer = valueOf; -function valueOf(value) { - // if !Object.isObject(value) - // generates a known JSHint "constructor invocation without new" warning - // supposed to be fixed, but isn't? https://github.com/jshint/jshint/issues/392 - /*jshint newcap: false */ - if (Object(value) !== value) { - return value; - } else { - return value.valueOf(); - } -} - -/** - * @returns whether the given object is a promise. - * Otherwise it is a fulfilled value. - */ -exports.isPromise = isPromise; -function isPromise(object) { - return object && typeof object.promiseSend === "function"; -} - -/** - * @returns whether the given object is a resolved promise. - */ -exports.isResolved = isResolved; -function isResolved(object) { - return isFulfilled(object) || isRejected(object); -} - -/** - * @returns whether the given object is a value or fulfilled - * promise. - */ -exports.isFulfilled = isFulfilled; -function isFulfilled(object) { - return !isPromise(valueOf(object)); -} - -/** - * @returns whether the given object is a rejected promise. - */ -exports.isRejected = isRejected; -function isRejected(object) { - object = valueOf(object); - return isPromise(object) && 'exception' in object; -} - -var rejections = []; -var errors = []; -if (typeof window !== "undefined" && window.console) { - // This promise library consumes exceptions thrown in handlers so - // they can be handled by a subsequent promise. The rejected - // promises get added to this array when they are created, and - // removed when they are handled. - console.log("Should be empty:", errors); -} - -/** - * Constructs a rejected promise. - * @param exception value describing the failure - */ -exports.reject = reject; -function reject(exception) { - exception = exception || new Error(); - var rejection = makePromise({ - "when": function (rejected) { - // note that the error has been handled - if (rejected) { - var at = array_indexOf(rejections, this); - if (at !== -1) { - errors.splice(at, 1); - rejections.splice(at, 1); - } - } - return rejected ? rejected(exception) : reject(exception); - } - }, function fallback(op) { - return reject(exception); - }, function valueOf() { - return this; - }, exception); - // note that the error has not been handled - rejections.push(rejection); - errors.push(exception); - return rejection; -} - -/** - * Constructs a promise for an immediate reference. - * @param value immediate reference - */ -exports.begin = resolve; // XXX experimental -exports.resolve = resolve; -exports.ref = deprecate(resolve, "ref", "resolve"); // XXX deprecated, use resolve -function resolve(object) { - // If the object is already a Promise, return it directly. This enables - // the resolve function to both be used to created references from objects, - // but to tolerably coerce non-promises to promises. - if (isPromise(object)) { - return object; - } - // assimilate thenables, CommonJS/Promises/A - if (object && typeof object.then === "function") { - var result = defer(); - object.then(result.resolve, result.reject); - return result.promise; - } - return makePromise({ - "when": function (rejected) { - return object; - }, - "get": function (name) { - return object[name]; - }, - "put": function (name, value) { - return object[name] = value; - }, - "del": function (name) { - return delete object[name]; - }, - "post": function (name, value) { - return object[name].apply(object, value); - }, - "apply": function (self, args) { - return object.apply(self, args); - }, - "fapply": function (args) { - return object.apply(void 0, args); - }, - "viewInfo": function () { - var on = object; - var properties = {}; - - function fixFalsyProperty(name) { - if (!properties[name]) { - properties[name] = typeof on[name]; - } - } - - while (on) { - Object.getOwnPropertyNames(on).forEach(fixFalsyProperty); - on = Object.getPrototypeOf(on); - } - return { - "type": typeof object, - "properties": properties - }; - }, - "keys": function () { - return object_keys(object); - } - }, void 0, function valueOf() { - return object; - }); -} - -/** - * Annotates an object such that it will never be - * transferred away from this process over any promise - * communication channel. - * @param object - * @returns promise a wrapping of that object that - * additionally responds to the "isDef" message - * without a rejection. - */ -exports.master = master; -function master(object) { - return makePromise({ - "isDef": function () {} - }, function fallback(op) { - var args = array_slice(arguments); - return send.apply(void 0, [object].concat(args)); - }, function () { - return valueOf(object); - }); -} - -exports.viewInfo = viewInfo; -function viewInfo(object, info) { - object = resolve(object); - if (info) { - return makePromise({ - "viewInfo": function () { - return info; - } - }, function fallback(op) { - var args = array_slice(arguments); - return send.apply(void 0, [object].concat(args)); - }, function () { - return valueOf(object); - }); - } else { - return send(object, "viewInfo"); - } -} - -exports.view = view; -function view(object) { - return viewInfo(object).when(function (info) { - var view; - if (info.type === "function") { - view = function () { - return apply(object, void 0, arguments); - }; - } else { - view = {}; - } - var properties = info.properties || {}; - object_keys(properties).forEach(function (name) { - if (properties[name] === "function") { - view[name] = function () { - return post(object, name, arguments); - }; - } - }); - return resolve(view); - }); -} - -/** - * Registers an observer on a promise. - * - * Guarantees: - * - * 1. that fulfilled and rejected will be called only once. - * 2. that either the fulfilled callback or the rejected callback will be - * called, but not both. - * 3. that fulfilled and rejected will not be called in this turn. - * - * @param value promise or immediate reference to observe - * @param fulfilled function to be called with the fulfilled value - * @param rejected function to be called with the rejection exception - * @return promise for the return value from the invoked callback - */ -exports.when = when; -function when(value, fulfilled, rejected) { - var deferred = defer(); - var done = false; // ensure the untrusted promise makes at most a - // single call to one of the callbacks - - function _fulfilled(value) { - try { - return fulfilled ? fulfilled(value) : value; - } catch (exception) { - return reject(exception); - } - } - - function _rejected(exception) { - try { - return rejected ? rejected(exception) : reject(exception); - } catch (newException) { - return reject(newException); - } - } - - nextTick(function () { - resolve(value).promiseSend("when", function (value) { - if (done) { - return; - } - done = true; - resolve(value).promiseSend("when", function (value) { - deferred.resolve(_fulfilled(value)); - }, function (exception) { - deferred.resolve(_rejected(exception)); - }); - }, function (exception) { - if (done) { - return; - } - done = true; - deferred.resolve(_rejected(exception)); - }); - }); - - return deferred.promise; -} - -/** - * Spreads the values of a promised array of arguments into the - * fulfillment callback. - * @param fulfilled callback that receives variadic arguments from the - * promised array - * @param rejected callback that receives the exception if the promise - * is rejected. - * @returns a promise for the return value or thrown exception of - * either callback. - */ -exports.spread = spread; -function spread(promise, fulfilled, rejected) { - return when(promise, function (values) { - return fulfilled.apply(void 0, values); - }, rejected); -} - -/** - * The async function is a decorator for generator functions, turning - * them into asynchronous generators. This presently only works in - * Firefox/Spidermonkey, however, this code does not cause syntax - * errors in older engines. This code should continue to work and - * will in fact improve over time as the language improves. - * - * Decorates a generator function such that: - * - it may yield promises - * - execution will continue when that promise is fulfilled - * - the value of the yield expression will be the fulfilled value - * - it returns a promise for the return value (when the generator - * stops iterating) - * - the decorated function returns a promise for the return value - * of the generator or the first rejected promise among those - * yielded. - * - if an error is thrown in the generator, it propagates through - * every following yield until it is caught, or until it escapes - * the generator function altogether, and is translated into a - * rejection for the promise returned by the decorated generator. - * - in present implementations of generators, when a generator - * function is complete, it throws ``StopIteration``, ``return`` is - * a syntax error in the presence of ``yield``, so there is no - * observable return value. There is a proposal[1] to add support - * for ``return``, which would permit the value to be carried by a - * ``StopIteration`` instance, in which case it would fulfill the - * promise returned by the asynchronous generator. This can be - * emulated today by throwing StopIteration explicitly with a value - * property. - * - * [1]: http://wiki.ecmascript.org/doku.php?id=strawman:async_functions#reference_implementation - * - */ -exports.async = async; -function async(makeGenerator) { - return function () { - // when verb is "send", arg is a value - // when verb is "throw", arg is an exception - function continuer(verb, arg) { - var result; - try { - result = generator[verb](arg); - } catch (exception) { - if (isStopIteration(exception)) { - return exception.value; - } else { - return reject(exception); - } - } - return when(result, callback, errback); - } - var generator = makeGenerator.apply(this, arguments); - var callback = continuer.bind(continuer, "send"); - var errback = continuer.bind(continuer, "throw"); - return callback(); - }; -} - -/** - * Throws a ReturnValue exception to stop an asynchronous generator. - * Only useful presently in Firefox/SpiderMonkey since generators are - * implemented. - * @param value the return value for the surrounding generator - * @throws ReturnValue exception with the value. - * @example - * Q.async(function () { - * var foo = yield getFooPromise(); - * var bar = yield getBarPromise(); - * Q.return(foo + bar); - * }) - */ -exports['return'] = _return; -function _return(value) { - throw new QReturnValue(value); -} - -/** - * Constructs a promise method that can be used to safely observe resolution of - * a promise for an arbitrarily named method like "propfind" in a future turn. - */ -exports.sender = deprecate(sender, "sender", "dispatcher"); // XXX deprecated, use dispatcher -exports.Method = deprecate(sender, "Method", "dispatcher"); // XXX deprecated, use dispatcher -function sender(op) { - return function (object) { - var args = array_slice(arguments, 1); - return send.apply(void 0, [object, op].concat(args)); - }; -} - -/** - * sends a message to a value in a future turn - * @param object* the recipient - * @param op the name of the message operation, e.g., "when", - * @param ...args further arguments to be forwarded to the operation - * @returns result {Promise} a promise for the result of the operation - */ -exports.send = deprecate(send, "send", "dispatch"); // XXX deprecated, use dispatch -function send(object, op) { - var deferred = defer(); - var args = array_slice(arguments, 2); - object = resolve(object); - nextTick(function () { - object.promiseSend.apply( - object, - [op, deferred.resolve].concat(args) - ); - }); - return deferred.promise; -} - -/** - * sends a message to a value in a future turn - * @param object* the recipient - * @param op the name of the message operation, e.g., "when", - * @param args further arguments to be forwarded to the operation - * @returns result {Promise} a promise for the result of the operation - */ -exports.dispatch = dispatch; -function dispatch(object, op, args) { - var deferred = defer(); - object = resolve(object); - nextTick(function () { - object.promiseSend.apply( - object, - [op, deferred.resolve].concat(args) - ); - }); - return deferred.promise; -} - -/** - * Constructs a promise method that can be used to safely observe resolution of - * a promise for an arbitrarily named method like "propfind" in a future turn. - * - * "dispatcher" constructs methods like "get(promise, name)" and "put(promise)". - */ -exports.dispatcher = dispatcher; -function dispatcher(op) { - return function (object) { - var args = array_slice(arguments, 1); - return dispatch(object, op, args); - }; -} - -/** - * Gets the value of a property in a future turn. - * @param object promise or immediate reference for target object - * @param name name of property to get - * @return promise for the property value - */ -exports.get = dispatcher("get"); - -/** - * Sets the value of a property in a future turn. - * @param object promise or immediate reference for object object - * @param name name of property to set - * @param value new value of property - * @return promise for the return value - */ -exports.put = dispatcher("put"); - -/** - * Deletes a property in a future turn. - * @param object promise or immediate reference for target object - * @param name name of property to delete - * @return promise for the return value - */ -exports["delete"] = // XXX experimental -exports.del = dispatcher("del"); - -/** - * Invokes a method in a future turn. - * @param object promise or immediate reference for target object - * @param name name of method to invoke - * @param value a value to post, typically an array of - * invocation arguments for promises that - * are ultimately backed with `resolve` values, - * as opposed to those backed with URLs - * wherein the posted value can be any - * JSON serializable object. - * @return promise for the return value - */ -// bound locally because it is used by other methods -var post = exports.post = dispatcher("post"); - -/** - * Invokes a method in a future turn. - * @param object promise or immediate reference for target object - * @param name name of method to invoke - * @param ...args array of invocation arguments - * @return promise for the return value - */ -exports.invoke = function (value, name) { - var args = array_slice(arguments, 2); - return post(value, name, args); -}; - -/** - * Applies the promised function in a future turn. - * @param object promise or immediate reference for target function - * @param thisp the `this` object for the call - * @param args array of application arguments - */ -// XXX deprecated, use fapply -var apply = exports.apply = deprecate(dispatcher("apply"), "apply", "fapply"); - -/** - * Applies the promised function in a future turn. - * @param object promise or immediate reference for target function - * @param args array of application arguments - */ -var fapply = exports.fapply = dispatcher("fapply"); - -/** - * Calls the promised function in a future turn. - * @param object promise or immediate reference for target function - * @param thisp the `this` object for the call - * @param ...args array of application arguments - */ -// XXX deprecated, use fcall -exports.call = deprecate(call, "call", "fcall"); -function call(value, thisp) { - var args = array_slice(arguments, 2); - return apply(value, thisp, args); -} - -/** - * Calls the promised function in a future turn. - * @param object promise or immediate reference for target function - * @param ...args array of application arguments - */ -exports["try"] = fcall; // XXX experimental -exports.fcall = fcall; -function fcall(value) { - var args = array_slice(arguments, 1); - return fapply(value, args); -} - -/** - * Binds the promised function, transforming return values into a fulfilled - * promise and thrown errors into a rejected one. - * @param object promise or immediate reference for target function - * @param thisp the `this` object for the call - * @param ...args array of application arguments - */ -exports.bind = deprecate(bind, "bind", "fbind"); // XXX deprecated, use fbind -function bind(value, thisp) { - var args = array_slice(arguments, 2); - return function bound() { - var allArgs = args.concat(array_slice(arguments)); - return apply(value, thisp, allArgs); - }; -} - -/** - * Binds the promised function, transforming return values into a fulfilled - * promise and thrown errors into a rejected one. - * @param object promise or immediate reference for target function - * @param ...args array of application arguments - */ -exports.fbind = fbind; -function fbind(value) { - var args = array_slice(arguments, 1); - return function fbound() { - var allArgs = args.concat(array_slice(arguments)); - return fapply(value, allArgs); - }; -} - -/** - * Requests the names of the owned properties of a promised - * object in a future turn. - * @param object promise or immediate reference for target object - * @return promise for the keys of the eventually resolved object - */ -exports.keys = dispatcher("keys"); - -/** - * Turns an array of promises into a promise for an array. If any of - * the promises gets rejected, the whole array is rejected immediately. - * @param {Array*} an array (or promise for an array) of values (or - * promises for values) - * @returns a promise for an array of the corresponding values - */ -// By Mark Miller -// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled -exports.all = all; -function all(promises) { - return when(promises, function (promises) { - var countDown = promises.length; - if (countDown === 0) { - return resolve(promises); - } - var deferred = defer(); - array_reduce(promises, function (undefined, promise, index) { - when(promise, function (value) { - promises[index] = value; - if (--countDown === 0) { - deferred.resolve(promises); - } - }) - .fail(deferred.reject); - }, void 0); - return deferred.promise; - }); -} - -/** - * Waits for all promises to be resolved, either fulfilled or - * rejected. This is distinct from `all` since that would stop - * waiting at the first rejection. The promise returned by - * `allResolved` will never be rejected. - * @param promises a promise for an array (or an array) of promises - * (or values) - * @return a promise for an array of promises - */ -exports.allResolved = allResolved; -function allResolved(promises) { - return when(promises, function (promises) { - return when(all(array_map(promises, function (promise) { - return when(promise, noop, noop); - })), function () { - return array_map(promises, resolve); - }); - }); -} - -/** - * Captures the failure of a promise, giving an oportunity to recover - * with a callback. If the given promise is fulfilled, the returned - * promise is fulfilled. - * @param {Any*} promise for something - * @param {Function} callback to fulfill the returned promise if the - * given promise is rejected - * @returns a promise for the return value of the callback - */ -exports["catch"] = // XXX experimental -exports.fail = fail; -function fail(promise, rejected) { - return when(promise, void 0, rejected); -} - -/** - * Provides an opportunity to observe the rejection of a promise, - * regardless of whether the promise is fulfilled or rejected. Forwards - * the resolution to the returned promise when the callback is done. - * The callback can return a promise to defer completion. - * @param {Any*} promise - * @param {Function} callback to observe the resolution of the given - * promise, takes no arguments. - * @returns a promise for the resolution of the given promise when - * ``fin`` is done. - */ -exports["finally"] = // XXX experimental -exports.fin = fin; -function fin(promise, callback) { - return when(promise, function (value) { - return when(callback(), function () { - return value; - }); - }, function (exception) { - return when(callback(), function () { - return reject(exception); - }); - }); -} - -/** - * Terminates a chain of promises, forcing rejections to be - * thrown as exceptions. - * @param {Any*} promise at the end of a chain of promises - * @returns nothing - */ -exports.end = end; // XXX stopgap -function end(promise) { - when(promise, void 0, function (error) { - // forward to a future turn so that ``when`` - // does not catch it and turn it into a rejection. - nextTick(function () { - // If possible (that is, if in V8), transform the error stack - // trace by removing Node and Q cruft, then concatenating with - // the stack trace of the promise we are ``end``ing. See #57. - if (Error.captureStackTrace && typeof error === "object" && - "stack" in error) { - var errorStackFrames = getStackFrames(error); - var promiseStackFrames = getStackFrames(promise); - - var combinedStackFrames = errorStackFrames.concat( - "From previous event:", - promiseStackFrames - ); - error.stack = formatStackTrace(error, combinedStackFrames); - } - - throw error; - }); - }); -} - -/** - * Causes a promise to be rejected if it does not get fulfilled before - * some milliseconds time out. - * @param {Any*} promise - * @param {Number} milliseconds timeout - * @returns a promise for the resolution of the given promise if it is - * fulfilled before the timeout, otherwise rejected. - */ -exports.timeout = timeout; -function timeout(promise, ms) { - var deferred = defer(); - var timeoutId = setTimeout(function () { - deferred.reject(new Error("Timed out after " + ms + " ms")); - }, ms); - - when(promise, function (value) { - clearTimeout(timeoutId); - deferred.resolve(value); - }, deferred.reject); - return deferred.promise; -} - -/** - * Returns a promise for the given value (or promised value) after some - * milliseconds. - * @param {Any*} promise - * @param {Number} milliseconds - * @returns a promise for the resolution of the given promise after some - * time has elapsed. - */ -exports.delay = delay; -function delay(promise, timeout) { - if (timeout === void 0) { - timeout = promise; - promise = void 0; - } - var deferred = defer(); - setTimeout(function () { - deferred.resolve(promise); - }, timeout); - return deferred.promise; -} - -/** - * Passes a continuation to a Node function, which is called with a given - * `this` value and arguments provided as an array, and returns a promise. - * - * var FS = require("fs"); - * Q.napply(FS.readFile, FS, [__filename]) - * .then(function (content) { - * }) - * - */ -exports.napply = napply; -function napply(callback, thisp, args) { - return nbind(callback, thisp).apply(void 0, args); -} - -/** - * Passes a continuation to a Node function, which is called with a given - * `this` value and arguments provided individually, and returns a promise. - * - * var FS = require("fs"); - * Q.ncall(FS.readFile, FS, __filename) - * .then(function (content) { - * }) - * - */ -exports.ncall = ncall; -function ncall(callback, thisp /*, ...args*/) { - var args = array_slice(arguments, 2); - return napply(callback, thisp, args); -} - -/** - * Wraps a NodeJS continuation passing function and returns an equivalent - * version that returns a promise. - * - * Q.nbind(FS.readFile, FS)(__filename) - * .then(console.log) - * .end() - * - */ -exports.nbind = nbind; -function nbind(callback /* thisp, ...args*/) { - if (arguments.length > 1) { - var thisp = arguments[1]; - var args = array_slice(arguments, 2); - - var originalCallback = callback; - callback = function () { - var combinedArgs = args.concat(array_slice(arguments)); - return originalCallback.apply(thisp, combinedArgs); - }; - } - return function () { - var deferred = defer(); - var args = array_slice(arguments); - // add a continuation that resolves the promise - args.push(deferred.makeNodeResolver()); - // trap exceptions thrown by the callback - fapply(callback, args) - .fail(deferred.reject); - return deferred.promise; - }; -} - -/** - * Calls a method of a Node-style object that accepts a Node-style - * callback with a given array of arguments, plus a provided callback. - * @param object an object that has the named method - * @param {String} name name of the method of object - * @param {Array} args arguments to pass to the method; the callback - * will be provided by Q and appended to these arguments. - * @returns a promise for the value or error - */ -exports.npost = npost; -function npost(object, name, args) { - return napply(object[name], object, args); -} - -/** - * Calls a method of a Node-style object that accepts a Node-style - * callback, forwarding the given variadic arguments, plus a provided - * callback argument. - * @param object an object that has the named method - * @param {String} name name of the method of object - * @param ...args arguments to pass to the method; the callback will - * be provided by Q and appended to these arguments. - * @returns a promise for the value or error - */ -exports.ninvoke = ninvoke; -function ninvoke(object, name /*, ...args*/) { - var args = array_slice(arguments, 2); - return napply(object[name], object, args); -} - -defend(exports); - -});