diff --git a/src/index.ts b/src/index.ts index 831af79..259288f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,14 @@ import joplin from 'api'; +import { fetchAllNotes } from './notesFetcher'; joplin.plugins.register({ onStart: async function() { - // eslint-disable-next-line no-console - console.info('Hello world. Test plugin started!'); + try { const notes = await fetchAllNotes(); + // eslint-disable-next-line no-console + console.info(`Note Graph Plugin started. Total notes fetched: ${notes.length}`); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error fetching notes:', error); + } }, }); diff --git a/src/notesFetcher.ts b/src/notesFetcher.ts new file mode 100644 index 0000000..343b606 --- /dev/null +++ b/src/notesFetcher.ts @@ -0,0 +1,101 @@ +import joplin from 'api'; + +export interface Note { + id: string; + title: string; + body: string; + parent_id: string; + created_time: number; + updated_time: number; + tags: Tag[]; + links: string[]; +} + +export interface Tag { + id: string; + title: string; + created_time: number; + updated_time: number; +} + +function extractLinks(body: string): string[] { + const linkPattern = new RegExp(':/([a-f0-9]{32})', 'g'); + const matches: string[] = []; + let match; + while ((match = linkPattern.exec(body)) !== null) { + matches.push(match[1]); + } + return matches; +} + +async function buildNoteTagsMap(): Promise> { + const noteTagsMap = new Map(); + + const tagsResponse = await joplin.data.get(['tags']); + const allTags = tagsResponse.items || []; + + for (const tag of allTags) { + const notesResponse = await joplin.data.get(['tags', tag.id, 'notes']); + for (const note of notesResponse.items || []) { + if (!noteTagsMap.has(note.id)) { + noteTagsMap.set(note.id, []); + } + noteTagsMap.get(note.id)!.push(tag); + } + } + + return noteTagsMap; +} + +export async function fetchAllNotes(): Promise { + const noteTagsMap = await buildNoteTagsMap(); + const notes: Note[] = []; + const fields = ['id', 'title', 'body', 'parent_id', 'created_time', 'updated_time']; + let page = 1; + let hasMore = true; + + while (hasMore) { + const response = await joplin.data.get(['notes'], { + fields, + limit: 100, + page, + }); + + for (const note of response.items) { + const tags = noteTagsMap.get(note.id) || []; + const links = extractLinks(note.body); + notes.push({ + ...note, + tags, + links, + }); + } + + hasMore = response.has_more; + page++; + } + + return notes; +} + +export async function getAllTags(): Promise { + const response = await joplin.data.get(['tags']); + return response.items || []; +} + +export async function getNotesWithTag(tagId: string): Promise { + const noteTagsMap = await buildNoteTagsMap(); + const response = await joplin.data.get(['tags', tagId, 'notes']); + const tagNotes: Note[] = []; + + for (const note of response.items || []) { + const links = extractLinks(note.body); + tagNotes.push({ + ...note, + tags: noteTagsMap.get(note.id) || [], + links, + }); + } + + return tagNotes; +} \ No newline at end of file