simple-customize-markdown-converter 1.0.0 → 1.0.2
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.
- package/README.md +1 -1
- package/dist/lexer.d.ts +4 -0
- package/dist/lexer.js +49 -8
- package/dist/parser.d.ts +3 -0
- package/dist/parser.js +47 -5
- package/dist/renderer.js +4 -1
- package/dist/types/node.d.ts +16 -2
- package/dist/types/token.d.ts +13 -0
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/lexer.d.ts
CHANGED
package/dist/lexer.js
CHANGED
|
@@ -17,6 +17,9 @@ class Lexer {
|
|
|
17
17
|
{ match: (lex) => lex.peek() === "`", emit: (lex) => lex.handleInlineBlock() },
|
|
18
18
|
{ match: (lex) => lex.peek() === "#", emit: (lex) => lex.handleHeader() },
|
|
19
19
|
{ match: (lex) => lex.peek() === "*" || lex.peek() === "_", emit: (lex) => lex.handleItalic() },
|
|
20
|
+
{ match: (lex) => lex.peek() === ">", emit: (lex) => lex.handleQuoteBlock() },
|
|
21
|
+
{ match: (lex) => lex.peek() === "[", emit: (lex) => lex.handleLink() },
|
|
22
|
+
{ match: (lex) => lex.peek() === "!" && lex.peek(1) === "[", emit: (lex) => lex.handleImage() },
|
|
20
23
|
{ match: (lex) => lex.peek() === "\n", emit: (lex) => lex.listToken.push({ type: "NewLine" }) },
|
|
21
24
|
];
|
|
22
25
|
while (!this.isEndOfFile()) {
|
|
@@ -56,18 +59,16 @@ class Lexer {
|
|
|
56
59
|
return this.listToken[this.listToken.length - 1];
|
|
57
60
|
}
|
|
58
61
|
handleHeader() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
else if (lastToken.type === "Header") {
|
|
64
|
-
lastToken.level++;
|
|
62
|
+
let level = 0;
|
|
63
|
+
while (this.peek() === "#") {
|
|
64
|
+
level++;
|
|
65
|
+
this.next();
|
|
65
66
|
}
|
|
66
|
-
this.next();
|
|
67
67
|
if (this.peek() === " ") {
|
|
68
68
|
this.next();
|
|
69
69
|
this.pos--;
|
|
70
70
|
}
|
|
71
|
+
this.listToken.push({ type: "Header", level });
|
|
71
72
|
}
|
|
72
73
|
handleCodeBlock() {
|
|
73
74
|
let lang = "";
|
|
@@ -83,7 +84,7 @@ class Lexer {
|
|
|
83
84
|
this.next();
|
|
84
85
|
}
|
|
85
86
|
this.next(2); //Skip close block (due to next() after each tokenize iteration)
|
|
86
|
-
this.listToken.push({ "type": "CodeBlock", lang: lang.trim(), content: content });
|
|
87
|
+
this.listToken.push({ "type": "CodeBlock", lang: lang.trim(), content: content.trimEnd() });
|
|
87
88
|
}
|
|
88
89
|
handleTextBlock() {
|
|
89
90
|
const currentChar = this.peek();
|
|
@@ -112,5 +113,45 @@ class Lexer {
|
|
|
112
113
|
// this.next() //Skip close block
|
|
113
114
|
this.listToken.push({ "type": "InlineCode", content: content });
|
|
114
115
|
}
|
|
116
|
+
handleQuoteBlock() {
|
|
117
|
+
this.listToken.push({ type: "Quote" });
|
|
118
|
+
}
|
|
119
|
+
handleLink() {
|
|
120
|
+
this.next(); //Skip [
|
|
121
|
+
const text = this.readUntil("]");
|
|
122
|
+
this.next(); //Skip ]
|
|
123
|
+
if (this.peek() === "(") {
|
|
124
|
+
this.next(); //Skip (
|
|
125
|
+
const url = this.readUntil(")");
|
|
126
|
+
//Don't skip ) due to auto skip on while loop
|
|
127
|
+
this.listToken.push({ type: "Link", text: text, href: url });
|
|
128
|
+
}
|
|
129
|
+
else
|
|
130
|
+
this.listToken.push({ type: "Text", value: `[${text}]` });
|
|
131
|
+
}
|
|
132
|
+
handleImage() {
|
|
133
|
+
this.next(); //Skip !
|
|
134
|
+
if (this.peek() !== "[")
|
|
135
|
+
return;
|
|
136
|
+
this.next(); //Skip [
|
|
137
|
+
const alt = this.readUntil("]");
|
|
138
|
+
this.next(); //Skip ]
|
|
139
|
+
if (this.peek() === "(") {
|
|
140
|
+
this.next(); //Skip (
|
|
141
|
+
const src = this.readUntil(")");
|
|
142
|
+
this.next(); //Skip )
|
|
143
|
+
this.listToken.push({ type: "Image", alt: alt, src: src });
|
|
144
|
+
}
|
|
145
|
+
else
|
|
146
|
+
this.listToken.push({ type: "Text", value: `![${alt}]` });
|
|
147
|
+
}
|
|
148
|
+
readUntil(char) {
|
|
149
|
+
let result = "";
|
|
150
|
+
while (this.peek() !== char) {
|
|
151
|
+
result += this.peek();
|
|
152
|
+
this.next();
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
115
156
|
}
|
|
116
157
|
exports.default = Lexer;
|
package/dist/parser.d.ts
CHANGED
package/dist/parser.js
CHANGED
|
@@ -37,12 +37,18 @@ class Parser {
|
|
|
37
37
|
listNode.push(this.parseHeader());
|
|
38
38
|
break;
|
|
39
39
|
}
|
|
40
|
-
case "CodeBlock":
|
|
41
|
-
|
|
42
|
-
listNode.push(this.parseCodeBlock());
|
|
43
|
-
this.next();
|
|
44
|
-
}
|
|
40
|
+
case "CodeBlock": {
|
|
41
|
+
listNode.push(this.parseCodeBlock());
|
|
45
42
|
break;
|
|
43
|
+
}
|
|
44
|
+
case "Quote": {
|
|
45
|
+
listNode.push(this.parseQuote());
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
case "Image": {
|
|
49
|
+
listNode.push(this.parseImage());
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
46
52
|
case "NewLine": {
|
|
47
53
|
this.next(); // skip
|
|
48
54
|
break;
|
|
@@ -60,6 +66,7 @@ class Parser {
|
|
|
60
66
|
}
|
|
61
67
|
parseCodeBlock() {
|
|
62
68
|
const tok = this.peek();
|
|
69
|
+
this.next();
|
|
63
70
|
return {
|
|
64
71
|
type: "CodeBlock",
|
|
65
72
|
lang: tok?.type === "CodeBlock" ? tok.lang : "",
|
|
@@ -91,6 +98,35 @@ class Parser {
|
|
|
91
98
|
content: tok?.type === "InlineCode" ? tok.content : ""
|
|
92
99
|
};
|
|
93
100
|
}
|
|
101
|
+
parseQuote() {
|
|
102
|
+
this.next(); //skip marker
|
|
103
|
+
return { type: "Quote", children: [{ type: "Paragraph", children: this.parseInlineUntil("NewLine") }] };
|
|
104
|
+
}
|
|
105
|
+
parseLink() {
|
|
106
|
+
const tok = this.peek();
|
|
107
|
+
this.next();
|
|
108
|
+
if (tok?.type === "Link") {
|
|
109
|
+
return {
|
|
110
|
+
type: "Link",
|
|
111
|
+
href: tok.href,
|
|
112
|
+
text: tok.text
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return { type: "Link", href: "", text: "" };
|
|
116
|
+
}
|
|
117
|
+
parseImage() {
|
|
118
|
+
const tok = this.peek();
|
|
119
|
+
this.next();
|
|
120
|
+
if (tok?.type === "Image") {
|
|
121
|
+
return {
|
|
122
|
+
type: "Image",
|
|
123
|
+
src: tok.src,
|
|
124
|
+
alt: tok.alt
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
else
|
|
128
|
+
return { type: "Image", src: "", alt: "" };
|
|
129
|
+
}
|
|
94
130
|
parseInlineUntil(stopType) {
|
|
95
131
|
const listNode = [];
|
|
96
132
|
while (!this.isEnd() && this.peek()?.type !== stopType) {
|
|
@@ -112,6 +148,12 @@ class Parser {
|
|
|
112
148
|
}
|
|
113
149
|
case "Text": {
|
|
114
150
|
listNode.push({ type: "Text", value: currentNode.value });
|
|
151
|
+
this.next();
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case "Link": {
|
|
155
|
+
listNode.push(this.parseLink());
|
|
156
|
+
break;
|
|
115
157
|
}
|
|
116
158
|
default: this.next();
|
|
117
159
|
}
|
package/dist/renderer.js
CHANGED
|
@@ -26,7 +26,10 @@ class Renderer {
|
|
|
26
26
|
CodeBlock: (node) => `<pre><code class="lang-${node.lang}">${this.escapeHtml(node.content)}</code></pre>`,
|
|
27
27
|
Bold: (_node, children) => `<strong>${children.join("")}</strong>`,
|
|
28
28
|
Italic: (_node, children) => `<em>${children.join("")}</em>`,
|
|
29
|
-
|
|
29
|
+
Quote: (_node, children) => `<blockquote>${children.join("")}</blockquote>`,
|
|
30
|
+
Link: (node) => `<a href="${node.href}">${node.text}</a>`,
|
|
31
|
+
Image: (node) => `<img src="${node.src}" alt="${node.alt}"/>`,
|
|
32
|
+
Text: (node) => node.value,
|
|
30
33
|
};
|
|
31
34
|
return this.option.elements?.[type] ?? defaultRender[type];
|
|
32
35
|
}
|
package/dist/types/node.d.ts
CHANGED
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
* - Header: A header with given `level` (1-6)
|
|
11
11
|
* - Bold: Bold text
|
|
12
12
|
* - Italic: Italic text
|
|
13
|
-
* - InlineCode: Inline code snippet, with `content`
|
|
14
|
-
* -
|
|
13
|
+
* - InlineCode: Inline code snippet, with it's `content`
|
|
14
|
+
* - Quote: A quote block
|
|
15
|
+
* - CodeBlock: A code block, with it's `lang` and `content`
|
|
16
|
+
* - Link: A link, with it's `text` and `href`
|
|
17
|
+
* - Image: An image, with it's `src` and `alt`
|
|
15
18
|
* - Text: Raw text content.
|
|
16
19
|
*/
|
|
17
20
|
export type Node = {
|
|
@@ -37,6 +40,17 @@ export type Node = {
|
|
|
37
40
|
type: "CodeBlock";
|
|
38
41
|
lang: string;
|
|
39
42
|
content: string;
|
|
43
|
+
} | {
|
|
44
|
+
type: "Quote";
|
|
45
|
+
children: Node[];
|
|
46
|
+
} | {
|
|
47
|
+
type: "Link";
|
|
48
|
+
href: string;
|
|
49
|
+
text: string;
|
|
50
|
+
} | {
|
|
51
|
+
type: "Image";
|
|
52
|
+
src: string;
|
|
53
|
+
alt: string;
|
|
40
54
|
} | {
|
|
41
55
|
type: "Text";
|
|
42
56
|
value: string;
|
package/dist/types/token.d.ts
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
* - Bold: Bold marker (`**`).
|
|
13
13
|
* - Italic: Italic marker (`*` or `_`).
|
|
14
14
|
* - InlineCode: Inline code snippet (`` ` ``), with its `content`.
|
|
15
|
+
* - Quote: A quote block (`>`).
|
|
16
|
+
* - Link: A link (`[text](url)`)
|
|
17
|
+
* - Image: An image (``)
|
|
15
18
|
* - EOF: A special token, this is the end of input.
|
|
16
19
|
*/
|
|
17
20
|
export type Token = {
|
|
@@ -33,6 +36,16 @@ export type Token = {
|
|
|
33
36
|
} | {
|
|
34
37
|
type: "InlineCode";
|
|
35
38
|
content: string;
|
|
39
|
+
} | {
|
|
40
|
+
type: "Quote";
|
|
41
|
+
} | {
|
|
42
|
+
type: "Link";
|
|
43
|
+
text: string;
|
|
44
|
+
href: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: "Image";
|
|
47
|
+
src: string;
|
|
48
|
+
alt: string;
|
|
36
49
|
} | {
|
|
37
50
|
type: "EOF";
|
|
38
51
|
};
|