Repository: platers/obsidian-linter (ts)

Issue:
YAMLException$1 reason: 'end of the stream or a document separator is expected at line x, column x:'
After spending some time with different options I wanted to use, I tried to lint all files in my vault...

Then hit this issue on many many files;

From lint all files in vault
```
main.ts:169 Linting error in file: Notes/TMS/Projects/Open Telemetry Conference/OpenTelemetry Research.md
main.ts:170 YAMLException$1 {name: 'YAMLException', reason: 'end of the stream or a document separator is expected', mark: Mark, message: 'end of the stream or a document separator is expec…column 1:\n    Capture point is metric event\n    ^', stack: 'YAMLException: end of the stream or a document sep…idian.md/app.js:1:1433729), <anonymous>:28440:32)'}mark: Mark {name: null, buffer: '---\n\n#date/2020/11/04\n\n## [OpenTelemetry - CNCF · …cting context from the RPC headers or envelope.\n\x00', position: 515, line: 28, column: 0}message: "end of the stream or a document separator is expected at line 29, column 1:\n    Capture point is metric event\n    ^"name: "YAMLException"reason: "end of the stream or a document separator is expected"stack: "YAMLException: end of the stream or a document separator is expected at line 29, column 1:\n    Capture point is metric event\n    ^\n    at generateError (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:19187:10)\n    at throwError (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:19193:9)\n    at readDocument (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:20565:5)\n    at loadDocuments (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:20608:5)\n    at Object.load$1 [as load] (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:20634:19)\n    at loadYAML (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25220:32)\n    at eval (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25691:33)\n    at formatYAML (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25180:21)\n    at Rule.Example.Text to insert [as apply] (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25689:16)\n    at LinterPlugin.lintText (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:28440:32)"[[Prototype]]: Error
eval @ main.ts:170
fulfilled @ tslib.es6.js:73
Promise.then (async)
step @ tslib.es6.js:75
eval @ tslib.es6.js:76
__awaiter @ tslib.es6.js:72
runLinterFile @ main.ts:161
eval @ main.ts:177
eval @ tslib.es6.js:76
__awaiter @ tslib.es6.js:72
eval @ main.ts:175
eval @ main.ts:175
eval @ tslib.es6.js:76
__awaiter @ tslib.es6.js:72
runLinterAllFiles @ main.ts:174
eval @ main.ts:400
eval @ tslib.es6.js:76
__awaiter @ tslib.es6.js:72
eval @ main.ts:397
```


On save
```
main.ts:184 running linter
app.js:1 Command failed to execute:  editor:save-file
app.js:1 YAMLException$1 {name: 'YAMLException', reason: 'end of the stream or a document separator is expected', mark: Mark, message: 'end of the stream or a document separator is expec…column 1:\n    Capture point is metric event\n    ^', stack: 'YAMLException: end of the stream or a document sep…idian.md/app.js:1:1433729), <anonymous>:28440:32)'}mark: Markbuffer: "---\n\n#date/2020/11/04\n\n## [OpenTelemetry - CNCF · GitHub](https://github.com/open-telemetry)\n\n## Trace;\n\nEach has a trace identifier\n\nA collection of spans\n- root + children\n- Each has its own span identifier\n- Each has a span context identifier\n\nTracer Interface object\n- Tracks current span\n- Allows access to span to add attribs, events\n- Allows finishing span once workload is complete\n\nTracer provider\n- Allows for multiple tracers to be instantiated in a single process, with different options\n\n## Metric\n\nCapture point is metric event\n- metric plus time captured\n\nThree metric instruments\n1. Counter - value summed over time\n2. Measure - value aggregated over time (sum, count, last value, histogram)\n3. Observer - current value\n\n## Context\n\nTrace's span context\n\nTelemetry context (generalised), also known as correlation context\n- Set of keys and values that can be serialised and propagated between services that are using OpenTelemetry.\n- Used to propagate values from one service to next, but also between functions with a service\n\nPropagation\n- Either referring to the act of serializing and deserializing a context object and passing it to a new service, or\n- Referring to passing it from thread to thread (or thread-like object) in a service.\n   - The specifics of this depend heavily on individual language features\n- For service-to-service communication (often referred to as an RPC, a remote process call) you’ll see references to injecting and extracting context from the RPC headers or envelope.\n\u0000"column: 0line: 25name: nullposition: 512[[Prototype]]: ObjectgetSnippet: ƒ getSnippet(indent, maxLength)length: 2name: "getSnippet"prototype: {constructor: ƒ}arguments: (...)caller: (...)[[FunctionLocation]]: mark.js:16[[Prototype]]: ƒ ()[[Scopes]]: Scopes[3]0: Closure (anonymous) {obsidian: Module, commonjsGlobal: global, __awaiter: ƒ, dedent: ƒ, commonjsRequire: ƒ, …}1: Script {Pos: ƒ}2: Global {window: global, self: global, document: document, name: '', location: Location, …}toString: ƒ toString(compact)constructor: ƒ Mark(name, buffer, position, line, column)[[Prototype]]: Objectmessage: "end of the stream or a document separator is expected at line 26, column 1:\n    Capture point is metric event\n    ^"name: "YAMLException"reason: "end of the stream or a document separator is expected"stack: "YAMLException: end of the stream or a document separator is expected at line 26, column 1:\n    Capture point is metric event\n    ^\n    at generateError (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:19187:10)\n    at throwError (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:19193:9)\n    at readDocument (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:20565:5)\n    at loadDocuments (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:20608:5)\n    at Object.load$1 [as load] (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:20634:19)\n    at loadYAML (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25220:32)\n    at eval (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25691:33)\n    at formatYAML (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25180:21)\n    at Rule.Example.Text to insert [as apply] (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:25689:16)\n    at LinterPlugin.lintText (eval at <anonymous> (app://obsidian.md/app.js:1:1433729), <anonymous>:28440:32)"[[Prototype]]: Errorconstructor: ƒ YAMLException$1(reason, mark)length: 2name: "YAMLException$1"prototype: Error {constructor: ƒ, toString: ƒ}constructor: ƒ YAMLException$1(reason, mark)toString: ƒ toString(compact)[[Prototype]]: Objectconstructor: ƒ Error()message: ""name: "Error"toString: ƒ toString()[[Prototype]]: Objectconstructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()__defineGetter__: ƒ __defineGetter__()__defineSetter__: ƒ __defineSetter__()__lookupGetter__: ƒ __lookupGetter__()__lookupSetter__: ƒ __lookupSetter__()__proto__: (...)get __proto__: ƒ __proto__()set __proto__: ƒ __proto__()arguments: (...)caller: (...)[[FunctionLocation]]: exception.js:5[[Prototype]]: ƒ ()[[Scopes]]: Scopes[3]toString: ƒ toString(compact)[[Prototype]]: Object
e.executeCommandById @ app.js:1
e.onTrigger @ app.js:1
e.handleKey @ app.js:1
e.handleKey @ app.js:1
t.handleKey @ app.js:1
e.onKeyEvent @ app.js:1
```


