chore: use Partial<Record<..>> for better type checking

This commit is contained in:
Nikita Galaiko 2023-09-21 13:39:47 +02:00
parent 49dfcace64
commit 9d99a4aad8
18 changed files with 78 additions and 57 deletions

View File

@ -18,7 +18,7 @@ export function subscribe(
return listen(`project://${params.projectId}/git/activity`, () => callback(params));
}
const stores: Record<string, WritableLoadable<Activity[]>> = {};
const stores: Partial<Record<string, WritableLoadable<Activity[]>>> = {};
export function getActivitiesStore(params: { projectId: string }) {
if (stores[params.projectId]) return stores[params.projectId];

View File

@ -3,13 +3,15 @@ import { asyncWritable, type WritableLoadable } from '@square/svelte-store';
import * as activities from './activities';
import * as sessions from '../ipc/sessions';
const list = (params: { projectId: string; contextLines?: number }) =>
invoke<Record<string, string>>('git_wd_diff', {
type Diffs = Partial<Record<string, string>>;
const list = (params: { projectId: string; contextLines?: number }): Promise<Diffs> =>
invoke('git_wd_diff', {
projectId: params.projectId,
contextLines: params.contextLines ?? 10000
});
const stores: Record<string, WritableLoadable<Record<string, string>>> = {};
const stores: Partial<Record<string, WritableLoadable<Diffs>>> = {};
export function getDiffsStore(params: { projectId: string }) {
if (stores[params.projectId]) return stores[params.projectId];

View File

@ -14,10 +14,11 @@ export function subscribe(
);
}
const stores: Record<string, WritableLoadable<string>> = {};
const stores: Partial<Record<string, WritableLoadable<string>>> = {};
export function getHeadStore(params: { projectId: string }) {
if (stores[params.projectId]) return stores[params.projectId];
export function getHeadStore(params: { projectId: string }): WritableLoadable<string> {
const cached = stores[params.projectId];
if (cached) return cached;
const store = asyncWritable([], () =>
get(params).then((head) => head.replace('refs/heads/', ''))
);

View File

@ -18,14 +18,17 @@ export function isUnstaged(status: Status): status is { unstaged: FileStatus } {
return 'unstaged' in status && status.unstaged !== null;
}
export function list(params: { projectId: string }) {
return invoke<Record<string, Status>>('git_status', params);
export function list(params: { projectId: string }): Promise<Statuses> {
return invoke('git_status', params);
}
const stores: Record<string, WritableLoadable<Record<string, Status>>> = {};
type Statuses = Partial<Record<string, Status>>;
export function getStatusStore(params: { projectId: string }) {
if (stores[params.projectId]) return stores[params.projectId];
const stores: Partial<Record<string, WritableLoadable<Statuses>>> = {};
export function getStatusStore(params: { projectId: string }): WritableLoadable<Statuses> {
const cached = stores[params.projectId];
if (cached) return cached;
const store = asyncWritable([], () => list(params));
sessions.subscribe(params, () => list(params).then(store.set));
activities.subscribe(params, () => list(params).then(store.set));

View File

@ -15,8 +15,14 @@ export function isInsert(operation: Operation): operation is OperationInsert {
export type Delta = { timestampMs: number; operations: Operation[] };
export async function list(params: { projectId: string; sessionId: string; paths?: string[] }) {
return invoke<Record<string, Delta[]>>('list_deltas', params);
type Deltas = Partial<Record<string, Delta[]>>;
export async function list(params: {
projectId: string;
sessionId: string;
paths?: string[];
}): Promise<Deltas> {
return invoke('list_deltas', params);
}
export function subscribe(

View File

@ -1,7 +1,7 @@
import { invoke, listen } from '$lib/ipc';
export async function list(params: { projectId: string; sessionId: string; paths?: string[] }) {
return invoke<Record<string, string>>('list_session_files', params);
return invoke<Partial<Record<string, string>>>('list_session_files', params);
}
export function subscribe(

View File

@ -2,7 +2,8 @@
import { collapse } from '$lib/paths';
import { isStaged, isUnstaged, type Status } from '$lib/api/git/statuses';
export let statuses: Record<string, Status>;
export let statuses: Partial<Record<string, Status>>;
$: pairs = Object.entries(statuses) as [string, Status][];
</script>
<div>
@ -23,7 +24,7 @@
<ul
class="rounded border border-yellow-400 bg-yellow-500 p-2 font-mono text-[12px] text-yellow-900"
>
{#each Object.entries(statuses) as [path, status]}
{#each pairs as [path, status]}
<li class="flex w-full gap-2">
<div class="flex w-[3ch] justify-between font-semibold">
<span>

View File

@ -2,10 +2,13 @@ import { writable, type Loadable, derived, Loaded } from 'svelte-loadable-store'
import * as bookmarks from '$lib/api/ipc/bookmarks';
import { get as getValue, type Readable } from '@square/svelte-store';
const stores: Record<string, Readable<Loadable<bookmarks.Bookmark[]>>> = {};
const stores: Partial<Record<string, Readable<Loadable<bookmarks.Bookmark[]>>>> = {};
export function getBookmarksStore(params: { projectId: string }) {
if (params.projectId in stores) return stores[params.projectId];
export function getBookmarksStore(params: {
projectId: string;
}): Readable<Loadable<bookmarks.Bookmark[]>> {
const cached = stores[params.projectId];
if (cached) return cached;
const store = writable(bookmarks.list(params), (set) => {
const unsubscribe = bookmarks.subscribe(params, (bookmark) => {

View File

@ -3,7 +3,7 @@ import * as deltas from '$lib/api/ipc/deltas';
import { get, type Writable } from '@square/svelte-store';
import type { Delta } from '$lib/api/ipc/deltas';
export interface DeltasStore extends Writable<Loadable<Record<string, Delta[]>>> {
export interface DeltasStore extends Writable<Loadable<Partial<Record<string, Delta[]>>>> {
subscribeStream(sessionId: string): () => void;
}
@ -13,7 +13,7 @@ export function getDeltasStore(params: { projectId: string; sessionId: string })
return store;
}
export function getDeltasStore2(projectId: string): DeltasStore {
const store = writable<Record<string, Delta[]>>();
const store = writable<Partial<Record<string, Delta[]>>>();
const subscribe = (sessionId: string) => {
const combinedParams = { sessionId, projectId };
deltas.list(combinedParams).then((results) => {
@ -30,14 +30,11 @@ export function getDeltasStore2(projectId: string): DeltasStore {
if (Loaded.isValue(result)) store.set(result);
});
} else {
oldValue;
store.set({
isLoading: false,
value: {
...oldValue.value,
[filePath]: oldValue.value[filePath]
? [...oldValue.value[filePath], ...newDeltas]
: newDeltas
[filePath]: [...(oldValue.value[filePath] || []), ...newDeltas]
}
});
}

View File

@ -2,11 +2,17 @@ import { writable, type Loadable, Loaded } from 'svelte-loadable-store';
import * as files from '$lib/api/ipc/files';
import { get, type Readable } from '@square/svelte-store';
const stores: Record<string, Readable<Loadable<Record<string, string>>>> = {};
type Files = Partial<Record<string, string>>;
export function getFilesStore(params: { projectId: string; sessionId: string }) {
const stores: Partial<Record<string, Readable<Loadable<Files>>>> = {};
export function getFilesStore(params: {
projectId: string;
sessionId: string;
}): Readable<Loadable<Files>> {
const key = `${params.projectId}/${params.sessionId}`;
if (key in stores) return stores[key];
const cached = stores[key];
if (cached) return cached;
const store = writable(files.list(params), (set) => {
const unsubscribe = files.subscribe(params, ({ filePath, contents }) => {
@ -27,5 +33,5 @@ export function getFilesStore(params: { projectId: string; sessionId: string })
};
});
stores[key] = store;
return store as Readable<Loadable<Record<string, string>>>;
return store as Readable<Loadable<Files>>;
}

View File

@ -3,7 +3,7 @@ import type { Session } from './api/ipc/sessions';
export type UISession = {
session: Session;
deltas: Record<string, Delta[]>;
deltas: Partial<Record<string, Delta[]>>;
earliestDeltaTimestampMs: number;
latestDeltaTimestampMs: number;
};

View File

@ -99,12 +99,12 @@ export async function withFileContent(
.map((branch) => branch.files)
.flat()
.map((file) => file.path);
const sessionFiles = await invoke<Record<string, string>>('list_session_files', {
const sessionFiles = await invoke<Partial<Record<string, string>>>('list_session_files', {
projectId: projectId,
sessionId: sessionId,
paths: filePaths
});
const sessionDeltas = await invoke<Record<string, Delta[]>>('list_deltas', {
const sessionDeltas = await invoke<Partial<Record<string, Delta[]>>>('list_deltas', {
projectId: projectId,
sessionId: sessionId,
paths: filePaths
@ -112,7 +112,7 @@ export async function withFileContent(
const branchesWithContnent = branches.map((branch) => {
branch.files.map((file) => {
const contentAtSessionStart = sessionFiles[file.path] || '';
const ds = sessionDeltas[file.path];
const ds = sessionDeltas[file.path] || [];
file.content = applyDeltas(contentAtSessionStart, ds);
});
return branch;

View File

@ -18,22 +18,20 @@
);
$: deltasByDate = derived(sessionDeltas, (sessionDeltas) =>
sessionDeltas.reduce(
(acc, sessionDelta) => {
Object.entries(sessionDelta).forEach(([filepath, deltas]) => {
const date = startOfDay(new Date(deltas[0].timestampMs)).toString();
if (!acc[date]) acc[date] = {};
if (!acc[date][filepath]) acc[date][filepath] = [];
acc[date][filepath].push(...deltas);
});
return acc;
},
{} as Record<string, Record<string, Delta[]>>
)
sessionDeltas.reduce((acc, sessionDelta) => {
Object.entries(sessionDelta).forEach(([filepath, deltas]) => {
if (!deltas) return;
const date = startOfDay(new Date(deltas[0].timestampMs)).toString();
if (!acc[date]) acc[date] = {};
if (!acc[date][filepath]) acc[date][filepath] = [];
acc[date][filepath].push(...deltas);
});
return acc;
}, {} as Record<string, Record<string, Delta[]>>)
);
$: buckets = derived(sessionDeltas, (sessionDeltas) => {
const deltas = sessionDeltas.flatMap((deltas) => Object.values(deltas).flat());
const deltas = sessionDeltas.flatMap((deltas) => Object.values(deltas).flat() as Delta[]);
const timestamps = deltas.map((delta) => delta.timestampMs);
return generateBuckets(timestamps, 18);
});

View File

@ -13,8 +13,8 @@
export let isCurrent: boolean;
export let session: Session;
export let currentFilepath: string;
export let deltas: Record<string, Delta[]>;
export let files: Record<string, string>;
export let deltas: Partial<Record<string, Delta[]>>;
export let files: Partial<Record<string, string>>;
const applyDeltas = (text: string, deltas: Delta[]) => {
const operations = deltas.flatMap((delta) => delta.operations);
@ -37,8 +37,10 @@
$: stats = Object.entries(deltas)
.map(([path, deltas]) => {
const doc = files[path] ?? '';
const left = deltas.length > 0 ? applyDeltas(doc, deltas.slice(0, deltas.length - 1)) : doc;
const right = deltas.length > 0 ? applyDeltas(left, deltas.slice(deltas.length - 1)) : left;
const left =
deltas && deltas.length > 0 ? applyDeltas(doc, deltas.slice(0, deltas.length - 1)) : doc;
const right =
deltas && deltas.length > 0 ? applyDeltas(left, deltas.slice(deltas.length - 1)) : left;
const diff = line(left.split('\n'), right.split('\n'));
const linesAdded = diff
.filter((d) => d[0] === 1)
@ -56,7 +58,7 @@
if (bookmarks.isLoading) return [];
if (Loaded.isError(bookmarks)) return [];
const timestamps = Object.values(deltas ?? {}).flatMap((deltas) =>
deltas.map((d) => d.timestampMs)
(deltas || []).map((d) => d.timestampMs)
);
const start = Math.min(...timestamps);
const end = Math.max(...timestamps);

View File

@ -12,7 +12,7 @@
import { format } from 'date-fns';
export let sessions: (Session & {
deltas: Readable<Record<string, Delta[]>>;
deltas: Readable<Partial<Record<string, Delta[]>>>;
})[];
export let currentSession: Session;

View File

@ -5,8 +5,8 @@
import SessionCard from './SessionCard.svelte';
export let sessions: (Session & {
deltas: Readable<Record<string, Delta[]>>;
files: Readable<Record<string, string>>;
deltas: Readable<Partial<Record<string, Delta[]>>>;
files: Readable<Partial<Record<string, string>>>;
})[];
export let currentSession: Session | undefined;
export let currentFilepath: string;

View File

@ -42,7 +42,9 @@
deltas: derived(getDeltasStore({ projectId: projectId, sessionId: session.id }), (deltas) =>
Object.entries(deltas)
.filter(([path]) => (filter ? path === filter : true))
.flatMap(([path, deltas]) => deltas.map((delta) => [path, delta] as [string, Delta]))
.flatMap(([path, deltas]) =>
(deltas || []).map((delta) => [path, delta] as [string, Delta])
)
.sort((a, b) => a[1].timestampMs - b[1].timestampMs)
),
files: derived(getFilesStore({ projectId, sessionId: session.id }), (files) =>

View File

@ -10,7 +10,7 @@
export let fullContext: boolean;
export let sessions: Session[];
export let deltas: Readable<Loadable<[string, Delta][][]>>;
export let files: Readable<Loadable<Record<string, string>[]>>;
export let files: Readable<Loadable<Partial<Record<string, string>>[]>>;
export let value: number;
export let frame: Frame | null = null;