Skip to content

Commit 81eb254

Browse files
author
Rich Harris
committed
better rest parameters exercise
1 parent c2432c6 commit 81eb254

File tree

6 files changed

+69
-26
lines changed

6 files changed

+69
-26
lines changed

content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
---
22
title: Rest parameters
3+
path: /how
4+
focus: /src/routes/[path]/+page.svelte
35
---
46

57
To match an unknown number of path segments, use a `[...rest]` parameter, so named for its resemblance to [rest parameters in JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
@@ -20,3 +22,5 @@ Rename `src/routes/[path]` to `src/routes/[...path]`. The route now matches any
2022
> ```
2123
>
2224
> Inside the `+page.server.js` file, `throw error(404)` inside `load`.
25+
26+
Rest parameters do _not_ need to go at the end — a route like `/items/[...path]/edit` or `/items/[...path].json` is totally valid.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__delete

content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-a/src/routes/[path]/+page.svelte

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,29 @@
44
let words = ['how', 'deep', 'does', 'the', 'rabbit', 'hole', 'go'];
55
66
$: depth = $page.params.path.split('/').filter(Boolean).length;
7-
8-
$: href =
9-
depth === words.length
10-
? '/'
11-
: `/${words.slice(0, depth + 1).join('/')}`;
7+
$: next = depth === words.length ? '/' : `/${words.slice(0, depth + 1).join('/')}`;
128
</script>
139

14-
<a {href}>{words[depth] ?? '?'}</a>
10+
<div class="flex">
11+
{#each words.slice(0, depth) as word}
12+
<p>{word}</p>
13+
{/each}
14+
15+
<p><a href={next}>{words[depth] ?? '?'}</a></p>
16+
</div>
1517

1618
<style>
17-
:global(html),
18-
:global(body) {
19+
.flex {
20+
display: flex;
1921
height: 100%;
20-
margin: 0;
22+
flex-direction: column;
23+
align-items: center;
24+
justify-content: center;
25+
}
26+
27+
p {
28+
margin: 0.5rem 0;
29+
line-height: 1;
2130
}
2231
2332
a {
@@ -26,6 +35,6 @@
2635
height: 100%;
2736
align-items: center;
2837
justify-content: center;
29-
font-size: 20vmin;
38+
font-size: 4rem;
3039
}
3140
</style>

content/tutorial/04-advanced-sveltekit/03-advanced-routing/02-rest-params/app-b/src/routes/[...path]/+page.svelte

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,29 @@
44
let words = ['how', 'deep', 'does', 'the', 'rabbit', 'hole', 'go'];
55
66
$: depth = $page.params.path.split('/').filter(Boolean).length;
7-
8-
$: href =
9-
depth === words.length
10-
? '/'
11-
: `/${words.slice(0, depth + 1).join('/')}`;
7+
$: next = depth === words.length ? '/' : `/${words.slice(0, depth + 1).join('/')}`;
128
</script>
139

14-
<a {href}>{words[depth] ?? '?'}</a>
10+
<div class="flex">
11+
{#each words.slice(0, depth) as word}
12+
<p>{word}</p>
13+
{/each}
14+
15+
<p><a href={next}>{words[depth] ?? '?'}</a></p>
16+
</div>
1517

1618
<style>
17-
:global(html),
18-
:global(body) {
19+
.flex {
20+
display: flex;
1921
height: 100%;
20-
margin: 0;
22+
flex-direction: column;
23+
align-items: center;
24+
justify-content: center;
25+
}
26+
27+
p {
28+
margin: 0.5rem 0;
29+
line-height: 1;
2130
}
2231
2332
a {
@@ -26,6 +35,6 @@
2635
height: 100%;
2736
align-items: center;
2837
justify-content: center;
29-
font-size: 20vmin;
38+
font-size: 4rem;
3039
}
3140
</style>

src/lib/client/adapters/webcontainer/index.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,17 @@ export async function create(base, error, progress, logs) {
119119
/** @type {import('$lib/types').Stub[]} */
120120
const to_write = [];
121121

122+
const force_delete = [];
123+
122124
for (const stub of stubs) {
123-
if (stub.type === 'file') {
125+
if (stub.name.endsWith('/__delete')) {
126+
force_delete.push(stub.name.slice(0, -9));
127+
} else if (stub.type === 'file') {
128+
if (stub.contents.startsWith('__delete')) {
129+
force_delete.push(stub.name);
130+
continue;
131+
}
132+
124133
const current = /** @type {import('$lib/types').FileStub} */ (
125134
current_stubs.get(stub.name)
126135
);
@@ -138,9 +147,12 @@ export async function create(base, error, progress, logs) {
138147

139148
// Don't delete the node_modules folder when switching from one exercise to another
140149
// where, as this crashes the dev server.
141-
const to_delete = Array.from(current_stubs.keys()).filter(
142-
(s) => !s.startsWith('/node_modules')
143-
);
150+
const to_delete = [
151+
...Array.from(current_stubs.keys()).filter(
152+
(s) => !s.startsWith('/node_modules')
153+
),
154+
...force_delete
155+
];
144156

145157
current_stubs = stubs_to_map(stubs);
146158

src/routes/tutorial/[slug]/filetree/Filetree.svelte

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
const dispatch = createEventDispatcher();
1616
17-
const hidden = new Set(['__client.js', 'node_modules']);
17+
const hidden = new Set(['__client.js', 'node_modules', '__delete']);
1818
1919
let modal_text = '';
2020
@@ -122,6 +122,14 @@
122122
dispatch('select', { name });
123123
}
124124
});
125+
126+
/** @param {import('$lib/types').Stub} file */
127+
function is_deleted(file) {
128+
if (file.type === 'directory') return `${file.name}/__delete` in exercise.a;
129+
if (file.text) return file.contents.startsWith('__delete');
130+
131+
return false;
132+
}
125133
</script>
126134

127135
<ul
@@ -147,7 +155,7 @@
147155
name: '',
148156
basename: exercise.scope.name
149157
}}
150-
contents={$files.filter((file) => !hidden.has(file.basename))}
158+
contents={$files.filter((file) => !hidden.has(file.basename) && !is_deleted(file))}
151159
/>
152160
</ul>
153161

0 commit comments

Comments
 (0)