File in question
[OpenTelemetry Research.md](https://github.com/platers/obsidian-linter/files/8216652/OpenTelemetry.Research.md)



Pull request:
Fix Issue with Yaml FrontMatter Including More Than Initial Frontmatter
@platers 

Fixes #176 

Changes Made:
- Updated yaml regex identification to not allow `---` in it
- Added a test to make sure this issue is not reintroduced by accident

Please let me know if it is fine to not do a peer review on these PRs. I come from a background where peer-reviews are required before merging.

Patch:
diff --git a/src/utils.ts b/src/utils.ts
index d6ef045..5fe71a8 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -8,7 +8,7 @@ import remarkGfm from 'remark-gfm';
 
 export const headerRegex = /^(\s*)(#+)(\s+)(.*)$/;
 export const fencedRegexTemplate = '^XXX\\.*?\n(?:((?:.|\n)*?)\n)?XXX(?=\\s|$)$';
-export const yamlRegex = /^---\n(?:((?:.|\n)*?)\n)?---(?=\n|$)/;
+export const yamlRegex = /^---\n((?:(((?!---)(?:.|\n)*?)\n)?))---(?=\n|$)/;
 export const backtickBlockRegexTemplate = fencedRegexTemplate.replaceAll('X', '`');
 export const tildeBlockRegexTemplate = fencedRegexTemplate.replaceAll('X', '~');
 export const indentedBlockRegex = '^((\t|( {4})).*\n)+';


Test patch:
diff --git a/src/test.ts b/src/test.ts
index c223459..9643a72 100644
--- a/src/test.ts
+++ b/src/test.ts
@@ -532,7 +532,7 @@ describe('yaml timestamp', () => {
   });
 });
 describe('Insert yaml attributes', () => {
-  it('Inits yaml is not exist', () => {
+  it('Inits yaml if it does not exist', () => {
     const before = dedent`
     `;
     const after = dedent`
@@ -540,6 +540,33 @@ describe('Insert yaml attributes', () => {
     tags:
     ---
     
+    `;
+    expect(rulesDict['insert-yaml-attributes'].apply(before, {'Text to insert': 'tags:'})).toBe(after);
+  });
+  // accounts for https://github.com/platers/obsidian-linter/issues/176
+  it('Inits yaml when the file has --- in it and no frontmatter', () => {
+    const before = dedent`
+    # Heading
+    Text
+
+    # Heading
+    - Text
+     - Text
+    ---
+
+    `;
+    const after = dedent`
+    ---
+    tags:
+    ---
+    # Heading
+    Text
+
+    # Heading
+    - Text
+     - Text
+    ---
+
     `;
     expect(rulesDict['insert-yaml-attributes'].apply(before, {'Text to insert': 'tags:'})).toBe(after);
   });