mirror of
https://github.com/foambubble/foam.git
synced 2026-01-10 22:48:09 -05:00
Compare commits
2 Commits
v0.27.3
...
feature/li
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac9aa741ef | ||
|
|
8b7e6983bf |
@@ -12,13 +12,15 @@ import { ID } from './types';
|
||||
|
||||
let processor: unified.Processor | null = null;
|
||||
|
||||
const ALIAS_DIVIDER_CHAR = '|';
|
||||
|
||||
function parse(markdown: string): Node {
|
||||
processor =
|
||||
processor ||
|
||||
unified()
|
||||
.use(markdownParse, { gfm: true })
|
||||
.use(frontmatterPlugin, ['yaml'])
|
||||
.use(wikiLinkPlugin);
|
||||
.use(wikiLinkPlugin, { aliasDivider: ALIAS_DIVIDER_CHAR });
|
||||
return processor.parse(markdown);
|
||||
}
|
||||
|
||||
@@ -53,9 +55,20 @@ export function createNoteFromMarkdown(
|
||||
}
|
||||
|
||||
if (node.type === 'wikiLink') {
|
||||
// links can be either in format [[text]] or [[text|alias]].
|
||||
const text = node.value as string;
|
||||
const alias = node.data?.alias as string;
|
||||
const literalContent = markdown.substring(
|
||||
node.position!.start.offset! + 2,
|
||||
node.position!.end.offset! - 2
|
||||
);
|
||||
const hasAlias =
|
||||
literalContent !== text && literalContent.includes(ALIAS_DIVIDER_CHAR);
|
||||
links.push({
|
||||
type: 'wikilink',
|
||||
slug: node.value as string,
|
||||
slug: text.trim(),
|
||||
alias: hasAlias ? alias.trim() : null,
|
||||
literalContent,
|
||||
position: node.position!,
|
||||
});
|
||||
}
|
||||
@@ -127,6 +140,7 @@ export function stringifyMarkdownLinkReferenceDefinition(
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export function createMarkdownReferences(
|
||||
graph: NoteGraph,
|
||||
noteId: ID,
|
||||
@@ -143,45 +157,78 @@ export function createMarkdownReferences(
|
||||
return [];
|
||||
}
|
||||
|
||||
return graph
|
||||
.getForwardLinks(noteId)
|
||||
.map(link => {
|
||||
let target = graph.getNote(link.to);
|
||||
// if we don't find the target by ID we search the graph by slug
|
||||
if (!target) {
|
||||
const candidates = graph.getNotes({ slug: link.link.slug });
|
||||
if (candidates.length > 1) {
|
||||
console.log(
|
||||
`Warning: Slug ${link.link.slug} matches ${candidates.length} documents. Picking one.`
|
||||
);
|
||||
}
|
||||
target = candidates.length > 0 ? candidates[0] : null;
|
||||
}
|
||||
// We are dropping links to non-existent notes here,
|
||||
// but int the future we may want to surface these too
|
||||
if (!target) {
|
||||
console.log(
|
||||
`Warning: Link '${link.to}' in '${noteId}' points to a non-existing note.`
|
||||
// if note doesn't exist, we can't find its links
|
||||
const note = graph.getNote(noteId);
|
||||
if (!note) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const forwardLinks = graph.getForwardLinks(noteId);
|
||||
|
||||
// Try to generate a definition for each [[link]] in the note.
|
||||
//
|
||||
// A note may have multiple [[link]] expressions to the same target
|
||||
// note with different aliases.s
|
||||
//
|
||||
// - note.links contains all the [[link]] expressions
|
||||
// - forwardLinks contains all the edges (links) between documents
|
||||
return (
|
||||
note.links
|
||||
.map(linkExpression => {
|
||||
// find the link between this and other document
|
||||
const link = forwardLinks.find(
|
||||
note => note.link.slug === linkExpression.slug
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const relativePath = path.relative(
|
||||
path.dirname(source.source.uri),
|
||||
target.source.uri
|
||||
);
|
||||
// if other document is not found, bail
|
||||
if (!link) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pathToNote = includeExtension
|
||||
? relativePath
|
||||
: dropExtension(relativePath);
|
||||
// find the target document
|
||||
let target = graph.getNote(link.to);
|
||||
|
||||
// [wiki-link-text]: path/to/file.md "Page title"
|
||||
return {
|
||||
label: link.link.slug,
|
||||
url: pathToNote,
|
||||
title: target.title || target.slug,
|
||||
};
|
||||
})
|
||||
.filter(Boolean)
|
||||
.sort() as NoteLinkDefinition[];
|
||||
// if we don't find the target by ID we search the graph by slug
|
||||
if (!target) {
|
||||
const candidates = graph.getNotes({ slug: linkExpression.slug });
|
||||
if (candidates.length > 1) {
|
||||
console.log(
|
||||
`Warning: Slug ${linkExpression.slug} matches ${candidates.length} documents. Picking one.`
|
||||
);
|
||||
}
|
||||
target = candidates.length > 0 ? candidates[0] : null;
|
||||
}
|
||||
|
||||
// We are dropping links to non-existent notes here,
|
||||
// but in the future we may want to surface these too
|
||||
if (!target) {
|
||||
console.log(
|
||||
`Warning: Link '${link.to}' in '${noteId}' points to a non-existing note.`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const relativePath = path.relative(
|
||||
path.dirname(source.source.uri),
|
||||
target.source.uri
|
||||
);
|
||||
|
||||
const pathToNote = includeExtension
|
||||
? relativePath
|
||||
: dropExtension(relativePath);
|
||||
|
||||
// [wiki-link-text]: path/to/file.md "Page title"
|
||||
return {
|
||||
label: linkExpression.literalContent,
|
||||
url: pathToNote,
|
||||
title: linkExpression.alias || target.title || target.slug,
|
||||
};
|
||||
})
|
||||
|
||||
// remove empty items
|
||||
.filter(Boolean)
|
||||
|
||||
// sort by label, ascending
|
||||
.sort((a, b) => (a!.label < b!.label ? -1 : 1)) as NoteLinkDefinition[]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ export interface NoteSource {
|
||||
export interface WikiLink {
|
||||
type: 'wikilink';
|
||||
slug: string;
|
||||
alias: string | null;
|
||||
literalContent: string;
|
||||
position: Position;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user