11import { describe , expect , it } from 'vitest'
2- import { MatcherPatternImpl , MatcherPatternPath } from './matcher-pattern'
3- import { createCompiledMatcher } from './matcher'
2+ import { MatcherPatternImpl } from './matcher-pattern'
3+ import { createCompiledMatcher , NO_MATCH_LOCATION } from './matcher'
4+ import {
5+ MatcherPatternParams_Base ,
6+ MatcherPattern ,
7+ MatcherPatternPath ,
8+ MatcherPatternQuery ,
9+ } from './new-matcher-pattern'
10+ import { miss } from './matchers/errors'
11+ import { EmptyParams } from './matcher-location'
412
513function createMatcherPattern (
614 ...args : ConstructorParameters < typeof MatcherPatternImpl >
715) {
816 return new MatcherPatternImpl ( ...args )
917}
1018
11- const EMPTY_PATH_PATTERN_MATCHER = {
12- match : ( path : string ) => ( { } ) ,
13- parse : ( params : { } ) => ( { } ) ,
14- serialize : ( params : { } ) => ( { } ) ,
15- buildPath : ( ) => '/' ,
16- } satisfies MatcherPatternPath
19+ const ANY_PATH_PATTERN_MATCHER : MatcherPatternPath < { pathMatch : string } > = {
20+ match ( path ) {
21+ return { pathMatch : path }
22+ } ,
23+ build ( { pathMatch } ) {
24+ return pathMatch
25+ } ,
26+ }
27+
28+ const EMPTY_PATH_PATTERN_MATCHER : MatcherPatternPath < EmptyParams > = {
29+ match : path => {
30+ if ( path !== '/' ) {
31+ throw miss ( )
32+ }
33+ return { }
34+ } ,
35+ build : ( ) => '/' ,
36+ }
37+
38+ const USER_ID_PATH_PATTERN_MATCHER : MatcherPatternPath < { id : number } > = {
39+ match ( value ) {
40+ const match = value . match ( / ^ \/ u s e r s \/ ( \d + ) $ / )
41+ if ( ! match ?. [ 1 ] ) {
42+ throw miss ( )
43+ }
44+ const id = Number ( match [ 1 ] )
45+ if ( Number . isNaN ( id ) ) {
46+ throw miss ( )
47+ }
48+ return { id }
49+ } ,
50+ build ( { id } ) {
51+ return `/users/${ id } `
52+ } ,
53+ }
54+
55+ const PAGE_QUERY_PATTERN_MATCHER : MatcherPatternQuery < { page : number } > = {
56+ match : query => {
57+ const page = Number ( query . page )
58+ return {
59+ page : Number . isNaN ( page ) ? 1 : page ,
60+ }
61+ } ,
62+ build : params => ( { page : String ( params . page ) } ) ,
63+ } satisfies MatcherPatternQuery < { page : number } >
64+
65+ const ANY_HASH_PATTERN_MATCHER : MatcherPatternParams_Base <
66+ string ,
67+ { hash : string | null }
68+ > = {
69+ match : hash => ( { hash : hash ? hash . slice ( 1 ) : null } ) ,
70+ build : ( { hash } ) => ( hash ? `#${ hash } ` : '' ) ,
71+ }
72+
73+ const EMPTY_PATH_ROUTE = {
74+ name : 'no params' ,
75+ path : EMPTY_PATH_PATTERN_MATCHER ,
76+ } satisfies MatcherPattern
77+
78+ const USER_ID_ROUTE = {
79+ name : 'user-id' ,
80+ path : USER_ID_PATH_PATTERN_MATCHER ,
81+ } satisfies MatcherPattern
1782
1883describe ( 'Matcher' , ( ) => {
84+ describe ( 'adding and removing' , ( ) => {
85+ it ( 'add static path' , ( ) => {
86+ const matcher = createCompiledMatcher ( )
87+ matcher . addRoute ( EMPTY_PATH_ROUTE )
88+ } )
89+
90+ it ( 'adds dynamic path' , ( ) => {
91+ const matcher = createCompiledMatcher ( )
92+ matcher . addRoute ( USER_ID_ROUTE )
93+ } )
94+ } )
95+
1996 describe ( 'resolve()' , ( ) => {
2097 describe ( 'absolute locationss as strings' , ( ) => {
2198 it ( 'resolves string locations with no params' , ( ) => {
2299 const matcher = createCompiledMatcher ( )
23- matcher . addRoute (
24- createMatcherPattern ( Symbol ( 'foo' ) , EMPTY_PATH_PATTERN_MATCHER )
25- )
100+ matcher . addRoute ( EMPTY_PATH_ROUTE )
26101
27- expect ( matcher . resolve ( '/foo ?a=a&b=b#h' ) ) . toMatchObject ( {
28- path : '/foo ' ,
102+ expect ( matcher . resolve ( '/?a=a&b=b#h' ) ) . toMatchObject ( {
103+ path : '/' ,
29104 params : { } ,
30105 query : { a : 'a' , b : 'b' } ,
31106 hash : '#h' ,
32107 } )
33108 } )
34109
110+ it ( 'resolves a not found string' , ( ) => {
111+ const matcher = createCompiledMatcher ( )
112+ expect ( matcher . resolve ( '/bar?q=1#hash' ) ) . toEqual ( {
113+ ...NO_MATCH_LOCATION ,
114+ fullPath : '/bar?q=1#hash' ,
115+ path : '/bar' ,
116+ query : { q : '1' } ,
117+ hash : '#hash' ,
118+ matched : [ ] ,
119+ } )
120+ } )
121+
35122 it ( 'resolves string locations with params' , ( ) => {
36123 const matcher = createCompiledMatcher ( )
37- matcher . addRoute (
38- // /users/:id
39- createMatcherPattern ( Symbol ( 'foo' ) , {
40- match : ( path : string ) => {
41- const match = path . match ( / ^ \/ f o o \/ ( [ ^ / ] + ?) $ / )
42- if ( ! match ) throw new Error ( 'no match' )
43- return { id : match [ 1 ] }
44- } ,
45- parse : ( params : { id : string } ) => ( { id : Number ( params . id ) } ) ,
46- serialize : ( params : { id : number } ) => ( { id : String ( params . id ) } ) ,
47- buildPath : params => `/foo/${ params . id } ` ,
48- } )
49- )
50-
51- expect ( matcher . resolve ( '/foo/1?a=a&b=b#h' ) ) . toMatchObject ( {
52- path : '/foo/1' ,
124+ matcher . addRoute ( USER_ID_ROUTE )
125+
126+ expect ( matcher . resolve ( '/users/1?a=a&b=b#h' ) ) . toMatchObject ( {
127+ path : '/users/1' ,
53128 params : { id : 1 } ,
54129 query : { a : 'a' , b : 'b' } ,
55130 hash : '#h' ,
56131 } )
57- expect ( matcher . resolve ( '/foo /54?a=a&b=b#h' ) ) . toMatchObject ( {
58- path : '/foo /54' ,
132+ expect ( matcher . resolve ( '/users /54?a=a&b=b#h' ) ) . toMatchObject ( {
133+ path : '/users /54' ,
59134 params : { id : 54 } ,
60135 query : { a : 'a' , b : 'b' } ,
61136 hash : '#h' ,
@@ -64,21 +139,16 @@ describe('Matcher', () => {
64139
65140 it ( 'resolve string locations with query' , ( ) => {
66141 const matcher = createCompiledMatcher ( )
67- matcher . addRoute (
68- createMatcherPattern ( Symbol ( 'foo' ) , EMPTY_PATH_PATTERN_MATCHER , {
69- match : query => ( {
70- id : Array . isArray ( query . id ) ? query . id [ 0 ] : query . id ,
71- } ) ,
72- parse : ( params : { id : string } ) => ( { id : Number ( params . id ) } ) ,
73- serialize : ( params : { id : number } ) => ( { id : String ( params . id ) } ) ,
74- } )
75- )
76-
77- expect ( matcher . resolve ( '/foo?id=100&b=b#h' ) ) . toMatchObject ( {
78- params : { id : 100 } ,
142+ matcher . addRoute ( {
143+ path : ANY_PATH_PATTERN_MATCHER ,
144+ query : PAGE_QUERY_PATTERN_MATCHER ,
145+ } )
146+
147+ expect ( matcher . resolve ( '/foo?page=100&b=b#h' ) ) . toMatchObject ( {
148+ params : { page : 100 } ,
79149 path : '/foo' ,
80150 query : {
81- id : '100' ,
151+ page : '100' ,
82152 b : 'b' ,
83153 } ,
84154 hash : '#h' ,
@@ -87,94 +157,37 @@ describe('Matcher', () => {
87157
88158 it ( 'resolves string locations with hash' , ( ) => {
89159 const matcher = createCompiledMatcher ( )
90- matcher . addRoute (
91- createMatcherPattern (
92- Symbol ( 'foo' ) ,
93- EMPTY_PATH_PATTERN_MATCHER ,
94- undefined ,
95- {
96- match : hash => hash ,
97- parse : hash => ( { a : hash . slice ( 1 ) } ) ,
98- serialize : ( { a } ) => '#a' ,
99- }
100- )
101- )
160+ matcher . addRoute ( {
161+ path : ANY_PATH_PATTERN_MATCHER ,
162+ hash : ANY_HASH_PATTERN_MATCHER ,
163+ } )
102164
103165 expect ( matcher . resolve ( '/foo?a=a&b=b#bar' ) ) . toMatchObject ( {
104166 hash : '#bar' ,
105- params : { a : 'bar' } ,
167+ params : { hash : 'bar' } ,
106168 path : '/foo' ,
107169 query : { a : 'a' , b : 'b' } ,
108170 } )
109171 } )
110172
111- it ( 'returns a valid location with an empty `matched` array if no match ' , ( ) => {
173+ it ( 'combines path, query and hash params ' , ( ) => {
112174 const matcher = createCompiledMatcher ( )
113- expect ( matcher . resolve ( '/bar' ) ) . toMatchInlineSnapshot (
114- {
115- hash : '' ,
116- matched : [ ] ,
117- params : { } ,
118- path : '/bar' ,
119- query : { } ,
120- } ,
121- `
122- {
123- "fullPath": "/bar",
124- "hash": "",
125- "matched": [],
126- "name": Symbol(no-match),
127- "params": {},
128- "path": "/bar",
129- "query": {},
130- }
131- `
132- )
133- } )
175+ matcher . addRoute ( {
176+ path : USER_ID_PATH_PATTERN_MATCHER ,
177+ query : PAGE_QUERY_PATTERN_MATCHER ,
178+ hash : ANY_HASH_PATTERN_MATCHER ,
179+ } )
134180
135- it ( 'resolves string locations with all' , ( ) => {
136- const matcher = createCompiledMatcher ( )
137- matcher . addRoute (
138- createMatcherPattern (
139- Symbol ( 'foo' ) ,
140- {
141- buildPath : params => `/foo/${ params . id } ` ,
142- match : path => {
143- const match = path . match ( / ^ \/ f o o \/ ( [ ^ / ] + ?) $ / )
144- if ( ! match ) throw new Error ( 'no match' )
145- return { id : match [ 1 ] }
146- } ,
147- parse : params => ( { id : Number ( params . id ) } ) ,
148- serialize : params => ( { id : String ( params . id ) } ) ,
149- } ,
150- {
151- match : query => ( {
152- id : Array . isArray ( query . id ) ? query . id [ 0 ] : query . id ,
153- } ) ,
154- parse : params => ( { q : Number ( params . id ) } ) ,
155- serialize : params => ( { id : String ( params . q ) } ) ,
156- } ,
157- {
158- match : hash => hash ,
159- parse : hash => ( { a : hash . slice ( 1 ) } ) ,
160- serialize : ( { a } ) => '#a' ,
161- }
162- )
163- )
164-
165- expect ( matcher . resolve ( '/foo/1?id=100#bar' ) ) . toMatchObject ( {
166- hash : '#bar' ,
167- params : { id : 1 , q : 100 , a : 'bar' } ,
181+ expect ( matcher . resolve ( '/users/24?page=100#bar' ) ) . toMatchObject ( {
182+ params : { id : 24 , page : 100 , hash : 'bar' } ,
168183 } )
169184 } )
170185 } )
171186
172187 describe ( 'relative locations as strings' , ( ) => {
173188 it ( 'resolves a simple relative location' , ( ) => {
174189 const matcher = createCompiledMatcher ( )
175- matcher . addRoute (
176- createMatcherPattern ( Symbol ( 'foo' ) , EMPTY_PATH_PATTERN_MATCHER )
177- )
190+ matcher . addRoute ( { path : ANY_PATH_PATTERN_MATCHER } )
178191
179192 expect (
180193 matcher . resolve ( 'foo' , matcher . resolve ( '/nested/' ) )
@@ -206,9 +219,10 @@ describe('Matcher', () => {
206219 describe ( 'named locations' , ( ) => {
207220 it ( 'resolves named locations with no params' , ( ) => {
208221 const matcher = createCompiledMatcher ( )
209- matcher . addRoute (
210- createMatcherPattern ( 'home' , EMPTY_PATH_PATTERN_MATCHER )
211- )
222+ matcher . addRoute ( {
223+ name : 'home' ,
224+ path : EMPTY_PATH_PATTERN_MATCHER ,
225+ } )
212226
213227 expect ( matcher . resolve ( { name : 'home' , params : { } } ) ) . toMatchObject ( {
214228 name : 'home' ,
0 commit comments