├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── bin └── Promise.min.js ├── historical_interest ├── Future.idl ├── ProgressFuture.idl ├── Promise.idl ├── README.md └── reworked_APIs │ ├── IndexedDB │ ├── after.idl │ ├── before.idl │ └── example │ │ ├── after.html │ │ └── before.html │ ├── QuotaAPI │ ├── after.idl │ └── before.idl │ ├── WebCrypto │ ├── after.idl │ ├── before.idl │ └── example │ │ ├── after.html │ │ └── before.html │ └── WebMIDI │ ├── after.idl │ └── before.idl ├── package.json ├── src └── Promise.js ├── tests ├── Promise-tests.js ├── promises-tests.js ├── test.html └── test.js ├── third_party └── doh │ ├── LICENSE │ ├── README │ ├── runner.js │ └── runner_async.js └── util ├── build.sh ├── console.js └── post.py /.gitignore: -------------------------------------------------------------------------------- 1 | .d8_history 2 | v8.log 3 | tmp 4 | out 5 | .svn 6 | *.swp 7 | .DS_Store 8 | *.sublime-project 9 | *.sublime-workspace 10 | npm-debug.log 11 | out.prof 12 | /node_modules/* 13 | /polyfill/node_modules/* 14 | /polyfill/dist/* 15 | /dist/* -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "polyfill/third_party/promises-tests"] 2 | path = third_party/promises-tests 3 | url = https://github.com/promises-aplus/promises-tests.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2011 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test build 2 | 3 | test: 4 | npm test 5 | 6 | build: 7 | cd util && ./build.sh 8 | 9 | .PHONY: test 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slightlyoff/Promises/0df361e4822d7cc8718645646e4150e4b5fa48ba/README.md -------------------------------------------------------------------------------- /bin/Promise.min.js: -------------------------------------------------------------------------------- 1 | (function(a,b,c){"use strict";c=!!c;var d,f,e=b.MutationObserver||b.WebKitMutationObserver;if("undefined"!=typeof process&&"[object process]"==={}.toString.call(process))d=function(a,b){process.nextTick(function(){a.call(b)})};else if(e){var g=[],h=new e(function(){var a=g.slice();g=[],a.forEach(function(a){a[0].call(a[1])})}),i=document.createElement("div");h.observe(i,{attributes:!0}),window.addEventListener("unload",function(){h.disconnect(),h=null}),d=function(a,b){g.push([a,b]),i.setAttribute("drainQueue","drainQueue")}}else d=function(a,b){setTimeout(function(){a.call(b)},1)};var j=function(a){return{enumerable:!0,configurable:!1,get:a}},k=function(a,b,c,d){return{enumerable:!!b,configurable:true,writable:true,value:a||function(){}}},l=function(a){return k(a,0,1,0)},m=function(a){return k(a,1)},n=function(a){try{var b=a.then;if("function"==typeof b)return!0}catch(c){}return!1},o=function(a){Error.call(this,a)};o.prototype=Object.create(Error.prototype);var p=function(){var a=[];return a.pump=function(b){d(function(){for(var c=a.length,d=0;c>d;)d++,a.shift()(b)})},a},q=function(a,b,e,f,g,h){var i=!1,k=this,l=function(a){d(function(){h("fulfilled"),f(a),b.pump(a)})},m=function(a){d(function(){h("rejected"),g(a),e.pump(a)})},o=function(a){return n(a)?(a.then(o,m),void 0):(l(a),void 0)},p=function(a){return function(b){i?"undefined"!=typeof console&&console.error("Cannot resolve a Promise multiple times."):(i=!0,a(b))}};this.resolve=p(o,"resolve"),this.fulfill=p(l,"fulfill"),this.reject=p(m,"reject"),this.cancel=function(){k.reject(Error("Cancel"))},this.timeout=function(){k.reject(Error("Timeout"))},c&&Object.defineProperties(this,{_isResolved:j(function(){return i})}),h("pending")},f=function(a){var e,f,b=new p,d=new p,g="pending";c&&Object.defineProperties(this,{_value:j(function(){return e}),_error:j(function(){return f}),_state:j(function(){return g})}),Object.defineProperties(this,{_addAcceptCallback:l(function(a){b.push(a),"fulfilled"==g&&b.pump(e)}),_addRejectCallback:l(function(a){d.push(a),"rejected"==g&&d.pump(f)})});var h=new q(this,b,d,function(a){e=a},function(a){f=a},function(a){g=a});try{a&&a(h)}catch(i){h.reject(i)}},r=function(a){return"function"==typeof a},s=function(a,b,c){return r(a)?function(){try{var c=a.apply(null,arguments);b.resolve(c)}catch(d){b.reject(d)}}:b[c].bind(b)},t=function(a,b,c){return r(a)&&c._addAcceptCallback(a),r(b)&&c._addRejectCallback(b),c};f.prototype=Object.create(null,{then:m(function(a,b){var c=this;return new f(function(d){t(s(a,d,"resolve"),s(b,d,"reject"),c)})}),"catch":m(function(a){var b=this;return new f(function(c){t(null,s(a,c,"reject"),b)})})}),f.isThenable=n;var u=function(a){return Array.prototype.slice.call(a).map(f.resolve)};f.any=function(){var a=u(arguments);return new f(function(b){if(a.length){var c=!1,d=function(a){c||(c=!0,b.resolve(a))},e=function(a){c||(c=!0,b.reject(a))};a.forEach(function(a){a.then(d,e)})}else b.reject("No futures passed to Promise.any()")})},f.every=function(){var a=u(arguments);return new f(function(b){if(a.length){var c=Array(a.length),d=0,e=function(e,f){d++,c[e]=f,d==a.length&&b.resolve(c)};a.forEach(function(a,c){a.then(e.bind(null,c),b.reject)})}else b.reject("No futures passed to Promise.every()")})},f.some=function(){var a=u(arguments);return new f(function(b){if(a.length){var c=0,d=function(){c++,c==a.length&&b.reject()};a.forEach(function(a){a.then(b.resolve,d)})}else b.reject("No futures passed to Promise.some()")})},f.fulfill=function(a){return new f(function(b){b.fulfill(a)})},f.resolve=function(a){return new f(function(b){b.resolve(a)})},f.reject=function(a){return new f(function(b){b.reject(a)})},a.Promise=f})(this,"undefined"!=typeof window?window:{},this.runningUnderTest||!1); 2 | -------------------------------------------------------------------------------- /historical_interest/Future.idl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Google Inc. All rights reserved. 3 | */ 4 | 5 | // 6 | // Design Notes 7 | // ============ 8 | // 9 | // Goals: 10 | // 11 | // This design for a DOM-compatible Future (nee, "Promise") type aims to be 12 | // usable in the majority of the web's single-response asynchronous APIs, 13 | // either directly or through subclass (e.g., to add progress notification). 14 | // 15 | // It also aims to enable end-users (non-spec authors) to build systems 16 | // using these types directly without appealing to libraries or DOM magic 17 | // for creating/fulfilling Futures. 18 | // 19 | // We identify the following features as required: 20 | // 21 | // * Chaining of .then() calls 22 | // * Subclassing by DOM API designers (see ProgressFuture.idl, e.g.) 23 | // * Eventual import or subsetting by TC39 for adding Futures to the 24 | // language directly. 25 | // 26 | // Non-Goals: 27 | // 28 | // Unifying or describing the internal behavior of events is a non-goal. 29 | // Futures are a single-request/single-repose formalism and may capture 30 | // values from past resposes. Events, on the other hand, describe a series 31 | // of future events. They cover separate use-cases and we do not seek to 32 | // join them here. 33 | // 34 | // Compatibility with existing promises/futures/deferreds libraries or 35 | // terminology is a non-goal. Where adopting existing terminology improves 36 | // the usability of this design, we will. Otherwise, appeals to 37 | // compatibility with published libraries, specifications, and practice are 38 | // not compelling. So far, this is compatible with the 39 | // Promises/A+ spec, although largely by accident and in part because it 40 | // leaves core compatibility points (such as defining what it means to be a 41 | // testable "Promise" type in return handling) undefined: 42 | // 43 | // https://github.com/promises-aplus/promises-spec 44 | // 45 | // Basic API: 46 | // 47 | // DOM Futures represent the completion of a single operation, past or 48 | // future, an error handling for that operation. 49 | // 50 | // Futures take an initialization function as their only parameter. This 51 | // function is called back synchronously (by the time construction finishes) 52 | // with references to the the resolve and reject functions that can later be 53 | // used to resolve the Future. 54 | // 55 | // function doAsyncWork() { 56 | // return new Future(function(r) { 57 | // setTimeout(function() { // ...time passes 58 | // // Do work here 59 | // r.resolve("success"); 60 | // }, 100); 61 | // }); 62 | // } 63 | // 64 | // // Callers of the function can be notified of resolution easily: 65 | // doAsyncWork().then(console.log.bind(console)); 66 | // 67 | // Futures provide a way for others to be notified when the resolution 68 | // occurs without handing them the ability to resolve the future itself. 69 | // This is accomplished either by providing callbacks to the ".then()" 70 | // method. 71 | // 72 | // Processing model: 73 | // 74 | // the delivery of any resolution or error must be "apparently 75 | // asynchronous", specifically they must be delayed at least to the "end of 76 | // microtask" as defined for the delivery of mutation observer and 77 | // object.observe() notifications. delivery at any point beyond that, e.g. 78 | // in the next turn or microtask, is allowed, but all implementations must 79 | // demonstrate the following behavior: 80 | // 81 | // var callbacks; 82 | // var f = new Future(function(c) { callbacks = c; }); 83 | // assertTrue(f.state == "pending"); 84 | // callbacks.resolve(null); 85 | // assertTrue(f.state == "pending"); 86 | // 87 | // try { 88 | // callbacks.resolve(null); 89 | // // Not reached 90 | // assertTrue(false); 91 | // } catch(e) { 92 | // // Catch the AlreadyResolved error thrown by the second resolve() 93 | // assertTrue(e instanceof AlreadyResolved); 94 | // } 95 | // 96 | // Chaining: 97 | // 98 | // Chaining is a requirement, meaning that it must be possible to call 99 | // ".then()" and receive a sensible result from which you can ".then()" 100 | // again. 101 | // 102 | // Futures return a new automatically-generated Future from each 103 | // "then()" call. The then()-generated Futures are resolved by the 104 | // callbacks passed to each "then()" invocation. These functions are called 105 | // based on the resolution and their return values are passed onward to the 106 | // next auto-generated Future: 107 | // 108 | // // Example invocation 109 | // var doItAsync = function() { 110 | // var callbacks; 111 | // var f = new Future(function(c) { callbacks = c; }); 112 | // // ... 113 | // return f; 114 | // }; 115 | // doItAsync() 116 | // .then(accept, reject) 117 | // .then(acceptIntermediate) 118 | // .done(acceptFinal); 119 | // 120 | // Chaining fast-forwards un-handled values to the next item in the chain 121 | // which registers a handler for that particular disposition (accept & 122 | // reject). As in RSVP.js, the "onerror" function passed to done() is called 123 | // here, logging the exception: 124 | // 125 | // doItAsync() 126 | // .then(function(){ throw new Error("spurious!"); }) 127 | // .then(accept) // "accept" is not called, and we fast-forward 128 | // .done(null, console.error.bind(console)); 129 | // 130 | // If the second call were to handle "error", the final callback would not 131 | // receive an "error" unless it also rejected its Future. e.g.: 132 | // 133 | // doItAsync() 134 | // .then(function(){ throw new Error("spurious!"); }) 135 | // .then(accept, console.error.bind(console)) // logs the error 136 | // .done(null, console.error.bind(console)); // does nothing 137 | // 138 | // Return Value Sniffing, value/error Chaining, and Forwarding: 139 | // 140 | // Like many other Future systems, the callbacks for accept & error 141 | // are used to resolve the auto-generated Future returned from a call to 142 | // then(). Below is the basic logic for then() callback return handling. 143 | // Major features: 144 | // 145 | // * If the return is a Future, merge the generated Future's behavior 146 | // with it. 147 | // * If the callback throws, reject() the generated future with the thrown 148 | // value, even if the value is not an Error. 149 | // * If the return value is any other kind, use it as the "value" for 150 | // resolving the generated Future. 151 | // 152 | // TODO(slightlyoff): updated example logic 153 | // 154 | // Similar logic is in place when using the resolve() method to provide a 155 | // value to resolve the Future with; if a value passed to resolve() is a 156 | // Future, the value of the "local" future assumes the value of the "far" 157 | // future. If it is any other value, it will be passed to accept(). The 158 | // behavior of accept is to move the Future to the "accepted" state and 159 | // set .value to whatever value is passed (regardless of type). 160 | // 161 | // Pseudo-code for resolve(): 162 | // 163 | // resolverInstance.resolve = function(value) { 164 | // if (isThenable(value)) { 165 | // value.then(this.resolve, this.reject); 166 | // return; 167 | // } 168 | // this.accept(value); 169 | // }.bind(resolverInstance); 170 | // 171 | // Delivery order: 172 | // 173 | // 1) then() callbacks in the order of registration 174 | // 2) then() callbacks added after initial dispatch phase ends 175 | // 176 | // 2 provides for a Future to have then() callbacks added after it is 177 | // resolved, allowing programmers to treat a Future object as something 178 | // which is safe to call .then() on at all times. For example, both calls to 179 | // then() in the following example will succeed and both callbacks will 180 | // receive the resolution value, albiet at different times: 181 | // 182 | // var callbacks; 183 | // var f = new Future(function(c) { callbacks = c; }); 184 | // setTimeout(callbacks.accept.bind(callbacks, "Success!"), 1); 185 | // f.then(function(value) { 186 | // // Just to illuminate the timing, we make sure that our next then() 187 | // // call occurs well outside the current turn. 188 | // setTimeout(function() { 189 | // f.then(console.log.bind(console)); 190 | // }, 1); 191 | // }); 192 | // 193 | // We observe that the second then()-added callback *DOES* log to the 194 | // console, but well after the initial resolution. All conforming 195 | // implementations MUST provide the ability for post-resolution then() calls 196 | // to resolve this way. 197 | // 198 | // Cancelation and Timeouts: 199 | // 200 | // The passed set of callbacks includes cancel() and timeout() functions. 201 | // These are syntactic sugar that generate Error objects with known name 202 | // values ("Cancel" and "Timeout", respectively). Handling these values is 203 | // done through the usual reject handler of a Future. Using only accept() 204 | // and reject() we can re-create these sugar functions easily: 205 | // 206 | // var callbacks; 207 | // var f = new Future(function(c) { callbacks = c; }); 208 | // // Compatible, ad-hoc versions of cancel() and timeout() 209 | // var cancel = function() { callbacks.reject(new Error("Cancel")); }; 210 | // var timeout = function() { callbacks.reject(new Error("Timeout")); }; 211 | // 212 | // // Register a reject handler that understands cancelation and timeout: 213 | // f.then(accept, function(reason) { 214 | // switch(reason.name) { 215 | // case "Cancel": 216 | // // handle cancelation... 217 | // break; 218 | // case "Timeout": 219 | // // ... 220 | // break; 221 | // default: 222 | // break; 223 | // } 224 | // }); 225 | // 226 | // Calling either the ad-hoc cancel() or callbacks.cancel() will have the 227 | // same effect. 228 | // 229 | // Errors and Exceptions: 230 | // 231 | // As seen in the example code above, exceptions throw by callback handlers 232 | // are caught by the system. This leads to some particular debugging hazards 233 | // which other systems have treated in various ways. Some have opted simply 234 | // not to swallow errors. Some propagate errors in various ways (this design 235 | // employs a variant of that approach). 236 | // 237 | // No matter what approach is pursued, integration with developer tooling is 238 | // key. Developer consoles SHOULD log un-caught errors from future chains. 239 | // That is to say, if future.done(onresponse); is the only handler given for 240 | // a resolver which is eventually rejected, developer tools should log the 241 | // unhandled error. 242 | 243 | // Futures begin in the "pending" state and progress to other 244 | // states. Once moved from the "pending" state, they may never be 245 | // returned to it. The states are exclusive. 246 | enum FutureState { 247 | "pending", 248 | "accepted", 249 | "rejected" 250 | }; 251 | 252 | interface FutureResolver { 253 | // Directly resolves the Future with the passed value 254 | void accept(optional any value); // can throw AlreadyResolved 255 | 256 | // Indirectly resolves the Future, chaining any passed Future's resolution 257 | void resolve(optional any value); // can throw AlreadyResolved 258 | 259 | // Rejects the future 260 | void reject(optional any error); // can throw AlreadyResolved 261 | 262 | // Rejects with an error of: Error("Cancel") 263 | void cancel(); // can throw AlreadyResolved 264 | 265 | // Rejects with an error of: Error("Timeout") 266 | void timeout(); // can throw AlreadyResolved 267 | 268 | // false until (and unless) calling any of the above methods would raise an 269 | // AlreadyResolved exception 270 | readonly attribute boolean isResolved; 271 | }; 272 | 273 | callback FutureCallback = void (FutureResolver resolver); 274 | callback AnyCallback = any (optional any value); 275 | 276 | [Constructor(FutureCallback init)] 277 | interface Future { 278 | attribute readonly any value; 279 | attribute readonly any error; 280 | attribute readonly FutureState state; 281 | 282 | // Returns a Future whose fulfillment value will be the return value 283 | // from whichever of the callbacks is eventually invoked. 284 | Future then(optional AnyCallback accept, optional AnyCallback reject); 285 | 286 | // A shorthand for not registering only an reject callback. Desugars to: 287 | // 288 | // Future.prototype.catch = function(reject) { 289 | // return this.then(undefined, reject); 290 | // }; 291 | Future catch(optional AnyCallback reject); 292 | 293 | // An end-of-chain callback. Equivalent to .then() except it does not generate 294 | // a new Future and therefore ignores the return values of the callbacks. 295 | void done(optional AnyCallback accept, optional AnyCallback reject); 296 | }; 297 | -------------------------------------------------------------------------------- /historical_interest/ProgressFuture.idl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013: 2 | // Alex Russell 3 | // Yehuda Katz 4 | // 5 | // Use of this source code is governed by 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | // A subclass of Future which adds support for progress notification. 9 | // 10 | // Usage 11 | // ===== 12 | // 13 | // doItAsyncWithProgress(...). 14 | // progress(function(progressValue) { ... }). 15 | // then(onaccept, onreject); 16 | 17 | interface ProgressFutureResolver extends FutureResolver { 18 | // Provide new progress which onprogress handlers will be notified of 19 | void progress(optional any progressValue); 20 | }; 21 | 22 | callback ProgressFutureInit = void (ProgressFutureResolver resolver); 23 | 24 | [Constructor(ProgressFutureInit init)] 25 | interface ProgressFuture : Future { 26 | // Returns the Future from which it was called ("this"). 27 | ProgressFuture progress(optional AnyCallback progressHandler); 28 | }; 29 | -------------------------------------------------------------------------------- /historical_interest/Promise.idl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 Google Inc. All rights reserved. 3 | */ 4 | 5 | // 6 | // Design Notes 7 | // ============ 8 | // 9 | // Goals: 10 | // 11 | // This design for a DOM-compatible Promise type aims to be 12 | // usable in the majority of the web's single-response asynchronous APIs, 13 | // either directly or through subclass (e.g., to add progress notification). 14 | // 15 | // It also aims to enable end-users (non-spec authors) to build systems 16 | // using these types directly without appealing to libraries or DOM magic 17 | // for creating/fulfilling Promises. 18 | // 19 | // We identify the following features as required: 20 | // 21 | // * Chaining of .then() calls 22 | // * Subclassing by DOM API designers (see ProgressPromise.idl, e.g.) 23 | // * Eventual import or subsetting by TC39 for adding Promises to the 24 | // language directly. 25 | // 26 | // Non-Goals: 27 | // 28 | // Unifying or describing the internal behavior of events is a non-goal. 29 | // Promises are a single-request/single-repose formalism and may capture 30 | // values from past resposes. Events, on the other hand, describe a series 31 | // of future events. They cover separate use-cases and we do not seek to 32 | // join them here. 33 | // 34 | // Compatibility with existing promises/futures/deferreds libraries or 35 | // terminology is a non-goal. Where adopting existing terminology improves 36 | // the usability of this design, we will. Otherwise, appeals to 37 | // compatibility with published libraries, specifications, and practice are 38 | // not compelling. So far, this is compatible with the 39 | // Promises/A+ spec, although largely by accident and in part because it 40 | // leaves core compatibility points (such as defining what it means to be a 41 | // testable "Promise" type in return handling) undefined: 42 | // 43 | // https://github.com/promises-aplus/promises-spec 44 | // 45 | // Basic API: 46 | // 47 | // DOM Promises represent the completion of a single operation, past or 48 | // future, an error handling for that operation. 49 | // 50 | // Promises take an initialization function as their only parameter. This 51 | // function is called back synchronously (by the time construction finishes) 52 | // with references to the the resolve and reject functions that can later be 53 | // used to resolve the Promise. 54 | // 55 | // function doAsyncWork() { 56 | // return new Promise(function(r) { 57 | // setTimeout(function() { // ...time passes 58 | // // Do work here 59 | // r.resolve("success"); 60 | // }, 100); 61 | // }); 62 | // } 63 | // 64 | // // Callers of the function can be notified of resolution easily: 65 | // doAsyncWork().then(console.log.bind(console)); 66 | // 67 | // Promises provide a way for others to be notified when the resolution 68 | // occurs without handing them the ability to resolve the future itself. 69 | // This is accomplished either by providing callbacks to the ".then()" 70 | // method. 71 | // 72 | // Processing model: 73 | // 74 | // the delivery of any resolution or error must be "apparently 75 | // asynchronous", specifically they must be delayed at least to the "end of 76 | // microtask" as defined for the delivery of mutation observer and 77 | // object.observe() notifications. delivery at any point beyond that, e.g. 78 | // in the next turn or microtask, is allowed, but all implementations must 79 | // demonstrate the following behavior: 80 | // 81 | // var callbacks; 82 | // var f = new Promise(function(c) { callbacks = c; }); 83 | // // Polyfills in debugging mode provide a "_state" property to track 84 | // // progress. 85 | // assertTrue(f._state == "pending"); 86 | // callbacks.resolve(null); 87 | // assertTrue(f._state == "pending"); 88 | // 89 | // try { 90 | // callbacks.resolve(null); 91 | // // Not reached 92 | // assertTrue(false); 93 | // } catch(e) { 94 | // // Catch the AlreadyResolved error thrown by the second resolve() 95 | // assertTrue(e instanceof AlreadyResolved); 96 | // } 97 | // 98 | // Chaining: 99 | // 100 | // Chaining is a requirement, meaning that it must be possible to call 101 | // ".then()" and receive a sensible result from which you can ".then()" 102 | // again. 103 | // 104 | // Promises return a new automatically-generated Promise from each 105 | // "then()" call. The then()-generated Promises are resolved by the 106 | // callbacks passed to each "then()" invocation. These functions are called 107 | // based on the resolution and their return values are passed onward to the 108 | // next auto-generated Promise: 109 | // 110 | // // Example invocation 111 | // var doItAsync = function() { 112 | // var callbacks; 113 | // var f = new Promise(function(c) { callbacks = c; }); 114 | // // ... 115 | // return f; 116 | // }; 117 | // doItAsync() 118 | // .then(fulfill, reject) 119 | // .then(fulfillIntermediate) 120 | // .then(fulfillFinal); 121 | // 122 | // Chaining fast-forwards un-handled values to the next item in the chain 123 | // which registers a handler for that particular disposition (fulfill & 124 | // reject). As in RSVP.js, the "onerror" function passed to then() is 125 | // called here, logging the exception: 126 | // 127 | // doItAsync() 128 | // .then(function(){ throw new Error("spurious!"); }) 129 | // .then(fulfill) // "fulfill" is not called, and we fast-forward 130 | // .then(null, console.error.bind(console)); 131 | // 132 | // If the second call were to handle "error", the final callback would not 133 | // receive an "error" unless it also rejected its Promise. e.g.: 134 | // 135 | // doItAsync() 136 | // .then(function(){ throw new Error("spurious!"); }) 137 | // .then(fulfill, console.error.bind(console)) // logs the error 138 | // .then(null, console.error.bind(console)); // does nothing 139 | // 140 | // Return Value Sniffing, value/error Chaining, and Forwarding: 141 | // 142 | // Like many other Promise systems, the callbacks for fulfill & error 143 | // are used to resolve the auto-generated Promise returned from a call to 144 | // then(). Below is the basic logic for then() callback return handling. 145 | // Major features: 146 | // 147 | // * If the return is a Promise, merge the generated Promise's behavior 148 | // with it. 149 | // * If the callback throws, reject() the generated future with the thrown 150 | // value, even if the value is not an Error. 151 | // * If the return value is any other kind, use it as the "value" for 152 | // resolving the generated Promise. 153 | // 154 | // TODO(slightlyoff): updated example logic 155 | // 156 | // Similar logic is in place when using the resolve() method to provide a 157 | // value to resolve the Promise with; if a value passed to resolve() is a 158 | // Promise, the value of the "local" future assumes the value of the "far" 159 | // future. If it is any other value, it will be passed to fulfill(). The 160 | // behavior of fulfill is to move the Promise to the "fulfilled" state and 161 | // set .value to whatever value is passed (regardless of type). 162 | // 163 | // Pseudo-code for resolve(): 164 | // 165 | // resolverInstance.resolve = function(value) { 166 | // if (isBrandedAsPromise(value)) { 167 | // value.then(this.resolve, this.reject); 168 | // return; 169 | // } 170 | // this.fulfill(value); 171 | // }.bind(resolverInstance); 172 | // 173 | // Delivery order: 174 | // 175 | // 1) then() callbacks in the order of registration 176 | // 2) then() callbacks added after initial dispatch phase ends 177 | // 178 | // 2 provides for a Promise to have then() callbacks added after it is 179 | // resolved, allowing programmers to treat a Promise object as something 180 | // which is safe to call .then() on at all times. For example, both calls to 181 | // then() in the following example will succeed and both callbacks will 182 | // receive the resolution value, albiet at different times: 183 | // 184 | // var callbacks; 185 | // var f = new Promise(function(c) { callbacks = c; }); 186 | // setTimeout(callbacks.fulfill.bind(callbacks, "Success!"), 1); 187 | // f.then(function(value) { 188 | // // Just to illuminate the timing, we make sure that our next then() 189 | // // call occurs well outside the current turn. 190 | // setTimeout(function() { 191 | // f.then(console.log.bind(console)); 192 | // }, 1); 193 | // }); 194 | // 195 | // We observe that the second then()-added callback *DOES* log to the 196 | // console, but well after the initial resolution. All conforming 197 | // implementations MUST provide the ability for post-resolution then() calls 198 | // to resolve this way. 199 | // 200 | // Cancelation and Timeouts: 201 | // 202 | // The passed set of callbacks includes cancel() and timeout() functions. 203 | // These are syntactic sugar that generate Error objects with known name 204 | // values ("Cancel" and "Timeout", respectively). Handling these values is 205 | // done through the usual reject handler of a Promise. Using only fulfill() 206 | // and reject() we can re-create these sugar functions easily: 207 | // 208 | // var callbacks; 209 | // var f = new Promise(function(c) { callbacks = c; }); 210 | // // Compatible, ad-hoc versions of cancel() and timeout() 211 | // var cancel = function() { callbacks.reject(new Error("Cancel")); }; 212 | // var timeout = function() { callbacks.reject(new Error("Timeout")); }; 213 | // 214 | // // Register a reject handler that understands cancelation and timeout: 215 | // f.then(fulfill, function(reason) { 216 | // switch(reason.name) { 217 | // case "Cancel": 218 | // // handle cancelation... 219 | // break; 220 | // case "Timeout": 221 | // // ... 222 | // break; 223 | // default: 224 | // break; 225 | // } 226 | // }); 227 | // 228 | // Calling either the ad-hoc cancel() or callbacks.cancel() will have the 229 | // same effect. 230 | // 231 | // Errors and Exceptions: 232 | // 233 | // As seen in the example code above, exceptions throw by callback handlers 234 | // are caught by the system. This leads to some particular debugging hazards 235 | // which other systems have treated in various ways. Some have opted simply 236 | // not to swallow errors. Some propagate errors in various ways (this design 237 | // employs a variant of that approach). 238 | // 239 | // No matter what approach is pursued, integration with developer tooling is 240 | // key. Developer consoles SHOULD log un-caught errors from future chains. 241 | // That is to say, if future.then(onresponse); is the only handler given for 242 | // a resolver which is eventually rejected, developer tools should log the 243 | // unhandled error. 244 | 245 | interface PromiseResolver { 246 | // Directly resolves the Promise with the passed value 247 | void fulfill(optional any value); 248 | 249 | // Indirectly resolves the Promise, chaining any passed Promise's resolution 250 | void resolve(optional any value); 251 | 252 | // Rejects the future 253 | void reject(optional any error); 254 | 255 | // Note that implementations may keep internal state here, notably an 256 | // "isResovled" flag. 257 | }; 258 | 259 | callback PromiseCallback = void (PromiseResolver resolver); 260 | callback AnyCallback = any (optional any value); 261 | 262 | [Constructor(PromiseCallback init)] 263 | interface Promise { 264 | ///////////////////////////////// 265 | // Instance Methods 266 | 267 | // Returns a Promise whose fulfillment value will be the return value 268 | // from whichever of the callbacks is eventually invoked. 269 | Promise then(optional AnyCallback fulfill, optional AnyCallback reject); 270 | 271 | // A shorthand for not registering only an reject callback. Desugars to: 272 | // 273 | // Promise.prototype.catch = function(reject) { 274 | // return this.then(undefined, reject); 275 | // }; 276 | // 277 | Promise catch(optional AnyCallback reject); 278 | 279 | ///////////////////////////////// 280 | // Statics 281 | 282 | static Promise fulfill(any value); 283 | static Promise resolve(any value); // same as any(value) 284 | static Promise reject(any value); 285 | 286 | // exposed as "any" in JavaScript, without "_" 287 | static Promise _any(any... values); 288 | // FIXME: Should be "all"? 289 | static Promise every(any... values); 290 | static Promise some(any... values); 291 | }; 292 | -------------------------------------------------------------------------------- /historical_interest/README.md: -------------------------------------------------------------------------------- 1 | #### NOTE: The IDL hosted here is now advisory. This repo hosts refactoring examples and designs, a high-fidelity polyfill, and rationale for this work. [See the living DOM spec for the current version](http://dom.spec.whatwg.org/#futures) if you are implementing Promises in a runtime. 2 | 3 | Promises/A+ logo, since DOMFutures are compatible 5 | 6 | # DOM Promises 7 | 8 | A Promises Design for DOM, currently in IDL. Also a p(r)ollyfill 9 | and re-worked APIs to take advantage of the new semantics. 10 | 11 | ## Promises? [I Don't Speak Your Crazy Moon Language](http://www.pigdog.org/auto/mr_bads_list/shortcolumn/1914.html). 12 | 13 | A Promise is an object that implements a standard contract for 14 | the results of an operation that may have already occurred or may happen in the 15 | future. 16 | 17 | There's a lot in that sentence that's meaningful, but the big ticket items are: 18 | 19 | * Promises are a contract for _a single result_, either success or failure. If 20 | you need to model something that happens multiple times, a single Future is 21 | not the answer (try events or an iterator that creates a stream of Promises). 22 | * Promises provide a mechanism for multiple parties to be informed of a value, 23 | much the same way many bits of code can hold a reference to a variable 24 | without knowing about each other. 25 | * Promises aren't, in themselves notable. Instead, they derive their value 26 | through being _the one way_ to encapsulate potentially asynchronous return 27 | values. 28 | 29 | To do all of this without syntax support from the language, Promises must be 30 | objects with standardized methods. The current design provides a constructable 31 | class that allows end-user code to vend instances of `Future` from their own APIs 32 | as well as a few standard methods: 33 | 34 | ```js 35 | // Accepts "accept" and "reject" callbacks, roughly the same thing as success 36 | // and failure for the operation. 37 | futureInstance.then(onaccept, onreject); 38 | 39 | // Accept and reject callbacks only ever have a single parameter, which is the 40 | // value or reason, respectively: 41 | futureInstance.then( 42 | function(value) { 43 | doSomethingWithTheResult(value); 44 | }, 45 | function(reason) { console.error(reason); } 46 | ); 47 | 48 | // .then() always returns a new Future, one which takes whatever value the 49 | // callback it's registered with returns: 50 | futureInstance.then(function(value) { 51 | return processValue(value); 52 | }) 53 | .then(function(processedValue) { 54 | // ... 55 | }); 56 | 57 | // A key part of the Futures design is that these operations are *chainable*, 58 | // even for asynchronous code. This makes it easy to compose asynchronous 59 | // operations in readable, linear-looking code: 60 | futureInstance.then(aHandlerThatReturnsAFuture) 61 | .then(doSomethingAfterTheSecondCallback); 62 | 63 | // .catch() gives you access only to errors: 64 | futureInstance.catch(onreject); 65 | ``` 66 | 67 | ## OK, So Why Promises For DOM? 68 | 69 | To understand why DOM needs Futures, think about a few of the asynchronous APIs 70 | in DOM that return single values: 71 | 72 | * [XHR](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest) 73 | * [Geolocation](http://www.w3.org/TR/geolocation-API/) 74 | * [IndexedDB](http://www.w3.org/TR/IndexedDB/) 75 | * [`onload`](https://developer.mozilla.org/en-US/docs/DOM/window.onload) 76 | 77 | There are some similarities today in how these APIs work. XHR and `onload` share 78 | the idea of a `readyState` property to let code detect if something has happened 79 | in the past, giving rise to logic like this: 80 | 81 | ```js 82 | if (document.readyState == "complete") { 83 | doStartupWork(); 84 | } else { 85 | document.addEventListener("load", doStartupWork, false); 86 | } 87 | ``` 88 | 89 | This is cumbersome and error-prone, not to mention ugly. IndexedDB's 90 | [`IDBRequest` class](https://developer.mozilla.org/en-US/docs/IndexedDB/IDBRequest) 91 | also supports a `readyState` property, but the values range from 92 | [1-2](https://developer.mozilla.org/en-US/docs/IndexedDB/IDBRequest#readyState_constants), 93 | not [0-4 as used in XHR](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#Properties) 94 | or [strings as used for documents](http://www.whatwg.org/specs/web-apps/current-work/multipage/dom.html#current-document-readiness). 95 | Making matters worse, the callback and event names don't even match! Clearly 96 | DOM needs a better way to do things. 97 | 98 | A uniform interface would allow us to manage our callbacks sanely across APIs: 99 | 100 | ```js 101 | // Example of what the future might hold, not in any current spec 102 | document.ready().then(doStartupWork); 103 | 104 | // By returning a Future subclass, XHR's send() method gets more usable too: 105 | var xhr = new XMLHttpRequest(); 106 | xhr.open("GET", filename, true); 107 | xhr.send().then(handleSuccessfulResponse, 108 | handleErrorResponse); 109 | 110 | // Geolocation can be easily refactored too: 111 | navigator.geolocation.getCurrentPosition().then(successCallback, errorCallback); 112 | 113 | // Even IDB gets saner: 114 | indexedDB.open(databaseName).then(function(db) { 115 | // ... 116 | }); 117 | ``` 118 | 119 | Providing a single abstraction for this sort of operation creates cross-cutting 120 | value across specifications, making it easier to use DOM and simpler for 121 | libraries to interoperate based on a standard design. 122 | 123 | ## OK, But Aren't You Late To This Party? 124 | 125 | There's a [long, long history of Promises](http://en.wikipedia.org/wiki/Futures_and_promises) 126 | both inside and outside JavaScript. Many other languages provide them via 127 | language syntax or standard library. Promises are such a common pattern inside 128 | JavaScript that nearly all major libraries provide some form them and vend 129 | them for many common operations which they wrap. There are differences in 130 | terminology and use, but the core ideas are mostly the same be they 131 | [jQuery Deferreds](http://api.jquery.com/category/deferred-object/), 132 | [WinJS Promises](http://msdn.microsoft.com/en-us/library/windows/apps/br211867.aspx), 133 | [Dojo Deferreds or Promises](http://dojotoolkit.org/documentation/tutorials/1.6/promises/), 134 | [Cujo Promises](https://github.com/cujojs/when), 135 | [Q Promises](https://github.com/kriskowal/q/wiki/API-Reference), [RSVP Promises (used heavily in Ember)](https://github.com/tildeio/rsvp.js), or even in [Node Promises](https://github.com/kriszyp/node-promise). The diversity of implementations has led both to incompatibility and efforts to standardize, the most promising of which is the [Promises/A+ effort](https://github.com/promises-aplus/promises-spec), which of course differs slightly from [Promises/A](http://wiki.commonjs.org/wiki/Promises/A) and greatly from [other pseudo-standard variants proposed over the years](http://wiki.commonjs.org/wiki/Promises). 136 | 137 | Promises/A+ doesn't define all of the semantics needed for a full implementation, 138 | and if we assume DOM needs Promises, it will also need an answer to those 139 | questions. That's what this repository is about. 140 | 141 | ## More Examples 142 | 143 | ```js 144 | // New APIs that vend Futures are easier to reason about. Instead of: 145 | if (document.readyState == "complete") { 146 | doStartupWork(); 147 | } else { 148 | document.addEventListener("load", doStartupWork, false); 149 | } 150 | 151 | // ...a Future-vending ready() method can be used at any time: 152 | document.ready().then(doStartupWork); 153 | 154 | // Like other Promises-style APIs, .then() and .done() are the 155 | // primary way to work with Futures, including via chaining, in 156 | // this example using an API proposed at: 157 | // https://github.com/slightlyoff/async-local-storage 158 | var storage = navigator.storage; 159 | storage.get("item 1").then(function(item1value) { 160 | return storage.set("item 1", "howdy"); 161 | }). 162 | done(function() { 163 | // The previous future is chained to not resolve until 164 | //item 1 is set to "howdy" 165 | storage.get("item 1").done(console.log); 166 | }); 167 | ``` 168 | 169 | Promises can also be new'd up and used in your own APIs, making them a powerful 170 | abstraction for building asynchronous contracts for single valued operations; 171 | basically any time you want to do some work asynchronously but only care about 172 | a single response value: 173 | 174 | ```js 175 | function fetchJSON(filename) { 176 | // Return a Promise that represents the fetch: 177 | return new Promise(function(resolver){ 178 | // The resolver is how a Promise is satisfied. It has reject(), fulfill(), 179 | // and resolve() methods that your code can use to inform listeners with: 180 | var xhr = new XMLHttpRequest(); 181 | xhr.open("GET", filename, true); 182 | xhr.send(); 183 | xhr.onreadystatechange = function() { 184 | if (xhr.readyState == 4) { 185 | try { 186 | resolver.resolve(JSON.parse(xhr.responseText)); 187 | } catch(e) { 188 | resolver.reject(e); 189 | } 190 | } 191 | } 192 | }); 193 | } 194 | 195 | // Now we can use the uniform Future API to reason about JSON fetches: 196 | fetchJSON("thinger.json").then(function(object) { ... } , 197 | function(error) { ... }); 198 | ``` 199 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/IndexedDB/after.idl: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Extracted via the web inspector from: 3 | * 4 | * http://www.w3.org/TR/IndexedDB/ 5 | * 6 | * By running: 7 | * 8 | * Array.prototype.slice.call( 9 | * document.querySelectorAll(".idl,.es-code") 10 | * ).map(function(n) { return n.innerText; }).join("\n\n\n"); 11 | * 12 | **/ 13 | 14 | /************************************** 15 | * 3.1.9 16 | **/ 17 | interface IDBKeyRange { 18 | readonly attribute any lower; 19 | readonly attribute any upper; 20 | readonly attribute boolean lowerOpen; 21 | readonly attribute boolean upperOpen; 22 | static IDBKeyRange only (any value); 23 | static IDBKeyRange lowerBound (any lower, optional boolean open); 24 | static IDBKeyRange upperBound (any upper, optional boolean open); 25 | static IDBKeyRange bound (any lower, any upper, optional boolean lowerOpen, optional boolean upperOpen); 26 | }; 27 | 28 | 29 | /************************************** 30 | * 3.1.12 31 | **/ 32 | dictionary IDBObjectStoreParameters { 33 | DOMString? keyPath = null; 34 | boolean autoIncrement = false; 35 | }; 36 | 37 | dictionary IDBIndexParameters { 38 | boolean unique = false; 39 | boolean multiEntry = false; 40 | }; 41 | 42 | dictionary IDBVersionChangeEventInit : EventInit { 43 | unsigned long long oldVersion = 0; 44 | unsigned long long? newVersion = null; 45 | }; 46 | 47 | 48 | /************************************** 49 | * 3.2.1 50 | **/ 51 | interface IDBRequest : Future { 52 | // Result becomes an alias for `value` 53 | readonly attribute any result; 54 | // `error` is no longer needed as it's part of Future. 55 | // readonly attribute DOMError error; 56 | 57 | readonly attribute Object source; 58 | readonly attribute IDBTransaction transaction; 59 | readonly attribute DOMString readyState; 60 | 61 | // Alias for onaccept 62 | [TreatNonCallableAsNull] 63 | attribute Function? onsuccess; 64 | // Alias for onreject 65 | [TreatNonCallableAsNull] 66 | attribute Function? onerror; 67 | }; 68 | 69 | IDBRequest implements EventTarget; 70 | 71 | interface IDBOpenDBRequest : IDBRequest { 72 | [TreatNonCallableAsNull] 73 | attribute Function? onblocked; 74 | [TreatNonCallableAsNull] 75 | attribute Function? onupgradeneeded; 76 | }; 77 | 78 | 79 | /************************************** 80 | * 3.2.2 81 | **/ 82 | [Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)] 83 | interface IDBVersionChangeEvent : Event { 84 | readonly attribute unsigned long long oldVersion; 85 | readonly attribute unsigned long long? newVersion; 86 | }; 87 | 88 | 89 | /************************************** 90 | * 3.2.3 91 | **/ 92 | Window implements IDBEnvironment; 93 | 94 | WorkerUtils implements IDBEnvironment; 95 | 96 | [NoInterfaceObject] 97 | interface IDBEnvironment { 98 | readonly attribute IDBFactory indexedDB; 99 | }; 100 | 101 | interface IDBFactory { 102 | IDBOpenDBRequest open (DOMString name, [EnforceRange] optional unsigned long long version); 103 | IDBOpenDBRequest deleteDatabase (DOMString name); 104 | short cmp (any first, any second); 105 | }; 106 | 107 | 108 | /************************************** 109 | * 3.2.4 110 | **/ 111 | interface IDBDatabase : EventTarget { 112 | readonly attribute DOMString name; 113 | readonly attribute unsigned long long version; 114 | readonly attribute DOMStringList objectStoreNames; 115 | IDBObjectStore createObjectStore (DOMString name, optional IDBObjectStoreParameters optionalParameters); 116 | void deleteObjectStore (DOMString name); 117 | IDBTransaction transaction (any storeNames, optional DOMString mode); 118 | void close (); 119 | [TreatNonCallableAsNull] 120 | attribute Function? onabort; 121 | [TreatNonCallableAsNull] 122 | attribute Function? onerror; 123 | [TreatNonCallableAsNull] 124 | attribute Function? onversionchange; 125 | }; 126 | 127 | 128 | /************************************** 129 | * 3.2.5 130 | **/ 131 | interface IDBObjectStore { 132 | readonly attribute DOMString name; 133 | readonly attribute DOMString keyPath; 134 | readonly attribute DOMStringList indexNames; 135 | readonly attribute IDBTransaction transaction; 136 | readonly attribute boolean autoIncremenent; 137 | // TODO: that the accept value for a successful put/add is...? 138 | IDBRequest put (any value, optional any key); 139 | IDBRequest add (any value, optional any key); 140 | IDBRequest delete (any key); 141 | IDBRequest get (any key); 142 | IDBRequest clear (); 143 | IDBRequest openCursor (optional any? range, optional DOMString direction); 144 | IDBIndex createIndex (DOMString name, any keyPath, optional IDBIndexParameters optionalParameters); 145 | IDBIndex index (DOMString name); 146 | void deleteIndex (DOMString indexName); 147 | IDBRequest count (optional any key); 148 | }; 149 | 150 | 151 | /************************************** 152 | * 3.2.6 153 | **/ 154 | interface IDBIndex { 155 | readonly attribute DOMString name; 156 | readonly attribute IDBObjectStore objectStore; 157 | readonly attribute DOMString keyPath; 158 | readonly attribute boolean multiEntry; 159 | readonly attribute boolean unique; 160 | IDBRequest openCursor (optional any? range, optional DOMString direction); 161 | IDBRequest openKeyCursor (optional any? range, optional DOMString direction); 162 | IDBRequest get (any key); 163 | IDBRequest getKey (any key); 164 | IDBRequest count (optional any key); 165 | }; 166 | 167 | 168 | /************************************** 169 | * 3.2.7 170 | **/ 171 | interface IDBCursor { 172 | readonly attribute Object source; 173 | readonly attribute DOMString direction; 174 | readonly attribute any key; 175 | readonly attribute any primaryKey; 176 | IDBRequest update (any value); 177 | void advance ([EnforceRange] unsigned long count); 178 | void continue (optional any key); 179 | IDBRequest delete (); 180 | }; 181 | 182 | interface IDBCursorWithValue : IDBCursor { 183 | readonly attribute any value; 184 | }; 185 | 186 | 187 | /************************************** 188 | * 3.2.8 189 | **/ 190 | interface IDBTransaction : EventTarget { 191 | readonly attribute DOMString mode; 192 | readonly attribute IDBDatabase db; 193 | readonly attribute DOMError error; 194 | IDBObjectStore objectStore (DOMString name); 195 | void abort (); 196 | [TreatNonCallableAsNull] 197 | attribute Function? onabort; 198 | [TreatNonCallableAsNull] 199 | attribute Function? oncomplete; 200 | [TreatNonCallableAsNull] 201 | attribute Function? onerror; 202 | IDBRequest open(); 203 | }; 204 | 205 | 206 | /************************************** 207 | * 3.3.1 208 | **/ 209 | WorkerUtils implements IDBEnvironmentSync; 210 | 211 | [NoInterfaceObject] 212 | interface IDBEnvironmentSync { 213 | readonly attribute IDBFactorySync indexedDBSync; 214 | }; 215 | 216 | interface IDBFactorySync { 217 | IDBDatabaseSync open (DOMString name, [EnforceRange] optional unsigned long long version, optional IDBVersionChangeCallback upgradeCallback, optional unsigned long timeout); 218 | void deleteDatabase (DOMString name); 219 | short cmp (any first, any second); 220 | }; 221 | 222 | 223 | /************************************** 224 | * 3.3.2 225 | **/ 226 | interface IDBDatabaseSync { 227 | readonly attribute DOMString name; 228 | readonly attribute unsigned long long version; 229 | readonly attribute DOMStringList objectStoreNames; 230 | IDBObjectStoreSync createObjectStore (DOMString name, optional IDBObjectStoreParameters optionalParameters); 231 | void deleteObjectStore (DOMString name); 232 | void transaction (any storeNames, IDBTransactionCallback callback, optional DOMString mode, optional unsigned long timeout); 233 | void close (); 234 | }; 235 | 236 | [NoInterfaceObject, Callback] 237 | interface IDBTransactionCallback { 238 | void transactionStarted (IDBTransactionSync transaction); 239 | }; 240 | 241 | [NoInterfaceObject, Callback] 242 | interface IDBVersionChangeCallback { 243 | void transactionStarted (IDBTransactionSync transaction, unsigned long long oldVersion); 244 | }; 245 | 246 | 247 | /************************************** 248 | * 3.3.3 249 | **/ 250 | interface IDBObjectStoreSync { 251 | readonly attribute DOMString name; 252 | readonly attribute any keyPath; 253 | readonly attribute DOMStringList indexNames; 254 | readonly attribute IDBTransactionSync transaction; 255 | readonly attribute boolean autoIncremenent;; 256 | any put (any value, optional any key); 257 | any add (any value, optional any key); 258 | boolean delete (any key); 259 | any get (any key); 260 | void clear (); 261 | IDBIndexSync createIndex (DOMString name, any keyPath, optional IDBIndexParameters optionalParameters); 262 | IDBIndexSync index (DOMString name); 263 | void deleteIndex (DOMString indexName); 264 | IDBCursorWithValueSync openCursor (optional any? range, optional DOMString direction); 265 | unsigned long count (optional any key); 266 | }; 267 | 268 | 269 | /************************************** 270 | * 3.3.4 271 | **/ 272 | interface IDBIndexSync { 273 | readonly attribute DOMString name; 274 | readonly attribute IDBObjectStoreSync objectStore; 275 | readonly attribute any keyPath; 276 | readonly attribute boolean multiEntry; 277 | readonly attribute boolean unique; 278 | IDBCursorWithValueSync openCursor (optional any? range, optional DOMString direction); 279 | IDBCursorSync openKeyCursor (optional any? range, optional DOMString direction); 280 | any get (any key); 281 | any getKey (any key); 282 | unsigned long count (optional any key); 283 | }; 284 | 285 | 286 | /************************************** 287 | * 3.3.5 288 | **/ 289 | interface IDBCursorSync { 290 | readonly attribute Object source; 291 | readonly attribute DOMString direction; 292 | readonly attribute any primaryKey; 293 | IDBRequest update (any value); 294 | boolean advance ([EnforceRange] unsigned long count); 295 | boolean continue (optional any key); 296 | boolean delete (); 297 | }; 298 | 299 | interface IDBCursorWithValueSync : IDBCursorSync { 300 | attribute any value; 301 | }; 302 | 303 | 304 | /************************************** 305 | * 3.3.6 306 | **/ 307 | interface IDBTransactionSync { 308 | readonly attribute DOMString mode; 309 | attribute IDBDatabaseSync db; 310 | readonly attribute DOMError error; 311 | IDBObjectStoreSync objectStore (DOMString name); 312 | void abort (); 313 | }; 314 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/IndexedDB/before.idl: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Extracted via the web inspector from: 3 | * 4 | * http://www.w3.org/TR/IndexedDB/ 5 | * 6 | * By running: 7 | * 8 | * Array.prototype.slice.call( 9 | * document.querySelectorAll(".idl,.es-code") 10 | * ).map(function(n) { return n.innerText; }).join("\n\n\n"); 11 | * 12 | **/ 13 | 14 | /************************************** 15 | * 3.1.9 16 | **/ 17 | interface IDBKeyRange { 18 | readonly attribute any lower; 19 | readonly attribute any upper; 20 | readonly attribute boolean lowerOpen; 21 | readonly attribute boolean upperOpen; 22 | static IDBKeyRange only (any value); 23 | static IDBKeyRange lowerBound (any lower, optional boolean open); 24 | static IDBKeyRange upperBound (any upper, optional boolean open); 25 | static IDBKeyRange bound (any lower, any upper, optional boolean lowerOpen, optional boolean upperOpen); 26 | }; 27 | 28 | 29 | /************************************** 30 | * 3.1.12 31 | **/ 32 | dictionary IDBObjectStoreParameters { 33 | DOMString? keyPath = null; 34 | boolean autoIncrement = false; 35 | }; 36 | 37 | dictionary IDBIndexParameters { 38 | boolean unique = false; 39 | boolean multiEntry = false; 40 | }; 41 | 42 | dictionary IDBVersionChangeEventInit : EventInit { 43 | unsigned long long oldVersion = 0; 44 | unsigned long long? newVersion = null; 45 | }; 46 | 47 | 48 | /************************************** 49 | * 3.2.1 50 | **/ 51 | interface IDBRequest : EventTarget { 52 | readonly attribute any result; 53 | readonly attribute DOMError error; 54 | readonly attribute Object source; 55 | readonly attribute IDBTransaction transaction; 56 | readonly attribute DOMString readyState; 57 | [TreatNonCallableAsNull] 58 | attribute Function? onsuccess; 59 | [TreatNonCallableAsNull] 60 | attribute Function? onerror; 61 | }; 62 | 63 | interface IDBOpenDBRequest : IDBRequest { 64 | [TreatNonCallableAsNull] 65 | attribute Function? onblocked; 66 | [TreatNonCallableAsNull] 67 | attribute Function? onupgradeneeded; 68 | }; 69 | 70 | 71 | /************************************** 72 | * 3.2.2 73 | **/ 74 | [Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)] 75 | interface IDBVersionChangeEvent : Event { 76 | readonly attribute unsigned long long oldVersion; 77 | readonly attribute unsigned long long? newVersion; 78 | }; 79 | 80 | 81 | /************************************** 82 | * 3.2.3 83 | **/ 84 | Window implements IDBEnvironment; 85 | 86 | WorkerUtils implements IDBEnvironment; 87 | 88 | [NoInterfaceObject] 89 | interface IDBEnvironment { 90 | readonly attribute IDBFactory indexedDB; 91 | }; 92 | 93 | interface IDBFactory { 94 | IDBOpenDBRequest open (DOMString name, [EnforceRange] optional unsigned long long version); 95 | IDBOpenDBRequest deleteDatabase (DOMString name); 96 | short cmp (any first, any second); 97 | }; 98 | 99 | 100 | /************************************** 101 | * 3.2.4 102 | **/ 103 | interface IDBDatabase : EventTarget { 104 | readonly attribute DOMString name; 105 | readonly attribute unsigned long long version; 106 | readonly attribute DOMStringList objectStoreNames; 107 | IDBObjectStore createObjectStore (DOMString name, optional IDBObjectStoreParameters optionalParameters); 108 | void deleteObjectStore (DOMString name); 109 | IDBTransaction transaction (any storeNames, optional DOMString mode); 110 | void close (); 111 | [TreatNonCallableAsNull] 112 | attribute Function? onabort; 113 | [TreatNonCallableAsNull] 114 | attribute Function? onerror; 115 | [TreatNonCallableAsNull] 116 | attribute Function? onversionchange; 117 | }; 118 | 119 | 120 | /************************************** 121 | * 3.2.5 122 | **/ 123 | interface IDBObjectStore { 124 | readonly attribute DOMString name; 125 | readonly attribute DOMString keyPath; 126 | readonly attribute DOMStringList indexNames; 127 | readonly attribute IDBTransaction transaction; 128 | readonly attribute boolean autoIncremenent;; 129 | IDBRequest put (any value, optional any key); 130 | IDBRequest add (any value, optional any key); 131 | IDBRequest delete (any key); 132 | IDBRequest get (any key); 133 | IDBRequest clear (); 134 | IDBRequest openCursor (optional any? range, optional DOMString direction); 135 | IDBIndex createIndex (DOMString name, any keyPath, optional IDBIndexParameters optionalParameters); 136 | IDBIndex index (DOMString name); 137 | void deleteIndex (DOMString indexName); 138 | IDBRequest count (optional any key); 139 | }; 140 | 141 | 142 | /************************************** 143 | * 3.2.6 144 | **/ 145 | interface IDBIndex { 146 | readonly attribute DOMString name; 147 | readonly attribute IDBObjectStore objectStore; 148 | readonly attribute DOMString keyPath; 149 | readonly attribute boolean multiEntry; 150 | readonly attribute boolean unique; 151 | IDBRequest openCursor (optional any? range, optional DOMString direction); 152 | IDBRequest openKeyCursor (optional any? range, optional DOMString direction); 153 | IDBRequest get (any key); 154 | IDBRequest getKey (any key); 155 | IDBRequest count (optional any key); 156 | }; 157 | 158 | 159 | /************************************** 160 | * 3.2.7 161 | **/ 162 | interface IDBCursor { 163 | readonly attribute Object source; 164 | readonly attribute DOMString direction; 165 | readonly attribute any key; 166 | readonly attribute any primaryKey; 167 | IDBRequest update (any value); 168 | void advance ([EnforceRange] unsigned long count); 169 | void continue (optional any key); 170 | IDBRequest delete (); 171 | }; 172 | 173 | interface IDBCursorWithValue : IDBCursor { 174 | readonly attribute any value; 175 | }; 176 | 177 | 178 | /************************************** 179 | * 3.2.8 180 | **/ 181 | interface IDBTransaction : EventTarget { 182 | readonly attribute DOMString mode; 183 | readonly attribute IDBDatabase db; 184 | readonly attribute DOMError error; 185 | IDBObjectStore objectStore (DOMString name); 186 | void abort (); 187 | [TreatNonCallableAsNull] 188 | attribute Function? onabort; 189 | [TreatNonCallableAsNull] 190 | attribute Function? oncomplete; 191 | [TreatNonCallableAsNull] 192 | attribute Function? onerror; 193 | }; 194 | 195 | 196 | /************************************** 197 | * 3.3.1 198 | **/ 199 | WorkerUtils implements IDBEnvironmentSync; 200 | 201 | [NoInterfaceObject] 202 | interface IDBEnvironmentSync { 203 | readonly attribute IDBFactorySync indexedDBSync; 204 | }; 205 | 206 | interface IDBFactorySync { 207 | IDBDatabaseSync open (DOMString name, [EnforceRange] optional unsigned long long version, optional IDBVersionChangeCallback upgradeCallback, optional unsigned long timeout); 208 | void deleteDatabase (DOMString name); 209 | short cmp (any first, any second); 210 | }; 211 | 212 | 213 | /************************************** 214 | * 3.3.2 215 | **/ 216 | interface IDBDatabaseSync { 217 | readonly attribute DOMString name; 218 | readonly attribute unsigned long long version; 219 | readonly attribute DOMStringList objectStoreNames; 220 | IDBObjectStoreSync createObjectStore (DOMString name, optional IDBObjectStoreParameters optionalParameters); 221 | void deleteObjectStore (DOMString name); 222 | void transaction (any storeNames, IDBTransactionCallback callback, optional DOMString mode, optional unsigned long timeout); 223 | void close (); 224 | }; 225 | 226 | [NoInterfaceObject, Callback] 227 | interface IDBTransactionCallback { 228 | void transactionStarted (IDBTransactionSync transaction); 229 | }; 230 | 231 | [NoInterfaceObject, Callback] 232 | interface IDBVersionChangeCallback { 233 | void transactionStarted (IDBTransactionSync transaction, unsigned long long oldVersion); 234 | }; 235 | 236 | 237 | 238 | /************************************** 239 | * 3.3.3 240 | **/ 241 | interface IDBObjectStoreSync { 242 | readonly attribute DOMString name; 243 | readonly attribute any keyPath; 244 | readonly attribute DOMStringList indexNames; 245 | readonly attribute IDBTransactionSync transaction; 246 | readonly attribute boolean autoIncremenent;; 247 | any put (any value, optional any key); 248 | any add (any value, optional any key); 249 | boolean delete (any key); 250 | any get (any key); 251 | void clear (); 252 | IDBIndexSync createIndex (DOMString name, any keyPath, optional IDBIndexParameters optionalParameters); 253 | IDBIndexSync index (DOMString name); 254 | void deleteIndex (DOMString indexName); 255 | IDBCursorWithValueSync openCursor (optional any? range, optional DOMString direction); 256 | unsigned long count (optional any key); 257 | }; 258 | 259 | 260 | /************************************** 261 | * 3.3.4 262 | **/ 263 | interface IDBIndexSync { 264 | readonly attribute DOMString name; 265 | readonly attribute IDBObjectStoreSync objectStore; 266 | readonly attribute any keyPath; 267 | readonly attribute boolean multiEntry; 268 | readonly attribute boolean unique; 269 | IDBCursorWithValueSync openCursor (optional any? range, optional DOMString direction); 270 | IDBCursorSync openKeyCursor (optional any? range, optional DOMString direction); 271 | any get (any key); 272 | any getKey (any key); 273 | unsigned long count (optional any key); 274 | }; 275 | 276 | 277 | /************************************** 278 | * 3.3.5 279 | **/ 280 | interface IDBCursorSync { 281 | readonly attribute Object source; 282 | readonly attribute DOMString direction; 283 | readonly attribute any primaryKey; 284 | IDBRequest update (any value); 285 | boolean advance ([EnforceRange] unsigned long count); 286 | boolean continue (optional any key); 287 | boolean delete (); 288 | }; 289 | 290 | interface IDBCursorWithValueSync : IDBCursorSync { 291 | attribute any value; 292 | }; 293 | 294 | 295 | /************************************** 296 | * 3.3.6 297 | **/ 298 | interface IDBTransactionSync { 299 | readonly attribute DOMString mode; 300 | attribute IDBDatabaseSync db; 301 | readonly attribute DOMError error; 302 | IDBObjectStoreSync objectStore (DOMString name); 303 | void abort (); 304 | }; -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/IndexedDB/example/after.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/IndexedDB/example/before.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/QuotaAPI/after.idl: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Extracted from: 3 | * http://www.w3.org/TR/quota-api/ 4 | * 5 | * By running: 6 | * 7 | * Array.prototype.slice.call( 8 | * document.querySelectorAll(".idl,.es-code") 9 | * ).map(function(n) { return n.innerText; }).join("\n\n\n"); 10 | * 11 | **/ 12 | 13 | /************************************** 14 | * 4.1 15 | **/ 16 | interface StorageQuota { 17 | Future queryUsageAndQuota(in optional StorageUsageCallback successCallback, 18 | in optional StorageErrorCallback errorCallback); 19 | Future requestQuota (in unsigned long long newQuotaInBytes, 20 | in optional StorageQuotaCallback successCallback, 21 | in optional StorageErrorCallback errorCallback); 22 | }; 23 | 24 | /************************************** 25 | * 4.2 26 | **/ 27 | callback StorageUsageCallback = void (in unsigned long long currentUsageInBytes, 28 | in unsigned long long currentQuotaInBytes); 29 | 30 | /************************************** 31 | * 4.3 32 | **/ 33 | callback StorageQuotaCallback = void (in unsigned long long grantedQuotaInBytes); 34 | 35 | /************************************** 36 | * 4.4 37 | **/ 38 | callback StorageErrorCallback = void (in DOMError error); 39 | 40 | /************************************** 41 | * 4.5 42 | **/ 43 | [NoInterfaceObject] 44 | interface StorageQuotaEnvironment { 45 | readonly attribute StorageQuota persistentStorage; 46 | readonly attribute StorageQuota temporaryStorage; 47 | }; -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/QuotaAPI/before.idl: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Extracted from: 3 | * http://www.w3.org/TR/quota-api/ 4 | * 5 | * By running: 6 | * 7 | * Array.prototype.slice.call( 8 | * document.querySelectorAll(".idl,.es-code") 9 | * ).map(function(n) { return n.innerText; }).join("\n\n\n"); 10 | * 11 | **/ 12 | 13 | /************************************** 14 | * 4.1 15 | **/ 16 | interface StorageQuota { 17 | void queryUsageAndQuota (in StorageUsageCallback successCallback, 18 | in optional StorageErrorCallback errorCallback); 19 | void requestQuota (in unsigned long long newQuotaInBytes, 20 | in optional StorageQuotaCallback successCallback, 21 | in optional StorageErrorCallback errorCallback); 22 | }; 23 | 24 | /************************************** 25 | * 4.2 26 | **/ 27 | callback StorageUsageCallback = void (in unsigned long long currentUsageInBytes, 28 | in unsigned long long currentQuotaInBytes); 29 | 30 | /************************************** 31 | * 4.3 32 | **/ 33 | callback StorageQuotaCallback = void (in unsigned long long grantedQuotaInBytes); 34 | 35 | /************************************** 36 | * 4.4 37 | **/ 38 | callback StorageErrorCallback = void (in DOMError error); 39 | 40 | /************************************** 41 | * 4.5 42 | **/ 43 | [NoInterfaceObject] 44 | interface StorageQuotaEnvironment { 45 | readonly attribute StorageQuota persistentStorage; 46 | readonly attribute StorageQuota temporaryStorage; 47 | }; -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/WebCrypto/after.idl: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Extracted from: 3 | * http://www.w3.org/TR/WebCryptoAPI 4 | **/ 5 | 6 | /************************************** 7 | * 9 8 | **/ 9 | [NoInterfaceObject] 10 | interface RandomSource { 11 | ArrayBufferView getRandomValues(ArrayBufferView array); 12 | }; 13 | 14 | /************************************** 15 | * 10 16 | **/ 17 | // TBD: ISSUE-28 18 | typedef (Algorithm or DOMString) AlgorithmIdentifier; 19 | 20 | dictionary AlgorithmParameters { 21 | }; 22 | 23 | dictionary Algorithm { 24 | DOMString name; 25 | AlgorithmParameters params; 26 | }; 27 | 28 | /************************************** 29 | * 11 30 | **/ 31 | enum KeyType { 32 | "secret", 33 | "public", 34 | "private" 35 | }; 36 | 37 | enum KeyUsage { 38 | "encrypt", 39 | "decrypt", 40 | "sign", 41 | "verify", 42 | "derive" 43 | }; 44 | 45 | interface Key { 46 | readonly attribute KeyType type; 47 | readonly attribute bool extractable; 48 | readonly attribute Algorithm algorithm; 49 | readonly attribute KeyUsage[] keyUsage; 50 | }; 51 | 52 | /************************************** 53 | * 12 54 | **/ 55 | interface CryptoOperation : Future { 56 | // Both process() and finish() return this for chaining. 57 | CrytpoOperation process(ArrayBufferView buffer); 58 | CrytpoOperation finish(); 59 | void abort(); 60 | 61 | readonly attribute Key? key; 62 | readonly attribute Algorithm algorithm; 63 | readonly attribute any result; 64 | }; 65 | 66 | /************************************** 67 | * 13 68 | * 69 | * REMOVED: supplanted by Future 70 | **/ 71 | 72 | /************************************** 73 | * 14 74 | **/ 75 | enum KeyFormat { 76 | // An unformatted sequence of bytes. Intended for secret keys. 77 | "raw", 78 | // The DER encoding of the PrivateKeyInfo structure from RFC 5208. 79 | "pkcs8", 80 | // The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280. 81 | "spki", 82 | // The key is represented as JSON according to the JSON Web Key format. 83 | "jwk", 84 | }; 85 | 86 | interface Crypto { 87 | CryptoOperation encrypt(AlgorithmIdentifier algorithm, 88 | Key key, 89 | optional ArrayBufferView? buffer = null); 90 | CryptoOperation decrypt(AlgorithmIdentifier algorithm, 91 | Key key, 92 | optional ArrayBufferView? buffer = null); 93 | CryptoOperation sign(AlgorithmIdentifier algorithm, 94 | Key key, 95 | optional ArrayBufferView? buffer = null); 96 | CryptoOperation verify(AlgorithmIdentifier algorithm, 97 | Key key, 98 | ArrayBufferView signature, 99 | optional ArrayBufferView? buffer = null); 100 | CryptoOperation digest(AlgorithmIdentifier algorithm, 101 | optional ArrayBufferView? buffer = null); 102 | 103 | // TBD: ISSUE-36 104 | Future generateKey(AlgorithmIdentifier algorithm, 105 | bool extractable = false, 106 | KeyUsage[] keyUsages = []); 107 | 108 | Future deriveKey(AlgorithmIdentifier algorithm, 109 | Key baseKey, 110 | AlgorithmIdentifier? derivedKeyType, 111 | bool extractable = false, 112 | KeyUsage[] keyUsages = []); 113 | 114 | // TBD: ISSUE-35 115 | Future importKey(KeyFormat format, 116 | ArrayBufferView keyData, 117 | AlgorithmIdentifier? algorithm, 118 | bool extractable = false, 119 | KeyUsage[] keyUsages = []); 120 | 121 | Future exportKey(KeyFormat format, Key key); 122 | }; 123 | 124 | Crypto implements RandomSource; 125 | 126 | partial interface Window { 127 | readonly attribute Crypto crypto; 128 | }; 129 | 130 | /************************************** 131 | * 15 132 | **/ 133 | interface WorkerCrypto { 134 | }; 135 | 136 | WorkerCrypto implements RandomSource; 137 | 138 | partial interface WorkerGlobalScope { 139 | readonly attribute WorkerCrypto crypto; 140 | }; 141 | 142 | /************************************** 143 | * 16 144 | */ 145 | typedef Uint8Array BigInteger; 146 | 147 | 148 | /************************************** 149 | * 17 150 | **/ 151 | interface KeyPair { 152 | Key publicKey; 153 | Key privateKey; 154 | }; 155 | 156 | 157 | /************************************** 158 | * 19.3.3 159 | **/ 160 | dictionary RsaKeyGenParams : AlgorithmParameters { 161 | // The length, in bits, of the RSA modulus 162 | unsigned long modulusLength; 163 | // The RSA public exponent 164 | BigInteger publicExponent; 165 | }; 166 | 167 | /************************************** 168 | * 19.4.3 169 | **/ 170 | dictionary RsaSsaParams : AlgorithmParameters { 171 | // The hash algorithm to use 172 | AlgorithmIdentifier hash; 173 | }; 174 | 175 | /************************************** 176 | * 19.5.3 177 | **/ 178 | dictionary RsaPssParams : AlgorithmParameters { 179 | // The hash function to apply to the message 180 | AlgorithmIdentifier hash; 181 | // The mask generation function 182 | AlgorithmIdentifier mgf; 183 | // The desired length of the random salt 184 | unsigned long saltLength; 185 | }; 186 | 187 | /************************************** 188 | * 19.6.3 189 | **/ 190 | dictionary RsaOaepParams : AlgorithmParameters { 191 | // The hash function to apply to the message 192 | AlgorithmIdentifier hash; 193 | // The mask generation function 194 | AlgorithmIdentifier mgf; 195 | // The optional label/application data to associate with the message 196 | ArrayBufferView? label; 197 | }; 198 | 199 | /************************************** 200 | * 19.7.3 201 | **/ 202 | dictionary EcdsaParams : AlgorithmParameters { 203 | // The hash algorithm to use 204 | AlgorithmIdentifier hash; 205 | }; 206 | enum NamedCurve { 207 | // NIST recommended curve P-256, also known as secp256r1. 208 | "P-256", 209 | // NIST recommended curve P-384, also known as secp384r1. 210 | "P-384", 211 | // NIST recommended curve P-521, also known as secp521r1. 212 | "P-521" 213 | }; 214 | 215 | /************************************** 216 | * 19.7.4 217 | **/ 218 | dictionary EcKeyGenParams : AlgorithmParameters { 219 | // A named curve 220 | NamedCurve namedCurve; 221 | }; 222 | 223 | /************************************** 224 | * 19.8.3 225 | **/ 226 | typedef Uint8Array ECPoint; 227 | 228 | dictionary EcdhKeyDeriveParams : AlgorithmParameters { 229 | // The peer's EC public key. 230 | ECPoint public; 231 | }; 232 | 233 | /************************************** 234 | * 19.9.3 235 | **/ 236 | dictionary AesCtrParams : AlgorithmParameters { 237 | // The initial value of the counter block. counter MUST be 16 bytes 238 | // (the AES block size). The counter bits are the rightmost length 239 | // bits of the counter block. The rest of the counter block is for 240 | // the nonce. The counter bits are incremented using the standard 241 | // incrementing function specified in NIST SP 800-38A Appendix B.1: 242 | // the counter bits are interpreted as a big-endian integer and 243 | // incremented by one. 244 | ArrayBuffer counter; 245 | // The length, in bits, of the rightmost part of the counter block 246 | // that is incremented. 247 | [EnforceRange] octet length; 248 | }; 249 | 250 | /************************************** 251 | * 19.9.4 252 | **/ 253 | dictionary AesKeyGenParams : AlgorithmParameters { 254 | // The length, in bits, of the key. 255 | [EnforceRange] unsigned short length; 256 | }; 257 | 258 | /************************************** 259 | * 19.10.3 260 | **/ 261 | dictionary AesCbcParams : AlgorithmParameters { 262 | // The initialization vector. MUST be 16 bytes. 263 | ArrayBufferView iv; 264 | }; 265 | 266 | /************************************** 267 | * 19.11.3 268 | **/ 269 | dictionary AesGcmParams : AlgorithmParameters { 270 | // The initialization vector to use. May be up to 2^56 bytes long. 271 | ArrayBufferView? iv; 272 | // The additional authentication data to include. 273 | ArrayBufferView? additionalData; 274 | // The desired length of the authentication tag. May be 0 - 128. 275 | [EnforceRange] octet? tagLength = 0; 276 | }; 277 | 278 | /************************************** 279 | * 19.12.3 280 | **/ 281 | dictionary HmacParams : AlgorithmParameters { 282 | // The inner hash function to use. 283 | AlgorithmIdentifier hash; 284 | }; 285 | 286 | /************************************** 287 | * 19.13.3 288 | **/ 289 | dictionary DhKeyGenParams : AlgorithmParameters { 290 | // The prime p. 291 | BigInteger prime; 292 | // The base g. 293 | BigInteger generator; 294 | }; 295 | 296 | /************************************** 297 | * 19.13.4 298 | **/ 299 | dictionary DhKeyDeriveParams : AlgorithmParameters { 300 | // The peer's public value. 301 | BigInteger public; 302 | }; 303 | 304 | /************************************** 305 | * 19.15.4 306 | **/ 307 | dictionary ConcatParams : AlgorithmParameters { 308 | // The digest method to use to derive the keying material. 309 | AlgorithmIdentifier hash; 310 | 311 | // A bit string corresponding to the AlgorithmId field of the OtherInfo parameter. 312 | // The AlgorithmId indicates how the derived keying material will be parsed and for which 313 | // algorithm(s) the derived secret keying material will be used. 314 | ArrayBufferView algorithmId; 315 | 316 | // A bit string that corresponds to the PartyUInfo field of the OtherInfo parameter. 317 | ArrayBufferView partyUInfo; 318 | // A bit string that corresponds to the PartyVInfo field of the OtherInfo parameter. 319 | ArrayBufferView partyVInfo; 320 | // An optional bit string that corresponds to the SuppPubInfo field of the OtherInfo parameter. 321 | ArrayBufferView? publicInfo; 322 | // An optional bit string that corresponds to the SuppPrivInfo field of the OtherInfo parameter. 323 | ArrayBufferView? privateInfo; 324 | }; 325 | 326 | /************************************** 327 | * 19.16.3 328 | **/ 329 | dictionary Pbkdf2Params : AlgorithmParameters { 330 | ArrayBufferView salt; 331 | [Clamp] unsigned long iterations; 332 | AlgorithmIdentifier prf; 333 | ArrayBufferView? password; 334 | } 335 | 336 | /************************************** 337 | * 21.1 338 | 339 | // Algorithm Object 340 | var algorithmKeyGen = { 341 | name: "RSASSA-PKCS1-v1_5", 342 | // RsaKeyGenParams 343 | params: { 344 | modulusLength: 2048, 345 | publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537 346 | } 347 | }; 348 | 349 | var algorithmSign = { 350 | name: "RSASSA-PKCS1-v1_5", 351 | // RsaSsaParams 352 | params: { 353 | hash: { 354 | name: "SHA-256", 355 | } 356 | } 357 | }; 358 | 359 | window.crypto.generateKey(algorithmKeyGen, false, ["sign"]).done( 360 | function(key) { 361 | var dataPart1 = convertPlainTextToArrayBufferView("hello,"); 362 | var dataPart2 = convertPlainTextToArrayBufferView(" world!"); 363 | // TODO: create example utility function that converts text -> ArrayBufferView 364 | 365 | // Because we are not supplying data to .sign(), a multi-part 366 | // CryptoOperation will be returned, which requires us to call .process() 367 | // and .finish(). 368 | window.crypt.sign(algorithmSign, key.privateKey) 369 | .process(dataPart1) 370 | .process(dataPart2) 371 | .finish() 372 | .done(console.log.bind(console, "The signature is: "), 373 | console.error.bind(console, "Unable to sign")); 374 | }, 375 | console.error.bind(console, "Unable to generate a key:") 376 | ); 377 | **/ 378 | 379 | /************************************** 380 | * 21.2 381 | var clearDataArrayBufferView = convertPlainTextToArrayBufferView("Plain Text Data"); 382 | // TODO: create example utility function that converts text -> ArrayBufferView 383 | 384 | var aesAlgorithmKeyGen = { 385 | name: "AES-CBC", 386 | // AesKeyGenParams 387 | params: { 388 | length: 128 389 | } 390 | }; 391 | 392 | var aesAlgorithmEncrypt = { 393 | name: "AES-CBC", 394 | // AesCbcParams 395 | params: { 396 | iv: window.crypto.getRandomValues(new Uint8Array(16)) 397 | } 398 | }; 399 | 400 | // Create a keygenerator to produce a one-time-use AES key to encrypt some data 401 | window.crypto.generateKey(aesAlgorithmKeyGen, false, ["encrypt"]).done( 402 | function(aesKey) { // A new, random AES key has been generated. 403 | // Unlike the signing example, which showed multi-part encryption, here we 404 | // will perform the entire AES operation in a single call. 405 | window.crypto.encrypt(aesAlgorithmEncrypt, 406 | aesKey, 407 | clearDataArrayBufferView) 408 | .done( 409 | function(cipherText) { 410 | console.log("Ciphertext is:", cipherText); 411 | }, 412 | console.error.bind(console, "Unable to AES encrypt."); 413 | ); 414 | } 415 | ); 416 | 417 | **/ 418 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/WebCrypto/before.idl: -------------------------------------------------------------------------------- 1 | /************************************** 2 | * Extracted from: 3 | * http://www.w3.org/TR/WebCryptoAPI 4 | **/ 5 | 6 | /************************************** 7 | * 9 8 | **/ 9 | [NoInterfaceObject] 10 | interface RandomSource { 11 | ArrayBufferView getRandomValues(ArrayBufferView array); 12 | }; 13 | 14 | /************************************** 15 | * 10 16 | **/ 17 | // TBD: ISSUE-28 18 | typedef (Algorithm or DOMString) AlgorithmIdentifier; 19 | 20 | dictionary AlgorithmParameters { 21 | }; 22 | 23 | dictionary Algorithm { 24 | DOMString name; 25 | AlgorithmParameters params; 26 | }; 27 | 28 | /************************************** 29 | * 11 30 | **/ 31 | enum KeyType { 32 | "secret", 33 | "public", 34 | "private" 35 | }; 36 | 37 | enum KeyUsage { 38 | "encrypt", 39 | "decrypt", 40 | "sign", 41 | "verify", 42 | "derive" 43 | }; 44 | 45 | interface Key { 46 | readonly attribute KeyType type; 47 | readonly attribute bool extractable; 48 | readonly attribute Algorithm algorithm; 49 | readonly attribute KeyUsage[] keyUsage; 50 | }; 51 | 52 | /************************************** 53 | * 12 54 | **/ 55 | interface CryptoOperation : EventTarget { 56 | void process(ArrayBufferView buffer); 57 | void finish(); 58 | void abort(); 59 | 60 | readonly attribute Key? key; 61 | readonly attribute Algorithm algorithm; 62 | readonly attribute any result; 63 | 64 | [TreatNonCallableasNull] attribute Function? onabort; 65 | [TreatNonCallableAsNull] attribute Function? onerror; 66 | [TreatNonCallableAsNull] attribute Function? onprogress; 67 | [TreatNonCallableAsNull] attribute Function? oncomplete; 68 | }; 69 | 70 | /************************************** 71 | * 13 72 | **/ 73 | interface KeyOperation : EventTarget { 74 | readonly attribute any result; 75 | 76 | [TreatNonCallableAsNull] attribute Function? onerror; 77 | [TreatNonCallableAsNull] attribute Function? oncomplete; 78 | }; 79 | 80 | /************************************** 81 | * 14 82 | **/ 83 | enum KeyFormat { 84 | // An unformatted sequence of bytes. Intended for secret keys. 85 | "raw", 86 | // The DER encoding of the PrivateKeyInfo structure from RFC 5208. 87 | "pkcs8", 88 | // The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280. 89 | "spki", 90 | // The key is represented as JSON according to the JSON Web Key format. 91 | "jwk", 92 | }; 93 | 94 | interface Crypto { 95 | CryptoOperation encrypt(AlgorithmIdentifier algorithm, 96 | Key key, 97 | optional ArrayBufferView? buffer = null); 98 | CryptoOperation decrypt(AlgorithmIdentifier algorithm, 99 | Key key, 100 | optional ArrayBufferView? buffer = null); 101 | CryptoOperation sign(AlgorithmIdentifier algorithm, 102 | Key key, 103 | optional ArrayBufferView? buffer = null); 104 | CryptoOperation verify(AlgorithmIdentifier algorithm, 105 | Key key, 106 | ArrayBufferView signature, 107 | optional ArrayBufferView? buffer = null); 108 | CryptoOperation digest(AlgorithmIdentifier algorithm, 109 | optional ArrayBufferView? buffer = null); 110 | 111 | // TBD: ISSUE-36 112 | KeyOperation generateKey(AlgorithmIdentifier algorithm, 113 | bool extractable = false, 114 | KeyUsage[] keyUsages = []); 115 | KeyOperation deriveKey(AlgorithmIdentifier algorithm, 116 | Key baseKey, 117 | AlgorithmIdentifier? derivedKeyType, 118 | bool extractable = false, 119 | KeyUsage[] keyUsages = []); 120 | 121 | // TBD: ISSUE-35 122 | KeyOperation importKey(KeyFormat format, 123 | ArrayBufferView keyData, 124 | AlgorithmIdentifier? algorithm, 125 | bool extractable = false, 126 | KeyUsage[] keyUsages = []); 127 | KeyOperation exportKey(KeyFormat format, Key key); 128 | }; 129 | 130 | Crypto implements RandomSource; 131 | 132 | partial interface Window { 133 | readonly attribute Crypto crypto; 134 | }; 135 | 136 | /************************************** 137 | * 15 138 | **/ 139 | interface WorkerCrypto { 140 | }; 141 | 142 | WorkerCrypto implements RandomSource; 143 | 144 | partial interface WorkerGlobalScope { 145 | readonly attribute WorkerCrypto crypto; 146 | }; 147 | 148 | /************************************** 149 | * 16 150 | */ 151 | typedef Uint8Array BigInteger; 152 | 153 | 154 | /************************************** 155 | * 17 156 | **/ 157 | interface KeyPair { 158 | Key publicKey; 159 | Key privateKey; 160 | }; 161 | 162 | 163 | /************************************** 164 | * 19.3.3 165 | **/ 166 | dictionary RsaKeyGenParams : AlgorithmParameters { 167 | // The length, in bits, of the RSA modulus 168 | unsigned long modulusLength; 169 | // The RSA public exponent 170 | BigInteger publicExponent; 171 | }; 172 | 173 | /************************************** 174 | * 19.4.3 175 | **/ 176 | dictionary RsaSsaParams : AlgorithmParameters { 177 | // The hash algorithm to use 178 | AlgorithmIdentifier hash; 179 | }; 180 | 181 | /************************************** 182 | * 19.5.3 183 | **/ 184 | dictionary RsaPssParams : AlgorithmParameters { 185 | // The hash function to apply to the message 186 | AlgorithmIdentifier hash; 187 | // The mask generation function 188 | AlgorithmIdentifier mgf; 189 | // The desired length of the random salt 190 | unsigned long saltLength; 191 | }; 192 | 193 | /************************************** 194 | * 19.6.3 195 | **/ 196 | dictionary RsaOaepParams : AlgorithmParameters { 197 | // The hash function to apply to the message 198 | AlgorithmIdentifier hash; 199 | // The mask generation function 200 | AlgorithmIdentifier mgf; 201 | // The optional label/application data to associate with the message 202 | ArrayBufferView? label; 203 | }; 204 | 205 | /************************************** 206 | * 19.7.3 207 | **/ 208 | dictionary EcdsaParams : AlgorithmParameters { 209 | // The hash algorithm to use 210 | AlgorithmIdentifier hash; 211 | }; 212 | enum NamedCurve { 213 | // NIST recommended curve P-256, also known as secp256r1. 214 | "P-256", 215 | // NIST recommended curve P-384, also known as secp384r1. 216 | "P-384", 217 | // NIST recommended curve P-521, also known as secp521r1. 218 | "P-521" 219 | }; 220 | 221 | /************************************** 222 | * 19.7.4 223 | **/ 224 | dictionary EcKeyGenParams : AlgorithmParameters { 225 | // A named curve 226 | NamedCurve namedCurve; 227 | }; 228 | 229 | /************************************** 230 | * 19.8.3 231 | **/ 232 | typedef Uint8Array ECPoint; 233 | 234 | dictionary EcdhKeyDeriveParams : AlgorithmParameters { 235 | // The peer's EC public key. 236 | ECPoint public; 237 | }; 238 | 239 | /************************************** 240 | * 19.9.3 241 | **/ 242 | dictionary AesCtrParams : AlgorithmParameters { 243 | // The initial value of the counter block. counter MUST be 16 bytes 244 | // (the AES block size). The counter bits are the rightmost length 245 | // bits of the counter block. The rest of the counter block is for 246 | // the nonce. The counter bits are incremented using the standard 247 | // incrementing function specified in NIST SP 800-38A Appendix B.1: 248 | // the counter bits are interpreted as a big-endian integer and 249 | // incremented by one. 250 | ArrayBuffer counter; 251 | // The length, in bits, of the rightmost part of the counter block 252 | // that is incremented. 253 | [EnforceRange] octet length; 254 | }; 255 | 256 | /************************************** 257 | * 19.9.4 258 | **/ 259 | dictionary AesKeyGenParams : AlgorithmParameters { 260 | // The length, in bits, of the key. 261 | [EnforceRange] unsigned short length; 262 | }; 263 | 264 | /************************************** 265 | * 19.10.3 266 | **/ 267 | dictionary AesCbcParams : AlgorithmParameters { 268 | // The initialization vector. MUST be 16 bytes. 269 | ArrayBufferView iv; 270 | }; 271 | 272 | /************************************** 273 | * 19.11.3 274 | **/ 275 | dictionary AesGcmParams : AlgorithmParameters { 276 | // The initialization vector to use. May be up to 2^56 bytes long. 277 | ArrayBufferView? iv; 278 | // The additional authentication data to include. 279 | ArrayBufferView? additionalData; 280 | // The desired length of the authentication tag. May be 0 - 128. 281 | [EnforceRange] octet? tagLength = 0; 282 | }; 283 | 284 | /************************************** 285 | * 19.12.3 286 | **/ 287 | dictionary HmacParams : AlgorithmParameters { 288 | // The inner hash function to use. 289 | AlgorithmIdentifier hash; 290 | }; 291 | 292 | /************************************** 293 | * 19.13.3 294 | **/ 295 | dictionary DhKeyGenParams : AlgorithmParameters { 296 | // The prime p. 297 | BigInteger prime; 298 | // The base g. 299 | BigInteger generator; 300 | }; 301 | 302 | /************************************** 303 | * 19.13.4 304 | **/ 305 | dictionary DhKeyDeriveParams : AlgorithmParameters { 306 | // The peer's public value. 307 | BigInteger public; 308 | }; 309 | 310 | /************************************** 311 | * 19.15.4 312 | **/ 313 | dictionary ConcatParams : AlgorithmParameters { 314 | // The digest method to use to derive the keying material. 315 | AlgorithmIdentifier hash; 316 | 317 | // A bit string corresponding to the AlgorithmId field of the OtherInfo parameter. 318 | // The AlgorithmId indicates how the derived keying material will be parsed and for which 319 | // algorithm(s) the derived secret keying material will be used. 320 | ArrayBufferView algorithmId; 321 | 322 | // A bit string that corresponds to the PartyUInfo field of the OtherInfo parameter. 323 | ArrayBufferView partyUInfo; 324 | // A bit string that corresponds to the PartyVInfo field of the OtherInfo parameter. 325 | ArrayBufferView partyVInfo; 326 | // An optional bit string that corresponds to the SuppPubInfo field of the OtherInfo parameter. 327 | ArrayBufferView? publicInfo; 328 | // An optional bit string that corresponds to the SuppPrivInfo field of the OtherInfo parameter. 329 | ArrayBufferView? privateInfo; 330 | }; 331 | 332 | /************************************** 333 | * 19.16.3 334 | **/ 335 | dictionary Pbkdf2Params : AlgorithmParameters { 336 | ArrayBufferView salt; 337 | [Clamp] unsigned long iterations; 338 | AlgorithmIdentifier prf; 339 | ArrayBufferView? password; 340 | } 341 | 342 | /************************************** 343 | * 21.1 344 | 345 | // Algorithm Object 346 | var algorithmKeyGen = { 347 | name: "RSASSA-PKCS1-v1_5", 348 | // RsaKeyGenParams 349 | params: { 350 | modulusLength: 2048, 351 | publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537 352 | } 353 | }; 354 | 355 | var algorithmSign = { 356 | name: "RSASSA-PKCS1-v1_5", 357 | // RsaSsaParams 358 | params: { 359 | hash: { 360 | name: "SHA-256", 361 | } 362 | } 363 | }; 364 | 365 | var keyGen = window.crypto.generateKey(algorithmKeyGen, 366 | false, // extractable 367 | ["sign"]); 368 | 369 | keyGen.oncomplete = function(event) { 370 | // Because we are not supplying data to .sign(), a multi-part 371 | // CryptoOperation will be returned, which requires us to call .process() 372 | // and .finish(). 373 | var signer = window.crypt.sign(algorithmSign, event.target.result.privateKey); 374 | signer.oncomplete = function(event) { 375 | console.log("The signature is: " + event.target.result); 376 | } 377 | signer.onerror = function(event) { 378 | console.error("Unable to sign"); 379 | } 380 | 381 | var dataPart1 = convertPlainTextToArrayBufferView("hello,"); 382 | var dataPart2 = convertPlainTextToArrayBufferView(" world!"); 383 | // TODO: create example utility function that converts text -> ArrayBufferView 384 | 385 | signer.process(dataPart1); 386 | signer.process(dataPart2); 387 | signer.finish(); 388 | }; 389 | 390 | keyGen.onerror = function(event) { 391 | console.error("Unable to generate a key."); 392 | }; 393 | 394 | **/ 395 | 396 | /************************************** 397 | * 21.2 398 | var clearDataArrayBufferView = convertPlainTextToArrayBufferView("Plain Text Data"); 399 | // TODO: create example utility function that converts text -> ArrayBufferView 400 | 401 | var aesAlgorithmKeyGen = { 402 | name: "AES-CBC", 403 | // AesKeyGenParams 404 | params: { 405 | length: 128 406 | } 407 | }; 408 | 409 | var aesAlgorithmEncrypt = { 410 | name: "AES-CBC", 411 | // AesCbcParams 412 | params: { 413 | iv: window.crypto.getRandomValues(new Uint8Array(16)) 414 | } 415 | }; 416 | 417 | // Create a keygenerator to produce a one-time-use AES key to encrypt some data 418 | var cryptoKeyGen = window.crypto.generateKey(aesAlgorithmKeyGen, 419 | false, // extractable 420 | ["encrypt"]); 421 | 422 | cryptoKeyGen.oncomplete = function(event) { 423 | // A new, random AES key has been generated. 424 | var aesKey = event.target.result; 425 | 426 | // Unlike the signing example, which showed multi-part encryption, here we 427 | // will perform the entire AES operation in a single call. 428 | var aesOp = window.crypto.encrypt(aesAlgorithmEncrypt, aesKey, clearDataArrayBufferView); 429 | aesOp.oncomplete = function(event) { 430 | // The clearData has been encrypted. 431 | var ciphertext = event.target.result; // ArrayBufferView 432 | }; 433 | aesOp.onerror = function(event) { 434 | console.error("Unable to AES encrypt."); 435 | }; 436 | }; 437 | 438 | **/ 439 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/WebCrypto/example/after.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/WebCrypto/example/before.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/WebMIDI/after.idl: -------------------------------------------------------------------------------- 1 | partial interface Navigator { 2 | Future requestMIDIAccess (optional boolean systemExclusiveSupportRequested = false ); 3 | }; 4 | 5 | interface MIDIAccess : EventTarget { 6 | sequence getInputs (); 7 | sequence getOutputs (); 8 | MIDIInput getInput (MIDIPort or DOMString or short target); 9 | MIDIOutput getOutput (MIDIPort or DOMString or short target); 10 | attribute EventHandler onconnect; 11 | attribute EventHandler ondisconnect; 12 | }; 13 | 14 | enum MIDIPortType { 15 | "input", 16 | "output" 17 | }; 18 | 19 | interface MIDIPort : EventTarget { 20 | readonly attribute DOMString id; 21 | readonly attribute DOMString? manufacturer; 22 | readonly attribute DOMString? name; 23 | readonly attribute MIDIPortType type; 24 | readonly attribute DOMString? version; 25 | attribute EventHandler ondisconnect; 26 | }; 27 | 28 | interface MIDIInput : MIDIPort { 29 | attribute EventHandler onmessage; 30 | }; 31 | 32 | interface MIDIOutput : MIDIPort { 33 | void send (sequence data, optional double timestamp); 34 | }; 35 | 36 | interface MIDIMessageEvent : Event { 37 | readonly attribute double receivedTime; 38 | readonly attribute Uint8Array data; 39 | }; 40 | 41 | interface MIDIConnectionEvent : Event { 42 | readonly attribute MIDIPort port; 43 | }; 44 | -------------------------------------------------------------------------------- /historical_interest/reworked_APIs/WebMIDI/before.idl: -------------------------------------------------------------------------------- 1 | partial interface Navigator { 2 | void requestMIDIAccess (SuccessCallback successCallback, optional ErrorCallback errorCallback, optional boolean systemExclusiveSupportRequested = false ); 3 | }; 4 | 5 | 6 | callback SuccessCallback = void (MIDIAccess access, boolean systemExclusiveAllowed); 7 | 8 | 9 | callback ErrorCallback = void (DOMError error); 10 | 11 | 12 | interface MIDIAccess : EventTarget { 13 | sequence getInputs (); 14 | sequence getOutputs (); 15 | MIDIInput getInput (MIDIPort or DOMString or short target); 16 | MIDIOutput getOutput (MIDIPort or DOMString or short target); 17 | attribute EventHandler onconnect; 18 | attribute EventHandler ondisconnect; 19 | }; 20 | 21 | 22 | enum MIDIPortType { 23 | "input", 24 | "output" 25 | }; 26 | 27 | 28 | interface MIDIPort : EventTarget { 29 | readonly attribute DOMString id; 30 | readonly attribute DOMString? manufacturer; 31 | readonly attribute DOMString? name; 32 | readonly attribute MIDIPortType type; 33 | readonly attribute DOMString? version; 34 | attribute EventHandler ondisconnect; 35 | }; 36 | 37 | 38 | interface MIDIInput : MIDIPort { 39 | attribute EventHandler onmessage; 40 | }; 41 | 42 | 43 | interface MIDIOutput : MIDIPort { 44 | void send (sequence data, optional double timestamp); 45 | }; 46 | 47 | 48 | interface MIDIMessageEvent : Event { 49 | readonly attribute double receivedTime; 50 | readonly attribute Uint8Array data; 51 | }; 52 | 53 | 54 | interface MIDIConnectionEvent : Event { 55 | readonly attribute MIDIPort port; 56 | }; 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DOMFuture", 3 | "description": "", 4 | "author": "Alex Russell ", 5 | "version" : "0.0.1", 6 | "license": "...", 7 | "main": "./bin/Promise.min.js", 8 | "url": "https://github.com/slightlyoff/Promises", 9 | "repository" : { 10 | "type" : "git", 11 | "url" : "https://github.com/slightlyoff/Promises.git" 12 | }, 13 | "contributors": [ 14 | { 15 | "name": "Alex Russell", 16 | "email": "slightlyoff@chromium.org", 17 | "url": "http://infrequently.org" 18 | } 19 | ], 20 | "scripts": { 21 | "test": "cd tests; node test.js && node promises-tests.js" 22 | }, 23 | "dependencies": { 24 | }, 25 | "devDependencies": { 26 | "eval" : "*", 27 | "filemap": "*" 28 | }, 29 | "engines" : { "node" : ">=0.8.x" } 30 | } 31 | -------------------------------------------------------------------------------- /src/Promise.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013: 2 | // Alex Russell 3 | // Yehuda Katz 4 | // 5 | // Use of this source code is governed by 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | // FIXME(slightlyoff): 9 | // - Document "npm test" 10 | // - Change global name from "Promise" to something less conflicty 11 | (function(global, browserGlobal, underTest) { 12 | "use strict"; 13 | 14 | // FIXME(slighltyoff): 15 | // * aggregates + tests 16 | // * check on fast-forwarding 17 | 18 | underTest = !!underTest; 19 | 20 | // 21 | // Async Utilities 22 | // 23 | 24 | // Borrowed from RSVP.js 25 | var async; 26 | 27 | var MutationObserver = browserGlobal.MutationObserver || 28 | browserGlobal.WebKitMutationObserver; 29 | var Promise; 30 | 31 | if (typeof process !== 'undefined' && 32 | {}.toString.call(process) === '[object process]') { 33 | async = function(callback, binding) { 34 | process.nextTick(function() { 35 | callback.call(binding); 36 | }); 37 | }; 38 | } else if (MutationObserver) { 39 | var queue = []; 40 | 41 | var observer = new MutationObserver(function() { 42 | var toProcess = queue.slice(); 43 | queue = []; 44 | toProcess.forEach(function(tuple) { 45 | tuple[0].call(tuple[1]); 46 | }); 47 | }); 48 | 49 | var element = document.createElement('div'); 50 | observer.observe(element, { attributes: true }); 51 | 52 | // Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661 53 | window.addEventListener('unload', function(){ 54 | observer.disconnect(); 55 | observer = null; 56 | }); 57 | 58 | async = function(callback, binding) { 59 | queue.push([callback, binding]); 60 | element.setAttribute('drainQueue', 'drainQueue'); 61 | }; 62 | } else { 63 | async = function(callback, binding) { 64 | setTimeout(function() { 65 | callback.call(binding); 66 | }, 1); 67 | }; 68 | } 69 | 70 | // 71 | // Object Model Utilities 72 | // 73 | 74 | // defineProperties utilities 75 | var _readOnlyProperty = function(v) { 76 | return { 77 | enumerable: true, 78 | configurable: false, 79 | get: v 80 | }; 81 | }; 82 | 83 | var _method = function(v, e, c, w) { 84 | return { 85 | enumerable: !!(e || 0), 86 | configurable: !!(c || 1), 87 | writable: !!(w || 1), 88 | value: v || function() {} 89 | }; 90 | }; 91 | 92 | var _pseudoPrivate = function(v) { return _method(v, 0, 1, 0); }; 93 | var _public = function(v) { return _method(v, 1); }; 94 | 95 | // 96 | // Promises Utilities 97 | // 98 | 99 | var isThenable = function(any) { 100 | try { 101 | var f = any.then; 102 | if (typeof f == "function") { 103 | return true; 104 | } 105 | } catch (e) { /*squelch*/ } 106 | return false; 107 | }; 108 | 109 | var AlreadyResolved = function(name) { 110 | Error.call(this, name); 111 | }; 112 | AlreadyResolved.prototype = Object.create(Error.prototype); 113 | 114 | var Backlog = function() { 115 | var bl = []; 116 | bl.pump = function(value) { 117 | async(function() { 118 | var l = bl.length; 119 | var x = 0; 120 | while(x < l) { 121 | x++; 122 | bl.shift()(value); 123 | } 124 | }); 125 | }; 126 | return bl; 127 | }; 128 | 129 | // 130 | // Resolver Constuctor 131 | // 132 | 133 | var Resolver = function(future, 134 | fulfillCallbacks, 135 | rejectCallbacks, 136 | setValue, 137 | setError, 138 | setState) { 139 | var isResolved = false; 140 | 141 | var resolver = this; 142 | var fulfill = function(value) { 143 | // console.log("queueing fulfill with:", value); 144 | async(function() { 145 | setState("fulfilled"); 146 | setValue(value); 147 | // console.log("fulfilling with:", value); 148 | fulfillCallbacks.pump(value); 149 | }); 150 | }; 151 | var reject = function(reason) { 152 | // console.log("queuing reject with:", reason); 153 | async(function() { 154 | setState("rejected"); 155 | setError(reason); 156 | // console.log("rejecting with:", reason); 157 | rejectCallbacks.pump(reason); 158 | }); 159 | }; 160 | var resolve = function(value) { 161 | if (isThenable(value)) { 162 | value.then(resolve, reject); 163 | return; 164 | } 165 | fulfill(value); 166 | }; 167 | var ifNotResolved = function(func, name) { 168 | return function(value) { 169 | if (!isResolved) { 170 | isResolved = true; 171 | func(value); 172 | } else { 173 | if (typeof console != "undefined") { 174 | console.error("Cannot resolve a Promise multiple times."); 175 | } 176 | } 177 | }; 178 | }; 179 | 180 | // Indirectly resolves the Promise, chaining any passed Promise's resolution 181 | this.resolve = ifNotResolved(resolve, "resolve"); 182 | 183 | // Directly fulfills the future, no matter what value's type is 184 | this.fulfill = ifNotResolved(fulfill, "fulfill"); 185 | 186 | // Rejects the future 187 | this.reject = ifNotResolved(reject, "reject"); 188 | 189 | this.cancel = function() { resolver.reject(new Error("Cancel")); }; 190 | this.timeout = function() { resolver.reject(new Error("Timeout")); }; 191 | 192 | if (underTest) { 193 | Object.defineProperties(this, { 194 | _isResolved: _readOnlyProperty(function() { return isResolved; }), 195 | }); 196 | } 197 | 198 | setState("pending"); 199 | }; 200 | 201 | // 202 | // Promise Constuctor 203 | // 204 | 205 | var Promise = function(init) { 206 | var fulfillCallbacks = new Backlog(); 207 | var rejectCallbacks = new Backlog(); 208 | var value; 209 | var error; 210 | var state = "pending"; 211 | 212 | if (underTest) { 213 | Object.defineProperties(this, { 214 | _value: _readOnlyProperty(function() { return value; }), 215 | _error: _readOnlyProperty(function() { return error; }), 216 | _state: _readOnlyProperty(function() { return state; }), 217 | }); 218 | } 219 | 220 | Object.defineProperties(this, { 221 | _addAcceptCallback: _pseudoPrivate( 222 | function(cb) { 223 | // console.log("adding fulfill callback:", cb); 224 | fulfillCallbacks.push(cb); 225 | if (state == "fulfilled") { 226 | fulfillCallbacks.pump(value); 227 | } 228 | } 229 | ), 230 | _addRejectCallback: _pseudoPrivate( 231 | function(cb) { 232 | // console.log("adding reject callback:", cb); 233 | rejectCallbacks.push(cb); 234 | if (state == "rejected") { 235 | rejectCallbacks.pump(error); 236 | } 237 | } 238 | ), 239 | }); 240 | var r = new Resolver(this, 241 | fulfillCallbacks, rejectCallbacks, 242 | function(v) { value = v; }, 243 | function(e) { error = e; }, 244 | function(s) { state = s; }) 245 | try { 246 | if (init) { init(r); } 247 | } catch(e) { 248 | r.reject(e); 249 | } 250 | }; 251 | 252 | // 253 | // Consructor 254 | // 255 | 256 | var isCallback = function(any) { 257 | return (typeof any == "function"); 258 | }; 259 | 260 | // Used in .then() 261 | var wrap = function(callback, resolver, disposition) { 262 | if (!isCallback(callback)) { 263 | // If we don't get a callback, we want to forward whatever resolution we get 264 | return resolver[disposition].bind(resolver); 265 | } 266 | 267 | return function() { 268 | try { 269 | var r = callback.apply(null, arguments); 270 | resolver.resolve(r); 271 | } catch(e) { 272 | // Exceptions reject the resolver 273 | resolver.reject(e); 274 | } 275 | }; 276 | }; 277 | 278 | var addCallbacks = function(onfulfill, onreject, scope) { 279 | if (isCallback(onfulfill)) { 280 | scope._addAcceptCallback(onfulfill); 281 | } 282 | if (isCallback(onreject)) { 283 | scope._addRejectCallback(onreject); 284 | } 285 | return scope; 286 | }; 287 | 288 | // 289 | // Prototype properties 290 | // 291 | 292 | Promise.prototype = Object.create(null, { 293 | "then": _public(function(onfulfill, onreject) { 294 | // The logic here is: 295 | // We return a new Promise whose resolution merges with the return from 296 | // onfulfill() or onerror(). If onfulfill() returns a Promise, we forward 297 | // the resolution of that future to the resolution of the returned 298 | // Promise. 299 | var f = this; 300 | return new Promise(function(r) { 301 | addCallbacks(wrap(onfulfill, r, "resolve"), 302 | wrap(onreject, r, "reject"), f); 303 | }); 304 | }), 305 | "catch": _public(function(onreject) { 306 | var f = this; 307 | return new Promise(function(r) { 308 | addCallbacks(null, wrap(onreject, r, "reject"), f); 309 | }); 310 | }), 311 | }); 312 | 313 | // 314 | // Statics 315 | // 316 | 317 | Promise.isThenable = isThenable; 318 | 319 | var toPromiseList = function(list) { 320 | return Array.prototype.slice.call(list).map(Promise.resolve); 321 | }; 322 | 323 | Promise.any = function(/*...futuresOrValues*/) { 324 | var futures = toPromiseList(arguments); 325 | return new Promise(function(r) { 326 | if (!futures.length) { 327 | r.reject("No futures passed to Promise.any()"); 328 | } else { 329 | var resolved = false; 330 | var firstSuccess = function(value) { 331 | if (resolved) { return; } 332 | resolved = true; 333 | r.resolve(value); 334 | }; 335 | var firstFailure = function(reason) { 336 | if (resolved) { return; } 337 | resolved = true; 338 | r.reject(reason); 339 | }; 340 | futures.forEach(function(f, idx) { 341 | f.then(firstSuccess, firstFailure); 342 | }); 343 | } 344 | }); 345 | }; 346 | 347 | Promise.every = function(/*...futuresOrValues*/) { 348 | var futures = toPromiseList(arguments); 349 | return new Promise(function(r) { 350 | if (!futures.length) { 351 | r.reject("No futures passed to Promise.every()"); 352 | } else { 353 | var values = new Array(futures.length); 354 | var count = 0; 355 | var accumulate = function(idx, v) { 356 | count++; 357 | values[idx] = v; 358 | if (count == futures.length) { 359 | r.resolve(values); 360 | } 361 | }; 362 | futures.forEach(function(f, idx) { 363 | f.then(accumulate.bind(null, idx), r.reject); 364 | }); 365 | } 366 | }); 367 | }; 368 | 369 | Promise.some = function() { 370 | var futures = toPromiseList(arguments); 371 | return new Promise(function(r) { 372 | if (!futures.length) { 373 | r.reject("No futures passed to Promise.some()"); 374 | } else { 375 | var count = 0; 376 | var accumulateFailures = function(e) { 377 | count++; 378 | if (count == futures.length) { 379 | r.reject(); 380 | } 381 | }; 382 | futures.forEach(function(f, idx) { 383 | f.then(r.resolve, accumulateFailures); 384 | }); 385 | } 386 | }); 387 | }; 388 | 389 | Promise.fulfill = function(value) { 390 | return new Promise(function(r) { 391 | r.fulfill(value); 392 | }); 393 | }; 394 | 395 | Promise.resolve = function(value) { 396 | return new Promise(function(r) { 397 | r.resolve(value); 398 | }); 399 | }; 400 | 401 | Promise.reject = function(reason) { 402 | return new Promise(function(r) { 403 | r.reject(reason); 404 | }); 405 | }; 406 | 407 | // 408 | // Export 409 | // 410 | 411 | global.Promise = Promise; 412 | 413 | })(this, 414 | (typeof window !== 'undefined') ? window : {}, 415 | this.runningUnderTest||false); 416 | -------------------------------------------------------------------------------- /tests/Promise-tests.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013: 2 | // Alex Russell (slightlyoff@chromium.org) 3 | // Use of this source code is governed by 4 | // http://www.apache.org/licenses/LICENSE-2.0 5 | 6 | (function() { 7 | "use strict"; 8 | 9 | var t = doh; 10 | 11 | // 12 | // Trivial utilities. 13 | // 14 | var log = console.log.bind(console); 15 | 16 | var rejected = Promise.reject; 17 | var asyncRejected = function(reason) { 18 | return new Promise(function(r) { 19 | setTimeout(r.reject.bind(r, reason), 0); 20 | }); 21 | }; 22 | 23 | var fulfilled = Promise.fulfill; 24 | var asyncAccepted = function(value) { 25 | return new Promise(function(r) { 26 | setTimeout(r.fulfill.bind(r, value), 0); 27 | }); 28 | }; 29 | 30 | var resolved = Promise.resolve; 31 | var asyncResolved = function(value) { 32 | return new Promise(function(r) { 33 | setTimeout(r.resolve.bind(r, value), 0); 34 | }); 35 | }; 36 | 37 | var pending = function() { 38 | var resolver; 39 | var future = new Promise(function(r) { resolver = r; }); 40 | return { 41 | future: future, 42 | fulfill: resolver.fulfill, 43 | reject: resolver.reject, 44 | resolve: resolver.resolve, 45 | }; 46 | }; 47 | 48 | var dummy = { dummy: "dummy" }; 49 | var sentinel = { sentinel: "sentinel" }; 50 | var fulfilledSentinel = fulfilled(sentinel); 51 | var rejectedSentinel = rejected(sentinel); 52 | 53 | var async = function(desc, test) { 54 | return { 55 | name: desc, 56 | runTest: function() { 57 | var d = new doh.Deferred(); 58 | test(d, d.callback.bind(d), d.errback.bind(d)); 59 | return d; 60 | } 61 | }; 62 | }; 63 | 64 | t.add("Promise", [ 65 | function prototypeMethods() { 66 | t.is(typeof Promise.prototype.then, "function"); 67 | t.is(Promise.prototype.then.length, 2); 68 | t.is(typeof Promise.prototype.catch, "function"); 69 | t.is(Promise.prototype.catch.length, 1); 70 | 71 | var c = 0; 72 | for(var x in Promise.prototype) { c++; } 73 | t.is(c, 2); 74 | }, 75 | 76 | function no_arg_ctor() { 77 | var future = new Promise(); 78 | t.is("pending", future._state); 79 | }, 80 | 81 | function base_state() { 82 | var resolver; 83 | t.is(undefined, resolver); 84 | var future = new Promise(function(r) { resolver = r; }); 85 | t.t(future instanceof Promise); 86 | t.is(undefined, future._value); 87 | t.is(undefined, future._error); 88 | t.is("pending", future._state); 89 | t.is("object", typeof resolver); 90 | t.is(false, resolver._isResolved); 91 | }, 92 | 93 | async("Is delivery delayed?", function(d) { 94 | var resolver; 95 | var resolved = false; 96 | var future = new Promise(function(r) { resolver = r; }); 97 | future.then(function(value) { 98 | resolved = true; 99 | t.is(true, value); 100 | d.callback(value); 101 | }); 102 | 103 | t.is(future._state, "pending"); 104 | t.is(false, resolved); 105 | // t.is(false, resolver._isResolved); 106 | resolver.resolve(true); 107 | // FIXME: what should future._value be here? 108 | 109 | t.is("pending", future._state); 110 | t.is(true, resolver._isResolved); 111 | }), 112 | 113 | function then_does_not_return_self() { 114 | var f = new Promise(); 115 | t.t(f.then() !== f); 116 | }, 117 | 118 | function catch_does_not_return_self() { 119 | var f = new Promise(); 120 | t.t(f.catch() !== f); 121 | }, 122 | 123 | async("Values forward correctly", function(d) { 124 | var eb = d.errback.bind(d); 125 | var f = fulfilled(dummy); 126 | f.then() 127 | .then(null, eb) 128 | .then(function(e) { 129 | t.is(dummy, e); 130 | d.callback(); 131 | }, eb); 132 | }), 133 | 134 | async("Errors forward correctly", function(d) { 135 | var f = rejected("meh"); 136 | f.then(log) 137 | .then(log, function(e) { 138 | t.is("meh", e); 139 | d.callback(); 140 | }); 141 | }), 142 | ]); 143 | 144 | doh.add("Resolver", [ 145 | 146 | function invariants() { 147 | new Promise(function(r) { 148 | t.is(r._isResolved, false) 149 | var isResolvedPD = Object.getOwnPropertyDescriptor(r, "_isResolved"); 150 | t.is("function", typeof isResolvedPD.get); 151 | t.is("undefined", typeof isResolvedPD.set); 152 | t.t(isResolvedPD.enumerable); 153 | t.f(isResolvedPD.configurable); 154 | 155 | t.is("function", typeof r.fulfill); 156 | t.is("function", typeof r.reject); 157 | t.is("function", typeof r.resolve); 158 | t.is("function", typeof r.cancel); 159 | t.is("function", typeof r.timeout); 160 | }); 161 | }, 162 | 163 | async("cancel", function(d) { 164 | var resolver; 165 | var future = new Promise(function(r) { 166 | try { 167 | resolver = r; 168 | t.f(r._isResolved); 169 | r.cancel(); 170 | t.t(resolver._isResolved); 171 | } catch(e) { 172 | d.errback(e); 173 | } 174 | }); 175 | t.is("pending", future._state); 176 | future.then( 177 | d.errback.bind(d), 178 | function(e) { 179 | t.is("object", typeof e); 180 | t.t(e instanceof Error); 181 | // FIXME: e doesn't seem to have a .name property!!! 182 | t.is("Error: Cancel", e.toString()); 183 | d.callback(); 184 | } 185 | ); 186 | t.t(resolver._isResolved); 187 | t.is("pending", future._state); 188 | }), 189 | 190 | async("timeout", function(d) { 191 | var resolver; 192 | var future = new Promise(function(r) { 193 | try { 194 | resolver = r; 195 | t.f(r._isResolved); 196 | r.timeout(); 197 | t.t(resolver._isResolved); 198 | } catch(e) { 199 | d.errback(e); 200 | } 201 | }); 202 | t.is("pending", future._state); 203 | future.then( 204 | d.errback.bind(d), 205 | function(e) { 206 | t.is("object", typeof e); 207 | t.t(e instanceof Error); 208 | t.is("Error: Timeout", e.toString()); 209 | d.callback(); 210 | } 211 | ); 212 | t.t(resolver._isResolved); 213 | t.is("pending", future._state); 214 | }), 215 | 216 | async("resolve forwards errors", function(d) { 217 | var e = new Error("synthetic"); 218 | var resolver; 219 | var f1 = new Promise(function(r) { 220 | r.reject(e); 221 | }); 222 | var f2 = new Promise(function(r) { 223 | r.resolve(f1); 224 | }); 225 | f2.then( 226 | d.errback.bind(d), 227 | function(err) { 228 | t.is("object", typeof err); 229 | t.t(err instanceof Error); 230 | t.is("Error: synthetic", err.toString()); 231 | t.is(e.toString(), err.toString()); 232 | t.is(e, err); 233 | d.callback(); 234 | } 235 | ); 236 | }), 237 | 238 | async("resolve forwards values", function(d) { 239 | var v = new Error("synthetic"); 240 | var resolver; 241 | var f1 = new Promise(function(r) { 242 | r.fulfill(v); 243 | }); 244 | var f2 = new Promise(function(r) { 245 | r.resolve(f1); 246 | }); 247 | f2.then( 248 | function(value) { 249 | t.is("object", typeof value); 250 | t.t(value instanceof Error); 251 | t.is("Error: synthetic", value.toString()); 252 | t.is(v, value); 253 | d.callback(); 254 | }, 255 | d.errback.bind(d) 256 | ); 257 | }), 258 | 259 | async("resolve does not forward non futures", function(d) { 260 | var v = new Error("synthetic"); 261 | var resolver; 262 | var f1 = new Promise(function(r) { 263 | r.resolve(v); 264 | }); 265 | var f2 = new Promise(function(r) { 266 | r.resolve(f1); 267 | }); 268 | f2.then( 269 | function(value) { 270 | t.is("object", typeof value); 271 | t.t(value instanceof Error); 272 | t.is("Error: synthetic", value.toString()); 273 | t.is(v, value); 274 | d.callback(); 275 | }, 276 | d.errback.bind(d) 277 | ); 278 | }), 279 | 280 | async("resolve forwards values through then", function(d) { 281 | var v = new Error("synthetic"); 282 | var resolver; 283 | var f1 = new Promise(function(r) { 284 | r.resolve(v); 285 | }); 286 | var f2 = new Promise(function(r) { 287 | r.resolve(f1); 288 | }); 289 | var f3 = f2.then( 290 | function(value) { 291 | t.is("object", typeof value); 292 | t.t(value instanceof Error); 293 | t.is("Error: synthetic", value.toString()); 294 | t.is(v, value); 295 | return new Promise(function(r) { 296 | r.resolve("some other value"); 297 | }); 298 | }, 299 | function(e) { return e; } 300 | ); 301 | f3.then( 302 | function(value) { 303 | t.is("some other value", value); 304 | d.callback(); 305 | }, 306 | d.errback.bind(d) 307 | ); 308 | }), 309 | 310 | async("Promises forward through then", function(d, then, error) { 311 | // FIXME(slightlyoff) 312 | then(); 313 | }), 314 | 315 | 316 | async("isResolved is true while forwarding", function(d) { 317 | var f1 = pending(); 318 | var r1; 319 | var f2 = new Promise(function(r) { 320 | r1 = r; 321 | r.resolve(f1); 322 | }); 323 | t.t(r1._isResolved); 324 | d.callback(); 325 | }), 326 | 327 | async("Throwing in a then callback rejects next.", function(d, then, e) { 328 | fulfilled(5).then(function(v) { 329 | throw new Error("Blarg!"); 330 | }).then(e, function(e){then();}); 331 | }), 332 | 333 | // 334 | // Inspired by the promises-tests repo. 335 | // 336 | async("non function rejected callbacks are ignored", 337 | function(d, then, error) { 338 | var nonFunction = 10; 339 | rejected(dummy).then(10, then); 340 | } 341 | ), 342 | 343 | async("non function fulfilled callbacks are ignored", 344 | function(d, then, error) { 345 | var nonFunction = 10; 346 | fulfilled(dummy).then(then, 10); 347 | } 348 | ), 349 | 350 | // Promise.any 351 | 352 | async("Promise.any fails on no values", function(d, then, error) { 353 | Promise.any().then(error, then); 354 | }), 355 | 356 | async("Promise.any succeeds on undefined", function(d, then, error) { 357 | Promise.any(undefined).then(then, error); 358 | }), 359 | 360 | async("Promise.any succeeds on raw values", function(d, then, error) { 361 | Promise.any("thinger", undefined, [], new String("blarg")).then(then, error); 362 | }), 363 | 364 | async("Promise.any fails on rejected", function(d, then, error) { 365 | Promise.any(rejected()).then(error, then); 366 | }), 367 | 368 | async("Promise.any succeeds on fulfilled", function(d, then, error) { 369 | Promise.any(fulfilled()).then(then, error); 370 | }), 371 | 372 | async("Promise.any succeeds on fulfilled sentinel", function(d, then, error) { 373 | Promise.any(fulfilledSentinel).then(then, error); 374 | }), 375 | 376 | async("Promise.any succeeds on asyncAccepted", function(d, then, error) { 377 | Promise.any(asyncAccepted()).then(then, error); 378 | }), 379 | 380 | async("Promise.any succeeds on value + fulfilled", function(d, then, error) { 381 | Promise.any("thinger", fulfilled(dummy)).then(then, error); 382 | }), 383 | 384 | async("Promise.any succeeds on fulfilled + rejected", function(d, then, error) { 385 | Promise.any(fulfilledSentinel, rejectedSentinel).then(then, error); 386 | }), 387 | 388 | async("Promise.any fails on rejected + fulfilled", function(d, then, error) { 389 | Promise.any(rejected(dummy), fulfilled("thinger")).then(error, then); 390 | }), 391 | 392 | async("Promise.any succeeds on pre-fulfilled + pre-rejected", 393 | function(d, then, error) { 394 | Promise.any(fulfilledSentinel, rejectedSentinel).then(then, error); 395 | } 396 | ), 397 | 398 | async("Promise.any succeeds on value + rejected", function(d, then, error) { 399 | Promise.any("value", rejected("error")).then(then, error); 400 | }), 401 | 402 | async("Promise.any succeeds on rejected + value", function(d, then, error) { 403 | Promise.any(rejectedSentinel, "thinger").then(then, error); 404 | }), 405 | 406 | // Promise.every 407 | 408 | async("Promise.every fails on no values", function(d, then, error) { 409 | Promise.every().then(error, then); 410 | }), 411 | 412 | async("Promise.every succeeds on undefined", function(d, then, error) { 413 | Promise.every(undefined).then(then, error); 414 | }), 415 | 416 | async("Promise.every succeeds on raw values", function(d, then, error) { 417 | Promise.every("thinger", undefined, [], new String("blarg")).then(then, error); 418 | }), 419 | 420 | async("Promise.every fails on rejected", function(d, then, error) { 421 | Promise.any(rejected()).then(error, then); 422 | }), 423 | 424 | async("Promise.every succeeds on fulfilled", function(d, then, error) { 425 | Promise.every(fulfilled()).then(then, error); 426 | }), 427 | 428 | async("Promise.every succeeds on asyncAccepted", function(d, then, error) { 429 | Promise.every(asyncAccepted()).then(then, error); 430 | }), 431 | 432 | async("Promise.every fails on rejected + value", function(d, then, error) { 433 | Promise.every(rejected(), "thinger").then(error, then); 434 | }), 435 | 436 | async("Promise.every fails on asyncRejected + value", function(d, then, error) { 437 | Promise.every(asyncRejected(), "thinger").then(error, then); 438 | }), 439 | 440 | async("Promise.every forwards values", function(d, then, error) { 441 | Promise.every( 442 | Promise.every(asyncAccepted(5), "thinger").then(function(values) { 443 | t.is([5, "thinger"], values); 444 | }), 445 | Promise.every(asyncAccepted(5), "thinger").then(function(values) { 446 | t.is([5, "thinger"], values); 447 | }) 448 | ).then(then, error); 449 | }), 450 | 451 | async("Promise.every forwards values multiple levels", 452 | function(d, then, error) { 453 | Promise.every(asyncResolved(asyncResolved(5)), "thinger") 454 | .then(function(values) { 455 | t.is([5, "thinger"], values); 456 | then(); 457 | }, error); 458 | } 459 | ), 460 | 461 | // Promise.some 462 | 463 | async("Promise.some fails on no values", function(d, then, error) { 464 | Promise.some().then(error, then); 465 | }), 466 | 467 | async("Promise.some succeeds on undefined", function(d, then, error) { 468 | Promise.some(undefined).then(then, error); 469 | }), 470 | 471 | async("Promise.some succeeds on raw values", function(d, then, error) { 472 | Promise.some("thinger", undefined, [], new String("blarg")).then(then, error); 473 | }), 474 | 475 | async("Promise.some fails on rejected", function(d, then, error) { 476 | Promise.some(rejected()).then(error, then); 477 | }), 478 | 479 | async("Promise.some succeeds on fulfilled", function(d, then, error) { 480 | Promise.some(fulfilled()).then(then, error); 481 | }), 482 | 483 | async("Promise.some succeeds on asyncAccepted", function(d, then, error) { 484 | Promise.some(asyncAccepted()).then(then, error); 485 | }), 486 | 487 | async("Promise.some succeeds on rejected + fulfilled", function(d, then, error) { 488 | Promise.some(rejectedSentinel, fulfilledSentinel).then(then, error); 489 | }), 490 | 491 | async("Promise.some succeeds on value + rejected", function(d, then, error) { 492 | Promise.some("thinger", rejectedSentinel).then(then, error); 493 | }), 494 | 495 | // Promise.fulfill 496 | 497 | async("Promise.fulfill is sane", function(d, then, error) { 498 | Promise.fulfill(sentinel).then(function(v) { 499 | t.is(sentinel, v); 500 | then(); 501 | }, error); 502 | }), 503 | 504 | // FIXME(slightlyoff): MOAR TESTS 505 | 506 | 507 | // Promise.resolve 508 | 509 | async("Promise.resolve is sane", function(d, then, error) { 510 | Promise.resolve(sentinel).then(function(v) { 511 | t.is(sentinel, v); 512 | then(); 513 | }, error); 514 | }), 515 | 516 | // FIXME(slightlyoff): MOAR TESTS 517 | 518 | 519 | // Promise.reject 520 | 521 | async("Promise.reject is sane", function(d, then, error) { 522 | Promise.reject(sentinel).then(error, function(reason) { 523 | t.is(sentinel, reason); 524 | then(); 525 | }); 526 | }), 527 | 528 | // FIXME(slightlyoff): MOAR TESTS 529 | ]); 530 | 531 | })(); 532 | -------------------------------------------------------------------------------- /tests/promises-tests.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013: 2 | // Alex Russell (slightlyoff@chromium.org) 3 | // Use of this source code is governed by 4 | // http://www.apache.org/licenses/LICENSE-2.0 5 | 6 | var promisesAplusTests = require("../third_party/promises-tests"); 7 | var fs = require("fs"); 8 | var _eval = require("eval"); 9 | 10 | var Promise = _eval(fs.readFileSync("../src/Promise.js", "utf-8") + 11 | "module.exports = Promise;"); 12 | 13 | var adapter = { 14 | rejected: function(reason) { 15 | return new Promise(function(r) { r.reject(reason); }); 16 | }, 17 | 18 | fulfilled: function(value) { 19 | return new Promise(function(r) { r.fulfill(value); }); 20 | }, 21 | 22 | pending: function() { 23 | var resolver; 24 | var future = new Promise(function(r) { resolver = r; }); 25 | return { 26 | promise: future, 27 | fulfill: function (value) { 28 | try { 29 | resolver.resolve(value); 30 | } catch (e) { } 31 | }, 32 | reject: function (reason) { 33 | try { 34 | resolver.reject(reason); 35 | } catch (e) { } 36 | } 37 | }; 38 | } 39 | }; 40 | 41 | promisesAplusTests(adapter, console.log); 42 | -------------------------------------------------------------------------------- /tests/test.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | Promise Tests 12 | 13 | 14 | 46 | 47 | 48 | 49 | 50 | 51 |

