From: Eduardo San Martin Morote Date: Wed, 11 Dec 2019 08:42:16 +0000 (+0100) Subject: feat: handle optional custom re X-Git-Tag: v4.0.0-alpha.0~155 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=750b554c66b727053c6ec5d530ba6f912f5e54ad;p=thirdparty%2Fvuejs%2Frouter.git feat: handle optional custom re --- diff --git a/__tests__/matcher/path-parser.spec.ts b/__tests__/matcher/path-parser.spec.ts index 1576ce3d..866c6ce0 100644 --- a/__tests__/matcher/path-parser.spec.ts +++ b/__tests__/matcher/path-parser.spec.ts @@ -52,6 +52,96 @@ describe('Path parser', () => { ]) }) + it('param custom re followed by static', () => { + expect(tokenizePath('/:id(\\d+)hey')).toEqual([ + [ + { + type: TokenType.Param, + value: 'id', + regexp: '\\d+', + repeatable: false, + optional: false, + }, + { + type: TokenType.Static, + value: 'hey', + }, + ], + ]) + }) + + it('param custom re followed by new segment', () => { + expect(tokenizePath('/:id(\\d+)/new')).toEqual([ + [ + { + type: TokenType.Param, + value: 'id', + regexp: '\\d+', + repeatable: false, + optional: false, + }, + ], + [ + { + type: TokenType.Static, + value: 'new', + }, + ], + ]) + }) + + it('param custom re?', () => { + expect(tokenizePath('/:id(\\d+)?')).toEqual([ + [ + { + type: TokenType.Param, + value: 'id', + regexp: '\\d+', + repeatable: false, + optional: true, + }, + ], + ]) + }) + + it('param custom re? followed by static', () => { + expect(tokenizePath('/:id(\\d+)?hey')).toEqual([ + [ + { + type: TokenType.Param, + value: 'id', + regexp: '\\d+', + repeatable: false, + optional: true, + }, + { + type: TokenType.Static, + value: 'hey', + }, + ], + ]) + }) + + it('param custom re? followed by new segment', () => { + expect(tokenizePath('/:id(\\d+)?/new')).toEqual([ + [ + { + type: TokenType.Param, + value: 'id', + regexp: '\\d+', + repeatable: false, + optional: true, + }, + ], + [ + { + type: TokenType.Static, + value: 'new', + }, + ], + ]) + }) + it('param single?', () => { expect(tokenizePath('/:id?')).toEqual([ [ diff --git a/src/matcher/tokenizer.ts b/src/matcher/tokenizer.ts index dee2dd93..d5fba2f4 100644 --- a/src/matcher/tokenizer.ts +++ b/src/matcher/tokenizer.ts @@ -7,6 +7,7 @@ const enum TokenizerState { Static, Param, ParamRegExp, // custom re for a param + ParamRegExpEnd, // check if there is any ? + * EscapeNext, } @@ -72,7 +73,8 @@ export function tokenizePath(path: string): Array { }) } else if ( state === TokenizerState.Param || - state === TokenizerState.ParamRegExp + state === TokenizerState.ParamRegExp || + state === TokenizerState.ParamRegExpEnd ) { if (segment.length > 1 && (char === '*' || char === '+')) crash( @@ -136,21 +138,26 @@ export function tokenizePath(path: string): Array { consumeBuffer() state = TokenizerState.Static // go back one character if we were not modifying - if (char !== '*' && char !== '?' && char !== '+') { - i-- - } + if (char !== '*' && char !== '?' && char !== '+') i-- } break case TokenizerState.ParamRegExp: if (char === ')') { - consumeBuffer() - state = TokenizerState.Static + state = TokenizerState.ParamRegExpEnd } else { customRe += char } break + case TokenizerState.ParamRegExpEnd: + // same as finalizing a param + consumeBuffer() + state = TokenizerState.Static + // go back one character if we were not modifying + if (char !== '*' && char !== '?' && char !== '+') i-- + break + default: crash('Unkwnonw state') break @@ -202,6 +209,15 @@ export function tokensToParser(segments: Array): PathParser { optional: token.optional, }) const re = token.regexp ? token.regexp : BASE_PARAM_PATTERN + if (re !== BASE_PARAM_PATTERN) { + try { + new RegExp(re) + } catch (err) { + throw new Error( + `Invalid custom RegExp for param "${token.value}": ` + err.message + ) + } + } pattern += token.repeatable ? `((?:${re})(?:/(?:${re}))*)` : `(${re})` if (token.optional) pattern += '?' }