diff --git a/src/renderer/components/sidebar-file-tree.tsx b/src/renderer/components/sidebar-file-tree.tsx
index 0b88b1c6ec..34e57b20a3 100644
--- a/src/renderer/components/sidebar-file-tree.tsx
+++ b/src/renderer/components/sidebar-file-tree.tsx
@@ -206,10 +206,8 @@ export const SidebarFileTree = observer(
return;
}
- const contents = appState.editorMosaic.value(editorId).trim();
try {
- appState.editorMosaic.addNewFile(id, contents);
- appState.editorMosaic.remove(editorId);
+ appState.editorMosaic.renameFile(editorId, id);
if (visible) appState.editorMosaic.show(id);
} catch (err) {
diff --git a/src/renderer/editor-mosaic.ts b/src/renderer/editor-mosaic.ts
index 9412392fd0..b6ec14e1ac 100644
--- a/src/renderer/editor-mosaic.ts
+++ b/src/renderer/editor-mosaic.ts
@@ -83,6 +83,7 @@ export class EditorMosaic {
addEditor: action,
setEditorFromBackup: action,
addNewFile: action,
+ renameFile: action,
});
// whenever the mosaics are changed,
@@ -291,6 +292,28 @@ export class EditorMosaic {
this.addFile(id, value);
}
+ /** Rename a file in the mosaic */
+ public renameFile(oldId: EditorId, newId: EditorId) {
+ if (!this.files.has(oldId)) {
+ throw new Error(`Cannot rename file "${oldId}": File doesn't exist`);
+ }
+
+ if (this.files.has(newId)) {
+ throw new Error(`Cannot rename file to "${newId}": File already exists`);
+ }
+
+ const entryPoint = this.mainEntryPointFile();
+
+ if (isMainEntryPoint(newId) && entryPoint !== oldId) {
+ throw new Error(
+ `Cannot rename file to "${newId}": Main entry point ${entryPoint} exists`,
+ );
+ }
+
+ this.addFile(newId, this.value(oldId).trim());
+ this.remove(oldId);
+ }
+
/** Get the contents of a single file. */
public value(id: EditorId): string {
const { backups, editors } = this;
diff --git a/tests/renderer/components/sidebar-file-tree-spec.tsx b/tests/renderer/components/sidebar-file-tree-spec.tsx
index be57f4dd52..4bd52eb0b5 100644
--- a/tests/renderer/components/sidebar-file-tree-spec.tsx
+++ b/tests/renderer/components/sidebar-file-tree-spec.tsx
@@ -103,6 +103,23 @@ describe('SidebarFileTree component', () => {
);
});
+ it('can rename one main entry point file to another main entry point file', async () => {
+ const wrapper = shallow();
+ const instance: any = wrapper.instance();
+
+ const EDITOR_NAME = MAIN_JS;
+ const EDITOR_NEW_NAME = MAIN_CJS;
+
+ store.showInputDialog = jest.fn().mockResolvedValueOnce(EDITOR_NEW_NAME);
+
+ await instance.renameEditor(EDITOR_NAME);
+
+ expect(editorMosaic.files.get(EDITOR_NAME)).toBe(undefined);
+ expect(editorMosaic.files.get(EDITOR_NEW_NAME)).toBe(
+ EditorPresence.Pending,
+ );
+ });
+
it('fails if trying to rename an editor to package(-lock).json', async () => {
const wrapper = shallow();
const instance: any = wrapper.instance();
@@ -153,7 +170,7 @@ describe('SidebarFileTree component', () => {
await instance.renameEditor(TO_BE_NAMED);
expect(store.showErrorDialog).toHaveBeenCalledWith(
- `Cannot add file "${EDITOR_NEW_NAME}": File already exists`,
+ `Cannot rename file to "${EDITOR_NEW_NAME}": File already exists`,
);
expect(editorMosaic.files.get(TO_BE_NAMED)).toBe(EditorPresence.Pending);
});
@@ -171,7 +188,7 @@ describe('SidebarFileTree component', () => {
await instance.renameEditor(TO_BE_NAMED);
expect(store.showErrorDialog).toHaveBeenCalledWith(
- `Cannot add file "${EDITOR_NEW_NAME}": Main entry point ${MAIN_JS} exists`,
+ `Cannot rename file to "${EDITOR_NEW_NAME}": Main entry point ${MAIN_JS} exists`,
);
expect(editorMosaic.files.get(TO_BE_NAMED)).toBe(EditorPresence.Pending);
});
diff --git a/tests/renderer/editor-mosaic-spec.ts b/tests/renderer/editor-mosaic-spec.ts
index 72e955ddb8..816f50a606 100644
--- a/tests/renderer/editor-mosaic-spec.ts
+++ b/tests/renderer/editor-mosaic-spec.ts
@@ -248,6 +248,15 @@ describe('EditorMosaic', () => {
});
});
+ describe('renameFile()', () => {
+ it('sets isEdited to true', () => {
+ editorMosaic.set(createEditorValues());
+ editorMosaic.isEdited = false;
+ editorMosaic.renameFile('renderer.js', 'bar.js');
+ expect(editorMosaic.isEdited).toBe(true);
+ });
+ });
+
describe('remove()', () => {
it('sets isEdited to true', () => {
editorMosaic.set(createEditorValues());