@sveltejs/kit 1.0.0-next.42 → 1.0.0-next.422

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +12 -9
  2. package/package.json +95 -63
  3. package/src/cli.js +112 -0
  4. package/src/core/adapt/builder.js +207 -0
  5. package/src/core/adapt/index.js +19 -0
  6. package/src/core/config/index.js +86 -0
  7. package/src/core/config/options.js +482 -0
  8. package/src/core/config/types.d.ts +1 -0
  9. package/src/core/constants.js +5 -0
  10. package/src/core/env.js +91 -0
  11. package/src/core/generate_manifest/index.js +99 -0
  12. package/src/core/prerender/crawl.js +194 -0
  13. package/src/core/prerender/prerender.js +378 -0
  14. package/src/core/prerender/queue.js +80 -0
  15. package/src/core/sync/create_manifest_data/index.js +506 -0
  16. package/src/core/sync/create_manifest_data/types.d.ts +40 -0
  17. package/src/core/sync/sync.js +59 -0
  18. package/src/core/sync/utils.js +44 -0
  19. package/src/core/sync/write_ambient.js +27 -0
  20. package/src/core/sync/write_client_manifest.js +82 -0
  21. package/src/core/sync/write_matchers.js +25 -0
  22. package/src/core/sync/write_root.js +88 -0
  23. package/src/core/sync/write_tsconfig.js +189 -0
  24. package/src/core/sync/write_types.js +769 -0
  25. package/src/core/utils.js +58 -0
  26. package/src/hooks.js +26 -0
  27. package/src/index/index.js +45 -0
  28. package/src/index/private.js +33 -0
  29. package/src/node/index.js +145 -0
  30. package/src/node/polyfills.js +40 -0
  31. package/src/runtime/app/env.js +11 -0
  32. package/src/runtime/app/navigation.js +22 -0
  33. package/src/runtime/app/paths.js +1 -0
  34. package/src/runtime/app/stores.js +91 -0
  35. package/src/runtime/client/ambient.d.ts +17 -0
  36. package/src/runtime/client/client.js +1258 -0
  37. package/src/runtime/client/fetcher.js +60 -0
  38. package/src/runtime/client/parse.js +36 -0
  39. package/src/runtime/client/singletons.js +11 -0
  40. package/src/runtime/client/start.js +46 -0
  41. package/src/runtime/client/types.d.ts +105 -0
  42. package/src/runtime/client/utils.js +113 -0
  43. package/src/runtime/components/error.svelte +16 -0
  44. package/{assets → src/runtime}/components/layout.svelte +0 -0
  45. package/src/runtime/env/dynamic/private.js +1 -0
  46. package/src/runtime/env/dynamic/public.js +1 -0
  47. package/src/runtime/env-private.js +7 -0
  48. package/src/runtime/env-public.js +7 -0
  49. package/src/runtime/env.js +6 -0
  50. package/src/runtime/hash.js +16 -0
  51. package/src/runtime/paths.js +11 -0
  52. package/src/runtime/server/endpoint.js +58 -0
  53. package/src/runtime/server/index.js +448 -0
  54. package/src/runtime/server/page/cookie.js +25 -0
  55. package/src/runtime/server/page/crypto.js +239 -0
  56. package/src/runtime/server/page/csp.js +249 -0
  57. package/src/runtime/server/page/fetch.js +266 -0
  58. package/src/runtime/server/page/index.js +416 -0
  59. package/src/runtime/server/page/load_data.js +127 -0
  60. package/src/runtime/server/page/render.js +359 -0
  61. package/src/runtime/server/page/respond_with_error.js +94 -0
  62. package/src/runtime/server/page/types.d.ts +44 -0
  63. package/src/runtime/server/utils.js +116 -0
  64. package/src/utils/error.js +22 -0
  65. package/src/utils/escape.js +104 -0
  66. package/src/utils/filesystem.js +108 -0
  67. package/src/utils/http.js +55 -0
  68. package/src/utils/misc.js +1 -0
  69. package/src/utils/routing.js +107 -0
  70. package/src/utils/url.js +97 -0
  71. package/src/vite/build/build_server.js +337 -0
  72. package/src/vite/build/build_service_worker.js +90 -0
  73. package/src/vite/build/utils.js +157 -0
  74. package/src/vite/dev/index.js +568 -0
  75. package/src/vite/index.js +566 -0
  76. package/src/vite/preview/index.js +186 -0
  77. package/src/vite/types.d.ts +3 -0
  78. package/src/vite/utils.js +334 -0
  79. package/svelte-kit.js +1 -1
  80. package/types/ambient.d.ts +355 -0
  81. package/types/index.d.ts +342 -0
  82. package/types/internal.d.ts +308 -0
  83. package/types/private.d.ts +209 -0
  84. package/CHANGELOG.md +0 -425
  85. package/assets/components/error.svelte +0 -13
  86. package/assets/runtime/app/env.js +0 -5
  87. package/assets/runtime/app/navigation.js +0 -41
  88. package/assets/runtime/app/paths.js +0 -1
  89. package/assets/runtime/app/stores.js +0 -93
  90. package/assets/runtime/chunks/utils.js +0 -19
  91. package/assets/runtime/internal/singletons.js +0 -23
  92. package/assets/runtime/internal/start.js +0 -770
  93. package/assets/runtime/paths.js +0 -12
  94. package/dist/api.js +0 -28
  95. package/dist/api.js.map +0 -1
  96. package/dist/chunks/index.js +0 -3521
  97. package/dist/chunks/index2.js +0 -587
  98. package/dist/chunks/index3.js +0 -246
  99. package/dist/chunks/index4.js +0 -530
  100. package/dist/chunks/index5.js +0 -761
  101. package/dist/chunks/index6.js +0 -322
  102. package/dist/chunks/standard.js +0 -99
  103. package/dist/chunks/utils.js +0 -83
  104. package/dist/cli.js +0 -546
  105. package/dist/cli.js.map +0 -1
  106. package/dist/create_app.js +0 -592
  107. package/dist/create_app.js.map +0 -1
  108. package/dist/index.js +0 -392
  109. package/dist/index.js.map +0 -1
  110. package/dist/index2.js +0 -3519
  111. package/dist/index2.js.map +0 -1
  112. package/dist/index3.js +0 -320
  113. package/dist/index3.js.map +0 -1
  114. package/dist/index4.js +0 -323
  115. package/dist/index4.js.map +0 -1
  116. package/dist/index5.js +0 -247
  117. package/dist/index5.js.map +0 -1
  118. package/dist/index6.js +0 -761
  119. package/dist/index6.js.map +0 -1
  120. package/dist/renderer.js +0 -2499
  121. package/dist/renderer.js.map +0 -1
  122. package/dist/ssr.js +0 -2581
  123. package/dist/standard.js +0 -100
  124. package/dist/standard.js.map +0 -1
  125. package/dist/utils.js +0 -84
  126. package/dist/utils.js.map +0 -1
