Skip to content

Commit 2af3b21

Browse files
Significant refactor
1 parent a19305f commit 2af3b21

File tree

1 file changed

+76
-61
lines changed

1 file changed

+76
-61
lines changed

src/main.ts

Lines changed: 76 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Notice, Plugin, TFile, Vault } from "obsidian";
1+
import { Notice, Plugin, TFile } from "obsidian";
22
import {
33
DEFAULT_SETTINGS,
44
AnkiLinkSettings,
@@ -13,6 +13,12 @@ interface ParsedNoteData {
1313
note: Note
1414
}
1515

16+
interface NoteSyncResult {
17+
added: number;
18+
linesModified: boolean;
19+
lines: string[];
20+
}
21+
1622
export default class AnkiLink extends Plugin {
1723
settings!: AnkiLinkSettings;
1824

@@ -59,85 +65,94 @@ export default class AnkiLink extends Plugin {
5965
await this.saveData(this.settings);
6066
}
6167

68+
/**
69+
* Sync all notes from all markdown files in the vault.
70+
* @returns The number of notes added
71+
*/
6272
async syncNotes(): Promise<number> {
63-
const { vault } = this.app;
64-
65-
const markdownFiles = vault.getMarkdownFiles();
73+
const markdownFiles = this.app.vault.getMarkdownFiles();
6674
await this.addMissingDecks();
6775

6876
let totalAdded = 0;
69-
const fileLines = await this.readFiles(vault, markdownFiles);
70-
const fileNoteData = await this.extractNoteData(fileLines);
7177
for (const file of markdownFiles) {
72-
let linesModified = false;
73-
const notesData = fileNoteData.get(file);
74-
const lines = fileLines.get(file);
75-
if (!notesData || !lines) {
76-
continue;
77-
}
78-
const notesWithNoId = [];
79-
const notesWithId = [];
80-
for (const note of notesData) {
81-
if (note.id == undefined) {
82-
notesWithNoId.push(note);
83-
} else {
84-
notesWithId.push(note);
85-
}
86-
}
87-
for (const noteData of notesData) {
88-
if (noteData.id == undefined) {
89-
noteData.id = await this.sendNote(noteData.note);
90-
lines[noteData.index] = `> [!flashcard] %%${noteData.id}%% ${noteData.note.fields.Front}`;
91-
linesModified = true;
92-
totalAdded += 1;
93-
} else {
94-
const ankiNote = await getNoteById(noteData.id);
95-
if (ankiNote) {
96-
const obsidianFields = noteData.note.fields;
97-
const ankiFields = ankiNote.fields;
98-
if (obsidianFields.Front !== ankiFields.Front.value || obsidianFields.Back !== ankiFields.Back.value) {
99-
await updateNoteById(ankiNote.noteId, obsidianFields);
100-
}
101-
} else {
102-
// Missing note for this ID in Anki (notesInfo returned [] or [{}]). Recreate it.
103-
const newId = await this.sendNote(noteData.note);
104-
noteData.id = newId;
105-
lines[noteData.index] = `> [!flashcard] %%${newId}%% ${noteData.note.fields.Front}`;
106-
linesModified = true;
107-
totalAdded += 1;
108-
}
109-
}
110-
}
111-
if (linesModified) {
112-
fileLines.set(file, lines);
113-
await vault.modify(file, lines.join("\n"));
114-
}
78+
const added = await this.syncSingleFile(file);
79+
totalAdded += added;
11580
}
11681
return totalAdded;
11782
}
11883

119-
private async extractNoteData(fileLines: Map<TFile, string[]>) {
120-
const fileNoteData = new Map<TFile, ParsedNoteData[]>();
121-
for (const [file, lines] of fileLines) {
122-
fileNoteData.set(file, this.parseDocument(lines))
84+
/**
85+
* Sync all notes from a document. Updates the document lines to include the new note IDs.
86+
* @param file The document to sync
87+
* @returns The number of notes added
88+
*/
89+
private async syncSingleFile(file: TFile): Promise<number> {
90+
const originalLines = (await this.app.vault.read(file)).split("\n");
91+
const notesData = this.parseDocument(originalLines);
92+
if (notesData.length === 0) return 0;
93+
94+
let totalAdded = 0;
95+
let linesModified = false;
96+
let lines = originalLines;
97+
for (const noteData of notesData) {
98+
const result = await this.syncSingleNote(noteData, lines);
99+
totalAdded += result.added;
100+
linesModified = result.linesModified;
101+
lines = result.lines;
123102
}
124-
return fileNoteData;
103+
104+
if (linesModified) {
105+
await this.app.vault.modify(file, lines.join("\n"));
106+
}
107+
return totalAdded;
125108
}
126109

127-
private async readFiles(vault: Vault, files: TFile[]) {
128-
const fileLines = new Map<TFile, string[]>();
129-
for (const file of files) {
130-
const lines = (await vault.read(file)).split("\n");
131-
fileLines.set(file, lines);
110+
/**
111+
* Sync a single extracted note from a document.
112+
* @param noteData The note data to sync
113+
* @param lines The lines of the document
114+
* @returns The note sync result
115+
*/
116+
private async syncSingleNote(noteData: ParsedNoteData, lines: string[]): Promise<NoteSyncResult> {
117+
if (noteData.id == undefined) {
118+
return this.createAndWriteNoteId(noteData, lines);
119+
}
120+
121+
const ankiNote = await getNoteById(noteData.id);
122+
if (!ankiNote) {
123+
// Missing note for this ID in Anki (notesInfo returned [] or [{}]). Recreate it.
124+
return this.createAndWriteNoteId(noteData, lines);
125+
}
126+
127+
const obsidianFields = noteData.note.fields;
128+
const ankiFields = ankiNote.fields;
129+
if (obsidianFields.Front !== ankiFields.Front.value || obsidianFields.Back !== ankiFields.Back.value) {
130+
await updateNoteById(ankiNote.noteId, obsidianFields);
132131
}
133-
return fileLines;
132+
return { added: 0, linesModified: false, lines };
134133
}
135134

135+
/**
136+
* Create a new note in Anki and update document lines to include the new note ID.
137+
* @param noteData The note data to create
138+
* @param lines The lines of the document
139+
* @returns The note sync result
140+
*/
141+
private async createAndWriteNoteId(noteData: ParsedNoteData, lines: string[]): Promise<NoteSyncResult> {
142+
const newId = await this.sendNote(noteData.note);
143+
const updatedLines = [...lines];
144+
updatedLines[noteData.index] = `> [!flashcard] %%${newId}%% ${noteData.note.fields.Front}`;
145+
return { added: 1, linesModified: true, lines: updatedLines };
146+
}
147+
148+
/**
149+
* Check if the target deck exists in Anki and create it if it doesn't.
150+
*/
136151
private async addMissingDecks() {
137152
const deckNamesRes = await sendDeckNamesRequest();
138153
if (deckNamesRes.error) throw new Error(`AnkiConnect: ${deckNamesRes.error}`)
139154
const decks = deckNamesRes.result;
140-
if (!decks.contains(TARGET_DECK)) {
155+
if (!decks.includes(TARGET_DECK)) {
141156
const createDeckRes = await sendCreateDeckRequest(TARGET_DECK);
142157
if (createDeckRes.error) throw new Error(`AnkiConnect: ${createDeckRes.error}`)
143158
}

0 commit comments

Comments
 (0)