From b83bf135d02c385e1467e41109852170d1e674f7 Mon Sep 17 00:00:00 2001 From: Ola Rubaj <52197250+olayway@users.noreply.github.com> Date: Thu, 10 Aug 2023 21:00:58 +0200 Subject: [PATCH] [#30][m]: extract wikilinks with Obsidian style shortest paths (#32) --- src/lib/markdowndb.ts | 4 +++- src/utils/extractWikiLinks.spec.ts | 25 ++++++++++++++++++++++--- src/utils/extractWikiLinks.ts | 17 ++++++++++------- src/utils/parseFile.spec.ts | 28 +++++++++++++++++++++++++--- src/utils/parseFile.ts | 4 ++-- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/src/lib/markdowndb.ts b/src/lib/markdowndb.ts index 5a78e4b..47793d9 100644 --- a/src/lib/markdowndb.ts +++ b/src/lib/markdowndb.ts @@ -132,7 +132,9 @@ export class MarkdownDB { flag: "r", }); - const { metadata, links } = parseFile(source); + const { metadata, links } = parseFile(source, { + permalinks: filePathsToIndex, + }); const filetype = metadata?.type || null; // TODO is there a better way to do this? diff --git a/src/utils/extractWikiLinks.spec.ts b/src/utils/extractWikiLinks.spec.ts index 0fba925..332e31c 100644 --- a/src/utils/extractWikiLinks.spec.ts +++ b/src/utils/extractWikiLinks.spec.ts @@ -35,9 +35,9 @@ describe("extractWikiLinks", () => { test("should extract wiki links", () => { const source = "[[Page 1]] [[Page 2]] [[Page 3]]"; const expectedLinks = [ - { linkType: "normal", linkSrc: "page-1" }, - { linkType: "normal", linkSrc: "page-2" }, - { linkType: "normal", linkSrc: "page-3" }, + { linkType: "normal", linkSrc: "Page 1" }, + { linkType: "normal", linkSrc: "Page 2" }, + { linkType: "normal", linkSrc: "Page 3" }, ]; const links = extractWikiLinks(source); expect(links).toHaveLength(expectedLinks.length); @@ -46,6 +46,25 @@ describe("extractWikiLinks", () => { }); }); + test("should extract wiki links with Obsidian-style shortest path", () => { + const source = "[[Page 1]] [[Page 2]] [[Page 3]]"; + const expectedLinks = [ + { linkType: "normal", linkSrc: "/some/folder/Page 1" }, + { linkType: "normal", linkSrc: "/some/folder/Page 2" }, + { linkType: "normal", linkSrc: "/some/folder/Page 3" }, + ]; + const permalinks = [ + "/some/folder/Page 1", + "/some/folder/Page 2", + "/some/folder/Page 3", + ]; + const links = extractWikiLinks(source, { permalinks }); + expect(links).toHaveLength(expectedLinks.length); + links.forEach((link) => { + expect(expectedLinks).toContainEqual(link); + }); + }); + test("should extract embedded wiki links", () => { const source = "![[My File.png]]]]"; const expectedLinks = [{ linkType: "embed", linkSrc: "My File.png" }]; diff --git a/src/utils/extractWikiLinks.ts b/src/utils/extractWikiLinks.ts index e174e2c..abdd0c3 100644 --- a/src/utils/extractWikiLinks.ts +++ b/src/utils/extractWikiLinks.ts @@ -1,12 +1,13 @@ import markdown from "remark-parse"; import { unified, Plugin } from "unified"; import { selectAll } from "unist-util-select"; -import remarkWikiLink from "@flowershow/remark-wiki-link"; +import remarkWikiLink from "@portaljs/remark-wiki-link"; import gfm from "remark-gfm"; export interface ExtractWikiLinksOptions { remarkPlugins?: Array; // remark plugins that add custom nodes to the AST extractors?: LinkExtractors; // mapping from custom node types (e.g. added by above plugins) to functions that should handle them + permalinks?: string[]; } export interface LinkExtractors { @@ -26,11 +27,6 @@ const extractWikiLinks = ( const userExtractors: LinkExtractors = options?.extractors || {}; const userRemarkPlugins: Array = options?.remarkPlugins || []; - const remarkPlugins = [ - gfm, - remarkWikiLink, // adds wikiLink type nodes to AST - ...userRemarkPlugins, - ]; const extractors: LinkExtractors = { link: (node: any) => ({ linkSrc: node.url, @@ -60,7 +56,14 @@ const extractWikiLinks = ( const processor = unified() .use(markdown) - .use([gfm, ...remarkPlugins]); + .use([ + gfm, + [ + remarkWikiLink, + { pathFormat: "obsidian-short", permalinks: options?.permalinks }, + ], + ...userRemarkPlugins, + ]); const ast = processor.parse(source); diff --git a/src/utils/parseFile.spec.ts b/src/utils/parseFile.spec.ts index 0250435..5541afc 100644 --- a/src/utils/parseFile.spec.ts +++ b/src/utils/parseFile.spec.ts @@ -18,13 +18,35 @@ describe("parseFile", () => { tags: ["hello", "world"], }; const expectedLinks = [ - { linkType: "normal", linkSrc: "some-link" }, - { linkType: "normal", linkSrc: "blog/some-other-link" }, - { linkType: "normal", linkSrc: "blog/some-other-link" }, + { linkType: "normal", linkSrc: "Some Link" }, + { linkType: "normal", linkSrc: "blog/Some Other Link" }, + { linkType: "normal", linkSrc: "blog/Some Other Link" }, { linkType: "embed", linkSrc: "Some Image.png" }, ]; const { metadata, links } = parseFile(source); expect(metadata).toEqual(expectedMetadata); expect(links).toEqual(expectedLinks); }); + + it("should parse a file returning metadata and wiki links with Obsidian-style shortest paths", () => { + const expectedMetadata = { + title: "Hello World", + tags: ["hello", "world"], + }; + const expectedLinks = [ + { linkType: "normal", linkSrc: "/some/folder/Some Link" }, + { linkType: "normal", linkSrc: "/some/folder/blog/Some Other Link" }, + { linkType: "normal", linkSrc: "/some/folder/blog/Some Other Link" }, + { linkType: "embed", linkSrc: "/some/folder/Some Image.png" }, + ]; + const permalinks = [ + "/some/folder/Some Link", + "/some/folder/blog/Some Other Link", + "/some/folder/blog/Some Other Link", + "/some/folder/Some Image.png", + ]; + const { metadata, links } = parseFile(source, { permalinks }); + expect(metadata).toEqual(expectedMetadata); + expect(links).toEqual(expectedLinks); + }); }); diff --git a/src/utils/parseFile.ts b/src/utils/parseFile.ts index 783e532..bb47396 100644 --- a/src/utils/parseFile.ts +++ b/src/utils/parseFile.ts @@ -1,12 +1,12 @@ import matter from "gray-matter"; import { extractWikiLinks } from "./extractWikiLinks.js"; -export function parseFile(source: string) { +export function parseFile(source: string, options?: { permalinks?: string[] }) { // Metadata const { data: metadata } = matter(source); // Links - const links = extractWikiLinks(source); + const links = extractWikiLinks(source, { permalinks: options?.permalinks }); return { metadata,