DOM Promise Polyfill Tests

52 | 53 | 54 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | // In which Node proves to, perhaps, be good for soemthing after all 2 | var filemap = require("filemap"); 3 | var _eval = require("eval"); 4 | 5 | var files = [ 6 | "../third_party/doh/runner_async.js", 7 | "../src/Promise.js", 8 | "Promise-tests.js" 9 | ]; 10 | 11 | // ...jsut as soon as we re-build the naive load() method 12 | filemap( 13 | files, 14 | "utf-8", 15 | function(contents) { 16 | var buff = "this.runningUnderTest = true;\n\n"; 17 | files.forEach(function(n) { 18 | buff += contents[n]; 19 | }); 20 | buff += "doh.run();"; 21 | _eval(buff); 22 | } 23 | ); 24 | -------------------------------------------------------------------------------- /third_party/doh/LICENSE: -------------------------------------------------------------------------------- 1 | Dojo is available under *either* the terms of the modified BSD license *or* the 2 | Academic Free License version 2.1. As a recipient of Dojo, you may choose which 3 | license to receive this code under (except as noted in per-module LICENSE 4 | files). Some modules may not be the copyright of the Dojo Foundation. These 5 | modules contain explicit declarations of copyright in both the LICENSE files in 6 | the directories in which they reside and in the code itself. No external 7 | contributions are allowed under licenses which are fundamentally incompatible 8 | with the AFL or BSD licenses that Dojo is distributed under. 9 | 10 | The text of the AFL and BSD licenses is reproduced below. 11 | 12 | ------------------------------------------------------------------------------- 13 | The "New" BSD License: 14 | ********************** 15 | 16 | Copyright (c) 2005-2011, The Dojo Foundation 17 | All rights reserved. 18 | 19 | Redistribution and use in source and binary forms, with or without 20 | modification, are permitted provided that the following conditions are met: 21 | 22 | * Redistributions of source code must retain the above copyright notice, this 23 | list of conditions and the following disclaimer. 24 | * Redistributions in binary form must reproduce the above copyright notice, 25 | this list of conditions and the following disclaimer in the documentation 26 | and/or other materials provided with the distribution. 27 | * Neither the name of the Dojo Foundation nor the names of its contributors 28 | may be used to endorse or promote products derived from this software 29 | without specific prior written permission. 30 | 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 32 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 33 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 34 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 35 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 37 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 39 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | 42 | ------------------------------------------------------------------------------- 43 | The Academic Free License, v. 2.1: 44 | ********************************** 45 | 46 | This Academic Free License (the "License") applies to any original work of 47 | authorship (the "Original Work") whose owner (the "Licensor") has placed the 48 | following notice immediately following the copyright notice for the Original 49 | Work: 50 | 51 | Licensed under the Academic Free License version 2.1 52 | 53 | 1) Grant of Copyright License. Licensor hereby grants You a world-wide, 54 | royalty-free, non-exclusive, perpetual, sublicenseable license to do the 55 | following: 56 | 57 | a) to reproduce the Original Work in copies; 58 | 59 | b) to prepare derivative works ("Derivative Works") based upon the Original 60 | Work; 61 | 62 | c) to distribute copies of the Original Work and Derivative Works to the 63 | public; 64 | 65 | d) to perform the Original Work publicly; and 66 | 67 | e) to display the Original Work publicly. 68 | 69 | 2) Grant of Patent License. Licensor hereby grants You a world-wide, 70 | royalty-free, non-exclusive, perpetual, sublicenseable license, under patent 71 | claims owned or controlled by the Licensor that are embodied in the Original 72 | Work as furnished by the Licensor, to make, use, sell and offer for sale the 73 | Original Work and Derivative Works. 74 | 75 | 3) Grant of Source Code License. The term "Source Code" means the preferred 76 | form of the Original Work for making modifications to it and all available 77 | documentation describing how to modify the Original Work. Licensor hereby 78 | agrees to provide a machine-readable copy of the Source Code of the Original 79 | Work along with each copy of the Original Work that Licensor distributes. 80 | Licensor reserves the right to satisfy this obligation by placing a 81 | machine-readable copy of the Source Code in an information repository 82 | reasonably calculated to permit inexpensive and convenient access by You for as 83 | long as Licensor continues to distribute the Original Work, and by publishing 84 | the address of that information repository in a notice immediately following 85 | the copyright notice that applies to the Original Work. 86 | 87 | 4) Exclusions From License Grant. Neither the names of Licensor, nor the names 88 | of any contributors to the Original Work, nor any of their trademarks or 89 | service marks, may be used to endorse or promote products derived from this 90 | Original Work without express prior written permission of the Licensor. Nothing 91 | in this License shall be deemed to grant any rights to trademarks, copyrights, 92 | patents, trade secrets or any other intellectual property of Licensor except as 93 | expressly stated herein. No patent license is granted to make, use, sell or 94 | offer to sell embodiments of any patent claims other than the licensed claims 95 | defined in Section 2. No right is granted to the trademarks of Licensor even if 96 | such marks are included in the Original Work. Nothing in this License shall be 97 | interpreted to prohibit Licensor from licensing under different terms from this 98 | License any Original Work that Licensor otherwise would have a right to 99 | license. 100 | 101 | 5) This section intentionally omitted. 102 | 103 | 6) Attribution Rights. You must retain, in the Source Code of any Derivative 104 | Works that You create, all copyright, patent or trademark notices from the 105 | Source Code of the Original Work, as well as any notices of licensing and any 106 | descriptive text identified therein as an "Attribution Notice." You must cause 107 | the Source Code for any Derivative Works that You create to carry a prominent 108 | Attribution Notice reasonably calculated to inform recipients that You have 109 | modified the Original Work. 110 | 111 | 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that 112 | the copyright in and to the Original Work and the patent rights granted herein 113 | by Licensor are owned by the Licensor or are sublicensed to You under the terms 114 | of this License with the permission of the contributor(s) of those copyrights 115 | and patent rights. Except as expressly stated in the immediately proceeding 116 | sentence, the Original Work is provided under this License on an "AS IS" BASIS 117 | and WITHOUT WARRANTY, either express or implied, including, without limitation, 118 | the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR 119 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. 120 | This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No 121 | license to Original Work is granted hereunder except under this disclaimer. 122 | 123 | 8) Limitation of Liability. Under no circumstances and under no legal theory, 124 | whether in tort (including negligence), contract, or otherwise, shall the 125 | Licensor be liable to any person for any direct, indirect, special, incidental, 126 | or consequential damages of any character arising as a result of this License 127 | or the use of the Original Work including, without limitation, damages for loss 128 | of goodwill, work stoppage, computer failure or malfunction, or any and all 129 | other commercial damages or losses. This limitation of liability shall not 130 | apply to liability for death or personal injury resulting from Licensor's 131 | negligence to the extent applicable law prohibits such limitation. Some 132 | jurisdictions do not allow the exclusion or limitation of incidental or 133 | consequential damages, so this exclusion and limitation may not apply to You. 134 | 135 | 9) Acceptance and Termination. If You distribute copies of the Original Work or 136 | a Derivative Work, You must make a reasonable effort under the circumstances to 137 | obtain the express assent of recipients to the terms of this License. Nothing 138 | else but this License (or another written agreement between Licensor and You) 139 | grants You permission to create Derivative Works based upon the Original Work 140 | or to exercise any of the rights granted in Section 1 herein, and any attempt 141 | to do so except under the terms of this License (or another written agreement 142 | between Licensor and You) is expressly prohibited by U.S. copyright law, the 143 | equivalent laws of other countries, and by international treaty. Therefore, by 144 | exercising any of the rights granted to You in Section 1 herein, You indicate 145 | Your acceptance of this License and all of its terms and conditions. 146 | 147 | 10) Termination for Patent Action. This License shall terminate automatically 148 | and You may no longer exercise any of the rights granted to You by this License 149 | as of the date You commence an action, including a cross-claim or counterclaim, 150 | against Licensor or any licensee alleging that the Original Work infringes a 151 | patent. This termination provision shall not apply for an action alleging 152 | patent infringement by combinations of the Original Work with other software or 153 | hardware. 154 | 155 | 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this 156 | License may be brought only in the courts of a jurisdiction wherein the 157 | Licensor resides or in which Licensor conducts its primary business, and under 158 | the laws of that jurisdiction excluding its conflict-of-law provisions. The 159 | application of the United Nations Convention on Contracts for the International 160 | Sale of Goods is expressly excluded. Any use of the Original Work outside the 161 | scope of this License or after its termination shall be subject to the 162 | requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et 163 | seq., the equivalent laws of other countries, and international treaty. This 164 | section shall survive the termination of this License. 165 | 166 | 12) Attorneys Fees. In any action to enforce the terms of this License or 167 | seeking damages relating thereto, the prevailing party shall be entitled to 168 | recover its costs and expenses, including, without limitation, reasonable 169 | attorneys' fees and costs incurred in connection with such action, including 170 | any appeal of such action. This section shall survive the termination of this 171 | License. 172 | 173 | 13) Miscellaneous. This License represents the complete agreement concerning 174 | the subject matter hereof. If any provision of this License is held to be 175 | unenforceable, such provision shall be reformed only to the extent necessary to 176 | make it enforceable. 177 | 178 | 14) Definition of "You" in This License. "You" throughout this License, whether 179 | in upper or lower case, means an individual or a legal entity exercising rights 180 | under, and complying with all of the terms of, this License. For legal 181 | entities, "You" includes any entity that controls, is controlled by, or is 182 | under common control with you. For purposes of this definition, "control" means 183 | (i) the power, direct or indirect, to cause the direction or management of such 184 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 185 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of such 186 | entity. 187 | 188 | 15) Right to Use. You may use the Original Work in all ways not otherwise 189 | restricted or conditioned by this License or by law, and Licensor promises not 190 | to interfere with or be responsible for such uses by You. 191 | 192 | This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. 193 | Permission is hereby granted to copy and distribute this license without 194 | modification. This license may not be modified without the express written 195 | permission of its copyright owner. 196 | -------------------------------------------------------------------------------- /third_party/doh/README: -------------------------------------------------------------------------------- 1 | DOH may be run standalone by issuing a command like the following: 2 | 3 | java -jar ../shrinksafe/js.jar runner.js testModule=tests.colors 4 | 5 | where the testModule argument is optional and shrinksafe/js.jar is just a 6 | convenient copy of the Rhino JavaScript engine -- the custom patch is not 7 | required. 8 | 9 | Optional arguments include: 10 | * dojoUrl - specifies the location of dojo.js 11 | * testUrl - specifies a Javascript file to load with initialization code 12 | * testModule - specifies a test module in the dojo package namespace 13 | -------------------------------------------------------------------------------- /third_party/doh/runner.js: -------------------------------------------------------------------------------- 1 | //guarantee in global scope and scope protection 2 | (function(/* Array? */scriptArgs) { 3 | 4 | //here's the definition of doh.runner...which really defines global doh 5 | var d = function(doh) { 6 | // 7 | // Utility Functions and Classes 8 | // 9 | 10 | if (typeof this["print"] == "undefined" && console) { 11 | print = console.log.bind(console); 12 | } 13 | 14 | doh.global = this; 15 | 16 | doh.squelch = true; 17 | doh._print = print; 18 | 19 | doh._line = "------------------------------------------------------------"; 20 | 21 | doh.debug = function(){ 22 | // summary: 23 | // takes any number of arguments and sends them to whatever debugging 24 | // or logging facility is available in this environment 25 | 26 | var a = Array.prototype.slice.call(arguments, 0); 27 | a.unshift("|"); 28 | doh._print(a.join(" ")); 29 | } 30 | 31 | doh.error = function(){ 32 | // summary: 33 | // logging method to be used to send Error objects, so that 34 | // whatever debugging or logging facility you have can decide to treat it 35 | // as an Error object and show additional information - such as stack trace 36 | 37 | // YOUR TEST RUNNER NEEDS TO IMPLEMENT THIS 38 | var a = Array.prototype.slice.call(arguments, 0); 39 | a.unshift("ERROR:"); 40 | doh._print(a.join(" ")); 41 | } 42 | 43 | doh._AssertFailure = function(msg, hint){ 44 | // idea for this as way of dis-ambiguating error types is from JUM. 45 | // The JUM is dead! Long live the JUM! 46 | 47 | if(!(this instanceof doh._AssertFailure)){ 48 | return new doh._AssertFailure(msg, hint); 49 | } 50 | if(hint){ 51 | msg = (new String(msg||""))+" with hint: \n\t\t"+(new String(hint)+"\n"); 52 | } 53 | this.message = new String(msg||""); 54 | return this; 55 | } 56 | doh._AssertFailure.prototype = new Error(); 57 | doh._AssertFailure.prototype.constructor = doh._AssertFailure; 58 | doh._AssertFailure.prototype.name = "doh._AssertFailure"; 59 | 60 | // 61 | // State Keeping and Reporting 62 | // 63 | 64 | doh._testCount = 0; 65 | doh._groupCount = 0; 66 | doh._errorCount = 0; 67 | doh._failureCount = 0; 68 | doh._currentGroup = null; 69 | doh._currentTest = null; 70 | 71 | doh._init = function(){ 72 | this._currentGroup = null; 73 | this._currentTest = null; 74 | this._errorCount = 0; 75 | this._failureCount = 0; 76 | this.debug(this._testCount, "tests to run in", this._groupCount, "groups"); 77 | } 78 | 79 | // doh._urls = []; 80 | doh._groups = {}; 81 | 82 | // 83 | // Test Registration 84 | // 85 | 86 | doh.registerTestNs = function(/*String*/ group, /*Object*/ ns){ 87 | // summary: 88 | // adds the passed namespace object to the list of objects to be 89 | // searched for test groups. Only "public" functions (not prefixed 90 | // with "_") will be added as tests to be run. If you'd like to use 91 | // fixtures (setUp(), tearDown(), and runTest()), please use 92 | // registerTest() or registerTests(). 93 | for(var x in ns){ 94 | if( (x.charAt(0) != "_") && 95 | (typeof ns[x] == "function") ){ 96 | this.registerTest(group, ns[x]); 97 | } 98 | } 99 | } 100 | 101 | doh._testRegistered = function(group, fixture){ 102 | // slot to be filled in 103 | } 104 | 105 | doh._groupStarted = function(group){ 106 | // slot to be filled in 107 | } 108 | 109 | doh._groupFinished = function(group, success){ 110 | // slot to be filled in 111 | } 112 | 113 | doh._testStarted = function(group, fixture){ 114 | // slot to be filled in 115 | } 116 | 117 | doh._testFinished = function(group, fixture, success){ 118 | // slot to be filled in 119 | } 120 | 121 | doh.registerGroup = function( /*String*/ group, 122 | /*Array||Function||Object*/ tests, 123 | /*Function*/ setUp, 124 | /*Function*/ tearDown, 125 | /*String*/ type){ 126 | // summary: 127 | // registers an entire group of tests at once and provides a setUp and 128 | // tearDown facility for groups. If you call this method with only 129 | // setUp and tearDown parameters, they will replace previously 130 | // installed setUp or tearDown functions for the group with the new 131 | // methods. 132 | // group: 133 | // string name of the group 134 | // tests: 135 | // either a function or an object or an array of functions/objects. If 136 | // an object, it must contain at *least* a "runTest" method, and may 137 | // also contain "setUp" and "tearDown" methods. These will be invoked 138 | // on either side of the "runTest" method (respectively) when the test 139 | // is run. If an array, it must contain objects matching the above 140 | // description or test functions. 141 | // setUp: a function for initializing the test group 142 | // tearDown: a function for initializing the test group 143 | // type: The type of tests these are, such as a group of performance tests 144 | // null/undefied are standard DOH tests, the valye 'perf' enables 145 | // registering them as performance tests. 146 | if(tests){ 147 | this.register(group, tests, type); 148 | } 149 | if(setUp){ 150 | this._groups[group].setUp = setUp; 151 | } 152 | if(tearDown){ 153 | this._groups[group].tearDown = tearDown; 154 | } 155 | } 156 | 157 | doh._getTestObj = function(group, test, type){ 158 | var tObj = test; 159 | if(typeof test == "string"){ 160 | if(test.substr(0, 4)=="url:"){ 161 | return this.registerUrl(group, test); 162 | }else{ 163 | tObj = { 164 | name: test.replace("/\s/g", "_") // FIXME: bad escapement 165 | }; 166 | tObj.runTest = new Function("t", test); 167 | } 168 | }else if(typeof test == "function"){ 169 | // if we didn't get a fixture, wrap the function 170 | tObj = { "runTest": test }; 171 | if(test["name"]){ 172 | tObj.name = test.name; 173 | }else{ 174 | try{ 175 | var fStr = "function "; 176 | var ts = tObj.runTest+""; 177 | if(0 <= ts.indexOf(fStr)){ 178 | tObj.name = ts.split(fStr)[1].split("(", 1)[0]; 179 | } 180 | // doh.debug(tObj.runTest.toSource()); 181 | }catch(e){ 182 | } 183 | } 184 | // FIXME: try harder to get the test name here 185 | } 186 | return tObj; 187 | } 188 | 189 | doh.registerTest = function(/*String*/ group, 190 | /*Function||Object*/ test, 191 | /*String*/ type){ 192 | // summary: 193 | // add the provided test function or fixture object to the specified 194 | // test group. 195 | // group: 196 | // string name of the group to add the test to 197 | // test: 198 | // either a function or an object. If an object, it must contain at 199 | // *least* a "runTest" method, and may also contain "setUp" and 200 | // "tearDown" methods. These will be invoked on either side of the 201 | // "runTest" method (respectively) when the test is run. 202 | // type: 203 | // An identifier denoting the type of testing that the test performs, such 204 | // as a performance test. If null, defaults to regular DOH test. 205 | if(!this._groups[group]){ 206 | this._groupCount++; 207 | this._groups[group] = []; 208 | this._groups[group].inFlight = 0; 209 | } 210 | var tObj = this._getTestObj(group, test, type); 211 | if(!tObj){ return null; } 212 | this._groups[group].push(tObj); 213 | this._testCount++; 214 | this._testRegistered(group, tObj); 215 | return tObj; 216 | }; 217 | 218 | doh.registerTests = function(/*String*/ group, 219 | /*Array*/ testArr, 220 | /*String*/ type){ 221 | // summary: 222 | // registers a group of tests, treating each element of testArr as 223 | // though it were being (along with group) passed to the registerTest 224 | // method. It also uses the type to decide how the tests should 225 | // behave, by defining the type of tests these are, such as performance 226 | // tests 227 | var register = this.registerTest.bind(this, group); 228 | testArr.forEach(function(test) { register(test, type); }); 229 | }; 230 | 231 | // FIXME: remove the doh.add alias SRTL. 232 | doh.register = doh.add = function(groupOrNs, testOrNull, type){ 233 | // summary: 234 | // "magical" variant of registerTests, registerTest, and 235 | // registerTestNs. Will accept the calling arguments of any of these 236 | // methods and will correctly guess the right one to register with. 237 | if( (arguments.length == 1)&& 238 | (typeof groupOrNs == "string") ){ 239 | if(groupOrNs.substr(0, 4)=="url:"){ 240 | this.registerUrl(groupOrNs, null, null, type); 241 | }else{ 242 | this.registerTest("ungrouped", groupOrNs, type); 243 | } 244 | } 245 | if(arguments.length == 1){ 246 | this.debug("invalid args passed to doh.register():", groupOrNs, ",", testOrNull); 247 | return; 248 | } 249 | if(typeof testOrNull == "string"){ 250 | if(testOrNull.substr(0, 4)=="url:"){ 251 | this.registerUrl(testOrNull, null, null, type); 252 | }else{ 253 | this.registerTest(groupOrNs, testOrNull, type); 254 | } 255 | // this.registerTestNs(groupOrNs, testOrNull); 256 | return; 257 | } 258 | if(doh._isArray(testOrNull)){ 259 | this.registerTests(groupOrNs, testOrNull, type); 260 | return; 261 | } 262 | this.registerTest(groupOrNs, testOrNull, type); 263 | }; 264 | 265 | // 266 | // Assertions and In-Test Utilities 267 | // 268 | 269 | doh.t = doh.assertTrue = function(/*Object*/ condition, /*String?*/ hint){ 270 | // summary: 271 | // is the passed item "truthy"? 272 | if(arguments.length < 1){ 273 | throw new doh._AssertFailure( 274 | "assertTrue failed because it was not passed at least 1 argument" 275 | ); 276 | } 277 | if(!eval(condition)){ 278 | throw new doh._AssertFailure("assertTrue('" + condition + "') failed", hint); 279 | } 280 | } 281 | 282 | doh.f = doh.assertFalse = function(/*Object*/ condition, /*String?*/ hint){ 283 | // summary: 284 | // is the passed item "falsey"? 285 | if(arguments.length < 1){ 286 | throw new doh._AssertFailure( 287 | "assertFalse failed because it was not passed at least 1 argument" 288 | ); 289 | } 290 | 291 | if(eval(condition)){ 292 | throw new doh._AssertFailure("assertFalse('" + condition + "') failed", hint); 293 | } 294 | } 295 | 296 | doh.e = doh.assertError = function(/*Error object*/expectedError, 297 | /*Object*/scope, 298 | /*String*/functionName, 299 | /*Array*/args, 300 | /*String?*/ hint){ 301 | // summary: 302 | // Test for a certain error to be thrown by the given function. 303 | // example: 304 | // t.assertError(dojox.data.QueryReadStore.InvalidAttributeError, store, "getValue", [item, "NOT THERE"]); 305 | // t.assertError(dojox.data.QueryReadStore.InvalidItemError, store, "getValue", ["not an item", "NOT THERE"]); 306 | try{ 307 | scope[functionName].apply(scope, args); 308 | }catch (e){ 309 | if(e instanceof expectedError){ 310 | return true; 311 | }else{ 312 | throw new doh._AssertFailure( 313 | "assertError() failed:\n\texpected error\n\t\t" + 314 | expectedError + "\n\tbut got\n\t\t" + e +"\n\n", 315 | hint 316 | ); 317 | } 318 | } 319 | throw new doh._AssertFailure( 320 | "assertError() failed:\n\texpected error\n\t\t" + 321 | expectedError+"\n\tbut no error caught\n\n", 322 | hint 323 | ); 324 | } 325 | 326 | 327 | doh.is = doh.assertEqual = function(/*Object*/ expected, /*Object*/ actual, /*String?*/ hint){ 328 | // summary: 329 | // are the passed expected and actual objects/values deeply 330 | // equivalent? 331 | 332 | // Compare undefined always with three equal signs, because undefined==null 333 | // is true, but undefined===null is false. 334 | if((expected === undefined)&&(actual === undefined)){ 335 | return true; 336 | } 337 | if(arguments.length < 2){ 338 | throw doh._AssertFailure( 339 | "assertEqual failed because it was not passed 2 arguments"); 340 | } 341 | if( 342 | (expected === actual) || 343 | (expected == actual) || 344 | ( typeof expected == "number" && 345 | typeof actual == "number" && 346 | isNaN(expected) && isNaN(actual) 347 | ) 348 | ){ 349 | return true; 350 | } 351 | if( 352 | (this._isArray(expected) && 353 | this._isArray(actual) 354 | ) && 355 | this._arrayEq(expected, actual) 356 | ){ 357 | return true; 358 | } 359 | if( 360 | (typeof expected == "object" && typeof actual == "object") && 361 | this._objPropEq(expected, actual) 362 | ){ 363 | return true; 364 | } 365 | throw new doh._AssertFailure( 366 | "assertEqual() failed:\n\texpected\n\t\t"+expected+ 367 | "\n\tbut got\n\t\t"+actual+"\n\n", 368 | hint); 369 | } 370 | 371 | doh.isNot = doh.assertNotEqual = function(/*Object*/ notExpected, 372 | /*Object*/ actual, 373 | /*String?*/ hint){ 374 | // summary: 375 | // are the passed notexpected and actual objects/values deeply 376 | // not equivalent? 377 | 378 | // Compare undefined always with three equal signs, because undefined==null 379 | // is true, but undefined===null is false. 380 | if( 381 | (notExpected === undefined) && 382 | (actual === undefined) 383 | ){ 384 | throw new doh._AssertFailure( 385 | "assertNotEqual() failed: not expected |"+notExpected+ 386 | "| but got |"+actual+"|", 387 | hint); 388 | } 389 | 390 | if(arguments.length < 2){ 391 | throw doh._AssertFailure( 392 | "assertEqual failed because it was not passed 2 arguments" 393 | ); 394 | } 395 | 396 | if((notExpected === actual)||(notExpected == actual)){ 397 | throw new doh._AssertFailure( 398 | "assertNotEqual() failed: not expected |"+notExpected+ 399 | "| but got |"+actual+"|", 400 | hint); 401 | } 402 | 403 | if( (this._isArray(notExpected) && this._isArray(actual))&& 404 | (this._arrayEq(notExpected, actual)) ){ 405 | throw new doh._AssertFailure( 406 | "assertNotEqual() failed: not expected |"+notExpected+ 407 | "| but got |"+actual+"|", 408 | hint); 409 | } 410 | if( ((typeof notExpected == "object")&&((typeof actual == "object"))) ){ 411 | var isequal = false; 412 | try{ 413 | isequal = this._objPropEq(notExpected, actual); 414 | } catch(e) { 415 | if( !(e instanceof doh._AssertFailure) ){ 416 | throw e; //other exceptions, just throw it 417 | } 418 | } 419 | if (isequal) { 420 | throw new doh._AssertFailure( 421 | "assertNotEqual() failed: not expected |"+notExpected+ 422 | "| but got |"+actual+"|", 423 | hint); 424 | } 425 | } 426 | return true; 427 | } 428 | 429 | doh._arrayEq = function(expected, actual){ 430 | if (expected.length != actual.length) { 431 | return false; 432 | } 433 | 434 | for(var x=0; x 1) ? "s" : "")+" to run"); 483 | } 484 | 485 | doh._handleFailure = function(groupName, fixture, e){ 486 | // this.debug("FAILED test:", fixture.name); 487 | // mostly borrowed from JUM 488 | this._groups[groupName].failures++; 489 | var out = ""; 490 | if(e instanceof this._AssertFailure){ 491 | this._failureCount++; 492 | if(e["fileName"]){ out += e.fileName + ':'; } 493 | if(e["lineNumber"]){ out += e.lineNumber + ' '; } 494 | out += e+": "+e.message; 495 | this.debug("\t_AssertFailure:", out); 496 | }else{ 497 | this._errorCount++; 498 | } 499 | this.error(e); 500 | if(fixture.runTest["toSource"]){ 501 | var ss = fixture.runTest.toSource(); 502 | this.debug("\tERROR IN:\n\t\t", ss); 503 | }else{ 504 | this.debug("\tERROR IN:\n\t\t", fixture.runTest); 505 | } 506 | if (e.rhinoException) { 507 | e.rhinoException.printStackTrace(); 508 | } else if(e.javaException) { 509 | e.javaException.printStackTrace(); 510 | } 511 | 512 | if (!doh.squelch) { 513 | throw e; 514 | } 515 | 516 | } 517 | 518 | doh._runFixture = function(groupName, fixture){ 519 | var tg = this._groups[groupName]; 520 | this._testStarted(groupName, fixture); 521 | var err = null; 522 | // run it, catching exceptions and reporting them 523 | try{ 524 | doh.debug(fixture.name); 525 | // let doh reference "this.group.thinger..." which can be set by 526 | // another test or group-level setUp function 527 | fixture.group = tg; 528 | // only execute the parts of the fixture we've got 529 | 530 | if(fixture["setUp"]){ 531 | fixture.setUp(this); 532 | } 533 | if(fixture["runTest"]){ // should we error out of a fixture doesn't have a runTest? 534 | fixture.startTime = new Date(); 535 | var ret = fixture.runTest(this); 536 | fixture.endTime = new Date(); 537 | if(ret){ 538 | return ret; 539 | } 540 | } 541 | if(fixture["tearDown"]){ 542 | fixture.tearDown(this); 543 | } 544 | }catch(e){ 545 | this._handleFailure(groupName, fixture, e); 546 | err = e; 547 | if(!fixture.endTime){ 548 | fixture.endTime = new Date(); 549 | } 550 | } 551 | } 552 | 553 | doh._testId = 0; 554 | doh.runGroup = function(/*String*/ groupName, /*Integer*/ idx){ 555 | // summary: 556 | // runs the specified test group 557 | 558 | var tg = this._groups[groupName]; 559 | if(tg.skip === true){ return; } 560 | if(this._isArray(tg)){ 561 | if(idx<=tg.length){ 562 | if(!tg.inFlight){ 563 | if(tg["tearDown"]){ tg.tearDown(this); } 564 | doh._groupFinished(groupName, !tg.failures); 565 | return; 566 | } 567 | } 568 | if(!idx){ 569 | tg.inFlight = 0; 570 | tg.iterated = false; 571 | tg.failures = 0; 572 | } 573 | doh._groupStarted(groupName); 574 | if(!idx){ 575 | this._setupGroupForRun(groupName, idx); 576 | if(tg["setUp"]){ tg.setUp(this); } 577 | } 578 | for(var y=(idx||0); y= 0)) { 191 | this._fire(); 192 | } 193 | }, 194 | 195 | _continue: function(res){ 196 | this._resback(res); 197 | this._unpause(); 198 | }, 199 | 200 | _resback: function(res){ 201 | this.fired = ((res instanceof Error) ? 1 : 0); 202 | this.results[this.fired] = res; 203 | this._fire(); 204 | }, 205 | 206 | _check: function(){ 207 | if(this.fired != -1){ 208 | if(!this.silentlyCancelled){ 209 | throw new Error("already called!"); 210 | } 211 | this.silentlyCancelled = false; 212 | return; 213 | } 214 | }, 215 | 216 | callback: function(res){ 217 | this._check(); 218 | this._resback(res); 219 | }, 220 | 221 | errback: function(res){ 222 | this._check(); 223 | if(!(res instanceof Error)){ 224 | res = new Error(res); 225 | } 226 | this._resback(res); 227 | }, 228 | 229 | addBoth: function(cb, cbfn){ 230 | var enclosed = this.getFunctionFromArgs(cb, cbfn); 231 | if(arguments.length > 2){ 232 | enclosed = doh.hitch(null, enclosed, arguments, 2); 233 | } 234 | return this.addCallbacks(enclosed, enclosed); 235 | }, 236 | 237 | addCallback: function(cb, cbfn){ 238 | var enclosed = this.getFunctionFromArgs(cb, cbfn); 239 | if(arguments.length > 2){ 240 | enclosed = doh.hitch(null, enclosed, arguments, 2); 241 | } 242 | return this.addCallbacks(enclosed, null); 243 | }, 244 | 245 | addErrback: function(cb, cbfn){ 246 | var enclosed = this.getFunctionFromArgs(cb, cbfn); 247 | if(arguments.length > 2){ 248 | enclosed = doh.hitch(null, enclosed, arguments, 2); 249 | } 250 | return this.addCallbacks(null, enclosed); 251 | }, 252 | 253 | addCallbacks: function(cb, eb){ 254 | this.chain.push([cb, eb]); 255 | if(this.fired >= 0){ 256 | this._fire(); 257 | } 258 | return this; 259 | }, 260 | 261 | _fire: function(){ 262 | var chain = this.chain; 263 | var fired = this.fired; 264 | var res = this.results[fired]; 265 | var self = this; 266 | var cb = null; 267 | while(chain.length > 0 && this.paused == 0){ 268 | // Array 269 | var pair = chain.shift(); 270 | var f = pair[fired]; 271 | if(f == null){ 272 | continue; 273 | } 274 | try { 275 | res = f(res); 276 | fired = ((res instanceof Error) ? 1 : 0); 277 | if(res instanceof doh.Deferred){ 278 | cb = function(res){ 279 | self._continue(res); 280 | }; 281 | this._pause(); 282 | } 283 | }catch(err){ 284 | fired = 1; 285 | res = err; 286 | } 287 | } 288 | this.fired = fired; 289 | this.results[fired] = res; 290 | if((cb)&&(this.paused)){ 291 | res.addBoth(cb); 292 | } 293 | } 294 | }); 295 | 296 | // 297 | // State Keeping and Reporting 298 | // 299 | 300 | doh._testCount = 0; 301 | doh._groupCount = 0; 302 | doh._errorCount = 0; 303 | doh._failureCount = 0; 304 | doh._currentGroup = null; 305 | doh._currentTest = null; 306 | doh._paused = true; 307 | 308 | doh._init = function(){ 309 | this._currentGroup = null; 310 | this._currentTest = null; 311 | this._errorCount = 0; 312 | this._failureCount = 0; 313 | this.debug(this._testCount, "tests to run in", this._groupCount, "groups"); 314 | } 315 | 316 | // doh._urls = []; 317 | doh._groups = {}; 318 | 319 | // 320 | // Test Registration 321 | // 322 | 323 | doh.registerTestNs = function(/*String*/ group, /*Object*/ ns){ 324 | // summary: 325 | // adds the passed namespace object to the list of objects to be 326 | // searched for test groups. Only "public" functions (not prefixed 327 | // with "_") will be added as tests to be run. If you'd like to use 328 | // fixtures (setUp(), tearDown(), and runTest()), please use 329 | // registerTest() or registerTests(). 330 | for(var x in ns){ 331 | if( (x.charAt(0) != "_") && 332 | (typeof ns[x] == "function") ){ 333 | this.registerTest(group, ns[x]); 334 | } 335 | } 336 | } 337 | 338 | doh._testRegistered = function(group, fixture){ 339 | // slot to be filled in 340 | } 341 | 342 | doh._groupStarted = function(group){ 343 | // slot to be filled in 344 | } 345 | 346 | doh._groupFinished = function(group, success){ 347 | // slot to be filled in 348 | } 349 | 350 | doh._testStarted = function(group, fixture){ 351 | // slot to be filled in 352 | } 353 | 354 | doh._testFinished = function(group, fixture, success){ 355 | // slot to be filled in 356 | } 357 | 358 | doh.registerGroup = function( /*String*/ group, 359 | /*Array||Function||Object*/ tests, 360 | /*Function*/ setUp, 361 | /*Function*/ tearDown){ 362 | // summary: 363 | // registers an entire group of tests at once and provides a setUp and 364 | // tearDown facility for groups. If you call this method with only 365 | // setUp and tearDown parameters, they will replace previously 366 | // installed setUp or tearDown functions for the group with the new 367 | // methods. 368 | // group: 369 | // string name of the group 370 | // tests: 371 | // either a function or an object or an array of functions/objects. If 372 | // an object, it must contain at *least* a "runTest" method, and may 373 | // also contain "setUp" and "tearDown" methods. These will be invoked 374 | // on either side of the "runTest" method (respectively) when the test 375 | // is run. If an array, it must contain objects matching the above 376 | // description or test functions. 377 | // setUp: a function for initializing the test group 378 | // tearDown: a function for initializing the test group 379 | if(tests){ 380 | this.register(group, tests); 381 | } 382 | if(setUp){ 383 | this._groups[group].setUp = setUp; 384 | } 385 | if(tearDown){ 386 | this._groups[group].tearDown = tearDown; 387 | } 388 | } 389 | 390 | doh._getTestObj = function(group, test){ 391 | var tObj = test; 392 | if(typeof test == "string"){ 393 | if(test.substr(0, 4)=="url:"){ 394 | return this.registerUrl(group, test); 395 | }else{ 396 | tObj = { 397 | name: test.replace("/\s/g", "_") // FIXME: bad escapement 398 | }; 399 | tObj.runTest = new Function("t", test); 400 | } 401 | }else if(typeof test == "function"){ 402 | // if we didn't get a fixture, wrap the function 403 | tObj = { "runTest": test }; 404 | if(test["name"]){ 405 | tObj.name = test.name; 406 | }else{ 407 | try{ 408 | var fStr = "function "; 409 | var ts = tObj.runTest+""; 410 | if(0 <= ts.indexOf(fStr)){ 411 | tObj.name = ts.split(fStr)[1].split("(", 1)[0]; 412 | } 413 | // doh.debug(tObj.runTest.toSource()); 414 | }catch(e){ 415 | } 416 | } 417 | // FIXME: try harder to get the test name here 418 | } 419 | return tObj; 420 | } 421 | 422 | doh.registerTest = function(/*String*/ group, /*Function||Object*/ test){ 423 | // summary: 424 | // add the provided test function or fixture object to the specified 425 | // test group. 426 | // group: 427 | // string name of the group to add the test to 428 | // test: 429 | // either a function or an object. If an object, it must contain at 430 | // *least* a "runTest" method, and may also contain "setUp" and 431 | // "tearDown" methods. These will be invoked on either side of the 432 | // "runTest" method (respectively) when the test is run. 433 | if(!this._groups[group]){ 434 | this._groupCount++; 435 | this._groups[group] = []; 436 | this._groups[group].inFlight = 0; 437 | } 438 | var tObj = this._getTestObj(group, test); 439 | if(!tObj){ return null; } 440 | this._groups[group].push(tObj); 441 | this._testCount++; 442 | this._testRegistered(group, tObj); 443 | return tObj; 444 | } 445 | 446 | doh.registerTests = function(/*String*/ group, /*Array*/ testArr){ 447 | // summary: 448 | // registers a group of tests, treating each element of testArr as 449 | // though it were being (along with group) passed to the registerTest 450 | // method. 451 | for(var x=0; x 1) ? "s" : "")+" to run"); 645 | } 646 | 647 | doh._handleFailure = function(groupName, fixture, e){ 648 | // this.debug("FAILED test:", fixture.name); 649 | // mostly borrowed from JUM 650 | this._groups[groupName].failures++; 651 | var out = ""; 652 | if(e instanceof this._AssertFailure){ 653 | this._failureCount++; 654 | if(e["fileName"]){ out += e.fileName + ':'; } 655 | if(e["lineNumber"]){ out += e.lineNumber + ' '; } 656 | out += e+": "+e.message; 657 | this.debug("\t_AssertFailure:", out); 658 | }else{ 659 | this._errorCount++; 660 | } 661 | this.debug(e); 662 | if(fixture.runTest["toSource"]){ 663 | var ss = fixture.runTest.toSource(); 664 | this.debug(" ", fixture.name||ss); 665 | if (e.stack) { 666 | this.debug(e.stack); 667 | } 668 | }else{ 669 | this.debug(" ", fixture.name||fixture.runTest); 670 | if (e.stack) { 671 | this.debug(e.stack); 672 | } 673 | } 674 | 675 | if(e.rhinoException){ 676 | e.rhinoException.printStackTrace(); 677 | }else if(e.javaException){ 678 | e.javaException.printStackTrace(); 679 | } 680 | } 681 | 682 | try{ 683 | setTimeout(function(){}, 0); 684 | }catch(e){ 685 | setTimeout = function(func){ 686 | return func(); 687 | } 688 | } 689 | 690 | doh._runFixture = function(groupName, fixture){ 691 | var tg = this._groups[groupName]; 692 | this._testStarted(groupName, fixture); 693 | var threw = false; 694 | var err = null; 695 | // run it, catching exceptions and reporting them 696 | try{ 697 | // let doh reference "this.group.thinger..." which can be set by 698 | // another test or group-level setUp function 699 | fixture.group = tg; 700 | // only execute the parts of the fixture we've got 701 | doh.debug("TEST:", fixture.name); 702 | if(fixture["setUp"]){ fixture.setUp(this); } 703 | if(fixture["runTest"]){ // should we error out of a fixture doesn't have a runTest? 704 | fixture.startTime = new Date(); 705 | var ret = fixture.runTest(this); 706 | fixture.endTime = new Date(); 707 | // if we get a deferred back from the test runner, we know we're 708 | // gonna wait for an async result. It's up to the test code to trap 709 | // errors and give us an errback or callback. 710 | if(ret instanceof doh.Deferred){ 711 | 712 | tg.inFlight++; 713 | ret.groupName = groupName; 714 | ret.fixture = fixture; 715 | 716 | ret.addErrback(function(err){ 717 | doh._handleFailure(groupName, fixture, err); 718 | }); 719 | 720 | var retEnd = function(){ 721 | if(fixture["tearDown"]){ fixture.tearDown(doh); } 722 | tg.inFlight--; 723 | if((!tg.inFlight)&&(tg.iterated)){ 724 | doh._groupFinished(groupName, !tg.failures); 725 | } 726 | doh._testFinished(groupName, fixture, ret.results[0]); 727 | if(doh._paused){ 728 | doh.run(); 729 | } 730 | } 731 | 732 | var timer = setTimeout(function(){ 733 | // ret.cancel(); 734 | // retEnd(); 735 | ret.errback(new Error("test timeout in "+fixture.name.toString())); 736 | }, fixture["timeout"]||1000); 737 | 738 | ret.addBoth(function(arg){ 739 | clearTimeout(timer); 740 | retEnd(); 741 | }); 742 | if(ret.fired < 0){ 743 | doh.pause(); 744 | } 745 | return ret; 746 | } 747 | } 748 | if(fixture["tearDown"]){ fixture.tearDown(this); } 749 | }catch(e){ 750 | threw = true; 751 | err = e; 752 | if(!fixture.endTime){ 753 | fixture.endTime = new Date(); 754 | } 755 | } 756 | var d = new doh.Deferred(); 757 | setTimeout(this.hitch(this, function(){ 758 | if(threw){ 759 | this._handleFailure(groupName, fixture, err); 760 | } 761 | this._testFinished(groupName, fixture, !threw); 762 | 763 | if((!tg.inFlight)&&(tg.iterated)){ 764 | doh._groupFinished(groupName, !tg.failures); 765 | }else if(tg.inFlight > 0){ 766 | setTimeout(this.hitch(this, function(){ 767 | doh.runGroup(groupName); // , idx); 768 | }), 100); 769 | this._paused = true; 770 | } 771 | if(doh._paused){ 772 | doh.run(); 773 | } 774 | }), 30); 775 | doh.pause(); 776 | return d; 777 | } 778 | 779 | doh._testId = 0; 780 | doh.runGroup = function(/*String*/ groupName, /*Integer*/ idx){ 781 | // summary: 782 | // runs the specified test group 783 | 784 | // the general structure of the algorithm is to run through the group's 785 | // list of doh, checking before and after each of them to see if we're in 786 | // a paused state. This can be caused by the test returning a deferred or 787 | // the user hitting the pause button. In either case, we want to halt 788 | // execution of the test until something external to us restarts it. This 789 | // means we need to pickle off enough state to pick up where we left off. 790 | 791 | // FIXME: need to make fixture execution async!! 792 | 793 | var tg = this._groups[groupName]; 794 | if(tg.skip === true){ return; } 795 | if(this._isArray(tg)){ 796 | if(idx<=tg.length){ 797 | if((!tg.inFlight)&&(tg.iterated == true)){ 798 | if(tg["tearDown"]){ tg.tearDown(this); } 799 | doh._groupFinished(groupName, !tg.failures); 800 | return; 801 | } 802 | } 803 | if(!idx){ 804 | tg.inFlight = 0; 805 | tg.iterated = false; 806 | tg.failures = 0; 807 | } 808 | doh._groupStarted(groupName); 809 | if(!idx){ 810 | this._setupGroupForRun(groupName, idx); 811 | if(tg["setUp"]){ tg.setUp(this); } 812 | } 813 | for(var y=(idx||0); y 5 | # 6 | # Use of this source code is governed under the Apache License, Version 2.0 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Run it through uglify. 10 | python post.py ../src/Promise.js > ../bin/Promise.min.js 11 | -------------------------------------------------------------------------------- /util/console.js: -------------------------------------------------------------------------------- 1 | (function(global) { 2 | if (typeof global.console != "undefined") { 3 | return; 4 | } 5 | 6 | var toString = function(item) { 7 | var t = (typeof item); 8 | if (t == "undefined") { 9 | return "undefined"; 10 | } else if (t == "string") { 11 | return item; 12 | } else if (t == "number") { 13 | return item + ""; 14 | } else if (item instanceof Array) { 15 | return item + ""; 16 | } 17 | return item + ""; 18 | } 19 | 20 | // A minimal console 21 | var log = function(hint, args){ 22 | var r = ""; 23 | var al = args.length; 24 | r += ((hint ? hint + ":" : "") + (args[0] ? toString(args[0]) : "")); 25 | for(var i = 1; i < al; i++){ 26 | r += (" " + toString(args[i])); 27 | } 28 | print(r); 29 | }; 30 | 31 | var makeLogger = function(hint) { 32 | return function() { 33 | log(hint, Array.prototype.slice.call(arguments, 0)); 34 | }; 35 | } 36 | 37 | // Intentionally define console in the global namespace 38 | global.console = { 39 | log: makeLogger(""), 40 | error: makeLogger("ERROR"), 41 | warn: makeLogger("WARN"), 42 | trace: makeLogger("TRACE"), 43 | time: function() {}, 44 | timeEnd: function() {}, 45 | profile: function() {}, 46 | profileEnd: function() {}, 47 | }; 48 | 49 | })(this); 50 | -------------------------------------------------------------------------------- /util/post.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012: 2 | # Alex Russell 3 | # 4 | # Use of this source code is governed under the Apache License, Version 2.0 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | 8 | import httplib, urllib, fileinput 9 | 10 | if __name__ == "__main__": 11 | params = urllib.urlencode({ 12 | "js_code": ''.join([ line for line in fileinput.input() ]) 13 | }) 14 | headers = { 15 | "Content-type": "application/x-www-form-urlencoded", 16 | "Accept": "text/plain" 17 | } 18 | conn = httplib.HTTPConnection("marijnhaverbeke.nl") 19 | conn.request("POST", "/uglifyjs", params, headers) 20 | response = conn.getresponse() 21 | data = response.read() 22 | print data 23 | conn.close() 24 | --------------------------------------------------------------------------------