Repository: platers/obsidian-linter
Pull request #92 (2021-10-04 19:27:26)

insert yaml attributes rule
implements #28 


Patch:
diff --git a/README.md b/README.md
index 4ca33f6..09e1014 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ Make sure to use Node 15.x or higher.
 Documentation for all rules can be found in the [rules docs](https://github.com/platers/obsidian-linter/blob/master/docs/rules.md). The docs are updated before the plugin is released, so may not be completely accurate.
 
 - [format-tags-in-yaml](https://github.com/platers/obsidian-linter/blob/master/docs/rules.md#format-tags-in-yaml)
+- [insert-yaml-attributes](https://github.com/platers/obsidian-linter/blob/master/docs/rules.md#insert-yaml-attributes)
 - [yaml-timestamp](https://github.com/platers/obsidian-linter/blob/master/docs/rules.md#yaml-timestamp)
 - [header-increment](https://github.com/platers/obsidian-linter/blob/master/docs/rules.md#header-increment)
 - [file-name-heading](https://github.com/platers/obsidian-linter/blob/master/docs/rules.md#file-name-heading)
diff --git a/docs/rules.md b/docs/rules.md
index 4cfe81a..b449e07 100644
--- a/docs/rules.md
+++ b/docs/rules.md
@@ -47,6 +47,39 @@ tags: one, two, three
 ---
 ```
 
+### Insert YAML attributes
+
+Alias: `insert-yaml-attributes`
+
+Inserts the given YAML attributes into the YAML frontmatter. Put each attribute on a single line.
+
+Options:
+- Text to insert: Text to insert into the YAML frontmatter
+	- Default: `aliases: 
+tags: `
+
+Example: Insert static lines into YAML frontmatter. Text to insert: `aliases:
+tags: doc
+animal: dog`
+
+Before:
+
+```markdown
+---
+animal: cat
+---
+```
+
+After:
+
+```markdown
+---
+aliases:
+tags: doc
+animal: cat
+---
+```
+
 ### YAML Timestamp
 
 Alias: `yaml-timestamp`
diff --git a/src/main.ts b/src/main.ts
index 240de85..180ef39 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -3,7 +3,7 @@ import {LinterSettings, Options, rules} from './rules';
 import {getDisabledRules} from './utils';
 import Diff from 'diff';
 import moment from 'moment';
-import {BooleanOption, DropdownOption, MomentFormatOption, TextOption} from './option';
+import {BooleanOption, DropdownOption, MomentFormatOption, TextAreaOption, TextOption} from './option';
 import dedent from 'ts-dedent';
 
 export default class LinterPlugin extends Plugin {
@@ -208,6 +208,20 @@ class SettingTab extends PluginSettingTab {
                 plugin.saveData(plugin.settings);
               });
             });
+      }; ;
+
+      TextAreaOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
+        new Setting(containerEl)
+            .setName(this.name)
+            .setDesc(this.description)
+            .addTextArea((textbox) => {
+              textbox.setValue(settings.ruleConfigs[this.ruleName][this.name]);
+              textbox.onChange((value) => {
+                this.setOption(value, settings);
+                plugin.settings = settings;
+                plugin.saveData(plugin.settings);
+              });
+            });
       };
 
       MomentFormatOption.prototype.display = function(containerEl: HTMLElement, settings: LinterSettings, plugin: LinterPlugin): void {
diff --git a/src/option.ts b/src/option.ts
index 2393ef4..fc0282e 100644
--- a/src/option.ts
+++ b/src/option.ts
@@ -43,6 +43,10 @@ export class TextOption extends Option {
   public defaultValue: string;
 }
 
+export class TextAreaOption extends Option {
+  public defaultValue: string;
+}
+
 export class MomentFormatOption extends Option {
   public defaultValue: boolean;
 }
diff --git a/src/rules.ts b/src/rules.ts
index f9d3f15..39b2988 100644
--- a/src/rules.ts
+++ b/src/rules.ts
@@ -1,7 +1,8 @@
 import dedent from 'ts-dedent';
 import moment from 'moment';
-import {formatYAML, headerRegex, ignoreCodeBlocksAndYAML, initYAML, insert} from './utils';
-import {Option, BooleanOption, MomentFormatOption, TextOption, DropdownOption, DropdownRecord} from './option';
+import {formatYAML, headerRegex, ignoreCodeBlocksAndYAML, initYAML, insert, yamlRegex} from './utils';
+import {Option, BooleanOption, MomentFormatOption, TextOption, DropdownOption, DropdownRecord, TextAreaOption} from './option';
+import {load} from 'js-yaml';
 
 export type Options = { [optionName: string]: any };
 type ApplyFunction = (text: string, options?: Options) => string;
@@ -462,6 +463,49 @@ export const rules: Rule[] = [
         ),
       ],
   ),
+  new Rule(
+      'Insert YAML attributes',
+      'Inserts the given YAML attributes into the YAML frontmatter. Put each attribute on a single line.',
+      RuleType.YAML,
+      (text: string, options = {}) => {
+        text = initYAML(text);
+        return formatYAML(text, (text) => {
+          const insert_lines = String(options['Text to insert']).split('\n').reverse();
+          const parsed_yaml = load(text.match(yamlRegex)[1]) as Record<string, any>;
+
+          for (const line of insert_lines) {
+            const key = line.split(':')[0];
+            if (!parsed_yaml.hasOwnProperty(key)) {
+              text = text.replace(/^---\n/, `---\n${line}\n`);
+            }
+          }
+
+          return text;
+        });
+      },
+      [
+        new Example(
+            'Insert static lines into YAML frontmatter. Text to insert: `aliases:\ntags: doc\nanimal: dog`',
+            dedent`
+            ---
+            animal: cat
+            ---
+            `,
+            dedent`
+            ---
+            aliases:
+            tags: doc
+            animal: cat
+            ---
+            `,
+            {'Text to insert': 'aliases:\ntags: doc\nanimal: dog'},
+        ),
+      ],
+      [
+        new TextAreaOption('Text to insert', 'Text to insert into the YAML frontmatter', 'aliases: \ntags: '),
+      ],
+  ),
+
   new Rule(
       'YAML Timestamp',
       'Keep track of the date the file was last edited in the YAML front matter. Gets dates from file metadata.',
diff --git a/src/utils.ts b/src/utils.ts
index c22644a..bc6d28e 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -91,9 +91,9 @@ export function formatYAML(text: string, func: (text: string) => string): string
     return text;
   }
 
-  let yaml = text.match(yamlRegex)[0];
-  yaml = func(yaml);
-  text = text.replace(yamlRegex, yaml);
+  const oldYaml = text.match(yamlRegex)[0];
+  const newYaml = func(oldYaml);
+  text = text.replace(oldYaml, newYaml);
 
   return text;
 }


Test patch:
diff --git a/src/test.ts b/src/test.ts
index 5d5d9a4..5d28883 100644
--- a/src/test.ts
+++ b/src/test.ts
@@ -392,6 +392,19 @@ describe('yaml timestamp', () => {
     expect(rulesDict['yaml-timestamp'].apply(before, {'Date Created': true})).toBe(after);
   });
 });
+describe('Insert yaml attributes', () => {
+  it('Inits yaml is not exist', () => {
+    const before = dedent`
+    `;
+    const after = dedent`
+    ---
+    tags:
+    ---
+    
+    `;
+    expect(rulesDict['insert-yaml-attributes'].apply(before, {'Text to insert': 'tags:'})).toBe(after);
+  });
+});
 
 describe('Disabled rules parsing', () => {
   it('No YAML', () => {