Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
taga3s committed Dec 15, 2024
1 parent 29023a1 commit cdfb8ef
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 99 deletions.
115 changes: 40 additions & 75 deletions app/packages/rehype-embedded-github-code/index.ts
Original file line number Diff line number Diff line change
@@ -1,98 +1,63 @@
import type { Element, Root } from "hast";
import type { Plugin } from "unified";
import type { Root } from "hast";
import type { Plugin, Transformer } from "unified";
import { h } from "hastscript";
import { visit } from "unist-util-visit";
import {
buildRequestURL,
extractCodeByLines,
extractFilePathFromURL,
extractLinesFromURL,
extractRefFromURL,
extractRepoNameFromURL,
} from "./util";
import { buildRequestURL, extractCodeByLines, extractRepoDataFromURL } from "./utils";

interface EmbeddedGithubCode {
url: string;
index: number;
parent: Root | Element;
}
type Option = {
githubPAT: string;
};

const rehypeEmbeddedGithubCode: Plugin<Option[], Root> = (options): Transformer<Root> => {
const { githubPAT } = options;

const headers = {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${githubPAT}`,
"X-GitHub-Api-Version": "2022-11-28",
};

const rehypeEmbeddedGithubCode: Plugin<[], Root> = () => {
const embeddedGithubCodes: EmbeddedGithubCode[] = [];
const githubCodePromises: Promise<void>[] = [];

return async (tree) => {
const transform: Transformer<Root> = async (tree) => {
visit(tree, "element", (node, index, parent) => {
if (
node.tagName !== "a" ||
node.properties["data-remark-target"] !== "remark-embedded-github-code" ||
typeof node.properties.href !== "string"
) {
if (node.tagName !== "a" || node.properties["data-remark"] !== "remark-embedded-github-code") {
return;
}

if (index === undefined || parent === undefined) {
return;
}

if (parent.type !== "root" && parent.type !== "element") {
return;
}

embeddedGithubCodes.push({
url: node.properties.href,
index,
parent,
});
});

await Promise.all(
embeddedGithubCodes.map(async (embeddedGithubCode) => {
const repoName = extractRepoNameFromURL(embeddedGithubCode.url);
const ref = extractRefFromURL(embeddedGithubCode.url);
const path = extractFilePathFromURL(embeddedGithubCode.url);
const lines = extractLinesFromURL(embeddedGithubCode.url);

const githubCodePromise = async (): Promise<void> => {
const { repoName, ref, path, lines } = extractRepoDataFromURL(String(node.properties.href));
const requestUrl = buildRequestURL(repoName, ref, path);

const response = await fetch(requestUrl, {
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${process.env.GITHUB_PAT}`,
"X-GitHub-Api-Version": "2022-11-28",
},
});
const content = (await response.json()) as { content: string };

const codeBase64 = content.content;
let code = Buffer.from(codeBase64, "base64").toString("utf-8");
if (lines) {
code = extractCodeByLines(code, lines);
}
try {
const response = await fetch(requestUrl, { headers });
if (!response.ok) {
throw new Error(`Failed to fetch code from GitHub: ${response.status}`);
}
const content = (await response.json()) as { content: string };
const codeBase64 = content.content;
const code = extractCodeByLines(Buffer.from(codeBase64, "base64").toString("utf-8"), lines);

const codeElement: Element = {
type: "element",
tagName: "code",
properties: {
className: "",
},
children: [
{
type: "text",
value: code,
},
],
};
const newElement = h("pre", [h("code", [h(null, [{ type: "text", value: code }])])]);

const preElement: Element = {
type: "element",
tagName: "pre",
children: [codeElement],
properties: {},
};
parent.children[index] = newElement;
} catch (error) {
throw new Error("Failed to fetch code from GitHub", { cause: error });
}
};
githubCodePromises.push(githubCodePromise());
});

embeddedGithubCode.parent.children[embeddedGithubCode.index] = preElement;
}),
);
await Promise.all(githubCodePromises);
};

return transform;
};

