@@ -6,6 +6,11 @@ const TAGS = {
66 '-' : [ '<hr />' ]
77} ;
88
9+ /**
10+ * Highlight option
11+ */
12+ let highlight = false ;
13+
914/** Outdent a string based on the first indented line's leading whitespace
1015 * @private
1116 */
@@ -21,96 +26,95 @@ function encodeAttr(str) {
2126}
2227
2328/** Parse Markdown into an HTML String. */
24- export default function snarkdown ( md , options = { } ) {
25- const highlight = options . highlight ;
29+ function parse ( md , prevLinks ) {
30+ let tokenizer = / ( (?: ^ | \n + ) (?: \n - - - + | \* \* (?: \* ) + ) \n ) | (?: ^ ` ` ` ( \w * ) \n ( [ \s \S ] * ?) \n ` ` ` $ ) | ( (?: (?: ^ | \n + ) (?: \t | { 2 , } ) .+ ) + \n * ) | ( (?: (?: ^ | \n ) ( [ > * + - ] | \d + \. ) \s + .* ) + ) | (?: \! \[ ( [ ^ \] ] * ?) \] \( ( [ ^ \) ] + ?) \) ) | ( \[ ) | ( \] (?: \( ( [ ^ \) ] + ?) \) ) ? ) | (?: (?: ^ | \n + ) ( [ ^ \s ] .* ) \n ( \- { 3 , } | = { 3 , } ) (?: \n + | $ ) ) | (?: (?: ^ | \n + ) ( # { 1 , 3 } ) \s * ( .+ ) (?: \n + | $ ) ) | (?: ` ( [ ^ ` ] .* ?) ` ) | ( \n \n * | \n { 2 , } | _ _ | \* \* | [ _ * ] ) / gm,
31+ context = [ ] ,
32+ out = '' ,
33+ links = prevLinks || { } ,
34+ last = 0 ,
35+ chunk , prev , token , inner , t ;
2636
27- return parse ( md ) ;
37+ function tag ( token ) {
38+ var desc = TAGS [ token . replace ( / \* / g, '_' ) [ 1 ] || '' ] ,
39+ end = context [ context . length - 1 ] == token ;
40+ if ( ! desc ) return token ;
41+ if ( ! desc [ 1 ] ) return desc [ 0 ] ;
42+ context [ end ?'pop' :'push' ] ( token ) ;
43+ return desc [ end | 0 ] ;
44+ }
2845
29- function parse ( md , prevLinks ) {
30- let tokenizer = / ( (?: ^ | \n + ) (?: \n - - - + | \* \* (?: \* ) + ) \n ) | (?: ^ ` ` ` ( \w * ) \n ( [ \s \S ] * ?) \n ` ` ` $ ) | ( (?: (?: ^ | \n + ) (?: \t | { 2 , } ) .+ ) + \n * ) | ( (?: (?: ^ | \n ) ( [ > * + - ] | \d + \. ) \s + .* ) + ) | (?: \! \[ ( [ ^ \] ] * ?) \] \( ( [ ^ \) ] + ?) \) ) | ( \[ ) | ( \] (?: \( ( [ ^ \) ] + ?) \) ) ? ) | (?: (?: ^ | \n + ) ( [ ^ \s ] .* ) \n ( \- { 3 , } | = { 3 , } ) (?: \n + | $ ) ) | (?: (?: ^ | \n + ) ( # { 1 , 3 } ) \s * ( .+ ) (?: \n + | $ ) ) | (?: ` ( [ ^ ` ] .* ?) ` ) | ( \n \n * | \n { 2 , } | _ _ | \* \* | [ _ * ] ) / gm,
31- context = [ ] ,
32- out = '' ,
33- links = prevLinks || { } ,
34- last = 0 ,
35- chunk , prev , token , inner , t ;
46+ function flush ( ) {
47+ let str = '' ;
48+ while ( context . length ) str += tag ( context [ context . length - 1 ] ) ;
49+ return str ;
50+ }
3651
37- function tag ( token ) {
38- var desc = TAGS [ token . replace ( / \* / g, '_' ) [ 1 ] || '' ] ,
39- end = context [ context . length - 1 ] == token ;
40- if ( ! desc ) return token ;
41- if ( ! desc [ 1 ] ) return desc [ 0 ] ;
42- context [ end ?'pop' :'push' ] ( token ) ;
43- return desc [ end | 0 ] ;
44- }
52+ md = md . replace ( / ^ \[ ( .+ ?) \] : \s * ( .+ ) $ / gm, ( s , name , url ) => {
53+ links [ name . toLowerCase ( ) ] = url ;
54+ return '' ;
55+ } ) . replace ( / ^ \n + | \n + $ / g, '' ) ;
4556
46- function flush ( ) {
47- let str = '' ;
48- while ( context . length ) str += tag ( context [ context . length - 1 ] ) ;
49- return str ;
57+ while ( ( token = tokenizer . exec ( md ) ) ) {
58+ prev = md . substring ( last , token . index ) ;
59+ last = tokenizer . lastIndex ;
60+ chunk = token [ 0 ] ;
61+ if ( prev . match ( / [ ^ \\ ] ( \\ \\ ) * \\ $ / ) ) {
62+ // escaped
5063 }
51-
52- md = md . replace ( / ^ \[ ( .+ ?) \] : \s * ( .+ ) $ / gm, ( s , name , url ) => {
53- links [ name . toLowerCase ( ) ] = url ;
54- return '' ;
55- } ) . replace ( / ^ \n + | \n + $ / g, '' ) ;
56-
57- while ( ( token = tokenizer . exec ( md ) ) ) {
58- prev = md . substring ( last , token . index ) ;
59- last = tokenizer . lastIndex ;
60- chunk = token [ 0 ] ;
61- if ( prev . match ( / [ ^ \\ ] ( \\ \\ ) * \\ $ / ) ) {
62- // escaped
63- }
64- // Code/Indent blocks:
65- else if ( token [ 3 ] || token [ 4 ] ) {
66- const lang = token [ 4 ] ?'poetry' :token [ 2 ] . toLowerCase ( ) ;
67- chunk = '<pre class="code ' + lang + '">' + outdent (
68- highlight ? highlight ( token [ 3 ] || token [ 4 ] , lang ) : encodeAttr ( token [ 3 ] || token [ 4 ] )
69- ) . replace ( / ^ \n + | \n + $ / g, '' ) + '</pre>' ;
70- }
71- // > Quotes, -* lists:
72- else if ( token [ 6 ] ) {
73- t = token [ 6 ] ;
74- if ( t . match ( / \. / ) ) {
75- token [ 5 ] = token [ 5 ] . replace ( / ^ \d + / gm, '' ) ;
76- }
77- inner = parse ( outdent ( token [ 5 ] . replace ( / ^ \s * [ > * + . - ] / gm, '' ) ) ) ;
78- if ( t === '>' ) t = 'blockquote' ;
79- else {
80- t = t . match ( / \. / ) ? 'ol' : 'ul' ;
81- inner = inner . replace ( / ^ ( .* ) ( \n | $ ) / gm, '<li>$1</li>' ) ;
82- }
83- chunk = '<' + t + '>' + inner + '</' + t + '>' ;
84- }
85- // Images:
86- else if ( token [ 8 ] ) {
87- chunk = `<img src="${ encodeAttr ( token [ 8 ] ) } " alt="${ encodeAttr ( token [ 7 ] ) } ">` ;
88- }
89- // Links:
90- else if ( token [ 10 ] ) {
91- out = out . replace ( '<a>' , `<a href="${ encodeAttr ( token [ 11 ] || links [ prev . toLowerCase ( ) ] ) } ">` ) ;
92- chunk = flush ( ) + '</a>' ;
93- }
94- else if ( token [ 9 ] ) {
95- chunk = '<a>' ;
96- }
97- // Headings:
98- else if ( token [ 12 ] || token [ 14 ] ) {
99- t = 'h' + ( token [ 14 ] ? token [ 14 ] . length : ( token [ 13 ] [ 0 ] === '=' ?1 :2 ) ) ;
100- chunk = '<' + t + '>' + parse ( token [ 12 ] || token [ 15 ] , links ) + '</' + t + '>' ;
101- }
102- // `code`:
103- else if ( token [ 16 ] ) {
104- chunk = '<code>' + encodeAttr ( token [ 16 ] ) + '</code>' ;
64+ // Code/Indent blocks:
65+ else if ( token [ 3 ] || token [ 4 ] ) {
66+ chunk = '<pre class="code ' + ( token [ 4 ] ?'poetry' :token [ 2 ] . toLowerCase ( ) ) + '">' + outdent (
67+ highlight ? highlight ( token [ 3 ] || token [ 4 ] , ( token [ 4 ] ?'poetry' :token [ 2 ] . toLowerCase ( ) ) ) : encodeAttr ( token [ 3 ] || token [ 4 ] )
68+ ) . replace ( / ^ \n + | \n + $ / g, '' ) + '</pre>' ;
69+ }
70+ // > Quotes, -* lists:
71+ else if ( token [ 6 ] ) {
72+ t = token [ 6 ] ;
73+ if ( t . match ( / \. / ) ) {
74+ token [ 5 ] = token [ 5 ] . replace ( / ^ \d + / gm, '' ) ;
10575 }
106- // Inline formatting: *em*, **strong** & friends
107- else if ( token [ 17 ] || token [ 1 ] ) {
108- chunk = tag ( token [ 17 ] || '--' ) ;
76+ inner = parse ( outdent ( token [ 5 ] . replace ( / ^ \s * [ > * + . - ] / gm, '' ) ) ) ;
77+ if ( t === '>' ) t = 'blockquote' ;
78+ else {
79+ t = t . match ( / \. / ) ? 'ol' : 'ul' ;
80+ inner = inner . replace ( / ^ ( .* ) ( \n | $ ) / gm, '<li>$1</li>' ) ;
10981 }
110- out += prev ;
111- out += chunk ;
82+ chunk = '<' + t + '>' + inner + '</' + t + '>' ;
11283 }
113-
114- return ( out + md . substring ( last ) + flush ( ) ) . trim ( ) ;
84+ // Images:
85+ else if ( token [ 8 ] ) {
86+ chunk = `<img src="${ encodeAttr ( token [ 8 ] ) } " alt="${ encodeAttr ( token [ 7 ] ) } ">` ;
87+ }
88+ // Links:
89+ else if ( token [ 10 ] ) {
90+ out = out . replace ( '<a>' , `<a href="${ encodeAttr ( token [ 11 ] || links [ prev . toLowerCase ( ) ] ) } ">` ) ;
91+ chunk = flush ( ) + '</a>' ;
92+ }
93+ else if ( token [ 9 ] ) {
94+ chunk = '<a>' ;
95+ }
96+ // Headings:
97+ else if ( token [ 12 ] || token [ 14 ] ) {
98+ t = 'h' + ( token [ 14 ] ? token [ 14 ] . length : ( token [ 13 ] [ 0 ] === '=' ?1 :2 ) ) ;
99+ chunk = '<' + t + '>' + parse ( token [ 12 ] || token [ 15 ] , links ) + '</' + t + '>' ;
100+ }
101+ // `code`:
102+ else if ( token [ 16 ] ) {
103+ chunk = '<code>' + encodeAttr ( token [ 16 ] ) + '</code>' ;
104+ }
105+ // Inline formatting: *em*, **strong** & friends
106+ else if ( token [ 17 ] || token [ 1 ] ) {
107+ chunk = tag ( token [ 17 ] || '--' ) ;
108+ }
109+ out += prev ;
110+ out += chunk ;
115111 }
112+
113+ return ( out + md . substring ( last ) + flush ( ) ) . trim ( ) ;
114+ }
115+
116+ export default function snarkdown ( md , opt ) {
117+ opt = opt || { } ;
118+ highlight = opt . highlight ;
119+ return parse ( md ) ;
116120}
0 commit comments