未验证 提交 08d7755e 编写于 作者: J JJ Kasper 提交者: GitHub

Update routeKeys to handle non-word characters (#12801)

This updates the named regexes output in the `routes-manifest` and the associated `routeKeys` to not use any non-word characters as this breaks the named regexes e.g. `"Invalid regular expression: "^/(?<data\-provider\-id>[^/]+?)(?:/)?$"`

x-ref: https://github.com/zeit/now/pull/4355 
上级 a3ffa2e6
...@@ -289,7 +289,7 @@ export default async function build(dir: string, conf = null): Promise<void> { ...@@ -289,7 +289,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
const routesManifestPath = path.join(distDir, ROUTES_MANIFEST) const routesManifestPath = path.join(distDir, ROUTES_MANIFEST)
const routesManifest: any = { const routesManifest: any = {
version: 1, version: 3,
pages404: true, pages404: true,
basePath: config.experimental.basePath, basePath: config.experimental.basePath,
redirects: redirects.map((r) => buildCustomRoute(r, 'redirect')), redirects: redirects.map((r) => buildCustomRoute(r, 'redirect')),
...@@ -302,8 +302,8 @@ export default async function build(dir: string, conf = null): Promise<void> { ...@@ -302,8 +302,8 @@ export default async function build(dir: string, conf = null): Promise<void> {
return { return {
page, page,
regex: routeRegex.re.source, regex: routeRegex.re.source,
routeKeys: routeRegex.routeKeys,
namedRegex: routeRegex.namedRegex, namedRegex: routeRegex.namedRegex,
routeKeys: Object.keys(routeRegex.groups),
} }
}), }),
} }
...@@ -615,8 +615,8 @@ export default async function build(dir: string, conf = null): Promise<void> { ...@@ -615,8 +615,8 @@ export default async function build(dir: string, conf = null): Promise<void> {
) )
let dataRouteRegex: string let dataRouteRegex: string
let routeKeys: string[] | undefined
let namedDataRouteRegex: string | undefined let namedDataRouteRegex: string | undefined
let routeKeys: { [named: string]: string } | undefined
if (isDynamicRoute(page)) { if (isDynamicRoute(page)) {
const routeRegex = getRouteRegex(dataRoute.replace(/\.json$/, '')) const routeRegex = getRouteRegex(dataRoute.replace(/\.json$/, ''))
...@@ -629,7 +629,7 @@ export default async function build(dir: string, conf = null): Promise<void> { ...@@ -629,7 +629,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
/\(\?:\/\)\?\$$/, /\(\?:\/\)\?\$$/,
'\\.json$' '\\.json$'
) )
routeKeys = Object.keys(routeRegex.groups) routeKeys = routeRegex.routeKeys
} else { } else {
dataRouteRegex = new RegExp( dataRouteRegex = new RegExp(
`^${path.posix.join( `^${path.posix.join(
......
...@@ -9,6 +9,7 @@ export function getRouteRegex( ...@@ -9,6 +9,7 @@ export function getRouteRegex(
): { ): {
re: RegExp re: RegExp
namedRegex?: string namedRegex?: string
routeKeys?: { [named: string]: string }
groups: { groups: {
[groupName: string]: { pos: number; repeat: boolean; optional: boolean } [groupName: string]: { pos: number; repeat: boolean; optional: boolean }
} }
...@@ -47,6 +48,8 @@ export function getRouteRegex( ...@@ -47,6 +48,8 @@ export function getRouteRegex(
// dead code eliminate for browser since it's only needed // dead code eliminate for browser since it's only needed
// while generating routes-manifest // while generating routes-manifest
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
const routeKeys: { [named: string]: string } = {}
namedParameterizedRoute = escapedRoute.replace( namedParameterizedRoute = escapedRoute.replace(
/\/\\\[([^/]+?)\\\](?=\/|$)/g, /\/\\\[([^/]+?)\\\](?=\/|$)/g,
(_, $1) => { (_, $1) => {
...@@ -56,18 +59,28 @@ export function getRouteRegex( ...@@ -56,18 +59,28 @@ export function getRouteRegex(
.replace(/\\([|\\{}()[\]^$+*?.-])/g, '$1') .replace(/\\([|\\{}()[\]^$+*?.-])/g, '$1')
.replace(/^\.{3}/, '') .replace(/^\.{3}/, '')
// replace any non-word characters since they can break
// the named regex
const cleanedKey = key.replace(/\W/g, '')
routeKeys[cleanedKey] = key
return isCatchAll return isCatchAll
? `/(?<${escapeRegex(key)}>.+?)` ? `/(?<${cleanedKey}>.+?)`
: `/(?<${escapeRegex(key)}>[^/]+?)` : `/(?<${cleanedKey}>[^/]+?)`
} }
) )
return {
re: new RegExp('^' + parameterizedRoute + '(?:/)?$', 'i'),
groups,
routeKeys,
namedRegex: `^${namedParameterizedRoute}(?:/)?$`,
}
} }
return { return {
re: new RegExp('^' + parameterizedRoute + '(?:/)?$', 'i'), re: new RegExp('^' + parameterizedRoute + '(?:/)?$', 'i'),
groups, groups,
namedRegex: namedParameterizedRoute
? `^${namedParameterizedRoute}(?:/)?$`
: undefined,
} }
} }
...@@ -127,11 +127,19 @@ class UrlNode { ...@@ -127,11 +127,19 @@ class UrlNode {
} }
} }
if (slugNames.indexOf(nextSlug) !== -1) { slugNames.forEach((slug) => {
throw new Error( if (slug === nextSlug) {
`You cannot have the same slug name "${nextSlug}" repeat within a single dynamic path` throw new Error(
) `You cannot have the same slug name "${nextSlug}" repeat within a single dynamic path`
} )
}
if (slug.replace(/\W/g, '') === nextSegment.replace(/\W/g, '')) {
throw new Error(
`You cannot have the slug names "${slug}" and "${nextSlug}" differ only by non-word symbols within a single dynamic path`
)
}
})
slugNames.push(nextSlug) slugNames.push(nextSlug)
} }
......
...@@ -491,7 +491,7 @@ const runTests = (isDev = false) => { ...@@ -491,7 +491,7 @@ const runTests = (isDev = false) => {
} }
expect(manifest).toEqual({ expect(manifest).toEqual({
version: 1, version: 3,
pages404: true, pages404: true,
basePath: '', basePath: '',
redirects: [ redirects: [
...@@ -872,19 +872,25 @@ const runTests = (isDev = false) => { ...@@ -872,19 +872,25 @@ const runTests = (isDev = false) => {
namedRegex: '^/another/(?<id>[^/]+?)(?:/)?$', namedRegex: '^/another/(?<id>[^/]+?)(?:/)?$',
page: '/another/[id]', page: '/another/[id]',
regex: normalizeRegEx('^\\/another\\/([^\\/]+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/another\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: ['id'], routeKeys: {
id: 'id',
},
}, },
{ {
namedRegex: '^/api/dynamic/(?<slug>[^/]+?)(?:/)?$', namedRegex: '^/api/dynamic/(?<slug>[^/]+?)(?:/)?$',
page: '/api/dynamic/[slug]', page: '/api/dynamic/[slug]',
regex: normalizeRegEx('^\\/api\\/dynamic\\/([^\\/]+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/api\\/dynamic\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: ['slug'], routeKeys: {
slug: 'slug',
},
}, },
{ {
namedRegex: '^/blog/(?<post>[^/]+?)(?:/)?$', namedRegex: '^/blog/(?<post>[^/]+?)(?:/)?$',
page: '/blog/[post]', page: '/blog/[post]',
regex: normalizeRegEx('^\\/blog\\/([^\\/]+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/blog\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: ['post'], routeKeys: {
post: 'post',
},
}, },
], ],
}) })
......
...@@ -515,14 +515,22 @@ function runTests(dev) { ...@@ -515,14 +515,22 @@ function runTests(dev) {
for (const route of manifest.dynamicRoutes) { for (const route of manifest.dynamicRoutes) {
route.regex = normalizeRegEx(route.regex) route.regex = normalizeRegEx(route.regex)
// ensure regexes are valid
new RegExp(route.regex)
new RegExp(route.namedRegex)
} }
for (const route of manifest.dataRoutes) { for (const route of manifest.dataRoutes) {
route.dataRouteRegex = normalizeRegEx(route.dataRouteRegex) route.dataRouteRegex = normalizeRegEx(route.dataRouteRegex)
// ensure regexes are valid
new RegExp(route.dataRouteRegex)
new RegExp(route.namedDataRouteRegex)
} }
expect(manifest).toEqual({ expect(manifest).toEqual({
version: 1, version: 3,
pages404: true, pages404: true,
basePath: '', basePath: '',
headers: [], headers: [],
...@@ -539,7 +547,9 @@ function runTests(dev) { ...@@ -539,7 +547,9 @@ function runTests(dev) {
)}\\/p1\\/p2\\/all\\-ssg\\/(.+?)\\.json$` )}\\/p1\\/p2\\/all\\-ssg\\/(.+?)\\.json$`
), ),
page: '/p1/p2/all-ssg/[...rest]', page: '/p1/p2/all-ssg/[...rest]',
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -551,7 +561,9 @@ function runTests(dev) { ...@@ -551,7 +561,9 @@ function runTests(dev) {
)}\\/p1\\/p2\\/nested\\-all\\-ssg\\/(.+?)\\.json$` )}\\/p1\\/p2\\/nested\\-all\\-ssg\\/(.+?)\\.json$`
), ),
page: '/p1/p2/nested-all-ssg/[...rest]', page: '/p1/p2/nested-all-ssg/[...rest]',
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -563,7 +575,9 @@ function runTests(dev) { ...@@ -563,7 +575,9 @@ function runTests(dev) {
)}\\/p1\\/p2\\/predefined\\-ssg\\/(.+?)\\.json$` )}\\/p1\\/p2\\/predefined\\-ssg\\/(.+?)\\.json$`
), ),
page: '/p1/p2/predefined-ssg/[...rest]', page: '/p1/p2/predefined-ssg/[...rest]',
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
], ],
dynamicRoutes: [ dynamicRoutes: [
...@@ -573,25 +587,50 @@ function runTests(dev) { ...@@ -573,25 +587,50 @@ function runTests(dev) {
regex: normalizeRegEx( regex: normalizeRegEx(
'^\\/blog\\/([^\\/]+?)\\/comment\\/([^\\/]+?)(?:\\/)?$' '^\\/blog\\/([^\\/]+?)\\/comment\\/([^\\/]+?)(?:\\/)?$'
), ),
routeKeys: ['name', 'id'], routeKeys: {
name: 'name',
id: 'id',
},
},
{
namedRegex: '^/catchall\\-dash/(?<helloworld>.+?)(?:/)?$',
page: '/catchall-dash/[...hello-world]',
regex: normalizeRegEx('^\\/catchall\\-dash\\/(.+?)(?:\\/)?$'),
routeKeys: {
helloworld: 'hello-world',
},
},
{
namedRegex: '^/dash/(?<helloworld>[^/]+?)(?:/)?$',
page: '/dash/[hello-world]',
regex: normalizeRegEx('^\\/dash\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: {
helloworld: 'hello-world',
},
}, },
{ {
namedRegex: `^/on\\-mount/(?<post>[^/]+?)(?:/)?$`, namedRegex: `^/on\\-mount/(?<post>[^/]+?)(?:/)?$`,
page: '/on-mount/[post]', page: '/on-mount/[post]',
regex: normalizeRegEx('^\\/on\\-mount\\/([^\\/]+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/on\\-mount\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: ['post'], routeKeys: {
post: 'post',
},
}, },
{ {
namedRegex: `^/p1/p2/all\\-ssg/(?<rest>.+?)(?:/)?$`, namedRegex: `^/p1/p2/all\\-ssg/(?<rest>.+?)(?:/)?$`,
page: '/p1/p2/all-ssg/[...rest]', page: '/p1/p2/all-ssg/[...rest]',
regex: normalizeRegEx('^\\/p1\\/p2\\/all\\-ssg\\/(.+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/p1\\/p2\\/all\\-ssg\\/(.+?)(?:\\/)?$'),
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
{ {
namedRegex: `^/p1/p2/all\\-ssr/(?<rest>.+?)(?:/)?$`, namedRegex: `^/p1/p2/all\\-ssr/(?<rest>.+?)(?:/)?$`,
page: '/p1/p2/all-ssr/[...rest]', page: '/p1/p2/all-ssr/[...rest]',
regex: normalizeRegEx('^\\/p1\\/p2\\/all\\-ssr\\/(.+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/p1\\/p2\\/all\\-ssr\\/(.+?)(?:\\/)?$'),
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
{ {
namedRegex: `^/p1/p2/nested\\-all\\-ssg/(?<rest>.+?)(?:/)?$`, namedRegex: `^/p1/p2/nested\\-all\\-ssg/(?<rest>.+?)(?:/)?$`,
...@@ -599,7 +638,9 @@ function runTests(dev) { ...@@ -599,7 +638,9 @@ function runTests(dev) {
regex: normalizeRegEx( regex: normalizeRegEx(
'^\\/p1\\/p2\\/nested\\-all\\-ssg\\/(.+?)(?:\\/)?$' '^\\/p1\\/p2\\/nested\\-all\\-ssg\\/(.+?)(?:\\/)?$'
), ),
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
{ {
namedRegex: `^/p1/p2/predefined\\-ssg/(?<rest>.+?)(?:/)?$`, namedRegex: `^/p1/p2/predefined\\-ssg/(?<rest>.+?)(?:/)?$`,
...@@ -607,19 +648,25 @@ function runTests(dev) { ...@@ -607,19 +648,25 @@ function runTests(dev) {
regex: normalizeRegEx( regex: normalizeRegEx(
'^\\/p1\\/p2\\/predefined\\-ssg\\/(.+?)(?:\\/)?$' '^\\/p1\\/p2\\/predefined\\-ssg\\/(.+?)(?:\\/)?$'
), ),
routeKeys: ['rest'], routeKeys: {
rest: 'rest',
},
}, },
{ {
namedRegex: `^/(?<name>[^/]+?)(?:/)?$`, namedRegex: `^/(?<name>[^/]+?)(?:/)?$`,
page: '/[name]', page: '/[name]',
regex: normalizeRegEx('^\\/([^\\/]+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: ['name'], routeKeys: {
name: 'name',
},
}, },
{ {
namedRegex: `^/(?<name>[^/]+?)/comments(?:/)?$`, namedRegex: `^/(?<name>[^/]+?)/comments(?:/)?$`,
page: '/[name]/comments', page: '/[name]/comments',
regex: normalizeRegEx('^\\/([^\\/]+?)\\/comments(?:\\/)?$'), regex: normalizeRegEx('^\\/([^\\/]+?)\\/comments(?:\\/)?$'),
routeKeys: ['name'], routeKeys: {
name: 'name',
},
}, },
{ {
namedRegex: `^/(?<name>[^/]+?)/on\\-mount\\-redir(?:/)?$`, namedRegex: `^/(?<name>[^/]+?)/on\\-mount\\-redir(?:/)?$`,
...@@ -627,13 +674,18 @@ function runTests(dev) { ...@@ -627,13 +674,18 @@ function runTests(dev) {
regex: normalizeRegEx( regex: normalizeRegEx(
'^\\/([^\\/]+?)\\/on\\-mount\\-redir(?:\\/)?$' '^\\/([^\\/]+?)\\/on\\-mount\\-redir(?:\\/)?$'
), ),
routeKeys: ['name'], routeKeys: {
name: 'name',
},
}, },
{ {
namedRegex: `^/(?<name>[^/]+?)/(?<comment>[^/]+?)(?:/)?$`, namedRegex: `^/(?<name>[^/]+?)/(?<comment>[^/]+?)(?:/)?$`,
page: '/[name]/[comment]', page: '/[name]/[comment]',
regex: normalizeRegEx('^\\/([^\\/]+?)\\/([^\\/]+?)(?:\\/)?$'), regex: normalizeRegEx('^\\/([^\\/]+?)\\/([^\\/]+?)(?:\\/)?$'),
routeKeys: ['name', 'comment'], routeKeys: {
name: 'name',
comment: 'comment',
},
}, },
], ],
}) })
......
...@@ -55,7 +55,9 @@ const expectedManifestRoutes = () => [ ...@@ -55,7 +55,9 @@ const expectedManifestRoutes = () => [
`^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog\\/([^\\/]+?)\\.json$` `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/blog\\/([^\\/]+?)\\.json$`
), ),
page: '/blog/[post]', page: '/blog/[post]',
routeKeys: ['post'], routeKeys: {
post: 'post',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -67,7 +69,10 @@ const expectedManifestRoutes = () => [ ...@@ -67,7 +69,10 @@ const expectedManifestRoutes = () => [
)}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$` )}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$`
), ),
page: '/blog/[post]/[comment]', page: '/blog/[post]/[comment]',
routeKeys: ['post', 'comment'], routeKeys: {
post: 'post',
comment: 'comment',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -77,7 +82,9 @@ const expectedManifestRoutes = () => [ ...@@ -77,7 +82,9 @@ const expectedManifestRoutes = () => [
`^\\/_next\\/data\\/${escapeRegex(buildId)}\\/catchall\\/(.+?)\\.json$` `^\\/_next\\/data\\/${escapeRegex(buildId)}\\/catchall\\/(.+?)\\.json$`
), ),
page: '/catchall/[...path]', page: '/catchall/[...path]',
routeKeys: ['path'], routeKeys: {
path: 'path',
},
}, },
{ {
dataRouteRegex: normalizeRegEx( dataRouteRegex: normalizeRegEx(
...@@ -131,7 +138,9 @@ const expectedManifestRoutes = () => [ ...@@ -131,7 +138,9 @@ const expectedManifestRoutes = () => [
)}\\/user\\/([^\\/]+?)\\/profile\\.json$` )}\\/user\\/([^\\/]+?)\\/profile\\.json$`
), ),
page: '/user/[user]/profile', page: '/user/[user]/profile',
routeKeys: ['user'], routeKeys: {
user: 'user',
},
}, },
] ]
......
...@@ -860,7 +860,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -860,7 +860,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/blog\\/([^\\/]+?)\\.json$` )}\\/blog\\/([^\\/]+?)\\.json$`
), ),
page: '/blog/[post]', page: '/blog/[post]',
routeKeys: ['post'], routeKeys: {
post: 'post',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -872,7 +874,10 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -872,7 +874,10 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$` )}\\/blog\\/([^\\/]+?)\\/([^\\/]+?)\\.json$`
), ),
page: '/blog/[post]/[comment]', page: '/blog/[post]/[comment]',
routeKeys: ['post', 'comment'], routeKeys: {
post: 'post',
comment: 'comment',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -884,7 +889,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -884,7 +889,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/catchall\\/(.+?)\\.json$` )}\\/catchall\\/(.+?)\\.json$`
), ),
page: '/catchall/[...slug]', page: '/catchall/[...slug]',
routeKeys: ['slug'], routeKeys: {
slug: 'slug',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -896,7 +903,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -896,7 +903,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/catchall\\-explicit\\/(.+?)\\.json$` )}\\/catchall\\-explicit\\/(.+?)\\.json$`
), ),
page: '/catchall-explicit/[...slug]', page: '/catchall-explicit/[...slug]',
routeKeys: ['slug'], routeKeys: {
slug: 'slug',
},
}, },
{ {
dataRouteRegex: normalizeRegEx( dataRouteRegex: normalizeRegEx(
...@@ -916,7 +925,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -916,7 +925,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
buildId buildId
)}/fallback\\-only/(?<slug>[^/]+?)\\.json$`, )}/fallback\\-only/(?<slug>[^/]+?)\\.json$`,
page: '/fallback-only/[slug]', page: '/fallback-only/[slug]',
routeKeys: ['slug'], routeKeys: {
slug: 'slug',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -928,7 +939,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -928,7 +939,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/lang\\/([^\\/]+?)\\/about\\.json$` )}\\/lang\\/([^\\/]+?)\\/about\\.json$`
), ),
page: '/lang/[lang]/about', page: '/lang/[lang]/about',
routeKeys: ['lang'], routeKeys: {
lang: 'lang',
},
}, },
{ {
namedDataRouteRegex: `^/_next/data/${escapeRegex( namedDataRouteRegex: `^/_next/data/${escapeRegex(
...@@ -940,7 +953,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -940,7 +953,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/non\\-json\\/([^\\/]+?)\\.json$` )}\\/non\\-json\\/([^\\/]+?)\\.json$`
), ),
page: '/non-json/[p]', page: '/non-json/[p]',
routeKeys: ['p'], routeKeys: {
p: 'p',
},
}, },
{ {
dataRouteRegex: normalizeRegEx( dataRouteRegex: normalizeRegEx(
...@@ -958,7 +973,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => { ...@@ -958,7 +973,9 @@ const runTests = (dev = false, isEmulatedServerless = false) => {
)}\\/user\\/([^\\/]+?)\\/profile\\.json$` )}\\/user\\/([^\\/]+?)\\/profile\\.json$`
), ),
page: '/user/[user]/profile', page: '/user/[user]/profile',
routeKeys: ['user'], routeKeys: {
user: 'user',
},
}, },
]) ])
}) })
......
...@@ -204,4 +204,13 @@ describe('getSortedRoutes', () => { ...@@ -204,4 +204,13 @@ describe('getSortedRoutes', () => {
`"You cannot define a route with the same specificity as a optional catch-all route (\\"/sub\\" and \\"/sub[[...all]]\\")."` `"You cannot define a route with the same specificity as a optional catch-all route (\\"/sub\\" and \\"/sub[[...all]]\\")."`
) )
}) })
it('catches param names differing only by non-word characters', () => {
expect(() =>
getSortedRoutes([
'/blog/[helloworld]',
'/blog/[helloworld]/[hello-world]',
])
).toThrowError(/differ only by non-word/)
})
}) })
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册