@thi.ng/hiccup-markdown 2.1.49 → 3.0.1

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/parse.js CHANGED
@@ -1,223 +1,534 @@
1
+ // Downloaded @ 2023-02-26T13:59:47.034Z
2
+ // Source: https://demo.thi.ng/umbrella/parse-playground/#ldoNR0ROTDE6IDxETkw-KyA9PiBkaXNjYXJkIDsKRE5MMjogPE5MPnsyLH0gOwpsYnI6ICdcXCchIDxOTD4hIDsKZXNjOiAnXFwnISAoICc8JyB8ICdbJyB8ICdfJyB8ICcqJyB8ICdgJyB8ICd-JyB8ICc6JyApIDsKaW5saW5lZGVsaW06ICggIiFbIiB8ICdbJyB8ICIqKiIgfCAnXycgfCAnYCcgfCAnPCcgfCAnXFwnIHwgIn5-IiB8ICIgOiIgfCA8bGJyPiApIDsKZGVsaW06ICggPGlubGluZWRlbGltPiB8IDxETkwyPiApIDsKZGVsaW0xOiAoIDxpbmxpbmVkZWxpbT4gfCA8Tkw-ICkgOwpib2R5OiAuKD8tPGRlbGltPiEpID0-IGpvaW4gOwpib2R5MTogLig_LTxkZWxpbTE-ISkgPT4gam9pbiA7Cgp3aWtpcmVmOiAiW1siISAuKD8rIl1dIiEpID0-IGpvaW4gOwpmbnJlZjogIlteIiEgPGxhYmVsPiA7CmZub3RlOiA8TFNUQVJUPiAiW14iISA8Zm5sYWJlbD4gPFdTMT4gPHBhcmE-IDsKZm5sYWJlbDogLig_KyJdOiIhKSA9PiBqb2luIDsKbGFiZWw6IC4oPysnXSchKSA9PiBqb2luIDsKdGFyZ2V0OiAuKD8rJyknISkgPT4gam9pbiA7Cmxpbms6ICdbJyEgPGxpbmtsYWJlbD4gJygnISA8dGFyZ2V0PiA7CmxpbmtyZWY6ICdbJyEgPGxpbmtsYWJlbD4gJ1snISA8bGFiZWw-IDsKbGlua2RlZjogPExTVEFSVD4gJ1snISA8bGFiZWw-ICc6JyEgPFdTMT4gPGxkdGFyZ2V0PiA7CmxkdGFyZ2V0OiAuKD8rPEROTDE-KSA9PiBqb2luIDsKbGlua2xhYmVsOiAoPGltZz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxsaW5rYm9keT4pKiAnXSchIDsKbGlua2RlbGltOiAoICIhWyIgfCAnWycgfCAiKioiIHwgJ18nIHwgIn5-IiB8ICdgJyB8ICddJykgOwpsaW5rYm9keTogLig_LTxsaW5rZGVsaW0-ISkgPT4gam9pbiA7CmltZzogIiFbIiEgPGxhYmVsPiAnKCchIDx0YXJnZXQ-IDsKYm9sZDogIioqIiEgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGJvZHkxPikqICIqKiIhIDsKaXRhbGljOiAnXychICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGlua3JlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8c3RyaWtlPiB8IDxjb2RlPiB8IDxlbW9qaT4gfCA8Ym9keTE-KSogJ18nISA7CnN0cmlrZTogIn5-IiEgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxib2R5MT4pKiAifn4iISA7CmNvZGU6ICdgJyEgLig_KydgJyEpID0-IGpvaW4gOwprYmQ6ICI8a2JkPiIhIC4oPysiPC9rYmQ-IiEpID0-IGpvaW4gOwplbW9qaTogJyAnPyAnOichICg8QUxQSEFfTlVNPiB8ICcrJyB8ICctJykoPysnOichKSA9PiBqb2luIDsKcGFyYTogKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rcmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8a2JkPiB8IDxlbW9qaT4gfCA8bGJyPiB8IDxlc2M-IHwgPGJvZHk-KSogPEROTDI-ISA7CgpoZGxldmVsOiAnIycrID0-IGNvdW50IDsKaGQ6IDxMU1RBUlQ-IDxoZGxldmVsPiA8V1MwPgogICAgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGJvZHkxPiApKiA8RE5MMT4gOwoKbGlsZXZlbDogJyAnKiA9PiBjb3VudCA7CnVpbnQ6IDxESUdJVD4rID0-IGludCA7CnVsaWQ6IDxETkw-IDxXUzA-ICctJyEgOwpvbGlkOiA8RE5MPiA8V1MwPiA8RElHSVQ-KyEgJy4nISA7CmxpZGVsaW06ICggPGRlbGltPiB8IDx1bGlkPiB8IDxvbGlkPiApIDsKbGlib2R5OiAuKD8tPGxpZGVsaW0-ISkgPT4gam9pbiA7CnRvZG86ICdbJyEgWyB4WF0gJ10nISA8V1MxPiA9PiBob2lzdFIgOwp1bGl0ZW06IDxMU1RBUlQ-IDxsaWxldmVsPiAiLSAiISA8dG9kbz4_CiAgICAgICAgKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPGxpYm9keT4gKSogPEROTD4gOwpvbGl0ZW06IDxMU1RBUlQ-IDxsaWxldmVsPiA8dWludD4gIi4gIiEgPHRvZG8-PwogICAgICAgICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxsaWJvZHk-ICkqIDxETkw-IDsKbGlzdDogKDx1bGl0ZW0-IHwgPG9saXRlbT4pKyA8RE5MMT4gOwoKY2JkZWxpbTogPExTVEFSVD4gImBgYCIhIDsKY29kZWJsb2NrOiA8Y2JkZWxpbT4hIDxjb2RlbWV0YT4gPGNvZGVib2R5PiA8RE5MMT4gOwpjb2RlbWV0YTogLig_KzxOTD4hKSA9PiBqb2luIDsKY29kZWJvZHk6IC4oPys8Y2JkZWxpbT4pID0-IGpvaW4gOwoKY3VzdG9tZGVsaW06IDxMU1RBUlQ-ICI6OjoiISA7CmN1c3RvbWJsb2NrOiA8Y3VzdG9tZGVsaW0-ISA8Y3VzdG9tbWV0YT4gPGN1c3RvbWJvZHk-IDxETkwxPiA7CmN1c3RvbW1ldGE6IC4oPys8Tkw-ISkgPT4gam9pbiA7CmN1c3RvbWJvZHk6IC4oPys8Y3VzdG9tZGVsaW0-KSA9PiBqb2luIDsKCm1ldGFibG9jazogPExTVEFSVD4gInt7eyIhIDxtZXRhYm9keT4gPEROTDE-IDsKbWV0YWJvZHk6IC4oPys8bWV0YWVuZD4hKSA9PiBqb2luIDsKbWV0YWVuZDogIn19fSIgPExFTkQ-IDsKCmJxbGV2ZWw6ICc-JysgPT4gY291bnQgOwpicWxpbmU6IDxMU1RBUlQ-IDxicWxldmVsPiAnICc_IQogICAgICAgICg8d2lraXJlZj4gfCA8aW1nPiB8IDxmbnJlZj4gfCA8bGluaz4gfCA8Ym9sZD4gfCA8aXRhbGljPiB8IDxzdHJpa2U-IHwgPGNvZGU-IHwgPGVtb2ppPiB8IDxicWxicj4gfCA8Ym9keTE-KSogPEROTD4gOwpicWxicjogJ1xcJyEoPy08RE5MPikgOwpicXVvdGU6IDxicWxpbmU-KyA8RE5MMT4gOwoKdGRlbGltOiAoPGlubGluZWRlbGltPiB8ICd8JyApIDsKdGJvZHk6IC4oPy08dGRlbGltPiEpID0-IGpvaW4gOwp0Y2VsbDogPFdTMD4gKDx3aWtpcmVmPiB8IDxpbWc-IHwgPGZucmVmPiB8IDxsaW5rPiB8IDxib2xkPiB8IDxpdGFsaWM-IHwgPHN0cmlrZT4gfCA8Y29kZT4gfCA8ZW1vamk-IHwgPHRib2R5PiApKiAnfCchIDsKdHJvdzogPExTVEFSVD4gJ3wnISA8dGNlbGw-KD8rPEROTD4pIDsKdGFibGU6IDx0cm93PisgPEROTDE-IDsKCmhyOiAiLS0iICctJysgPEROTDE-ID0-IGpvaW4gOwoKbWFpbjogPFdTMD4gKDxoZD4gfCA8bGlzdD4gfCA8YnF1b3RlPiB8IDxjb2RlYmxvY2s-IHwgPGN1c3RvbWJsb2NrPiB8IDxtZXRhYmxvY2s-IHwgPHRhYmxlPiB8IDxocj4gfCA8Zm5vdGU-IHwgPGxpbmtkZWY-IHwgPHBhcmE-KSogO6RtYWlu2gKLIyBIZWxsbyA6d29ybGQ6OnNtaWxlOlteYWJjXQoKYSBcPCBiCgpMZXQgYGV4cDIoeCkgPSAyKip4YAoKUHJlc3MgPGtiZD5Db250cm9sPC9rYmQ-ICsgPGtiZD5SPC9rYmQ-IHRvIHJlbG9hZC4KCjo6OmFsZXJ0ClRlc3QgW2xhYmVsXVtyZWZyZWZdCjo6OgoKLS0tCgp7e3sgeyJpZCI6IDEyMywgInByb3RlY3RlZCI6IHRydWUgfSB9fX0KU28gW1tzbWlsZV9mb28xMl1dIPCfmI0gd2hhdCdzIFt0aGlzXSguL3RoaXMubWQpW14yXSB0aGVuOgoKQSBbbGluayBfd2l0aCAqKm5lc3RlZCB-fmZvcm1hdH5-KiogYW5kIGByZWZlcmVuY2VgX11bcmVmcmVmXS4uLgoKYGBgdHMgdGFuZ2xlOm5vIGxuOnllcwpjb25zdCBmb28gPSA0MjsKLy8gdGhlIGVuZApgYGAKCjEuIGZvbwogIDQuIGJhcgogICAgIGJheiBhbmQgc28gb24KICAgICBtdWx0aWxpbmUKMi4gWyBdIHRhc2sKMy4gW3hdICoqZG9uZSoqCgo-IGJsb2NrcXVvdGUKPiBtdWx0aWxpbmUgdG9vXAo-PiBuZXN0ZWQKPj4-IGxldmVsIDMKPiAtLSBzb3VyY2UKCnwgZm9vIHwgYmFyIHwKfDotfC06fAp8IFtbcmVmIzIyXV0gfCBgb25gICoqb2ZmKiogfAoKW15hYmNdOiBGb28gX2Jhcl8gYmF6CgpbXjJdOiBUT0RPCgpbcmVmcmVmXTogaHR0cDovL3RoaS5uZy8KW2Zvb106IC4vZm9vLm1kI2JhcgoK2TUxMS4gYWJjCiAgLSB4eXoKMjEuIHh4eAogIDEuIGZvbwogICAgMS4gYmFyCjMxLiB5eXkKCtlWPiAqKmxldmVsIDFhKioKPj4gbGV2ZWwgMmEKPj4gbGV2ZWwgMmIKPgo-IGxldmVsIDFiCgpbKipmb28qKl0oYmFyKQoKKiohW2Zvb10oYmFyKSoqCgo
1
3
  import { peek } from "@thi.ng/arrays/peek";
