Repository: withastro/astro
File: packages/astro/src/core/app/index.ts (TypeScript)

Code before:
					}
				} catch (e: any) {
					this.#logger.error(
						'router',
						`Astro tried to parse ${protocol}//${host} as an URL, but it threw a parsing error. Check the X-Forwarded-Host and X-Forwarded-Proto headers.`,
					);
					this.#logger.error('router', `Error: ${e}`);
				}
			}
		}
		return pathname;
	}

	#redirectTrailingSlash(pathname: string): string | undefined {
		const { trailingSlash } = this.#manifest;

		// Ignore root and internal paths
		if (pathname === '/' || pathname.startsWith('/_')) {
			return;
		}

		// Redirect multiple trailing slashes to collapsed path
		if (MANY_SLASHES.test(pathname)) {
			const path = pathname.replace(MANY_SLASHES, trailingSlash === 'never' ? '' : '/');
			return path ? path : '/';
		}

		if (trailingSlash === 'ignore') {
			return;
		}

		// Add a trailing slash if it's not a file
		const hasTrailingSlash = pathname.endsWith('/');
		if (trailingSlash === 'always' && !hasTrailingSlash && !hasFileExtension(pathname)) {
			return `${pathname}/`;
		}
		if (trailingSlash === 'never' && hasTrailingSlash) {
			return pathname.slice(0, -1);
		}
	}

	async render(request: Request, renderOptions?: RenderOptions): Promise<Response> {
		let routeData: RouteData | undefined;
		let locals: object | undefined;
		let clientAddress: string | undefined;
		let addCookieHeader: boolean | undefined;

		const url = new URL(request.url);
		const redirect = this.#redirectTrailingSlash(url.pathname);

		if (redirect) {

Review comment (refactor):
This function should be moved inside `internal-helpers` (the `MANY_SLASHES` constant, too) since it's been used in multiple places 

Code after:
				} catch (e: any) {
					this.#logger.error(
						'router',
						`Astro tried to parse ${protocol}//${host} as an URL, but it threw a parsing error. Check the X-Forwarded-Host and X-Forwarded-Proto headers.`,
					);
					this.#logger.error('router', `Error: ${e}`);
				}
			}
		}
		return pathname;
	}

	#redirectTrailingSlash(pathname: string): string {
		const { trailingSlash } = this.#manifest;

		// Ignore root and internal paths
		if (pathname === '/' || pathname.startsWith('/_')) {
			return pathname;
		}

		// Redirect multiple trailing slashes to collapsed path
		const path = collapseDuplicateTrailingSlashes(pathname, trailingSlash !== 'never');
		if (path !== pathname) {
			return path;
		}

		if (trailingSlash === 'ignore') {
			return pathname;
		}

		if (trailingSlash === 'always' && !hasFileExtension(pathname)) {
			return appendForwardSlash(pathname);
		}
		if (trailingSlash === 'never') {
			return removeTrailingForwardSlash(pathname);
		}

		return pathname;
	}

	async render(request: Request, renderOptions?: RenderOptions): Promise<Response> {
		let routeData: RouteData | undefined;
		let locals: object | undefined;
		let clientAddress: string | undefined;
		let addCookieHeader: boolean | undefined;
		const url = new URL(request.url);
		const redirect = this.#redirectTrailingSlash(url.pathname);

		if (redirect !== url.pathname) {
			const status = request.method === 'GET' ? 301 : 308;
			return new Response(redirectTemplate({ status, location: redirect, from: request.url }), {