@sveltejs/kit 1.0.0-next.430 → 1.0.0-next.433

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.
@@ -1,28 +1,8 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
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
- */
4
+ import { posixify, rimraf, walk } from '../../utils/filesystem.js';
5
+ import { compact } from '../../utils/array.js';
26
6
 
27
7
  /**
28
8
  * @typedef {{
@@ -32,200 +12,133 @@ import { remove_from_previous, write_if_changed } from './utils.js';
32
12
  * } | null} Proxy
33
13
  */
34
14
 
15
+ /** @type {import('typescript')} */
16
+ // @ts-ignore
17
+ let ts = undefined;
18
+ try {
19
+ ts = (await import('typescript')).default;
20
+ } catch {}
21
+
35
22
  const cwd = process.cwd();
36
23
 
37
24
  const shared_names = new Set(['load']);
38
25
  const server_names = new Set(['load', 'POST', 'PUT', 'PATCH', 'DELETE']); // TODO replace with a single `action`
39
26
 
40
- let first_run = true;
41
-
42
27
  /**
43
28
  * Creates types for the whole manifest
44
- *
45
29
  * @param {import('types').ValidatedConfig} config
46
30
  * @param {import('types').ManifestData} manifest_data
47
31
  */
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
- }
32
+ export async function write_all_types(config, manifest_data) {
33
+ if (!ts) return;
57
34
 
58
35
  const types_dir = `${config.kit.outDir}/types`;
59
36
 
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);
37
+ // empty out files that no longer need to exist
38
+ const routes_dir = path.relative('.', config.kit.files.routes);
39
+ const expected_directories = new Set(
40
+ manifest_data.routes.map((route) => path.join(routes_dir, route.id))
41
+ );
67
42
 
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));
43
+ if (fs.existsSync(types_dir)) {
44
+ for (const file of walk(types_dir)) {
45
+ const dir = path.dirname(file);
46
+ if (!expected_directories.has(dir)) {
47
+ rimraf(file);
48
+ }
49
+ }
73
50
  }
74
51
 
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
- });
52
+ // For each directory, write $types.d.ts
53
+ for (const route of manifest_data.routes) {
54
+ update_types(config, manifest_data, route);
55
+ }
83
56
  }
84
57
 
85
58
  /**
86
59
  * Creates types related to the given file. This should only be called
87
60
  * if the file in question was edited, not if it was created/deleted/moved.
88
- *
89
61
  * @param {import('types').ValidatedConfig} config
90
62
  * @param {import('types').ManifestData} manifest_data
91
63
  * @param {string} file
92
64
  */
93
- export async function write_type(config, manifest_data, file) {
65
+ export async function write_types(config, manifest_data, file) {
66
+ if (!ts) return;
67
+
94
68
  if (!path.basename(file).startsWith('+')) {
95
69
  // Not a route file
96
70
  return;
97
71
  }
98
72
 
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
- }
73
+ const filepath = path.relative(config.kit.files.routes, file);
74
+ const id = path.dirname(filepath);
107
75
 
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);
76
+ const route = manifest_data.routes.find((route) => route.id === id);
77
+ if (!route) return; // this shouldn't ever happen
111
78
 
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);
79
+ update_types(config, manifest_data, route);
114
80
  }
115
81
 
