import { createRouter as newRouter, createMemoryHistory } from '../src'
-import { NavigationAborted, NavigationGuardRedirect } from '../src/errors'
+import { ErrorTypes } from '../src/errors'
import { components, tick } from './utils'
import { RouteRecord } from '../src/types'
try {
await router.push('/foo')
} catch (err) {
- expect(err).toBeInstanceOf(NavigationAborted)
+ expect(err.type).toBe(ErrorTypes.NAVIGATION_ABORTED)
}
- expect(onError).toHaveBeenCalledWith(expect.any(NavigationAborted))
+ expect(onError).toHaveBeenCalledWith(
+ expect.objectContaining({ type: ErrorTypes.NAVIGATION_ABORTED })
+ )
})
it('triggers erros caused by new navigations of a next(redirect) trigered by history', async () => {
expect(onError).toHaveBeenCalledTimes(2)
expect(onError).toHaveBeenNthCalledWith(
1,
- expect.any(NavigationGuardRedirect)
+ expect.objectContaining({ type: ErrorTypes.NAVIGATION_GUARD_REDIRECT })
)
expect(onError.mock.calls[0]).toMatchObject([
{ to: { params: { p: '1' } }, from: { fullPath: '/p/0' } },
])
- expect(onError).toHaveBeenNthCalledWith(2, expect.any(NavigationAborted))
+ expect(onError).toHaveBeenNthCalledWith(
+ 2,
+ expect.objectContaining({ type: ErrorTypes.NAVIGATION_ABORTED })
+ )
expect(onError.mock.calls[1]).toMatchObject([
{ to: { params: { p: '1' } }, from: { params: { p: 'other' } } },
])
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Router Matcher resolve LocationAsName throws if the named route does not exists 1`] = `
-[NoRouteMatchError: No match for
-{"name":"Home"}]
+[Error: No match for
+ {"name":"Home"}]
`;
exports[`Router Matcher resolve LocationAsRelative throws if the current named route does not exists 1`] = `
-[NoRouteMatchError: No match for
-{"params":{"a":"foo"}}
+[Error: No match for
+ {"params":{"a":"foo"}}
while being at
{"name":"home","params":{},"path":"/","meta":{}}]
`;
import fakePromise from 'faked-promise'
import { createRouter, createMemoryHistory, createWebHistory } from '../src'
-import { NavigationCancelled } from '../src/errors'
+import { ErrorTypes } from '../src/errors'
import { createDom, components, tick } from './utils'
import {
RouteRecord,
try {
await pA
} catch (err) {
- expect(err).toBeInstanceOf(NavigationCancelled)
+ expect(err.type).toBe(ErrorTypes.NAVIGATION_CANCELLED)
}
expect(router.currentRoute.value.fullPath).toBe('/p/b')
}
"version": "4.0.0-alpha.3",
"main": "dist/vue-router.cjs.js",
"browser": "dist/vue-router.esm.js",
- "unpkg": "dist/vue-router.js",
+ "unpkg": "dist/vue-router.global.js",
"module": "dist/vue-router.esm-bundler.js",
"typings": "dist/vue-router.d.ts",
"sideEffects": false,
+import path from 'path'
+import ts from 'rollup-plugin-typescript2'
import replace from '@rollup/plugin-replace'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'
-import ts from 'rollup-plugin-typescript2'
-import alias from '@rollup/plugin-alias'
-import { terser } from 'rollup-plugin-terser'
-import pkg from './package.json'
+
+const pkg = require('./package.json')
+const name = pkg.name
const banner = `/*!
* ${pkg.name} v${pkg.version}
* @license MIT
*/`
-const exportName = 'VueRouter'
-
-function createEntry(
- {
- format, // Rollup format (iife, umd, cjs, es)
- external = ['vue', '@vue/reactivity', '@vue/runtime-core'], // Rollup external option
- input = 'src/index.ts', // entry point
- env = 'development', // NODE_ENV variable
- minify = false,
- isBrowser = false, // produce a browser module version or not
- } = {
- input: 'src/index.ts',
- env: 'development',
- minify: false,
- isBrowser: false,
- }
-) {
- // force production mode when minifying
- if (minify) env = 'production'
- const isProductionBuild =
- process.env.__DEV__ === 'false' || env === 'production'
+// ensure TS checks only once for each build
+let hasTSChecked = false
- const config = {
- input,
- plugins: [
- replace({
- __VERSION__: JSON.stringify(pkg.version),
- __DEV__:
- (format === 'es' && !isBrowser) || format === 'cjs'
- ? // preserve to be handled by bundlers
- `process.env.NODE_ENV !== 'production'`
- : // hard coded dev/prod builds
- !isProductionBuild,
- }),
- alias({
- resolve: ['ts'],
- }),
- ],
- output: {
- banner,
- file: 'dist/vue-router.other.js',
- format,
- globals: {
- '@vue/reactivity': 'Vue',
- '@vue/runtime-core': 'Vue',
- vue: 'Vue',
- },
- },
- }
+const outputConfigs = {
+ // each file name has the format: `dist/${name}.${format}.js`
+ // format being a key of this object
+ 'esm-bundler': {
+ file: pkg.module,
+ format: `es`,
+ },
+ cjs: {
+ file: pkg.main,
+ format: `cjs`,
+ },
+ global: {
+ file: pkg.unpkg,
+ format: `iife`,
+ },
+ esm: {
+ file: pkg.browser,
+ format: `es`,
+ },
+}
- if (format === 'iife') {
- // config.input = 'src/entries/iife.ts'
- config.output.file = pkg.unpkg
- config.output.name = exportName
- } else if (format === 'es') {
- config.output.file = isBrowser ? pkg.browser : pkg.module
- } else if (format === 'cjs') {
- config.output.file = 'dist/vue-router.cjs.js'
+const allFormats = Object.keys(outputConfigs)
+// in vue-router there are not that many
+const packageFormats = allFormats
+const packageConfigs = packageFormats.map(format =>
+ createConfig(format, outputConfigs[format])
+)
+
+// only add the production ready if we are bundling the options
+packageFormats.forEach(format => {
+ if (format === 'cjs') {
+ packageConfigs.push(createProductionConfig(format))
+ } else if (format === 'global') {
+ packageConfigs.push(createMinifiedConfig(format))
}
+})
+
+export default packageConfigs
- if (!external) {
- config.plugins.push(resolve(), commonjs())
- } else {
- config.external = external
+function createConfig(format, output, plugins = []) {
+ if (!output) {
+ console.log(require('chalk').yellow(`invalid format: "${format}"`))
+ process.exit(1)
}
- config.plugins.push(
- ts({
- // only check once, during the es version with browser (it includes external libs)
- check: format === 'es' && isBrowser && !minify,
- tsconfigOverride: {
- compilerOptions: {
- // same for d.ts files
- declaration: format === 'es' && isBrowser && !minify,
- module: 'esnext', // we need to override it because mocha requires this value to be commonjs
- target: format === 'iife' || format === 'cjs' ? 'es5' : 'esnext',
- },
+ output.sourcemap = true
+ output.banner = banner
+ output.externalLiveBindings = false
+ output.globals = { vue: 'Vue' }
+
+ const isProductionBuild = /\.prod\.js$/.test(output.file)
+ const isGlobalBuild = format === 'global'
+ const isRawESMBuild = format === 'esm'
+ const isNodeBuild = format === 'cjs'
+ const isBundlerESMBuild = /esm-bundler/.test(format)
+
+ if (isGlobalBuild) output.name = 'VueRouter'
+
+ const shouldEmitDeclarations = !hasTSChecked
+
+ const tsPlugin = ts({
+ check: !hasTSChecked,
+ tsconfig: path.resolve(__dirname, 'tsconfig.json'),
+ cacheRoot: path.resolve(__dirname, 'node_modules/.rts2_cache'),
+ tsconfigOverride: {
+ compilerOptions: {
+ sourceMap: output.sourcemap,
+ declaration: shouldEmitDeclarations,
+ declarationMap: shouldEmitDeclarations,
},
- })
- )
+ exclude: ['__tests__', 'test-dts'],
+ },
+ })
+ // we only need to check TS and generate declarations once for each build.
+ // it also seems to run into weird issues when checking multiple times
+ // during a single build.
+ hasTSChecked = true
- if (minify) {
- config.plugins.push(
- terser({
- module: format === 'es',
- // output: {
- // preamble: banner,
- // },
- })
- )
- config.output.file = config.output.file.replace(/\.js$/i, '.min.js')
+ const external = ['vue']
+
+ const nodePlugins = [resolve(), commonjs()]
+
+ return {
+ input: `src/index.ts`,
+ // Global and Browser ESM builds inlines everything so that they can be
+ // used alone.
+ external,
+ plugins: [
+ tsPlugin,
+ createReplacePlugin(
+ isProductionBuild,
+ isBundlerESMBuild,
+ // isBrowserBuild?
+ isGlobalBuild || isRawESMBuild || isBundlerESMBuild,
+ isGlobalBuild,
+ isNodeBuild
+ ),
+ ...nodePlugins,
+ ...plugins,
+ ],
+ output,
+ // onwarn: (msg, warn) => {
+ // if (!/Circular/.test(msg)) {
+ // warn(msg)
+ // }
+ // },
}
+}
- return config
+function createReplacePlugin(
+ isProduction,
+ isBundlerESMBuild,
+ isBrowserBuild,
+ isGlobalBuild,
+ isNodeBuild
+) {
+ const replacements = {
+ __COMMIT__: `"${process.env.COMMIT}"`,
+ __VERSION__: `"${pkg.version}"`,
+ __DEV__: isBundlerESMBuild
+ ? // preserve to be handled by bundlers
+ `(process.env.NODE_ENV !== 'production')`
+ : // hard coded dev/prod builds
+ !isProduction,
+ // this is only used during tests
+ __TEST__: isBundlerESMBuild ? `(process.env.NODE_ENV === 'test')` : false,
+ // If the build is expected to run directly in the browser (global / esm builds)
+ __BROWSER__: isBrowserBuild,
+ // is targeting bundlers?
+ __BUNDLER__: isBundlerESMBuild,
+ __GLOBAL__: isGlobalBuild,
+ // is targeting Node (SSR)?
+ __NODE_JS__: isNodeBuild,
+ }
+ // allow inline overrides like
+ //__RUNTIME_COMPILE__=true yarn build
+ Object.keys(replacements).forEach(key => {
+ if (key in process.env) {
+ replacements[key] = process.env[key]
+ }
+ })
+ return replace(replacements)
+}
+
+function createProductionConfig(format) {
+ return createConfig(format, {
+ file: `dist/${name}.${format}.prod.js`,
+ format: outputConfigs[format].format,
+ })
}
-export default [
- // browser-friendly UMD build
- createEntry({ format: 'iife' }),
- createEntry({ format: 'iife', minify: true }),
- createEntry({ format: 'cjs' }),
- // TODO: prod vs env
- createEntry({ format: 'es' }),
- createEntry({ format: 'es', isBrowser: true }),
-]
+function createMinifiedConfig(format) {
+ const { terser } = require('rollup-plugin-terser')
+ return createConfig(
+ format,
+ {
+ file: `dist/${name}.${format}.prod.js`,
+ format: outputConfigs[format].format,
+ },
+ [
+ terser({
+ module: /^esm/.test(format),
+ compress: {
+ ecma: 2015,
+ pure_getters: true,
+ },
+ }),
+ ]
+ )
+}
import {
- RouteLocationNormalized,
- RouteLocation,
- MatcherLocationNormalized,
MatcherLocation,
+ MatcherLocationNormalized,
+ RouteLocation,
+ RouteLocationNormalized,
} from './types'
-// we could use symbols, but this is for IE9 only and there is
-// not Symbol support anyway
-const isRouterError = '__RouterError'
-
-/**
- * Generic Error coming from the Router.
- */
-export class RouterError extends Error {
- protected __proto__: any
- // @ts-ignore for IE inheritance support
- private [isRouterError] = true
-
- /**
- * Creates a Router specific Error
- *
- * @param message Error Message
- */
- constructor(message: string) {
- super(message)
-
- // restore prototype chain
- const actualProto = new.target.prototype
-
- if (Object.setPrototypeOf) {
- Object.setPrototypeOf(this, actualProto)
- } else {
- this.__proto__ = actualProto
- }
- }
-
- static is(error: Error): error is RouterError {
- // only IE9 seems to break the inheritance chain
- // and set Error as the name
- if (error.name === 'Error') {
- // @ts-ignore for IE inheritance support
- return error[isRouterError]
- } else {
- return error instanceof RouterError
- }
- }
-
- get name() {
- return this.constructor.name
- }
+export const enum ErrorTypes {
+ MATCHER_NOT_FOUND,
+ NAVIGATION_GUARD_REDIRECT,
+ NAVIGATION_ABORTED,
+ NAVIGATION_CANCELLED,
+ // Using string enums because error codes are exposed to developers
+ // and number enums could collide with other error codes in runtime
+ // MATCHER_NOT_FOUND = 'MATCHER_NOT_FOUND',
+ // NAVIGATION_GUARD_REDIRECT = 'NAVIGATION_GUARD_REDIRECT',
+ // NAVIGATION_ABORTED = 'NAVIGATION_ABORTED',
+ // NAVIGATION_CANCELLED = 'NAVIGATION_CANCELLED',
}
-const isNoRouteMatchError = '__NoRouteMatchError'
-export class NoRouteMatchError extends RouterError {
- // @ts-ignore for IE inheritance support
- private [isNoRouteMatchError] = true
-
- constructor(
- location: MatcherLocation,
- currentLocation?: MatcherLocationNormalized
- ) {
- super(
- 'No match for\n' +
- JSON.stringify(location) +
- (currentLocation
- ? '\nwhile being at\n' + JSON.stringify(currentLocation)
- : '')
- )
- }
-
- static is(error: Error): error is NoRouteMatchError {
- // only IE9 seems to break the inheritance chain
- // and set Error as the name
- if (error.name === 'Error') {
- // @ts-ignore for IE inheritance support
- return error[isNoRouteMatchError]
- } else {
- return error instanceof NoRouteMatchError
- }
- }
+interface RouterErrorBase extends Error {
+ type: ErrorTypes
}
-const isInvalidRouteMatch = '__InvalidRouteMatch'
-/**
- * Error used when the matcher fails to resolve a location
- */
-export class InvalidRouteMatch extends RouterError {
- // @ts-ignore for IE inheritance support
- private [isNoRouteMatchError] = true
-
- constructor(location: any) {
- // TODO: improve the error to include currentLocation and use it for more cases
- super(
- `Cannot redirect using a relative location:\n${stringifyRoute(
- location
- )}\nUse the function redirect and explicitly provide a name`
- )
- }
-
- static is(error: Error): error is InvalidRouteMatch {
- // only IE9 seems to break the inheritance chain
- // and set Error as the name
- if (error.name === 'Error') {
- // @ts-ignore for IE inheritance support
- return error[isInvalidRouteMatch]
- } else {
- return error instanceof InvalidRouteMatch
- }
- }
+export interface MatcherError extends RouterErrorBase {
+ type: ErrorTypes.MATCHER_NOT_FOUND
+ location: MatcherLocation
+ currentLocation?: MatcherLocationNormalized
}
-const isNavigationGuardRedirect = '__NavigationGuardRedirect'
-/**
- * Error used when rejecting a navigation because of a redirection. Contains
- * information about where we where trying to go and where we are going instead
- */
-export class NavigationGuardRedirect extends RouterError {
- // @ts-ignore for IE inheritance support
- private [isNoRouteMatchError] = true
-
- to: RouteLocation
+export interface NavigationError extends RouterErrorBase {
+ type: ErrorTypes.NAVIGATION_ABORTED | ErrorTypes.NAVIGATION_CANCELLED
from: RouteLocationNormalized
- // TODO: refactor order of arguments
- // TODO: refactor into parent class NavigationError
- constructor(from: RouteLocationNormalized, to: RouteLocation) {
- super(
- `Redirected from "${from.fullPath}" to "${stringifyRoute(
- to
- )}" via a navigation guard`
- )
-
- this.from = from
- this.to = to
- }
-
- static is(error: Error): error is NavigationGuardRedirect {
- // only IE9 seems to break the inheritance chain
- // and set Error as the name
- if (error.name === 'Error') {
- // @ts-ignore for IE inheritance support
- return error[isNavigationGuardRedirect]
- } else {
- return error instanceof NavigationGuardRedirect
- }
- }
-}
-
-const isNavigationAborted = '__NavigationAborted'
-/**
- * Navigation aborted by next(false)
- */
-export class NavigationAborted extends RouterError {
- // @ts-ignore for IE inheritance support
- private [isNavigationAborted] = true
-
to: RouteLocationNormalized
- from: RouteLocationNormalized
- constructor(to: RouteLocationNormalized, from: RouteLocationNormalized) {
- super(
- `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard`
- )
-
- this.from = from
- this.to = to
- }
-
- static is(error: Error): error is NavigationAborted {
- // only IE9 seems to break the inheritance chain
- // and set Error as the name
- if (error.name === 'Error') {
- // @ts-ignore for IE inheritance support
- return error[isNavigationAborted]
- } else {
- return error instanceof NavigationAborted
- }
- }
}
-const isNavigationCancelled = '__NavigationCancelled'
-/**
- * Navigation canceled by the user by pushing/replacing a new location
- * TODO: is the name good?
- */
-// @ts-ignore RouterError is a constructor
-export class NavigationCancelled extends RouterError {
- // @ts-ignore for IE inheritance support
- private [isNavigationCancelled] = true
-
- to: RouteLocationNormalized
- from: RouteLocationNormalized
- constructor(to: RouteLocationNormalized, from: RouteLocationNormalized) {
- super(
- `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new \`push\` or \`replace\``
- )
+export interface NavigationRedirectError
+ extends Omit<NavigationError, 'to' | 'type'> {
+ type: ErrorTypes.NAVIGATION_GUARD_REDIRECT
+ to: RouteLocation
+}
- this.from = from
- this.to = to
- }
+// DEV only debug messages
+const ErrorTypeMessages = {
+ [ErrorTypes.MATCHER_NOT_FOUND]({ location, currentLocation }: MatcherError) {
+ return `No match for\n ${JSON.stringify(location)}${
+ currentLocation
+ ? '\nwhile being at\n' + JSON.stringify(currentLocation)
+ : ''
+ }`
+ },
+ [ErrorTypes.NAVIGATION_GUARD_REDIRECT]({
+ from,
+ to,
+ }: NavigationRedirectError) {
+ return `Redirected from "${from.fullPath}" to "${stringifyRoute(
+ to
+ )}" via a navigation guard`
+ },
+ [ErrorTypes.NAVIGATION_ABORTED]({ from, to }: NavigationError) {
+ return `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard`
+ },
+ [ErrorTypes.NAVIGATION_CANCELLED]({ from, to }: NavigationError) {
+ return `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new \`push\` or \`replace\``
+ },
+}
- static is(error: Error): error is NavigationCancelled {
- // only IE9 seems to break the inheritance chain
- // and set Error as the name
- if (error.name === 'Error') {
- // @ts-ignore for IE inheritance support
- return error[isNavigationCancelled]
- } else {
- return error instanceof NavigationCancelled
- }
+// Possible internal errors
+type RouterError = NavigationError | NavigationRedirectError | MatcherError
+// Public errors, TBD
+// export type PublicRouterError = NavigationError
+
+export function createRouterError<E extends RouterError>(
+ type: E['type'],
+ params: Omit<E, 'type' | keyof Error>
+): E {
+ if (__DEV__ || !__BROWSER__) {
+ return Object.assign(
+ new Error(ErrorTypeMessages[type](params as any)),
+ { type },
+ params
+ ) as E
+ } else {
+ return Object.assign(new Error(), { type }, params) as E
}
}
-const propertiesToLog: (keyof RouteLocationNormalized)[] = [
- 'params',
- 'query',
- 'hash',
-]
+const propertiesToLog = ['params', 'query', 'hash'] as const
function stringifyRoute(to: RouteLocation): string {
if (typeof to === 'string') return to
if ('path' in to) return to.path
- const location: Partial<RouteLocationNormalized> = {}
+ const location = {} as Record<string, unknown>
for (const key of propertiesToLog) {
- // @ts-ignore
if (key in to) location[key] = to[key]
}
return JSON.stringify(location, null, 2)
// Global compile-time constants
declare var __DEV__: boolean
+declare var __BROWSER__: boolean
export {
RouteLocationNormalized,
- START_LOCATION_NORMALIZED as START_LOCATION,
- // needed for types, should probably be removed by changing the
RouteLocationOptions,
+ START_LOCATION_NORMALIZED as START_LOCATION,
} from './types'
-export { createRouter, Router } from './router'
+export { createRouter, Router, RouterOptions } from './router'
export { onBeforeRouteLeave } from './navigationGuards'
export { useRoute, useRouter } from './injectKeys'
MatcherLocationNormalized,
ListenerRemover,
} from '../types'
-import { NoRouteMatchError } from '../errors'
+import { createRouterError, ErrorTypes, MatcherError } from '../errors'
import { createRouteRecordMatcher, RouteRecordMatcher } from './path-matcher'
import { RouteRecordNormalized } from './types'
import {
if ('name' in location && location.name) {
matcher = matcherMap.get(location.name)
- if (!matcher) throw new NoRouteMatchError(location)
+ if (!matcher)
+ throw createRouterError<MatcherError>(ErrorTypes.MATCHER_NOT_FOUND, {
+ location,
+ })
name = matcher.record.name
// TODO: merge params with current location. Should this be done by name. I think there should be some kind of relationship between the records like children of a parent should keep parent props but not the rest
matcher = currentLocation.name
? matcherMap.get(currentLocation.name)
: matchers.find(m => m.re.test(currentLocation.path))
- if (!matcher) throw new NoRouteMatchError(location, currentLocation)
+ if (!matcher)
+ throw createRouterError<MatcherError>(ErrorTypes.MATCHER_NOT_FOUND, {
+ location,
+ currentLocation,
+ })
name = matcher.record.name
params = location.params || currentLocation.params
path = matcher.stringify(params)
scrollToPosition,
} from './utils/scroll'
import { createRouterMatcher } from './matcher'
-import {
- NavigationCancelled,
- NavigationGuardRedirect,
- NavigationAborted,
-} from './errors'
+import { createRouterError, ErrorTypes, NavigationError } from './errors'
import {
extractComponentsGuards,
guardToPromiseFn,
try {
await navigate(toLocation, from)
} catch (error) {
- if (NavigationGuardRedirect.is(error)) {
- // push was called while waiting in guards
- if (pendingLocation !== toLocation) {
- triggerError(new NavigationCancelled(toLocation, from))
- }
+ // push was called while waiting in guards
+ // TODO: write tests
+ if (pendingLocation !== toLocation) {
+ triggerError(
+ createRouterError<NavigationError>(ErrorTypes.NAVIGATION_CANCELLED, {
+ from,
+ to: toLocation,
+ })
+ )
+ }
+
+ if (error.type === ErrorTypes.NAVIGATION_GUARD_REDIRECT) {
// preserve the original redirectedFrom if any
return pushWithRedirect(error.to, redirectedFrom || toLocation)
- } else {
- // TODO: write tests
- if (pendingLocation !== toLocation) {
- triggerError(new NavigationCancelled(toLocation, from))
- }
}
+
+ // unkwnown error
triggerError(error)
}
) {
// a more recent navigation took place
if (pendingLocation !== toLocation) {
- return triggerError(new NavigationCancelled(toLocation, from), isPush)
+ return triggerError(
+ createRouterError<NavigationError>(ErrorTypes.NAVIGATION_CANCELLED, {
+ from,
+ to: toLocation,
+ }),
+ isPush
+ )
}
// remove registered guards from removed matched records
false
)
} catch (error) {
- if (NavigationGuardRedirect.is(error)) {
+ if (error.type === ErrorTypes.NAVIGATION_GUARD_REDIRECT) {
// TODO: refactor the duplication of new NavigationCancelled by
// checking instanceof NavigationError (it's another TODO)
// a more recent navigation took place
if (pendingLocation !== toLocation) {
- return triggerError(new NavigationCancelled(toLocation, from), false)
+ return triggerError(
+ createRouterError<NavigationError>(
+ ErrorTypes.NAVIGATION_CANCELLED,
+ {
+ from,
+ to: toLocation,
+ }
+ ),
+ false
+ )
}
triggerError(error, false)
// the error is already handled by router.push
// we just want to avoid logging the error
pushWithRedirect(error.to, toLocation).catch(() => {})
- } else if (NavigationAborted.is(error)) {
+ } else if (error.type === ErrorTypes.NAVIGATION_ABORTED) {
console.log('Cancelled, going to', -info.distance)
// TODO: test on different browsers ensure consistent behavior
history.go(-info.distance, false)
} from '../types'
import { isRouteLocation } from '../types'
-import { NavigationGuardRedirect, NavigationAborted } from '../errors'
+import {
+ createRouterError,
+ ErrorTypes,
+ NavigationError,
+ NavigationRedirectError,
+} from '../errors'
export function guardToPromiseFn(
guard: NavigationGuard,
const next: NavigationGuardCallback = (
valid?: boolean | RouteLocation | NavigationGuardNextCallback
) => {
- if (valid === false) reject(new NavigationAborted(to, from))
+ if (valid === false)
+ reject(
+ createRouterError<NavigationError>(ErrorTypes.NAVIGATION_ABORTED, {
+ from,
+ to,
+ })
+ )
else if (isRouteLocation(valid)) {
- reject(new NavigationGuardRedirect(to, valid))
+ reject(
+ createRouterError<NavigationRedirectError>(
+ ErrorTypes.NAVIGATION_GUARD_REDIRECT,
+ {
+ from: to,
+ to: valid,
+ }
+ )
+ )
} else if (!valid || valid === true) {
resolve()
} else {
{
"include": ["src/global.d.ts", "src/**/*.ts", "__tests__/**/*.ts"],
"compilerOptions": {
- "target": "esnext",
- "module": "commonjs",
- // "lib": ["es2017.object"] /* Specify library files to be included in the compilation. */,
- "declaration": true,
- "declarationMap": true,
- "sourceMap": true,
- "outDir": "./dist",
- "removeComments": false,
+ "baseUrl": ".",
+ "rootDir": ".",
+ "outDir": "dist",
+ "sourceMap": false,
"noEmit": true,
- "strict": true,
+ "target": "esnext",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "allowJs": false,
"noUnusedLocals": true,
- // "noUnusedParameters": true,
+ "strictNullChecks": true,
+ "noImplicitAny": true,
+ "noImplicitThis": true,
"noImplicitReturns": true,
+ "strict": true,
+ "isolatedModules": false,
- "moduleResolution": "node",
- "esModuleInterop": true
+ "experimentalDecorators": true,
+ "resolveJsonModule": true,
+ "esModuleInterop": true,
+ "removeComments": false,
+ "jsx": "preserve",
+ "lib": ["esnext", "dom"],
+ "types": ["jest", "node"]
}
}