expect(
assertErrorMatch({ path: '/', component }, { path: '/foo' })
).toMatchInlineSnapshot(
- `[Error: No match for {"path":"/foo","params":{},"query":{},"hash":"","fullPath":"/"}]`
+ `[NoRouteMatchError: No match for {"path":"/foo","params":{},"query":{},"hash":"","fullPath":"/"}]`
)
})
})
expect(
assertErrorMatch({ path: '/', component }, { name: 'Home' })
).toMatchInlineSnapshot(
- `[Error: No match for {"path":"/","name":"Home","params":{},"query":{},"hash":"","fullPath":"/"}]`
+ `[NoRouteMatchError: No match for {"path":"/","name":"Home","params":{},"query":{},"hash":"","fullPath":"/"}]`
)
})
})
{ path: '/redirect', params: {}, matched: [], name: undefined }
)
).toMatchInlineSnapshot(`
- [Error: Cannot redirect using a relative location:
- {
- "params": {}
- }
- Use the function redirect and explicitely provide a name]
- `)
+ [InvalidRouteMatch: Cannot redirect using a relative location:
+ {
+ "params": {}
+ }
+ Use the function redirect and explicitely provide a name]
+ `)
})
it('normalize a location when redirecting', () => {
{ ...start, matched: start.matched.map(normalizeRouteRecord) }
)
).toMatchInlineSnapshot(
- `[Error: No match for {"name":"home","params":{},"path":"/"}]`
+ `[NoRouteMatchError: No match for {"name":"home","params":{},"path":"/"}]`
)
})
})
{
"include": ["./**/*.ts"],
"compilerOptions": {
- "target": "es3" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
+ "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
// "lib": ["es2017.object"] /* Specify library files to be included in the compilation. */,
// "declaration": true /* Generates corresponding '.d.ts' file. */,
"jsdom": "^15.1.1",
"mocha": "^6.1.3",
"prettier": "^1.18.2",
- "rollup": "^1.16.3",
+ "rollup": "^1.16.6",
"rollup-plugin-alias": "^1.5.2",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-replace": "^2.2.0",
- "rollup-plugin-terser": "^5.0.0",
+ "rollup-plugin-terser": "^5.1.0",
"rollup-plugin-typescript2": "^0.21.2",
"ts-jest": "^24.0.2",
"ts-loader": "^6.0.4",
// 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' ? 'es3' : 'esnext',
+ target: format === 'iife' || format === 'cjs' ? 'es5' : 'esnext',
},
},
})
// Own simplified consola version
+// Consola doesn't work on IE9
+
+type LogCommand = 'info' | 'log' | 'error' | 'warn'
+const logs: LogCommand[] = ['info', 'log', 'error', 'warn']
export default {
tag: '',
if (this.tag) console.info(`[${this.tag}]`, ...args)
else console.info(...args)
},
+
+ mockTypes(spyCreator: () => any): void {
+ for (const log of logs) {
+ // @ts-ignore
+ this[log] = spyCreator()
+ }
+ },
}
import { RouteLocationNormalized, RouteLocation } from './types'
-export class NoRouteMatchError extends Error {
+// 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 suport
+ return error[isRouterError]
+ } else {
+ return error instanceof RouterError
+ }
+ }
+
+ get name() {
+ return this.constructor.name
+ }
+}
+
+const isNoRouteMatchError = '__NoRouteMatchError'
+export class NoRouteMatchError extends RouterError {
+ // @ts-ignore for IE inheritance support
+ private [isNoRouteMatchError] = true
+
constructor(currentLocation: any, location: any) {
super('No match for ' + JSON.stringify({ ...currentLocation, ...location }))
- Object.setPrototypeOf(this, new.target.prototype)
+ }
+
+ 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 suport
+ return error[isNoRouteMatchError]
+ } else {
+ return error instanceof NoRouteMatchError
+ }
}
}
+const isInvalidRouteMatch = '__InvalidRouteMatch'
/**
* Error used when the matcher fails to resolve a location
*/
-export class InvalidRouteMatch extends Error {
+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(
location
)}\nUse the function redirect and explicitely provide a name`
)
- Object.setPrototypeOf(this, new.target.prototype)
+ }
+
+ 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 suport
+ return error[isInvalidRouteMatch]
+ } else {
+ return error instanceof InvalidRouteMatch
+ }
}
}
+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 Error {
+export class NavigationGuardRedirect extends RouterError {
+ // @ts-ignore for IE inheritance support
+ private [isNoRouteMatchError] = true
+
to: RouteLocation
from: RouteLocationNormalized
// TODO: refactor order of argumnets
to
)}" via a navigation guard`
)
- Object.setPrototypeOf(this, new.target.prototype)
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 suport
+ return error[isNavigationGuardRedirect]
+ } else {
+ return error instanceof NavigationGuardRedirect
+ }
+ }
}
+const isNavigationAborted = '__NavigationAborted'
/**
* Navigation aborted by next(false)
*/
-export class NavigationAborted extends Error {
+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`
+ `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard`
)
- Object.setPrototypeOf(this, new.target.prototype)
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 suport
+ 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?
*/
-export class NavigationCancelled extends Error {
+// @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\``
+ `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new \`push\` or \`replace\``
)
- Object.setPrototypeOf(this, new.target.prototype)
this.from = from
this.to = to
}
+
+ 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 suport
+ return error[isNavigationCancelled]
+ } else {
+ return error instanceof NavigationCancelled
+ }
+ }
}
function stringifyRoute(to: RouteLocation): string {
-import consola from 'consola'
+import consola from '../consola'
import { BaseHistory, HistoryLocationNormalized, HistoryLocation } from './base'
import { NavigationCallback, HistoryState, NavigationDirection } from './base'
import { Router, RouterOptions } from './router'
import { HTML5History } from './history/html5'
+import { HashHistory } from './history/hash'
+import { AbstractHistory } from './history/abstract'
+import { BaseHistory } from './history/base'
import { PluginFunction, VueConstructor } from 'vue'
import View from './components/View'
import Link from './components/Link'
strats.created
}
-export { Router, HTML5History, plugin }
+export {
+ Router,
+ HTML5History,
+ HashHistory,
+ AbstractHistory,
+ BaseHistory,
+ plugin,
+}
export default class VueRouter extends Router {
static install = plugin
}
this.updateReactiveRoute()
} catch (error) {
- if (error instanceof NavigationGuardRedirect) {
+ if (NavigationGuardRedirect.is(error)) {
// TODO: refactor the duplication of new NavigationCancelled by
// checking instanceof NavigationError (it's another TODO)
// a more recent navigation took place
// the error is already handled by router.push
// we just want to avoid logging the error
this.push(error.to).catch(() => {})
- } else if (error instanceof NavigationAborted) {
+ } else if (NavigationAborted.is(error)) {
// TODO: test on different browsers ensure consistent behavior
// TODO: this doesn't work if the user directly calls window.history.go(-n) with n > 1
// We can override the go method to retrieve the number but not sure if all browsers allow that
try {
await this.navigate(toLocation, this.currentRoute)
} catch (error) {
- if (error instanceof NavigationGuardRedirect) {
+ if (NavigationGuardRedirect.is(error)) {
// push was called while waiting in guards
if (this.pendingLocation !== toLocation) {
// TODO: trigger onError as well
try {
await this.navigate(toLocation, this.currentRoute)
} catch (error) {
- if (error instanceof NavigationGuardRedirect) {
+ if (NavigationGuardRedirect.is(error)) {
// push was called while waiting in guards
if (this.pendingLocation !== toLocation) {
// TODO: trigger onError as well
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1"
integrity sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng==
-"@types/node@^12.0.8":
- version "12.0.10"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.10.tgz#51babf9c7deadd5343620055fc8aff7995c8b031"
- integrity sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==
+"@types/node@^12.0.10":
+ version "12.0.12"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.12.tgz#cc791b402360db1eaf7176479072f91ee6c6c7ca"
+ integrity sha512-Uy0PN4R5vgBUXFoJrKryf5aTk3kJ8Rv3PdlHjl6UaX+Cqp1QE0yPQ68MPXGrZOfG7gZVNDIJZYyot0B9ubXUrQ==
"@types/resolve@0.0.8":
version "0.0.8"
magic-string "^0.25.2"
rollup-pluginutils "^2.6.0"
-rollup-plugin-terser@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.0.0.tgz#ac50fdb703b580447a7e6b1692aeed515a6be8cf"
- integrity sha512-W+jJ4opYnlmNyVW0vtRufs+EGf68BIJ7bnOazgz8mgz8pA9lUyrEifAhPs5y9M16wFeAyBGaRjKip4dnFBtXaw==
+rollup-plugin-terser@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.1.0.tgz#82e637613d5af6c85ac4319b508b1c065d64075c"
+ integrity sha512-tvJweguo+f9T1SBcSmEMaArCUM07mIg61ArqPj3Fty9OdwTLCxBUBdxS3e1cU68Z1lXf52JBhbt3yRuQoHLtQg==
dependencies:
"@babel/code-frame" "^7.0.0"
jest-worker "^24.6.0"
+ rollup-pluginutils "^2.8.1"
serialize-javascript "^1.7.0"
terser "^4.0.0"
dependencies:
estree-walker "^0.6.1"
-rollup@^1.16.3:
- version "1.16.3"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.16.3.tgz#9b8bcf31523efc83447a9624bd2fe6ca58caa1e7"
- integrity sha512-iXINUUEk2NTZXE3GcUtLQt2cvfQsAUXBQ8AFsDK8tg7Wp5bwTKdZXPdzB2IJQwHpdUNfsIgYMAfajurh7SVTnA==
+rollup@^1.16.6:
+ version "1.16.6"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.16.6.tgz#0d979e3edd14a27e5436a145c7f1fcef35e0083b"
+ integrity sha512-oM3iKkzPCq9Da95wCnNfS8YlNZjgCD5c/TceKnJIthI9FOeJqnO3PUr/C5Suv9Kjzh0iphKL02PLeja3A5AMIA==
dependencies:
"@types/estree" "0.0.39"
- "@types/node" "^12.0.8"
+ "@types/node" "^12.0.10"
acorn "^6.1.1"
rsvp@^4.8.4: