@sveltejs/kit 1.0.0-next.41 → 1.0.0-next.412

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 (129) hide show
  1. package/README.md +12 -9
  2. package/package.json +97 -63
  3. package/src/cli.js +119 -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 +488 -0
  8. package/src/core/config/types.d.ts +1 -0
  9. package/src/core/constants.js +3 -0
  10. package/src/core/generate_manifest/index.js +99 -0
  11. package/src/core/prerender/crawl.js +194 -0
  12. package/src/core/prerender/prerender.js +378 -0
  13. package/src/core/prerender/queue.js +80 -0
  14. package/src/core/sync/create_manifest_data/index.js +496 -0
  15. package/src/core/sync/create_manifest_data/types.d.ts +40 -0
  16. package/src/core/sync/sync.js +59 -0
  17. package/src/core/sync/utils.js +97 -0
  18. package/src/core/sync/write_ambient.js +87 -0
  19. package/src/core/sync/write_client_manifest.js +82 -0
  20. package/src/core/sync/write_matchers.js +25 -0
  21. package/src/core/sync/write_root.js +88 -0
  22. package/src/core/sync/write_tsconfig.js +189 -0
  23. package/src/core/sync/write_types.js +727 -0
  24. package/src/core/utils.js +58 -0
  25. package/src/hooks.js +26 -0
  26. package/src/index/index.js +45 -0
  27. package/src/index/private.js +33 -0
  28. package/src/node/index.js +145 -0
  29. package/src/node/polyfills.js +40 -0
  30. package/src/packaging/index.js +218 -0
  31. package/src/packaging/types.d.ts +8 -0
  32. package/src/packaging/typescript.js +150 -0
  33. package/src/packaging/utils.js +143 -0
  34. package/src/runtime/app/env.js +11 -0
  35. package/src/runtime/app/navigation.js +22 -0
  36. package/src/runtime/app/paths.js +1 -0
  37. package/src/runtime/app/stores.js +94 -0
  38. package/src/runtime/client/ambient.d.ts +17 -0
  39. package/src/runtime/client/client.js +1281 -0
  40. package/src/runtime/client/fetcher.js +60 -0
  41. package/src/runtime/client/parse.js +36 -0
  42. package/src/runtime/client/singletons.js +11 -0
  43. package/src/runtime/client/start.js +48 -0
  44. package/src/runtime/client/types.d.ts +106 -0
  45. package/src/runtime/client/utils.js +113 -0
  46. package/src/runtime/components/error.svelte +16 -0
  47. package/{assets → src/runtime}/components/layout.svelte +0 -0
  48. package/src/runtime/env/dynamic/private.js +1 -0
  49. package/src/runtime/env/dynamic/public.js +1 -0
  50. package/src/runtime/env-private.js +7 -0
  51. package/src/runtime/env-public.js +7 -0
  52. package/src/runtime/env.js +6 -0
  53. package/src/runtime/hash.js +16 -0
  54. package/src/runtime/paths.js +11 -0
  55. package/src/runtime/server/endpoint.js +42 -0
  56. package/src/runtime/server/index.js +434 -0
  57. package/src/runtime/server/page/cookie.js +25 -0
  58. package/src/runtime/server/page/crypto.js +239 -0
  59. package/src/runtime/server/page/csp.js +249 -0
  60. package/src/runtime/server/page/fetch.js +266 -0
  61. package/src/runtime/server/page/index.js +418 -0
  62. package/src/runtime/server/page/load_data.js +94 -0
  63. package/src/runtime/server/page/render.js +363 -0
  64. package/src/runtime/server/page/respond_with_error.js +105 -0
  65. package/src/runtime/server/page/types.d.ts +44 -0
  66. package/src/runtime/server/utils.js +116 -0
  67. package/src/utils/error.js +22 -0
  68. package/src/utils/escape.js +104 -0
  69. package/src/utils/filesystem.js +108 -0
  70. package/src/utils/http.js +55 -0
  71. package/src/utils/misc.js +1 -0
  72. package/src/utils/routing.js +107 -0
  73. package/src/utils/url.js +97 -0
  74. package/src/vite/build/build_server.js +339 -0
  75. package/src/vite/build/build_service_worker.js +90 -0
  76. package/src/vite/build/utils.js +153 -0
  77. package/src/vite/dev/index.js +569 -0
  78. package/src/vite/index.js +540 -0
  79. package/src/vite/preview/index.js +186 -0
  80. package/src/vite/types.d.ts +3 -0
  81. package/src/vite/utils.js +335 -0
  82. package/svelte-kit.js +1 -1
  83. package/types/ambient.d.ts +368 -0
  84. package/types/index.d.ts +345 -0
  85. package/types/internal.d.ts +309 -0
  86. package/types/private.d.ts +236 -0
  87. package/CHANGELOG.md +0 -419
  88. package/assets/components/error.svelte +0 -13
  89. package/assets/runtime/app/env.js +0 -5
  90. package/assets/runtime/app/navigation.js +0 -41
  91. package/assets/runtime/app/paths.js +0 -1
  92. package/assets/runtime/app/stores.js +0 -93
  93. package/assets/runtime/chunks/utils.js +0 -19
  94. package/assets/runtime/internal/singletons.js +0 -23
  95. package/assets/runtime/internal/start.js +0 -770
  96. package/assets/runtime/paths.js +0 -12
  97. package/dist/api.js +0 -28
  98. package/dist/api.js.map +0 -1
  99. package/dist/chunks/index.js +0 -3519
  100. package/dist/chunks/index2.js +0 -587
  101. package/dist/chunks/index3.js +0 -246
  102. package/dist/chunks/index4.js +0 -524
  103. package/dist/chunks/index5.js +0 -761
  104. package/dist/chunks/index6.js +0 -322
  105. package/dist/chunks/standard.js +0 -99
  106. package/dist/chunks/utils.js +0 -83
  107. package/dist/cli.js +0 -546
  108. package/dist/cli.js.map +0 -1
  109. package/dist/create_app.js +0 -592
  110. package/dist/create_app.js.map +0 -1
  111. package/dist/index.js +0 -392
  112. package/dist/index.js.map +0 -1
  113. package/dist/index2.js +0 -3519
  114. package/dist/index2.js.map +0 -1
  115. package/dist/index3.js +0 -320
  116. package/dist/index3.js.map +0 -1
  117. package/dist/index4.js +0 -323
  118. package/dist/index4.js.map +0 -1
  119. package/dist/index5.js +0 -247
  120. package/dist/index5.js.map +0 -1
  121. package/dist/index6.js +0 -761
  122. package/dist/index6.js.map +0 -1
  123. package/dist/renderer.js +0 -2499
  124. package/dist/renderer.js.map +0 -1
  125. package/dist/ssr.js +0 -2581
  126. package/dist/standard.js +0 -100
  127. package/dist/standard.js.map +0 -1
  128. package/dist/utils.js +0 -84
  129. package/dist/utils.js.map +0 -1
