Skip to content

Commit

Permalink
breaking: remove resolvePath (#11265)
Browse files Browse the repository at this point in the history
closes #10282

---------

Co-authored-by: Rich Harris <[email protected]>
Co-authored-by: Simon Holthausen <[email protected]>
  • Loading branch information
3 people authored Dec 12, 2023
1 parent 63ad25a commit 6f6fa38
Show file tree
Hide file tree
Showing 12 changed files with 474 additions and 426 deletions.
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

0 comments on commit 6f6fa38

Please sign in to comment.