refactor: importer service (#2674)
This commit is contained in:
@@ -4,33 +4,30 @@
|
||||
|
||||
import { jsonTextContentData, htmlTestData, jsonListContentData } from './testData'
|
||||
import { GoogleKeepConverter } from './GoogleKeepConverter'
|
||||
import { PureCryptoInterface } from '@standardnotes/sncrypto-common'
|
||||
import { GenerateUuid } from '@standardnotes/services'
|
||||
import { FileItem, SuperConverterServiceInterface } from '@standardnotes/snjs'
|
||||
import { ContentType, DecryptedTransferPayload, NoteContent } from '@standardnotes/snjs'
|
||||
import { CreateNoteFn } from '../Converter'
|
||||
|
||||
describe('GoogleKeepConverter', () => {
|
||||
const crypto = {
|
||||
generateUUID: () => String(Math.random()),
|
||||
} as unknown as PureCryptoInterface
|
||||
|
||||
const superConverterService: SuperConverterServiceInterface = {
|
||||
isValidSuperString: () => true,
|
||||
convertOtherFormatToSuperString: (data: string) => data,
|
||||
convertSuperStringToOtherFormat: async (data: string) => data,
|
||||
getEmbeddedFileIDsFromSuperString: () => [],
|
||||
uploadAndReplaceInlineFilesInSuperString: async (
|
||||
superString: string,
|
||||
_uploadFile: (file: File) => Promise<FileItem | undefined>,
|
||||
_linkFile: (file: FileItem) => Promise<void>,
|
||||
_generateUuid: GenerateUuid,
|
||||
) => superString,
|
||||
}
|
||||
const generateUuid = new GenerateUuid(crypto)
|
||||
const createNote: CreateNoteFn = ({ title, text, createdAt, updatedAt, trashed, archived, pinned }) =>
|
||||
({
|
||||
uuid: Math.random().toString(),
|
||||
created_at: createdAt,
|
||||
updated_at: updatedAt,
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title,
|
||||
text,
|
||||
trashed,
|
||||
archived,
|
||||
pinned,
|
||||
references: [],
|
||||
},
|
||||
}) as unknown as DecryptedTransferPayload<NoteContent>
|
||||
|
||||
it('should parse json data', () => {
|
||||
const converter = new GoogleKeepConverter(superConverterService, generateUuid)
|
||||
const converter = new GoogleKeepConverter()
|
||||
|
||||
const textContent = converter.tryParseAsJson(jsonTextContentData, false)
|
||||
const textContent = converter.tryParseAsJson(jsonTextContentData, createNote, (md) => md)
|
||||
|
||||
expect(textContent).not.toBeNull()
|
||||
expect(textContent?.created_at).toBeInstanceOf(Date)
|
||||
@@ -43,7 +40,7 @@ describe('GoogleKeepConverter', () => {
|
||||
expect(textContent?.content.archived).toBe(false)
|
||||
expect(textContent?.content.pinned).toBe(false)
|
||||
|
||||
const listContent = converter.tryParseAsJson(jsonListContentData, false)
|
||||
const listContent = converter.tryParseAsJson(jsonListContentData, createNote, (md) => md)
|
||||
|
||||
expect(listContent).not.toBeNull()
|
||||
expect(listContent?.created_at).toBeInstanceOf(Date)
|
||||
@@ -58,13 +55,15 @@ describe('GoogleKeepConverter', () => {
|
||||
})
|
||||
|
||||
it('should parse html data', () => {
|
||||
const converter = new GoogleKeepConverter(superConverterService, generateUuid)
|
||||
const converter = new GoogleKeepConverter()
|
||||
|
||||
const result = converter.tryParseAsHtml(
|
||||
htmlTestData,
|
||||
{
|
||||
name: 'note-2.html',
|
||||
},
|
||||
createNote,
|
||||
(html) => html,
|
||||
false,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { ContentType } from '@standardnotes/domain-core'
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { GenerateUuid } from '@standardnotes/services'
|
||||
import { SuperConverterServiceInterface } from '@standardnotes/files'
|
||||
import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { NoteType } from '@standardnotes/features'
|
||||
import { Converter, CreateNoteFn } from '../Converter'
|
||||
|
||||
type Content =
|
||||
| {
|
||||
@@ -25,28 +22,44 @@ type GoogleKeepJsonNote = {
|
||||
userEditedTimestampUsec: number
|
||||
} & Content
|
||||
|
||||
export class GoogleKeepConverter {
|
||||
constructor(
|
||||
private superConverterService: SuperConverterServiceInterface,
|
||||
private _generateUuid: GenerateUuid,
|
||||
) {}
|
||||
export class GoogleKeepConverter implements Converter {
|
||||
constructor() {}
|
||||
|
||||
async convertGoogleKeepBackupFileToNote(
|
||||
file: File,
|
||||
isEntitledToSuper: boolean,
|
||||
): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
getImportType(): string {
|
||||
return 'google-keep'
|
||||
}
|
||||
|
||||
const possiblePayloadFromJson = this.tryParseAsJson(content, isEntitledToSuper)
|
||||
getSupportedFileTypes(): string[] {
|
||||
return ['text/html', 'application/json']
|
||||
}
|
||||
|
||||
if (possiblePayloadFromJson) {
|
||||
return possiblePayloadFromJson
|
||||
isContentValid(content: string): boolean {
|
||||
try {
|
||||
const parsed = JSON.parse(content)
|
||||
return GoogleKeepConverter.isValidGoogleKeepJson(parsed)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
const possiblePayloadFromHtml = this.tryParseAsHtml(content, file, isEntitledToSuper)
|
||||
return false
|
||||
}
|
||||
|
||||
convert: Converter['convert'] = async (
|
||||
file,
|
||||
{ createNote, canUseSuper, convertHTMLToSuper, convertMarkdownToSuper, readFileAsText },
|
||||
) => {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const possiblePayloadFromJson = this.tryParseAsJson(content, createNote, convertMarkdownToSuper)
|
||||
|
||||
if (possiblePayloadFromJson) {
|
||||
return [possiblePayloadFromJson]
|
||||
}
|
||||
|
||||
const possiblePayloadFromHtml = this.tryParseAsHtml(content, file, createNote, convertHTMLToSuper, canUseSuper)
|
||||
|
||||
if (possiblePayloadFromHtml) {
|
||||
return possiblePayloadFromHtml
|
||||
return [possiblePayloadFromHtml]
|
||||
}
|
||||
|
||||
throw new Error('Could not parse Google Keep backup file')
|
||||
@@ -55,7 +68,9 @@ export class GoogleKeepConverter {
|
||||
tryParseAsHtml(
|
||||
data: string,
|
||||
file: { name: string },
|
||||
isEntitledToSuper: boolean,
|
||||
createNote: CreateNoteFn,
|
||||
convertHTMLToSuper: (html: string) => string,
|
||||
canUseSuper: boolean,
|
||||
): DecryptedTransferPayload<NoteContent> {
|
||||
const rootElement = document.createElement('html')
|
||||
rootElement.innerHTML = data
|
||||
@@ -85,18 +100,18 @@ export class GoogleKeepConverter {
|
||||
const checked = item.classList.contains('checked')
|
||||
item.setAttribute('aria-checked', checked ? 'true' : 'false')
|
||||
|
||||
if (!isEntitledToSuper) {
|
||||
if (!canUseSuper) {
|
||||
item.textContent = `- ${checked ? '[x]' : '[ ]'} ${item.textContent?.trim()}\n`
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (!isEntitledToSuper) {
|
||||
if (!canUseSuper) {
|
||||
// Replace <br> with \n so line breaks get recognised
|
||||
contentElement.innerHTML = contentElement.innerHTML.replace(/<br>/g, '\n')
|
||||
content = contentElement.textContent
|
||||
} else {
|
||||
content = this.superConverterService.convertOtherFormatToSuperString(rootElement.innerHTML, 'html')
|
||||
content = convertHTMLToSuper(rootElement.innerHTML)
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
@@ -105,25 +120,13 @@ export class GoogleKeepConverter {
|
||||
|
||||
const title = rootElement.getElementsByClassName('title')[0]?.textContent || file.name
|
||||
|
||||
return {
|
||||
created_at: date,
|
||||
created_at_timestamp: date.getTime(),
|
||||
updated_at: date,
|
||||
updated_at_timestamp: date.getTime(),
|
||||
uuid: this._generateUuid.execute().getValue(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: title,
|
||||
text: content,
|
||||
references: [],
|
||||
...(isEntitledToSuper
|
||||
? {
|
||||
noteType: NoteType.Super,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
return createNote({
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
title: title,
|
||||
text: content,
|
||||
noteType: NoteType.Super,
|
||||
})
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -148,7 +151,11 @@ export class GoogleKeepConverter {
|
||||
)
|
||||
}
|
||||
|
||||
tryParseAsJson(data: string, isEntitledToSuper: boolean): DecryptedTransferPayload<NoteContent> | null {
|
||||
tryParseAsJson(
|
||||
data: string,
|
||||
createNote: CreateNoteFn,
|
||||
convertMarkdownToSuper: (md: string) => string,
|
||||
): DecryptedTransferPayload<NoteContent> | null {
|
||||
try {
|
||||
const parsed = JSON.parse(data) as GoogleKeepJsonNote
|
||||
if (!GoogleKeepConverter.isValidGoogleKeepJson(parsed)) {
|
||||
@@ -165,31 +172,17 @@ export class GoogleKeepConverter {
|
||||
})
|
||||
.join('\n')
|
||||
}
|
||||
if (isEntitledToSuper) {
|
||||
text = this.superConverterService.convertOtherFormatToSuperString(text, 'md')
|
||||
}
|
||||
return {
|
||||
created_at: date,
|
||||
created_at_timestamp: date.getTime(),
|
||||
updated_at: date,
|
||||
updated_at_timestamp: date.getTime(),
|
||||
uuid: this._generateUuid.execute().getValue(),
|
||||
content_type: ContentType.TYPES.Note,
|
||||
content: {
|
||||
title: parsed.title,
|
||||
text,
|
||||
references: [],
|
||||
archived: Boolean(parsed.isArchived),
|
||||
trashed: Boolean(parsed.isTrashed),
|
||||
pinned: Boolean(parsed.isPinned),
|
||||
...(isEntitledToSuper
|
||||
? {
|
||||
noteType: NoteType.Super,
|
||||
editorIdentifier: NativeFeatureIdentifier.TYPES.SuperEditor,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
}
|
||||
text = convertMarkdownToSuper(text)
|
||||
return createNote({
|
||||
createdAt: date,
|
||||
updatedAt: date,
|
||||
title: parsed.title,
|
||||
text,
|
||||
archived: Boolean(parsed.isArchived),
|
||||
trashed: Boolean(parsed.isTrashed),
|
||||
pinned: Boolean(parsed.isPinned),
|
||||
noteType: NoteType.Super,
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user