Skip to content

Commit 9cbf8a2

Browse files
committed
Give plugins access to notion url --> docusaurus url conversion
1 parent ebd893f commit 9cbf8a2

File tree

7 files changed

+10939
-7565
lines changed

7 files changed

+10939
-7565
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"callouts",
88
"DOCU_NOTION",
99
"docu-notion",
10+
"docunotion",
1011
"Greenshot",
1112
"imgur",
1213
"kanban",
@@ -17,4 +18,4 @@
1718
"statusBar.noFolderBackground": "#d649ca",
1819
"statussBar.prominentBackground": "#d649ca"
1920
}
20-
}
21+
}

src/plugins/internalLinks.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,40 @@ import { IDocuNotionContext, IPlugin } from "./pluginTypes";
22
import { error, warning } from "../log";
33
import { NotionPage } from "../NotionPage";
44

5+
// converts a url to a local link, if it is a link to a page in the Notion site
6+
// only here for plugins, notion won't normally be giving us raw urls (at least not that I've noticed)
7+
// If it finds a URL but can't find the page it points to, it will return undefined.
8+
// If it doesn't find a match at all, it returns undefined.
9+
export function convertInternalUrl(
10+
context: IDocuNotionContext,
11+
url: string
12+
): string | undefined {
13+
const kGetIDFromNotionURL = /https:\/\/www\.notion\.so\S+-([a-z,0-9]+)+.*/;
14+
const match = kGetIDFromNotionURL.exec(url);
15+
if (match === null) {
16+
warning(
17+
`[standardInternalLinkConversion] Could not parse link ${url} as a Notion URL`
18+
);
19+
return undefined;
20+
}
21+
const id = match[1];
22+
const pages = context.pages;
23+
// find the page where pageId matches hrefFromNotion
24+
const targetPage = pages.find(p => {
25+
return p.matchesLinkId(id);
26+
});
27+
28+
if (!targetPage) {
29+
// About this situation. See https://github.com/sillsdev/docu-notion/issues/9
30+
warning(
31+
`[standardInternalLinkConversion] Could not find the target of this link. Note that links to outline sections are not supported. ${url}. https://github.com/sillsdev/docu-notion/issues/9`
32+
);
33+
return undefined;
34+
}
35+
return convertLinkHref(context, targetPage, url);
36+
}
37+
38+
// handles the whole markdown link, including the label
539
function convertInternalLink(
640
context: IDocuNotionContext,
741
markdownLink: string

src/plugins/pluginTestRun.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import { Client } from "@notionhq/client";
22
import { GetPageResponse } from "@notionhq/client/build/src/api-endpoints";
3-
import { info } from "console";
43
import { NotionToMarkdown } from "notion-to-md";
54
import { IDocuNotionContext } from "./pluginTypes";
65
import { HierarchicalNamedLayoutStrategy } from "../HierarchicalNamedLayoutStrategy";
7-
import { error, logDebug, verbose, warning } from "../log";
86
import { NotionPage } from "../NotionPage";
97
import { getMarkdownFromNotionBlocks } from "../transform";
108
import { IDocuNotionConfig } from "../config/configuration";
119
import { NotionBlock } from "../types";
10+
import { convertInternalUrl } from "./internalLinks";
1211

1312
export async function blocksToMarkdown(
1413
config: IDocuNotionConfig,
@@ -34,6 +33,10 @@ export async function blocksToMarkdown(
3433
resolve([]);
3534
});
3635
},
36+
convertNotionLinkToLocalDocusaurusLink: (url: string) => {
37+
return convertInternalUrl(docunotionContext, url);
38+
},
39+
3740
//TODO might be needed for some tests, e.g. the image transformer...
3841
directoryContainingMarkdown: "not yet",
3942
relativeFilePathToFolderContainingPage: "not yet",

