@khanacademy/simple-markdown 0.8.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/src/index.js ADDED
@@ -0,0 +1,2043 @@
1
+ /* eslint-disable prefer-spread, no-regex-spaces, no-unused-vars, guard-for-in, no-console, no-var */
2
+ // @flow
3
+
4
+ /**
5
+ * Simple-Markdown
6
+ * ===============
7
+ *
8
+ * Simple-Markdown's primary goal is to be easy to adapt. It aims
9
+ * to be compliant with John Gruber's [Markdown Syntax page][1],
10
+ * but compatiblity with other markdown implementations' edge-cases
11
+ * will be sacrificed where it conflicts with simplicity or
12
+ * extensibility.
13
+ *
14
+ * If your goal is to simply embed a standard markdown implementation
15
+ * in your website, simple-markdown is probably not the best library
16
+ * for you (although it should work). But if you have struggled to
17
+ * customize an existing library to meet your needs, simple-markdown
18
+ * might be able to help.
19
+ *
20
+ * Many of the regexes and original logic has been adapted from
21
+ * the wonderful [marked.js](https://github.com/chjj/marked)
22
+ */
23
+
24
+ // Flow Type Definitions:
25
+
26
+ type Capture =
27
+ | (Array<string> & {index: number})
28
+ | (Array<string> & {index?: number});
29
+
30
+ type Attr = string | number | boolean | null | void;
31
+
32
+ type SingleASTNode = {
33
+ type: string,
34
+ [string]: any,
35
+ };
36
+
37
+ type UnTypedASTNode = {
38
+ [string]: any,
39
+ };
40
+
41
+ type ASTNode = SingleASTNode | Array<SingleASTNode>;
42
+
43
+ type State = {
44
+ key?: string | number | void,
45
+ inline?: ?boolean,
46
+ [string]: any,
47
+ };
48
+
49
+ type ReactElement = React$Element<any>;
50
+ type ReactElements = React$Node;
51
+
52
+ type MatchFunction = {regex?: RegExp} & ((
53
+ source: string,
54
+ state: State,
55
+ prevCapture: string,
56
+ ) => ?Capture);
57
+
58
+ type Parser = (source: string, state?: ?State) => Array<SingleASTNode>;
59
+
60
+ type ParseFunction = (
61
+ capture: Capture,
62
+ nestedParse: Parser,
63
+ state: State,
64
+ ) => UnTypedASTNode | ASTNode;
65
+
66
+ type SingleNodeParseFunction = (
67
+ capture: Capture,
68
+ nestedParse: Parser,
69
+ state: State,
70
+ ) => UnTypedASTNode;
71
+
72
+ type Output<Result> = (node: ASTNode, state?: ?State) => Result;
73
+
74
+ type NodeOutput<Result> = (
75
+ node: SingleASTNode,
76
+ nestedOutput: Output<Result>,
77
+ state: State,
78
+ ) => Result;
79
+
80
+ type ArrayNodeOutput<Result> = (
81
+ node: Array<SingleASTNode>,
82
+ nestedOutput: Output<Result>,
83
+ state: State,
84
+ ) => Result;
85
+
86
+ type ReactOutput = Output<ReactElements>;
87
+ type ReactNodeOutput = NodeOutput<ReactElements>;
88
+ type HtmlOutput = Output<string>;
89
+ type HtmlNodeOutput = NodeOutput<string>;
90
+
91
+ type ParserRule = {
92
+ +order: number,
93
+ +match: MatchFunction,
94
+ +quality?: (capture: Capture, state: State, prevCapture: string) => number,
95
+ +parse: ParseFunction,
96
+ };
97
+
98
+ type SingleNodeParserRule = {
99
+ +order: number,
100
+ +match: MatchFunction,
101
+ +quality?: (capture: Capture, state: State, prevCapture: string) => number,
102
+ +parse: SingleNodeParseFunction,
103
+ };
104
+
105
+ type ReactOutputRule = {
106
+ // we allow null because some rules are never output results, and that's
107
+ // legal as long as no parsers return an AST node matching that rule.
108
+ // We don't use ? because this makes it be explicitly defined as either
109
+ // a valid function or null, so it can't be forgotten.
110
+ +react: ReactNodeOutput | null,
111
+ };
112
+
113
+ type HtmlOutputRule = {
114
+ +html: HtmlNodeOutput | null,
115
+ };
116
+
117
+ type ArrayRule = {
118
+ +react?: ArrayNodeOutput<ReactElements>,
119
+ +html?: ArrayNodeOutput<string>,
120
+ +[string]: ArrayNodeOutput<any>,
121
+ };
122
+
123
+ type ParserRules = {
124
+ +Array?: ArrayRule,
125
+ +[type: string]: ParserRule,
126
+ };
127
+
128
+ type OutputRules<Rule> = {
129
+ +Array?: ArrayRule,
130
+ +[type: string]: Rule,
131
+ };
132
+ type Rules<OutputRule> = {
133
+ +Array?: ArrayRule,
134
+ +[type: string]: ParserRule & OutputRule,
135
+ };
136
+ type ReactRules = {
137
+ +Array?: {
138
+ +react: ArrayNodeOutput<ReactElements>,
139
+ },
140
+ +[type: string]: ParserRule & ReactOutputRule,
141
+ };
142
+ type HtmlRules = {
143
+ +Array?: {
144
+ +html: ArrayNodeOutput<string>,
145
+ },
146
+ +[type: string]: ParserRule & HtmlOutputRule,
147
+ };
148
+
149
+ // We want to clarify our defaultRules types a little bit more so clients can
150
+ // reuse defaultRules built-ins. So we make some stronger guarantess when
151
+ // we can:
152
+ type NonNullReactOutputRule = {
153
+ +react: ReactNodeOutput,
154
+ };
155
+ type ElementReactOutputRule = {
156
+ +react: NodeOutput<ReactElement>,
157
+ };
158
+ type TextReactOutputRule = {
159
+ +react: NodeOutput<string>,
160
+ };
161
+ type NonNullHtmlOutputRule = {
162
+ +html: HtmlNodeOutput,
163
+ };
164
+
165
+ type DefaultInRule = SingleNodeParserRule & ReactOutputRule & HtmlOutputRule;
166
+ type TextInOutRule = SingleNodeParserRule &
167
+ TextReactOutputRule &
168
+ NonNullHtmlOutputRule;
169
+ type LenientInOutRule = SingleNodeParserRule &
170
+ NonNullReactOutputRule &
171
+ NonNullHtmlOutputRule;
172
+ type DefaultInOutRule = SingleNodeParserRule &
173
+ ElementReactOutputRule &
174
+ NonNullHtmlOutputRule;
175
+
176
+ type DefaultRules = {
177
+ +Array: {
178
+ +react: ArrayNodeOutput<ReactElements>,
179
+ +html: ArrayNodeOutput<string>,
180
+ },
181
+ +heading: DefaultInOutRule,
182
+ +nptable: DefaultInRule,
183
+ +lheading: DefaultInRule,
184
+ +hr: DefaultInOutRule,
185
+ +codeBlock: DefaultInOutRule,
186
+ +fence: DefaultInRule,
187
+ +blockQuote: DefaultInOutRule,
188
+ +list: DefaultInOutRule,
189
+ +def: LenientInOutRule,
190
+ +table: DefaultInOutRule,
191
+ +tableSeparator: DefaultInRule,
192
+ +newline: TextInOutRule,
193
+ +paragraph: DefaultInOutRule,
194
+ +escape: DefaultInRule,
195
+ +autolink: DefaultInRule,
196
+ +mailto: DefaultInRule,
197
+ +url: DefaultInRule,
198
+ +link: DefaultInOutRule,
199
+ +image: DefaultInOutRule,
200
+ +reflink: DefaultInRule,
201
+ +refimage: DefaultInRule,
202
+ +em: DefaultInOutRule,
203
+ +strong: DefaultInOutRule,
204
+ +u: DefaultInOutRule,
205
+ +del: DefaultInOutRule,
206
+ +inlineCode: DefaultInOutRule,
207
+ +br: DefaultInOutRule,
208
+ +text: TextInOutRule,
209
+ };
210
+
211
+ type RefNode = {
212
+ type: string,
213
+ content?: ASTNode,
214
+ target?: string,
215
+ title?: string,
216
+ alt?: string,
217
+ };
218
+
219
+ // End Flow Definitions
220
+
221
+ var CR_NEWLINE_R = /\r\n?/g;
222
+ var TAB_R = /\t/g;
223
+ var FORMFEED_R = /\f/g;
224
+
225
+ /**
226
+ * Turn various whitespace into easy-to-process whitespace
227
+ */
228
+ var preprocess = function (source: string): string {
229
+ return source
230
+ .replace(CR_NEWLINE_R, "\n")
231
+ .replace(FORMFEED_R, "")
232
+ .replace(TAB_R, " ");
233
+ };
234
+
235
+ var populateInitialState = function (
236
+ givenState: ?State,
237
+ defaultState: ?State,
238
+ ): State {
239
+ var state: State = givenState || {};
240
+ if (defaultState != null) {
241
+ for (var prop in defaultState) {
242
+ // $FlowFixMe
243
+ if (Object.prototype.hasOwnProperty.call(defaultState, prop)) {
244
+ state[prop] = defaultState[prop];
245
+ }
246
+ }
247
+ }
248
+ return state;
249
+ };
250
+
251
+ /**
252
+ * Creates a parser for a given set of rules, with the precedence
253
+ * specified as a list of rules.
254
+ *
255
+ * @param {SimpleMarkdown.ParserRules} rules
256
+ * an object containing
257
+ * rule type -> {match, order, parse} objects
258
+ * (lower order is higher precedence)
259
+ * @param {SimpleMarkdown.OptionalState} [defaultState]
260
+ *
261
+ * @returns {SimpleMarkdown.Parser}
262
+ * The resulting parse function, with the following parameters:
263
+ * @source: the input source string to be parsed
264
+ * @state: an optional object to be threaded through parse
265
+ * calls. Allows clients to add stateful operations to
266
+ * parsing, such as keeping track of how many levels deep
267
+ * some nesting is. For an example use-case, see passage-ref
268
+ * parsing in src/widgets/passage/passage-markdown.jsx
269
+ */
270
+ var parserFor = function (rules: ParserRules, defaultState: ?State): Parser {
271
+ // Sorts rules in order of increasing order, then
272
+ // ascending rule name in case of ties.
273
+ var ruleList = Object.keys(rules).filter(function (type) {
274
+ var rule = rules[type];
275
+ if (rule == null || rule.match == null) {
276
+ return false;
277
+ }
278
+ var order = rule.order;
279
+ if (
280
+ (typeof order !== "number" || !isFinite(order)) &&
281
+ typeof console !== "undefined"
282
+ ) {
283
+ console.warn(
284
+ "simple-markdown: Invalid order for rule `" +
285
+ type +
286
+ "`: " +
287
+ String(order),
288
+ );
289
+ }
290
+ return true;
291
+ });
292
+
293
+ ruleList.sort(function (typeA, typeB) {
294
+ var ruleA: ParserRule = (rules[typeA]: any);
295
+ var ruleB: ParserRule = (rules[typeB]: any);
296
+ var orderA = ruleA.order;
297
+ var orderB = ruleB.order;
298
+
299
+ // First sort based on increasing order
300
+ if (orderA !== orderB) {
301
+ return orderA - orderB;
302
+ }
303
+
304
+ var secondaryOrderA = ruleA.quality ? 0 : 1;
305
+ var secondaryOrderB = ruleB.quality ? 0 : 1;
306
+
307
+ if (secondaryOrderA !== secondaryOrderB) {
308
+ return secondaryOrderA - secondaryOrderB;
309
+
310
+ // Then based on increasing unicode lexicographic ordering
311
+ } else if (typeA < typeB) {
312
+ return -1;
313
+ } else if (typeA > typeB) {
314
+ return 1;
315
+ } else {
316
+ // Rules should never have the same name,
317
+ // but this is provided for completeness.
318
+ return 0;
319
+ }
320
+ });
321
+
322
+ var latestState: State;
323
+ var nestedParse = function (source: string, state: ?State): Parser {
324
+ var result: Array<SingleASTNode> = [];
325
+ state = state || latestState;
326
+ latestState = state;
327
+ while (source) {
328
+ // store the best match, it's rule, and quality:
329
+ var ruleType = null;
330
+ var rule = null;
331
+ var capture = null;
332
+ var quality = NaN;
333
+
334
+ // loop control variables:
335
+ var i = 0;
336
+ var currRuleType = ruleList[0];
337
+
338
+ // $FlowFixMe
339
+ var currRule: ParserRule = rules[currRuleType];
340
+
341
+ do {
342
+ var currOrder = currRule.order;
343
+ var prevCaptureStr =
344
+ state.prevCapture == null ? "" : state.prevCapture[0];
345
+ var currCapture = currRule.match(source, state, prevCaptureStr);
346
+
347
+ if (currCapture) {
348
+ var currQuality = currRule.quality
349
+ ? currRule.quality(currCapture, state, prevCaptureStr)
350
+ : 0;
351
+ // This should always be true the first time because
352
+ // the initial quality is NaN (that's why there's the
353
+ // condition negation).
354
+ if (!(currQuality <= quality)) {
355
+ ruleType = currRuleType;
356
+ rule = currRule;
357
+ capture = currCapture;
358
+ quality = currQuality;
359
+ }
360
+ }
361
+
362
+ // Move on to the next item.
363
+ // Note that this makes `currRule` be the next item
364
+ i++;
365
+ currRuleType = ruleList[i];
366
+ // $FlowFixMe
367
+ currRule = rules[currRuleType];
368
+ } while (
369
+ // keep looping while we're still within the ruleList
370
+ currRule &&
371
+ // if we don't have a match yet, continue
372
+ (!capture ||
373
+ // or if we have a match, but the next rule is
374
+ // at the same order, and has a quality measurement
375
+ // functions, then this rule must have a quality
376
+ // measurement function (since they are sorted before
377
+ // those without), and we need to check if there is
378
+ // a better quality match
379
+ (currRule.order === currOrder && currRule.quality))
380
+ );
381
+
382
+ // TODO(aria): Write tests for these
383
+ if (rule == null || capture == null) {
384
+ throw new Error(
385
+ "Could not find a matching rule for the below " +
386
+ "content. The rule with highest `order` should " +
387
+ "always match content provided to it. Check " +
388
+ "the definition of `match` for '" +
389
+ ruleList[ruleList.length - 1] +
390
+ "'. It seems to not match the following source:\n" +
391
+ source,
392
+ );
393
+ }
394
+ if (capture.index) {
395
+ // If present and non-zero, i.e. a non-^ regexp result:
396
+ throw new Error(
397
+ "`match` must return a capture starting at index 0 " +
398
+ "(the current parse index). Did you forget a ^ at the " +
399
+ "start of the RegExp?",
400
+ );
401
+ }
402
+
403
+ // $FlowFixMe
404
+ var parsed = rule.parse(capture, nestedParse, state);
405
+ // We maintain the same object here so that rules can
406
+ // store references to the objects they return and
407
+ // modify them later. (oops sorry! but this adds a lot
408
+ // of power--see reflinks.)
409
+ if (Array.isArray(parsed)) {
410
+ // $FlowFixMe
411
+ Array.prototype.push.apply(result, parsed);
412
+ } else {
413
+ // We also let rules override the default type of
414
+ // their parsed node if they would like to, so that
415
+ // there can be a single output function for all links,
416
+ // even if there are several rules to parse them.
417
+ if (parsed.type == null) {
418
+ // $FlowFixMe
419
+ parsed.type = ruleType;
420
+ }
421
+ result.push(parsed);
422
+ }
423
+
424
+ state.prevCapture = capture;
425
+ source = source.substring(state.prevCapture[0].length);
426
+ }
427
+
428
+ // $FlowFixMe
429
+ return result;
430
+ };
431
+
432
+ var outerParse = function (source: string, state: ?State): Parser {
433
+ latestState = populateInitialState(state, defaultState);
434
+ if (!latestState.inline && !latestState.disableAutoBlockNewlines) {
435
+ source = source + "\n\n";
436
+ }
437
+ // We store the previous capture so that match functions can
438
+ // use some limited amount of lookbehind. Lists use this to
439
+ // ensure they don't match arbitrary '- ' or '* ' in inline
440
+ // text (see the list rule for more information). This stores
441
+ // the full regex capture object, if there is one.
442
+ latestState.prevCapture = null;
443
+ return nestedParse(preprocess(source), latestState);
444
+ };
445
+
446
+ // $FlowFixMe
447
+ return outerParse;
448
+ };
449
+
450
+ // Creates a match function for an inline scoped element from a regex
451
+ var inlineRegex = function (regex: RegExp): MatchFunction {
452
+ var match = function (
453
+ source: string,
454
+ state: State,
455
+ prevCapture: string,
456
+ ): ?Capture {
457
+ if (state.inline) {
458
+ // $FlowFixMe
459
+ return regex.exec(source);
460
+ } else {
461
+ return null;
462
+ }
463
+ };
464
+ match.regex = regex;
465
+
466
+ return match;
467
+ };
468
+
469
+ // Creates a match function for a block scoped element from a regex
470
+ var blockRegex = function (regex: RegExp): MatchFunction {
471
+ // $FlowFixMe
472
+ var match: MatchFunction = function (source, state) {
473
+ if (state.inline) {
474
+ return null;
475
+ } else {
476
+ return regex.exec(source);
477
+ }
478
+ };
479
+ match.regex = regex;
480
+ return match;
481
+ };
482
+
483
+ // Creates a match function from a regex, ignoring block/inline scope
484
+ var anyScopeRegex = function (regex: RegExp): MatchFunction {
485
+ // $FlowFixMe
486
+ var match: MatchFunction = function (source, state) {
487
+ return regex.exec(source);
488
+ };
489
+ match.regex = regex;
490
+ return match;
491
+ };
492
+
493
+ var TYPE_SYMBOL =
494
+ (typeof Symbol === "function" &&
495
+ Symbol.for &&
496
+ Symbol.for("react.element")) ||
497
+ 0xeac7;
498
+
499
+ var reactElement = function (
500
+ type: string,
501
+ key: string | number | null | void,
502
+ props: {[string]: any},
503
+ ): ReactElement {
504
+ var element: ReactElement = ({
505
+ $$typeof: TYPE_SYMBOL,
506
+ type: type,
507
+ key: key == null ? undefined : key,
508
+ ref: null,
509
+ props: props,
510
+ _owner: null,
511
+ }: any);
512
+ return element;
513
+ };
514
+
515
+ /** Returns a closed HTML tag.
516
+ * @param {string} tagName - Name of HTML tag (eg. "em" or "a")
517
+ * @param {string} content - Inner content of tag
518
+ * @param {{ [attr: string]: SimpleMarkdown.Attr }} [attributes] - Optional extra attributes of tag as an object of key-value pairs
519
+ * eg. { "href": "http://google.com" }. Falsey attributes are filtered out.
520
+ * @param {boolean} [isClosed] - boolean that controls whether tag is closed or not (eg. img tags).
521
+ * defaults to true
522
+ */
523
+ var htmlTag = function (
524
+ tagName: string,
525
+ content: string,
526
+ attributes: ?{[any]: ?Attr},
527
+ isClosed: ?boolean,
528
+ ) {
529
+ attributes = attributes || {};
530
+ isClosed = typeof isClosed !== "undefined" ? isClosed : true;
531
+
532
+ var attributeString = "";
533
+ for (var attr in attributes) {
534
+ var attribute = attributes[attr];
535
+ // Removes falsey attributes
536
+ if (
537
+ // $FlowFixMe
538
+ Object.prototype.hasOwnProperty.call(attributes, attr) &&
539
+ attribute
540
+ ) {
541
+ attributeString +=
542
+ " " + sanitizeText(attr) + '="' + sanitizeText(attribute) + '"';
543
+ }
544
+ }
545
+
546
+ var unclosedTag = "<" + tagName + attributeString + ">";
547
+
548
+ if (isClosed) {
549
+ return unclosedTag + content + "</" + tagName + ">";
550
+ } else {
551
+ return unclosedTag;
552
+ }
553
+ };
554
+
555
+ var EMPTY_PROPS = {};
556
+
557
+ /**
558
+ * @param {string | null | undefined} url - url to sanitize
559
+ * @returns {string | null} - url if safe, or null if a safe url could not be made
560
+ */
561
+ var sanitizeUrl = function (url: ?string) {
562
+ if (url == null) {
563
+ return null;
564
+ }
565
+ try {
566
+ var prot = new URL(url, "https://localhost").protocol;
567
+ if (
568
+ prot.indexOf("javascript:") === 0 ||
569
+ prot.indexOf("vbscript:") === 0 ||
570
+ prot.indexOf("data:") === 0
571
+ ) {
572
+ return null;
573
+ }
574
+ } catch (e) {
575
+ // invalid URLs should throw a TypeError
576
+ // see for instance: `new URL("");`
577
+ return null;
578
+ }
579
+ return url;
580
+ };
581
+
582
+ var SANITIZE_TEXT_R = /[<>&"']/g;
583
+ var SANITIZE_TEXT_CODES = {
584
+ "<": "&lt;",
585
+ ">": "&gt;",
586
+ "&": "&amp;",
587
+ '"': "&quot;",
588
+ "'": "&#x27;",
589
+ "/": "&#x2F;",
590
+ "`": "&#96;",
591
+ };
592
+
593
+ var sanitizeText = function (text: Attr): string {
594
+ return String(text).replace(SANITIZE_TEXT_R, function (chr) {
595
+ return SANITIZE_TEXT_CODES[chr];
596
+ });
597
+ };
598
+
599
+ var UNESCAPE_URL_R = /\\([^0-9A-Za-z\s])/g;
600
+
601
+ var unescapeUrl = function (rawUrlString: string): string {
602
+ return rawUrlString.replace(UNESCAPE_URL_R, "$1");
603
+ };
604
+
605
+ /**
606
+ * Parse some content with the parser `parse`, with state.inline
607
+ * set to true. Useful for block elements; not generally necessary
608
+ * to be used by inline elements (where state.inline is already true.
609
+ */
610
+ var parseInline = function (
611
+ parse: Parser,
612
+ content: string,
613
+ state: State,
614
+ ): ASTNode {
615
+ var isCurrentlyInline = state.inline || false;
616
+ state.inline = true;
617
+ var result = parse(content, state);
618
+ state.inline = isCurrentlyInline;
619
+ return result;
620
+ };
621
+
622
+ var parseBlock = function (
623
+ parse: Parser,
624
+ content: string,
625
+ state: State,
626
+ ): ASTNode {
627
+ var isCurrentlyInline = state.inline || false;
628
+ state.inline = false;
629
+ var result = parse(content + "\n\n", state);
630
+ state.inline = isCurrentlyInline;
631
+ return result;
632
+ };
633
+
634
+ var parseCaptureInline = function (
635
+ capture: Capture,
636
+ parse: Parser,
637
+ state: State,
638
+ ): UnTypedASTNode {
639
+ return {
640
+ content: parseInline(parse, capture[1], state),
641
+ };
642
+ };
643
+
644
+ var ignoreCapture = function (): UnTypedASTNode {
645
+ return {};
646
+ };
647
+
648
+ // recognize a `*` `-`, `+`, `1.`, `2.`... list bullet
649
+ var LIST_BULLET = "(?:[*+-]|\\d+\\.)";
650
+ // recognize the start of a list item:
651
+ // leading space plus a bullet plus a space (` * `)
652
+ var LIST_ITEM_PREFIX = "( *)(" + LIST_BULLET + ") +";
653
+ var LIST_ITEM_PREFIX_R = new RegExp("^" + LIST_ITEM_PREFIX);
654
+ // recognize an individual list item:
655
+ // * hi
656
+ // this is part of the same item
657
+ //
658
+ // as is this, which is a new paragraph in the same item
659
+ //
660
+ // * but this is not part of the same item
661
+ var LIST_ITEM_R = new RegExp(
662
+ LIST_ITEM_PREFIX +
663
+ "[^\\n]*(?:\\n" +
664
+ "(?!\\1" +
665
+ LIST_BULLET +
666
+ " )[^\\n]*)*(\n|$)",
667
+ "gm",
668
+ );
669
+ var BLOCK_END_R = /\n{2,}$/;
670
+ var INLINE_CODE_ESCAPE_BACKTICKS_R = /^ (?= *`)|(` *) $/g;
671
+ // recognize the end of a paragraph block inside a list item:
672
+ // two or more newlines at end end of the item
673
+ var LIST_BLOCK_END_R = BLOCK_END_R;
674
+ var LIST_ITEM_END_R = / *\n+$/;
675
+ // check whether a list item has paragraphs: if it does,
676
+ // we leave the newlines at the end
677
+ var LIST_R = new RegExp(
678
+ "^( *)(" +
679
+ LIST_BULLET +
680
+ ") " +
681
+ "[\\s\\S]+?(?:\n{2,}(?! )" +
682
+ "(?!\\1" +
683
+ LIST_BULLET +
684
+ " )\\n*" +
685
+ // the \\s*$ here is so that we can parse the inside of nested
686
+ // lists, where our content might end before we receive two `\n`s
687
+ "|\\s*\n*$)",
688
+ );
689
+ var LIST_LOOKBEHIND_R = /(?:^|\n)( *)$/;
690
+
691
+ var TABLES = (function () {
692
+ // predefine regexes so we don't have to create them inside functions
693
+ // sure, regex literals should be fast, even inside functions, but they
694
+ // aren't in all browsers.
695
+ var TABLE_BLOCK_TRIM = /\n+/g;
696
+ var TABLE_ROW_SEPARATOR_TRIM = /^ *\| *| *\| *$/g;
697
+ var TABLE_CELL_END_TRIM = / *$/;
698
+ var TABLE_RIGHT_ALIGN = /^ *-+: *$/;
699
+ var TABLE_CENTER_ALIGN = /^ *:-+: *$/;
700
+ var TABLE_LEFT_ALIGN = /^ *:-+ *$/;
701
+
702
+ // TODO: This needs a real type
703
+ type TableAlignment = any;
704
+
705
+ var parseTableAlignCapture = function (
706
+ alignCapture: string,
707
+ ): TableAlignment {
708
+ if (TABLE_RIGHT_ALIGN.test(alignCapture)) {
709
+ return "right";
710
+ } else if (TABLE_CENTER_ALIGN.test(alignCapture)) {
711
+ return "center";
712
+ } else if (TABLE_LEFT_ALIGN.test(alignCapture)) {
713
+ return "left";
714
+ } else {
715
+ return null;
716
+ }
717
+ };
718
+
719
+ var parseTableAlign = function (
720
+ source: string,
721
+ parse: Parser,
722
+ state: State,
723
+ trimEndSeparators: boolean,
724
+ ): Array<TableAlignment> {
725
+ if (trimEndSeparators) {
726
+ source = source.replace(TABLE_ROW_SEPARATOR_TRIM, "");
727
+ }
728
+ var alignText = source.trim().split("|");
729
+ return alignText.map(parseTableAlignCapture);
730
+ };
731
+
732
+ var parseTableRow = function (
733
+ source: string,
734
+ parse: Parser,
735
+ state: State,
736
+ trimEndSeparators: boolean,
737
+ ): Array<Array<SingleASTNode>> {
738
+ var prevInTable = state.inTable;
739
+ state.inTable = true;
740
+ var tableRow = parse(source.trim(), state);
741
+ state.inTable = prevInTable;
742
+
743
+ var cells = [[]];
744
+ tableRow.forEach(function (node, i) {
745
+ if (node.type === "tableSeparator") {
746
+ // Filter out empty table separators at the start/end:
747
+ if (
748
+ !trimEndSeparators ||
749
+ (i !== 0 && i !== tableRow.length - 1)
750
+ ) {
751
+ // Split the current row:
752
+ cells.push([]);
753
+ }
754
+ } else {
755
+ if (
756
+ node.type === "text" &&
757
+ (tableRow[i + 1] == null ||
758
+ tableRow[i + 1].type === "tableSeparator")
759
+ ) {
760
+ node.content = node.content.replace(
761
+ TABLE_CELL_END_TRIM,
762
+ "",
763
+ );
764
+ }
765
+ cells[cells.length - 1].push(node);
766
+ }
767
+ });
768
+
769
+ return cells;
770
+ };
771
+
772
+ /**
773
+ * @param {string} source
774
+ * @param {SimpleMarkdown.Parser} parse
775
+ * @param {SimpleMarkdown.State} state
776
+ * @param {boolean} trimEndSeparators
777
+ * @returns {SimpleMarkdown.ASTNode[][]}
778
+ */
779
+ var parseTableCells = function (
780
+ source: string,
781
+ parse: Parser,
782
+ state: State,
783
+ trimEndSeparators: boolean,
784
+ ): Array<Array<ASTNode>> {
785
+ var rowsText = source.trim().split("\n");
786
+
787
+ return rowsText.map(function (rowText) {
788
+ // $FlowFixMe
789
+ return parseTableRow(rowText, parse, state, trimEndSeparators);
790
+ });
791
+ };
792
+
793
+ /**
794
+ * @param {boolean} trimEndSeparators
795
+ * @returns {SimpleMarkdown.SingleNodeParseFunction}
796
+ */
797
+ var parseTable = function (trimEndSeparators) {
798
+ return function (capture, parse, state) {
799
+ state.inline = true;
800
+ var header = parseTableRow(
801
+ capture[1],
802
+ parse,
803
+ state,
804
+ trimEndSeparators,
805
+ );
806
+ var align = parseTableAlign(
807
+ capture[2],
808
+ parse,
809
+ state,
810
+ trimEndSeparators,
811
+ );
812
+ var cells = parseTableCells(
813
+ capture[3],
814
+ parse,
815
+ state,
816
+ trimEndSeparators,
817
+ );
818
+ state.inline = false;
819
+
820
+ return {
821
+ type: "table",
822
+ header: header,
823
+ align: align,
824
+ cells: cells,
825
+ };
826
+ };
827
+ };
828
+
829
+ return {
830
+ parseTable: parseTable(true),
831
+ parseNpTable: parseTable(false),
832
+ TABLE_REGEX:
833
+ /^ *(\|.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/,
834
+ NPTABLE_REGEX:
835
+ /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
836
+ };
837
+ })();
838
+
839
+ var LINK_INSIDE = "(?:\\[[^\\]]*\\]|[^\\[\\]]|\\](?=[^\\[]*\\]))*";
840
+ var LINK_HREF_AND_TITLE =
841
+ "\\s*<?((?:\\([^)]*\\)|[^\\s\\\\]|\\\\.)*?)>?(?:\\s+['\"]([\\s\\S]*?)['\"])?\\s*";
842
+ var AUTOLINK_MAILTO_CHECK_R = /mailto:/i;
843
+
844
+ var parseRef = function (
845
+ capture: Capture,
846
+ state: State,
847
+ refNode: RefNode,
848
+ ): RefNode {
849
+ var ref = (capture[2] || capture[1]).replace(/\s+/g, " ").toLowerCase();
850
+
851
+ // We store information about previously seen defs on
852
+ // state._defs (_ to deconflict with client-defined
853
+ // state). If the def for this reflink/refimage has
854
+ // already been seen, we can use its target/source
855
+ // and title here:
856
+ if (state._defs && state._defs[ref]) {
857
+ var def = state._defs[ref];
858
+ // `refNode` can be a link or an image. Both use
859
+ // target and title properties.
860
+ refNode.target = def.target;
861
+ refNode.title = def.title;
862
+ }
863
+
864
+ // In case we haven't seen our def yet (or if someone
865
+ // overwrites that def later on), we add this node
866
+ // to the list of ref nodes for that def. Then, when
867
+ // we find the def, we can modify this link/image AST
868
+ // node :).
869
+ // I'm sorry.
870
+ state._refs = state._refs || {};
871
+ state._refs[ref] = state._refs[ref] || [];
872
+ state._refs[ref].push(refNode);
873
+
874
+ return refNode;
875
+ };
876
+
877
+ var currOrder = 0;
878
+
879
+ var defaultRules: DefaultRules = {
880
+ Array: {
881
+ react: function (arr, output, state) {
882
+ var oldKey = state.key;
883
+ var result: Array<ReactElements> = [];
884
+
885
+ // map output over the ast, except group any text
886
+ // nodes together into a single string output.
887
+ for (var i = 0, key = 0; i < arr.length; i++, key++) {
888
+ // `key` is our numerical `state.key`, which we increment for
889
+ // every output node, but don't change for joined text nodes.
890
+ // (i, however, must change for joined text nodes)
891
+ state.key = "" + i;
892
+
893
+ var node = arr[i];
894
+ if (node.type === "text") {
895
+ node = {type: "text", content: node.content};
896
+ for (
897
+ ;
898
+ i + 1 < arr.length && arr[i + 1].type === "text";
899
+ i++
900
+ ) {
901
+ node.content += arr[i + 1].content;
902
+ }
903
+ }
904
+
905
+ result.push(output(node, state));
906
+ }
907
+
908
+ state.key = oldKey;
909
+ return result;
910
+ },
911
+ html: function (arr, output, state) {
912
+ var result = "";
913
+
914
+ // map output over the ast, except group any text
915
+ // nodes together into a single string output.
916
+ for (var i = 0, key = 0; i < arr.length; i++) {
917
+ var node = arr[i];
918
+ if (node.type === "text") {
919
+ node = {type: "text", content: node.content};
920
+ for (
921
+ ;
922
+ i + 1 < arr.length && arr[i + 1].type === "text";
923
+ i++
924
+ ) {
925
+ node.content += arr[i + 1].content;
926
+ }
927
+ }
928
+
929
+ result += output(node, state);
930
+ }
931
+ return result;
932
+ },
933
+ },
934
+ heading: {
935
+ order: currOrder++,
936
+ match: blockRegex(/^ *(#{1,6})([^\n]+?)#* *(?:\n *)+\n/),
937
+ parse: function (capture, parse, state) {
938
+ return {
939
+ level: capture[1].length,
940
+ content: parseInline(parse, capture[2].trim(), state),
941
+ };
942
+ },
943
+ react: function (node, output, state) {
944
+ return reactElement("h" + node.level, state.key, {
945
+ children: output(node.content, state),
946
+ });
947
+ },
948
+ html: function (node, output, state) {
949
+ return htmlTag("h" + node.level, output(node.content, state));
950
+ },
951
+ },
952
+ nptable: {
953
+ order: currOrder++,
954
+ match: blockRegex(TABLES.NPTABLE_REGEX),
955
+ parse: TABLES.parseNpTable,
956
+ react: null,
957
+ html: null,
958
+ },
959
+ lheading: {
960
+ order: currOrder++,
961
+ match: blockRegex(/^([^\n]+)\n *(=|-){3,} *(?:\n *)+\n/),
962
+ parse: function (capture, parse, state) {
963
+ return {
964
+ type: "heading",
965
+ level: capture[2] === "=" ? 1 : 2,
966
+ content: parseInline(parse, capture[1], state),
967
+ };
968
+ },
969
+ react: null,
970
+ html: null,
971
+ },
972
+ hr: {
973
+ order: currOrder++,
974
+ match: blockRegex(/^( *[-*_]){3,} *(?:\n *)+\n/),
975
+ parse: ignoreCapture,
976
+ react: function (node, output, state) {
977
+ return reactElement("hr", state.key, EMPTY_PROPS);
978
+ },
979
+ html: function (node, output, state) {
980
+ return "<hr>";
981
+ },
982
+ },
983
+ codeBlock: {
984
+ order: currOrder++,
985
+ match: blockRegex(/^(?: [^\n]+\n*)+(?:\n *)+\n/),
986
+ parse: function (capture, parse, state) {
987
+ var content = capture[0].replace(/^ /gm, "").replace(/\n+$/, "");
988
+ return {
989
+ lang: undefined,
990
+ content: content,
991
+ };
992
+ },
993
+ react: function (node, output, state) {
994
+ var className = node.lang
995
+ ? "markdown-code-" + node.lang
996
+ : undefined;
997
+
998
+ return reactElement("pre", state.key, {
999
+ children: reactElement("code", null, {
1000
+ className: className,
1001
+ children: node.content,
1002
+ }),
1003
+ });
1004
+ },
1005
+ html: function (node, output, state) {
1006
+ var className = node.lang
1007
+ ? "markdown-code-" + node.lang
1008
+ : undefined;
1009
+
1010
+ var codeBlock = htmlTag("code", sanitizeText(node.content), {
1011
+ class: className,
1012
+ });
1013
+ return htmlTag("pre", codeBlock);
1014
+ },
1015
+ },
1016
+ fence: {
1017
+ order: currOrder++,
1018
+ match: blockRegex(
1019
+ /^ *(`{3,}|~{3,}) *(?:(\S+) *)?\n([\s\S]+?)\n?\1 *(?:\n *)+\n/,
1020
+ ),
1021
+ parse: function (capture, parse, state) {
1022
+ return {
1023
+ type: "codeBlock",
1024
+ lang: capture[2] || undefined,
1025
+ content: capture[3],
1026
+ };
1027
+ },
1028
+ react: null,
1029
+ html: null,
1030
+ },
1031
+ blockQuote: {
1032
+ order: currOrder++,
1033
+ match: blockRegex(/^( *>[^\n]+(\n[^\n]+)*\n*)+\n{2,}/),
1034
+ parse: function (capture, parse, state) {
1035
+ var content = capture[0].replace(/^ *> ?/gm, "");
1036
+ return {
1037
+ content: parse(content, state),
1038
+ };
1039
+ },
1040
+ react: function (node, output, state) {
1041
+ return reactElement("blockquote", state.key, {
1042
+ children: output(node.content, state),
1043
+ });
1044
+ },
1045
+ html: function (node, output, state) {
1046
+ return htmlTag("blockquote", output(node.content, state));
1047
+ },
1048
+ },
1049
+ list: {
1050
+ order: currOrder++,
1051
+ // $FlowFixMe
1052
+ match: function (source, state) {
1053
+ // We only want to break into a list if we are at the start of a
1054
+ // line. This is to avoid parsing "hi * there" with "* there"
1055
+ // becoming a part of a list.
1056
+ // You might wonder, "but that's inline, so of course it wouldn't
1057
+ // start a list?". You would be correct! Except that some of our
1058
+ // lists can be inline, because they might be inside another list,
1059
+ // in which case we can parse with inline scope, but need to allow
1060
+ // nested lists inside this inline scope.
1061
+ var prevCaptureStr =
1062
+ state.prevCapture == null ? "" : state.prevCapture[0];
1063
+ var isStartOfLineCapture = LIST_LOOKBEHIND_R.exec(prevCaptureStr);
1064
+ var isListBlock = state._list || !state.inline;
1065
+
1066
+ if (isStartOfLineCapture && isListBlock) {
1067
+ source = isStartOfLineCapture[1] + source;
1068
+ return LIST_R.exec(source);
1069
+ } else {
1070
+ return null;
1071
+ }
1072
+ },
1073
+ parse: function (capture, parse, state) {
1074
+ var bullet = capture[2];
1075
+ var ordered = bullet.length > 1;
1076
+ var start = ordered ? +bullet : undefined;
1077
+ var items: Array<string> = capture[0]
1078
+ .replace(LIST_BLOCK_END_R, "\n")
1079
+ .match(LIST_ITEM_R);
1080
+
1081
+ // We know this will match here, because of how the regexes are
1082
+ // defined
1083
+
1084
+ var lastItemWasAParagraph = false;
1085
+ var itemContent = items.map(function (item: string, i: number) {
1086
+ // We need to see how far indented this item is:
1087
+ var prefixCapture = LIST_ITEM_PREFIX_R.exec(item);
1088
+ var space = prefixCapture ? prefixCapture[0].length : 0;
1089
+ // And then we construct a regex to "unindent" the subsequent
1090
+ // lines of the items by that amount:
1091
+ var spaceRegex = new RegExp("^ {1," + space + "}", "gm");
1092
+
1093
+ // Before processing the item, we need a couple things
1094
+ var content = item
1095
+ // remove indents on trailing lines:
1096
+ .replace(spaceRegex, "")
1097
+ // remove the bullet:
1098
+ .replace(LIST_ITEM_PREFIX_R, "");
1099
+
1100
+ // I'm not sur4 why this is necessary again?
1101
+
1102
+ // Handling "loose" lists, like:
1103
+ //
1104
+ // * this is wrapped in a paragraph
1105
+ //
1106
+ // * as is this
1107
+ //
1108
+ // * as is this
1109
+ var isLastItem = i === items.length - 1;
1110
+ var containsBlocks = content.indexOf("\n\n") !== -1;
1111
+
1112
+ // Any element in a list is a block if it contains multiple
1113
+ // newlines. The last element in the list can also be a block
1114
+ // if the previous item in the list was a block (this is
1115
+ // because non-last items in the list can end with \n\n, but
1116
+ // the last item can't, so we just "inherit" this property
1117
+ // from our previous element).
1118
+ var thisItemIsAParagraph =
1119
+ containsBlocks || (isLastItem && lastItemWasAParagraph);
1120
+ lastItemWasAParagraph = thisItemIsAParagraph;
1121
+
1122
+ // backup our state for restoration afterwards. We're going to
1123
+ // want to set state._list to true, and state.inline depending
1124
+ // on our list's looseness.
1125
+ var oldStateInline = state.inline;
1126
+ var oldStateList = state._list;
1127
+ state._list = true;
1128
+
1129
+ // Parse inline if we're in a tight list, or block if we're in
1130
+ // a loose list.
1131
+ var adjustedContent;
1132
+ if (thisItemIsAParagraph) {
1133
+ state.inline = false;
1134
+ adjustedContent = content.replace(LIST_ITEM_END_R, "\n\n");
1135
+ } else {
1136
+ state.inline = true;
1137
+ adjustedContent = content.replace(LIST_ITEM_END_R, "");
1138
+ }
1139
+
1140
+ var result = parse(adjustedContent, state);
1141
+
1142
+ // Restore our state before returning
1143
+ state.inline = oldStateInline;
1144
+ state._list = oldStateList;
1145
+ return result;
1146
+ });
1147
+
1148
+ return {
1149
+ ordered: ordered,
1150
+ start: start,
1151
+ items: itemContent,
1152
+ };
1153
+ },
1154
+ react: function (node, output, state) {
1155
+ var ListWrapper = node.ordered ? "ol" : "ul";
1156
+
1157
+ return reactElement(ListWrapper, state.key, {
1158
+ start: node.start,
1159
+ children: node.items.map(function (item: ASTNode, i: number) {
1160
+ return reactElement("li", "" + i, {
1161
+ children: output(item, state),
1162
+ });
1163
+ }),
1164
+ });
1165
+ },
1166
+ html: function (node, output, state) {
1167
+ var listItems = node.items
1168
+ .map(function (item: ASTNode) {
1169
+ return htmlTag("li", output(item, state));
1170
+ })
1171
+ .join("");
1172
+
1173
+ var listTag = node.ordered ? "ol" : "ul";
1174
+ var attributes = {
1175
+ start: node.start,
1176
+ };
1177
+ return htmlTag(listTag, listItems, attributes);
1178
+ },
1179
+ },
1180
+ def: {
1181
+ order: currOrder++,
1182
+ // TODO(aria): This will match without a blank line before the next
1183
+ // block element, which is inconsistent with most of the rest of
1184
+ // simple-markdown.
1185
+ match: blockRegex(
1186
+ /^ *\[([^\]]+)\]: *<?([^\s>]*)>?(?: +["(]([^\n]+)[")])? *\n(?: *\n)*/,
1187
+ ),
1188
+ parse: function (capture, parse, state) {
1189
+ var def = capture[1].replace(/\s+/g, " ").toLowerCase();
1190
+ var target = capture[2];
1191
+ var title = capture[3];
1192
+
1193
+ // Look for previous links/images using this def
1194
+ // If any links/images using this def have already been declared,
1195
+ // they will have added themselves to the state._refs[def] list
1196
+ // (_ to deconflict with client-defined state). We look through
1197
+ // that list of reflinks for this def, and modify those AST nodes
1198
+ // with our newly found information now.
1199
+ // Sorry :(.
1200
+ if (state._refs && state._refs[def]) {
1201
+ // `refNode` can be a link or an image
1202
+ state._refs[def].forEach(function (refNode: RefNode) {
1203
+ refNode.target = target;
1204
+ refNode.title = title;
1205
+ });
1206
+ }
1207
+
1208
+ // Add this def to our map of defs for any future links/images
1209
+ // In case we haven't found any or all of the refs referring to
1210
+ // this def yet, we add our def to the table of known defs, so
1211
+ // that future reflinks can modify themselves appropriately with
1212
+ // this information.
1213
+ state._defs = state._defs || {};
1214
+ state._defs[def] = {
1215
+ target: target,
1216
+ title: title,
1217
+ };
1218
+
1219
+ // return the relevant parsed information
1220
+ // for debugging only.
1221
+ return {
1222
+ def: def,
1223
+ target: target,
1224
+ title: title,
1225
+ };
1226
+ },
1227
+ react: function () {
1228
+ return null;
1229
+ },
1230
+ html: function () {
1231
+ return "";
1232
+ },
1233
+ },
1234
+ table: {
1235
+ order: currOrder++,
1236
+ match: blockRegex(TABLES.TABLE_REGEX),
1237
+ parse: TABLES.parseTable,
1238
+ react: function (node, output, state) {
1239
+ var getStyle = function (colIndex: number): {
1240
+ [attr: string]: Attr,
1241
+ } {
1242
+ return node.align[colIndex] == null
1243
+ ? {}
1244
+ : {
1245
+ textAlign: node.align[colIndex],
1246
+ };
1247
+ };
1248
+
1249
+ var headers = node.header.map(function (
1250
+ content: ASTNode,
1251
+ i: number,
1252
+ ) {
1253
+ return reactElement("th", "" + i, {
1254
+ style: getStyle(i),
1255
+ scope: "col",
1256
+ children: output(content, state),
1257
+ });
1258
+ });
1259
+
1260
+ var rows = node.cells.map(function (
1261
+ row: Array<ASTNode>,
1262
+ r: number,
1263
+ ) {
1264
+ return reactElement("tr", "" + r, {
1265
+ children: row.map(function (content: ASTNode, c: number) {
1266
+ return reactElement("td", "" + c, {
1267
+ style: getStyle(c),
1268
+ children: output(content, state),
1269
+ });
1270
+ }),
1271
+ });
1272
+ });
1273
+
1274
+ return reactElement("table", state.key, {
1275
+ children: [
1276
+ reactElement("thead", "thead", {
1277
+ children: reactElement("tr", null, {
1278
+ children: headers,
1279
+ }),
1280
+ }),
1281
+ reactElement("tbody", "tbody", {
1282
+ children: rows,
1283
+ }),
1284
+ ],
1285
+ });
1286
+ },
1287
+ html: function (node, output, state) {
1288
+ var getStyle = function (colIndex: number): string {
1289
+ return node.align[colIndex] == null
1290
+ ? ""
1291
+ : "text-align:" + node.align[colIndex] + ";";
1292
+ };
1293
+
1294
+ var headers = node.header
1295
+ .map(function (content: ASTNode, i: number) {
1296
+ return htmlTag("th", output(content, state), {
1297
+ style: getStyle(i),
1298
+ scope: "col",
1299
+ });
1300
+ })
1301
+ .join("");
1302
+
1303
+ var rows = node.cells
1304
+ .map(function (row: Array<ASTNode>) {
1305
+ var cols = row
1306
+ .map(function (content: ASTNode, c: number) {
1307
+ return htmlTag("td", output(content, state), {
1308
+ style: getStyle(c),
1309
+ });
1310
+ })
1311
+ .join("");
1312
+
1313
+ return htmlTag("tr", cols);
1314
+ })
1315
+ .join("");
1316
+
1317
+ var thead = htmlTag("thead", htmlTag("tr", headers));
1318
+ var tbody = htmlTag("tbody", rows);
1319
+
1320
+ return htmlTag("table", thead + tbody);
1321
+ },
1322
+ },
1323
+ newline: {
1324
+ order: currOrder++,
1325
+ match: blockRegex(/^(?:\n *)*\n/),
1326
+ parse: ignoreCapture,
1327
+ react: function (node, output, state) {
1328
+ return "\n";
1329
+ },
1330
+ html: function (node, output, state) {
1331
+ return "\n";
1332
+ },
1333
+ },
1334
+ paragraph: {
1335
+ order: currOrder++,
1336
+ match: blockRegex(/^((?:[^\n]|\n(?! *\n))+)(?:\n *)+\n/),
1337
+ parse: parseCaptureInline,
1338
+ react: function (node, output, state) {
1339
+ return reactElement("div", state.key, {
1340
+ className: "paragraph",
1341
+ children: output(node.content, state),
1342
+ });
1343
+ },
1344
+ html: function (node, output, state) {
1345
+ var attributes = {
1346
+ class: "paragraph",
1347
+ };
1348
+ return htmlTag("div", output(node.content, state), attributes);
1349
+ },
1350
+ },
1351
+ escape: {
1352
+ order: currOrder++,
1353
+ // We don't allow escaping numbers, letters, or spaces here so that
1354
+ // backslashes used in plain text still get rendered. But allowing
1355
+ // escaping anything else provides a very flexible escape mechanism,
1356
+ // regardless of how this grammar is extended.
1357
+ match: inlineRegex(/^\\([^0-9A-Za-z\s])/),
1358
+ parse: function (capture, parse, state) {
1359
+ return {
1360
+ type: "text",
1361
+ content: capture[1],
1362
+ };
1363
+ },
1364
+ react: null,
1365
+ html: null,
1366
+ },
1367
+ tableSeparator: {
1368
+ order: currOrder++,
1369
+ // $FlowFixMe
1370
+ match: function (source, state) {
1371
+ if (!state.inTable) {
1372
+ return null;
1373
+ }
1374
+ return /^ *\| */.exec(source);
1375
+ },
1376
+ parse: function () {
1377
+ return {type: "tableSeparator"};
1378
+ },
1379
+ // These shouldn't be reached, but in case they are, be reasonable:
1380
+ react: function () {
1381
+ return " | ";
1382
+ },
1383
+ html: function () {
1384
+ return " &vert; ";
1385
+ },
1386
+ },
1387
+ autolink: {
1388
+ order: currOrder++,
1389
+ match: inlineRegex(/^<([^: >]+:\/[^ >]+)>/),
1390
+ parse: function (capture, parse, state) {
1391
+ return {
1392
+ type: "link",
1393
+ content: [
1394
+ {
1395
+ type: "text",
1396
+ content: capture[1],
1397
+ },
1398
+ ],
1399
+ target: capture[1],
1400
+ };
1401
+ },
1402
+ react: null,
1403
+ html: null,
1404
+ },
1405
+ mailto: {
1406
+ order: currOrder++,
1407
+ match: inlineRegex(/^<([^ >]+@[^ >]+)>/),
1408
+ parse: function (capture, parse, state) {
1409
+ var address = capture[1];
1410
+ var target = capture[1];
1411
+
1412
+ // Check for a `mailto:` already existing in the link:
1413
+ if (!AUTOLINK_MAILTO_CHECK_R.test(target)) {
1414
+ target = "mailto:" + target;
1415
+ }
1416
+
1417
+ return {
1418
+ type: "link",
1419
+ content: [
1420
+ {
1421
+ type: "text",
1422
+ content: address,
1423
+ },
1424
+ ],
1425
+ target: target,
1426
+ };
1427
+ },
1428
+ react: null,
1429
+ html: null,
1430
+ },
1431
+ url: {
1432
+ order: currOrder++,
1433
+ match: inlineRegex(/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/),
1434
+ parse: function (capture, parse, state) {
1435
+ return {
1436
+ type: "link",
1437
+ content: [
1438
+ {
1439
+ type: "text",
1440
+ content: capture[1],
1441
+ },
1442
+ ],
1443
+ target: capture[1],
1444
+ title: undefined,
1445
+ };
1446
+ },
1447
+ react: null,
1448
+ html: null,
1449
+ },
1450
+ link: {
1451
+ order: currOrder++,
1452
+ match: inlineRegex(
1453
+ new RegExp(
1454
+ "^\\[(" + LINK_INSIDE + ")\\]\\(" + LINK_HREF_AND_TITLE + "\\)",
1455
+ ),
1456
+ ),
1457
+ parse: function (capture, parse, state) {
1458
+ var link = {
1459
+ content: parse(capture[1], state),
1460
+ target: unescapeUrl(capture[2]),
1461
+ title: capture[3],
1462
+ };
1463
+ return link;
1464
+ },
1465
+ react: function (node, output, state) {
1466
+ return reactElement("a", state.key, {
1467
+ href: sanitizeUrl(node.target),
1468
+ title: node.title,
1469
+ children: output(node.content, state),
1470
+ });
1471
+ },
1472
+ html: function (node, output, state) {
1473
+ var attributes = {
1474
+ href: sanitizeUrl(node.target),
1475
+ title: node.title,
1476
+ };
1477
+
1478
+ return htmlTag("a", output(node.content, state), attributes);
1479
+ },
1480
+ },
1481
+ image: {
1482
+ order: currOrder++,
1483
+ match: inlineRegex(
1484
+ new RegExp(
1485
+ "^!\\[(" +
1486
+ LINK_INSIDE +
1487
+ ")\\]\\(" +
1488
+ LINK_HREF_AND_TITLE +
1489
+ "\\)",
1490
+ ),
1491
+ ),
1492
+ parse: function (capture, parse, state) {
1493
+ var image = {
1494
+ alt: capture[1],
1495
+ target: unescapeUrl(capture[2]),
1496
+ title: capture[3],
1497
+ };
1498
+ return image;
1499
+ },
1500
+ react: function (node, output, state) {
1501
+ return reactElement("img", state.key, {
1502
+ src: sanitizeUrl(node.target),
1503
+ alt: node.alt,
1504
+ title: node.title,
1505
+ });
1506
+ },
1507
+ html: function (node, output, state) {
1508
+ var attributes = {
1509
+ src: sanitizeUrl(node.target),
1510
+ alt: node.alt,
1511
+ title: node.title,
1512
+ };
1513
+
1514
+ return htmlTag("img", "", attributes, false);
1515
+ },
1516
+ },
1517
+ reflink: {
1518
+ order: currOrder++,
1519
+ match: inlineRegex(
1520
+ new RegExp(
1521
+ // The first [part] of the link
1522
+ "^\\[(" +
1523
+ LINK_INSIDE +
1524
+ ")\\]" +
1525
+ // The [ref] target of the link
1526
+ "\\s*\\[([^\\]]*)\\]",
1527
+ ),
1528
+ ),
1529
+ parse: function (capture, parse, state) {
1530
+ return parseRef(capture, state, {
1531
+ type: "link",
1532
+ content: parse(capture[1], state),
1533
+ });
1534
+ },
1535
+ react: null,
1536
+ html: null,
1537
+ },
1538
+ refimage: {
1539
+ order: currOrder++,
1540
+ match: inlineRegex(
1541
+ new RegExp(
1542
+ // The first [part] of the link
1543
+ "^!\\[(" +
1544
+ LINK_INSIDE +
1545
+ ")\\]" +
1546
+ // The [ref] target of the link
1547
+ "\\s*\\[([^\\]]*)\\]",
1548
+ ),
1549
+ ),
1550
+ parse: function (capture, parse, state) {
1551
+ return parseRef(capture, state, {
1552
+ type: "image",
1553
+ alt: capture[1],
1554
+ });
1555
+ },
1556
+ react: null,
1557
+ html: null,
1558
+ },
1559
+ em: {
1560
+ order: currOrder /* same as strong/u */,
1561
+ match: inlineRegex(
1562
+ new RegExp(
1563
+ // only match _s surrounding words.
1564
+ "^\\b_" +
1565
+ "((?:__|\\\\[\\s\\S]|[^\\\\_])+?)_" +
1566
+ "\\b" +
1567
+ // Or match *s:
1568
+ "|" +
1569
+ // Only match *s that are followed by a non-space:
1570
+ "^\\*(?=\\S)(" +
1571
+ // Match at least one of:
1572
+ "(?:" +
1573
+ // - `**`: so that bolds inside italics don't close the
1574
+ // italics
1575
+ "\\*\\*|" +
1576
+ // - escape sequence: so escaped *s don't close us
1577
+ "\\\\[\\s\\S]|" +
1578
+ // - whitespace: followed by a non-* (we don't
1579
+ // want ' *' to close an italics--it might
1580
+ // start a list)
1581
+ "\\s+(?:\\\\[\\s\\S]|[^\\s\\*\\\\]|\\*\\*)|" +
1582
+ // - non-whitespace, non-*, non-backslash characters
1583
+ "[^\\s\\*\\\\]" +
1584
+ ")+?" +
1585
+ // followed by a non-space, non-* then *
1586
+ ")\\*(?!\\*)",
1587
+ ),
1588
+ ),
1589
+ quality: function (capture) {
1590
+ // precedence by length, `em` wins ties:
1591
+ return capture[0].length + 0.2;
1592
+ },
1593
+ parse: function (capture, parse, state) {
1594
+ return {
1595
+ content: parse(capture[2] || capture[1], state),
1596
+ };
1597
+ },
1598
+ react: function (node, output, state) {
1599
+ return reactElement("em", state.key, {
1600
+ children: output(node.content, state),
1601
+ });
1602
+ },
1603
+ html: function (node, output, state) {
1604
+ return htmlTag("em", output(node.content, state));
1605
+ },
1606
+ },
1607
+ strong: {
1608
+ order: currOrder /* same as em */,
1609
+ match: inlineRegex(/^\*\*((?:\\[\s\S]|[^\\])+?)\*\*(?!\*)/),
1610
+ quality: function (capture) {
1611
+ // precedence by length, wins ties vs `u`:
1612
+ return capture[0].length + 0.1;
1613
+ },
1614
+ parse: parseCaptureInline,
1615
+ react: function (node, output, state) {
1616
+ return reactElement("strong", state.key, {
1617
+ children: output(node.content, state),
1618
+ });
1619
+ },
1620
+ html: function (node, output, state) {
1621
+ return htmlTag("strong", output(node.content, state));
1622
+ },
1623
+ },
1624
+ u: {
1625
+ order: currOrder++ /* same as em&strong; increment for next rule */,
1626
+ match: inlineRegex(/^__((?:\\[\s\S]|[^\\])+?)__(?!_)/),
1627
+ quality: function (capture) {
1628
+ // precedence by length, loses all ties
1629
+ return capture[0].length;
1630
+ },
1631
+ parse: parseCaptureInline,
1632
+ react: function (node, output, state) {
1633
+ return reactElement("u", state.key, {
1634
+ children: output(node.content, state),
1635
+ });
1636
+ },
1637
+ html: function (node, output, state) {
1638
+ return htmlTag("u", output(node.content, state));
1639
+ },
1640
+ },
1641
+ del: {
1642
+ order: currOrder++,
1643
+ match: inlineRegex(
1644
+ /^~~(?=\S)((?:\\[\s\S]|~(?!~)|[^\s~\\]|\s(?!~~))+?)~~/,
1645
+ ),
1646
+ parse: parseCaptureInline,
1647
+ react: function (node, output, state) {
1648
+ return reactElement("del", state.key, {
1649
+ children: output(node.content, state),
1650
+ });
1651
+ },
1652
+ html: function (node, output, state) {
1653
+ return htmlTag("del", output(node.content, state));
1654
+ },
1655
+ },
1656
+ inlineCode: {
1657
+ order: currOrder++,
1658
+ match: inlineRegex(/^(`+)([\s\S]*?[^`])\1(?!`)/),
1659
+ parse: function (capture, parse, state) {
1660
+ return {
1661
+ content: capture[2].replace(
1662
+ INLINE_CODE_ESCAPE_BACKTICKS_R,
1663
+ "$1",
1664
+ ),
1665
+ };
1666
+ },
1667
+ react: function (node, output, state) {
1668
+ return reactElement("code", state.key, {
1669
+ children: node.content,
1670
+ });
1671
+ },
1672
+ html: function (node, output, state) {
1673
+ return htmlTag("code", sanitizeText(node.content));
1674
+ },
1675
+ },
1676
+ br: {
1677
+ order: currOrder++,
1678
+ match: anyScopeRegex(/^ {2,}\n/),
1679
+ parse: ignoreCapture,
1680
+ react: function (node, output, state) {
1681
+ return reactElement("br", state.key, EMPTY_PROPS);
1682
+ },
1683
+ html: function (node, output, state) {
1684
+ return "<br>";
1685
+ },
1686
+ },
1687
+ text: {
1688
+ order: currOrder++,
1689
+ // Here we look for anything followed by non-symbols,
1690
+ // double newlines, or double-space-newlines
1691
+ // We break on any symbol characters so that this grammar
1692
+ // is easy to extend without needing to modify this regex
1693
+ match: anyScopeRegex(
1694
+ /^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff]|\n\n| {2,}\n|\w+:\S|$)/,
1695
+ ),
1696
+ parse: function (capture, parse, state) {
1697
+ return {
1698
+ content: capture[0],
1699
+ };
1700
+ },
1701
+ react: function (node, output, state) {
1702
+ return node.content;
1703
+ },
1704
+ html: function (node, output, state) {
1705
+ return sanitizeText(node.content);
1706
+ },
1707
+ },
1708
+ };
1709
+
1710
+ /** (deprecated) */
1711
+ var ruleOutput = function (
1712
+ // $FlowFixMe
1713
+ rules: OutputRules<Rule>,
1714
+ property: $Keys<Rule>,
1715
+ ) {
1716
+ if (!property && typeof console !== "undefined") {
1717
+ console.warn(
1718
+ "simple-markdown ruleOutput should take 'react' or " +
1719
+ "'html' as the second argument.",
1720
+ );
1721
+ }
1722
+
1723
+ var nestedRuleOutput = function (
1724
+ ast: SingleASTNode,
1725
+ outputFunc: Output<any>,
1726
+ state: State,
1727
+ ) {
1728
+ return rules[ast.type][property](ast, outputFunc, state);
1729
+ };
1730
+ return nestedRuleOutput;
1731
+ };
1732
+
1733
+ /** (deprecated)
1734
+ */
1735
+ var reactFor = function (outputFunc: ReactNodeOutput): ReactOutput {
1736
+ var nestedOutput: ReactOutput = function (ast, state) {
1737
+ state = state || {};
1738
+ if (Array.isArray(ast)) {
1739
+ var oldKey = state.key;
1740
+ var result: Array<ReactElements> = [];
1741
+
1742
+ // map nestedOutput over the ast, except group any text
1743
+ // nodes together into a single string output.
1744
+ var lastResult = null;
1745
+ for (var i = 0; i < ast.length; i++) {
1746
+ state.key = "" + i;
1747
+ var nodeOut = nestedOutput(ast[i], state);
1748
+ if (
1749
+ typeof nodeOut === "string" &&
1750
+ typeof lastResult === "string"
1751
+ ) {
1752
+ lastResult = lastResult + nodeOut;
1753
+ result[result.length - 1] = lastResult;
1754
+ } else {
1755
+ result.push(nodeOut);
1756
+ lastResult = nodeOut;
1757
+ }
1758
+ }
1759
+
1760
+ state.key = oldKey;
1761
+ return result;
1762
+ } else {
1763
+ return outputFunc(ast, nestedOutput, state);
1764
+ }
1765
+ };
1766
+ return nestedOutput;
1767
+ };
1768
+
1769
+ /** (deprecated)
1770
+ */
1771
+ var htmlFor = function (outputFunc: HtmlNodeOutput): HtmlOutput {
1772
+ var nestedOutput: HtmlOutput = function (ast, state) {
1773
+ state = state || {};
1774
+ if (Array.isArray(ast)) {
1775
+ return ast
1776
+ .map(function (node) {
1777
+ return nestedOutput(node, state);
1778
+ })
1779
+ .join("");
1780
+ } else {
1781
+ return outputFunc(ast, nestedOutput, state);
1782
+ }
1783
+ };
1784
+ return nestedOutput;
1785
+ };
1786
+
1787
+ var outputFor = function (
1788
+ rules: OutputRules<Rule>,
1789
+ property: $Keys<Rule>,
1790
+ defaultState: ?State = {},
1791
+ ) {
1792
+ if (!property) {
1793
+ throw new Error(
1794
+ "simple-markdown: outputFor: `property` must be " +
1795
+ "defined. " +
1796
+ "if you just upgraded, you probably need to replace `outputFor` " +
1797
+ "with `reactFor`",
1798
+ );
1799
+ }
1800
+
1801
+ var latestState: State;
1802
+ // $FlowFixMe[incompatible-type]
1803
+ var arrayRule: ArrayRule = rules.Array || defaultRules.Array;
1804
+
1805
+ // Tricks to convince tsc that this var is not null:
1806
+ var arrayRuleCheck = arrayRule[property];
1807
+ if (!arrayRuleCheck) {
1808
+ throw new Error(
1809
+ "simple-markdown: outputFor: to join nodes of type `" +
1810
+ property +
1811
+ "` you must provide an `Array:` joiner rule with that type, " +
1812
+ "Please see the docs for details on specifying an Array rule.",
1813
+ );
1814
+ }
1815
+ var arrayRuleOutput = arrayRuleCheck;
1816
+
1817
+ var nestedOutput: Output<any> = function (ast, state) {
1818
+ state = state || latestState;
1819
+ latestState = state;
1820
+ if (Array.isArray(ast)) {
1821
+ return arrayRuleOutput(ast, nestedOutput, state);
1822
+ } else {
1823
+ return rules[ast.type][property](ast, nestedOutput, state);
1824
+ }
1825
+ };
1826
+
1827
+ var outerOutput: Output<any> = function (ast, state) {
1828
+ latestState = populateInitialState(state, defaultState);
1829
+ return nestedOutput(ast, latestState);
1830
+ };
1831
+ return outerOutput;
1832
+ };
1833
+
1834
+ // $FlowFixMe[incompatible-call]
1835
+ var defaultRawParse = parserFor(defaultRules);
1836
+
1837
+ var defaultBlockParse = function (
1838
+ source: string,
1839
+ state: ?State,
1840
+ ): Array<SingleASTNode> {
1841
+ state = state || {};
1842
+ state.inline = false;
1843
+ return defaultRawParse(source, state);
1844
+ };
1845
+
1846
+ var defaultInlineParse = function (
1847
+ source: string,
1848
+ state: ?State,
1849
+ ): Array<SingleASTNode> {
1850
+ state = state || {};
1851
+ state.inline = true;
1852
+ return defaultRawParse(source, state);
1853
+ };
1854
+
1855
+ var defaultImplicitParse = function (
1856
+ source: string,
1857
+ state: ?State,
1858
+ ): Array<SingleASTNode> {
1859
+ var isBlock = BLOCK_END_R.test(source);
1860
+ state = state || {};
1861
+ state.inline = !isBlock;
1862
+ return defaultRawParse(source, state);
1863
+ };
1864
+
1865
+ // $FlowFixMe[incompatible-call]
1866
+ var defaultReactOutput: ReactOutput = outputFor(defaultRules, "react");
1867
+ // $FlowFixMe[incompatible-call]
1868
+ var defaultHtmlOutput: HtmlOutput = outputFor(defaultRules, "html");
1869
+
1870
+ var markdownToReact = function (source: string, state: ?State): ReactElements {
1871
+ return defaultReactOutput(defaultBlockParse(source, state), state);
1872
+ };
1873
+
1874
+ var markdownToHtml = function (source: string, state: ?State): string {
1875
+ return defaultHtmlOutput(defaultBlockParse(source, state), state);
1876
+ };
1877
+
1878
+ // TODO: This needs definition
1879
+ type ReactMarkdownProps = any;
1880
+ var ReactMarkdown = function (props: ReactMarkdownProps): ReactElement {
1881
+ var divProps = {};
1882
+
1883
+ for (var prop in props) {
1884
+ if (
1885
+ prop !== "source" &&
1886
+ // $FlowFixMe
1887
+ Object.prototype.hasOwnProperty.call(props, prop)
1888
+ ) {
1889
+ divProps[prop] = props[prop];
1890
+ }
1891
+ }
1892
+ divProps.children = markdownToReact(props.source);
1893
+
1894
+ return reactElement("div", null, divProps);
1895
+ };
1896
+
1897
+ type Exports = {
1898
+ +defaultRules: DefaultRules,
1899
+ +parserFor: (rules: ParserRules, defaultState?: ?State) => Parser,
1900
+ +outputFor: <Rule: Object>(
1901
+ rules: OutputRules<Rule>,
1902
+ param: $Keys<Rule>,
1903
+ defaultState?: ?State,
1904
+ ) => Output<any>,
1905
+
1906
+ +ruleOutput: <Rule: Object>(
1907
+ rules: OutputRules<Rule>,
1908
+ param: $Keys<Rule>,
1909
+ ) => NodeOutput<any>,
1910
+ +reactFor: (ReactNodeOutput) => ReactOutput,
1911
+ +htmlFor: (HtmlNodeOutput) => HtmlOutput,
1912
+
1913
+ +inlineRegex: (regex: RegExp) => MatchFunction,
1914
+ +blockRegex: (regex: RegExp) => MatchFunction,
1915
+ +anyScopeRegex: (regex: RegExp) => MatchFunction,
1916
+ +parseInline: (parse: Parser, content: string, state: State) => ASTNode,
1917
+ +parseBlock: (parse: Parser, content: string, state: State) => ASTNode,
1918
+
1919
+ +markdownToReact: (source: string, state?: ?State) => ReactElements,
1920
+ +markdownToHtml: (source: string, state?: ?State) => string,
1921
+ +ReactMarkdown: (props: {source: string, [string]: any}) => ReactElement,
1922
+
1923
+ +defaultRawParse: (source: string, state?: ?State) => Array<SingleASTNode>,
1924
+ +defaultBlockParse: (
1925
+ source: string,
1926
+ state?: ?State,
1927
+ ) => Array<SingleASTNode>,
1928
+ +defaultInlineParse: (
1929
+ source: string,
1930
+ state?: ?State,
1931
+ ) => Array<SingleASTNode>,
1932
+ +defaultImplicitParse: (
1933
+ source: string,
1934
+ state?: ?State,
1935
+ ) => Array<SingleASTNode>,
1936
+
1937
+ +defaultReactOutput: ReactOutput,
1938
+ +defaultHtmlOutput: HtmlOutput,
1939
+
1940
+ +preprocess: (source: string) => string,
1941
+ +sanitizeText: (text: Attr) => string,
1942
+ +sanitizeUrl: (url: ?string) => ?string,
1943
+ +unescapeUrl: (url: string) => string,
1944
+ +htmlTag: (
1945
+ tagName: string,
1946
+ content: string,
1947
+ attributes: ?{[any]: ?Attr},
1948
+ isClosed: ?boolean,
1949
+ ) => string,
1950
+ +reactElement: (
1951
+ type: string,
1952
+ key: string | null,
1953
+ props: {[string]: any},
1954
+ ) => ReactElement,
1955
+ };
1956
+
1957
+ export type {
1958
+ // Hopefully you shouldn't have to use these, but they're here if you need!
1959
+ // Top-level API:
1960
+ State,
1961
+ Parser,
1962
+ Output,
1963
+ ReactOutput,
1964
+ HtmlOutput,
1965
+ // Most of the following types should be considered experimental and
1966
+ // subject to change or change names. Again, they shouldn't be necessary,
1967
+ // but if they are I'd love to hear how so I can better support them!
1968
+
1969
+ // Individual Rule fields:
1970
+ Capture,
1971
+ MatchFunction,
1972
+ ParseFunction,
1973
+ NodeOutput,
1974
+ ArrayNodeOutput,
1975
+ ReactNodeOutput,
1976
+ // Single rules:
1977
+ ParserRule,
1978
+ ReactOutputRule,
1979
+ HtmlOutputRule,
1980
+ // Sets of rules:
1981
+ ParserRules,
1982
+ OutputRules,
1983
+ Rules,
1984
+ ReactRules,
1985
+ HtmlRules,
1986
+ };
1987
+
1988
+ // $FlowFixMe
1989
+ var SimpleMarkdown: Exports = {
1990
+ defaultRules: defaultRules,
1991
+ parserFor: parserFor,
1992
+ outputFor: outputFor,
1993
+
1994
+ inlineRegex: inlineRegex,
1995
+ blockRegex: blockRegex,
1996
+ anyScopeRegex: anyScopeRegex,
1997
+ parseInline: parseInline,
1998
+ parseBlock: parseBlock,
1999
+
2000
+ // default wrappers:
2001
+ markdownToReact: markdownToReact,
2002
+ markdownToHtml: markdownToHtml,
2003
+ ReactMarkdown: ReactMarkdown,
2004
+
2005
+ defaultBlockParse: defaultBlockParse,
2006
+ defaultInlineParse: defaultInlineParse,
2007
+ defaultImplicitParse: defaultImplicitParse,
2008
+
2009
+ defaultReactOutput: defaultReactOutput,
2010
+ defaultHtmlOutput: defaultHtmlOutput,
2011
+
2012
+ preprocess: preprocess,
2013
+ sanitizeText: sanitizeText,
2014
+ sanitizeUrl: sanitizeUrl,
2015
+ unescapeUrl: unescapeUrl,
2016
+ htmlTag: htmlTag,
2017
+ reactElement: reactElement,
2018
+
2019
+ // deprecated:
2020
+ defaultRawParse: defaultRawParse,
2021
+ ruleOutput: ruleOutput,
2022
+ reactFor: reactFor,
2023
+ htmlFor: htmlFor,
2024
+
2025
+ defaultParse: function () {
2026
+ if (typeof console !== "undefined") {
2027
+ console.warn(
2028
+ "defaultParse is deprecated, please use `defaultImplicitParse`",
2029
+ );
2030
+ }
2031
+ return defaultImplicitParse.apply(null, (arguments: any));
2032
+ },
2033
+ defaultOutput: function () {
2034
+ if (typeof console !== "undefined") {
2035
+ console.warn(
2036
+ "defaultOutput is deprecated, please use `defaultReactOutput`",
2037
+ );
2038
+ }
2039
+ return defaultReactOutput.apply(null, (arguments: any));
2040
+ },
2041
+ };
2042
+
2043
+ export default SimpleMarkdown;