From: Eduardo San Martin Morote Date: Fri, 29 Mar 2019 19:26:29 +0000 (+0100) Subject: wip: RouterMatcher X-Git-Tag: v4.0.0-alpha.0~471 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f952110f7661f419b6fc6ca7a3293fddc0b68044;p=thirdparty%2Fvuejs%2Frouter.git wip: RouterMatcher --- diff --git a/src/index.ts b/src/index.ts index c6899dd1..23b53070 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,11 @@ import BaseHistory from './history/base' import pathToRegexp from 'path-to-regexp' -import { Location, RouteRecord, ParamsType, START_RECORD } from './types/index' +import { + RouterLocation, + RouteRecord, + ParamsType, + START_RECORD, +} from './types/index' interface RouterOptions { history: BaseHistory @@ -45,7 +50,7 @@ export class Router { * Trigger a navigation, should resolve all guards first * @param to Where to go */ - push(to: Location) { + push(to: RouterLocation) { // TODO: resolve URL const path = this.resolve(to) // TODO: call hooks, guards @@ -59,14 +64,14 @@ export class Router { ) } - getRouteRecord(location: Location) {} + getRouteRecord(location: RouterLocation) {} /** - * Transforms a Location object into a URL string. If a string is + * Transforms a RouterLocation object into a URL string. If a string is * passed, it returns the string itself - * @param location Location to resolve to a url + * @param location RouterLocation to resolve to a url */ - resolve(location: Readonly): string { + resolve(location: Readonly): string { if (typeof location === 'string') return location if ('path' in location) { // TODO: convert query, hash, warn params diff --git a/src/matcher.ts b/src/matcher.ts new file mode 100644 index 00000000..55f88702 --- /dev/null +++ b/src/matcher.ts @@ -0,0 +1,80 @@ +import pathToRegexp from 'path-to-regexp' +import { + RouteRecord, + ParamsType, + START_RECORD, + RouterLocation, + RouterLocationNormalized, +} from './types/index' + +// TODO: rename +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 RouterMatcher { + private matchers: RouteMatcher[] = [] + + constructor(routes: RouteRecord[]) { + this.matchers = routes.map(generateMatcher) + } + + /** + * Normalize a RouterLocation into an object that is easier to handle + * @param location location to normalize + * @param currentLocation current location, to reuse params and location + */ + normalize( + location: Readonly, + currentLocation: Readonly + ): RouterLocationNormalized { + return {} as RouterLocationNormalized + } + + /** + * 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): 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 || {}) + } +} diff --git a/src/types/index.ts b/src/types/index.ts index 1f356bc4..3b609b9e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -6,7 +6,7 @@ export type ParamsType = Record // (params: ParamsType): any // } -// export interface Location { +// export interface RouterLocation { // record: RouteRecord // path: string // params: ReturnType @@ -23,8 +23,8 @@ export interface RouteRecord { // props: PT } -// TODO location should be an object -export type Location = +// TODO: location should be an object +export type RouterLocation = | string | { path: string @@ -37,6 +37,14 @@ export type Location = params: ParamsType } +export interface RouterLocationNormalized { + path: string + name?: string + params: ParamsType + query: TODO + hash: TODO +} + export type HistoryLocation = string // pushState clones the state passed and do not accept everything