]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
refactor: types
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 31 Jan 2020 18:04:59 +0000 (19:04 +0100)
committerEduardo San Martin Morote <posva13@gmail.com>
Fri, 31 Jan 2020 18:04:59 +0000 (19:04 +0100)
12 files changed:
__tests__/RouterView.spec.ts
__tests__/matcher/resolve.spec.ts
__tests__/utils.ts
playground/views/GuardedWithLeave.vue
src/components/Link.ts
src/components/View.ts
src/index.ts
src/matcher/types.ts
src/navigationGuards.ts [new file with mode: 0644]
src/router.ts
src/types/index.ts
webpack.config.js

index 001af68faaa0083825240a871483481da31353e9..b88b57c06ea9a889a41f584ee3a9b7e45428ddc4 100644 (file)
@@ -1,16 +1,13 @@
 /**
  * @jest-environment jsdom
  */
-import RouterView from '../src/components/View'
-import { components } from './utils'
-import {
-  START_LOCATION_NORMALIZED,
-  RouteLocationNormalized,
-} from '../src/types'
+import { View as RouterView } from '../src/components/View'
+import { components, RouteLocationNormalizedLoose } from './utils'
+import { START_LOCATION_NORMALIZED } from '../src/types'
 import { ref, markNonReactive } from 'vue'
 import { mount, tick } from './mount'
 