@@ -0,0 +1,727 @@
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 the file wasn't tweaked, we can use the return type of the original file.
394
+ // The advantage is that type updates are reflected without saving.
395
+ const from = proxy.modified
396
+ ? `./proxy${replace_ext_with_js(basename)}`
397
+ : path_to_original(outdir, node.server);
398
+
399
+ types.push(`Kit.AwaitedErrors<typeof import('${from}').${method}>`);
400
+ }
401
+ }
402
+ errors = types.length ? types.join(' | ') : 'null';
403
+ } else {
404
+ errors = 'unknown';
405
+ }
406
+ } else {
407
+ server_data = 'null';
408
+ }
409
+
410
+ if (node.shared) {
411
+ const content = fs.readFileSync(node.shared, 'utf8');
412
+ const proxy = tweak_types(ts, content, shared_names);
413
+ if (proxy?.modified) {
414
+ written_proxies.push(write(`${outdir}/proxy${path.basename(node.shared)}`, proxy.code));
415
+ }
416
+
417
+ data = get_data_type(node.shared, 'load', server_data, proxy);
418
+ load = `Kit.Load<${params}, ${server_data}, ${get_parent_type('LayoutData')}>`;
419
+ } else {
420
+ data = server_data;
421
+ }
422
+
423
+ return { data, server_data, load, server_load, errors, written_proxies };
424
+
425
+ /**
426
+ * @param {string} file_path
427
+ * @param {string} method
428
+ * @param {string} fallback
429
+ * @param {Proxy} proxy
430
+ */
431
+ function get_data_type(file_path, method, fallback, proxy) {
432
+ if (proxy) {
433
+ if (proxy.exports.includes(method)) {
434
+ // If the file wasn't tweaked, we can use the return type of the original file.
435
+ // The advantage is that type updates are reflected without saving.
436
+ const from = proxy.modified
437
+ ? `./proxy${replace_ext_with_js(path.basename(file_path))}`
438
+ : path_to_original(outdir, file_path);
439
+ return `Kit.AwaitedProperties<Awaited<ReturnType<typeof import('${from}').${method}>>>`;
440
+ } else {
441
+ return fallback;
442
+ }
443
+ } else {
444
+ return 'unknown';
445
+ }
446
+ }
447
+
448
+ /**
449
+ * Get the parent type string by recursively looking up the parent layout and accumulate them to one type.
450
+ * @param {string} type
451
+ */
452
+ function get_parent_type(type) {
453
+ const parent_imports = [];
454
+ let parent = node.parent;
455
+ let acc_diff = 0;
456
+
457
+ while (parent) {
458
+ acc_diff += parent.folder_depth_diff;
459
+ let parent_group = /** @type {NodeGroup} */ (groups.get(parent.key));
460
+ // unshift because we need it the other way round for the import string
461
+ parent_imports.unshift(
462
+ (acc_diff === 0 ? '' : `import('` + '../'.repeat(acc_diff) + '$types.js' + `').`) +
463
+ `${type}${parent.name ? `.${parent.name}` : ''}`
464
+ );
465
+ let parent_layout = /** @type {Node} */ (
466
+ parent.name ? parent_group.named_layouts.get(parent.name) : parent_group.default_layout
467
+ );
468
+ parent = parent_layout.parent;
469
+ }
470
+
471
+ let parent_str = parent_imports[0] || 'null';
472
+ for (let i = 1; i < parent_imports.length; i++) {
473
+ // Omit is necessary because a parent could have a property with the same key which would
474
+ // cause a type conflict. At runtime the child overwrites the parent property in this case,
475
+ // so reflect that in the type definition.
476
+ parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & ${parent_imports[i]}`;
477
+ }
478
+ return parent_str;
479
+ }
480
+ }
481
+
482
+ /**
483
+ * @param {string} outdir
484
+ * @param {string} file_path
485
+ */
486
+ function path_to_original(outdir, file_path) {
487
+ return posixify(path.relative(outdir, path.join(cwd, replace_ext_with_js(file_path))));
488
+ }
489
+
490
+ /**
491
+ * @param {string} file_path
492
+ */
493
+ function replace_ext_with_js(file_path) {
494
+ // Another extension than `.js` (or nothing, but that fails with node16 moduleResolution)
495
+ // will result in TS failing to lookup the file
496
+ const ext = path.extname(file_path);
497
+ return file_path.slice(0, -ext.length) + '.js';
498
+ }
499
+
500
+ /**
501
+ * @param {import('typescript')} ts
502
+ * @param {string} content
503
+ * @param {Set<string>} names
504
+ * @returns {Proxy}
505
+ */
506
+ export function tweak_types(ts, content, names) {
507
+ try {
508
+ let modified = false;
509
+
510
+ const ast = ts.createSourceFile(
511
+ 'filename.ts',
512
+ content,
513
+ ts.ScriptTarget.Latest,
514
+ false,
515
+ ts.ScriptKind.TS
516
+ );
517
+
518
+ const code = new MagicString(content);
519
+
520
+ const exports = new Map();
521
+
522
+ ast.forEachChild((node) => {
523
+ if (
524
+ ts.isExportDeclaration(node) &&
525
+ node.exportClause &&
526
+ ts.isNamedExports(node.exportClause)
527
+ ) {
528
+ node.exportClause.elements.forEach((element) => {
529
+ const exported = element.name;
530
+ if (names.has(element.name.text)) {
531
+ const local = element.propertyName || element.name;
532
+ exports.set(exported.text, local.text);
533
+ }
534
+ });
535
+ }
536
+
537
+ if (node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
538
+ if (ts.isFunctionDeclaration(node) && node.name?.text && names.has(node.name?.text)) {
539
+ exports.set(node.name.text, node.name.text);
540
+ }
541
+
542
+ if (ts.isVariableStatement(node)) {
543
+ node.declarationList.declarations.forEach((declaration) => {
544
+ if (ts.isIdentifier(declaration.name) && names.has(declaration.name.text)) {
545
+ exports.set(declaration.name.text, declaration.name.text);
546
+ }
547
+ });
548
+ }
549
+ }
550
+ });
551
+
552
+ /**
553
+ * @param {import('typescript').Node} node
554
+ * @param {import('typescript').Node} value
555
+ */
556
+ function replace_jsdoc_type_tags(node, value) {
557
+ // @ts-ignore
558
+ if (node.jsDoc) {
559
+ // @ts-ignore
560
+ for (const comment of node.jsDoc) {
561
+ for (const tag of comment.tags) {
562
+ if (ts.isJSDocTypeTag(tag)) {
563
+ const is_fn =
564
+ ts.isFunctionDeclaration(value) ||
565
+ ts.isFunctionExpression(value) ||
566
+ ts.isArrowFunction(value);
567
+
568
+ if (is_fn && value.parameters?.length > 0) {
569
+ code.overwrite(tag.tagName.pos, tag.tagName.end, 'param');
570
+ code.prependRight(tag.typeExpression.pos + 1, 'Parameters<');
571
+ code.appendLeft(tag.typeExpression.end - 1, '>[0]');
572
+ code.appendLeft(tag.typeExpression.end, ' event');
573
+ } else {
574
+ code.overwrite(tag.pos, tag.end, '');
575
+ }
576
+ modified = true;
577
+ }
578
+ }
579
+ }
580
+ }
581
+ }
582
+
583
+ ast.forEachChild((node) => {
584
+ if (ts.isFunctionDeclaration(node) && node.name?.text && names.has(node.name?.text)) {
585
+ // remove JSDoc comment above `export function load ...`
586
+ replace_jsdoc_type_tags(node, node);
587
+ }
588
+
589
+ if (ts.isVariableStatement(node)) {
590
+ // remove JSDoc comment above `export const load = ...`
591
+ if (
592
+ ts.isIdentifier(node.declarationList.declarations[0].name) &&
593
+ names.has(node.declarationList.declarations[0].name.text) &&
594
+ node.declarationList.declarations[0].initializer
595
+ ) {
596
+ replace_jsdoc_type_tags(node, node.declarationList.declarations[0].initializer);
597
+ }
598
+
599
+ for (const declaration of node.declarationList.declarations) {
600
+ if (
601
+ ts.isIdentifier(declaration.name) &&
602
+ names.has(declaration.name.text) &&
603
+ declaration.initializer
604
+ ) {
605
+ // edge case — remove JSDoc comment above individual export
606
+ replace_jsdoc_type_tags(declaration, declaration.initializer);
607
+
608
+ // remove type from `export const load: Load ...`
609
+ if (declaration.type) {
610
+ let a = declaration.type.pos;
611
+ let b = declaration.type.end;
612
+ while (/\s/.test(content[a])) a += 1;
613
+
614
+ const type = content.slice(a, b);
615
+ code.remove(declaration.name.end, declaration.type.end);
616
+
617
+ const rhs = declaration.initializer;
618
+
619
+ if (
620
+ rhs &&
621
+ (ts.isArrowFunction(rhs) || ts.isFunctionExpression(rhs)) &&
622
+ rhs.parameters.length
623
+ ) {
624
+ const arg = rhs.parameters[0];
625
+
626
+ const add_parens = content[arg.pos - 1] !== '(';
627
+
628
+ if (add_parens) code.prependRight(arg.pos, '(');
629
+
630
+ if (arg && !arg.type) {
631
+ code.appendLeft(
632
+ arg.name.end,
633
+ `: Parameters<${type}>[0]` + (add_parens ? ')' : '')
634
+ );
635
+ }
636
+ }
637
+
638
+ modified = true;
639
+ }
640
+ }
641
+ }
642
+ }
643
+ });
644
+
645
+ return {
646
+ modified,
647
+ code: code.toString(),
648
+ exports: Array.from(exports.keys())
649
+ };
650
+ } catch {
651
+ return null;
652
+ }
653
+ }
654
+
655
+ /**
656
+ * @param {string} file
657
+ * @param {string} content
658
+ */
659
+ function write(file, content) {
660
+ write_if_changed(file, content);
661
+ return file;
662
+ }
663
+
664
+ /**
665
+ * Finds the nearest layout for given node.
666
+ * Assumes that nodes is sorted by path length (lowest first).
667
+ *
668
+ * @param {string} routes_dir
669
+ * @param {import('types').PageNode[]} nodes
670
+ * @param {number} start_idx
671
+ */
672
+ export function find_nearest_layout(routes_dir, nodes, start_idx) {
673
+ const start_file = /** @type {string} */ (
674
+ nodes[start_idx].component || nodes[start_idx].shared || nodes[start_idx].server
675
+ );
676
+
677
+ let name = '';
678
+ const match = /^\+(layout|page)(?:-([^@.]+))?(?:@([^@.]+))?/.exec(path.basename(start_file));
679
+ if (!match) throw new Error(`Unexpected route file: ${start_file}`);
680
+ if (match[3] && match[3] !== 'default') {
681
+ name = match[3]; // a named layout is referenced
682
+ }
683
+
684
+ let common_path = path.dirname(start_file);
685
+ if (match[1] === 'layout' && !name) {
686
+ // We are a default layout, so we skip the current level
687
+ common_path = path.dirname(common_path);
688
+ }
689
+
690
+ for (let i = start_idx; i >= 0; i -= 1) {
691
+ const node = nodes[i];
692
+ const file = /** @type {string} */ (node.component || node.shared || node.server);
693
+
694
+ const current_path = path.dirname(file);
695
+ const common_path_length = common_path.split('/').length;
696
+ const current_path_length = current_path.split('/').length;
697
+
698
+ if (common_path_length < current_path_length) {
699
+ // this is a layout in a different tree
700
+ continue;
701
+ } else if (common_path_length > current_path_length) {
702
+ // we've gone back up a folder level
703
+ common_path = path.dirname(common_path);
704
+ }
705
+ if (common_path !== current_path) {
706
+ // this is a layout in a different tree
707
+ continue;
708
+ }
709
+ if (
710
+ path.basename(file, path.extname(file)).split('@')[0] !==
711
+ '+layout' + (name ? `-${name}` : '')
712
+ ) {
713
+ // this is not the layout we are searching for
714
+ continue;
715
+ }
716
+
717
+ // matching parent layout found
718
+ let folder_depth_diff =
719
+ posixify(path.relative(path.dirname(start_file), common_path + '/$types.js')).split('/')
720
+ .length - 1;
721
+ return {
722
+ key: path.dirname(file).slice(routes_dir.length + 1),
723
+ name,
724
+ folder_depth_diff
725
+ };
726
+ }
727
+ }