From a5f32864dd61cf31aa9e3e0d0cf847706a3600e5 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Fri, 12 Jun 2026 14:05:01 -0700 Subject: [PATCH] chore: remove renderer local version migration --- src/ambient.d.ts | 1 - src/ipc-events.ts | 2 -- src/main/versions.ts | 42 +--------------------- src/preload/preload.ts | 3 -- src/renderer/app.tsx | 10 ++++-- src/renderer/versions.ts | 12 ++++--- tests/main/versions.spec.ts | 64 +-------------------------------- tests/mocks/electron-fiddle.ts | 1 - tests/renderer/versions.spec.ts | 38 ++++++++++++++++++++ 9 files changed, 55 insertions(+), 118 deletions(-) diff --git a/src/ambient.d.ts b/src/ambient.d.ts index 4161091d90..3400e8234f 100644 --- a/src/ambient.d.ts +++ b/src/ambient.d.ts @@ -139,7 +139,6 @@ declare global { addLocalVersion(token: string, name: string): Array; cancelPendingLocalVersion(token: string): void; removeLocalVersion(version: string): Array; - migrateLocalVersions(versions: Version[]): boolean; getNodeTypes( version: string, ): Promise<{ version: string; types: NodeTypes } | undefined>; diff --git a/src/ipc-events.ts b/src/ipc-events.ts index 186d04f2d2..62514cc9e9 100644 --- a/src/ipc-events.ts +++ b/src/ipc-events.ts @@ -50,7 +50,6 @@ export enum IpcEvents { ADD_LOCAL_VERSION = 'ADD_LOCAL_VERSION', REMOVE_LOCAL_VERSION = 'REMOVE_LOCAL_VERSION', CANCEL_PENDING_LOCAL_VERSION = 'CANCEL_PENDING_LOCAL_VERSION', - MIGRATE_LOCAL_VERSIONS = 'MIGRATE_LOCAL_VERSIONS', GET_OLDEST_SUPPORTED_MAJOR = 'GET_OLDEST_SUPPORTED_MAJOR', GET_RELEASED_VERSIONS = 'GET_RELEASED_VERSIONS', GET_RELEASE_INFO = 'GET_RELEASE_INFO', @@ -106,7 +105,6 @@ export const ipcMainEvents = [ IpcEvents.ADD_LOCAL_VERSION, IpcEvents.REMOVE_LOCAL_VERSION, IpcEvents.CANCEL_PENDING_LOCAL_VERSION, - IpcEvents.MIGRATE_LOCAL_VERSIONS, IpcEvents.GET_OLDEST_SUPPORTED_MAJOR, IpcEvents.GET_RELEASED_VERSIONS, IpcEvents.GET_USERNAME, diff --git a/src/main/versions.ts b/src/main/versions.ts index 79f545f40c..1f77a7805e 100644 --- a/src/main/versions.ts +++ b/src/main/versions.ts @@ -12,7 +12,6 @@ import { IpcEvents } from '../ipc-events'; let knownVersions: ElectronVersions; let localVersions: Array = []; let localVersionsPath: string; -let migrated = false; /** * Helper to check if this version is from a released major branch. @@ -82,7 +81,6 @@ function loadLocalVersions(): void { const raw = fs.readFileSync(localVersionsPath, 'utf-8'); const data = JSON.parse(raw); if (data && typeof data === 'object') { - migrated = !!data.migrated; localVersions = Array.isArray(data.versions) ? data.versions.filter( (v: any) => @@ -105,7 +103,7 @@ function persistLocalVersions(): void { try { fs.writeFileSync( localVersionsPath, - JSON.stringify({ migrated, versions: localVersions }, null, 2), + JSON.stringify({ versions: localVersions }, null, 2), ); } catch (err) { console.warn('Failed to save local versions:', err); @@ -182,38 +180,6 @@ export function removeLocalVersion(version: string): Array { return localVersions; } -/** - * One-time migration of local versions from the renderer's localStorage - * to the main process store. Returns true if the migration was accepted, - * false if it was already performed previously. - */ -export function migrateLocalVersions(versions: Array): boolean { - if (migrated) { - return false; - } - - // Validate and merge incoming versions - const validVersions = versions.filter( - (v) => - v && - typeof v.version === 'string' && - v.version.length > 0 && - typeof v.localPath === 'string' && - v.localPath.length > 0, - ); - - for (const ver of validVersions) { - if (!localVersions.find((v) => v.localPath === ver.localPath)) { - localVersions.push(ver); - } - } - - migrated = true; - persistLocalVersions(); - - return true; -} - export async function setupVersions() { knownVersions = await ElectronVersions.create({ initialVersions: releases, @@ -261,12 +227,6 @@ export async function setupVersions() { event.returnValue = undefined; }, ); - ipcMainManager.on( - IpcEvents.MIGRATE_LOCAL_VERSIONS, - (event, versions: Version[]) => { - event.returnValue = migrateLocalVersions(versions); - }, - ); ipcMainManager.on(IpcEvents.GET_OLDEST_SUPPORTED_MAJOR, (event) => { event.returnValue = getOldestSupportedMajor(); }); diff --git a/src/preload/preload.ts b/src/preload/preload.ts index c8a113faa7..f803341539 100644 --- a/src/preload/preload.ts +++ b/src/preload/preload.ts @@ -180,9 +180,6 @@ export async function setupFiddleGlobal() { removeLocalVersion(version: string): Array { return ipcRenderer.sendSync(IpcEvents.REMOVE_LOCAL_VERSION, version); }, - migrateLocalVersions(versions: Version[]): boolean { - return ipcRenderer.sendSync(IpcEvents.MIGRATE_LOCAL_VERSIONS, versions); - }, getOldestSupportedMajor() { return ipcRenderer.sendSync(IpcEvents.GET_OLDEST_SUPPORTED_MAJOR); }, diff --git a/src/renderer/app.tsx b/src/renderer/app.tsx index aaccd64593..fc5d26296d 100644 --- a/src/renderer/app.tsx +++ b/src/renderer/app.tsx @@ -8,8 +8,8 @@ import { AppState } from './state'; import { activateTheme, getCurrentTheme, getTheme } from './themes'; import { getPackageJson } from './utils/get-package'; import { + discardLocalVersionsFromLocalStorage, getElectronVersions, - migrateLocalVersionsFromLocalStorage, } from './versions'; import { PREFERS_DARK_MEDIA_QUERY } from '../constants'; import { @@ -36,7 +36,7 @@ export class App { public readonly electronTypes: ElectronTypes; constructor() { - migrateLocalVersionsFromLocalStorage(); + const legacyLocalVersionsDiscarded = discardLocalVersionsFromLocalStorage(); this.state = new AppState(getElectronVersions()); this.fileManager = new FileManager(this.state); @@ -45,6 +45,12 @@ export class App { this.getEditorValues = this.getEditorValues.bind(this); this.electronTypes = new ElectronTypes(window.monaco); + + if (legacyLocalVersionsDiscarded) { + void this.state.showInfoDialog( + 'Fiddle has changed how it stores local Electron versions. Existing local versions have been removed and must be re-added.', + ); + } } private confirmReplaceUnsaved(): Promise { diff --git a/src/renderer/versions.ts b/src/renderer/versions.ts index c40cb22e0e..3afd20a2b0 100644 --- a/src/renderer/versions.ts +++ b/src/renderer/versions.ts @@ -10,23 +10,25 @@ import { } from '../interfaces'; /** - * One-time migration: move local versions from localStorage to main process. - * Must be called before getElectronVersions(). + * Legacy builds stored local versions in renderer localStorage - discard them. + * Returns true if any legacy local versions were found and discarded, else false. */ -export function migrateLocalVersionsFromLocalStorage(): void { +export function discardLocalVersionsFromLocalStorage(): boolean { const raw = window.localStorage.getItem(GlobalSetting.localVersion); - if (!raw) return; + if (!raw) return false; try { const versions: Array = JSON.parse(raw); if (Array.isArray(versions) && versions.length !== 0) { - window.ElectronFiddle.migrateLocalVersions(versions); + return true; } } catch { // We tried our best, if something is corrupt just remove and move on } finally { window.localStorage.removeItem(GlobalSetting.localVersion); } + + return false; } /** diff --git a/tests/main/versions.spec.ts b/tests/main/versions.spec.ts index e18037e608..0c36728a63 100644 --- a/tests/main/versions.spec.ts +++ b/tests/main/versions.spec.ts @@ -12,7 +12,6 @@ import { getOldestSupportedMajor, getReleasedVersions, isReleasedMajor, - migrateLocalVersions, removeLocalVersion, setPendingLocalPath, setupVersions, @@ -102,7 +101,7 @@ describe('versions', () => { }); describe('local version management', () => { - const emptyState = JSON.stringify({ migrated: false, versions: [] }); + const emptyState = JSON.stringify({ versions: [] }); beforeEach(async () => { // Provide clean persisted state so loadLocalVersions resets properly @@ -181,66 +180,9 @@ describe('versions', () => { }); }); - describe('migrateLocalVersions()', () => { - it('accepts migration on first call', () => { - const versions: Version[] = [ - { version: '1.0.0', localPath: '/path/a' }, - { version: '2.0.0', localPath: '/path/b' }, - ]; - - const accepted = migrateLocalVersions(versions); - expect(accepted).toBe(true); - expect(getLocalVersions()).toEqual(versions); - expect(fs.writeFileSync).toHaveBeenCalled(); - }); - - it('rejects migration on subsequent calls', () => { - migrateLocalVersions([{ version: '1.0.0', localPath: '/path/a' }]); - vi.mocked(fs.writeFileSync).mockClear(); - - const accepted = migrateLocalVersions([ - { version: '3.0.0', localPath: '/path/c' }, - ]); - expect(accepted).toBe(false); - expect(fs.writeFileSync).not.toHaveBeenCalled(); - }); - - it('filters out invalid entries', () => { - const versions = [ - { version: '1.0.0', localPath: '/valid' }, - { version: '2.0.0', localPath: '' }, - { version: null, localPath: '/no-version' }, - null, - ] as unknown as Version[]; - - migrateLocalVersions(versions); - expect(getLocalVersions()).toEqual([ - { version: '1.0.0', localPath: '/valid' }, - ]); - }); - - it('does not add duplicates by localPath', () => { - setPendingLocalPath('token-dup', '/path/a'); - addLocalVersion('token-dup', 'build a'); - - migrateLocalVersions([ - { version: '1.0.0-dup', localPath: '/path/a' }, - { version: '2.0.0', localPath: '/path/b' }, - ]); - - const locals = getLocalVersions(); - expect(locals.filter((v) => v.localPath === '/path/a')).toHaveLength(1); - expect(locals).toContainEqual({ - version: '2.0.0', - localPath: '/path/b', - }); - }); - }); - describe('loadLocalVersions()', () => { it('loads persisted versions on setup', async () => { const stored = { - migrated: true, versions: [{ version: '5.0.0', localPath: '/stored' }], }; vi.mocked(fs.existsSync).mockReturnValue(true); @@ -249,10 +191,6 @@ describe('versions', () => { await setupVersions(); expect(getLocalVersions()).toEqual(stored.versions); - // Since migrated was true, further migration should be rejected - expect( - migrateLocalVersions([{ version: '6.0.0', localPath: '/new' }]), - ).toBe(false); }); }); }); diff --git a/tests/mocks/electron-fiddle.ts b/tests/mocks/electron-fiddle.ts index 7d91103d07..2874190213 100644 --- a/tests/mocks/electron-fiddle.ts +++ b/tests/mocks/electron-fiddle.ts @@ -28,7 +28,6 @@ export class ElectronFiddleMock { public addLocalVersion = vi.fn(); public cancelPendingLocalVersion = vi.fn(); public removeLocalVersion = vi.fn(); - public migrateLocalVersions = vi.fn(); public getNodeTypes = vi.fn(); public getOldestSupportedMajor = vi.fn(); public getReleaseInfo = vi.fn(); diff --git a/tests/renderer/versions.spec.ts b/tests/renderer/versions.spec.ts index 3acaa89d0b..c0b64f86dd 100644 --- a/tests/renderer/versions.spec.ts +++ b/tests/renderer/versions.spec.ts @@ -9,6 +9,7 @@ import { } from '../../src/interfaces'; import { addLocalVersion, + discardLocalVersionsFromLocalStorage, fetchVersions, getDefaultVersion, getLocalVersions, @@ -125,4 +126,41 @@ describe('versions', () => { ); }); }); + + describe('discardLocalVersionsFromLocalStorage()', () => { + it('returns true and removes legacy local versions', () => { + vi.mocked(localStorage.getItem).mockReturnValue( + JSON.stringify([{ version: '1.0.0', localPath: '/legacy/path' }]), + ); + + const result = discardLocalVersionsFromLocalStorage(); + + expect(result).toBe(true); + expect(localStorage.removeItem).toHaveBeenCalledWith( + GlobalSetting.localVersion, + ); + }); + + it('returns false for empty legacy versions but still removes key', () => { + vi.mocked(localStorage.getItem).mockReturnValue(JSON.stringify([])); + + const result = discardLocalVersionsFromLocalStorage(); + + expect(result).toBe(false); + expect(localStorage.removeItem).toHaveBeenCalledWith( + GlobalSetting.localVersion, + ); + }); + + it('returns false and removes legacy key even when value is invalid json', () => { + vi.mocked(localStorage.getItem).mockReturnValue('not-json'); + + const result = discardLocalVersionsFromLocalStorage(); + + expect(result).toBe(false); + expect(localStorage.removeItem).toHaveBeenCalledWith( + GlobalSetting.localVersion, + ); + }); + }); });