@sveltejs/kit 1.0.0-next.304 → 1.0.0-next.307
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 +44 -34
- package/dist/chunks/index.js +12 -5
- package/dist/chunks/index2.js +1 -0
- package/dist/chunks/index3.js +1 -1
- package/dist/chunks/misc.js +33 -32
- package/dist/chunks/sync.js +324 -271
- package/dist/cli.js +10 -8
- package/package.json +2 -2
- package/types/index.d.ts +6 -10
- package/types/internal.d.ts +4 -6
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
|
@@ -2081,38 +2081,46 @@ async function respond_with_error({
|
|
|
2081
2081
|
resolve_opts
|
|
2082
2082
|
}) {
|
|
2083
2083
|
try {
|
|
2084
|
-
const
|
|
2085
|
-
|
|
2084
|
+
const branch = [];
|
|
2085
|
+
let stuff = {};
|
|
2086
|
+
|
|
2087
|
+
if (resolve_opts.ssr) {
|
|
2088
|
+
const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
|
|
2089
|
+
const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
|
|
2090
|
+
|
|
2091
|
+
const layout_loaded = /** @type {Loaded} */ (
|
|
2092
|
+
await load_node({
|
|
2093
|
+
event,
|
|
2094
|
+
options,
|
|
2095
|
+
state,
|
|
2096
|
+
route: null,
|
|
2097
|
+
node: default_layout,
|
|
2098
|
+
$session,
|
|
2099
|
+
stuff: {},
|
|
2100
|
+
is_error: false,
|
|
2101
|
+
is_leaf: false
|
|
2102
|
+
})
|
|
2103
|
+
);
|
|
2086
2104
|
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2105
|
+
const error_loaded = /** @type {Loaded} */ (
|
|
2106
|
+
await load_node({
|
|
2107
|
+
event,
|
|
2108
|
+
options,
|
|
2109
|
+
state,
|
|
2110
|
+
route: null,
|
|
2111
|
+
node: default_error,
|
|
2112
|
+
$session,
|
|
2113
|
+
stuff: layout_loaded ? layout_loaded.stuff : {},
|
|
2114
|
+
is_error: true,
|
|
2115
|
+
is_leaf: false,
|
|
2116
|
+
status,
|
|
2117
|
+
error
|
|
2118
|
+
})
|
|
2119
|
+
);
|
|
2100
2120
|
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
options,
|
|
2105
|
-
state,
|
|
2106
|
-
route: null,
|
|
2107
|
-
node: default_error,
|
|
2108
|
-
$session,
|
|
2109
|
-
stuff: layout_loaded ? layout_loaded.stuff : {},
|
|
2110
|
-
is_error: true,
|
|
2111
|
-
is_leaf: false,
|
|
2112
|
-
status,
|
|
2113
|
-
error
|
|
2114
|
-
})
|
|
2115
|
-
);
|
|
2121
|
+
branch.push(layout_loaded, error_loaded);
|
|
2122
|
+
stuff = error_loaded.stuff;
|
|
2123
|
+
}
|
|
2116
2124
|
|
|
2117
2125
|
return await render_response({
|
|
2118
2126
|
options,
|
|
@@ -2122,10 +2130,10 @@ async function respond_with_error({
|
|
|
2122
2130
|
hydrate: options.hydrate,
|
|
2123
2131
|
router: options.router
|
|
2124
2132
|
},
|
|
2125
|
-
stuff
|
|
2133
|
+
stuff,
|
|
2126
2134
|
status,
|
|
2127
2135
|
error,
|
|
2128
|
-
branch
|
|
2136
|
+
branch,
|
|
2129
2137
|
event,
|
|
2130
2138
|
resolve_opts
|
|
2131
2139
|
});
|
|
@@ -2181,7 +2189,8 @@ async function respond$1(opts) {
|
|
|
2181
2189
|
|
|
2182
2190
|
try {
|
|
2183
2191
|
nodes = await Promise.all(
|
|
2184
|
-
|
|
2192
|
+
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
2193
|
+
route.a.map((n) => (n == undefined ? n : options.manifest._.nodes[n]()))
|
|
2185
2194
|
);
|
|
2186
2195
|
} catch (err) {
|
|
2187
2196
|
const error = coalesce_to_error(err);
|
|
@@ -2280,7 +2289,8 @@ async function respond$1(opts) {
|
|
|
2280
2289
|
if (error) {
|
|
2281
2290
|
while (i--) {
|
|
2282
2291
|
if (route.b[i]) {
|
|
2283
|
-
const
|
|
2292
|
+
const index = /** @type {number} */ (route.b[i]);
|
|
2293
|
+
const error_node = await options.manifest._.nodes[index]();
|
|
2284
2294
|
|
|
2285
2295
|
/** @type {Loaded} */
|
|
2286
2296
|
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';
|
|
@@ -131,8 +132,8 @@ async function create_plugin(config, cwd) {
|
|
|
131
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
|
|
|
@@ -214,7 +215,13 @@ async function create_plugin(config, cwd) {
|
|
|
214
215
|
|
|
215
216
|
if (req.url === '/favicon.ico') return not_found(res);
|
|
216
217
|
|
|
217
|
-
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
|
+
}
|
|
218
225
|
|
|
219
226
|
/** @type {Partial<import('types').Hooks>} */
|
|
220
227
|
const user_hooks = resolve_entry(config.kit.files.hooks)
|
|
@@ -370,9 +377,9 @@ async function create_plugin(config, cwd) {
|
|
|
370
377
|
}
|
|
371
378
|
|
|
372
379
|
/** @param {import('http').ServerResponse} res */
|
|
373
|
-
function not_found(res) {
|
|
380
|
+
function not_found(res, message = 'Not found') {
|
|
374
381
|
res.statusCode = 404;
|
|
375
|
-
res.end(
|
|
382
|
+
res.end(message);
|
|
376
383
|
}
|
|
377
384
|
|
|
378
385
|
/**
|
package/dist/chunks/index2.js
CHANGED
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,201 @@ 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
|
|
199
|
+
.slice(0, -extension.length)
|
|
200
|
+
.replace(/(?:^|\/)index((?:@[a-zA-Z0-9_-]+)?(?:\.[a-z]+)?)?$/, '$1');
|
|
201
|
+
const project_relative = `${routes_base}/${file}`;
|
|
197
202
|
|
|
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
|
-
});
|
|
203
|
+
const segments = id.split('/');
|
|
204
|
+
const name = /** @type {string} */ (segments.pop());
|
|
208
205
|
|
|
209
|
-
|
|
206
|
+
if (name === '__layout.reset') {
|
|
207
|
+
throw new Error(
|
|
208
|
+
'__layout.reset has been removed in favour of named layouts: https://kit.svelte.dev/docs/layouts#named-layouts'
|
|
209
|
+
);
|
|
210
|
+
}
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
const
|
|
212
|
+
if (name === '__error' || layout_pattern.test(name)) {
|
|
213
|
+
const dir = segments.join('/');
|
|
213
214
|
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
id_parts.push(item.name);
|
|
215
|
+
if (!tree.has(dir)) {
|
|
216
|
+
tree.set(dir, {
|
|
217
|
+
error: undefined,
|
|
218
|
+
layouts: {}
|
|
219
|
+
});
|
|
220
220
|
}
|
|
221
221
|
|
|
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);
|
|
222
|
+
const group = /** @type {Node} */ (tree.get(dir));
|
|
226
223
|
|
|
227
|
-
|
|
228
|
-
|
|
224
|
+
if (name === '__error') {
|
|
225
|
+
group.error = project_relative;
|
|
226
|
+
} else {
|
|
227
|
+
const match = /** @type {RegExpMatchArray} */ (layout_pattern.exec(name));
|
|
228
|
+
|
|
229
|
+
if (match[1] === DEFAULT) {
|
|
230
|
+
throw new Error(`${project_relative} cannot use reserved "${DEFAULT}" name`);
|
|
229
231
|
}
|
|
230
232
|
|
|
231
|
-
|
|
232
|
-
if (layout) components.push(layout);
|
|
233
|
-
if (error) components.push(error);
|
|
233
|
+
const layout_id = match[1] || DEFAULT;
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
} else {
|
|
242
|
-
const id = id_parts.join('/');
|
|
243
|
-
const { pattern } = parse_route_id(id);
|
|
235
|
+
const defined = group.layouts[layout_id];
|
|
236
|
+
if (defined && defined !== default_layout) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`Duplicate layout ${project_relative} already defined at ${defined.file}`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
244
241
|
|
|
245
|
-
|
|
246
|
-
|
|
242
|
+
group.layouts[layout_id] = {
|
|
243
|
+
file: project_relative,
|
|
244
|
+
name
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
247
|
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
return;
|
|
249
|
+
} else if (dunder_pattern.test(file)) {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`Files and directories prefixed with __ are reserved (saw ${project_relative})`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
250
254
|
|
|
251
|
-
|
|
252
|
-
while (i--) {
|
|
253
|
-
if (!errors[i] && !concatenated[i]) {
|
|
254
|
-
errors.splice(i, 1);
|
|
255
|
-
concatenated.splice(i, 1);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
255
|
+
if (!config.kit.routes(file)) return;
|
|
258
256
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
257
|
+
if (/\]\[/.test(id)) {
|
|
258
|
+
throw new Error(`Invalid route ${project_relative} — parameters must be separated`);
|
|
259
|
+
}
|
|
263
260
|
|
|
264
|
-
|
|
261
|
+
if (count_occurrences('[', id) !== count_occurrences(']', id)) {
|
|
262
|
+
throw new Error(`Invalid route ${project_relative} — brackets are unbalanced`);
|
|
263
|
+
}
|
|
265
264
|
|
|
266
|
-
|
|
265
|
+
if (!units.has(id)) {
|
|
266
|
+
units.set(id, {
|
|
267
|
+
id,
|
|
268
|
+
pattern: parse_route_id(id).pattern,
|
|
269
|
+
segments: id
|
|
270
|
+
.split('/')
|
|
271
|
+
.filter(Boolean)
|
|
272
|
+
.map((segment) => {
|
|
273
|
+
/** @type {Part[]} */
|
|
274
|
+
const parts = [];
|
|
275
|
+
segment.split(/\[(.+?)\]/).map((content, i) => {
|
|
276
|
+
const dynamic = !!(i % 2);
|
|
277
|
+
|
|
278
|
+
if (!content) return;
|
|
279
|
+
|
|
280
|
+
parts.push({
|
|
281
|
+
content,
|
|
282
|
+
dynamic,
|
|
283
|
+
rest: dynamic && content.startsWith('...'),
|
|
284
|
+
type: (dynamic && content.split('=')[1]) || null
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
return parts;
|
|
288
|
+
}),
|
|
289
|
+
page: undefined,
|
|
290
|
+
endpoint: undefined
|
|
291
|
+
});
|
|
292
|
+
}
|
|
267
293
|
|
|
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
|
-
}
|
|
294
|
+
const unit = /** @type {Unit} */ (units.get(id));
|
|
288
295
|
|
|
289
|
-
|
|
296
|
+
if (config.extensions.find((ext) => file.endsWith(ext))) {
|
|
297
|
+
const { layouts, errors } = trace(project_relative, file, tree, config.extensions);
|
|
298
|
+
unit.page = {
|
|
299
|
+
a: layouts.concat(project_relative),
|
|
300
|
+
b: errors
|
|
301
|
+
};
|
|
302
|
+
} else {
|
|
303
|
+
unit.endpoint = project_relative;
|
|
304
|
+
}
|
|
305
|
+
});
|
|
290
306
|
|
|
291
|
-
|
|
292
|
-
const
|
|
307
|
+
/** @type {string[]} */
|
|
308
|
+
const components = [];
|
|
293
309
|
|
|
294
|
-
|
|
310
|
+
tree.forEach(({ layouts, error }) => {
|
|
311
|
+
// we do [default, error, ...other_layouts] so that components[0] and [1]
|
|
312
|
+
// are the root layout/error. kinda janky, there's probably a nicer way
|
|
313
|
+
if (layouts[DEFAULT]) {
|
|
314
|
+
components.push(layouts[DEFAULT].file);
|
|
315
|
+
}
|
|
295
316
|
|
|
296
|
-
|
|
317
|
+
if (error) {
|
|
318
|
+
components.push(error);
|
|
319
|
+
}
|
|
297
320
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (route.type === 'page') {
|
|
301
|
-
lookup.set(route.id, route);
|
|
321
|
+
for (const id in layouts) {
|
|
322
|
+
if (id !== DEFAULT) components.push(layouts[id].file);
|
|
302
323
|
}
|
|
303
|
-
}
|
|
324
|
+
});
|
|
304
325
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
lookup.get(route.id).shadow = route.file;
|
|
310
|
-
routes.splice(i, 1);
|
|
326
|
+
units.forEach((unit) => {
|
|
327
|
+
if (unit.page) {
|
|
328
|
+
const leaf = /** @type {string} */ (unit.page.a[unit.page.a.length - 1]);
|
|
329
|
+
components.push(leaf);
|
|
311
330
|
}
|
|
312
|
-
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
Array.from(units.values())
|
|
334
|
+
.sort(compare)
|
|
335
|
+
.forEach((unit) => {
|
|
336
|
+
// TODO when we introduce layout endpoints and scoped middlewares, we
|
|
337
|
+
// will probably want to have a single unified route type here
|
|
338
|
+
// (created in the list_files(...).forEach(...) callback)
|
|
339
|
+
if (unit.page) {
|
|
340
|
+
routes.push({
|
|
341
|
+
type: 'page',
|
|
342
|
+
id: unit.id,
|
|
343
|
+
pattern: unit.pattern,
|
|
344
|
+
path: unit.id.includes('[') ? '' : `/${unit.id.replace(/@(?:[a-zA-Z0-9_-]+)/g, '')}`,
|
|
345
|
+
shadow: unit.endpoint || null,
|
|
346
|
+
a: unit.page.a,
|
|
347
|
+
b: unit.page.b
|
|
348
|
+
});
|
|
349
|
+
} else if (unit.endpoint) {
|
|
350
|
+
routes.push({
|
|
351
|
+
type: 'endpoint',
|
|
352
|
+
id: unit.id,
|
|
353
|
+
pattern: unit.pattern,
|
|
354
|
+
file: unit.endpoint
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
});
|
|
313
358
|
|
|
359
|
+
/** @type {import('types').Asset[]} */
|
|
314
360
|
const assets = fs__default.existsSync(config.kit.files.assets)
|
|
315
|
-
? list_files(
|
|
361
|
+
? list_files(config.kit.files.assets).map((file) => ({
|
|
362
|
+
file,
|
|
363
|
+
size: fs__default.statSync(`${config.kit.files.assets}/${file}`).size,
|
|
364
|
+
type: mime.getType(file)
|
|
365
|
+
}))
|
|
316
366
|
: [];
|
|
317
367
|
|
|
318
368
|
const params_base = path__default.relative(cwd, config.kit.files.params);
|
|
@@ -336,8 +386,6 @@ function create_manifest_data({
|
|
|
336
386
|
|
|
337
387
|
return {
|
|
338
388
|
assets,
|
|
339
|
-
layout,
|
|
340
|
-
error,
|
|
341
389
|
components,
|
|
342
390
|
routes,
|
|
343
391
|
matchers
|
|
@@ -345,142 +393,162 @@ function create_manifest_data({
|
|
|
345
393
|
}
|
|
346
394
|
|
|
347
395
|
/**
|
|
348
|
-
* @param {string}
|
|
349
|
-
* @param {string}
|
|
396
|
+
* @param {string} file
|
|
397
|
+
* @param {string} path
|
|
398
|
+
* @param {Tree} tree
|
|
399
|
+
* @param {string[]} extensions
|
|
350
400
|
*/
|
|
351
|
-
function
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
401
|
+
function trace(file, path, tree, extensions) {
|
|
402
|
+
/** @type {Array<string | undefined>} */
|
|
403
|
+
const layouts = [];
|
|
404
|
+
|
|
405
|
+
/** @type {Array<string | undefined>} */
|
|
406
|
+
const errors = [];
|
|
407
|
+
|
|
408
|
+
const parts = path.split('/');
|
|
409
|
+
const filename = /** @type {string} */ (parts.pop());
|
|
410
|
+
const extension = /** @type {string} */ (extensions.find((ext) => path.endsWith(ext)));
|
|
411
|
+
const base = filename.slice(0, -extension.length);
|
|
412
|
+
|
|
413
|
+
let layout_id = base.includes('@') ? base.split('@')[1] : DEFAULT;
|
|
414
|
+
|
|
415
|
+
// walk up the tree, find which __layout and __error components
|
|
416
|
+
// apply to this page
|
|
417
|
+
// eslint-disable-next-line
|
|
418
|
+
while (true) {
|
|
419
|
+
const node = tree.get(parts.join('/'));
|
|
420
|
+
const layout = node?.layouts[layout_id];
|
|
421
|
+
|
|
422
|
+
// any segment that has neither a __layout nor an __error can be discarded.
|
|
423
|
+
// in other words these...
|
|
424
|
+
// layouts: [a, , b, c]
|
|
425
|
+
// errors: [d, , e, ]
|
|
426
|
+
//
|
|
427
|
+
// ...can be compacted to these:
|
|
428
|
+
// layouts: [a, b, c]
|
|
429
|
+
// errors: [d, e, ]
|
|
430
|
+
if (node?.error || layout?.file) {
|
|
431
|
+
errors.unshift(node?.error);
|
|
432
|
+
layouts.unshift(layout?.file);
|
|
433
|
+
}
|
|
360
434
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return spread_pattern.test(b.file) ? -1 : 1;
|
|
435
|
+
if (layout?.name.includes('@')) {
|
|
436
|
+
layout_id = layout.name.split('@')[1];
|
|
437
|
+
} else {
|
|
438
|
+
if (layout) layout_id = DEFAULT;
|
|
439
|
+
if (parts.length === 0) break;
|
|
440
|
+
parts.pop();
|
|
441
|
+
}
|
|
369
442
|
}
|
|
370
443
|
|
|
371
|
-
|
|
444
|
+
if (layout_id !== DEFAULT) {
|
|
445
|
+
throw new Error(`${file} references missing layout "${layout_id}"`);
|
|
446
|
+
}
|
|
372
447
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
448
|
+
// trim empty space off the end of the errors array
|
|
449
|
+
let i = errors.length;
|
|
450
|
+
while (i--) if (errors[i]) break;
|
|
451
|
+
errors.length = i + 1;
|
|
376
452
|
|
|
377
|
-
|
|
378
|
-
|
|
453
|
+
return { layouts, errors };
|
|
454
|
+
}
|
|
379
455
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
456
|
+
/**
|
|
457
|
+
* @param {Unit} a
|
|
458
|
+
* @param {Unit} b
|
|
459
|
+
*/
|
|
460
|
+
function compare(a, b) {
|
|
461
|
+
const max_segments = Math.max(a.segments.length, b.segments.length);
|
|
462
|
+
for (let i = 0; i < max_segments; i += 1) {
|
|
463
|
+
const sa = a.segments[i];
|
|
464
|
+
const sb = b.segments[i];
|
|
465
|
+
|
|
466
|
+
// /x < /x/y, but /[...x]/y < /[...x]
|
|
467
|
+
if (!sa) return a.id.includes('[...') ? +1 : -1;
|
|
468
|
+
if (!sb) return b.id.includes('[...') ? -1 : +1;
|
|
469
|
+
|
|
470
|
+
const max_parts = Math.max(sa.length, sb.length);
|
|
471
|
+
for (let i = 0; i < max_parts; i += 1) {
|
|
472
|
+
const pa = sa[i];
|
|
473
|
+
const pb = sb[i];
|
|
474
|
+
|
|
475
|
+
// xy < x[y], but [x].json < [x]
|
|
476
|
+
if (pa === undefined) return pb.dynamic ? -1 : +1;
|
|
477
|
+
if (pb === undefined) return pa.dynamic ? +1 : -1;
|
|
478
|
+
|
|
479
|
+
// x < [x]
|
|
480
|
+
if (pa.dynamic !== pb.dynamic) {
|
|
481
|
+
return pa.dynamic ? +1 : -1;
|
|
383
482
|
}
|
|
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
483
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
484
|
+
if (pa.dynamic) {
|
|
485
|
+
// [x] < [...x]
|
|
486
|
+
if (pa.rest !== pb.rest) {
|
|
487
|
+
return pa.rest ? +1 : -1;
|
|
488
|
+
}
|
|
398
489
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
490
|
+
// [x=type] < [x]
|
|
491
|
+
if (!!pa.type !== !!pb.type) {
|
|
492
|
+
return pa.type ? -1 : +1;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
404
495
|
}
|
|
405
496
|
}
|
|
406
497
|
|
|
407
|
-
|
|
408
|
-
|
|
498
|
+
const a_is_endpoint = !a.page && a.endpoint;
|
|
499
|
+
const b_is_endpoint = !b.page && b.endpoint;
|
|
500
|
+
|
|
501
|
+
if (a_is_endpoint !== b_is_endpoint) {
|
|
502
|
+
return a_is_endpoint ? -1 : +1;
|
|
409
503
|
}
|
|
410
504
|
|
|
411
|
-
|
|
412
|
-
return a.file < b.file ? -1 : 1;
|
|
505
|
+
return a < b ? -1 : 1;
|
|
413
506
|
}
|
|
414
507
|
|
|
415
508
|
/**
|
|
416
|
-
* @param {string}
|
|
417
|
-
* @param {string}
|
|
509
|
+
* @param {string} needle
|
|
510
|
+
* @param {string} haystack
|
|
418
511
|
*/
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (count_occurrences('[', part) !== count_occurrences(']', part)) {
|
|
425
|
-
throw new Error(`Invalid route ${file} — brackets are unbalanced`);
|
|
512
|
+
function count_occurrences(needle, haystack) {
|
|
513
|
+
let count = 0;
|
|
514
|
+
for (let i = 0; i < haystack.length; i += 1) {
|
|
515
|
+
if (haystack[i] === needle) count += 1;
|
|
426
516
|
}
|
|
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;
|
|
517
|
+
return count;
|
|
457
518
|
}
|
|
458
519
|
|
|
459
520
|
/**
|
|
460
|
-
* @param {
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
* path: string;
|
|
464
|
-
* files?: import('types').Asset[]
|
|
465
|
-
* }} args
|
|
521
|
+
* @param {string} dir
|
|
522
|
+
* @param {string} [path]
|
|
523
|
+
* @param {string[]} [files]
|
|
466
524
|
*/
|
|
467
|
-
function list_files(
|
|
468
|
-
fs__default.readdirSync(dir
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
525
|
+
function list_files(dir, path = '', files = []) {
|
|
526
|
+
fs__default.readdirSync(dir, { withFileTypes: true })
|
|
527
|
+
.sort(({ name: a }, { name: b }) => {
|
|
528
|
+
// sort each directory in (__layout, __error, everything else) order
|
|
529
|
+
// so that we can trace layouts/errors immediately
|
|
530
|
+
|
|
531
|
+
if (a.startsWith('__layout')) {
|
|
532
|
+
if (!b.startsWith('__layout')) return -1;
|
|
533
|
+
} else if (b.startsWith('__layout')) {
|
|
534
|
+
return 1;
|
|
535
|
+
} else if (a.startsWith('__')) {
|
|
536
|
+
if (!b.startsWith('__')) return -1;
|
|
537
|
+
} else if (b.startsWith('__')) {
|
|
538
|
+
return 1;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return a < b ? -1 : 1;
|
|
542
|
+
})
|
|
543
|
+
.forEach((file) => {
|
|
544
|
+
const joined = path ? `${path}/${file.name}` : file.name;
|
|
545
|
+
|
|
546
|
+
if (file.isDirectory()) {
|
|
547
|
+
list_files(`${dir}/${file.name}`, joined, files);
|
|
548
|
+
} else {
|
|
549
|
+
files.push(joined);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
484
552
|
|
|
485
553
|
return files;
|
|
486
554
|
}
|
|
@@ -549,7 +617,7 @@ function write_manifest(manifest_data, base, output) {
|
|
|
549
617
|
.join(',\n\t\t\t\t\t')}
|
|
550
618
|
]`.replace(/^\t/gm, '');
|
|
551
619
|
|
|
552
|
-
/** @param {string
|
|
620
|
+
/** @param {Array<string | undefined>} parts */
|
|
553
621
|
const get_indices = (parts) =>
|
|
554
622
|
`[${parts.map((part) => (part ? component_indexes[part] : '')).join(', ')}]`;
|
|
555
623
|
|
|
@@ -833,21 +901,6 @@ function write_types(config, manifest_data) {
|
|
|
833
901
|
/** @type {Map<string, { params: string[], type: 'page' | 'endpoint' | 'both' }>} */
|
|
834
902
|
const shadow_types = new Map();
|
|
835
903
|
|
|
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
904
|
manifest_data.routes.forEach((route) => {
|
|
852
905
|
const file = route.type === 'endpoint' ? route.file : route.shadow;
|
|
853
906
|
|
|
@@ -857,7 +910,7 @@ function write_types(config, manifest_data) {
|
|
|
857
910
|
);
|
|
858
911
|
const key = file.slice(0, -ext.length);
|
|
859
912
|
shadow_types.set(key, {
|
|
860
|
-
params:
|
|
913
|
+
params: parse_route_id(key).names,
|
|
861
914
|
type: route.type === 'endpoint' ? 'endpoint' : 'both'
|
|
862
915
|
});
|
|
863
916
|
}
|
|
@@ -870,7 +923,7 @@ function write_types(config, manifest_data) {
|
|
|
870
923
|
const key = component.slice(0, -ext.length);
|
|
871
924
|
|
|
872
925
|
if (!shadow_types.has(key)) {
|
|
873
|
-
shadow_types.set(key, { params:
|
|
926
|
+
shadow_types.set(key, { params: parse_route_id(key).names, type: 'page' });
|
|
874
927
|
}
|
|
875
928
|
});
|
|
876
929
|
|
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.307');
|
|
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
|
}
|
|
@@ -979,7 +981,6 @@ prog
|
|
|
979
981
|
prog
|
|
980
982
|
.command('package')
|
|
981
983
|
.describe('Create a package')
|
|
982
|
-
.option('-d, --dir', 'Destination directory', 'package')
|
|
983
984
|
.action(async () => {
|
|
984
985
|
try {
|
|
985
986
|
const config = await load_config();
|
|
@@ -1039,15 +1040,16 @@ async function check_port(port) {
|
|
|
1039
1040
|
* host: string;
|
|
1040
1041
|
* https: boolean;
|
|
1041
1042
|
* port: number;
|
|
1043
|
+
* base: string;
|
|
1042
1044
|
* loose?: boolean;
|
|
1043
1045
|
* allow?: string[];
|
|
1044
1046
|
* cwd?: string;
|
|
1045
1047
|
* }} param0
|
|
1046
1048
|
*/
|
|
1047
|
-
function welcome({ port, host, https, open, loose, allow, cwd }) {
|
|
1048
|
-
if (open) launch(port, https);
|
|
1049
|
+
function welcome({ port, host, https, open, base, loose, allow, cwd }) {
|
|
1050
|
+
if (open) launch(port, https, base);
|
|
1049
1051
|
|
|
1050
|
-
console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.
|
|
1052
|
+
console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.307'}\n`));
|
|
1051
1053
|
|
|
1052
1054
|
const protocol = https ? 'https:' : 'http:';
|
|
1053
1055
|
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.307",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/sveltejs/kit",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
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,26 +215,22 @@ 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>,
|
|
228
224
|
Output extends ResponseBody = ResponseBody
|
|
229
225
|
> {
|
|
230
|
-
(event: RequestEvent<Params>): RequestHandlerOutput<Output
|
|
226
|
+
(event: RequestEvent<Params>): MaybePromise<RequestHandlerOutput<Output>>;
|
|
231
227
|
}
|
|
232
228
|
|
|
233
|
-
export
|
|
229
|
+
export interface RequestHandlerOutput<Output extends ResponseBody = ResponseBody> {
|
|
234
230
|
status?: number;
|
|
235
231
|
headers?: Headers | Partial<ResponseHeaders>;
|
|
236
232
|
body?: Output;
|
|
237
|
-
}
|
|
233
|
+
}
|
|
238
234
|
|
|
239
235
|
export type ResponseBody = JSONValue | Uint8Array | ReadableStream | import('stream').Readable;
|
|
240
236
|
|
package/types/internal.d.ts
CHANGED
|
@@ -101,8 +101,6 @@ export class InternalServer extends Server {
|
|
|
101
101
|
|
|
102
102
|
export interface ManifestData {
|
|
103
103
|
assets: Asset[];
|
|
104
|
-
layout: string;
|
|
105
|
-
error: string;
|
|
106
104
|
components: string[];
|
|
107
105
|
routes: RouteData[];
|
|
108
106
|
matchers: Record<string, string>;
|
|
@@ -128,8 +126,8 @@ export interface PageData {
|
|
|
128
126
|
shadow: string | null;
|
|
129
127
|
pattern: RegExp;
|
|
130
128
|
path: string;
|
|
131
|
-
a: string
|
|
132
|
-
b: string
|
|
129
|
+
a: Array<string | undefined>;
|
|
130
|
+
b: Array<string | undefined>;
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
export type PayloadScriptAttributes =
|
|
@@ -285,12 +283,12 @@ export interface SSRPage {
|
|
|
285
283
|
/**
|
|
286
284
|
* plan a is to render 1 or more layout components followed by a leaf component.
|
|
287
285
|
*/
|
|
288
|
-
a: number
|
|
286
|
+
a: Array<number | undefined>;
|
|
289
287
|
/**
|
|
290
288
|
* plan b — if one of them components fails in `load` we backtrack until we find
|
|
291
289
|
* the nearest error component.
|
|
292
290
|
*/
|
|
293
|
-
b: number
|
|
291
|
+
b: Array<number | undefined>;
|
|
294
292
|
}
|
|
295
293
|
|
|
296
294
|
export interface SSRPagePart {
|