Switch to double quotes and reformat codebase with Biome

This commit is contained in:
Mohamed Boudra
2026-03-21 20:22:15 +07:00
parent ab40786882
commit f6579dbeb4
805 changed files with 38132 additions and 40175 deletions
@@ -1,95 +1,95 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { afterEach, describe, expect, it, vi } from "vitest";
async function loadModuleForPlatform(platform: 'web' | 'ios' | 'android') {
vi.resetModules()
vi.doMock('react-native', () => ({ Platform: { OS: platform } }))
return import('./desktop-updates')
async function loadModuleForPlatform(platform: "web" | "ios" | "android") {
vi.resetModules();
vi.doMock("react-native", () => ({ Platform: { OS: platform } }));
return import("./desktop-updates");
}
describe('desktop-updates helpers', () => {
describe("desktop-updates helpers", () => {
afterEach(() => {
vi.doUnmock('react-native')
vi.restoreAllMocks()
vi.resetModules()
})
vi.doUnmock("react-native");
vi.restoreAllMocks();
vi.resetModules();
});
it('normalizes versions for app-daemon comparisons', async () => {
const { normalizeVersionForComparison } = await loadModuleForPlatform('web')
it("normalizes versions for app-daemon comparisons", async () => {
const { normalizeVersionForComparison } = await loadModuleForPlatform("web");
expect(normalizeVersionForComparison(' v0.1.15 ')).toBe('0.1.15')
expect(normalizeVersionForComparison('0.1.15')).toBe('0.1.15')
expect(normalizeVersionForComparison(null)).toBeNull()
})
expect(normalizeVersionForComparison(" v0.1.15 ")).toBe("0.1.15");
expect(normalizeVersionForComparison("0.1.15")).toBe("0.1.15");
expect(normalizeVersionForComparison(null)).toBeNull();
});
it('detects version mismatch after normalization', async () => {
const { isVersionMismatch } = await loadModuleForPlatform('web')
it("detects version mismatch after normalization", async () => {
const { isVersionMismatch } = await loadModuleForPlatform("web");
expect(isVersionMismatch('v0.1.15', '0.1.15')).toBe(false)
expect(isVersionMismatch('0.1.15', '0.1.16')).toBe(true)
expect(isVersionMismatch('0.1.15', null)).toBe(false)
})
expect(isVersionMismatch("v0.1.15", "0.1.15")).toBe(false);
expect(isVersionMismatch("0.1.15", "0.1.16")).toBe(true);
expect(isVersionMismatch("0.1.15", null)).toBe(false);
});
it('formats display versions with v prefix and unavailable fallback', async () => {
const { formatVersionWithPrefix } = await loadModuleForPlatform('web')
it("formats display versions with v prefix and unavailable fallback", async () => {
const { formatVersionWithPrefix } = await loadModuleForPlatform("web");
expect(formatVersionWithPrefix('0.2.0')).toBe('v0.2.0')
expect(formatVersionWithPrefix('v0.2.0')).toBe('v0.2.0')
expect(formatVersionWithPrefix(null)).toBe('\u2014')
})
expect(formatVersionWithPrefix("0.2.0")).toBe("v0.2.0");
expect(formatVersionWithPrefix("v0.2.0")).toBe("v0.2.0");
expect(formatVersionWithPrefix(null)).toBe("\u2014");
});
it('parses valid local daemon version result', async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
it("parses valid local daemon version result", async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform("web");
expect(parseLocalDaemonVersionResult({ version: '0.1.15', error: null })).toEqual({
version: '0.1.15',
expect(parseLocalDaemonVersionResult({ version: "0.1.15", error: null })).toEqual({
version: "0.1.15",
error: null,
})
})
});
});
it('parses local daemon version error result', async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
it("parses local daemon version error result", async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform("web");
expect(
parseLocalDaemonVersionResult({ version: null, error: 'paseo command not found in PATH' })
parseLocalDaemonVersionResult({ version: null, error: "paseo command not found in PATH" }),
).toEqual({
version: null,
error: 'paseo command not found in PATH',
})
})
error: "paseo command not found in PATH",
});
});
it('parses unexpected local daemon version result', async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
it("parses unexpected local daemon version result", async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform("web");
expect(parseLocalDaemonVersionResult(null)).toEqual({
version: null,
error: 'Unexpected response from version check.',
})
error: "Unexpected response from version check.",
});
expect(parseLocalDaemonVersionResult('not an object')).toEqual({
expect(parseLocalDaemonVersionResult("not an object")).toEqual({
version: null,
error: 'Unexpected response from version check.',
})
})
error: "Unexpected response from version check.",
});
});
it('trims whitespace in parsed version', async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform('web')
it("trims whitespace in parsed version", async () => {
const { parseLocalDaemonVersionResult } = await loadModuleForPlatform("web");
expect(parseLocalDaemonVersionResult({ version: ' 0.1.15 ', error: null })).toEqual({
version: '0.1.15',
expect(parseLocalDaemonVersionResult({ version: " 0.1.15 ", error: null })).toEqual({
version: "0.1.15",
error: null,
})
})
});
});
it('builds copyable daemon update diagnostics', async () => {
const { buildDaemonUpdateDiagnostics } = await loadModuleForPlatform('web')
it("builds copyable daemon update diagnostics", async () => {
const { buildDaemonUpdateDiagnostics } = await loadModuleForPlatform("web");
const diagnostics = buildDaemonUpdateDiagnostics({
exitCode: 1,
stdout: 'stdout text',
stderr: 'stderr text',
})
stdout: "stdout text",
stderr: "stderr text",
});
expect(diagnostics).toContain('Exit code: 1')
expect(diagnostics).toContain('STDOUT:\nstdout text')
expect(diagnostics).toContain('STDERR:\nstderr text')
})
})
expect(diagnostics).toContain("Exit code: 1");
expect(diagnostics).toContain("STDOUT:\nstdout text");
expect(diagnostics).toContain("STDERR:\nstderr text");
});
});
@@ -1,77 +1,77 @@
import { Platform } from 'react-native'
import { isDesktop } from '@/desktop/host'
import { invokeDesktopCommand } from '@/desktop/electron/invoke'
import { Platform } from "react-native";
import { isDesktop } from "@/desktop/host";
import { invokeDesktopCommand } from "@/desktop/electron/invoke";
export interface DesktopAppUpdateCheckResult {
hasUpdate: boolean
currentVersion: string | null
latestVersion: string | null
body: string | null
date: string | null
hasUpdate: boolean;
currentVersion: string | null;
latestVersion: string | null;
body: string | null;
date: string | null;
}
export interface DesktopAppUpdateInstallResult {
installed: boolean
version: string | null
message: string
installed: boolean;
version: string | null;
message: string;
}
export interface LocalDaemonUpdateResult {
exitCode: number
stdout: string
stderr: string
exitCode: number;
stdout: string;
stderr: string;
}
export interface LocalDaemonVersionResult {
version: string | null
error: string | null
version: string | null;
error: string | null;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null
return typeof value === "object" && value !== null;
}
function toStringOrNull(value: unknown): string | null {
if (typeof value !== 'string') {
return null
if (typeof value !== "string") {
return null;
}
const trimmed = value.trim()
return trimmed.length > 0 ? trimmed : null
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
}
function toStringOrEmpty(value: unknown): string {
return typeof value === 'string' ? value : ''
return typeof value === "string" ? value : "";
}
function toNumberOr(defaultValue: number, value: unknown): number {
return typeof value === 'number' && Number.isFinite(value) ? value : defaultValue
return typeof value === "number" && Number.isFinite(value) ? value : defaultValue;
}
export function shouldShowDesktopUpdateSection(): boolean {
return Platform.OS === 'web' && isDesktop()
return Platform.OS === "web" && isDesktop();
}
export function parseLocalDaemonVersionResult(raw: unknown): LocalDaemonVersionResult {
if (!isRecord(raw)) {
return { version: null, error: 'Unexpected response from version check.' }
return { version: null, error: "Unexpected response from version check." };
}
return {
version: toStringOrNull(raw.version),
error: toStringOrNull(raw.error),
}
};
}
export async function getLocalDaemonVersion(): Promise<LocalDaemonVersionResult> {
const result = await invokeDesktopCommand<unknown>('get_local_daemon_version')
return parseLocalDaemonVersionResult(result)
const result = await invokeDesktopCommand<unknown>("get_local_daemon_version");
return parseLocalDaemonVersionResult(result);
}
export async function checkDesktopAppUpdate(): Promise<DesktopAppUpdateCheckResult> {
const result = await invokeDesktopCommand<unknown>('check_app_update')
const result = await invokeDesktopCommand<unknown>("check_app_update");
if (!isRecord(result)) {
throw new Error('Unexpected response while checking desktop updates.')
throw new Error("Unexpected response while checking desktop updates.");
}
return {
@@ -80,78 +80,70 @@ export async function checkDesktopAppUpdate(): Promise<DesktopAppUpdateCheckResu
latestVersion: toStringOrNull(result.latestVersion),
body: toStringOrNull(result.body),
date: toStringOrNull(result.date),
}
};
}
export async function installDesktopAppUpdate(): Promise<DesktopAppUpdateInstallResult> {
const result = await invokeDesktopCommand<unknown>('install_app_update')
const result = await invokeDesktopCommand<unknown>("install_app_update");
if (!isRecord(result)) {
throw new Error('Unexpected response while installing desktop update.')
throw new Error("Unexpected response while installing desktop update.");
}
return {
installed: result.installed === true,
version: toStringOrNull(result.version),
message: toStringOrNull(result.message) ?? 'Update completed.',
}
message: toStringOrNull(result.message) ?? "Update completed.",
};
}
export async function runLocalDaemonUpdate(): Promise<LocalDaemonUpdateResult> {
const result = await invokeDesktopCommand<unknown>('run_local_daemon_update')
const result = await invokeDesktopCommand<unknown>("run_local_daemon_update");
if (!isRecord(result)) {
throw new Error('Unexpected response while updating local daemon.')
throw new Error("Unexpected response while updating local daemon.");
}
return {
exitCode: toNumberOr(1, result.exitCode),
stdout: toStringOrEmpty(result.stdout),
stderr: toStringOrEmpty(result.stderr),
}
};
}
export function normalizeVersionForComparison(version: string | null | undefined): string | null {
const value = version?.trim()
const value = version?.trim();
if (!value) {
return null
return null;
}
return value.replace(/^v/i, '')
return value.replace(/^v/i, "");
}
export function isVersionMismatch(
appVersion: string | null | undefined,
daemonVersion: string | null | undefined
daemonVersion: string | null | undefined,
): boolean {
const app = normalizeVersionForComparison(appVersion)
const daemon = normalizeVersionForComparison(daemonVersion)
const app = normalizeVersionForComparison(appVersion);
const daemon = normalizeVersionForComparison(daemonVersion);
if (!app || !daemon) {
return false
return false;
}
return app !== daemon
return app !== daemon;
}
export function formatVersionWithPrefix(version: string | null | undefined): string {
const value = version?.trim()
const value = version?.trim();
if (!value) {
return '\u2014'
return "\u2014";
}
return value.startsWith('v') ? value : `v${value}`
return value.startsWith("v") ? value : `v${value}`;
}
export function buildDaemonUpdateDiagnostics(result: LocalDaemonUpdateResult): string {
const stdout = result.stdout.length > 0 ? result.stdout : '(empty)'
const stderr = result.stderr.length > 0 ? result.stderr : '(empty)'
const stdout = result.stdout.length > 0 ? result.stdout : "(empty)";
const stderr = result.stderr.length > 0 ? result.stderr : "(empty)";
return [
`Exit code: ${result.exitCode}`,
'',
'STDOUT:',
stdout,
'',
'STDERR:',
stderr,
].join('\n')
return [`Exit code: ${result.exitCode}`, "", "STDOUT:", stdout, "", "STDERR:", stderr].join("\n");
}
@@ -10,14 +10,8 @@ const CHANGELOG_URL = "https://paseo.sh/changelog";
export function UpdateBanner() {
const { theme } = useUnistyles();
const {
isDesktop,
status,
availableUpdate,
checkForUpdates,
installUpdate,
isInstalling,
} = useDesktopAppUpdater();
const { isDesktop, status, availableUpdate, checkForUpdates, installUpdate, isInstalling } =
useDesktopAppUpdater();
const [dismissed, setDismissed] = useState(false);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
@@ -46,18 +40,12 @@ export function UpdateBanner() {
return (
<View style={styles.container} pointerEvents="box-none">
<View style={styles.banner}>
<Pressable
onPress={() => setDismissed(true)}
hitSlop={8}
style={styles.closeButton}
>
<Pressable onPress={() => setDismissed(true)} hitSlop={8} style={styles.closeButton}>
<X size={14} color={theme.colors.foregroundMuted} />
</Pressable>
<View style={styles.textSection}>
<Text style={styles.title}>
{isInstalled ? "Update installed" : "Update available"}
</Text>
<Text style={styles.title}>{isInstalled ? "Update installed" : "Update available"}</Text>
<Text style={styles.subtitle}>
{isInstalled
? "Restart to use the new version."
@@ -68,10 +56,7 @@ export function UpdateBanner() {
<View style={styles.actions}>
<Pressable
onPress={() => void openExternalUrl(CHANGELOG_URL)}
style={({ pressed }) => [
styles.outlineButton,
pressed && styles.buttonPressed,
]}
style={({ pressed }) => [styles.outlineButton, pressed && styles.buttonPressed]}
>
<Text style={styles.outlineButtonText}>What's new</Text>
</Pressable>
@@ -1,4 +1,4 @@
import { useCallback, useRef, useState } from 'react'
import { useCallback, useRef, useState } from "react";
import {
checkDesktopAppUpdate,
formatVersionWithPrefix,
@@ -6,163 +6,163 @@ import {
shouldShowDesktopUpdateSection,
type DesktopAppUpdateCheckResult,
type DesktopAppUpdateInstallResult,
} from '@/desktop/updates/desktop-updates'
} from "@/desktop/updates/desktop-updates";
export type DesktopAppUpdateStatus =
| 'idle'
| 'checking'
| 'up-to-date'
| 'available'
| 'installing'
| 'installed'
| 'error'
| "idle"
| "checking"
| "up-to-date"
| "available"
| "installing"
| "installed"
| "error";
export interface UseDesktopAppUpdaterReturn {
isDesktop: boolean
status: DesktopAppUpdateStatus
statusText: string
availableUpdate: DesktopAppUpdateCheckResult | null
errorMessage: string | null
lastCheckedAt: number | null
isChecking: boolean
isInstalling: boolean
checkForUpdates: (options?: { silent?: boolean }) => Promise<DesktopAppUpdateCheckResult | null>
installUpdate: () => Promise<DesktopAppUpdateInstallResult | null>
isDesktop: boolean;
status: DesktopAppUpdateStatus;
statusText: string;
availableUpdate: DesktopAppUpdateCheckResult | null;
errorMessage: string | null;
lastCheckedAt: number | null;
isChecking: boolean;
isInstalling: boolean;
checkForUpdates: (options?: { silent?: boolean }) => Promise<DesktopAppUpdateCheckResult | null>;
installUpdate: () => Promise<DesktopAppUpdateInstallResult | null>;
}
function getErrorMessage(error: unknown): string {
if (error instanceof Error && typeof error.message === 'string') {
return error.message
if (error instanceof Error && typeof error.message === "string") {
return error.message;
}
return String(error)
return String(error);
}
function formatStatusText(input: {
status: DesktopAppUpdateStatus
availableUpdate: DesktopAppUpdateCheckResult | null
installMessage: string | null
status: DesktopAppUpdateStatus;
availableUpdate: DesktopAppUpdateCheckResult | null;
installMessage: string | null;
}): string {
const { status, availableUpdate, installMessage } = input
const { status, availableUpdate, installMessage } = input;
if (status === 'checking') {
return 'Checking for app updates...'
if (status === "checking") {
return "Checking for app updates...";
}
if (status === 'installing') {
return 'Installing app update...'
if (status === "installing") {
return "Installing app update...";
}
if (status === 'up-to-date') {
return 'App is up to date.'
if (status === "up-to-date") {
return "App is up to date.";
}
if (status === 'available') {
if (status === "available") {
if (availableUpdate?.latestVersion) {
return `Update available: ${formatVersionWithPrefix(availableUpdate.latestVersion)}`
return `Update available: ${formatVersionWithPrefix(availableUpdate.latestVersion)}`;
}
return 'An app update is available.'
return "An app update is available.";
}
if (status === 'installed') {
return installMessage ?? 'App update installed. Restart required.'
if (status === "installed") {
return installMessage ?? "App update installed. Restart required.";
}
if (status === 'error') {
return 'Failed to update app.'
if (status === "error") {
return "Failed to update app.";
}
return 'Update status has not been checked yet.'
return "Update status has not been checked yet.";
}
export function useDesktopAppUpdater(): UseDesktopAppUpdaterReturn {
const isDesktop = shouldShowDesktopUpdateSection()
const requestVersionRef = useRef(0)
const [status, setStatus] = useState<DesktopAppUpdateStatus>('idle')
const [availableUpdate, setAvailableUpdate] = useState<DesktopAppUpdateCheckResult | null>(null)
const [errorMessage, setErrorMessage] = useState<string | null>(null)
const [installMessage, setInstallMessage] = useState<string | null>(null)
const [lastCheckedAt, setLastCheckedAt] = useState<number | null>(null)
const isDesktop = shouldShowDesktopUpdateSection();
const requestVersionRef = useRef(0);
const [status, setStatus] = useState<DesktopAppUpdateStatus>("idle");
const [availableUpdate, setAvailableUpdate] = useState<DesktopAppUpdateCheckResult | null>(null);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [installMessage, setInstallMessage] = useState<string | null>(null);
const [lastCheckedAt, setLastCheckedAt] = useState<number | null>(null);
const checkForUpdates = useCallback(
async (options: { silent?: boolean } = {}) => {
if (!isDesktop) {
return null
return null;
}
const requestVersion = requestVersionRef.current + 1
requestVersionRef.current = requestVersion
const requestVersion = requestVersionRef.current + 1;
requestVersionRef.current = requestVersion;
if (!options.silent) {
setStatus('checking')
setStatus("checking");
}
setErrorMessage(null)
setErrorMessage(null);
try {
const result = await checkDesktopAppUpdate()
const result = await checkDesktopAppUpdate();
if (requestVersion !== requestVersionRef.current) {
return result
return result;
}
setInstallMessage(null)
setLastCheckedAt(Date.now())
setInstallMessage(null);
setLastCheckedAt(Date.now());
if (result.hasUpdate) {
setAvailableUpdate(result)
setStatus('available')
setAvailableUpdate(result);
setStatus("available");
} else {
setAvailableUpdate(null)
setStatus('up-to-date')
setAvailableUpdate(null);
setStatus("up-to-date");
}
return result
return result;
} catch (error) {
if (requestVersion !== requestVersionRef.current) {
return null
return null;
}
const message = getErrorMessage(error)
const message = getErrorMessage(error);
if (options.silent) {
console.warn('[DesktopUpdater] Silent update check failed', message)
console.warn("[DesktopUpdater] Silent update check failed", message);
} else {
setStatus('error')
setErrorMessage(message)
setStatus("error");
setErrorMessage(message);
}
return null
return null;
}
},
[isDesktop]
)
[isDesktop],
);
const installUpdate = useCallback(async () => {
if (!isDesktop) {
return null
return null;
}
setStatus('installing')
setErrorMessage(null)
setStatus("installing");
setErrorMessage(null);
try {
const result = await installDesktopAppUpdate()
setLastCheckedAt(Date.now())
const result = await installDesktopAppUpdate();
setLastCheckedAt(Date.now());
if (result.installed) {
setAvailableUpdate(null)
setInstallMessage(result.message)
setStatus('installed')
setAvailableUpdate(null);
setInstallMessage(result.message);
setStatus("installed");
} else {
setAvailableUpdate(null)
setInstallMessage(result.message)
setStatus('up-to-date')
setAvailableUpdate(null);
setInstallMessage(result.message);
setStatus("up-to-date");
}
return result
return result;
} catch (error) {
const message = getErrorMessage(error)
setStatus('error')
setErrorMessage(message)
return null
const message = getErrorMessage(error);
setStatus("error");
setErrorMessage(message);
return null;
}
}, [isDesktop])
}, [isDesktop]);
return {
isDesktop,
@@ -175,9 +175,9 @@ export function useDesktopAppUpdater(): UseDesktopAppUpdaterReturn {
availableUpdate,
errorMessage,
lastCheckedAt,
isChecking: status === 'checking',
isInstalling: status === 'installing',
isChecking: status === "checking",
isInstalling: status === "installing",
checkForUpdates,
installUpdate,
}
};
}