Repository: platers/obsidian-linter (ts)

Issue:
Bug: Consecutive Blockquotes Merging
## Describe the Bug

After updating to 1.11.0, consecutive blockquotes are merged, the empty lines in between not serving as separation anymore but replaced by ">".

Suspect due to https://github.com/platers/obsidian-linter/pull/658

## How to Reproduce

Example to reproduce issue with

``` markdown
> [!quote] Title 1
> The quote 1

> [!quote] Title 2
> The quote 2
```

## Expected Behavior

Keep empty lines between consecutive blockquotes.

Expected output: No change

What I got:
``` markdown
> [!quote] Title 1
> The quote 1
>
> [!quote] Title 2
> The quote 2
```


Pull request:
Fix Blockquotes Getting Merged when an Empty Line is Between Them
Fixes #668 

Changes Made:
- Added tests to make sure that blockquotes one or more empty lines between them will not get merged
- Updated the logic to make sure that a blockquote that ends with a blank line at the end will get a blank line as its ending or starting empty line
- Fixed a typo in a comment
- Removed an unused param for getting the empty line

Patch:
diff --git a/src/utils/mdast.ts b/src/utils/mdast.ts
index ed65cb3..9058cac 100644
--- a/src/utils/mdast.ts
+++ b/src/utils/mdast.ts
@@ -436,7 +436,7 @@ export function ensureEmptyLinesAroundMathBlock(text: string, numberOfDollarSign
 export function ensureEmptyLinesAroundBlockquotes(text: string): string {
   const positions: Position[] = getPositions(MDAstTypes.Blockquote, text);
   for (const position of positions) {
-    // make sure to shift end to the next new line character just in case blocquotes are nested which can cause changes to move content out of the original position expected
+    // make sure to shift end to the next new line character just in case blockquotes are nested which can cause changes to move content out of the original position expected
     let endIndex = position.end.offset;
     while (endIndex < text.length - 1 && text.charAt(endIndex) !== '\n') {
       endIndex++;
diff --git a/src/utils/strings.ts b/src/utils/strings.ts
index 12b628a..0046d72 100644
--- a/src/utils/strings.ts
+++ b/src/utils/strings.ts
@@ -53,7 +53,7 @@ function getStartOfLineWhitespaceOrBlockquoteLevel(text: string, startPosition:
   return [startOfLine, index];
 }
 
-function getEmptyLine(startOfLine: string, priorLine: string = ''): string {
+function getEmptyLine(priorLine: string = ''): string {
   const [priorLineStart] = getStartOfLineWhitespaceOrBlockquoteLevel(priorLine, priorLine.length);
 
   return '\n' + priorLineStart.trim();
@@ -113,6 +113,12 @@ function makeSureContentHasASingleEmptyLineBeforeItUnlessItStartsAFileForBlockqu
     return text.substring(startOfContent + 1);
   }
 
+  const startingEmptyLines = text.substring(startOfNewContent, startOfContent);
+  const startsWithEmptyLine = startingEmptyLines === '\n' || startingEmptyLines.startsWith('\n\n');
+  if (startsWithEmptyLine) {
+    return text.substring(0, startOfNewContent) + '\n' + text.substring(startOfContent);
+  }
+
   const indexOfLastNewLine = text.lastIndexOf('\n', startOfNewContent - 1);
   let priorLine = '';
   if (indexOfLastNewLine === -1) {
@@ -121,7 +127,7 @@ function makeSureContentHasASingleEmptyLineBeforeItUnlessItStartsAFileForBlockqu
     priorLine = text.substring(indexOfLastNewLine, startOfNewContent);
   }
 
-  return text.substring(0, startOfNewContent) + getEmptyLine(startOfLine, priorLine) + text.substring(startOfContent);
+  return text.substring(0, startOfNewContent) + getEmptyLine(priorLine) + text.substring(startOfContent);
 }
 
 function makeSureContentHasASingleEmptyLineAfterItUnlessItEndsAFile(text: string, endOfContent: number): string {
@@ -188,6 +194,12 @@ function makeSureContentHasASingleEmptyLineAfterItUnlessItEndsAFileForBlockquote
     return text.substring(0, endOfContent);
   }
 
+  const endingEmptyLines = text.substring(endOfContent, endOfNewContent);
+  const endsInEmptyLine = endingEmptyLines === '\n' || endingEmptyLines.endsWith('\n\n');
+  if (endsInEmptyLine) {
+    return text.substring(0, endOfContent) + '\n' + text.substring(endOfNewContent);
+  }
+
   const indexOfSecondNewLineAfterContent = text.indexOf('\n', endOfNewContent + 1);
   let nextLine = '';
   if (indexOfSecondNewLineAfterContent === -1) {
@@ -196,7 +208,8 @@ function makeSureContentHasASingleEmptyLineAfterItUnlessItEndsAFileForBlockquote
     nextLine = text.substring(endOfNewContent + 1, indexOfSecondNewLineAfterContent);
   }
 
-  return text.substring(0, endOfContent) + getEmptyLine(startOfLine, nextLine) + text.substring(endOfNewContent);
+
+  return text.substring(0, endOfContent) + getEmptyLine(nextLine) + text.substring(endOfNewContent);
 }
 
 /**


Test patch:
diff --git a/__tests__/empty-line-around-blockquotes.test.ts b/__tests__/empty-line-around-blockquotes.test.ts
new file mode 100644
index 0000000..c6e3d21
--- /dev/null
+++ b/__tests__/empty-line-around-blockquotes.test.ts
@@ -0,0 +1,94 @@
+import EmptyLineAroundBlockquotes from '../src/rules/empty-line-around-blockquotes';
+import dedent from 'ts-dedent';
+import {ruleTest} from './common';
+
+ruleTest({
+  RuleBuilderClass: EmptyLineAroundBlockquotes,
+  testCases: [
+    { // accounts for https://github.com/platers/obsidian-linter/issues/668
+      testName: 'Make sure that consecutive blockquotes are not merged when a blank line is between them',
+      before: dedent`
+        > [!quote] Title 1
+        > The quote 1
+        ${''}
+        > [!quote] Title 2
+        > The quote 2
+      `,
+      after: dedent`
+        > [!quote] Title 1
+        > The quote 1
+        ${''}
+        > [!quote] Title 2
+        > The quote 2
+      `,
+    },
+    { // accounts for https://github.com/platers/obsidian-linter/issues/668
+      testname: 'Make sure that consecutive blockquotes are not merged when multiple blank lines are between them',
+      before: dedent`
+        > [!quote] title 1
+        > the quote 1
+        ${''}
+        ${''}
+        > [!quote] title 2
+        > the quote 2
+      `,
+      after: dedent`
+        > [!quote] title 1
+        > the quote 1
+        ${''}
+        > [!quote] title 2
+        > the quote 2
+      `,
+    },
+    { // accounts for https://github.com/platers/obsidian-linter/issues/668
+      testName: 'Make sure that consecutive blockquotes are not merged when a blank line is between them',
+      before: dedent`
+        > [!quote] Title 1
+        > The quote 1
+        ${''}
+        > [!quote] Title 2
+        > The quote 2
+        ${''}
+        > [!quote] Title 3
+        > The quote 3
+      `,
+      after: dedent`
+        > [!quote] Title 1
+        > The quote 1
+        ${''}
+        > [!quote] Title 2
+        > The quote 2
+        ${''}
+        > [!quote] Title 3
+        > The quote 3
+      `,
+    },
+    { // accounts for https://github.com/platers/obsidian-linter/issues/668
+      testName: 'Make sure that consecutive blockquotes are not merged when multiple blank lines are between them',
+      before: dedent`
+        > [!quote] Title 1
+        > The quote 1
+        ${''}
+        ${''}
+        > [!quote] Title 2
+        > The quote 2
+        ${''}
+        ${''}
+        ${''}
+        ${''}
+        > [!quote] Title 3
+        > The quote 3
+      `,
+      after: dedent`
+        > [!quote] Title 1
+        > The quote 1
+        ${''}
+        > [!quote] Title 2
+        > The quote 2
+        ${''}
+        > [!quote] Title 3
+        > The quote 3
+      `,
+    },
+  ],
+});