simple-customize-markdown-converter 1.0.7 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,346 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Parser = void 0;
4
+ class Parser {
5
+ constructor(listToken, footNoteResolver) {
6
+ this.pos = 0;
7
+ this.listToken = listToken;
8
+ this.footNoteResolver = footNoteResolver;
9
+ }
10
+ /**
11
+ * Parse a list token to a node
12
+ * @return A parsed abstract syntax tree (AST)
13
+ */
14
+ parse() {
15
+ return {
16
+ type: "Document",
17
+ children: this.parseBlocks()
18
+ };
19
+ }
20
+ peek(offset = 0) {
21
+ const i = this.pos + offset;
22
+ return i < this.listToken.length ? this.listToken[i] : null;
23
+ }
24
+ next(amount = 1) {
25
+ this.pos += amount;
26
+ }
27
+ isEnd() {
28
+ return this.peek()?.type === "EOF";
29
+ }
30
+ parseBlocks() {
31
+ const listNode = [];
32
+ while (!this.isEnd()) {
33
+ const currentNode = this.peek();
34
+ if (!currentNode)
35
+ break;
36
+ switch (currentNode.type) {
37
+ case "Header": {
38
+ listNode.push(this.parseHeader());
39
+ break;
40
+ }
41
+ case "CodeBlock": {
42
+ listNode.push(this.parseCodeBlock());
43
+ break;
44
+ }
45
+ case "Quote": {
46
+ listNode.push(this.parseQuote());
47
+ break;
48
+ }
49
+ case "Image": {
50
+ listNode.push(this.parseImage());
51
+ break;
52
+ }
53
+ case "HorizontalLine": {
54
+ listNode.push(this.parseHorizontalLine());
55
+ break;
56
+ }
57
+ case "ListStart": {
58
+ listNode.push(this.parseList());
59
+ break;
60
+ }
61
+ case "TableStart": {
62
+ listNode.push(this.parseTable());
63
+ break;
64
+ }
65
+ case "HTMLBlock": {
66
+ listNode.push(this.parseHtmlBlock());
67
+ break;
68
+ }
69
+ case "FootnoteDef": {
70
+ this.parseFootnoteDef();
71
+ this.next();
72
+ break;
73
+ }
74
+ case "NewLine": {
75
+ this.next(); // skip
76
+ break;
77
+ }
78
+ default: listNode.push(this.parseParagraph());
79
+ }
80
+ }
81
+ return listNode;
82
+ }
83
+ parseParagraph() {
84
+ return {
85
+ type: "Paragraph",
86
+ children: this.parseInlineUntil("NewLine")
87
+ };
88
+ }
89
+ parseCodeBlock() {
90
+ const tok = this.peek();
91
+ this.next();
92
+ return {
93
+ type: "CodeBlock",
94
+ lang: tok?.type === "CodeBlock" ? tok.lang : "",
95
+ content: tok?.type === "CodeBlock" ? tok.content : ""
96
+ };
97
+ }
98
+ parseHeader() {
99
+ const currentNode = this.peek();
100
+ this.next();
101
+ return {
102
+ type: "Header",
103
+ level: currentNode?.type === "Header" ? currentNode.level : 1,
104
+ children: this.parseInlineUntil("NewLine") //Temp
105
+ };
106
+ }
107
+ parseBold() {
108
+ this.next(); // skip marker
109
+ return { type: "Bold", children: this.parseInlineUntil("Bold") };
110
+ }
111
+ parseItalic() {
112
+ this.next(); // skip marker
113
+ return { type: "Italic", children: this.parseInlineUntil("Italic") };
114
+ }
115
+ parseStrikethrough() {
116
+ this.next(); // skip marker
117
+ return { type: "Strikethrough", children: this.parseInlineUntil("Strikethrough") };
118
+ }
119
+ parseInlineCode() {
120
+ const tok = this.peek();
121
+ this.next();
122
+ return {
123
+ type: "InlineCode",
124
+ content: tok?.type === "InlineCode" ? tok.content : ""
125
+ };
126
+ }
127
+ parseQuote() {
128
+ this.next(); //skip marker
129
+ return { type: "Quote", children: [{ type: "Paragraph", children: this.parseInlineUntil("NewLine") }] };
130
+ }
131
+ parseList() {
132
+ const tok = this.peek();
133
+ if (tok?.type === "ListStart") {
134
+ this.next(); //skip marker
135
+ const result = {
136
+ type: "List",
137
+ level: tok.level,
138
+ ordered: tok.ordered,
139
+ children: [],
140
+ };
141
+ let nextToken = this.peek();
142
+ while (!this.isEnd()) {
143
+ if (nextToken?.type === "ListItem" || nextToken?.type === "TaskItem") {
144
+ result.children.push(this.parseListItem());
145
+ nextToken = this.peek();
146
+ }
147
+ else if (nextToken?.type === "ListEnd") {
148
+ this.next();
149
+ break;
150
+ }
151
+ else
152
+ break;
153
+ }
154
+ return result;
155
+ }
156
+ //Temp return
157
+ return {
158
+ type: "Text",
159
+ value: ""
160
+ };
161
+ }
162
+ parseListItem() {
163
+ const currentToken = this.peek();
164
+ this.next(); // skip marker
165
+ const children = [];
166
+ while (!this.isEnd()) {
167
+ const tok = this.peek();
168
+ if (!tok)
169
+ break;
170
+ if (tok.type === "NewLine") {
171
+ this.next();
172
+ continue;
173
+ }
174
+ if (tok.type === "ListStart") {
175
+ children.push(this.parseList());
176
+ continue;
177
+ }
178
+ if (["ListItem", "TaskItem", "ListEnd"].includes(tok.type)) {
179
+ break;
180
+ }
181
+ children.push(...this.parseInlineUntil("NewLine"));
182
+ }
183
+ return currentToken?.type === "TaskItem" ? {
184
+ type: "TaskItem",
185
+ checked: currentToken.type === "TaskItem" ? currentToken.checked : false,
186
+ children: children
187
+ } : {
188
+ type: "ListItem",
189
+ children: children
190
+ };
191
+ }
192
+ parseLink() {
193
+ const tok = this.peek();
194
+ this.next();
195
+ if (tok?.type === "Link") {
196
+ return {
197
+ type: "Link",
198
+ href: tok.href,
199
+ text: tok.text
200
+ };
201
+ }
202
+ return { type: "Link", href: "", text: "" };
203
+ }
204
+ parseImage() {
205
+ const tok = this.peek();
206
+ this.next();
207
+ if (tok?.type === "Image") {
208
+ return {
209
+ type: "Image",
210
+ src: tok.src,
211
+ alt: tok.alt
212
+ };
213
+ }
214
+ else
215
+ return { type: "Image", src: "", alt: "" };
216
+ }
217
+ parseTable() {
218
+ this.next(); // skip TableStart token
219
+ const parseRow = () => {
220
+ const rowStartToken = this.peek();
221
+ if (rowStartToken?.type !== "RowStart")
222
+ return { isHeader: false, cells: [] };
223
+ this.next(); // skip RowStart token
224
+ const cells = [];
225
+ while (this.peek() && this.peek().type !== "RowEnd") {
226
+ cells.push(parseCell());
227
+ }
228
+ this.next(); // skip RowEnd token
229
+ return {
230
+ isHeader: rowStartToken.isHeader,
231
+ cells: cells
232
+ };
233
+ };
234
+ const parseCell = () => {
235
+ const cellStartToken = this.peek();
236
+ if (cellStartToken?.type !== "CellStart")
237
+ return { align: "left", children: [] };
238
+ this.next(); // skip CellStart token
239
+ const childrens = this.parseInlineUntil("CellEnd");
240
+ return {
241
+ align: cellStartToken.align,
242
+ children: childrens
243
+ };
244
+ };
245
+ const rows = [];
246
+ while (this.peek()?.type !== "TableEnd") {
247
+ rows.push(parseRow());
248
+ if (this.isEnd())
249
+ break;
250
+ }
251
+ this.next();
252
+ return {
253
+ type: "Table",
254
+ rows: rows
255
+ };
256
+ }
257
+ parseHtmlBlock() {
258
+ const tok = this.peek();
259
+ this.next(); // skip marker
260
+ if (tok?.type === "HTMLBlock") {
261
+ return { type: "HTMLBlock", value: tok.value };
262
+ }
263
+ else
264
+ return { type: "Text", value: "" };
265
+ }
266
+ parseHtmlInline() {
267
+ const tok = this.peek();
268
+ this.next(); // skip marker
269
+ if (tok?.type === "HTMLInline") {
270
+ return { type: "HTMLInline", value: tok.value };
271
+ }
272
+ else
273
+ return { type: "Text", value: "" };
274
+ }
275
+ parseHorizontalLine() {
276
+ this.next(); // skip marker
277
+ return { type: "HorizontalLine" };
278
+ }
279
+ parseFootnoteDef() {
280
+ const tok = this.peek();
281
+ if (tok?.type !== "FootnoteDef")
282
+ return;
283
+ this.footNoteResolver.addDef(tok.id, tok.content);
284
+ }
285
+ parseFootnoteRef() {
286
+ const tok = this.peek();
287
+ this.next();
288
+ if (tok?.type !== "FootnoteRef")
289
+ return { type: "Text", value: "" };
290
+ this.footNoteResolver.addUsedRef(tok.id);
291
+ return { type: "FootnoteRef", id: tok.id };
292
+ }
293
+ parseInlineUntil(stopType, isConsumeStopToken = true) {
294
+ const stop = Array.isArray(stopType) ? stopType : [stopType];
295
+ const listNode = [];
296
+ while (!this.isEnd()) {
297
+ const currentNode = this.peek();
298
+ if (!currentNode)
299
+ break;
300
+ if (stop.includes(currentNode.type))
301
+ break;
302
+ switch (currentNode.type) {
303
+ case "Bold": {
304
+ listNode.push(this.parseBold());
305
+ break;
306
+ }
307
+ case "Italic": {
308
+ listNode.push(this.parseItalic());
309
+ break;
310
+ }
311
+ case "Strikethrough": {
312
+ listNode.push(this.parseStrikethrough());
313
+ break;
314
+ }
315
+ case "InlineCode": {
316
+ listNode.push(this.parseInlineCode());
317
+ break;
318
+ }
319
+ case "Text": {
320
+ listNode.push({ type: "Text", value: currentNode.value });
321
+ this.next();
322
+ break;
323
+ }
324
+ case "Link": {
325
+ listNode.push(this.parseLink());
326
+ break;
327
+ }
328
+ case "HTMLInline": {
329
+ listNode.push(this.parseHtmlInline());
330
+ break;
331
+ }
332
+ case "FootnoteRef": {
333
+ listNode.push(this.parseFootnoteRef());
334
+ break;
335
+ }
336
+ //Special case
337
+ case "HTMLBlock": return listNode;
338
+ default: this.next();
339
+ }
340
+ }
341
+ if (isConsumeStopToken)
342
+ this.next(); //Skip stop token
343
+ return listNode;
344
+ }
345
+ }
346
+ exports.Parser = Parser;
@@ -0,0 +1,3 @@
1
+ /**
2
+ * @deprecated - Delete this file later
3
+ */
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ /**
3
+ * @deprecated - Delete this file later
4
+ */
5
+ // import { FootnoteResolver } from "./resolver"
6
+ // import { Node, TableRow } from "../types/node"
7
+ // import { RenderElements, RenderOption } from "../types/options/renderOptions"
8
+ // export default class Renderer {
9
+ // option: RenderOption
10
+ // footNoteResolver: FootnoteResolver
11
+ // constructor(option: RenderOption, footNoteResolver: FootnoteResolver) {
12
+ // this.option = option
13
+ // this.footNoteResolver = footNoteResolver
14
+ // }
15
+ // /**
16
+ // * Render a Node (AST) to a HTML string according renderer options
17
+ // *
18
+ // * @param node - The abstract syntax tree (AST) from the Parser
19
+ // * @returns The rendered HTML string.
20
+ // */
21
+ // render<K extends Node["type"]>(node: Extract<Node, { type: K }>): string {
22
+ // //Get proper handler type
23
+ // const handler = this.handleRender(node.type)
24
+ // //If node have children, recursive to handle all node's children
25
+ // const children = "children" in node ? node.children.map((ele) => this.render(ele)) : []
26
+ // return handler(node, children)
27
+ // }
28
+ // private handleRender<K extends Node["type"]>(type: K): NonNullable<RenderElements[K]> {
29
+ // const defaultRender: RenderElements = {
30
+ // //Base structural nodes
31
+ // Document: (_node, children) => children.join("") + this.renderFootnotes(),
32
+ // Paragraph: (_node, children) => `<p>${children.join("")}</p>`,
33
+ // //Container nodes
34
+ // CodeBlock: (node) => `<pre><code class="lang-${node.lang}">${this.escapeHtml(node.content)}</code></pre>`,
35
+ // Header: (node, children) => `<h${node.level}${node.level <= 2 ? ' style="border-bottom: 1px solid #d1d9e0b3"' : ''}>${children.join("")}</h${node.level}>`,
36
+ // Quote: (_node, children) => `<blockquote style="margin:0; padding:0 1em; color:#59636e; border-left:.25em solid #d1d9e0;">${children.join("")}</blockquote>`,
37
+ // //For list nodes
38
+ // List: (node, children) => node.ordered ? `<ol>${children.join("")}</ol>` : `<ul>${children.join("")}</ul>`,
39
+ // ListItem: (_node, children) => `<li>${children.join("")}</li>`,
40
+ // TaskItem: (node, children) => `<li><input type="checkbox" disabled ${node.checked ? "checked" : ""}>${children.join("")}</li>`,
41
+ // //Styling nodes
42
+ // Bold: (_node, children) => `<strong>${children.join("")}</strong>`,
43
+ // Italic: (_node, children) => `<em>${children.join("")}</em>`,
44
+ // Strikethrough: (_node, children) => `<s>${children.join("")}</s>`,
45
+ // InlineCode: (node) => `<code>${this.escapeHtml(node.content)}</code>`,
46
+ // //Media nodes
47
+ // Link: (node) => `<a href="${node.href}">${node.text}</a>`,
48
+ // Image: (node) => `<img src="${node.src}" alt="${node.alt}"/>`,
49
+ // //Leaf nodes
50
+ // HorizontalLine: (_node) => `<hr>`,
51
+ // Text: (node) => node.value,
52
+ // //For table nodes
53
+ // Table: (node, children) => this.renderTable(node, children),
54
+ // //For HTML
55
+ // HTMLBlock: (node) => node.value,
56
+ // HTMLInline: (node) => node.value,
57
+ // //For footnote
58
+ // FootnoteRef: (node) => {
59
+ // const idx = this.footNoteResolver.getUsedRefById(node.id)
60
+ // return `<sup id="fnref:${idx}"><a href="#fn:${idx}" class="footnote-ref">[${idx}]</a></sup>`
61
+ // }
62
+ // }
63
+ // return (this.option.elements?.[type] ?? defaultRender[type])!
64
+ // }
65
+ // private renderTable(node: Node, children: string[]) {
66
+ // if (node.type === "Table") {
67
+ // const header = node.rows.filter(row => row.isHeader)
68
+ // const body = node.rows.filter(row => !row.isHeader)
69
+ // const renderRows = (row: TableRow) => {
70
+ // const tag = row.isHeader ? "th" : "td"
71
+ // const cells = row.cells.map(cell => {
72
+ // const align = `style="text-align:${cell.align}"`
73
+ // return `<${tag} ${align}>${cell.children.map(c => this.render(c)).join("")}</${tag}>`
74
+ // }).join("")
75
+ // return `<tr>${cells}</tr>`
76
+ // }
77
+ // const tHead = header.length ? `<thead>${header.map(renderRows).join("")}</thead>` : ""
78
+ // const tBody = body.length ? `<tbody>${body.map(renderRows).join("")}</tbody>` : ""
79
+ // return `<table>${tHead}${tBody}</table>`
80
+ // }
81
+ // else return `<p>${children.join("\n")}</p>`
82
+ // }
83
+ // private escapeHtml(str: string) {
84
+ // return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
85
+ // }
86
+ // private renderFootnotes(): string {
87
+ // if (this.footNoteResolver.isResolverValid()) {
88
+ // const used = this.footNoteResolver.getUsedRef()
89
+ // if (used.length === 0) return ""
90
+ // const items = used.map((id, i) => {
91
+ // const def = this.footNoteResolver.getDef(id) ?? ""
92
+ // const idx = i + 1
93
+ // return `<li id="fn:${idx}"><p>${def} <a href="#fnref:${idx}" class="footnote-backref">↩</a></p></li>`
94
+ // })
95
+ // return `<section class="footnotes"><ol>${items.join("")}</ol></section>`
96
+ // }
97
+ // else return ""
98
+ // }
99
+ // }
@@ -0,0 +1,15 @@
1
+ declare abstract class Resolver {
2
+ abstract isResolverValid(): boolean;
3
+ }
4
+ export declare class FootnoteResolver extends Resolver {
5
+ private defs;
6
+ private usedRef;
7
+ addDef(id: string, content: string): void;
8
+ addUsedRef(id: string): void;
9
+ resolve(id: string): string | undefined;
10
+ getUsedRef(): string[];
11
+ getUsedRefById(id: string): number;
12
+ getDef(id: string): string | undefined;
13
+ isResolverValid(): boolean;
14
+ }
15
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FootnoteResolver = void 0;
4
+ class Resolver {
5
+ }
6
+ class FootnoteResolver extends Resolver {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.defs = new Map();
10
+ this.usedRef = [];
11
+ }
12
+ addDef(id, content) {
13
+ this.defs.set(id, content);
14
+ }
15
+ addUsedRef(id) {
16
+ if (!this.usedRef.includes(id)) {
17
+ this.usedRef.push(id);
18
+ }
19
+ }
20
+ resolve(id) {
21
+ return this.defs.get(id);
22
+ }
23
+ getUsedRef() {
24
+ return this.usedRef;
25
+ }
26
+ getUsedRefById(id) {
27
+ return this.usedRef.indexOf(id) + 1;
28
+ }
29
+ getDef(id) {
30
+ return this.defs.get(id);
31
+ }
32
+ isResolverValid() {
33
+ return this.defs.size !== 0 && this.usedRef.length !== 0;
34
+ }
35
+ }
36
+ exports.FootnoteResolver = FootnoteResolver;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- import { RenderOption } from "./types/renderOptions";
2
- export { RenderOption };
1
+ import { MarkdownDefaultOptions } from "./types/options";
2
+ import { RenderOption } from "./types/options/renderOptions";
3
+ import { Node } from "./types/node";
4
+ export { RenderOption, MarkdownDefaultOptions, Node };
3
5
  /**
4
6
  * Convert a Markdown string into HTML.
5
7
  * @param input - The Markdown source string
@@ -12,4 +14,4 @@ export { RenderOption };
12
14
  * // => <p>Hello <strong>world</strong></p>
13
15
  * ```
14
16
  */
