From 32df16b517df20408014b86b2859417604d09f94 Mon Sep 17 00:00:00 2001 From: Yugal Kaushik Date: Mon, 18 May 2026 20:14:23 +0530 Subject: [PATCH 1/2] fetches note, tags and links --- src/index.ts | 10 ++++-- src/notesFetcher.ts | 86 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/notesFetcher.ts 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..f47d7f2 --- /dev/null +++ b/src/notesFetcher.ts @@ -0,0 +1,86 @@ +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 fetchTagsForNote(noteId: string): Promise { + const response = await joplin.data.get(['notes', noteId, 'tags']); + return response.items || []; +} + +export async function fetchAllNotes(): Promise { + 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 = await fetchTagsForNote(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 response = await joplin.data.get(['tags', tagId, 'notes']); + const tagNotes: Note[] = []; + + for (const note of response.items || []) { + const tags = await fetchTagsForNote(note.id); + const links = extractLinks(note.body); + tagNotes.push({ + ...note, + tags, + links, + }); + } + + return tagNotes; +} \ No newline at end of file From 97dbdfe2203f087bbeee98f1c2d989082438e64f Mon Sep 17 00:00:00 2001 From: Yugal Kaushik Date: Tue, 19 May 2026 13:39:30 +0530 Subject: [PATCH 2/2] updates logic --- src/notesFetcher.ts | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/notesFetcher.ts b/src/notesFetcher.ts index f47d7f2..343b606 100644 --- a/src/notesFetcher.ts +++ b/src/notesFetcher.ts @@ -28,12 +28,27 @@ function extractLinks(body: string): string[] { return matches; } -async function fetchTagsForNote(noteId: string): Promise { - const response = await joplin.data.get(['notes', noteId, 'tags']); - return response.items || []; +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; @@ -47,7 +62,7 @@ export async function fetchAllNotes(): Promise { }); for (const note of response.items) { - const tags = await fetchTagsForNote(note.id); + const tags = noteTagsMap.get(note.id) || []; const links = extractLinks(note.body); notes.push({ ...note, @@ -69,15 +84,15 @@ export async function getAllTags(): Promise { } 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 tags = await fetchTagsForNote(note.id); const links = extractLinks(note.body); tagNotes.push({ ...note, - tags, + tags: noteTagsMap.get(note.id) || [], links, }); }