Skip to content

Commit

Permalink
[#30][m]: extract wikilinks with Obsidian style shortest paths (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
olayway authored Aug 10, 2023
1 parent 62ef0c0 commit b83bf13
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 16 deletions.
4 changes: 3 additions & 1 deletion src/lib/markdowndb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
25 changes: 22 additions & 3 deletions src/utils/extractWikiLinks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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" }];
Expand Down
17 changes: 10 additions & 7 deletions src/utils/extractWikiLinks.ts
Original file line number Diff line number Diff line change
@@ -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<Plugin>; // 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 {
Expand All @@ -26,11 +27,6 @@ const extractWikiLinks = (
const userExtractors: LinkExtractors = options?.extractors || {};
const userRemarkPlugins: Array<Plugin> = options?.remarkPlugins || [];

const remarkPlugins = [
gfm,
remarkWikiLink, // adds wikiLink type nodes to AST
...userRemarkPlugins,
];
const extractors: LinkExtractors = {
link: (node: any) => ({
linkSrc: node.url,
Expand Down Expand Up @@ -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);

Expand Down
28 changes: 25 additions & 3 deletions src/utils/parseFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
4 changes: 2 additions & 2 deletions src/utils/parseFile.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down

0 comments on commit b83bf13

Please sign in to comment.