274 lines
6.0 KiB
TypeScript

import { sendCommand } from "./client";
import {
normalizeFragment,
type FragmentDto,
type FragmentDtoRaw,
} from "./fragments";
import { pickCase } from "./normalize";
export type ParsedSectionDto = {
title: string;
content: string[];
checkboxes: Record<string, boolean>;
};
export type JournalEntryDto = {
date: string;
fragments: FragmentDto[];
rawContent: string;
sections: Record<string, ParsedSectionDto>;
};
export type EntryListItemDto = {
fileName: string;
filePath: string;
};
export type EntryLoadResultDto = {
fileName: string;
filePath: string;
entry: JournalEntryDto;
};
export type EntrySaveResultDto = {
filePath: string;
};
export type EntrySearchRequestDto = {
dataDirectory: string;
query?: string;
section?: string;
startDate?: string;
endDate?: string;
tags?: string[];
types?: string[];
checked?: string[];
unchecked?: string[];
};
export type EntrySearchResultDto = {
fileName: string;
entry: JournalEntryDto;
};
type ParsedSectionDtoRaw = {
title?: string;
content?: string[];
checkboxes?: Record<string, boolean>;
Title?: string;
Content?: string[];
Checkboxes?: Record<string, boolean>;
};
type JournalEntryDtoRaw = {
date?: string;
fragments?: FragmentDtoRaw[];
rawContent?: string;
sections?: Record<string, ParsedSectionDtoRaw>;
Date?: string;
Fragments?: FragmentDtoRaw[];
RawContent?: string;
Sections?: Record<string, ParsedSectionDtoRaw>;
};
type EntryListItemDtoRaw = {
fileName?: string;
filePath?: string;
FileName?: string;
FilePath?: string;
};
type EntryLoadResultDtoRaw = {
fileName?: string;
filePath?: string;
entry?: JournalEntryDtoRaw;
date?: string;
rawContent?: string;
FileName?: string;
FilePath?: string;
Entry?: JournalEntryDtoRaw;
Date?: string;
RawContent?: string;
};
type EntrySaveResultDtoRaw = {
filePath?: string;
FilePath?: string;
};
type EntrySearchResultDtoRaw = {
fileName?: string;
entry?: JournalEntryDtoRaw;
date?: string;
rawContent?: string;
FileName?: string;
Entry?: JournalEntryDtoRaw;
Date?: string;
RawContent?: string;
};
function normalizeSection(raw: ParsedSectionDtoRaw): ParsedSectionDto {
return {
title: pickCase(raw, "title", "Title", ""),
content: pickCase(raw, "content", "Content", [] as string[]),
checkboxes: pickCase(
raw,
"checkboxes",
"Checkboxes",
{} as Record<string, boolean>,
),
};
}
function normalizeJournalEntry(
raw: JournalEntryDtoRaw | undefined,
): JournalEntryDto {
const fragments = pickCase(
raw,
"fragments",
"Fragments",
[] as FragmentDtoRaw[],
);
const sections = pickCase(
raw,
"sections",
"Sections",
{} as Record<string, ParsedSectionDtoRaw>,
);
return {
date: pickCase(raw, "date", "Date", ""),
fragments: fragments.map(normalizeFragment),
rawContent: pickCase(raw, "rawContent", "RawContent", ""),
sections: Object.fromEntries(
Object.entries(sections).map(([key, value]) => [
key,
normalizeSection(value),
]),
),
};
}
function normalizeEntryListItem(raw: EntryListItemDtoRaw): EntryListItemDto {
return {
fileName: pickCase(raw, "fileName", "FileName", ""),
filePath: pickCase(raw, "filePath", "FilePath", ""),
};
}
function normalizeEntryLoadResult(
raw: EntryLoadResultDtoRaw,
): EntryLoadResultDto {
const nestedEntry = pickCase(
raw,
"entry",
"Entry",
undefined as JournalEntryDtoRaw | undefined,
);
const entry = nestedEntry
? normalizeJournalEntry(nestedEntry)
: normalizeJournalEntry({
date: pickCase(raw, "date", "Date", undefined as string | undefined),
rawContent: pickCase(
raw,
"rawContent",
"RawContent",
undefined as string | undefined,
),
fragments: [],
sections: {},
});
return {
fileName: pickCase(raw, "fileName", "FileName", ""),
filePath: pickCase(raw, "filePath", "FilePath", ""),
entry,
};
}
function normalizeEntrySearchResult(
raw: EntrySearchResultDtoRaw,
): EntrySearchResultDto {
const nestedEntry = pickCase(
raw,
"entry",
"Entry",
undefined as JournalEntryDtoRaw | undefined,
);
const entry = nestedEntry
? normalizeJournalEntry(nestedEntry)
: normalizeJournalEntry({
date: pickCase(raw, "date", "Date", undefined as string | undefined),
rawContent: pickCase(
raw,
"rawContent",
"RawContent",
undefined as string | undefined,
),
fragments: [],
sections: {},
});
return {
fileName: pickCase(raw, "fileName", "FileName", ""),
entry,
};
}
export async function listEntries(
dataDirectory?: string,
): Promise<EntryListItemDto[]> {
const data = await sendCommand<EntryListItemDtoRaw[]>({
action: "entries.list",
payload: { dataDirectory },
});
return data
.map(normalizeEntryListItem)
.filter((item) => Boolean(item.filePath));
}
export async function loadEntry(filePath: string): Promise<EntryLoadResultDto> {
const data = await sendCommand<EntryLoadResultDtoRaw>({
action: "entries.load",
payload: { filePath },
});
return normalizeEntryLoadResult(data);
}
export async function saveEntry(payload: {
content: string;
filePath?: string;
mode?: string;
fileName?: string;
}): Promise<EntrySaveResultDto> {
const data = await sendCommand<EntrySaveResultDtoRaw>({
action: "entries.save",
payload,
});
return {
filePath: pickCase(data, "filePath", "FilePath", ""),
};
}
export async function deleteEntry(filePath: string): Promise<boolean> {
return sendCommand<boolean>({
action: "entries.delete",
payload: { filePath },
});
}
export async function searchEntries(
payload: EntrySearchRequestDto,
): Promise<EntrySearchResultDto[]> {
const data = await sendCommand<EntrySearchResultDtoRaw[]>({
action: "search.entries",
payload,
});
return data
.map(normalizeEntrySearchResult)
.filter((item) => Boolean(item.fileName));
}