diff --git a/.changeset/proud-rules-bow.md b/.changeset/proud-rules-bow.md new file mode 100644 index 000000000000..19b710b2784c --- /dev/null +++ b/.changeset/proud-rules-bow.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: better type-safety for `page.route.id`, `page.params`, page.url.pathname` and various other places diff --git a/.changeset/slow-weeks-wave.md b/.changeset/slow-weeks-wave.md new file mode 100644 index 000000000000..91be7b1af779 --- /dev/null +++ b/.changeset/slow-weeks-wave.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: `resolve(...)` and `asset(...)` helpers for resolving paths diff --git a/.changeset/wicked-bananas-yawn.md b/.changeset/wicked-bananas-yawn.md new file mode 100644 index 000000000000..a74d96b71ea8 --- /dev/null +++ b/.changeset/wicked-bananas-yawn.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': minor +--- + +feat: Add `$app/types` module with `Asset`, `RouteId`, `Pathname`, `ResolvedPathname` `RouteParams` and `LayoutParams` diff --git a/documentation/docs/98-reference/20-$app-types.md b/documentation/docs/98-reference/20-$app-types.md new file mode 100644 index 000000000000..96f1dcaaa94f --- /dev/null +++ b/documentation/docs/98-reference/20-$app-types.md @@ -0,0 +1,82 @@ +--- +title: $app/types +--- + +This module contains generated types for the routes in your app. + +```js +// @noErrors +import type { RouteId, RouteParams, LayoutParams } from '$app/types'; +``` + +## Asset + +A union of all the filenames of assets contained in your `static` directory. + +
+ +```dts +type Asset = '/favicon.png' | '/robots.txt'; +``` + +
+ +## RouteId + +A union of all the route IDs in your app. Used for `page.route.id` and `event.route.id`. + +
+ +```dts +type RouteId = '/' | '/my-route' | '/my-other-route/[param]'; +``` + +
+ +## Pathname + +A union of all valid pathnames in your app. + +
+ +```dts +type Pathname = '/' | '/my-route' | `/my-other-route/${string}` & {}; +``` + +
+ +## ResolvedPathname + +`Pathname`, but possibly prefixed with a [base path](https://svelte.dev/docs/kit/configuration#paths). Used for `page.url.pathname`. + +
+ +```dts +type Pathname = `${'' | `/${string}`}/` | `${'' | `/${string}`}/my-route` | `${'' | `/${string}`}/my-other-route/${string} | {}`; +``` + +
+ +## RouteParams + +A utility for getting the parameters associated with a given route. + +
+ +```dts +type RouteParams = { /* generated */ } | Record; +``` + +
+ +## LayoutParams + +A utility for getting the parameters associated with a given layout, which is similar to `RouteParams` but also includes optional parameters for any child route. + +
+ +```dts +type RouteParams = { /* generated */ } | Record; +``` + +
diff --git a/packages/adapter-auto/tsconfig.json b/packages/adapter-auto/tsconfig.json index c1f396b255ce..99b99d00b826 100644 --- a/packages/adapter-auto/tsconfig.json +++ b/packages/adapter-auto/tsconfig.json @@ -7,7 +7,8 @@ "target": "es2022", "module": "node16", "moduleResolution": "node16", - "baseUrl": "." + "baseUrl": ".", + "skipLibCheck": true }, "include": ["**/*.js"] } diff --git a/packages/adapter-node/tsconfig.json b/packages/adapter-node/tsconfig.json index 895d76f908cf..e550f4e7748e 100644 --- a/packages/adapter-node/tsconfig.json +++ b/packages/adapter-node/tsconfig.json @@ -11,7 +11,8 @@ "baseUrl": ".", "paths": { "@sveltejs/kit": ["../kit/types/index"] - } + }, + "skipLibCheck": true }, "include": ["index.js", "src/**/*.js", "tests/**/*.js", "internal.d.ts", "utils.js"], "exclude": ["tests/smoke.spec_disabled.js"] diff --git a/packages/adapter-static/tsconfig.json b/packages/adapter-static/tsconfig.json index dafbce422a39..9360c09e0730 100644 --- a/packages/adapter-static/tsconfig.json +++ b/packages/adapter-static/tsconfig.json @@ -11,7 +11,8 @@ "baseUrl": ".", "paths": { "@sveltejs/kit": ["../kit/types/index"] - } + }, + "skipLibCheck": true }, "include": ["index.js", "test/utils.js"] } diff --git a/packages/adapter-vercel/tsconfig.json b/packages/adapter-vercel/tsconfig.json index 3d157ebc29e5..e832e33d4024 100644 --- a/packages/adapter-vercel/tsconfig.json +++ b/packages/adapter-vercel/tsconfig.json @@ -12,6 +12,7 @@ "baseUrl": ".", "paths": { "@sveltejs/kit": ["../kit/types/index"] - } + }, + "skipLibCheck": true } } diff --git a/packages/kit/scripts/generate-dts.js b/packages/kit/scripts/generate-dts.js index e8579ec59054..1af5db6ae96b 100644 --- a/packages/kit/scripts/generate-dts.js +++ b/packages/kit/scripts/generate-dts.js @@ -1,5 +1,5 @@ import { createBundle } from 'dts-buddy'; -import { readFileSync } from 'node:fs'; +import { readFileSync, writeFileSync } from 'node:fs'; await createBundle({ output: 'types/index.d.ts', @@ -28,3 +28,9 @@ if (types.includes('__sveltekit/')) { types ); } + +// this is hacky as all hell but it gets the tests passing. might be a bug in dts-buddy? +// prettier-ignore +writeFileSync('./types/index.d.ts', types.replace("declare module '$app/server' {", `declare module '$app/server' { + // @ts-ignore + import { LayoutParams as AppLayoutParams, RouteId as AppRouteId } from '$app/types'`)); diff --git a/packages/kit/src/core/sync/write_tsconfig.js b/packages/kit/src/core/sync/write_tsconfig.js index e9df340902e1..6bca8214bdb1 100644 --- a/packages/kit/src/core/sync/write_tsconfig.js +++ b/packages/kit/src/core/sync/write_tsconfig.js @@ -98,7 +98,10 @@ export function get_tsconfig(kit) { const config = { compilerOptions: { // generated options - paths: get_tsconfig_paths(kit), + paths: { + ...get_tsconfig_paths(kit), + '$app/types': ['./types/index.d.ts'] + }, rootDirs: [config_relative('.'), './types'], // essential options diff --git a/packages/kit/src/core/sync/write_tsconfig.spec.js b/packages/kit/src/core/sync/write_tsconfig.spec.js index 65a6d09f1499..fbd780d74bdd 100644 --- a/packages/kit/src/core/sync/write_tsconfig.spec.js +++ b/packages/kit/src/core/sync/write_tsconfig.spec.js @@ -20,6 +20,7 @@ test('Creates tsconfig path aliases from kit.alias', () => { // $lib isn't part of the outcome because there's a "path exists" // check in the implementation expect(compilerOptions.paths).toEqual({ + '$app/types': ['./types/index.d.ts'], simpleKey: ['../simple/value'], 'simpleKey/*': ['../simple/value/*'], key: ['../value'], diff --git a/packages/kit/src/core/sync/write_types/index.js b/packages/kit/src/core/sync/write_types/index.js index 308d566606f8..fdba231e2b0a 100644 --- a/packages/kit/src/core/sync/write_types/index.js +++ b/packages/kit/src/core/sync/write_types/index.js @@ -5,6 +5,15 @@ import MagicString from 'magic-string'; import { posixify, rimraf, walk } from '../../../utils/filesystem.js'; import { compact } from '../../../utils/array.js'; import { ts } from '../ts.js'; +import { s } from '../../../utils/misc.js'; + +const remove_relative_parent_traversals = (/** @type {string} */ path) => + path.replace(/\.\.\//g, ''); +const replace_optional_params = (/** @type {string} */ id) => + id.replace(/\/\[\[[^\]]+\]\]/g, '${string}'); +const replace_required_params = (/** @type {string} */ id) => + id.replace(/\/\[[^\]]+\]/g, '/${string}'); +const is_whitespace = (/** @type {string} */ char) => /\s/.test(char); /** * @typedef {{ @@ -35,7 +44,9 @@ export function write_all_types(config, manifest_data) { const types_dir = `${config.kit.outDir}/types`; // empty out files that no longer need to exist - const routes_dir = posixify(path.relative('.', config.kit.files.routes)).replace(/\.\.\//g, ''); + const routes_dir = remove_relative_parent_traversals( + posixify(path.relative('.', config.kit.files.routes)) + ); const expected_directories = new Set( manifest_data.routes.map((route) => path.join(routes_dir, route.id)) ); @@ -49,6 +60,65 @@ export function write_all_types(config, manifest_data) { } } + /** @type {string[]} */ + const pathnames = []; + + /** @type {string[]} */ + const dynamic_routes = []; + + /** @type {string[]} */ + const layouts = []; + + for (const route of manifest_data.routes) { + if (route.params.length > 0) { + const params = route.params.map((p) => `${p.name}${p.optional ? '?:' : ':'} string`); + const route_type = `${s(route.id)}: { ${params.join('; ')} }`; + + dynamic_routes.push(route_type); + + pathnames.push(`\`${replace_required_params(replace_optional_params(route.id))}\` & {}`); + } else { + pathnames.push(s(route.id)); + } + + /** @type {Map} */ + const child_params = new Map(route.params.map((p) => [p.name, p.optional])); + + for (const child of manifest_data.routes.filter((r) => r.id.startsWith(route.id))) { + for (const p of child.params) { + if (!child_params.has(p.name)) { + child_params.set(p.name, true); // always optional + } + } + } + + const layout_params = Array.from(child_params) + .map(([name, optional]) => `${name}${optional ? '?:' : ':'} string`) + .join('; '); + + const layout_type = `${s(route.id)}: ${layout_params.length > 0 ? `{ ${layout_params} }` : 'undefined'}`; + layouts.push(layout_type); + } + + try { + fs.mkdirSync(types_dir, { recursive: true }); + } catch {} + + fs.writeFileSync( + `${types_dir}/index.d.ts`, + [ + `type DynamicRoutes = {\n\t${dynamic_routes.join(';\n\t')}\n};`, + `type Layouts = {\n\t${layouts.join(';\n\t')}\n};`, + // we enumerate these rather than doing `keyof Routes` so that the list is visible on hover + `export type RouteId = ${manifest_data.routes.map((r) => s(r.id)).join(' | ')};`, + 'export type RouteParams = T extends keyof DynamicRoutes ? DynamicRoutes[T] : Record;', + 'export type LayoutParams = Layouts[T] | Record;', + `export type Pathname = ${pathnames.join(' | ')};`, + 'export type ResolvedPathname = `${"" | `/${string}`}${Pathname}`;', + `export type Asset = ${manifest_data.assets.map((asset) => s('/' + asset.file)).join(' | ') || 'never'};` + ].join('\n\n') + ); + // Read/write meta data on each invocation, not once per node process, // it could be invoked by another process in the meantime. const meta_data_file = `${types_dir}/route_meta_data.json`; @@ -174,7 +244,9 @@ function create_routes_map(manifest_data) { * @param {Set} [to_delete] */ function update_types(config, routes, route, to_delete = new Set()) { - const routes_dir = posixify(path.relative('.', config.kit.files.routes)).replace(/\.\.\//g, ''); + const routes_dir = remove_relative_parent_traversals( + posixify(path.relative('.', config.kit.files.routes)) + ); const outdir = path.join(config.kit.outDir, 'types', routes_dir, route.id); // now generate new types @@ -731,7 +803,7 @@ export function tweak_types(content, is_server) { if (declaration.type) { let a = declaration.type.pos; const b = declaration.type.end; - while (/\s/.test(content[a])) a += 1; + while (is_whitespace(content[a])) a += 1; const type = content.slice(a, b); code.remove(declaration.name.end, declaration.type.end); @@ -803,7 +875,7 @@ export function tweak_types(content, is_server) { if (declaration.type) { let a = declaration.type.pos; const b = declaration.type.end; - while (/\s/.test(content[a])) a += 1; + while (is_whitespace(content[a])) a += 1; const type = content.slice(a, b); code.remove(declaration.name.end, declaration.type.end); diff --git a/packages/kit/src/core/sync/write_types/index.spec.js b/packages/kit/src/core/sync/write_types/index.spec.js index 210922514089..82af21f9d3f4 100644 --- a/packages/kit/src/core/sync/write_types/index.spec.js +++ b/packages/kit/src/core/sync/write_types/index.spec.js @@ -1,4 +1,5 @@ import { execSync } from 'node:child_process'; +import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { assert, expect, test } from 'vitest'; @@ -33,15 +34,14 @@ test('Creates correct $types', { timeout: 6000 }, () => { // To save us from creating a real SvelteKit project for each of the tests, // we first run the type generation directly for each test case, and then // call `tsc` to check that the generated types are valid. - run_test('actions'); - run_test('simple-page-shared-only'); - run_test('simple-page-server-only'); - run_test('simple-page-server-and-shared'); - run_test('layout'); - run_test('layout-advanced'); - run_test('slugs'); - run_test('slugs-layout-not-all-pages-have-load'); - run_test('param-type-inference'); + const directories = fs + .readdirSync(cwd) + .filter((dir) => fs.statSync(`${cwd}/${dir}`).isDirectory()); + + for (const dir of directories) { + run_test(dir); + } + try { execSync('pnpm testtypes', { cwd }); } catch (e) { diff --git a/packages/kit/src/core/sync/write_types/test/app-types/+page.ts b/packages/kit/src/core/sync/write_types/test/app-types/+page.ts new file mode 100644 index 000000000000..6da67ea0e75a --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/app-types/+page.ts @@ -0,0 +1,30 @@ +import type { RouteId, RouteParams, Pathname } from './.svelte-kit/types/index.d.ts'; + +declare let id: RouteId; + +// okay +id = '/'; +id = '/foo/[bar]/[baz]'; + +// @ts-expect-error +id = '/nope'; + +// read `id` otherwise it is treated as unused +id; + +declare let params: RouteParams<'/foo/[bar]/[baz]'>; + +// @ts-expect-error +params.foo; // not okay +params.bar; // okay +params.baz; // okay + +declare let pathname: Pathname; + +// @ts-expect-error +pathname = '/nope'; +pathname = '/foo'; +pathname = '/foo/1/2'; + +// read `pathname` otherwise it is treated as unused +pathname; diff --git a/packages/kit/src/core/sync/write_types/test/app-types/foo/[bar]/[baz]/+page.ts b/packages/kit/src/core/sync/write_types/test/app-types/foo/[bar]/[baz]/+page.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/tsconfig.json b/packages/kit/src/core/sync/write_types/test/tsconfig.json index 39ea59584873..9c43f3c10e41 100644 --- a/packages/kit/src/core/sync/write_types/test/tsconfig.json +++ b/packages/kit/src/core/sync/write_types/test/tsconfig.json @@ -14,6 +14,6 @@ "types": ["../../../../types/internal"] } }, - "include": ["./**/*.js"], + "include": ["./**/*.js", "./**/*.ts"], "exclude": ["./**/.svelte-kit/**"] } diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index ec930b7d073a..e4fe96a925c3 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -19,6 +19,12 @@ import { } from '../types/private.js'; import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types'; import type { PluginOptions } from '@sveltejs/vite-plugin-svelte'; +import { + RouteId as AppRouteId, + LayoutParams as AppLayoutParams, + ResolvedPathname + // @ts-ignore +} from '$app/types'; export { PrerenderOption } from '../types/private.js'; @@ -858,11 +864,11 @@ export interface Transporter< * rather than using `Load` directly. */ export type Load< - Params extends Partial> = Partial>, + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, InputData extends Record | null = Record | null, ParentData extends Record = Record, OutputData extends Record | void = Record | void, - RouteId extends string | null = string | null + RouteId extends AppRouteId | null = AppRouteId | null > = (event: LoadEvent) => MaybePromise; /** @@ -870,10 +876,10 @@ export type Load< * rather than using `LoadEvent` directly. */ export interface LoadEvent< - Params extends Partial> = Partial>, + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, Data extends Record | null = Record | null, ParentData extends Record = Record, - RouteId extends string | null = string | null + RouteId extends AppRouteId | null = AppRouteId | null > extends NavigationEvent { /** * `fetch` is equivalent to the [native `fetch` web API](https://developer.mozilla.org/en-US/docs/Web/API/fetch), with a few additional features: @@ -978,8 +984,8 @@ export interface LoadEvent< } export interface NavigationEvent< - Params extends Partial> = Partial>, - RouteId extends string | null = string | null + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, + RouteId extends AppRouteId | null = AppRouteId | null > { /** * The parameters of the current page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object @@ -1118,13 +1124,13 @@ export interface AfterNavigate extends Omit { * The shape of the [`page`](https://svelte.dev/docs/kit/$app-state#page) reactive object and the [`$page`](https://svelte.dev/docs/kit/$app-stores) store. */ export interface Page< - Params extends Record = Record, - RouteId extends string | null = string | null + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, + RouteId extends AppRouteId | null = AppRouteId | null > { /** * The URL of the current page. */ - url: URL; + url: URL & { pathname: ResolvedPathname }; /** * The parameters of the current page - e.g. for a route like `/blog/[slug]`, a `{ slug: string }` object. */ @@ -1166,8 +1172,8 @@ export interface Page< export type ParamMatcher = (param: string) => boolean; export interface RequestEvent< - Params extends Partial> = Partial>, - RouteId extends string | null = string | null + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, + RouteId extends AppRouteId | null = AppRouteId | null > { /** * Get or set cookies related to the current request @@ -1258,8 +1264,8 @@ export interface RequestEvent< * It receives `Params` as the first generic argument, which you can skip by using [generated types](https://svelte.dev/docs/kit/types#Generated-types) instead. */ export type RequestHandler< - Params extends Partial> = Partial>, - RouteId extends string | null = string | null + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, + RouteId extends AppRouteId | null = AppRouteId | null > = (event: RequestEvent) => MaybePromise; export interface ResolveOptions { @@ -1337,16 +1343,16 @@ export interface SSRManifest { * rather than using `ServerLoad` directly. */ export type ServerLoad< - Params extends Partial> = Partial>, + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, ParentData extends Record = Record, OutputData extends Record | void = Record | void, - RouteId extends string | null = string | null + RouteId extends AppRouteId | null = AppRouteId | null > = (event: ServerLoadEvent) => MaybePromise; export interface ServerLoadEvent< - Params extends Partial> = Partial>, + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, ParentData extends Record = Record, - RouteId extends string | null = string | null + RouteId extends AppRouteId | null = AppRouteId | null > extends RequestEvent { /** * `await parent()` returns data from parent `+layout.server.js` `load` functions. @@ -1413,9 +1419,9 @@ export interface ServerLoadEvent< * See [form actions](https://svelte.dev/docs/kit/form-actions) for more information. */ export type Action< - Params extends Partial> = Partial>, + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, OutputData extends Record | void = Record | void, - RouteId extends string | null = string | null + RouteId extends AppRouteId | null = AppRouteId | null > = (event: RequestEvent) => MaybePromise; /** @@ -1423,9 +1429,9 @@ export type Action< * See [form actions](https://svelte.dev/docs/kit/form-actions) for more information. */ export type Actions< - Params extends Partial> = Partial>, + Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>, OutputData extends Record | void = Record | void, - RouteId extends string | null = string | null + RouteId extends AppRouteId | null = AppRouteId | null > = Record>; /** diff --git a/packages/kit/src/runtime/app/paths/index.js b/packages/kit/src/runtime/app/paths/index.js index 5a150fbfaa0f..d9f29bbdc395 100644 --- a/packages/kit/src/runtime/app/paths/index.js +++ b/packages/kit/src/runtime/app/paths/index.js @@ -1,8 +1,14 @@ -export { base, assets } from '__sveltekit/paths'; -import { base } from '__sveltekit/paths'; +import { base, assets } from '__sveltekit/paths'; import { resolve_route } from '../../../utils/routing.js'; -/** @type {import('./types.d.ts').resolveRoute} */ -export function resolveRoute(id, params) { +/** @type {import('./types.d.ts').asset} */ +export function asset(file) { + return (assets || base) + file; +} + +/** @type {import('./types.d.ts').resolve} */ +export function resolve(id, params) { return base + resolve_route(id, params); } + +export { base, assets, resolve as resolveRoute }; diff --git a/packages/kit/src/runtime/app/paths/types.d.ts b/packages/kit/src/runtime/app/paths/types.d.ts index d17c45dd4efd..a7785db7bd66 100644 --- a/packages/kit/src/runtime/app/paths/types.d.ts +++ b/packages/kit/src/runtime/app/paths/types.d.ts @@ -1,7 +1,12 @@ +// @ts-ignore +import { Asset, RouteId, RouteParams, Pathname, ResolvedPathname } from '$app/types'; + /** * A string that matches [`config.kit.paths.base`](https://svelte.dev/docs/kit/configuration#paths). * * Example usage: `Link` + * + * @deprecated Use `resolve(...)` instead */ export let base: '' | `/${string}`; @@ -9,22 +14,57 @@ export let base: '' | `/${string}`; * An absolute path that matches [`config.kit.paths.assets`](https://svelte.dev/docs/kit/configuration#paths). * * > [!NOTE] If a value for `config.kit.paths.assets` is specified, it will be replaced with `'/_svelte_kit_assets'` during `vite dev` or `vite preview`, since the assets don't yet live at their eventual URL. + * + * @deprecated Use `asset(...)` instead */ export let assets: '' | `https://${string}` | `http://${string}` | '/_svelte_kit_assets'; +type ResolveArgs = T extends RouteId + ? RouteParams extends Record + ? [route: T] + : [route: T, params: RouteParams] + : [route: T]; + /** - * Populate a route ID with params to resolve a pathname. + * Resolve a pathname by prefixing it with the base path, if any, or resolve a route ID by populating dynamic segments with parameters. + * + * During server rendering, the base path is relative and depends on the page currently being rendered. + * * @example * ```js - * import { resolveRoute } from '$app/paths'; - * - * resolveRoute( - * `/blog/[slug]/[...somethingElse]`, - * { - * slug: 'hello-world', - * somethingElse: 'something/else' - * } - * ); // `/blog/hello-world/something/else` + * import { resolve } from '$app/paths'; + * + * // using a pathname + * const resolved = resolve(`/blog/hello-world`); + * + * // using a route ID plus parameters + * const resolved = resolve('/blog/[slug]', { + * slug: 'hello-world' + * }); * ``` + * @since 2.22 + */ +export function resolve(...args: ResolveArgs): ResolvedPathname; + +/** + * Resolve the URL of an asset in your `static` directory, by prefixing it with [`config.kit.paths.assets`](https://svelte.dev/docs/kit/configuration#paths) if configured, or otherwise by prefixing it with the base path. + * + * During server rendering, the base path is relative and depends on the page currently being rendered. + * + * @example + * ```svelte + * + * + * a potato + * ``` + */ +export function asset(file: Asset): string; + +/** + * @deprecated Use `resolve(...)` instead */ -export function resolveRoute(id: string, params: Record): string; +export function resolveRoute( + ...args: ResolveArgs +): ResolvedPathname; diff --git a/packages/kit/test/apps/basics/src/routes/+layout.svelte b/packages/kit/test/apps/basics/src/routes/+layout.svelte index 6272671c81ae..969229a5f678 100644 --- a/packages/kit/test/apps/basics/src/routes/+layout.svelte +++ b/packages/kit/test/apps/basics/src/routes/+layout.svelte @@ -1,4 +1,4 @@ - + * + * a potato * ``` */ - export function resolveRoute(id: string, params: Record): string; + export function asset(file: Asset): string; + + /** + * @deprecated Use `resolve(...)` instead + */ + export function resolveRoute( + ...args: ResolveArgs + ): ResolvedPathname; export {}; } declare module '$app/server' { + // @ts-ignore + import { LayoutParams as AppLayoutParams, RouteId as AppRouteId } from '$app/types' import type { RequestEvent } from '@sveltejs/kit'; /** * Read the contents of an imported asset from the filesystem @@ -2422,7 +2463,7 @@ declare module '$app/server' { * In environments without [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage), this must be called synchronously (i.e. not after an `await`). * @since 2.20.0 */ - export function getRequestEvent(): RequestEvent>, string | null>; + export function getRequestEvent(): RequestEvent, any>; export {}; }