Skip to content

Commit 258d063

Browse files
committed
[fix] treat edit as remove+add
fixes errors around renaming to something with a / in it
1 parent 3ef8939 commit 258d063

File tree

3 files changed

+73
-52
lines changed

3 files changed

+73
-52
lines changed

src/lib/types/index.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export interface PartStub {
8282

8383
export interface FileTreeContext {
8484
select: (file: FileStub) => void;
85-
add: (stubs: Stub[]) => Promise<void>;
85+
add: (name: string, type: 'file' | 'directory') => Promise<void>;
8686
edit: (stub: Stub, name: string) => Promise<void>;
8787
remove: (stub: Stub) => Promise<void>;
8888
selected: Writable<FileStub | null>;

src/routes/tutorial/[slug]/+page.svelte

+71-24
Original file line numberDiff line numberDiff line change
@@ -83,49 +83,47 @@
8383
$selected = file;
8484
},
8585
86-
add: async (stubs) => {
87-
const illegal_create = stubs.some(
86+
add: async (name, type) => {
87+
const new_stubs = add_stub(name, type, current_stubs);
88+
89+
const illegal_create = new_stubs.some(
8890
(s) => !editing_constraints.create.some((c) => s.name === c)
8991
);
90-
9192
if (illegal_create) {
9293
modal_text =
9394
'Only the following files and folders are allowed to be created in this tutorial chapter:\n' +
9495
editing_constraints.create.join('\n');
9596
return;
9697
}
9798
98-
current_stubs = [...current_stubs, ...stubs];
99-
99+
current_stubs = [...current_stubs, ...new_stubs];
100100
await load_files(current_stubs);
101101
102-
if (stubs[0].type === 'file') {
103-
select(stubs[0]);
102+
if (new_stubs[0].type === 'file') {
103+
select(new_stubs[0]);
104104
}
105105
},
106106
107107
edit: async (to_rename, new_name) => {
108-
/** @type {Array<[import('$lib/types').Stub, import('$lib/types').Stub]>}*/
109-
const changed = [];
110-
const updated_stubs = current_stubs.map((s) => {
111-
if (!s.name.startsWith(to_rename.name)) {
112-
return s;
113-
}
114-
108+
// treat edit as a remove followed by an add
109+
const out = current_stubs.filter((s) => s.name.startsWith(to_rename.name));
110+
const updated_stubs = current_stubs.filter((s) => !out.includes(s));
111+
/** @type {Map<string, import('$lib/types').Stub>} */
112+
const new_stubs = new Map();
113+
for (const s of out) {
115114
const name =
116115
s.name.slice(0, to_rename.name.length - to_rename.basename.length) +
117116
new_name +
118117
s.name.slice(to_rename.name.length);
119-
const basename = s === to_rename ? new_name : s.basename;
120-
const new_stub = { ...s, name, basename };
121-
122-
changed.push([s, new_stub]);
123-
return new_stub;
124-
});
118+
// deduplicate
119+
for (const to_add of add_stub(name, s.type, updated_stubs)) {
120+
new_stubs.set(to_add.name, to_add);
121+
}
122+
}
125123
126124
const illegal_rename =
127125
!editing_constraints.remove.some((r) => to_rename.name === r) ||
128-
changed.some(([, s]) => !editing_constraints.create.some((c) => s.name === c));
126+
[...new_stubs.keys()].some((name) => !editing_constraints.create.some((c) => name === c));
129127
if (illegal_rename) {
130128
modal_text =
131129
'Only the following files and folders are allowed to be renamed in this tutorial chapter:\n' +
@@ -135,11 +133,11 @@
135133
return;
136134
}
137135
138-
current_stubs = updated_stubs;
136+
current_stubs = updated_stubs.concat(...new_stubs.values());
139137
await load_files(current_stubs);
140138
141-
if (to_rename.type === 'file') {
142-
select(/** @type {any} */ (changed.find(([old_s]) => old_s === to_rename))[1]);
139+
if (to_rename.type === 'file' && $selected?.name === to_rename.name) {
140+
select(/** @type {any} */ ([...new_stubs.values()].find((s) => s.type === 'file')));
143141
}
144142
},
145143
@@ -165,6 +163,55 @@
165163
selected
166164
});
167165
166+
/**
167+
* @param {string} name
168+
* @param {'file' | 'directory'} type
169+
* @param {import('$lib/types').Stub[]} current
170+
*/
171+
function add_stub(name, type, current) {
172+
// find directory which contains the new file
173+
/** @type {import('$lib/types').DirectoryStub} */
174+
let dir = /** @type {any} we know it will be assigned after the loop */ (null);
175+
for (const stub of current) {
176+
if (
177+
stub.type === 'directory' &&
178+
name.startsWith(stub.name) &&
179+
(!dir || dir.name.length < stub.name.length)
180+
) {
181+
dir = stub;
182+
}
183+
}
184+
185+
const new_name = name.slice(dir.name.length + 1);
186+
const prefix = dir.name + '/';
187+
const depth = prefix.split('/').length - 2;
188+
const parts = new_name.split('/');
189+
/** @type {import('$lib/types').Stub[]} */
190+
const stubs = [];
191+
192+
for (let i = 1; i <= parts.length; i++) {
193+
const part = parts.slice(0, i).join('/');
194+
const basename = /** @type{string} */ (part.split('/').pop());
195+
const name = prefix + part;
196+
if (!current.some((s) => s.name === name)) {
197+
if (i < parts.length || type === 'directory') {
198+
stubs.push({ type: 'directory', name, depth: depth + i, basename });
199+
} else if (i === parts.length && type === 'file') {
200+
stubs.push({
201+
type: 'file',
202+
name,
203+
depth: depth + i,
204+
basename,
205+
text: true,
206+
contents: ''
207+
});
208+
}
209+
}
210+
}
211+
212+
return stubs;
213+
}
214+
168215
/** @type {import('$lib/types').Adapter | undefined} */
169216
let adapter;
170217

src/routes/tutorial/[slug]/Folder.svelte

+1-27
Original file line numberDiff line numberDiff line change
@@ -107,33 +107,7 @@
107107
if (state === 'edit_folder') {
108108
edit(/** @type {import('$lib/types').DirectoryStub} */ (file), new_name);
109109
} else {
110-
const parts = new_name.split('/');
111-
/** @type {import('$lib/types').Stub[]} */
112-
const stubs = [];
113-
114-
for (let i = 1; i <= parts.length; i++) {
115-
const part = parts.slice(0, i).join('/');
116-
const basename = /** @type{string} */ (part.split('/').pop());
117-
const name = prefix + part;
118-
if (!files.some((file) => file.name === name)) {
119-
if (i < parts.length || state === 'add_folder') {
120-
stubs.push({ type: 'directory', name, depth: depth + i, basename });
121-
} else if (i === parts.length && state === 'add_file') {
122-
stubs.push({
123-
type: 'file',
124-
name,
125-
depth: depth + i,
126-
basename,
127-
text: true,
128-
contents: ''
129-
});
130-
}
131-
}
132-
}
133-
134-
if (stubs.length) {
135-
add(stubs);
136-
}
110+
add(prefix + new_name, state === 'add_folder' ? 'directory' : 'file');
137111
}
138112
}
139113

0 commit comments

Comments
 (0)