From: Eduardo San Martin Morote Date: Wed, 11 Dec 2019 09:21:04 +0000 (+0100) Subject: feat: stringify url X-Git-Tag: v4.0.0-alpha.0~154 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ac817442b39f361ee7672ea276be7476c01005f6;p=thirdparty%2Fvuejs%2Frouter.git feat: stringify url --- diff --git a/__tests__/matcher/path-parser.spec.ts b/__tests__/matcher/path-parser.spec.ts index 866c6ce0..db412e3a 100644 --- a/__tests__/matcher/path-parser.spec.ts +++ b/__tests__/matcher/path-parser.spec.ts @@ -422,6 +422,18 @@ describe('Path parser', () => { }) }) + it('catch all', () => { + matchParams('/:rest(.*)', '/a/b/c', { rest: 'a/b/c' }) + matchParams('/:rest(.*)/no', '/a/b/c/no', { rest: 'a/b/c' }) + }) + + it('catch all non-greedy', () => { + matchParams('/:rest(.*?)/b/:other(.*)', '/a/b/c', { + rest: 'a', + other: 'c', + }) + }) + it('param multiple', () => { matchParams('/:a-:b-:c', '/one-two-three', { a: 'one', @@ -450,4 +462,57 @@ describe('Path parser', () => { // end of parsing urls }) + + describe('generating urls', () => { + function matchStringify( + path: string, + params: Exclude< + ReturnType['parse']>, + null + >, + expectedUrl: string + ) { + const pathParser = tokensToParser(tokenizePath(path)) + + expect(pathParser.stringify(params)).toEqual(expectedUrl) + } + + it('no params one segment', () => { + matchStringify('/home', {}, '/home') + }) + + it('single param one segment', () => { + matchStringify('/:id', { id: 'one' }, '/one') + }) + + it('multiple param one segment', () => { + matchStringify('/:a-:b', { a: 'one', b: 'two' }, '/one-two') + }) + + it('repeatable params+', () => { + matchStringify('/:a+', { a: ['one', 'two'] }, '/one/two') + }) + + it('repeatable params*', () => { + matchStringify('/:a*', { a: ['one', 'two'] }, '/one/two') + }) + + it('optional param?', () => { + matchStringify('/:a?/other', { a: '' }, '/other') + matchStringify('/:a?/other', {}, '/other') + }) + + it('optional param? with static segment', () => { + matchStringify('/b-:a?/other', { a: '' }, '/b-/other') + matchStringify('/b-:a?/other', {}, '/b-/other') + }) + + it('optional param*', () => { + matchStringify('/:a*/other', { a: '' }, '/other') + matchStringify('/:a*/other', { a: [] }, '/other') + matchStringify('/:a*/other', {}, '/other') + }) + + // end of stringifying urls + }) }) diff --git a/src/matcher/tokenizer.ts b/src/matcher/tokenizer.ts index d5fba2f4..5c4ff579 100644 --- a/src/matcher/tokenizer.ts +++ b/src/matcher/tokenizer.ts @@ -245,7 +245,32 @@ export function tokensToParser(segments: Array): PathParser { function stringify(params: Params): string { let path = '' - // TODO: implem + let avoidDuplicatedSlash = false + for (const segment of segments) { + if (!avoidDuplicatedSlash || path[path.length - 1] !== '/') path += '/' + avoidDuplicatedSlash = false + + for (const token of segment) { + const { value } = token + if (token.type === TokenType.Static) { + path += value + } else if (token.type === TokenType.Param) { + const param: string | string[] = value in params ? params[value] : '' + + if (Array.isArray(param) && !token.repeatable) + throw new Error( + `Provided param "${value}" is an array but it is not repeatable (* or + modifiers)` + ) + const text: string = Array.isArray(param) ? param.join('/') : param + if (!text) { + if (!token.optional) + throw new Error(`Missing required param "${value}"`) + else avoidDuplicatedSlash = true + } + path += text + } + } + } return path }