-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrenderer.ts
109 lines (90 loc) · 3.89 KB
/
renderer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { toAst } from "./utils.ts";
import { transformer } from "./transformer.ts";
import { generator } from "./generator.ts";
import { strike, strikethroughExt } from "./deps.ts";
import type { Node } from "./nodeTypes.ts";
export interface Extension {
/** Called before AST generation, if a string is returned,
* it will override the input markdown for later extension's init fn and processing steps */
init?(md: string, options: Options): string | void;
/** Called with the generated AST's root node, before any transformations */
postAST?(astRoot: Node, options: Options): void;
/** Called with each node */
transformNode?(
/** The builtin recursive transform function, can be called, to transform the node's children */
transformerFn: (node: Node, parent: Node, options: Options) => void,
node: Node,
parent: Node | undefined,
options: Options,
): boolean | void;
/** Called after all the transformations ran for all nodes */
postTransform?(astRoot: Node, options: Options): void;
/** Called with each node. It should return the string representation of
* the rendered node,if the extension handles that specific node, or void,
* if its not handled by the extension. */
generateNode?(
/** The builtin recursive generator function, can be called, to render the node's children */
generatorFn: (node: Node, parent: Node, options: Options) => string | undefined,
node: Node,
parent: Node | undefined,
options: Options,
): string | void;
/** Called after the string representation is created. */
postGenerate?(rendered: string, options: Options): string;
}
export interface MdastOptions {
/** SyntaxExtension[] */
// deno-lint-ignore no-explicit-any
extensions?: any[];
/** MdastExtension[] */
// deno-lint-ignore no-explicit-any
mdastExtensions?: any[];
}
/** Options for the processing and rendering of the markdown */
export interface Options {
extensions?: Extension[];
/** Whether to add borders to the generated tables. Defaults to `true`. */
tableBorder?: boolean; // TODO or string to override borderChars
/** Override list icons for the different list levels. For lists deeper than whats provided, the last icon will be used. Defaults to `['-', '◦', '▪', '▸']` */
listIcons?: string[];
/** Only affects thematicBreak line width currently. Defaults to `Deno.consoleSize().columns`*/
lineWidth?: number;
/** **UNSTABLE**: The AST generator may change in the future.
*
* Currently https://github.com/syntax-tree/mdast-util-from-markdown is used as the AST generator
*/
mdast?: {
/** BufferEncoding https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings*/
encoding?: string;
options?: MdastOptions;
};
}
/** Returns a string for the provided markdown, which printed in a terminal results in a formatted markdown text
*
* @param {string} md The input markdown string
* @param {Options} [options={}] Options for the processing and rendering of the markdown
* @returns {string} The rendered output of the provided markdown text
*/
export function renderMarkdown(md: string, options: Options = {}): string {
options?.extensions?.forEach((ext) => {
md = ext.init?.(md, options) || md;
});
const mdastOptions = {
mdastExtensions: [strikethroughExt, ...(options?.mdast?.options?.mdastExtensions || [])],
extensions: [strike(), ...(options?.mdast?.options?.extensions || [])],
};
const mdastEncoding = options.mdast?.encoding || "utf8";
const mdast = toAst(md, mdastEncoding, mdastOptions);
options?.extensions?.forEach((ext) => {
ext.postAST?.(mdast, options);
});
transformer(mdast, options);
options?.extensions?.forEach((ext) => {
ext.postTransform?.(mdast, options);
});
let mdString = generator(mdast, null!, options) ?? "";
options?.extensions?.forEach((ext) => {
mdString = ext.postGenerate?.(mdString, options) ?? mdString;
});
return mdString;
}