2
- import { alts } from "@thi.ng/fsm/alts";
3
- import { fsm } from "@thi.ng/fsm/fsm";
4
- import { not } from "@thi.ng/fsm/not";
5
- import { whitespace } from "@thi.ng/fsm/range";
6
- import { repeat } from "@thi.ng/fsm/repeat";
7
- import { seq } from "@thi.ng/fsm/seq";
8
- import { str } from "@thi.ng/fsm/str";
9
- import { untilStr } from "@thi.ng/fsm/until";
10
- import { comp } from "@thi.ng/transducers/comp";
11
- import { filter } from "@thi.ng/transducers/filter";
4
+ import { isArray } from "@thi.ng/checks/is-array";
5
+ import { isPlainObject } from "@thi.ng/checks/is-plain-object";
6
+ import { isPrimitive } from "@thi.ng/checks/is-primitive";
7
+ import { isString } from "@thi.ng/checks/is-string";
8
+ import { DEFAULT, defmulti } from "@thi.ng/defmulti";
9
+ import { EMOJI } from "@thi.ng/emoji/emoji";
10
+ import { defContext } from "@thi.ng/parse/context";
11
+ import { defGrammar } from "@thi.ng/parse/grammar";
12
+ import { escapeEntities } from "@thi.ng/strings/entities";
13
+ import { slugifyGH } from "@thi.ng/strings/slugify";
14
+ export const GRAMMAR = defGrammar(`
15
+ DNL1: <DNL>+ => discard ;
16
+ DNL2: <NL>{2,} ;
17
+ lbr: '\\\\'! <NL>! ;
18
+ esc: '\\\\'! ( '<' | '[' | '_' | '*' | '\`' | '~' | ':' ) ;
19
+ inlinedelim: ( "![" | '[' | "**" | '_' | '\`' | '<' | '\\\\' | "~~" | " :" | <lbr> ) ;
20
+ delim: ( <inlinedelim> | <DNL2> ) ;
21
+ delim1: ( <inlinedelim> | <NL> ) ;
22
+ body: .(?-<delim>!) => join ;
23
+ body1: .(?-<delim1>!) => join ;
24
+
25
+ wikiref: "[["! .(?+"]]"!) => join ;
26
+ fnref: "[^"! <label> ;
27
+ fnote: <LSTART> "[^"! <fnlabel> <WS1> <para> ;
28
+ fnlabel: .(?+"]:"!) => join ;
29
+ label: .(?+']'!) => join ;
30
+ target: .(?+')'!) => join ;
31
+ link: '['! <linklabel> '('! <target> ;
32
+ linkref: '['! <linklabel> '['! <label> ;
33
+ linkdef: <LSTART> '['! <label> ':'! <WS1> <ldtarget> ;
34
+ ldtarget: .(?+<DNL1>) => join ;
35
+ linklabel: (<img> | <bold> | <italic> | <strike> | <code> | <emoji> | <linkbody>)* ']'! ;
36
+ linkdelim: ( "![" | '[' | "**" | '_' | "~~" | '\`' | ']') ;
37
+ linkbody: .(?-<linkdelim>!) => join ;
38
+ img: "!["! <label> '('! <target> ;
39
+ bold: "**"! (<wikiref> | <img> | <fnref> | <linkref> | <link> | <italic> | <strike> | <code> | <emoji> | <body1>)* "**"! ;
40
+ italic: '_'! (<wikiref> | <img> | <fnref> | <linkref> | <link> | <bold> | <strike> | <code> | <emoji> | <body1>)* '_'! ;
41
+ strike: "~~"! (<wikiref> | <img> | <fnref> | <linkref> | <link> | <bold> | <italic> | <code> | <emoji> | <body1>)* "~~"! ;
42
+ code: '\`'! .(?+'\`'!) => join ;
43
+ kbd: "<kbd>"! .(?+"</kbd>"!) => join ;
44
+ emoji: ' '? ':'! (<ALPHA_NUM> | '+' | '-')(?+':'!) => join ;
45
+ para: (<wikiref> | <img> | <fnref> | <linkref> | <link> | <bold> | <italic> | <strike> | <code> | <kbd> | <emoji> | <lbr> | <esc> | <body>)* <DNL2>! ;
46
+
47
+ hdlevel: '#'+ => count ;
48
+ hd: <LSTART> <hdlevel> <WS0>
49
+ (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <body1> )* <DNL1> ;
50
+
51
+ lilevel: ' '* => count ;
52
+ uint: <DIGIT>+ => int ;
53
+ ulid: <DNL> <WS0> '-'! ;
54
+ olid: <DNL> <WS0> <DIGIT>+! '.'! ;
55
+ lidelim: ( <delim> | <ulid> | <olid> ) ;
56
+ libody: .(?-<lidelim>!) => join ;
57
+ todo: '['! [ xX] ']'! <WS1> => hoistR ;
58
+ ulitem: <LSTART> <lilevel> "- "! <todo>?
59
+ (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <libody> )* <DNL> ;
60
+ olitem: <LSTART> <lilevel> <uint> ". "! <todo>?
61
+ (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <libody> )* <DNL> ;
62
+ list: (<ulitem> | <olitem>)+ <DNL1> ;
63
+
64
+ cbdelim: <LSTART> "\`\`\`"! ;
65
+ codeblock: <cbdelim>! <codemeta> <codebody> <DNL1> ;
66
+ codemeta: .(?+<NL>!) => join ;
67
+ codebody: .(?+<cbdelim>) => join ;
68
+
69
+ customdelim: <LSTART> ":::"! ;
70
+ customblock: <customdelim>! <custommeta> <custombody> <DNL1> ;
71
+ custommeta: .(?+<NL>!) => join ;
72
+ custombody: .(?+<customdelim>) => join ;
73
+
74
+ metablock: <LSTART> "{{{"! <metabody> <DNL1> ;
75
+ metabody: .(?+<metaend>!) => join ;
76
+ metaend: "}}}" <LEND> ;
77
+
78
+ bqlevel: '>'+ => count ;
79
+ bqline: <LSTART> <bqlevel> ' '?!
80
+ (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <bqlbr> | <body1>)* <DNL> ;
81
+ bqlbr: '\\\\'!(?-<DNL>) ;
82
+ bquote: <bqline>+ <DNL1> ;
83
+
84
+ tdelim: (<inlinedelim> | '|' ) ;
85
+ tbody: .(?-<tdelim>!) => join ;
86
+ tcell: <WS0> (<wikiref> | <img> | <fnref> | <link> | <bold> | <italic> | <strike> | <code> | <emoji> | <tbody> )* '|'! ;
87
+ trow: <LSTART> '|'! <tcell>(?+<DNL>) ;
88
+ table: <trow>+ <DNL1> ;
89
+
90
+ hr: "--" '-'+ <DNL1> => join ;
91
+
92
+ main: <WS0> (<hd> | <list> | <bquote> | <codeblock> | <customblock> | <metablock> | <table> | <hr> | <fnote> | <linkdef> | <para>)* ;
93
+ `);
94
+ export const DEFAULT_TAG_TRANSFORMS = {
95
+ bold: (_, body) => ["strong", {}, ...body],
96
+ blockquote: (_, body, meta) => ["blockquote", withMeta({}, meta), ...body],
97
+ br: () => ["br", {}],
98
+ code: (_, body) => ["code", {}, body],
99
+ codeblock: (_, lang, __head, body, meta) => [
100
+ "pre",
101
+ withMeta({ data: { lang }, __head }, meta),
102
+ ["code", {}, body],
103
+ ],
104
+ custom: (_, type, __head, body, meta) => [
105
+ "custom",
106
+ withMeta({ type, __head }, meta),
107
+ body,
108
+ ],
109
+ emoji: (_, id) => EMOJI[id] || id,
110
+ footnote: (_, id, body, meta) => [
111
+ "li",
112
+ withMeta({ id: `fn-${id}` }, meta),
113
+ ["sup", {}, `[${id}] `],
114
+ ...body,
115
+ " ",
116
+ ["a", { href: `#fnref-${id}` }, "↩︎"],
117
+ ],
118
+ footnoteRef: (_, id) => [
119
+ "sup",
120
+ {},
121
+ ["a", { id: `fnref-${id}`, href: `#fn-${id}` }, `[${id}]`],
122
+ ],
123
+ footnoteWrapper: (_, notes) => [
124
+ "ul",
125
+ { id: "footnotes" },
126
+ ...Object.keys(notes)
127
+ .sort()
128
+ .map((id) => notes[id]),
129
+ ],
130
+ heading: (_, level, id, body, meta) => [
131
+ level > 6 ? "p" : `h${level}`,
132
+ withMeta({ id }, meta),
133
+ ...body,
134
+ ],
135
+ hr: (_, __length, meta) => ["hr", withMeta({ __length }, meta)],
136
+ img: (_, alt, src, title) => ["img", { src, alt, title }],
137
+ italic: (_, body) => ["em", {}, ...body],
138
+ kbd: (_, key) => ["kbd", {}, key],
139
+ link: (_, href, title, body) => ["a", { href, title }, ...body],
140
+ linkRef: (ctx, refID, body) => [
141
+ "a",
142
+ {
143
+ href: () => ctx.linkRefs[refID]?.[0],
144
+ title: () => ctx.linkRefs[refID]?.[1],
145
+ },
146
+ ...body,
147
+ ],
148
+ meta: (_, body) => body,
149
+ olitem: (_, attribs, index, body) => [
150
+ "li",
151
+ { ...attribs, __index: index },
152
+ ...body,
153
+ ],
154
+ ol: (_, items, meta) => ["ol", withMeta({}, meta), ...items],
155
+ para: (_, body, meta) => ["p", withMeta({}, meta), ...body],
156
+ strike: (_, body) => ["s", {}, ...body],
157
+ table: (_, __align, head, rows, meta) => [
158
+ "table",
159
+ withMeta({ __align }, meta),
160
+ ["thead", {}, head],
161
+ ["tbody", {}, ...rows],
162
+ ],
163
+ tableCell: (_, body) => ["td", {}, ...body],
164
+ tableHead: (_, body) => ["th", {}, ...body],
165
+ tableRow: (_, __, cells) => ["tr", {}, ...cells],
166
+ ul: (_, items, meta) => ["ul", withMeta({}, meta), ...items],
167
+ ulitem: (_, attribs, body) => ["li", attribs, ...body],
168
+ wikiref: (_, id, label) => [
169
+ "a",
170
+ { class: "wikiref", href: encodeURI(id.replace(/\s+/g, "_")) },
171
+ label || id,
172
+ ],
173
+ };
174
+ export class ParseError extends Error {
175
+ constructor(state) {
176
+ super(state
177
+ ? `stopped line: ${state.l}, col: ${state.c} (pos: ${state.p})`
178
+ : undefined);
179
+ this.state = state;
180
+ }
181
+ }
12
182
  /**
13
- * Parser state IDs
183
+ * Parses given Markdown source string into a tree structure defined by given
184
+ * {@link TagTransforms}.
185
+ *
186
+ * @remarks
187
+ * The tag transforms are optional and the default implementations can be
188
+ * overwritten on tag-by-tag basis. The default transforms yield a simple hiccup
189
+ * tree (aka each tag will be an array in the form: `["tagname", {...},
190
+ * ...body]`).
191
+ *
192
+ * See [thi.ng/hiccup](https://thi.ng/hiccup) and related packages for further
193
+ * details.
194
+ *
195
+ * @param src
196
+ * @param opts
14
197
  */
