Skip to content

Instantly share code, notes, and snippets.

@AmericanBagel
Created September 2, 2023 02:46
Show Gist options
  • Save AmericanBagel/7392bb863cbc3d6ddf860aa9e8b1f620 to your computer and use it in GitHub Desktop.
Save AmericanBagel/7392bb863cbc3d6ddf860aa9e8b1f620 to your computer and use it in GitHub Desktop.
Obsidian QuickAdd Script - Convert Dataview Inline YAML to YAML
module.exports = {
settings: {
name: 'Convert Dataview Inline YAML to YAML',
author: 'AmericanBagel',
options: {
'Excluded Files': {
type: 'text',
defaultValue: '.git',
placeholder: 'A ":" seperated list of strings or regex',
},
},
},
entry: async (params, settings) => {
const {
quickAddApi: { inputPrompt, suggester },
} = params;
const metaedit = app.plugins.plugins['metaedit'].api;
const vault = app.vault;
const fs = app.vault.adapter;
function clearFormattingCharacters(string) {
return string.replace(/[*_~]/g, '');
}
function getDataviewInlineYamlLines(string) {
const lines = string.split('\n');
const matches = [];
lines.forEach((line) => {
// (?!`(\$=|=).*`) to exclude inline dataview code
if (
line.match(
/^[*_~]{0,3}[a-zA-Z-_]+[*_~]{0,3}::.*$(?!`(\$=|=).*`)/g
)
&& line.match(/^[*_~]{0,3}[a-zA-Z-_]+[*_~]{0,3}:: (?!`(\$=|=).*`)/gm)
) {
matches.push(line);
}
});
return matches;
}
function removeDataviewInlineYamlLines(string) {
const lines = string.split('\n');
let output = [];
lines.forEach((line) => {
// (?!`(\$=|=).*`) to exclude inline dataview code
if (
!line.match(
/^[*_~]{0,3}[a-zA-Z-_]+[*_~]{0,3}::.*$/g
)
) {
output.push(line);
}
});
output = output.join('\n');
output = output.replace(/%%\s%%/g, '');
return output;
}
function convertToKebabCase(string) {
return string
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
}
function parseAndAddProperty(obj, line) {
const arr = line.split(':: ');
obj[convertToKebabCase(clearFormattingCharacters(arr[0]))] = arr[1];
}
function isTag(string) {
// if (string.match(/(#[^\s]+)+/g))
if (string.startsWith('#')) {
return true;
}
}
function isLink(string) {
if (string.match(/(\[\[[^\s]+\]\])[ ]*/g)) {
return true;
}
}
function getLinkFrontmatter(key, value) {
console.log(value);
console.log(typeof value);
// This regex makes it only split when outside double brackets
return listToFrontmatter(key, value.match(/(\[\[[^\]]*\]\]|\S)+/g));
}
function getTagFrontmatter(key, value) {
console.log(value);
console.log(typeof value);
return listToFrontmatter(
key,
value.split(' ').map((tag) => tag.replace(/^#/g, ''))
);
}
function listToFrontmatter(key, _value) {
console.log('listToFrontmatter');
console.log('_value: ' + _value);
let value = _value;
if (typeof _value === 'string') {
value = _value.replace(/[ \t]+$/g, '').split(' ');
}
console.log(value);
let out = `${key}:\n`;
for (element of value) {
out += ` - "${element}"\n`;
}
return out;
}
function propertyToFrontmatter(key, value) {
return `${key}: ${value}\n`;
}
async function convertNote(note) {
let contents = await vault.read(note);
const inlineLines = getDataviewInlineYamlLines(contents);
inlineLines.forEach(
(line) => (line = clearFormattingCharacters(line))
);
if (inlineLines.length > 0) {
const inlineProperties = {};
inlineLines.forEach((line) =>
parseAndAddProperty(inlineProperties, line)
);
let frontmatter = '';
for (const [key, value] of Object.entries(inlineProperties)) {
if (isLink(value)) {
console.log('isLink');
frontmatter += getLinkFrontmatter(key, value);
} else if (isTag(value)) {
console.log('isTag');
frontmatter += getTagFrontmatter(key, value);
} else {
frontmatter += propertyToFrontmatter(key, value);
}
}
contents = removeDataviewInlineYamlLines(contents);
let sections = contents.split('---\n');
if (sections.length === 1) {
contents = `---\n${frontmatter}---\n\n` + contents;
} else {
sections[1] =
sections[1].replace(/(?<=\n|^)\s/g, '') + frontmatter;
contents = sections.join('---\n');
}
await fs.write(note.path, contents);
}
}
// Start
const excluded = settings['Excluded Files']?.split(':');
let files = await app.vault.getMarkdownFiles();
console.log(files);
files = files.filter((file) => {
// Check if any excluded substring is present in the file name
return !excluded.some((substring) => file.path.includes(substring));
});
const shouldContinue = await params.quickAddApi.yesNoPrompt(
'Are you sure you want to continue?',
'This will format ALL notes in your vault that are not excluded by the settings. This will effect ' +
files.length +
' files.'
);
files.forEach(async (file) => {
convertNote(file);
});
},
};
module.exports = {
settings: {
name: 'Convert Dataview Inline YAML to YAML',
author: 'AmericanBagel',
options: {
'Excluded Files': {
type: 'text',
defaultValue: '.git',
placeholder: 'A ":" seperated list of strings or regex',
},
},
},
entry: async (params, settings) => {
const {
quickAddApi: { inputPrompt, suggester },
} = params;
const metaedit = app.plugins.plugins['metaedit'].api;
const vault = app.vault;
const fs = app.vault.adapter;
function clearFormattingCharacters(string) {
return string.replace(/[*_~]/g, '');
}
function getDataviewInlineYamlLines(string) {
const lines = string.split('\n');
const matches = [];
lines.forEach((line) => {
// (?!`(\$=|=).*`) to exclude inline dataview code
if (
line.match(
/^[*_~]{0,3}[a-zA-Z-_]+[*_~]{0,3}::.*$(?!`(\$=|=).*`)/g
)
&& line.match(/^[*_~]{0,3}[a-zA-Z-_]+[*_~]{0,3}:: (?!`(\$=|=).*`)/gm)
) {
matches.push(line);
}
});
return matches;
}
function removeDataviewInlineYamlLines(string) {
const lines = string.split('\n');
let output = [];
lines.forEach((line) => {
// (?!`(\$=|=).*`) to exclude inline dataview code
if (
!line.match(
/^[*_~]{0,3}[a-zA-Z-_]+[*_~]{0,3}::.*$/g
)
) {
output.push(line);
}
});
output = output.join('\n');
output = output.replace(/%%\s%%/g, '');
return output;
}
function convertToKebabCase(string) {
return string
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
}
function parseAndAddProperty(obj, line) {
const arr = line.split(':: ');
obj[convertToKebabCase(clearFormattingCharacters(arr[0]))] = arr[1];
}
function isTag(string) {
// if (string.match(/(#[^\s]+)+/g))
if (string.startsWith('#')) {
return true;
}
}
function isLink(string) {
if (string.match(/(\[\[[^\s]+\]\])[ ]*/g)) {
return true;
}
}
function getLinkFrontmatter(key, value) {
console.log(value);
console.log(typeof value);
// This regex makes it only split when outside double brackets
return listToFrontmatter(key, value.match(/(\[\[[^\]]*\]\]|\S)+/g));
}
function getTagFrontmatter(key, value) {
console.log(value);
console.log(typeof value);
return listToFrontmatter(
key,
value.split(' ').map((tag) => tag.replace(/^#/g, ''))
);
}
function listToFrontmatter(key, _value) {
console.log('listToFrontmatter');
console.log('_value: ' + _value);
let value = _value;
if (typeof _value === 'string') {
value = _value.replace(/[ \t]+$/g, '').split(' ');
}
console.log(value);
let out = `${key}:\n`;
for (element of value) {
out += ` - "${element}"\n`;
}
return out;
}
function propertyToFrontmatter(key, value) {
return `${key}: ${value}\n`;
}
async function convertNote(note) {
let contents = await vault.read(note);
const inlineLines = getDataviewInlineYamlLines(contents);
inlineLines.forEach(
(line) => (line = clearFormattingCharacters(line))
);
if (inlineLines.length > 0) {
const inlineProperties = {};
inlineLines.forEach((line) =>
parseAndAddProperty(inlineProperties, line)
);
let frontmatter = '';
for (const [key, value] of Object.entries(inlineProperties)) {
if (isLink(value)) {
console.log('isLink');
frontmatter += getLinkFrontmatter(key, value);
} else if (isTag(value)) {
console.log('isTag');
frontmatter += getTagFrontmatter(key, value);
} else {
frontmatter += propertyToFrontmatter(key, value);
}
}
contents = removeDataviewInlineYamlLines(contents);
let sections = contents.split('---\n');
if (sections.length === 1) {
contents = `---\n${frontmatter}---\n\n` + contents;
} else {
sections[1] =
sections[1].replace(/(?<=\n|^)\s/g, '') + frontmatter;
contents = sections.join('---\n');
}
await fs.write(note.path, contents);
}
}
// Start
const excluded = settings['Excluded Files']?.split(':');
let files = await app.vault.getMarkdownFiles();
console.log(files);
files = files.filter((file) => {
// Check if any excluded substring is present in the file name
return !excluded.some((substring) => file.path.includes(substring));
});
const shouldContinue = await params.quickAddApi.yesNoPrompt(
'Are you sure you want to continue?',
'This will format ALL notes in your vault that are not excluded by the settings. This will effect ' +
files.length +
' files.'
);
files.forEach(async (file) => {
convertNote(file);
});
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment