@sveltejs/kit 1.0.0-next.300 → 1.0.0-next.303
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 +54 -14
- package/assets/server/index.js +4 -3
- package/dist/chunks/index.js +1 -2
- package/dist/chunks/index2.js +0 -1
- package/dist/chunks/index3.js +1 -2
- package/dist/chunks/index4.js +7 -19
- package/dist/chunks/misc.js +75 -1
- package/dist/chunks/sync.js +94 -219
- package/dist/cli.js +8 -3
- package/package.json +1 -1
- package/types/internal.d.ts +0 -4
- package/dist/chunks/routing.js +0 -39
package/assets/client/start.js
CHANGED
|
@@ -250,39 +250,75 @@ function initial_fetch(resource, opts) {
|
|
|
250
250
|
return fetch(resource, opts);
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
253
|
+
const param_pattern = /^(\.\.\.)?(\w+)(?:=(\w+))?$/;
|
|
254
|
+
|
|
255
|
+
/** @param {string} id */
|
|
256
|
+
function parse_route_id(id) {
|
|
255
257
|
/** @type {string[]} */
|
|
256
258
|
const names = [];
|
|
257
259
|
|
|
258
260
|
/** @type {string[]} */
|
|
259
261
|
const types = [];
|
|
260
262
|
|
|
263
|
+
// `/foo` should get an optional trailing slash, `/foo.json` should not
|
|
264
|
+
// const add_trailing_slash = !/\.[a-z]+$/.test(key);
|
|
265
|
+
let add_trailing_slash = true;
|
|
266
|
+
|
|
261
267
|
const pattern =
|
|
262
|
-
|
|
268
|
+
id === ''
|
|
263
269
|
? /^\/$/
|
|
264
270
|
: new RegExp(
|
|
265
|
-
`^${decodeURIComponent(
|
|
271
|
+
`^${decodeURIComponent(id)
|
|
266
272
|
.split('/')
|
|
267
|
-
.map((segment) => {
|
|
273
|
+
.map((segment, i, segments) => {
|
|
268
274
|
// special case — /[...rest]/ could contain zero segments
|
|
269
|
-
const match = /^\[\.\.\.(\w+)(
|
|
275
|
+
const match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment);
|
|
270
276
|
if (match) {
|
|
271
277
|
names.push(match[1]);
|
|
272
278
|
types.push(match[2]);
|
|
273
279
|
return '(?:/(.*))?';
|
|
274
280
|
}
|
|
275
281
|
|
|
282
|
+
const is_last = i === segments.length - 1;
|
|
283
|
+
|
|
276
284
|
return (
|
|
277
285
|
'/' +
|
|
278
|
-
segment
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
286
|
+
segment
|
|
287
|
+
.split(/\[(.+?)\]/)
|
|
288
|
+
.map((content, i) => {
|
|
289
|
+
if (i % 2) {
|
|
290
|
+
const [, rest, name, type] = /** @type {RegExpMatchArray} */ (
|
|
291
|
+
param_pattern.exec(content)
|
|
292
|
+
);
|
|
293
|
+
names.push(name);
|
|
294
|
+
types.push(type);
|
|
295
|
+
return rest ? '(.*?)' : '([^/]+?)';
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (is_last && content.includes('.')) add_trailing_slash = false;
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
content // allow users to specify characters on the file system in an encoded manner
|
|
302
|
+
.normalize()
|
|
303
|
+
// We use [ and ] to denote parameters, so users must encode these on the file
|
|
304
|
+
// system to match against them. We don't decode all characters since others
|
|
305
|
+
// can already be epressed and so that '%' can be easily used directly in filenames
|
|
306
|
+
.replace(/%5[Bb]/g, '[')
|
|
307
|
+
.replace(/%5[Dd]/g, ']')
|
|
308
|
+
// '#', '/', and '?' can only appear in URL path segments in an encoded manner.
|
|
309
|
+
// They will not be touched by decodeURI so need to be encoded here, so
|
|
310
|
+
// that we can match against them.
|
|
311
|
+
// We skip '/' since you can't create a file with it on any OS
|
|
312
|
+
.replace(/#/g, '%23')
|
|
313
|
+
.replace(/\?/g, '%3F')
|
|
314
|
+
// escape characters that have special meaning in regex
|
|
315
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
316
|
+
); // TODO handle encoding
|
|
317
|
+
})
|
|
318
|
+
.join('')
|
|
283
319
|
);
|
|
284
320
|
})
|
|
285
|
-
.join('')}
|
|
321
|
+
.join('')}${add_trailing_slash ? '/?' : ''}$`
|
|
286
322
|
);
|
|
287
323
|
|
|
288
324
|
return { pattern, names, types };
|
|
@@ -527,7 +563,11 @@ function create_client({ target, session, base, trailing_slash }) {
|
|
|
527
563
|
const current_token = (token = {});
|
|
528
564
|
let navigation_result = intent && (await load_route(intent, no_cache));
|
|
529
565
|
|
|
530
|
-
if (
|
|
566
|
+
if (
|
|
567
|
+
!navigation_result &&
|
|
568
|
+
url.origin === location.origin &&
|
|
569
|
+
url.pathname === location.pathname
|
|
570
|
+
) {
|
|
531
571
|
// this could happen in SPA fallback mode if the user navigated to
|
|
532
572
|
// `/non-existent-page`. if we fall back to reloading the page, it
|
|
533
573
|
// will create an infinite loop. so whereas we normally handle
|
|
@@ -985,7 +1025,7 @@ function create_client({ target, session, base, trailing_slash }) {
|
|
|
985
1025
|
// @ts-expect-error
|
|
986
1026
|
if (node.loaded.fallthrough) {
|
|
987
1027
|
throw new Error(
|
|
988
|
-
'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-
|
|
1028
|
+
'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching'
|
|
989
1029
|
);
|
|
990
1030
|
}
|
|
991
1031
|
|
package/assets/server/index.js
CHANGED
|
@@ -2498,8 +2498,6 @@ function negotiate(accept, types) {
|
|
|
2498
2498
|
return accepted;
|
|
2499
2499
|
}
|
|
2500
2500
|
|
|
2501
|
-
/** @param {string} key */
|
|
2502
|
-
|
|
2503
2501
|
/**
|
|
2504
2502
|
* @param {RegExpMatchArray} match
|
|
2505
2503
|
* @param {string[]} names
|
|
@@ -2543,7 +2541,10 @@ async function respond(request, options, state) {
|
|
|
2543
2541
|
return new Response(undefined, {
|
|
2544
2542
|
status: 301,
|
|
2545
2543
|
headers: {
|
|
2546
|
-
location:
|
|
2544
|
+
location:
|
|
2545
|
+
// ensure paths starting with '//' are not treated as protocol-relative
|
|
2546
|
+
(normalized.startsWith('//') ? url.origin + normalized : normalized) +
|
|
2547
|
+
(url.search === '?' ? '' : url.search)
|
|
2547
2548
|
}
|
|
2548
2549
|
});
|
|
2549
2550
|
}
|
package/dist/chunks/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import { update, init } from './sync.js';
|
|
|
11
11
|
import { getRequest, setResponse } from '../node.js';
|
|
12
12
|
import { sequence } from '../hooks.js';
|
|
13
13
|
import { p as posixify } from './filesystem.js';
|
|
14
|
-
import { p as parse_route_id } from './
|
|
14
|
+
import { p as parse_route_id } from './misc.js';
|
|
15
15
|
import 'sade';
|
|
16
16
|
import 'child_process';
|
|
17
17
|
import 'net';
|
|
@@ -23,7 +23,6 @@ import 'node:zlib';
|
|
|
23
23
|
import 'node:stream';
|
|
24
24
|
import 'node:util';
|
|
25
25
|
import 'node:url';
|
|
26
|
-
import './misc.js';
|
|
27
26
|
import 'stream';
|
|
28
27
|
|
|
29
28
|
/**
|
package/dist/chunks/index2.js
CHANGED
package/dist/chunks/index3.js
CHANGED
package/dist/chunks/index4.js
CHANGED
|
@@ -2,14 +2,13 @@ import { $ } from '../cli.js';
|
|
|
2
2
|
import { r as rimraf, m as mkdirp, c as copy } from './filesystem.js';
|
|
3
3
|
import { g as generate_manifest } from './index3.js';
|
|
4
4
|
import 'sade';
|
|
5
|
+
import 'fs';
|
|
5
6
|
import 'path';
|
|
6
7
|
import 'child_process';
|
|
7
8
|
import 'net';
|
|
8
|
-
import 'fs';
|
|
9
9
|
import 'url';
|
|
10
10
|
import 'os';
|
|
11
11
|
import './misc.js';
|
|
12
|
-
import './routing.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* @param {{
|
|
@@ -49,7 +48,11 @@ function create_builder({ config, build_data, prerendered, log }) {
|
|
|
49
48
|
/** @type {import('types').RouteDefinition[]} */
|
|
50
49
|
const facades = routes.map((route) => ({
|
|
51
50
|
type: route.type,
|
|
52
|
-
segments: route.
|
|
51
|
+
segments: route.id.split('/').map((segment) => ({
|
|
52
|
+
dynamic: segment.includes('['),
|
|
53
|
+
rest: segment.includes('[...'),
|
|
54
|
+
content: segment
|
|
55
|
+
})),
|
|
53
56
|
pattern: route.pattern,
|
|
54
57
|
methods: route.type === 'page' ? ['get'] : build_data.server.methods[route.file]
|
|
55
58
|
}));
|
|
@@ -78,22 +81,7 @@ function create_builder({ config, build_data, prerendered, log }) {
|
|
|
78
81
|
// also be included, since the page likely needs the endpoint
|
|
79
82
|
filtered.forEach((route) => {
|
|
80
83
|
if (route.type === 'page') {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
const endpoint = routes.find((candidate) => {
|
|
84
|
-
if (candidate.segments.length !== length) return false;
|
|
85
|
-
|
|
86
|
-
for (let i = 0; i < length; i += 1) {
|
|
87
|
-
const a = route.segments[i];
|
|
88
|
-
const b = candidate.segments[i];
|
|
89
|
-
|
|
90
|
-
if (i === length - 1) {
|
|
91
|
-
return b.content === `${a.content}.json`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (a.content !== b.content) return false;
|
|
95
|
-
}
|
|
96
|
-
});
|
|
84
|
+
const endpoint = routes.find((candidate) => candidate.id === route.id + '.json');
|
|
97
85
|
|
|
98
86
|
if (endpoint) {
|
|
99
87
|
filtered.add(endpoint);
|
package/dist/chunks/misc.js
CHANGED
|
@@ -1,3 +1,77 @@
|
|
|
1
|
+
const param_pattern = /^(\.\.\.)?(\w+)(?:=(\w+))?$/;
|
|
2
|
+
|
|
3
|
+
/** @param {string} id */
|
|
4
|
+
function parse_route_id(id) {
|
|
5
|
+
/** @type {string[]} */
|
|
6
|
+
const names = [];
|
|
7
|
+
|
|
8
|
+
/** @type {string[]} */
|
|
9
|
+
const types = [];
|
|
10
|
+
|
|
11
|
+
// `/foo` should get an optional trailing slash, `/foo.json` should not
|
|
12
|
+
// const add_trailing_slash = !/\.[a-z]+$/.test(key);
|
|
13
|
+
let add_trailing_slash = true;
|
|
14
|
+
|
|
15
|
+
const pattern =
|
|
16
|
+
id === ''
|
|
17
|
+
? /^\/$/
|
|
18
|
+
: new RegExp(
|
|
19
|
+
`^${decodeURIComponent(id)
|
|
20
|
+
.split('/')
|
|
21
|
+
.map((segment, i, segments) => {
|
|
22
|
+
// special case — /[...rest]/ could contain zero segments
|
|
23
|
+
const match = /^\[\.\.\.(\w+)(?:=(\w+))?\]$/.exec(segment);
|
|
24
|
+
if (match) {
|
|
25
|
+
names.push(match[1]);
|
|
26
|
+
types.push(match[2]);
|
|
27
|
+
return '(?:/(.*))?';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const is_last = i === segments.length - 1;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
'/' +
|
|
34
|
+
segment
|
|
35
|
+
.split(/\[(.+?)\]/)
|
|
36
|
+
.map((content, i) => {
|
|
37
|
+
if (i % 2) {
|
|
38
|
+
const [, rest, name, type] = /** @type {RegExpMatchArray} */ (
|
|
39
|
+
param_pattern.exec(content)
|
|
40
|
+
);
|
|
41
|
+
names.push(name);
|
|
42
|
+
types.push(type);
|
|
43
|
+
return rest ? '(.*?)' : '([^/]+?)';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (is_last && content.includes('.')) add_trailing_slash = false;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
content // allow users to specify characters on the file system in an encoded manner
|
|
50
|
+
.normalize()
|
|
51
|
+
// We use [ and ] to denote parameters, so users must encode these on the file
|
|
52
|
+
// system to match against them. We don't decode all characters since others
|
|
53
|
+
// can already be epressed and so that '%' can be easily used directly in filenames
|
|
54
|
+
.replace(/%5[Bb]/g, '[')
|
|
55
|
+
.replace(/%5[Dd]/g, ']')
|
|
56
|
+
// '#', '/', and '?' can only appear in URL path segments in an encoded manner.
|
|
57
|
+
// They will not be touched by decodeURI so need to be encoded here, so
|
|
58
|
+
// that we can match against them.
|
|
59
|
+
// We skip '/' since you can't create a file with it on any OS
|
|
60
|
+
.replace(/#/g, '%23')
|
|
61
|
+
.replace(/\?/g, '%3F')
|
|
62
|
+
// escape characters that have special meaning in regex
|
|
63
|
+
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
64
|
+
); // TODO handle encoding
|
|
65
|
+
})
|
|
66
|
+
.join('')
|
|
67
|
+
);
|
|
68
|
+
})
|
|
69
|
+
.join('')}${add_trailing_slash ? '/?' : ''}$`
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return { pattern, names, types };
|
|
73
|
+
}
|
|
74
|
+
|
|
1
75
|
const s = JSON.stringify;
|
|
2
76
|
|
|
3
|
-
export { s };
|
|
77
|
+
export { parse_route_id as p, s };
|
package/dist/chunks/sync.js
CHANGED
|
@@ -2,8 +2,8 @@ import path__default from 'path';
|
|
|
2
2
|
import fs__default from 'fs';
|
|
3
3
|
import { g as get_runtime_path, $ } from '../cli.js';
|
|
4
4
|
import { p as posixify, c as copy, m as mkdirp } from './filesystem.js';
|
|
5
|
+
import { p as parse_route_id, s } from './misc.js';
|
|
5
6
|
import { fileURLToPath } from 'url';
|
|
6
|
-
import { s } from './misc.js';
|
|
7
7
|
import 'sade';
|
|
8
8
|
import 'child_process';
|
|
9
9
|
import 'net';
|
|
@@ -122,9 +122,7 @@ var mime = new Mime(standard, other);
|
|
|
122
122
|
* type: string | null;
|
|
123
123
|
* }} Part
|
|
124
124
|
* @typedef {{
|
|
125
|
-
* basename: string;
|
|
126
125
|
* name: string;
|
|
127
|
-
* ext: string;
|
|
128
126
|
* parts: Part[],
|
|
129
127
|
* file: string;
|
|
130
128
|
* is_dir: boolean;
|
|
@@ -170,14 +168,13 @@ function create_manifest_data({
|
|
|
170
168
|
/**
|
|
171
169
|
* @param {string} dir
|
|
172
170
|
* @param {string[]} parent_id
|
|
173
|
-
* @param {Part[][]} parent_segments
|
|
174
|
-
* @param {string[]} parent_params
|
|
175
171
|
* @param {Array<string|undefined>} layout_stack // accumulated __layout.svelte components
|
|
176
172
|
* @param {Array<string|undefined>} error_stack // accumulated __error.svelte components
|
|
177
173
|
*/
|
|
178
|
-
function walk(dir, parent_id,
|
|
174
|
+
function walk(dir, parent_id, layout_stack, error_stack) {
|
|
179
175
|
/** @type {Item[]} */
|
|
180
|
-
|
|
176
|
+
const items = [];
|
|
177
|
+
|
|
181
178
|
fs__default.readdirSync(dir).forEach((basename) => {
|
|
182
179
|
const resolved = path__default.join(dir, basename);
|
|
183
180
|
const file = posixify(path__default.relative(cwd, resolved));
|
|
@@ -190,110 +187,38 @@ function create_manifest_data({
|
|
|
190
187
|
|
|
191
188
|
if (ext === undefined) return;
|
|
192
189
|
|
|
193
|
-
const name =
|
|
194
|
-
|
|
195
|
-
// TODO remove this after a while
|
|
196
|
-
['layout', 'layout.reset', 'error'].forEach((reserved) => {
|
|
197
|
-
if (name === `$${reserved}`) {
|
|
198
|
-
const prefix = posixify(path__default.relative(cwd, dir));
|
|
199
|
-
const bad = `${prefix}/$${reserved}${ext}`;
|
|
200
|
-
const good = `${prefix}/__${reserved}${ext}`;
|
|
201
|
-
|
|
202
|
-
throw new Error(`${bad} should be renamed ${good}`);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
190
|
+
const name = basename.slice(0, basename.length - ext.length);
|
|
205
191
|
|
|
206
|
-
if (
|
|
192
|
+
if (name.startsWith('__') && !specials.has(name)) {
|
|
207
193
|
throw new Error(`Files and directories prefixed with __ are reserved (saw ${file})`);
|
|
208
194
|
}
|
|
209
195
|
|
|
210
|
-
if (!
|
|
211
|
-
|
|
212
|
-
if (!config.kit.routes(file)) {
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const segment = is_dir ? basename : name;
|
|
217
|
-
|
|
218
|
-
if (/\]\[/.test(segment)) {
|
|
219
|
-
throw new Error(`Invalid route ${file} — parameters must be separated`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (count_occurrences('[', segment) !== count_occurrences(']', segment)) {
|
|
223
|
-
throw new Error(`Invalid route ${file} — brackets are unbalanced`);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const parts = get_parts(segment, file);
|
|
227
|
-
const is_index = is_dir ? false : basename.startsWith('index.');
|
|
228
|
-
const is_page = config.extensions.indexOf(ext) !== -1;
|
|
229
|
-
const route_suffix = basename.slice(basename.indexOf('.'), -ext.length);
|
|
196
|
+
if (!config.kit.routes(file)) return;
|
|
230
197
|
|
|
231
198
|
items.push({
|
|
232
|
-
basename,
|
|
233
|
-
name,
|
|
234
|
-
ext,
|
|
235
|
-
parts,
|
|
236
199
|
file,
|
|
200
|
+
name,
|
|
201
|
+
parts: get_parts(name, file),
|
|
202
|
+
route_suffix: basename.slice(basename.indexOf('.'), -ext.length),
|
|
237
203
|
is_dir,
|
|
238
|
-
is_index,
|
|
239
|
-
is_page
|
|
240
|
-
route_suffix
|
|
204
|
+
is_index: !is_dir && basename.startsWith('index.'),
|
|
205
|
+
is_page: config.extensions.includes(ext)
|
|
241
206
|
});
|
|
242
207
|
});
|
|
243
|
-
|
|
208
|
+
|
|
209
|
+
items.sort(comparator);
|
|
244
210
|
|
|
245
211
|
items.forEach((item) => {
|
|
246
|
-
const
|
|
247
|
-
const segments = parent_segments.slice();
|
|
212
|
+
const id_parts = parent_id.slice();
|
|
248
213
|
|
|
249
214
|
if (item.is_index) {
|
|
250
|
-
if (item.route_suffix) {
|
|
251
|
-
|
|
252
|
-
const last_segment = segments[segments.length - 1].slice();
|
|
253
|
-
const last_part = last_segment[last_segment.length - 1];
|
|
254
|
-
|
|
255
|
-
if (last_part.dynamic) {
|
|
256
|
-
last_segment.push({
|
|
257
|
-
dynamic: false,
|
|
258
|
-
rest: false,
|
|
259
|
-
content: item.route_suffix,
|
|
260
|
-
type: null
|
|
261
|
-
});
|
|
262
|
-
} else {
|
|
263
|
-
last_segment[last_segment.length - 1] = {
|
|
264
|
-
dynamic: false,
|
|
265
|
-
rest: false,
|
|
266
|
-
content: `${last_part.content}${item.route_suffix}`,
|
|
267
|
-
type: null
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
segments[segments.length - 1] = last_segment;
|
|
272
|
-
id[id.length - 1] += item.route_suffix;
|
|
273
|
-
} else {
|
|
274
|
-
segments.push(item.parts);
|
|
275
|
-
}
|
|
215
|
+
if (item.route_suffix && id_parts.length > 0) {
|
|
216
|
+
id_parts[id_parts.length - 1] += item.route_suffix;
|
|
276
217
|
}
|
|
277
218
|
} else {
|
|
278
|
-
|
|
279
|
-
segments.push(item.parts);
|
|
219
|
+
id_parts.push(item.name);
|
|
280
220
|
}
|
|
281
221
|
|
|
282
|
-
const params = parent_params.slice();
|
|
283
|
-
params.push(...item.parts.filter((p) => p.dynamic).map((p) => p.content));
|
|
284
|
-
|
|
285
|
-
// TODO seems slightly backwards to derive the simple segment representation
|
|
286
|
-
// from the more complex form, rather than vice versa — maybe swap it round
|
|
287
|
-
const simple_segments = segments.map((segment) => {
|
|
288
|
-
return {
|
|
289
|
-
dynamic: segment.some((part) => part.dynamic),
|
|
290
|
-
rest: segment.some((part) => part.rest),
|
|
291
|
-
content: segment
|
|
292
|
-
.map((part) => (part.dynamic ? `[${part.content}]` : part.content))
|
|
293
|
-
.join('')
|
|
294
|
-
};
|
|
295
|
-
});
|
|
296
|
-
|
|
297
222
|
if (item.is_dir) {
|
|
298
223
|
const layout_reset = find_layout('__layout.reset', item.file);
|
|
299
224
|
const layout = find_layout('__layout', item.file);
|
|
@@ -308,62 +233,55 @@ function create_manifest_data({
|
|
|
308
233
|
if (error) components.push(error);
|
|
309
234
|
|
|
310
235
|
walk(
|
|
311
|
-
path__default.join(dir, item.
|
|
312
|
-
|
|
313
|
-
segments,
|
|
314
|
-
params,
|
|
236
|
+
path__default.join(dir, item.name),
|
|
237
|
+
id_parts,
|
|
315
238
|
layout_reset ? [layout_reset] : layout_stack.concat(layout),
|
|
316
239
|
layout_reset ? [error] : error_stack.concat(error)
|
|
317
240
|
);
|
|
318
|
-
} else
|
|
319
|
-
|
|
241
|
+
} else {
|
|
242
|
+
const id = id_parts.join('/');
|
|
243
|
+
const { pattern } = parse_route_id(id);
|
|
320
244
|
|
|
321
|
-
|
|
322
|
-
|
|
245
|
+
if (item.is_page) {
|
|
246
|
+
components.push(item.file);
|
|
323
247
|
|
|
324
|
-
|
|
248
|
+
const concatenated = layout_stack.concat(item.file);
|
|
249
|
+
const errors = error_stack.slice();
|
|
325
250
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
251
|
+
let i = concatenated.length;
|
|
252
|
+
while (i--) {
|
|
253
|
+
if (!errors[i] && !concatenated[i]) {
|
|
254
|
+
errors.splice(i, 1);
|
|
255
|
+
concatenated.splice(i, 1);
|
|
256
|
+
}
|
|
331
257
|
}
|
|
332
|
-
}
|
|
333
258
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
259
|
+
i = errors.length;
|
|
260
|
+
while (i--) {
|
|
261
|
+
if (errors[i]) break;
|
|
262
|
+
}
|
|
338
263
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
type: 'endpoint',
|
|
361
|
-
id: id.join('/'),
|
|
362
|
-
segments: simple_segments,
|
|
363
|
-
pattern,
|
|
364
|
-
file: item.file,
|
|
365
|
-
params
|
|
366
|
-
});
|
|
264
|
+
errors.splice(i + 1);
|
|
265
|
+
|
|
266
|
+
const path = id.includes('[') ? '' : `/${id}`;
|
|
267
|
+
|
|
268
|
+
routes.push({
|
|
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
|
+
}
|
|
367
285
|
}
|
|
368
286
|
});
|
|
369
287
|
}
|
|
@@ -375,7 +293,7 @@ function create_manifest_data({
|
|
|
375
293
|
|
|
376
294
|
components.push(layout, error);
|
|
377
295
|
|
|
378
|
-
walk(config.kit.files.routes, [], [
|
|
296
|
+
walk(config.kit.files.routes, [], [layout], [error]);
|
|
379
297
|
|
|
380
298
|
const lookup = new Map();
|
|
381
299
|
for (const route of routes) {
|
|
@@ -410,7 +328,7 @@ function create_manifest_data({
|
|
|
410
328
|
matchers[type] = path__default.join(params_base, file);
|
|
411
329
|
} else {
|
|
412
330
|
throw new Error(
|
|
413
|
-
`
|
|
331
|
+
`Matcher names must match /^[a-zA-Z_][a-zA-Z0-9_]*$/ — "${file}" is invalid`
|
|
414
332
|
);
|
|
415
333
|
}
|
|
416
334
|
}
|
|
@@ -438,11 +356,7 @@ function count_occurrences(needle, haystack) {
|
|
|
438
356
|
return count;
|
|
439
357
|
}
|
|
440
358
|
|
|
441
|
-
|
|
442
|
-
function is_spread(path) {
|
|
443
|
-
const spread_pattern = /\[\.{3}/g;
|
|
444
|
-
return spread_pattern.test(path);
|
|
445
|
-
}
|
|
359
|
+
const spread_pattern = /\[\.{3}/;
|
|
446
360
|
|
|
447
361
|
/**
|
|
448
362
|
* @param {Item} a
|
|
@@ -450,9 +364,8 @@ function is_spread(path) {
|
|
|
450
364
|
*/
|
|
451
365
|
function comparator(a, b) {
|
|
452
366
|
if (a.is_index !== b.is_index) {
|
|
453
|
-
if (a.is_index) return
|
|
454
|
-
|
|
455
|
-
return is_spread(b.file) ? -1 : 1;
|
|
367
|
+
if (a.is_index) return spread_pattern.test(a.file) ? 1 : -1;
|
|
368
|
+
return spread_pattern.test(b.file) ? -1 : 1;
|
|
456
369
|
}
|
|
457
370
|
|
|
458
371
|
const max = Math.max(a.parts.length, b.parts.length);
|
|
@@ -504,6 +417,14 @@ function comparator(a, b) {
|
|
|
504
417
|
* @param {string} file
|
|
505
418
|
*/
|
|
506
419
|
function get_parts(part, file) {
|
|
420
|
+
if (/\]\[/.test(part)) {
|
|
421
|
+
throw new Error(`Invalid route ${file} — parameters must be separated`);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (count_occurrences('[', part) !== count_occurrences(']', part)) {
|
|
425
|
+
throw new Error(`Invalid route ${file} — brackets are unbalanced`);
|
|
426
|
+
}
|
|
427
|
+
|
|
507
428
|
/** @type {Part[]} */
|
|
508
429
|
const result = [];
|
|
509
430
|
part.split(/\[(.+?\(.+?\)|.+?)\]/).map((str, i) => {
|
|
@@ -535,52 +456,6 @@ function get_parts(part, file) {
|
|
|
535
456
|
return result;
|
|
536
457
|
}
|
|
537
458
|
|
|
538
|
-
/**
|
|
539
|
-
* @param {Part[][]} segments
|
|
540
|
-
* @param {boolean} add_trailing_slash
|
|
541
|
-
*/
|
|
542
|
-
function get_pattern(segments, add_trailing_slash) {
|
|
543
|
-
const path = segments
|
|
544
|
-
.map((segment) => {
|
|
545
|
-
if (segment.length === 1 && segment[0].rest) {
|
|
546
|
-
// special case — `src/routes/foo/[...bar]/baz` matches `/foo/baz`
|
|
547
|
-
// so we need to make the leading slash optional
|
|
548
|
-
return '(?:\\/(.*))?';
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
const parts = segment.map((part) => {
|
|
552
|
-
if (part.rest) return '(.*?)';
|
|
553
|
-
if (part.dynamic) return '([^/]+?)';
|
|
554
|
-
|
|
555
|
-
return (
|
|
556
|
-
part.content
|
|
557
|
-
// allow users to specify characters on the file system in an encoded manner
|
|
558
|
-
.normalize()
|
|
559
|
-
// We use [ and ] to denote parameters, so users must encode these on the file
|
|
560
|
-
// system to match against them. We don't decode all characters since others
|
|
561
|
-
// can already be epressed and so that '%' can be easily used directly in filenames
|
|
562
|
-
.replace(/%5[Bb]/g, '[')
|
|
563
|
-
.replace(/%5[Dd]/g, ']')
|
|
564
|
-
// '#', '/', and '?' can only appear in URL path segments in an encoded manner.
|
|
565
|
-
// They will not be touched by decodeURI so need to be encoded here, so
|
|
566
|
-
// that we can match against them.
|
|
567
|
-
// We skip '/' since you can't create a file with it on any OS
|
|
568
|
-
.replace(/#/g, '%23')
|
|
569
|
-
.replace(/\?/g, '%3F')
|
|
570
|
-
// escape characters that have special meaning in regex
|
|
571
|
-
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
572
|
-
);
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
return '\\/' + parts.join('');
|
|
576
|
-
})
|
|
577
|
-
.join('');
|
|
578
|
-
|
|
579
|
-
const trailing = add_trailing_slash && segments.length ? '\\/?$' : '$';
|
|
580
|
-
|
|
581
|
-
return new RegExp(`^${path || '\\/'}${trailing}`);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
459
|
/**
|
|
585
460
|
* @param {{
|
|
586
461
|
* config: import('types').ValidatedConfig;
|
|
@@ -704,6 +579,28 @@ function write_manifest(manifest_data, base, output) {
|
|
|
704
579
|
);
|
|
705
580
|
}
|
|
706
581
|
|
|
582
|
+
/**
|
|
583
|
+
* @param {import('types').ManifestData} manifest_data
|
|
584
|
+
* @param {string} output
|
|
585
|
+
*/
|
|
586
|
+
function write_matchers(manifest_data, output) {
|
|
587
|
+
const imports = [];
|
|
588
|
+
const matchers = [];
|
|
589
|
+
|
|
590
|
+
for (const key in manifest_data.matchers) {
|
|
591
|
+
const src = manifest_data.matchers[key];
|
|
592
|
+
|
|
593
|
+
imports.push(`import { match as ${key} } from ${s(path__default.relative(output, src))};`);
|
|
594
|
+
matchers.push(key);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const module = imports.length
|
|
598
|
+
? `${imports.join('\n')}\n\nexport const matchers = { ${matchers.join(', ')} };`
|
|
599
|
+
: 'export const matchers = {};';
|
|
600
|
+
|
|
601
|
+
write_if_changed(`${output}/client-matchers.js`, module);
|
|
602
|
+
}
|
|
603
|
+
|
|
707
604
|
/**
|
|
708
605
|
* @param {import('types').ManifestData} manifest_data
|
|
709
606
|
* @param {string} output
|
|
@@ -1003,28 +900,6 @@ function write_types(config, manifest_data) {
|
|
|
1003
900
|
});
|
|
1004
901
|
}
|
|
1005
902
|
|
|
1006
|
-
/**
|
|
1007
|
-
* @param {import('types').ManifestData} manifest_data
|
|
1008
|
-
* @param {string} output
|
|
1009
|
-
*/
|
|
1010
|
-
function write_validators(manifest_data, output) {
|
|
1011
|
-
const imports = [];
|
|
1012
|
-
const matchers = [];
|
|
1013
|
-
|
|
1014
|
-
for (const key in manifest_data.matchers) {
|
|
1015
|
-
const src = manifest_data.matchers[key];
|
|
1016
|
-
|
|
1017
|
-
imports.push(`import { match as ${key} } from ${s(path__default.relative(output, src))};`);
|
|
1018
|
-
matchers.push(key);
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
const module = imports.length
|
|
1022
|
-
? `${imports.join('\n')}\n\nexport const matchers = { ${matchers.join(', ')} };`
|
|
1023
|
-
: 'export const matchers = {};';
|
|
1024
|
-
|
|
1025
|
-
write_if_changed(`${output}/client-matchers.js`, module);
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
903
|
/** @param {import('types').ValidatedConfig} config */
|
|
1029
904
|
function init(config) {
|
|
1030
905
|
copy_assets(path__default.join(config.kit.outDir, 'runtime'));
|
|
@@ -1040,7 +915,7 @@ function update(config) {
|
|
|
1040
915
|
|
|
1041
916
|
write_manifest(manifest_data, base, output);
|
|
1042
917
|
write_root(manifest_data, output);
|
|
1043
|
-
|
|
918
|
+
write_matchers(manifest_data, output);
|
|
1044
919
|
write_types(config, manifest_data);
|
|
1045
920
|
|
|
1046
921
|
return { manifest_data };
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import sade from 'sade';
|
|
2
|
+
import fs__default from 'fs';
|
|
2
3
|
import path__default, { join, relative } from 'path';
|
|
3
4
|
import { exec as exec$1 } from 'child_process';
|
|
4
5
|
import { createConnection, createServer } from 'net';
|
|
5
|
-
import fs__default from 'fs';
|
|
6
6
|
import * as url from 'url';
|
|
7
7
|
import { networkInterfaces, release } from 'os';
|
|
8
8
|
|
|
@@ -869,7 +869,7 @@ async function launch(port, https) {
|
|
|
869
869
|
exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
|
|
870
870
|
}
|
|
871
871
|
|
|
872
|
-
const prog = sade('svelte-kit').version('1.0.0-next.
|
|
872
|
+
const prog = sade('svelte-kit').version('1.0.0-next.303');
|
|
873
873
|
|
|
874
874
|
prog
|
|
875
875
|
.command('dev')
|
|
@@ -996,6 +996,11 @@ prog
|
|
|
996
996
|
.command('sync')
|
|
997
997
|
.describe('Synchronise generated files')
|
|
998
998
|
.action(async () => {
|
|
999
|
+
if (!fs__default.existsSync('svelte.config.js')) {
|
|
1000
|
+
console.warn('Missing svelte.config.js — skipping');
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
999
1004
|
try {
|
|
1000
1005
|
const config = await load_config();
|
|
1001
1006
|
const sync = await import('./chunks/sync.js');
|
|
@@ -1042,7 +1047,7 @@ async function check_port(port) {
|
|
|
1042
1047
|
function welcome({ port, host, https, open, loose, allow, cwd }) {
|
|
1043
1048
|
if (open) launch(port, https);
|
|
1044
1049
|
|
|
1045
|
-
console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.
|
|
1050
|
+
console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.303'}\n`));
|
|
1046
1051
|
|
|
1047
1052
|
const protocol = https ? 'https:' : 'http:';
|
|
1048
1053
|
const exposed = typeof host !== 'undefined' && host !== 'localhost' && host !== '127.0.0.1';
|
package/package.json
CHANGED
package/types/internal.d.ts
CHANGED
|
@@ -78,9 +78,7 @@ export type CSRRoute = {
|
|
|
78
78
|
export interface EndpointData {
|
|
79
79
|
type: 'endpoint';
|
|
80
80
|
id: string;
|
|
81
|
-
segments: RouteSegment[];
|
|
82
81
|
pattern: RegExp;
|
|
83
|
-
params: string[];
|
|
84
82
|
file: string;
|
|
85
83
|
}
|
|
86
84
|
|
|
@@ -129,9 +127,7 @@ export interface PageData {
|
|
|
129
127
|
type: 'page';
|
|
130
128
|
id: string;
|
|
131
129
|
shadow: string | null;
|
|
132
|
-
segments: RouteSegment[];
|
|
133
130
|
pattern: RegExp;
|
|
134
|
-
params: string[];
|
|
135
131
|
path: string;
|
|
136
132
|
a: string[];
|
|
137
133
|
b: string[];
|
package/dist/chunks/routing.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/** @param {string} key */
|
|
2
|
-
function parse_route_id(key) {
|
|
3
|
-
/** @type {string[]} */
|
|
4
|
-
const names = [];
|
|
5
|
-
|
|
6
|
-
/** @type {string[]} */
|
|
7
|
-
const types = [];
|
|
8
|
-
|
|
9
|
-
const pattern =
|
|
10
|
-
key === ''
|
|
11
|
-
? /^\/$/
|
|
12
|
-
: new RegExp(
|
|
13
|
-
`^${decodeURIComponent(key)
|
|
14
|
-
.split('/')
|
|
15
|
-
.map((segment) => {
|
|
16
|
-
// special case — /[...rest]/ could contain zero segments
|
|
17
|
-
const match = /^\[\.\.\.(\w+)(?:=\w+)?\]$/.exec(segment);
|
|
18
|
-
if (match) {
|
|
19
|
-
names.push(match[1]);
|
|
20
|
-
types.push(match[2]);
|
|
21
|
-
return '(?:/(.*))?';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
'/' +
|
|
26
|
-
segment.replace(/\[(\.\.\.)?(\w+)(?:=(\w+))?\]/g, (m, rest, name, type) => {
|
|
27
|
-
names.push(name);
|
|
28
|
-
types.push(type);
|
|
29
|
-
return rest ? '(.*?)' : '([^/]+?)';
|
|
30
|
-
})
|
|
31
|
-
);
|
|
32
|
-
})
|
|
33
|
-
.join('')}/?$`
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
return { pattern, names, types };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export { parse_route_id as p };
|