Skip to content

Commit d462758

Browse files
committed
refactor: renames and minor changes
1 parent b57cb21 commit d462758

File tree

4 files changed

+72
-24
lines changed

4 files changed

+72
-24
lines changed

packages/router/src/new-route-resolver/matcher-location.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { MatcherName } from './matcher'
66
*/
77
export type MatcherParamsFormatted = Record<string, unknown>
88

9-
export interface MatcherLocationAsName {
9+
export interface MatcherLocationAsNamed {
1010
name: MatcherName
1111
params: MatcherParamsFormatted
1212
query?: LocationQueryRaw

packages/router/src/new-route-resolver/matcher-pattern.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ export interface MatcherPattern {
4747
* query: { used: String }, // we require a `used` query param
4848
* })
4949
* // /?used=2
50-
* pattern.parseLocation({ path: '/', query: { used: '' }, hash: '' }) // null
50+
* pattern.parseLocation({ path: '/', query: { used: '' }, hash: '' }) // null becauso no /foo
5151
* // /foo?used=2&notUsed&notUsed=2#hello
5252
* pattern.parseLocation({ path: '/foo', query: { used: '2', notUsed: [null, '2']}, hash: '#hello' })
53-
* // { used: '2' } // we extract the required params
54-
* // /foo?used=2#hello
53+
* // [{}, { used: '2' }, {}]// we extract the required params
54+
* // /foo?other=2#hello
5555
* pattern.parseLocation({ path: '/foo', query: {}, hash: '#hello' })
5656
* // null // the query param is missing
5757
* ```
@@ -109,6 +109,7 @@ export interface PatternPathParamOptions<T = unknown>
109109

110110
export interface PatternQueryParamOptions<T = unknown>
111111
extends PatternParamOptions_Base<T> {
112+
// FIXME: can be removed? seems to be the same as above
112113
get: (value: MatcherQueryParamsValue) => T
113114
set?: (value: T) => MatcherQueryParamsValue
114115
}
@@ -153,7 +154,7 @@ export class MatcherPatternImpl implements MatcherPattern {
153154
query: MatcherQueryParams
154155
hash: string
155156
}) {
156-
// TODO: is this performant? bench compare to a check with `null
157+
// TODO: is this performant? bench compare to a check with `null`
157158
try {
158159
return [
159160
this.path.match(location.path),
Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,42 @@
1-
import { describe, it } from 'vitest'
1+
import { describe, expectTypeOf, it } from 'vitest'
22
import { NEW_LocationResolved, createCompiledMatcher } from './matcher'
33

44
describe('Matcher', () => {
5-
it('resolves locations', () => {
6-
const matcher = createCompiledMatcher()
7-
matcher.resolve('/foo')
8-
// @ts-expect-error: needs currentLocation
9-
matcher.resolve('foo')
10-
matcher.resolve('foo', {} as NEW_LocationResolved)
11-
matcher.resolve({ name: 'foo', params: {} })
12-
// @ts-expect-error: needs currentLocation
13-
matcher.resolve({ params: { id: 1 } })
14-
matcher.resolve({ params: { id: 1 } }, {} as NEW_LocationResolved)
5+
const matcher = createCompiledMatcher()
6+
7+
describe('matcher.resolve()', () => {
8+
it('resolves absolute string locations', () => {
9+
expectTypeOf(
10+
matcher.resolve('/foo')
11+
).toEqualTypeOf<NEW_LocationResolved>()
12+
})
13+
14+
it('fails on non absolute location without a currentLocation', () => {
15+
// @ts-expect-error: needs currentLocation
16+
matcher.resolve('foo')
17+
})
18+
19+
it('resolves relative locations', () => {
20+
expectTypeOf(
21+
matcher.resolve('foo', {} as NEW_LocationResolved)
22+
).toEqualTypeOf<NEW_LocationResolved>()
23+
})
24+
25+
it('resolved named locations', () => {
26+
expectTypeOf(
27+
matcher.resolve({ name: 'foo', params: {} })
28+
).toEqualTypeOf<NEW_LocationResolved>()
29+
})
30+
31+
it('fails on object relative location without a currentLocation', () => {
32+
// @ts-expect-error: needs currentLocation
33+
matcher.resolve({ params: { id: 1 } })
34+
})
35+
36+
it('resolves object relative locations with a currentLocation', () => {
37+
expectTypeOf(
38+
matcher.resolve({ params: { id: 1 } }, {} as NEW_LocationResolved)
39+
).toEqualTypeOf<NEW_LocationResolved>()
40+
})
1541
})
1642
})

packages/router/src/new-route-resolver/matcher.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from '../encoding'
1414
import { parseURL, stringifyURL } from '../location'
1515
import type {
16-
MatcherLocationAsName,
16+
MatcherLocationAsNamed,
1717
MatcherLocationAsRelative,
1818
MatcherParamsFormatted,
1919
} from './matcher-location'
@@ -31,7 +31,7 @@ export interface RouteResolver {
3131

3232
/**
3333
* Resolves a string location relative to another location. A relative location can be `./same-folder`,
34-
* `../parent-folder`, or even `same-folder`.
34+
* `../parent-folder`, `same-folder`, or even `?page=2`.
3535
*/
3636
resolve(
3737
relativeLocation: string,
@@ -41,7 +41,7 @@ export interface RouteResolver {
4141
/**
4242
* Resolves a location by its name. Any required params or query must be passed in the `options` argument.
4343
*/
44-
resolve(location: MatcherLocationAsName): NEW_LocationResolved
44+
resolve(location: MatcherLocationAsNamed): NEW_LocationResolved
4545

4646
/**
4747
* Resolves a location by its path. Any required query must be passed.
@@ -67,7 +67,7 @@ export interface RouteResolver {
6767
type MatcherResolveArgs =
6868
| [absoluteLocation: `/${string}`]
6969
| [relativeLocation: string, currentLocation: NEW_LocationResolved]
70-
| [location: MatcherLocationAsName]
70+
| [location: MatcherLocationAsNamed]
7171
| [
7272
relativeLocation: MatcherLocationAsRelative,
7373
currentLocation: NEW_LocationResolved
@@ -108,7 +108,11 @@ export type MatcherPathParams = Record<string, MatcherPathParamsValue>
108108
export type MatcherQueryParamsValue = string | null | Array<string | null>
109109
export type MatcherQueryParams = Record<string, MatcherQueryParamsValue>
110110

111-
export function applyToParams<R>(
111+
/**
112+
* Apply a function to all properties in an object. It's used to encode/decode params and queries.
113+
* @internal
114+
*/
115+
export function applyFnToObject<R>(
112116
fn: (v: string | number | null | undefined) => R,
113117
params: MatcherPathParams | LocationQuery | undefined
114118
): Record<string, R | R[]> {
@@ -195,7 +199,7 @@ function transformObject<T>(
195199
}
196200

197201
export const NO_MATCH_LOCATION = {
198-
name: Symbol('no-match'),
202+
name: __DEV__ ? Symbol('no-match') : Symbol(),
199203
params: {},
200204
matched: [],
201205
} satisfies Omit<NEW_LocationResolved, 'path' | 'hash' | 'query' | 'fullPath'>
@@ -215,8 +219,9 @@ export function createCompiledMatcher(): RouteResolver {
215219

216220
function resolve(...args: MatcherResolveArgs): NEW_LocationResolved {
217221
const [location, currentLocation] = args
222+
223+
// string location, e.g. '/foo', '../bar', 'baz', '?page=1'
218224
if (typeof location === 'string') {
219-
// string location, e.g. '/foo', '../bar', 'baz'
220225
const url = parseURL(parseQuery, location, currentLocation?.path)
221226

222227
let matcher: MatcherPattern | undefined
@@ -257,14 +262,30 @@ export function createCompiledMatcher(): RouteResolver {
257262
}
258263
} else {
259264
// relative location or by name
265+
if (__DEV__ && location.name == null && currentLocation == null) {
266+
console.warn(
267+
`Cannot resolve an unnamed relative location without a current location. This will throw in production.`,
268+
location
269+
)
270+
return {
271+
...NO_MATCH_LOCATION,
272+
fullPath: '/',
273+
path: '/',
274+
query: {},
275+
hash: '',
276+
}
277+
}
278+
279+
// either one of them must be defined and is catched by the dev only warn above
260280
const name = location.name ?? currentLocation!.name
261281
const matcher = matchers.get(name)
262282
if (!matcher) {
263283
throw new Error(`Matcher "${String(location.name)}" not found`)
264284
}
265285

266286
// unencoded params in a formatted form that the user came up with
267-
const params = location.params ?? currentLocation!.params
287+
const params: MatcherParamsFormatted =
288+
location.params ?? currentLocation!.params
268289
const mixedUnencodedParams = matcher.matchParams(params)
269290

270291
if (!mixedUnencodedParams) {

0 commit comments

Comments
 (0)