15
- export declare function convertMarkdownToHTML(input: string, options?: RenderOption): string;
17
+ export declare function convertMarkdownToHTML(input: string, options?: MarkdownDefaultOptions): string;
package/dist/index.js CHANGED
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.convertMarkdownToHTML = convertMarkdownToHTML;
7
- const lexer_1 = __importDefault(require("./lexer"));
8
- const parser_1 = require("./parser");
9
- const renderer_1 = __importDefault(require("./renderer"));
10
- const resolver_1 = require("./resolver");
7
+ const lexer_1 = __importDefault(require("./core/lexer"));
8
+ const parser_1 = require("./core/parser");
9
+ const resolver_1 = require("./core/resolver");
10
+ const default_1 = __importDefault(require("./renderers/default"));
11
11
  /**
12
12
  * Convert a Markdown string into HTML.
13
13
  * @param input - The Markdown source string
@@ -20,9 +20,12 @@ const resolver_1 = require("./resolver");
20
20
  * // => <p>Hello <strong>world</strong></p>
21
21
  * ```
22
22
  */
23
- function convertMarkdownToHTML(input, options = {}) {
23
+ function convertMarkdownToHTML(input, options = {
24
+ renderOptions: {},
25
+ converterOptions: { allowDangerousHtml: false }
26
+ }) {
24
27
  const tokens = new lexer_1.default(input).tokenize();
25
28
  const footNoteResolver = new resolver_1.FootnoteResolver();
26
29
  const nodes = new parser_1.Parser(tokens, footNoteResolver).parse();
27
- return new renderer_1.default(options, footNoteResolver).render(nodes);
30
+ return new default_1.default(options, footNoteResolver).render(nodes);
28
31
  }
@@ -0,0 +1,39 @@
1
+ import React from "react";
2
+ import { ReactRenderOption } from "./types/options/reactRenderOptions";
3
+ import { MarkdownReactOptions } from "./types/options";
4
+ import { Node } from "./types/node";
5
+ export { MarkdownReactOptions, ReactRenderOption, Node };
6
+ /**
7
+ * Convert a Markdown string into a ReactNode.
8
+ * @param input - The Markdown source string
9
+ * @param renderOptions - Optional rendering options
10
+ * @param options - Optional handle options
11
+ * @returns The rendered `React.ReactNode` ready to be rendered into a React component.
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * const node = convertMarkdownToReactNode("## Hello React");
16
+ * return <div>{node}</div>;
17
+ * ```
18
+ */
19
+ export declare function convertMarkdownToReactNode(input: string, options?: MarkdownReactOptions): React.ReactNode;
20
+ /**
21
+ * A React commponent that renders Markdown content.
22
+ * Using `React.useMemo` to ensure performance and prevent unnecessary re-render.
23
+ * @param props.content - The Markdown source to render.
24
+ * @param props.options - Optional configuration for the renderer.
25
+ * @param props.className - Optional CSS classes for the wrapping `div` element.
26
+ * @example
27
+ * ```tsx
28
+ * <MarkdownComponent
29
+ * content="**Bold text here**"
30
+ * className="markdown markdown-rendered"
31
+ * options={{ converterOptions: { allowDangerousHtml: true } }}
32
+ * />
33
+ * ```
34
+ */
35
+ export declare const MarkdownComponent: React.FC<{
36
+ content: string;
37
+ options?: MarkdownReactOptions;
38
+ className?: string;
39
+ }>;
package/dist/react.js ADDED
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MarkdownComponent = void 0;
7
+ exports.convertMarkdownToReactNode = convertMarkdownToReactNode;
8
+ const react_1 = __importDefault(require("react"));
9
+ const lexer_1 = __importDefault(require("./core/lexer"));
10
+ const resolver_1 = require("./core/resolver");
11
+ const parser_1 = require("./core/parser");
12
+ const react_2 = __importDefault(require("./renderers/react"));
13
+ /**
14
+ * Convert a Markdown string into a ReactNode.
15
+ * @param input - The Markdown source string
16
+ * @param renderOptions - Optional rendering options
17
+ * @param options - Optional handle options
18
+ * @returns The rendered `React.ReactNode` ready to be rendered into a React component.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const node = convertMarkdownToReactNode("## Hello React");
23
+ * return <div>{node}</div>;
24
+ * ```
25
+ */
26
+ function convertMarkdownToReactNode(input, options = {
27
+ renderOptions: {},
28
+ converterOptions: { allowDangerousHtml: false }
29
+ }) {
30
+ const tokens = new lexer_1.default(input).tokenize();
31
+ const footNoteResolver = new resolver_1.FootnoteResolver();
32
+ const nodes = new parser_1.Parser(tokens, footNoteResolver).parse();
33
+ return new react_2.default(footNoteResolver, options).render(nodes);
34
+ }
35
+ /**
36
+ * A React commponent that renders Markdown content.
37
+ * Using `React.useMemo` to ensure performance and prevent unnecessary re-render.
38
+ * @param props.content - The Markdown source to render.
39
+ * @param props.options - Optional configuration for the renderer.
40
+ * @param props.className - Optional CSS classes for the wrapping `div` element.
41
+ * @example
42
+ * ```tsx
43
+ * <MarkdownComponent
44
+ * content="**Bold text here**"
45
+ * className="markdown markdown-rendered"
46
+ * options={{ converterOptions: { allowDangerousHtml: true } }}
47
+ * />
48
+ * ```
49
+ */
50
+ const MarkdownComponent = ({ content, className, options }) => {
51
+ const rendered = react_1.default.useMemo(() => {
52
+ return convertMarkdownToReactNode(content, options);
53
+ }, [content, options]);
54
+ return react_1.default.createElement("div", { className }, rendered);
55
+ };
56
+ exports.MarkdownComponent = MarkdownComponent;
@@ -0,0 +1,26 @@
1
+ import { FootnoteResolver } from "../core/resolver";
2
+ import { Node } from "../types/node";
3
+ import { MarkdownDefaultOptions } from "../types/options";
4
+ export default class DefaultRenderer {
5
+ options: MarkdownDefaultOptions;
6
+ footNoteResolver: FootnoteResolver;
7
+ constructor(options: MarkdownDefaultOptions, footNoteResolver: FootnoteResolver);
8
+ /**
9
+ * Render a Node (AST) to a HTML string according renderer options
10
+ *
11
+ * @param node - The abstract syntax tree (AST) from the Parser
12
+ * @returns The rendered HTML string.
13
+ */
14
+ render<K extends Node["type"]>(node: Extract<Node, {
15
+ type: K;
16
+ }>): string;
17
+ /**
18
+ * Select the appropriate rendering handler for a specific node type
19
+ * @param type - The type of AST Note
20
+ * @returns A function take a node and its children to procude a string.
21
+ */
22
+ private handleRender;
23
+ private renderTable;
24
+ private escapeHtml;
25
+ private renderFootnotes;
26
+ }