15
- var State;
16
- (function (State) {
17
- State[State["BLOCKQUOTE"] = 0] = "BLOCKQUOTE";
18
- State[State["CODE"] = 1] = "CODE";
19
- State[State["CODEBLOCK"] = 2] = "CODEBLOCK";
20
- State[State["EMPHASIS"] = 3] = "EMPHASIS";
21
- State[State["END_BLOCKQUOTE"] = 4] = "END_BLOCKQUOTE";
22
- State[State["END_LI"] = 5] = "END_LI";
23
- State[State["END_PARA"] = 6] = "END_PARA";
24
- State[State["END_HEADING"] = 7] = "END_HEADING";
25
- State[State["END_TABLE"] = 8] = "END_TABLE";
26
- State[State["HEADING"] = 9] = "HEADING";
27
- State[State["IMG"] = 10] = "IMG";
28
- State[State["LINK"] = 11] = "LINK";
29
- State[State["LI"] = 12] = "LI";
30
- State[State["PARA"] = 13] = "PARA";
31
- State[State["START"] = 14] = "START";
32
- State[State["START_CODEBLOCK"] = 15] = "START_CODEBLOCK";
33
- State[State["STRIKE"] = 16] = "STRIKE";
34
- State[State["STRONG"] = 17] = "STRONG";
35
- State[State["TABLE"] = 18] = "TABLE";
36
- })(State || (State = {}));
198
+ export const parse = (src, { tags, opts, linkRefs, logger, } = {}) => {
199
+ const parseCtx = parseRaw(src, opts?.retain);
200
+ const mdCtx = defTransformContext(tags, opts, linkRefs, logger);
201
+ const result = [];
202
+ transformScope(parseCtx.root, mdCtx, result);
203
+ return {
204
+ result,
205
+ ctx: mdCtx,
206
+ complete: !!parseCtx.done,
207
+ state: parseCtx.state,
208
+ };
209
+ };
37
210
  /**
38
- * Default hiccup element factories
211
+ * 1st stage of the parsing (with out result transformations). This calls the
212
+ * `main` rule of the provided parse {@link GRAMMAR} and returns a parse
213
+ * context, incl. the raw abstract syntax tree of the parsed document. If
214
+ * parsing failed entirely (due to invalid input), throws a {@link ParseError}.
215
+ *
216
+ * @remarks
217
+ * Note: Even if the function returns a result, parsing might only have
218
+ * partially successful (can be checked via the [`.done`
219
+ * flag](https://docs.thi.ng/umbrella/parse/classes/ParseContext.html#done)).
220
+ *
221
+ * This function is only for advanced use. Mostly you'll probably want to use
222
+ * the main {@link parse} function instead.
223
+ *
224
+ * @param src
225
+ * @param retain
39
226
  */
