]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
wip: resolving in matcher
authorEduardo San Martin Morote <posva13@gmail.com>
Fri, 29 Mar 2019 21:49:18 +0000 (22:49 +0100)
committerEduardo San Martin Morote <posva13@gmail.com>
Fri, 29 Mar 2019 21:49:18 +0000 (22:49 +0100)
explorations/html5.ts
src/history/html5.ts
src/index.ts
src/matcher.ts
src/types/index.ts
src/uitls/index.ts [new file with mode: 0644]

index b0241d2952d74e64c1cea116ef4e7ecbaf31c50a..dff41b04e71baeb7df16bbea4f04e17e6adcddb5 100644 (file)
@@ -54,3 +54,7 @@ r.push({
     id: 'no-name',
   },
 })
+
+r.push({
+  hash: '#hey',
+})
index 2dc939e5c5b13ecb1eee4dc5d5350d79bf054711..c549532e0dd08083a88a1af997f6884868524133 100644 (file)
@@ -35,7 +35,6 @@ export default class HTML5History extends BaseHistory {
       to
     )
     this.location = to
-    cs.warn('changed location to', this.location)
   }
 
   replace(to: HistoryLocation) {
@@ -54,7 +53,6 @@ export default class HTML5History extends BaseHistory {
       to
     )
     this.location = to
-    cs.warn('changed location to', this.location)
   }
 
   push(to: HistoryLocation, data?: HistoryState) {
@@ -78,7 +76,6 @@ export default class HTML5History extends BaseHistory {
     cs.info('push', this.location, '->', to, 'with state', state)
     this.history.pushState(state, '', to)
     this.location = to
-    cs.warn('changed location to', this.location)
   }
 
   listen(callback: NavigationCallback) {
@@ -93,7 +90,6 @@ export default class HTML5History extends BaseHistory {
       // we have the state from the old entry, not the current one being removed
       // TODO: correctly parse pathname
       this.location = state ? state._current : buildFullPath
-      cs.warn('changed location to', this.location)
       callback(this.location, from, {
         type:
           from === state._forward
index 23b5307095daf4cc80a3ba07b936383e8d6f3e51..2df393680bd89d6369a3d395d23d70992acd7057 100644 (file)
@@ -1,10 +1,10 @@
 import BaseHistory from './history/base'
-import pathToRegexp from 'path-to-regexp'
+import { RouterMatcher } from './matcher'
 import {
   RouterLocation,
   RouteRecord,
-  ParamsType,
-  START_RECORD,
+  START_LOCATION_NORMALIZED,
+  RouterLocationNormalized,
 } from './types/index'
 
 interface RouterOptions {
@@ -12,38 +12,16 @@ interface RouterOptions {
   routes: RouteRecord[]
 }
 
-interface RouteMatcher {
-  re: RegExp
-  resolve: (params: ParamsType) => string
-  record: RouteRecord
-  keys: string[]
-}
-
-function generateMatcher(record: RouteRecord) {
-  const keys: pathToRegexp.Key[] = []
-  // TODO: if children use option end: false ?
-  const re = pathToRegexp(record.path, keys)
-  return {
-    re,
-    resolve: pathToRegexp.compile(record.path),
-    keys: keys.map(k => '' + k.name),
-    record,
-  }
-}
-
-const START_MATCHER = generateMatcher(START_RECORD)
-
 export class Router {
   protected history: BaseHistory
-  private routes: RouteMatcher[]
-  currentRoute: RouteRecord = START_RECORD
-  currentMatcher: RouteMatcher = START_MATCHER
+  private matcher: RouterMatcher
+  currentRoute: RouterLocationNormalized = START_LOCATION_NORMALIZED
 
   constructor(options: RouterOptions) {
     this.history = options.history
     this.history.ensureLocation()
 
-    this.routes = options.routes.map(generateMatcher)
+    this.matcher = new RouterMatcher(options.routes)
   }
 
   /**
@@ -52,47 +30,10 @@ export class Router {
    */
   push(to: RouterLocation) {
     // TODO: resolve URL
-    const path = this.resolve(to)
+    const path = this.matcher.resolve(to, this.currentRoute)
     // TODO: call hooks, guards
-    this.history.push(
-      path +
-        // TODO: test purposes only
-        '?value=' +
-        Math.round(Math.random() * 10) +
-        '#e' +
-        Math.round(Math.random() * 10)
-    )
+    this.history.push(path)
   }
 
   getRouteRecord(location: RouterLocation) {}
-
-  /**
-   * Transforms a RouterLocation object into a URL string. If a string is
-   * passed, it returns the string itself
-   * @param location RouterLocation to resolve to a url
-   */
-  resolve(location: Readonly<RouterLocation>): string {
-    if (typeof location === 'string') return location
-    if ('path' in location) {
-      // TODO: convert query, hash, warn params
-      return location.path
-    }
-
-    let matcher: RouteMatcher | void
-    if (!('name' in location)) {
-      // TODO: use current location
-      // location = {...location, name: this.}
-      matcher = this.routes.find(r => r.record.name === this.currentRoute.name)
-      // return '/using current location'
-    } else {
-      matcher = this.routes.find(r => r.record.name === location.name)
-    }
-
-    if (!matcher) {
-      // TODO: error
-      throw new Error('No match for' + location)
-    }
-
-    return matcher.resolve(location.params || {})
-  }
 }
index 55f88702dce7cac14074516c2999da64c351ea40..a47ac7ede560693caf88e212f50182ba02ddd3a7 100644 (file)
@@ -1,16 +1,16 @@
 import pathToRegexp from 'path-to-regexp'
 import {
   RouteRecord,
-  ParamsType,
-  START_RECORD,
+  RouteParams,
   RouterLocation,
   RouterLocationNormalized,
 } from './types/index'
+import { stringifyQuery } from './uitls'
 
 // TODO: rename
 interface RouteMatcher {
   re: RegExp
-  resolve: (params: ParamsType) => string
+  resolve: (params: RouteParams) => string
   record: RouteRecord
   keys: string[]
 }
@@ -27,8 +27,6 @@ function generateMatcher(record: RouteRecord) {
   }
 }
 
-const START_MATCHER = generateMatcher(START_RECORD)
-
 export class RouterMatcher {
   private matchers: RouteMatcher[] = []
 
@@ -53,21 +51,36 @@ export class RouterMatcher {
    * passed, it returns the string itself
    * @param location RouterLocation to resolve to a url
    */
-  resolve(location: Readonly<RouterLocation>): string {
+  resolve(
+    location: Readonly<RouterLocation>,
+    currentLocation: RouterLocationNormalized
+  ): string {
     if (typeof location === 'string') return location
+
     if ('path' in location) {
-      // TODO: convert query, hash, warn params
-      return location.path
+      // TODO: warn missing params
+      return (
+        location.path + stringifyQuery(location.query) + (location.hash || '')
+      )
     }
 
     let matcher: RouteMatcher | void
     if (!('name' in location)) {
       // TODO: use current location
       // location = {...location, name: this.}
-      matcher = this.routes.find(r => r.record.name === this.currentRoute.name)
+      if (currentLocation.name) {
+        // we don't want to match an undefined name
+        matcher = this.matchers.find(
+          m => m.record.name === currentLocation.name
+        )
+      } else {
+        matcher = this.matchers.find(
+          m => m.record.path === currentLocation.path
+        )
+      }
       // return '/using current location'
     } else {
-      matcher = this.routes.find(r => r.record.name === location.name)
+      matcher = this.matchers.find(m => m.record.name === location.name)
     }
 
     if (!matcher) {
index 3b609b9e01f17ce6e48febd72f2171016d360ae0..9a0cc59cbfeca111dad3876b3300a0ca0f0cfb78 100644 (file)
@@ -1,9 +1,10 @@
 type TODO = any
 
-export type ParamsType = Record<string, string | string[]>
+export type RouteParams = Record<string, string | string[]>
+export type RouteQuery = Record<string, string | null>
 
 // interface PropsTransformer {
-//   (params: ParamsType): any
+//   (params: RouteParams): any
 // }
 
 // export interface RouterLocation<PT extends PropsTransformer> {
@@ -28,19 +29,25 @@ export type RouterLocation =
   | string
   | {
       path: string
+      query?: RouteQuery
+      hash?: string
     }
   | {
       name: string
-      params?: ParamsType
+      params?: RouteParams
+      query?: RouteQuery
+      hash?: string
     }
   | {
-      params: ParamsType
+      params?: RouteParams
+      query?: RouteQuery
+      hash?: string
     }
 
 export interface RouterLocationNormalized {
   path: string
   name?: string
-  params: ParamsType
+  params: RouteParams
   query: TODO
   hash: TODO
 }
@@ -69,6 +76,13 @@ export const START_RECORD: RouteRecord = {
   component: { render: h => h() },
 }
 
+export const START_LOCATION_NORMALIZED: RouterLocationNormalized = {
+  path: '/',
+  params: {},
+  query: {},
+  hash: '',
+}
+
 export enum NavigationType {
   back,
   forward,
diff --git a/src/uitls/index.ts b/src/uitls/index.ts
new file mode 100644 (file)
index 0000000..99c787c
--- /dev/null
@@ -0,0 +1,13 @@
+import { RouteQuery } from '../types'
+
+export function stringifyQuery(query: RouteQuery | void): string {
+  if (!query) return ''
+
+  let search = '?'
+  for (const key in query) {
+    search += `${key}=${query[key]}`
+  }
+
+  // no query means empty string
+  return search === '?' ? '' : ''
+}