diff --git a/.travis.yml b/.travis.yml index 1059b8a..dd08b4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js node_js: # we recommend testing addons with the same minimum supported node version as Ember CLI # so that your addon works for all apps - - "4" + - "6" sudo: false dist: trusty diff --git a/addon/-private/defer.ts b/addon/-private/defer.ts index 5fbf7d7..2c56d28 100644 --- a/addon/-private/defer.ts +++ b/addon/-private/defer.ts @@ -1,12 +1,13 @@ import EmberObject from '@ember/object'; import { run } from '@ember/runloop'; -import { CancelableDeferred } from 'ember-milestones/interfaces'; +import { CancelableDeferred } from 'ember-milestones'; import require from 'require'; import { defer as rsvpDefer, reject as rsvpReject, } from 'rsvp'; +/** @hide */ export let defer: (label?: string) => CancelableDeferred; if (require.has('ember-concurrency')) { diff --git a/addon/-private/milestone-coordinator.ts b/addon/-private/milestone-coordinator.ts index 584fa3a..3740d0f 100644 --- a/addon/-private/milestone-coordinator.ts +++ b/addon/-private/milestone-coordinator.ts @@ -1,12 +1,15 @@ import { assert } from '@ember/debug'; -import { CancelableDeferred } from 'ember-milestones/interfaces'; +import { CancelableDeferred } from 'ember-milestones'; +import { MilestoneCoordinator as IMilestoneCoordinator } from 'ember-milestones'; import { defer } from './defer'; import MilestoneHandle from './milestone-handle'; import MilestoneTarget from './milestone-target'; +/** @hide */ export const ACTIVE_COORDINATORS: { [key: string]: MilestoneCoordinator } = Object.create(null); -export default class MilestoneCoordinator { +/** @hide */ +export default class MilestoneCoordinator implements IMilestoneCoordinator { public static forMilestone(name: string): MilestoneCoordinator | undefined { return ACTIVE_COORDINATORS[name]; } diff --git a/addon/-private/milestone-handle.ts b/addon/-private/milestone-handle.ts index dcc5c3a..2d86a11 100644 --- a/addon/-private/milestone-handle.ts +++ b/addon/-private/milestone-handle.ts @@ -3,14 +3,16 @@ import { next, run } from '@ember/runloop'; import { Promise } from 'rsvp'; import MilestoneCoordinator from 'ember-milestones/-private/milestone-coordinator'; + import { CancelableDeferred, MilestoneHandle as IMilestoneHandle, ResolutionOptions, -} from 'ember-milestones/interfaces'; +} from 'ember-milestones'; type Resolution = 'continue' | 'throw' | 'return' | 'cancel'; +/** @hide */ export default class MilestoneHandle implements IMilestoneHandle { private resolution: Resolution | null = null; diff --git a/addon/-private/milestone-target.ts b/addon/-private/milestone-target.ts index 8b88465..d925af0 100644 --- a/addon/-private/milestone-target.ts +++ b/addon/-private/milestone-target.ts @@ -3,11 +3,12 @@ import { MilestoneHandle, MilestoneTarget as IMilestoneTarget, ResolutionOptions, -} from 'ember-milestones/interfaces'; +} from 'ember-milestones'; import RSVP, { defer } from 'rsvp'; const debug = logger('ember-milestones:target'); +/** @hide */ export default class MilestoneTarget implements IMilestoneTarget { private _coordinatorDeferred: RSVP.Deferred = defer(); diff --git a/addon/index.ts b/addon/index.ts index 9c4d542..2dc9342 100644 --- a/addon/index.ts +++ b/addon/index.ts @@ -1,14 +1,5 @@ -import CoordinatorImpl from 'ember-milestones/-private/milestone-coordinator'; -import { - MilestoneCoordinator, - MilestoneTarget, - MilestoneTestOptions, - TestHooks, -} from 'ember-milestones/interfaces'; - -export * from 'ember-milestones/interfaces'; - import logger from 'debug'; +import CoordinatorImpl from 'ember-milestones/-private/milestone-coordinator'; const debugActive = logger('ember-milestones:active'); const debugInactive = logger('ember-milestones:inactive'); @@ -18,7 +9,7 @@ const debugInactive = logger('ember-milestones:inactive'); * when they are reached until instructed on how to proceed via a `MilestoneHandle`. * * Inactive milestones will pass through to their given callbacks as though the - * milestone wrapper weren't present at all. + * milestone wrapper weren't present at all... */ export function activateMilestones(milestones: string[]): MilestoneCoordinator { return new CoordinatorImpl(milestones); @@ -111,3 +102,141 @@ export function setupMilestones(hooks: TestHooks, names: string[], options: Mile milestones.deactivateAll(); }); } + +/** + * A `MilestoneCoordinator` is the result of an `activateMilestones` call, + * which provides the ability to interact with the milestones you've activated + * and subsequently deactivate them. + * + * In most cases, you can simply use the importable `advanceTo` and + * `deactivateAllMilestones` functions from the `'ember-milestones'` module + * rather than interacting directly with a `MilestoneCoordinator` instance. + */ +export interface MilestoneCoordinator { + /** + * Advance until the given milestone is reached, continuing past any others + * that are active for this coordinator in the meantime. + */ + advanceTo(name: string): MilestoneTarget; + + /** + * Deactivate all milestones associated with this coordinator. + */ + deactivateAll(): void; +} + +/** + * A `MilestoneTarget` represents the 'goal' of proceeding to a certain + * milestone. It's a `PromiseLike` object that resolves to a `MilestoneHandle` + * when its associated milestone is reached. + * + * A `MilestoneTarget` also contains shortcut methods for easily invoking + * a particular behavior when the milestone is reached. + */ +export interface MilestoneTarget extends PromiseLike { + /** + * Return the given value when the milestone is reached. The following two + * lines are equivalent: + * + * await advanceTo('milestone').andReturn(value); + * await advanceTo('milestone').then(m => m.return(value)); + */ + andReturn(value?: any, options?: ResolutionOptions): Promise; + + /** + * Throw the given error when the milestone is reached. The following two + * lines are equivalent: + * + * await advanceTo('milestone').andThrow(error); + * await advanceTo('milestone').then(m => m.throw(error)); + */ + andThrow(error: any, options?: ResolutionOptions): Promise; + + /** + * Invoke the milestone's original callback when reached. The following two + * lines are equivalent: + * + * await advanceTo('milestone').andContinue(); + * await advanceTo('milestone').then(m => m.continue()); + */ + andContinue(options?: ResolutionOptions): Promise; + + /** + * Trigger a task cancellation when the milestone is reached. The following two + * lines are equivalent: + * + * await advanceTo('milestone').andCancel(); + * await advanceTo('milestone').then(m => m.cancel()); + * + * Note that cancellation is only possible when `ember-concurrency` is present. + */ + andCancel(options?: ResolutionOptions): Promise; +} + +/** + * A `MilestoneHandle` represents a milestone that your application code is + * currently paused at. It provides methods for determining how that milestone + * will ultimately resolve, whether you invoke the original behavior or stub + * out a different return value, error, or cancellation. + */ +export interface MilestoneHandle { + /** + * Settle this milestone by invoking its original callback. The promise + * returned by this method will resolve once the result of the original + * callback has settled. + */ + continue(options?: ResolutionOptions): Promise; + + /** + * Settle this milestone by resolving its promise with the given value. + */ + return(value?: any, options?: ResolutionOptions): Promise; + + /** + * Settle this milestone by rejecting its promise with the given error. + */ + throw(error: any, options?: ResolutionOptions): Promise; + + /** + * Settle this milestone by causing it to behave as a canceled task. + * + * Note that cancellation is only available if `ember-concurrency` is + * present. + */ + cancel(options?: ResolutionOptions): Promise; +} + +export interface ResolutionOptions { + /** + * Whether to resolve the promise returned by a `MilestoneHandle` method as + * soon as possible or not. + * + * By default, resolution will be scheduled in a subsequent task so that any + * other pending tasks have a chance to execute. If you set `immediate: true`, + * however, the resolution will happen immediately, queueing a microtask. + */ + immediate?: boolean; +} + +/** @hide */ +export interface CancelableDeferred { + promise: Promise; + cancel(reason?: string): void; + resolve(value?: T): void; + reject(error?: any): void; +} + +/** @hide */ +export interface TestHooks { + beforeEach(callback: () => any): void; + afterEach(callback: () => any): void; +} + +/** @hide */ +export interface MilestoneTestOptions { + /** + * An optional name to store a `MilestoneCoordinator` under on the test + * context, if you need direct access to it. + */ + as?: string; +} diff --git a/addon/interfaces.ts b/addon/interfaces.ts deleted file mode 100644 index a0a0c0e..0000000 --- a/addon/interfaces.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * A `MilestoneCoordinator` is the result of an `activateMilestones` call, - * which provides the ability to interact with the milestones you've activated - * and subsequently deactivate them. - * - * In most cases, you can simply use the importable `advanceTo` and - * `deactivateAllMilestones` functions from the `'ember-milestones'` module - * rather than interacting directly with a `MilestoneCoordinator` instance. - */ -export interface MilestoneCoordinator { - /** - * Advance until the given milestone is reached, continuing past any others - * that are active for this coordinator in the meantime. - */ - advanceTo(name: string): MilestoneTarget; - - /** - * Deactivate all milestones associated with this coordinator. - */ - deactivateAll(): void; -} - -/** - * A `MilestoneTarget` represents the 'goal' of proceeding to a certain - * milestone. It's a `PromiseLike` object that resolves to a `MilestoneHandle` - * when its associated milestone is reached. - * - * A `MilestoneTarget` also contains shortcut methods for easily invoking - * a particular behavior when the milestone is reached. - */ -export interface MilestoneTarget extends PromiseLike { - /** - * Return the given value when the milestone is reached. The following two - * lines are equivalent: - * - * await advanceTo('milestone').andReturn(value); - * await advanceTo('milestone').then(m => m.return(value)); - */ - andReturn(value?: any, options?: ResolutionOptions): Promise; - - /** - * Throw the given error when the milestone is reached. The following two - * lines are equivalent: - * - * await advanceTo('milestone').andThrow(error); - * await advanceTo('milestone').then(m => m.throw(error)); - */ - andThrow(error: any, options?: ResolutionOptions): Promise; - - /** - * Invoke the milestone's original callback when reached. The following two - * lines are equivalent: - * - * await advanceTo('milestone').andContinue(); - * await advanceTo('milestone').then(m => m.continue()); - */ - andContinue(options?: ResolutionOptions): Promise; - - /** - * Trigger a task cancellation when the milestone is reached. The following two - * lines are equivalent: - * - * await advanceTo('milestone').andCancel(); - * await advanceTo('milestone').then(m => m.cancel()); - * - * Note that cancellation is only possible when `ember-concurrency` is present. - */ - andCancel(options?: ResolutionOptions): Promise; -} - -/** - * A `MilestoneHandle` represents a milestone that your application code is - * currently paused at. It provides methods for determining how that milestone - * will ultimately resolve, whether you invoke the original behavior or stub - * out a different return value, error, or cancellation. - */ -export interface MilestoneHandle { - /** - * Settle this milestone by invoking its original callback. The promise - * returned by this method will resolve once the result of the original - * callback has settled. - */ - continue(options?: ResolutionOptions): Promise; - - /** - * Settle this milestone by resolving its promise with the given value. - */ - return(value?: any, options?: ResolutionOptions): Promise; - - /** - * Settle this milestone by rejecting its promise with the given error. - */ - throw(error: any, options?: ResolutionOptions): Promise; - - /** - * Settle this milestone by causing it to behave as a canceled task. - * - * Note that cancellation is only available if `ember-concurrency` is - * present. - */ - cancel(options?: ResolutionOptions): Promise; -} - -export interface ResolutionOptions { - /** - * Whether to resolve the promise returned by a `MilestoneHandle` method as - * soon as possible or not. - * - * By default, resolution will be scheduled in a subsequent task so that any - * other pending tasks have a chance to execute. If you set `immediate: true`, - * however, the resolution will happen immediately, queueing a microtask. - */ - immediate?: boolean; -} - -export interface CancelableDeferred { - promise: Promise; - cancel(reason?: string): void; - resolve(value?: T): void; - reject(error?: any): void; -} - -export interface TestHooks { - beforeEach(callback: () => any): void; - afterEach(callback: () => any): void; -} - -export interface MilestoneTestOptions { - /** - * An optional name to store a `MilestoneCoordinator` under on the test - * context, if you need direct access to it. - */ - as?: string; -}