40
- const DEFAULT_TAGS = {
41
- blockquote: (xs) => ["blockquote", {}, ...xs],
42
- code: (body) => ["code", {}, body],
43
- codeblock: (lang, body) => ["pre", { lang }, body],
44
- em: (body) => ["em", {}, body],
45
- heading: (level, xs) => [level < 7 ? `h${level}` : "p", {}, ...xs],
46
- hr: () => ["hr", {}],
47
- img: (src, alt) => ["img", { src, alt }],
48
- li: (xs) => ["li", {}, ...xs],
49
- link: (href, body) => ["a", { href }, body],
50
- list: (type, xs) => [type, {}, ...xs],
51
- paragraph: (xs) => ["p", {}, ...xs],
52
- strong: (body) => ["strong", {}, body],
53
- strike: (body) => ["del", {}, body],
54
- table: (rows) => ["table", {}, ["tbody", {}, ...rows]],
55
- td: (_, xs) => ["td", {}, ...xs],
56
- tr: (_, xs) => ["tr", {}, ...xs],
57
- };
58
- const BQUOTE = ">";
59
- const CODE = "`";
60
- const CODEBLOCK = "```";
61
- const CODEBLOCK_END = "\n```\n";
62
- const EM = "_";
63
- const HD = "#";
64
- const HR = "-";
65
- const IMG = "![";
66
- const LI = "- ";
67
- const LINK_LABEL = "[";
68
- const LINK_LABEL_END = "]";
69
- const LINK_HREF = "(";
70
- const LINK_HREF_END = ")";
71
- const NL = "\n";
72
- const STRIKE = "~~";
73
- const STRONG = "**";
74
- const TD = "|";
75
- // state / context handling helpers
76
- const transition = (ctx, id) => {
77
- ctx.children = [];
78
- ctx.body = "";
79
- return [id];
80
- };
81
- const push = (id, next) => (ctx) => {
82
- ctx.stack.push({ id, children: ctx.children.concat(ctx.body) });
83
- return transition(ctx, next);
227
+ export const parseRaw = (src, retain = false) => {
228
+ const ctx = defContext(src + "\n\n", { retain });
229
+ if (!GRAMMAR.rules.main(ctx))
230
+ throw new ParseError(ctx.state);
231
+ return ctx;
84
232
  };
85
- const pop = (result) => (ctx, body) => {
86
- const { id, children } = ctx.stack.pop();
87
- children.push(result(ctx, body));
88
- ctx.children = children;
89
- ctx.body = "";
90
- return [id];
91
- };
92
- const collectChildren = (ctx) => (ctx.children.push(ctx.body), ctx.children);
93
- const collect = (id) => (ctx, buf) => {
94
- ctx.body += buf.join("");
95
- return [id];
96
- };
97
- const collectHeading = (tag) => (ctx) => [14 /* State.START */, [tag(ctx.hd, collectChildren(ctx))]];
98
- const collectAndRestart = (tag) => (ctx) => [14 /* State.START */, [tag(collectChildren(ctx))]];
99
- const collectBlockQuote = (ctx) => (ctx.children.push(ctx.body, ["br", {}]),
100
- (ctx.body = ""),
101
- [0 /* State.BLOCKQUOTE */]);
102
- const collectCodeBlock = (tag) => (ctx, body) => [14 /* State.START */, [tag(ctx.lang, body)]];
103
- const collectLi = (ctx, tag) => ctx.container.push(tag(collectChildren(ctx)));
104
- const collectList = (type, list, item) => (ctx) => {
105
- collectLi(ctx, item);
106
- return [14 /* State.START */, [list(type, ctx.container)]];
233
+ export const defTransformContext = (tags, opts, linkRefs, logger) => ({
234
+ footnotes: {},
235
+ headings: [],
236
+ linkRefs: linkRefs || {},
237
+ hasFootnotes: false,
238
+ logger,
239
+ meta: null,
240
+ row: 0,
241
+ opts: {
242
+ escape: false,
243
+ retain: false,
244
+ ...opts,
245
+ },
246
+ tags: { ...DEFAULT_TAG_TRANSFORMS, ...tags },
247
+ });
248
+ /**
249
+ * Polymorphic & recursive parse scope/node transformation function. Takes a
250
+ * single scope, context and accumulator array, then calls itself recursively
251
+ * for any child scopes and passes relevant data to its user defined
252
+ * {@link TagTransforms} handler and adds result to the accumulator array.
253
+ *
254
+ */
255
+ export const transformScope = defmulti((x, ctx) => {
256
+ ctx.logger && ctx.logger.debug(x);
257
+ return x.id;
258
+ }, {
259
+ body1: "body",
260
+ bqlbr: "lbr",
261
+ bqline: "repeat0",
262
+ label: "body",
263
+ libody: "body",
264
+ linkbody: "body",
265
+ main: "root",
266
+ repeat1: "repeat0",
267
+ tbody: "body",
268
+ }, {
269
+ [DEFAULT]: (scope, ctx) => {
270
+ throw new Error(`unknown ID: ${scope.id}, ctx: ${JSON.stringify(ctx)}`);
271
+ },
272
+ root: ({ children }, ctx, acc) => {
273
+ if (!children)
274
+ return;
275
+ transformScope(children[0], ctx, acc);
276
+ if (ctx.hasFootnotes) {
277
+ __collect(acc, ctx.tags.footnoteWrapper(ctx, ctx.footnotes));
278
+ }
279
+ },
280
+ main: (scope, ctx, acc) => transformScope(scope.children[0], ctx, acc),
281
+ repeat0: (scope, ctx, acc) => scope.children && __children(ctx, scope.children, acc),
282
+ body: (scope, ctx, acc) => __collect(acc, __escape(ctx, scope.result)),
283
+ bold: (scope, ctx, acc) => __collect(acc, ctx.tags.bold(ctx, __children(ctx, scope.children))),
284
+ bquote: (scope, ctx, acc) => {
285
+ const stack = [[]];
286
+ const children = scope.children[0].children;
287
+ const $unwind = (level) => {
288
+ while (level < stack.length) {
289
+ const nested = stack.pop();
290
+ __collect(peek(stack), ctx.tags.blockquote(ctx, __trimBody(nested)));
291
+ }
292
+ return peek(stack);
293
+ };
294
+ for (let i = 0, n = children.length - 1; i <= n; i++) {
295
+ const [{ result: level }, bqline] = children[i].children;
296
+ let body = peek(stack);
297
+ if (level > stack.length) {
298
+ while (level > stack.length)
299
+ stack.push((body = []));
300
+ }
301
+ else if (level < stack.length) {
302
+ body = $unwind(level);
303
+ }
304
+ else if (body.length) {
305
+ const prev = children[i - 1].children[1];
306
+ if (!bqline.children) {
307
+ __collect(body, ctx.tags.br(ctx));
308
+ __collect(body, ctx.tags.br(ctx));
309
+ }
310
+ else if (prev.children &&
311
+ peek(prev.children).id !== "bqlbr") {
312
+ body.push(" ");
313
+ }
314
+ }
315
+ transformScope(bqline, ctx, body);
316
+ }
317
+ __collect(acc, ctx.tags.blockquote(ctx, __trimBody($unwind(1)), ctx.meta));
318
+ ctx.meta = null;
319
+ },
320
+ code: (scope, ctx, acc) => __collect(acc, ctx.tags.code(ctx, __escape(ctx, scope.result))),
321
+ codeblock: ({ children }, ctx, acc) => {
322
+ const [lang, ...head] = children[0].result.split(" ");
323
+ const body = children[1].result.trim();
324
+ __collect(acc, ctx.tags.codeblock(ctx, lang, head, __escape(ctx, body), ctx.meta));
325
+ ctx.meta = null;
326
+ },
327
+ customblock: ({ children }, ctx, acc) => {
328
+ const [type, ...head] = children[0].result.split(" ");
329
+ __collect(acc, ctx.tags.custom(ctx, type, head, children[1].result.trim(), ctx.meta));
330
+ ctx.meta = null;
331
+ },
332
+ emoji: ({ result }, ctx, acc) => {
333
+ if (result[0] === " ") {
334
+ __collect(acc, " ");
335
+ result = result.substring(1);
336
+ }
337
+ __collect(acc, ctx.tags.emoji(ctx, result));
338
+ },
339
+ esc: (scope, ctx, acc) => acc.push(__escape(ctx, scope.children[0].result)),
340
+ fnote: ({ children }, ctx) => {
341
+ const body = [];
342
+ const id = children[0].result;
343
+ transformScope(children[1].children[0], ctx, body);
344
+ const res = ctx.tags.footnote(ctx, id, body, ctx.meta);
345
+ if (res != null) {
346
+ ctx.hasFootnotes = true;
347
+ ctx.footnotes[id] = res;
348
+ }
349
+ ctx.meta = null;
350
+ },
351
+ fnref: (scope, ctx, acc) => __collect(acc, ctx.tags.footnoteRef(ctx, scope.children[0].result)),
352
+ hd: ({ children }, ctx, acc) => {
353
+ const body = [];
354
+ const level = children[0].result;
355
+ transformScope(children[1], ctx, body);
356
+ ctx.headings.push({ level, body });
357
+ __trimBody(body);
358
+ __collect(acc, ctx.tags.heading(ctx, level, slugifyGH(extractBody(body).join("")), body, ctx.meta));
359
+ ctx.meta = null;
360
+ },
361
+ hr: (scope, ctx, acc) => {
362
+ __collect(acc, ctx.tags.hr(ctx, scope.result.length, ctx.meta));
363
+ ctx.meta = null;
364
+ },
365
+ img: ({ children }, ctx, acc) => __collect(acc, ctx.tags.img(ctx, __escape(ctx, children[0].result.trim()), ...__linkTitle(children[1].result))),
366
+ italic: (scope, ctx, acc) => __collect(acc, ctx.tags.italic(ctx, __children(ctx, scope.children))),
367
+ kbd: (scope, ctx, acc) => __collect(acc, ctx.tags.kbd(ctx, scope.result)),
368
+ lbr: (_, ctx, acc) => __collect(acc, ctx.tags.br(ctx)),
369
+ link: ({ children }, ctx, acc) => __collect(acc, ctx.tags.link(ctx, ...__linkTitle(children[1].result), __children(ctx, children[0].children))),
370
+ linkdef: ({ children }, ctx) => {
371
+ ctx.linkRefs[children[0].result] = __linkTitle(children[1].result);
372
+ },
373
+ linkref: ({ children }, ctx, acc) => __collect(acc, ctx.tags.linkRef(ctx, children[1].result, __children(ctx, children[0].children))),
374
+ list: (scope, ctx, acc) => {
375
+ const children = scope.children[0].children;
376
+ const stack = [
377
+ [children[0].id === "ulitem" ? "ul" : "ol"],
378
+ ];
379
+ const levels = [0];
380
+ for (let item of children) {
381
+ const currLevel = item.children[0].result;
382
+ if (currLevel > peek(levels)) {
383
+ const sublist = [item.id === "ulitem" ? "ul" : "ol"];
384
+ const parent = peek(stack);
385
+ parent.length > 1
386
+ ? peek(parent).push(sublist)
387
+ : parent.push([
388
+ parent[0] === "ul" ? "ulitem" : "olitem",
389
+ {},
390
+ sublist,
391
+ ]);
392
+ stack.push(sublist);
393
+ levels.push(currLevel);
394
+ }
395
+ else if (currLevel < peek(levels)) {
396
+ while (currLevel < peek(levels)) {
397
+ stack.pop();
398
+ levels.pop();
399
+ }
400
+ }
401
+ transformScope(item, ctx, peek(stack));
402
+ }
403
+ const $list = (root, isRoot = false) => ctx.tags[root[0]](ctx, root.slice(1).map($item), isRoot ? ctx.meta : null);
404
+ const $item = (item) => {
405
+ let last = item[item.length - 1];
406
+ if (last[0] === "ul" || last[0] === "ol")
407
+ item[item.length - 1] = $list(last);
408
+ return item[0] === "ulitem"
409
+ ? ctx.tags.ulitem(ctx, item[1], item.slice(2))
410
+ : ctx.tags.olitem(ctx, item[1], item[2], item.slice(3));
411
+ };
412
+ __collect(acc, $list(stack[0], true));
413
+ ctx.meta = null;
414
+ },
415
+ metablock: ({ children }, ctx) => {
416
+ ctx.meta = ctx.tags.meta(ctx, children[0].result.trim());
417
+ },
418
+ olitem: ({ children }, ctx, acc) => {
419
+ const body = [];
420
+ transformScope(children[3], ctx, body);
421
+ __collect(acc, [
422
+ "olitem",
423
+ __listItemAttribs(children[2]),
424
+ children[1].result,
425
+ ...__trimBody(body),
426
+ ]);
427
+ },
428
+ para: (scope, ctx, acc) => {
429
+ __collect(acc, ctx.tags.para(ctx, __trimBody(__children(ctx, scope.children)), ctx.meta));
430
+ ctx.meta = null;
431
+ },
432
+ strike: (scope, ctx, acc) => __collect(acc, ctx.tags.strike(ctx, __children(ctx, scope.children))),
433
+ table: (scope, ctx, acc) => {
434
+ const children = scope.children[0].children;
435
+ const head = [];
436
+ const rows = [];
437
+ ctx.row = 0;
438
+ transformScope(children[0], ctx, head);
439
+ let align;
440
+ if (children.length > 1) {
441
+ align = __columnAlignments(children[1].children[0].children);
442
+ for (let i = 2, n = children.length; i < n; i++) {
443
+ ctx.row = i - 1;
444
+ transformScope(children[i], ctx, rows);
445
+ }
446
+ }
447
+ else {
448
+ align = new Array(children[0].children[0].children.length).fill("left");
449
+ }
450
+ __collect(acc, ctx.tags.table(ctx, align, head[0], rows, ctx.meta));
451
+ ctx.meta = null;
452
+ },
453
+ tcell: ({ children }, ctx, acc) => __collect(acc, (ctx.row > 0 ? ctx.tags.tableCell : ctx.tags.tableHead)(ctx, __trimBody(__children(ctx, children)))),
454
+ trow: ({ children }, ctx, acc) => __collect(acc, ctx.tags.tableRow(ctx, ctx.row, __children(ctx, children[0].children))),
455
+ ulitem: ({ children }, ctx, acc) => {
456
+ const body = [];
457
+ transformScope(children[2], ctx, body);
458
+ __collect(acc, [
459
+ "ulitem",
460
+ __listItemAttribs(children[1]),
461
+ ...__trimBody(body),
462
+ ]);
463
+ },
464
+ wikiref: (scope, ctx, acc) => {
465
+ const [id, label] = scope.result.split("|");
466
+ __collect(acc, ctx.tags.wikiref(ctx, id, label));
467
+ },
468
+ });
469
+ /**
470
+ * Takes an attributes object and optional metadata. If `meta` is not nullish,
471
+ * assigns it as `__meta` key in given object. Returns object.
472
+ *
473
+ * @param target
474
+ * @param meta
475
+ */
476
+ export const withMeta = (target, meta) => {
477
+ if (meta != null)
478
+ target.__meta = meta;
479
+ return target;
107
480
  };
108
- const collectTD = (tag) => (ctx) => {
109
- ctx.children.push(ctx.body);
110
- ctx.container.push(tag(peek(ctx.stack).container.length, ctx.children));
111
- return transition(ctx, 18 /* State.TABLE */);
481
+ /**
482
+ * Takes a hiccup tree and extracts only the primitive body values (strings,
483
+ * numbers, booleans) and returns them as array.
484
+ *
485
+ * @param body
486
+ * @param acc
487
+ */
488
+ export const extractBody = (body, acc = []) => {
489
+ for (let x of isPlainObject(body[1]) ? body.slice(2) : body) {
490
+ if (isPrimitive(x))
491
+ acc.push(x);
492
+ else if (isArray(x))
493
+ extractBody(x, acc);
494
+ }
495
+ return acc;
112
496
  };
113
- const collectTR = (tag) => (ctx) => {
114
- const rows = peek(ctx.stack).container;
115
- rows.push(tag(rows.length, ctx.container));
116
- ctx.container = [];
117
- return transition(ctx, 8 /* State.END_TABLE */);
497
+ /** @internal */
498
+ const __collect = (acc, x) => x != null && acc.push(x);
499
+ /** @internal */
500
+ const __children = (ctx, children, acc = []) => {
501
+ for (let c of children)
502
+ transformScope(c, ctx, acc);
503
+ return acc;
118
504
  };
119
- const collectTable = (tag) => (ctx) => {
120
- const rows = ctx.stack.pop().container;
121
- rows.splice(1, 1);
122
- return [14 /* State.START */, [tag(rows)]];
505
+ /** @internal */
506
+ const __escape = (ctx, x) => ctx.opts.escape ? escapeEntities(x) : x;
507
+ /** @internal */
508
+ const __listItemAttribs = (scope) => scope?.id === "todo"
509
+ ? {
510
+ __todo: true,
511
+ __done: scope.result === "x",
512
+ }
513
+ : {};
514
+ /** @internal */
515
+ const __trimBody = (body) => {
516
+ if (body.length === 1 && isString(body[0]))
517
+ body[0] = body[0].trim();
518
+ return body;
123
519
  };
124
- const collectInline = (fn) => pop((ctx, body) => fn(ctx.body + body.trim()));
125
- const heading = (ctx, body) => ((ctx.hd = body.length), transition(ctx, 9 /* State.HEADING */));
126
- const matchInline = (id) => [
127
- str("![", push(id, 10 /* State.IMG */)),
128
- str(LINK_LABEL, push(id, 11 /* State.LINK */)),
129
- str(STRIKE, push(id, 16 /* State.STRIKE */)),
130
- str(STRONG, push(id, 17 /* State.STRONG */)),
131
- str(EM, push(id, 3 /* State.EMPHASIS */)),
132
- str(CODE, push(id, 1 /* State.CODE */)),
133
- ];
134
- const matchLink = (result) => seq([
135
- untilStr(LINK_LABEL_END, (ctx, body) => ((ctx.title = body), undefined)),
136
- str(LINK_HREF),
137
- untilStr(LINK_HREF_END, (ctx, body) => ((ctx.href = body), undefined)),
138
- ], pop((ctx) => result(ctx.href, ctx.title)));
139
- const matchPara = (id, next) => alts([
140
- ...matchInline(id),
141
- str(NL, (ctx) => ((ctx.body += " "), [next])),
142
- ], collect(id));
143
- const newPara = (ctx, buf) => ((ctx.body = buf.join("")), (ctx.children = []), [13 /* State.PARA */]);
144
- const newParaInline = (next) => (ctx) => {
145
- ctx.stack.push({ id: 13 /* State.PARA */, children: [] });
146
- return transition(ctx, next);
520
+ /** @internal */
521
+ const __columnAlignments = (children) => {
522
+ const align = [];
523
+ for (let c of children) {
524
+ const raw = c.children[0].children[0].result.trim();
525
+ const isLeft = raw.startsWith(":-") ? 1 : 0;
526
+ const isRight = raw.endsWith("-:") ? 2 : 0;
527
+ align.push((["default", "left", "right", "center"][isLeft | isRight]));
528
+ }
529
+ return align;
147
530
  };
148
- const newParaCode = (ctx, x) => ((ctx.body = x[1]),
149
- ctx.stack.push({ id: 13 /* State.PARA */, children: [] }),
150
- [1 /* State.CODE */]);
151
- const newList = (ctx) => ((ctx.container = []), transition(ctx, 12 /* State.LI */));
152
- const newTable = (ctx) => (ctx.stack.push({ id: 18 /* State.TABLE */, container: [] }),
153
- (ctx.container = []),
154
- transition(ctx, 18 /* State.TABLE */));
155
- /**
156
- * Main parser / transducer. Defines state map with the various Markdown
157
- * syntax matchers and state transition handlers. The returned parser
158
- * itself is only used in `index.ts`.
159
- */
160
- export const parse = (_tags) => {
161
- const tags = { ...DEFAULT_TAGS, ..._tags };
162
- return comp(filter((x) => x !== "\r"), fsm({
163
- [14 /* State.START */]: alts([
164
- whitespace(() => [14 /* State.START */]),
165
- repeat(str(HD), 1, Infinity, heading),
166
- str(BQUOTE, (ctx) => transition(ctx, 0 /* State.BLOCKQUOTE */)),
167
- str(LI, newList),
168
- alts([
169
- seq([str(CODE), not(str(CODE))], newParaCode),
170
- str(CODEBLOCK, () => [15 /* State.START_CODEBLOCK */]),
171
- ], undefined, (_, next) => next),
172
- seq([repeat(str(HR), 3, Infinity), str(NL)], () => [
173
- 14 /* State.START */,
174
- [tags.hr()],
175
- ]),
176
- str(IMG, newParaInline(10 /* State.IMG */)),
177
- str(LINK_LABEL, newParaInline(11 /* State.LINK */)),
178
- str(STRONG, newParaInline(17 /* State.STRONG */)),
179
- str(STRIKE, newParaInline(16 /* State.STRIKE */)),
180
- str(EM, newParaInline(3 /* State.EMPHASIS */)),
181
- str(TD, newTable),
182
- ], newPara),
183
- [13 /* State.PARA */]: matchPara(13 /* State.PARA */, 6 /* State.END_PARA */),
184
- [6 /* State.END_PARA */]: alts([
185
- ...matchInline(13 /* State.PARA */),
186
- str(NL, collectAndRestart(tags.paragraph)),
187
- ], collect(13 /* State.PARA */)),
188
- [0 /* State.BLOCKQUOTE */]: matchPara(0 /* State.BLOCKQUOTE */, 4 /* State.END_BLOCKQUOTE */),
189
- [4 /* State.END_BLOCKQUOTE */]: alts([
190
- ...matchInline(0 /* State.BLOCKQUOTE */),
191
- str(BQUOTE, collectBlockQuote),
192
- str(NL, collectAndRestart(tags.blockquote)),
193
- ], collect(0 /* State.BLOCKQUOTE */)),
194
- [9 /* State.HEADING */]: matchPara(9 /* State.HEADING */, 7 /* State.END_HEADING */),
195
- [7 /* State.END_HEADING */]: alts([
196
- ...matchInline(9 /* State.HEADING */),
197
- str(NL, collectHeading(tags.heading)),
198
- ], collect(9 /* State.HEADING */)),
199
- [15 /* State.START_CODEBLOCK */]: untilStr(NL, (ctx, lang) => ((ctx.lang = lang), [2 /* State.CODEBLOCK */])),
200
- [2 /* State.CODEBLOCK */]: untilStr(CODEBLOCK_END, collectCodeBlock(tags.codeblock)),
201
- [12 /* State.LI */]: matchPara(12 /* State.LI */, 5 /* State.END_LI */),
202
- [5 /* State.END_LI */]: alts([
203
- str(NL, collectList("ul", tags.list, tags.li)),
204
- str(LI, (ctx) => (collectLi(ctx, tags.li),
205
- transition(ctx, 12 /* State.LI */))),
206
- ], collect(12 /* State.LI */)),
207
- [11 /* State.LINK */]: matchLink(tags.link),
208
- [10 /* State.IMG */]: matchLink(tags.img),
209
- [17 /* State.STRONG */]: untilStr(STRONG, collectInline(tags.strong)),
210
- [16 /* State.STRIKE */]: untilStr(STRIKE, collectInline(tags.strike)),
211
- [3 /* State.EMPHASIS */]: untilStr(EM, collectInline(tags.em)),
212
- [1 /* State.CODE */]: untilStr(CODE, collectInline(tags.code)),
213
- [18 /* State.TABLE */]: alts([
214
- ...matchInline(18 /* State.TABLE */),
215
- str(TD, collectTD(tags.td)),
216
- str(NL, collectTR(tags.tr)),
217
- ], collect(18 /* State.TABLE */)),
218
- [8 /* State.END_TABLE */]: alts([
219
- str(NL, collectTable(tags.table)),
220
- str(TD, () => [18 /* State.TABLE */]),
221
- ]),
222
- }, { stack: [] }, 14 /* State.START */));
531
+ const __linkTitle = (src) => {
532
+ const match = /\s"(.+)"$/.exec(src);
533
+ return match ? [src.substring(0, match.index), match[1]] : [src, undefined];
223
534
  };