diff --git a/.changeset/loud-peaches-enjoy.md b/.changeset/loud-peaches-enjoy.md new file mode 100644 index 000000000000..9da39ac14878 --- /dev/null +++ b/.changeset/loud-peaches-enjoy.md @@ -0,0 +1,6 @@ +--- +'create-svelte': patch +'@sveltejs/kit': patch +--- + +[feat] add App.PageData type diff --git a/packages/create-svelte/templates/default/src/app.d.ts b/packages/create-svelte/templates/default/src/app.d.ts index d22f2a7de403..a4416cababbe 100644 --- a/packages/create-svelte/templates/default/src/app.d.ts +++ b/packages/create-svelte/templates/default/src/app.d.ts @@ -6,6 +6,8 @@ declare namespace App { userid: string; } + // interface PageData {} + // interface Platform {} // interface PrivateEnv {} diff --git a/packages/create-svelte/templates/libskeleton/src/app.d.ts b/packages/create-svelte/templates/libskeleton/src/app.d.ts index 66327cbb1af3..637dfc2d0f8b 100644 --- a/packages/create-svelte/templates/libskeleton/src/app.d.ts +++ b/packages/create-svelte/templates/libskeleton/src/app.d.ts @@ -5,6 +5,7 @@ // and what to do when importing types declare namespace App { // interface Locals {} + // interface PageData {} // interface Platform {} // interface PrivateEnv {} // interface PublicEnv {} diff --git a/packages/create-svelte/templates/skeleton/src/app.d.ts b/packages/create-svelte/templates/skeleton/src/app.d.ts index 4eac1d5c9b82..7ef2c828b181 100644 --- a/packages/create-svelte/templates/skeleton/src/app.d.ts +++ b/packages/create-svelte/templates/skeleton/src/app.d.ts @@ -3,6 +3,7 @@ // and what to do when importing types declare namespace App { // interface Locals {} + // interface PageData {} // interface Platform {} // interface PrivateEnv {} // interface PublicEnv {} diff --git a/packages/kit/src/core/sync/create_manifest_data/index.js b/packages/kit/src/core/sync/create_manifest_data/index.js index 906e0d9cd455..a55c8ceeda28 100644 --- a/packages/kit/src/core/sync/create_manifest_data/index.js +++ b/packages/kit/src/core/sync/create_manifest_data/index.js @@ -180,7 +180,7 @@ function create_routes_and_nodes(cwd, config, fallback) { component: project_relative }; } else if (item.is_layout) { - if (!route.layout) route.layout = { depth }; + if (!route.layout) route.layout = { depth, child_pages: [] }; route.layout.component = project_relative; if (item.uses_layout !== undefined) route.layout.parent_id = item.uses_layout; } else { @@ -189,7 +189,7 @@ function create_routes_and_nodes(cwd, config, fallback) { if (item.uses_layout !== undefined) route.leaf.parent_id = item.uses_layout; } } else if (item.is_layout) { - if (!route.layout) route.layout = { depth }; + if (!route.layout) route.layout = { depth, child_pages: [] }; route.layout[item.kind] = project_relative; } else if (item.is_page) { if (!route.leaf) route.leaf = { depth }; @@ -223,7 +223,7 @@ function create_routes_and_nodes(cwd, config, fallback) { } if (!root.layout?.component) { - if (!root.layout) root.layout = { depth: 0 }; + if (!root.layout) root.layout = { depth: 0, child_pages: [] }; root.layout.component = posixify(path.relative(cwd, `${fallback}/layout.svelte`)); } @@ -290,6 +290,9 @@ function create_routes_and_nodes(cwd, config, fallback) { } if (current_route.layout) { + /** @type {import('types').PageNode[]} */ (current_route.layout.child_pages).push( + route.leaf + ); current_node.parent = current_node = current_route.layout; parent_id = current_node.parent_id; } else { diff --git a/packages/kit/src/core/sync/sync.js b/packages/kit/src/core/sync/sync.js index 4d451066770b..153923d7a3b6 100644 --- a/packages/kit/src/core/sync/sync.js +++ b/packages/kit/src/core/sync/sync.js @@ -4,7 +4,7 @@ import { write_client_manifest } from './write_client_manifest.js'; import { write_matchers } from './write_matchers.js'; import { write_root } from './write_root.js'; import { write_tsconfig } from './write_tsconfig.js'; -import { write_types, write_all_types } from './write_types.js'; +import { write_types, write_all_types } from './write_types/index.js'; import { write_ambient } from './write_ambient.js'; /** diff --git a/packages/kit/src/core/sync/write_types.spec.js b/packages/kit/src/core/sync/write_types.spec.js deleted file mode 100644 index bb56c892cb8c..000000000000 --- a/packages/kit/src/core/sync/write_types.spec.js +++ /dev/null @@ -1,105 +0,0 @@ -import { test } from 'uvu'; -import * as assert from 'uvu/assert'; -import { tweak_types } from './write_types.js'; - -test('Rewrites types for a TypeScript module', () => { - const source = ` - export const GET: Get = ({ params }) => { - return { - a: 1 - }; - }; - `; - - const rewritten = tweak_types(source, new Set(['GET'])); - - assert.equal(rewritten?.exports, ['GET']); - assert.equal( - rewritten?.code, - ` - export const GET = ({ params }: Parameters[0]) => { - return { - a: 1 - }; - }; - ` - ); -}); - -test('Rewrites types for a TypeScript module without param', () => { - const source = ` - export const GET: Get = () => { - return { - a: 1 - }; - }; - `; - - const rewritten = tweak_types(source, new Set(['GET'])); - - assert.equal(rewritten?.exports, ['GET']); - assert.equal( - rewritten?.code, - ` - export const GET = () => { - return { - a: 1 - }; - }; - ` - ); -}); - -test('Rewrites types for a JavaScript module with `function`', () => { - const source = ` - /** @type {import('./$types').Get} */ - export function GET({ params }) { - return { - a: 1 - }; - }; - `; - - const rewritten = tweak_types(source, new Set(['GET'])); - - assert.equal(rewritten?.exports, ['GET']); - assert.equal( - rewritten?.code, - ` - /** @param {Parameters[0]} event */ - export function GET({ params }) { - return { - a: 1 - }; - }; - ` - ); -}); - -test('Rewrites types for a JavaScript module with `const`', () => { - const source = ` - /** @type {import('./$types').Get} */ - export const GET = ({ params }) => { - return { - a: 1 - }; - }; - `; - - const rewritten = tweak_types(source, new Set(['GET'])); - - assert.equal(rewritten?.exports, ['GET']); - assert.equal( - rewritten?.code, - ` - /** @param {Parameters[0]} event */ - export const GET = ({ params }) => { - return { - a: 1 - }; - }; - ` - ); -}); - -test.run(); diff --git a/packages/kit/src/core/sync/write_types.js b/packages/kit/src/core/sync/write_types/index.js similarity index 72% rename from packages/kit/src/core/sync/write_types.js rename to packages/kit/src/core/sync/write_types/index.js index ab1204d3a7fa..a7e5d02e4730 100644 --- a/packages/kit/src/core/sync/write_types.js +++ b/packages/kit/src/core/sync/write_types/index.js @@ -1,8 +1,8 @@ import fs from 'fs'; import path from 'path'; import MagicString from 'magic-string'; -import { posixify, rimraf, walk } from '../../utils/filesystem.js'; -import { compact } from '../../utils/array.js'; +import { posixify, rimraf, walk } from '../../../utils/filesystem.js'; +import { compact } from '../../../utils/array.js'; /** * @typedef {{ @@ -49,9 +49,10 @@ export async function write_all_types(config, manifest_data) { } } + const routes_map = create_routes_map(manifest_data); // For each directory, write $types.d.ts for (const route of manifest_data.routes) { - update_types(config, manifest_data, route); + update_types(config, routes_map, route); } } @@ -76,16 +77,33 @@ export async function write_types(config, manifest_data, file) { const route = manifest_data.routes.find((route) => route.id === id); if (!route) return; // this shouldn't ever happen - update_types(config, manifest_data, route); + update_types(config, create_routes_map(manifest_data), route); } /** - * - * @param {import('types').ValidatedConfig} config + * Collect all leafs into a leaf -> route map * @param {import('types').ManifestData} manifest_data + */ +function create_routes_map(manifest_data) { + /** @type {Map} */ + const map = new Map(); + for (const route of manifest_data.routes) { + if (route.leaf) { + map.set(route.leaf, route); + } + } + return map; +} + +/** + * Update types for a specific route + * @param {import('types').ValidatedConfig} config + * @param {Map} routes * @param {import('types').RouteData} route */ -function update_types(config, manifest_data, route) { +function update_types(config, routes, route) { + if (!route.leaf && !route.layout && !route.endpoint) return; // nothing to do + const routes_dir = posixify(path.relative('.', config.kit.files.routes)); const outdir = path.join(config.kit.outDir, 'types', routes_dir, route.id); @@ -112,8 +130,6 @@ function update_types(config, manifest_data, route) { input_files.push(route.endpoint.file); } - if (!route.leaf && !route.layout && !route.endpoint) return; // nothing to do - try { fs.mkdirSync(outdir, { recursive: true }); } catch {} @@ -138,6 +154,7 @@ function update_types(config, manifest_data, route) { // track which old files end up being surplus to requirements const to_delete = new Set(output_files.map((file) => file.name)); + // now generate new types const imports = [`import type * as Kit from '@sveltejs/kit';`]; /** @type {string[]} */ @@ -155,32 +172,25 @@ function update_types(config, manifest_data, route) { declarations.push(`interface RouteParams extends Partial> {}`); } - if (route.leaf) { - const { data, server_data, load, server_load, errors, written_proxies } = process_node( - route.leaf, - outdir, - 'RouteParams' + if (route.layout || route.leaf) { + // These could also be placed in our public types, but it would bloat them unnecessarily and we may want to change these in the future + declarations.push(`type MaybeWithVoid = {} extends T ? T | void : T;`); + declarations.push( + `export type RequiredKeys = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];` ); + declarations.push( + `type OutputDataShape = MaybeWithVoid> & Partial> & Record>` + ); + declarations.push(`type EnsureParentData = NonNullable extends never ? {} : T;`); + } - for (const file of written_proxies) to_delete.delete(file); - - exports.push(`export type Errors = ${errors};`); + if (route.leaf) { + const { declarations: d, exports: e, written_proxies } = process_node(route.leaf, outdir, true); - exports.push(`export type PageData = ${data};`); - if (load) { - exports.push( - `export type PageLoad | void = Record | void> = ${load};` - ); - exports.push('export type PageLoadEvent = Parameters[0];'); - } + exports.push(...e); + declarations.push(...d); - exports.push(`export type PageServerData = ${server_data};`); - if (server_load) { - exports.push( - `export type PageServerLoad | void = Record | void> = ${server_load};` - ); - exports.push('export type PageServerLoadEvent = Parameters[0];'); - } + for (const file of written_proxies) to_delete.delete(file); if (route.leaf.server) { exports.push(`export type Action = Kit.Action`); @@ -188,15 +198,18 @@ function update_types(config, manifest_data, route) { } if (route.layout) { - // TODO collect children in create_manifest_data, instead of this inefficient O(n^2) algorithm + let all_pages_have_load = true; const layout_params = new Set(); - manifest_data.routes.forEach((other) => { - if (other.page && other.id.startsWith(route.id + '/')) { - // TODO this is O(n^2), see if we need to speed it up - for (const name of other.names) { + route.layout.child_pages?.forEach((page) => { + const leaf = routes.get(page); + if (leaf) { + for (const name of leaf.names) { layout_params.add(name); } } + if (!page.server && !page.shared) { + all_pages_have_load = false; + } }); if (layout_params.size > 0) { @@ -206,29 +219,16 @@ function update_types(config, manifest_data, route) { declarations.push(`interface LayoutParams extends RouteParams {}`); } - const { data, server_data, load, server_load, written_proxies } = process_node( - route.layout, - outdir, - 'LayoutParams' - ); + const { + exports: e, + declarations: d, + written_proxies + } = process_node(route.layout, outdir, false, all_pages_have_load); - for (const file of written_proxies) to_delete.delete(file); - - exports.push(`export type LayoutData = ${data};`); - if (load) { - exports.push( - `export type LayoutLoad | void = Record | void> = ${load};` - ); - exports.push('export type LayoutLoadEvent = Parameters[0];'); - } + exports.push(...e); + declarations.push(...d); - exports.push(`export type LayoutServerData = ${server_data};`); - if (server_load) { - exports.push( - `export type LayoutServerLoad | void = Record | void> = ${server_load};` - ); - exports.push('export type LayoutServerLoadEvent = Parameters[0];'); - } + for (const file of written_proxies) to_delete.delete(file); } if (route.endpoint) { @@ -251,18 +251,24 @@ function update_types(config, manifest_data, route) { /** * @param {import('types').PageNode} node * @param {string} outdir - * @param {string} params + * @param {boolean} is_page + * @param {boolean} [all_pages_have_load] */ -function process_node(node, outdir, params) { - let data; - let load; - let server_load; - let errors; +function process_node(node, outdir, is_page, all_pages_have_load = true) { + const params = `${is_page ? 'Route' : 'Layout'}Params`; + const prefix = is_page ? 'Page' : 'Layout'; /** @type {string[]} */ let written_proxies = []; + /** @type {string[]} */ + const declarations = []; + /** @type {string[]} */ + const exports = []; + /** @type {string} */ let server_data; + /** @type {string} */ + let data; if (node.server) { const content = fs.readFileSync(node.server, 'utf8'); @@ -274,33 +280,52 @@ function process_node(node, outdir, params) { } server_data = get_data_type(node.server, 'null', proxy); - server_load = `Kit.ServerLoad<${params}, ${get_parent_type( - node, - 'LayoutServerData' - )}, OutputData>`; - if (proxy) { - const types = []; - for (const method of ['POST', 'PUT', 'PATCH']) { - if (proxy.exports.includes(method)) { - // If the file wasn't tweaked, we can use the return type of the original file. - // The advantage is that type updates are reflected without saving. - const from = proxy.modified - ? `./proxy${replace_ext_with_js(basename)}` - : path_to_original(outdir, node.server); - - types.push(`Kit.AwaitedErrors`); + const parent_type = `${prefix}ServerParentData`; + + declarations.push( + `type ${parent_type} = EnsureParentData<${get_parent_type(node, 'LayoutServerData')}>;` + ); + + // +page.js load present -> server can return all-optional data + const output_data_shape = + node.shared || (!is_page && all_pages_have_load) + ? `Partial & Record | void` + : `OutputDataShape<${parent_type}>`; + exports.push( + `export type ${prefix}ServerLoad = Kit.ServerLoad<${params}, ${parent_type}, OutputData>;` + ); + + exports.push(`export type ${prefix}ServerLoadEvent = Parameters<${prefix}ServerLoad>[0];`); + + if (is_page) { + let errors = 'unknown'; + if (proxy) { + const types = []; + for (const method of ['POST', 'PUT', 'PATCH', 'DELETE']) { + if (proxy.exports.includes(method)) { + // If the file wasn't tweaked, we can use the return type of the original file. + // The advantage is that type updates are reflected without saving. + const from = proxy.modified + ? `./proxy${replace_ext_with_js(basename)}` + : path_to_original(outdir, node.server); + + types.push(`Kit.AwaitedErrors`); + } } + errors = types.length ? types.join(' | ') : 'null'; } - errors = types.length ? types.join(' | ') : 'null'; - } else { - errors = 'unknown'; + exports.push(`export type Errors = ${errors};`); } } else { server_data = 'null'; } + exports.push(`export type ${prefix}ServerData = ${server_data};`); - const parent_type = get_parent_type(node, 'LayoutData'); + const parent_type = `${prefix}ParentData`; + declarations.push( + `type ${parent_type} = EnsureParentData<${get_parent_type(node, 'LayoutData')}>;` + ); if (node.shared) { const content = fs.readFileSync(node.shared, 'utf8'); @@ -310,17 +335,28 @@ function process_node(node, outdir, params) { written_proxies.push(`proxy${path.basename(node.shared)}`); } - const type = get_data_type(node.shared, `${parent_type} & ${server_data}`, proxy); + const type = get_data_type(node.shared, `${parent_type} & ${prefix}ServerData`, proxy); data = `Omit<${parent_type}, keyof ${type}> & ${type}`; - load = `Kit.Load<${params}, ${server_data}, ${parent_type}, OutputData>`; + + const output_data_shape = + !is_page && all_pages_have_load + ? `Partial & Record | void` + : `OutputDataShape<${parent_type}>`; + exports.push( + `export type ${prefix}Load = Kit.Load<${params}, ${prefix}ServerData, ${parent_type}, OutputData>;` + ); + + exports.push(`export type ${prefix}LoadEvent = Parameters<${prefix}Load>[0];`); } else if (server_data === 'null') { data = parent_type; } else { - data = `Omit<${parent_type}, keyof ${server_data}> & ${server_data}`; + data = `Omit<${parent_type}, keyof ${prefix}ServerData> & ${prefix}ServerData`; } - return { data, server_data, load, server_load, errors, written_proxies }; + exports.push(`export type ${prefix}Data = ${data};`); + + return { declarations, exports, written_proxies }; /** * @param {string} file_path @@ -364,7 +400,7 @@ function get_parent_type(node, type) { parent = parent.parent; } - let parent_str = parent_imports[0] || 'Record'; + let parent_str = parent_imports[0] || '{}'; for (let i = 1; i < parent_imports.length; i++) { // Omit is necessary because a parent could have a property with the same key which would // cause a type conflict. At runtime the child overwrites the parent property in this case, diff --git a/packages/kit/src/core/sync/write_types/index.spec.js b/packages/kit/src/core/sync/write_types/index.spec.js new file mode 100644 index 000000000000..83d4221fb8ca --- /dev/null +++ b/packages/kit/src/core/sync/write_types/index.spec.js @@ -0,0 +1,190 @@ +import path from 'path'; +import fs from 'fs'; +import { format } from 'prettier'; +import { fileURLToPath } from 'url'; +import { test } from 'uvu'; +import * as assert from 'uvu/assert'; +import { rimraf, walk } from '../../../utils/filesystem.js'; +import options from '../../config/options.js'; +import create_manifest_data from '../create_manifest_data/index.js'; +import { tweak_types, write_all_types } from './index.js'; + +const cwd = fileURLToPath(new URL('./test', import.meta.url)); + +/** + * @param {string} dir + * @param {import('types').Config} config + */ +async function run_test(dir, config = {}) { + rimraf(path.join(cwd, dir, '.svelte-kit')); + + const initial = options(config, 'config'); + + initial.kit.files.assets = path.resolve(cwd, 'static'); + initial.kit.files.params = path.resolve(cwd, 'params'); + initial.kit.files.routes = path.resolve(cwd, dir); + initial.kit.outDir = path.resolve(cwd, path.join(dir, '.svelte-kit')); + + const manifest = create_manifest_data({ + config: /** @type {import('types').ValidatedConfig} */ (initial) + }); + await write_all_types(initial, manifest); + + const expected_dir = path.join(cwd, dir, '_expected'); + const expected_files = walk(expected_dir, true); + const actual_dir = path.join( + path.join(cwd, dir, '.svelte-kit', 'types'), + path.relative(process.cwd(), path.join(cwd, dir)) + ); + const actual_files = walk(actual_dir, true); + + assert.equal(actual_files, expected_files); + + for (const file of actual_files) { + const expected_file = path.join(expected_dir, file); + const actual_file = path.join(actual_dir, file); + if (fs.statSync(path.join(actual_dir, file)).isDirectory()) { + assert.ok(fs.statSync(actual_file).isDirectory(), 'Expected a directory'); + continue; + } + + const expected = format(fs.readFileSync(expected_file, 'utf-8'), { + parser: 'typescript' + }); + const actual = format(fs.readFileSync(actual_file, 'utf-8'), { + parser: 'typescript' + }); + const err_msg = `Expected equal file contents for ${file} in ${dir}`; + assert.fixture(actual, expected, err_msg); + } +} + +test('Create $types for page.js', async () => { + await run_test('simple-page-shared-only'); +}); + +test('Create $types for page.server.js', async () => { + await run_test('simple-page-server-only'); +}); + +test('Create $types for page(.server).js', async () => { + await run_test('simple-page-server-and-shared'); +}); + +test('Create $types for layout and page', async () => { + await run_test('layout'); +}); + +test('Create $types for grouped layout and page', async () => { + await run_test('layout-advanced'); +}); + +test('Create $types with params', async () => { + await run_test('slugs'); +}); + +test('Create $types with params and required return types for layout', async () => { + await run_test('slugs-layout-not-all-pages-have-load'); +}); + +test('Rewrites types for a TypeScript module', () => { + const source = ` + export const GET: Get = ({ params }) => { + return { + a: 1 + }; + }; + `; + + const rewritten = tweak_types(source, new Set(['GET'])); + + assert.equal(rewritten?.exports, ['GET']); + assert.equal( + rewritten?.code, + ` + export const GET = ({ params }: Parameters[0]) => { + return { + a: 1 + }; + }; + ` + ); +}); + +test('Rewrites types for a TypeScript module without param', () => { + const source = ` + export const GET: Get = () => { + return { + a: 1 + }; + }; + `; + + const rewritten = tweak_types(source, new Set(['GET'])); + + assert.equal(rewritten?.exports, ['GET']); + assert.equal( + rewritten?.code, + ` + export const GET = () => { + return { + a: 1 + }; + }; + ` + ); +}); + +test('Rewrites types for a JavaScript module with `function`', () => { + const source = ` + /** @type {import('./$types').Get} */ + export function GET({ params }) { + return { + a: 1 + }; + }; + `; + + const rewritten = tweak_types(source, new Set(['GET'])); + + assert.equal(rewritten?.exports, ['GET']); + assert.equal( + rewritten?.code, + ` + /** @param {Parameters[0]} event */ + export function GET({ params }) { + return { + a: 1 + }; + }; + ` + ); +}); + +test('Rewrites types for a JavaScript module with `const`', () => { + const source = ` + /** @type {import('./$types').Get} */ + export const GET = ({ params }) => { + return { + a: 1 + }; + }; + `; + + const rewritten = tweak_types(source, new Set(['GET'])); + + assert.equal(rewritten?.exports, ['GET']); + assert.equal( + rewritten?.code, + ` + /** @param {Parameters[0]} event */ + export const GET = ({ params }) => { + return { + a: 1 + }; + }; + ` + ); +}); + +test.run(); diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+layout.server.js b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+layout.server.js new file mode 100644 index 000000000000..c5ebe18b75ea --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+layout.server.js @@ -0,0 +1,5 @@ +export function load() { + return { + main: 'main' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+layout.svelte b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+layout.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+page.js b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+page.js new file mode 100644 index 000000000000..8be13fff391b --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+page.js @@ -0,0 +1,5 @@ +export function load() { + return { + page: 'page' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+page@.svelte b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/+page@.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.js b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.js new file mode 100644 index 000000000000..f798381b7b93 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.js @@ -0,0 +1,5 @@ +export function load() { + return { + sub: 'sub' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.svelte b/packages/kit/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/+layout.js b/packages/kit/src/core/sync/write_types/test/layout-advanced/+layout.js new file mode 100644 index 000000000000..5bcedfef9288 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/+layout.js @@ -0,0 +1,5 @@ +export function load() { + return { + root: 'root' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/+layout.svelte b/packages/kit/src/core/sync/write_types/test/layout-advanced/+layout.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/$types.d.ts new file mode 100644 index 000000000000..3e110d4caa45 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/$types.d.ts @@ -0,0 +1,32 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +interface LayoutParams extends RouteParams {} +type LayoutParentData = EnsureParentData<{}>; + +export type LayoutServerData = null; +export type LayoutLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.Load; +export type LayoutLoadEvent = Parameters[0]; +export type LayoutData = Omit< + LayoutParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/(main)/$types.d.ts b/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/(main)/$types.d.ts new file mode 100644 index 000000000000..e44ab634f04e --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/(main)/$types.d.ts @@ -0,0 +1,42 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData; +interface LayoutParams extends RouteParams {} +type LayoutServerParentData = EnsureParentData; +type LayoutParentData = EnsureParentData; + +export type PageServerData = null; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; +export type LayoutServerLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.ServerLoad; +export type LayoutServerLoadEvent = Parameters[0]; +export type LayoutServerData = Kit.AwaitedProperties< + Awaited> +>; +export type LayoutData = Omit & LayoutServerData; diff --git a/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/(main)/sub/$types.d.ts b/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/(main)/sub/$types.d.ts new file mode 100644 index 000000000000..23b239b052d8 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout-advanced/_expected/(main)/sub/$types.d.ts @@ -0,0 +1,32 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData< + Omit & + import('../$types.js').LayoutData +>; + +export type PageServerData = null; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/layout/+layout.js b/packages/kit/src/core/sync/write_types/test/layout/+layout.js new file mode 100644 index 000000000000..3b51904671c5 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout/+layout.js @@ -0,0 +1,5 @@ +export function load() { + return { + shared: 'shared' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout/+layout.server.js b/packages/kit/src/core/sync/write_types/test/layout/+layout.server.js new file mode 100644 index 000000000000..2d7f37001f6a --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout/+layout.server.js @@ -0,0 +1,5 @@ +export function load() { + return { + server: 'server' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout/+layout.svelte b/packages/kit/src/core/sync/write_types/test/layout/+layout.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/layout/+page.js b/packages/kit/src/core/sync/write_types/test/layout/+page.js new file mode 100644 index 000000000000..2abb61fe6db1 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout/+page.js @@ -0,0 +1,5 @@ +export function load() { + return { + pageShared: 'pageShared' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout/+page.server.js b/packages/kit/src/core/sync/write_types/test/layout/+page.server.js new file mode 100644 index 000000000000..e1f9d0ae50d4 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout/+page.server.js @@ -0,0 +1,5 @@ +export function load() { + return { + pageServer: 'pageServer' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/layout/+page.svelte b/packages/kit/src/core/sync/write_types/test/layout/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/layout/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/layout/_expected/$types.d.ts new file mode 100644 index 000000000000..bcbfa0032ea4 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/layout/_expected/$types.d.ts @@ -0,0 +1,67 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageServerParentData = EnsureParentData; +type PageParentData = EnsureParentData; +interface LayoutParams extends RouteParams {} +type LayoutServerParentData = EnsureParentData<{}>; +type LayoutParentData = EnsureParentData<{}>; + +export type PageServerLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.ServerLoad; +export type PageServerLoadEvent = Parameters[0]; +export type Errors = null; +export type PageServerData = Kit.AwaitedProperties< + Awaited> +>; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; +export type Action = Kit.Action; +export type LayoutServerLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.ServerLoad; +export type LayoutServerLoadEvent = Parameters[0]; +export type LayoutServerData = Kit.AwaitedProperties< + Awaited> +>; +export type LayoutLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.Load; +export type LayoutLoadEvent = Parameters[0]; +export type LayoutData = Omit< + LayoutParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.js b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.js new file mode 100644 index 000000000000..3b51904671c5 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.js @@ -0,0 +1,5 @@ +export function load() { + return { + shared: 'shared' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.server.js b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.server.js new file mode 100644 index 000000000000..2d7f37001f6a --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.server.js @@ -0,0 +1,5 @@ +export function load() { + return { + server: 'server' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.svelte b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/_expected/$types.d.ts new file mode 100644 index 000000000000..0352df17aa2e --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-server-and-shared/_expected/$types.d.ts @@ -0,0 +1,44 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageServerParentData = EnsureParentData; +type PageParentData = EnsureParentData; +interface LayoutParams extends RouteParams {} +type LayoutParentData = EnsureParentData<{}>; + +export type PageServerLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.ServerLoad; +export type PageServerLoadEvent = Parameters[0]; +export type Errors = null; +export type PageServerData = Kit.AwaitedProperties< + Awaited> +>; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; +export type Action = Kit.Action; +export type LayoutServerData = null; +export type LayoutData = LayoutParentData; diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-only/+page.server.js b/packages/kit/src/core/sync/write_types/test/simple-page-server-only/+page.server.js new file mode 100644 index 000000000000..d8d7765c6e25 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-server-only/+page.server.js @@ -0,0 +1,5 @@ +export function load() { + return { + foo: 'bar' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-only/+page.svelte b/packages/kit/src/core/sync/write_types/test/simple-page-server-only/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-server-only/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/simple-page-server-only/_expected/$types.d.ts new file mode 100644 index 000000000000..b3b6e0532d8f --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-server-only/_expected/$types.d.ts @@ -0,0 +1,30 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageServerParentData = EnsureParentData; +type PageParentData = EnsureParentData; +interface LayoutParams extends RouteParams {} +type LayoutParentData = EnsureParentData<{}>; + +export type PageServerLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.ServerLoad; +export type PageServerLoadEvent = Parameters[0]; +export type Errors = null; +export type PageServerData = Kit.AwaitedProperties< + Awaited> +>; +export type PageData = Omit & PageServerData; +export type Action = Kit.Action; +export type LayoutServerData = null; +export type LayoutData = LayoutParentData; diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/+page.js b/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/+page.js new file mode 100644 index 000000000000..3b51904671c5 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/+page.js @@ -0,0 +1,5 @@ +export function load() { + return { + shared: 'shared' + }; +} diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/+page.svelte b/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/_expected/$types.d.ts new file mode 100644 index 000000000000..87acd240845e --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/simple-page-shared-only/_expected/$types.d.ts @@ -0,0 +1,33 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData; +interface LayoutParams extends RouteParams {} +type LayoutParentData = EnsureParentData<{}>; + +export type PageServerData = null; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; +export type LayoutServerData = null; +export type LayoutData = LayoutParentData; diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.js b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.js new file mode 100644 index 000000000000..23addb029828 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.js @@ -0,0 +1 @@ +export function load() {} diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.svelte b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.svelte new file mode 100644 index 000000000000..23addb029828 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.svelte @@ -0,0 +1 @@ +export function load() {} diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/$types.d.ts new file mode 100644 index 000000000000..6e86e3b4257d --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/$types.d.ts @@ -0,0 +1,33 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +interface LayoutParams extends RouteParams { + rest?: string; + slug?: string; +} +type LayoutParentData = EnsureParentData<{}>; + +export type LayoutServerData = null; +export type LayoutLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type LayoutLoadEvent = Parameters[0]; +export type LayoutData = Omit< + LayoutParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/$types.d.ts new file mode 100644 index 000000000000..ee7c0aa4125d --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/$types.d.ts @@ -0,0 +1,34 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +interface LayoutParams extends RouteParams { + rest?: string; +} +type LayoutParentData = EnsureParentData; + +export type LayoutServerData = null; +export type LayoutLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.Load; +export type LayoutLoadEvent = Parameters[0]; +export type LayoutData = Omit< + LayoutParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[...rest]/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[...rest]/$types.d.ts new file mode 100644 index 000000000000..65dcc3f0d4cc --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[...rest]/$types.d.ts @@ -0,0 +1,38 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> { + rest: string; +} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData< + Omit & + import('../$types.js').LayoutData +>; + +export type PageServerData = null; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited< + ReturnType + > + > +> & + Kit.AwaitedProperties< + Awaited< + ReturnType + > + >; diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[slug]/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[slug]/$types.d.ts new file mode 100644 index 000000000000..1d74940b8505 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[slug]/$types.d.ts @@ -0,0 +1,19 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> { + slug: string; +} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData; + +export type PageServerData = null; +export type PageData = PageParentData; diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.js b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.js new file mode 100644 index 000000000000..23addb029828 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.js @@ -0,0 +1 @@ +export function load() {} diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.svelte b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.svelte new file mode 100644 index 000000000000..23addb029828 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.svelte @@ -0,0 +1 @@ +export function load() {} diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.js b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.js new file mode 100644 index 000000000000..45fa74a24858 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.js @@ -0,0 +1,3 @@ +export function load() { + return { rest: 'rest' }; +} diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.svelte b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[slug]/+page@.svelte b/packages/kit/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[slug]/+page@.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/slugs/+layout.js b/packages/kit/src/core/sync/write_types/test/slugs/+layout.js new file mode 100644 index 000000000000..23addb029828 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/+layout.js @@ -0,0 +1 @@ +export function load() {} diff --git a/packages/kit/src/core/sync/write_types/test/slugs/+layout.svelte b/packages/kit/src/core/sync/write_types/test/slugs/+layout.svelte new file mode 100644 index 000000000000..23addb029828 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/+layout.svelte @@ -0,0 +1 @@ +export function load() {} diff --git a/packages/kit/src/core/sync/write_types/test/slugs/[...rest]/+page.js b/packages/kit/src/core/sync/write_types/test/slugs/[...rest]/+page.js new file mode 100644 index 000000000000..45fa74a24858 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/[...rest]/+page.js @@ -0,0 +1,3 @@ +export function load() { + return { rest: 'rest' }; +} diff --git a/packages/kit/src/core/sync/write_types/test/slugs/[...rest]/+page.svelte b/packages/kit/src/core/sync/write_types/test/slugs/[...rest]/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/slugs/[slug]/+page.js b/packages/kit/src/core/sync/write_types/test/slugs/[slug]/+page.js new file mode 100644 index 000000000000..8e5a438b5c9f --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/[slug]/+page.js @@ -0,0 +1,3 @@ +export function load() { + return { slug: 'slug' }; +} diff --git a/packages/kit/src/core/sync/write_types/test/slugs/[slug]/+page.svelte b/packages/kit/src/core/sync/write_types/test/slugs/[slug]/+page.svelte new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/kit/src/core/sync/write_types/test/slugs/_expected/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs/_expected/$types.d.ts new file mode 100644 index 000000000000..d9e4f80790dc --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/_expected/$types.d.ts @@ -0,0 +1,35 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> {} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +interface LayoutParams extends RouteParams { + rest?: string; + slug?: string; +} +type LayoutParentData = EnsureParentData<{}>; + +export type LayoutServerData = null; +export type LayoutLoad< + OutputData extends (Partial & Record) | void = + | (Partial & Record) + | void +> = Kit.Load; +export type LayoutLoadEvent = Parameters[0]; +export type LayoutData = Omit< + LayoutParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/slugs/_expected/[...rest]/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs/_expected/[...rest]/$types.d.ts new file mode 100644 index 000000000000..2ef369b909ce --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/_expected/[...rest]/$types.d.ts @@ -0,0 +1,31 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> { + rest: string; +} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData; + +export type PageServerData = null; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/src/core/sync/write_types/test/slugs/_expected/[slug]/$types.d.ts b/packages/kit/src/core/sync/write_types/test/slugs/_expected/[slug]/$types.d.ts new file mode 100644 index 000000000000..8d649e793a04 --- /dev/null +++ b/packages/kit/src/core/sync/write_types/test/slugs/_expected/[slug]/$types.d.ts @@ -0,0 +1,31 @@ +import type * as Kit from '@sveltejs/kit'; + +interface RouteParams extends Partial> { + slug: string; +} +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { + [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; +}[keyof T]; +type OutputDataShape = MaybeWithVoid< + Omit> & + Partial> & + Record +>; +type EnsureParentData = NonNullable extends never ? {} : T; +type PageParentData = EnsureParentData; + +export type PageServerData = null; +export type PageLoad< + OutputData extends OutputDataShape = OutputDataShape +> = Kit.Load; +export type PageLoadEvent = Parameters[0]; +export type PageData = Omit< + PageParentData, + keyof Kit.AwaitedProperties< + Awaited> + > +> & + Kit.AwaitedProperties< + Awaited> + >; diff --git a/packages/kit/tsconfig.json b/packages/kit/tsconfig.json index 0f0c4abeb6d7..75005513a5b9 100644 --- a/packages/kit/tsconfig.json +++ b/packages/kit/tsconfig.json @@ -16,5 +16,6 @@ "noUnusedLocals": true, "noUnusedParameters": true }, - "include": ["scripts/**/*", "src/**/*", "types/**/*"] + "include": ["scripts/**/*", "src/**/*", "types/**/*"], + "exclude": ["./**/write_types/test/*/_expected/**"] } diff --git a/packages/kit/types/ambient.d.ts b/packages/kit/types/ambient.d.ts index f0a9efcef93a..f80e5e375fab 100644 --- a/packages/kit/types/ambient.d.ts +++ b/packages/kit/types/ambient.d.ts @@ -7,6 +7,8 @@ * declare namespace App { * interface Locals {} * + * interface PageData {} + * * interface Platform {} * * interface PrivateEnv {} @@ -47,6 +49,13 @@ declare namespace App { */ export interface Locals {} + /** + * Defines the common shape of the [$page.data store](https://kit.svelte.dev/docs/modules#$app-stores-page) - that is, the data that is shared between all pages. + * The `Load` and `ServerLoad` functions in `./$types` will be narrowed accordingly. + * Use optional properties for data that is only present on specific pages. Do not add an index signature (`[key: string]: any`). + */ + export interface PageData {} + /** * If your adapter provides [platform-specific context](https://kit.svelte.dev/docs/adapters#supported-environments-platform-specific-context) via `event.platform`, you can specify it here. */ diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 260cdfc00350..36f4b1be10e8 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -228,7 +228,7 @@ export interface Page = Record; + data: App.PageData & Record; } export interface ParamMatcher { diff --git a/packages/kit/types/internal.d.ts b/packages/kit/types/internal.d.ts index 5e8376edbbce..932220f00679 100644 --- a/packages/kit/types/internal.d.ts +++ b/packages/kit/types/internal.d.ts @@ -122,6 +122,10 @@ export interface PageNode { server?: string; parent_id?: string; parent?: PageNode; + /** + * Filled with the pages that reference this layout (if this is a layout) + */ + child_pages?: PageNode[]; } export type PayloadScriptAttributes =