@sveltejs/kit 1.0.0-next.43 → 1.0.0-next.430
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/README.md +12 -9
- package/package.json +95 -63
- package/src/cli.js +112 -0
- package/src/core/adapt/builder.js +207 -0
- package/src/core/adapt/index.js +19 -0
- package/src/core/config/index.js +86 -0
- package/src/core/config/options.js +488 -0
- package/src/core/config/types.d.ts +1 -0
- package/src/core/constants.js +5 -0
- package/src/core/env.js +97 -0
- package/src/core/generate_manifest/index.js +99 -0
- package/src/core/prerender/crawl.js +194 -0
- package/src/core/prerender/prerender.js +378 -0
- package/src/core/prerender/queue.js +80 -0
- package/src/core/sync/create_manifest_data/index.js +506 -0
- package/src/core/sync/create_manifest_data/types.d.ts +40 -0
- package/src/core/sync/sync.js +59 -0
- package/src/core/sync/utils.js +44 -0
- package/src/core/sync/write_ambient.js +27 -0
- package/src/core/sync/write_client_manifest.js +82 -0
- package/src/core/sync/write_matchers.js +25 -0
- package/src/core/sync/write_root.js +91 -0
- package/src/core/sync/write_tsconfig.js +195 -0
- package/src/core/sync/write_types.js +775 -0
- package/src/core/utils.js +70 -0
- package/src/hooks.js +26 -0
- package/src/index/index.js +45 -0
- package/src/index/private.js +33 -0
- package/src/node/index.js +145 -0
- package/src/node/polyfills.js +40 -0
- package/src/runtime/app/env.js +11 -0
- package/src/runtime/app/navigation.js +22 -0
- package/src/runtime/app/paths.js +1 -0
- package/src/runtime/app/stores.js +102 -0
- package/src/runtime/client/ambient.d.ts +17 -0
- package/src/runtime/client/client.js +1289 -0
- package/src/runtime/client/fetcher.js +60 -0
- package/src/runtime/client/parse.js +36 -0
- package/src/runtime/client/singletons.js +21 -0
- package/src/runtime/client/start.js +46 -0
- package/src/runtime/client/types.d.ts +105 -0
- package/src/runtime/client/utils.js +113 -0
- package/src/runtime/components/error.svelte +16 -0
- package/{assets → src/runtime}/components/layout.svelte +0 -0
- package/src/runtime/env/dynamic/private.js +1 -0
- package/src/runtime/env/dynamic/public.js +1 -0
- package/src/runtime/env-private.js +7 -0
- package/src/runtime/env-public.js +7 -0
- package/src/runtime/env.js +6 -0
- package/src/runtime/hash.js +16 -0
- package/src/runtime/paths.js +11 -0
- package/src/runtime/server/endpoint.js +58 -0
- package/src/runtime/server/index.js +448 -0
- package/src/runtime/server/page/cookie.js +25 -0
- package/src/runtime/server/page/crypto.js +239 -0
- package/src/runtime/server/page/csp.js +249 -0
- package/src/runtime/server/page/fetch.js +266 -0
- package/src/runtime/server/page/index.js +416 -0
- package/src/runtime/server/page/load_data.js +135 -0
- package/src/runtime/server/page/render.js +362 -0
- package/src/runtime/server/page/respond_with_error.js +94 -0
- package/src/runtime/server/page/types.d.ts +44 -0
- package/src/runtime/server/utils.js +116 -0
- package/src/utils/error.js +22 -0
- package/src/utils/escape.js +104 -0
- package/src/utils/filesystem.js +108 -0
- package/src/utils/http.js +55 -0
- package/src/utils/misc.js +1 -0
- package/src/utils/routing.js +108 -0
- package/src/utils/url.js +97 -0
- package/src/vite/build/build_server.js +337 -0
- package/src/vite/build/build_service_worker.js +90 -0
- package/src/vite/build/utils.js +160 -0
- package/src/vite/dev/index.js +551 -0
- package/src/vite/index.js +574 -0
- package/src/vite/preview/index.js +186 -0
- package/src/vite/types.d.ts +3 -0
- package/src/vite/utils.js +345 -0
- package/svelte-kit.js +1 -1
- package/types/ambient.d.ts +357 -0
- package/types/index.d.ts +343 -0
- package/types/internal.d.ts +308 -0
- package/types/private.d.ts +209 -0
- package/CHANGELOG.md +0 -431
- package/assets/components/error.svelte +0 -13
- package/assets/runtime/app/env.js +0 -5
- package/assets/runtime/app/navigation.js +0 -41
- package/assets/runtime/app/paths.js +0 -1
- package/assets/runtime/app/stores.js +0 -93
- package/assets/runtime/chunks/utils.js +0 -19
- package/assets/runtime/internal/singletons.js +0 -23
- package/assets/runtime/internal/start.js +0 -770
- package/assets/runtime/paths.js +0 -12
- package/dist/.DS_Store +0 -0
- package/dist/chunks/index.js +0 -3521
- package/dist/chunks/index2.js +0 -587
- package/dist/chunks/index3.js +0 -246
- package/dist/chunks/index4.js +0 -538
- package/dist/chunks/index5.js +0 -761
- package/dist/chunks/index6.js +0 -322
- package/dist/chunks/standard.js +0 -99
- package/dist/chunks/utils.js +0 -83
- package/dist/cli.js +0 -546
- package/dist/ssr.js +0 -2581
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import mime from 'mime';
|
|
4
|
+
import { runtime_directory } from '../../utils.js';
|
|
5
|
+
import { posixify } from '../../../utils/filesystem.js';
|
|
6
|
+
import { parse_route_id } from '../../../utils/routing.js';
|
|
7
|
+
|
|
8
|
+
const DEFAULT = 'default';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {{
|
|
12
|
+
* config: import('types').ValidatedConfig;
|
|
13
|
+
* fallback?: string;
|
|
14
|
+
* cwd?: string;
|
|
15
|
+
* }} opts
|
|
16
|
+
* @returns {import('types').ManifestData}
|
|
17
|
+
*/
|
|
18
|
+
export default function create_manifest_data({
|
|
19
|
+
config,
|
|
20
|
+
fallback = `${runtime_directory}/components`,
|
|
21
|
+
cwd = process.cwd()
|
|
22
|
+
}) {
|
|
23
|
+
/** @type {Map<string, import('types').RouteData>} */
|
|
24
|
+
const route_map = new Map();
|
|
25
|
+
|
|
26
|
+
/** @type {Map<string, import('./types').Part[][]>} */
|
|
27
|
+
const segment_map = new Map();
|
|
28
|
+
|
|
29
|
+
/** @type {import('./types').RouteTree} */
|
|
30
|
+
const tree = new Map();
|
|
31
|
+
|
|
32
|
+
const default_layout = {
|
|
33
|
+
component: posixify(path.relative(cwd, `${fallback}/layout.svelte`))
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// set default root layout/error
|
|
37
|
+
tree.set('', {
|
|
38
|
+
error: {
|
|
39
|
+
component: posixify(path.relative(cwd, `${fallback}/error.svelte`))
|
|
40
|
+
},
|
|
41
|
+
layouts: { [DEFAULT]: default_layout }
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/** @param {string} id */
|
|
45
|
+
function tree_node(id) {
|
|
46
|
+
if (!tree.has(id)) {
|
|
47
|
+
tree.set(id, {
|
|
48
|
+
error: undefined,
|
|
49
|
+
layouts: {}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return /** @type {import('./types').RouteTreeNode} */ (tree.get(id));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const routes_base = posixify(path.relative(cwd, config.kit.files.routes));
|
|
57
|
+
const valid_extensions = [...config.extensions, ...config.kit.moduleExtensions];
|
|
58
|
+
|
|
59
|
+
if (fs.existsSync(config.kit.files.routes)) {
|
|
60
|
+
list_files(config.kit.files.routes).forEach((filepath) => {
|
|
61
|
+
const extension = valid_extensions.find((ext) => filepath.endsWith(ext));
|
|
62
|
+
if (!extension) return;
|
|
63
|
+
|
|
64
|
+
const project_relative = `${routes_base}/${filepath}`;
|
|
65
|
+
const segments = filepath.split('/');
|
|
66
|
+
const file = /** @type {string} */ (segments.pop());
|
|
67
|
+
|
|
68
|
+
if (file[0] !== '+') return; // not a route file
|
|
69
|
+
|
|
70
|
+
const item = analyze(project_relative, file, config.extensions, config.kit.moduleExtensions);
|
|
71
|
+
const id = segments.join('/');
|
|
72
|
+
|
|
73
|
+
if (/\]\[/.test(id)) {
|
|
74
|
+
throw new Error(`Invalid route ${project_relative} — parameters must be separated`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (count_occurrences('[', id) !== count_occurrences(']', id)) {
|
|
78
|
+
throw new Error(`Invalid route ${project_relative} — brackets are unbalanced`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// error/layout files should be added to the tree, but don't result
|
|
82
|
+
// in a route being created, so deal with them first. note: we are
|
|
83
|
+
// relying on the fact that the +error and +layout files precede
|
|
84
|
+
// +page files alphabetically, and will therefore be processes
|
|
85
|
+
// before we reach the page
|
|
86
|
+
if (item.kind === 'component' && item.is_error) {
|
|
87
|
+
tree_node(id).error = {
|
|
88
|
+
component: project_relative
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (item.is_layout) {
|
|
95
|
+
if (item.declares_layout === DEFAULT) {
|
|
96
|
+
throw new Error(`${project_relative} cannot use reserved "${DEFAULT}" name`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const layout_id = item.declares_layout || DEFAULT;
|
|
100
|
+
|
|
101
|
+
const group = tree_node(id);
|
|
102
|
+
|
|
103
|
+
const defined = group.layouts[layout_id] || (group.layouts[layout_id] = {});
|
|
104
|
+
|
|
105
|
+
if (defined[item.kind] && layout_id !== DEFAULT) {
|
|
106
|
+
// edge case
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Duplicate layout ${project_relative} already defined at ${defined[item.kind]}`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
defined[item.kind] = project_relative;
|
|
113
|
+
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const type = item.kind === 'server' && !item.is_layout && !item.is_page ? 'endpoint' : 'page';
|
|
118
|
+
|
|
119
|
+
if (type === 'endpoint' && route_map.has(id)) {
|
|
120
|
+
// note that we are relying on +server being lexically ordered after
|
|
121
|
+
// all other route files — if we added +view or something this is
|
|
122
|
+
// potentially brittle, since the server might be added before
|
|
123
|
+
// another route file. a problem for another day
|
|
124
|
+
throw new Error(
|
|
125
|
+
`${file} cannot share a directory with other route files (${project_relative})`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!route_map.has(id)) {
|
|
130
|
+
const pattern = parse_route_id(id).pattern;
|
|
131
|
+
|
|
132
|
+
segment_map.set(
|
|
133
|
+
id,
|
|
134
|
+
segments.filter(Boolean).map((segment) => {
|
|
135
|
+
/** @type {import('./types').Part[]} */
|
|
136
|
+
const parts = [];
|
|
137
|
+
segment.split(/\[(.+?)\]/).map((content, i) => {
|
|
138
|
+
const dynamic = !!(i % 2);
|
|
139
|
+
|
|
140
|
+
if (!content) return;
|
|
141
|
+
|
|
142
|
+
parts.push({
|
|
143
|
+
content,
|
|
144
|
+
dynamic,
|
|
145
|
+
rest: dynamic && content.startsWith('...'),
|
|
146
|
+
type: (dynamic && content.split('=')[1]) || null
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
return parts;
|
|
150
|
+
})
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (type === 'endpoint') {
|
|
154
|
+
route_map.set(id, {
|
|
155
|
+
type,
|
|
156
|
+
id,
|
|
157
|
+
pattern,
|
|
158
|
+
file: project_relative
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
route_map.set(id, {
|
|
162
|
+
type,
|
|
163
|
+
id,
|
|
164
|
+
pattern,
|
|
165
|
+
errors: [],
|
|
166
|
+
layouts: [],
|
|
167
|
+
leaf: {}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (item.is_page) {
|
|
173
|
+
const route = /** @type {import('types').PageData} */ (route_map.get(id));
|
|
174
|
+
|
|
175
|
+
// This ensures that layouts and errors are set for pages that have no Svelte file
|
|
176
|
+
// and only redirect or throw an error, but are set to the Svelte file definition if it exists.
|
|
177
|
+
// This ensures the proper error page is used and rendered in the proper layout.
|
|
178
|
+
if (item.kind === 'component' || route.layouts.length === 0) {
|
|
179
|
+
const { layouts, errors } = trace(
|
|
180
|
+
tree,
|
|
181
|
+
id,
|
|
182
|
+
item.kind === 'component' ? item.uses_layout : undefined,
|
|
183
|
+
project_relative
|
|
184
|
+
);
|
|
185
|
+
route.layouts = layouts;
|
|
186
|
+
route.errors = errors;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (item.kind === 'component') {
|
|
190
|
+
route.leaf.component = project_relative;
|
|
191
|
+
} else if (item.kind === 'server') {
|
|
192
|
+
route.leaf.server = project_relative;
|
|
193
|
+
} else {
|
|
194
|
+
route.leaf.shared = project_relative;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// TODO remove for 1.0
|
|
200
|
+
if (route_map.size === 0) {
|
|
201
|
+
throw new Error(
|
|
202
|
+
'The filesystem router API has changed, see https://github.com/sveltejs/kit/discussions/5774 for details'
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** @type {import('types').PageNode[]} */
|
|
208
|
+
const nodes = [];
|
|
209
|
+
|
|
210
|
+
tree.forEach(({ layouts, error }) => {
|
|
211
|
+
// we do [default, error, ...other_layouts] so that components[0] and [1]
|
|
212
|
+
// are the root layout/error. kinda janky, there's probably a nicer way
|
|
213
|
+
if (layouts[DEFAULT]) {
|
|
214
|
+
nodes.push(layouts[DEFAULT]);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (error) {
|
|
218
|
+
nodes.push(error);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
for (const id in layouts) {
|
|
222
|
+
if (id !== DEFAULT) {
|
|
223
|
+
nodes.push(layouts[id]);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
route_map.forEach((route) => {
|
|
229
|
+
if (route.type === 'page') {
|
|
230
|
+
nodes.push(route.leaf);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const routes = Array.from(route_map.values()).sort((a, b) => compare(a, b, segment_map));
|
|
235
|
+
|
|
236
|
+
/** @type {import('types').Asset[]} */
|
|
237
|
+
const assets = fs.existsSync(config.kit.files.assets)
|
|
238
|
+
? list_files(config.kit.files.assets).map((file) => ({
|
|
239
|
+
file,
|
|
240
|
+
size: fs.statSync(`${config.kit.files.assets}/${file}`).size,
|
|
241
|
+
type: mime.getType(file)
|
|
242
|
+
}))
|
|
243
|
+
: [];
|
|
244
|
+
|
|
245
|
+
const params_base = path.relative(cwd, config.kit.files.params);
|
|
246
|
+
|
|
247
|
+
/** @type {Record<string, string>} */
|
|
248
|
+
const matchers = {};
|
|
249
|
+
if (fs.existsSync(config.kit.files.params)) {
|
|
250
|
+
for (const file of fs.readdirSync(config.kit.files.params)) {
|
|
251
|
+
const ext = path.extname(file);
|
|
252
|
+
if (!config.kit.moduleExtensions.includes(ext)) continue;
|
|
253
|
+
const type = file.slice(0, -ext.length);
|
|
254
|
+
|
|
255
|
+
if (/^\w+$/.test(type)) {
|
|
256
|
+
const matcher_file = path.join(params_base, file);
|
|
257
|
+
|
|
258
|
+
// Disallow same matcher with different extensions
|
|
259
|
+
if (matchers[type]) {
|
|
260
|
+
throw new Error(`Duplicate matchers: ${matcher_file} and ${matchers[type]}`);
|
|
261
|
+
} else {
|
|
262
|
+
matchers[type] = matcher_file;
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
throw new Error(
|
|
266
|
+
`Matcher names can only have underscores and alphanumeric characters — "${file}" is invalid`
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
assets,
|
|
274
|
+
nodes,
|
|
275
|
+
routes,
|
|
276
|
+
matchers
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @param {string} project_relative
|
|
282
|
+
* @param {string} file
|
|
283
|
+
* @param {string[]} component_extensions
|
|
284
|
+
* @param {string[]} module_extensions
|
|
285
|
+
* @returns {import('./types').RouteFile}
|
|
286
|
+
*/
|
|
287
|
+
function analyze(project_relative, file, component_extensions, module_extensions) {
|
|
288
|
+
const component_extension = component_extensions.find((ext) => file.endsWith(ext));
|
|
289
|
+
if (component_extension) {
|
|
290
|
+
const name = file.slice(0, -component_extension.length);
|
|
291
|
+
const pattern =
|
|
292
|
+
/^\+(?:(page(?:@([a-zA-Z0-9_-]+))?)|(layout(?:-([a-zA-Z0-9_-]+))?(?:@([a-zA-Z0-9_-]+))?)|(error))$/;
|
|
293
|
+
const match = pattern.exec(name);
|
|
294
|
+
if (!match) {
|
|
295
|
+
throw new Error(`Files prefixed with + are reserved (saw ${project_relative})`);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
kind: 'component',
|
|
300
|
+
is_page: !!match[1],
|
|
301
|
+
is_layout: !!match[3],
|
|
302
|
+
is_error: !!match[6],
|
|
303
|
+
uses_layout: match[2] || match[5],
|
|
304
|
+
declares_layout: match[4]
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const module_extension = module_extensions.find((ext) => file.endsWith(ext));
|
|
309
|
+
if (module_extension) {
|
|
310
|
+
const name = file.slice(0, -module_extension.length);
|
|
311
|
+
const pattern =
|
|
312
|
+
/^\+(?:(server)|(page(?:@([a-zA-Z0-9_-]+))?(\.server)?)|(layout(?:-([a-zA-Z0-9_-]+))?(?:@([a-zA-Z0-9_-]+))?(\.server)?))$/;
|
|
313
|
+
const match = pattern.exec(name);
|
|
314
|
+
if (!match) {
|
|
315
|
+
throw new Error(`Files prefixed with + are reserved (saw ${project_relative})`);
|
|
316
|
+
} else if (match[3] || match[7]) {
|
|
317
|
+
throw new Error(
|
|
318
|
+
// prettier-ignore
|
|
319
|
+
`Only Svelte files can reference named layouts. Remove '@${match[3] || match[7]}' from ${file} (at ${project_relative})`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const kind = !!(match[1] || match[4] || match[8]) ? 'server' : 'shared';
|
|
324
|
+
|
|
325
|
+
return {
|
|
326
|
+
kind,
|
|
327
|
+
is_page: !!match[2],
|
|
328
|
+
is_layout: !!match[5],
|
|
329
|
+
declares_layout: match[6]
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
throw new Error(`Files and directories prefixed with + are reserved (saw ${project_relative})`);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* @param {import('./types').RouteTree} tree
|
|
338
|
+
* @param {string} id
|
|
339
|
+
* @param {string} layout_id
|
|
340
|
+
* @param {string} project_relative
|
|
341
|
+
*/
|
|
342
|
+
function trace(tree, id, layout_id = DEFAULT, project_relative) {
|
|
343
|
+
/** @type {Array<import('types').PageNode | undefined>} */
|
|
344
|
+
const layouts = [];
|
|
345
|
+
|
|
346
|
+
/** @type {Array<import('types').PageNode | undefined>} */
|
|
347
|
+
const errors = [];
|
|
348
|
+
|
|
349
|
+
const parts = id.split('/').filter(Boolean);
|
|
350
|
+
|
|
351
|
+
// walk up the tree, find which +layout and +error components
|
|
352
|
+
// apply to this page
|
|
353
|
+
while (true) {
|
|
354
|
+
const node = tree.get(parts.join('/'));
|
|
355
|
+
const layout = node?.layouts[layout_id];
|
|
356
|
+
|
|
357
|
+
if (layout && layouts.indexOf(layout) > -1) {
|
|
358
|
+
// TODO this needs to be fixed for #5748
|
|
359
|
+
throw new Error(
|
|
360
|
+
`Recursive layout detected: ${layout.component} -> ${layouts
|
|
361
|
+
.map((l) => l?.component)
|
|
362
|
+
.join(' -> ')}`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// any segment that has neither a +layout nor an +error can be discarded.
|
|
367
|
+
// in other words these...
|
|
368
|
+
// layouts: [a, , b, c]
|
|
369
|
+
// errors: [d, , e, ]
|
|
370
|
+
//
|
|
371
|
+
// ...can be compacted to these:
|
|
372
|
+
// layouts: [a, b, c]
|
|
373
|
+
// errors: [d, e, ]
|
|
374
|
+
if (node?.error || layout) {
|
|
375
|
+
errors.unshift(node?.error);
|
|
376
|
+
layouts.unshift(layout);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const parent_layout_id = layout?.component?.split('/').at(-1)?.split('@')[1]?.split('.')[0];
|
|
380
|
+
|
|
381
|
+
if (parent_layout_id) {
|
|
382
|
+
layout_id = parent_layout_id;
|
|
383
|
+
} else {
|
|
384
|
+
if (layout) layout_id = DEFAULT;
|
|
385
|
+
if (parts.length === 0) break;
|
|
386
|
+
parts.pop();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (layout_id !== DEFAULT) {
|
|
391
|
+
throw new Error(`${project_relative} references missing layout "${layout_id}"`);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// trim empty space off the end of the errors array
|
|
395
|
+
let i = errors.length;
|
|
396
|
+
while (i--) if (errors[i]) break;
|
|
397
|
+
errors.length = i + 1;
|
|
398
|
+
|
|
399
|
+
return { layouts, errors };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* @param {import('types').RouteData} a
|
|
404
|
+
* @param {import('types').RouteData} b
|
|
405
|
+
* @param {Map<string, import('./types').Part[][]>} segment_map
|
|
406
|
+
*/
|
|
407
|
+
function compare(a, b, segment_map) {
|
|
408
|
+
const a_segments = /** @type {import('./types').Part[][]} */ (segment_map.get(a.id));
|
|
409
|
+
const b_segments = /** @type {import('./types').Part[][]} */ (segment_map.get(b.id));
|
|
410
|
+
|
|
411
|
+
const max_segments = Math.max(a_segments.length, b_segments.length);
|
|
412
|
+
for (let i = 0; i < max_segments; i += 1) {
|
|
413
|
+
const sa = a_segments[i];
|
|
414
|
+
const sb = b_segments[i];
|
|
415
|
+
|
|
416
|
+
// /x < /x/y, but /[...x]/y < /[...x]
|
|
417
|
+
if (!sa) return a.id.includes('[...') ? +1 : -1;
|
|
418
|
+
if (!sb) return b.id.includes('[...') ? -1 : +1;
|
|
419
|
+
|
|
420
|
+
const max_parts = Math.max(sa.length, sb.length);
|
|
421
|
+
for (let i = 0; i < max_parts; i += 1) {
|
|
422
|
+
const pa = sa[i];
|
|
423
|
+
const pb = sb[i];
|
|
424
|
+
|
|
425
|
+
// xy < x[y], but [x].json < [x]
|
|
426
|
+
if (pa === undefined) return pb.dynamic ? -1 : +1;
|
|
427
|
+
if (pb === undefined) return pa.dynamic ? +1 : -1;
|
|
428
|
+
|
|
429
|
+
// x < [x]
|
|
430
|
+
if (pa.dynamic !== pb.dynamic) {
|
|
431
|
+
return pa.dynamic ? +1 : -1;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (pa.dynamic) {
|
|
435
|
+
// [x] < [...x]
|
|
436
|
+
if (pa.rest !== pb.rest) {
|
|
437
|
+
return pa.rest ? +1 : -1;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// [x=type] < [x]
|
|
441
|
+
if (!!pa.type !== !!pb.type) {
|
|
442
|
+
return pa.type ? -1 : +1;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const a_is_endpoint = a.type === 'endpoint';
|
|
449
|
+
const b_is_endpoint = b.type === 'endpoint';
|
|
450
|
+
|
|
451
|
+
if (a_is_endpoint !== b_is_endpoint) {
|
|
452
|
+
return a_is_endpoint ? -1 : +1;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return a < b ? -1 : 1;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @param {string} needle
|
|
460
|
+
* @param {string} haystack
|
|
461
|
+
*/
|
|
462
|
+
function count_occurrences(needle, haystack) {
|
|
463
|
+
let count = 0;
|
|
464
|
+
for (let i = 0; i < haystack.length; i += 1) {
|
|
465
|
+
if (haystack[i] === needle) count += 1;
|
|
466
|
+
}
|
|
467
|
+
return count;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* @param {string} dir
|
|
472
|
+
* @param {string} [path]
|
|
473
|
+
* @param {string[]} [files]
|
|
474
|
+
*/
|
|
475
|
+
function list_files(dir, path = '', files = []) {
|
|
476
|
+
fs.readdirSync(dir)
|
|
477
|
+
.sort((a, b) => {
|
|
478
|
+
// sort each directory in (+layout, +error, everything else) order
|
|
479
|
+
// so that we can trace layouts/errors immediately
|
|
480
|
+
|
|
481
|
+
if (a.startsWith('+layout') || a.startsWith('+error')) {
|
|
482
|
+
if (!b.startsWith('+layout') && !b.startsWith('+error')) return -1;
|
|
483
|
+
} else if (b.startsWith('+layout') || b.startsWith('+error')) {
|
|
484
|
+
return 1;
|
|
485
|
+
} else if (a.startsWith('__')) {
|
|
486
|
+
if (!b.startsWith('__')) return -1;
|
|
487
|
+
} else if (b.startsWith('__')) {
|
|
488
|
+
return 1;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return a < b ? -1 : 1;
|
|
492
|
+
})
|
|
493
|
+
.forEach((file) => {
|
|
494
|
+
const full = `${dir}/${file}`;
|
|
495
|
+
const stats = fs.statSync(full);
|
|
496
|
+
const joined = path ? `${path}/${file}` : file;
|
|
497
|
+
|
|
498
|
+
if (stats.isDirectory()) {
|
|
499
|
+
list_files(full, joined, files);
|
|
500
|
+
} else {
|
|
501
|
+
files.push(joined);
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
return files;
|
|
506
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PageNode } from 'types';
|
|
2
|
+
|
|
3
|
+
interface Part {
|
|
4
|
+
content: string;
|
|
5
|
+
dynamic: boolean;
|
|
6
|
+
rest: boolean;
|
|
7
|
+
type: string | null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface RouteTreeNode {
|
|
11
|
+
error: PageNode | undefined;
|
|
12
|
+
layouts: Record<string, PageNode>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type RouteTree = Map<string, RouteTreeNode>;
|
|
16
|
+
|
|
17
|
+
interface RouteComponent {
|
|
18
|
+
kind: 'component';
|
|
19
|
+
is_page: boolean;
|
|
20
|
+
is_layout: boolean;
|
|
21
|
+
is_error: boolean;
|
|
22
|
+
uses_layout: string | undefined;
|
|
23
|
+
declares_layout: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface RouteSharedModule {
|
|
27
|
+
kind: 'shared';
|
|
28
|
+
is_page: boolean;
|
|
29
|
+
is_layout: boolean;
|
|
30
|
+
declares_layout: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface RouteServerModule {
|
|
34
|
+
kind: 'server';
|
|
35
|
+
is_page: boolean;
|
|
36
|
+
is_layout: boolean;
|
|
37
|
+
declares_layout: string | undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type RouteFile = RouteComponent | RouteSharedModule | RouteServerModule;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import create_manifest_data from './create_manifest_data/index.js';
|
|
3
|
+
import { write_client_manifest } from './write_client_manifest.js';
|
|
4
|
+
import { write_matchers } from './write_matchers.js';
|
|
5
|
+
import { write_root } from './write_root.js';
|
|
6
|
+
import { write_tsconfig } from './write_tsconfig.js';
|
|
7
|
+
import { write_type, write_types } from './write_types.js';
|
|
8
|
+
import { write_ambient } from './write_ambient.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initialize SvelteKit's generated files.
|
|
12
|
+
* @param {import('types').ValidatedConfig} config
|
|
13
|
+
* @param {string} mode
|
|
14
|
+
*/
|
|
15
|
+
export function init(config, mode) {
|
|
16
|
+
write_tsconfig(config.kit);
|
|
17
|
+
write_ambient(config.kit, mode);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Update SvelteKit's generated files
|
|
22
|
+
* @param {import('types').ValidatedConfig} config
|
|
23
|
+
*/
|
|
24
|
+
export async function create(config) {
|
|
25
|
+
const manifest_data = create_manifest_data({ config });
|
|
26
|
+
|
|
27
|
+
const output = path.join(config.kit.outDir, 'generated');
|
|
28
|
+
|
|
29
|
+
write_client_manifest(manifest_data, output);
|
|
30
|
+
write_root(manifest_data, output);
|
|
31
|
+
write_matchers(manifest_data, output);
|
|
32
|
+
await write_types(config, manifest_data);
|
|
33
|
+
|
|
34
|
+
return { manifest_data };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Update SvelteKit's generated files in response to a single file content update.
|
|
39
|
+
* Do not call this when the file in question was created/deleted.
|
|
40
|
+
*
|
|
41
|
+
* @param {import('types').ValidatedConfig} config
|
|
42
|
+
* @param {import('types').ManifestData} manifest_data
|
|
43
|
+
* @param {string} file
|
|
44
|
+
*/
|
|
45
|
+
export async function update(config, manifest_data, file) {
|
|
46
|
+
await write_type(config, manifest_data, file);
|
|
47
|
+
|
|
48
|
+
return { manifest_data };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Run sync.init and sync.update in series, returning the result from sync.update.
|
|
53
|
+
* @param {import('types').ValidatedConfig} config
|
|
54
|
+
* @param {string} mode The Vite mode
|
|
55
|
+
*/
|
|
56
|
+
export async function all(config, mode) {
|
|
57
|
+
init(config, mode);
|
|
58
|
+
return await create(config);
|
|
59
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { mkdirp } from '../../utils/filesystem.js';
|
|
4
|
+
|
|
5
|
+
/** @type {Map<string, string>} */
|
|
6
|
+
const previous_contents = new Map();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} file
|
|
10
|
+
* @param {string} code
|
|
11
|
+
*/
|
|
12
|
+
export function write_if_changed(file, code) {
|
|
13
|
+
if (code !== previous_contents.get(file)) {
|
|
14
|
+
write(file, code);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} file
|
|
20
|
+
* @param {string} code
|
|
21
|
+
*/
|
|
22
|
+
export function write(file, code) {
|
|
23
|
+
previous_contents.set(file, code);
|
|
24
|
+
mkdirp(path.dirname(file));
|
|
25
|
+
fs.writeFileSync(file, code);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {(file: string) => boolean} should_remove
|
|
30
|
+
*/
|
|
31
|
+
export function remove_from_previous(should_remove) {
|
|
32
|
+
for (const key of previous_contents.keys()) {
|
|
33
|
+
if (should_remove(key)) {
|
|
34
|
+
previous_contents.delete(key);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** @param {string} str */
|
|
40
|
+
export function trim(str) {
|
|
41
|
+
const indentation = /** @type {RegExpExecArray} */ (/\n?(\s*)/.exec(str))[1];
|
|
42
|
+
const pattern = new RegExp(`^${indentation}`, 'gm');
|
|
43
|
+
return str.replace(pattern, '').trim();
|
|
44
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { get_env } from '../../vite/utils.js';
|
|
3
|
+
import { GENERATED_COMMENT } from '../constants.js';
|
|
4
|
+
import { create_types } from '../env.js';
|
|
5
|
+
import { write_if_changed } from './utils.js';
|
|
6
|
+
|
|
7
|
+
const types_reference = '/// <reference types="@sveltejs/kit" />\n\n';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Writes ambient declarations including types reference to @sveltejs/kit,
|
|
11
|
+
* and the existing environment variables in process.env to
|
|
12
|
+
* $env/static/private and $env/static/public
|
|
13
|
+
* @param {import('types').ValidatedKitConfig} config
|
|
14
|
+
* @param {string} mode The Vite mode
|
|
15
|
+
*/
|
|
16
|
+
export function write_ambient(config, mode) {
|
|
17
|
+
const env = get_env(config.env, mode);
|
|
18
|
+
|
|
19
|
+
write_if_changed(
|
|
20
|
+
path.join(config.outDir, 'ambient.d.ts'),
|
|
21
|
+
GENERATED_COMMENT +
|
|
22
|
+
types_reference +
|
|
23
|
+
create_types('$env/static/public', env.public) +
|
|
24
|
+
'\n\n' +
|
|
25
|
+
create_types('$env/static/private', env.private)
|
|
26
|
+
);
|
|
27
|
+
}
|