flinker-markdown 1.0.0 → 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.
- package/README.md +19 -0
- package/dist/esm/index.js +1 -3
- package/dist/esm/md.js +250 -0
- package/dist/types/index.d.ts +1 -3
- package/dist/types/md.d.ts +57 -0
- package/package.json +1 -1
- package/dist/esm/components.js +0 -707
- package/dist/esm/core.js +0 -190
- package/dist/esm/processor.js +0 -155
- package/dist/types/components.d.ts +0 -156
- package/dist/types/core.d.ts +0 -91
- package/dist/types/processor.d.ts +0 -23
package/README.md
CHANGED
|
@@ -9,5 +9,24 @@ See demo:
|
|
|
9
9
|
npm i flinker-markdown
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
## Example
|
|
13
|
+
```ts
|
|
14
|
+
interface MarkdownProps extends TextProps {
|
|
15
|
+
absolutePathPrefix?: string
|
|
16
|
+
showRawText?: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const parser = new MDParser(grammar)
|
|
20
|
+
export const Markdown = () => {
|
|
21
|
+
return div<MarkdownProps>()
|
|
22
|
+
.map(s => {
|
|
23
|
+
if (!s.showRawText) {
|
|
24
|
+
s.htmlText = s.text ? md(parser, s.text, s.absolutePathPrefix) : ''
|
|
25
|
+
s.text = ''
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
12
31
|
## License
|
|
13
32
|
MIT
|
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { buildClassName, buildRule } from "./core";
|
|
3
|
-
export { UIComponent, vstack, vstackMapper, hstack, hstackMapper, Text, div, p, span, h1, h2, h3, h4, h5, h6, Button, btn, LinkBtn, link, switcher, observer, List, vlist, hlist, spacer, Image, image, Input, input, textarea } from "./components";
|
|
1
|
+
export { md, MDInlineGrammarRule, MDLineGrammarRule, MDMultilineGrammarRule, GlobalGrammarRule, MDGrammar, MDParser } from "./md";
|
package/dist/esm/md.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
export class MDInlineGrammarRule {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.matcher = [new RegExp(''), ''];
|
|
4
|
+
this.childrenInlineRules = [];
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export class MDLineGrammarRule {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.matcher = [new RegExp(''), ''];
|
|
10
|
+
this.childrenInlineRules = [];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class GlobalGrammarRule {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.childrenMultilineRules = [];
|
|
16
|
+
this.childrenLineRules = [];
|
|
17
|
+
this.childrenInlineRules = [];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class MDMultilineGrammarRule {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.startMatcher = [new RegExp(''), ''];
|
|
23
|
+
this.endMatcher = [new RegExp(''), ''];
|
|
24
|
+
this.childrenMultilineRules = [];
|
|
25
|
+
this.childrenLineRules = [];
|
|
26
|
+
this.childrenInlineRules = [];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class MDGrammar {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.globalRule = new GlobalGrammarRule();
|
|
32
|
+
const defLinePreproccessing = (v) => {
|
|
33
|
+
let res = v;
|
|
34
|
+
res = res.replace(/</g, '<');
|
|
35
|
+
//character escaping
|
|
36
|
+
res = res.replace(/\\`/gm, '`');
|
|
37
|
+
res = res.replace(/\\#/gm, '#');
|
|
38
|
+
res = res.replace(/\\_/g, '_');
|
|
39
|
+
return res;
|
|
40
|
+
};
|
|
41
|
+
//
|
|
42
|
+
// INLINE GRAMMAR RULES
|
|
43
|
+
//
|
|
44
|
+
this.strong = new MDInlineGrammarRule();
|
|
45
|
+
this.strong.matcher = [/_{3,}([^_]+)_{3,}/g, '<strong>$1</strong>'];
|
|
46
|
+
this.bold = new MDInlineGrammarRule();
|
|
47
|
+
this.bold.matcher = [/_{2,}([^_]+)_{2,}/g, '<b>$1</b>'];
|
|
48
|
+
this.italic = new MDInlineGrammarRule();
|
|
49
|
+
this.italic.matcher = [/_([^_]+)_/g, '<i>$1</i>'];
|
|
50
|
+
this.em = new MDInlineGrammarRule();
|
|
51
|
+
this.em.matcher = [/`([^`]+)`/g, '<em>$1</em>'];
|
|
52
|
+
this.em.childrenInlineRules = [this.strong, this.bold, this.italic];
|
|
53
|
+
this.code = new MDInlineGrammarRule();
|
|
54
|
+
this.code.matcher = [/``([^`]+)``/g, '<code>$1</code>'];
|
|
55
|
+
this.figure = new MDInlineGrammarRule();
|
|
56
|
+
this.figure.matcher = [/!\[([^\]]+)\]\(([^)]+)\)\(([^)]+)\)/gm, '<figure><img alt="$1" src="$2"/><figcaption>$3</figcaption></figure>'];
|
|
57
|
+
this.img = new MDInlineGrammarRule();
|
|
58
|
+
this.img.matcher = [/!\[([^\]]+)\]\(([^)]+)\)/gm, '<img alt="$1" src="$2"/>'];
|
|
59
|
+
this.link = new MDInlineGrammarRule();
|
|
60
|
+
this.link.matcher = [/\[([^\]]*)\]\(([^)]+)\)/, (line, descr, url) => {
|
|
61
|
+
return '<a href="' + url + '">' + (descr || url) + '</a>';
|
|
62
|
+
}];
|
|
63
|
+
this.globalRule.childrenInlineRules = [this.code, this.figure, this.img, this.link, this.strong, this.bold, this.em, this.italic];
|
|
64
|
+
//
|
|
65
|
+
// LINE GRAMMAR RULES
|
|
66
|
+
//
|
|
67
|
+
this.header = new MDLineGrammarRule();
|
|
68
|
+
this.header.matcher = [/^\$?(#{1,6}) (.*)$/, (line, signs, header) => {
|
|
69
|
+
const count = signs.length;
|
|
70
|
+
return '<h' + count + '>' + header + '</h' + count + '>';
|
|
71
|
+
}];
|
|
72
|
+
this.header.childrenInlineRules = [this.strong, this.bold, this.italic];
|
|
73
|
+
this.header.preProccessing = defLinePreproccessing;
|
|
74
|
+
this.quote = new MDLineGrammarRule();
|
|
75
|
+
this.quote.matcher = [/^> (.*)$/, '<blockquote><p>$1</p></blockquote>'];
|
|
76
|
+
this.quote.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
77
|
+
this.quote.preProccessing = defLinePreproccessing;
|
|
78
|
+
this.alignRight = new MDLineGrammarRule();
|
|
79
|
+
this.alignRight.matcher = [/^==> (.*)$/, '<div class="md-right">$1</div>'];
|
|
80
|
+
this.alignRight.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
81
|
+
this.alignRight.preProccessing = defLinePreproccessing;
|
|
82
|
+
this.alignCenter = new MDLineGrammarRule();
|
|
83
|
+
this.alignCenter.matcher = [/^=> (.*)$/, '<div class="md-center">$1</div>'];
|
|
84
|
+
this.alignCenter.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
85
|
+
this.alignCenter.preProccessing = defLinePreproccessing;
|
|
86
|
+
this.stars = new MDLineGrammarRule();
|
|
87
|
+
this.stars.matcher = [/^(\*{3,})/, '<p class="md-delim">$1</p>'];
|
|
88
|
+
this.p = new MDLineGrammarRule();
|
|
89
|
+
this.p.matcher = [/^(.*)$/, '<p>$1</p>'];
|
|
90
|
+
this.p.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
91
|
+
this.p.preProccessing = defLinePreproccessing;
|
|
92
|
+
this.br = new MDLineGrammarRule();
|
|
93
|
+
this.br.matcher = [/^\n$/, '<br/>'];
|
|
94
|
+
this.oli = new MDLineGrammarRule();
|
|
95
|
+
this.oli.matcher = [/^\d+\. (.*)$/, '<li>$1</li>'];
|
|
96
|
+
this.oli.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
97
|
+
this.oli.preProccessing = defLinePreproccessing;
|
|
98
|
+
this.uli = new MDLineGrammarRule();
|
|
99
|
+
this.uli.matcher = [/^\+ (.*)$/, '<li>$1</li>'];
|
|
100
|
+
this.uli.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
101
|
+
this.uli.preProccessing = defLinePreproccessing;
|
|
102
|
+
this.globalRule.childrenLineRules = [this.header, this.quote, this.alignCenter, this.alignRight, this.stars, this.br, this.p];
|
|
103
|
+
//
|
|
104
|
+
// MULTILINE GRAMMAR RULES
|
|
105
|
+
//
|
|
106
|
+
this.ol = new MDMultilineGrammarRule();
|
|
107
|
+
this.ul = new MDMultilineGrammarRule();
|
|
108
|
+
this.ol.startMatcher = [/^```ol *$/, '<ol>'];
|
|
109
|
+
this.ol.endMatcher = [/^``` *$/, '</ol>'];
|
|
110
|
+
this.ol.childrenLineRules = [this.oli, this.br, this.p];
|
|
111
|
+
this.ol.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
112
|
+
this.ol.childrenMultilineRules = [this.ol, this.ul];
|
|
113
|
+
this.ul.startMatcher = [/^```ul *$/, '<ul>'];
|
|
114
|
+
this.ul.endMatcher = [/^``` *$/, '</ul>'];
|
|
115
|
+
this.ul.childrenLineRules = [this.uli, this.br, this.p];
|
|
116
|
+
this.ul.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
117
|
+
this.ul.childrenMultilineRules = [this.ol, this.ul];
|
|
118
|
+
this.table = new MDMultilineGrammarRule();
|
|
119
|
+
this.table.startMatcher = [/^```tbl *$/, '<table>'];
|
|
120
|
+
this.table.endMatcher = [/^``` *$/, '</table>'];
|
|
121
|
+
const tableRow = new MDLineGrammarRule();
|
|
122
|
+
tableRow.matcher = [/^(.*)$/, (line) => {
|
|
123
|
+
return '<tr>' + line.split(/,(?! )/).map(v => '<td>' + v + '</td>').join('') + '</tr>';
|
|
124
|
+
}];
|
|
125
|
+
tableRow.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
126
|
+
tableRow.preProccessing = defLinePreproccessing;
|
|
127
|
+
this.table.childrenLineRules = [tableRow];
|
|
128
|
+
this.div = new MDMultilineGrammarRule();
|
|
129
|
+
this.div.startMatcher = [/^```([a-zA-Z]+) */, '<div class="$1"><div>'];
|
|
130
|
+
this.div.endMatcher = [/^``` *$/, '</div></div>'];
|
|
131
|
+
this.div.childrenInlineRules = this.globalRule.childrenInlineRules;
|
|
132
|
+
this.div.childrenLineRules = [this.quote, this.alignCenter, this.alignRight, this.br, this.p];
|
|
133
|
+
this.div.childrenMultilineRules = [this.div];
|
|
134
|
+
this.globalRule.childrenMultilineRules = [this.ol, this.ul, this.table, this.div];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
class MDParserContext {
|
|
138
|
+
constructor(text) {
|
|
139
|
+
this._rowIndex = -1;
|
|
140
|
+
this.rows = text.split('\n');
|
|
141
|
+
}
|
|
142
|
+
nextRow() {
|
|
143
|
+
this._rowIndex++;
|
|
144
|
+
return this._rowIndex < this.rows.length ? this.rows[this._rowIndex] : undefined;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export class MDParser {
|
|
148
|
+
constructor(grammar) {
|
|
149
|
+
this.globalRule = grammar.globalRule;
|
|
150
|
+
}
|
|
151
|
+
run(text) {
|
|
152
|
+
const ctx = new MDParserContext(text);
|
|
153
|
+
return this.parseMultiline(ctx, this.globalRule);
|
|
154
|
+
}
|
|
155
|
+
parseMultiline(ctx, rule) {
|
|
156
|
+
let res = '';
|
|
157
|
+
let exactlyMatched = false;
|
|
158
|
+
while (true) {
|
|
159
|
+
let row = ctx.nextRow();
|
|
160
|
+
if (row === undefined)
|
|
161
|
+
break;
|
|
162
|
+
if (!row)
|
|
163
|
+
row = '\n';
|
|
164
|
+
exactlyMatched = false;
|
|
165
|
+
if (!(rule instanceof GlobalGrammarRule) && row.match(rule.endMatcher[0])) {
|
|
166
|
+
res += row.replace(rule.endMatcher[0], rule.endMatcher[1]);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
for (let i = 0; i < rule.childrenMultilineRules.length; i++) {
|
|
170
|
+
const r = rule.childrenMultilineRules[i];
|
|
171
|
+
if (row.match(r.startMatcher[0])) {
|
|
172
|
+
exactlyMatched = true;
|
|
173
|
+
res += row.replace(r.startMatcher[0], r.startMatcher[1]);
|
|
174
|
+
res += this.parseMultiline(ctx, r);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (exactlyMatched)
|
|
179
|
+
continue;
|
|
180
|
+
for (let i = 0; i < rule.childrenLineRules.length; i++) {
|
|
181
|
+
const r = rule.childrenLineRules[i];
|
|
182
|
+
if (row.match(r.matcher[0])) {
|
|
183
|
+
exactlyMatched = true;
|
|
184
|
+
let line = r.preProccessing ? r.preProccessing(row) : row;
|
|
185
|
+
line = line.replace(r.matcher[0], r.matcher[1]);
|
|
186
|
+
line = this.parseLine(line, r.childrenInlineRules);
|
|
187
|
+
if (r.postProccessing)
|
|
188
|
+
line = r.postProccessing(line);
|
|
189
|
+
res += line;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (exactlyMatched)
|
|
194
|
+
continue;
|
|
195
|
+
console.warn('Line is not handled by any rule, line: <', row, '>', 'parent rule:', rule);
|
|
196
|
+
res += this.parseLine(row, rule.childrenInlineRules);
|
|
197
|
+
}
|
|
198
|
+
if (rule.postProccessing)
|
|
199
|
+
res = rule.postProccessing(res);
|
|
200
|
+
return res;
|
|
201
|
+
}
|
|
202
|
+
parseLine(text, inlineRules) {
|
|
203
|
+
if (!text || inlineRules.length === 0)
|
|
204
|
+
return text;
|
|
205
|
+
if (inlineRules.length === 1) {
|
|
206
|
+
return text.replace(inlineRules[0].matcher[0], inlineRules[0].matcher[1]);
|
|
207
|
+
}
|
|
208
|
+
const buffer = [];
|
|
209
|
+
let rules = [...inlineRules];
|
|
210
|
+
let value = text;
|
|
211
|
+
while (value) {
|
|
212
|
+
const candidateRules = [];
|
|
213
|
+
let matchedRule;
|
|
214
|
+
let matchedRuleMinSearchIndex = value.length;
|
|
215
|
+
for (let i = 0; i < rules.length; i++) {
|
|
216
|
+
const r = rules[i];
|
|
217
|
+
const si = value.search(r.matcher[0]);
|
|
218
|
+
if (si !== -1) {
|
|
219
|
+
candidateRules.push(r);
|
|
220
|
+
if (si < matchedRuleMinSearchIndex) {
|
|
221
|
+
matchedRuleMinSearchIndex = si;
|
|
222
|
+
matchedRule = r;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (!matchedRule) {
|
|
227
|
+
buffer.push(value);
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
buffer.push(value.substring(0, matchedRuleMinSearchIndex));
|
|
231
|
+
value = value.substring(matchedRuleMinSearchIndex);
|
|
232
|
+
let replacingSubstring = value.match(matchedRule.matcher[0])?.[0] ?? '';
|
|
233
|
+
value = value.substring(replacingSubstring.length);
|
|
234
|
+
replacingSubstring = replacingSubstring.replace(matchedRule.matcher[0], matchedRule.matcher[1]);
|
|
235
|
+
if (matchedRule.childrenInlineRules.length > 0)
|
|
236
|
+
replacingSubstring = this.parseLine(replacingSubstring, matchedRule.childrenInlineRules);
|
|
237
|
+
buffer.push(replacingSubstring);
|
|
238
|
+
rules = candidateRules;
|
|
239
|
+
}
|
|
240
|
+
return buffer.join('');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// const parser = new MDParser(new MDGrammar)
|
|
244
|
+
export const md = (parser, text, absolutePathPrefix) => {
|
|
245
|
+
let res = parser.run(text);
|
|
246
|
+
// allow images and links to have a relative path
|
|
247
|
+
if (absolutePathPrefix)
|
|
248
|
+
res = res.replace(/src="((?!https?:)[^"]+)"/gm, 'src="' + absolutePathPrefix + '$1"');
|
|
249
|
+
return res;
|
|
250
|
+
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { RulePriority, buildClassName, buildRule, BorderStyle, PointerEventsStyle, FontWeight, UIComponentProps } from "./core";
|
|
3
|
-
export { HtmlTag, AnyUIComponent, ObserveAffect, UIComponent, StackHAlign, StackVAlign, StackProps, vstack, vstackMapper, hstack, hstackMapper, TextProps, Text, div, p, span, h1, h2, h3, h4, h5, h6, ButtonProps, Button, btn, LinkProps, LinkBtn, link, SwitcherProps, switcher, observer, OnReceiver, List, vlist, hlist, SpacerProps, spacer, ImageProps, Image, image, InputType, InputMode, TurnType, InputProps, Input, input, textarea } from "./components";
|
|
1
|
+
export { md, MDInlineGrammarRule, MDLineGrammarRule, MDMultilineGrammarRule, GlobalGrammarRule, MDGrammar, MDParser } from "./md";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export declare class MDInlineGrammarRule {
|
|
2
|
+
matcher: [RegExp, any];
|
|
3
|
+
childrenInlineRules: MDInlineGrammarRule[];
|
|
4
|
+
}
|
|
5
|
+
export declare class MDLineGrammarRule {
|
|
6
|
+
matcher: [RegExp, any];
|
|
7
|
+
preProccessing?: (v: string) => string;
|
|
8
|
+
postProccessing?: (v: string) => string;
|
|
9
|
+
childrenInlineRules: MDInlineGrammarRule[];
|
|
10
|
+
}
|
|
11
|
+
export declare class GlobalGrammarRule {
|
|
12
|
+
postProccessing?: (v: string) => string;
|
|
13
|
+
childrenMultilineRules: MDMultilineGrammarRule[];
|
|
14
|
+
childrenLineRules: MDLineGrammarRule[];
|
|
15
|
+
childrenInlineRules: MDInlineGrammarRule[];
|
|
16
|
+
}
|
|
17
|
+
export declare class MDMultilineGrammarRule {
|
|
18
|
+
startMatcher: [RegExp, any];
|
|
19
|
+
endMatcher: [RegExp, any];
|
|
20
|
+
postProccessing?: (v: string) => string;
|
|
21
|
+
childrenMultilineRules: MDMultilineGrammarRule[];
|
|
22
|
+
childrenLineRules: MDLineGrammarRule[];
|
|
23
|
+
childrenInlineRules: MDInlineGrammarRule[];
|
|
24
|
+
}
|
|
25
|
+
export declare class MDGrammar {
|
|
26
|
+
readonly globalRule: GlobalGrammarRule;
|
|
27
|
+
readonly strong: MDInlineGrammarRule;
|
|
28
|
+
readonly bold: MDInlineGrammarRule;
|
|
29
|
+
readonly italic: MDInlineGrammarRule;
|
|
30
|
+
readonly em: MDInlineGrammarRule;
|
|
31
|
+
readonly code: MDInlineGrammarRule;
|
|
32
|
+
readonly figure: MDInlineGrammarRule;
|
|
33
|
+
readonly img: MDInlineGrammarRule;
|
|
34
|
+
readonly link: MDInlineGrammarRule;
|
|
35
|
+
readonly header: MDLineGrammarRule;
|
|
36
|
+
readonly quote: MDLineGrammarRule;
|
|
37
|
+
readonly alignRight: MDLineGrammarRule;
|
|
38
|
+
readonly alignCenter: MDLineGrammarRule;
|
|
39
|
+
readonly stars: MDLineGrammarRule;
|
|
40
|
+
readonly p: MDLineGrammarRule;
|
|
41
|
+
readonly br: MDLineGrammarRule;
|
|
42
|
+
readonly oli: MDLineGrammarRule;
|
|
43
|
+
readonly uli: MDLineGrammarRule;
|
|
44
|
+
readonly ol: MDMultilineGrammarRule;
|
|
45
|
+
readonly ul: MDMultilineGrammarRule;
|
|
46
|
+
readonly table: MDMultilineGrammarRule;
|
|
47
|
+
readonly div: MDMultilineGrammarRule;
|
|
48
|
+
constructor();
|
|
49
|
+
}
|
|
50
|
+
export declare class MDParser {
|
|
51
|
+
readonly globalRule: GlobalGrammarRule;
|
|
52
|
+
constructor(grammar: MDGrammar);
|
|
53
|
+
run(text: string): string;
|
|
54
|
+
private parseMultiline;
|
|
55
|
+
private parseLine;
|
|
56
|
+
}
|
|
57
|
+
export declare const md: (parser: MDParser, text: string, absolutePathPrefix?: string) => string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flinker-markdown",
|
|
3
3
|
"description": "Free TypeScript library for parsing markdown text (customisable, not standardized).",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/Dittner/FlinkerMD.git"
|