Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add typedefinitions #209

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"doc": "doc",
"test": "tests"
},
"types": "types/index.d.ts",
"typings": "types/index.d.ts",
"scripts": {
"build": "ember build",
"start": "ember serve",
Expand All @@ -18,6 +20,8 @@
"author": "Alex Matchneer <machty@gmail.com>",
"license": "MIT",
"devDependencies": {
"@types/ember": "^2.8.15",
"@types/rsvp": "^4.0.1",
"broccoli-asset-rev": "https://github.com/ef4/broccoli-asset-rev#838f1b7186fde566d3e8010196c1f974423a4946",
"broccoli-clean-css": "^1.1.0",
"documentation": "^3.0.4",
Expand Down
125 changes: 125 additions & 0 deletions types/Task.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import RSVP from "rsvp";
import ComputedProperty from '@ember/object/computed'

export class TaskProperty<T> extends ComputedProperty<T>{
/**
* This behaves like the {@linkcode TaskProperty#on task(...).on() modifier},
* but instead will cause the task to be canceled if any of the
* specified events fire on the parent object.
*
* [See the Live Example](/#/docs/examples/route-tasks/1)
*
*/
cancelOn(...eventNames: string[]): this;

/**
* Logs lifecycle events to aid in debugging unexpected
* Task behavior. Presently only logs cancelation events
* and the reason for the cancelation, e.g. "TaskInstance
* 'doStuff' was canceled because the object it lives on
* was destroyed or unrendered"
*/
debug(): this;
drop(): this;
enqueue(): this;
group(groupPath: any): this;
keepLatest(): this;
maxConcurrency(n: number): this;
on(...eventNames: string[]): this;
restartable(): this;
}
export type TaskState = 'dropped' | 'cancelled' | 'finished' | 'running' | 'waiting';
export class TaskInstance<T> extends RSVP.Promise<T> {
/** If this TaskInstance is canceled or throws an error (or yields a promise that rejects), this property will be set with that error. Otherwise, it is null. */
readonly error?: Error;

/** True if the task instance has started, else false. */
readonly hasStarted: ComputedProperty<boolean>;

/** True if the task instance was canceled before it could run to completion. */
readonly isCancelled: ComputedProperty<boolean>;

/** True if the TaskInstance was canceled before it could ever start running.
* For example, calling .perform() twice on a task with the .drop() modifier
* applied will result in the second task instance being dropped.
*/
readonly isDropped?: ComputedProperty<boolean>;

/** True if the task instance resolves to a rejection. */
readonly isError?: ComputedProperty<boolean>;

/** True if the task has run to completion. */
readonly isFinished: ComputedProperty<boolean>;

/** True if the task is still running. */
readonly isRunning: ComputedProperty<boolean>;

/** True if the task instance is fulfilled. */
readonly isSuccessful: boolean;

/** Describes the state that the task instance is in. Can be used for debugging, or potentially driving some UI state. */
readonly state: TaskState;

/** If this TaskInstance runs to completion by returning a property other than a rejecting promise, this property will be set with that value. */
readonly value: T;

/** Cancels the task instance. Has no effect if the task instance has already been canceled or has already finished running. */
cancel(): void;
}

export class Task<T, P> extends TaskProperty<T> {
/** true if the task is not in the running or queued state. */
readonly isIdle: boolean;
/** true if any future task instances are queued. */
readonly isQueued: boolean;
/** true if any current task instances are running. */
readonly isRunning: boolean;

/** The most recently started task instance. */
readonly last?: TaskInstance<T>;

/** The most recently canceled task instance. */
readonly lastCancelled?: TaskInstance<T>;

/** The most recently completed task instance. */
readonly lastComplete?: TaskInstance<T>;

/** The most recent task instance that errored. */
readonly lastErrored?: TaskInstance<T>;

/** The most recent task instance that is incomplete. */
readonly lastIncomplete?: TaskInstance<T>;

/** The most recently performed task instance. */
readonly lastPerformed?: TaskInstance<T>;

/** The most recent task instance that is currently running. */
readonly lastRunning?: TaskInstance<T>;

/** The most recent task instance that succeeded. */
readonly lastSucessful?: TaskInstance<T>;

/** The number of times this task has been performed. */
readonly performCount: number;

/** The current state of the task: "running", "queued" or "idle". */
readonly state: 'running' | 'queued' | 'idle';

/**
* Cancels all running or queued TaskInstances for this Task.
* If you're trying to cancel a specific TaskInstance (rather than all of
* the instances running under this task) call .cancel() on the specific
* TaskInstance.
*/
cancelAll(): void;

/**
* Creates a new TaskInstance and attempts to run it right away.
* If running this task instance would increase the task's concurrency
* to a number greater than the task's maxConcurrency, this task instance
* might be immediately canceled (dropped), or enqueued to run at later
* time, after the currently running task(s) have finished.
* @param arg args to pass to the task function
*/
perform(...arg: any[]): void;
}
88 changes: 88 additions & 0 deletions types/ember-concurrency-tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'jquery';
import {
task,
timeout,
waitForEvent,
taskGroup,
waitForProperty,
waitForQueue
} from 'ember-concurrency';
import Ember from 'ember';
import Controller from '@ember/controller';

Ember.Component.extend({
loopingTask: task(function *(this: Ember.Component) {
while (true) {
this.set<any, any>('num', Math.random());
yield timeout(100);
}
}).on('init')
});

Ember.Component.extend({
myTask: task(function *(this: any) {
const clickEvent = yield waitForEvent($('body'), 'click');
const emberEvent = yield waitForEvent(this, 'foo');
// somewhere else: component.trigger('foo', { value: 123 });
})
});

Ember.Component.extend({
myTask: task(function *() {
console.log("Pausing for a second...");
yield timeout(1000);
console.log("Done!");
})
});
function* taskFn() { yield 1; }

Controller.extend({
chores: taskGroup().drop(),

mowLawn: task(taskFn).group('chores'),
doDishes: task(taskFn).group('chores'),
changeDiapers: task(taskFn).group('chores')
});

Ember.Component.extend({
myTask: task(function *() {
while (true) {
console.log("Hello!");
yield timeout(1000);
}
})
});

Ember.Component.extend({
myTask: task(function *(this: Ember.Evented) {
console.log("Please click anywhere..");
const clickEvent = yield waitForEvent($('body'), 'click');
console.log("Got event", clickEvent);

const emberEvent = yield waitForEvent(this, 'foo');
console.log("Got foo event", emberEvent);

// somewhere else: component.trigger('foo', { value: 123 });
})
});

Ember.Component.extend({
foo: 0,

myTask: task(function *(this: any) {
console.log("Waiting for `foo` to become 5");

yield waitForProperty(this, 'foo', v => v === 5);

// somewhere else: this.set('foo', 5)

console.log("`foo` is 5!");
})
});

Ember.Component.extend({
myTask: task(function *() {
yield waitForQueue('afterRender');
console.log("now we're in the afterRender queue");
})
});
34 changes: 34 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Type definitions for ember-concurrency 0.8
// Project: https://github.com/machty/ember-concurrency#readme
// Definitions by: Arnav Gupta <https://github.com/championswimmer>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4

import Ember from 'ember';
import RSVP from 'rsvp';
import { Task, TaskProperty, TaskInstance } from './Task';

export { Task, TaskProperty, TaskInstance };
export const all: typeof RSVP.all;
export const allSettled: typeof RSVP.allSettled;
export const hash: typeof RSVP.hash;
export const race: typeof RSVP.race;

/**
* Returns true if the object passed to it is a
* TaskCancelation error. If you call someTask.perform().catch(...)
* or otherwise treat a TaskInstance like a promise, you may need
* to handle the cancelation of a TaskInstance differently from
* other kinds of errors it might throw, and you can use this
* convenience function to distinguish cancelation from errors.
*
* @param {Error} error
* @returns {boolean}
*/
export function didCancel(error?: Error): boolean;
export function task<T> (generatorFunction: (...args: any[]) => Generator): TaskProperty<T>;
export function taskGroup(...args: any[]): any;
export function timeout(ms: number): any;
export function waitForEvent(object: Ember.Evented | RSVP.EventTarget | EventTarget, eventName: string): any;
export function waitForProperty(object: any, key: string, callback: (...args: any[]) => any): any;
export function waitForQueue(queueName: string): any;
25 changes: 25 additions & 0 deletions types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es2015",
"dom"
],
"target": "es2015",
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"ember-concurrency-tests.ts"
]
}