@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.
@@ -250,39 +250,75 @@ function initial_fetch(resource, opts) {
250
250
  return fetch(resource, opts);
251
251
  }
252
252
 
253
- /** @param {string} key */
254
- function parse_route_id(key) {
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
- key === ''
268
+ id === ''
263
269
  ? /^\/$/
264
270
  : new RegExp(
265
- `^${decodeURIComponent(key)
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+)(?:=\w+)?\]$/.exec(segment);
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.replace(/\[(\.\.\.)?(\w+)(?:=(\w+))?\]/g, (m, rest, name, type) => {
279
- names.push(name);
280
- types.push(type);
281
- return rest ? '(.*?)' : '([^/]+?)';
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 (!navigation_result && url.pathname === location.pathname) {
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-validation'
1028
+ 'fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching'
989
1029
  );
990
1030
  }
991
1031
 
@@ -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: normalized + (url.search === '?' ? '' : url.search)
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
  }
@@ -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 './routing.js';
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
  /**
@@ -15,7 +15,6 @@ import 'sade';
15
15
  import 'child_process';
16
16
  import 'net';
17
17
  import 'os';
18
- import './routing.js';
19
18
  import 'node:http';
20
19
  import 'node:https';
21
20
  import 'node:zlib';
@@ -1,5 +1,4 @@
1
- import { s } from './misc.js';
2
- import { p as parse_route_id } from './routing.js';
1
+ import { s, p as parse_route_id } from './misc.js';
3
2
  import { a as get_mime_lookup } from '../cli.js';
4
3
 
5
4
  /**
@@ -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.segments,
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 length = route.segments.length;
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);
@@ -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 };
@@ -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, parent_segments, parent_params, layout_stack, error_stack) {
174
+ function walk(dir, parent_id, layout_stack, error_stack) {
179
175
  /** @type {Item[]} */
180
- let items = [];
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 = ext ? basename.slice(0, -ext.length) : basename;
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 (basename.startsWith('__') && !specials.has(name)) {
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 (!is_dir && !/^(\.[a-z0-9]+)+$/i.test(ext)) return null; // filter out tmp files etc
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
- items = items.sort(comparator);
208
+
209
+ items.sort(comparator);
244
210
 
245
211
  items.forEach((item) => {
246
- const id = parent_id.slice();
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
- if (segments.length > 0) {
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
- id.push(item.name);
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.basename),
312
- id,
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 if (item.is_page) {
319
- components.push(item.file);
241
+ } else {
242
+ const id = id_parts.join('/');
243
+ const { pattern } = parse_route_id(id);
320
244
 
321
- const concatenated = layout_stack.concat(item.file);
322
- const errors = error_stack.slice();
245
+ if (item.is_page) {
246
+ components.push(item.file);
323
247
 
324
- const pattern = get_pattern(segments, true);
248
+ const concatenated = layout_stack.concat(item.file);
249
+ const errors = error_stack.slice();
325
250
 
326
- let i = concatenated.length;
327
- while (i--) {
328
- if (!errors[i] && !concatenated[i]) {
329
- errors.splice(i, 1);
330
- concatenated.splice(i, 1);
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
- i = errors.length;
335
- while (i--) {
336
- if (errors[i]) break;
337
- }
259
+ i = errors.length;
260
+ while (i--) {
261
+ if (errors[i]) break;
262
+ }
338
263
 
339
- errors.splice(i + 1);
340
-
341
- const path = segments.every((segment) => segment.length === 1 && !segment[0].dynamic)
342
- ? `/${segments.map((segment) => segment[0].content).join('/')}`
343
- : '';
344
-
345
- routes.push({
346
- type: 'page',
347
- id: id.join('/'),
348
- segments: simple_segments,
349
- pattern,
350
- params,
351
- path,
352
- shadow: null,
353
- a: /** @type {string[]} */ (concatenated),
354
- b: /** @type {string[]} */ (errors)
355
- });
356
- } else {
357
- const pattern = get_pattern(segments, !item.route_suffix);
358
-
359
- routes.push({
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, [], [], [], [layout], [error]);
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
- `Validator names must match /^[a-zA-Z_][a-zA-Z0-9_]*$/ — "${file}" is invalid`
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
- /** @param {string} path */
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 is_spread(a.file) ? 1 : -1;
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
- write_validators(manifest_data, output);
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.300');
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.300'}\n`));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.300",
3
+ "version": "1.0.0-next.303",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -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[];
@@ -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 };