1
1
import { 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'
4
12
5
13
function createMatcherPattern (
6
14
...args : ConstructorParameters < typeof MatcherPatternImpl >
7
15
) {
8
16
return new MatcherPatternImpl ( ...args )
9
17
}
10
18
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
17
82
18
83
describe ( '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
+
19
96
describe ( 'resolve()' , ( ) => {
20
97
describe ( 'absolute locationss as strings' , ( ) => {
21
98
it ( 'resolves string locations with no params' , ( ) => {
22
99
const matcher = createCompiledMatcher ( )
23
- matcher . addRoute (
24
- createMatcherPattern ( Symbol ( 'foo' ) , EMPTY_PATH_PATTERN_MATCHER )
25
- )
100
+ matcher . addRoute ( EMPTY_PATH_ROUTE )
26
101
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 : '/' ,
29
104
params : { } ,
30
105
query : { a : 'a' , b : 'b' } ,
31
106
hash : '#h' ,
32
107
} )
33
108
} )
34
109
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
+
35
122
it ( 'resolves string locations with params' , ( ) => {
36
123
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' ,
53
128
params : { id : 1 } ,
54
129
query : { a : 'a' , b : 'b' } ,
55
130
hash : '#h' ,
56
131
} )
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' ,
59
134
params : { id : 54 } ,
60
135
query : { a : 'a' , b : 'b' } ,
61
136
hash : '#h' ,
@@ -64,21 +139,16 @@ describe('Matcher', () => {
64
139
65
140
it ( 'resolve string locations with query' , ( ) => {
66
141
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 } ,
79
149
path : '/foo' ,
80
150
query : {
81
- id : '100' ,
151
+ page : '100' ,
82
152
b : 'b' ,
83
153
} ,
84
154
hash : '#h' ,
@@ -87,94 +157,37 @@ describe('Matcher', () => {
87
157
88
158
it ( 'resolves string locations with hash' , ( ) => {
89
159
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
+ } )
102
164
103
165
expect ( matcher . resolve ( '/foo?a=a&b=b#bar' ) ) . toMatchObject ( {
104
166
hash : '#bar' ,
105
- params : { a : 'bar' } ,
167
+ params : { hash : 'bar' } ,
106
168
path : '/foo' ,
107
169
query : { a : 'a' , b : 'b' } ,
108
170
} )
109
171
} )
110
172
111
- it ( 'returns a valid location with an empty `matched` array if no match ' , ( ) => {
173
+ it ( 'combines path, query and hash params ' , ( ) => {
112
174
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
+ } )
134
180
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' } ,
168
183
} )
169
184
} )
170
185
} )
171
186
172
187
describe ( 'relative locations as strings' , ( ) => {
173
188
it ( 'resolves a simple relative location' , ( ) => {
174
189
const matcher = createCompiledMatcher ( )
175
- matcher . addRoute (
176
- createMatcherPattern ( Symbol ( 'foo' ) , EMPTY_PATH_PATTERN_MATCHER )
177
- )
190
+ matcher . addRoute ( { path : ANY_PATH_PATTERN_MATCHER } )
178
191
179
192
expect (
180
193
matcher . resolve ( 'foo' , matcher . resolve ( '/nested/' ) )
@@ -206,9 +219,10 @@ describe('Matcher', () => {
206
219
describe ( 'named locations' , ( ) => {
207
220
it ( 'resolves named locations with no params' , ( ) => {
208
221
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
+ } )
212
226
213
227
expect ( matcher . resolve ( { name : 'home' , params : { } } ) ) . toMatchObject ( {
214
228
name : 'home' ,
0 commit comments