diff --git a/packages/core/src/utils/__tests__/html-parser.test.ts b/packages/core/src/utils/__tests__/html-parser.test.ts
new file mode 100644
index 000000000..4ffe935d4
--- /dev/null
+++ b/packages/core/src/utils/__tests__/html-parser.test.ts
@@ -0,0 +1,141 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2023 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see
Hello
", + expected: "Hello
" + }, + { + title: "complete html with body", + input: "Hello
", + expected: "Hello
" + }, + { + title: "complete html with body attributes", + input: 'Hello', + expected: 'Hello' + }, + { + title: "html without body", + input: "Hello
", + expected: + "Hello
" + }, + { + title: "doctype html without body", + input: "Hello
", + expected: "Hello
" + }, + { + title: "body with attributes without html", + input: 'Hello
', + expected: 'Hello
' + }, + { + title: "body without closing tag", + input: "Hello
", + expected: "Hello
" + }, + { + title: "html with unclosed body", + input: 'Hello
', + expected: 'Hello
' + }, + { + title: "uppercase tags", + input: "Hello
", + expected: "Hello
" + }, + { + title: "orphaned closing tag", + input: "HelloWorld", + expected: + "Hello</p>World"
+ },
+ {
+ title: "unclosed tag at end",
+ input: "Hello", + expected: + "
<div><p>Hello"
+ },
+ {
+ title: "mismatched closing tags",
+ input: "Hello
Hello
Hello
", + expected: "Hello
" + } +]; + +describe("normalizeToHtmlBody", () => { + HTML_INPUT_TYPES.forEach(({ title, input, expected }) => { + it(`should normalize ${title}`, () => { + expect(normalizeToHtmlBody(input)).toBe(expected); + }); + }); + + it("should always return html and body sequence at root", () => { + for (const { input } of HTML_INPUT_TYPES) { + const normalized = normalizeToHtmlBody(input).toLowerCase(); + expect(normalized.startsWith("")).toBe(true); + expect(normalized.includes("")).toBe(true); + } + }); + + it("should handle runtime non-string values safely", () => { + expect(normalizeToHtmlBody(null as unknown as string)).toBe( + "" + ); + expect(normalizeToHtmlBody(undefined as unknown as string)).toBe( + "" + ); + }); +}); diff --git a/packages/core/src/utils/html-parser.ts b/packages/core/src/utils/html-parser.ts index 82a90932a..9d385edb2 100644 --- a/packages/core/src/utils/html-parser.ts +++ b/packages/core/src/utils/html-parser.ts @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see${escaped}`;
+}
+
+export function normalizeToHtmlBody(input: string) {
+ const source = typeof input === "string" ? input.trim() : "";
+ if (!source) return "";
+
+ // If HTML has broken/incomplete tags, wrap in code block for display
+ if (!isHtmlValid(source)) {
+ return wrapInCodeBlock(source);
+ }
+
+ const hasHtmlTag = /]*>/i.test(source);
+ const hasBodyOpenTag = /]*>/i.test(source);
+ const hasBodyCloseTag = /<\/body>/i.test(source);
+
+ // If a full body block exists, normalize to