Skip to content

Commit 150e1a3

Browse files
authored
chore: improve import tools (#3000)
1 parent b111c3b commit 150e1a3

5 files changed

Lines changed: 48 additions & 11 deletions

File tree

packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,15 +388,23 @@ export class EvernoteConverter implements Converter {
388388
}
389389

390390
stripHTML(html: string) {
391-
const tmp = document.createElement('html')
392-
tmp.innerHTML = html
393-
return tmp.textContent || tmp.innerText || ''
391+
const doc = new DOMParser().parseFromString(html, 'text/html')
392+
return doc.body.textContent || ''
394393
}
395394
}
396395

397396
function changeElementTag(element: HTMLElement, newTag: string) {
398-
const attributes = Array.prototype.slice.call(element.attributes)
399-
element.outerHTML = `<${newTag} ${attributes.map((attr) => attr.name + '="' + attr.value + '"').join(' ')}>${
400-
element.innerHTML
401-
}</${newTag}>`
397+
const doc = element.ownerDocument
398+
const parent = element.parentElement
399+
if (!parent) {
400+
return
401+
}
402+
const replacement = doc.createElement(newTag)
403+
for (const attr of Array.from(element.attributes)) {
404+
replacement.setAttribute(attr.name, attr.value)
405+
}
406+
while (element.firstChild) {
407+
replacement.appendChild(element.firstChild)
408+
}
409+
parent.replaceChild(replacement, element)
402410
}

packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ export class GoogleKeepConverter implements Converter {
7474
convertHTMLToSuper: HTMLToSuperConverterFunction,
7575
canUseSuper: boolean,
7676
): Promise<SNNote> {
77-
const rootElement = document.createElement('html')
78-
rootElement.innerHTML = data
77+
const doc = new DOMParser().parseFromString(data, 'text/html')
78+
const rootElement = doc.documentElement
7979

8080
const headingElement = rootElement.getElementsByClassName('heading')[0]
8181
const parsedDate = new Date(headingElement?.textContent || '')
@@ -110,8 +110,9 @@ export class GoogleKeepConverter implements Converter {
110110
})
111111

112112
if (!canUseSuper) {
113-
// Replace <br> with \n so line breaks get recognised
114-
contentElement.innerHTML = contentElement.innerHTML.replace(/<br>/g, '\n')
113+
Array.from(contentElement.querySelectorAll('br')).forEach((br) => {
114+
br.replaceWith(doc.createTextNode('\n'))
115+
})
115116
content = contentElement.textContent
116117
} else {
117118
content = convertHTMLToSuper(rootElement.innerHTML, {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { assertImportFileWithinSizeLimit, MaxImportFileSizeBytes } from './ImportLimits'
2+
3+
describe('ImportLimits', () => {
4+
it('rejects files over the configured limit', () => {
5+
const file = new File(['x'], 'note.html', { type: 'text/html' })
6+
Object.defineProperty(file, 'size', { value: MaxImportFileSizeBytes + 1 })
7+
expect(() => assertImportFileWithinSizeLimit(file)).toThrow('Import file is too large')
8+
})
9+
10+
it('allows files at or below max import size', () => {
11+
const file = new File(['x'], 'note.html', { type: 'text/html' })
12+
Object.defineProperty(file, 'size', { value: MaxImportFileSizeBytes })
13+
expect(() => assertImportFileWithinSizeLimit(file)).not.toThrow()
14+
})
15+
})
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const MaxImportFileSizeBytes = 50 * 1_000_000
2+
3+
export function assertImportFileWithinSizeLimit(file: File): void {
4+
if (file.size > MaxImportFileSizeBytes) {
5+
throw new Error('Import file is too large')
6+
}
7+
}

packages/ui-services/src/Import/Importer.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { EvernoteConverter } from './EvernoteConverter/EvernoteConverter'
1212
import { GoogleKeepConverter } from './GoogleKeepConverter/GoogleKeepConverter'
1313
import { PlaintextConverter } from './PlaintextConverter/PlaintextConverter'
1414
import { SimplenoteConverter } from './SimplenoteConverter/SimplenoteConverter'
15+
import { assertImportFileWithinSizeLimit, MaxImportFileSizeBytes } from './ImportLimits'
1516
import { readFileAsText } from './Utils'
1617
import {
1718
DecryptedItemInterface,
@@ -74,6 +75,9 @@ export class Importer {
7475
}
7576

7677
detectService = async (file: File): Promise<string | null> => {
78+
if (file.size > MaxImportFileSizeBytes) {
79+
return null
80+
}
7781
const content = await readFileAsText(file)
7882

7983
const { ext } = parseFileName(file.name)
@@ -232,6 +236,8 @@ export class Importer {
232236
throw new Error('Importing Super notes requires a subscription')
233237
}
234238

239+
assertImportFileWithinSizeLimit(file)
240+
235241
const successful: ConversionResult['successful'] = []
236242
const errored: ConversionResult['errored'] = []
237243

0 commit comments

Comments
 (0)