@sveltejs/kit 1.0.0-next.291 → 1.0.0-next.292
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.
- package/assets/client/start.js +18 -11
- package/assets/server/index.js +24 -10
- package/dist/chunks/filesystem.js +110 -0
- package/dist/chunks/index.js +8 -9
- package/dist/chunks/index2.js +692 -38
- package/dist/chunks/index3.js +8 -10
- package/dist/chunks/index4.js +42 -738
- package/dist/chunks/index5.js +157 -75
- package/dist/chunks/index6.js +2 -1
- package/dist/chunks/object.js +83 -0
- package/dist/chunks/{tsconfig.js → sync.js} +327 -360
- package/dist/chunks/url.js +56 -0
- package/dist/cli.js +24 -135
- package/package.json +5 -19
- package/types/ambient.d.ts +4 -0
- package/types/index.d.ts +3 -1
- package/types/internal.d.ts +12 -7
- package/types/private.d.ts +13 -5
|
@@ -1,348 +1,13 @@
|
|
|
1
|
-
import fs__default from 'fs';
|
|
2
1
|
import path__default from 'path';
|
|
2
|
+
import fs__default from 'fs';
|
|
3
|
+
import { g as get_runtime_path, $ } from '../cli.js';
|
|
4
|
+
import { p as posixify, c as copy, m as mkdirp } from './filesystem.js';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
3
6
|
import { s } from './misc.js';
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* deeply merged together. None of the original objects will be mutated at any
|
|
9
|
-
* level, and the returned object will have no references to the original
|
|
10
|
-
* objects at any depth. If there's a conflict the last one wins, except for
|
|
11
|
-
* arrays which will be combined.
|
|
12
|
-
* @param {...Object} objects
|
|
13
|
-
* @returns {[Record<string, any>, string[]]} a 2-tuple with the merged object,
|
|
14
|
-
* and a list of merge conflicts if there were any, in dotted notation
|
|
15
|
-
*/
|
|
16
|
-
function deep_merge(...objects) {
|
|
17
|
-
const result = {};
|
|
18
|
-
/** @type {string[]} */
|
|
19
|
-
const conflicts = [];
|
|
20
|
-
objects.forEach((o) => merge_into(result, o, conflicts));
|
|
21
|
-
return [result, conflicts];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* normalize kit.vite.resolve.alias as an array
|
|
26
|
-
* @param {import('vite').AliasOptions} o
|
|
27
|
-
* @returns {import('vite').Alias[]}
|
|
28
|
-
*/
|
|
29
|
-
function normalize_alias(o) {
|
|
30
|
-
if (Array.isArray(o)) return o;
|
|
31
|
-
return Object.entries(o).map(([find, replacement]) => ({ find, replacement }));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Merges b into a, recursively, mutating a.
|
|
36
|
-
* @param {Record<string, any>} a
|
|
37
|
-
* @param {Record<string, any>} b
|
|
38
|
-
* @param {string[]} conflicts array to accumulate conflicts in
|
|
39
|
-
* @param {string[]} path array of property names representing the current
|
|
40
|
-
* location in the tree
|
|
41
|
-
*/
|
|
42
|
-
function merge_into(a, b, conflicts = [], path = []) {
|
|
43
|
-
/**
|
|
44
|
-
* Checks for "plain old Javascript object", typically made as an object
|
|
45
|
-
* literal. Excludes Arrays and built-in types like Buffer.
|
|
46
|
-
* @param {any} x
|
|
47
|
-
*/
|
|
48
|
-
const is_plain_object = (x) => typeof x === 'object' && x.constructor === Object;
|
|
49
|
-
|
|
50
|
-
for (const prop in b) {
|
|
51
|
-
// normalize alias objects to array
|
|
52
|
-
if (prop === 'alias' && path[path.length - 1] === 'resolve') {
|
|
53
|
-
if (a[prop]) a[prop] = normalize_alias(a[prop]);
|
|
54
|
-
if (b[prop]) b[prop] = normalize_alias(b[prop]);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (is_plain_object(b[prop])) {
|
|
58
|
-
if (!is_plain_object(a[prop])) {
|
|
59
|
-
if (a[prop] !== undefined) {
|
|
60
|
-
conflicts.push([...path, prop].join('.'));
|
|
61
|
-
}
|
|
62
|
-
a[prop] = {};
|
|
63
|
-
}
|
|
64
|
-
merge_into(a[prop], b[prop], conflicts, [...path, prop]);
|
|
65
|
-
} else if (Array.isArray(b[prop])) {
|
|
66
|
-
if (!Array.isArray(a[prop])) {
|
|
67
|
-
if (a[prop] !== undefined) {
|
|
68
|
-
conflicts.push([...path, prop].join('.'));
|
|
69
|
-
}
|
|
70
|
-
a[prop] = [];
|
|
71
|
-
}
|
|
72
|
-
a[prop].push(...b[prop]);
|
|
73
|
-
} else {
|
|
74
|
-
// Since we're inside a for/in loop which loops over enumerable
|
|
75
|
-
// properties only, we want parity here and to check if 'a' has
|
|
76
|
-
// enumerable-only property 'prop'. Using 'hasOwnProperty' to
|
|
77
|
-
// exclude inherited properties is close enough. It is possible
|
|
78
|
-
// that someone uses Object.defineProperty to create a direct,
|
|
79
|
-
// non-enumerable property but let's not worry about that.
|
|
80
|
-
if (Object.prototype.hasOwnProperty.call(a, prop)) {
|
|
81
|
-
conflicts.push([...path, prop].join('.'));
|
|
82
|
-
}
|
|
83
|
-
a[prop] = b[prop];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** @type {Map<string, string>} */
|
|
89
|
-
const previous_contents = new Map();
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @param {string} file
|
|
93
|
-
* @param {string} code
|
|
94
|
-
*/
|
|
95
|
-
function write_if_changed(file, code) {
|
|
96
|
-
if (code !== previous_contents.get(file)) {
|
|
97
|
-
previous_contents.set(file, code);
|
|
98
|
-
mkdirp(path__default.dirname(file));
|
|
99
|
-
fs__default.writeFileSync(file, code);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** @typedef {import('types').ManifestData} ManifestData */
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* @param {{
|
|
107
|
-
* config: import('types').ValidatedConfig;
|
|
108
|
-
* manifest_data: ManifestData;
|
|
109
|
-
* cwd: string;
|
|
110
|
-
* }} options
|
|
111
|
-
*/
|
|
112
|
-
function create_app({ config, manifest_data, cwd = process.cwd() }) {
|
|
113
|
-
const output = path__default.join(config.kit.outDir, 'generated');
|
|
114
|
-
const base = path__default.relative(cwd, output);
|
|
115
|
-
|
|
116
|
-
write_if_changed(`${output}/manifest.js`, generate_client_manifest(manifest_data, base));
|
|
117
|
-
write_if_changed(`${output}/root.svelte`, generate_app(manifest_data));
|
|
118
|
-
|
|
119
|
-
create_types(config, manifest_data);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* @param {string} str
|
|
124
|
-
*/
|
|
125
|
-
function trim(str) {
|
|
126
|
-
return str.replace(/^\t\t/gm, '').trim();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* @param {ManifestData} manifest_data
|
|
131
|
-
* @param {string} base
|
|
132
|
-
*/
|
|
133
|
-
function generate_client_manifest(manifest_data, base) {
|
|
134
|
-
/** @type {Record<string, number>} */
|
|
135
|
-
const component_indexes = {};
|
|
136
|
-
|
|
137
|
-
/** @param {string} c */
|
|
138
|
-
const get_path = (c) => path__default.relative(base, c);
|
|
139
|
-
|
|
140
|
-
const components = `[
|
|
141
|
-
${manifest_data.components
|
|
142
|
-
.map((component, i) => {
|
|
143
|
-
component_indexes[component] = i;
|
|
144
|
-
|
|
145
|
-
return `() => import(${s(get_path(component))})`;
|
|
146
|
-
})
|
|
147
|
-
.join(',\n\t\t\t\t')}
|
|
148
|
-
]`.replace(/^\t/gm, '');
|
|
149
|
-
|
|
150
|
-
/** @param {string[]} parts */
|
|
151
|
-
const get_indices = (parts) =>
|
|
152
|
-
`[${parts.map((part) => (part ? `c[${component_indexes[part]}]` : '')).join(', ')}]`;
|
|
153
|
-
|
|
154
|
-
const routes = `[
|
|
155
|
-
${manifest_data.routes
|
|
156
|
-
.map((route) => {
|
|
157
|
-
if (route.type === 'page') {
|
|
158
|
-
const params =
|
|
159
|
-
route.params.length > 0 &&
|
|
160
|
-
'(m) => ({ ' +
|
|
161
|
-
route.params
|
|
162
|
-
.map((param, i) => {
|
|
163
|
-
return param.startsWith('...')
|
|
164
|
-
? `${param.slice(3)}: d(m[${i + 1}] || '')`
|
|
165
|
-
: `${param}: d(m[${i + 1}])`;
|
|
166
|
-
})
|
|
167
|
-
.join(', ') +
|
|
168
|
-
'})';
|
|
169
|
-
|
|
170
|
-
const tuple = [route.pattern, get_indices(route.a), get_indices(route.b)];
|
|
171
|
-
|
|
172
|
-
// optional items
|
|
173
|
-
if (params || route.shadow) tuple.push(params || 'null');
|
|
174
|
-
if (route.shadow) tuple.push('1');
|
|
175
|
-
|
|
176
|
-
return `// ${route.a[route.a.length - 1]}\n\t\t[${tuple.join(', ')}]`;
|
|
177
|
-
}
|
|
178
|
-
})
|
|
179
|
-
.filter(Boolean)
|
|
180
|
-
.join(',\n\n\t\t')}
|
|
181
|
-
]`.replace(/^\t/gm, '');
|
|
182
|
-
|
|
183
|
-
return trim(`
|
|
184
|
-
const c = ${components};
|
|
185
|
-
|
|
186
|
-
const d = decodeURIComponent;
|
|
187
|
-
|
|
188
|
-
export const routes = ${routes};
|
|
189
|
-
|
|
190
|
-
// we import the root layout/error components eagerly, so that
|
|
191
|
-
// connectivity errors after initialisation don't nuke the app
|
|
192
|
-
export const fallback = [c[0](), c[1]()];
|
|
193
|
-
`);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* @param {ManifestData} manifest_data
|
|
198
|
-
*/
|
|
199
|
-
function generate_app(manifest_data) {
|
|
200
|
-
// TODO remove default layout altogether
|
|
201
|
-
|
|
202
|
-
const max_depth = Math.max(
|
|
203
|
-
...manifest_data.routes.map((route) =>
|
|
204
|
-
route.type === 'page' ? route.a.filter(Boolean).length : 0
|
|
205
|
-
),
|
|
206
|
-
1
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
const levels = [];
|
|
210
|
-
for (let i = 0; i <= max_depth; i += 1) {
|
|
211
|
-
levels.push(i);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
let l = max_depth;
|
|
215
|
-
|
|
216
|
-
let pyramid = `<svelte:component this={components[${l}]} {...(props_${l} || {})}/>`;
|
|
217
|
-
|
|
218
|
-
while (l--) {
|
|
219
|
-
pyramid = `
|
|
220
|
-
{#if components[${l + 1}]}
|
|
221
|
-
<svelte:component this={components[${l}]} {...(props_${l} || {})}>
|
|
222
|
-
${pyramid.replace(/\n/g, '\n\t\t\t\t\t')}
|
|
223
|
-
</svelte:component>
|
|
224
|
-
{:else}
|
|
225
|
-
<svelte:component this={components[${l}]} {...(props_${l} || {})} />
|
|
226
|
-
{/if}
|
|
227
|
-
`
|
|
228
|
-
.replace(/^\t\t\t/gm, '')
|
|
229
|
-
.trim();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return trim(`
|
|
233
|
-
<!-- This file is generated by @sveltejs/kit — do not edit it! -->
|
|
234
|
-
<script>
|
|
235
|
-
import { setContext, afterUpdate, onMount } from 'svelte';
|
|
236
|
-
|
|
237
|
-
// stores
|
|
238
|
-
export let stores;
|
|
239
|
-
export let page;
|
|
240
|
-
|
|
241
|
-
export let components;
|
|
242
|
-
${levels.map((l) => `export let props_${l} = null;`).join('\n\t\t\t')}
|
|
243
|
-
|
|
244
|
-
setContext('__svelte__', stores);
|
|
245
|
-
|
|
246
|
-
$: stores.page.set(page);
|
|
247
|
-
afterUpdate(stores.page.notify);
|
|
248
|
-
|
|
249
|
-
let mounted = false;
|
|
250
|
-
let navigated = false;
|
|
251
|
-
let title = null;
|
|
252
|
-
|
|
253
|
-
onMount(() => {
|
|
254
|
-
const unsubscribe = stores.page.subscribe(() => {
|
|
255
|
-
if (mounted) {
|
|
256
|
-
navigated = true;
|
|
257
|
-
title = document.title || 'untitled page';
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
mounted = true;
|
|
262
|
-
return unsubscribe;
|
|
263
|
-
});
|
|
264
|
-
</script>
|
|
265
|
-
|
|
266
|
-
${pyramid.replace(/\n/g, '\n\t\t')}
|
|
267
|
-
|
|
268
|
-
{#if mounted}
|
|
269
|
-
<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px">
|
|
270
|
-
{#if navigated}
|
|
271
|
-
{title}
|
|
272
|
-
{/if}
|
|
273
|
-
</div>
|
|
274
|
-
{/if}
|
|
275
|
-
`);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* @param {import('types').ValidatedConfig} config
|
|
280
|
-
* @param {ManifestData} manifest_data
|
|
281
|
-
*/
|
|
282
|
-
function create_types(config, manifest_data) {
|
|
283
|
-
/** @type {Map<string, { params: string[], type: 'page' | 'endpoint' | 'both' }>} */
|
|
284
|
-
const shadow_types = new Map();
|
|
285
|
-
|
|
286
|
-
/** @param {string} key */
|
|
287
|
-
function extract_params(key) {
|
|
288
|
-
/** @type {string[]} */
|
|
289
|
-
const params = [];
|
|
290
|
-
|
|
291
|
-
const pattern = /\[([^\]]+)\]/g;
|
|
292
|
-
let match;
|
|
293
|
-
|
|
294
|
-
while ((match = pattern.exec(key))) {
|
|
295
|
-
params.push(match[1]);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return params;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
manifest_data.routes.forEach((route) => {
|
|
302
|
-
if (route.type === 'endpoint') {
|
|
303
|
-
const key = route.file.slice(0, -path__default.extname(route.file).length);
|
|
304
|
-
shadow_types.set(key, { params: extract_params(key), type: 'endpoint' });
|
|
305
|
-
} else if (route.shadow) {
|
|
306
|
-
const key = route.shadow.slice(0, -path__default.extname(route.shadow).length);
|
|
307
|
-
shadow_types.set(key, { params: extract_params(key), type: 'both' });
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
manifest_data.components.forEach((component) => {
|
|
312
|
-
if (component.startsWith('.')) return; // exclude fallback components
|
|
313
|
-
|
|
314
|
-
const ext = /** @type {string} */ (config.extensions.find((ext) => component.endsWith(ext)));
|
|
315
|
-
const key = component.slice(0, -ext.length);
|
|
316
|
-
|
|
317
|
-
if (!shadow_types.has(key)) {
|
|
318
|
-
shadow_types.set(key, { params: extract_params(key), type: 'page' });
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
shadow_types.forEach(({ params, type }, key) => {
|
|
323
|
-
const arg = `{ ${params.map((param) => `${param}: string`).join('; ')} }`;
|
|
324
|
-
|
|
325
|
-
const imports = [
|
|
326
|
-
type !== 'page' && 'RequestHandler as GenericRequestHandler',
|
|
327
|
-
type !== 'endpoint' && 'Load as GenericLoad'
|
|
328
|
-
]
|
|
329
|
-
.filter(Boolean)
|
|
330
|
-
.join(', ');
|
|
331
|
-
|
|
332
|
-
const file = `${config.kit.outDir}/types/${key || 'index'}.d.ts`;
|
|
333
|
-
const content = [
|
|
334
|
-
'// this file is auto-generated',
|
|
335
|
-
`import type { ${imports} } from '@sveltejs/kit';`,
|
|
336
|
-
type !== 'page' && `export type RequestHandler = GenericRequestHandler<${arg}>;`,
|
|
337
|
-
type !== 'endpoint' &&
|
|
338
|
-
`export type Load<Props = Record<string, any>> = GenericLoad<${arg}, Props>;`
|
|
339
|
-
]
|
|
340
|
-
.filter(Boolean)
|
|
341
|
-
.join('\n');
|
|
342
|
-
|
|
343
|
-
write_if_changed(file, content);
|
|
344
|
-
});
|
|
345
|
-
}
|
|
7
|
+
import 'sade';
|
|
8
|
+
import 'child_process';
|
|
9
|
+
import 'net';
|
|
10
|
+
import 'os';
|
|
346
11
|
|
|
347
12
|
/**
|
|
348
13
|
* @param typeMap [Object] Map of MIME type -> Array[extensions]
|
|
@@ -517,7 +182,12 @@ function create_manifest_data({
|
|
|
517
182
|
const file = posixify(path__default.relative(cwd, resolved));
|
|
518
183
|
const is_dir = fs__default.statSync(resolved).isDirectory();
|
|
519
184
|
|
|
520
|
-
const ext =
|
|
185
|
+
const ext = is_dir
|
|
186
|
+
? ''
|
|
187
|
+
: config.extensions.find((ext) => basename.endsWith(ext)) ||
|
|
188
|
+
config.kit.endpointExtensions.find((ext) => basename.endsWith(ext));
|
|
189
|
+
|
|
190
|
+
if (ext === undefined) return;
|
|
521
191
|
|
|
522
192
|
const name = ext ? basename.slice(0, -ext.length) : basename;
|
|
523
193
|
|
|
@@ -704,20 +374,19 @@ function create_manifest_data({
|
|
|
704
374
|
|
|
705
375
|
walk(config.kit.files.routes, [], [], [], [layout], [error]);
|
|
706
376
|
|
|
707
|
-
|
|
377
|
+
const lookup = new Map();
|
|
378
|
+
for (const route of routes) {
|
|
379
|
+
if (route.type === 'page') {
|
|
380
|
+
lookup.set(route.key, route);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
708
384
|
let i = routes.length;
|
|
709
385
|
while (i--) {
|
|
710
386
|
const route = routes[i];
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
if (prev.type !== 'endpoint' || route.type !== 'page') {
|
|
715
|
-
const relative = path__default.relative(cwd, path__default.resolve(config.kit.files.routes, prev.key));
|
|
716
|
-
throw new Error(`Duplicate route files: ${relative}`);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
route.shadow = prev.file;
|
|
720
|
-
routes.splice(--i, 1);
|
|
387
|
+
if (route.type === 'endpoint' && lookup.has(route.key)) {
|
|
388
|
+
lookup.get(route.key).shadow = route.file;
|
|
389
|
+
routes.splice(i, 1);
|
|
721
390
|
}
|
|
722
391
|
}
|
|
723
392
|
|
|
@@ -905,18 +574,215 @@ function list_files({ config, dir, path, files = [] }) {
|
|
|
905
574
|
return files;
|
|
906
575
|
}
|
|
907
576
|
|
|
577
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
578
|
+
const __dirname = path__default.dirname(__filename);
|
|
579
|
+
|
|
580
|
+
/** @param {string} dest */
|
|
581
|
+
function copy_assets(dest) {
|
|
582
|
+
let prefix = '..';
|
|
583
|
+
do {
|
|
584
|
+
// we jump through these hoops so that this function
|
|
585
|
+
// works whether or not it's been bundled
|
|
586
|
+
const resolved = path__default.resolve(__dirname, `${prefix}/assets`);
|
|
587
|
+
|
|
588
|
+
if (fs__default.existsSync(resolved)) {
|
|
589
|
+
copy(resolved, dest);
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
prefix = `../${prefix}`;
|
|
594
|
+
} while (true); // eslint-disable-line
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/** @type {Map<string, string>} */
|
|
598
|
+
const previous_contents = new Map();
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* @param {string} file
|
|
602
|
+
* @param {string} code
|
|
603
|
+
*/
|
|
604
|
+
function write_if_changed(file, code) {
|
|
605
|
+
if (code !== previous_contents.get(file)) {
|
|
606
|
+
previous_contents.set(file, code);
|
|
607
|
+
mkdirp(path__default.dirname(file));
|
|
608
|
+
fs__default.writeFileSync(file, code);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** @param {string} str */
|
|
613
|
+
function trim(str) {
|
|
614
|
+
const indentation = /** @type {RegExpExecArray} */ (/\n?(\s*)/.exec(str))[1];
|
|
615
|
+
const pattern = new RegExp(`^${indentation}`, 'gm');
|
|
616
|
+
return str.replace(pattern, '').trim();
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @param {import('types').ManifestData} manifest_data
|
|
621
|
+
* @param {string} base
|
|
622
|
+
* @param {string} output
|
|
623
|
+
*/
|
|
624
|
+
function write_manifest(manifest_data, base, output) {
|
|
625
|
+
/** @type {Record<string, number>} */
|
|
626
|
+
const component_indexes = {};
|
|
627
|
+
|
|
628
|
+
/** @param {string} c */
|
|
629
|
+
const get_path = (c) => path__default.relative(base, c);
|
|
630
|
+
|
|
631
|
+
const components = `[
|
|
632
|
+
${manifest_data.components
|
|
633
|
+
.map((component, i) => {
|
|
634
|
+
component_indexes[component] = i;
|
|
635
|
+
|
|
636
|
+
return `() => import(${s(get_path(component))})`;
|
|
637
|
+
})
|
|
638
|
+
.join(',\n\t\t\t\t\t')}
|
|
639
|
+
]`.replace(/^\t/gm, '');
|
|
640
|
+
|
|
641
|
+
/** @param {string[]} parts */
|
|
642
|
+
const get_indices = (parts) =>
|
|
643
|
+
`[${parts.map((part) => (part ? `c[${component_indexes[part]}]` : '')).join(', ')}]`;
|
|
644
|
+
|
|
645
|
+
const routes = `[
|
|
646
|
+
${manifest_data.routes
|
|
647
|
+
.map((route) => {
|
|
648
|
+
if (route.type === 'page') {
|
|
649
|
+
const params =
|
|
650
|
+
route.params.length > 0 &&
|
|
651
|
+
'(m) => ({ ' +
|
|
652
|
+
route.params
|
|
653
|
+
.map((param, i) => {
|
|
654
|
+
return param.startsWith('...')
|
|
655
|
+
? `${param.slice(3)}: d(m[${i + 1}] || '')`
|
|
656
|
+
: `${param}: d(m[${i + 1}])`;
|
|
657
|
+
})
|
|
658
|
+
.join(', ') +
|
|
659
|
+
'})';
|
|
660
|
+
|
|
661
|
+
const tuple = [route.pattern, get_indices(route.a), get_indices(route.b)];
|
|
662
|
+
|
|
663
|
+
// optional items
|
|
664
|
+
if (params || route.shadow) tuple.push(params || 'null');
|
|
665
|
+
if (route.shadow) tuple.push(`'${route.key}'`);
|
|
666
|
+
|
|
667
|
+
return `// ${route.a[route.a.length - 1]}\n\t\t[${tuple.join(', ')}]`;
|
|
668
|
+
}
|
|
669
|
+
})
|
|
670
|
+
.filter(Boolean)
|
|
671
|
+
.join(',\n\n\t\t')}
|
|
672
|
+
]`.replace(/^\t/gm, '');
|
|
673
|
+
|
|
674
|
+
write_if_changed(
|
|
675
|
+
`${output}/manifest.js`,
|
|
676
|
+
trim(`
|
|
677
|
+
const c = ${components};
|
|
678
|
+
|
|
679
|
+
const d = decodeURIComponent;
|
|
680
|
+
|
|
681
|
+
export const routes = ${routes};
|
|
682
|
+
|
|
683
|
+
// we import the root layout/error components eagerly, so that
|
|
684
|
+
// connectivity errors after initialisation don't nuke the app
|
|
685
|
+
export const fallback = [c[0](), c[1]()];
|
|
686
|
+
`)
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* @param {import('types').ManifestData} manifest_data
|
|
692
|
+
* @param {string} output
|
|
693
|
+
*/
|
|
694
|
+
function write_root(manifest_data, output) {
|
|
695
|
+
// TODO remove default layout altogether
|
|
696
|
+
|
|
697
|
+
const max_depth = Math.max(
|
|
698
|
+
...manifest_data.routes.map((route) =>
|
|
699
|
+
route.type === 'page' ? route.a.filter(Boolean).length : 0
|
|
700
|
+
),
|
|
701
|
+
1
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
const levels = [];
|
|
705
|
+
for (let i = 0; i <= max_depth; i += 1) {
|
|
706
|
+
levels.push(i);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
let l = max_depth;
|
|
710
|
+
|
|
711
|
+
let pyramid = `<svelte:component this={components[${l}]} {...(props_${l} || {})}/>`;
|
|
712
|
+
|
|
713
|
+
while (l--) {
|
|
714
|
+
pyramid = `
|
|
715
|
+
{#if components[${l + 1}]}
|
|
716
|
+
<svelte:component this={components[${l}]} {...(props_${l} || {})}>
|
|
717
|
+
${pyramid.replace(/\n/g, '\n\t\t\t\t\t')}
|
|
718
|
+
</svelte:component>
|
|
719
|
+
{:else}
|
|
720
|
+
<svelte:component this={components[${l}]} {...(props_${l} || {})} />
|
|
721
|
+
{/if}
|
|
722
|
+
`
|
|
723
|
+
.replace(/^\t\t\t/gm, '')
|
|
724
|
+
.trim();
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
write_if_changed(
|
|
728
|
+
`${output}/root.svelte`,
|
|
729
|
+
trim(`
|
|
730
|
+
<!-- This file is generated by @sveltejs/kit — do not edit it! -->
|
|
731
|
+
<script>
|
|
732
|
+
import { setContext, afterUpdate, onMount } from 'svelte';
|
|
733
|
+
|
|
734
|
+
// stores
|
|
735
|
+
export let stores;
|
|
736
|
+
export let page;
|
|
737
|
+
|
|
738
|
+
export let components;
|
|
739
|
+
${levels.map((l) => `export let props_${l} = null;`).join('\n\t\t\t\t')}
|
|
740
|
+
|
|
741
|
+
setContext('__svelte__', stores);
|
|
742
|
+
|
|
743
|
+
$: stores.page.set(page);
|
|
744
|
+
afterUpdate(stores.page.notify);
|
|
745
|
+
|
|
746
|
+
let mounted = false;
|
|
747
|
+
let navigated = false;
|
|
748
|
+
let title = null;
|
|
749
|
+
|
|
750
|
+
onMount(() => {
|
|
751
|
+
const unsubscribe = stores.page.subscribe(() => {
|
|
752
|
+
if (mounted) {
|
|
753
|
+
navigated = true;
|
|
754
|
+
title = document.title || 'untitled page';
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
mounted = true;
|
|
759
|
+
return unsubscribe;
|
|
760
|
+
});
|
|
761
|
+
</script>
|
|
762
|
+
|
|
763
|
+
${pyramid.replace(/\n/g, '\n\t\t\t')}
|
|
764
|
+
|
|
765
|
+
{#if mounted}
|
|
766
|
+
<div id="svelte-announcer" aria-live="assertive" aria-atomic="true" style="position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px">
|
|
767
|
+
{#if navigated}
|
|
768
|
+
{title}
|
|
769
|
+
{/if}
|
|
770
|
+
</div>
|
|
771
|
+
{/if}
|
|
772
|
+
`)
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
908
776
|
/** @param {string} file */
|
|
909
777
|
const exists = (file) => fs__default.existsSync(file) && file;
|
|
910
778
|
|
|
911
779
|
/** @param {import('types').ValidatedConfig} config */
|
|
912
|
-
function
|
|
780
|
+
function write_tsconfig(config) {
|
|
913
781
|
const out = path__default.join(config.kit.outDir, 'tsconfig.json');
|
|
914
782
|
const user_file = exists('tsconfig.json') || exists('jsconfig.json');
|
|
915
783
|
|
|
916
784
|
if (user_file) validate(config, out, user_file);
|
|
917
785
|
|
|
918
|
-
mkdirp(config.kit.outDir);
|
|
919
|
-
|
|
920
786
|
/** @param {string} file */
|
|
921
787
|
const project_relative = (file) => posixify(path__default.relative('.', file));
|
|
922
788
|
|
|
@@ -936,7 +802,7 @@ function generate_tsconfig(config) {
|
|
|
936
802
|
include.push(config_relative(`${dir}/**/*.svelte`));
|
|
937
803
|
});
|
|
938
804
|
|
|
939
|
-
|
|
805
|
+
write_if_changed(
|
|
940
806
|
out,
|
|
941
807
|
JSON.stringify(
|
|
942
808
|
{
|
|
@@ -1029,4 +895,105 @@ function validate(config, out, user_file) {
|
|
|
1029
895
|
}
|
|
1030
896
|
}
|
|
1031
897
|
|
|
1032
|
-
|
|
898
|
+
/**
|
|
899
|
+
* @param {import('types').ValidatedConfig} config
|
|
900
|
+
* @param {import('types').ManifestData} manifest_data
|
|
901
|
+
*/
|
|
902
|
+
function write_types(config, manifest_data) {
|
|
903
|
+
/** @type {Map<string, { params: string[], type: 'page' | 'endpoint' | 'both' }>} */
|
|
904
|
+
const shadow_types = new Map();
|
|
905
|
+
|
|
906
|
+
/** @param {string} key */
|
|
907
|
+
function extract_params(key) {
|
|
908
|
+
/** @type {string[]} */
|
|
909
|
+
const params = [];
|
|
910
|
+
|
|
911
|
+
const pattern = /\[([^\]]+)\]/g;
|
|
912
|
+
let match;
|
|
913
|
+
|
|
914
|
+
while ((match = pattern.exec(key))) {
|
|
915
|
+
params.push(match[1]);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
return params;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
manifest_data.routes.forEach((route) => {
|
|
922
|
+
const file = route.type === 'endpoint' ? route.file : route.shadow;
|
|
923
|
+
|
|
924
|
+
if (file) {
|
|
925
|
+
const ext = /** @type {string} */ (
|
|
926
|
+
config.kit.endpointExtensions.find((ext) => file.endsWith(ext))
|
|
927
|
+
);
|
|
928
|
+
const key = file.slice(0, -ext.length);
|
|
929
|
+
shadow_types.set(key, {
|
|
930
|
+
params: extract_params(key),
|
|
931
|
+
type: route.type === 'endpoint' ? 'endpoint' : 'both'
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
manifest_data.components.forEach((component) => {
|
|
937
|
+
if (component.startsWith('.')) return; // exclude fallback components
|
|
938
|
+
|
|
939
|
+
const ext = /** @type {string} */ (config.extensions.find((ext) => component.endsWith(ext)));
|
|
940
|
+
const key = component.slice(0, -ext.length);
|
|
941
|
+
|
|
942
|
+
if (!shadow_types.has(key)) {
|
|
943
|
+
shadow_types.set(key, { params: extract_params(key), type: 'page' });
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
shadow_types.forEach(({ params, type }, key) => {
|
|
948
|
+
const arg =
|
|
949
|
+
params.length > 0 ? `{ ${params.map((param) => `${param}: string`).join('; ')} }` : '{}';
|
|
950
|
+
|
|
951
|
+
const imports = [
|
|
952
|
+
type !== 'page' && 'RequestHandler as GenericRequestHandler',
|
|
953
|
+
type !== 'endpoint' && 'Load as GenericLoad'
|
|
954
|
+
]
|
|
955
|
+
.filter(Boolean)
|
|
956
|
+
.join(', ');
|
|
957
|
+
|
|
958
|
+
const file = `${config.kit.outDir}/types/${key || 'index'}.d.ts`;
|
|
959
|
+
const content = [
|
|
960
|
+
'// this file is auto-generated',
|
|
961
|
+
`import type { ${imports} } from '@sveltejs/kit';`,
|
|
962
|
+
type !== 'page' && `export type RequestHandler = GenericRequestHandler<${arg}>;`,
|
|
963
|
+
type !== 'endpoint' &&
|
|
964
|
+
`export type Load<Props = Record<string, any>> = GenericLoad<${arg}, Props>;`
|
|
965
|
+
]
|
|
966
|
+
.filter(Boolean)
|
|
967
|
+
.join('\n');
|
|
968
|
+
|
|
969
|
+
write_if_changed(file, content);
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/** @param {import('types').ValidatedConfig} config */
|
|
974
|
+
function init(config) {
|
|
975
|
+
copy_assets(path__default.join(config.kit.outDir, 'runtime'));
|
|
976
|
+
write_tsconfig(config);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/** @param {import('types').ValidatedConfig} config */
|
|
980
|
+
function update(config) {
|
|
981
|
+
const manifest_data = create_manifest_data({ config });
|
|
982
|
+
|
|
983
|
+
const output = path__default.join(config.kit.outDir, 'generated');
|
|
984
|
+
const base = path__default.relative('.', output);
|
|
985
|
+
|
|
986
|
+
write_manifest(manifest_data, base, output);
|
|
987
|
+
write_root(manifest_data, output);
|
|
988
|
+
write_types(config, manifest_data);
|
|
989
|
+
|
|
990
|
+
return { manifest_data };
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/** @param {import('types').ValidatedConfig} config */
|
|
994
|
+
function all(config) {
|
|
995
|
+
init(config);
|
|
996
|
+
return update(config);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
export { all, init, update };
|