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());