├── .gitignore
├── Makefile
├── Promise.csproj
├── Promise.js
├── Promise.nuspec
├── Promise.sln
├── Promise.ts
├── PromiseTests.js
├── PromiseTests.ts
├── README.md
├── Scripts
└── typings
│ └── qunit
│ └── qunit.d.ts
├── index.html
├── packages.config
├── packages
└── repositories.config
├── web.Debug.config
├── web.Release.config
└── web.config
/.gitignore:
--------------------------------------------------------------------------------
1 | /.vs/
2 | /bin/
3 | /obj/
4 | /promise_all.*
5 | /*.user
6 | /*.nupkg
7 | /*.suo
8 | /packages/
9 | !/packages/repositories.config
10 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | id=Promise.TypeScript
2 | version=1.0-rc
3 | package=${id}.${version}.nupkg
4 |
5 | .PHONY: pushnuget
6 | pushnuget: nuget
7 | nuget push ${package}
8 |
9 | .PHONY: nuget
10 | nuget:
11 | nuget pack -Properties "Name=${id};Version=${version}" Promise.nuspec
12 |
13 |
--------------------------------------------------------------------------------
/Promise.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | {601A876B-45BD-41C9-AA85-F96ACB4FDB8D}
6 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
7 | Library
8 | bin
9 | v4.0
10 | full
11 | true
12 | true
13 |
14 |
15 |
16 |
17 | ..\
18 | true
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | web.config
40 |
41 |
42 | web.config
43 |
44 |
45 |
46 | 10.0
47 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
48 |
49 |
50 | Promise
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | True
59 | True
60 | 0
61 | /
62 | http://localhost:7375/
63 | False
64 | False
65 |
66 |
67 | False
68 |
69 |
70 |
71 |
72 |
73 | ES5
74 | true
75 | true
76 | AMD
77 | promise_all.js
78 |
79 |
80 | ES5
81 | false
82 | false
83 | AMD
84 | promise_all.js
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/Promise.js:
--------------------------------------------------------------------------------
1 | var P;
2 | (function (P) {
3 | function defer() {
4 | return new DeferredI();
5 | }
6 | P.defer = defer;
7 | function resolve(v) {
8 | if (typeof v === "undefined") { v = {}; }
9 | return defer().resolve(v).promise();
10 | }
11 | P.resolve = resolve;
12 | function reject(err) {
13 | return defer().reject(err).promise();
14 | }
15 | P.reject = reject;
16 | function unfold(unspool, seed) {
17 | var d = defer();
18 | var elements = [];
19 | unfoldCore(elements, d, unspool, seed);
20 | return d.promise();
21 | }
22 | P.unfold = unfold;
23 | function unfoldCore(elements, deferred, unspool, seed) {
24 | var result = unspool(seed);
25 | if (!result) {
26 | deferred.resolve(elements);
27 | return;
28 | }
29 | while(result.next && result.promise.status == P.Status.Resolved) {
30 | elements.push(result.promise.result);
31 | result = unspool(result.next);
32 | if (!result) {
33 | deferred.resolve(elements);
34 | return;
35 | }
36 | }
37 | result.promise.done(function (v) {
38 | elements.push(v);
39 | if (!result.next) {
40 | deferred.resolve(elements);
41 | } else {
42 | unfoldCore(elements, deferred, unspool, result.next);
43 | }
44 | }).fail(function (e) {
45 | deferred.reject(e);
46 | });
47 | }
48 | (function (Status) {
49 | Status._map = [];
50 | Status._map[0] = "Unfulfilled";
51 | Status.Unfulfilled = 0;
52 | Status._map[1] = "Rejected";
53 | Status.Rejected = 1;
54 | Status._map[2] = "Resolved";
55 | Status.Resolved = 2;
56 | })(P.Status || (P.Status = {}));
57 | var Status = P.Status;
58 | function when() {
59 | var promises = [];
60 | for (var _i = 0; _i < (arguments.length - 0); _i++) {
61 | promises[_i] = arguments[_i + 0];
62 | }
63 | var allDone = defer();
64 | if (!promises.length) {
65 | allDone.resolve([]);
66 | return allDone.promise();
67 | }
68 | var resolved = 0;
69 | var results = [];
70 | promises.forEach(function (p, i) {
71 | p.done(function (v) {
72 | results[i] = v;
73 | ++resolved;
74 | if (resolved === promises.length && allDone.status != Status.Rejected) {
75 | allDone.resolve(results);
76 | }
77 | }).fail(function (e) {
78 | allDone.reject(new Error("when: one or more promises were rejected"));
79 | });
80 | });
81 | return allDone.promise();
82 | }
83 | P.when = when;
84 | var PromiseI = (function () {
85 | function PromiseI(deferred) {
86 | this.deferred = deferred;
87 | }
88 | Object.defineProperty(PromiseI.prototype, "status", {
89 | get: function () {
90 | return this.deferred.status;
91 | },
92 | enumerable: true,
93 | configurable: true
94 | });
95 | Object.defineProperty(PromiseI.prototype, "result", {
96 | get: function () {
97 | return this.deferred.result;
98 | },
99 | enumerable: true,
100 | configurable: true
101 | });
102 | Object.defineProperty(PromiseI.prototype, "error", {
103 | get: function () {
104 | return this.deferred.error;
105 | },
106 | enumerable: true,
107 | configurable: true
108 | });
109 | PromiseI.prototype.done = function (f) {
110 | this.deferred.done(f);
111 | return this;
112 | };
113 | PromiseI.prototype.fail = function (f) {
114 | this.deferred.fail(f);
115 | return this;
116 | };
117 | PromiseI.prototype.always = function (f) {
118 | this.deferred.always(f);
119 | return this;
120 | };
121 | PromiseI.prototype.then = function (f) {
122 | return this.deferred.then(f);
123 | };
124 | PromiseI.prototype.thenConvert = function (f) {
125 | return this.deferred.thenConvert(f);
126 | };
127 | return PromiseI;
128 | })();
129 | var DeferredI = (function () {
130 | function DeferredI() {
131 | this._resolved = function (_) {
132 | };
133 | this._rejected = function (_) {
134 | };
135 | this._status = Status.Unfulfilled;
136 | this._error = {
137 | message: ""
138 | };
139 | this._promise = new PromiseI(this);
140 | }
141 | DeferredI.prototype.promise = function () {
142 | return this._promise;
143 | };
144 | Object.defineProperty(DeferredI.prototype, "status", {
145 | get: function () {
146 | return this._status;
147 | },
148 | enumerable: true,
149 | configurable: true
150 | });
151 | Object.defineProperty(DeferredI.prototype, "result", {
152 | get: function () {
153 | if (this._status != Status.Resolved) {
154 | throw new Error("Promise: result not available");
155 | }
156 | return this._result;
157 | },
158 | enumerable: true,
159 | configurable: true
160 | });
161 | Object.defineProperty(DeferredI.prototype, "error", {
162 | get: function () {
163 | if (this._status != Status.Rejected) {
164 | throw new Error("Promise: rejection reason not available");
165 | }
166 | return this._error;
167 | },
168 | enumerable: true,
169 | configurable: true
170 | });
171 | DeferredI.prototype.then = function (f) {
172 | var d = defer();
173 | this.done(function (v) {
174 | var p2 = f(v);
175 | p2.done(function (v2) {
176 | return d.resolve(v2);
177 | }).fail(function (err) {
178 | return d.reject(err);
179 | });
180 | }).fail(function (err) {
181 | return d.reject(err);
182 | });
183 | return d.promise();
184 | };
185 | DeferredI.prototype.thenConvert = function (f) {
186 | var d = defer();
187 | this.done(function (v) {
188 | return d.resolve(f(v));
189 | }).fail(function (err) {
190 | return d.reject(err);
191 | });
192 | return d.promise();
193 | };
194 | DeferredI.prototype.done = function (f) {
195 | if (this.status === Status.Resolved) {
196 | f(this._result);
197 | return this;
198 | }
199 | if (this.status !== Status.Unfulfilled) {
200 | return this;
201 | }
202 | var prev = this._resolved;
203 | this._resolved = function (v) {
204 | prev(v);
205 | f(v);
206 | };
207 | return this;
208 | };
209 | DeferredI.prototype.fail = function (f) {
210 | if (this.status === Status.Rejected) {
211 | f(this._error);
212 | return this;
213 | }
214 | if (this.status !== Status.Unfulfilled) {
215 | return this;
216 | }
217 | var prev = this._rejected;
218 | this._rejected = function (e) {
219 | prev(e);
220 | f(e);
221 | };
222 | return this;
223 | };
224 | DeferredI.prototype.always = function (f) {
225 | this.done(function (v) {
226 | return f(v);
227 | }).fail(function (err) {
228 | return f(null, err);
229 | });
230 | return this;
231 | };
232 | DeferredI.prototype.resolve = function (result) {
233 | if (this._status !== Status.Unfulfilled) {
234 | throw new Error("tried to resolve a fulfilled promise");
235 | }
236 | this._result = result;
237 | this._status = Status.Resolved;
238 | this._resolved(result);
239 | this.detach();
240 | return this;
241 | };
242 | DeferredI.prototype.reject = function (err) {
243 | if (this._status !== Status.Unfulfilled) {
244 | throw new Error("tried to reject a fulfilled promise");
245 | }
246 | this._error = err;
247 | this._status = Status.Rejected;
248 | this._rejected(err);
249 | this.detach();
250 | return this;
251 | };
252 | DeferredI.prototype.detach = function () {
253 | this._resolved = function (_) {
254 | };
255 | this._rejected = function (_) {
256 | };
257 | };
258 | return DeferredI;
259 | })();
260 | })(P || (P = {}));
261 |
--------------------------------------------------------------------------------
/Promise.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $Name$
5 | $Version$
6 | pragmatrix
7 | pragmatrix
8 | https://github.com/pragmatrix/Promise
9 | false
10 | Generic Promises for TypeScript 0.9 beta
11 | promises promise futures async-programming asynchronous async callbacks typescript
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Promise.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Promise", "Promise.csproj", "{601A876B-45BD-41C9-AA85-F96ACB4FDB8D}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {601A876B-45BD-41C9-AA85-F96ACB4FDB8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {601A876B-45BD-41C9-AA85-F96ACB4FDB8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {601A876B-45BD-41C9-AA85-F96ACB4FDB8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {601A876B-45BD-41C9-AA85-F96ACB4FDB8D}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Promise.ts:
--------------------------------------------------------------------------------
1 | /**
2 | Module P: Generic Promises for TypeScript
3 |
4 | Project, documentation, and license: https://github.com/pragmatrix/Promise
5 | */
6 |
7 | module P {
8 |
9 | /**
10 | Returns a new "Deferred" value that may be resolved or rejected.
11 | */
12 |
13 | export function defer(): Deferred
14 | {
15 | return new DeferredI();
16 | }
17 |
18 | /**
19 | Converts a value to a resolved promise.
20 | */
21 |
22 | export function resolve(v: Value): Promise
23 | {
24 | return defer().resolve(v).promise();
25 | }
26 |
27 | /**
28 | Returns a rejected promise.
29 | */
30 |
31 | export function reject(err: Rejection): Promise
32 | {
33 | return defer().reject(err).promise();
34 | }
35 |
36 | /**
37 | http://en.wikipedia.org/wiki/Anamorphism
38 |
39 | Given a seed value, unfold calls the unspool function, waits for the returned promise to be resolved, and then
40 | calls it again if a next seed value was returned.
41 |
42 | All the values of all promise results are collected into the resulting promise which is resolved as soon
43 | the last generated element value is resolved.
44 | */
45 |
46 | export function unfold(
47 | unspool: (current: Seed) => { promise: Promise; next?: Seed },
48 | seed: Seed)
49 | : Promise
50 | {
51 | var d = defer();
52 | var elements: Element[] = new Array();
53 |
54 | unfoldCore(elements, d, unspool, seed)
55 |
56 | return d.promise();
57 | }
58 |
59 | function unfoldCore(
60 | elements: Element[],
61 | deferred: Deferred,
62 | unspool: (current: Seed) => { promise: Promise; next?: Seed },
63 | seed: Seed): void
64 | {
65 | var result = unspool(seed);
66 | if (!result) {
67 | deferred.resolve(elements);
68 | return;
69 | }
70 |
71 | // fastpath: don't waste stack space if promise resolves immediately.
72 |
73 | while (result.next && result.promise.status == P.Status.Resolved)
74 | {
75 | elements.push(result.promise.result);
76 | result = unspool(result.next);
77 | if (!result) {
78 | deferred.resolve(elements);
79 | return;
80 | }
81 | }
82 |
83 | result.promise
84 | .done(v =>
85 | {
86 | elements.push(v);
87 | if (!result.next)
88 | deferred.resolve(elements);
89 | else
90 | unfoldCore(elements, deferred, unspool, result.next);
91 | } )
92 | .fail(e =>
93 | {
94 | deferred.reject(e);
95 | } );
96 | }
97 |
98 | /**
99 | The status of a Promise. Initially a Promise is Unfulfilled and may
100 | change to Rejected or Resolved.
101 |
102 | Once a promise is either Rejected or Resolved, it can not change its
103 | status anymore.
104 | */
105 |
106 | export enum Status {
107 | Unfulfilled,
108 | Rejected,
109 | Resolved
110 | }
111 |
112 | /**
113 | If a promise gets rejected, at least a message that indicates the error or
114 | reason for the rejection must be provided.
115 | */
116 |
117 | export interface Rejection
118 | {
119 | message: string;
120 | }
121 |
122 | /**
123 | Both Promise and Deferred share these properties.
124 | */
125 |
126 | export interface PromiseState
127 | {
128 | /// The current status of the promise.
129 | status: Status;
130 |
131 | /// If the promise got resolved, the result of the promise.
132 | result?: Value;
133 |
134 | /// If the promise got rejected, the rejection message.
135 | error?: Rejection;
136 | }
137 |
138 | /**
139 | A Promise supports basic composition and registration of handlers that are called when the
140 | promise is fulfilled.
141 |
142 | When multiple handlers are registered with done(), fail(), or always(), they are called in the
143 | same order.
144 | */
145 |
146 | export interface Promise extends PromiseState
147 | {
148 | /**
149 | Returns a promise that represents a promise chain that consists of this
150 | promise and the promise that is returned by the function provided.
151 | The function receives the value of this promise as soon it is resolved.
152 |
153 | If this promise fails, the function is never called and the returned promise
154 | will also fail.
155 | */
156 | then(f: (v: Value) => Promise): Promise;
157 | then(f: (v: Value) => T2): Promise;
158 |
159 | /// Add a handler that is called when the promise gets resolved.
160 | done(f: (v: Value) => void ): Promise;
161 | /// Add a handler that is called when the promise gets rejected.
162 | fail(f: (err: Rejection) => void ): Promise;
163 | /// Add a handler that is called when the promise gets fulfilled (either resolved or rejected).
164 | always(f: (v?: Value, err?: Rejection) => void ): Promise;
165 | }
166 |
167 | /**
168 | Deferred supports the explicit resolving and rejecting of the
169 | promise and the registration of fulfillment handlers.
170 |
171 | A Deferred should be only visible to the function that initially sets up
172 | an asynchronous process. Callers of that function should only see the Promise that
173 | is returned by promise().
174 | */
175 |
176 | export interface Deferred extends PromiseState
177 | {
178 | /// Returns the encapsulated promise of this deferred instance.
179 | /// The returned promise supports composition but removes the ability to resolve or reject
180 | /// the promise.
181 | promise(): Promise;
182 |
183 | /// Resolve the promise.
184 | resolve(result: Value): Deferred;
185 | /// Reject the promise.
186 | reject(err: Rejection): Deferred;
187 |
188 | done(f: (v: Value) => void ): Deferred;
189 | fail(f: (err: Rejection) => void ): Deferred;
190 | always(f: (v?: Value, err?: Rejection) => void ): Deferred;
191 | }
192 |
193 | /**
194 | Creates a promise that gets resolved when all the promises in the argument list get resolved.
195 | As soon one of the arguments gets rejected, the resulting promise gets rejected.
196 | If no promises were provided, the resulting promise is immediately resolved.
197 | */
198 |
199 | export function when(...promises: Promise[]): Promise
200 | {
201 | var allDone = defer();
202 | if (!promises.length) {
203 | allDone.resolve([]);
204 | return allDone.promise();
205 | }
206 |
207 | var resolved = 0;
208 | var results = [];
209 |
210 | promises.forEach((p, i) => {
211 | p
212 | .done(v => {
213 | results[i] = v;
214 | ++resolved;
215 | if (resolved === promises.length && allDone.status !== Status.Rejected)
216 | allDone.resolve(results);
217 | } )
218 | .fail(e => {
219 | if (allDone.status !== Status.Rejected)
220 | allDone.reject(new Error("when: one or more promises were rejected"));
221 | } );
222 | } );
223 |
224 | return allDone.promise();
225 | }
226 |
227 | /**
228 | Implementation of a promise.
229 |
230 | The Promise instance is a proxy to the Deferred instance.
231 | */
232 |
233 | class PromiseI implements Promise
234 | {
235 | constructor(public deferred: DeferredI)
236 | { }
237 |
238 | get status(): Status { return this.deferred.status; }
239 | get result(): Value { return this.deferred.result; }
240 | get error(): Rejection { return this.deferred.error; }
241 |
242 | done(f: (v: Value) => void ): Promise {
243 | this.deferred.done(f);
244 | return this;
245 | }
246 |
247 | fail(f: (err: Rejection) => void ): Promise {
248 | this.deferred.fail(f);
249 | return this;
250 | }
251 |
252 | always(f: (v?: Value, err?: Rejection) => void ): Promise {
253 | this.deferred.always(f);
254 | return this;
255 | }
256 |
257 | then(f: (v: Value) => any): Promise
258 | {
259 | return this.deferred.then(f);
260 | }
261 | }
262 |
263 | /**
264 | Implementation of a deferred.
265 | */
266 |
267 | class DeferredI implements Deferred{
268 |
269 | private _resolved: (v: Value) => void = _ => { };
270 | private _rejected: (err: Rejection) => void = _ => { };
271 |
272 | private _status: Status = Status.Unfulfilled;
273 | private _result: Value;
274 | private _error: Rejection = { message: "" };
275 | private _promise: Promise;
276 |
277 | constructor() {
278 | this._promise = new PromiseI(this);
279 | }
280 |
281 | promise(): Promise {
282 | return this._promise;
283 | }
284 |
285 | get status(): Status {
286 | return this._status;
287 | }
288 |
289 | get result(): Value {
290 | if (this._status != Status.Resolved)
291 | throw new Error("Promise: result not available");
292 | return this._result;
293 | }
294 |
295 | get error(): Rejection {
296 | if (this._status != Status.Rejected)
297 | throw new Error("Promise: rejection reason not available");
298 | return this._error;
299 | }
300 |
301 | then(f: (v: Value) => any): Promise
302 | {
303 | var d = defer();
304 |
305 | this
306 | .done(v =>
307 | {
308 | var promiseOrValue = f(v);
309 |
310 | // todo: need to find another way to check if r is really of interface
311 | // type Promise, otherwise we would not support other
312 | // implementations here.
313 | if (promiseOrValue instanceof PromiseI)
314 | {
315 | var p = > promiseOrValue;
316 | p.done(v2 => d.resolve(v2))
317 | .fail(err => d.reject(err));
318 | return p;
319 | }
320 |
321 | d.resolve(promiseOrValue);
322 | } )
323 | .fail(err => d.reject(err));
324 |
325 | return d.promise();
326 | }
327 |
328 | done(f: (v: Value) => void ): Deferred
329 | {
330 | if (this.status === Status.Resolved) {
331 | f(this._result);
332 | return this;
333 | }
334 |
335 | if (this.status !== Status.Unfulfilled)
336 | return this;
337 |
338 | var prev = this._resolved;
339 | this._resolved = v => { prev(v); f(v); }
340 |
341 | return this;
342 | }
343 |
344 | fail(f: (err: Rejection) => void ): Deferred
345 | {
346 | if (this.status === Status.Rejected) {
347 | f(this._error);
348 | return this;
349 | }
350 |
351 | if (this.status !== Status.Unfulfilled)
352 | return this;
353 |
354 | var prev = this._rejected;
355 | this._rejected = e => { prev(e); f(e); }
356 |
357 | return this;
358 | }
359 |
360 | always(f: (v?: Value, err?: Rejection) => void ): Deferred
361 | {
362 | this
363 | .done(v => f(v))
364 | .fail(err => f(null, err));
365 |
366 | return this;
367 | }
368 |
369 | resolve(result: Value) {
370 | if (this._status !== Status.Unfulfilled)
371 | throw new Error("tried to resolve a fulfilled promise");
372 |
373 | this._result = result;
374 | this._status = Status.Resolved;
375 | this._resolved(result);
376 |
377 | this.detach();
378 | return this;
379 | }
380 |
381 | reject(err: Rejection) {
382 | if (this._status !== Status.Unfulfilled)
383 | throw new Error("tried to reject a fulfilled promise");
384 |
385 | this._error = err;
386 | this._status = Status.Rejected;
387 | this._rejected(err);
388 |
389 | this.detach();
390 | return this;
391 | }
392 |
393 | private detach()
394 | {
395 | this._resolved = _ => { };
396 | this._rejected = _ => { };
397 | }
398 | }
399 |
400 | /**
401 | Promise Generators and Iterators.
402 | */
403 |
404 | export interface Generator
405 | {
406 | (): Iterator;
407 | }
408 |
409 | export interface Iterator
410 | {
411 | advance(): Promise;
412 | current: E;
413 | }
414 |
415 | export function generator(g: () => () => Promise): Generator
416 | {
417 | return () => iterator(g());
418 | };
419 |
420 | export function iterator(f: () => Promise): Iterator
421 | {
422 | return new IteratorI(f);
423 | }
424 |
425 | class IteratorI implements Iterator
426 | {
427 | current: E = undefined;
428 |
429 | constructor(private f: () => Promise)
430 | { }
431 |
432 | advance() : Promise
433 | {
434 | var res = this.f();
435 | return res.then(value =>
436 | {
437 | if (isUndefined(value))
438 | return false;
439 |
440 | this.current = value;
441 | return true;
442 | } );
443 | }
444 | }
445 |
446 | /**
447 | Iterator functions.
448 | */
449 |
450 | export function each(gen: Generator, f: (e: E) => void ): Promise<{}>
451 | {
452 | var d = defer();
453 | eachCore(d, gen(), f);
454 | return d.promise();
455 | }
456 |
457 | function eachCore(fin: Deferred<{}>, it: Iterator, f: (e: E) => void ) : void
458 | {
459 | it.advance()
460 | .done(hasValue =>
461 | {
462 | if (!hasValue)
463 | {
464 | fin.resolve({});
465 | return;
466 | }
467 |
468 | f(it.current)
469 | eachCore(fin, it, f);
470 | } )
471 | .fail(err => fin.reject(err));
472 | }
473 |
474 | /**
475 | std
476 | */
477 |
478 | export function isUndefined(v)
479 | {
480 | return typeof v === 'undefined';
481 | }
482 | }
--------------------------------------------------------------------------------
/PromiseTests.js:
--------------------------------------------------------------------------------
1 | var PromiseTests;
2 | (function (PromiseTests) {
3 | var defer = P.defer;
4 | var when = P.when;
5 | test("when resolve: status===Resolved", function () {
6 | var d = defer();
7 | d.resolve(0);
8 | ok(d.status === P.Status.Resolved);
9 | });
10 | test("when reject: status===Resolved", function () {
11 | var d = defer();
12 | d.reject({
13 | message: "na"
14 | });
15 | ok(d.status === P.Status.Rejected);
16 | });
17 | test("when resolved twice throw", function () {
18 | var d = defer();
19 | d.resolve(0);
20 | throws(function () {
21 | d.resolve(1);
22 | });
23 | });
24 | test("when rejected twice throw", function () {
25 | var d = defer();
26 | d.reject({
27 | message: "nana"
28 | });
29 | throws(function () {
30 | d.reject({
31 | message: "ohoh"
32 | });
33 | });
34 | });
35 | test("when resolve: done", function () {
36 | var d = defer();
37 | d.done(function () {
38 | ok(true);
39 | });
40 | d.resolve(1);
41 | });
42 | test("when already resolved: done", function () {
43 | var d = defer();
44 | d.resolve(1);
45 | d.done(function () {
46 | ok(true);
47 | });
48 | });
49 | test("when rejected: fail", function () {
50 | var d = defer();
51 | d.fail(function () {
52 | ok(true);
53 | });
54 | d.reject({
55 | message: "na"
56 | });
57 | });
58 | test("when already rejected rejected: fail", function () {
59 | var d = defer();
60 | d.reject({
61 | message: "na"
62 | });
63 | d.fail(function () {
64 | ok(true);
65 | });
66 | });
67 | test("when rejected, call always", function () {
68 | var d = defer();
69 | d.reject({
70 | message: "na"
71 | });
72 | d.always(function (v, err) {
73 | ok(!v && err.message === "na");
74 | });
75 | });
76 | test("when resolved, call always", function () {
77 | var d = defer();
78 | d.resolve(10);
79 | d.always(function (v, err) {
80 | ok(!err && v === 10);
81 | });
82 | });
83 | test("actually passes the value to the done", function () {
84 | var d = defer();
85 | d.done(function (value) {
86 | ok(4711 === value);
87 | });
88 | d.resolve(4711);
89 | });
90 | test("actually passes the error message to the fail handler", function () {
91 | var d = defer();
92 | d.fail(function (err) {
93 | ok("nana" === err.message);
94 | });
95 | d.reject({
96 | message: "nana"
97 | });
98 | });
99 | test("two done handler are called in sequence", function () {
100 | expect(2);
101 | var d = defer();
102 | var seq = 0;
103 | d.done(function () {
104 | ok(0 === seq++);
105 | });
106 | d.done(function () {
107 | ok(1 === seq++);
108 | });
109 | d.resolve(0);
110 | });
111 | test("two fail handler are called in sequence", function () {
112 | expect(2);
113 | var d = defer();
114 | var seq = 0;
115 | d.fail(function () {
116 | ok(0 === seq++);
117 | });
118 | d.fail(function () {
119 | ok(1 === seq++);
120 | });
121 | d.reject({
122 | message: ""
123 | });
124 | });
125 | test("then receives the value", function () {
126 | var d = defer();
127 | var d2 = d.promise().then(function (n) {
128 | ok(n === 10);
129 | return defer().promise();
130 | });
131 | d.resolve(10);
132 | });
133 | test("combined resolve", function () {
134 | expect(2);
135 | var d = defer();
136 | var p = d.promise().then(function (n) {
137 | ok(n === 10);
138 | var d2 = defer();
139 | d2.resolve(4);
140 | return d2.promise();
141 | });
142 | d.resolve(10);
143 | p.done(function (n) {
144 | return ok(n === 4);
145 | });
146 | });
147 | test("then: first rejected: first and outer fails", function () {
148 | expect(2);
149 | var first = defer();
150 | var outer = first.promise().then(function (n) {
151 | ok(false);
152 | return defer().promise();
153 | });
154 | first.fail(function (err) {
155 | ok(true);
156 | });
157 | outer.fail(function (err) {
158 | ok(true);
159 | });
160 | first.reject({
161 | message: "fail"
162 | });
163 | });
164 | test("then: first resolved and second rejected: second fails and outer fails", function () {
165 | expect(2);
166 | var first = defer();
167 | var second = defer();
168 | var outer = first.promise().then(function (n) {
169 | return second.promise();
170 | });
171 | second.fail(function (err) {
172 | ok(true);
173 | });
174 | outer.fail(function (err) {
175 | ok(true);
176 | });
177 | first.resolve(1);
178 | second.reject({
179 | message: "fail"
180 | });
181 | });
182 | test("when no arguments given, when resolves immediately", function () {
183 | var p = when();
184 | p.done(function (v) {
185 | ok(!v.length);
186 | });
187 | });
188 | test("when all are resolved, when resolves", function () {
189 | expect(3);
190 | var d = defer();
191 | var d2 = defer();
192 | var p = when(d.promise(), d2.promise());
193 | p.done(function (v) {
194 | ok(v.length === 2);
195 | ok(v[0] === 10);
196 | ok(v[1] === true);
197 | });
198 | d.resolve(10);
199 | d2.resolve(true);
200 | });
201 | test("when first fails, when fails", function () {
202 | var d = defer();
203 | var d2 = defer();
204 | var p = when(d.promise(), d2.promise());
205 | p.fail(function (err) {
206 | ok(true);
207 | });
208 | d.reject({
209 | message: "nana"
210 | });
211 | });
212 | test("when second fails, when fails", function () {
213 | var d = defer();
214 | var d2 = defer();
215 | var p = when(d.promise(), d2.promise());
216 | p.fail(function (err) {
217 | ok(true);
218 | });
219 | d2.reject({
220 | message: "nana"
221 | });
222 | });
223 | test("accessing the result property of a resolved promise does not throw", function () {
224 | var p = P.resolve(1);
225 | ok(1 === p.result);
226 | });
227 | test("accessing the result of an unfulfilled or rejected promise throws", function () {
228 | var d = defer();
229 | var p = d.promise();
230 | throws(function () {
231 | p.result;
232 | });
233 | d.reject({
234 | message: "no!"
235 | });
236 | throws(function () {
237 | p.result;
238 | });
239 | });
240 | test("accessing the error property of a rejected promise does not throw", function () {
241 | var d = defer();
242 | d.reject({
243 | message: "rejected"
244 | });
245 | ok(d.error.message === "rejected");
246 | });
247 | test("accessing the error property of an unfulfilled or resolved promise throws", function () {
248 | var d = defer();
249 | var p = d.promise();
250 | throws(function () {
251 | p.error;
252 | });
253 | d.resolve(1);
254 | throws(function () {
255 | p.error;
256 | });
257 | });
258 | })(PromiseTests || (PromiseTests = {}));
259 |
--------------------------------------------------------------------------------
/PromiseTests.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | module PromiseTests {
5 |
6 | var defer = P.defer;
7 | var when = P.when;
8 | interface Promise extends P.Promise {}
9 |
10 | // state
11 |
12 | test("when resolve: status===Resolved", () =>
13 | {
14 | var d = defer();
15 | d.resolve(0);
16 | ok(d.status === P.Status.Resolved);
17 | } );
18 |
19 | test("when reject: status===Resolved", () =>
20 | {
21 | var d = defer();
22 | d.reject({ message: "na" });
23 | ok(d.status === P.Status.Rejected);
24 | } );
25 |
26 | // double resolve reject
27 |
28 | test("when resolved twice throw", () =>
29 | {
30 | var d = defer();
31 | d.resolve(0);
32 | throws(() =>
33 | {
34 | d.resolve(1);
35 | } );
36 | } );
37 |
38 | test("when rejected twice throw", () =>
39 | {
40 | var d = defer();
41 | d.reject({ message: "nana" });
42 |
43 | throws(() =>
44 | {
45 | d.reject({ message: "ohoh" });
46 | } );
47 | } );
48 |
49 | // done / fail / always handlers
50 |
51 | test("when resolve: done", () =>
52 | {
53 | var d = defer();
54 | d.done(() => {
55 | ok(true);
56 | } );
57 |
58 | d.resolve(1);
59 | } );
60 |
61 | test("when already resolved: done", () =>
62 | {
63 | var d = defer();
64 | d.resolve(1);
65 | d.done(() => {
66 | ok(true);
67 | } );
68 | } );
69 |
70 | test("when rejected: fail", () =>
71 | {
72 | var d = defer();
73 | d.fail(() => {
74 | ok(true);
75 | } );
76 | d.reject({ message: "na" });
77 | } );
78 |
79 | test("when already rejected: fail", () =>
80 | {
81 | var d = defer();
82 | d.reject({ message: "na" });
83 | d.fail(() => {
84 | ok(true);
85 | } );
86 | } );
87 |
88 | test("when rejected, always call", () =>
89 | {
90 | var d = defer();
91 | d.reject({ message: "na" });
92 | d.always((v?, err?) => {
93 | ok(!v && err.message === "na");
94 | } );
95 | } );
96 |
97 | test("when resolved, always call", () =>
98 | {
99 | var d = defer();
100 | d.resolve(10);
101 | d.always((v?, err?) => {
102 | ok(!err && v === 10);
103 | } );
104 | } );
105 |
106 | // values and errors
107 |
108 | test("actually passes the value to done", () =>
109 | {
110 | var d = defer();
111 | d.done((value) => {
112 | ok(4711===value);
113 | } );
114 | d.resolve(4711);
115 | } );
116 |
117 | test("actually passes the error message to the fail handler", () =>
118 | {
119 | var d = defer();
120 | d.fail((err) => {
121 | ok("nana" === err.message);
122 | } );
123 | d.reject({ message: "nana" });
124 | } );
125 |
126 | // handler sequencing
127 |
128 | test("two done handler are called in sequence", () =>
129 | {
130 | expect(2);
131 |
132 | var d = defer();
133 | var seq = 0;
134 |
135 | d.done(() =>
136 | {
137 | ok(0 === seq++);
138 | } );
139 |
140 | d.done(() =>
141 | {
142 | ok(1 === seq++);
143 | } );
144 |
145 | d.resolve(0);
146 | } );
147 |
148 | test("two fail handler are called in sequence", () =>
149 | {
150 | expect(2);
151 |
152 | var d = defer();
153 | var seq = 0;
154 |
155 | d.fail(() =>
156 | {
157 | ok(0 === seq++);
158 | } );
159 |
160 | d.fail(() =>
161 | {
162 | ok(1 === seq++);
163 | } );
164 |
165 | d.reject({ message: "" });
166 | } );
167 |
168 | // then
169 |
170 | test("then receives the value", () =>
171 | {
172 | var d = defer();
173 | var d2 = d.promise().then(n => {
174 | ok(n === 10);
175 | return defer().promise();
176 | });
177 |
178 | d.resolve(10);
179 | } );
180 |
181 | test("combined resolve", () =>
182 | {
183 | expect(2);
184 |
185 | var d = defer();
186 | var p = d.promise().then(n => {
187 | ok(n === 10);
188 | var d2 = defer();
189 | d2.resolve(4);
190 | return d2.promise();
191 | } );
192 |
193 | d.resolve(10);
194 | p.done(n => ok(n === 4));
195 | } );
196 |
197 |
198 | test("then: first rejected: first and outer fails", () =>
199 | {
200 | expect(2);
201 |
202 | var first = defer();
203 | var outer = first.promise().then(n => {
204 | ok(false);
205 | return defer().promise();
206 | } );
207 |
208 | first.fail(err =>
209 | {
210 | ok(true);
211 | } );
212 |
213 | outer.fail(err =>
214 | {
215 | ok(true);
216 | } );
217 |
218 | first.reject({ message: "fail" });
219 | } );
220 |
221 | test("then: first resolved and second rejected: second fails and outer fails", () =>
222 | {
223 | expect(2);
224 |
225 | var first = defer();
226 | var second = defer();
227 |
228 | var outer = first.promise().then(n => {
229 | return second.promise();
230 | } );
231 |
232 | second.fail(err =>
233 | {
234 | ok(true);
235 | } );
236 |
237 | outer.fail(err =>
238 | {
239 | ok(true);
240 | } );
241 |
242 | first.resolve(1);
243 | second.reject({ message: "fail" });
244 | } );
245 |
246 |
247 | test("then: then with a resolved value calls the right overload", () =>
248 | {
249 | var first = defer();
250 | var outer = first.promise().then(v => 4);
251 |
252 | outer.done(x =>
253 | {
254 | ok(x == 4);
255 | } );
256 |
257 | first.resolve(1);
258 | })
259 |
260 | // when
261 |
262 | test("when: no arguments given, when resolves immediately", () =>
263 | {
264 | var p = when();
265 | p.done(v => {
266 | ok(!v.length);
267 | } );
268 | } );
269 |
270 | test("when: all are resolved, when resolves", () =>
271 | {
272 | expect(3);
273 |
274 | var d = defer();
275 | var d2 = defer();
276 |
277 | var p = when(d.promise(), d2.promise());
278 | p.done(v =>
279 | {
280 | ok(v.length === 2);
281 | ok(v[0] === 10);
282 | ok(v[1] === true);
283 | } );
284 |
285 | d.resolve(10);
286 | d2.resolve(true);
287 | } );
288 |
289 | test("when: first fails, when fails", () =>
290 | {
291 | var d = defer();
292 | var d2 = defer();
293 |
294 | var p = when(d.promise(), d2.promise());
295 | p.fail(err =>
296 | {
297 | ok(true);
298 | } );
299 |
300 | d.reject({ message: "nana" });
301 | } );
302 |
303 | test("when: second fails, when fails", () =>
304 | {
305 | var d = defer();
306 | var d2 = defer();
307 |
308 | var p = when(d.promise(), d2.promise());
309 | p.fail(err =>
310 | {
311 | ok(true);
312 | } );
313 |
314 | d2.reject({ message: "nana" });
315 | } );
316 |
317 | test("when: both fail, when fails", () =>
318 | {
319 | var d = defer();
320 | var d2 = defer();
321 |
322 | var p = when(d.promise(), d2.promise());
323 | p.fail(err =>
324 | {
325 | ok(true);
326 | } );
327 |
328 | d.reject({ message: "nana" });
329 | d2.reject({ message: "nana" });
330 | } );
331 |
332 | // result / error
333 |
334 | test("accessing the result property of a resolved promise does not throw", () =>
335 | {
336 | var p = P.resolve(1);
337 | ok(1 === p.result);
338 | } );
339 |
340 | test("accessing the result of an unfulfilled or rejected promise throws", () =>
341 | {
342 | var d = defer();
343 | var p = d.promise();
344 | throws(() =>
345 | {
346 | p.result;
347 | } );
348 |
349 | d.reject({ message: "no!" });
350 |
351 | throws(() =>
352 | {
353 | p.result;
354 | } );
355 | } );
356 |
357 |
358 | test("accessing the error property of a rejected promise does not throw", () =>
359 | {
360 | var d = defer();
361 | d.reject({ message: "rejected" });
362 |
363 | ok(d.error.message === "rejected");
364 | } );
365 |
366 | test("accessing the error property of an unfulfilled or resolved promise throws", () =>
367 | {
368 | var d = defer();
369 | var p = d.promise();
370 | throws(() =>
371 | {
372 | p.error;
373 | } );
374 |
375 | d.resolve(1);
376 |
377 | throws(() =>
378 | {
379 | p.error;
380 | } );
381 | } );
382 |
383 | }
384 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## A Generic Promise implementation for TypeScript
2 |
3 | Promises are used to structure asynchronous programs and to avoid callback hell. While they are not as full featured like [Rx](https://github.com/Reactive-Extensions/RxJS) for example, they are attractive because their implementation is rather simple.
4 |
5 | ### Installing Promise.ts
6 |
7 | Assuming that you are using Visual Studio, have [TypeScript 1.0rc](http://www.typescriptlang.org) installed:
8 |
9 | - [install the nuget package](http://nuget.org/packages/Promise.TypeScript/).
10 |
11 | - Then refer the Promise.ts file like:
12 |
13 | ///
14 |
15 | - and to your module:
16 |
17 | export var defer = P.defer;
18 | export var when = P.when;
19 | export interface Promise extends P.Promise {}
20 |
21 | ### Using Promise.ts
22 |
23 | #### Creating Functions that return Promises
24 |
25 | The pattern for creating promises is as follows: First a "deferred" is created that represent a precursor to a promise, then the deferred is bound to the callbacks, and then it returns the promise which may then be composed by the caller.
26 |
27 | For example:
28 |
29 | function readBlob(blob: Blob): Promise
30 | {
31 | var d = defer();
32 |
33 | var reader = new FileReader();
34 |
35 | reader.onerror = (err) => d.reject(err);
36 | reader.onabort = () => {
37 | d.reject({ message: "aborted" });
38 | }
39 | reader.onloadend = () => {
40 | d.resolve(reader.result);
41 | }
42 |
43 | reader.readAsArrayBuffer(blob);
44 |
45 | return d.promise();
46 | }
47 |
48 | The function above starts the reading operation and returns a promise that represents the future result.
49 |
50 | #### Composing Promises
51 |
52 | The promise returned by `readBlob()` can now be composed with other functions that return promises:
53 |
54 | readBlob(blob).then(bytes => writeFile("name", bytes));
55 |
56 | `then` also accepts regular values which act like an already resolved promise, for example
57 |
58 | readBlob(blob).then(bytes => bytes.reverse());
59 |
60 | returns a promise that represents the read operation of the block and the reversing of its binary content. The returned promise gets resolved as soon the conversion function finishes.
61 |
62 | Starting parallel processes is also straight forward:
63 |
64 | var blobReader = readBlob(blob);
65 | var f1 = blobReader.then(bytes => writeFile("name", bytes));
66 | var f2 = blobReader.then(bytes => writeFile("name2", bytes));
67 |
68 | Would then write the received bytes to the file "name" and "name2" at the same time.
69 |
70 | Note that it is also possible to retrieve the result directly from the `blobReader` instance:
71 |
72 | var f1 = blobReader.then(() => writeFile("name1", blobReader.result));
73 |
74 | .. which may simplify complex composition scenarios.
75 |
76 | And when we need to join the results together, the `when` combinator takes a number of promises and returns one that resolves when all its arguments are resolved:
77 |
78 | when(f1, f2).then(() => commitToDatabaseThatAllFilesAreWritten());
79 |
80 | Note that the returning type of `when` is `Promise`, which resolves to an array that contains the results `when` was waiting for.
81 |
82 | #### Adding Handlers
83 |
84 | In addition to the composition features, there are low level primitive functions that can be used to register certain handlers:
85 |
86 | p.done(value => {});
87 |
88 | registers a handler that is called when the promise is resolved.
89 |
90 | p.fail(err => {});
91 |
92 | registers a handler that is called when the promise is rejected.
93 |
94 | p.always((value?, err?) => {});
95 |
96 | registers a handler that is called when either the promise is resolved or rejected.
97 |
98 | When multiple handlers of the same kind are registered, they are called in their registration order.
99 |
100 | ### Ideas
101 |
102 | - An explicit parallel combinator.
103 | - Instead of `any[]`, use Tuples for the return type of `when()`. Because TypeScript does not have a standard library, someone needs to create `Tuple<>` types. BTW: What about creating a standard library that can be distributed as a number of nuget packages similar to the [DefinitelyTyped](https://github.com/borisyankov/DefinitelyTyped) repository?
104 | - Some looping or recursing construct that avoids eating stack space. The [recur special form](http://clojure.org/special_forms#recur) in Clojure looks like a good idea to start from.
105 | - Progress notifications anyone?
106 | - Exception handling.
107 |
108 | ### Design & Implementation Details
109 |
110 | I've decided to make it a bit harder to compose deferreds by not adding the composition methods to the `Deferred` interface. This makes the implementation simpler and has the additional advantage that implementors need to think and explicitly call `promise()` before they can start composing.
111 |
112 | I've decided against all exception handling for now, because I have never used promises before and don't know what exactly programmers would expect. Obviously this might change for a future version.
113 |
114 | ### License
115 |
116 | Copyright (c) 2014, Armin Sander All rights reserved.
117 |
118 | - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
119 |
120 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
121 |
122 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
123 |
124 | Neither the name of Armin Sander nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
125 |
126 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARMIN SANDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
127 |
--------------------------------------------------------------------------------
/Scripts/typings/qunit/qunit.d.ts:
--------------------------------------------------------------------------------
1 | // Type definitions for QUnit 1.10
2 | // Project: http://qunitjs.com/
3 | // Definitions by: Diullei Gomes
4 | // DefinitelyTyped: https://github.com/borisyankov/DefinitelyTyped
5 |
6 |
7 | interface DoneCallbackObject {
8 | /**
9 | * The number of failed assertions
10 | */
11 | failed: number;
12 |
13 | /**
14 | * The number of passed assertions
15 | */
16 | passed: number;
17 |
18 | /**
19 | * The total number of assertions
20 | */
21 | total: number;
22 |
23 | /**
24 | * The time in milliseconds it took tests to run from start to finish.
25 | */
26 | runtime: number;
27 | }
28 |
29 | interface LogCallbackObject {
30 | /**
31 | * The boolean result of an assertion, true means passed, false means failed.
32 | */
33 | result: boolean;
34 |
35 | /**
36 | * One side of a comparision assertion. Can be undefined when ok() is used.
37 | */
38 | actual: Object;
39 |
40 | /**
41 | * One side of a comparision assertion. Can be undefined when ok() is used.
42 | */
43 | expected: Object;
44 |
45 | /**
46 | * A string description provided by the assertion.
47 | */
48 | message: string;
49 |
50 | /**
51 | * The associated stacktrace, either from an exception or pointing to the source
52 | * of the assertion. Depends on browser support for providing stacktraces, so can be
53 | * undefined.
54 | */
55 | source: string;
56 | }
57 |
58 | interface ModuleStartCallbackObject {
59 | /**
60 | * Name of the next module to run
61 | */
62 | name: string;
63 | }
64 |
65 | interface ModuleDoneCallbackObject {
66 | /**
67 | * Name of this module
68 | */
69 | name: string;
70 |
71 | /**
72 | * The number of failed assertions
73 | */
74 | failed: number;
75 |
76 | /**
77 | * The number of passed assertions
78 | */
79 | passed: number;
80 |
81 | /**
82 | * The total number of assertions
83 | */
84 | total: number;
85 | }
86 |
87 | interface TestDoneCallbackObject {
88 | /**
89 | * TName of the next test to run
90 | */
91 | name: string;
92 |
93 | /**
94 | * Name of the current module
95 | */
96 | module: string;
97 |
98 | /**
99 | * The number of failed assertions
100 | */
101 | failed: number;
102 |
103 | /**
104 | * The number of passed assertions
105 | */
106 | passed: number;
107 |
108 | /**
109 | * The total number of assertions
110 | */
111 | total: number;
112 |
113 | /**
114 | * The total runtime, including setup and teardown
115 | */
116 | duration: number;
117 | }
118 |
119 | interface TestStartCallbackObject {
120 | /**
121 | * Name of the next test to run
122 | */
123 | name: string;
124 |
125 | /**
126 | * Name of the current module
127 | */
128 | module: string;
129 | }
130 |
131 | interface Config {
132 | altertitle: boolean;
133 | autostart: boolean;
134 | current: Object;
135 | reorder: boolean;
136 | requireExpects: boolean;
137 | urlConfig: any[];
138 | done: any;
139 | }
140 |
141 | interface LifecycleObject {
142 | /**
143 | * Runs before each test
144 | */
145 | setup?: () => any;
146 |
147 | /**
148 | * Runs after each test
149 | */
150 | teardown?: () => any;
151 | }
152 |
153 | interface QUnitAssert {
154 | /* ASSERT */
155 | assert: any;
156 | current_testEnvironment: any;
157 | jsDump: any;
158 |
159 | /**
160 | * A deep recursive comparison assertion, working on primitive types, arrays, objects,
161 | * regular expressions, dates and functions.
162 | *
163 | * The deepEqual() assertion can be used just like equal() when comparing the value of
164 | * objects, such that { key: value } is equal to { key: value }. For non-scalar values,
165 | * identity will be disregarded by deepEqual.
166 | *
167 | * @param actual Object or Expression being tested
168 | * @param expected Known comparison value
169 | * @param message A short description of the assertion
170 | */
171 | deepEqual(actual: any, expected: any, message?: string);
172 |
173 | /**
174 | * A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
175 | *
176 | * The equal assertion uses the simple comparison operator (==) to compare the actual
177 | * and expected arguments. When they are equal, the assertion passes; otherwise, it fails.
178 | * When it fails, both actual and expected values are displayed in the test result,
179 | * in addition to a given message.
180 | *
181 | * @param actual Expression being tested
182 | * @param expected Known comparison value
183 | * @param message A short description of the assertion
184 | */
185 | equal(actual: any, expected: any, message?: string);
186 |
187 | /**
188 | * An inverted deep recursive comparison assertion, working on primitive types,
189 | * arrays, objects, regular expressions, dates and functions.
190 | *
191 | * The notDeepEqual() assertion can be used just like equal() when comparing the
192 | * value of objects, such that { key: value } is equal to { key: value }. For non-scalar
193 | * values, identity will be disregarded by notDeepEqual.
194 | *
195 | * @param actual Object or Expression being tested
196 | * @param expected Known comparison value
197 | * @param message A short description of the assertion
198 | */
199 | notDeepEqual(actual: any, expected: any, message?: string);
200 |
201 | /**
202 | * A non-strict comparison assertion, checking for inequality.
203 | *
204 | * The notEqual assertion uses the simple inverted comparison operator (!=) to compare
205 | * the actual and expected arguments. When they aren't equal, the assertion passes;
206 | * otherwise, it fails. When it fails, both actual and expected values are displayed
207 | * in the test result, in addition to a given message.
208 | *
209 | * @param actual Expression being tested
210 | * @param expected Known comparison value
211 | * @param message A short description of the assertion
212 | */
213 | notEqual(actual: any, expected: any, message?: string);
214 |
215 | notPropEqual(actual: any, expected: any, message?: string);
216 |
217 | propEqual(actual: any, expected: any, message?: string);
218 |
219 | /**
220 | * A non-strict comparison assertion, checking for inequality.
221 | *
222 | * The notStrictEqual assertion uses the strict inverted comparison operator (!==)
223 | * to compare the actual and expected arguments. When they aren't equal, the assertion
224 | * passes; otherwise, it fails. When it fails, both actual and expected values are
225 | * displayed in the test result, in addition to a given message.
226 | *
227 | * @param actual Expression being tested
228 | * @param expected Known comparison value
229 | * @param message A short description of the assertion
230 | */
231 | notStrictEqual(actual: any, expected: any, message?: string);
232 |
233 | /**
234 | * A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
235 | * Passes if the first argument is truthy.
236 | *
237 | * The most basic assertion in QUnit, ok() requires just one argument. If the argument
238 | * evaluates to true, the assertion passes; otherwise, it fails. If a second message
239 | * argument is provided, it will be displayed in place of the result.
240 | *
241 | * @param state Expression being tested
242 | * @param message A short description of the assertion
243 | */
244 | ok(state: any, message?: string);
245 |
246 | /**
247 | * A strict type and value comparison assertion.
248 | *
249 | * The strictEqual() assertion provides the most rigid comparison of type and value with
250 | * the strict equality operator (===)
251 | *
252 | * @param actual Expression being tested
253 | * @param expected Known comparison value
254 | * @param message A short description of the assertion
255 | */
256 | strictEqual(actual: any, expected: any, message?: string);
257 |
258 | /**
259 | * Assertion to test if a callback throws an exception when run.
260 | *
261 | * When testing code that is expected to throw an exception based on a specific set of
262 | * circumstances, use throws() to catch the error object for testing and comparison.
263 | *
264 | * @param block Function to execute
265 | * @param expected Error Object to compare
266 | * @param message A short description of the assertion
267 | */
268 | throws(block: () => any, expected: any, message?: string);
269 |
270 | /**
271 | * @param block Function to execute
272 | * @param message A short description of the assertion
273 | */
274 | throws(block: () => any, message?: string);
275 | }
276 |
277 | interface QUnitStatic extends QUnitAssert{
278 | /* ASYNC CONTROL */
279 |
280 | /**
281 | * Start running tests again after the testrunner was stopped. See stop().
282 | *
283 | * When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
284 | *
285 | * @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
286 | */
287 | start(decrement?: number);
288 |
289 | /**
290 | * Stop the testrunner to wait for async tests to run. Call start() to continue.
291 | *
292 | * When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
293 | *
294 | * On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
295 | *
296 | * @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
297 | */
298 | stop(increment? : number);
299 |
300 | /* CALLBACKS */
301 |
302 | /**
303 | * Register a callback to fire whenever the test suite begins.
304 | *
305 | * QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
306 | * but thats already in use elsewhere and can't be changed.)
307 | *
308 | * @param callback Callback to execute
309 | */
310 | begin(callback: () => any);
311 |
312 | /**
313 | * Register a callback to fire whenever the test suite ends.
314 | *
315 | * @param callback Callback to execute.
316 | */
317 | done(callback: (details: DoneCallbackObject) => any);
318 |
319 | /**
320 | * Register a callback to fire whenever an assertion completes.
321 | *
322 | * This is one of several callbacks QUnit provides. Its intended for integration scenarios like
323 | * PhantomJS or Jenkins. The properties of the details argument are listed below as options.
324 | *
325 | * @param callback Callback to execute.
326 | */
327 | log(callback: (details: LogCallbackObject) => any);
328 |
329 | /**
330 | * Register a callback to fire whenever a module ends.
331 | *
332 | * @param callback Callback to execute.
333 | */
334 | moduleDone(callback: (details: ModuleDoneCallbackObject) => any);
335 |
336 | /**
337 | * Register a callback to fire whenever a module begins.
338 | *
339 | * @param callback Callback to execute.
340 | */
341 | moduleStart(callback: (details: ModuleStartCallbackObject) => any);
342 |
343 | /**
344 | * Register a callback to fire whenever a test ends.
345 | *
346 | * @param callback Callback to execute.
347 | */
348 | testDone(callback: (details: TestDoneCallbackObject) => any);
349 |
350 | /**
351 | * Register a callback to fire whenever a test begins.
352 | *
353 | * @param callback Callback to execute.
354 | */
355 | testStart(callback: (details: TestStartCallbackObject) => any);
356 |
357 | /* CONFIGURATION */
358 |
359 | /**
360 | * QUnit has a bunch of internal configuration defaults, some of which are
361 | * useful to override. Check the description for each option for details.
362 | */
363 | config: Config;
364 |
365 | /* TEST */
366 |
367 | /**
368 | * Add an asynchronous test to run. The test must include a call to start().
369 | *
370 | * For testing asynchronous code, asyncTest will automatically stop the test runner
371 | * and wait for your code to call start() to continue.
372 | *
373 | * @param name Title of unit being tested
374 | * @param expected Number of assertions in this test
375 | * @param test Function to close over assertions
376 | */
377 | asyncTest(name: string, expected: number, test: () => any);
378 |
379 | /**
380 | * Add an asynchronous test to run. The test must include a call to start().
381 | *
382 | * For testing asynchronous code, asyncTest will automatically stop the test runner
383 | * and wait for your code to call start() to continue.
384 | *
385 | * @param name Title of unit being tested
386 | * @param test Function to close over assertions
387 | */
388 | asyncTest(name: string, test: () => any);
389 |
390 | /**
391 | * Specify how many assertions are expected to run within a test.
392 | *
393 | * To ensure that an explicit number of assertions are run within any test, use
394 | * expect( number ) to register an expected count. If the number of assertions
395 | * run does not match the expected count, the test will fail.
396 | *
397 | * @param amount Number of assertions in this test.
398 | */
399 | expect(amount: number);
400 |
401 | /**
402 | * Group related tests under a single label.
403 | *
404 | * All tests that occur after a call to module() will be grouped into that module.
405 | * The test names will all be preceded by the module name in the test results.
406 | * You can then use that module name to select tests to run.
407 | *
408 | * @param name Label for this group of tests
409 | * @param lifecycle Callbacks to run before and after each test
410 | */
411 | module(name: string, lifecycle?: LifecycleObject);
412 |
413 | /**
414 | * Add a test to run.
415 | *
416 | * When testing the most common, synchronous code, use test().
417 | * The assert argument to the callback contains all of QUnit's assertion methods.
418 | * If you are avoiding using any of QUnit's globals, you can use the assert
419 | * argument instead.
420 | *
421 | * @param title Title of unit being tested
422 | * @param expected Number of assertions in this test
423 | * @param test Function to close over assertions
424 | */
425 | test(title: string, expected: number, test: (assert: QUnitAssert) => any);
426 |
427 | /**
428 | * @param title Title of unit being tested
429 | * @param test Function to close over assertions
430 | */
431 | test(title: string, test: (assert: QUnitAssert) => any);
432 |
433 | /**
434 | * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
435 | */
436 | equiv(a: any, b: any);
437 |
438 | // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
439 | raises: any;
440 |
441 | /**
442 | * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L897
443 | */
444 | push(result, actual, expected, message): any;
445 |
446 | /**
447 | * https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L839
448 | */
449 | reset(): any;
450 | }
451 |
452 | /* ASSERT */
453 |
454 | /**
455 | * A deep recursive comparison assertion, working on primitive types, arrays, objects,
456 | * regular expressions, dates and functions.
457 | *
458 | * The deepEqual() assertion can be used just like equal() when comparing the value of
459 | * objects, such that { key: value } is equal to { key: value }. For non-scalar values,
460 | * identity will be disregarded by deepEqual.
461 | *
462 | * @param actual Object or Expression being tested
463 | * @param expected Known comparison value
464 | * @param message A short description of the assertion
465 | */
466 | declare function deepEqual(actual: any, expected: any, message?: string);
467 |
468 | /**
469 | * A non-strict comparison assertion, roughly equivalent to JUnit assertEquals.
470 | *
471 | * The equal assertion uses the simple comparison operator (==) to compare the actual
472 | * and expected arguments. When they are equal, the assertion passes; otherwise, it fails.
473 | * When it fails, both actual and expected values are displayed in the test result,
474 | * in addition to a given message.
475 | *
476 | * @param actual Expression being tested
477 | * @param expected Known comparison value
478 | * @param message A short description of the assertion
479 | */
480 | declare function equal(actual: any, expected: any, message?: string);
481 |
482 | /**
483 | * An inverted deep recursive comparison assertion, working on primitive types,
484 | * arrays, objects, regular expressions, dates and functions.
485 | *
486 | * The notDeepEqual() assertion can be used just like equal() when comparing the
487 | * value of objects, such that { key: value } is equal to { key: value }. For non-scalar
488 | * values, identity will be disregarded by notDeepEqual.
489 | *
490 | * @param actual Object or Expression being tested
491 | * @param expected Known comparison value
492 | * @param message A short description of the assertion
493 | */
494 | declare function notDeepEqual(actual: any, expected: any, message?: string);
495 |
496 | /**
497 | * A non-strict comparison assertion, checking for inequality.
498 | *
499 | * The notEqual assertion uses the simple inverted comparison operator (!=) to compare
500 | * the actual and expected arguments. When they aren't equal, the assertion passes;
501 | * otherwise, it fails. When it fails, both actual and expected values are displayed
502 | * in the test result, in addition to a given message.
503 | *
504 | * @param actual Expression being tested
505 | * @param expected Known comparison value
506 | * @param message A short description of the assertion
507 | */
508 | declare function notEqual(actual: any, expected: any, message?: string);
509 |
510 | /**
511 | * A non-strict comparison assertion, checking for inequality.
512 | *
513 | * The notStrictEqual assertion uses the strict inverted comparison operator (!==)
514 | * to compare the actual and expected arguments. When they aren't equal, the assertion
515 | * passes; otherwise, it fails. When it fails, both actual and expected values are
516 | * displayed in the test result, in addition to a given message.
517 | *
518 | * @param actual Expression being tested
519 | * @param expected Known comparison value
520 | * @param message A short description of the assertion
521 | */
522 | declare function notStrictEqual(actual: any, expected: any, message?: string);
523 |
524 | /**
525 | * A boolean assertion, equivalent to CommonJS’s assert.ok() and JUnit’s assertTrue().
526 | * Passes if the first argument is truthy.
527 | *
528 | * The most basic assertion in QUnit, ok() requires just one argument. If the argument
529 | * evaluates to true, the assertion passes; otherwise, it fails. If a second message
530 | * argument is provided, it will be displayed in place of the result.
531 | *
532 | * @param state Expression being tested
533 | * @param message A short description of the assertion
534 | */
535 | declare function ok(state: any, message?: string);
536 |
537 | /**
538 | * A strict type and value comparison assertion.
539 | *
540 | * The strictEqual() assertion provides the most rigid comparison of type and value with
541 | * the strict equality operator (===)
542 | *
543 | * @param actual Expression being tested
544 | * @param expected Known comparison value
545 | * @param message A short description of the assertion
546 | */
547 | declare function strictEqual(actual: any, expected: any, message?: string);
548 |
549 | /**
550 | * Assertion to test if a callback throws an exception when run.
551 | *
552 | * When testing code that is expected to throw an exception based on a specific set of
553 | * circumstances, use throws() to catch the error object for testing and comparison.
554 | *
555 | * @param block Function to execute
556 | * @param expected Error Object to compare
557 | * @param message A short description of the assertion
558 | */
559 | declare function throws(block: () => any, expected: any, message?: string);
560 |
561 | /**
562 | * @param block Function to execute
563 | * @param message A short description of the assertion
564 | */
565 | declare function throws(block: () => any, message?: string);
566 |
567 | /* ASYNC CONTROL */
568 |
569 | /**
570 | * Start running tests again after the testrunner was stopped. See stop().
571 | *
572 | * When your async test has multiple exit points, call start() for the corresponding number of stop() increments.
573 | *
574 | * @param decrement Optional argument to merge multiple start() calls into one. Use with multiple corrsponding stop() calls.
575 | */
576 | declare function start(decrement?: number);
577 |
578 | /**
579 | * Stop the testrunner to wait for async tests to run. Call start() to continue.
580 | *
581 | * When your async test has multiple exit points, call stop() with the increment argument, corresponding to the number of start() calls you need.
582 | *
583 | * On Blackberry 5.0, window.stop is a native read-only function. If you deal with that browser, use QUnit.stop() instead, which will work anywhere.
584 | *
585 | * @param decrement Optional argument to merge multiple stop() calls into one. Use with multiple corrsponding start() calls.
586 | */
587 | declare function stop(increment? : number);
588 |
589 | /* CALLBACKS */
590 |
591 | /**
592 | * Register a callback to fire whenever the test suite begins.
593 | *
594 | * QUnit.begin() is called once before running any tests. (a better would've been QUnit.start,
595 | * but thats already in use elsewhere and can't be changed.)
596 | *
597 | * @param callback Callback to execute
598 | */
599 | declare function begin(callback: () => any);
600 |
601 | /**
602 | * Register a callback to fire whenever the test suite ends.
603 | *
604 | * @param callback Callback to execute.
605 | */
606 | declare function done(callback: (details: DoneCallbackObject) => any);
607 |
608 | /**
609 | * Register a callback to fire whenever an assertion completes.
610 | *
611 | * This is one of several callbacks QUnit provides. Its intended for integration scenarios like
612 | * PhantomJS or Jenkins. The properties of the details argument are listed below as options.
613 | *
614 | * @param callback Callback to execute.
615 | */
616 | declare function log(callback: (details: LogCallbackObject) => any);
617 |
618 | /**
619 | * Register a callback to fire whenever a module ends.
620 | *
621 | * @param callback Callback to execute.
622 | */
623 | declare function moduleDone(callback: (details: ModuleDoneCallbackObject) => any);
624 |
625 | /**
626 | * Register a callback to fire whenever a module begins.
627 | *
628 | * @param callback Callback to execute.
629 | */
630 | declare function moduleStart(callback: (name: string) => any);
631 |
632 | /**
633 | * Register a callback to fire whenever a test ends.
634 | *
635 | * @param callback Callback to execute.
636 | */
637 | declare function testDone(callback: (details: TestDoneCallbackObject) => any);
638 |
639 | /**
640 | * Register a callback to fire whenever a test begins.
641 | *
642 | * @param callback Callback to execute.
643 | */
644 | declare function testStart(callback: (details: TestStartCallbackObject) => any);
645 |
646 | /* TEST */
647 |
648 | /**
649 | * Add an asynchronous test to run. The test must include a call to start().
650 | *
651 | * For testing asynchronous code, asyncTest will automatically stop the test runner
652 | * and wait for your code to call start() to continue.
653 | *
654 | * @param name Title of unit being tested
655 | * @param expected Number of assertions in this test
656 | * @param test Function to close over assertions
657 | */
658 | declare function asyncTest(name: string, expected?: any, test?: () => any);
659 |
660 | /**
661 | * Add an asynchronous test to run. The test must include a call to start().
662 | *
663 | * For testing asynchronous code, asyncTest will automatically stop the test runner
664 | * and wait for your code to call start() to continue.
665 | *
666 | * @param name Title of unit being tested
667 | * @param test Function to close over assertions
668 | */
669 | declare function asyncTest(name: string, test: () => any);
670 |
671 | /**
672 | * Specify how many assertions are expected to run within a test.
673 | *
674 | * To ensure that an explicit number of assertions are run within any test, use
675 | * expect( number ) to register an expected count. If the number of assertions
676 | * run does not match the expected count, the test will fail.
677 | *
678 | * @param amount Number of assertions in this test.
679 | */
680 | declare function expect(amount: number);
681 |
682 | // ** conflict with TypeScript module keyword. Must be used on QUnit namespace
683 | //declare var module: (name: string, lifecycle?: LifecycleObject) => any;
684 |
685 | /**
686 | * Add a test to run.
687 | *
688 | * When testing the most common, synchronous code, use test().
689 | * The assert argument to the callback contains all of QUnit's assertion methods.
690 | * If you are avoiding using any of QUnit's globals, you can use the assert
691 | * argument instead.
692 | *
693 | * @param title Title of unit being tested
694 | * @param expected Number of assertions in this test
695 | * @param test Function to close over assertions
696 | */
697 | declare function test(title: string, expected: number, test: (assert?: QUnitAssert) => any);
698 |
699 | /**
700 | * @param title Title of unit being tested
701 | * @param test Function to close over assertions
702 | */
703 | declare function test(title: string, test: (assert?: QUnitAssert) => any);
704 |
705 | declare function notPropEqual(actual: any, expected: any, message?: string);
706 |
707 | declare function propEqual(actual: any, expected: any, message?: string);
708 |
709 | // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L1568
710 | declare function equiv(a: any, b: any);
711 |
712 | // https://github.com/jquery/qunit/blob/master/qunit/qunit.js#L661
713 | declare var raises: any;
714 |
715 | /* QUNIT */
716 | declare var QUnit: QUnitStatic;
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/packages/repositories.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
--------------------------------------------------------------------------------
/web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------