@@ -0,0 +1,769 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import MagicString from 'magic-string';
4
+ import { posixify, rimraf } from '../../utils/filesystem.js';
5
+ import { parse_route_id } from '../../utils/routing.js';
6
+ import { remove_from_previous, write_if_changed } from './utils.js';
7
+
8
+ /**
9
+ * @typedef { import('types').PageNode & {
10
+ * parent?: {
11
+ * key: string;
12
+ * name: string;
13
+ * folder_depth_diff: number;
14
+ * }
15
+ * } } Node
16
+ */
17
+
18
+ /**
19
+ * @typedef {{
20
+ * leaf?: Node;
21
+ * default_layout?: Node;
22
+ * named_layouts: Map<string, Node>;
23
+ * endpoint?: string;
24
+ * }} NodeGroup
25
+ */
26
+
27
+ /**
28
+ * @typedef {{
29
+ * modified: boolean;
30
+ * code: string;
31
+ * exports: any[];
32
+ * } | null} Proxy
33
+ */
34
+
35
+ const cwd = process.cwd();
36
+
37
+ const shared_names = new Set(['load']);
38
+ const server_names = new Set(['load', 'POST', 'PUT', 'PATCH', 'DELETE']); // TODO replace with a single `action`
39
+
40
+ let first_run = true;
41
+
42
+ /**
43
+ * Creates types for the whole manifest
44
+ *
45
+ * @param {import('types').ValidatedConfig} config
46
+ * @param {import('types').ManifestData} manifest_data
47
+ */
48
+ export async function write_types(config, manifest_data) {
49
+ /** @type {import('typescript') | undefined} */
50
+ let ts = undefined;
51
+ try {
52
+ ts = (await import('typescript')).default;
53
+ } catch (e) {
54
+ // No TypeScript installed - skip type generation
55
+ return;
56
+ }
57
+
58
+ const types_dir = `${config.kit.outDir}/types`;
59
+
60
+ if (first_run) {
61
+ rimraf(types_dir);
62
+ first_run = false;
63
+ }
64
+
65
+ const routes_dir = posixify(path.relative('.', config.kit.files.routes));
66
+ const groups = get_groups(manifest_data, routes_dir);
67
+
68
+ let written_files = new Set();
69
+ // ...then, for each directory, write $types.d.ts
70
+ for (const [dir] of groups) {
71
+ const written = write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts);
72
+ written.forEach((w) => written_files.add(w));
73
+ }
74
+
75
+ // Remove all files that were not updated, which means their original was removed
76
+ remove_from_previous((file) => {
77
+ const was_removed = file.startsWith(types_dir) && !written_files.has(file);
78
+ if (was_removed) {
79
+ rimraf(file);
80
+ }
81
+ return was_removed;
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Creates types related to the given file. This should only be called
87
+ * if the file in question was edited, not if it was created/deleted/moved.
88
+ *
89
+ * @param {import('types').ValidatedConfig} config
90
+ * @param {import('types').ManifestData} manifest_data
91
+ * @param {string} file
92
+ */
93
+ export async function write_type(config, manifest_data, file) {
94
+ if (!path.basename(file).startsWith('+')) {
95
+ // Not a route file
96
+ return;
97
+ }
98
+
99
+ /** @type {import('typescript') | undefined} */
100
+ let ts = undefined;
101
+ try {
102
+ ts = (await import('typescript')).default;
103
+ } catch (e) {
104
+ // No TypeScript installed - skip type generation
105
+ return;
106
+ }
107
+
108
+ const routes_dir = posixify(path.relative('.', config.kit.files.routes));
109
+ const file_dir = posixify(path.dirname(file).slice(config.kit.files.routes.length + 1));
110
+ const groups = get_groups(manifest_data, routes_dir);
111
+
112
+ // We are only interested in the directory that contains the file
113
+ write_types_for_dir(config, manifest_data, routes_dir, file_dir, groups, ts);
114
+ }
115
+
116
+ /**
117
+ * @param {import('types').ManifestData} manifest_data
118
+ * @param {string} routes_dir
119
+ */
120
+ function get_groups(manifest_data, routes_dir) {
121
+ /**
122
+ * A map of all directories : route files. We don't just use
123
+ * manifest_data.routes, because that will exclude +layout
124
+ * files that aren't accompanied by a +page
125
+ * @type {Map<string, NodeGroup>}
126
+ */
127
+ const groups = new Map();
128
+
129
+ /** @param {string} dir */
130
+ function get_group(dir) {
131
+ let group = groups.get(dir);
132
+ if (!group) {
133
+ group = {
134
+ named_layouts: new Map()
135
+ };
136
+ groups.set(dir, group);
137
+ }
138
+
139
+ return group;
140
+ }
141
+
142
+ // first, sort nodes (necessary for finding the nearest layout more efficiently)...
143
+ const nodes = [...manifest_data.nodes].sort((n1, n2) => {
144
+ // Sort by path length first...
145
+ const path_length_diff =
146
+ /** @type {string} */ (n1.component ?? n1.shared ?? n1.server).split('/').length -
147
+ /** @type {string} */ (n2.component ?? n2.shared ?? n2.server).split('/').length;
148
+
149
+ return (
150
+ path_length_diff ||
151
+ // ...on ties, sort named layouts first
152
+ (path.basename(n1.component || '').includes('-')
153
+ ? -1
154
+ : path.basename(n2.component || '').includes('-')
155
+ ? 1
156
+ : 0)
157
+ );
158
+ });
159
+
160
+ // ...then, populate `directories` with +page/+layout files...
161
+ for (let i = 0; i < nodes.length; i += 1) {
162
+ /** @type {Node} */
163
+ const node = { ...nodes[i] }; // shallow copy so we don't mutate the original when setting parent
164
+
165
+ // skip default layout/error
166
+ if (!node?.component?.startsWith(routes_dir)) continue;
167
+
168
+ const parts = /** @type {string} */ (node.component ?? node.shared ?? node.server).split('/');
169
+
170
+ const file = /** @type {string} */ (parts.pop());
171
+ const dir = parts.join('/').slice(routes_dir.length + 1);
172
+
173
+ // error pages don't need types
174
+ if (!file || file.startsWith('+error')) continue;
175
+
176
+ const group = get_group(dir);
177
+
178
+ if (file.startsWith('+page')) {
179
+ group.leaf = node;
180
+ } else {
181
+ const match = /^\+layout(?:-([^@.]+))?/.exec(file);
182
+
183
+ // this shouldn't happen, but belt and braces. also keeps TS happy,
184
+ // and we live to keep TS happy
185
+ if (!match) throw new Error(`Unexpected route file: ${file}`);
186
+
187
+ if (match[1]) {
188
+ group.named_layouts.set(match[1], node);
189
+ } else {
190
+ group.default_layout = node;
191
+ }
192
+ }
193
+
194
+ node.parent = find_nearest_layout(routes_dir, nodes, i);
195
+ }
196
+
197
+ // ...then add +server.js files...
198
+ for (const route of manifest_data.routes) {
199
+ if (route.type === 'endpoint') {
200
+ get_group(route.id).endpoint = route.file;
201
+ }
202
+ }
203
+
204
+ return groups;
205
+ }
206
+
207
+ /**
208
+ *
209
+ * @param {import('types').ValidatedConfig} config
210
+ * @param {import('types').ManifestData} manifest_data
211
+ * @param {string} routes_dir
212
+ * @param {string} dir
213
+ * @param {Map<string, NodeGroup>} groups
214
+ * @param {import('typescript')} ts
215
+ */
216
+ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts) {
217
+ const group = groups.get(dir);
218
+ if (!group) {
219
+ return [];
220
+ }
221
+
222
+ const outdir = `${config.kit.outDir}/types/${routes_dir}/${dir}`;
223
+
224
+ const imports = [`import type * as Kit from '@sveltejs/kit';`];
225
+
226
+ /** @type {string[]} */
227
+ const written_files = [];
228
+
229
+ /** @type {string[]} */
230
+ const declarations = [];
231
+
232
+ /** @type {string[]} */
233
+ const exports = [];
234
+
235
+ const route_params = parse_route_id(dir).names;
236
+
237
+ if (route_params.length > 0) {
238
+ const params = route_params.map((param) => `${param}: string`).join('; ');
239
+ declarations.push(
240
+ `interface RouteParams extends Partial<Record<string, string>> { ${params} }`
241
+ );
242
+ } else {
243
+ declarations.push(`interface RouteParams extends Partial<Record<string, string>> {}`);
244
+ }
245
+
246
+ if (group.leaf) {
247
+ const { data, server_data, load, server_load, errors, written_proxies } = process_node(
248
+ ts,
249
+ group.leaf,
250
+ outdir,
251
+ 'RouteParams',
252
+ groups
253
+ );
254
+ written_files.push(...written_proxies);
255
+
256
+ exports.push(`export type Errors = ${errors};`);
257
+
258
+ exports.push(`export type PageData = ${data};`);
259
+ if (load) {
260
+ exports.push(
261
+ `export type PageLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
262
+ );
263
+ exports.push('export type PageLoadEvent = Parameters<PageLoad>[0];');
264
+ }
265
+
266
+ exports.push(`export type PageServerData = ${server_data};`);
267
+ if (server_load) {
268
+ exports.push(
269
+ `export type PageServerLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
270
+ );
271
+ exports.push('export type PageServerLoadEvent = Parameters<PageServerLoad>[0];');
272
+ }
273
+
274
+ if (group.leaf.server) {
275
+ exports.push(`export type Action = Kit.Action<RouteParams>`);
276
+ }
277
+ }
278
+
279
+ if (group.default_layout || group.named_layouts.size > 0) {
280
+ // TODO to be completely rigorous, we should have a LayoutParams per
281
+ // layout, and only include params for child pages that use each layout.
282
+ // but that's more work than i care to do right now
283
+ const layout_params = new Set();
284
+ manifest_data.routes.forEach((route) => {
285
+ if (route.type === 'page' && route.id.startsWith(dir + '/')) {
286
+ // TODO this is O(n^2), see if we need to speed it up
287
+ for (const name of parse_route_id(route.id).names) {
288
+ layout_params.add(name);
289
+ }
290
+ }
291
+ });
292
+
293
+ if (layout_params.size > 0) {
294
+ const params = Array.from(layout_params).map((param) => `${param}?: string`);
295
+ declarations.push(`interface LayoutParams extends RouteParams { ${params.join('; ')} }`);
296
+ } else {
297
+ declarations.push(`interface LayoutParams extends RouteParams {}`);
298
+ }
299
+
300
+ if (group.default_layout) {
301
+ const { data, server_data, load, server_load, written_proxies } = process_node(
302
+ ts,
303
+ group.default_layout,
304
+ outdir,
305
+ 'LayoutParams',
306
+ groups
307
+ );
308
+ written_files.push(...written_proxies);
309
+
310
+ exports.push(`export type LayoutData = ${data};`);
311
+ if (load) {
312
+ exports.push(
313
+ `export type LayoutLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
314
+ );
315
+ exports.push('export type LayoutLoadEvent = Parameters<LayoutLoad>[0];');
316
+ }
317
+
318
+ exports.push(`export type LayoutServerData = ${server_data};`);
319
+ if (server_load) {
320
+ exports.push(
321
+ `export type LayoutServerLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
322
+ );
323
+ exports.push('export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0];');
324
+ }
325
+ }
326
+
327
+ if (group.named_layouts.size > 0) {
328
+ /** @type {string[]} */
329
+ const data_exports = [];
330
+
331
+ /** @type {string[]} */
332
+ const server_data_exports = [];
333
+
334
+ /** @type {string[]} */
335
+ const load_exports = [];
336
+
337
+ /** @type {string[]} */
338
+ const load_event_exports = [];
339
+
340
+ /** @type {string[]} */
341
+ const server_load_exports = [];
342
+
343
+ /** @type {string[]} */
344
+ const server_load_event_exports = [];
345
+
346
+ for (const [name, node] of group.named_layouts) {
347
+ const { data, server_data, load, server_load, written_proxies } = process_node(
348
+ ts,
349
+ node,
350
+ outdir,
351
+ 'LayoutParams',
352
+ groups
353
+ );
354
+ written_files.push(...written_proxies);
355
+ data_exports.push(`export type ${name} = ${data};`);
356
+ server_data_exports.push(`export type ${name} = ${server_data};`);
357
+ if (load) {
358
+ load_exports.push(
359
+ `export type ${name}<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
360
+ );
361
+ load_event_exports.push(`export type ${name} = Parameters<LayoutLoad.${name}>[0];`);
362
+ }
363
+ if (server_load) {
364
+ server_load_exports.push(
365
+ `export type ${name}<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
366
+ );
367
+ server_load_event_exports.push(
368
+ `export type ${name} = Parameters<LayoutServerLoad.${name}>[0];`
369
+ );
370
+ }
371
+ }
372
+
373
+ exports.push(`\nexport namespace LayoutData {\n\t${data_exports.join('\n\t')}\n}`);
374
+ exports.push(`\nexport namespace LayoutLoad {\n\t${load_exports.join('\n\t')}\n}`);
375
+ exports.push(`\nexport namespace LayoutLoadEvent {\n\t${load_event_exports.join('\n\t')}\n}`);
376
+ exports.push(
377
+ `\nexport namespace LayoutServerData {\n\t${server_data_exports.join('\n\t')}\n}`
378
+ );
379
+ exports.push(
380
+ `\nexport namespace LayoutServerLoad {\n\t${server_load_exports.join('\n\t')}\n}`
381
+ );
382
+ exports.push(
383
+ `\nexport namespace LayoutServerLoadEvent {\n\t${server_load_event_exports.join('\n\t')}\n}`
384
+ );
385
+ }
386
+ }
387
+
388
+ if (group.endpoint) {
389
+ exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams>;`);
390
+ exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams>;`);
391
+ }
392
+
393
+ const output = [imports.join('\n'), declarations.join('\n'), exports.join('\n')]
394
+ .filter(Boolean)
395
+ .join('\n\n');
396
+
397
+ written_files.push(write(`${outdir}/$types.d.ts`, output));
398
+
399
+ return written_files;
400
+ }
401
+
402
+ /**
403
+ * @param {import('typescript')} ts
404
+ * @param {Node} node
405
+ * @param {string} outdir
406
+ * @param {string} params
407
+ * @param {Map<string, NodeGroup>} groups
408
+ */
409
+ function process_node(ts, node, outdir, params, groups) {
410
+ let data;
411
+ let load;
412
+ let server_load;
413
+ let errors;
414
+
415
+ /** @type {string[]} */
416
+ let written_proxies = [];
417
+
418
+ let server_data;
419
+
420
+ if (node.server) {
421
+ const content = fs.readFileSync(node.server, 'utf8');
422
+ const proxy = tweak_types(ts, content, server_names);
423
+ const basename = path.basename(node.server);
424
+ if (proxy?.modified) {
425
+ written_proxies.push(write(`${outdir}/proxy${basename}`, proxy.code));
426
+ }
427
+
428
+ server_data = get_data_type(node.server, 'load', 'null', proxy);
429
+ server_load = `Kit.ServerLoad<${params}, ${get_parent_type('LayoutServerData')}, OutputData>`;
430
+
431
+ if (proxy) {
432
+ const types = [];
433
+ for (const method of ['POST', 'PUT', 'PATCH']) {
434
+ if (proxy.exports.includes(method)) {
435
+ // If the file wasn't tweaked, we can use the return type of the original file.
436
+ // The advantage is that type updates are reflected without saving.
437
+ const from = proxy.modified
438
+ ? `./proxy${replace_ext_with_js(basename)}`
439
+ : path_to_original(outdir, node.server);
440
+
441
+ types.push(`Kit.AwaitedErrors<typeof import('${from}').${method}>`);
442
+ }
443
+ }
444
+ errors = types.length ? types.join(' | ') : 'null';
445
+ } else {
446
+ errors = 'unknown';
447
+ }
448
+ } else {
449
+ server_data = 'null';
450
+ }
451
+
452
+ if (node.shared) {
453
+ const content = fs.readFileSync(node.shared, 'utf8');
454
+ const proxy = tweak_types(ts, content, shared_names);
455
+ if (proxy?.modified) {
456
+ written_proxies.push(write(`${outdir}/proxy${path.basename(node.shared)}`, proxy.code));
457
+ }
458
+
459
+ data = get_data_type(node.shared, 'load', server_data, proxy);
460
+ load = `Kit.Load<${params}, ${server_data}, ${get_parent_type('LayoutData')}, OutputData>`;
461
+ } else {
462
+ data = server_data;
463
+ }
464
+
465
+ return { data, server_data, load, server_load, errors, written_proxies };
466
+
467
+ /**
468
+ * @param {string} file_path
469
+ * @param {string} method
470
+ * @param {string} fallback
471
+ * @param {Proxy} proxy
472
+ */
473
+ function get_data_type(file_path, method, fallback, proxy) {
474
+ if (proxy) {
475
+ if (proxy.exports.includes(method)) {
476
+ // If the file wasn't tweaked, we can use the return type of the original file.
477
+ // The advantage is that type updates are reflected without saving.
478
+ const from = proxy.modified
479
+ ? `./proxy${replace_ext_with_js(path.basename(file_path))}`
480
+ : path_to_original(outdir, file_path);
481
+ return `Kit.AwaitedProperties<Awaited<ReturnType<typeof import('${from}').${method}>>>`;
482
+ } else {
483
+ return fallback;
484
+ }
485
+ } else {
486
+ return 'unknown';
487
+ }
488
+ }
489
+
490
+ /**
491
+ * Get the parent type string by recursively looking up the parent layout and accumulate them to one type.
492
+ * @param {string} type
493
+ */
494
+ function get_parent_type(type) {
495
+ const parent_imports = [];
496
+ let parent = node.parent;
497
+ let acc_diff = 0;
498
+
499
+ while (parent) {
500
+ acc_diff += parent.folder_depth_diff;
501
+ let parent_group = /** @type {NodeGroup} */ (groups.get(parent.key));
502
+ // unshift because we need it the other way round for the import string
503
+ parent_imports.unshift(
504
+ (acc_diff === 0 ? '' : `import('` + '../'.repeat(acc_diff) + '$types.js' + `').`) +
505
+ `${type}${parent.name ? `.${parent.name}` : ''}`
506
+ );
507
+ let parent_layout = /** @type {Node} */ (
508
+ parent.name ? parent_group.named_layouts.get(parent.name) : parent_group.default_layout
509
+ );
510
+ parent = parent_layout.parent;
511
+ }
512
+
513
+ let parent_str = parent_imports[0] || 'Record<never, never>';
514
+ for (let i = 1; i < parent_imports.length; i++) {
515
+ // Omit is necessary because a parent could have a property with the same key which would
516
+ // cause a type conflict. At runtime the child overwrites the parent property in this case,
517
+ // so reflect that in the type definition.
518
+ parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & ${parent_imports[i]}`;
519
+ }
520
+ return parent_str;
521
+ }
522
+ }
523
+
524
+ /**
525
+ * @param {string} outdir
526
+ * @param {string} file_path
527
+ */
528
+ function path_to_original(outdir, file_path) {
529
+ return posixify(path.relative(outdir, path.join(cwd, replace_ext_with_js(file_path))));
530
+ }
531
+
532
+ /**
533
+ * @param {string} file_path
534
+ */
535
+ function replace_ext_with_js(file_path) {
536
+ // Another extension than `.js` (or nothing, but that fails with node16 moduleResolution)
537
+ // will result in TS failing to lookup the file
538
+ const ext = path.extname(file_path);
539
+ return file_path.slice(0, -ext.length) + '.js';
540
+ }
541
+
542
+ /**
543
+ * @param {import('typescript')} ts
544
+ * @param {string} content
545
+ * @param {Set<string>} names
546
+ * @returns {Proxy}
547
+ */
548
+ export function tweak_types(ts, content, names) {
549
+ try {
550
+ let modified = false;
551
+
552
+ const ast = ts.createSourceFile(
553
+ 'filename.ts',
554
+ content,
555
+ ts.ScriptTarget.Latest,
556
+ false,
557
+ ts.ScriptKind.TS
558
+ );
559
+
560
+ const code = new MagicString(content);
561
+
562
+ const exports = new Map();
563
+
564
+ ast.forEachChild((node) => {
565
+ if (
566
+ ts.isExportDeclaration(node) &&
567
+ node.exportClause &&
568
+ ts.isNamedExports(node.exportClause)
569
+ ) {
570
+ node.exportClause.elements.forEach((element) => {
571
+ const exported = element.name;
572
+ if (names.has(element.name.text)) {
573
+ const local = element.propertyName || element.name;
574
+ exports.set(exported.text, local.text);
575
+ }
576
+ });
577
+ }
578
+
579
+ if (node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
580
+ if (ts.isFunctionDeclaration(node) && node.name?.text && names.has(node.name?.text)) {
581
+ exports.set(node.name.text, node.name.text);
582
+ }
583
+
584
+ if (ts.isVariableStatement(node)) {
585
+ node.declarationList.declarations.forEach((declaration) => {
586
+ if (ts.isIdentifier(declaration.name) && names.has(declaration.name.text)) {
587
+ exports.set(declaration.name.text, declaration.name.text);
588
+ }
589
+ });
590
+ }
591
+ }
592
+ });
593
+
594
+ /**
595
+ * @param {import('typescript').Node} node
596
+ * @param {import('typescript').Node} value
597
+ */
598
+ function replace_jsdoc_type_tags(node, value) {
599
+ // @ts-ignore
600
+ if (node.jsDoc) {
601
+ // @ts-ignore
602
+ for (const comment of node.jsDoc) {
603
+ for (const tag of comment.tags) {
604
+ if (ts.isJSDocTypeTag(tag)) {
605
+ const is_fn =
606
+ ts.isFunctionDeclaration(value) ||
607
+ ts.isFunctionExpression(value) ||
608
+ ts.isArrowFunction(value);
609
+
610
+ if (is_fn && value.parameters?.length > 0) {
611
+ code.overwrite(tag.tagName.pos, tag.tagName.end, 'param');
612
+ code.prependRight(tag.typeExpression.pos + 1, 'Parameters<');
613
+ code.appendLeft(tag.typeExpression.end - 1, '>[0]');
614
+ code.appendLeft(tag.typeExpression.end, ' event');
615
+ } else {
616
+ code.overwrite(tag.pos, tag.end, '');
617
+ }
618
+ modified = true;
619
+ }
620
+ }
621
+ }
622
+ }
623
+ }
624
+
625
+ ast.forEachChild((node) => {
626
+ if (ts.isFunctionDeclaration(node) && node.name?.text && names.has(node.name?.text)) {
627
+ // remove JSDoc comment above `export function load ...`
628
+ replace_jsdoc_type_tags(node, node);
629
+ }
630
+
631
+ if (ts.isVariableStatement(node)) {
632
+ // remove JSDoc comment above `export const load = ...`
633
+ if (
634
+ ts.isIdentifier(node.declarationList.declarations[0].name) &&
635
+ names.has(node.declarationList.declarations[0].name.text) &&
636
+ node.declarationList.declarations[0].initializer
637
+ ) {
638
+ replace_jsdoc_type_tags(node, node.declarationList.declarations[0].initializer);
639
+ }
640
+
641
+ for (const declaration of node.declarationList.declarations) {
642
+ if (
643
+ ts.isIdentifier(declaration.name) &&
644
+ names.has(declaration.name.text) &&
645
+ declaration.initializer
646
+ ) {
647
+ // edge case — remove JSDoc comment above individual export
648
+ replace_jsdoc_type_tags(declaration, declaration.initializer);
649
+
650
+ // remove type from `export const load: Load ...`
651
+ if (declaration.type) {
652
+ let a = declaration.type.pos;
653
+ let b = declaration.type.end;
654
+ while (/\s/.test(content[a])) a += 1;
655
+
656
+ const type = content.slice(a, b);
657
+ code.remove(declaration.name.end, declaration.type.end);
658
+
659
+ const rhs = declaration.initializer;
660
+
661
+ if (
662
+ rhs &&
663
+ (ts.isArrowFunction(rhs) || ts.isFunctionExpression(rhs)) &&
664
+ rhs.parameters.length
665
+ ) {
666
+ const arg = rhs.parameters[0];
667
+
668
+ const add_parens = content[arg.pos - 1] !== '(';
669
+
670
+ if (add_parens) code.prependRight(arg.pos, '(');
671
+
672
+ if (arg && !arg.type) {
673
+ code.appendLeft(
674
+ arg.name.end,
675
+ `: Parameters<${type}>[0]` + (add_parens ? ')' : '')
676
+ );
677
+ }
678
+ }
679
+
680
+ modified = true;
681
+ }
682
+ }
683
+ }
684
+ }
685
+ });
686
+
687
+ return {
688
+ modified,
689
+ code: code.toString(),
690
+ exports: Array.from(exports.keys())
691
+ };
692
+ } catch {
693
+ return null;
694
+ }
695
+ }
696
+
697
+ /**
698
+ * @param {string} file
699
+ * @param {string} content
700
+ */
701
+ function write(file, content) {
702
+ write_if_changed(file, content);
703
+ return file;
704
+ }
705
+
706
+ /**
707
+ * Finds the nearest layout for given node.
708
+ * Assumes that nodes is sorted by path length (lowest first).
709
+ *
710
+ * @param {string} routes_dir
711
+ * @param {import('types').PageNode[]} nodes
712
+ * @param {number} start_idx
713
+ */
714
+ export function find_nearest_layout(routes_dir, nodes, start_idx) {
715
+ const start_file = /** @type {string} */ (
716
+ nodes[start_idx].component || nodes[start_idx].shared || nodes[start_idx].server
717
+ );
718
+
719
+ let name = '';
720
+ const match = /^\+(layout|page)(?:-([^@.]+))?(?:@([^@.]+))?/.exec(path.basename(start_file));
721
+ if (!match) throw new Error(`Unexpected route file: ${start_file}`);
722
+ if (match[3] && match[3] !== 'default') {
723
+ name = match[3]; // a named layout is referenced
724
+ }
725
+
726
+ let common_path = path.dirname(start_file);
727
+ if (match[1] === 'layout' && !match[2] && !name) {
728
+ // We are a default layout, so we skip the current level
729
+ common_path = path.dirname(common_path);
730
+ }
731
+
732
+ for (let i = start_idx - 1; i >= 0; i -= 1) {
733
+ const node = nodes[i];
734
+ const file = /** @type {string} */ (node.component || node.shared || node.server);
735
+
736
+ const current_path = path.dirname(file);
737
+ const common_path_length = common_path.split('/').length;
738
+ const current_path_length = current_path.split('/').length;
739
+
740
+ if (common_path_length < current_path_length) {
741
+ // this is a layout in a different tree
742
+ continue;
743
+ } else if (common_path_length > current_path_length) {
744
+ // we've gone back up a folder level
745
+ common_path = path.dirname(common_path);
746
+ }
747
+ if (common_path !== current_path) {
748
+ // this is a layout in a different tree
749
+ continue;
750
+ }
751
+ if (
752
+ path.basename(file, path.extname(file)).split('@')[0] !==
753
+ '+layout' + (name ? `-${name}` : '')
754
+ ) {
755
+ // this is not the layout we are searching for
756
+ continue;
757
+ }
758
+
759
+ // matching parent layout found
760
+ let folder_depth_diff =
761
+ posixify(path.relative(path.dirname(start_file), common_path + '/$types.js')).split('/')
762
+ .length - 1;
763
+ return {
764
+ key: path.dirname(file).slice(routes_dir.length + 1),
765
+ name,
766
+ folder_depth_diff
767
+ };
768
+ }
769
+ }