@sveltejs/kit 1.0.0-next.403 → 1.0.0-next.407

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