Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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);
}
},
});
101 changes: 101 additions & 0 deletions src/notesFetcher.ts
Original file line number Diff line number Diff line change
@@ -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<Map<string, Tag[]>> {
const noteTagsMap = new Map<string, Tag[]>();

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<Note[]> {
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<Tag[]> {
const response = await joplin.data.get(['tags']);
return response.items || [];
}

export async function getNotesWithTag(tagId: string): Promise<Note[]> {
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;
}