Skip to content

Commit

Permalink
Migrate TransitionAbortedError to builder + interface.
Browse files Browse the repository at this point in the history
Avoid trying to manually extend from a native error, instead use a
normal `Error` and add our name/code to it.
  • Loading branch information
rwjblue committed Nov 6, 2020
1 parent fe81e70 commit 10b5631
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 38 deletions.
3 changes: 2 additions & 1 deletion lib/router/route-info.ts
Expand Up @@ -9,6 +9,7 @@ import InternalTransition, {
QUERY_PARAMS_SYMBOL,
} from './transition';
import { isParam, isPromise, merge } from './utils';
import {buildTransitionAborted} from './transition-aborted-error';

interface IModel {
id?: string | number;
Expand Down Expand Up @@ -372,7 +373,7 @@ export default class InternalRouteInfo<T extends Route> {

private checkForAbort<U>(transition: InternalTransition<T>, value: U) {
if (transition.isAborted) {
throw new Error('Transition aborted');
throw buildTransitionAborted();
}

return value;
Expand Down
8 changes: 4 additions & 4 deletions lib/router/router.ts
Expand Up @@ -14,7 +14,7 @@ import InternalTransition, {
QUERY_PARAMS_SYMBOL,
STATE_SYMBOL,
} from './transition';
import TransitionAbortedError from './transition-aborted-error';
import { buildTransitionAborted, isTransitionAborted } from './transition-aborted-error';
import { TransitionIntent } from './transition-intent';
import NamedTransitionIntent from './transition-intent/named-transition-intent';
import URLTransitionIntent from './transition-intent/url-transition-intent';
Expand Down Expand Up @@ -371,7 +371,7 @@ export default abstract class Router<T extends Route> {
// Resolve with the final route.
return routeInfos[routeInfos.length - 1].route!;
} catch (e) {
if (!(e instanceof TransitionAbortedError)) {
if (!isTransitionAborted(e)) {
let infos = transition[STATE_SYMBOL]!.routeInfos;
transition.trigger(true, 'error', e, transition, infos[infos.length - 1].route);
transition.abort();
Expand Down Expand Up @@ -524,7 +524,7 @@ export default abstract class Router<T extends Route> {
}

if (transition && transition.isAborted) {
throw new TransitionAbortedError();
throw buildTransitionAborted();
}

route.context = context;
Expand All @@ -538,7 +538,7 @@ export default abstract class Router<T extends Route> {
}

if (transition && transition.isAborted) {
throw new TransitionAbortedError();
throw buildTransitionAborted();
}

currentRouteInfos.push(routeInfo);
Expand Down
39 changes: 15 additions & 24 deletions lib/router/transition-aborted-error.ts
@@ -1,29 +1,20 @@
export interface TransitionAbortedErrorContructor {
new (message?: string): ITransitionAbortedError;
readonly prototype: ITransitionAbortedError;
export interface TransitionAbortedError extends Error {
name: 'TransitionAborted';
code: 'TRANSITION_ABORTED';
}

export interface ITransitionAbortedError extends Error {
constructor: TransitionAbortedErrorContructor;
export function isTransitionAborted(maybeError: unknown): maybeError is TransitionAbortedError {
return (
typeof maybeError === 'object' &&
maybeError !== null &&
(maybeError as TransitionAbortedError).code === 'TRANSITION_ABORTED'
);
}

const TransitionAbortedError: TransitionAbortedErrorContructor = (function () {
TransitionAbortedError.prototype = Object.create(Error.prototype);
TransitionAbortedError.prototype.constructor = TransitionAbortedError;
export function buildTransitionAborted(): TransitionAbortedError {
let error = new Error('TransitionAborted') as TransitionAbortedError;
error.name = 'TransitionAborted';
error.code = 'TRANSITION_ABORTED';

function TransitionAbortedError(this: ITransitionAbortedError, message?: string) {
let error = Error.call(this, message);
this.name = 'TransitionAborted';
this.message = message || 'TransitionAborted';

if (Error.captureStackTrace) {
Error.captureStackTrace(this, TransitionAbortedError);
} else {
this.stack = error.stack;
}
}

return TransitionAbortedError as any;
})();

export default TransitionAbortedError;
return error;
}
3 changes: 2 additions & 1 deletion lib/router/transition-state.ts
Expand Up @@ -3,6 +3,7 @@ import { Dict } from './core';
import InternalRouteInfo, { Route, ResolvedRouteInfo } from './route-info';
import Transition from './transition';
import { forEach, promiseLabel } from './utils';
import { buildTransitionAborted } from './transition-aborted-error';

interface IParams {
[key: string]: unknown;
Expand Down Expand Up @@ -88,7 +89,7 @@ export default class TransitionState<T extends Route> {
// Proceed after ensuring that the redirect hook
// didn't abort this transition by transitioning elsewhere.
if (transition.isAborted) {
throw new Error('Transition aborted');
throw buildTransitionAborted();
}

return resolveOneRouteInfo();
Expand Down
7 changes: 4 additions & 3 deletions lib/router/transition.ts
Expand Up @@ -2,7 +2,7 @@ import { Promise } from 'rsvp';
import { Dict, Maybe, Option } from './core';
import InternalRouteInfo, { Route, RouteInfo, RouteInfoWithAttributes } from './route-info';
import Router from './router';
import TransitionAborted, { ITransitionAbortedError } from './transition-aborted-error';
import { TransitionAbortedError, buildTransitionAborted } from './transition-aborted-error';
import { OpaqueIntent } from './transition-intent';
import TransitionState, { TransitionError } from './transition-state';
import { log, promiseLabel } from './utils';
Expand Down Expand Up @@ -439,9 +439,10 @@ export default class Transition<T extends Route> implements Partial<Promise<T>>
Logs and returns an instance of TransitionAborted.
*/
export function logAbort(transition: Transition<any>): ITransitionAbortedError {
export function logAbort(transition: Transition<any>): TransitionAbortedError {
log(transition.router, transition.sequence, 'detected abort.');
return new TransitionAborted();

return buildTransitionAborted();
}

export function isTransition(obj: unknown): obj is typeof Transition {
Expand Down
4 changes: 2 additions & 2 deletions tests/test_helpers.ts
Expand Up @@ -3,10 +3,10 @@ import Router, { Route, Transition } from 'router';
import { Dict } from 'router/core';
import RouteInfo, { UnresolvedRouteInfoByParam } from 'router/route-info';
import { logAbort, PublicTransition } from 'router/transition';
import TransitionAbortedError from 'router/transition-aborted-error';
import { TransitionError } from 'router/transition-state';
import { UnrecognizedURLError } from 'router/unrecognized-url-error';
import { configure, resolve } from 'rsvp';
import { isTransitionAborted } from 'router/transition-aborted-error';

QUnit.config.testTimeout = 1000;

Expand Down Expand Up @@ -45,7 +45,7 @@ function module(name: string, options?: any) {

function assertAbort(assert: Assert) {
return function _assertAbort(e: Error) {
assert.ok(e instanceof TransitionAbortedError, 'transition was redirected/aborted');
assert.ok(isTransitionAborted(e), 'transition was redirected/aborted');
};
}

Expand Down
6 changes: 3 additions & 3 deletions tests/transition-aborted-error_test.ts
@@ -1,4 +1,4 @@
import TransitionAbortedError from 'router/transition-aborted-error';
import { isTransitionAborted, buildTransitionAborted } from 'router/transition-aborted-error';
import { module, test } from './test_helpers';

module('transition-aborted-error');
Expand All @@ -7,7 +7,7 @@ test('correct inheritance and name', function (assert) {
let error;

try {
throw new TransitionAbortedError('Message');
throw buildTransitionAborted();
} catch (e) {
error = e;
}
Expand All @@ -19,6 +19,6 @@ test('correct inheritance and name', function (assert) {
"TransitionAbortedError has the name 'TransitionAborted'"
);

assert.ok(error instanceof TransitionAbortedError);
assert.ok(isTransitionAborted(error));
assert.ok(error instanceof Error);
});

0 comments on commit 10b5631

Please sign in to comment.