<script setup lang="ts">
-import { ref } from 'vue'
+import { computed, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const url = ref('')
+
+const queryPage = computed({
+ get: () =>
+ typeof route.params.page === 'number'
+ ? (route.params.page as number)
+ : null,
+ set: (value: number) => {
+ // TODO: relative location
+ router.push({
+ ...route,
+ // @ts-expect-error: FIXME: wtf
+ params: { ...route.params, page: value },
+ })
+ },
+})
</script>
<template>
|
<RouterLink to="/profiles">Profiles list</RouterLink>
</nav>
- <form @submit.prevent="router.push(url, route)">
+ <form @submit.prevent="router.push(url)">
<label for="path">Path:</label>
<input
id="path"
<br />
params: <code>{{ route.params }}</code>
<br />
+ <template v-if="queryPage != null">
+ page: <input type="number" v-model.number="queryPage" />
+ <br />
+ </template>
meta: <code>{{ route.meta }}</code>
</p>
MatcherPatternQuery,
} from 'vue-router/experimental'
import PageHome from '../pages/(home).vue'
+import type { EmptyParams } from 'vue-router/experimental'
// type ExtractMatcherQueryParams<T> =
// T extends MatcherPatternQuery<infer P> ? P : never
build: params => ({ page: String(params.page) }),
}
-const QUERY_PATTERN_MATCHER: MatcherPatternQuery<{ q: string }> = {
+const QUERY_PATTERN_MATCHER: MatcherPatternQuery<{ q?: string }> = {
match: query => {
return {
q: typeof query.q === 'string' ? query.q : '',
}
},
- build: params => {
- return { q: params.q || '' }
+ // NOTE: we need either to cast or to add an explicit return type annotation
+ // because of the special meaning of {} in TypeScript.
+ build: (params): { q?: string } => {
+ return params.q ? { q: params.q } : ({} as EmptyParams)
},
}
// QUERY_PATTERN_MATCHER
// )
-const QUERY_MATCHER_COMBINED: MatcherPatternQuery<{
- page: number
- q: string
-}> = {
- match: query => {
- return {
- ...PAGE_QUERY_PATTERN_MATCHER.match(query),
- ...QUERY_PATTERN_MATCHER.match(query),
- }
- },
- build: params => ({
- ...PAGE_QUERY_PATTERN_MATCHER.build(params),
- ...QUERY_PATTERN_MATCHER.build(params),
- }),
-}
-
const ANY_HASH_PATTERN_MATCHER: MatcherPatternHash<// hash could be named anything, in this case it creates a param named hash
{ hash: string | null }> = {
match: hash => ({ hash: hash ? hash.slice(1) : null }),
const r_home = normalizeRouteRecord({
name: 'home',
path: new MatcherPatternPathStatic('/'),
- query: QUERY_MATCHER_COMBINED,
+ query: [PAGE_QUERY_PATTERN_MATCHER, QUERY_PATTERN_MATCHER],
parent: r_group,
components: { default: PageHome },
})
meta: {
layout: 'profile',
},
- query: PAGE_QUERY_PATTERN_MATCHER,
+ query: [PAGE_QUERY_PATTERN_MATCHER],
})
const r_profiles_list = normalizeRouteRecord({
{
name: 'any-path',
path: ANY_PATH_PATTERN_MATCHER,
- query: PAGE_QUERY_PATTERN_MATCHER_LOCAL,
+ query: [PAGE_QUERY_PATTERN_MATCHER_LOCAL],
},
])
{
name: 'user-detail',
path: USER_ID_PATH_PATTERN_MATCHER,
- query: PAGE_QUERY_PATTERN_MATCHER_LOCAL,
+ query: [PAGE_QUERY_PATTERN_MATCHER_LOCAL],
hash: ANY_HASH_PATTERN_MATCHER,
},
])
{
name: 'query',
path: EMPTY_PATH_PATTERN_MATCHER,
- query: {
- match(q) {
- return { q }
- },
- build({ q }) {
- return { ...q }
- },
- } satisfies MatcherPatternQuery<{ q: MatcherQueryParams }>,
+ query: [
+ {
+ match(q) {
+ return { q }
+ },
+ build({ q }) {
+ return { ...q }
+ },
+ } satisfies MatcherPatternQuery<{ q: MatcherQueryParams }>,
+ ],
},
])
expect(resolver.resolve('/?%23%2F%3F=%23%2F%3F')).toMatchObject({
/**
* {@link MatcherPattern} for the query section of the URI.
*/
- query?: MatcherPatternQuery
+ query?: MatcherPatternQuery[]
/**
* {@link MatcherPattern} for the hash section of the URI.
extends EXPERIMENTAL_ResolverRecord_Base {
name?: undefined
path?: undefined
- query?: undefined
+ // Query is the only kind of matcher that is non-exclusive
+ // all matched records get their queries merged
+ // query?: undefined
hash?: undefined
}
...currentLocation?.query,
...normalizeQuery(to.query),
},
- ...matched.map(record => record.query?.build(params))
+ ...matched.flatMap(record =>
+ record.query?.map(query => query.build(params))
+ )
)
return {
matched = buildMatched(record)
const queryParams: MatcherQueryParams = Object.assign(
{},
- ...matched.map(record => record.query?.match(url.query))
+ ...matched.flatMap(record =>
+ record.query?.map(query => query.match(url.query))
+ )
)
// TODO: test performance
// for (const record of matched) {