Skip to content

Commit 54dfb87

Browse files
refactor(RegisteredHook): remove IEventHook; rename EventHook to RegisteredHook
refactor(TransitionHook): Remove TransitionHookOptions.rejectIfSuperseded
1 parent f486ced commit 54dfb87

9 files changed

+78
-100
lines changed

src/common/trace.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export class Trace {
168168
digest = this.approximateDigests,
169169
event = parse("traceData.hookType")(options) || "internal",
170170
context = parse("traceData.context.state.name")(options) || parse("traceData.context")(options) || "unknown",
171-
name = functionToString((step as any).eventHook.callback);
171+
name = functionToString((step as any).registeredHook.callback);
172172
console.log(`Transition #${tid} Digest #${digest}: Hook -> ${event} context: ${context}, ${maxLength(200, name)}`);
173173
}
174174

src/transition/hookBuilder.ts

+13-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {extend, tail, assertPredicate, unnestR, identity} from "../common/common
44
import {isArray} from "../common/predicates";
55

66
import {
7-
TransitionOptions, TransitionHookOptions, IHookRegistry, TreeChanges, IEventHook, IMatchingNodes,
7+
TransitionOptions, TransitionHookOptions, IHookRegistry, TreeChanges, IMatchingNodes,
88
TransitionHookPhase, TransitionHookScope
99
} from "./interface";
1010

@@ -14,15 +14,16 @@ import {State} from "../state/stateObject";
1414
import {PathNode} from "../path/node";
1515
import {TransitionService} from "./transitionService";
1616
import {TransitionHookType} from "./transitionHookType";
17+
import {RegisteredHook} from "./hookRegistry";
1718

1819
/**
1920
* This class returns applicable TransitionHooks for a specific Transition instance.
2021
*
21-
* Hooks (IEventHook) may be registered globally, e.g., $transitions.onEnter(...), or locally, e.g.
22-
* myTransition.onEnter(...). The HookBuilder finds matching IEventHooks (where the match criteria is
22+
* Hooks ([[RegisteredHook]]) may be registered globally, e.g., $transitions.onEnter(...), or locally, e.g.
23+
* myTransition.onEnter(...). The HookBuilder finds matching RegisteredHooks (where the match criteria is
2324
* determined by the type of hook)
2425
*
25-
* The HookBuilder also converts IEventHooks objects to TransitionHook objects, which are used to run a Transition.
26+
* The HookBuilder also converts RegisteredHooks objects to TransitionHook objects, which are used to run a Transition.
2627
*
2728
* The HookBuilder constructor is given the $transitions service and a Transition instance. Thus, a HookBuilder
2829
* instance may only be used for one specific Transition object. (side note: the _treeChanges accessor is private
@@ -62,7 +63,7 @@ export class HookBuilder {
6263
/**
6364
* Returns an array of newly built TransitionHook objects.
6465
*
65-
* - Finds all IEventHooks registered for the given `hookType` which matched the transition's [[TreeChanges]].
66+
* - Finds all RegisteredHooks registered for the given `hookType` which matched the transition's [[TreeChanges]].
6667
* - Finds [[PathNode]] (or `PathNode[]`) to use as the TransitionHook context(s)
6768
* - For each of the [[PathNode]]s, creates a TransitionHook
6869
*
@@ -73,7 +74,7 @@ export class HookBuilder {
7374
let matchingHooks = this.getMatchingHooks(hookType, this.treeChanges);
7475
if (!matchingHooks) return [];
7576

76-
const makeTransitionHooks = (hook: IEventHook) => {
77+
const makeTransitionHooks = (hook: RegisteredHook) => {
7778
// Fetch the Nodes that caused this hook to match.
7879
let matches: IMatchingNodes = hook.matches(this.treeChanges);
7980
// Select the PathNode[] that will be used as TransitionHook context objects
@@ -87,7 +88,7 @@ export class HookBuilder {
8788
}, this.baseHookOptions);
8889

8990
let state = hookType.hookScope === TransitionHookScope.STATE ? node.state : null;
90-
let transitionHook = new TransitionHook(this.transition, state, hook, hookType, _options);
91+
let transitionHook = new TransitionHook(this.transition, state, hook, _options);
9192
return <HookTuple> { hook, node, transitionHook };
9293
});
9394
};
@@ -99,30 +100,30 @@ export class HookBuilder {
99100
}
100101

101102
/**
102-
* Finds all IEventHooks from:
103+
* Finds all RegisteredHooks from:
103104
* - The Transition object instance hook registry
104105
* - The TransitionService ($transitions) global hook registry
105106
*
106107
* which matched:
107108
* - the eventType
108109
* - the matchCriteria (to, from, exiting, retained, entering)
109110
*
110-
* @returns an array of matched [[IEventHook]]s
111+
* @returns an array of matched [[RegisteredHook]]s
111112
*/
112-
public getMatchingHooks(hookType: TransitionHookType, treeChanges: TreeChanges): IEventHook[] {
113+
public getMatchingHooks(hookType: TransitionHookType, treeChanges: TreeChanges): RegisteredHook[] {
113114
let isCreate = hookType.hookPhase === TransitionHookPhase.CREATE;
114115

115116
// Instance and Global hook registries
116117
let registries = isCreate ? [ this.$transitions ] : [ this.transition, this.$transitions ];
117118

118119
return registries.map((reg: IHookRegistry) => reg.getHooks(hookType.name)) // Get named hooks from registries
119120
.filter(assertPredicate(isArray, `broken event named: ${hookType.name}`)) // Sanity check
120-
.reduce(unnestR, []) // Un-nest IEventHook[][] to IEventHook[] array
121+
.reduce(unnestR, []) // Un-nest RegisteredHook[][] to RegisteredHook[] array
121122
.filter(hook => hook.matches(treeChanges)); // Only those satisfying matchCriteria
122123
}
123124
}
124125

