Skip to content

Commit 9bcc5db

Browse files
fix(transition): Normalize error() to always return Rejection
In a7464bb we normalized the `Transition.error()` to always return a `Rejection` object. However, we missed two cases: transition invalid and/or invalid parameter values. This fixes those two cases. We also updated the docs and return types (switch from `any` to `Rejection`) to better reflect this change.
1 parent 453b028 commit 9bcc5db

File tree

3 files changed

+83
-12
lines changed

3 files changed

+83
-12
lines changed

src/hooks/invalidTransition.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Transition } from '../transition/transition';
1212
*/
1313
function invalidTransitionHook(trans: Transition) {
1414
if (!trans.valid()) {
15-
throw new Error(trans.error());
15+
throw new Error(trans.error().toString());
1616
}
1717
}
1818

src/transition/rejectFactory.ts

+68-1
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,88 @@ import { stringify } from '../common/strings';
88
import { is } from '../common/hof';
99

1010
export enum RejectType {
11+
/**
12+
* A new transition superseded this one.
13+
*
14+
* While this transition was running, a new transition started.
15+
* This transition is cancelled because it was superseded by new transition.
16+
*/
1117
SUPERSEDED = 2,
18+
19+
/**
20+
* The transition was aborted
21+
*
22+
* The transition was aborted by a hook which returned `false`
23+
*/
1224
ABORTED = 3,
25+
26+
/**
27+
* The transition was invalid
28+
*
29+
* The transition was never started because it was invalid
30+
*/
1331
INVALID = 4,
32+
33+
/**
34+
* The transition was ignored
35+
*
36+
* The transition was ignored because it would have no effect.
37+
*
38+
* Either:
39+
*
40+
* - The transition is targeting the current state and parameter values
41+
* - The transition is targeting the same state and parameter values as the currently running transition.
42+
*/
1443
IGNORED = 5,
44+
45+
/**
46+
* The transition errored.
47+
*
48+
* This generally means a hook threw an error or returned a rejected promise
49+
*/
1550
ERROR = 6,
1651
}
1752

1853
/** @hidden */
1954
let id = 0;
2055

2156
export class Rejection {
57+
/** @hidden */
2258
$id = id++;
23-
type: number;
59+
/**
60+
* The type of the rejection.
61+
*
62+
* This value is an number representing the type of transition rejection.
63+
* If using Typescript, this is a Typescript enum.
64+
*
65+
* - [[RejectType.SUPERSEDED]] (`2`)
66+
* - [[RejectType.ABORTED]] (`3`)
67+
* - [[RejectType.INVALID]] (`4`)
68+
* - [[RejectType.IGNORED]] (`5`)
69+
* - [[RejectType.ERROR]] (`6`)
70+
*
71+
*/
72+
type: RejectType;
73+
74+
/**
75+
* A message describing the rejection
76+
*/
2477
message: string;
78+
79+
/**
80+
* A detail object
81+
*
82+
* This value varies based on the mechanism for rejecting the transition.
83+
* For example, if an error was thrown from a hook, the `detail` will be the `Error` object.
84+
* If a hook returned a rejected promise, the `detail` will be the rejected value.
85+
*/
2586
detail: any;
87+
88+
/**
89+
* Indicates if the transition was redirected.
90+
*
91+
* When a transition is redirected, the rejection [[type]] will be [[RejectType.SUPERSEDED]] and this flag will be true.
92+
*/
2693
redirected: boolean;
2794

2895
/** Returns true if the obj is a rejected promise created from the `asPromise` factory */

src/transition/transition.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { UIRouter } from '../router';
3636
import { UIInjector } from '../interface';
3737
import { RawParams } from '../params/interface';
3838
import { ResolvableLiteral } from '../resolve/interface';
39+
import { Rejection } from './rejectFactory';
3940

4041
/** @hidden */
4142
const stateSelf: (_state: StateObject) => StateDeclaration = prop('self');
@@ -87,7 +88,7 @@ export class Transition implements IHookRegistry {
8788
/** @hidden */
8889
_aborted: boolean;
8990
/** @hidden */
90-
private _error: any;
91+
private _error: Rejection;
9192

9293
/** @hidden Holds the hook registration functions such as those passed to Transition.onStart() */
9394
_registeredHooks: RegisteredHooks = {};
@@ -703,7 +704,7 @@ export class Transition implements IHookRegistry {
703704
runAllHooks(getHooksFor(TransitionHookPhase.SUCCESS));
704705
};
705706

706-
const transitionError = (reason: any) => {
707+
const transitionError = (reason: Rejection) => {
707708
trace.traceError(reason, this);
708709
this.success = false;
709710
this._deferred.reject(reason);
@@ -770,20 +771,23 @@ export class Transition implements IHookRegistry {
770771
* If the transition is invalid (and could not be run), returns the reason the transition is invalid.
771772
* If the transition was valid and ran, but was not successful, returns the reason the transition failed.
772773
*
773-
* @returns an error message explaining why the transition is invalid, or the reason the transition failed.
774+
* @returns a transition rejection explaining why the transition is invalid, or the reason the transition failed.
774775
*/
775-
error() {
776+
error(): Rejection {
776777
const state: StateObject = this.$to();
777778

778-
if (state.self.abstract) return `Cannot transition to abstract state '${state.name}'`;
779+
if (state.self.abstract) {
780+
return Rejection.invalid(`Cannot transition to abstract state '${state.name}'`);
781+
}
779782

780-
const paramDefs = state.parameters(),
781-
values = this.params();
783+
const paramDefs = state.parameters();
784+
const values = this.params();
782785
const invalidParams = paramDefs.filter(param => !param.validates(values[param.id]));
786+
783787
if (invalidParams.length) {
784-
return `Param values not valid for state '${state.name}'. Invalid params: [ ${invalidParams
785-
.map(param => param.id)
786-
.join(', ')} ]`;
788+
const invalidValues = invalidParams.map(param => `[${param.id}:${stringify(values[param.id])}]`).join(', ');
789+
const detail = `The following parameter values are not valid for state '${state.name}': ${invalidValues}`;
790+
return Rejection.invalid(detail);
787791
}
788792

789793
if (this.success === false) return this._error;

0 commit comments

Comments
 (0)