src/plugins/pluginTypes.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ export type IRegexMarkdownModification = {
4646
// Based on that regex, the outputPattern will be used to replace the matched text
4747
replacementPattern?: string;
4848
// Instead of a pattern, you can use this if you have to ask a server somewhere for help in getting the new markdown
49-
getReplacement?(s: string): Promise<string>;
49+
getReplacement?(
50+
context: IDocuNotionContext,
51+
match: RegExpExecArray
52+
): Promise<string>;
53+
// normally, anything in code blocks is will be ignored. If you want to make changes inside of code blocks, set this to true.
54+
includeCodeBlocks?: boolean;
5055

5156
// If the output is creating things like react elements, you can import their definitions here
5257
imports?: string[];
@@ -66,6 +71,7 @@ export type IDocuNotionContext = {
6671
notionToMarkdown: NotionToMarkdown;
6772
directoryContainingMarkdown: string;
6873
relativeFilePathToFolderContainingPage: string;
74+
convertNotionLinkToLocalDocusaurusLink: (url: string) => string;
6975
pages: NotionPage[];
7076
counts: ICounts;
7177
};

src/pull.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { Client, isFullBlock } from "@notionhq/client";
2828
import { exit } from "process";
2929
import { IDocuNotionConfig, loadConfigAsync } from "./config/configuration";
3030
import { NotionBlock } from "./types";
31+
import { convertInternalUrl } from "./plugins/internalLinks";
3132

3233
export type DocuNotionOptions = {
3334
notionToken: string;
@@ -110,6 +111,8 @@ async function outputPages(
110111
options: options,
111112
pages: pages,
112113
counts: counts, // review will this get copied or pointed to?
114+
convertNotionLinkToLocalDocusaurusLink: (url: string) =>
115+
convertInternalUrl(context, url),
113116
};
114117
for (const page of pages) {
115118
layoutStrategy.pageWasSeen(page);

src/transform.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ export async function getMarkdownFromNotionBlocks(
5656
//console.log("markdown after link fixes", markdown);
5757

5858
// simple regex-based tweaks. These are usually related to docusaurus
59-
const { imports, body } = await doTransformsOnMarkdown(config, markdown);
59+
const { imports, body } = await doTransformsOnMarkdown(
60+
context,
61+
config,
62+
markdown
63+
);
6064

6165
// console.log("markdown after regex fixes", markdown);
6266
// console.log("body after regex", body);
@@ -82,6 +86,7 @@ function doNotionBlockTransforms(
8286
}
8387

8488
async function doTransformsOnMarkdown(
89+
context: IDocuNotionContext,
8590
config: IDocuNotionConfig,
8691
input: string
8792
) {
@@ -109,15 +114,24 @@ async function doTransformsOnMarkdown(
109114
// regex.exec is stateful, so we don't want to mess up the plugin's use of its own regex, so we clone it.
110115
// we also add the "g" flag to make sure we get all matches
111116
const regex = new RegExp(`${codeBlocks.source}|(${mod.regex.source})`, "g");
112-
let count = 0;
113117
while ((match = regex.exec(input)) !== null) {
114118
if (match[0]) {
115119
const original = match[0];
116-
if (original.startsWith("```") && original.endsWith("```")) {
117-
continue; // code block
120+
if (
121+
original.startsWith("```") &&
122+
original.endsWith("```") &&
123+
!mod.includeCodeBlocks
124+
) {
125+
continue; // code block, and they didn't say to include them
118126
}
119127
if (mod.getReplacement) {
120-
replacement = await mod.getReplacement(original);
128+
// our match here has an extra group, which is an implementation detail
129+
// that shouldn't be made visible to the plugin
130+
const matchAsThePluginWouldExpectIt = mod.regex.exec(match[0])!;
131+
replacement = await mod.getReplacement(
132+
context,
133+
matchAsThePluginWouldExpectIt
134+
);
121135
} else if (mod.replacementPattern) {
122136
console.log(`mod.replacementPattern.replace("$1", ${match[2]}`);
123137
replacement = mod.replacementPattern.replace("$1", match[2]);
@@ -149,7 +163,8 @@ async function doNotionToMarkdown(
149163
blocks
150164
);
151165

152-
let markdown = docunotionContext.notionToMarkdown.toMarkdownString(mdBlocks);
166+
const markdown =
167+
docunotionContext.notionToMarkdown.toMarkdownString(mdBlocks);
153168
return markdown;
154169
}
155170

@@ -187,6 +202,7 @@ function doLinkFixes(
187202
config.plugins.some(plugin => {
188203
if (!plugin.linkModifier) return false;
189204
if (plugin.linkModifier.match.exec(originalLinkMarkdown) === null) {
205+
verbose(`plugin "${plugin.name}" did not match this url`);
190206
return false;
191207
}
192208
const newMarkdown = plugin.linkModifier.convert(

0 commit comments

Comments
 (0)