export { rehypeEmbeddedGithubCode };
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
const extractRepoNameFromURL = (url: string): string => {
const base = url.replace("https://github.com/", "");
const urlParts = base.split("/");
const extractRepoName = (urlParts: string[]): string => {
return urlParts.slice(0, 2).join("/");
};

const extractFilePathFromURL = (url: string): string => {
const base = url.replace("https://github.com/", "");
const urlParts = base.split("/");
const extractFilePath = (urlParts: string[]): string => {
const result = urlParts.slice(4).join("/");
const hashIndex = result.indexOf("#");
if (hashIndex === -1) {
Expand All @@ -15,9 +11,7 @@ const extractFilePathFromURL = (url: string): string => {
return result.slice(0, hashIndex);
};

const extractRefFromURL = (url: string): string => {
const base = url.replace("https://github.com/", "");
const urlParts = base.split("/");
const extractRef = (urlParts: string[]): string => {
return urlParts[3];
};

Expand All @@ -26,9 +20,7 @@ type LineNumbers = {
endLine: number;
};

const extractLinesFromURL = (url: string): LineNumbers | undefined => {
const base = url.replace("https://github.com/", "");
const urlParts = base.split("/");
const extractLines = (urlParts: string[]): LineNumbers | undefined => {
const result = urlParts.slice(4).join("/");
const hashIndex = result.indexOf("#");
if (hashIndex === -1) {
Expand All @@ -43,20 +35,25 @@ const extractLinesFromURL = (url: string): LineNumbers | undefined => {
};
};

const extractRepoDataFromURL = (url: string) => {
const base = url.replace("https://github.com/", "");
const urlParts = base.split("/");
return {
repoName: extractRepoName(urlParts),
ref: extractRef(urlParts),
path: extractFilePath(urlParts),
lines: extractLines(urlParts),
};
};

const buildRequestURL = (repo: string, ref: string, path: string): string => {
return `https://api.github.com/repos/${repo}/contents/${path}?ref=${ref}`;
};

const extractCodeByLines = (code: string, lines: LineNumbers): string => {
const extractCodeByLines = (code: string, lines: LineNumbers | undefined): string => {
if (!lines) return code;
const codeLines = code.split("\n");
return codeLines.slice(lines.startLine - 1, lines.endLine).join("\n");
};

export {
extractRepoNameFromURL,
extractFilePathFromURL,
extractRefFromURL,
extractLinesFromURL,
buildRequestURL,
extractCodeByLines,
};
export { extractRepoDataFromURL, buildRequestURL, extractCodeByLines };
4 changes: 2 additions & 2 deletions app/packages/remark-embedded-github-code/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { visit } from "unist-util-visit";

const remarkEmbeddedGithubCode: Plugin<[], Root> = () => {
//TODO: check this regex
const regex = /https:\/\/github\.com\/[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+\/blob\/[a-zA-Z0-9._-]+\/?[^\s]*/g;
const regex = new RegExp(/https:\/\/github\.com\/[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+\/blob\/[a-zA-Z0-9._-]+\/?[^\s]*/g);
return (tree) => {
visit(tree, "link", (node, _, parent) => {
if (node.url && typeof node.url === "string") {
const matches = node.url.match(regex);
if (matches) {
node.data = {
hProperties: {
"data-remark-target": "remark-embedded-github-code",
"data-remark": "remark-embedded-github-code",
},
};

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
"@types/mdast": "^4.0.4",
"@types/unist": "^3.0.3",
"hast": "^1.0.0",
"hast-util-is-element": "^3.0.0",
"hast-util-to-html": "^9.0.3",
"hastscript": "^9.0.0",
"mdast": "^3.0.0",
"puppeteer": "^23.10.0",
"rehype-parse": "^9.0.1",
Expand Down
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default defineConfig(() => {
mdx({
jsxImportSource: 'hono/jsx',
remarkPlugins: [remarkGfm, remarkBreaks, remarkFrontmatter, remarkMdxFrontmatter, remarkEmbeddedGithubCode, remarkMomijiCodeFilename, remarkEmojiName, remarkAttentionBlock],
rehypePlugins: [[rehypeMomiji, { excludeLangs: ['mermaid'] }], rehypeMermaid, rehypeEmbeddedGithubCode, rehypeAttentionBlock],
rehypePlugins: [[rehypeMomiji, { excludeLangs: ['mermaid'] }], rehypeMermaid, [rehypeEmbeddedGithubCode, { githubPAT: "" }], rehypeAttentionBlock],
})
],
}
Expand Down

0 comments on commit cdfb8ef

Please sign in to comment.