Repository: platers/obsidian-linter (ts)

Issue:
Bug: bar links with hash get embraced repeatedly on lint.
## Describe the Bug

a bare link with any trailing hash part like `https://foo.bar#hash` get embraced with `<` and `>` repeatedly on lint.


## How to Reproduce

Consider `https://foo.bar#hash`, when the file is linted three times, would result in `<<<https://foo.bar#hash>>>`.


Pull request:
Fix Issue with Additional Angle Brackets Around URL When It Ends in `#some-text-here`
Fixes #339 

Changes Made:
- Updated regex for tags to make sure they are only matched on if they start a line or follow some kind of whitespace
- Added logic to remove multiple angle brackets
- Added an example to show the addition in the logic
- Added a UT so we hopefully do not cause the same issue down the road

Patch:
diff --git a/docs/rules.md b/docs/rules.md
index 72c8d6b..6b8683a 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -578,7 +578,7 @@ modified: Wednesday, January 1st 2020, 4:00:00 pm
 
 Alias: `yaml-title`
 
-Inserts the title of the file into the YAML frontmatter. Gets the title from the first H1 or filename.
+Inserts the title of the file into the YAML frontmatter. Gets the title from the first H1 or filename if there is no H1.
 
 Options:
 - Title Key: Which YAML key to use for title
@@ -1253,6 +1253,23 @@ backticks around a url should stay the same, but only if the only contents of th
 single quotes around a url should stay the same, but only if the contents of the single quotes is the url: '<https://github.com> some text here'
 double quotes around a url should stay the same, but only if the contents of the double quotes is the url: "<https://github.com> some text here"
 ``````
+Example: Multiple angle brackets at the start and or end of a url will be reduced down to 1
+
+Before:
+
+``````markdown
+<<https://github.com>
+<https://google.com>>
+<<https://gitlab.com>>
+``````
+
+After:
+
+``````markdown
+<https://github.com>
+<https://google.com>
+<https://gitlab.com>
+``````
 
 ### Proper Ellipsis
 
diff --git a/src/rules/no-bare-urls.ts b/src/rules/no-bare-urls.ts
index 728552f..798a4f7 100644
--- a/src/rules/no-bare-urls.ts
+++ b/src/rules/no-bare-urls.ts
@@ -39,8 +39,25 @@ export default class NoBareUrls extends RuleBuilder<NoBareUrlsOptions> {
 
         const previousChar = urlStart === 0 ? undefined : text.charAt(urlStart - 1);
         const nextChar = urlEnd >= text.length ? undefined : text.charAt(urlEnd);
-        if (previousChar != undefined && (previousChar === '`' || previousChar === '"' || previousChar === '\'' || previousChar === '[' || previousChar === '<') &&
-          nextChar != undefined && (nextChar === '`' || nextChar === '"' || nextChar === '\'' || nextChar === ']' || nextChar === '>')) {
+        if (previousChar != undefined && (previousChar === '`' || previousChar === '"' || previousChar === '\'' || previousChar === '[') &&
+          nextChar != undefined && (nextChar === '`' || nextChar === '"' || nextChar === '\'' || nextChar === ']')) {
+          startSearch = urlStart + urlMatch.length;
+          continue;
+        }
+
+        if (previousChar != undefined && previousChar === '<' && nextChar != undefined && nextChar === '>') {
+          let startOfOpeningChevrons = urlStart - 1;
+          while (startOfOpeningChevrons > 0 && text.charAt(startOfOpeningChevrons-1) === '<') {
+            startOfOpeningChevrons--;
+          }
+
+          let endOfClosingChevrons = urlEnd;
+          while (endOfClosingChevrons < text.length -1 && text.charAt(endOfClosingChevrons+1) === '>') {
+            endOfClosingChevrons++;
+          }
+
+          text = replaceTextBetweenStartAndEndWithNewValue(text, startOfOpeningChevrons, endOfClosingChevrons+1, '<' + urlMatch + '>');
+
           startSearch = urlStart + urlMatch.length;
           continue;
         }
@@ -94,6 +111,19 @@ export default class NoBareUrls extends RuleBuilder<NoBareUrlsOptions> {
           double quotes around a url should stay the same, but only if the contents of the double quotes is the url: "<https://github.com> some text here"
         `,
       }),
+      new ExampleBuilder({
+        description: 'Multiple angle brackets at the start and or end of a url will be reduced down to 1',
+        before: dedent`
+          <<https://github.com>
+          <https://google.com>>
+          <<https://gitlab.com>>
+        `,
+        after: dedent`
+          <https://github.com>
+          <https://google.com>
+          <https://gitlab.com>
+        `,
+      }),
     ];
   }
   get optionBuilders(): OptionBuilderBase<NoBareUrlsOptions>[] {
diff --git a/src/rules/yaml-title.ts b/src/rules/yaml-title.ts
index 53356dc..51487a1 100644
--- a/src/rules/yaml-title.ts
+++ b/src/rules/yaml-title.ts
@@ -20,7 +20,7 @@ export default class YamlTitle extends RuleBuilder<YamlTitleOptions> {
     return 'YAML Title';
   }
   get description(): string {
-    return 'Inserts the title of the file into the YAML frontmatter. Gets the title from the first H1 or filename.';
+    return 'Inserts the title of the file into the YAML frontmatter. Gets the title from the first H1 or filename if there is no H1.';
   }
   get type(): RuleType {
     return RuleType.YAML;
diff --git a/src/utils/regex.ts b/src/utils/regex.ts
index fc8ca5d..b4646ce 100644
--- a/src/utils/regex.ts
+++ b/src/utils/regex.ts
@@ -10,7 +10,7 @@ export const indentedBlockRegex = '^((\t|( {4})).*\n)+';
 export const codeBlockRegex = new RegExp(`${backtickBlockRegexTemplate}|${tildeBlockRegexTemplate}|${indentedBlockRegex}`, 'gm');
 export const wikiLinkRegex = /(!?)(\[{2}[^[\n\]]*\]{2})/g;
 export const genericLinkRegex = /^!?\[.*\](.*)$/;
-export const tagRegex = /#[^\s#]{1,}/g;
+export const tagRegex = /(?:\s|^)#[^\s#]{1,}/g;
 export const obsidianMultilineCommentRegex = /^%%\n[^%]*\n%%/gm;
 export const wordSplitterRegex = /[,\s]+/;
 


Test patch:
diff --git a/__tests__/no-bare-urls.test.ts b/__tests__/no-bare-urls.test.ts
index a335001..5270180 100644
--- a/__tests__/no-bare-urls.test.ts
+++ b/__tests__/no-bare-urls.test.ts
@@ -17,5 +17,15 @@ ruleTest({
         ![image alt text](https://github.com/favicon.ico)
       `,
     },
+    {
+      // accounts for https://github.com/platers/obsidian-linter/issues/339
+      testName: 'Urls with a hashtag referring to header that are surrounded by `<` and `> should be left alone',
+      before: dedent`
+        <https://google.com#hashtag>
+      `,
+      after: dedent`
+        <https://google.com#hashtag>
+      `,
+    },
   ],
 });