116
82
  /**
83
+ *
84
+ * @param {import('types').ValidatedConfig} config
117
85
  * @param {import('types').ManifestData} manifest_data
118
- * @param {string} routes_dir
86
+ * @param {import('types').RouteData} route
119
87
  */
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
- const file_path = /** @type {string} */ (node.component ?? node.shared ?? node.server);
166
- // skip default layout/error
167
- if (!file_path.startsWith(routes_dir)) continue;
168
-
169
- const parts = file_path.split('/');
170
-
171
- const file = /** @type {string} */ (parts.pop());
172
- const dir = parts.join('/').slice(routes_dir.length + 1);
173
-
174
- // error pages don't need types
175
- if (!file || file.startsWith('+error')) continue;
176
-
177
- const group = get_group(dir);
178
-
179
- if (file.startsWith('+page')) {
180
- group.leaf = node;
181
- } else {
182
- const match = /^\+layout(?:-([^@.]+))?/.exec(file);
88
+ function update_types(config, manifest_data, route) {
89
+ const routes_dir = posixify(path.relative('.', config.kit.files.routes));
90
+ const outdir = path.join(config.kit.outDir, 'types', routes_dir, route.id);
183
91
 
184
- // this shouldn't happen, but belt and braces. also keeps TS happy,
185
- // and we live to keep TS happy
186
- if (!match) throw new Error(`Unexpected route file: ${file}`);
92
+ // first, check if the types are out of date
93
+ const input_files = [];
187
94
 
188
- if (match[1]) {
189
- group.named_layouts.set(match[1], node);
190
- } else {
191
- group.default_layout = node;
192
- }
193
- }
95
+ /** @type {import('types').PageNode | null} */
96
+ let node = route.leaf;
97
+ while (node) {
98
+ if (node.shared) input_files.push(node.shared);
99
+ if (node.server) input_files.push(node.server);
100
+ node = node.parent ?? null;
101
+ }
194
102
 
195
- node.parent = find_nearest_layout(routes_dir, nodes, i);
103
+ /** @type {import('types').PageNode | null} */
104
+ node = route.layout;
105
+ while (node) {
106
+ if (node.shared) input_files.push(node.shared);
107
+ if (node.server) input_files.push(node.server);
108
+ node = node.parent ?? null;
196
109
  }
197
110
 
198
- // ...then add +server.js files...
199
- for (const route of manifest_data.routes) {
200
- if (route.type === 'endpoint') {
201
- get_group(route.id).endpoint = route.file;
202
- }
111
+ if (route.endpoint) {
112
+ input_files.push(route.endpoint.file);
203
113
  }
204
114
 
205
- return groups;
206
- }
115
+ if (input_files.length === 0) return; // nothing to do
207
116
 
208
- /**
209
- *
210
- * @param {import('types').ValidatedConfig} config
211
- * @param {import('types').ManifestData} manifest_data
212
- * @param {string} routes_dir
213
- * @param {string} dir
214
- * @param {Map<string, NodeGroup>} groups
215
- * @param {import('typescript')} ts
216
- */
217
- function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts) {
218
- const group = groups.get(dir);
219
- if (!group) {
220
- return [];
221
- }
117
+ try {
118
+ fs.mkdirSync(outdir, { recursive: true });
119
+ } catch {}
120
+
121
+ const output_files = compact(
122
+ fs.readdirSync(outdir).map((name) => {
123
+ const stats = fs.statSync(path.join(outdir, name));
124
+ if (stats.isDirectory()) return;
125
+ return {
126
+ name,
127
+ updated: stats.mtimeMs
128
+ };
129
+ })
130
+ );
222
131
 
223
- const outdir = `${config.kit.outDir}/types/${routes_dir}/${dir}`;
132
+ const source_last_updated = Math.max(...input_files.map((file) => fs.statSync(file).mtimeMs));
133
+ const types_last_updated = Math.max(...output_files.map((file) => file?.updated));
224
134
 
225
- const imports = [`import type * as Kit from '@sveltejs/kit';`];
135
+ // types were generated more recently than the source files, so don't regenerate
136
+ if (types_last_updated > source_last_updated) return;
226
137
 
227
- /** @type {string[]} */
228
- const written_files = [];
138
+ // track which old files end up being surplus to requirements
139
+ const to_delete = new Set(output_files.map((file) => file.name));
140
+
141
+ const imports = [`import type * as Kit from '@sveltejs/kit';`];
229
142
 
230
143
  /** @type {string[]} */
231
144
  const declarations = [];
@@ -233,10 +146,8 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
233
146
  /** @type {string[]} */
234
147
  const exports = [];
235
148
 
236
- const route_params = parse_route_id(dir).names;
237
-
238
- if (route_params.length > 0) {
239
- const params = route_params.map((param) => `${param}: string`).join('; ');
149
+ if (route.names.length > 0) {
150
+ const params = route.names.map((param) => `${param}: string`).join('; ');
240
151
  declarations.push(
241
152
  `interface RouteParams extends Partial<Record<string, string>> { ${params} }`
242
153
  );
@@ -244,15 +155,14 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
244
155
  declarations.push(`interface RouteParams extends Partial<Record<string, string>> {}`);
245
156
  }
246
157
 
247
- if (group.leaf) {
158
+ if (route.leaf) {
248
159
  const { data, server_data, load, server_load, errors, written_proxies } = process_node(
249
- ts,
250
- group.leaf,
160
+ route.leaf,
251
161
  outdir,
252
- 'RouteParams',
253
- groups
162
+ 'RouteParams'
254
163
  );
255
- written_files.push(...written_proxies);
164
+
165
+ for (const file of written_proxies) to_delete.delete(file);
256
166
 
257
167
  exports.push(`export type Errors = ${errors};`);
258
168
 
@@ -272,20 +182,18 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
272
182
  exports.push('export type PageServerLoadEvent = Parameters<PageServerLoad>[0];');
273
183
  }
274
184
 
275
- if (group.leaf.server) {
185
+ if (route.leaf.server) {
276
186
  exports.push(`export type Action = Kit.Action<RouteParams>`);
277
187
  }
278
188
  }
279
189
 
280
- if (group.default_layout || group.named_layouts.size > 0) {
281
- // TODO to be completely rigorous, we should have a LayoutParams per
282
- // layout, and only include params for child pages that use each layout.
283
- // but that's more work than i care to do right now
190
+ if (route.layout) {
191
+ // TODO collect children in create_manifest_data, instead of this inefficient O(n^2) algorithm
284
192
  const layout_params = new Set();
285
- manifest_data.routes.forEach((route) => {
286
- if (route.type === 'page' && route.id.startsWith(dir + '/')) {
193
+ manifest_data.routes.forEach((other) => {
194
+ if (other.page && other.id.startsWith(route.id + '/')) {
287
195
  // TODO this is O(n^2), see if we need to speed it up
288
- for (const name of parse_route_id(route.id.slice(dir.length + 1)).names) {
196
+ for (const name of other.names) {
289
197
  layout_params.add(name);
290
198
  }
291
199
  }
@@ -298,95 +206,32 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
298
206
  declarations.push(`interface LayoutParams extends RouteParams {}`);
299
207
  }
300
208
 
301
- if (group.default_layout) {
302
- const { data, server_data, load, server_load, written_proxies } = process_node(
303
- ts,
304
- group.default_layout,
305
- outdir,
306
- 'LayoutParams',
307
- groups
308
- );
309
- written_files.push(...written_proxies);
310
-
311
- exports.push(`export type LayoutData = ${data};`);
312
- if (load) {
313
- exports.push(
314
- `export type LayoutLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
315
- );
316
- exports.push('export type LayoutLoadEvent = Parameters<LayoutLoad>[0];');
317
- }
318
-
319
- exports.push(`export type LayoutServerData = ${server_data};`);
320
- if (server_load) {
321
- exports.push(
322
- `export type LayoutServerLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
323
- );
324
- exports.push('export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0];');
325
- }
326
- }
209
+ const { data, server_data, load, server_load, written_proxies } = process_node(
210
+ route.layout,
211
+ outdir,
212
+ 'LayoutParams'
213
+ );
327
214
 
328
- if (group.named_layouts.size > 0) {
329
- /** @type {string[]} */
330
- const data_exports = [];
331
-
332
- /** @type {string[]} */
333
- const server_data_exports = [];
334
-
335
- /** @type {string[]} */
336
- const load_exports = [];
337
-
338
- /** @type {string[]} */
339
- const load_event_exports = [];
340
-
341
- /** @type {string[]} */
342
- const server_load_exports = [];
343
-
344
- /** @type {string[]} */
345
- const server_load_event_exports = [];
346
-
347
- for (const [name, node] of group.named_layouts) {
348
- const { data, server_data, load, server_load, written_proxies } = process_node(
349
- ts,
350
- node,
351
- outdir,
352
- 'LayoutParams',
353
- groups
354
- );
355
- written_files.push(...written_proxies);
356
- data_exports.push(`export type ${name} = ${data};`);
357
- server_data_exports.push(`export type ${name} = ${server_data};`);
358
- if (load) {
359
- load_exports.push(
360
- `export type ${name}<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
361
- );
362
- load_event_exports.push(`export type ${name} = Parameters<LayoutLoad.${name}>[0];`);
363
- }
364
- if (server_load) {
365
- server_load_exports.push(
366
- `export type ${name}<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
367
- );
368
- server_load_event_exports.push(
369
- `export type ${name} = Parameters<LayoutServerLoad.${name}>[0];`
370
- );
371
- }
372
- }
215
+ for (const file of written_proxies) to_delete.delete(file);
373
216
 
374
- exports.push(`\nexport namespace LayoutData {\n\t${data_exports.join('\n\t')}\n}`);
375
- exports.push(`\nexport namespace LayoutLoad {\n\t${load_exports.join('\n\t')}\n}`);
376
- exports.push(`\nexport namespace LayoutLoadEvent {\n\t${load_event_exports.join('\n\t')}\n}`);
377
- exports.push(
378
- `\nexport namespace LayoutServerData {\n\t${server_data_exports.join('\n\t')}\n}`
379
- );
217
+ exports.push(`export type LayoutData = ${data};`);
218
+ if (load) {
380
219
  exports.push(
381
- `\nexport namespace LayoutServerLoad {\n\t${server_load_exports.join('\n\t')}\n}`
220
+ `export type LayoutLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${load};`
382
221
  );
222
+ exports.push('export type LayoutLoadEvent = Parameters<LayoutLoad>[0];');
223
+ }
224
+
225
+ exports.push(`export type LayoutServerData = ${server_data};`);
226
+ if (server_load) {
383
227
  exports.push(
384
- `\nexport namespace LayoutServerLoadEvent {\n\t${server_load_event_exports.join('\n\t')}\n}`
228
+ `export type LayoutServerLoad<OutputData extends Record<string, any> | void = Record<string, any> | void> = ${server_load};`
385
229
  );
230
+ exports.push('export type LayoutServerLoadEvent = Parameters<LayoutServerLoad>[0];');
386
231
  }
387
232
  }
388
233
 
389
- if (group.endpoint) {
234
+ if (route.endpoint) {
390
235
  exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams>;`);
391
236
  exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams>;`);
392
237
  }
@@ -395,19 +240,20 @@ function write_types_for_dir(config, manifest_data, routes_dir, dir, groups, ts)
395
240
  .filter(Boolean)
396
241
  .join('\n\n');
397
242
 
398
- written_files.push(write(`${outdir}/$types.d.ts`, output));
243
+ fs.writeFileSync(`${outdir}/$types.d.ts`, output);
244
+ to_delete.delete('$types.d.ts');
399
245
 
400
- return written_files;
246
+ for (const file of to_delete) {
247
+ fs.unlinkSync(path.join(outdir, file));
248
+ }
401
249
  }
402
250
 
403
251
  /**
404
- * @param {import('typescript')} ts
405
- * @param {Node} node
252
+ * @param {import('types').PageNode} node
406
253
  * @param {string} outdir
407
254
  * @param {string} params
408
- * @param {Map<string, NodeGroup>} groups
409
255
  */
410
- function process_node(ts, node, outdir, params, groups) {
256
+ function process_node(node, outdir, params) {
411
257
  let data;
412
258
  let load;
413
259
  let server_load;
@@ -420,14 +266,18 @@ function process_node(ts, node, outdir, params, groups) {
420
266
 
421
267
  if (node.server) {
422
268
  const content = fs.readFileSync(node.server, 'utf8');
423
- const proxy = tweak_types(ts, content, server_names);
269
+ const proxy = tweak_types(content, server_names);
424
270
  const basename = path.basename(node.server);
425
271
  if (proxy?.modified) {
426
- written_proxies.push(write(`${outdir}/proxy${basename}`, proxy.code));
272
+ fs.writeFileSync(`${outdir}/proxy${basename}`, proxy.code);
273
+ written_proxies.push(`proxy${basename}`);
427
274
  }
428
275
 
429
276
  server_data = get_data_type(node.server, 'null', proxy);
430
- server_load = `Kit.ServerLoad<${params}, ${get_parent_type('LayoutServerData')}, OutputData>`;
277
+ server_load = `Kit.ServerLoad<${params}, ${get_parent_type(
278
+ node,
279
+ 'LayoutServerData'
280
+ )}, OutputData>`;
431
281
 
432
282
  if (proxy) {
433
283
  const types = [];
@@ -450,13 +300,14 @@ function process_node(ts, node, outdir, params, groups) {
450
300
  server_data = 'null';
451
301
  }
452
302
 
453
- const parent_type = get_parent_type('LayoutData');
303
+ const parent_type = get_parent_type(node, 'LayoutData');
454
304
 
455
305
  if (node.shared) {
456
306
  const content = fs.readFileSync(node.shared, 'utf8');
457
- const proxy = tweak_types(ts, content, shared_names);
307
+ const proxy = tweak_types(content, shared_names);
458
308
  if (proxy?.modified) {
459
- written_proxies.push(write(`${outdir}/proxy${path.basename(node.shared)}`, proxy.code));
309
+ fs.writeFileSync(`${outdir}/proxy${path.basename(node.shared)}`, proxy.code);
310
+ written_proxies.push(`proxy${path.basename(node.shared)}`);
460
311
  }
461
312
 
462
313
  const type = get_data_type(node.shared, `${parent_type} & ${server_data}`, proxy);
@@ -492,39 +343,35 @@ function process_node(ts, node, outdir, params, groups) {
492
343
  return 'unknown';
493
344
  }
494
345
  }
346
+ }
495
347
 
496
- /**
497
- * Get the parent type string by recursively looking up the parent layout and accumulate them to one type.
498
- * @param {string} type
499
- */
500
- function get_parent_type(type) {
501
- const parent_imports = [];
502
- let parent = node.parent;
503
- let acc_diff = 0;
504
-
505
- while (parent) {
506
- acc_diff += parent.folder_depth_diff;
507
- let parent_group = /** @type {NodeGroup} */ (groups.get(parent.key));
508
- // unshift because we need it the other way round for the import string
509
- parent_imports.unshift(
510
- (acc_diff === 0 ? '' : `import('` + '../'.repeat(acc_diff) + '$types.js' + `').`) +
511
- `${type}${parent.name ? `.${parent.name}` : ''}`
512
- );
513
- let parent_layout = /** @type {Node} */ (
514
- parent.name ? parent_group.named_layouts.get(parent.name) : parent_group.default_layout
515
- );
516
- parent = parent_layout.parent;
517
- }
348
+ /**
349
+ * Get the parent type string by recursively looking up the parent layout and accumulate them to one type.
350
+ * @param {import('types').PageNode} node
351
+ * @param {string} type
352
+ */
353
+ function get_parent_type(node, type) {
354
+ const parent_imports = [];
518
355
 
519
- let parent_str = parent_imports[0] || 'Record<never, never>';
520
- for (let i = 1; i < parent_imports.length; i++) {
521
- // Omit is necessary because a parent could have a property with the same key which would
522
- // cause a type conflict. At runtime the child overwrites the parent property in this case,
523
- // so reflect that in the type definition.
524
- parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & ${parent_imports[i]}`;
525
- }
526
- return parent_str;
356
+ let parent = node.parent;
357
+
358
+ while (parent) {
359
+ const d = node.depth - parent.depth;
360
+ // unshift because we need it the other way round for the import string
361
+ parent_imports.unshift(
362
+ `${d === 0 ? '' : `import('${'../'.repeat(d)}${'$types.js'}').`}${type}`
363
+ );
364
+ parent = parent.parent;
365
+ }
366
+
367
+ let parent_str = parent_imports[0] || 'Record<never, never>';
368
+ for (let i = 1; i < parent_imports.length; i++) {
369
+ // Omit is necessary because a parent could have a property with the same key which would
370
+ // cause a type conflict. At runtime the child overwrites the parent property in this case,
371
+ // so reflect that in the type definition.
372
+ parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & ${parent_imports[i]}`;
527
373
  }
374
+ return parent_str;
528
375
  }
529
376
 
530
377
  /**
@@ -546,12 +393,11 @@ function replace_ext_with_js(file_path) {
546
393
  }
547
394
 
548
395
  /**
549
- * @param {import('typescript')} ts
550
396
  * @param {string} content
551
397
  * @param {Set<string>} names
552
398
  * @returns {Proxy}
553
399
  */
554
- export function tweak_types(ts, content, names) {
400
+ export function tweak_types(content, names) {
555
401
  try {
556
402
  let modified = false;
557
403
 
@@ -699,77 +545,3 @@ export function tweak_types(ts, content, names) {
699
545
  return null;
700
546
  }
701
547
  }
702
-
703
- /**
704
- * @param {string} file
705
- * @param {string} content
706
- */
707
- function write(file, content) {
708
- write_if_changed(file, content);
709
- return file;
710
- }
711
-
712
- /**
713
- * Finds the nearest layout for given node.
714
- * Assumes that nodes is sorted by path length (lowest first).
715
- *
716
- * @param {string} routes_dir
717
- * @param {import('types').PageNode[]} nodes
718
- * @param {number} start_idx
719
- */
720
- export function find_nearest_layout(routes_dir, nodes, start_idx) {
721
- const start_file = /** @type {string} */ (
722
- nodes[start_idx].component || nodes[start_idx].shared || nodes[start_idx].server
723
- );
724
-
725
- let name = '';
726
- const match = /^\+(layout|page)(?:-([^@.]+))?(?:@([^@.]+))?/.exec(path.basename(start_file));
727
- if (!match) throw new Error(`Unexpected route file: ${start_file}`);
728
- if (match[3] && match[3] !== 'default') {
729
- name = match[3]; // a named layout is referenced
730
- }
731
-
732
- let common_path = path.dirname(start_file);
733
- if (match[1] === 'layout' && !match[2] && !name) {
734
- // We are a default layout, so we skip the current level
735
- common_path = path.dirname(common_path);
736
- }
737
-
738
- for (let i = start_idx - 1; i >= 0; i -= 1) {
739
- const node = nodes[i];
740
- const file = /** @type {string} */ (node.component || node.shared || node.server);
741
-
742
- const current_path = path.dirname(file);
743
- const common_path_length = common_path.split('/').length;
744
- const current_path_length = current_path.split('/').length;
745
-
746
- if (common_path_length < current_path_length) {
747
- // this is a layout in a different tree
748
- continue;
749
- } else if (common_path_length > current_path_length) {
750
- // we've gone back up a folder level
751
- common_path = path.dirname(common_path);
752
- }
753
- if (common_path !== current_path) {
754
- // this is a layout in a different tree
755
- continue;
756
- }
757
- if (
758
- path.basename(file, path.extname(file)).split('@')[0] !==
759
- '+layout' + (name ? `-${name}` : '')
760
- ) {
761
- // this is not the layout we are searching for
762
- continue;
763
- }
764
-
765
- // matching parent layout found
766
- let folder_depth_diff =
767
- posixify(path.relative(path.dirname(start_file), common_path + '/$types.js')).split('/')
768
- .length - 1;
769
- return {
770
- key: path.dirname(file).slice(routes_dir.length + 1),
771
- name,
772
- folder_depth_diff
773
- };
774
- }
775
- }