diff --git a/.gitignore b/.gitignore index 8173ea1..8dc6a8f 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ node_modules # tests coverage -test/mocks/testDatabase.sqlite # Don't include the compiled main.js file in the repo. # They should be uploaded to GitHub releases instead. main.js diff --git a/README.md b/README.md index d152c92..3f1de3a 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ The plugin uses Handlebars and Markdown to customize the output of your highligh - If you highlight parts of two adjacent sentences, the `contextualText` will contain both sentences. - `{{{highlight}}}` - The highlighted text. - `{{{note}}}` - A note you added for the highlight. + - `{{{highlightLocation}}}` - A unique identifier of the highlighted text. It is used to create a link to the highlighted text in Apple Books. For example: `[Apple Books Highlight Link](ibooks://assetid/{{bookId}}#{{highlightLocation}})`. - `{{highlightStyle}}` - The style of the highlight. It can be one of the following values: - `0` (underline) - `1` (green) diff --git a/migrations/0001_marvelous_mentallo.sql b/migrations/0001_marvelous_mentallo.sql new file mode 100644 index 0000000..890215a --- /dev/null +++ b/migrations/0001_marvelous_mentallo.sql @@ -0,0 +1 @@ +ALTER TABLE ZAEANNOTATION ADD `ZANNOTATIONLOCATION` text; \ No newline at end of file diff --git a/migrations/meta/0001_snapshot.json b/migrations/meta/0001_snapshot.json new file mode 100644 index 0000000..930a422 --- /dev/null +++ b/migrations/meta/0001_snapshot.json @@ -0,0 +1,151 @@ +{ + "version": "5", + "dialect": "sqlite", + "id": "0e719ef5-4a90-4b4c-8245-5cf855c5b3f1", + "prevId": "9ab8f1f7-710a-4b2c-9ba7-b286cb403847", + "tables": { + "ZAEANNOTATION": { + "name": "ZAEANNOTATION", + "columns": { + "ZANNOTATIONASSETID": { + "name": "ZANNOTATIONASSETID", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZFUTUREPROOFING5": { + "name": "ZFUTUREPROOFING5", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONREPRESENTATIVETEXT": { + "name": "ZANNOTATIONREPRESENTATIVETEXT", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONSELECTEDTEXT": { + "name": "ZANNOTATIONSELECTEDTEXT", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ZANNOTATIONLOCATION": { + "name": "ZANNOTATIONLOCATION", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONNOTE": { + "name": "ZANNOTATIONNOTE", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONCREATIONDATE": { + "name": "ZANNOTATIONCREATIONDATE", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONMODIFICATIONDATE": { + "name": "ZANNOTATIONMODIFICATIONDATE", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONSTYLE": { + "name": "ZANNOTATIONSTYLE", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZANNOTATIONDELETED": { + "name": "ZANNOTATIONDELETED", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "ZBKLIBRARYASSET": { + "name": "ZBKLIBRARYASSET", + "columns": { + "ZASSETID": { + "name": "ZASSETID", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZTITLE": { + "name": "ZTITLE", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZAUTHOR": { + "name": "ZAUTHOR", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZGENRE": { + "name": "ZGENRE", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZLANGUAGE": { + "name": "ZLANGUAGE", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZLASTOPENDATE": { + "name": "ZLASTOPENDATE", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ZCOVERURL": { + "name": "ZCOVERURL", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index c00c08f..c0b2aaa 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -8,6 +8,13 @@ "when": 1713726520358, "tag": "0000_outstanding_wolf_cub", "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1720611694414, + "tag": "0001_marvelous_mentallo", + "breakpoints": true } ] } \ No newline at end of file diff --git a/preview.png b/preview.png index be57c44..eb55059 100644 Binary files a/preview.png and b/preview.png differ diff --git a/src/db/constants.ts b/src/db/constants.ts index 9764d28..324476b 100644 --- a/src/db/constants.ts +++ b/src/db/constants.ts @@ -19,6 +19,7 @@ export const HIGHLIGHTS_LIBRARY_COLUMNS = [ 'ZFUTUREPROOFING5', 'ZANNOTATIONREPRESENTATIVETEXT', 'ZANNOTATIONSELECTEDTEXT', + 'ZANNOTATIONLOCATION', 'ZANNOTATIONNOTE', 'ZANNOTATIONCREATIONDATE', 'ZANNOTATIONMODIFICATIONDATE', diff --git a/src/db/schemas.ts b/src/db/schemas.ts index 49596e8..a800810 100644 --- a/src/db/schemas.ts +++ b/src/db/schemas.ts @@ -17,6 +17,7 @@ export const annotations = sqliteTable(HIGHLIGHTS_LIBRARY_NAME, { ZFUTUREPROOFING5: text('ZFUTUREPROOFING5'), ZANNOTATIONREPRESENTATIVETEXT: text('ZANNOTATIONREPRESENTATIVETEXT'), ZANNOTATIONSELECTEDTEXT: text('ZANNOTATIONSELECTEDTEXT').notNull(), + ZANNOTATIONLOCATION: text('ZANNOTATIONLOCATION'), ZANNOTATIONNOTE: text('ZANNOTATIONNOTE'), ZANNOTATIONCREATIONDATE: integer('ZANNOTATIONCREATIONDATE'), ZANNOTATIONMODIFICATIONDATE: integer('ZANNOTATIONMODIFICATIONDATE'), diff --git a/src/db/seedData.ts b/src/db/seedData.ts index 90d3085..cdce389 100644 --- a/src/db/seedData.ts +++ b/src/db/seedData.ts @@ -37,6 +37,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPhone User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the iPhone User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-iphone-user-guide", "ZANNOTATIONNOTE": "Test note for the hightlight from the iPhone User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -47,6 +48,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPad User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the iPad User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-ipad-user-guide", "ZANNOTATIONNOTE": "Test note for the hightlight from the iPad User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -57,6 +59,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Mac User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the Mac User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-mac-user-guide", "ZANNOTATIONNOTE": "Test note for the hightlight from the Mac User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -67,6 +70,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Apple Watch User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the Apple Watch User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-apple-watch-user-guide", "ZANNOTATIONNOTE": "Test note for the hightlight from the Apple Watch User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -77,6 +81,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPhone User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the iPhone User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-iphone-user-guide", "ZANNOTATIONNOTE": "Test note for the deleted hightlight from the iPhone User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -87,6 +92,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPad User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the iPad User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-ipad-user-guide", "ZANNOTATIONNOTE": "Test note for the deleted hightlight from the iPad User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -97,6 +103,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Mac User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the Mac User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-mac-user-guide", "ZANNOTATIONNOTE": "Test note for the deleted hightlight from the Mac User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, @@ -107,6 +114,7 @@ export const defaultAnnotations = [{ "ZFUTUREPROOFING5": "Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Apple Watch User Guide", "ZANNOTATIONSELECTEDTEXT": "hightlight from the Apple Watch User Guide", + "ZANNOTATIONLOCATION": "test-highlight-link-from-the-apple-watch-user-guide", "ZANNOTATIONNOTE": "Test note for the deleted hightlight from the Apple Watch User Guide", "ZANNOTATIONCREATIONDATE": 685151385.91602, "ZANNOTATIONMODIFICATIONDATE": 685151385.91602, diff --git a/src/methods/aggregateDetails.ts b/src/methods/aggregateDetails.ts index bc584e8..013c6bb 100644 --- a/src/methods/aggregateDetails.ts +++ b/src/methods/aggregateDetails.ts @@ -33,6 +33,7 @@ export const aggregateBookAndHighlightDetails = async (): Promise { expect(highlights[0].ZANNOTATIONNOTE).toEqual('Test note for the hightlight from the iPhone User Guide'); expect(highlights[3].ZANNOTATIONREPRESENTATIVETEXT).toEqual('This is a contextual text for the hightlight from the Apple Watch User Guide'); }); + + test('Should return a highlight link for each highlight when highlights library is not empty', async () => { + await seedDatabase(annotations, defaultAnnotations); + + const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH); + const highlights = await annotationsRequest(dbPath, `SELECT * FROM ${HIGHLIGHTS_LIBRARY_NAME} WHERE ZANNOTATIONDELETED = 0`); + + expect(highlights.length).toEqual(4); + expect(highlights[0].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-iphone-user-guide'); + expect(highlights[1].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-ipad-user-guide'); + expect(highlights[2].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-mac-user-guide'); + expect(highlights[3].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-apple-watch-user-guide'); + }); }); describe('Database load testing', () => { @@ -89,6 +102,7 @@ describe('Database load testing', () => { ZFUTUREPROOFING5: `Introduction ${j}`, ZANNOTATIONREPRESENTATIVETEXT: `This is a contextual text for the hightlight from the Book ${i}`, ZANNOTATIONSELECTEDTEXT: `hightlight from the Book ${i}`, + ZANNOTATIONLOCATION: `test-highlight-link-from-the-book-${i}`, ZANNOTATIONNOTE: `Test note for the hightlight from the Book ${i}`, ZANNOTATIONCREATIONDATE: 685151385.91602, ZANNOTATIONMODIFICATIONDATE: 685151385.91602, @@ -110,6 +124,9 @@ describe('Database load testing', () => { expect(dbBooks.length).toEqual(1000); expect(dbAnnotations.length).toEqual(3000); + const dbAnnotationLocations = dbAnnotations.filter(({ZANNOTATIONLOCATION}) => ZANNOTATIONLOCATION !== null && ZANNOTATIONLOCATION !== undefined); + expect(dbAnnotationLocations.length).toEqual(3000); + expect(endTime - startTime).toBeLessThan(500); }); }); diff --git a/test/mocks/aggregatedDetailsData.ts b/test/mocks/aggregatedDetailsData.ts index 8459df7..49bd7f0 100644 --- a/test/mocks/aggregatedDetailsData.ts +++ b/test/mocks/aggregatedDetailsData.ts @@ -13,6 +13,7 @@ export const annotationsToAggregate = [{ "ZFUTUREPROOFING5": "Aggregated Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide", "ZANNOTATIONSELECTEDTEXT": "aggregated hightlight from the Apple iPhone User Guide", + "ZANNOTATIONLOCATION": "aggregated-highlight-link-from-the-apple-iphone-user-guide", "ZANNOTATIONNOTE": "Test note for the aggregated hightlight from the Apple iPhone User Guide", "ZANNOTATIONCREATIONDATE": 731876693.002279, "ZANNOTATIONMODIFICATIONDATE": 731876693.002279, @@ -23,6 +24,7 @@ export const annotationsToAggregate = [{ "ZFUTUREPROOFING5": "Another aggregated Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation", "ZANNOTATIONSELECTEDTEXT": "aggregated hightlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation", + "ZANNOTATIONLOCATION": "aggregated-highlight-link-from-the-apple-iphone-user-guide", "ZANNOTATIONNOTE": "Test note for the aggregated hightlight from the Apple iPhone User Guide\n\nalong with a new line to test the preservation of indentation", "ZANNOTATIONCREATIONDATE": 731876693.002279, "ZANNOTATIONMODIFICATIONDATE": 731876693.002279, @@ -43,6 +45,7 @@ export const aggregatedHighlights = [{ "contextualText": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide", "highlight": "aggregated hightlight from the Apple iPhone User Guide", "note": "Test note for the aggregated hightlight from the Apple iPhone User Guide", + "highlightLocation": "aggregated-highlight-link-from-the-apple-iphone-user-guide", "highlightStyle": 3, "highlightCreationDate": 731876693.002279, "highlightModificationDate": 731876693.002279 @@ -51,6 +54,7 @@ export const aggregatedHighlights = [{ "contextualText": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation", "highlight": "aggregated hightlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation", "note": "Test note for the aggregated hightlight from the Apple iPhone User Guide\nalong with a new line to test the preservation of indentation", + "highlightLocation": "aggregated-highlight-link-from-the-apple-iphone-user-guide", "highlightStyle": 3, "highlightCreationDate": 731876693.002279, "highlightModificationDate": 731876693.002279 diff --git a/test/mocks/rawTemplates.ts b/test/mocks/rawTemplates.ts index 4884507..bec0a86 100644 --- a/test/mocks/rawTemplates.ts +++ b/test/mocks/rawTemplates.ts @@ -24,6 +24,7 @@ Number of annotations:: {{annotations.length}} {{else if (eq highlightStyle "5")}}- 🎯 Highlight:: {{{highlight}}} {{/if}} - 📝 Note:: {{#if note}}{{{note}}}{{else}}N/A{{/if}} +- 📙 Highlight Link:: {{#if highlightLocation}}[Apple Books Highlight Link](ibooks://assetid/{{../bookId}}#{{highlightLocation}}){{else}}N/A{{/if}} - 📅 Highlight taken on:: {{dateFormat highlightCreationDate "YYYY-MM-DD hh:mm:ss A Z"}} - 📅 Highlight modified on:: {{dateFormat highlightModificationDate "YYYY-MM-DD hh:mm:ss A Z"}} diff --git a/test/mocks/renderedTemplate.ts b/test/mocks/renderedTemplate.ts index 2d0622b..e6d0f09 100644 --- a/test/mocks/renderedTemplate.ts +++ b/test/mocks/renderedTemplate.ts @@ -12,6 +12,7 @@ Number of annotations:: 2 - 🔖 Context:: This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide - 🎯 Highlight:: aggregated hightlight from the Apple iPhone User Guide - 📝 Note:: Test note for the aggregated hightlight from the Apple iPhone User Guide +- 📙 Highlight Link:: [Apple Books Highlight Link](ibooks://assetid/THBFYNJKTGFTTVCGSAE5#aggregated-highlight-link-from-the-apple-iphone-user-guide) ---- @@ -22,6 +23,7 @@ containing a new line to test the preservation of indentation containing a new line to test the preservation of indentation - 📝 Note:: Test note for the aggregated hightlight from the Apple iPhone User Guide along with a new line to test the preservation of indentation +- 📙 Highlight Link:: [Apple Books Highlight Link](ibooks://assetid/THBFYNJKTGFTTVCGSAE5#aggregated-highlight-link-from-the-apple-iphone-user-guide) `; @@ -44,6 +46,7 @@ Number of annotations:: 2 - 🔖 Context:: This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide - 🎯 Highlight:: aggregated hightlight from the Apple iPhone User Guide - 📝 Note:: Test note for the aggregated hightlight from the Apple iPhone User Guide +- 📙 Highlight Link:: [Apple Books Highlight Link](ibooks://assetid/THBFYNJKTGFTTVCGSAE5#aggregated-highlight-link-from-the-apple-iphone-user-guide) - 📅 Highlight taken on:: 2024-03-11 03:04:53 PM -04:00 - 📅 Highlight modified on:: 2024-03-11 03:04:53 PM -04:00 @@ -56,6 +59,7 @@ containing a new line to test the preservation of indentation containing a new line to test the preservation of indentation - 📝 Note:: Test note for the aggregated hightlight from the Apple iPhone User Guide along with a new line to test the preservation of indentation +- 📙 Highlight Link:: [Apple Books Highlight Link](ibooks://assetid/THBFYNJKTGFTTVCGSAE5#aggregated-highlight-link-from-the-apple-iphone-user-guide) - 📅 Highlight taken on:: 2024-03-11 03:04:53 PM -04:00 - 📅 Highlight modified on:: 2024-03-11 03:04:53 PM -04:00 diff --git a/test/mocks/testDatabase.sqlite b/test/mocks/testDatabase.sqlite index c7cfef2..34683e4 100644 Binary files a/test/mocks/testDatabase.sqlite and b/test/mocks/testDatabase.sqlite differ diff --git a/test/pluginDocs.spec.ts b/test/pluginDocs.spec.ts index 293845f..338a1e6 100644 --- a/test/pluginDocs.spec.ts +++ b/test/pluginDocs.spec.ts @@ -23,6 +23,7 @@ describe('Plugin documentation', () => { expect(readme).toContain('{{{contextualText}}}'); expect(readme).toContain('{{{highlight}}}'); expect(readme).toContain('{{{note}}}'); + expect(readme).toContain('{{{highlightLocation}}}'); expect(readme).toContain('{{highlightStyle}}'); expect(readme).toContain('{{highlightCreationDate}}'); expect(readme).toContain('{{highlightModificationDate}}'); diff --git a/test/pluginInfo.spec.ts b/test/pluginInfo.spec.ts index f2c8ae4..4d3a781 100644 --- a/test/pluginInfo.spec.ts +++ b/test/pluginInfo.spec.ts @@ -78,6 +78,7 @@ describe('Plugin constants', () => { 'ZFUTUREPROOFING5', 'ZANNOTATIONREPRESENTATIVETEXT', 'ZANNOTATIONSELECTEDTEXT', + 'ZANNOTATIONLOCATION', 'ZANNOTATIONNOTE', 'ZANNOTATIONCREATIONDATE', 'ZANNOTATIONMODIFICATIONDATE',