obsidian-frontmatter-links
obsidian-frontmatter-links copied to clipboard
#29 - Fix multi-link string parsing
This should hopefully fix the multi-link string parsing issue (#29). Turns out I'm way better at JS than TS though, so I haven't even figured out how to build the TS code.
I tested the JS code on the following YAML (both with quotes on/off), and then ported everything to TS:
link: http://example.com
link-with-quotes: "http://example.com"
wikilink: "[[Wikilink]]"
external-markdown-link: "[External Markdown Link](http://example.com)"
internal-markdown-link: "[Internal Markdown Link](Internal)"
multi-link: "Text [[Link1]] more text [[Link2|alias]] more text"
multi-link2: "Text [External Markdown Link](http://example.com) more text [[Another link]] Test"
wierd-link: "[[Test (foo)]]"
weird-link2: "[[Test [bar]]]"
(Would be useful to have these as a standard test case perhaps?)
If I messed up the TS code somehow, feel free to fix it, or to disregard this PR entirely.
I hope it will be merged, I really need this fix and I'm not able to make a working version of the fixed plugin by my own :(
@Cammagno Here are the js functions in the mean time. Just replace manually, I guess:
findLinks:
findLinks(view, linkSlices) {
const settings = app.plugins.plugins["frontmatter-links"].settings;
let externalLinkFrom;
let externalLinkTo;
for (let { from, to } of view.visibleRanges) {
(0, import_language.syntaxTree)(view.state).iterate({
from,
to,
enter(node) {
if (externalLinkFrom === null) {
if (node.name === "hmd-frontmatter") {
externalLinkFrom = node.from;
externalLinkTo = node.to;
}
} else {
if (node.name === "atom_hmd-frontmatter" || node.name === "def_hmd-frontmatter") {
let text = view.state.sliceDoc(externalLinkFrom, externalLinkTo);
if ((0, import_valid_url2.isUri)(text)) {
linkSlices.push({
originalText: text,
href: text,
from: externalLinkFrom,
to: externalLinkTo
});
}
externalLinkFrom = null;
} else {
externalLinkTo = node.to;
}
}
if (node.name === "hmd-frontmatter_string") {
const pattern = /\[\[(.+?\]?)(?:\|(.+?))?\]\]|\[(.+?)\]\((.+?)\)/gm;
const text = view.state.sliceDoc(node.from + 1, node.to - 1);
let start = node.from + 1;
let match;
let href;
let alias;
let markdownLink;
let from;
let to;
let matches = [...text.matchAll(pattern)];
if (matches.length === 0) {
if (text) {
if ((0, import_valid_url2.isUri)(text)) {
linkSlices.push({
originalText: text,
href: text,
alias,
from: node.from + (settings.hideQuotes ? 0 : 1),
to: node.to - (settings.hideQuotes ? 0 : 1),
markdownLink
});
}
}
} else {
matches.forEach((match) => {
from = start + match.index;
to = from + match[0].length;
if (match[4] === undefined) {
markdownLink = false;
href = match[1];
alias = match[2];
} else {
markdownLink = true;
href = match[4];
alias = match[3];
}
let isEntireString = from === start && to === node.to - 1;
let quoteOffset = (isEntireString && settings.hideQuotes) ? 1 : 0
if (href) {
linkSlices.push({
originalText: match[0],
href,
alias,
from: from - quoteOffset,
to: to + quoteOffset,
markdownLink
});
}
});
}
}
}
});
}
}
addFrontmatterLinksToCache:
function addFrontmatterLinksToCache(file, frontmatter) {
if (!frontmatter) {
return;
}
for (let key of Object.keys(frontmatter)) {
const value = frontmatter[key];
if (typeof value === "string") {
const pattern = /\[\[(.+?\]?)(?:\|(.+?))?\]\]|\[(.+?)\]\((.+?)\)/gm;
let matches = [...value.matchAll(pattern)];
matches.forEach((match) => {
if (!match) {
return;
}
let href = (match[4] === undefined ? match[1] : match[4]);
if ((0, import_valid_url3.isUri)(href)) {
return;
}
let f = app.metadataCache.getFirstLinkpathDest(href, "");
let links;
if (f instanceof import_obsidian3.TFile) {
href = f.path;
links = app.metadataCache.resolvedLinks;
} else {
links = app.metadataCache.unresolvedLinks;
}
if (links[file.path][href]) {
links[file.path][href] += 1;
} else {
links[file.path][href] = 1;
}
});
} else if (typeof value === "object") {
addFrontmatterLinksToCache(file, value);
}
}
}
@Cammagno Here are the js functions in the mean time. Just replace manually
Thanks a lot, it works! :))