Repository: platers/obsidian-linter (ts)

Issue:
BUG: Multiple Callouts/Blockquotes Merged if They End in an Empty Indicator an Empty Line and Then Another Callout or Blockquote Follows Them
Multiple callouts become condensed into one when the 'empty line around blockquotes' setting is on. The expected result after running the linter would be for the '>' not to be inserted into the document. This new bug essentially removes blank lines between multiple callouts and was introduced with the latest update (V1.11.0)

Before Linter
```
## HEADING 2
> [!TLDR] Titel
> blah blah blah

> [!FAQ] Title
> blah blah blah

> [!NOTES] Title
> blah blah blah
```

After Linter
```
## HEADING 2
> [!TLDR] Titel
> blah blah blah
> 
> [!FAQ] Title
> blah blah blah
>
> [!NOTES] Title
> blah blah blah
```

Pull request description:
Fix Blockquotes Merging When Blank Blockquote Line Between 2 Blockquotes
Fixes #684 

Changes Made:
- When looking at blockquote values prior to it or after it, make sure that a blank line ends the blockquote content search to avoid merging blockquotes.
- Added tests for the scenarios in question

Patch:
diff --git a/src/utils/strings.ts b/src/utils/strings.ts
index 939d0ef..5490779 100644
--- a/src/utils/strings.ts
+++ b/src/utils/strings.ts
@@ -92,21 +92,33 @@ function makeSureContentHasASingleEmptyLineBeforeItUnlessItStartsAFileForBlockqu
   let index = startOfContent;
   let startOfNewContent = startOfContent;
   let lineNestingLevel = 0;
+  let foundABlankLine = false;
+  let previousChar = '';
   while (index >= 0) {
     const currentChar = text.charAt(index);
     if (currentChar.trim() !== '' && currentChar !== '>') {
       break; // if non-whitespace, non-gt-bracket is encountered, then the line has content
     } else if (currentChar === '>') {
+      // if we go from having a blank line at any point to then having more blockquote content we know we have encountered another blockquote
+      if (foundABlankLine) {
+        break;
+      }
+
       lineNestingLevel++;
     } else if (currentChar === '\n') {
       if (lineNestingLevel === 0 || lineNestingLevel === nestingLevel || (lineNestingLevel + 1) === nestingLevel) {
         startOfNewContent = index;
         lineNestingLevel = 0;
+
+        if (previousChar === '\n') {
+          foundABlankLine = true;
+        }
       } else {
         break;
       }
     }
     index--;
+    previousChar = currentChar;
   }
 
   if (index < 0 || startOfNewContent === 0) {
@@ -169,11 +181,18 @@ function makeSureContentHasASingleEmptyLineAfterItUnlessItEndsAFileForBlockquote
   let endOfNewContent = endOfContent;
   let isFirstNewLine = true;
   let lineNestingLevel = 0;
+  let foundABlankLine = false;
+  let previousChar = '';
   while (index < text.length) {
     const currentChar = text.charAt(index);
     if (currentChar.trim() !== '' && currentChar !== '>') {
       break; // if non-whitespace is encountered, then the line has content
     } else if (currentChar === '>') {
+      // if we go from having a blank line at any point to then having more blockquote content we know we have encountered another blockquote
+      if (foundABlankLine) {
+        break;
+      }
+
       lineNestingLevel++;
     } else if (currentChar === '\n') {
       if (lineNestingLevel === 0 || lineNestingLevel === nestingLevel || (lineNestingLevel + 1) === nestingLevel) {
@@ -183,11 +202,17 @@ function makeSureContentHasASingleEmptyLineAfterItUnlessItEndsAFileForBlockquote
         } else {
           endOfNewContent = index;
         }
+
+        if (previousChar === '\n') {
+          foundABlankLine = true;
+        }
       } else {
         break;
       }
     }
     index++;
+
+    previousChar = currentChar;
   }
 
   if (index === text.length || endOfNewContent === text.length - 1) {


Test patch:
diff --git a/__tests__/empty-line-around-blockquotes.test.ts b/__tests__/empty-line-around-blockquotes.test.ts
index c6e3d21..70fa4d1 100644
--- a/__tests__/empty-line-around-blockquotes.test.ts
+++ b/__tests__/empty-line-around-blockquotes.test.ts
@@ -23,7 +23,7 @@ ruleTest({
       `,
     },
     { // 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',
+      testName: 'Make sure that consecutive blockquotes are not merged when multiple blank lines are between them',
       before: dedent`
         > [!quote] title 1
         > the quote 1
@@ -90,5 +90,41 @@ ruleTest({
         > The quote 3
       `,
     },
+    { // accounts for https://github.com/platers/obsidian-linter/issues/684
+      testName: 'Make sure that consecutive blockquotes do not get merged when the first one ends with an empty blockquote line',
+      before: dedent`
+        > [!FAQ] Title
+        > 
+        ${''}
+        > [!NOTES] Title
+        > Content
+      `,
+      after: dedent`
+        > [!FAQ] Title
+        > 
+        ${''}
+        > [!NOTES] Title
+        > Content
+      `,
+    },
+    { // accounts for https://github.com/platers/obsidian-linter/issues/684
+      testName: 'Make sure that consecutive blockquotes do not get merged when the second one starts with an empty blockquote line',
+      before: dedent`
+        > [!FAQ] Title
+        > Content here
+        ${''}
+        >
+        > [!NOTES] Title
+        > Content
+      `,
+      after: dedent`
+        > [!FAQ] Title
+        > Content here
+        ${''}
+        >
+        > [!NOTES] Title
+        > Content
+      `,
+    },
   ],
 });