@sveltejs/kit 1.0.0-next.303 → 1.0.0-next.306
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 +35 -34
- package/assets/server/index.js +4 -2
- package/dist/chunks/index.js +23 -27
- package/dist/chunks/index2.js +18 -17
- package/dist/chunks/index3.js +1 -1
- package/dist/chunks/misc.js +33 -32
- package/dist/chunks/sync.js +322 -271
- package/dist/cli.js +10 -7
- package/package.json +3 -3
- package/types/index.d.ts +3 -7
- package/types/internal.d.ts +4 -7
- package/types/private.d.ts +0 -4
package/assets/client/start.js
CHANGED
|
@@ -269,7 +269,7 @@ function parse_route_id(id) {
|
|
|
269
269
|
? /^\/$/
|
|
270
270
|
: new RegExp(
|
|
271
271
|
`^${decodeURIComponent(id)
|
|
272
|
-
.split(
|
|
272
|
+
.split(/(?:@(?:~|[a-zA-Z0-9_-]*))?(?:\/|$)/)
|
|
273
273
|
.map((segment, i, segments) => {
|
|
274
274
|
// special case — /[...rest]/ could contain zero segments
|
|
275
275
|
const match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment);
|
|
@@ -282,40 +282,41 @@ function parse_route_id(id) {
|
|
|
282
282
|
const is_last = i === segments.length - 1;
|
|
283
283
|
|
|
284
284
|
return (
|
|
285
|
+
segment &&
|
|
285
286
|
'/' +
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
287
|
+
segment
|
|
288
|
+
.split(/\[(.+?)\]/)
|
|
289
|
+
.map((content, i) => {
|
|
290
|
+
if (i % 2) {
|
|
291
|
+
const [, rest, name, type] = /** @type {RegExpMatchArray} */ (
|
|
292
|
+
param_pattern.exec(content)
|
|
293
|
+
);
|
|
294
|
+
names.push(name);
|
|
295
|
+
types.push(type);
|
|
296
|
+
return rest ? '(.*?)' : '([^/]+?)';
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (is_last && content.includes('.')) add_trailing_slash = false;
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
content // allow users to specify characters on the file system in an encoded manner
|
|
303
|
+
.normalize()
|
|
304
|
+
// We use [ and ] to denote parameters, so users must encode these on the file
|
|
305
|
+
// system to match against them. We don't decode all characters since others
|
|
306
|
+
// can already be epressed and so that '%' can be easily used directly in filenames
|
|
307
|
+
.replace(/%5[Bb]/g, '[')
|
|
308
|
+
.replace(/%5[Dd]/g, ']')
|
|
309
|
+
// '#', '/', and '?' can only appear in URL path segments in an encoded manner.
|
|
310
|
+
// They will not be touched by decodeURI so need to be encoded here, so
|
|
311
|
+
// that we can match against them.
|
|
312
|
+
// We skip '/' since you can't create a file with it on any OS
|
|
313
|
+
.replace(/#/g, '%23')
|
|
314
|
+
.replace(/\?/g, '%3F')
|
|
315
|
+
// escape characters that have special meaning in regex
|
|
316
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
317
|
+
); // TODO handle encoding
|
|
318
|
+
})
|
|
319
|
+
.join('')
|
|
319
320
|
);
|
|
320
321
|
})
|
|
321
322
|
.join('')}${add_trailing_slash ? '/?' : ''}$`
|
package/assets/server/index.js
CHANGED
|
@@ -2181,7 +2181,8 @@ async function respond$1(opts) {
|
|
|
2181
2181
|
|
|
2182
2182
|
try {
|
|
2183
2183
|
nodes = await Promise.all(
|
|
2184
|
-
|
|
2184
|
+
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
2185
|
+
route.a.map((n) => (n == undefined ? n : options.manifest._.nodes[n]()))
|
|
2185
2186
|
);
|
|
2186
2187
|
} catch (err) {
|
|
2187
2188
|
const error = coalesce_to_error(err);
|
|
@@ -2280,7 +2281,8 @@ async function respond$1(opts) {
|
|
|
2280
2281
|
if (error) {
|
|
2281
2282
|
while (i--) {
|
|
2282
2283
|
if (route.b[i]) {
|
|
2283
|
-
const
|
|
2284
|
+
const index = /** @type {number} */ (route.b[i]);
|
|
2285
|
+
const error_node = await options.manifest._.nodes[index]();
|
|
2284
2286
|
|
|
2285
2287
|
/** @type {Loaded} */
|
|
2286
2288
|
let node_loaded;
|
package/dist/chunks/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { getRequest, setResponse } from '../node.js';
|
|
|
12
12
|
import { sequence } from '../hooks.js';
|
|
13
13
|
import { p as posixify } from './filesystem.js';
|
|
14
14
|
import { p as parse_route_id } from './misc.js';
|
|
15
|
+
import { n as normalize_path } from './url.js';
|
|
15
16
|
import 'sade';
|
|
16
17
|
import 'child_process';
|
|
17
18
|
import 'net';
|
|
@@ -73,7 +74,7 @@ async function create_plugin(config, cwd) {
|
|
|
73
74
|
const url = id.startsWith('..') ? `/@fs${path__default.posix.resolve(id)}` : `/${id}`;
|
|
74
75
|
|
|
75
76
|
const module = /** @type {import('types').SSRComponent} */ (
|
|
76
|
-
await vite.ssrLoadModule(url)
|
|
77
|
+
await vite.ssrLoadModule(url, { fixStacktrace: false })
|
|
77
78
|
);
|
|
78
79
|
const node = await vite.moduleGraph.getModuleByUrl(url);
|
|
79
80
|
|
|
@@ -95,7 +96,7 @@ async function create_plugin(config, cwd) {
|
|
|
95
96
|
(query.has('svelte') && query.get('type') === 'style')
|
|
96
97
|
) {
|
|
97
98
|
try {
|
|
98
|
-
const mod = await vite.ssrLoadModule(dep.url);
|
|
99
|
+
const mod = await vite.ssrLoadModule(dep.url, { fixStacktrace: false });
|
|
99
100
|
styles[dep.url] = mod.default;
|
|
100
101
|
} catch {
|
|
101
102
|
// this can happen with dynamically imported modules, I think
|
|
@@ -128,11 +129,11 @@ async function create_plugin(config, cwd) {
|
|
|
128
129
|
shadow: route.shadow
|
|
129
130
|
? async () => {
|
|
130
131
|
const url = path__default.resolve(cwd, /** @type {string} */ (route.shadow));
|
|
131
|
-
return await vite.ssrLoadModule(url);
|
|
132
|
+
return await vite.ssrLoadModule(url, { fixStacktrace: false });
|
|
132
133
|
}
|
|
133
134
|
: null,
|
|
134
|
-
a: route.a.map((id) => manifest_data.components.indexOf(id)),
|
|
135
|
-
b: route.b.map((id) => manifest_data.components.indexOf(id))
|
|
135
|
+
a: route.a.map((id) => (id ? manifest_data.components.indexOf(id) : undefined)),
|
|
136
|
+
b: route.b.map((id) => (id ? manifest_data.components.indexOf(id) : undefined))
|
|
136
137
|
};
|
|
137
138
|
}
|
|
138
139
|
|
|
@@ -144,7 +145,7 @@ async function create_plugin(config, cwd) {
|
|
|
144
145
|
types,
|
|
145
146
|
load: async () => {
|
|
146
147
|
const url = path__default.resolve(cwd, route.file);
|
|
147
|
-
return await vite.ssrLoadModule(url);
|
|
148
|
+
return await vite.ssrLoadModule(url, { fixStacktrace: false });
|
|
148
149
|
}
|
|
149
150
|
};
|
|
150
151
|
}),
|
|
@@ -155,7 +156,7 @@ async function create_plugin(config, cwd) {
|
|
|
155
156
|
for (const key in manifest_data.matchers) {
|
|
156
157
|
const file = manifest_data.matchers[key];
|
|
157
158
|
const url = path__default.resolve(cwd, file);
|
|
158
|
-
const module = await vite.ssrLoadModule(url);
|
|
159
|
+
const module = await vite.ssrLoadModule(url, { fixStacktrace: false });
|
|
159
160
|
|
|
160
161
|
if (module.match) {
|
|
161
162
|
matchers[key] = module.match;
|
|
@@ -172,20 +173,7 @@ async function create_plugin(config, cwd) {
|
|
|
172
173
|
|
|
173
174
|
/** @param {Error} error */
|
|
174
175
|
function fix_stack_trace(error) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// ideally vite would expose ssrRewriteStacktrace, but
|
|
178
|
-
// in lieu of that, we can implement it ourselves. we
|
|
179
|
-
// don't want to mutate the error object, because
|
|
180
|
-
// the stack trace could be 'fixed' multiple times,
|
|
181
|
-
// and Vite will fix stack traces before we even
|
|
182
|
-
// see them if they occur during ssrLoadModule
|
|
183
|
-
const original = error.stack;
|
|
184
|
-
vite.ssrFixStacktrace(error);
|
|
185
|
-
const fixed = error.stack;
|
|
186
|
-
error.stack = original;
|
|
187
|
-
|
|
188
|
-
return fixed;
|
|
176
|
+
return error.stack ? vite.ssrRewriteStacktrace(error.stack) : error.stack;
|
|
189
177
|
}
|
|
190
178
|
|
|
191
179
|
update_manifest();
|
|
@@ -227,11 +215,17 @@ async function create_plugin(config, cwd) {
|
|
|
227
215
|
|
|
228
216
|
if (req.url === '/favicon.ico') return not_found(res);
|
|
229
217
|
|
|
230
|
-
if (!decoded.startsWith(config.kit.paths.base))
|
|
218
|
+
if (!decoded.startsWith(config.kit.paths.base)) {
|
|
219
|
+
const suggestion = normalize_path(
|
|
220
|
+
config.kit.paths.base + req.url,
|
|
221
|
+
config.kit.trailingSlash
|
|
222
|
+
);
|
|
223
|
+
return not_found(res, `Not found (did you mean ${suggestion}?)`);
|
|
224
|
+
}
|
|
231
225
|
|
|
232
226
|
/** @type {Partial<import('types').Hooks>} */
|
|
233
227
|
const user_hooks = resolve_entry(config.kit.files.hooks)
|
|
234
|
-
? await vite.ssrLoadModule(`/${config.kit.files.hooks}
|
|
228
|
+
? await vite.ssrLoadModule(`/${config.kit.files.hooks}`, { fixStacktrace: false })
|
|
235
229
|
: {};
|
|
236
230
|
|
|
237
231
|
const handle = user_hooks.handle || (({ event, resolve }) => resolve(event));
|
|
@@ -271,13 +265,15 @@ async function create_plugin(config, cwd) {
|
|
|
271
265
|
// can get loaded twice via different URLs, which causes failures. Might
|
|
272
266
|
// require changes to Vite to fix
|
|
273
267
|
const { default: root } = await vite.ssrLoadModule(
|
|
274
|
-
`/${posixify(path__default.relative(cwd, `${config.kit.outDir}/generated/root.svelte`))}
|
|
268
|
+
`/${posixify(path__default.relative(cwd, `${config.kit.outDir}/generated/root.svelte`))}`,
|
|
269
|
+
{ fixStacktrace: false }
|
|
275
270
|
);
|
|
276
271
|
|
|
277
272
|
const paths = await vite.ssrLoadModule(
|
|
278
273
|
true
|
|
279
274
|
? `/${posixify(path__default.relative(cwd, `${config.kit.outDir}/runtime/paths.js`))}`
|
|
280
|
-
: `/@fs${runtime}/paths.js
|
|
275
|
+
: `/@fs${runtime}/paths.js`,
|
|
276
|
+
{ fixStacktrace: false }
|
|
281
277
|
);
|
|
282
278
|
|
|
283
279
|
paths.set_paths({
|
|
@@ -381,9 +377,9 @@ async function create_plugin(config, cwd) {
|
|
|
381
377
|
}
|
|
382
378
|
|
|
383
379
|
/** @param {import('http').ServerResponse} res */
|
|
384
|
-
function not_found(res) {
|
|
380
|
+
function not_found(res, message = 'Not found') {
|
|
385
381
|
res.statusCode = 404;
|
|
386
|
-
res.end(
|
|
382
|
+
res.end(message);
|
|
387
383
|
}
|
|
388
384
|
|
|
389
385
|
/**
|
package/dist/chunks/index2.js
CHANGED
|
@@ -71,6 +71,7 @@ async function build_service_worker(
|
|
|
71
71
|
|
|
72
72
|
export const files = [
|
|
73
73
|
${manifest_data.assets
|
|
74
|
+
.filter((asset) => config.kit.serviceWorker.files(asset.file))
|
|
74
75
|
.map((asset) => `${s(`${config.kit.paths.base}/${asset.file}`)}`)
|
|
75
76
|
.join(',\n\t\t\t\t')}
|
|
76
77
|
];
|
|
@@ -1003,10 +1004,6 @@ async function prerender({ config, entries, files, log }) {
|
|
|
1003
1004
|
paths: []
|
|
1004
1005
|
};
|
|
1005
1006
|
|
|
1006
|
-
if (!config.kit.prerender.enabled) {
|
|
1007
|
-
return prerendered;
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
1007
|
installFetch();
|
|
1011
1008
|
|
|
1012
1009
|
const server_root = join(config.kit.outDir, 'output');
|
|
@@ -1023,6 +1020,23 @@ async function prerender({ config, entries, files, log }) {
|
|
|
1023
1020
|
|
|
1024
1021
|
const server = new Server(manifest);
|
|
1025
1022
|
|
|
1023
|
+
const rendered = await server.respond(new Request('http://sveltekit-prerender/[fallback]'), {
|
|
1024
|
+
getClientAddress,
|
|
1025
|
+
prerender: {
|
|
1026
|
+
fallback: true,
|
|
1027
|
+
default: false,
|
|
1028
|
+
dependencies: new Map()
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
const file = `${config.kit.outDir}/output/prerendered/fallback.html`;
|
|
1033
|
+
mkdirp(dirname(file));
|
|
1034
|
+
writeFileSync(file, await rendered.text());
|
|
1035
|
+
|
|
1036
|
+
if (!config.kit.prerender.enabled) {
|
|
1037
|
+
return prerendered;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1026
1040
|
const error = normalise_error_handler(log, config.kit.prerender.onError);
|
|
1027
1041
|
|
|
1028
1042
|
const q = queue(config.kit.prerender.concurrency);
|
|
@@ -1214,19 +1228,6 @@ async function prerender({ config, entries, files, log }) {
|
|
|
1214
1228
|
await q.done();
|
|
1215
1229
|
}
|
|
1216
1230
|
|
|
1217
|
-
const rendered = await server.respond(new Request('http://sveltekit-prerender/[fallback]'), {
|
|
1218
|
-
getClientAddress,
|
|
1219
|
-
prerender: {
|
|
1220
|
-
fallback: true,
|
|
1221
|
-
default: false,
|
|
1222
|
-
dependencies: new Map()
|
|
1223
|
-
}
|
|
1224
|
-
});
|
|
1225
|
-
|
|
1226
|
-
const file = `${config.kit.outDir}/output/prerendered/fallback.html`;
|
|
1227
|
-
mkdirp(dirname(file));
|
|
1228
|
-
writeFileSync(file, await rendered.text());
|
|
1229
|
-
|
|
1230
1231
|
return prerendered;
|
|
1231
1232
|
}
|
|
1232
1233
|
|
package/dist/chunks/index3.js
CHANGED
|
@@ -54,7 +54,7 @@ function generate_manifest({ build_data, relative_path, routes, format = 'esm' }
|
|
|
54
54
|
assets.push(build_data.service_worker);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
/** @param {string} id */
|
|
57
|
+
/** @param {string | undefined} id */
|
|
58
58
|
const get_index = (id) => id && /** @type {LookupEntry} */ (bundled_nodes.get(id)).index;
|
|
59
59
|
|
|
60
60
|
const matchers = new Set();
|
package/dist/chunks/misc.js
CHANGED
|
@@ -17,7 +17,7 @@ function parse_route_id(id) {
|
|
|
17
17
|
? /^\/$/
|
|
18
18
|
: new RegExp(
|
|
19
19
|
`^${decodeURIComponent(id)
|
|
20
|
-
.split(
|
|
20
|
+
.split(/(?:@(?:~|[a-zA-Z0-9_-]*))?(?:\/|$)/)
|
|
21
21
|
.map((segment, i, segments) => {
|
|
22
22
|
// special case — /[...rest]/ could contain zero segments
|
|
23
23
|
const match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment);
|
|
@@ -30,40 +30,41 @@ function parse_route_id(id) {
|
|
|
30
30
|
const is_last = i === segments.length - 1;
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
|
+
segment &&
|
|
33
34
|
'/' +
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
segment
|
|
36
|
+
.split(/\[(.+?)\]/)
|
|
37
|
+
.map((content, i) => {
|
|
38
|
+
if (i % 2) {
|
|
39
|
+
const [, rest, name, type] = /** @type {RegExpMatchArray} */ (
|
|
40
|
+
param_pattern.exec(content)
|
|
41
|
+
);
|
|
42
|
+
names.push(name);
|
|
43
|
+
types.push(type);
|
|
44
|
+
return rest ? '(.*?)' : '([^/]+?)';
|
|
45
|
+
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
if (is_last && content.includes('.')) add_trailing_slash = false;
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
return (
|
|
50
|
+
content // allow users to specify characters on the file system in an encoded manner
|
|
51
|
+
.normalize()
|
|
52
|
+
// We use [ and ] to denote parameters, so users must encode these on the file
|
|
53
|
+
// system to match against them. We don't decode all characters since others
|
|
54
|
+
// can already be epressed and so that '%' can be easily used directly in filenames
|
|
55
|
+
.replace(/%5[Bb]/g, '[')
|
|
56
|
+
.replace(/%5[Dd]/g, ']')
|
|
57
|
+
// '#', '/', and '?' can only appear in URL path segments in an encoded manner.
|
|
58
|
+
// They will not be touched by decodeURI so need to be encoded here, so
|
|
59
|
+
// that we can match against them.
|
|
60
|
+
// We skip '/' since you can't create a file with it on any OS
|
|
61
|
+
.replace(/#/g, '%23')
|
|
62
|
+
.replace(/\?/g, '%3F')
|
|
63
|
+
// escape characters that have special meaning in regex
|
|
64
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
65
|
+
); // TODO handle encoding
|
|
66
|
+
})
|
|
67
|
+
.join('')
|
|
67
68
|
);
|
|
68
69
|
})
|
|
69
70
|
.join('')}${add_trailing_slash ? '/?' : ''}$`
|
package/dist/chunks/sync.js
CHANGED
|
@@ -121,18 +121,39 @@ var mime = new Mime(standard, other);
|
|
|
121
121
|
* rest: boolean;
|
|
122
122
|
* type: string | null;
|
|
123
123
|
* }} Part
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* A route, consisting of an endpoint module and/or an array of components
|
|
128
|
+
* (n layouts and one leaf) for successful navigations and an array of
|
|
129
|
+
* n error components to render if navigation fails
|
|
124
130
|
* @typedef {{
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
131
|
+
* id: string;
|
|
132
|
+
* pattern: RegExp;
|
|
133
|
+
* segments: Part[][];
|
|
134
|
+
* page?: {
|
|
135
|
+
* a: Array<string | undefined>;
|
|
136
|
+
* b: Array<string | undefined>;
|
|
137
|
+
* };
|
|
138
|
+
* endpoint?: string;
|
|
139
|
+
* }} Unit
|
|
133
140
|
*/
|
|
134
141
|
|
|
135
|
-
|
|
142
|
+
/**
|
|
143
|
+
* @typedef {{
|
|
144
|
+
* error: string | undefined;
|
|
145
|
+
* layouts: Record<string, { file: string, name: string }>
|
|
146
|
+
* }} Node
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @typedef {Map<string, Node>} Tree
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
const layout_pattern = /^__layout(?:-([a-zA-Z0-9_-]+))?(?:@([a-zA-Z0-9_-]+))?$/;
|
|
154
|
+
const dunder_pattern = /(^|\/)__(?!tests?__)/; // forbid __-prefixed files/directories except __error, __layout[-...], __test__, __tests__
|
|
155
|
+
|
|
156
|
+
const DEFAULT = 'default';
|
|
136
157
|
|
|
137
158
|
/**
|
|
138
159
|
* @param {{
|
|
@@ -147,172 +168,199 @@ function create_manifest_data({
|
|
|
147
168
|
fallback = `${get_runtime_path(config)}/components`,
|
|
148
169
|
cwd = process.cwd()
|
|
149
170
|
}) {
|
|
150
|
-
/**
|
|
151
|
-
* @param {string} file_name
|
|
152
|
-
* @param {string} dir
|
|
153
|
-
*/
|
|
154
|
-
function find_layout(file_name, dir) {
|
|
155
|
-
const files = config.extensions.map((ext) => posixify(path__default.join(dir, `${file_name}${ext}`)));
|
|
156
|
-
return files.find((file) => fs__default.existsSync(path__default.resolve(cwd, file)));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** @type {string[]} */
|
|
160
|
-
const components = [];
|
|
161
|
-
|
|
162
171
|
/** @type {import('types').RouteData[]} */
|
|
163
172
|
const routes = [];
|
|
164
173
|
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* @param {string} dir
|
|
170
|
-
* @param {string[]} parent_id
|
|
171
|
-
* @param {Array<string|undefined>} layout_stack // accumulated __layout.svelte components
|
|
172
|
-
* @param {Array<string|undefined>} error_stack // accumulated __error.svelte components
|
|
173
|
-
*/
|
|
174
|
-
function walk(dir, parent_id, layout_stack, error_stack) {
|
|
175
|
-
/** @type {Item[]} */
|
|
176
|
-
const items = [];
|
|
174
|
+
/** @type {Map<string, Unit>} */
|
|
175
|
+
const units = new Map();
|
|
177
176
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const file = posixify(path__default.relative(cwd, resolved));
|
|
181
|
-
const is_dir = fs__default.statSync(resolved).isDirectory();
|
|
177
|
+
/** @type {Tree} */
|
|
178
|
+
const tree = new Map();
|
|
182
179
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
const default_layout = {
|
|
181
|
+
file: posixify(path__default.relative(cwd, `${fallback}/layout.svelte`)),
|
|
182
|
+
name: DEFAULT
|
|
183
|
+
};
|
|
187
184
|
|
|
188
|
-
|
|
185
|
+
// set default root layout/error
|
|
186
|
+
tree.set('', {
|
|
187
|
+
error: posixify(path__default.relative(cwd, `${fallback}/error.svelte`)),
|
|
188
|
+
layouts: { [DEFAULT]: default_layout }
|
|
189
|
+
});
|
|
189
190
|
|
|
190
|
-
|
|
191
|
+
const routes_base = posixify(path__default.relative(cwd, config.kit.files.routes));
|
|
192
|
+
const valid_extensions = [...config.extensions, ...config.kit.endpointExtensions];
|
|
191
193
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
list_files(config.kit.files.routes).forEach((file) => {
|
|
195
|
+
const extension = valid_extensions.find((ext) => file.endsWith(ext));
|
|
196
|
+
if (!extension) return;
|
|
195
197
|
|
|
196
|
-
|
|
198
|
+
const id = file.slice(0, -extension.length).replace(/\/?index(\.[a-z]+)?$/, '$1');
|
|
199
|
+
const project_relative = `${routes_base}/${file}`;
|
|
197
200
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
name,
|
|
201
|
-
parts: get_parts(name, file),
|
|
202
|
-
route_suffix: basename.slice(basename.indexOf('.'), -ext.length),
|
|
203
|
-
is_dir,
|
|
204
|
-
is_index: !is_dir && basename.startsWith('index.'),
|
|
205
|
-
is_page: config.extensions.includes(ext)
|
|
206
|
-
});
|
|
207
|
-
});
|
|
201
|
+
const segments = id.split('/');
|
|
202
|
+
const name = /** @type {string} */ (segments.pop());
|
|
208
203
|
|
|
209
|
-
|
|
204
|
+
if (name === '__layout.reset') {
|
|
205
|
+
throw new Error(
|
|
206
|
+
'__layout.reset has been removed in favour of named layouts: https://kit.svelte.dev/docs/layouts#named-layouts'
|
|
207
|
+
);
|
|
208
|
+
}
|
|
210
209
|
|
|
211
|
-
|
|
212
|
-
const
|
|
210
|
+
if (name === '__error' || layout_pattern.test(name)) {
|
|
211
|
+
const dir = segments.join('/');
|
|
213
212
|
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
id_parts.push(item.name);
|
|
213
|
+
if (!tree.has(dir)) {
|
|
214
|
+
tree.set(dir, {
|
|
215
|
+
error: undefined,
|
|
216
|
+
layouts: {}
|
|
217
|
+
});
|
|
220
218
|
}
|
|
221
219
|
|
|
222
|
-
|
|
223
|
-
const layout_reset = find_layout('__layout.reset', item.file);
|
|
224
|
-
const layout = find_layout('__layout', item.file);
|
|
225
|
-
const error = find_layout('__error', item.file);
|
|
220
|
+
const group = /** @type {Node} */ (tree.get(dir));
|
|
226
221
|
|
|
227
|
-
|
|
228
|
-
|
|
222
|
+
if (name === '__error') {
|
|
223
|
+
group.error = project_relative;
|
|
224
|
+
} else {
|
|
225
|
+
const match = /** @type {RegExpMatchArray} */ (layout_pattern.exec(name));
|
|
226
|
+
|
|
227
|
+
if (match[1] === DEFAULT) {
|
|
228
|
+
throw new Error(`${project_relative} cannot use reserved "${DEFAULT}" name`);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
|
|
232
|
-
if (layout) components.push(layout);
|
|
233
|
-
if (error) components.push(error);
|
|
231
|
+
const layout_id = match[1] || DEFAULT;
|
|
234
232
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
} else {
|
|
242
|
-
const id = id_parts.join('/');
|
|
243
|
-
const { pattern } = parse_route_id(id);
|
|
233
|
+
const defined = group.layouts[layout_id];
|
|
234
|
+
if (defined && defined !== default_layout) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`Duplicate layout ${project_relative} already defined at ${defined.file}`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
244
239
|
|
|
245
|
-
|
|
246
|
-
|
|
240
|
+
group.layouts[layout_id] = {
|
|
241
|
+
file: project_relative,
|
|
242
|
+
name
|
|
243
|
+
};
|
|
244
|
+
}
|
|
247
245
|
|
|
248
|
-
|
|
249
|
-
|
|
246
|
+
return;
|
|
247
|
+
} else if (dunder_pattern.test(file)) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Files and directories prefixed with __ are reserved (saw ${project_relative})`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
250
252
|
|
|
251
|
-
|
|
252
|
-
while (i--) {
|
|
253
|
-
if (!errors[i] && !concatenated[i]) {
|
|
254
|
-
errors.splice(i, 1);
|
|
255
|
-
concatenated.splice(i, 1);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
253
|
+
if (!config.kit.routes(file)) return;
|
|
258
254
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
255
|
+
if (/\]\[/.test(id)) {
|
|
256
|
+
throw new Error(`Invalid route ${project_relative} — parameters must be separated`);
|
|
257
|
+
}
|
|
263
258
|
|
|
264
|
-
|
|
259
|
+
if (count_occurrences('[', id) !== count_occurrences(']', id)) {
|
|
260
|
+
throw new Error(`Invalid route ${project_relative} — brackets are unbalanced`);
|
|
261
|
+
}
|
|
265
262
|
|
|
266
|
-
|
|
263
|
+
if (!units.has(id)) {
|
|
264
|
+
units.set(id, {
|
|
265
|
+
id,
|
|
266
|
+
pattern: parse_route_id(id).pattern,
|
|
267
|
+
segments: id
|
|
268
|
+
.split('/')
|
|
269
|
+
.filter(Boolean)
|
|
270
|
+
.map((segment) => {
|
|
271
|
+
/** @type {Part[]} */
|
|
272
|
+
const parts = [];
|
|
273
|
+
segment.split(/\[(.+?)\]/).map((content, i) => {
|
|
274
|
+
const dynamic = !!(i % 2);
|
|
275
|
+
|
|
276
|
+
if (!content) return;
|
|
277
|
+
|
|
278
|
+
parts.push({
|
|
279
|
+
content,
|
|
280
|
+
dynamic,
|
|
281
|
+
rest: dynamic && content.startsWith('...'),
|
|
282
|
+
type: (dynamic && content.split('=')[1]) || null
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
return parts;
|
|
286
|
+
}),
|
|
287
|
+
page: undefined,
|
|
288
|
+
endpoint: undefined
|
|
289
|
+
});
|
|
290
|
+
}
|
|
267
291
|
|
|
268
|
-
|
|
269
|
-
type: 'page',
|
|
270
|
-
id,
|
|
271
|
-
pattern,
|
|
272
|
-
path,
|
|
273
|
-
shadow: null,
|
|
274
|
-
a: /** @type {string[]} */ (concatenated),
|
|
275
|
-
b: /** @type {string[]} */ (errors)
|
|
276
|
-
});
|
|
277
|
-
} else {
|
|
278
|
-
routes.push({
|
|
279
|
-
type: 'endpoint',
|
|
280
|
-
id,
|
|
281
|
-
pattern,
|
|
282
|
-
file: item.file
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
}
|
|
292
|
+
const unit = /** @type {Unit} */ (units.get(id));
|
|
288
293
|
|
|
289
|
-
|
|
294
|
+
if (config.extensions.find((ext) => file.endsWith(ext))) {
|
|
295
|
+
const { layouts, errors } = trace(project_relative, file, tree, config.extensions);
|
|
296
|
+
unit.page = {
|
|
297
|
+
a: layouts.concat(project_relative),
|
|
298
|
+
b: errors
|
|
299
|
+
};
|
|
300
|
+
} else {
|
|
301
|
+
unit.endpoint = project_relative;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
290
304
|
|
|
291
|
-
|
|
292
|
-
const
|
|
305
|
+
/** @type {string[]} */
|
|
306
|
+
const components = [];
|
|
293
307
|
|
|
294
|
-
|
|
308
|
+
tree.forEach(({ layouts, error }) => {
|
|
309
|
+
// we do [default, error, ...other_layouts] so that components[0] and [1]
|
|
310
|
+
// are the root layout/error. kinda janky, there's probably a nicer way
|
|
311
|
+
if (layouts[DEFAULT]) {
|
|
312
|
+
components.push(layouts[DEFAULT].file);
|
|
313
|
+
}
|
|
295
314
|
|
|
296
|
-
|
|
315
|
+
if (error) {
|
|
316
|
+
components.push(error);
|
|
317
|
+
}
|
|
297
318
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (route.type === 'page') {
|
|
301
|
-
lookup.set(route.id, route);
|
|
319
|
+
for (const id in layouts) {
|
|
320
|
+
if (id !== DEFAULT) components.push(layouts[id].file);
|
|
302
321
|
}
|
|
303
|
-
}
|
|
322
|
+
});
|
|
304
323
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
lookup.get(route.id).shadow = route.file;
|
|
310
|
-
routes.splice(i, 1);
|
|
324
|
+
units.forEach((unit) => {
|
|
325
|
+
if (unit.page) {
|
|
326
|
+
const leaf = /** @type {string} */ (unit.page.a[unit.page.a.length - 1]);
|
|
327
|
+
components.push(leaf);
|
|
311
328
|
}
|
|
312
|
-
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
Array.from(units.values())
|
|
332
|
+
.sort(compare)
|
|
333
|
+
.forEach((unit) => {
|
|
334
|
+
// TODO when we introduce layout endpoints and scoped middlewares, we
|
|
335
|
+
// will probably want to have a single unified route type here
|
|
336
|
+
// (created in the list_files(...).forEach(...) callback)
|
|
337
|
+
if (unit.page) {
|
|
338
|
+
routes.push({
|
|
339
|
+
type: 'page',
|
|
340
|
+
id: unit.id,
|
|
341
|
+
pattern: unit.pattern,
|
|
342
|
+
path: unit.id.includes('[') ? '' : `/${unit.id.replace(/@(?:[a-zA-Z0-9_-]+)/g, '')}`,
|
|
343
|
+
shadow: unit.endpoint || null,
|
|
344
|
+
a: unit.page.a,
|
|
345
|
+
b: unit.page.b
|
|
346
|
+
});
|
|
347
|
+
} else if (unit.endpoint) {
|
|
348
|
+
routes.push({
|
|
349
|
+
type: 'endpoint',
|
|
350
|
+
id: unit.id,
|
|
351
|
+
pattern: unit.pattern,
|
|
352
|
+
file: unit.endpoint
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
});
|
|
313
356
|
|
|
357
|
+
/** @type {import('types').Asset[]} */
|
|
314
358
|
const assets = fs__default.existsSync(config.kit.files.assets)
|
|
315
|
-
? list_files(
|
|
359
|
+
? list_files(config.kit.files.assets).map((file) => ({
|
|
360
|
+
file,
|
|
361
|
+
size: fs__default.statSync(`${config.kit.files.assets}/${file}`).size,
|
|
362
|
+
type: mime.getType(file)
|
|
363
|
+
}))
|
|
316
364
|
: [];
|
|
317
365
|
|
|
318
366
|
const params_base = path__default.relative(cwd, config.kit.files.params);
|
|
@@ -336,8 +384,6 @@ function create_manifest_data({
|
|
|
336
384
|
|
|
337
385
|
return {
|
|
338
386
|
assets,
|
|
339
|
-
layout,
|
|
340
|
-
error,
|
|
341
387
|
components,
|
|
342
388
|
routes,
|
|
343
389
|
matchers
|
|
@@ -345,142 +391,162 @@ function create_manifest_data({
|
|
|
345
391
|
}
|
|
346
392
|
|
|
347
393
|
/**
|
|
348
|
-
* @param {string}
|
|
349
|
-
* @param {string}
|
|
394
|
+
* @param {string} file
|
|
395
|
+
* @param {string} path
|
|
396
|
+
* @param {Tree} tree
|
|
397
|
+
* @param {string[]} extensions
|
|
350
398
|
*/
|
|
351
|
-
function
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
399
|
+
function trace(file, path, tree, extensions) {
|
|
400
|
+
/** @type {Array<string | undefined>} */
|
|
401
|
+
const layouts = [];
|
|
402
|
+
|
|
403
|
+
/** @type {Array<string | undefined>} */
|
|
404
|
+
const errors = [];
|
|
405
|
+
|
|
406
|
+
const parts = path.split('/');
|
|
407
|
+
const filename = /** @type {string} */ (parts.pop());
|
|
408
|
+
const extension = /** @type {string} */ (extensions.find((ext) => path.endsWith(ext)));
|
|
409
|
+
const base = filename.slice(0, -extension.length);
|
|
410
|
+
|
|
411
|
+
let layout_id = base.includes('@') ? base.split('@')[1] : DEFAULT;
|
|
412
|
+
|
|
413
|
+
// walk up the tree, find which __layout and __error components
|
|
414
|
+
// apply to this page
|
|
415
|
+
// eslint-disable-next-line
|
|
416
|
+
while (true) {
|
|
417
|
+
const node = tree.get(parts.join('/'));
|
|
418
|
+
const layout = node?.layouts[layout_id];
|
|
419
|
+
|
|
420
|
+
// any segment that has neither a __layout nor an __error can be discarded.
|
|
421
|
+
// in other words these...
|
|
422
|
+
// layouts: [a, , b, c]
|
|
423
|
+
// errors: [d, , e, ]
|
|
424
|
+
//
|
|
425
|
+
// ...can be compacted to these:
|
|
426
|
+
// layouts: [a, b, c]
|
|
427
|
+
// errors: [d, e, ]
|
|
428
|
+
if (node?.error || layout?.file) {
|
|
429
|
+
errors.unshift(node?.error);
|
|
430
|
+
layouts.unshift(layout?.file);
|
|
431
|
+
}
|
|
360
432
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return spread_pattern.test(b.file) ? -1 : 1;
|
|
433
|
+
if (layout?.name.includes('@')) {
|
|
434
|
+
layout_id = layout.name.split('@')[1];
|
|
435
|
+
} else {
|
|
436
|
+
if (layout) layout_id = DEFAULT;
|
|
437
|
+
if (parts.length === 0) break;
|
|
438
|
+
parts.pop();
|
|
439
|
+
}
|
|
369
440
|
}
|
|
370
441
|
|
|
371
|
-
|
|
442
|
+
if (layout_id !== DEFAULT) {
|
|
443
|
+
throw new Error(`${file} references missing layout "${layout_id}"`);
|
|
444
|
+
}
|
|
372
445
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
446
|
+
// trim empty space off the end of the errors array
|
|
447
|
+
let i = errors.length;
|
|
448
|
+
while (i--) if (errors[i]) break;
|
|
449
|
+
errors.length = i + 1;
|
|
376
450
|
|
|
377
|
-
|
|
378
|
-
|
|
451
|
+
return { layouts, errors };
|
|
452
|
+
}
|
|
379
453
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
454
|
+
/**
|
|
455
|
+
* @param {Unit} a
|
|
456
|
+
* @param {Unit} b
|
|
457
|
+
*/
|
|
458
|
+
function compare(a, b) {
|
|
459
|
+
const max_segments = Math.max(a.segments.length, b.segments.length);
|
|
460
|
+
for (let i = 0; i < max_segments; i += 1) {
|
|
461
|
+
const sa = a.segments[i];
|
|
462
|
+
const sb = b.segments[i];
|
|
463
|
+
|
|
464
|
+
// /x < /x/y, but /[...x]/y < /[...x]
|
|
465
|
+
if (!sa) return a.id.includes('[...') ? +1 : -1;
|
|
466
|
+
if (!sb) return b.id.includes('[...') ? -1 : +1;
|
|
467
|
+
|
|
468
|
+
const max_parts = Math.max(sa.length, sb.length);
|
|
469
|
+
for (let i = 0; i < max_parts; i += 1) {
|
|
470
|
+
const pa = sa[i];
|
|
471
|
+
const pb = sb[i];
|
|
472
|
+
|
|
473
|
+
// xy < x[y], but [x].json < [x]
|
|
474
|
+
if (pa === undefined) return pb.dynamic ? -1 : +1;
|
|
475
|
+
if (pb === undefined) return pa.dynamic ? +1 : -1;
|
|
476
|
+
|
|
477
|
+
// x < [x]
|
|
478
|
+
if (pa.dynamic !== pb.dynamic) {
|
|
479
|
+
return pa.dynamic ? +1 : -1;
|
|
383
480
|
}
|
|
384
|
-
// sort alphabetically
|
|
385
|
-
return a_sub_part.content < b_sub_part.content ? -1 : 1;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// If one is ...rest order it later
|
|
389
|
-
if (a_sub_part.rest !== b_sub_part.rest) return a_sub_part.rest ? 1 : -1;
|
|
390
|
-
|
|
391
|
-
if (a_sub_part.dynamic !== b_sub_part.dynamic) {
|
|
392
|
-
return a_sub_part.dynamic ? 1 : -1;
|
|
393
|
-
}
|
|
394
481
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
482
|
+
if (pa.dynamic) {
|
|
483
|
+
// [x] < [...x]
|
|
484
|
+
if (pa.rest !== pb.rest) {
|
|
485
|
+
return pa.rest ? +1 : -1;
|
|
486
|
+
}
|
|
398
487
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
488
|
+
// [x=type] < [x]
|
|
489
|
+
if (!!pa.type !== !!pb.type) {
|
|
490
|
+
return pa.type ? -1 : +1;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
404
493
|
}
|
|
405
494
|
}
|
|
406
495
|
|
|
407
|
-
|
|
408
|
-
|
|
496
|
+
const a_is_endpoint = !a.page && a.endpoint;
|
|
497
|
+
const b_is_endpoint = !b.page && b.endpoint;
|
|
498
|
+
|
|
499
|
+
if (a_is_endpoint !== b_is_endpoint) {
|
|
500
|
+
return a_is_endpoint ? -1 : +1;
|
|
409
501
|
}
|
|
410
502
|
|
|
411
|
-
|
|
412
|
-
return a.file < b.file ? -1 : 1;
|
|
503
|
+
return a < b ? -1 : 1;
|
|
413
504
|
}
|
|
414
505
|
|
|
415
506
|
/**
|
|
416
|
-
* @param {string}
|
|
417
|
-
* @param {string}
|
|
507
|
+
* @param {string} needle
|
|
508
|
+
* @param {string} haystack
|
|
418
509
|
*/
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (count_occurrences('[', part) !== count_occurrences(']', part)) {
|
|
425
|
-
throw new Error(`Invalid route ${file} — brackets are unbalanced`);
|
|
510
|
+
function count_occurrences(needle, haystack) {
|
|
511
|
+
let count = 0;
|
|
512
|
+
for (let i = 0; i < haystack.length; i += 1) {
|
|
513
|
+
if (haystack[i] === needle) count += 1;
|
|
426
514
|
}
|
|
427
|
-
|
|
428
|
-
/** @type {Part[]} */
|
|
429
|
-
const result = [];
|
|
430
|
-
part.split(/\[(.+?\(.+?\)|.+?)\]/).map((str, i) => {
|
|
431
|
-
if (!str) return;
|
|
432
|
-
const dynamic = i % 2 === 1;
|
|
433
|
-
|
|
434
|
-
const [, content, type] = dynamic
|
|
435
|
-
? /^((?:\.\.\.)?[a-zA-Z_][a-zA-Z0-9_]*)(?:=([a-zA-Z_][a-zA-Z0-9_]*))?$/.exec(str) || [
|
|
436
|
-
null,
|
|
437
|
-
null,
|
|
438
|
-
null
|
|
439
|
-
]
|
|
440
|
-
: [null, str, null];
|
|
441
|
-
|
|
442
|
-
if (!content) {
|
|
443
|
-
throw new Error(
|
|
444
|
-
`Invalid route ${file} — parameter name and type must match /^[a-zA-Z_][a-zA-Z0-9_]*$/`
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
result.push({
|
|
449
|
-
content,
|
|
450
|
-
dynamic,
|
|
451
|
-
rest: dynamic && /^\.{3}.+$/.test(content),
|
|
452
|
-
type
|
|
453
|
-
});
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
return result;
|
|
515
|
+
return count;
|
|
457
516
|
}
|
|
458
517
|
|
|
459
518
|
/**
|
|
460
|
-
* @param {
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
* path: string;
|
|
464
|
-
* files?: import('types').Asset[]
|
|
465
|
-
* }} args
|
|
519
|
+
* @param {string} dir
|
|
520
|
+
* @param {string} [path]
|
|
521
|
+
* @param {string[]} [files]
|
|
466
522
|
*/
|
|
467
|
-
function list_files(
|
|
468
|
-
fs__default.readdirSync(dir
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
523
|
+
function list_files(dir, path = '', files = []) {
|
|
524
|
+
fs__default.readdirSync(dir, { withFileTypes: true })
|
|
525
|
+
.sort(({ name: a }, { name: b }) => {
|
|
526
|
+
// sort each directory in (__layout, __error, everything else) order
|
|
527
|
+
// so that we can trace layouts/errors immediately
|
|
528
|
+
|
|
529
|
+
if (a.startsWith('__layout')) {
|
|
530
|
+
if (!b.startsWith('__layout')) return -1;
|
|
531
|
+
} else if (b.startsWith('__layout')) {
|
|
532
|
+
return 1;
|
|
533
|
+
} else if (a.startsWith('__')) {
|
|
534
|
+
if (!b.startsWith('__')) return -1;
|
|
535
|
+
} else if (b.startsWith('__')) {
|
|
536
|
+
return 1;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return a < b ? -1 : 1;
|
|
540
|
+
})
|
|
541
|
+
.forEach((file) => {
|
|
542
|
+
const joined = path ? `${path}/${file.name}` : file.name;
|
|
543
|
+
|
|
544
|
+
if (file.isDirectory()) {
|
|
545
|
+
list_files(`${dir}/${file.name}`, joined, files);
|
|
546
|
+
} else {
|
|
547
|
+
files.push(joined);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
484
550
|
|
|
485
551
|
return files;
|
|
486
552
|
}
|
|
@@ -549,7 +615,7 @@ function write_manifest(manifest_data, base, output) {
|
|
|
549
615
|
.join(',\n\t\t\t\t\t')}
|
|
550
616
|
]`.replace(/^\t/gm, '');
|
|
551
617
|
|
|
552
|
-
/** @param {string
|
|
618
|
+
/** @param {Array<string | undefined>} parts */
|
|
553
619
|
const get_indices = (parts) =>
|
|
554
620
|
`[${parts.map((part) => (part ? component_indexes[part] : '')).join(', ')}]`;
|
|
555
621
|
|
|
@@ -833,21 +899,6 @@ function write_types(config, manifest_data) {
|
|
|
833
899
|
/** @type {Map<string, { params: string[], type: 'page' | 'endpoint' | 'both' }>} */
|
|
834
900
|
const shadow_types = new Map();
|
|
835
901
|
|
|
836
|
-
/** @param {string} key */
|
|
837
|
-
function extract_params(key) {
|
|
838
|
-
/** @type {string[]} */
|
|
839
|
-
const params = [];
|
|
840
|
-
|
|
841
|
-
const pattern = /\[(?:\.{3})?([^\]]+)\]/g;
|
|
842
|
-
let match;
|
|
843
|
-
|
|
844
|
-
while ((match = pattern.exec(key))) {
|
|
845
|
-
params.push(match[1]);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
return params;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
902
|
manifest_data.routes.forEach((route) => {
|
|
852
903
|
const file = route.type === 'endpoint' ? route.file : route.shadow;
|
|
853
904
|
|
|
@@ -857,7 +908,7 @@ function write_types(config, manifest_data) {
|
|
|
857
908
|
);
|
|
858
909
|
const key = file.slice(0, -ext.length);
|
|
859
910
|
shadow_types.set(key, {
|
|
860
|
-
params:
|
|
911
|
+
params: parse_route_id(key).names,
|
|
861
912
|
type: route.type === 'endpoint' ? 'endpoint' : 'both'
|
|
862
913
|
});
|
|
863
914
|
}
|
|
@@ -870,7 +921,7 @@ function write_types(config, manifest_data) {
|
|
|
870
921
|
const key = component.slice(0, -ext.length);
|
|
871
922
|
|
|
872
923
|
if (!shadow_types.has(key)) {
|
|
873
|
-
shadow_types.set(key, { params:
|
|
924
|
+
shadow_types.set(key, { params: parse_route_id(key).names, type: 'page' });
|
|
874
925
|
}
|
|
875
926
|
});
|
|
876
927
|
|
package/dist/cli.js
CHANGED
|
@@ -853,8 +853,9 @@ function handle_error(e) {
|
|
|
853
853
|
/**
|
|
854
854
|
* @param {number} port
|
|
855
855
|
* @param {boolean} https
|
|
856
|
+
* @param {string} base
|
|
856
857
|
*/
|
|
857
|
-
async function launch(port, https) {
|
|
858
|
+
async function launch(port, https, base) {
|
|
858
859
|
const { exec } = await import('child_process');
|
|
859
860
|
let cmd = 'open';
|
|
860
861
|
if (process.platform == 'win32') {
|
|
@@ -866,10 +867,10 @@ async function launch(port, https) {
|
|
|
866
867
|
cmd = 'xdg-open';
|
|
867
868
|
}
|
|
868
869
|
}
|
|
869
|
-
exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
|
|
870
|
+
exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}${base}`);
|
|
870
871
|
}
|
|
871
872
|
|
|
872
|
-
const prog = sade('svelte-kit').version('1.0.0-next.
|
|
873
|
+
const prog = sade('svelte-kit').version('1.0.0-next.306');
|
|
873
874
|
|
|
874
875
|
prog
|
|
875
876
|
.command('dev')
|
|
@@ -903,6 +904,7 @@ prog
|
|
|
903
904
|
host: address_info.address,
|
|
904
905
|
https: !!(https || server_config.https),
|
|
905
906
|
open: open || !!server_config.open,
|
|
907
|
+
base: config.kit.paths.base,
|
|
906
908
|
loose: server_config.fs.strict === false,
|
|
907
909
|
allow: server_config.fs.allow,
|
|
908
910
|
cwd
|
|
@@ -970,7 +972,7 @@ prog
|
|
|
970
972
|
|
|
971
973
|
await preview({ port, host, config, https });
|
|
972
974
|
|
|
973
|
-
welcome({ port, host, https, open });
|
|
975
|
+
welcome({ port, host, https, open, base: config.kit.paths.base });
|
|
974
976
|
} catch (error) {
|
|
975
977
|
handle_error(error);
|
|
976
978
|
}
|
|
@@ -1039,15 +1041,16 @@ async function check_port(port) {
|
|
|
1039
1041
|
* host: string;
|
|
1040
1042
|
* https: boolean;
|
|
1041
1043
|
* port: number;
|
|
1044
|
+
* base: string;
|
|
1042
1045
|
* loose?: boolean;
|
|
1043
1046
|
* allow?: string[];
|
|
1044
1047
|
* cwd?: string;
|
|
1045
1048
|
* }} param0
|
|
1046
1049
|
*/
|
|
1047
|
-
function welcome({ port, host, https, open, loose, allow, cwd }) {
|
|
1048
|
-
if (open) launch(port, https);
|
|
1050
|
+
function welcome({ port, host, https, open, base, loose, allow, cwd }) {
|
|
1051
|
+
if (open) launch(port, https, base);
|
|
1049
1052
|
|
|
1050
|
-
console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.
|
|
1053
|
+
console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.306'}\n`));
|
|
1051
1054
|
|
|
1052
1055
|
const protocol = https ? 'https:' : 'http:';
|
|
1053
1056
|
const exposed = typeof host !== 'undefined' && host !== 'localhost' && host !== '127.0.0.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.306",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/sveltejs/kit",
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.32",
|
|
14
14
|
"sade": "^1.7.4",
|
|
15
|
-
"vite": "^2.
|
|
15
|
+
"vite": "^2.9.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@playwright/test": "^1.
|
|
18
|
+
"@playwright/test": "^1.20.2",
|
|
19
19
|
"@rollup/plugin-replace": "^4.0.0",
|
|
20
20
|
"@types/amphtml-validator": "^1.0.1",
|
|
21
21
|
"@types/cookie": "^0.4.1",
|
package/types/index.d.ts
CHANGED
|
@@ -184,7 +184,7 @@ export interface HandleError {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
|
-
* The
|
|
187
|
+
* The `(input: LoadInput) => LoadOutput` `load` function exported from `<script context="module">` in a page or layout.
|
|
188
188
|
*
|
|
189
189
|
* Note that you can use [generated types](/docs/types#generated-types) instead of manually specifying the Params generic argument.
|
|
190
190
|
*/
|
|
@@ -215,13 +215,9 @@ export interface ParamMatcher {
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
|
-
* A function exported from an endpoint that corresponds to an
|
|
219
|
-
* HTTP verb (`get`, `put`, `patch`, etc) and handles requests with
|
|
220
|
-
* that method. Note that since 'delete' is a reserved word in
|
|
221
|
-
* JavaScript, delete handles are called `del` instead.
|
|
218
|
+
* A `(event: RequestEvent) => RequestHandlerOutput` function exported from an endpoint that corresponds to an HTTP verb (`get`, `put`, `patch`, etc) and handles requests with that method. Note that since 'delete' is a reserved word in JavaScript, delete handles are called `del` instead.
|
|
222
219
|
*
|
|
223
|
-
* Note that you can use [generated types](/docs/types#generated-types)
|
|
224
|
-
* instead of manually specifying the `Params` generic argument.
|
|
220
|
+
* Note that you can use [generated types](/docs/types#generated-types) instead of manually specifying the `Params` generic argument.
|
|
225
221
|
*/
|
|
226
222
|
export interface RequestHandler<
|
|
227
223
|
Params extends Record<string, string> = Record<string, string>,
|
package/types/internal.d.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
RequestOptions,
|
|
19
19
|
ResolveOptions,
|
|
20
20
|
ResponseHeaders,
|
|
21
|
-
RouteSegment,
|
|
22
21
|
TrailingSlash
|
|
23
22
|
} from './private';
|
|
24
23
|
|
|
@@ -102,8 +101,6 @@ export class InternalServer extends Server {
|
|
|
102
101
|
|
|
103
102
|
export interface ManifestData {
|
|
104
103
|
assets: Asset[];
|
|
105
|
-
layout: string;
|
|
106
|
-
error: string;
|
|
107
104
|
components: string[];
|
|
108
105
|
routes: RouteData[];
|
|
109
106
|
matchers: Record<string, string>;
|
|
@@ -129,8 +126,8 @@ export interface PageData {
|
|
|
129
126
|
shadow: string | null;
|
|
130
127
|
pattern: RegExp;
|
|
131
128
|
path: string;
|
|
132
|
-
a: string
|
|
133
|
-
b: string
|
|
129
|
+
a: Array<string | undefined>;
|
|
130
|
+
b: Array<string | undefined>;
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
export type PayloadScriptAttributes =
|
|
@@ -286,12 +283,12 @@ export interface SSRPage {
|
|
|
286
283
|
/**
|
|
287
284
|
* plan a is to render 1 or more layout components followed by a leaf component.
|
|
288
285
|
*/
|
|
289
|
-
a: number
|
|
286
|
+
a: Array<number | undefined>;
|
|
290
287
|
/**
|
|
291
288
|
* plan b — if one of them components fails in `load` we backtrack until we find
|
|
292
289
|
* the nearest error component.
|
|
293
290
|
*/
|
|
294
|
-
b: number
|
|
291
|
+
b: Array<number | undefined>;
|
|
295
292
|
}
|
|
296
293
|
|
|
297
294
|
export interface SSRPagePart {
|
package/types/private.d.ts
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
// but which cannot be imported from `@sveltejs/kit`. Care should
|
|
3
3
|
// be taken to avoid breaking changes when editing this file
|
|
4
4
|
|
|
5
|
-
import { ValidatedConfig } from './internal';
|
|
6
|
-
|
|
7
5
|
export interface AdapterEntry {
|
|
8
6
|
/**
|
|
9
7
|
* A string that uniquely identifies an HTTP service (e.g. serverless function) and is used for deduplication.
|
|
@@ -191,8 +189,6 @@ export interface Logger {
|
|
|
191
189
|
|
|
192
190
|
export type MaybePromise<T> = T | Promise<T>;
|
|
193
191
|
|
|
194
|
-
export type Only<T, U> = { [P in keyof T]: T[P] } & { [P in Exclude<keyof U, keyof T>]?: never };
|
|
195
|
-
|
|
196
192
|
export interface Prerendered {
|
|
197
193
|
pages: Map<
|
|
198
194
|
string,
|