sproutcore 1.10.0.rc.3 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/VERSION.yml +1 -1
- data/lib/buildtasks/manifest.rake +3 -2
- data/lib/frameworks/sproutcore/Buildfile +3 -1
- data/lib/frameworks/sproutcore/CHANGELOG.md +26 -2
- data/lib/frameworks/sproutcore/apps/showcase/resources/main_page.js +3 -0
- data/lib/frameworks/sproutcore/apps/showcase/views/views_item_view.js +1 -1
- data/lib/frameworks/sproutcore/apps/welcome/english.lproj/main_page.js +3 -0
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +5 -5
- data/lib/frameworks/sproutcore/frameworks/bootstrap/tests/system/browser.js +9 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane_statechart.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/browser.js +6 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +17 -55
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/animation.js +57 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/isVisible.js +24 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/view_states_test.js +31 -13
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +8 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +24 -20
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +39 -29
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +400 -242
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +37 -32
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +1 -8
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/modal.js +3 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/panel.js +4 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +53 -6
- data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +9 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +16 -12
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +16 -2
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +10 -8
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js +102 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/validators/password.js +15 -7
- data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/testing/system/runner.js +4 -0
- data/lib/frameworks/sproutcore/phantomjs/minimist.js +181 -0
- data/lib/frameworks/sproutcore/phantomjs/q.js +1937 -0
- data/lib/frameworks/sproutcore/phantomjs/test_runner.js +733 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/44px/button.css +2 -2
- data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/button.css +11 -11
- data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/button.css +5 -5
- data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/jumbo/button.css +3 -3
- data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/small/button.css +3 -3
- data/lib/frameworks/sproutcore/themes/ace/resources/button/popup/select.css +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/checkbox/ace/checkbox.css +3 -3
- data/lib/frameworks/sproutcore/themes/ace/resources/collection/source-list/source_list_view.css +4 -4
- data/lib/frameworks/sproutcore/themes/ace/resources/disclosure/ace/disclosure.css +6 -6
- data/lib/frameworks/sproutcore/themes/ace/resources/imagebutton/ace/imagebutton.css +5 -5
- data/lib/frameworks/sproutcore/themes/ace/resources/menu/menu.css +16 -16
- data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +42 -42
- data/lib/frameworks/sproutcore/themes/ace/resources/progress/ace/progress.css +19 -19
- data/lib/frameworks/sproutcore/themes/ace/resources/radio/radio.css +12 -12
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal.css +7 -7
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal_touch.css +18 -18
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical.css +8 -8
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical_touch.css +16 -16
- data/lib/frameworks/sproutcore/themes/ace/resources/segmented/44px/segmented.css +2 -2
- data/lib/frameworks/sproutcore/themes/ace/resources/segmented/segmented.css +13 -13
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/slider.css +11 -11
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/slider.css +11 -11
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/slider.css +11 -11
- data/lib/frameworks/sproutcore/themes/ace/resources/split/split.css +6 -6
- data/lib/frameworks/sproutcore/themes/ace/resources/toolbar/toolbar.css +2 -2
- data/lib/frameworks/sproutcore/themes/iphone_theme/english.lproj/button.css +3 -3
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/button.css +18 -18
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/checkbox.css +7 -7
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/collection.css +2 -2
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/core.css +7 -7
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/disclosure.css +3 -3
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/list_item.css +4 -4
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/menu.css +3 -3
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/menu_item_view.css +5 -5
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/panel.css +7 -7
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/picker.css +3 -3
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/progress.css +5 -5
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/radio.css +4 -4
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/scroller.css +3 -3
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/segmented.css +7 -7
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/slider.css +2 -2
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/split_view.css +2 -2
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/toolbar.css +3 -3
- data/lib/sproutcore/tools/server.rb +9 -3
- metadata +8 -83
- data/lib/frameworks/sproutcore/design/Assorted Images/sproutcore-startup-landscape.jpg +0 -0
- data/lib/frameworks/sproutcore/design/Assorted Images/sproutcore-startup-landscape.png +0 -0
- data/lib/frameworks/sproutcore/design/Assorted Images/sproutcore-startup-portrait.jpg +0 -0
- data/lib/frameworks/sproutcore/design/Assorted Images/sproutcore-startup-portrait.png +0 -0
- data/lib/frameworks/sproutcore/design/Assorted Images/sproutcore-startup.png +0 -0
- data/lib/frameworks/sproutcore/design/Record State Table.numbers +0 -0
- data/lib/frameworks/sproutcore/design/greenhouse-statechart.pdf +0 -0
- data/lib/frameworks/sproutcore/tests/phantomjs_runner.phantomjs +0 -611
- data/lib/frameworks/sproutcore/themes/ace/designs/dark.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/designs/light.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/designs/psds/panel/PanelPane.opacity +0 -0
- data/lib/frameworks/sproutcore/themes/ace/designs/psds/panel/Pointers.opacity +0 -0
- data/lib/frameworks/sproutcore/themes/ace/designs/switch/switch_handle.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/designs/switch/switch_off.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/designs/switch/switch_on.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/10.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/100.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/102.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/110.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/120.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/127.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/18.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/19.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/2.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/24.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/26.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/27.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/28.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/29.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/30.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/31.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/33.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/37.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/41.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/16/99.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/10.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/100.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/102.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/110.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/120.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/127.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/18.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/19.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/2.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/24.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/26.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/27.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/28.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/29.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/30.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/31.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/33.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/37.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/41.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/24/99.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/10.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/100.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/102.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/110.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/120.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/127.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/18.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/19.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/2.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/24.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/26.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/27.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/28.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/29.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/30.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/31.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/33.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/37.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/41.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/32/99.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/48/10.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/48/18.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/48/19.png +0 -0
- data/lib/frameworks/sproutcore/themes/legacy_theme/Source/icons/48/2.png +0 -0
@@ -7,13 +7,21 @@
|
|
7
7
|
// ========================================================================
|
8
8
|
// SC.Validator.Password Base Tests
|
9
9
|
// ========================================================================
|
10
|
-
/*globals module test ok isObj equals expects */
|
10
|
+
/*globals module, test, ok, isObj, equals, expects */
|
11
11
|
// htmlbody('<!-- Test Styles -->\
|
12
12
|
// <form id="form" action="formaction"><input type="password" name="action" value="Test" id="field" maxlength="30"/></form>\
|
13
13
|
// ');
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
module("SC.Validator.password");
|
15
|
+
|
16
|
+
test("Attaching the field to the form");
|
17
|
+
/* WON'T FIX AT THIS TIME.
|
18
|
+
|
19
|
+
This entire file was commented out.
|
20
|
+
An empty unit test file will cause a timeout in the test runner,
|
21
|
+
so I'm converting this to a warning.
|
22
|
+
|
23
|
+
, function() {
|
24
|
+
var a = SC.Validator.Password.attachTo(SC.$("#form"), SC.$('#field'));
|
25
|
+
alert(a);
|
26
|
+
});
|
27
|
+
*/
|
@@ -154,7 +154,7 @@ SC.RunLoop = SC.Object.extend(/** @scope SC.RunLoop.prototype */ {
|
|
154
154
|
// loop and may fire before the invokeOnce code in this case.
|
155
155
|
var isRunLoopInProgress = this.get('isRunLoopInProgress');
|
156
156
|
if (!isRunLoopInProgress) {
|
157
|
-
SC.warn("Developer Warning: invokeOnce called outside of the run loop
|
157
|
+
SC.warn("Developer Warning: invokeOnce called outside of the run loop, which may cause unexpected problems. Check the stack trace below for what triggered this, and see http://blog.sproutcore.com/1-10-upgrade-invokefoo/ for more.");
|
158
158
|
console.trace();
|
159
159
|
}
|
160
160
|
//@endif
|
@@ -226,7 +226,7 @@ SC.RunLoop = SC.Object.extend(/** @scope SC.RunLoop.prototype */ {
|
|
226
226
|
// loop and may fire before the invokeLast code in this case.
|
227
227
|
var isRunLoopInProgress = this.get('isRunLoopInProgress');
|
228
228
|
if (!isRunLoopInProgress) {
|
229
|
-
SC.warn("Developer Warning: invokeLast called outside of the run loop
|
229
|
+
SC.warn("Developer Warning: invokeLast called outside of the run loop, which may cause unexpected problems. Check the stack trace below for what triggered this, and see http://blog.sproutcore.com/1-10-upgrade-invokefoo/ for more.");
|
230
230
|
console.trace();
|
231
231
|
}
|
232
232
|
//@endif
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module.exports = function (args, opts) {
|
2
|
+
if (!opts) opts = {};
|
3
|
+
|
4
|
+
var flags = { bools : {}, strings : {} };
|
5
|
+
|
6
|
+
[].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
|
7
|
+
flags.bools[key] = true;
|
8
|
+
});
|
9
|
+
|
10
|
+
[].concat(opts.string).filter(Boolean).forEach(function (key) {
|
11
|
+
flags.strings[key] = true;
|
12
|
+
});
|
13
|
+
|
14
|
+
var aliases = {};
|
15
|
+
Object.keys(opts.alias || {}).forEach(function (key) {
|
16
|
+
aliases[key] = [].concat(opts.alias[key]);
|
17
|
+
aliases[key].forEach(function (x) {
|
18
|
+
aliases[x] = [key].concat(aliases[key].filter(function (y) {
|
19
|
+
return x !== y;
|
20
|
+
}));
|
21
|
+
});
|
22
|
+
});
|
23
|
+
|
24
|
+
var defaults = opts['default'] || {};
|
25
|
+
|
26
|
+
var argv = { _ : [] };
|
27
|
+
Object.keys(flags.bools).forEach(function (key) {
|
28
|
+
setArg(key, defaults[key] === undefined ? false : defaults[key]);
|
29
|
+
});
|
30
|
+
|
31
|
+
function setArg (key, val) {
|
32
|
+
var value = !flags.strings[key] && isNumber(val)
|
33
|
+
? Number(val) : val
|
34
|
+
;
|
35
|
+
setKey(argv, key.split('.'), value);
|
36
|
+
|
37
|
+
(aliases[key] || []).forEach(function (x) {
|
38
|
+
setKey(argv, x.split('.'), value);
|
39
|
+
});
|
40
|
+
}
|
41
|
+
|
42
|
+
for (var i = 0; i < args.length; i++) {
|
43
|
+
var arg = args[i];
|
44
|
+
|
45
|
+
if (arg === '--') {
|
46
|
+
argv._.push.apply(argv._, args.slice(i + 1));
|
47
|
+
break;
|
48
|
+
}
|
49
|
+
else if (arg.match(/^--.+=/)) {
|
50
|
+
// Using [\s\S] instead of . because js doesn't support the
|
51
|
+
// 'dotall' regex modifier. See:
|
52
|
+
// http://stackoverflow.com/a/1068308/13216
|
53
|
+
var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
|
54
|
+
setArg(m[1], m[2]);
|
55
|
+
}
|
56
|
+
else if (arg.match(/^--no-.+/)) {
|
57
|
+
var key = arg.match(/^--no-(.+)/)[1];
|
58
|
+
setArg(key, false);
|
59
|
+
}
|
60
|
+
else if (arg.match(/^--.+/)) {
|
61
|
+
var key = arg.match(/^--(.+)/)[1];
|
62
|
+
var next = args[i + 1];
|
63
|
+
if (next !== undefined && !next.match(/^-/)
|
64
|
+
&& !flags.bools[key]
|
65
|
+
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) {
|
66
|
+
setArg(key, next);
|
67
|
+
i++;
|
68
|
+
}
|
69
|
+
else if (/^(true|false)$/.test(next)) {
|
70
|
+
setArg(key, next === 'true');
|
71
|
+
i++;
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
setArg(key, true);
|
75
|
+
}
|
76
|
+
}
|
77
|
+
else if (arg.match(/^-[^-]+/)) {
|
78
|
+
var letters = arg.slice(1,-1).split('');
|
79
|
+
|
80
|
+
var broken = false;
|
81
|
+
for (var j = 0; j < letters.length; j++) {
|
82
|
+
var next = arg.slice(j+2);
|
83
|
+
|
84
|
+
if (next === '-') {
|
85
|
+
setArg(letters[j], next)
|
86
|
+
continue;
|
87
|
+
}
|
88
|
+
|
89
|
+
if (/[A-Za-z]/.test(letters[j])
|
90
|
+
&& /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
|
91
|
+
setArg(letters[j], next);
|
92
|
+
broken = true;
|
93
|
+
break;
|
94
|
+
}
|
95
|
+
|
96
|
+
if (letters[j+1] && letters[j+1].match(/\W/)) {
|
97
|
+
setArg(letters[j], arg.slice(j+2));
|
98
|
+
broken = true;
|
99
|
+
break;
|
100
|
+
}
|
101
|
+
else {
|
102
|
+
setArg(letters[j], true);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
var key = arg.slice(-1)[0];
|
107
|
+
if (!broken && key !== '-') {
|
108
|
+
|
109
|
+
if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
|
110
|
+
&& !flags.bools[key]
|
111
|
+
&& (aliases[key] ? !flags.bools[aliases[key]] : true)) {
|
112
|
+
setArg(key, args[i+1]);
|
113
|
+
i++;
|
114
|
+
}
|
115
|
+
else if (args[i+1] && /true|false/.test(args[i+1])) {
|
116
|
+
setArg(key, args[i+1] === 'true');
|
117
|
+
i++;
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
setArg(key, true);
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
else {
|
125
|
+
argv._.push(
|
126
|
+
flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
|
127
|
+
);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
Object.keys(defaults).forEach(function (key) {
|
132
|
+
if (!hasKey(argv, key.split('.'))) {
|
133
|
+
setKey(argv, key.split('.'), defaults[key]);
|
134
|
+
|
135
|
+
(aliases[key] || []).forEach(function (x) {
|
136
|
+
setKey(argv, x.split('.'), defaults[key]);
|
137
|
+
});
|
138
|
+
}
|
139
|
+
});
|
140
|
+
|
141
|
+
return argv;
|
142
|
+
};
|
143
|
+
|
144
|
+
function hasKey (obj, keys) {
|
145
|
+
var o = obj;
|
146
|
+
keys.slice(0,-1).forEach(function (key) {
|
147
|
+
o = (o[key] || {});
|
148
|
+
});
|
149
|
+
|
150
|
+
var key = keys[keys.length - 1];
|
151
|
+
return key in o;
|
152
|
+
}
|
153
|
+
|
154
|
+
function setKey (obj, keys, value) {
|
155
|
+
var o = obj;
|
156
|
+
keys.slice(0,-1).forEach(function (key) {
|
157
|
+
if (o[key] === undefined) o[key] = {};
|
158
|
+
o = o[key];
|
159
|
+
});
|
160
|
+
|
161
|
+
var key = keys[keys.length - 1];
|
162
|
+
if (o[key] === undefined || typeof o[key] === 'boolean') {
|
163
|
+
o[key] = value;
|
164
|
+
}
|
165
|
+
else if (Array.isArray(o[key])) {
|
166
|
+
o[key].push(value);
|
167
|
+
}
|
168
|
+
else {
|
169
|
+
o[key] = [ o[key], value ];
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
function isNumber (x) {
|
174
|
+
if (typeof x === 'number') return true;
|
175
|
+
if (/^0x[0-9a-f]+$/i.test(x)) return true;
|
176
|
+
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
|
177
|
+
}
|
178
|
+
|
179
|
+
function longest (xs) {
|
180
|
+
return Math.max.apply(null, xs.map(function (x) { return x.length }));
|
181
|
+
}
|
@@ -0,0 +1,1937 @@
|
|
1
|
+
// vim:ts=4:sts=4:sw=4:
|
2
|
+
/*!
|
3
|
+
*
|
4
|
+
* Copyright 2009-2012 Kris Kowal under the terms of the MIT
|
5
|
+
* license found at http://github.com/kriskowal/q/raw/master/LICENSE
|
6
|
+
*
|
7
|
+
* With parts by Tyler Close
|
8
|
+
* Copyright 2007-2009 Tyler Close under the terms of the MIT X license found
|
9
|
+
* at http://www.opensource.org/licenses/mit-license.html
|
10
|
+
* Forked at ref_send.js version: 2009-05-11
|
11
|
+
*
|
12
|
+
* With parts by Mark Miller
|
13
|
+
* Copyright (C) 2011 Google Inc.
|
14
|
+
*
|
15
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
16
|
+
* you may not use this file except in compliance with the License.
|
17
|
+
* You may obtain a copy of the License at
|
18
|
+
*
|
19
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
20
|
+
*
|
21
|
+
* Unless required by applicable law or agreed to in writing, software
|
22
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
23
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
24
|
+
* See the License for the specific language governing permissions and
|
25
|
+
* limitations under the License.
|
26
|
+
*
|
27
|
+
*/
|
28
|
+
|
29
|
+
(function (definition) {
|
30
|
+
// Turn off strict mode for this function so we can assign to global.Q
|
31
|
+
/* jshint strict: false */
|
32
|
+
|
33
|
+
// This file will function properly as a <script> tag, or a module
|
34
|
+
// using CommonJS and NodeJS or RequireJS module formats. In
|
35
|
+
// Common/Node/RequireJS, the module exports the Q API and when
|
36
|
+
// executed as a simple <script>, it creates a Q global instead.
|
37
|
+
|
38
|
+
// Montage Require
|
39
|
+
if (typeof bootstrap === "function") {
|
40
|
+
bootstrap("promise", definition);
|
41
|
+
|
42
|
+
// CommonJS
|
43
|
+
} else if (typeof exports === "object") {
|
44
|
+
module.exports = definition();
|
45
|
+
|
46
|
+
// RequireJS
|
47
|
+
} else if (typeof define === "function" && define.amd) {
|
48
|
+
define(definition);
|
49
|
+
|
50
|
+
// SES (Secure EcmaScript)
|
51
|
+
} else if (typeof ses !== "undefined") {
|
52
|
+
if (!ses.ok()) {
|
53
|
+
return;
|
54
|
+
} else {
|
55
|
+
ses.makeQ = definition;
|
56
|
+
}
|
57
|
+
|
58
|
+
// <script>
|
59
|
+
} else {
|
60
|
+
Q = definition();
|
61
|
+
}
|
62
|
+
|
63
|
+
})(function () {
|
64
|
+
"use strict";
|
65
|
+
|
66
|
+
var hasStacks = false;
|
67
|
+
try {
|
68
|
+
throw new Error();
|
69
|
+
} catch (e) {
|
70
|
+
hasStacks = !!e.stack;
|
71
|
+
}
|
72
|
+
|
73
|
+
// All code after this point will be filtered from stack traces reported
|
74
|
+
// by Q.
|
75
|
+
var qStartingLine = captureLine();
|
76
|
+
var qFileName;
|
77
|
+
|
78
|
+
// shims
|
79
|
+
|
80
|
+
// used for fallback in "allResolved"
|
81
|
+
var noop = function () {};
|
82
|
+
|
83
|
+
// Use the fastest possible means to execute a task in a future turn
|
84
|
+
// of the event loop.
|
85
|
+
var nextTick =(function () {
|
86
|
+
// linked list of tasks (single, with head node)
|
87
|
+
var head = {task: void 0, next: null};
|
88
|
+
var tail = head;
|
89
|
+
var flushing = false;
|
90
|
+
var requestTick = void 0;
|
91
|
+
var isNodeJS = false;
|
92
|
+
|
93
|
+
function flush() {
|
94
|
+
/* jshint loopfunc: true */
|
95
|
+
|
96
|
+
while (head.next) {
|
97
|
+
head = head.next;
|
98
|
+
var task = head.task;
|
99
|
+
head.task = void 0;
|
100
|
+
var domain = head.domain;
|
101
|
+
|
102
|
+
if (domain) {
|
103
|
+
head.domain = void 0;
|
104
|
+
domain.enter();
|
105
|
+
}
|
106
|
+
|
107
|
+
try {
|
108
|
+
task();
|
109
|
+
|
110
|
+
} catch (e) {
|
111
|
+
if (isNodeJS) {
|
112
|
+
// In node, uncaught exceptions are considered fatal errors.
|
113
|
+
// Re-throw them synchronously to interrupt flushing!
|
114
|
+
|
115
|
+
// Ensure continuation if the uncaught exception is suppressed
|
116
|
+
// listening "uncaughtException" events (as domains does).
|
117
|
+
// Continue in next event to avoid tick recursion.
|
118
|
+
if (domain) {
|
119
|
+
domain.exit();
|
120
|
+
}
|
121
|
+
setTimeout(flush, 0);
|
122
|
+
if (domain) {
|
123
|
+
domain.enter();
|
124
|
+
}
|
125
|
+
|
126
|
+
throw e;
|
127
|
+
|
128
|
+
} else {
|
129
|
+
// In browsers, uncaught exceptions are not fatal.
|
130
|
+
// Re-throw them asynchronously to avoid slow-downs.
|
131
|
+
setTimeout(function() {
|
132
|
+
throw e;
|
133
|
+
}, 0);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
if (domain) {
|
138
|
+
domain.exit();
|
139
|
+
}
|
140
|
+
}
|
141
|
+
|
142
|
+
flushing = false;
|
143
|
+
}
|
144
|
+
|
145
|
+
nextTick = function (task) {
|
146
|
+
tail = tail.next = {
|
147
|
+
task: task,
|
148
|
+
domain: isNodeJS && process.domain,
|
149
|
+
next: null
|
150
|
+
};
|
151
|
+
|
152
|
+
if (!flushing) {
|
153
|
+
flushing = true;
|
154
|
+
requestTick();
|
155
|
+
}
|
156
|
+
};
|
157
|
+
|
158
|
+
if (typeof process !== "undefined" && process.nextTick) {
|
159
|
+
// Node.js before 0.9. Note that some fake-Node environments, like the
|
160
|
+
// Mocha test runner, introduce a `process` global without a `nextTick`.
|
161
|
+
isNodeJS = true;
|
162
|
+
|
163
|
+
requestTick = function () {
|
164
|
+
process.nextTick(flush);
|
165
|
+
};
|
166
|
+
|
167
|
+
} else if (typeof setImmediate === "function") {
|
168
|
+
// In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
|
169
|
+
if (typeof window !== "undefined") {
|
170
|
+
requestTick = setImmediate.bind(window, flush);
|
171
|
+
} else {
|
172
|
+
requestTick = function () {
|
173
|
+
setImmediate(flush);
|
174
|
+
};
|
175
|
+
}
|
176
|
+
|
177
|
+
} else if (typeof MessageChannel !== "undefined") {
|
178
|
+
// modern browsers
|
179
|
+
// http://www.nonblocking.io/2011/06/windownexttick.html
|
180
|
+
var channel = new MessageChannel();
|
181
|
+
// At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create
|
182
|
+
// working message ports the first time a page loads.
|
183
|
+
channel.port1.onmessage = function () {
|
184
|
+
requestTick = requestPortTick;
|
185
|
+
channel.port1.onmessage = flush;
|
186
|
+
flush();
|
187
|
+
};
|
188
|
+
var requestPortTick = function () {
|
189
|
+
// Opera requires us to provide a message payload, regardless of
|
190
|
+
// whether we use it.
|
191
|
+
channel.port2.postMessage(0);
|
192
|
+
};
|
193
|
+
requestTick = function () {
|
194
|
+
setTimeout(flush, 0);
|
195
|
+
requestPortTick();
|
196
|
+
};
|
197
|
+
|
198
|
+
} else {
|
199
|
+
// old browsers
|
200
|
+
requestTick = function () {
|
201
|
+
setTimeout(flush, 0);
|
202
|
+
};
|
203
|
+
}
|
204
|
+
|
205
|
+
return nextTick;
|
206
|
+
})();
|
207
|
+
|
208
|
+
// Attempt to make generics safe in the face of downstream
|
209
|
+
// modifications.
|
210
|
+
// There is no situation where this is necessary.
|
211
|
+
// If you need a security guarantee, these primordials need to be
|
212
|
+
// deeply frozen anyway, and if you don’t need a security guarantee,
|
213
|
+
// this is just plain paranoid.
|
214
|
+
// However, this does have the nice side-effect of reducing the size
|
215
|
+
// of the code by reducing x.call() to merely x(), eliminating many
|
216
|
+
// hard-to-minify characters.
|
217
|
+
// See Mark Miller’s explanation of what this does.
|
218
|
+
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
|
219
|
+
var call = Function.call;
|
220
|
+
function uncurryThis(f) {
|
221
|
+
return function () {
|
222
|
+
return call.apply(f, arguments);
|
223
|
+
};
|
224
|
+
}
|
225
|
+
// This is equivalent, but slower:
|
226
|
+
// uncurryThis = Function_bind.bind(Function_bind.call);
|
227
|
+
// http://jsperf.com/uncurrythis
|
228
|
+
|
229
|
+
var array_slice = uncurryThis(Array.prototype.slice);
|
230
|
+
|
231
|
+
var array_reduce = uncurryThis(
|
232
|
+
Array.prototype.reduce || function (callback, basis) {
|
233
|
+
var index = 0,
|
234
|
+
length = this.length;
|
235
|
+
// concerning the initial value, if one is not provided
|
236
|
+
if (arguments.length === 1) {
|
237
|
+
// seek to the first value in the array, accounting
|
238
|
+
// for the possibility that is is a sparse array
|
239
|
+
do {
|
240
|
+
if (index in this) {
|
241
|
+
basis = this[index++];
|
242
|
+
break;
|
243
|
+
}
|
244
|
+
if (++index >= length) {
|
245
|
+
throw new TypeError();
|
246
|
+
}
|
247
|
+
} while (1);
|
248
|
+
}
|
249
|
+
// reduce
|
250
|
+
for (; index < length; index++) {
|
251
|
+
// account for the possibility that the array is sparse
|
252
|
+
if (index in this) {
|
253
|
+
basis = callback(basis, this[index], index);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
return basis;
|
257
|
+
}
|
258
|
+
);
|
259
|
+
|
260
|
+
var array_indexOf = uncurryThis(
|
261
|
+
Array.prototype.indexOf || function (value) {
|
262
|
+
// not a very good shim, but good enough for our one use of it
|
263
|
+
for (var i = 0; i < this.length; i++) {
|
264
|
+
if (this[i] === value) {
|
265
|
+
return i;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
return -1;
|
269
|
+
}
|
270
|
+
);
|
271
|
+
|
272
|
+
var array_map = uncurryThis(
|
273
|
+
Array.prototype.map || function (callback, thisp) {
|
274
|
+
var self = this;
|
275
|
+
var collect = [];
|
276
|
+
array_reduce(self, function (undefined, value, index) {
|
277
|
+
collect.push(callback.call(thisp, value, index, self));
|
278
|
+
}, void 0);
|
279
|
+
return collect;
|
280
|
+
}
|
281
|
+
);
|
282
|
+
|
283
|
+
var object_create = Object.create || function (prototype) {
|
284
|
+
function Type() { }
|
285
|
+
Type.prototype = prototype;
|
286
|
+
return new Type();
|
287
|
+
};
|
288
|
+
|
289
|
+
var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
|
290
|
+
|
291
|
+
var object_keys = Object.keys || function (object) {
|
292
|
+
var keys = [];
|
293
|
+
for (var key in object) {
|
294
|
+
if (object_hasOwnProperty(object, key)) {
|
295
|
+
keys.push(key);
|
296
|
+
}
|
297
|
+
}
|
298
|
+
return keys;
|
299
|
+
};
|
300
|
+
|
301
|
+
var object_toString = uncurryThis(Object.prototype.toString);
|
302
|
+
|
303
|
+
function isObject(value) {
|
304
|
+
return value === Object(value);
|
305
|
+
}
|
306
|
+
|
307
|
+
// generator related shims
|
308
|
+
|
309
|
+
// FIXME: Remove this function once ES6 generators are in SpiderMonkey.
|
310
|
+
function isStopIteration(exception) {
|
311
|
+
return (
|
312
|
+
object_toString(exception) === "[object StopIteration]" ||
|
313
|
+
exception instanceof QReturnValue
|
314
|
+
);
|
315
|
+
}
|
316
|
+
|
317
|
+
// FIXME: Remove this helper and Q.return once ES6 generators are in
|
318
|
+
// SpiderMonkey.
|
319
|
+
var QReturnValue;
|
320
|
+
if (typeof ReturnValue !== "undefined") {
|
321
|
+
QReturnValue = ReturnValue;
|
322
|
+
} else {
|
323
|
+
QReturnValue = function (value) {
|
324
|
+
this.value = value;
|
325
|
+
};
|
326
|
+
}
|
327
|
+
|
328
|
+
// Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only
|
329
|
+
// engine that has a deployed base of browsers that support generators.
|
330
|
+
// However, SM's generators use the Python-inspired semantics of
|
331
|
+
// outdated ES6 drafts. We would like to support ES6, but we'd also
|
332
|
+
// like to make it possible to use generators in deployed browsers, so
|
333
|
+
// we also support Python-style generators. At some point we can remove
|
334
|
+
// this block.
|
335
|
+
var hasES6Generators;
|
336
|
+
try {
|
337
|
+
/* jshint evil: true, nonew: false */
|
338
|
+
new Function("(function* (){ yield 1; })");
|
339
|
+
hasES6Generators = true;
|
340
|
+
} catch (e) {
|
341
|
+
hasES6Generators = false;
|
342
|
+
}
|
343
|
+
|
344
|
+
// long stack traces
|
345
|
+
|
346
|
+
var STACK_JUMP_SEPARATOR = "From previous event:";
|
347
|
+
|
348
|
+
function makeStackTraceLong(error, promise) {
|
349
|
+
// If possible, transform the error stack trace by removing Node and Q
|
350
|
+
// cruft, then concatenating with the stack trace of `promise`. See #57.
|
351
|
+
if (hasStacks &&
|
352
|
+
promise.stack &&
|
353
|
+
typeof error === "object" &&
|
354
|
+
error !== null &&
|
355
|
+
error.stack &&
|
356
|
+
error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
|
357
|
+
) {
|
358
|
+
var stacks = [];
|
359
|
+
for (var p = promise; !!p; p = p.source) {
|
360
|
+
if (p.stack) {
|
361
|
+
stacks.unshift(p.stack);
|
362
|
+
}
|
363
|
+
}
|
364
|
+
stacks.unshift(error.stack);
|
365
|
+
|
366
|
+
var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n");
|
367
|
+
error.stack = filterStackString(concatedStacks);
|
368
|
+
}
|
369
|
+
}
|
370
|
+
|
371
|
+
function filterStackString(stackString) {
|
372
|
+
var lines = stackString.split("\n");
|
373
|
+
var desiredLines = [];
|
374
|
+
for (var i = 0; i < lines.length; ++i) {
|
375
|
+
var line = lines[i];
|
376
|
+
|
377
|
+
if (!isInternalFrame(line) && !isNodeFrame(line) && line) {
|
378
|
+
desiredLines.push(line);
|
379
|
+
}
|
380
|
+
}
|
381
|
+
return desiredLines.join("\n");
|
382
|
+
}
|
383
|
+
|
384
|
+
function isNodeFrame(stackLine) {
|
385
|
+
return stackLine.indexOf("(module.js:") !== -1 ||
|
386
|
+
stackLine.indexOf("(node.js:") !== -1;
|
387
|
+
}
|
388
|
+
|
389
|
+
function getFileNameAndLineNumber(stackLine) {
|
390
|
+
// Named functions: "at functionName (filename:lineNumber:columnNumber)"
|
391
|
+
// In IE10 function name can have spaces ("Anonymous function") O_o
|
392
|
+
var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine);
|
393
|
+
if (attempt1) {
|
394
|
+
return [attempt1[1], Number(attempt1[2])];
|
395
|
+
}
|
396
|
+
|
397
|
+
// Anonymous functions: "at filename:lineNumber:columnNumber"
|
398
|
+
var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine);
|
399
|
+
if (attempt2) {
|
400
|
+
return [attempt2[1], Number(attempt2[2])];
|
401
|
+
}
|
402
|
+
|
403
|
+
// Firefox style: "function@filename:lineNumber or @filename:lineNumber"
|
404
|
+
var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine);
|
405
|
+
if (attempt3) {
|
406
|
+
return [attempt3[1], Number(attempt3[2])];
|
407
|
+
}
|
408
|
+
}
|
409
|
+
|
410
|
+
function isInternalFrame(stackLine) {
|
411
|
+
var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine);
|
412
|
+
|
413
|
+
if (!fileNameAndLineNumber) {
|
414
|
+
return false;
|
415
|
+
}
|
416
|
+
|
417
|
+
var fileName = fileNameAndLineNumber[0];
|
418
|
+
var lineNumber = fileNameAndLineNumber[1];
|
419
|
+
|
420
|
+
return fileName === qFileName &&
|
421
|
+
lineNumber >= qStartingLine &&
|
422
|
+
lineNumber <= qEndingLine;
|
423
|
+
}
|
424
|
+
|
425
|
+
// discover own file name and line number range for filtering stack
|
426
|
+
// traces
|
427
|
+
function captureLine() {
|
428
|
+
if (!hasStacks) {
|
429
|
+
return;
|
430
|
+
}
|
431
|
+
|
432
|
+
try {
|
433
|
+
throw new Error();
|
434
|
+
} catch (e) {
|
435
|
+
var lines = e.stack.split("\n");
|
436
|
+
var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2];
|
437
|
+
var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine);
|
438
|
+
if (!fileNameAndLineNumber) {
|
439
|
+
return;
|
440
|
+
}
|
441
|
+
|
442
|
+
qFileName = fileNameAndLineNumber[0];
|
443
|
+
return fileNameAndLineNumber[1];
|
444
|
+
}
|
445
|
+
}
|
446
|
+
|
447
|
+
function deprecate(callback, name, alternative) {
|
448
|
+
return function () {
|
449
|
+
if (typeof console !== "undefined" &&
|
450
|
+
typeof console.warn === "function") {
|
451
|
+
console.warn(name + " is deprecated, use " + alternative +
|
452
|
+
" instead.", new Error("").stack);
|
453
|
+
}
|
454
|
+
return callback.apply(callback, arguments);
|
455
|
+
};
|
456
|
+
}
|
457
|
+
|
458
|
+
// end of shims
|
459
|
+
// beginning of real work
|
460
|
+
|
461
|
+
/**
|
462
|
+
* Constructs a promise for an immediate reference, passes promises through, or
|
463
|
+
* coerces promises from different systems.
|
464
|
+
* @param value immediate reference or promise
|
465
|
+
*/
|
466
|
+
function Q(value) {
|
467
|
+
// If the object is already a Promise, return it directly. This enables
|
468
|
+
// the resolve function to both be used to created references from objects,
|
469
|
+
// but to tolerably coerce non-promises to promises.
|
470
|
+
if (isPromise(value)) {
|
471
|
+
return value;
|
472
|
+
}
|
473
|
+
|
474
|
+
// assimilate thenables
|
475
|
+
if (isPromiseAlike(value)) {
|
476
|
+
return coerce(value);
|
477
|
+
} else {
|
478
|
+
return fulfill(value);
|
479
|
+
}
|
480
|
+
}
|
481
|
+
Q.resolve = Q;
|
482
|
+
|
483
|
+
/**
|
484
|
+
* Performs a task in a future turn of the event loop.
|
485
|
+
* @param {Function} task
|
486
|
+
*/
|
487
|
+
Q.nextTick = nextTick;
|
488
|
+
|
489
|
+
/**
|
490
|
+
* Controls whether or not long stack traces will be on
|
491
|
+
*/
|
492
|
+
Q.longStackSupport = false;
|
493
|
+
|
494
|
+
/**
|
495
|
+
* Constructs a {promise, resolve, reject} object.
|
496
|
+
*
|
497
|
+
* `resolve` is a callback to invoke with a more resolved value for the
|
498
|
+
* promise. To fulfill the promise, invoke `resolve` with any value that is
|
499
|
+
* not a thenable. To reject the promise, invoke `resolve` with a rejected
|
500
|
+
* thenable, or invoke `reject` with the reason directly. To resolve the
|
501
|
+
* promise to another thenable, thus putting it in the same state, invoke
|
502
|
+
* `resolve` with that other thenable.
|
503
|
+
*/
|
504
|
+
Q.defer = defer;
|
505
|
+
function defer() {
|
506
|
+
// if "messages" is an "Array", that indicates that the promise has not yet
|
507
|
+
// been resolved. If it is "undefined", it has been resolved. Each
|
508
|
+
// element of the messages array is itself an array of complete arguments to
|
509
|
+
// forward to the resolved promise. We coerce the resolution value to a
|
510
|
+
// promise using the `resolve` function because it handles both fully
|
511
|
+
// non-thenable values and other thenables gracefully.
|
512
|
+
var messages = [], progressListeners = [], resolvedPromise;
|
513
|
+
|
514
|
+
var deferred = object_create(defer.prototype);
|
515
|
+
var promise = object_create(Promise.prototype);
|
516
|
+
|
517
|
+
promise.promiseDispatch = function (resolve, op, operands) {
|
518
|
+
var args = array_slice(arguments);
|
519
|
+
if (messages) {
|
520
|
+
messages.push(args);
|
521
|
+
if (op === "when" && operands[1]) { // progress operand
|
522
|
+
progressListeners.push(operands[1]);
|
523
|
+
}
|
524
|
+
} else {
|
525
|
+
nextTick(function () {
|
526
|
+
resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
|
527
|
+
});
|
528
|
+
}
|
529
|
+
};
|
530
|
+
|
531
|
+
// XXX deprecated
|
532
|
+
promise.valueOf = deprecate(function () {
|
533
|
+
if (messages) {
|
534
|
+
return promise;
|
535
|
+
}
|
536
|
+
var nearerValue = nearer(resolvedPromise);
|
537
|
+
if (isPromise(nearerValue)) {
|
538
|
+
resolvedPromise = nearerValue; // shorten chain
|
539
|
+
}
|
540
|
+
return nearerValue;
|
541
|
+
}, "valueOf", "inspect");
|
542
|
+
|
543
|
+
promise.inspect = function () {
|
544
|
+
if (!resolvedPromise) {
|
545
|
+
return { state: "pending" };
|
546
|
+
}
|
547
|
+
return resolvedPromise.inspect();
|
548
|
+
};
|
549
|
+
|
550
|
+
if (Q.longStackSupport && hasStacks) {
|
551
|
+
try {
|
552
|
+
throw new Error();
|
553
|
+
} catch (e) {
|
554
|
+
// NOTE: don't try to use `Error.captureStackTrace` or transfer the
|
555
|
+
// accessor around; that causes memory leaks as per GH-111. Just
|
556
|
+
// reify the stack trace as a string ASAP.
|
557
|
+
//
|
558
|
+
// At the same time, cut off the first line; it's always just
|
559
|
+
// "[object Promise]\n", as per the `toString`.
|
560
|
+
promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1);
|
561
|
+
}
|
562
|
+
}
|
563
|
+
|
564
|
+
// NOTE: we do the checks for `resolvedPromise` in each method, instead of
|
565
|
+
// consolidating them into `become`, since otherwise we'd create new
|
566
|
+
// promises with the lines `become(whatever(value))`. See e.g. GH-252.
|
567
|
+
|
568
|
+
function become(newPromise) {
|
569
|
+
resolvedPromise = newPromise;
|
570
|
+
promise.source = newPromise;
|
571
|
+
|
572
|
+
array_reduce(messages, function (undefined, message) {
|
573
|
+
nextTick(function () {
|
574
|
+
newPromise.promiseDispatch.apply(newPromise, message);
|
575
|
+
});
|
576
|
+
}, void 0);
|
577
|
+
|
578
|
+
messages = void 0;
|
579
|
+
progressListeners = void 0;
|
580
|
+
}
|
581
|
+
|
582
|
+
deferred.promise = promise;
|
583
|
+
deferred.resolve = function (value) {
|
584
|
+
if (resolvedPromise) {
|
585
|
+
return;
|
586
|
+
}
|
587
|
+
|
588
|
+
become(Q(value));
|
589
|
+
};
|
590
|
+
|
591
|
+
deferred.fulfill = function (value) {
|
592
|
+
if (resolvedPromise) {
|
593
|
+
return;
|
594
|
+
}
|
595
|
+
|
596
|
+
become(fulfill(value));
|
597
|
+
};
|
598
|
+
deferred.reject = function (reason) {
|
599
|
+
if (resolvedPromise) {
|
600
|
+
return;
|
601
|
+
}
|
602
|
+
|
603
|
+
become(reject(reason));
|
604
|
+
};
|
605
|
+
deferred.notify = function (progress) {
|
606
|
+
if (resolvedPromise) {
|
607
|
+
return;
|
608
|
+
}
|
609
|
+
|
610
|
+
array_reduce(progressListeners, function (undefined, progressListener) {
|
611
|
+
nextTick(function () {
|
612
|
+
progressListener(progress);
|
613
|
+
});
|
614
|
+
}, void 0);
|
615
|
+
};
|
616
|
+
|
617
|
+
return deferred;
|
618
|
+
}
|
619
|
+
|
620
|
+
/**
|
621
|
+
* Creates a Node-style callback that will resolve or reject the deferred
|
622
|
+
* promise.
|
623
|
+
* @returns a nodeback
|
624
|
+
*/
|
625
|
+
defer.prototype.makeNodeResolver = function () {
|
626
|
+
var self = this;
|
627
|
+
return function (error, value) {
|
628
|
+
if (error) {
|
629
|
+
self.reject(error);
|
630
|
+
} else if (arguments.length > 2) {
|
631
|
+
self.resolve(array_slice(arguments, 1));
|
632
|
+
} else {
|
633
|
+
self.resolve(value);
|
634
|
+
}
|
635
|
+
};
|
636
|
+
};
|
637
|
+
|
638
|
+
/**
|
639
|
+
* @param resolver {Function} a function that returns nothing and accepts
|
640
|
+
* the resolve, reject, and notify functions for a deferred.
|
641
|
+
* @returns a promise that may be resolved with the given resolve and reject
|
642
|
+
* functions, or rejected by a thrown exception in resolver
|
643
|
+
*/
|
644
|
+
Q.promise = promise;
|
645
|
+
function promise(resolver) {
|
646
|
+
if (typeof resolver !== "function") {
|
647
|
+
throw new TypeError("resolver must be a function.");
|
648
|
+
}
|
649
|
+
var deferred = defer();
|
650
|
+
try {
|
651
|
+
resolver(deferred.resolve, deferred.reject, deferred.notify);
|
652
|
+
} catch (reason) {
|
653
|
+
deferred.reject(reason);
|
654
|
+
}
|
655
|
+
return deferred.promise;
|
656
|
+
}
|
657
|
+
|
658
|
+
// XXX experimental. This method is a way to denote that a local value is
|
659
|
+
// serializable and should be immediately dispatched to a remote upon request,
|
660
|
+
// instead of passing a reference.
|
661
|
+
Q.passByCopy = function (object) {
|
662
|
+
//freeze(object);
|
663
|
+
//passByCopies.set(object, true);
|
664
|
+
return object;
|
665
|
+
};
|
666
|
+
|
667
|
+
Promise.prototype.passByCopy = function () {
|
668
|
+
//freeze(object);
|
669
|
+
//passByCopies.set(object, true);
|
670
|
+
return this;
|
671
|
+
};
|
672
|
+
|
673
|
+
/**
|
674
|
+
* If two promises eventually fulfill to the same value, promises that value,
|
675
|
+
* but otherwise rejects.
|
676
|
+
* @param x {Any*}
|
677
|
+
* @param y {Any*}
|
678
|
+
* @returns {Any*} a promise for x and y if they are the same, but a rejection
|
679
|
+
* otherwise.
|
680
|
+
*
|
681
|
+
*/
|
682
|
+
Q.join = function (x, y) {
|
683
|
+
return Q(x).join(y);
|
684
|
+
};
|
685
|
+
|
686
|
+
Promise.prototype.join = function (that) {
|
687
|
+
return Q([this, that]).spread(function (x, y) {
|
688
|
+
if (x === y) {
|
689
|
+
// TODO: "===" should be Object.is or equiv
|
690
|
+
return x;
|
691
|
+
} else {
|
692
|
+
throw new Error("Can't join: not the same: " + x + " " + y);
|
693
|
+
}
|
694
|
+
});
|
695
|
+
};
|
696
|
+
|
697
|
+
/**
|
698
|
+
* Returns a promise for the first of an array of promises to become fulfilled.
|
699
|
+
* @param answers {Array[Any*]} promises to race
|
700
|
+
* @returns {Any*} the first promise to be fulfilled
|
701
|
+
*/
|
702
|
+
Q.race = race;
|
703
|
+
function race(answerPs) {
|
704
|
+
return promise(function(resolve, reject) {
|
705
|
+
// Switch to this once we can assume at least ES5
|
706
|
+
// answerPs.forEach(function(answerP) {
|
707
|
+
// Q(answerP).then(resolve, reject);
|
708
|
+
// });
|
709
|
+
// Use this in the meantime
|
710
|
+
for (var i = 0, len = answerPs.length; i < len; i++) {
|
711
|
+
Q(answerPs[i]).then(resolve, reject);
|
712
|
+
}
|
713
|
+
});
|
714
|
+
}
|
715
|
+
|
716
|
+
Promise.prototype.race = function () {
|
717
|
+
return this.then(Q.race);
|
718
|
+
};
|
719
|
+
|
720
|
+
/**
|
721
|
+
* Constructs a Promise with a promise descriptor object and optional fallback
|
722
|
+
* function. The descriptor contains methods like when(rejected), get(name),
|
723
|
+
* set(name, value), post(name, args), and delete(name), which all
|
724
|
+
* return either a value, a promise for a value, or a rejection. The fallback
|
725
|
+
* accepts the operation name, a resolver, and any further arguments that would
|
726
|
+
* have been forwarded to the appropriate method above had a method been
|
727
|
+
* provided with the proper name. The API makes no guarantees about the nature
|
728
|
+
* of the returned object, apart from that it is usable whereever promises are
|
729
|
+
* bought and sold.
|
730
|
+
*/
|
731
|
+
Q.makePromise = Promise;
|
732
|
+
function Promise(descriptor, fallback, inspect) {
|
733
|
+
if (fallback === void 0) {
|
734
|
+
fallback = function (op) {
|
735
|
+
return reject(new Error(
|
736
|
+
"Promise does not support operation: " + op
|
737
|
+
));
|
738
|
+
};
|
739
|
+
}
|
740
|
+
if (inspect === void 0) {
|
741
|
+
inspect = function () {
|
742
|
+
return {state: "unknown"};
|
743
|
+
};
|
744
|
+
}
|
745
|
+
|
746
|
+
var promise = object_create(Promise.prototype);
|
747
|
+
|
748
|
+
promise.promiseDispatch = function (resolve, op, args) {
|
749
|
+
var result;
|
750
|
+
try {
|
751
|
+
if (descriptor[op]) {
|
752
|
+
result = descriptor[op].apply(promise, args);
|
753
|
+
} else {
|
754
|
+
result = fallback.call(promise, op, args);
|
755
|
+
}
|
756
|
+
} catch (exception) {
|
757
|
+
result = reject(exception);
|
758
|
+
}
|
759
|
+
if (resolve) {
|
760
|
+
resolve(result);
|
761
|
+
}
|
762
|
+
};
|
763
|
+
|
764
|
+
promise.inspect = inspect;
|
765
|
+
|
766
|
+
// XXX deprecated `valueOf` and `exception` support
|
767
|
+
if (inspect) {
|
768
|
+
var inspected = inspect();
|
769
|
+
if (inspected.state === "rejected") {
|
770
|
+
promise.exception = inspected.reason;
|
771
|
+
}
|
772
|
+
|
773
|
+
promise.valueOf = deprecate(function () {
|
774
|
+
var inspected = inspect();
|
775
|
+
if (inspected.state === "pending" ||
|
776
|
+
inspected.state === "rejected") {
|
777
|
+
return promise;
|
778
|
+
}
|
779
|
+
return inspected.value;
|
780
|
+
});
|
781
|
+
}
|
782
|
+
|
783
|
+
return promise;
|
784
|
+
}
|
785
|
+
|
786
|
+
Promise.prototype.toString = function () {
|
787
|
+
return "[object Promise]";
|
788
|
+
};
|
789
|
+
|
790
|
+
Promise.prototype.then = function (fulfilled, rejected, progressed) {
|
791
|
+
var self = this;
|
792
|
+
var deferred = defer();
|
793
|
+
var done = false; // ensure the untrusted promise makes at most a
|
794
|
+
// single call to one of the callbacks
|
795
|
+
|
796
|
+
function _fulfilled(value) {
|
797
|
+
try {
|
798
|
+
return typeof fulfilled === "function" ? fulfilled(value) : value;
|
799
|
+
} catch (exception) {
|
800
|
+
return reject(exception);
|
801
|
+
}
|
802
|
+
}
|
803
|
+
|
804
|
+
function _rejected(exception) {
|
805
|
+
if (typeof rejected === "function") {
|
806
|
+
makeStackTraceLong(exception, self);
|
807
|
+
try {
|
808
|
+
return rejected(exception);
|
809
|
+
} catch (newException) {
|
810
|
+
return reject(newException);
|
811
|
+
}
|
812
|
+
}
|
813
|
+
return reject(exception);
|
814
|
+
}
|
815
|
+
|
816
|
+
function _progressed(value) {
|
817
|
+
return typeof progressed === "function" ? progressed(value) : value;
|
818
|
+
}
|
819
|
+
|
820
|
+
nextTick(function () {
|
821
|
+
self.promiseDispatch(function (value) {
|
822
|
+
if (done) {
|
823
|
+
return;
|
824
|
+
}
|
825
|
+
done = true;
|
826
|
+
|
827
|
+
deferred.resolve(_fulfilled(value));
|
828
|
+
}, "when", [function (exception) {
|
829
|
+
if (done) {
|
830
|
+
return;
|
831
|
+
}
|
832
|
+
done = true;
|
833
|
+
|
834
|
+
deferred.resolve(_rejected(exception));
|
835
|
+
}]);
|
836
|
+
});
|
837
|
+
|
838
|
+
// Progress propagator need to be attached in the current tick.
|
839
|
+
self.promiseDispatch(void 0, "when", [void 0, function (value) {
|
840
|
+
var newValue;
|
841
|
+
var threw = false;
|
842
|
+
try {
|
843
|
+
newValue = _progressed(value);
|
844
|
+
} catch (e) {
|
845
|
+
threw = true;
|
846
|
+
if (Q.onerror) {
|
847
|
+
Q.onerror(e);
|
848
|
+
} else {
|
849
|
+
throw e;
|
850
|
+
}
|
851
|
+
}
|
852
|
+
|
853
|
+
if (!threw) {
|
854
|
+
deferred.notify(newValue);
|
855
|
+
}
|
856
|
+
}]);
|
857
|
+
|
858
|
+
return deferred.promise;
|
859
|
+
};
|
860
|
+
|
861
|
+
/**
|
862
|
+
* Registers an observer on a promise.
|
863
|
+
*
|
864
|
+
* Guarantees:
|
865
|
+
*
|
866
|
+
* 1. that fulfilled and rejected will be called only once.
|
867
|
+
* 2. that either the fulfilled callback or the rejected callback will be
|
868
|
+
* called, but not both.
|
869
|
+
* 3. that fulfilled and rejected will not be called in this turn.
|
870
|
+
*
|
871
|
+
* @param value promise or immediate reference to observe
|
872
|
+
* @param fulfilled function to be called with the fulfilled value
|
873
|
+
* @param rejected function to be called with the rejection exception
|
874
|
+
* @param progressed function to be called on any progress notifications
|
875
|
+
* @return promise for the return value from the invoked callback
|
876
|
+
*/
|
877
|
+
Q.when = when;
|
878
|
+
function when(value, fulfilled, rejected, progressed) {
|
879
|
+
return Q(value).then(fulfilled, rejected, progressed);
|
880
|
+
}
|
881
|
+
|
882
|
+
Promise.prototype.thenResolve = function (value) {
|
883
|
+
return this.then(function () { return value; });
|
884
|
+
};
|
885
|
+
|
886
|
+
Q.thenResolve = function (promise, value) {
|
887
|
+
return Q(promise).thenResolve(value);
|
888
|
+
};
|
889
|
+
|
890
|
+
Promise.prototype.thenReject = function (reason) {
|
891
|
+
return this.then(function () { throw reason; });
|
892
|
+
};
|
893
|
+
|
894
|
+
Q.thenReject = function (promise, reason) {
|
895
|
+
return Q(promise).thenReject(reason);
|
896
|
+
};
|
897
|
+
|
898
|
+
/**
|
899
|
+
* If an object is not a promise, it is as "near" as possible.
|
900
|
+
* If a promise is rejected, it is as "near" as possible too.
|
901
|
+
* If it’s a fulfilled promise, the fulfillment value is nearer.
|
902
|
+
* If it’s a deferred promise and the deferred has been resolved, the
|
903
|
+
* resolution is "nearer".
|
904
|
+
* @param object
|
905
|
+
* @returns most resolved (nearest) form of the object
|
906
|
+
*/
|
907
|
+
|
908
|
+
// XXX should we re-do this?
|
909
|
+
Q.nearer = nearer;
|
910
|
+
function nearer(value) {
|
911
|
+
if (isPromise(value)) {
|
912
|
+
var inspected = value.inspect();
|
913
|
+
if (inspected.state === "fulfilled") {
|
914
|
+
return inspected.value;
|
915
|
+
}
|
916
|
+
}
|
917
|
+
return value;
|
918
|
+
}
|
919
|
+
|
920
|
+
/**
|
921
|
+
* @returns whether the given object is a promise.
|
922
|
+
* Otherwise it is a fulfilled value.
|
923
|
+
*/
|
924
|
+
Q.isPromise = isPromise;
|
925
|
+
function isPromise(object) {
|
926
|
+
return isObject(object) &&
|
927
|
+
typeof object.promiseDispatch === "function" &&
|
928
|
+
typeof object.inspect === "function";
|
929
|
+
}
|
930
|
+
|
931
|
+
Q.isPromiseAlike = isPromiseAlike;
|
932
|
+
function isPromiseAlike(object) {
|
933
|
+
return isObject(object) && typeof object.then === "function";
|
934
|
+
}
|
935
|
+
|
936
|
+
/**
|
937
|
+
* @returns whether the given object is a pending promise, meaning not
|
938
|
+
* fulfilled or rejected.
|
939
|
+
*/
|
940
|
+
Q.isPending = isPending;
|
941
|
+
function isPending(object) {
|
942
|
+
return isPromise(object) && object.inspect().state === "pending";
|
943
|
+
}
|
944
|
+
|
945
|
+
Promise.prototype.isPending = function () {
|
946
|
+
return this.inspect().state === "pending";
|
947
|
+
};
|
948
|
+
|
949
|
+
/**
|
950
|
+
* @returns whether the given object is a value or fulfilled
|
951
|
+
* promise.
|
952
|
+
*/
|
953
|
+
Q.isFulfilled = isFulfilled;
|
954
|
+
function isFulfilled(object) {
|
955
|
+
return !isPromise(object) || object.inspect().state === "fulfilled";
|
956
|
+
}
|
957
|
+
|
958
|
+
Promise.prototype.isFulfilled = function () {
|
959
|
+
return this.inspect().state === "fulfilled";
|
960
|
+
};
|
961
|
+
|
962
|
+
/**
|
963
|
+
* @returns whether the given object is a rejected promise.
|
964
|
+
*/
|
965
|
+
Q.isRejected = isRejected;
|
966
|
+
function isRejected(object) {
|
967
|
+
return isPromise(object) && object.inspect().state === "rejected";
|
968
|
+
}
|
969
|
+
|
970
|
+
Promise.prototype.isRejected = function () {
|
971
|
+
return this.inspect().state === "rejected";
|
972
|
+
};
|
973
|
+
|
974
|
+
//// BEGIN UNHANDLED REJECTION TRACKING
|
975
|
+
|
976
|
+
// This promise library consumes exceptions thrown in handlers so they can be
|
977
|
+
// handled by a subsequent promise. The exceptions get added to this array when
|
978
|
+
// they are created, and removed when they are handled. Note that in ES6 or
|
979
|
+
// shimmed environments, this would naturally be a `Set`.
|
980
|
+
var unhandledReasons = [];
|
981
|
+
var unhandledRejections = [];
|
982
|
+
var unhandledReasonsDisplayed = false;
|
983
|
+
var trackUnhandledRejections = true;
|
984
|
+
function displayUnhandledReasons() {
|
985
|
+
if (
|
986
|
+
!unhandledReasonsDisplayed &&
|
987
|
+
typeof window !== "undefined" &&
|
988
|
+
!window.Touch &&
|
989
|
+
window.console
|
990
|
+
) {
|
991
|
+
console.warn("[Q] Unhandled rejection reasons (should be empty):",
|
992
|
+
unhandledReasons);
|
993
|
+
}
|
994
|
+
|
995
|
+
unhandledReasonsDisplayed = true;
|
996
|
+
}
|
997
|
+
|
998
|
+
function logUnhandledReasons() {
|
999
|
+
for (var i = 0; i < unhandledReasons.length; i++) {
|
1000
|
+
var reason = unhandledReasons[i];
|
1001
|
+
console.warn("Unhandled rejection reason:", reason);
|
1002
|
+
}
|
1003
|
+
}
|
1004
|
+
|
1005
|
+
function resetUnhandledRejections() {
|
1006
|
+
unhandledReasons.length = 0;
|
1007
|
+
unhandledRejections.length = 0;
|
1008
|
+
unhandledReasonsDisplayed = false;
|
1009
|
+
|
1010
|
+
if (!trackUnhandledRejections) {
|
1011
|
+
trackUnhandledRejections = true;
|
1012
|
+
|
1013
|
+
// Show unhandled rejection reasons if Node exits without handling an
|
1014
|
+
// outstanding rejection. (Note that Browserify presently produces a
|
1015
|
+
// `process` global without the `EventEmitter` `on` method.)
|
1016
|
+
if (typeof process !== "undefined" && process.on) {
|
1017
|
+
process.on("exit", logUnhandledReasons);
|
1018
|
+
}
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
function trackRejection(promise, reason) {
|
1023
|
+
if (!trackUnhandledRejections) {
|
1024
|
+
return;
|
1025
|
+
}
|
1026
|
+
|
1027
|
+
unhandledRejections.push(promise);
|
1028
|
+
if (reason && typeof reason.stack !== "undefined") {
|
1029
|
+
unhandledReasons.push(reason.stack);
|
1030
|
+
} else {
|
1031
|
+
unhandledReasons.push("(no stack) " + reason);
|
1032
|
+
}
|
1033
|
+
displayUnhandledReasons();
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
function untrackRejection(promise) {
|
1037
|
+
if (!trackUnhandledRejections) {
|
1038
|
+
return;
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
var at = array_indexOf(unhandledRejections, promise);
|
1042
|
+
if (at !== -1) {
|
1043
|
+
unhandledRejections.splice(at, 1);
|
1044
|
+
unhandledReasons.splice(at, 1);
|
1045
|
+
}
|
1046
|
+
}
|
1047
|
+
|
1048
|
+
Q.resetUnhandledRejections = resetUnhandledRejections;
|
1049
|
+
|
1050
|
+
Q.getUnhandledReasons = function () {
|
1051
|
+
// Make a copy so that consumers can't interfere with our internal state.
|
1052
|
+
return unhandledReasons.slice();
|
1053
|
+
};
|
1054
|
+
|
1055
|
+
Q.stopUnhandledRejectionTracking = function () {
|
1056
|
+
resetUnhandledRejections();
|
1057
|
+
if (typeof process !== "undefined" && process.on) {
|
1058
|
+
process.removeListener("exit", logUnhandledReasons);
|
1059
|
+
}
|
1060
|
+
trackUnhandledRejections = false;
|
1061
|
+
};
|
1062
|
+
|
1063
|
+
resetUnhandledRejections();
|
1064
|
+
|
1065
|
+
//// END UNHANDLED REJECTION TRACKING
|
1066
|
+
|
1067
|
+
/**
|
1068
|
+
* Constructs a rejected promise.
|
1069
|
+
* @param reason value describing the failure
|
1070
|
+
*/
|
1071
|
+
Q.reject = reject;
|
1072
|
+
function reject(reason) {
|
1073
|
+
var rejection = Promise({
|
1074
|
+
"when": function (rejected) {
|
1075
|
+
// note that the error has been handled
|
1076
|
+
if (rejected) {
|
1077
|
+
untrackRejection(this);
|
1078
|
+
}
|
1079
|
+
return rejected ? rejected(reason) : this;
|
1080
|
+
}
|
1081
|
+
}, function fallback() {
|
1082
|
+
return this;
|
1083
|
+
}, function inspect() {
|
1084
|
+
return { state: "rejected", reason: reason };
|
1085
|
+
});
|
1086
|
+
|
1087
|
+
// Note that the reason has not been handled.
|
1088
|
+
trackRejection(rejection, reason);
|
1089
|
+
|
1090
|
+
return rejection;
|
1091
|
+
}
|
1092
|
+
|
1093
|
+
/**
|
1094
|
+
* Constructs a fulfilled promise for an immediate reference.
|
1095
|
+
* @param value immediate reference
|
1096
|
+
*/
|
1097
|
+
Q.fulfill = fulfill;
|
1098
|
+
function fulfill(value) {
|
1099
|
+
return Promise({
|
1100
|
+
"when": function () {
|
1101
|
+
return value;
|
1102
|
+
},
|
1103
|
+
"get": function (name) {
|
1104
|
+
return value[name];
|
1105
|
+
},
|
1106
|
+
"set": function (name, rhs) {
|
1107
|
+
value[name] = rhs;
|
1108
|
+
},
|
1109
|
+
"delete": function (name) {
|
1110
|
+
delete value[name];
|
1111
|
+
},
|
1112
|
+
"post": function (name, args) {
|
1113
|
+
// Mark Miller proposes that post with no name should apply a
|
1114
|
+
// promised function.
|
1115
|
+
if (name === null || name === void 0) {
|
1116
|
+
return value.apply(void 0, args);
|
1117
|
+
} else {
|
1118
|
+
return value[name].apply(value, args);
|
1119
|
+
}
|
1120
|
+
},
|
1121
|
+
"apply": function (thisp, args) {
|
1122
|
+
return value.apply(thisp, args);
|
1123
|
+
},
|
1124
|
+
"keys": function () {
|
1125
|
+
return object_keys(value);
|
1126
|
+
}
|
1127
|
+
}, void 0, function inspect() {
|
1128
|
+
return { state: "fulfilled", value: value };
|
1129
|
+
});
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
/**
|
1133
|
+
* Converts thenables to Q promises.
|
1134
|
+
* @param promise thenable promise
|
1135
|
+
* @returns a Q promise
|
1136
|
+
*/
|
1137
|
+
function coerce(promise) {
|
1138
|
+
var deferred = defer();
|
1139
|
+
nextTick(function () {
|
1140
|
+
try {
|
1141
|
+
promise.then(deferred.resolve, deferred.reject, deferred.notify);
|
1142
|
+
} catch (exception) {
|
1143
|
+
deferred.reject(exception);
|
1144
|
+
}
|
1145
|
+
});
|
1146
|
+
return deferred.promise;
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
/**
|
1150
|
+
* Annotates an object such that it will never be
|
1151
|
+
* transferred away from this process over any promise
|
1152
|
+
* communication channel.
|
1153
|
+
* @param object
|
1154
|
+
* @returns promise a wrapping of that object that
|
1155
|
+
* additionally responds to the "isDef" message
|
1156
|
+
* without a rejection.
|
1157
|
+
*/
|
1158
|
+
Q.master = master;
|
1159
|
+
function master(object) {
|
1160
|
+
return Promise({
|
1161
|
+
"isDef": function () {}
|
1162
|
+
}, function fallback(op, args) {
|
1163
|
+
return dispatch(object, op, args);
|
1164
|
+
}, function () {
|
1165
|
+
return Q(object).inspect();
|
1166
|
+
});
|
1167
|
+
}
|
1168
|
+
|
1169
|
+
/**
|
1170
|
+
* Spreads the values of a promised array of arguments into the
|
1171
|
+
* fulfillment callback.
|
1172
|
+
* @param fulfilled callback that receives variadic arguments from the
|
1173
|
+
* promised array
|
1174
|
+
* @param rejected callback that receives the exception if the promise
|
1175
|
+
* is rejected.
|
1176
|
+
* @returns a promise for the return value or thrown exception of
|
1177
|
+
* either callback.
|
1178
|
+
*/
|
1179
|
+
Q.spread = spread;
|
1180
|
+
function spread(value, fulfilled, rejected) {
|
1181
|
+
return Q(value).spread(fulfilled, rejected);
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
Promise.prototype.spread = function (fulfilled, rejected) {
|
1185
|
+
return this.all().then(function (array) {
|
1186
|
+
return fulfilled.apply(void 0, array);
|
1187
|
+
}, rejected);
|
1188
|
+
};
|
1189
|
+
|
1190
|
+
/**
|
1191
|
+
* The async function is a decorator for generator functions, turning
|
1192
|
+
* them into asynchronous generators. Although generators are only part
|
1193
|
+
* of the newest ECMAScript 6 drafts, this code does not cause syntax
|
1194
|
+
* errors in older engines. This code should continue to work and will
|
1195
|
+
* in fact improve over time as the language improves.
|
1196
|
+
*
|
1197
|
+
* ES6 generators are currently part of V8 version 3.19 with the
|
1198
|
+
* --harmony-generators runtime flag enabled. SpiderMonkey has had them
|
1199
|
+
* for longer, but under an older Python-inspired form. This function
|
1200
|
+
* works on both kinds of generators.
|
1201
|
+
*
|
1202
|
+
* Decorates a generator function such that:
|
1203
|
+
* - it may yield promises
|
1204
|
+
* - execution will continue when that promise is fulfilled
|
1205
|
+
* - the value of the yield expression will be the fulfilled value
|
1206
|
+
* - it returns a promise for the return value (when the generator
|
1207
|
+
* stops iterating)
|
1208
|
+
* - the decorated function returns a promise for the return value
|
1209
|
+
* of the generator or the first rejected promise among those
|
1210
|
+
* yielded.
|
1211
|
+
* - if an error is thrown in the generator, it propagates through
|
1212
|
+
* every following yield until it is caught, or until it escapes
|
1213
|
+
* the generator function altogether, and is translated into a
|
1214
|
+
* rejection for the promise returned by the decorated generator.
|
1215
|
+
*/
|
1216
|
+
Q.async = async;
|
1217
|
+
function async(makeGenerator) {
|
1218
|
+
return function () {
|
1219
|
+
// when verb is "send", arg is a value
|
1220
|
+
// when verb is "throw", arg is an exception
|
1221
|
+
function continuer(verb, arg) {
|
1222
|
+
var result;
|
1223
|
+
if (hasES6Generators) {
|
1224
|
+
try {
|
1225
|
+
result = generator[verb](arg);
|
1226
|
+
} catch (exception) {
|
1227
|
+
return reject(exception);
|
1228
|
+
}
|
1229
|
+
if (result.done) {
|
1230
|
+
return result.value;
|
1231
|
+
} else {
|
1232
|
+
return when(result.value, callback, errback);
|
1233
|
+
}
|
1234
|
+
} else {
|
1235
|
+
// FIXME: Remove this case when SM does ES6 generators.
|
1236
|
+
try {
|
1237
|
+
result = generator[verb](arg);
|
1238
|
+
} catch (exception) {
|
1239
|
+
if (isStopIteration(exception)) {
|
1240
|
+
return exception.value;
|
1241
|
+
} else {
|
1242
|
+
return reject(exception);
|
1243
|
+
}
|
1244
|
+
}
|
1245
|
+
return when(result, callback, errback);
|
1246
|
+
}
|
1247
|
+
}
|
1248
|
+
var generator = makeGenerator.apply(this, arguments);
|
1249
|
+
var callback = continuer.bind(continuer, "next");
|
1250
|
+
var errback = continuer.bind(continuer, "throw");
|
1251
|
+
return callback();
|
1252
|
+
};
|
1253
|
+
}
|
1254
|
+
|
1255
|
+
/**
|
1256
|
+
* The spawn function is a small wrapper around async that immediately
|
1257
|
+
* calls the generator and also ends the promise chain, so that any
|
1258
|
+
* unhandled errors are thrown instead of forwarded to the error
|
1259
|
+
* handler. This is useful because it's extremely common to run
|
1260
|
+
* generators at the top-level to work with libraries.
|
1261
|
+
*/
|
1262
|
+
Q.spawn = spawn;
|
1263
|
+
function spawn(makeGenerator) {
|
1264
|
+
Q.done(Q.async(makeGenerator)());
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
// FIXME: Remove this interface once ES6 generators are in SpiderMonkey.
|
1268
|
+
/**
|
1269
|
+
* Throws a ReturnValue exception to stop an asynchronous generator.
|
1270
|
+
*
|
1271
|
+
* This interface is a stop-gap measure to support generator return
|
1272
|
+
* values in older Firefox/SpiderMonkey. In browsers that support ES6
|
1273
|
+
* generators like Chromium 29, just use "return" in your generator
|
1274
|
+
* functions.
|
1275
|
+
*
|
1276
|
+
* @param value the return value for the surrounding generator
|
1277
|
+
* @throws ReturnValue exception with the value.
|
1278
|
+
* @example
|
1279
|
+
* // ES6 style
|
1280
|
+
* Q.async(function* () {
|
1281
|
+
* var foo = yield getFooPromise();
|
1282
|
+
* var bar = yield getBarPromise();
|
1283
|
+
* return foo + bar;
|
1284
|
+
* })
|
1285
|
+
* // Older SpiderMonkey style
|
1286
|
+
* Q.async(function () {
|
1287
|
+
* var foo = yield getFooPromise();
|
1288
|
+
* var bar = yield getBarPromise();
|
1289
|
+
* Q.return(foo + bar);
|
1290
|
+
* })
|
1291
|
+
*/
|
1292
|
+
Q["return"] = _return;
|
1293
|
+
function _return(value) {
|
1294
|
+
throw new QReturnValue(value);
|
1295
|
+
}
|
1296
|
+
|
1297
|
+
/**
|
1298
|
+
* The promised function decorator ensures that any promise arguments
|
1299
|
+
* are settled and passed as values (`this` is also settled and passed
|
1300
|
+
* as a value). It will also ensure that the result of a function is
|
1301
|
+
* always a promise.
|
1302
|
+
*
|
1303
|
+
* @example
|
1304
|
+
* var add = Q.promised(function (a, b) {
|
1305
|
+
* return a + b;
|
1306
|
+
* });
|
1307
|
+
* add(Q(a), Q(B));
|
1308
|
+
*
|
1309
|
+
* @param {function} callback The function to decorate
|
1310
|
+
* @returns {function} a function that has been decorated.
|
1311
|
+
*/
|
1312
|
+
Q.promised = promised;
|
1313
|
+
function promised(callback) {
|
1314
|
+
return function () {
|
1315
|
+
return spread([this, all(arguments)], function (self, args) {
|
1316
|
+
return callback.apply(self, args);
|
1317
|
+
});
|
1318
|
+
};
|
1319
|
+
}
|
1320
|
+
|
1321
|
+
/**
|
1322
|
+
* sends a message to a value in a future turn
|
1323
|
+
* @param object* the recipient
|
1324
|
+
* @param op the name of the message operation, e.g., "when",
|
1325
|
+
* @param args further arguments to be forwarded to the operation
|
1326
|
+
* @returns result {Promise} a promise for the result of the operation
|
1327
|
+
*/
|
1328
|
+
Q.dispatch = dispatch;
|
1329
|
+
function dispatch(object, op, args) {
|
1330
|
+
return Q(object).dispatch(op, args);
|
1331
|
+
}
|
1332
|
+
|
1333
|
+
Promise.prototype.dispatch = function (op, args) {
|
1334
|
+
var self = this;
|
1335
|
+
var deferred = defer();
|
1336
|
+
nextTick(function () {
|
1337
|
+
self.promiseDispatch(deferred.resolve, op, args);
|
1338
|
+
});
|
1339
|
+
return deferred.promise;
|
1340
|
+
};
|
1341
|
+
|
1342
|
+
/**
|
1343
|
+
* Gets the value of a property in a future turn.
|
1344
|
+
* @param object promise or immediate reference for target object
|
1345
|
+
* @param name name of property to get
|
1346
|
+
* @return promise for the property value
|
1347
|
+
*/
|
1348
|
+
Q.get = function (object, key) {
|
1349
|
+
return Q(object).dispatch("get", [key]);
|
1350
|
+
};
|
1351
|
+
|
1352
|
+
Promise.prototype.get = function (key) {
|
1353
|
+
return this.dispatch("get", [key]);
|
1354
|
+
};
|
1355
|
+
|
1356
|
+
/**
|
1357
|
+
* Sets the value of a property in a future turn.
|
1358
|
+
* @param object promise or immediate reference for object object
|
1359
|
+
* @param name name of property to set
|
1360
|
+
* @param value new value of property
|
1361
|
+
* @return promise for the return value
|
1362
|
+
*/
|
1363
|
+
Q.set = function (object, key, value) {
|
1364
|
+
return Q(object).dispatch("set", [key, value]);
|
1365
|
+
};
|
1366
|
+
|
1367
|
+
Promise.prototype.set = function (key, value) {
|
1368
|
+
return this.dispatch("set", [key, value]);
|
1369
|
+
};
|
1370
|
+
|
1371
|
+
/**
|
1372
|
+
* Deletes a property in a future turn.
|
1373
|
+
* @param object promise or immediate reference for target object
|
1374
|
+
* @param name name of property to delete
|
1375
|
+
* @return promise for the return value
|
1376
|
+
*/
|
1377
|
+
Q.del = // XXX legacy
|
1378
|
+
Q["delete"] = function (object, key) {
|
1379
|
+
return Q(object).dispatch("delete", [key]);
|
1380
|
+
};
|
1381
|
+
|
1382
|
+
Promise.prototype.del = // XXX legacy
|
1383
|
+
Promise.prototype["delete"] = function (key) {
|
1384
|
+
return this.dispatch("delete", [key]);
|
1385
|
+
};
|
1386
|
+
|
1387
|
+
/**
|
1388
|
+
* Invokes a method in a future turn.
|
1389
|
+
* @param object promise or immediate reference for target object
|
1390
|
+
* @param name name of method to invoke
|
1391
|
+
* @param value a value to post, typically an array of
|
1392
|
+
* invocation arguments for promises that
|
1393
|
+
* are ultimately backed with `resolve` values,
|
1394
|
+
* as opposed to those backed with URLs
|
1395
|
+
* wherein the posted value can be any
|
1396
|
+
* JSON serializable object.
|
1397
|
+
* @return promise for the return value
|
1398
|
+
*/
|
1399
|
+
// bound locally because it is used by other methods
|
1400
|
+
Q.mapply = // XXX As proposed by "Redsandro"
|
1401
|
+
Q.post = function (object, name, args) {
|
1402
|
+
return Q(object).dispatch("post", [name, args]);
|
1403
|
+
};
|
1404
|
+
|
1405
|
+
Promise.prototype.mapply = // XXX As proposed by "Redsandro"
|
1406
|
+
Promise.prototype.post = function (name, args) {
|
1407
|
+
return this.dispatch("post", [name, args]);
|
1408
|
+
};
|
1409
|
+
|
1410
|
+
/**
|
1411
|
+
* Invokes a method in a future turn.
|
1412
|
+
* @param object promise or immediate reference for target object
|
1413
|
+
* @param name name of method to invoke
|
1414
|
+
* @param ...args array of invocation arguments
|
1415
|
+
* @return promise for the return value
|
1416
|
+
*/
|
1417
|
+
Q.send = // XXX Mark Miller's proposed parlance
|
1418
|
+
Q.mcall = // XXX As proposed by "Redsandro"
|
1419
|
+
Q.invoke = function (object, name /*...args*/) {
|
1420
|
+
return Q(object).dispatch("post", [name, array_slice(arguments, 2)]);
|
1421
|
+
};
|
1422
|
+
|
1423
|
+
Promise.prototype.send = // XXX Mark Miller's proposed parlance
|
1424
|
+
Promise.prototype.mcall = // XXX As proposed by "Redsandro"
|
1425
|
+
Promise.prototype.invoke = function (name /*...args*/) {
|
1426
|
+
return this.dispatch("post", [name, array_slice(arguments, 1)]);
|
1427
|
+
};
|
1428
|
+
|
1429
|
+
/**
|
1430
|
+
* Applies the promised function in a future turn.
|
1431
|
+
* @param object promise or immediate reference for target function
|
1432
|
+
* @param args array of application arguments
|
1433
|
+
*/
|
1434
|
+
Q.fapply = function (object, args) {
|
1435
|
+
return Q(object).dispatch("apply", [void 0, args]);
|
1436
|
+
};
|
1437
|
+
|
1438
|
+
Promise.prototype.fapply = function (args) {
|
1439
|
+
return this.dispatch("apply", [void 0, args]);
|
1440
|
+
};
|
1441
|
+
|
1442
|
+
/**
|
1443
|
+
* Calls the promised function in a future turn.
|
1444
|
+
* @param object promise or immediate reference for target function
|
1445
|
+
* @param ...args array of application arguments
|
1446
|
+
*/
|
1447
|
+
Q["try"] =
|
1448
|
+
Q.fcall = function (object /* ...args*/) {
|
1449
|
+
return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]);
|
1450
|
+
};
|
1451
|
+
|
1452
|
+
Promise.prototype.fcall = function (/*...args*/) {
|
1453
|
+
return this.dispatch("apply", [void 0, array_slice(arguments)]);
|
1454
|
+
};
|
1455
|
+
|
1456
|
+
/**
|
1457
|
+
* Binds the promised function, transforming return values into a fulfilled
|
1458
|
+
* promise and thrown errors into a rejected one.
|
1459
|
+
* @param object promise or immediate reference for target function
|
1460
|
+
* @param ...args array of application arguments
|
1461
|
+
*/
|
1462
|
+
Q.fbind = function (object /*...args*/) {
|
1463
|
+
var promise = Q(object);
|
1464
|
+
var args = array_slice(arguments, 1);
|
1465
|
+
return function fbound() {
|
1466
|
+
return promise.dispatch("apply", [
|
1467
|
+
this,
|
1468
|
+
args.concat(array_slice(arguments))
|
1469
|
+
]);
|
1470
|
+
};
|
1471
|
+
};
|
1472
|
+
Promise.prototype.fbind = function (/*...args*/) {
|
1473
|
+
var promise = this;
|
1474
|
+
var args = array_slice(arguments);
|
1475
|
+
return function fbound() {
|
1476
|
+
return promise.dispatch("apply", [
|
1477
|
+
this,
|
1478
|
+
args.concat(array_slice(arguments))
|
1479
|
+
]);
|
1480
|
+
};
|
1481
|
+
};
|
1482
|
+
|
1483
|
+
/**
|
1484
|
+
* Requests the names of the owned properties of a promised
|
1485
|
+
* object in a future turn.
|
1486
|
+
* @param object promise or immediate reference for target object
|
1487
|
+
* @return promise for the keys of the eventually settled object
|
1488
|
+
*/
|
1489
|
+
Q.keys = function (object) {
|
1490
|
+
return Q(object).dispatch("keys", []);
|
1491
|
+
};
|
1492
|
+
|
1493
|
+
Promise.prototype.keys = function () {
|
1494
|
+
return this.dispatch("keys", []);
|
1495
|
+
};
|
1496
|
+
|
1497
|
+
/**
|
1498
|
+
* Turns an array of promises into a promise for an array. If any of
|
1499
|
+
* the promises gets rejected, the whole array is rejected immediately.
|
1500
|
+
* @param {Array*} an array (or promise for an array) of values (or
|
1501
|
+
* promises for values)
|
1502
|
+
* @returns a promise for an array of the corresponding values
|
1503
|
+
*/
|
1504
|
+
// By Mark Miller
|
1505
|
+
// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled
|
1506
|
+
Q.all = all;
|
1507
|
+
function all(promises) {
|
1508
|
+
return when(promises, function (promises) {
|
1509
|
+
var countDown = 0;
|
1510
|
+
var deferred = defer();
|
1511
|
+
array_reduce(promises, function (undefined, promise, index) {
|
1512
|
+
var snapshot;
|
1513
|
+
if (
|
1514
|
+
isPromise(promise) &&
|
1515
|
+
(snapshot = promise.inspect()).state === "fulfilled"
|
1516
|
+
) {
|
1517
|
+
promises[index] = snapshot.value;
|
1518
|
+
} else {
|
1519
|
+
++countDown;
|
1520
|
+
when(
|
1521
|
+
promise,
|
1522
|
+
function (value) {
|
1523
|
+
promises[index] = value;
|
1524
|
+
if (--countDown === 0) {
|
1525
|
+
deferred.resolve(promises);
|
1526
|
+
}
|
1527
|
+
},
|
1528
|
+
deferred.reject,
|
1529
|
+
function (progress) {
|
1530
|
+
deferred.notify({ index: index, value: progress });
|
1531
|
+
}
|
1532
|
+
);
|
1533
|
+
}
|
1534
|
+
}, void 0);
|
1535
|
+
if (countDown === 0) {
|
1536
|
+
deferred.resolve(promises);
|
1537
|
+
}
|
1538
|
+
return deferred.promise;
|
1539
|
+
});
|
1540
|
+
}
|
1541
|
+
|
1542
|
+
Promise.prototype.all = function () {
|
1543
|
+
return all(this);
|
1544
|
+
};
|
1545
|
+
|
1546
|
+
/**
|
1547
|
+
* Waits for all promises to be settled, either fulfilled or
|
1548
|
+
* rejected. This is distinct from `all` since that would stop
|
1549
|
+
* waiting at the first rejection. The promise returned by
|
1550
|
+
* `allResolved` will never be rejected.
|
1551
|
+
* @param promises a promise for an array (or an array) of promises
|
1552
|
+
* (or values)
|
1553
|
+
* @return a promise for an array of promises
|
1554
|
+
*/
|
1555
|
+
Q.allResolved = deprecate(allResolved, "allResolved", "allSettled");
|
1556
|
+
function allResolved(promises) {
|
1557
|
+
return when(promises, function (promises) {
|
1558
|
+
promises = array_map(promises, Q);
|
1559
|
+
return when(all(array_map(promises, function (promise) {
|
1560
|
+
return when(promise, noop, noop);
|
1561
|
+
})), function () {
|
1562
|
+
return promises;
|
1563
|
+
});
|
1564
|
+
});
|
1565
|
+
}
|
1566
|
+
|
1567
|
+
Promise.prototype.allResolved = function () {
|
1568
|
+
return allResolved(this);
|
1569
|
+
};
|
1570
|
+
|
1571
|
+
/**
|
1572
|
+
* @see Promise#allSettled
|
1573
|
+
*/
|
1574
|
+
Q.allSettled = allSettled;
|
1575
|
+
function allSettled(promises) {
|
1576
|
+
return Q(promises).allSettled();
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
/**
|
1580
|
+
* Turns an array of promises into a promise for an array of their states (as
|
1581
|
+
* returned by `inspect`) when they have all settled.
|
1582
|
+
* @param {Array[Any*]} values an array (or promise for an array) of values (or
|
1583
|
+
* promises for values)
|
1584
|
+
* @returns {Array[State]} an array of states for the respective values.
|
1585
|
+
*/
|
1586
|
+
Promise.prototype.allSettled = function () {
|
1587
|
+
return this.then(function (promises) {
|
1588
|
+
return all(array_map(promises, function (promise) {
|
1589
|
+
promise = Q(promise);
|
1590
|
+
function regardless() {
|
1591
|
+
return promise.inspect();
|
1592
|
+
}
|
1593
|
+
return promise.then(regardless, regardless);
|
1594
|
+
}));
|
1595
|
+
});
|
1596
|
+
};
|
1597
|
+
|
1598
|
+
/**
|
1599
|
+
* Captures the failure of a promise, giving an oportunity to recover
|
1600
|
+
* with a callback. If the given promise is fulfilled, the returned
|
1601
|
+
* promise is fulfilled.
|
1602
|
+
* @param {Any*} promise for something
|
1603
|
+
* @param {Function} callback to fulfill the returned promise if the
|
1604
|
+
* given promise is rejected
|
1605
|
+
* @returns a promise for the return value of the callback
|
1606
|
+
*/
|
1607
|
+
Q.fail = // XXX legacy
|
1608
|
+
Q["catch"] = function (object, rejected) {
|
1609
|
+
return Q(object).then(void 0, rejected);
|
1610
|
+
};
|
1611
|
+
|
1612
|
+
Promise.prototype.fail = // XXX legacy
|
1613
|
+
Promise.prototype["catch"] = function (rejected) {
|
1614
|
+
return this.then(void 0, rejected);
|
1615
|
+
};
|
1616
|
+
|
1617
|
+
/**
|
1618
|
+
* Attaches a listener that can respond to progress notifications from a
|
1619
|
+
* promise's originating deferred. This listener receives the exact arguments
|
1620
|
+
* passed to ``deferred.notify``.
|
1621
|
+
* @param {Any*} promise for something
|
1622
|
+
* @param {Function} callback to receive any progress notifications
|
1623
|
+
* @returns the given promise, unchanged
|
1624
|
+
*/
|
1625
|
+
Q.progress = progress;
|
1626
|
+
function progress(object, progressed) {
|
1627
|
+
return Q(object).then(void 0, void 0, progressed);
|
1628
|
+
}
|
1629
|
+
|
1630
|
+
Promise.prototype.progress = function (progressed) {
|
1631
|
+
return this.then(void 0, void 0, progressed);
|
1632
|
+
};
|
1633
|
+
|
1634
|
+
/**
|
1635
|
+
* Provides an opportunity to observe the settling of a promise,
|
1636
|
+
* regardless of whether the promise is fulfilled or rejected. Forwards
|
1637
|
+
* the resolution to the returned promise when the callback is done.
|
1638
|
+
* The callback can return a promise to defer completion.
|
1639
|
+
* @param {Any*} promise
|
1640
|
+
* @param {Function} callback to observe the resolution of the given
|
1641
|
+
* promise, takes no arguments.
|
1642
|
+
* @returns a promise for the resolution of the given promise when
|
1643
|
+
* ``fin`` is done.
|
1644
|
+
*/
|
1645
|
+
Q.fin = // XXX legacy
|
1646
|
+
Q["finally"] = function (object, callback) {
|
1647
|
+
return Q(object)["finally"](callback);
|
1648
|
+
};
|
1649
|
+
|
1650
|
+
Promise.prototype.fin = // XXX legacy
|
1651
|
+
Promise.prototype["finally"] = function (callback) {
|
1652
|
+
callback = Q(callback);
|
1653
|
+
return this.then(function (value) {
|
1654
|
+
return callback.fcall().then(function () {
|
1655
|
+
return value;
|
1656
|
+
});
|
1657
|
+
}, function (reason) {
|
1658
|
+
// TODO attempt to recycle the rejection with "this".
|
1659
|
+
return callback.fcall().then(function () {
|
1660
|
+
throw reason;
|
1661
|
+
});
|
1662
|
+
});
|
1663
|
+
};
|
1664
|
+
|
1665
|
+
/**
|
1666
|
+
* Terminates a chain of promises, forcing rejections to be
|
1667
|
+
* thrown as exceptions.
|
1668
|
+
* @param {Any*} promise at the end of a chain of promises
|
1669
|
+
* @returns nothing
|
1670
|
+
*/
|
1671
|
+
Q.done = function (object, fulfilled, rejected, progress) {
|
1672
|
+
return Q(object).done(fulfilled, rejected, progress);
|
1673
|
+
};
|
1674
|
+
|
1675
|
+
Promise.prototype.done = function (fulfilled, rejected, progress) {
|
1676
|
+
var onUnhandledError = function (error) {
|
1677
|
+
// forward to a future turn so that ``when``
|
1678
|
+
// does not catch it and turn it into a rejection.
|
1679
|
+
nextTick(function () {
|
1680
|
+
makeStackTraceLong(error, promise);
|
1681
|
+
if (Q.onerror) {
|
1682
|
+
Q.onerror(error);
|
1683
|
+
} else {
|
1684
|
+
throw error;
|
1685
|
+
}
|
1686
|
+
});
|
1687
|
+
};
|
1688
|
+
|
1689
|
+
// Avoid unnecessary `nextTick`ing via an unnecessary `when`.
|
1690
|
+
var promise = fulfilled || rejected || progress ?
|
1691
|
+
this.then(fulfilled, rejected, progress) :
|
1692
|
+
this;
|
1693
|
+
|
1694
|
+
if (typeof process === "object" && process && process.domain) {
|
1695
|
+
onUnhandledError = process.domain.bind(onUnhandledError);
|
1696
|
+
}
|
1697
|
+
|
1698
|
+
promise.then(void 0, onUnhandledError);
|
1699
|
+
};
|
1700
|
+
|
1701
|
+
/**
|
1702
|
+
* Causes a promise to be rejected if it does not get fulfilled before
|
1703
|
+
* some milliseconds time out.
|
1704
|
+
* @param {Any*} promise
|
1705
|
+
* @param {Number} milliseconds timeout
|
1706
|
+
* @param {String} custom error message (optional)
|
1707
|
+
* @returns a promise for the resolution of the given promise if it is
|
1708
|
+
* fulfilled before the timeout, otherwise rejected.
|
1709
|
+
*/
|
1710
|
+
Q.timeout = function (object, ms, message) {
|
1711
|
+
return Q(object).timeout(ms, message);
|
1712
|
+
};
|
1713
|
+
|
1714
|
+
Promise.prototype.timeout = function (ms, message) {
|
1715
|
+
var deferred = defer();
|
1716
|
+
var timeoutId = setTimeout(function () {
|
1717
|
+
deferred.reject(new Error(message || "Timed out after " + ms + " ms"));
|
1718
|
+
}, ms);
|
1719
|
+
|
1720
|
+
this.then(function (value) {
|
1721
|
+
clearTimeout(timeoutId);
|
1722
|
+
deferred.resolve(value);
|
1723
|
+
}, function (exception) {
|
1724
|
+
clearTimeout(timeoutId);
|
1725
|
+
deferred.reject(exception);
|
1726
|
+
}, deferred.notify);
|
1727
|
+
|
1728
|
+
return deferred.promise;
|
1729
|
+
};
|
1730
|
+
|
1731
|
+
/**
|
1732
|
+
* Returns a promise for the given value (or promised value), some
|
1733
|
+
* milliseconds after it resolved. Passes rejections immediately.
|
1734
|
+
* @param {Any*} promise
|
1735
|
+
* @param {Number} milliseconds
|
1736
|
+
* @returns a promise for the resolution of the given promise after milliseconds
|
1737
|
+
* time has elapsed since the resolution of the given promise.
|
1738
|
+
* If the given promise rejects, that is passed immediately.
|
1739
|
+
*/
|
1740
|
+
Q.delay = function (object, timeout) {
|
1741
|
+
if (timeout === void 0) {
|
1742
|
+
timeout = object;
|
1743
|
+
object = void 0;
|
1744
|
+
}
|
1745
|
+
return Q(object).delay(timeout);
|
1746
|
+
};
|
1747
|
+
|
1748
|
+
Promise.prototype.delay = function (timeout) {
|
1749
|
+
return this.then(function (value) {
|
1750
|
+
var deferred = defer();
|
1751
|
+
setTimeout(function () {
|
1752
|
+
deferred.resolve(value);
|
1753
|
+
}, timeout);
|
1754
|
+
return deferred.promise;
|
1755
|
+
});
|
1756
|
+
};
|
1757
|
+
|
1758
|
+
/**
|
1759
|
+
* Passes a continuation to a Node function, which is called with the given
|
1760
|
+
* arguments provided as an array, and returns a promise.
|
1761
|
+
*
|
1762
|
+
* Q.nfapply(FS.readFile, [__filename])
|
1763
|
+
* .then(function (content) {
|
1764
|
+
* })
|
1765
|
+
*
|
1766
|
+
*/
|
1767
|
+
Q.nfapply = function (callback, args) {
|
1768
|
+
return Q(callback).nfapply(args);
|
1769
|
+
};
|
1770
|
+
|
1771
|
+
Promise.prototype.nfapply = function (args) {
|
1772
|
+
var deferred = defer();
|
1773
|
+
var nodeArgs = array_slice(args);
|
1774
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1775
|
+
this.fapply(nodeArgs).fail(deferred.reject);
|
1776
|
+
return deferred.promise;
|
1777
|
+
};
|
1778
|
+
|
1779
|
+
/**
|
1780
|
+
* Passes a continuation to a Node function, which is called with the given
|
1781
|
+
* arguments provided individually, and returns a promise.
|
1782
|
+
* @example
|
1783
|
+
* Q.nfcall(FS.readFile, __filename)
|
1784
|
+
* .then(function (content) {
|
1785
|
+
* })
|
1786
|
+
*
|
1787
|
+
*/
|
1788
|
+
Q.nfcall = function (callback /*...args*/) {
|
1789
|
+
var args = array_slice(arguments, 1);
|
1790
|
+
return Q(callback).nfapply(args);
|
1791
|
+
};
|
1792
|
+
|
1793
|
+
Promise.prototype.nfcall = function (/*...args*/) {
|
1794
|
+
var nodeArgs = array_slice(arguments);
|
1795
|
+
var deferred = defer();
|
1796
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1797
|
+
this.fapply(nodeArgs).fail(deferred.reject);
|
1798
|
+
return deferred.promise;
|
1799
|
+
};
|
1800
|
+
|
1801
|
+
/**
|
1802
|
+
* Wraps a NodeJS continuation passing function and returns an equivalent
|
1803
|
+
* version that returns a promise.
|
1804
|
+
* @example
|
1805
|
+
* Q.nfbind(FS.readFile, __filename)("utf-8")
|
1806
|
+
* .then(console.log)
|
1807
|
+
* .done()
|
1808
|
+
*/
|
1809
|
+
Q.nfbind =
|
1810
|
+
Q.denodeify = function (callback /*...args*/) {
|
1811
|
+
var baseArgs = array_slice(arguments, 1);
|
1812
|
+
return function () {
|
1813
|
+
var nodeArgs = baseArgs.concat(array_slice(arguments));
|
1814
|
+
var deferred = defer();
|
1815
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1816
|
+
Q(callback).fapply(nodeArgs).fail(deferred.reject);
|
1817
|
+
return deferred.promise;
|
1818
|
+
};
|
1819
|
+
};
|
1820
|
+
|
1821
|
+
Promise.prototype.nfbind =
|
1822
|
+
Promise.prototype.denodeify = function (/*...args*/) {
|
1823
|
+
var args = array_slice(arguments);
|
1824
|
+
args.unshift(this);
|
1825
|
+
return Q.denodeify.apply(void 0, args);
|
1826
|
+
};
|
1827
|
+
|
1828
|
+
Q.nbind = function (callback, thisp /*...args*/) {
|
1829
|
+
var baseArgs = array_slice(arguments, 2);
|
1830
|
+
return function () {
|
1831
|
+
var nodeArgs = baseArgs.concat(array_slice(arguments));
|
1832
|
+
var deferred = defer();
|
1833
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1834
|
+
function bound() {
|
1835
|
+
return callback.apply(thisp, arguments);
|
1836
|
+
}
|
1837
|
+
Q(bound).fapply(nodeArgs).fail(deferred.reject);
|
1838
|
+
return deferred.promise;
|
1839
|
+
};
|
1840
|
+
};
|
1841
|
+
|
1842
|
+
Promise.prototype.nbind = function (/*thisp, ...args*/) {
|
1843
|
+
var args = array_slice(arguments, 0);
|
1844
|
+
args.unshift(this);
|
1845
|
+
return Q.nbind.apply(void 0, args);
|
1846
|
+
};
|
1847
|
+
|
1848
|
+
/**
|
1849
|
+
* Calls a method of a Node-style object that accepts a Node-style
|
1850
|
+
* callback with a given array of arguments, plus a provided callback.
|
1851
|
+
* @param object an object that has the named method
|
1852
|
+
* @param {String} name name of the method of object
|
1853
|
+
* @param {Array} args arguments to pass to the method; the callback
|
1854
|
+
* will be provided by Q and appended to these arguments.
|
1855
|
+
* @returns a promise for the value or error
|
1856
|
+
*/
|
1857
|
+
Q.nmapply = // XXX As proposed by "Redsandro"
|
1858
|
+
Q.npost = function (object, name, args) {
|
1859
|
+
return Q(object).npost(name, args);
|
1860
|
+
};
|
1861
|
+
|
1862
|
+
Promise.prototype.nmapply = // XXX As proposed by "Redsandro"
|
1863
|
+
Promise.prototype.npost = function (name, args) {
|
1864
|
+
var nodeArgs = array_slice(args || []);
|
1865
|
+
var deferred = defer();
|
1866
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1867
|
+
this.dispatch("post", [name, nodeArgs]).fail(deferred.reject);
|
1868
|
+
return deferred.promise;
|
1869
|
+
};
|
1870
|
+
|
1871
|
+
/**
|
1872
|
+
* Calls a method of a Node-style object that accepts a Node-style
|
1873
|
+
* callback, forwarding the given variadic arguments, plus a provided
|
1874
|
+
* callback argument.
|
1875
|
+
* @param object an object that has the named method
|
1876
|
+
* @param {String} name name of the method of object
|
1877
|
+
* @param ...args arguments to pass to the method; the callback will
|
1878
|
+
* be provided by Q and appended to these arguments.
|
1879
|
+
* @returns a promise for the value or error
|
1880
|
+
*/
|
1881
|
+
Q.nsend = // XXX Based on Mark Miller's proposed "send"
|
1882
|
+
Q.nmcall = // XXX Based on "Redsandro's" proposal
|
1883
|
+
Q.ninvoke = function (object, name /*...args*/) {
|
1884
|
+
var nodeArgs = array_slice(arguments, 2);
|
1885
|
+
var deferred = defer();
|
1886
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1887
|
+
Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject);
|
1888
|
+
return deferred.promise;
|
1889
|
+
};
|
1890
|
+
|
1891
|
+
Promise.prototype.nsend = // XXX Based on Mark Miller's proposed "send"
|
1892
|
+
Promise.prototype.nmcall = // XXX Based on "Redsandro's" proposal
|
1893
|
+
Promise.prototype.ninvoke = function (name /*...args*/) {
|
1894
|
+
var nodeArgs = array_slice(arguments, 1);
|
1895
|
+
var deferred = defer();
|
1896
|
+
nodeArgs.push(deferred.makeNodeResolver());
|
1897
|
+
this.dispatch("post", [name, nodeArgs]).fail(deferred.reject);
|
1898
|
+
return deferred.promise;
|
1899
|
+
};
|
1900
|
+
|
1901
|
+
/**
|
1902
|
+
* If a function would like to support both Node continuation-passing-style and
|
1903
|
+
* promise-returning-style, it can end its internal promise chain with
|
1904
|
+
* `nodeify(nodeback)`, forwarding the optional nodeback argument. If the user
|
1905
|
+
* elects to use a nodeback, the result will be sent there. If they do not
|
1906
|
+
* pass a nodeback, they will receive the result promise.
|
1907
|
+
* @param object a result (or a promise for a result)
|
1908
|
+
* @param {Function} nodeback a Node.js-style callback
|
1909
|
+
* @returns either the promise or nothing
|
1910
|
+
*/
|
1911
|
+
Q.nodeify = nodeify;
|
1912
|
+
function nodeify(object, nodeback) {
|
1913
|
+
return Q(object).nodeify(nodeback);
|
1914
|
+
}
|
1915
|
+
|
1916
|
+
Promise.prototype.nodeify = function (nodeback) {
|
1917
|
+
if (nodeback) {
|
1918
|
+
this.then(function (value) {
|
1919
|
+
nextTick(function () {
|
1920
|
+
nodeback(null, value);
|
1921
|
+
});
|
1922
|
+
}, function (error) {
|
1923
|
+
nextTick(function () {
|
1924
|
+
nodeback(error);
|
1925
|
+
});
|
1926
|
+
});
|
1927
|
+
} else {
|
1928
|
+
return this;
|
1929
|
+
}
|
1930
|
+
};
|
1931
|
+
|
1932
|
+
// All code before this point will be filtered from stack traces.
|
1933
|
+
var qEndingLine = captureLine();
|
1934
|
+
|
1935
|
+
return Q;
|
1936
|
+
|
1937
|
+
});
|