Skip to content

breaking: remove resolvePath #11265

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

Merged
merged 8 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eighty-scissors-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': major
---

breaking: remove `resolvePath` in favour of `resolveRoute` from `$app/paths`
17 changes: 17 additions & 0 deletions documentation/docs/60-appendix/30-migrating-to-sveltekit-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,23 @@ This inconsistency is fixed in version 2. Paths are either always relative or al

Previously it was possible to track URLs from `fetch`es on the server in order to rerun load functions. This poses a possible security risk (private URLs leaking), and as such it was behind the `dangerZone.trackServerFetches` setting, which is now removed.

## `resolvePath` has been removed

SvelteKit 1 included a function called `resolvePath` which allows you to resolve a route ID (like `/blog/[slug]`) and a set of parameters (like `{ slug: 'hello' }`) to a pathname. Unfortunately the return value didn't include the `base` path, limiting its usefulness in cases where `base` was set.

As such, SvelteKit 2 replaces `resolvePath` with a (slightly better named) function called `resolveRoute`, which is imported from `$app/paths` and which takes `base` into account.

```diff
-import { resolvePath } from '@sveltejs/kit';
-import { base } from '$app/paths';
+import { resolveRoute } from '$app/paths';

-const path = base + resolvePath('/blog/[slug]', { slug });
+const path = resolveRoute('/blog/[slug]', { slug });
```

`svelte-migrate` will do the method replacement for you, though if you later prepend the result with `base`, you need to remove that yourself.

## Updated dependency requirements

SvelteKit requires Node `18.13` or higher, Vite `^5.0`, vite-plugin-svelte `^3.0`, TypeScript `^5.0` and Svelte version 4 or higher. `svelte-migrate` will do the `package.json` bumps for you.
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/src/core/postbuild/analyse.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {
import { load_config } from '../config/index.js';
import { forked } from '../../utils/fork.js';
import { installPolyfills } from '../../exports/node/polyfills.js';
import { resolvePath } from '../../exports/index.js';
import { ENDPOINT_METHODS } from '../../constants.js';
import { filter_private_env, filter_public_env } from '../../utils/env.js';
import { resolve_route } from '../../utils/routing.js';

export default forked(import.meta.url, analyse);

Expand Down Expand Up @@ -101,7 +101,7 @@ async function analyse({ manifest_path, env }) {
},
prerender: page?.prerender ?? endpoint?.prerender,
entries:
entries && (await entries()).map((entry_object) => resolvePath(route.id, entry_object))
entries && (await entries()).map((entry_object) => resolve_route(route.id, entry_object))
});
}

Expand Down
56 changes: 0 additions & 56 deletions packages/kit/src/exports/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { HttpError, Redirect, ActionFailure } from '../runtime/control.js';
import { BROWSER, DEV } from 'esm-env';
import { get_route_segments } from '../utils/routing.js';

export { VERSION } from '../version.js';

Expand Down Expand Up @@ -183,58 +182,3 @@ export function fail(status, data) {
// @ts-expect-error unique symbol missing
return new ActionFailure(status, data);
}

const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;

let warned = false;

/**
* @deprecated Use `resolveRoute` from `$app/paths` instead.
*
* Populate a route ID with params to resolve a pathname.
* @example
* ```js
* resolvePath(
* `/blog/[slug]/[...somethingElse]`,
* {
* slug: 'hello-world',
* somethingElse: 'something/else'
* }
* ); // `/blog/hello-world/something/else`
* ```
* @param {string} id
* @param {Record<string, string | undefined>} params
* @returns {string}
*/
export function resolvePath(id, params) {
if (!warned) {
console.warn('`resolvePath` is deprecated. Use `resolveRoute` from `$app/paths` instead.');
warned = true;
}

const segments = get_route_segments(id);
return (
'/' +
segments
.map((segment) =>
segment.replace(basic_param_pattern, (_, optional, rest, name) => {
const param_value = params[name];

// This is nested so TS correctly narrows the type
if (!param_value) {
if (optional) return '';
if (rest && param_value !== undefined) return '';
throw new Error(`Missing parameter '${name}' in route ${id}`);
}

if (param_value.startsWith('/') || param_value.endsWith('/'))
throw new Error(
`Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
);
return param_value;
})
)
.filter(Boolean)
.join('/')
);
}
59 changes: 0 additions & 59 deletions packages/kit/src/exports/index.spec.js

This file was deleted.

31 changes: 2 additions & 29 deletions packages/kit/src/runtime/app/paths.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
export { base, assets } from '__sveltekit/paths';
import { base } from '__sveltekit/paths';
import { get_route_segments } from '../../utils/routing.js';

const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
import { resolve_route } from '../../utils/routing.js';

/**
* Populate a route ID with params to resolve a pathname.
Expand All @@ -21,30 +19,5 @@ const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
* @returns {string}
*/
export function resolveRoute(id, params) {
const segments = get_route_segments(id);
return (
base +
'/' +
segments
.map((segment) =>
segment.replace(basic_param_pattern, (_, optional, rest, name) => {
const param_value = params[name];

// This is nested so TS correctly narrows the type
if (!param_value) {
if (optional) return '';
if (rest && param_value !== undefined) return '';
throw new Error(`Missing parameter '${name}' in route ${id}`);
}

if (param_value.startsWith('/') || param_value.endsWith('/'))
throw new Error(
`Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
);
return param_value;
})
)
.filter(Boolean)
.join('/')
);
return base + resolve_route(id, params);
}
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/server/page/actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as devalue from 'devalue';
import { json } from '../../../exports/index.js';
import { error, json } from '../../../exports/index.js';
import { normalize_error } from '../../../utils/error.js';
import { is_form_content_type, negotiate } from '../../../utils/http.js';
import { HttpError, Redirect, ActionFailure } from '../../control.js';
Expand Down
46 changes: 46 additions & 0 deletions packages/kit/src/utils/routing.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,49 @@ function escape(str) {
.replace(/[.*+?^${}()|\\]/g, '\\$&')
);
}

const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;

/**
* Populate a route ID with params to resolve a pathname.
* @example
* ```js
* resolveRoute(
* `/blog/[slug]/[...somethingElse]`,
* {
* slug: 'hello-world',
* somethingElse: 'something/else'
* }
* ); // `/blog/hello-world/something/else`
* ```
* @param {string} id
* @param {Record<string, string | undefined>} params
* @returns {string}
*/
export function resolve_route(id, params) {
const segments = get_route_segments(id);
return (
'/' +
segments
.map((segment) =>
segment.replace(basic_param_pattern, (_, optional, rest, name) => {
const param_value = params[name];

// This is nested so TS correctly narrows the type
if (!param_value) {
if (optional) return '';
if (rest && param_value !== undefined) return '';
throw new Error(`Missing parameter '${name}' in route ${id}`);
}

if (param_value.startsWith('/') || param_value.endsWith('/'))
throw new Error(
`Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
);
return param_value;
})
)
.filter(Boolean)
.join('/')
);
}
Loading