Created
October 12, 2024 06:22
-
-
Save CreatiCoding/28d841883aef3b701835ee6dc8272cb0 to your computer and use it in GitHub Desktop.
markdown api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rehypeStringify from "rehype-stringify"; | |
import remarkParse from "remark-parse"; | |
import remarkRehype from "remark-rehype"; | |
import remarkGfm from "remark-gfm"; | |
import unified, { ProcessorSettings, Settings } from "unified"; | |
import type { NextApiRequest, NextApiResponse } from "next"; | |
// case 1 curl -XPOST "http://localhost:3000/api/markdown/render" -d '{ "markdown": "#test\n##test\n\n| ![](https://divopsor.github.io/blog-images/2024/05/18/the-best-welfare-is-colleagues-2-present-1.jpg) | ![](https://divopsor.github.io/blog-images/2024/05/18/the-best-welfare-is-colleagues-2-present-2.jpg) |\n| --- | --- |\n| ![](https://divopsor.github.io/blog-images/2024/05/18/the-best-welfare-is-colleagues-2-present-3.jpg) | ![](https://divopsor.github.io/blog-images/2024/05/18/the-best-welfare-is-colleagues-2.jpg) |\n" }' -H "Content-Type: application/json" | jq | |
// case 2 curl -XPOST "http://localhost:3000/api/markdown/render" -d '{ "markdown": "test![width=100% test](https://asd.com)" }' -H "Content-Type: application/json" | jq | |
export default async function handler( | |
req: NextApiRequest, | |
res: NextApiResponse | |
) { | |
try { | |
const markdown = req.body.markdown as string; | |
if (markdown == null || markdown === "") { | |
return res.status(200).json({ data: "" }); | |
} | |
const file = await unified() | |
.use(remarkParse as ProcessorSettings<Settings>) | |
.use(remarkRehype, { | |
handlers: (node: any) => { | |
console.log(node); | |
if (node.tagName === "img") { | |
node.properties.loading = "lazy"; | |
} | |
}, | |
}) | |
.use(remarkGfm) | |
.use(rehypeStringify) | |
.use(remarkNewlinesToBrs) | |
.use(remarkImageAltToWidth) | |
.process(markdown); | |
return res.status(200).json({ | |
data: String(file), | |
}); | |
} catch (error: any) { | |
res | |
.status(400) | |
.json({ message: "Internal server error", errorMessage: error.message }); | |
} | |
} | |
const visit = require("unist-util-visit"); | |
const u = require("unist-builder"); | |
const remarkNewlinesToBrs = () => (tree: any) => { | |
visit(tree, "text", (node: any, index: any, parent: any) => { | |
const isTable = ["table", "thead", "tbody", "tr", "td"].includes( | |
parent.tagName | |
); | |
if (isTable) { | |
if (node.value.includes("\n")) { | |
// Split the text at newlines | |
const parts = node.value.split("\n"); | |
const newNodes: any = []; | |
parts.forEach((part: any, i: any) => { | |
if (part !== "" || i !== parts.length - 1) { | |
// Add text node for the non-empty part | |
newNodes.push(u("text", part)); | |
} | |
}); | |
// Replace the current text node with the new nodes | |
parent.children.splice(index, 1, ...newNodes); | |
} | |
return; | |
} | |
if (node.value.includes("\n")) { | |
// Split the text at newlines | |
const parts = node.value.split("\n"); | |
const newNodes: any = []; | |
parts.forEach((part: any, i: any) => { | |
if (part !== "") { | |
// Add text node for the non-empty part | |
newNodes.push(u("text", part)); | |
} | |
if (i !== parts.length - 1) { | |
// Add a `br` element node for each newline, except after the last part | |
newNodes.push(u("element", { tagName: "br" }, [])); | |
} | |
}); | |
// Replace the current text node with the new nodes | |
parent.children.splice(index, 1, ...newNodes); | |
} | |
}); | |
}; | |
const remarkImageAltToWidth = () => (tree: any) => { | |
visit(tree, "element", (node: any, index: any, parent: any) => { | |
if (node.tagName === "img") { | |
const alt = node.properties.alt as string; | |
if (alt && alt.startsWith("width=")) { | |
const width = alt.split(" ")[0].split("=")[1]; | |
node.properties.alt = alt.split(" ").slice(1).join(" "); | |
node.properties.style = `width: ${width};${ | |
node.properties.style ? ` ${node.properties.style}` : "" | |
}`; | |
} | |
} | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "api", | |
"private": true, | |
"scripts": { | |
"dev": "next dev", | |
"build": "next build", | |
"start": "next start", | |
"lint": "next lint", | |
"prepare": "husky install" | |
}, | |
"dependencies": { | |
"@babel/core": "^7.19.1", | |
"@emotion/react": "^11.10.4", | |
"date-fns": "^3.6.0", | |
"multer": "^1.4.5-lts.1", | |
"next": "12.3.1", | |
"react": "18.2.0", | |
"react-dom": "18.2.0", | |
"rehype-stringify": "^8.0.0", | |
"remark-gfm": "^1.0.0", | |
"remark-parse": "^9.0.0", | |
"remark-rehype": "^8.1.0", | |
"unified": "^9.2.1", | |
"unist-builder": "^2.0.3", | |
"unist-util-visit": "^2.0.3" | |
}, | |
"devDependencies": { | |
"@emotion/babel-plugin": "^11.10.2", | |
"@types/babel__core": "^7", | |
"@types/eslint": "^8", | |
"@types/multer": "^1", | |
"@types/node": "18.7.18", | |
"@types/react": "18.0.21", | |
"@types/react-dom": "18.0.6", | |
"@typescript-eslint/eslint-plugin": "^5.36.2", | |
"@typescript-eslint/parser": "^5.36.2", | |
"eslint": "8.23.1", | |
"eslint-config-next": "12.3.1", | |
"eslint-plugin-import": "^2.26.0", | |
"husky": "^8.0.1", | |
"typescript": "4.8.3" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment