From 8f37c029d33732ce7575749d76cf36caebd11f87 Mon Sep 17 00:00:00 2001 From: Peter Kaufman Date: Fri, 15 Nov 2024 14:23:37 -0500 Subject: [PATCH 1/5] added an initial change that may not even work long term --- package-lock.json | 21 +++++++------- package.json | 3 +- src/rules/yaml-key-sort.ts | 58 +++++++++++++++++++------------------- src/utils/yaml.ts | 19 +++++++++++++ 4 files changed, 60 insertions(+), 41 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6f277dd..0dc5dca8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-linter", - "version": "1.27.0-rc-1", + "version": "1.27.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-linter", - "version": "1.27.0-rc-1", + "version": "1.27.1", "license": "MIT", "dependencies": { "@popperjs/core": "^2.11.6", @@ -26,7 +26,8 @@ "moment-parseformat": "^4.0.0", "quick-lru": "^7.0.0", "ts-dedent": "^2.2.0", - "unist-util-visit": "^5.0.0" + "unist-util-visit": "^5.0.0", + "yaml": "^2.6.0" }, "devDependencies": { "@babel/core": "^7.24.0", @@ -11760,10 +11761,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "dev": true, + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", "bin": { "yaml": "bin.mjs" }, @@ -20021,10 +20021,9 @@ "dev": true }, "yaml": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.1.tgz", - "integrity": "sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==", - "dev": true + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", + "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==" }, "yargs": { "version": "17.7.2", diff --git a/package.json b/package.json index c58f7263..e36cac00 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "moment-parseformat": "^4.0.0", "quick-lru": "^7.0.0", "ts-dedent": "^2.2.0", - "unist-util-visit": "^5.0.0" + "unist-util-visit": "^5.0.0", + "yaml": "^2.6.0" } } diff --git a/src/rules/yaml-key-sort.ts b/src/rules/yaml-key-sort.ts index 345e0bf9..61a357dc 100644 --- a/src/rules/yaml-key-sort.ts +++ b/src/rules/yaml-key-sort.ts @@ -1,7 +1,8 @@ import {Options, RuleType} from '../rules'; import RuleBuilder, {BooleanOptionBuilder, DropdownOptionBuilder, ExampleBuilder, OptionBuilderBase, TextAreaOptionBuilder} from './rule-builder'; import dedent from 'ts-dedent'; -import {getYAMLText, getYamlSectionValue, loadYAML, removeYamlSection, setYamlSection} from '../utils/yaml'; +import {getYAMLJSON as parseYaml, getYAMLText, getYamlSectionValue, loadYAML, removeYamlSection, setYamlSection} from '../utils/yaml'; +import {Document} from 'yaml'; type YamlSortOrderForOtherKeys = 'None' | 'Ascending Alphabetical' | 'Descending Alphabetical'; @@ -40,7 +41,7 @@ export default class YamlKeySort extends RuleBuilder { return text; } - let yamlText = oldYaml; + const yamlText = oldYaml; const priorityAtStartOfYaml: boolean = options.priorityKeysAtStartOfYaml; const yamlKeys: string[] = options.yamlKeyPrioritySortOrder; @@ -57,55 +58,54 @@ export default class YamlKeySort extends RuleBuilder { } const yamlObject = loadYAML(yamlText); - const sortKeysResult = this.getYAMLKeysSorted(yamlText, yamlKeys, yamlObject); - const priorityKeysSorted = sortKeysResult.sortedYamlKeyValues; - yamlText = sortKeysResult.remainingYaml; + const doc = parseYaml(yamlText); + const newDoc = new Document(null, yamlObject.options); + // newDoc.items.splice(0, 1); + let remainingKeys = this.getYAMLKeysSorted(yamlKeys, doc, newDoc); + // const priorityKeysSorted = sortKeysResult.sortedYamlKeyValues; + // yamlText = sortKeysResult.remainingYaml; const sortOrder = options.yamlSortOrderForOtherKeys; if (yamlObject == null) { - return this.getTextWithNewYamlFrontmatter(text, oldYaml, priorityKeysSorted, yamlText, priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); + return this.getTextWithNewYamlFrontmatter(text, oldYaml, newDoc.toString(), doc.toString(), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } - let remainingKeys = Object.keys(yamlObject); let sortMethod: (previousKey: string, currentKey: string) => number; if (sortOrder === 'Ascending Alphabetical') { sortMethod = this.sortAlphabeticallyAsc; } else if (sortOrder === 'Descending Alphabetical') { sortMethod = this.sortAlphabeticallyDesc; } else { - return this.getTextWithNewYamlFrontmatter(text, oldYaml, priorityKeysSorted, yamlText, priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); + return this.getTextWithNewYamlFrontmatter(text, oldYaml, newDoc.toString(), doc.toString(), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } remainingKeys = remainingKeys.sort(sortMethod); - const remainingKeysSortResult = this.getYAMLKeysSorted(yamlText, remainingKeys, yamlObject); + this.getYAMLKeysSorted(remainingKeys, doc, newDoc); - return this.getTextWithNewYamlFrontmatter(text, oldYaml, priorityKeysSorted, remainingKeysSortResult.sortedYamlKeyValues, priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); + return this.getTextWithNewYamlFrontmatter(text, oldYaml, newDoc.toString(), doc.toString(), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } - getYAMLKeysSorted(yaml: string, keys: string[], yamlObject: any): {remainingYaml: string, sortedYamlKeyValues: string} { - let specifiedYamlKeysSorted = ''; + getYAMLKeysSorted(keys: string[], yamlObject: Document, newDocument: Document): string[] { + // @ts-ignore TODO: fix the need for ts-ignore here + const initialKeys = yamlObject.contents.items as object[]; for (const key of keys) { // we skip any nested elements when sorting to prevent issues where possible - if (!(key in yamlObject)) { - continue; - } - - const value = getYamlSectionValue(yaml, key, false); - - if (value !== null) { - if (value.includes('\n')) { - specifiedYamlKeysSorted += `${key}:${value}\n`; - } else { - specifiedYamlKeysSorted += `${key}: ${value}\n`; + for (let i = 0; i < initialKeys.length; i++) { + // @ts-ignore TODO: fix the need for this ts ignore + if (initialKeys[i].key == key) { + newDocument.add(initialKeys[i]); + initialKeys.splice(i, 1); + break; } - - yaml = removeYamlSection(yaml, key, false); } } - return { - remainingYaml: yaml, - sortedYamlKeyValues: specifiedYamlKeysSorted, - }; + const remainingKeys = [] as string[]; + for (const val of initialKeys) { + // @ts-ignore TODO: fix the need for this ts ignore + remainingKeys.push(val.key as string); + } + + return remainingKeys; } updateDateModifiedIfYamlChanged(oldYaml: string, newYaml: string, dateModifiedKey: string, currentTimeFormatted: string): string { if (oldYaml == newYaml) { diff --git a/src/utils/yaml.ts b/src/utils/yaml.ts index bf55c190..30585e7f 100644 --- a/src/utils/yaml.ts +++ b/src/utils/yaml.ts @@ -2,6 +2,7 @@ import {load, dump} from 'js-yaml'; import {getTextInLanguage} from '../lang/helpers'; import {escapeDollarSigns, yamlRegex} from './regex'; import {isNumeric} from './strings'; +import YAML from 'yaml'; export const OBSIDIAN_TAG_KEY_SINGULAR = 'tag'; @@ -101,6 +102,24 @@ export function loadYAML(yaml_text: string): any { return parsed_yaml; } +export function getYAMLJSON(yaml_text: string): YAML.Document { + if (yaml_text == null) { + return null; + } + + // replacing tabs at the beginning of new lines with 2 spaces fixes loading YAML that has tabs at the start of a line + // https://github.com/platers/obsidian-linter/issues/157 + const parsed_yaml = YAML.parseDocument(yaml_text.replace(/\n(\t)+/g, '\n ')); + if (parsed_yaml == null) { + return null; + } + + // console.log(parsed_yaml); + // console.log(parsed_yaml.toString()); + + return parsed_yaml; +} + export enum TagSpecificArrayFormats { SingleStringSpaceDelimited = 'single string space delimited', SingleLineSpaceDelimited = 'single-line space delimited', From f9b49507aa37186a89e8d9e34af42a41fb0062d6 Mon Sep 17 00:00:00 2001 From: Peter Kaufman Date: Fri, 15 Nov 2024 18:02:06 -0500 Subject: [PATCH 2/5] swapped over to yaml from js-yaml which seems to be working according to the UTs --- src/rules/yaml-key-sort.ts | 59 ++++++++++++++++++++++++-------------- src/utils/yaml.ts | 25 +++++++++------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/src/rules/yaml-key-sort.ts b/src/rules/yaml-key-sort.ts index 61a357dc..409819aa 100644 --- a/src/rules/yaml-key-sort.ts +++ b/src/rules/yaml-key-sort.ts @@ -1,8 +1,8 @@ import {Options, RuleType} from '../rules'; import RuleBuilder, {BooleanOptionBuilder, DropdownOptionBuilder, ExampleBuilder, OptionBuilderBase, TextAreaOptionBuilder} from './rule-builder'; import dedent from 'ts-dedent'; -import {getYAMLJSON as parseYaml, getYAMLText, getYamlSectionValue, loadYAML, removeYamlSection, setYamlSection} from '../utils/yaml'; -import {Document} from 'yaml'; +import {parseYAML, getYAMLText, loadYAML, setYamlSection, astToString} from '../utils/yaml'; +import {Document, YAMLMap} from 'yaml'; type YamlSortOrderForOtherKeys = 'None' | 'Ascending Alphabetical' | 'Descending Alphabetical'; @@ -22,6 +22,18 @@ class YamlKeySortOptions implements Options { yamlSortOrderForOtherKeys?: YamlSortOrderForOtherKeys = 'None'; } +interface Key { + value?: string; +} + +interface Node { + constructor: { name: string }; + key?: Key; + value?: any; + items?: [string, any][]; + moved?: boolean; +} + @RuleBuilder.register export default class YamlKeySort extends RuleBuilder { constructor() { @@ -58,16 +70,15 @@ export default class YamlKeySort extends RuleBuilder { } const yamlObject = loadYAML(yamlText); - const doc = parseYaml(yamlText); - const newDoc = new Document(null, yamlObject.options); - // newDoc.items.splice(0, 1); - let remainingKeys = this.getYAMLKeysSorted(yamlKeys, doc, newDoc); - // const priorityKeysSorted = sortKeysResult.sortedYamlKeyValues; - // yamlText = sortKeysResult.remainingYaml; + const doc = parseYAML(yamlText); + const startingPriorityKeys = new Document(yamlObject.options); + startingPriorityKeys.contents = new YAMLMap(); + + let remainingKeys = this.getYAMLKeysSorted(yamlKeys, doc, startingPriorityKeys); const sortOrder = options.yamlSortOrderForOtherKeys; if (yamlObject == null) { - return this.getTextWithNewYamlFrontmatter(text, oldYaml, newDoc.toString(), doc.toString(), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); + return this.getTextWithNewYamlFrontmatter(text, oldYaml, astToString(startingPriorityKeys), astToString(doc), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } let sortMethod: (previousKey: string, currentKey: string) => number; @@ -76,33 +87,34 @@ export default class YamlKeySort extends RuleBuilder { } else if (sortOrder === 'Descending Alphabetical') { sortMethod = this.sortAlphabeticallyDesc; } else { - return this.getTextWithNewYamlFrontmatter(text, oldYaml, newDoc.toString(), doc.toString(), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); + return this.getTextWithNewYamlFrontmatter(text, oldYaml, astToString(startingPriorityKeys), astToString(doc), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } + const remainingDocKeys = new Document(yamlObject.options); + remainingDocKeys.contents = new YAMLMap(); + remainingKeys = remainingKeys.sort(sortMethod); - this.getYAMLKeysSorted(remainingKeys, doc, newDoc); + this.getYAMLKeysSorted(remainingKeys, doc, remainingDocKeys); - return this.getTextWithNewYamlFrontmatter(text, oldYaml, newDoc.toString(), doc.toString(), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); + return this.getTextWithNewYamlFrontmatter(text, oldYaml, astToString(startingPriorityKeys), astToString(remainingDocKeys), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } getYAMLKeysSorted(keys: string[], yamlObject: Document, newDocument: Document): string[] { - // @ts-ignore TODO: fix the need for ts-ignore here - const initialKeys = yamlObject.contents.items as object[]; + const initialKeys: Node[] = (yamlObject.contents as Node).items as Node[]; + const remainingKeys: string[] = []; + for (const key of keys) { - // we skip any nested elements when sorting to prevent issues where possible for (let i = 0; i < initialKeys.length; i++) { - // @ts-ignore TODO: fix the need for this ts ignore - if (initialKeys[i].key == key) { - newDocument.add(initialKeys[i]); + const node = initialKeys[i]; + if (node.key.value === key) { + newDocument.add(node); initialKeys.splice(i, 1); break; } } } - const remainingKeys = [] as string[]; - for (const val of initialKeys) { - // @ts-ignore TODO: fix the need for this ts ignore - remainingKeys.push(val.key as string); + for (const node of initialKeys) { + remainingKeys.push(node.key.value); } return remainingKeys; @@ -247,16 +259,19 @@ export default class YamlKeySort extends RuleBuilder { status: WIP date: 02/15/2022 --- + Any blank line is attached to the line that follows it `, after: dedent` --- tags: computer + ${''} status: WIP keywords: [] date: 02/15/2022 type: programming language: Typescript --- + Any blank line is attached to the line that follows it `, options: { yamlKeyPrioritySortOrder: [ diff --git a/src/utils/yaml.ts b/src/utils/yaml.ts index 30585e7f..8c7a8b74 100644 --- a/src/utils/yaml.ts +++ b/src/utils/yaml.ts @@ -2,7 +2,7 @@ import {load, dump} from 'js-yaml'; import {getTextInLanguage} from '../lang/helpers'; import {escapeDollarSigns, yamlRegex} from './regex'; import {isNumeric} from './strings'; -import YAML from 'yaml'; +import {parse, parseDocument, Document, stringify} from 'yaml'; export const OBSIDIAN_TAG_KEY_SINGULAR = 'tag'; @@ -94,7 +94,7 @@ export function loadYAML(yaml_text: string): any { // replacing tabs at the beginning of new lines with 2 spaces fixes loading YAML that has tabs at the start of a line // https://github.com/platers/obsidian-linter/issues/157 - const parsed_yaml = load(yaml_text.replace(/\n(\t)+/g, '\n ')) as {}; + const parsed_yaml = parse(yaml_text.replace(/\n(\t)+/g, '\n ')) as {}; if (parsed_yaml == null) { return {}; } @@ -102,24 +102,29 @@ export function loadYAML(yaml_text: string): any { return parsed_yaml; } -export function getYAMLJSON(yaml_text: string): YAML.Document { +export function parseYAML(yaml_text: string): Document { if (yaml_text == null) { return null; } // replacing tabs at the beginning of new lines with 2 spaces fixes loading YAML that has tabs at the start of a line // https://github.com/platers/obsidian-linter/issues/157 - const parsed_yaml = YAML.parseDocument(yaml_text.replace(/\n(\t)+/g, '\n ')); + const parsed_yaml = parseDocument(yaml_text.replace(/\n(\t)+/g, '\n ')); if (parsed_yaml == null) { return null; } - // console.log(parsed_yaml); - // console.log(parsed_yaml.toString()); - return parsed_yaml; } +export function astToString(ast: Document): string { + if (!ast || !ast.contents || !ast.contents.items || ast.contents.items.length == 0) { + return ''; + } + + return ast.toString(); +} + export enum TagSpecificArrayFormats { SingleStringSpaceDelimited = 'single string space delimited', SingleLineSpaceDelimited = 'single-line space delimited', @@ -401,7 +406,7 @@ export function escapeStringIfNecessaryAndPossible(value: string, defaultEscapeC } try { - const unescaped = load(basicEscape) as string; + const unescaped = parse(basicEscape) as string; if (unescaped === value) { return basicEscape; } @@ -409,13 +414,13 @@ export function escapeStringIfNecessaryAndPossible(value: string, defaultEscapeC // invalid YAML } - const escapeWithDefaultCharacter = dump(value, { + const escapeWithDefaultCharacter = stringify(value, { lineWidth: -1, quotingType: defaultEscapeCharacter, forceQuotes: forceEscape, }).slice(0, -1); - const escapeWithOtherCharacter = dump(value, { + const escapeWithOtherCharacter = stringify(value, { lineWidth: -1, quotingType: defaultEscapeCharacter == '"' ? '\'' : '"', forceQuotes: forceEscape, From 8fbaa410907b87965e471ca46bb2ec6fb354b05e Mon Sep 17 00:00:00 2001 From: Peter Kaufman Date: Fri, 22 Nov 2024 12:24:55 -0500 Subject: [PATCH 3/5] updated the basic yaml key sort from using js-yaml to yaml --- __tests__/yaml-key-sort.test.ts | 80 ++++++++++++++++++++++++++++----- src/rules/yaml-key-sort.ts | 15 +------ src/typings/obsidian-ex.d.ts | 2 +- src/typings/yaml.d.ts | 24 ++++++++++ src/utils/yaml.ts | 9 +++- 5 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 src/typings/yaml.d.ts diff --git a/__tests__/yaml-key-sort.test.ts b/__tests__/yaml-key-sort.test.ts index 7a75001d..0ada961b 100644 --- a/__tests__/yaml-key-sort.test.ts +++ b/__tests__/yaml-key-sort.test.ts @@ -165,16 +165,16 @@ ruleTest({ `, after: dedent` --- - related-companies:${' '} - stakeholders:${' '} - pr-pipeline-stage:${' '} - pr-priority:${' '} - pr-size:${' '} - pr-urgency:${' '} - pr-type:${' '} - pr-okr:${' '} - pr-due-date:${' '} - pr-completed-date:${' '} + related-companies: + stakeholders: + pr-pipeline-stage: + pr-priority: + pr-size: + pr-urgency: + pr-type: + pr-okr: + pr-due-date: + pr-completed-date: template: "[[Pro New Project Outcome Template]]" created-date: '[[<% tp.file.creation_date("YYYY-MM-DD") %>]]' modified: Tuesday, October 22nd 2024, 10:58:16 am @@ -199,5 +199,65 @@ ruleTest({ ], }, }, + { // accounts for https://github.com/platers/obsidian-linter/issues/1082 + testName: 'Make sure that literal operator `|` is handled correctly', + before: dedent` + --- + sorting-spec: | + order-desc: a-z + first: alphabetical + --- + `, + after: dedent` + --- + first: alphabetical + sorting-spec: | + order-desc: a-z + --- + `, + options: { + yamlKeyPrioritySortOrder: [ + 'first', + 'sorting-spec:', + ], + }, + }, + { // accounts for https://github.com/platers/obsidian-linter/issues/912 + testName: 'Make sure that lots of nesting does not get broken', + before: dedent` + --- + AAA: + - BBB: x + CCC: x + - DDD: x + EEE: x + FFF: + - GGG: x + - HHH + III: x + FFF: + -${' '} + --- + `, + after: dedent` + --- + AAA: + - BBB: x + CCC: x + - DDD: x + EEE: x + FFF: + - GGG: x + - HHH + III: x + FFF: + ${' '} + -${' '} + --- + `, // note that this does look wonky, but it works the same in Obsidian, so I am going to consider this fine for now + options: { + yamlSortOrderForOtherKeys: 'Ascending Alphabetical', + }, + }, ], }); diff --git a/src/rules/yaml-key-sort.ts b/src/rules/yaml-key-sort.ts index 409819aa..417afb58 100644 --- a/src/rules/yaml-key-sort.ts +++ b/src/rules/yaml-key-sort.ts @@ -3,6 +3,7 @@ import RuleBuilder, {BooleanOptionBuilder, DropdownOptionBuilder, ExampleBuilder import dedent from 'ts-dedent'; import {parseYAML, getYAMLText, loadYAML, setYamlSection, astToString} from '../utils/yaml'; import {Document, YAMLMap} from 'yaml'; +import {YamlNode} from '../typings/yaml'; type YamlSortOrderForOtherKeys = 'None' | 'Ascending Alphabetical' | 'Descending Alphabetical'; @@ -22,18 +23,6 @@ class YamlKeySortOptions implements Options { yamlSortOrderForOtherKeys?: YamlSortOrderForOtherKeys = 'None'; } -interface Key { - value?: string; -} - -interface Node { - constructor: { name: string }; - key?: Key; - value?: any; - items?: [string, any][]; - moved?: boolean; -} - @RuleBuilder.register export default class YamlKeySort extends RuleBuilder { constructor() { @@ -99,7 +88,7 @@ export default class YamlKeySort extends RuleBuilder { return this.getTextWithNewYamlFrontmatter(text, oldYaml, astToString(startingPriorityKeys), astToString(remainingDocKeys), priorityAtStartOfYaml, options.dateModifiedKey, options.currentTimeFormatted, options.yamlTimestampDateModifiedEnabled); } getYAMLKeysSorted(keys: string[], yamlObject: Document, newDocument: Document): string[] { - const initialKeys: Node[] = (yamlObject.contents as Node).items as Node[]; + const initialKeys: YamlNode[] = (yamlObject.contents as YamlNode).items as YamlNode[]; const remainingKeys: string[] = []; for (const key of keys) { diff --git a/src/typings/obsidian-ex.d.ts b/src/typings/obsidian-ex.d.ts index 46a596fe..7b0ee3cc 100644 --- a/src/typings/obsidian-ex.d.ts +++ b/src/typings/obsidian-ex.d.ts @@ -74,7 +74,7 @@ declare module 'obsidian' { * CodeMirror editor instance */ cm?: EditorView; -} + } } diff --git a/src/typings/yaml.d.ts b/src/typings/yaml.d.ts new file mode 100644 index 00000000..fc877efb --- /dev/null +++ b/src/typings/yaml.d.ts @@ -0,0 +1,24 @@ +import {QuoteCharacter} from '../utils/yaml'; + +interface YamlProperties { + lineWidth: number, + quotingType: QuoteCharacter, + forceQuotes: boolean, +} + +interface Key { + value?: string; +} + +interface YamlNode { + constructor: { name: string }; + key?: Key; + value?: any; + items?: [string, any][]; + moved?: boolean; +} + +declare module 'yaml' { + // for now we really just need this for use with strings, so we shall work with that; + export function stringify(value: string, properties?: YamlProperties): string; +} diff --git a/src/utils/yaml.ts b/src/utils/yaml.ts index 8c7a8b74..e54fa8e4 100644 --- a/src/utils/yaml.ts +++ b/src/utils/yaml.ts @@ -1,8 +1,8 @@ -import {load, dump} from 'js-yaml'; import {getTextInLanguage} from '../lang/helpers'; import {escapeDollarSigns, yamlRegex} from './regex'; import {isNumeric} from './strings'; import {parse, parseDocument, Document, stringify} from 'yaml'; +import {YamlNode} from 'src/typings/yaml'; export const OBSIDIAN_TAG_KEY_SINGULAR = 'tag'; @@ -118,7 +118,12 @@ export function parseYAML(yaml_text: string): Document { } export function astToString(ast: Document): string { - if (!ast || !ast.contents || !ast.contents.items || ast.contents.items.length == 0) { + if (!ast || !ast.contents) { + return ''; + } + + const items = (ast.contents as YamlNode).items as YamlNode[]; + if (!items || items.length == 0) { return ''; } From 5866c6b995ac1e5b905eb909d7520e9a28f262f8 Mon Sep 17 00:00:00 2001 From: Peter Kaufman Date: Fri, 22 Nov 2024 13:05:32 -0500 Subject: [PATCH 4/5] added a couple more test cases --- __tests__/yaml-key-sort.test.ts | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/__tests__/yaml-key-sort.test.ts b/__tests__/yaml-key-sort.test.ts index 0ada961b..3b7b1f02 100644 --- a/__tests__/yaml-key-sort.test.ts +++ b/__tests__/yaml-key-sort.test.ts @@ -255,6 +255,51 @@ ruleTest({ -${' '} --- `, // note that this does look wonky, but it works the same in Obsidian, so I am going to consider this fine for now + // see https://github.com/eemeli/yaml/issues/590 for more information on this + options: { + yamlSortOrderForOtherKeys: 'Ascending Alphabetical', + }, + }, + { // accounts for https://github.com/platers/obsidian-linter/issues/660 + testName: 'Make sure that comments are not removed when sorting', + before: dedent` + --- + created: 2023-02-18T10:53:01+00:00 + # Dont remove me + disabled rules: [capitalize-headings] + modified: 2023-03-20T14:53:42+00:00 + --- + `, + after: dedent` + --- + created: 2023-02-18T10:53:01+00:00 + # Dont remove me + disabled rules: [ capitalize-headings ] + modified: 2023-03-20T14:53:42+00:00 + --- + `, + options: { + yamlSortOrderForOtherKeys: 'Ascending Alphabetical', + }, + }, + { // accounts for https://github.com/platers/obsidian-linter/issues/660 + testName: 'Make sure that scalars are not removed when sorting', + before: dedent` + --- + name: John + husband: Tim + biography: | + A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. + --- + `, + after: dedent` + --- + biography: | + A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. A very nice chap. + husband: Tim + name: John + --- + `, options: { yamlSortOrderForOtherKeys: 'Ascending Alphabetical', }, From 503b55cae275a1dff81b17629b4af6ad2f67b613 Mon Sep 17 00:00:00 2001 From: Peter Kaufman Date: Fri, 22 Nov 2024 13:07:10 -0500 Subject: [PATCH 5/5] remove js-yaml and its types from the package info --- package-lock.json | 22 ++++++---------------- package.json | 2 -- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0dc5dca8..940d88c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "@popperjs/core": "^2.11.6", "async-lock": "^1.4.1", "diff-match-patch": "^1.0.5", - "js-yaml": "^4.1.0", "loglevel": "^1.9.1", "mdast-util-from-markdown": "^2.0.0", "mdast-util-frontmatter": "^2.0.1", @@ -42,7 +41,6 @@ "@types/diff": "^5.0.9", "@types/diff-match-patch": "^1.0.32", "@types/jest": "^29.5.12", - "@types/js-yaml": "^4.0.5", "@types/node": "^20.11.28", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", @@ -3409,12 +3407,6 @@ "pretty-format": "^29.0.0" } }, - "node_modules/@types/js-yaml": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -4307,7 +4299,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -8501,6 +8494,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -14162,12 +14156,6 @@ "pretty-format": "^29.0.0" } }, - "@types/js-yaml": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true - }, "@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -14769,7 +14757,8 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-union": { "version": "2.1.0", @@ -17803,6 +17792,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { "argparse": "^2.0.1" } diff --git a/package.json b/package.json index e36cac00..b7de6537 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "@types/diff": "^5.0.9", "@types/diff-match-patch": "^1.0.32", "@types/jest": "^29.5.12", - "@types/js-yaml": "^4.0.5", "@types/node": "^20.11.28", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", @@ -61,7 +60,6 @@ "@popperjs/core": "^2.11.6", "async-lock": "^1.4.1", "diff-match-patch": "^1.0.5", - "js-yaml": "^4.1.0", "loglevel": "^1.9.1", "mdast-util-from-markdown": "^2.0.0", "mdast-util-frontmatter": "^2.0.1",