From: Eduardo San Martin Morote Date: Thu, 19 Dec 2019 23:05:53 +0000 (+0100) Subject: refactor: remove old files X-Git-Tag: v4.0.0-alpha.0~132 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0524c90d49a6d0bc13ca960d187e055654b64fe5;p=thirdparty%2Fvuejs%2Frouter.git refactor: remove old files --- diff --git a/__tests__/matcher/ranking.spec.ts b/__tests__/matcher/ranking.spec.ts deleted file mode 100644 index 95665aeb..00000000 --- a/__tests__/matcher/ranking.spec.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { createRouteRecordMatcher } from '../../src/matcher/path-matcher' -import { RegExpOptions } from 'path-to-regexp' -import { RouteComponent } from '../../src/types' -import { RouteRecordMatcher } from '../../src/matcher/types' - -// @ts-ignore -const component: RouteComponent = null - -function stringifyOptions(options: any) { - return Object.keys(options).length ? ` (${JSON.stringify(options)})` : '' -} - -describe('createRouteRecordMatcher', () => { - function checkPathOrder( - paths: Array, - options: RegExpOptions = {} - ) { - const normalizedPaths = paths.map(pathOrCombined => { - if (Array.isArray(pathOrCombined)) - return [pathOrCombined[0], { ...options, ...pathOrCombined[1] }] - return [pathOrCombined, options] - }) - - const matchers: Array = normalizedPaths - .slice() - // Because sorting order is conserved, allows to mismatch order on - // routes with the same ranking - .reverse() - .map(([path, options]) => ({ - ...createRouteRecordMatcher( - { - // @ts-ignore types are correct - path, - components: { default: component }, - }, - null, - options - ), - // add original options - _options: options, - })) - .sort((a, b) => b.score - a.score) - - expect(matchers.map(matcher => matcher.record.path)).toEqual( - normalizedPaths.map(([path]) => path) - ) - - // Fail if two consecutive records have the same record - for (let i = 1; i < matchers.length; i++) { - const a = matchers[i - 1] - const b = matchers[i] - try { - expect(a.score).not.toBe(b.score) - } catch (e) { - throw new Error( - `Record "${a.record.path}"${stringifyOptions( - matchers[i - 1]._options - )} and "${b.record.path}"${stringifyOptions( - matchers[i]._options - )} have the same score: ${ - a.score - }. Avoid putting routes with the same score on the same test` - ) - } - } - } - - it('orders a rest param with root', () => { - checkPathOrder(['/a/', '/a/:w(.*)', '/a']) - }) - - it('orders sub segments with params', () => { - checkPathOrder(['/a-b-c', '/a-:b-c', '/a-:b-:c', '/a-:b']) - }) - - it('works', () => { - checkPathOrder([ - '/a/b/c', - '/a/:b/c', - '/a/b', - '/a/:b', - '/:a/-:b', - '/:a/:b', - '/a', - '/a-:b', - '/a-:w(.*)', - '/:a-b', - '/:a-:b-:c', - '/:a-:b', - '/:a-:b(.*)', - '/:w', - '/:w+', - '/', - ]) - }) - - it('puts the wildcard at the end', () => { - checkPathOrder(['/', '/:rest(.*)']) - }) - - it('prioritises custom regex', () => { - checkPathOrder(['/:a(\\d+)', '/:a', '/:a(.*)']) - checkPathOrder(['/b-:a(\\d+)', '/b-:a', '/b-:a(.*)']) - }) - - it('handles sub segments optional params', () => { - // TODO: /a/c should be be bigger than /a/c/:b? - checkPathOrder(['/a/d/c', '/a/b/c:b', '/a/c/:b', '/a/c/:b?', '/a/c']) - }) - - it('handles optional in sub segments', () => { - checkPathOrder([ - '/a/_2_', - // something like /a/_23_ - '/a/_:b(\\d)?_', - '/a/_:b\\_', // the _ is escaped but b can be also letters - '/a/a_:b', - ]) - }) - - it('works with long paths', () => { - checkPathOrder([ - '/a/b/c/d/e', - '/:k-foo/b/c/d/e', - '/:k/b/c/d/e', - '/:k/b/c/d/:j', - ]) - }) - - it('ending slashes less than params', () => { - checkPathOrder([ - ['/a/:b/', { strict: true }], - ['/a/b', { strict: false }], - ['/a/:b', { strict: true }], - ]) - }) - - it('prioritizes ending slashes', () => { - checkPathOrder([ - // no strict - '/a/b/', - '/a/b', - '/a/', - '/a', - ]) - - checkPathOrder([ - ['/a/b/', { strict: true }], - '/a/b/', - ['/a/b', { strict: true }], - '/a/b', - ['/a/', { strict: true }], - '/a/', - ['/a', { strict: true }], - '/a', - ]) - }) - - it('prioritizes case sensitive', () => { - checkPathOrder([ - ['/a/', { sensitive: true }], - '/a/', // explicit ending slash - ['/a', { sensitive: true }], - '/a', // also matches /A - ]) - }) - - it('ranks repeated params properly', () => { - checkPathOrder([ - '/:a', - '/:a+', - '/:a?', - '/:a*', - // FIXME: this one should appear here but it appears before /:a* - // '/:a(.*)' - ]) - }) -}) diff --git a/src/matcher/index.ts b/src/matcher/index.ts index 28b73fe5..ab93e1e2 100644 --- a/src/matcher/index.ts +++ b/src/matcher/index.ts @@ -8,10 +8,7 @@ import { } from '../types' import { NoRouteMatchError, InvalidRouteMatch } from '../errors' // import { createRouteRecordMatcher } from './path-matcher' -import { - createRouteRecordMatcher, - RouteRecordMatcher, -} from './new-path-matcher' +import { createRouteRecordMatcher, RouteRecordMatcher } from './path-matcher' import { RouteRecordNormalized } from './types' import { PathParams, diff --git a/src/matcher/new-path-matcher.ts b/src/matcher/new-path-matcher.ts deleted file mode 100644 index fdbb10b2..00000000 --- a/src/matcher/new-path-matcher.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { RouteRecordNormalized } from './types' -import { - tokensToParser, - PathParser, - PathParserOptions, -} from './path-parser-ranker' -import { tokenizePath } from './path-tokenizer' - -export interface RouteRecordMatcher extends PathParser { - record: RouteRecordNormalized - parent: RouteRecordMatcher | undefined - // TODO: children so they can be removed - // children: RouteRecordMatcher[] -} - -export function createRouteRecordMatcher( - record: Readonly, - parent: RouteRecordMatcher | undefined, - options?: PathParserOptions -): RouteRecordMatcher { - const parser = tokensToParser(tokenizePath(record.path), options) - - return { - ...parser, - record, - parent, - } -} diff --git a/src/matcher/path-matcher.ts b/src/matcher/path-matcher.ts index b1f5edd5..fdbb10b2 100644 --- a/src/matcher/path-matcher.ts +++ b/src/matcher/path-matcher.ts @@ -1,222 +1,28 @@ -import pathToRegexp from 'path-to-regexp' -import { RouteRecordNormalized, RouteRecordMatcher } from './types' - -const enum PathScore { - _multiplier = 10, - Segment = 4 * _multiplier, // /a-segment - SubSegment = 2 * _multiplier, // /multiple-:things-in-one-:segment - Static = 3 * _multiplier, // /static - Dynamic = 2 * _multiplier, // /:someId - DynamicCustomRegexp = 2.5 * _multiplier, // /:someId(\\d+) - Wildcard = -1 * _multiplier, // /:namedWildcard(.*) - SubWildcard = 1 * _multiplier, // Wildcard as a subsegment - Repeatable = -0.5 * _multiplier, // /:w+ or /:w* - // these two have to be under 0.1 so a strict /:page is still lower than /:a-:b - Strict = 0.07 * _multiplier, // when options strict: true is passed, as the regex omits \/? - CaseSensitive = 0.025 * _multiplier, // when options strict: true is passed, as the regex omits \/? - Optional = -4 * _multiplier, // /:w? or /:w* - SubOptional = -0.1 * _multiplier, // optional inside a subsegment /a-:w? or /a-:w* - Root = 1 * _multiplier, // just / +import { RouteRecordNormalized } from './types' +import { + tokensToParser, + PathParser, + PathParserOptions, +} from './path-parser-ranker' +import { tokenizePath } from './path-tokenizer' + +export interface RouteRecordMatcher extends PathParser { + record: RouteRecordNormalized + parent: RouteRecordMatcher | undefined + // TODO: children so they can be removed + // children: RouteRecordMatcher[] } -/** - * Non Working Rankings: - * - ?p=AAOsIPQgYAEL9lNgQAGKBeACgQMODLpiY5C0gAQYhGyZkaNyaRFZOwOOkPODO_HsENkAAA.. - * the case sensitive and the strict option on the optional parameter `/:a-:w?` or `/:a?-:w` will come before `/:a-b` - */ - -// allows to check if the user provided a custom regexp -const isDefaultPathRegExpRE = /^\[\^[^\]]+\]\+\?$/ - export function createRouteRecordMatcher( record: Readonly, parent: RouteRecordMatcher | undefined, - options: pathToRegexp.RegExpOptions + options?: PathParserOptions ): RouteRecordMatcher { - const keys: pathToRegexp.Key[] = [] - // options only use `delimiter` - const tokens = pathToRegexp.parse(record.path, options) - const re = pathToRegexp.tokensToRegExp(tokens, keys, options) - // we pass a copy because later on we are modifying the original token array - // to compute the score of routes - const resolve = pathToRegexp.tokensToFunction([...tokens]) - - let score = - (options.strict ? PathScore.Strict : 0) + - (options.sensitive ? PathScore.CaseSensitive : 0) - - // console.log(tokens) - // console.log('--- GROUPING ---') - - // special case for root path - if (tokens.length === 1 && tokens[0] === '/') { - score = PathScore.Segment + PathScore.Root - } else { - // allows us to group tokens into one single segment - // it will point to the first token of the current group - let currentSegment = 0 - // we group them in arrays to process them later - const groups: Array = [] - // we skip the first element as it must be part of the first group - const token = tokens[0] - if (typeof token === 'string') { - // TODO: refactor code in loop (right now it is duplicated) - // we still need to check for / inside the string - // remove the empty string because of the leading slash - const sections = token.split('/').slice(1) - if (sections.length > 1) { - // the last one is going to replace currentSegment - const last = sections.pop() as string // ts complains but length >= 2 - // we need to finalize previous group but we cannot use current entry - // here we are sure that currentSegment < i because the token doesn't start with / - // assert(currentSegment < i) - const first = sections.shift() as string // ts complains but length >= 2 - // so we cut until the current segment and add the first section of current token as well - groups.push(tokens.slice(currentSegment, 0).concat('/' + first)) - // equivalent to - // groups.push(['/' + first]) - - // we add the remaining sections as static groups - for (const section of sections) { - groups.push(['/' + section]) - } - - // we replace current entry with the last section and reset current segment - tokens[0] = '/' + last - // currentSegment = 0 - } - } - - for (let i = 1; i < tokens.length; i++) { - const token = tokens[i] - if (typeof token === 'string') { - if (token.charAt(0) === '/') { - // finalize previous group and start a new one - groups.push(tokens.slice(currentSegment, i)) - currentSegment = i - } else { - // we still need to check for / inside the string - const sections = token.split('/') - if (sections.length > 1) { - // the last one is going to replace currentSegment - const last = sections.pop() as string // ts complains but length >= 2 - // we need to finalize previous group but we cannot use current entry - // here we are sure that currentSegment < i because the token doesn't start with / - // assert(currentSegment < i) - const first = sections.shift() as string // ts complains but length >= 2 - // so we cut until the current segment and add the first section of current token as well - groups.push(tokens.slice(currentSegment, i).concat(first)) - - // we add the remaining sections as static groups - for (const section of sections) { - groups.push(['/' + section]) - } + const parser = tokensToParser(tokenizePath(record.path), options) - // we replace current entry with the last section and reset current segment - tokens[i] = '/' + last - currentSegment = i - } - } - } else if (token.prefix.charAt(0) === '/') { - // finalize previous group and start a new one - groups.push(tokens.slice(currentSegment, i)) - currentSegment = i - } - } - - // add the remaining segment as one group - // TODO: refactor the handling of ending with static like /:a/b/c - if (currentSegment < tokens.length) { - let token: pathToRegexp.Token - if ( - tokens.length - currentSegment === 1 && - typeof (token = tokens[tokens.length - 1]) === 'string' - ) { - // the remaining group is a single string, so it must start with a leading / - const sections = token.split('/').slice(1) - // we add the remaining sections as static groups - for (const section of sections) { - groups.push(['/' + section]) - } - } else { - groups.push(tokens.slice(currentSegment)) - } - } - - const scoreForSegment = function scoreForSegment( - group: pathToRegexp.Token - ): number { - let score = PathScore.Segment - if (typeof group === 'string') { - score += group === '/' ? PathScore.Root : PathScore.Static - } else { - score += - group.pattern === '.*' - ? PathScore.Wildcard - : isDefaultPathRegExpRE.test(group.pattern) - ? PathScore.Dynamic - : PathScore.DynamicCustomRegexp - score += - +group.optional * PathScore.Optional + - +group.repeat * PathScore.Repeatable - // if (typeof group.name === 'number') { - // throw new TypeError('Name your param') - // } - // keys.push(group.name) - } - return score - } - - const scoreForSubSegment = function scoreForSubSegment( - group: pathToRegexp.Token - ): number { - let score = 0 - if (typeof group === 'string') { - // in a sub segment, it doesn't matter if it's root or not - score += PathScore.Static - } else { - score += - group.pattern === '.*' - ? PathScore.SubWildcard - : isDefaultPathRegExpRE.test(group.pattern) - ? PathScore.Dynamic - : PathScore.DynamicCustomRegexp - score += +group.optional * PathScore.SubOptional - if (typeof group.name === 'number') { - throw new TypeError('Name your param') - } - // keys.push(group.name) - } - return score - } - - for (const group of groups) { - // console.log(group) - if (group.length === 1) { - score += scoreForSegment(group[0]) - } else { - score += PathScore.Segment + PathScore.SubSegment - let multiplier = 1 / 10 - for (let i = 0; i < group.length; i++) { - score += scoreForSubSegment(group[i]) * multiplier - multiplier /= 10 - } - } - // segments.push('/' + section) - } - - // console.log(record.path, { score }) - // console.log('____'.repeat(20)) - } - - // create the object before hand so it can be passed to children return { - parent, + ...parser, record, - re, - // TODO: handle numbers differently. Maybe take the max one and say there are x unnamed keys - keys: keys.map(key => String(key.name)), - resolve, - score, + parent, } } diff --git a/src/matcher/types.ts b/src/matcher/types.ts index edc2681c..709a24db 100644 --- a/src/matcher/types.ts +++ b/src/matcher/types.ts @@ -1,8 +1,4 @@ -import { - RouteParams, - RouteRecordMultipleViews, - RouteRecordRedirect, -} from '../types' +import { RouteRecordMultipleViews, RouteRecordRedirect } from '../types' interface RouteRecordRedirectNormalized { path: RouteRecordRedirect['path'] @@ -23,16 +19,3 @@ interface RouteRecordViewNormalized { export type RouteRecordNormalized = | RouteRecordRedirectNormalized | RouteRecordViewNormalized - -// TODO: move to a different file -export interface RouteRecordMatcher { - re: RegExp - resolve: (params?: RouteParams) => string - record: RouteRecordNormalized - parent: RouteRecordMatcher | undefined - // TODO: children so they can be removed - // children: RouteMatcher[] - // TODO: needs information like optional, repeatable - keys: string[] - score: number -}