From 99012afe6f8885c713fb65c99e30623709e99e7d Mon Sep 17 00:00:00 2001 From: Abdullah Malek <19255312+absorpheus@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:10:55 +0100 Subject: [PATCH 1/2] fix: remove new lines from the end of contextual text blocks --- src/methods/aggregateDetails.ts | 10 +- src/types.ts | 3 + src/utils/index.ts | 2 + src/utils/preserveNewlineIndentation.ts | 6 + src/utils/removeTrailingSpaces.ts | 6 + test/mocks/detailsData.ts | 18 +++ test/mocks/rawTemplates.ts | 17 +++ test/mocks/renderedTemplate.ts | 18 +++ test/preserveNewlineIndentation.spec.ts | 31 +++++ test/removeTrailingSpaces.spec.ts | 156 ++++++++++++++++++++++++ test/renderHighlightsTemplate.spec.ts | 5 +- test/saveHighlightsToVault.spec.ts | 7 +- 12 files changed, 266 insertions(+), 13 deletions(-) create mode 100644 src/utils/index.ts create mode 100644 src/utils/preserveNewlineIndentation.ts create mode 100644 src/utils/removeTrailingSpaces.ts create mode 100644 test/mocks/detailsData.ts create mode 100644 test/preserveNewlineIndentation.spec.ts create mode 100644 test/removeTrailingSpaces.spec.ts diff --git a/src/methods/aggregateDetails.ts b/src/methods/aggregateDetails.ts index 013c6bb..ec17ffc 100644 --- a/src/methods/aggregateDetails.ts +++ b/src/methods/aggregateDetails.ts @@ -1,6 +1,7 @@ import { IBook, IBookAnnotation, ICombinedBooksAndHighlights } from '../types'; import { getBooks } from './getBooks'; import { getAnnotations } from './getAnnotations'; +import { preserveNewlineIndentation, removeTrailingSpaces } from 'src/utils' export const aggregateBookAndHighlightDetails = async (): Promise => { const books = await getBooks(); @@ -30,7 +31,7 @@ export const aggregateBookAndHighlightDetails = async (): Promise { - const stringWithNewLines = /\n+\s*/g; - - return stringWithNewLines.test(textBlock) ? textBlock.replace(stringWithNewLines, '\n') : textBlock; -} diff --git a/src/types.ts b/src/types.ts index b071311..5e2640f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,6 +26,9 @@ export interface IHighlight { highlight: string; highlightLocation: string; note: string; + highlightStyle: IBookAnnotation['ZANNOTATIONSTYLE'], + highlightCreationDate: number; + highlightModificationDate: number; } export interface ICombinedBooksAndHighlights { bookTitle: string; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..a112e67 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './preserveNewlineIndentation' +export * from './removeTrailingSpaces' diff --git a/src/utils/preserveNewlineIndentation.ts b/src/utils/preserveNewlineIndentation.ts new file mode 100644 index 0000000..c0bf6ba --- /dev/null +++ b/src/utils/preserveNewlineIndentation.ts @@ -0,0 +1,6 @@ +// Handler of double new line characters (\n\n) to preserve proper indentation in text blocks +export const preserveNewlineIndentation = (textBlock: string): string => { + const stringWithNewLines = /\n+\s*/g; + + return stringWithNewLines.test(textBlock) ? textBlock.replace(stringWithNewLines, '\n') : textBlock; +} diff --git a/src/utils/removeTrailingSpaces.ts b/src/utils/removeTrailingSpaces.ts new file mode 100644 index 0000000..cff48c3 --- /dev/null +++ b/src/utils/removeTrailingSpaces.ts @@ -0,0 +1,6 @@ +// Handler of all space, tab or newline characters at the end of text blocks to prevent new lines appearing +export const removeTrailingSpaces = (textBlock: string): string => { + const endLineSpaces = /\s+$/; + + return endLineSpaces.test(textBlock) ? textBlock.replace(endLineSpaces, '') : textBlock; +} diff --git a/test/mocks/detailsData.ts b/test/mocks/detailsData.ts new file mode 100644 index 0000000..974e13c --- /dev/null +++ b/test/mocks/detailsData.ts @@ -0,0 +1,18 @@ +export const highlights = [{ + "bookTitle": "Designing Data-Intensive Applications", + "bookId": "28AEDF62F12B289C88BD6659BD6E50CC", + "bookAuthor": "Kleppmann, Martin", + "bookGenre": "Technology", + "bookLanguage": "EN", + "bookLastOpenedDate": 731876693.002279, + "bookCoverUrl": '', + "annotations": [{ + "chapter": '', + "contextualText": `Chapter 1 introduces the terminology and approach\nthat we're going to use throughout this book. It examines what we actually mean by\nwords like reliability, scalability, and maintainability, and how\nwe can try to achieve these goals.`, + "highlight": `Chapter 1 introduces the terminology and approach\nthat we're going to use throughout this book. It examines what we actually mean by\nwords like reliability, scalability, and maintainability, and how\nwe can try to achieve these goals.`, + "note": `Test note for the hightlight from Designing Data-Intensive Applications`, + "highlightStyle": 3, + "highlightCreationDate": 731876693.002279, + "highlightModificationDate": 731876693.002279 + }] +}] diff --git a/test/mocks/rawTemplates.ts b/test/mocks/rawTemplates.ts index bec0a86..cec0a7b 100644 --- a/test/mocks/rawTemplates.ts +++ b/test/mocks/rawTemplates.ts @@ -30,3 +30,20 @@ Number of annotations:: {{annotations.length}} {{/each}} `; + +export const rawCustomTemplateWrappedTextBlockMock = `Title:: 📕 {{{bookTitle}}} +Author:: {{{bookAuthor}}} +Link:: [Apple Books Link](ibooks://assetid/{{bookId}}) + +## Annotations + +Number of annotations:: {{annotations.length}} + +{{#each annotations}} +---- + +> [!QUOTE] +> {{{highlight}}} + +{{/each}} +`; diff --git a/test/mocks/renderedTemplate.ts b/test/mocks/renderedTemplate.ts index 239b317..2e54b0b 100644 --- a/test/mocks/renderedTemplate.ts +++ b/test/mocks/renderedTemplate.ts @@ -64,3 +64,21 @@ along with a new line to test the preservation of indentation - 📅 Highlight modified on:: 2024-03-11 03:04:53 PM -04:00 `; + +export const renderedCustomTemplateWrappedTextBlockMock = `Title:: 📕 Designing Data-Intensive Applications +Author:: Kleppmann, Martin +Link:: [Apple Books Link](ibooks://assetid/28AEDF62F12B289C88BD6659BD6E50CC) + +## Annotations + +Number of annotations:: 1 + +---- + +> [!QUOTE] +> Chapter 1 introduces the terminology and approach +that we're going to use throughout this book. It examines what we actually mean by +words like reliability, scalability, and maintainability, and how +we can try to achieve these goals. + +`; diff --git a/test/preserveNewlineIndentation.spec.ts b/test/preserveNewlineIndentation.spec.ts new file mode 100644 index 0000000..d95ae56 --- /dev/null +++ b/test/preserveNewlineIndentation.spec.ts @@ -0,0 +1,31 @@ +import { describe, expect, test } from 'vitest' +import { preserveNewlineIndentation } from 'src/utils' +import { renderHighlightsTemplate } from 'src/methods/renderHighlightsTemplate' +import { rawCustomTemplateWrappedTextBlockMock } from './mocks/rawTemplates' +import { renderedCustomTemplateWrappedTextBlockMock } from './mocks/renderedTemplate' +import { highlights } from './mocks/detailsData' +import { ICombinedBooksAndHighlights } from 'src/types' + +describe('preserveNewlineIndentation', () => { + test('Should handle double new line characters to preserve proper indentation in text', () => { + const text = `This is an example text to test the handling of double newline\n\ncharacters in text.` + const actual = preserveNewlineIndentation(text) + const expected = `This is an example text to test the handling of double newline\ncharacters in text.` + + expect(actual).toEqual(expected) + }) + + test('Should handle multiple double new line characters to preserve proper indentation in text', () => { + const text = `This is an example\n\ntext to test\n\nthe handling of multiple double newline\n\ncharacters in text.` + const actual = preserveNewlineIndentation(text) + const expected = `This is an example\ntext to test\nthe handling of multiple double newline\ncharacters in text.` + + expect(actual).toEqual(expected) + }) + + test('Should render a custom template and preserve the proper indentation when a text block is wrapped', async () => { + const renderedTemplate = await renderHighlightsTemplate(highlights[0] as ICombinedBooksAndHighlights, rawCustomTemplateWrappedTextBlockMock); + + expect(renderedTemplate).toEqual(renderedCustomTemplateWrappedTextBlockMock); + }); +}) diff --git a/test/removeTrailingSpaces.spec.ts b/test/removeTrailingSpaces.spec.ts new file mode 100644 index 0000000..87dcffc --- /dev/null +++ b/test/removeTrailingSpaces.spec.ts @@ -0,0 +1,156 @@ +import { describe, expect, test } from 'vitest' +import { removeTrailingSpaces } from 'src/utils' + +describe('removeTrailingSpaces', () => { + test('Should remove a newline character at the end of text', () => { + const text = `This is an example text to test the removal of a newline character at the end of the text.\n` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of a newline character at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove double newline characters at the end of text', () => { + const text = `This is an example text to test the removal of double newline characters at the end of the text.\n\n` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of double newline characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove triple newline characters at the end of text', () => { + const text = `This is an example text to test the removal of triple newline characters at the end of the text.\n\n\n` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of triple newline characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove many newline characters at the end of text', () => { + const text = `This is an example text to test the removal of many newline characters at the end of the text.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many newline characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove many newline characters at the end of text while preserving space, tab and newline characters within the text', () => { + const text = `This is an example text to test the removal of many newline characters at the end of the text while preserving space , tab\t and newline\n characters within the text.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many newline characters at the end of the text while preserving space , tab\t and newline\n characters within the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove a tab character at the end of text', () => { + const text = `This is an example text to test the removal of a tab character at the end of the text.\t` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of a tab character at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove double tab characters at the end of text', () => { + const text = `This is an example text to test the removal of double tab characters at the end of the text.\t\t` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of double tab characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove triple tab characters at the end of text', () => { + const text = `This is an example text to test the removal of triple tab characters at the end of the text.\t\t\t` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of triple tab characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove many tab characters at the end of text', () => { + const text = `This is an example text to test the removal of many tab characters at the end of the text.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many tab characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove many tab characters at the end of text while preserving space, tab and newline characters within the text', () => { + const text = `This is an example text to test the removal of many tab characters at the end of the text while preserving space , tab\t and newline\n characters within the text.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many tab characters at the end of the text while preserving space , tab\t and newline\n characters within the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove a space character at the end of text', () => { + const text = `This is an example text to test the removal of a space character at the end of the text. ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of a space character at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove double space characters at the end of text', () => { + const text = `This is an example text to test the removal of double space characters at the end of the text. ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of double space characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove triple space characters at the end of text', () => { + const text = `This is an example text to test the removal of triple space characters at the end of the text. ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of triple space characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove many space characters at the end of text', () => { + const text = `This is an example text to test the removal of many space characters at the end of the text. ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many space characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove many space characters at the end of text while preserving space, tab and newline characters at the end of the text.', () => { + const text = `This is an example text to test the removal of many space characters at the end of the text preserving space , tab\b and newline\n characters at the end of the text. ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many space characters at the end of the text preserving space , tab\b and newline\n characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove multiple space, tab and newline characters at the end of text', () => { + const text = `This is an example text to test the removal of many space, tab and newline characters at the end of the text. \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many space, tab and newline characters at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should remove multiple space, tab and newline characters at the end of text while preserving space, tab and newline characters within text', () => { + const text = `This is an example text to test the removal of many space , tab\t and newline\n characters at the end of the text while preserving space, tab and newline characters within text. \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t \n\t ` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test the removal of many space , tab\t and newline\n characters at the end of the text while preserving space, tab and newline characters within text.` + + expect(actual).toEqual(expected) + }) + + test('Should return the text when no space, tab or newline characters exist at the end of the text', () => { + const text = `This is an example text to test that the text is returned when no space, tab or newline characters exist at the end of the text.` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test that the text is returned when no space, tab or newline characters exist at the end of the text.` + + expect(actual).toEqual(expected) + }) + + test('Should return the text when no space, tab or newline characters exist at the end of the text while preserving space, tab and newline characters within text', () => { + const text = `This is an example text to test that the text is returned when no space , tab\t or newline\n characters exist at the end of the text while preserving space, tab and newline characters within text.` + const actual = removeTrailingSpaces(text) + const expected = `This is an example text to test that the text is returned when no space , tab\t or newline\n characters exist at the end of the text while preserving space, tab and newline characters within text.` + + expect(actual).toEqual(expected) + }) +}) diff --git a/test/renderHighlightsTemplate.spec.ts b/test/renderHighlightsTemplate.spec.ts index a8e2daf..6a95311 100644 --- a/test/renderHighlightsTemplate.spec.ts +++ b/test/renderHighlightsTemplate.spec.ts @@ -8,6 +8,7 @@ import { aggregatedHighlights } from './mocks/aggregatedDetailsData'; import { rawCustomTemplateMock } from './mocks/rawTemplates'; import { defaultTemplateMock, renderedCustomTemplateMock } from './mocks/renderedTemplate'; import defaultTemplate from '../src/template'; +import { ICombinedBooksAndHighlights } from 'src/types'; describe('renderHighlightsTemplate', () => { const helpers = Handlebars.helpers; @@ -18,7 +19,7 @@ describe('renderHighlightsTemplate', () => { describe('Template rendering', () => { test('Should render a default template with the provided data', async () => { - const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0], defaultTemplate); + const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0] as ICombinedBooksAndHighlights, defaultTemplate); expect(renderedTemplate).toEqual(defaultTemplateMock); }); @@ -26,7 +27,7 @@ describe('renderHighlightsTemplate', () => { test('Should render a custom template with the provided data', async () => { tzSpy.mockImplementation(() => 'America/New_York'); - const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0], rawCustomTemplateMock); + const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0] as ICombinedBooksAndHighlights, rawCustomTemplateMock); expect(renderedTemplate).toEqual(renderedCustomTemplateMock); }); diff --git a/test/saveHighlightsToVault.spec.ts b/test/saveHighlightsToVault.spec.ts index 2ad95c2..d730fda 100644 --- a/test/saveHighlightsToVault.spec.ts +++ b/test/saveHighlightsToVault.spec.ts @@ -3,6 +3,7 @@ import SaveHighlights from '../src/methods/saveHighlightsToVault'; import { AppleBooksHighlightsImportPluginSettings } from '../src/settings'; import { aggregatedHighlights } from './mocks/aggregatedDetailsData'; import { defaultTemplateMock } from './mocks/renderedTemplate'; +import { ICombinedBooksAndHighlights } from '../src/types' const mockVault = { getAbstractFileByPath: vi.fn(), @@ -43,7 +44,7 @@ describe('Save highlights to vault', () => { const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings); const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights'); - await saveHighlights.saveHighlightsToVault(aggregatedHighlights); + await saveHighlights.saveHighlightsToVault(aggregatedHighlights as ICombinedBooksAndHighlights[]); expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1); expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights'); @@ -66,7 +67,7 @@ describe('Save highlights to vault', () => { const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, highlightsFolder: '' }); const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue(''); - await saveHighlights.saveHighlightsToVault(aggregatedHighlights); + await saveHighlights.saveHighlightsToVault(aggregatedHighlights as ICombinedBooksAndHighlights[]); expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1); expect(spyGetAbstractFileByPath).toHaveBeenCalledWith(''); @@ -92,7 +93,7 @@ describe('Save highlights to vault', () => { }; }); - await saveHighlights.saveHighlightsToVault(aggregatedHighlights); + await saveHighlights.saveHighlightsToVault(aggregatedHighlights as ICombinedBooksAndHighlights[]); expect(spyList).toHaveBeenCalledTimes(1); expect(spyList).toReturnWith({ From 56d3a0ce4dd85aa03b653bc21c0416b2e4fc2f75 Mon Sep 17 00:00:00 2001 From: Antonio Date: Fri, 19 Jul 2024 01:57:46 +0300 Subject: [PATCH 2/2] test(core): ensure proper rendering of highlights in custom templates --- test/mocks/aggregatedDetailsData.ts | 4 +- test/mocks/detailsData.ts | 18 ------- test/mocks/rawTemplates.ts | 2 +- test/mocks/renderedTemplate.ts | 27 ++++++---- test/preserveNewlineIndentation.spec.ts | 31 ----------- test/renderHighlightsTemplate.spec.ts | 10 +++- test/saveHighlightsToVault.spec.ts | 69 +++++++++++++++++++++++-- 7 files changed, 95 insertions(+), 66 deletions(-) delete mode 100644 test/mocks/detailsData.ts delete mode 100644 test/preserveNewlineIndentation.spec.ts diff --git a/test/mocks/aggregatedDetailsData.ts b/test/mocks/aggregatedDetailsData.ts index e652dae..9045c7b 100644 --- a/test/mocks/aggregatedDetailsData.ts +++ b/test/mocks/aggregatedDetailsData.ts @@ -23,7 +23,7 @@ export const annotationsToAggregate = [{ "ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE5", "ZFUTUREPROOFING5": "Another aggregated Introduction", "ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the aggregated highlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation", - "ZANNOTATIONSELECTEDTEXT": "aggregated highlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation", + "ZANNOTATIONSELECTEDTEXT": "aggregated highlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation\n\nand another new line\n\nto check one more time", "ZANNOTATIONLOCATION": "aggregated-highlight-link-from-the-apple-iphone-user-guide", "ZANNOTATIONNOTE": "Test note for the aggregated highlight from the Apple iPhone User Guide\n\nalong with a new line to test the preservation of indentation", "ZANNOTATIONCREATIONDATE": 731876693.002279, @@ -52,7 +52,7 @@ export const aggregatedHighlights = [{ }, { "chapter": "Another aggregated Introduction", "contextualText": "This is a contextual text for the aggregated highlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation", - "highlight": "aggregated highlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation", + "highlight": "aggregated highlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation\nand another new line\nto check one more time", "note": "Test note for the aggregated highlight 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, diff --git a/test/mocks/detailsData.ts b/test/mocks/detailsData.ts deleted file mode 100644 index 974e13c..0000000 --- a/test/mocks/detailsData.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const highlights = [{ - "bookTitle": "Designing Data-Intensive Applications", - "bookId": "28AEDF62F12B289C88BD6659BD6E50CC", - "bookAuthor": "Kleppmann, Martin", - "bookGenre": "Technology", - "bookLanguage": "EN", - "bookLastOpenedDate": 731876693.002279, - "bookCoverUrl": '', - "annotations": [{ - "chapter": '', - "contextualText": `Chapter 1 introduces the terminology and approach\nthat we're going to use throughout this book. It examines what we actually mean by\nwords like reliability, scalability, and maintainability, and how\nwe can try to achieve these goals.`, - "highlight": `Chapter 1 introduces the terminology and approach\nthat we're going to use throughout this book. It examines what we actually mean by\nwords like reliability, scalability, and maintainability, and how\nwe can try to achieve these goals.`, - "note": `Test note for the hightlight from Designing Data-Intensive Applications`, - "highlightStyle": 3, - "highlightCreationDate": 731876693.002279, - "highlightModificationDate": 731876693.002279 - }] -}] diff --git a/test/mocks/rawTemplates.ts b/test/mocks/rawTemplates.ts index cec0a7b..ef2500f 100644 --- a/test/mocks/rawTemplates.ts +++ b/test/mocks/rawTemplates.ts @@ -31,7 +31,7 @@ Number of annotations:: {{annotations.length}} {{/each}} `; -export const rawCustomTemplateWrappedTextBlockMock = `Title:: 📕 {{{bookTitle}}} +export const rawCustomTemplateMockWithWrappedTextBlockContainingNewlines = `Title:: 📕 {{{bookTitle}}} Author:: {{{bookAuthor}}} Link:: [Apple Books Link](ibooks://assetid/{{bookId}}) diff --git a/test/mocks/renderedTemplate.ts b/test/mocks/renderedTemplate.ts index 2e54b0b..5e5e78f 100644 --- a/test/mocks/renderedTemplate.ts +++ b/test/mocks/renderedTemplate.ts @@ -21,6 +21,8 @@ Number of annotations:: 2 containing a new line to test the preservation of indentation - 🎯 Highlight:: aggregated highlight from the Apple iPhone User Guide containing a new line to test the preservation of indentation +and another new line +to check one more time - 📝 Note:: Test note for the aggregated highlight 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) @@ -56,7 +58,9 @@ Number of annotations:: 2 - 🔖 Context:: This is a contextual text for the aggregated highlight from the Apple iPhone User Guide containing a new line to test the preservation of indentation - 🎯 Highlight:: aggregated highlight from the Apple iPhone User Guide -containing a new line to test the preservation of indentation +containing a new line to test the preservation of indentation +and another new line +to check one more time - 📝 Note:: Test note for the aggregated highlight 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) @@ -65,20 +69,25 @@ along with a new line to test the preservation of indentation `; -export const renderedCustomTemplateWrappedTextBlockMock = `Title:: 📕 Designing Data-Intensive Applications -Author:: Kleppmann, Martin -Link:: [Apple Books Link](ibooks://assetid/28AEDF62F12B289C88BD6659BD6E50CC) +export const renderedCustomTemplateMockWithWrappedTextBlockContainingNewlines = `Title:: 📕 Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title +Author:: Apple Inc. +Link:: [Apple Books Link](ibooks://assetid/THBFYNJKTGFTTVCGSAE5) ## Annotations -Number of annotations:: 1 +Number of annotations:: 2 ---- > [!QUOTE] -> Chapter 1 introduces the terminology and approach -that we're going to use throughout this book. It examines what we actually mean by -words like reliability, scalability, and maintainability, and how -we can try to achieve these goals. +> aggregated highlight from the Apple iPhone User Guide + +---- + +> [!QUOTE] +> aggregated highlight from the Apple iPhone User Guide +containing a new line to test the preservation of indentation +and another new line +to check one more time `; diff --git a/test/preserveNewlineIndentation.spec.ts b/test/preserveNewlineIndentation.spec.ts deleted file mode 100644 index d95ae56..0000000 --- a/test/preserveNewlineIndentation.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, test } from 'vitest' -import { preserveNewlineIndentation } from 'src/utils' -import { renderHighlightsTemplate } from 'src/methods/renderHighlightsTemplate' -import { rawCustomTemplateWrappedTextBlockMock } from './mocks/rawTemplates' -import { renderedCustomTemplateWrappedTextBlockMock } from './mocks/renderedTemplate' -import { highlights } from './mocks/detailsData' -import { ICombinedBooksAndHighlights } from 'src/types' - -describe('preserveNewlineIndentation', () => { - test('Should handle double new line characters to preserve proper indentation in text', () => { - const text = `This is an example text to test the handling of double newline\n\ncharacters in text.` - const actual = preserveNewlineIndentation(text) - const expected = `This is an example text to test the handling of double newline\ncharacters in text.` - - expect(actual).toEqual(expected) - }) - - test('Should handle multiple double new line characters to preserve proper indentation in text', () => { - const text = `This is an example\n\ntext to test\n\nthe handling of multiple double newline\n\ncharacters in text.` - const actual = preserveNewlineIndentation(text) - const expected = `This is an example\ntext to test\nthe handling of multiple double newline\ncharacters in text.` - - expect(actual).toEqual(expected) - }) - - test('Should render a custom template and preserve the proper indentation when a text block is wrapped', async () => { - const renderedTemplate = await renderHighlightsTemplate(highlights[0] as ICombinedBooksAndHighlights, rawCustomTemplateWrappedTextBlockMock); - - expect(renderedTemplate).toEqual(renderedCustomTemplateWrappedTextBlockMock); - }); -}) diff --git a/test/renderHighlightsTemplate.spec.ts b/test/renderHighlightsTemplate.spec.ts index 6a95311..bbe0130 100644 --- a/test/renderHighlightsTemplate.spec.ts +++ b/test/renderHighlightsTemplate.spec.ts @@ -5,8 +5,8 @@ import Handlebars from 'handlebars'; import { describe, expect, test, vi } from 'vitest'; import { renderHighlightsTemplate } from '../src/methods/renderHighlightsTemplate'; import { aggregatedHighlights } from './mocks/aggregatedDetailsData'; -import { rawCustomTemplateMock } from './mocks/rawTemplates'; -import { defaultTemplateMock, renderedCustomTemplateMock } from './mocks/renderedTemplate'; +import { rawCustomTemplateMock, rawCustomTemplateMockWithWrappedTextBlockContainingNewlines } from './mocks/rawTemplates'; +import { defaultTemplateMock, renderedCustomTemplateMock, renderedCustomTemplateMockWithWrappedTextBlockContainingNewlines } from './mocks/renderedTemplate'; import defaultTemplate from '../src/template'; import { ICombinedBooksAndHighlights } from 'src/types'; @@ -31,6 +31,12 @@ describe('renderHighlightsTemplate', () => { expect(renderedTemplate).toEqual(renderedCustomTemplateMock); }); + + test('Should render a custom template with the provided data and preserve newlines in wrapped text blocks', async () => { + const renderedTemplate = await renderHighlightsTemplate(aggregatedHighlights[0] as ICombinedBooksAndHighlights, rawCustomTemplateMockWithWrappedTextBlockContainingNewlines); + + expect(renderedTemplate).toEqual(renderedCustomTemplateMockWithWrappedTextBlockContainingNewlines); + }); }); describe('Custom Handlebars helpers', () => { diff --git a/test/saveHighlightsToVault.spec.ts b/test/saveHighlightsToVault.spec.ts index d730fda..6862ce8 100644 --- a/test/saveHighlightsToVault.spec.ts +++ b/test/saveHighlightsToVault.spec.ts @@ -1,8 +1,16 @@ +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; +import timezone from 'dayjs/plugin/timezone'; import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import SaveHighlights from '../src/methods/saveHighlightsToVault'; import { AppleBooksHighlightsImportPluginSettings } from '../src/settings'; +import { rawCustomTemplateMock, rawCustomTemplateMockWithWrappedTextBlockContainingNewlines } from './mocks/rawTemplates'; import { aggregatedHighlights } from './mocks/aggregatedDetailsData'; -import { defaultTemplateMock } from './mocks/renderedTemplate'; +import { + defaultTemplateMock, + renderedCustomTemplateMock, + renderedCustomTemplateMockWithWrappedTextBlockContainingNewlines, +} from './mocks/renderedTemplate'; import { ICombinedBooksAndHighlights } from '../src/types' const mockVault = { @@ -39,7 +47,11 @@ afterEach(() => { const settings = new AppleBooksHighlightsImportPluginSettings(); describe('Save highlights to vault', () => { - test('Should save highlights to vault', async () => { + dayjs.extend(utc); + dayjs.extend(timezone); + const tzSpy = vi.spyOn(dayjs.tz, 'guess'); + + test('Should save highlights to vault using the default template', async () => { // eslint-disable-next-line const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings); const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights'); @@ -62,7 +74,58 @@ describe('Save highlights to vault', () => { ); }); - test('Should skip saving highlights to vault highlights are not found', async () => { + test('Should save highlights to vault using the custom colored template', async () => { + tzSpy.mockImplementation(() => 'America/New_York'); + + settings.template = rawCustomTemplateMock; + + // eslint-disable-next-line + const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings); + const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights'); + + await saveHighlights.saveHighlightsToVault(aggregatedHighlights as ICombinedBooksAndHighlights[]); + + expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1); + expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights'); + + expect(mockVault.delete).toHaveBeenCalledTimes(1); + expect(mockVault.delete).toHaveBeenCalledWith('ibooks-highlights', true); + + expect(mockVault.createFolder).toHaveBeenCalledTimes(1); + expect(mockVault.createFolder).toHaveBeenCalledWith('ibooks-highlights'); + + expect(mockVault.create).toHaveBeenCalledTimes(1); + expect(mockVault.create).toHaveBeenCalledWith( + `ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md`, + renderedCustomTemplateMock + ); + }); + + test('Should save highlights to vault using the custom template with wrapped text block', async () => { + settings.template = rawCustomTemplateMockWithWrappedTextBlockContainingNewlines; + // eslint-disable-next-line + const saveHighlights = new SaveHighlights({ vault: mockVault } as any, settings); + const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('ibooks-highlights'); + + await saveHighlights.saveHighlightsToVault(aggregatedHighlights as ICombinedBooksAndHighlights[]); + + expect(spyGetAbstractFileByPath).toHaveBeenCalledTimes(1); + expect(spyGetAbstractFileByPath).toHaveBeenCalledWith('ibooks-highlights'); + + expect(mockVault.delete).toHaveBeenCalledTimes(1); + expect(mockVault.delete).toHaveBeenCalledWith('ibooks-highlights', true); + + expect(mockVault.createFolder).toHaveBeenCalledTimes(1); + expect(mockVault.createFolder).toHaveBeenCalledWith('ibooks-highlights'); + + expect(mockVault.create).toHaveBeenCalledTimes(1); + expect(mockVault.create).toHaveBeenCalledWith( + `ibooks-highlights/Apple iPhone - User Guide - Instructions - with - restricted - symbols - in - title.md`, + renderedCustomTemplateMockWithWrappedTextBlockContainingNewlines + ); + }); + + test('Should skip saving highlights to vault if highlights are not found', async () => { // eslint-disable-next-line const saveHighlights = new SaveHighlights({ vault: mockVault } as any, { ...settings, highlightsFolder: '' }); const spyGetAbstractFileByPath = vi.spyOn(mockVault, 'getAbstractFileByPath').mockReturnValue('');