From 0dc2c19102315018a7931ebf87342c419276282f Mon Sep 17 00:00:00 2001 From: Chris Thielen Date: Tue, 6 Dec 2016 20:28:05 -0600 Subject: [PATCH] refactor(plugin): Add transition plugin API feat(transition): Allow plugins to define own transition events like `onEnter` refactory(dynamic): Detect dynamic transitions checking: reload, to/from length, to/from equality, parameter values --- src/common/common.ts | 5 +- src/transition/hookBuilder.ts | 8 +- src/transition/hookRegistry.ts | 122 +++++++++++++----- src/transition/index.ts | 1 + src/transition/interface.ts | 3 + src/transition/transition.ts | 32 +++-- ...tionHookType.ts => transitionEventType.ts} | 6 +- src/transition/transitionHook.ts | 8 +- src/transition/transitionService.ts | 87 ++++++++----- test/hookBuilderSpec.ts | 2 +- 10 files changed, 185 insertions(+), 89 deletions(-) rename src/transition/{transitionHookType.ts => transitionEventType.ts} (80%) diff --git a/src/common/common.ts b/src/common/common.ts index df233126..68c378f4 100644 --- a/src/common/common.ts +++ b/src/common/common.ts @@ -86,9 +86,10 @@ export interface Obj extends Object { * @param bindTo The object which the functions will be bound to * @param fnNames The function names which will be bound (Defaults to all the functions found on the 'from' object) */ -export function bindFunctions(from: Obj, to: Obj, bindTo: Obj, fnNames: string[] = Object.keys(from)) { - return fnNames.filter(name => typeof from[name] === 'function') +export function bindFunctions(from: Obj, to: Obj, bindTo: Obj, fnNames: string[] = Object.keys(from)): Obj { + fnNames.filter(name => typeof from[name] === 'function') .forEach(name => to[name] = from[name].bind(bindTo)); + return to; } diff --git a/src/transition/hookBuilder.ts b/src/transition/hookBuilder.ts index 34ac8a9f..fd343385 100644 --- a/src/transition/hookBuilder.ts +++ b/src/transition/hookBuilder.ts @@ -13,7 +13,7 @@ import {TransitionHook} from "./transitionHook"; import {State} from "../state/stateObject"; import {PathNode} from "../path/node"; import {TransitionService} from "./transitionService"; -import {TransitionHookType} from "./transitionHookType"; +import {TransitionEventType} from "./transitionEventType"; import {RegisteredHook} from "./hookRegistry"; /** @@ -54,7 +54,7 @@ export class HookBuilder { } buildHooksForPhase(phase: TransitionHookPhase): TransitionHook[] { - return this.$transitions.getTransitionHookTypes(phase) + return this.$transitions._pluginapi.getTransitionEventTypes(phase) .map(type => this.buildHooks(type)) .reduce(unnestR, []) .filter(identity); @@ -69,7 +69,7 @@ export class HookBuilder { * * @param hookType the type of the hook registration function, e.g., 'onEnter', 'onFinish'. */ - buildHooks(hookType: TransitionHookType): TransitionHook[] { + buildHooks(hookType: TransitionEventType): TransitionHook[] { // Find all the matching registered hooks for a given hook type let matchingHooks = this.getMatchingHooks(hookType, this.treeChanges); if (!matchingHooks) return []; @@ -110,7 +110,7 @@ export class HookBuilder { * * @returns an array of matched [[RegisteredHook]]s */ - public getMatchingHooks(hookType: TransitionHookType, treeChanges: TreeChanges): RegisteredHook[] { + public getMatchingHooks(hookType: TransitionEventType, treeChanges: TreeChanges): RegisteredHook[] { let isCreate = hookType.hookPhase === TransitionHookPhase.CREATE; // Instance and Global hook registries diff --git a/src/transition/hookRegistry.ts b/src/transition/hookRegistry.ts index f89bca72..8197e769 100644 --- a/src/transition/hookRegistry.ts +++ b/src/transition/hookRegistry.ts @@ -1,8 +1,10 @@ /** @coreapi @module transition */ /** for typedoc */ -import {extend, removeFrom, allTrueR, tail} from "../common/common"; +import { extend, removeFrom, allTrueR, tail, uniqR, pushTo, equals, values, identity } from "../common/common"; import {isString, isFunction} from "../common/predicates"; import {PathNode} from "../path/node"; -import {TransitionStateHookFn, TransitionHookFn} from "./interface"; // has or is using +import { + TransitionStateHookFn, TransitionHookFn, TransitionHookPhase, TransitionHookScope, IHookRegistry +} from "./interface"; // has or is using import { HookRegOptions, HookMatchCriteria, IHookRegistration, TreeChanges, @@ -10,7 +12,8 @@ import { } from "./interface"; import {Glob} from "../common/glob"; import {State} from "../state/stateObject"; -import {TransitionHookType} from "./transitionHookType"; +import {TransitionEventType} from "./transitionEventType"; +import { TransitionService } from "./transitionService"; /** * Determines if the given state matches the matchCriteria @@ -49,31 +52,89 @@ export function matchState(state: State, criterion: HookMatchCriterion) { * The registration data for a registered transition hook */ export class RegisteredHook implements RegisteredHook { - hookType: TransitionHookType; - callback: HookFn; matchCriteria: HookMatchCriteria; priority: number; bind: any; _deregistered: boolean; - constructor(hookType: TransitionHookType, + constructor(public tranSvc: TransitionService, + public eventType: TransitionEventType, + public callback: HookFn, matchCriteria: HookMatchCriteria, - callback: HookFn, - options: HookRegOptions = {}) { - this.hookType = hookType; - this.callback = callback; - this.matchCriteria = extend({ to: true, from: true, exiting: true, retained: true, entering: true }, matchCriteria); + options: HookRegOptions = {} as any) { + this.matchCriteria = extend(this._getDefaultMatchCriteria(), matchCriteria); this.priority = options.priority || 0; this.bind = options.bind || null; this._deregistered = false; } - private static _matchingNodes(nodes: PathNode[], criterion: HookMatchCriterion): PathNode[] { + /** + * Given an array of PathNodes, and a HookMatchCriteria, returns an array containing + * the PathNodes that the criteria matches, or null if there were no matching nodes. + * + * Returning null is significant to distinguish between the default + * "match-all criterion value" of `true` compared to a () => true, + * when the nodes is an empty array. + * + * This is useful to allow a transition match criteria of `entering: true` + * to still match a transition, even when `entering === []`. Contrast that + * with `entering: (state) => true` which only matches when a state is actually + * being entered. + */ + private _matchingNodes(nodes: PathNode[], criterion: HookMatchCriterion): PathNode[] { if (criterion === true) return nodes; let matching = nodes.filter(node => matchState(node.state, criterion)); return matching.length ? matching : null; } + /** + * Returns an object which has all the criteria match paths as keys and `true` as values, i.e.: + * + * { to: true, from: true, entering: true, exiting: true, retained: true } + */ + private _getDefaultMatchCriteria(): HookMatchCriteria { + return this.tranSvc._pluginapi.getTransitionEventTypes() + .map(type => type.criteriaMatchPath) + .reduce(uniqR, []) + .reduce((acc, path) => (acc[path] = true, acc), {}); + } + + /** + * For all the criteria match paths in all TransitionHookTypes, + * return an object where: keys are pathname, vals are TransitionHookScope + */ + private _getPathScopes(): { [key: string]: TransitionHookScope } { + return this.tranSvc._pluginapi.getTransitionEventTypes().reduce((paths, type) => { + paths[type.criteriaMatchPath] = type.hookScope; + return paths + }, {}); + } + + /** + * Create a IMatchingNodes object from the TransitionHookTypes that basically looks like this: + * + * let matches: IMatchingNodes = { + * to: _matchingNodes([tail(treeChanges.to)], mc.to), + * from: _matchingNodes([tail(treeChanges.from)], mc.from), + * exiting: _matchingNodes(treeChanges.exiting, mc.exiting), + * retained: _matchingNodes(treeChanges.retained, mc.retained), + * entering: _matchingNodes(treeChanges.entering, mc.entering), + * }; + */ + private _getMatchingNodes(treeChanges: TreeChanges): IMatchingNodes { + let pathScopes: { [key: string]: TransitionHookScope } = this._getPathScopes(); + + return Object.keys(pathScopes).reduce((mn: IMatchingNodes, pathName: string) => { + // STATE scope criteria matches against every node in the path. + // TRANSITION scope criteria matches against only the last node in the path + let isStateHook = pathScopes[pathName] === TransitionHookScope.STATE; + let nodes: PathNode[] = isStateHook ? treeChanges[pathName] : [tail(treeChanges[pathName])]; + + mn[pathName] = this._matchingNodes(nodes, this.matchCriteria[pathName]); + return mn; + }, {} as IMatchingNodes); + } + /** * Determines if this hook's [[matchCriteria]] match the given [[TreeChanges]] * @@ -81,21 +142,10 @@ export class RegisteredHook implements RegisteredHook { * are the matching [[PathNode]]s for each [[HookMatchCriterion]] (to, from, exiting, retained, entering) */ matches(treeChanges: TreeChanges): IMatchingNodes { - let mc = this.matchCriteria, _matchingNodes = RegisteredHook._matchingNodes; - - let matches: IMatchingNodes = { - to: _matchingNodes([tail(treeChanges.to)], mc.to), - from: _matchingNodes([tail(treeChanges.from)], mc.from), - exiting: _matchingNodes(treeChanges.exiting, mc.exiting), - retained: _matchingNodes(treeChanges.retained, mc.retained), - entering: _matchingNodes(treeChanges.entering, mc.entering), - }; + let matches = this._getMatchingNodes(treeChanges); // Check if all the criteria matched the TreeChanges object - let allMatched: boolean = ["to", "from", "exiting", "retained", "entering"] - .map(prop => matches[prop]) - .reduce(allTrueR, true); - + let allMatched = values(matches).every(identity); return allMatched ? matches : null; } } @@ -106,17 +156,23 @@ export interface RegisteredHooks { } /** @hidden Return a registration function of the requested type. */ -export function makeHookRegistrationFn(registeredHooks: RegisteredHooks, type: TransitionHookType): IHookRegistration { - let name = type.name; - registeredHooks[name] = []; +export function makeEvent(registry: IHookRegistry, transitionService: TransitionService, eventType: TransitionEventType) { + // Create the object which holds the registered transition hooks. + let _registeredHooks = registry._registeredHooks = (registry._registeredHooks || {}); + let hooks = _registeredHooks[eventType.name] = []; - return function (matchObject, callback, options = {}) { - let registeredHook = new RegisteredHook(type, matchObject, callback, options); - registeredHooks[name].push(registeredHook); + // Create hook registration function on the IHookRegistry for the event + registry[eventType.name] = hookRegistrationFn; + + function hookRegistrationFn(matchObject, callback, options = {}) { + let registeredHook = new RegisteredHook(transitionService, eventType, callback, matchObject, options); + hooks.push(registeredHook); return function deregisterEventHook() { registeredHook._deregistered = true; - removeFrom(registeredHooks[name])(registeredHook); + removeFrom(hooks)(registeredHook); }; - }; + } + + return hookRegistrationFn; } \ No newline at end of file diff --git a/src/transition/index.ts b/src/transition/index.ts index 38ad87b7..cb868427 100644 --- a/src/transition/index.ts +++ b/src/transition/index.ts @@ -16,5 +16,6 @@ export * from "./hookRegistry"; export * from "./rejectFactory"; export * from "./transition"; export * from "./transitionHook"; +export * from "./transitionEventType"; export * from "./transitionService"; diff --git a/src/transition/interface.ts b/src/transition/interface.ts index d3eee6c1..3a065139 100644 --- a/src/transition/interface.ts +++ b/src/transition/interface.ts @@ -694,6 +694,9 @@ export interface IHookRegistry { * ``` */ getHooks(hookName: string): RegisteredHook[]; + + /** @hidden place to store the hooks */ + _registeredHooks: { [key: string]: RegisteredHook[] } } /** A predicate type which takes a [[State]] and returns a boolean */ diff --git a/src/transition/transition.ts b/src/transition/transition.ts index 4a89b391..8a4f59d7 100644 --- a/src/transition/transition.ts +++ b/src/transition/transition.ts @@ -18,7 +18,7 @@ import { import { TransitionStateHookFn, TransitionHookFn } from "./interface"; // has or is using import {TransitionHook} from "./transitionHook"; -import {matchState, RegisteredHooks, makeHookRegistrationFn, RegisteredHook} from "./hookRegistry"; +import {matchState, RegisteredHooks, makeEvent, RegisteredHook} from "./hookRegistry"; import {HookBuilder} from "./hookBuilder"; import {PathNode} from "../path/node"; import {PathFactory} from "../path/pathFactory"; @@ -84,7 +84,7 @@ export class Transition implements IHookRegistry { private _error: any; /** @hidden Holds the hook registration functions such as those passed to Transition.onStart() */ - private _transitionHooks: RegisteredHooks = { }; + _registeredHooks: RegisteredHooks = { }; /** @hidden */ private _options: TransitionOptions; @@ -116,14 +116,14 @@ export class Transition implements IHookRegistry { * (which can then be used to register hooks) */ private createTransitionHookRegFns() { - this.router.transitionService.getTransitionHookTypes() + this.router.transitionService._pluginapi.getTransitionEventTypes() .filter(type => type.hookPhase !== TransitionHookPhase.CREATE) - .forEach(type => this[type.name] = makeHookRegistrationFn(this._transitionHooks, type)); + .forEach(type => makeEvent(this, this.router.transitionService, type)); } /** @hidden @internalapi */ getHooks(hookName: string): RegisteredHook[] { - return this._transitionHooks[hookName]; + return this._registeredHooks[hookName]; } /** @@ -509,13 +509,23 @@ export class Transition implements IHookRegistry { /** @hidden If a transition doesn't exit/enter any states, returns any [[Param]] whose value changed */ private _changedParams(): Param[] { let tc = this._treeChanges; - let to = tc.to; - let from = tc.from; - if (this._options.reload || tc.entering.length || tc.exiting.length) return undefined; - - let nodeSchemas: Param[][] = to.map((node: PathNode) => node.paramSchema); - let [toValues, fromValues] = [to, from].map(path => path.map(x => x.paramValues)); + /** Return undefined if it's not a "dynamic" transition, for the following reasons */ + // If user explicitly wants a reload + if (this._options.reload) return undefined; + // If any states are exiting or entering + if (tc.exiting.length || tc.entering.length) return undefined; + // If to/from path lengths differ + if (tc.to.length !== tc.from.length) return undefined; + // If the to/from paths are different + let pathsDiffer: boolean = arrayTuples(tc.to, tc.from) + .map(tuple => tuple[0].state !== tuple[1].state) + .reduce(anyTrueR, false); + if (pathsDiffer) return undefined; + + // Find any parameter values that differ + let nodeSchemas: Param[][] = tc.to.map((node: PathNode) => node.paramSchema); + let [toValues, fromValues] = [tc.to, tc.from].map(path => path.map(x => x.paramValues)); let tuples = arrayTuples(nodeSchemas, toValues, fromValues); return tuples.map(([schema, toVals, fromVals]) => Param.changed(schema, toVals, fromVals)).reduce(unnestR, []); diff --git a/src/transition/transitionHookType.ts b/src/transition/transitionEventType.ts similarity index 80% rename from src/transition/transitionHookType.ts rename to src/transition/transitionEventType.ts index 04771738..0078bc4f 100644 --- a/src/transition/transitionHookType.ts +++ b/src/transition/transitionEventType.ts @@ -10,7 +10,7 @@ import {GetErrorHandler, GetResultHandler, TransitionHook} from "./transitionHoo * @interalapi * @module transition */ -export class TransitionHookType { +export class TransitionEventType { constructor(public name: string, public hookPhase: TransitionHookPhase, @@ -18,8 +18,8 @@ export class TransitionHookType { public hookOrder: number, public criteriaMatchPath: string, public reverseSort: boolean = false, - public getResultHandler: GetResultHandler = TransitionHook.HANDLE_RESULT, - public getErrorHandler: GetErrorHandler = TransitionHook.REJECT_ERROR, + public getResultHandler: GetResultHandler = TransitionHook.HANDLE_RESULT, + public getErrorHandler: GetErrorHandler = TransitionHook.REJECT_ERROR, public rejectIfSuperseded: boolean = true, ) { } } diff --git a/src/transition/transitionHook.ts b/src/transition/transitionHook.ts index 85ec9c35..5e33bfaf 100644 --- a/src/transition/transitionHook.ts +++ b/src/transition/transitionHook.ts @@ -11,7 +11,7 @@ import {Rejection} from "./rejectFactory"; import {TargetState} from "../state/targetState"; import {Transition} from "./transition"; import {State} from "../state/stateObject"; -import {TransitionHookType} from "./transitionHookType"; +import {TransitionEventType} from "./transitionEventType"; import {StateService} from "../state/stateService"; // has or is using import {RegisteredHook} from "./hookRegistry"; // has or is using @@ -58,7 +58,7 @@ export class TransitionHook { undefined; private rejectIfSuperseded = () => - this.registeredHook.hookType.rejectIfSuperseded && this.options.current() !== this.options.transition; + this.registeredHook.eventType.rejectIfSuperseded && this.options.current() !== this.options.transition; invokeHook(): Promise { let hook = this.registeredHook; @@ -76,8 +76,8 @@ export class TransitionHook { let trans = this.transition; let state = this.stateContext; - let errorHandler = hook.hookType.getErrorHandler(this); - let resultHandler = hook.hookType.getResultHandler(this); + let errorHandler = hook.eventType.getErrorHandler(this); + let resultHandler = hook.eventType.getResultHandler(this); resultHandler = resultHandler || identity; if (!errorHandler) { diff --git a/src/transition/transitionService.ts b/src/transition/transitionService.ts index 1edf7e38..ba73f13a 100644 --- a/src/transition/transitionService.ts +++ b/src/transition/transitionService.ts @@ -9,7 +9,7 @@ import { } from "./interface"; // has or is using import {Transition} from "./transition"; -import {RegisteredHooks, makeHookRegistrationFn, RegisteredHook} from "./hookRegistry"; +import {RegisteredHooks, makeEvent, RegisteredHook} from "./hookRegistry"; import {TargetState} from "../state/targetState"; import {PathNode} from "../path/node"; import {ViewService} from "../view/view"; @@ -21,10 +21,10 @@ import {registerUpdateUrl} from "../hooks/url"; import {registerRedirectToHook} from "../hooks/redirectTo"; import {registerOnExitHook, registerOnRetainHook, registerOnEnterHook} from "../hooks/onEnterExitRetain"; import {registerLazyLoadHook} from "../hooks/lazyLoad"; -import {TransitionHookType} from "./transitionHookType"; -import {TransitionHook} from "./transitionHook"; +import {TransitionEventType} from "./transitionEventType"; +import { TransitionHook, GetResultHandler, GetErrorHandler } from "./transitionHook"; import {isDefined} from "../common/predicates"; -import { removeFrom, values } from "../common/common"; +import { removeFrom, values, bindFunctions } from "../common/common"; import { Disposable } from "../interface"; /** @@ -102,9 +102,9 @@ export class TransitionService implements IHookRegistry, Disposable { public $view: ViewService; /** @hidden The transition hook types, such as `onEnter`, `onStart`, etc */ - private _transitionHookTypes: TransitionHookType[] = []; + private _eventTypes: TransitionEventType[] = []; /** @hidden The registered transition hooks */ - private _transitionHooks: RegisteredHooks = { }; + _registeredHooks: RegisteredHooks = { }; /** * This object has hook de-registration functions for the built-in hooks. @@ -136,7 +136,7 @@ export class TransitionService implements IHookRegistry, Disposable { dispose(router: UIRouter) { delete router.globals.transition; - values(this._transitionHooks).forEach((hooksArray: RegisteredHook[]) => hooksArray.forEach(hook => { + values(this._registeredHooks).forEach((hooksArray: RegisteredHook[]) => hooksArray.forEach(hook => { hook._deregistered = true; removeFrom(hooksArray, hook); })); @@ -162,48 +162,67 @@ export class TransitionService implements IHookRegistry, Disposable { const Phase = TransitionHookPhase; const TH = TransitionHook; - let hookTypes = [ - new TransitionHookType("onCreate", Phase.CREATE, Scope.TRANSITION, 0, "to", false, TH.IGNORE_RESULT, TH.THROW_ERROR, false), + this.defineEvent("onCreate", Phase.CREATE, Scope.TRANSITION, 0, "to", false, TH.IGNORE_RESULT, TH.THROW_ERROR, false); - new TransitionHookType("onBefore", Phase.BEFORE, Scope.TRANSITION, 0, "to", false, TH.HANDLE_RESULT), + this.defineEvent("onBefore", Phase.BEFORE, Scope.TRANSITION, 0, "to", false, TH.HANDLE_RESULT); - new TransitionHookType("onStart", Phase.ASYNC, Scope.TRANSITION, 0, "to"), - new TransitionHookType("onExit", Phase.ASYNC, Scope.STATE, 10, "exiting", true), - new TransitionHookType("onRetain", Phase.ASYNC, Scope.STATE, 20, "retained"), - new TransitionHookType("onEnter", Phase.ASYNC, Scope.STATE, 30, "entering"), - new TransitionHookType("onFinish", Phase.ASYNC, Scope.TRANSITION, 40, "to"), + this.defineEvent("onStart", Phase.ASYNC, Scope.TRANSITION, 0, "to"); + this.defineEvent("onExit", Phase.ASYNC, Scope.STATE, 100, "exiting", true); + this.defineEvent("onRetain", Phase.ASYNC, Scope.STATE, 200, "retained"); + this.defineEvent("onEnter", Phase.ASYNC, Scope.STATE, 300, "entering"); + this.defineEvent("onFinish", Phase.ASYNC, Scope.TRANSITION, 400, "to"); - new TransitionHookType("onSuccess", Phase.SUCCESS, Scope.TRANSITION, 0, "to", false, TH.IGNORE_RESULT, TH.LOG_ERROR, false), - new TransitionHookType("onError", Phase.ERROR, Scope.TRANSITION, 0, "to", false, TH.IGNORE_RESULT, TH.LOG_ERROR, false), - ]; - - hookTypes.forEach(type => this[type.name] = this.registerTransitionHookType(type)) + this.defineEvent("onSuccess", Phase.SUCCESS, Scope.TRANSITION, 0, "to", false, TH.IGNORE_RESULT, TH.LOG_ERROR, false); + this.defineEvent("onError", Phase.ERROR, Scope.TRANSITION, 0, "to", false, TH.IGNORE_RESULT, TH.LOG_ERROR, false); } + _pluginapi = bindFunctions(this, {}, this, [ + 'registerTransitionHookType', + 'getTransitionEventTypes', + 'getHooks', + ]); + /** * Defines a transition hook type and returns a transition hook registration * function (which can then be used to register hooks of this type). * @internalapi */ - registerTransitionHookType(hookType: TransitionHookType) { - this._transitionHookTypes.push(hookType); - return makeHookRegistrationFn(this._transitionHooks, hookType); - } + defineEvent(name: string, + hookPhase: TransitionHookPhase, + hookScope: TransitionHookScope, + hookOrder: number, + criteriaMatchPath: string, + reverseSort: boolean = false, + getResultHandler: GetResultHandler = TransitionHook.HANDLE_RESULT, + getErrorHandler: GetErrorHandler = TransitionHook.REJECT_ERROR, + rejectIfSuperseded: boolean = true) + { + let eventType = new TransitionEventType(name, hookPhase, hookScope, hookOrder, criteriaMatchPath, reverseSort, getResultHandler, getErrorHandler, rejectIfSuperseded); + + this._eventTypes.push(eventType); + makeEvent(this, this, eventType); + }; - getTransitionHookTypes(phase?: TransitionHookPhase): TransitionHookType[] { + + /** + * @hidden + * Returns the known event types, such as `onBefore` + * If a phase argument is provided, returns only events for the given phase. + */ + private getTransitionEventTypes(phase?: TransitionHookPhase): TransitionEventType[] { let transitionHookTypes = isDefined(phase) ? - this._transitionHookTypes.filter(type => type.hookPhase === phase) : - this._transitionHookTypes.slice(); + this._eventTypes.filter(type => type.hookPhase === phase) : + this._eventTypes.slice(); return transitionHookTypes.sort((l, r) => { - let byphase = l.hookPhase - r.hookPhase; - return byphase === 0 ? l.hookOrder - r.hookOrder : byphase; + let cmpByPhase = l.hookPhase - r.hookPhase; + return cmpByPhase === 0 ? l.hookOrder - r.hookOrder : cmpByPhase; }) } /** @hidden */ - getHooks(hookName: string): RegisteredHook[] { - return this._transitionHooks[hookName]; + public getHooks(hookName: string): RegisteredHook[] { + return this._registeredHooks[hookName]; } /** @hidden */ @@ -233,3 +252,9 @@ export class TransitionService implements IHookRegistry, Disposable { fns.lazyLoad = registerLazyLoadHook(this); } } + +export interface TransitionServicePluginAPI { + registerTransitionHookType(hookType: TransitionEventType): void; + getTransitionEventTypes(phase?: TransitionHookPhase): TransitionEventType[]; + getHooks(hookName: string): RegisteredHook[]; +} \ No newline at end of file diff --git a/test/hookBuilderSpec.ts b/test/hookBuilderSpec.ts index 37cd4163..94392ab6 100644 --- a/test/hookBuilderSpec.ts +++ b/test/hookBuilderSpec.ts @@ -163,7 +163,7 @@ describe('HookBuilder:', function() { describe('should have the correct state context', function() { const hookTypeByName = name => - $trans.getTransitionHookTypes().filter(type => type.name === name)[0]; + $trans._pluginapi.getTransitionEventTypes().filter(type => type.name === name)[0]; const context = hook => hook.stateContext && hook.stateContext.name;