Repository navigation
fix(@angular/ssr): resolve parameters in redirect targets #34321
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -152,12 +152,19 @@ export function stripIndexHtmlFromURL(url: URL): URL { | |||||||||||||||||||||||
| return url; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Matches a `*<n>` placeholder that makes up a whole path segment, which may be followed by | ||||||||||||||||||||||||
| * the query or fragment of the URL. | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| const POSITIONAL_PLACEHOLDER_REGEXP = /^\*(\d+)(?=[?#]|$)/; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Resolves `*` placeholders in a path template by mapping them to corresponding segments | ||||||||||||||||||||||||
| * from a base path. This is useful for constructing paths dynamically based on a given base path. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * The function processes the `toPath` string, replacing each `*` placeholder with | ||||||||||||||||||||||||
| * the corresponding segment from the `fromPath`. If the `toPath` contains no placeholders, | ||||||||||||||||||||||||
| * the corresponding segment from the `fromPath`, and each `*<n>` placeholder with the | ||||||||||||||||||||||||
| * segment at position `n` of the `fromPath`. If the `toPath` contains no placeholders, | ||||||||||||||||||||||||
| * it is returned as-is. Invalid `toPath` formats (not starting with `/`) will throw an error. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * @param toPath - A path template string that may contain `*` placeholders. Each `*` is replaced | ||||||||||||||||||||||||
|
|
@@ -176,6 +183,10 @@ export function stripIndexHtmlFromURL(url: URL): URL { | |||||||||||||||||||||||
| * const resolvedPath = buildPathWithParams('/*\/details', '/123/abc'); | ||||||||||||||||||||||||
| * console.log(resolvedPath); // Outputs: '/123/details' | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * // Example with a positional placeholder | ||||||||||||||||||||||||
| * const positionalPath = buildPathWithParams('/user/*1', '/123/abc'); | ||||||||||||||||||||||||
| * console.log(positionalPath); // Outputs: '/user/123' | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * // Example with a static path | ||||||||||||||||||||||||
| * const staticPath = buildPathWithParams('/static/path', '/base/unused'); | ||||||||||||||||||||||||
| * console.log(staticPath); // Outputs: '/static/path' | ||||||||||||||||||||||||
|
|
@@ -197,12 +208,51 @@ export function buildPathWithParams(toPath: string, fromPath: string): string { | |||||||||||||||||||||||
| const fromPathParts = fromPath.split('/'); | ||||||||||||||||||||||||
| const toPathParts = toPath.split('/'); | ||||||||||||||||||||||||
| const resolvedParts = toPathParts.map((part, index) => | ||||||||||||||||||||||||
| toPathParts[index] === '*' ? fromPathParts[index] : part, | ||||||||||||||||||||||||
| part === '*' | ||||||||||||||||||||||||
| ? fromPathParts[index] | ||||||||||||||||||||||||
| : part.replace(POSITIONAL_PLACEHOLDER_REGEXP, (_, position) => fromPathParts[position]), | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
Comment on lines
210
to
214
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not reachable: each |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return joinUrlParts(...resolvedParts); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
| * Resolves `:name` placeholders in the query of a URL, like the Angular router does for redirects. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * Each query parameter whose value is a `:name` placeholder gets the values of the `name` | ||||||||||||||||||||||||
| * query parameter of `fromParams`, and is removed if `fromParams` has no such parameter. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * @param toUrl - A URL whose query may contain `:name` placeholders. | ||||||||||||||||||||||||
| * @param fromParams - The query parameters that provide the values for the placeholders. | ||||||||||||||||||||||||
| * @returns The URL with its query placeholders resolved. | ||||||||||||||||||||||||
| * | ||||||||||||||||||||||||
| * @example | ||||||||||||||||||||||||
| * ```typescript | ||||||||||||||||||||||||
| * buildQueryWithParams('/search?q=:term', new URLSearchParams('term=cats')); // returns '/search?q=cats' | ||||||||||||||||||||||||
| * ``` | ||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||
| export function buildQueryWithParams(toUrl: string, fromParams: URLSearchParams): string { | ||||||||||||||||||||||||
| const [, path, query, fragment] = /^([^?#]*)\?([^#]*)(.*)$/.exec(toUrl) ?? []; | ||||||||||||||||||||||||
| if (query === undefined || !query.includes('=:')) { | ||||||||||||||||||||||||
| return toUrl; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const resolvedParams = new URLSearchParams(); | ||||||||||||||||||||||||
| for (const [name, value] of new URLSearchParams(query)) { | ||||||||||||||||||||||||
| if (value[0] === ':') { | ||||||||||||||||||||||||
| for (const sourceValue of fromParams.getAll(value.slice(1))) { | ||||||||||||||||||||||||
|
alan-agius4 marked this conversation as resolved.
|
||||||||||||||||||||||||
| resolvedParams.append(name, sourceValue); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||
| resolvedParams.append(name, value); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const resolvedQuery = resolvedParams.toString(); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return path + (resolvedQuery ? `?${resolvedQuery}` : '') + fragment; | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| const MATRIX_PARAMS_REGEX = /;[^/]+/g; | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.