{
	"issue": {
		"url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
		"repository_url": "https://api.github.com/repos/laurent22/joplin",
		"labels_url": "https://api.github.com/repos/laurent22/joplin/issues/14400/labels{/name}",
		"comments_url": "https://api.github.com/repos/laurent22/joplin/issues/14400/comments",
		"events_url": "https://api.github.com/repos/laurent22/joplin/issues/14400/events",
		"html_url": "https://github.com/laurent22/joplin/pull/14400",
		"id": 3969159811,
		"node_id": "PR_kwDOBLftOs7FMqfQ",
		"number": 14400,
		"title": "Desktop: Fixes #14396: Fixed Google Docs paste producing stray ** and literal <br/> in Markdown",
		"user": {
			"login": "varunkumar-22",
			"id": 219557905,
			"node_id": "U_kgDODRYwEQ",
			"avatar_url": "https://avatars.githubusercontent.com/u/219557905?v=4",
			"gravatar_id": "",
			"url": "https://api.github.com/users/varunkumar-22",
			"html_url": "https://github.com/varunkumar-22",
			"followers_url": "https://api.github.com/users/varunkumar-22/followers",
			"following_url": "https://api.github.com/users/varunkumar-22/following{/other_user}",
			"gists_url": "https://api.github.com/users/varunkumar-22/gists{/gist_id}",
			"starred_url": "https://api.github.com/users/varunkumar-22/starred{/owner}{/repo}",
			"subscriptions_url": "https://api.github.com/users/varunkumar-22/subscriptions",
			"organizations_url": "https://api.github.com/users/varunkumar-22/orgs",
			"repos_url": "https://api.github.com/users/varunkumar-22/repos",
			"events_url": "https://api.github.com/users/varunkumar-22/events{/privacy}",
			"received_events_url": "https://api.github.com/users/varunkumar-22/received_events",
			"type": "User",
			"user_view_type": "public",
			"site_admin": false
		},
		"labels": [
			{
				"id": 519700741,
				"node_id": "MDU6TGFiZWw1MTk3MDA3NDE=",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/bug",
				"name": "bug",
				"color": "cf353b",
				"default": true,
				"description": "It's a bug"
			},
			{
				"id": 1080341216,
				"node_id": "MDU6TGFiZWwxMDgwMzQxMjE2",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/desktop",
				"name": "desktop",
				"color": "ffc274",
				"default": false,
				"description": "All desktop platforms"
			},
			{
				"id": 1366672371,
				"node_id": "MDU6TGFiZWwxMzY2NjcyMzcx",
				"url": "https://api.github.com/repos/laurent22/joplin/labels/editor",
				"name": "editor",
				"color": "91ca55",
				"default": false,
				"description": ""
			}
		],
		"state": "closed",
		"locked": false,
		"assignees": [],
		"milestone": null,
		"comments": 9,
		"created_at": "2026-02-20T15:41:01Z",
		"updated_at": "2026-02-22T09:02:56Z",
		"closed_at": "2026-02-22T09:02:47Z",
		"assignee": null,
		"author_association": "CONTRIBUTOR",
		"active_lock_reason": null,
		"draft": false,
		"pull_request": {
			"url": "https://api.github.com/repos/laurent22/joplin/pulls/14400",
			"html_url": "https://github.com/laurent22/joplin/pull/14400",
			"diff_url": "https://github.com/laurent22/joplin/pull/14400.diff",
			"patch_url": "https://github.com/laurent22/joplin/pull/14400.patch",
			"merged_at": null
		},
		"body": "fixes #14396\r\n\r\n### AI Assistance Disclosure\r\nAI tools were used to assist with:\r\n- Translating my designed logic into implementation code\r\n- Generating additional test case ideas for verification\r\n- Improving wording and clarity in the PR description\r\n\r\nThe core logic, architectural decisions, and debugging process were done by me. All AI-generated output was carefully reviewed, validated, and modified where necessary. I fully understand the submitted code.\r\n\r\n### Problem:\r\nWhen you paste content from Google Docs into the Rich Text editor, the resulting Markdown ends up with stray `** `markers, literal `<br/>` tags, and `&nbsp`; characters scattered throughout the note.\r\n\r\nThis happens because Google Docs puts some unusual HTML on the clipboard:\r\n\r\n- It wraps text in `<b style=\"font-weight:normal\">` tags — bold tags that aren't actually bold\r\n- It leaves behind empty `<b></b>` tags with no content\r\n- It wraps `<br>` inside styled `<span>` tags (e.g.` <span style=\"...\"><br/></span>`) instead of using bare`<br>`\r\n- It uses `<br>` for line breaks instead of proper `<p>` paragraphs\r\n- It injects `&nbsp;` entities for spacing\r\n\r\nWhen our HTML-to-Markdown converter (Turndown) processes this, an empty `<b></b>` becomes `**,` and the `<br> `tags cause broken paragraph spacing,  and `&nbsp;` entities leak into the Markdown.\r\n\r\n### Fix\r\nThis PR adds a `sanitizeGoogleDocsHtml() `function in `resourceHandling.ts` that cleans up Google Docs HTML before it goes through the HTML→Markdown→HTML conversion. It only runs when the clipboard contains Google Docs content (detected by the` docs-internal-guid-` marker), so paste from other sources is completely unaffected.\r\n\r\nThe cleanup does four things:\r\n\r\n1. **Strips empty formatting tags**  : removes `<b></b>,` `<strong></strong>`, `<i></i>`, etc. that have no visible text\r\n2. **Unwraps fake-bold wrappers** : replaces `<b style=\"font-weight:normal\">content</b> `with just content \r\n3. **Splits `<p>` containing `<br`> into separate `<p>` blocks**: first unwraps `<br>` from `<span>` wrappers (Google Docs' actual format), then splits at `<br>` boundaries. Only targets` <p>`  leaves `<li>`, `<td>`, `<blockquote>` alone\r\n4.  **Normalises top-level` <br>` into proper `<p>` blocks** : only at the top level; `<br>` inside lists, tables, and blockquotes is preserved, and existing` <p>` blocks are left alone\r\nAdditionally, `&nbsp;` entities reintroduced by the `sanitizer's DOMParser`→`innerHTML` round-trip are cleaned to regular spaces.\r\n### Architecture Safety\r\n\r\n- `sanitizeGoogleDocsHtml` is only called inside `processPastedHtml`, which is only used by TinyMCE (Rich Text editor) paste\r\n- CodeMirror (Markdown editor) does not call this function\r\n- No files in `packages/lib/`, `packages/app-mobile/`, `packages/app-cli/`, or `packages/server/` were modified\r\n- `HtmlToMd` and `MdToHtml` are untouched\r\n- The function is idempotent  after sanitization, the `docs-internal-guid-` marker is removed, so a second pass returns immediately\r\n- Non-text content (`<img>`, `<video>`, `<svg>`) is preserved during both the empty-tag removal and `<br>` splitting steps\r\n\r\n### Test results\r\n```\r\nPASS gui/NoteEditor/utils/resourceHandling.test.ts\r\n  resourceHandling\r\n    ✓ should sanitize pasted HTML\r\n    ✓ should clean up pasted HTML\r\n    ✓ should preserve images pasted from the resource directory\r\n    ✓ should remove empty inline formatting tags\r\n    ✓ should remove empty <b> tags containing only empty spans\r\n    ✓ should unwrap fake-bold <b style=\"font-weight:normal\"> with content\r\n    ✓ should normalize top-level <br> into <p> blocks\r\n    ✓ should NOT normalize <br> inside <li>\r\n    ✓ should split <p> containing <br> into multiple <p> blocks\r\n    ✓ should handle trailing <br> inside <p>\r\n    ✓ should unwrap <br> from <span> wrappers (real Google Docs format)\r\n    ✓ should handle <br> between and after <p> blocks\r\n    ✓ should handle Google Docs structure with empty paragraph breaks\r\n    ✓ should NOT touch content when <p> blocks already exist\r\n    ✓ should return non-Google Docs HTML unchanged\r\n    ✓ end-to-end: Google Docs paste produces clean Markdown with all content preserved\r\nTests: 16 passed, 16 total\r\n\r\n```\r\n### Demo\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/6e208f14-b5a0-4792-82d0-053cae30e3f0\r\n\r\n",
		"closed_by": {
			"login": "laurent22",
			"id": 1285584,
			"node_id": "MDQ6VXNlcjEyODU1ODQ=",
			"avatar_url": "https://avatars.githubusercontent.com/u/1285584?v=4",
			"gravatar_id": "",
			"url": "https://api.github.com/users/laurent22",
			"html_url": "https://github.com/laurent22",
			"followers_url": "https://api.github.com/users/laurent22/followers",
			"following_url": "https://api.github.com/users/laurent22/following{/other_user}",
			"gists_url": "https://api.github.com/users/laurent22/gists{/gist_id}",
			"starred_url": "https://api.github.com/users/laurent22/starred{/owner}{/repo}",
			"subscriptions_url": "https://api.github.com/users/laurent22/subscriptions",
			"organizations_url": "https://api.github.com/users/laurent22/orgs",
			"repos_url": "https://api.github.com/users/laurent22/repos",
			"events_url": "https://api.github.com/users/laurent22/events{/privacy}",
			"received_events_url": "https://api.github.com/users/laurent22/received_events",
			"type": "User",
			"user_view_type": "public",
			"site_admin": false
		},
		"reactions": {
			"url": "https://api.github.com/repos/laurent22/joplin/issues/14400/reactions",
			"total_count": 0,
			"+1": 0,
			"-1": 0,
			"laugh": 0,
			"hooray": 0,
			"confused": 0,
			"heart": 0,
			"rocket": 0,
			"eyes": 0
		},
		"timeline_url": "https://api.github.com/repos/laurent22/joplin/issues/14400/timeline",
		"performed_via_github_app": null,
		"state_reason": null
	},
	"comments": [
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935656244",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3935656244",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3935656244,
			"node_id": "IC_kwDOBLftOs7qlVk0",
			"user": {
				"login": "github-actions[bot]",
				"id": 41898282,
				"node_id": "MDM6Qm90NDE4OTgyODI=",
				"avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/github-actions%5Bbot%5D",
				"html_url": "https://github.com/apps/github-actions",
				"followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
				"following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
				"gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
				"organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
				"repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
				"events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
				"received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
				"type": "Bot",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-20T15:41:12Z",
			"updated_at": "2026-02-22T09:02:56Z",
			"body": "****CLA Assistant Lite bot**** All contributors have signed the CLA  ✍️ ✅",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935656244/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": {
				"id": 15368,
				"client_id": "Iv1.05c79e9ad1f6bdfa",
				"slug": "github-actions",
				"node_id": "MDM6QXBwMTUzNjg=",
				"owner": {
					"login": "github",
					"id": 9919,
					"node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
					"avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
					"gravatar_id": "",
					"url": "https://api.github.com/users/github",
					"html_url": "https://github.com/github",
					"followers_url": "https://api.github.com/users/github/followers",
					"following_url": "https://api.github.com/users/github/following{/other_user}",
					"gists_url": "https://api.github.com/users/github/gists{/gist_id}",
					"starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
					"subscriptions_url": "https://api.github.com/users/github/subscriptions",
					"organizations_url": "https://api.github.com/users/github/orgs",
					"repos_url": "https://api.github.com/users/github/repos",
					"events_url": "https://api.github.com/users/github/events{/privacy}",
					"received_events_url": "https://api.github.com/users/github/received_events",
					"type": "Organization",
					"user_view_type": "public",
					"site_admin": false
				},
				"name": "GitHub Actions",
				"description": "Automate your workflow from idea to production",
				"external_url": "https://help.github.com/en/actions",
				"html_url": "https://github.com/apps/github-actions",
				"created_at": "2018-07-30T09:30:17Z",
				"updated_at": "2026-05-05T14:51:38Z",
				"permissions": {
					"actions": "write",
					"administration": "read",
					"artifact_metadata": "write",
					"attestations": "write",
					"checks": "write",
					"code_quality": "write",
					"contents": "write",
					"copilot_requests": "write",
					"deployments": "write",
					"discussions": "write",
					"issues": "write",
					"merge_queues": "write",
					"metadata": "read",
					"models": "read",
					"packages": "write",
					"pages": "write",
					"pull_requests": "write",
					"repository_hooks": "write",
					"repository_projects": "write",
					"security_events": "write",
					"statuses": "write",
					"vulnerability_alerts": "read"
				},
				"events": [
					"branch_protection_rule",
					"check_run",
					"check_suite",
					"create",
					"delete",
					"deployment",
					"deployment_status",
					"discussion",
					"discussion_comment",
					"fork",
					"gollum",
					"issues",
					"issue_comment",
					"label",
					"merge_group",
					"milestone",
					"page_build",
					"public",
					"pull_request",
					"pull_request_review",
					"pull_request_review_comment",
					"push",
					"registry_package",
					"release",
					"repository",
					"repository_dispatch",
					"status",
					"watch",
					"workflow_dispatch",
					"workflow_run"
				]
			}
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935660129",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3935660129",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3935660129,
			"node_id": "IC_kwDOBLftOs7qlWhh",
			"user": {
				"login": "coderabbitai[bot]",
				"id": 136622811,
				"node_id": "BOT_kgDOCCSy2w",
				"avatar_url": "https://avatars.githubusercontent.com/in/347564?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/coderabbitai%5Bbot%5D",
				"html_url": "https://github.com/apps/coderabbitai",
				"followers_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/followers",
				"following_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/following{/other_user}",
				"gists_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/subscriptions",
				"organizations_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/orgs",
				"repos_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/repos",
				"events_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/events{/privacy}",
				"received_events_url": "https://api.github.com/users/coderabbitai%5Bbot%5D/received_events",
				"type": "Bot",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-20T15:42:02Z",
			"updated_at": "2026-02-21T14:51:23Z",
			"body": "<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds a Google Docs HTML sanitizer and integrates it into the paste processing pipeline to clean docs-internal markup (empty inline tags, fake bold wrappers, and top-level breaks) before image handling and HTML→Markdown conversion.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**Google Docs HTML Sanitisation** <br> `packages/app-desktop/gui/NoteEditor/utils/resourceHandling.ts`|New exported `sanitizeGoogleDocsHtml(html: string)` implemented and invoked during pasted-HTML processing; removes empty inline formatting, unwraps faux bold wrappers, splits/normalises <br>-based paragraphs, and strips remaining top-level breaks.|\n|**Sanitiser Tests** <br> `packages/app-desktop/gui/NoteEditor/utils/resourceHandling.test.ts`|Added comprehensive tests for `sanitizeGoogleDocsHtml()` exercising empty element removal, wrapper unwrapping, paragraph splitting, list-item break preservation, trailing/empty-break handling, and integration with `processPastedHtml`.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Clipboard\n    participant processPastedHtml\n    participant sanitizeGoogleDocsHtml\n    participant ImageProcessor\n    participant MarkdownConverter\n    participant Editor\n\n    User->>Clipboard: Copy from Google Docs\n    User->>processPastedHtml: Paste into Rich Text Editor\n    processPastedHtml->>sanitizeGoogleDocsHtml: Pass pasted HTML (detect docs-internal-guid-)\n    sanitizeGoogleDocsHtml->>sanitizeGoogleDocsHtml: Remove empty inline tags / unwrap wrappers\n    sanitizeGoogleDocsHtml->>sanitizeGoogleDocsHtml: Split/normalise <br> into <p>\n    sanitizeGoogleDocsHtml->>processPastedHtml: Return sanitised HTML\n    processPastedHtml->>ImageProcessor: Handle embedded images\n    ImageProcessor->>MarkdownConverter: Forward processed HTML\n    MarkdownConverter->>Editor: Provide converted Markdown / content\n```\n\n## Suggested labels\n\n`editor`\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 4 | ❌ 1</summary>\n\n### ❌ Failed checks (1 warning)\n\n|     Check name     | Status     | Explanation                                                                           | Resolution                                                                         |\n| :----------------: | :--------- | :------------------------------------------------------------------------------------ | :--------------------------------------------------------------------------------- |\n| Docstring Coverage | ⚠️ Warning | Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |\n\n<details>\n<summary>✅ Passed checks (4 passed)</summary>\n\n|         Check name         | Status   | Explanation                                                                                                                                                                                                         |\n| :------------------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|         Title check        | ✅ Passed | The title accurately describes the main change: adding sanitization for Google Docs HTML to fix stray ** markers and literal <br/> tags in Markdown output.                                                         |\n|      Description check     | ✅ Passed | The description thoroughly explains the problem, the solution, architectural safety considerations, and includes test results and a demo, all directly related to the changeset.                                    |\n|     Linked Issues check    | ✅ Passed | The PR fully addresses issue `#14396` by implementing sanitizeGoogleDocsHtml() to remove stray ** markers, literal <br/> tags, and &nbsp; entities from Google Docs pastes, directly resolving all reported problems. |\n| Out of Scope Changes check | ✅ Passed | All changes are within scope: modifications limited to resourceHandling.ts and its test file to add Google Docs sanitization; no unrelated changes to other packages or core conversion functions.                  |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings (stacked PR)\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> 📝 Generate docstrings (commit on current branch)\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n<!-- tips_start -->\n\n---\n\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- [encoded data, 9304 characters] -->\n\n<!-- internal state end -->",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935660129/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": {
				"id": 347564,
				"client_id": "Iv1.6aaafe4fe882736b",
				"slug": "coderabbitai",
				"node_id": "A_kwHOB96YWc4ABU2s",
				"owner": {
					"login": "coderabbitai",
					"id": 132028505,
					"node_id": "O_kgDOB96YWQ",
					"avatar_url": "https://avatars.githubusercontent.com/u/132028505?v=4",
					"gravatar_id": "",
					"url": "https://api.github.com/users/coderabbitai",
					"html_url": "https://github.com/coderabbitai",
					"followers_url": "https://api.github.com/users/coderabbitai/followers",
					"following_url": "https://api.github.com/users/coderabbitai/following{/other_user}",
					"gists_url": "https://api.github.com/users/coderabbitai/gists{/gist_id}",
					"starred_url": "https://api.github.com/users/coderabbitai/starred{/owner}{/repo}",
					"subscriptions_url": "https://api.github.com/users/coderabbitai/subscriptions",
					"organizations_url": "https://api.github.com/users/coderabbitai/orgs",
					"repos_url": "https://api.github.com/users/coderabbitai/repos",
					"events_url": "https://api.github.com/users/coderabbitai/events{/privacy}",
					"received_events_url": "https://api.github.com/users/coderabbitai/received_events",
					"type": "Organization",
					"user_view_type": "public",
					"site_admin": false
				},
				"name": "coderabbitai",
				"description": "# Transforming Code Reviews with AI\r\n\r\n## Features\r\n\r\n**Automated Reviews**: Continuous reviews of the pull requests including incremental commits. \r\n\r\n**Summarization**: Generates high-level summary and a technical walkthrough of the PR changes. \r\n\r\n**Line-by-line review**: Provides line-by-line suggestions committable with one click.\r\n\r\n**Codebase verification**:  Verifies the impact on the overall codebase and identifies missing changes.\r\n\r\n**Insights into your code**:  Ask any questions on your codebase within the pull request \r\n\r\n**Chat about your code** : Chat with the bot around your code. The more you chat, the smarter it gets.\r\n\r\n**Issue Validation**:  Validates the PR against the linked issues and identifies other related issues \r\n\r\n\r\n\r\n",
				"external_url": "https://coderabbit.ai?utm_source=cr_app&utm_medium=github",
				"html_url": "https://github.com/apps/coderabbitai",
				"created_at": "2023-06-14T15:47:27Z",
				"updated_at": "2026-03-14T07:58:44Z",
				"permissions": {
					"actions": "read",
					"checks": "write",
					"contents": "write",
					"discussions": "read",
					"issues": "write",
					"members": "read",
					"metadata": "read",
					"pull_requests": "write",
					"statuses": "write"
				},
				"events": [
					"issues",
					"issue_comment",
					"label",
					"organization",
					"pull_request",
					"pull_request_review",
					"pull_request_review_comment",
					"pull_request_review_thread",
					"release",
					"repository"
				]
			}
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935665515",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3935665515",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3935665515,
			"node_id": "IC_kwDOBLftOs7qlX1r",
			"user": {
				"login": "varunkumar-22",
				"id": 219557905,
				"node_id": "U_kgDODRYwEQ",
				"avatar_url": "https://avatars.githubusercontent.com/u/219557905?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/varunkumar-22",
				"html_url": "https://github.com/varunkumar-22",
				"followers_url": "https://api.github.com/users/varunkumar-22/followers",
				"following_url": "https://api.github.com/users/varunkumar-22/following{/other_user}",
				"gists_url": "https://api.github.com/users/varunkumar-22/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/varunkumar-22/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/varunkumar-22/subscriptions",
				"organizations_url": "https://api.github.com/users/varunkumar-22/orgs",
				"repos_url": "https://api.github.com/users/varunkumar-22/repos",
				"events_url": "https://api.github.com/users/varunkumar-22/events{/privacy}",
				"received_events_url": "https://api.github.com/users/varunkumar-22/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-20T15:43:13Z",
			"updated_at": "2026-02-20T15:43:13Z",
			"body": "I have read the CLA Document and I hereby sign the CLA",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935665515/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935893031",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3935893031",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3935893031,
			"node_id": "IC_kwDOBLftOs7qmPYn",
			"user": {
				"login": "mrjo118",
				"id": 6963004,
				"node_id": "MDQ6VXNlcjY5NjMwMDQ=",
				"avatar_url": "https://avatars.githubusercontent.com/u/6963004?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/mrjo118",
				"html_url": "https://github.com/mrjo118",
				"followers_url": "https://api.github.com/users/mrjo118/followers",
				"following_url": "https://api.github.com/users/mrjo118/following{/other_user}",
				"gists_url": "https://api.github.com/users/mrjo118/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/mrjo118/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/mrjo118/subscriptions",
				"organizations_url": "https://api.github.com/users/mrjo118/orgs",
				"repos_url": "https://api.github.com/users/mrjo118/repos",
				"events_url": "https://api.github.com/users/mrjo118/events{/privacy}",
				"received_events_url": "https://api.github.com/users/mrjo118/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-20T16:30:41Z",
			"updated_at": "2026-02-20T19:51:48Z",
			"body": "Your testing only covers the Rich text editor, but I think the place you have changed might impact the Markdown editor as well.\r\n\r\nHow does pasting text from Google Docs editor behave before and after the change?\r\n\r\nAlso, would it still work to paste raw html code into the Markdown editor, or would the new logic strip out the html source in that scenario?\r\n\r\nEDIT: Ok it looks like processPastedHtml is only invoked by the Rich text editor, so testing for the markdown editor is out of scope",
			"author_association": "COLLABORATOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3935893031/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3936762785",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3936762785",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3936762785,
			"node_id": "IC_kwDOBLftOs7qpjuh",
			"user": {
				"login": "laurent22",
				"id": 1285584,
				"node_id": "MDQ6VXNlcjEyODU1ODQ=",
				"avatar_url": "https://avatars.githubusercontent.com/u/1285584?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/laurent22",
				"html_url": "https://github.com/laurent22",
				"followers_url": "https://api.github.com/users/laurent22/followers",
				"following_url": "https://api.github.com/users/laurent22/following{/other_user}",
				"gists_url": "https://api.github.com/users/laurent22/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/laurent22/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/laurent22/subscriptions",
				"organizations_url": "https://api.github.com/users/laurent22/orgs",
				"repos_url": "https://api.github.com/users/laurent22/repos",
				"events_url": "https://api.github.com/users/laurent22/events{/privacy}",
				"received_events_url": "https://api.github.com/users/laurent22/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-20T19:44:11Z",
			"updated_at": "2026-02-20T19:44:11Z",
			"body": "Please make sure you read our AI policy: https://github.com/joplin/gsoc/blob/master/ai_policy.md",
			"author_association": "OWNER",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3936762785/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3938294004",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3938294004",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3938294004,
			"node_id": "IC_kwDOBLftOs7qvZj0",
			"user": {
				"login": "varunkumar-22",
				"id": 219557905,
				"node_id": "U_kgDODRYwEQ",
				"avatar_url": "https://avatars.githubusercontent.com/u/219557905?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/varunkumar-22",
				"html_url": "https://github.com/varunkumar-22",
				"followers_url": "https://api.github.com/users/varunkumar-22/followers",
				"following_url": "https://api.github.com/users/varunkumar-22/following{/other_user}",
				"gists_url": "https://api.github.com/users/varunkumar-22/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/varunkumar-22/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/varunkumar-22/subscriptions",
				"organizations_url": "https://api.github.com/users/varunkumar-22/orgs",
				"repos_url": "https://api.github.com/users/varunkumar-22/repos",
				"events_url": "https://api.github.com/users/varunkumar-22/events{/privacy}",
				"received_events_url": "https://api.github.com/users/varunkumar-22/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-21T06:40:04Z",
			"updated_at": "2026-02-21T06:40:04Z",
			"body": "@mrjo118 Thanks for pointing this out,  after performing extensive testing with multiple types of Google Docs content including: simple paragraphs, mixed bold/italic text, soft line breaks, lists, and some edge cases with trailing breaks and spacing. During that testing, I did find one remaining issue.\r\n\r\nWhen Google Docs wraps everything inside a single` <p> `and inserts` <br> `between inline nodes, my current normalization logic doesn’t split that paragraph. Because of that, the `<br>` can still survive the HTML -> Markdown -> HTML roundtrip and show up as a literal `<br>` in Markdown.\r\n\r\nSo the fix works for:\r\n\r\n- Empty inline formatting (no more stray **)\r\n- Fake bold wrappers\r\n- Non-breaking spaces\r\n- Top-level <br> sequences\r\n\r\nBut it doesn’t yet fully handle `<br>` inside existing` <p>` blocks.\r\n\r\nI’ll update the implementation to safely split those paragraphs without touching lists, tables, or other structural elements. Also, I noticed a few potential edge cases flagged by the bots and earlier comments from @laurent22, so I’d like to address those as well.\r\n\r\nOnce all of that is cleaned up, I’d prefer to do one more architectural pass to make sure:\r\n\r\n- The logic remains strictly scoped to Google Docs content\r\n- The Markdown editor flow is completely unaffected\r\n- We’re not over-normalizing anything unintentionally\r\n\r\nI’ll push an updated revision after tightening this up. Thanks again , the feedback definitely helped catch this gap. Could you advise on the preferred way to handle `<br>` inside existing `<p>` blocks while keeping the transformation safely scoped?\r\n\r\n\r\n\r\n",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3938294004/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3938309698",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3938309698",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3938309698,
			"node_id": "IC_kwDOBLftOs7qvdZC",
			"user": {
				"login": "varunkumar-22",
				"id": 219557905,
				"node_id": "U_kgDODRYwEQ",
				"avatar_url": "https://avatars.githubusercontent.com/u/219557905?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/varunkumar-22",
				"html_url": "https://github.com/varunkumar-22",
				"followers_url": "https://api.github.com/users/varunkumar-22/followers",
				"following_url": "https://api.github.com/users/varunkumar-22/following{/other_user}",
				"gists_url": "https://api.github.com/users/varunkumar-22/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/varunkumar-22/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/varunkumar-22/subscriptions",
				"organizations_url": "https://api.github.com/users/varunkumar-22/orgs",
				"repos_url": "https://api.github.com/users/varunkumar-22/repos",
				"events_url": "https://api.github.com/users/varunkumar-22/events{/privacy}",
				"received_events_url": "https://api.github.com/users/varunkumar-22/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-21T06:52:22Z",
			"updated_at": "2026-02-21T06:52:22Z",
			"body": "@laurent22 Thanks for pointing this out , I’ve now read the AI policy carefully.\r\nI did use AI assistance during this contribution, mainly to help translate my designed logic into code form, generate additional test cases to verify behavior, and improve wording in the PR description.\r\n\r\nThe core logic and approach were designed by me, and I reviewed, tested, and verified all generated output before submitting. I fully understand the implementation.\r\n\r\nI’ll update the PR to include a proper “AI Assistance Disclosure” section as required.",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3938309698/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3938888072",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3938888072",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3938888072,
			"node_id": "IC_kwDOBLftOs7qxqmI",
			"user": {
				"login": "varunkumar-22",
				"id": 219557905,
				"node_id": "U_kgDODRYwEQ",
				"avatar_url": "https://avatars.githubusercontent.com/u/219557905?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/varunkumar-22",
				"html_url": "https://github.com/varunkumar-22",
				"followers_url": "https://api.github.com/users/varunkumar-22/followers",
				"following_url": "https://api.github.com/users/varunkumar-22/following{/other_user}",
				"gists_url": "https://api.github.com/users/varunkumar-22/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/varunkumar-22/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/varunkumar-22/subscriptions",
				"organizations_url": "https://api.github.com/users/varunkumar-22/orgs",
				"repos_url": "https://api.github.com/users/varunkumar-22/repos",
				"events_url": "https://api.github.com/users/varunkumar-22/events{/privacy}",
				"received_events_url": "https://api.github.com/users/varunkumar-22/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-21T14:38:51Z",
			"updated_at": "2026-02-21T14:38:51Z",
			"body": "@mrjo118 \r\n\r\n### Before/after behavior when pasting from Google Docs into Rich Text editor\r\n**BEFORE**\r\n\r\nhttps://github.com/user-attachments/assets/aeba3829-877a-444a-8ebd-bf88200be8b3\r\n\r\n---\r\n\r\n**AFTER**\r\n\r\nhttps://github.com/user-attachments/assets/87e95717-b42c-4d1e-ab3f-c48b77147a6a\r\n\r\n---\r\n### Raw HTML Paste in Markdown Editor\r\n\r\n\r\nhttps://github.com/user-attachments/assets/2c51a55d-91d3-4c6d-b998-2f6a9b7101bf\r\n\r\n\r\n",
			"author_association": "CONTRIBUTOR",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3938888072/reactions",
				"total_count": 0,
				"+1": 0,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		},
		{
			"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3940537489",
			"html_url": "https://github.com/laurent22/joplin/pull/14400#issuecomment-3940537489",
			"issue_url": "https://api.github.com/repos/laurent22/joplin/issues/14400",
			"id": 3940537489,
			"node_id": "IC_kwDOBLftOs7q39SR",
			"user": {
				"login": "laurent22",
				"id": 1285584,
				"node_id": "MDQ6VXNlcjEyODU1ODQ=",
				"avatar_url": "https://avatars.githubusercontent.com/u/1285584?v=4",
				"gravatar_id": "",
				"url": "https://api.github.com/users/laurent22",
				"html_url": "https://github.com/laurent22",
				"followers_url": "https://api.github.com/users/laurent22/followers",
				"following_url": "https://api.github.com/users/laurent22/following{/other_user}",
				"gists_url": "https://api.github.com/users/laurent22/gists{/gist_id}",
				"starred_url": "https://api.github.com/users/laurent22/starred{/owner}{/repo}",
				"subscriptions_url": "https://api.github.com/users/laurent22/subscriptions",
				"organizations_url": "https://api.github.com/users/laurent22/orgs",
				"repos_url": "https://api.github.com/users/laurent22/repos",
				"events_url": "https://api.github.com/users/laurent22/events{/privacy}",
				"received_events_url": "https://api.github.com/users/laurent22/received_events",
				"type": "User",
				"user_view_type": "public",
				"site_admin": false
			},
			"created_at": "2026-02-22T09:02:47Z",
			"updated_at": "2026-02-22T09:02:47Z",
			"body": "I'm afraid this generated code is not reviewable because too large and complex, so I'm not confident something didn't get broken. I would suggest focussing on issues that you could potentially write yourself without AI assistance",
			"author_association": "OWNER",
			"reactions": {
				"url": "https://api.github.com/repos/laurent22/joplin/issues/comments/3940537489/reactions",
				"total_count": 1,
				"+1": 1,
				"-1": 0,
				"laugh": 0,
				"hooray": 0,
				"confused": 0,
				"heart": 0,
				"rocket": 0,
				"eyes": 0
			},
			"performed_via_github_app": null
		}
	]
}