This repository has been archived by the owner on May 22, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for custom routes (#1523)
* feat: add support for custom routes * chore: fix tests * refactor: restructure code * refactor: gracefully handle invalid `URLPattern` instances
- Loading branch information
1 parent
13f5034
commit 70de542
Showing
15 changed files
with
305 additions
and
19 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { RUNTIME } from '../runtimes/runtime.js' | ||
|
||
import { FunctionBundlingUserError } from './error.js' | ||
import { ExtendedURLPattern } from './urlpattern.js' | ||
|
||
export type Route = { pattern: string } & ({ literal: string } | { expression: string }) | ||
|
||
// Based on https://developer.mozilla.org/en-US/docs/Web/API/URL_Pattern_API. | ||
const isExpression = (part: string) => | ||
part.includes('*') || part.startsWith(':') || part.includes('{') || part.includes('[') || part.includes('(') | ||
|
||
// Detects whether a path can be represented as a literal or whether it needs | ||
// a regular expression. | ||
const isPathLiteral = (path: string) => { | ||
const parts = path.split('/') | ||
|
||
return parts.every((part) => !isExpression(part)) | ||
} | ||
|
||
export const getRoutesFromPath = (path: unknown, functionName: string): Route[] => { | ||
if (!path) { | ||
return [] | ||
} | ||
|
||
if (typeof path !== 'string') { | ||
throw new FunctionBundlingUserError(`'path' property must be a string, found '${typeof path}'`, { | ||
functionName, | ||
runtime: RUNTIME.JAVASCRIPT, | ||
}) | ||
} | ||
|
||
if (!path.startsWith('/')) { | ||
throw new FunctionBundlingUserError(`'path' property must start with a '/'`, { | ||
functionName, | ||
runtime: RUNTIME.JAVASCRIPT, | ||
}) | ||
} | ||
|
||
if (isPathLiteral(path)) { | ||
return [{ pattern: path, literal: path }] | ||
} | ||
|
||
try { | ||
const pattern = new ExtendedURLPattern({ pathname: path }) | ||
|
||
// Removing the `^` and `$` delimiters because we'll need to modify what's | ||
// between them. | ||
const regex = pattern.regexp.pathname.source.slice(1, -1) | ||
|
||
// Wrapping the expression source with `^` and `$`. Also, adding an optional | ||
// trailing slash, so that a declaration of `path: "/foo"` matches requests | ||
// for both `/foo` and `/foo/`. | ||
const normalizedRegex = `^${regex}\\/?$` | ||
|
||
return [{ pattern: path, expression: normalizedRegex }] | ||
} catch { | ||
throw new FunctionBundlingUserError(`'${path}' is not a valid path according to the URLPattern specification`, { | ||
functionName, | ||
runtime: RUNTIME.JAVASCRIPT, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { URLPattern } from 'urlpattern-polyfill' | ||
|
||
export class ExtendedURLPattern extends URLPattern { | ||
// @ts-expect-error Internal property that the underlying class is using but | ||
// not exposing. | ||
regexp: Record<string, RegExp> | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default async () => | ||
new Response('<h1>Hello world</h1>', { | ||
headers: { | ||
'content-type': 'text/html', | ||
}, | ||
}) | ||
|
||
export const config = { | ||
path: {}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default async () => | ||
new Response('<h1>Hello world</h1>', { | ||
headers: { | ||
'content-type': 'text/html', | ||
}, | ||
}) | ||
|
||
export const config = { | ||
path: '/products', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default async () => | ||
new Response('<h1>Hello world</h1>', { | ||
headers: { | ||
'content-type': 'text/html', | ||
}, | ||
}) | ||
|
||
export const config = { | ||
path: '/products/:id', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default async () => | ||
new Response('<h1>Hello world</h1>', { | ||
headers: { | ||
'content-type': 'text/html', | ||
}, | ||
}) | ||
|
||
export const config = { | ||
path: '/numbers/(\\d+)', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
70de542
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⏱ Benchmark results