From a76650d656fcd1648f0691a5eed0645c671ddebe Mon Sep 17 00:00:00 2001 From: Antonio Date: Sat, 4 May 2024 22:41:36 +0300 Subject: [PATCH] refactor(core): split functionality for better testability --- main.ts | 53 ++++---------------------- package.json | 4 ++ src/db/seed.ts | 8 ++-- src/methods/saveHighlightsToVault.ts | 56 ++++++++++++++++++++++++++++ src/search.ts | 2 +- src/settings.ts | 42 ++++++++++++--------- src/{types/index.ts => types.ts} | 7 ---- styles.css | 6 ++- 8 files changed, 102 insertions(+), 76 deletions(-) create mode 100644 src/methods/saveHighlightsToVault.ts rename src/{types/index.ts => types.ts} (85%) diff --git a/main.ts b/main.ts index 05939d8..2a26795 100644 --- a/main.ts +++ b/main.ts @@ -1,19 +1,16 @@ -import { normalizePath, Notice, Plugin } from 'obsidian'; -import path from 'path'; -import { DEFAULT_SETTINGS, IBookHighlightsSettingTab } from './src/settings'; +import { Notice, Plugin } from 'obsidian'; import { IBookHighlightsPluginSearchModal } from './src/search'; -import { - ICombinedBooksAndHighlights, - IBookHighlightsPluginSettings -} from './src/types'; import { aggregateBookAndHighlightDetails } from './src/methods/aggregateDetails'; -import { renderHighlightsTemplate } from './src/methods/renderHighlightsTemplate'; +import SaveHighlights from './src/methods/saveHighlightsToVault'; +import { AppleBooksHighlightsImportPluginSettings, IBookHighlightsSettingTab } from './src/settings'; export default class IBookHighlightsPlugin extends Plugin { - settings: IBookHighlightsPluginSettings; + settings: AppleBooksHighlightsImportPluginSettings; + saveHighlights: SaveHighlights; async onload() { const settings = await this.loadSettings(); + this.saveHighlights = new SaveHighlights(this.app, settings); if (settings.importOnStart) { await this.aggregateAndSaveHighlights(); @@ -25,7 +22,6 @@ export default class IBookHighlightsPlugin extends Plugin { }).catch((error) => { new Notice(`[${this.manifest.name}]:\nError importing highlights. Check console for details (⌥ ⌘ I)`, 0); console.error(`[${this.manifest.name}]: ${error}`); - }); }); @@ -62,7 +58,7 @@ export default class IBookHighlightsPlugin extends Plugin { onunload() { } async loadSettings() { - this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + this.settings = Object.assign(new AppleBooksHighlightsImportPluginSettings(), await this.loadData()); return this.settings; } @@ -78,39 +74,6 @@ export default class IBookHighlightsPlugin extends Plugin { throw ('No highlights found. Make sure you made some highlights in your Apple Books.'); } - await this.saveHighlightsToVault(highlights); - } - - async saveHighlightsToVault(highlights: ICombinedBooksAndHighlights[]) { - const highlightsFolderPath = this.app.vault.getAbstractFileByPath(this.settings.highlightsFolder); - const isBackupEnabled = this.settings.backup; - - // Backup highlights folder if backup is enabled - if (highlightsFolderPath) { - if (isBackupEnabled) { - const highlightsFilesToBackup = (await this.app.vault.adapter.list(highlightsFolderPath.path)).files; - const highlightsBackupFolder = `${this.settings.highlightsFolder}-bk-${Date.now()}`; - - await this.app.vault.createFolder(highlightsBackupFolder); - - highlightsFilesToBackup.forEach(async (file: string) => { - const fileName = path.basename(file); - await this.app.vault.adapter.copy(normalizePath(file), normalizePath(path.join(highlightsBackupFolder, fileName))); - }); - } - await this.app.vault.delete(highlightsFolderPath, true); - } - - await this.app.vault.createFolder(this.settings.highlightsFolder); - - - highlights.forEach(async (highlight: ICombinedBooksAndHighlights) => { - const renderedTemplate = await renderHighlightsTemplate(highlight, this.settings.template); - - await this.app.vault.create( - normalizePath(path.join(this.settings.highlightsFolder, `${highlight.bookTitle}.md`)), - renderedTemplate - ); - }); + await this.saveHighlights.saveHighlightsToVault(highlights); } } diff --git a/package.json b/package.json index f6e5838..af28a51 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,10 @@ "type": "git", "url": "git+https://github.com/bandantonio/obsidian-apple-books-highlights-plugin.git" }, + "engines": { + "node": ">=20.8.0", + "npm": ">=10.0.0" + }, "devDependencies": { "@types/better-sqlite3": "^7.6.10", "@types/node": "^18.4.1", diff --git a/src/db/seed.ts b/src/db/seed.ts index d34f756..d449ec9 100644 --- a/src/db/seed.ts +++ b/src/db/seed.ts @@ -8,16 +8,16 @@ const db = drizzle(sqlite); export const seedDatabase = async (table: typeof bookLibrary | typeof annotations, seed: any[]) => { const tableName = (table === bookLibrary) ? 'books' : 'annotations'; console.log(`Seeding ${tableName} database...`); - + try { await db.delete(table); - + await db.insert(table).values(seed); } catch (error) { console.error(error); process.exit(1); } - + console.log(`Seeding ${tableName} successful`); - + }; diff --git a/src/methods/saveHighlightsToVault.ts b/src/methods/saveHighlightsToVault.ts new file mode 100644 index 0000000..0c28f21 --- /dev/null +++ b/src/methods/saveHighlightsToVault.ts @@ -0,0 +1,56 @@ +import { App, Vault } from 'obsidian'; +import path from 'path'; +import { ICombinedBooksAndHighlights } from '../types'; +import { AppleBooksHighlightsImportPluginSettings } from '../settings'; +import { renderHighlightsTemplate } from './renderHighlightsTemplate'; + +export default class SaveHighlights { + private app: App; + private vault: Vault; + private settings: AppleBooksHighlightsImportPluginSettings; + + constructor(app: App, settings: AppleBooksHighlightsImportPluginSettings) { + this.app = app; + this.vault = this.app.vault; + this.settings = settings; + } + + async saveHighlightsToVault(highlights: ICombinedBooksAndHighlights[]): Promise { + const highlightsFolderPath = this.vault.getAbstractFileByPath( + this.settings.highlightsFolder + ); + + const isBackupEnabled = this.settings.backup; + + // // Backup highlights folder if backup is enabled + if (highlightsFolderPath) { + if (isBackupEnabled) { + const highlightsFilesToBackup = (await this.vault.adapter.list(highlightsFolderPath.path)).files; + + const highlightsBackupFolder = `${this.settings.highlightsFolder}-bk-${Date.now()}`; + + await this.vault.createFolder(highlightsBackupFolder); + + highlightsFilesToBackup.forEach(async (file: string) => { + const fileName = path.basename(file); + + await this.vault.adapter.copy(file, path.join(highlightsBackupFolder, fileName)) + }); + } + + await this.vault.delete(highlightsFolderPath, true); + } + + await this.vault.createFolder(this.settings.highlightsFolder); + + highlights.forEach(async (highlight: ICombinedBooksAndHighlights) => { + const renderedTemplate = await renderHighlightsTemplate(highlight, this.settings.template); + const filePath = path.join(this.settings.highlightsFolder, `${highlight.bookTitle}.md`); + + await this.vault.create( + filePath, + renderedTemplate + ); + }); + } +} diff --git a/src/search.ts b/src/search.ts index c9376cc..1976265 100644 --- a/src/search.ts +++ b/src/search.ts @@ -37,6 +37,6 @@ export class IBookHighlightsPluginSearchModal extends IBookHighlightsPluginSugge //eslint-disable-next-line onChooseSuggestion(item: ICombinedBooksAndHighlights, event: MouseEvent | KeyboardEvent) { - this.plugin.saveHighlightsToVault([item]); + this.plugin.saveHighlights.saveHighlightsToVault([item]); } } diff --git a/src/settings.ts b/src/settings.ts index c71d11d..1949fbc 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,16 +1,15 @@ import { App, Notice, PluginSettingTab, Setting } from 'obsidian'; import IBookHighlightsPlugin from '../main'; import defaultTemplate from './template'; -import { IBookHighlightsPluginSettings } from './types'; -export const DEFAULT_SETTINGS: IBookHighlightsPluginSettings = { - highlightsFolder: 'ibooks-highlights', - backup: false, - importOnStart: false, - template: defaultTemplate, +export class AppleBooksHighlightsImportPluginSettings { + highlightsFolder: string = 'ibooks-highlights'; + backup: boolean = false; + importOnStart: boolean = false; + template: string = defaultTemplate; } -class IBookHighlightsSettingTab extends PluginSettingTab { +export class IBookHighlightsSettingTab extends PluginSettingTab { plugin: IBookHighlightsPlugin; constructor(app: App, plugin: IBookHighlightsPlugin) { @@ -23,16 +22,24 @@ class IBookHighlightsSettingTab extends PluginSettingTab { containerEl.empty(); - new Setting(containerEl) + const folder = new Setting(containerEl) .setName('Highlights folder') .setDesc('A folder (within the root of your vault) where you want to save imported highlights') - .addText(text => text - .setPlaceholder('Folder to save highlights') - .setValue(this.plugin.settings.highlightsFolder) - .onChange(async (value) => { - this.plugin.settings.highlightsFolder = value; - await this.plugin.saveSettings(); - })); + .setClass('ibooks-highlights-folder') + + folder.addText(text => text + .setPlaceholder('Folder to save highlights') + .setValue(this.plugin.settings.highlightsFolder) + .onChange(async (value) => { + if (!value) { + folder.controlEl.addClass('setting-error'); + return; + } + + folder.controlEl.removeClass('setting-error'); + this.plugin.settings.highlightsFolder = value; + await this.plugin.saveSettings(); + })); new Setting(containerEl) .setName('Import highlights on start') @@ -44,7 +51,7 @@ class IBookHighlightsSettingTab extends PluginSettingTab { await this.plugin.saveSettings(); }); }); - + new Setting(containerEl) .setName('Backup highlights') .setDesc('Backup highlights folder before import. Backup folder template: -bk- (For example, ibooks-highlights-bk-1704060001)') @@ -62,7 +69,7 @@ class IBookHighlightsSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Template') .setDesc('Template for highlight files') - .setClass("ibooks-highlights-template") + .setClass('ibooks-highlights-template') .addTextArea((text) => { text .setPlaceholder('Template') @@ -97,4 +104,3 @@ class IBookHighlightsSettingTab extends PluginSettingTab { } } -export { IBookHighlightsSettingTab } \ No newline at end of file diff --git a/src/types/index.ts b/src/types.ts similarity index 85% rename from src/types/index.ts rename to src/types.ts index 2ccfe6c..08f8d8c 100644 --- a/src/types/index.ts +++ b/src/types.ts @@ -1,10 +1,3 @@ -export interface IBookHighlightsPluginSettings { - highlightsFolder: string; - template: string; - backup: boolean; - importOnStart: boolean; -} - export interface IBook { ZASSETID: string; ZTITLE: string; diff --git a/styles.css b/styles.css index 472b5ed..118dda0 100644 --- a/styles.css +++ b/styles.css @@ -2,4 +2,8 @@ width: 100%; height: 350px; overflow: auto; -} \ No newline at end of file +} + +.ibooks-highlights-folder > .setting-item-control.setting-error > input { + border-color: #b00; +}