-const routes: Record<string, RouteLocationNormalized> = {
+const routes: Record<string, RouteLocationNormalizedLoose> = {
   root: {
     fullPath: '/',
     name: undefined,
@@ -71,7 +68,7 @@ const routes: Record<string, RouteLocationNormalized> = {
 }
 
 describe('RouterView', () => {
-  function factory(route: RouteLocationNormalized, props: any = {}) {
+  function factory(route: RouteLocationNormalizedLoose, props: any = {}) {
     const router = {
       currentRoute: ref(markNonReactive(route)),
     }
@@ -105,7 +102,7 @@ describe('RouterView', () => {
   })
 
   it('displays nothing when route is unmatched', () => {
-    const { el } = factory(START_LOCATION_NORMALIZED)
+    const { el } = factory(START_LOCATION_NORMALIZED as any)
     // NOTE: I wonder if this will stay stable in future releases
     expect(el.childElementCount).toBe(0)
   })
index c6788fc6b7ce3e2e029550287645b274101aeac7..1a380614136d5b2e3af76045a88c58ca47db4dca 100644 (file)
@@ -6,9 +6,8 @@ import {
   MatcherLocation,
   MatcherLocationNormalized,
   MatcherLocationRedirect,
-  RouteRecordMultipleViews,
 } from '../../src/types'
-import { normalizeRouteRecord } from '../utils'
+import { normalizeRouteRecord, MatcherLocationNormalizedLoose } from '../utils'
 
 // @ts-ignore
 const component: RouteComponent = null
@@ -16,21 +15,6 @@ const component: RouteComponent = null
 // for normalized records
 const components = { default: component }
 
-interface MatcherLocationNormalizedLoose {
-  name: string
-  path: string
-  // record?
-  params: any
-  redirectedFrom?: Partial<MatcherLocationNormalized>
-  meta: any
-  matched: Partial<RouteRecordViewLoose>[]
-}
-
-type RouteRecordViewLoose = Pick<
-  RouteRecordMultipleViews,
-  'path' | 'name' | 'components' | 'children' | 'meta' | 'beforeEnter'
->
-
 describe('Router Matcher', () => {
   describe('resolve', () => {
     function assertRecordMatch(
index d786d4fa3c49182bf1566c24c9e9e64c3b35a03a..9e5c45a7cff4fde76dc4833d7908a34f11492b74 100644 (file)
@@ -1,6 +1,12 @@
 import { JSDOM, ConstructorOptions } from 'jsdom'
-import { NavigationGuard, RouteRecord } from '../src/types'
-import { h, resolveComponent } from '@vue/runtime-core'
+import {
+  NavigationGuard,
+  RouteRecord,
+  RouteRecordMultipleViews,
+  MatcherLocationNormalized,
+  RouteLocationNormalized,
+} from '../src/types'
+import { h, resolveComponent } from 'vue'
 import { RouteRecordMatched } from '../src/matcher/types'
 
 export const tick = (time?: number) =>
@@ -12,6 +18,35 @@ export const tick = (time?: number) =>
 export type NAVIGATION_METHOD = 'push' | 'replace'
 export const NAVIGATION_TYPES: NAVIGATION_METHOD[] = ['push', 'replace']
 
+export interface RouteRecordViewLoose
+  extends Pick<
+    RouteRecordMultipleViews,
+    'path' | 'name' | 'components' | 'children' | 'meta' | 'beforeEnter'
+  > {
+  leaveGuards?: any
+}
+
+// @ts-ignore we are intentionally overriding the type
+export interface RouteLocationNormalizedLoose extends RouteLocationNormalized {
+  name: string | undefined
+  path: string
+  // record?
+  params: any
+  redirectedFrom?: Partial<MatcherLocationNormalized>
+  meta: any
+  matched: Partial<RouteRecordViewLoose>[]
+}
+
+export interface MatcherLocationNormalizedLoose {
+  name: string
+  path: string
+  // record?
+  params: any
+  redirectedFrom?: Partial<MatcherLocationNormalized>
+  meta: any
+  matched: Partial<RouteRecordViewLoose>[]
+}
+
 declare global {
   namespace NodeJS {
     interface Global {
index 0e4e73eb2bee65ad1606ef05394bbc4982c371aa..c56547b9ca8463b0ffffbac65b21588ceb8ceb6c 100644 (file)
@@ -8,7 +8,7 @@
 <script>
 // @ts-check
 import { defineComponent } from 'vue'
-import { onRouteLeave } from '../../src'
+import { onBeforeRouteLeave } from '../../src'
 
 export default defineComponent({
   name: 'GuardedWithLeave',
@@ -16,7 +16,7 @@ export default defineComponent({
 
   setup() {
     console.log('setup in cant leave')
-    onRouteLeave(function(to, from, next) {
+    onBeforeRouteLeave(function(to, from, next) {
       if (window.confirm()) next()
       else {
         // @ts-ignore
index 36f192b77fa2f89543555c85ea3bbb9e5ec98fac..8d615a4482117dd297fad1e6584aca11c5eb74c9 100644 (file)
@@ -1,5 +1,13 @@
-import { defineComponent, h, PropType, inject } from '@vue/runtime-core'
-import { computed, reactive, isRef, Ref } from '@vue/reactivity'
+import {
+  defineComponent,
+  h,
+  PropType,
+  inject,
+  computed,
+  reactive,
+  isRef,
+  Ref,
+} from 'vue'
 import { RouteLocation } from '../types'
 
 interface UseLinkProps {
index 8bf3ff2ad3551dfa2f0d6c662b0bf8868517fdab..b3753f1a98cccaefd8b62dbca4392a10030f1f4a 100644 (file)
@@ -6,9 +6,15 @@ import {
   PropType,
   computed,
   Component,
-} from '@vue/runtime-core'
+  InjectionKey,
+  Ref,
+} from 'vue'
+import { RouteRecordMatched } from '../matcher/types'
 
-const View = defineComponent({
+// TODO: make it work with no symbols too for IE
+export const matchedRouteKey = Symbol() as InjectionKey<Ref<RouteRecordMatched>>
+
+export const View = defineComponent({
   name: 'RouterView',
   props: {
     name: {
@@ -27,7 +33,7 @@ const View = defineComponent({
       () => matchedRoute.value && matchedRoute.value.components[props.name]
     )
 
-    provide('matchedRoute', matchedRoute)
+    provide(matchedRouteKey, matchedRoute)
 
     return () => {
       return ViewComponent.value
@@ -36,5 +42,3 @@ const View = defineComponent({
     }
   },
 })
-
-export default View
index 857f24733f8de5b218381ce7e2e568dcc911a859..94cd1dbea1965dc44026733ea878608dd4196063 100644 (file)
@@ -1,34 +1,22 @@
 import { createRouter, Router } from './router'
-import { App, Ref, inject, getCurrentInstance } from '@vue/runtime-core'
+import { App, Ref, InjectionKey } from 'vue'
 import createHistory from './history/html5'
 import createMemoryHistory from './history/memory'
 import createHashHistory from './history/hash'
-import View from './components/View'
+import { View } from './components/View'
 import Link from './components/Link'
 import {
   RouteLocationNormalized,
   START_LOCATION_NORMALIZED as START_LOCATION,
-  NavigationGuard,
 } from './types'
-import { RouteRecordNormalized } from './matcher/types'
+import { onBeforeRouteLeave } from './navigationGuards'
 
-declare module '@vue/runtime-core' {
-  function inject(name: 'router'): Router
-  function inject(name: 'route'): Ref<RouteLocationNormalized>
-  function inject(name: 'matchedRoute'): Ref<RouteRecordNormalized>
-}
-
-// @ts-ignore: we are not importing it so it complains
-declare module '@vue/runtime-dom' {
-  function inject(name: 'router'): Router
-  function inject(name: 'route'): RouteLocationNormalized
-}
-
-// @ts-ignore: we are not importing it so it complains
 declare module 'vue' {
-  function inject<T>(name: string, defaultValue: T): T
+  function inject<T>(key: InjectionKey<T> | string): T | undefined
+  function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
+  function inject(key: InjectionKey<any> | string, defaultValue?: unknown): any
   function inject(name: 'router'): Router
-  function inject(name: 'route'): RouteLocationNormalized
+  function inject(name: 'route'): Ref<RouteLocationNormalized>
 }
 
 export function RouterPlugin(app: App, router: Router) {
@@ -57,16 +45,6 @@ export function RouterPlugin(app: App, router: Router) {
   app.provide('route', router.currentRoute)
 }
 
-function onRouteLeave(leaveGuard: NavigationGuard) {
-  const matched = inject('matchedRoute').value
-  if (!matched) {
-    console.log('no matched record')
-    return
-  }
-
-  matched.leaveGuards.push(leaveGuard.bind(getCurrentInstance()!.proxy))
-}
-
 export {
   createHistory,
   createMemoryHistory,
@@ -75,5 +53,5 @@ export {
   RouteLocationNormalized,
   Router,
   START_LOCATION,
-  onRouteLeave,
+  onBeforeRouteLeave,
 }
index 4ffccba2705e369dbe7411c6e93884bb35904f0a..82a45aa0aff03f8802e75a9c99f6c67fd73fadbf 100644 (file)
@@ -4,7 +4,7 @@ import {
   NavigationGuard,
 } from '../types'
 
-interface RouteRecordNormalizedCommon {
+export interface RouteRecordNormalizedCommon {
   leaveGuards: NavigationGuard[]
 }
 
diff --git a/src/navigationGuards.ts b/src/navigationGuards.ts
new file mode 100644 (file)
index 0000000..623bf89
--- /dev/null
@@ -0,0 +1,25 @@
+import { NavigationGuard } from './types'
+import { inject, getCurrentInstance, warn } from 'vue'
+import { matchedRouteKey } from './components/View'
+
+// TODO: why is this necessary if it's in global.d.ts, included in tsconfig.json
+declare var __DEV__: boolean
+
+export function onBeforeRouteLeave(leaveGuard: NavigationGuard) {
+  const instance = getCurrentInstance()
+  if (!instance) {
+    __DEV__ &&
+      warn('onRouteLeave must be called at the top of a setup function')
+    return
+  }
+
+  const matched = inject(matchedRouteKey, {}).value
+
+  if (!matched) {
+    __DEV__ &&
+      warn('onRouteLeave must be called at the top of a setup function')
+    return
+  }
+
+  matched.leaveGuards.push(leaveGuard.bind(instance!.proxy))
+}
index 6227079d998606aed94e7758ec7fa430ee48fb2f..6714f996103b0a4f3b81bbfcd35fb4fd63a8baaf 100644 (file)
@@ -10,6 +10,7 @@ import {
   RouteQueryAndHash,
   Lazy,
   TODO,
+  Immutable,
 } from './types'
 import {
   RouterHistory,
@@ -33,8 +34,7 @@ import { extractComponentsGuards, guardToPromiseFn } from './utils'
 import { useCallbacks } from './utils/callbacks'
 import { encodeParam } from './utils/encoding'
 import { decode } from './utils/encoding'
-import { ref, Ref, markNonReactive } from '@vue/reactivity'
-import { nextTick } from '@vue/runtime-core'
+import { ref, Ref, markNonReactive, nextTick } from 'vue'
 import { RouteRecordMatched } from './matcher/types'
 
 type ErrorHandler = (error: any) => any
@@ -58,7 +58,7 @@ export interface RouterOptions {
 
 export interface Router {
   history: RouterHistory
-  currentRoute: Ref<RouteLocationNormalized>
+  currentRoute: Ref<Immutable<RouteLocationNormalized>>
 
   resolve(to: RouteLocation): RouteLocationNormalized
   createHref(to: RouteLocationNormalized): string
@@ -117,7 +117,7 @@ export function createRouter({
   const beforeGuards = useCallbacks<NavigationGuard>()
   const afterGuards = useCallbacks<PostNavigationGuard>()
   const currentRoute = ref<RouteLocationNormalized>(START_LOCATION_NORMALIZED)
-  let pendingLocation: Readonly<RouteLocationNormalized> = START_LOCATION_NORMALIZED
+  let pendingLocation: Immutable<RouteLocationNormalized> = START_LOCATION_NORMALIZED
 
   if (isClient && 'scrollRestoration' in window.history) {
     window.history.scrollRestoration = 'manual'
index 19f0dac1c95d8b14e852d248003cbb67434010ed..964f5755ef3d6259800c55a311972e5731e3226d 100644 (file)
@@ -1,6 +1,6 @@
 import { HistoryQuery, RawHistoryQuery } from '../history/common'
 import { PathParserOptions } from '../matcher/path-parser-ranker'
-import { markNonReactive } from '@vue/reactivity'
+import { markNonReactive } from 'vue'
 import { RouteRecordMatched } from '../matcher/types'
 
 // type Component = ComponentOptions<Vue> | typeof Vue | AsyncComponent
@@ -54,7 +54,7 @@ export interface RouteLocationNormalized
   fullPath: string
   query: HistoryQuery // the normalized version cannot have numbers
   // TODO: do the same for params
-  name: string | void
+  name: string | null | undefined
   matched: RouteRecordMatched[] // non-enumerable
   redirectedFrom?: RouteLocationNormalized
   meta: Record<string | number | symbol, any>
@@ -135,7 +135,6 @@ export type RouteRecord =
   | RouteRecordMultipleViews
   | RouteRecordRedirect
 
-// TODO: this should probably be generate by ensureLocation
 export const START_LOCATION_NORMALIZED: RouteLocationNormalized = markNonReactive(
   {
     path: '/',
index 7af1aef7dfe861173d95566d6f2a49453a6ac1a9..d9dc64e5911b2c902121d710994b186def091596 100644 (file)
@@ -53,6 +53,7 @@ const config = (env = {}) => ({
       template: resolve(__dirname, 'playground/index.html'),
     }),
     new webpack.DefinePlugin({
+      __DEV__: JSON.stringify(!env.prod),
       'process.env': {
         NODE_ENV: JSON.stringify(process.env.NODE_ENV),
       },