125-
interface HookTuple { hook: IEventHook, node: PathNode, transitionHook: TransitionHook }
126+
interface HookTuple { hook: RegisteredHook, node: PathNode, transitionHook: TransitionHook }
126127

127128
/**
128129
* A factory for a sort function for HookTuples.

src/transition/hookRegistry.ts

+24-13
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import {PathNode} from "../path/node";
55
import {TransitionStateHookFn, TransitionHookFn} from "./interface"; // has or is using
66

77
import {
8-
HookRegOptions, HookMatchCriteria, IEventHook, IHookRegistry, IHookRegistration, TreeChanges,
8+
HookRegOptions, HookMatchCriteria, IHookRegistration, TreeChanges,
99
HookMatchCriterion, IMatchingNodes, HookFn
1010
} from "./interface";
1111
import {Glob} from "../common/glob";
1212
import {State} from "../state/stateObject";
13+
import {TransitionHookType} from "./transitionHookType";
1314

1415
/**
1516
* Determines if the given state matches the matchCriteria
@@ -43,15 +44,23 @@ export function matchState(state: State, criterion: HookMatchCriterion) {
4344
return !!matchFn(state);
4445
}
4546

46-
/** @hidden */
47-
export class EventHook implements IEventHook {
47+
/**
48+
* @hidden
49+
* The registration data for a registered transition hook
50+
*/
51+
export class RegisteredHook implements RegisteredHook {
52+
hookType: TransitionHookType;
4853
callback: HookFn;
4954
matchCriteria: HookMatchCriteria;
5055
priority: number;
5156
bind: any;
5257
_deregistered: boolean;
5358

54-
constructor(matchCriteria: HookMatchCriteria, callback: HookFn, options: HookRegOptions = <any>{}) {
59+
constructor(hookType: TransitionHookType,
60+
matchCriteria: HookMatchCriteria,
61+
callback: HookFn,
62+
options: HookRegOptions = <any>{}) {
63+
this.hookType = hookType;
5564
this.callback = callback;
5665
this.matchCriteria = extend({ to: true, from: true, exiting: true, retained: true, entering: true }, matchCriteria);
5766
this.priority = options.priority || 0;
@@ -72,7 +81,7 @@ export class EventHook implements IEventHook {
7281
* are the matching [[PathNode]]s for each [[HookMatchCriterion]] (to, from, exiting, retained, entering)
7382
*/
7483
matches(treeChanges: TreeChanges): IMatchingNodes {
75-
let mc = this.matchCriteria, _matchingNodes = EventHook._matchingNodes;
84+
let mc = this.matchCriteria, _matchingNodes = RegisteredHook._matchingNodes;
7685

7786
let matches: IMatchingNodes = {
7887
to: _matchingNodes([tail(treeChanges.to)], mc.to),
@@ -92,20 +101,22 @@ export class EventHook implements IEventHook {
92101
}
93102

94103
/** @hidden */
95-
export interface IEventHooks {
96-
[key: string]: IEventHook[];
104+
export interface RegisteredHooks {
105+
[key: string]: RegisteredHook[];
97106
}
98107

99108
/** @hidden Return a registration function of the requested type. */
100-
export function makeHookRegistrationFn(hooks: IEventHooks, name:string): IHookRegistration {
101-
hooks[name] = [];
109+
export function makeHookRegistrationFn(registeredHooks: RegisteredHooks, type: TransitionHookType): IHookRegistration {
110+
let name = type.name;
111+
registeredHooks[name] = [];
112+
102113
return function (matchObject, callback, options = {}) {
103-
let eventHook = new EventHook(matchObject, callback, options);
104-
hooks[name].push(eventHook);
114+
let registeredHook = new RegisteredHook(type, matchObject, callback, options);
115+
registeredHooks[name].push(registeredHook);
105116

106117
return function deregisterEventHook() {
107-
eventHook._deregistered = true;
108-
removeFrom(hooks[name])(eventHook);
118+
registeredHook._deregistered = true;
119+
removeFrom(registeredHooks[name])(registeredHook);
109120
};
110121
};
111122
}

src/transition/interface.ts

+2-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {Transition} from "./transition";
66
import {State} from "../state/stateObject";
77
import {PathNode} from "../path/node";
88
import {TargetState} from "../state/targetState";
9+
import {RegisteredHook} from "./hookRegistry";
910

1011
/**
1112
* The TransitionOptions object can be used to change the behavior of a transition.
@@ -86,8 +87,6 @@ export interface TransitionOptions {
8687

8788
/** @internalapi */
8889
export interface TransitionHookOptions {
89-
async ?: boolean;
90-
rejectIfSuperseded ?: boolean;
9190
current ?: () => Transition; //path?
9291
transition ?: Transition;
9392
hookType ?: string;
@@ -694,7 +693,7 @@ export interface IHookRegistry {
694693
* $transitions.getHooks("onEnter")
695694
* ```
696695
*/
697-
getHooks(hookName: string): IEventHook[];
696+
getHooks(hookName: string): RegisteredHook[];
698697
}
699698

700699
/** A predicate type which takes a [[State]] and returns a boolean */
@@ -791,14 +790,5 @@ export interface IMatchingNodes {
791790
*/
792791
export type HookMatchCriterion = (string|IStateMatch|boolean)
793792

794-
/** @hidden */
795-
export interface IEventHook {
796-
callback: HookFn;
797-
priority?: number;
798-
bind?: any;
799-
matches: (treeChanges: TreeChanges) => IMatchingNodes;
800-
_deregistered: boolean;
801-
}
802-
803793
export enum TransitionHookPhase { CREATE, BEFORE, ASYNC, SUCCESS, ERROR }
804794
export enum TransitionHookScope { TRANSITION, STATE }

src/transition/transition.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ import { prop, propEq, val, not } from "../common/hof";
1111

1212
import {StateDeclaration, StateOrName} from "../state/interface";
1313
import {
14-
TransitionOptions, TreeChanges, IHookRegistry, IEventHook, TransitionHookPhase,
14+
TransitionOptions, TreeChanges, IHookRegistry, TransitionHookPhase,
1515
TransitionCreateHookFn
1616
} from "./interface";
1717

1818
import { TransitionStateHookFn, TransitionHookFn } from "./interface"; // has or is using
1919

2020
import {TransitionHook} from "./transitionHook";
21-
import {matchState, IEventHooks, makeHookRegistrationFn} from "./hookRegistry";
21+
import {matchState, RegisteredHooks, makeHookRegistrationFn, RegisteredHook} from "./hookRegistry";
2222
import {HookBuilder} from "./hookBuilder";
2323
import {PathNode} from "../path/node";
2424
import {PathFactory} from "../path/pathFactory";
@@ -86,7 +86,7 @@ export class Transition implements IHookRegistry {
8686
private _error: any;
8787

8888
/** @hidden Holds the hook registration functions such as those passed to Transition.onStart() */
89-
private _transitionHooks: IEventHooks = { };
89+
private _transitionHooks: RegisteredHooks = { };
9090

9191
/** @hidden */
9292
private _options: TransitionOptions;
@@ -120,11 +120,11 @@ export class Transition implements IHookRegistry {
120120
private createTransitionHookRegFns() {
121121
this.router.transitionService.getTransitionHookTypes()
122122
.filter(type => type.hookPhase !== TransitionHookPhase.CREATE)
123-
.forEach(type => this[type.name] = makeHookRegistrationFn(this._transitionHooks, type.name));
123+
.forEach(type => this[type.name] = makeHookRegistrationFn(this._transitionHooks, type));
124124
}
125125

126126
/** @hidden @internalapi */
127-
getHooks(hookName: string): IEventHook[] {
127+
getHooks(hookName: string): RegisteredHook[] {
128128
return this._transitionHooks[hookName];
129129
}
130130

src/transition/transitionHook.ts

+19-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @coreapi @module transition */ /** for typedoc */
2-
import {TransitionHookOptions, IEventHook, HookResult} from "./interface";
2+
import {TransitionHookOptions, HookResult} from "./interface";
33
import {defaults, noop, identity} from "../common/common";
44
import {fnToString, maxLength} from "../common/strings";
55
import {isPromise} from "../common/predicates";
@@ -11,12 +11,11 @@ import {Rejection} from "./rejectFactory";
1111
import {TargetState} from "../state/targetState";
1212
import {Transition} from "./transition";
1313
import {State} from "../state/stateObject";
14+
import {TransitionHookType} from "./transitionHookType";
1415
import {StateService} from "../state/stateService"; // has or is using
15-
import {TransitionHookType} from "./transitionHookType"; // has or is using
16+
import {RegisteredHook} from "./hookRegistry"; // has or is using
1617

1718
let defaultOptions: TransitionHookOptions = {
18-
async: true,
19-
rejectIfSuperseded: true,
2019
current: noop,
2120
transition: null,
2221
traceData: {},
@@ -33,8 +32,7 @@ export type ErrorHandler = (error) => Promise<any>;
3332
export class TransitionHook {
3433
constructor(private transition: Transition,
3534
private stateContext: State,
36-
private eventHook: IEventHook,
37-
private hookType: TransitionHookType,
35+
private registeredHook: RegisteredHook,
3836
private options: TransitionHookOptions) {
3937
this.options = defaults(options, defaultOptions);
4038
}
@@ -59,43 +57,40 @@ export class TransitionHook {
5957
static THROW_ERROR: GetErrorHandler = (hook: TransitionHook) =>
6058
undefined;
6159

62-
private rejectForSuperseded = () =>
63-
this.hookType.rejectIfSuperseded && this.options.current() !== this.options.transition;
60+
private rejectIfSuperseded = () =>
61+
this.registeredHook.hookType.rejectIfSuperseded && this.options.current() !== this.options.transition;
6462

6563
invokeHook(): Promise<HookResult> {
66-
if (this.eventHook._deregistered) return;
64+
let hook = this.registeredHook;
65+
if (hook._deregistered) return;
6766

6867
let options = this.options;
6968
trace.traceHookInvocation(this, options);
7069

71-
if (this.rejectForSuperseded()) {
70+
if (this.rejectIfSuperseded()) {
7271
return Rejection.superseded(options.current()).toPromise();
7372
}
7473

75-
let errorHandler = this.hookType.errorHandler(this);
76-
let resultHandler = this.hookType.resultHandler(this);
77-
78-
return this._invokeCallback(resultHandler, errorHandler);
79-
}
80-
81-
private _invokeCallback(resultHandler: ResultHandler, errorHandler: ErrorHandler): Promise<HookResult> {
82-
let cb = this.eventHook.callback;
74+
let cb = hook.callback;
8375
let bind = this.options.bind;
8476
let trans = this.transition;
8577
let state = this.stateContext;
78+
79+
let errorHandler = hook.hookType.getErrorHandler(this);
80+
let resultHandler = hook.hookType.getResultHandler(this);
8681
resultHandler = resultHandler || identity;
8782

8883
if (!errorHandler) {
8984
return resultHandler(cb.call(bind, trans, state));
90-
}
91-
85+
}
86+
9287
try {
9388
return resultHandler(cb.call(bind, trans, state));
9489
} catch (error) {
9590
return errorHandler(error);
9691
}
9792
}
98-
93+
9994
/**
10095
* This method handles the return value of a Transition Hook.
10196
*
@@ -108,7 +103,7 @@ export class TransitionHook {
108103
handleHookResult(result: HookResult): Promise<HookResult> {
109104
// This transition is no longer current.
110105
// Another transition started while this hook was still running.
111-
if (this.rejectForSuperseded()) {
106+
if (this.rejectIfSuperseded()) {
112107
// Abort this transition
113108
return Rejection.superseded(this.options.current()).toPromise();
114109
}
@@ -136,10 +131,10 @@ export class TransitionHook {
136131
}
137132

138133
toString() {
139-
let { options, eventHook } = this;
134+
let { options, registeredHook } = this;
140135
let event = parse("traceData.hookType")(options) || "internal",
141136
context = parse("traceData.context.state.name")(options) || parse("traceData.context")(options) || "unknown",
142-
name = fnToString(eventHook.callback);
137+
name = fnToString(registeredHook.callback);
143138
return `${event} context: ${context}, ${maxLength(200, name)}`;
144139
}
145140

0 commit comments

Comments
 (0)