diff --git a/packages/router/src/util.js b/packages/router/src/util.js
index 4cd21fa7ca75..2c85344acb84 100644
--- a/packages/router/src/util.js
+++ b/packages/router/src/util.js
@@ -1,13 +1,15 @@
-// Create a React Context with the given name.
+/** Create a React Context with the given name. */
const createNamedContext = (name, defaultValue) => {
const Ctx = React.createContext(defaultValue)
Ctx.displayName = name
return Ctx
}
-// Get param name and type tranform for a route
-//
-// '/blog/{year}/{month}/{day:Int}' => [['year'], ['month'], ['day', 'Int']]
+/**
+ * Get param name and type transform for a route
+ *
+ * '/blog/{year}/{month}/{day:Int}' => [['year'], ['month'], ['day', 'Int']]
+ */
const paramsForRoute = (route) => {
// Match the strings between `{` and `}`.
const params = [...route.matchAll(/\{([^}]+)\}/g)]
@@ -18,7 +20,7 @@ const paramsForRoute = (route) => {
})
}
-// Definitions of the core param types.
+/** Definitions of the core param types. */
const coreParamTypes = {
Int: {
constraint: /\d+/,
@@ -26,23 +28,25 @@ const coreParamTypes = {
},
}
-// Determine if the given route is a match for the given pathname. If so,
-// extract any named params and return them in an object.
-//
-// route - The route path as specified in the
-// pathname - The pathname from the window.location.
-// allParamTypes - The object containing all param type definitions.
-//
-// Examples:
-//
-// matchPath('/blog/{year}/{month}/{day}', '/blog/2019/12/07')
-// => { match: true, params: { year: '2019', month: '12', day: '07' }}
-//
-// matchPath('/about', '/')
-// => { match: false }
-//
-// matchPath('/post/{id:Int}', '/post/7')
-// => { match: true, params: { id: 7 }}
+/**
+ * Determine if the given route is a match for the given pathname. If so,
+ * extract any named params and return them in an object.
+ *
+ * route - The route path as specified in the
+ * pathname - The pathname from the window.location.
+ * allParamTypes - The object containing all param type definitions.
+ *
+ * Examples:
+ *
+ * matchPath('/blog/{year}/{month}/{day}', '/blog/2019/12/07')
+ * => { match: true, params: { year: '2019', month: '12', day: '07' }}
+ *
+ * matchPath('/about', '/')
+ * => { match: false }
+ *
+ * matchPath('/post/{id:Int}', '/post/7')
+ * => { match: true, params: { id: 7 }}
+ */
const matchPath = (route, pathname, paramTypes) => {
// Get the names and the transform types for the given route.
const routeParams = paramsForRoute(route)
@@ -92,33 +96,38 @@ const matchPath = (route, pathname, paramTypes) => {
return { match: true, params }
}
-// Parse the given search string into key/value pairs and return them in an
-// object.
-//
-// Examples:
-//
-// parseSearch('?key1=val1&key2=val2')
-// => { key1: 'val1', key2: 'val2' }
+/**
+ * Parse the given search string into key/value pairs and return them in an
+ * object.
+ *
+ * Examples:
+ *
+ * parseSearch('?key1=val1&key2=val2')
+ * => { key1: 'val1', key2: 'val2' }
+ *
+ * @fixme
+ * This utility ignores keys with multiple values such as `?foo=1&foo=2`.
+ */
const parseSearch = (search) => {
- if (search === '') {
- return {}
- }
- const searchPart = search.substring(1)
- const pairs = searchPart.split('&')
- const searchProps = {}
- pairs.forEach((pair) => {
- const keyval = pair.split('=')
- searchProps[keyval[0]] = keyval[1] || ''
- })
- return searchProps
+ const searchParams = new URLSearchParams(search)
+
+ return [...searchParams.keys()].reduce(
+ (params, key) => ({
+ ...params,
+ [key]: searchParams.get(key),
+ }),
+ {}
+ )
}
-// Validate a path to make sure it follows the router's rules. If any problems
-// are found, a descriptive Error will be thrown, as problems with routes are
-// critical enough to be considered fatal.
+/**
+ * Validate a path to make sure it follows the router's rules. If any problems
+ * are found, a descriptive Error will be thrown, as problems with routes are
+ * critical enough to be considered fatal.
+ */
const validatePath = (path) => {
// Check that path begins with a slash.
- if (path[0] !== '/') {
+ if (!path.startsWith('/')) {
throw new Error('Route path does not begin with a slash: "' + path + '"')
}
@@ -135,13 +144,16 @@ const validatePath = (path) => {
}
}
-// Take a given route path and replace any named parameters with those in the
-// given args object. Any extra params not used in the path will be appended
-// as key=value pairs in the search part.
-//
-// Examples:
-// replaceParams('/tags/{tag}', { tag: 'code', extra: 'foo' })
-// => '/tags/code?extra=foo
+/**
+ * Take a given route path and replace any named parameters with those in the
+ * given args object. Any extra params not used in the path will be appended
+ * as key=value pairs in the search part.
+ *
+ * Examples:
+ *
+ * replaceParams('/tags/{tag}', { tag: 'code', extra: 'foo' })
+ * => '/tags/code?extra=foo
+ */
const replaceParams = (path, args = {}) => {
// Split the path apart and replace named parameters with those sent in,
// then join it back together.