3 var whitespace = require('is-whitespace-character');
4 var locate = require('../locate/link');
9 var own = {}.hasOwnProperty;
11 var C_BACKSLASH = '\\';
12 var C_BRACKET_OPEN = '[';
13 var C_BRACKET_CLOSE = ']';
14 var C_PAREN_OPEN = '(';
15 var C_PAREN_CLOSE = ')';
19 var C_DOUBLE_QUOTE = '"';
20 var C_SINGLE_QUOTE = '\'';
22 /* Map of characters, which can be used to mark link
23 * and image titles. */
24 var LINK_MARKERS = {};
26 LINK_MARKERS[C_DOUBLE_QUOTE] = C_DOUBLE_QUOTE;
27 LINK_MARKERS[C_SINGLE_QUOTE] = C_SINGLE_QUOTE;
29 /* Map of characters, which can be used to mark link
30 * and image titles in commonmark-mode. */
31 var COMMONMARK_LINK_MARKERS = {};
33 COMMONMARK_LINK_MARKERS[C_DOUBLE_QUOTE] = C_DOUBLE_QUOTE;
34 COMMONMARK_LINK_MARKERS[C_SINGLE_QUOTE] = C_SINGLE_QUOTE;
35 COMMONMARK_LINK_MARKERS[C_PAREN_OPEN] = C_PAREN_CLOSE;
37 function link(eat, value, silent) {
41 var character = value.charAt(0);
42 var pedantic = self.options.pedantic;
43 var commonmark = self.options.commonmark;
44 var gfm = self.options.gfm;
65 /* Detect whether this is an image. */
66 if (character === '!') {
69 character = value.charAt(++index);
72 /* Eat the opening. */
73 if (character !== C_BRACKET_OPEN) {
77 /* Exit when this is a link and we’re already inside
79 if (!isImage && self.inLink) {
83 subvalue += character;
87 /* Eat the content. */
88 length = value.length;
95 while (index < length) {
96 character = value.charAt(index);
99 if (character === C_TICK) {
100 /* Inline-code in link content. */
103 while (value.charAt(index + 1) === C_TICK) {
104 subqueue += character;
111 } else if (count >= opening) {
114 } else if (character === C_BACKSLASH) {
115 /* Allow brackets to be escaped. */
117 subqueue += value.charAt(index);
118 /* In GFM mode, brackets in code still count.
119 * In all other modes, they don’t. This empty
120 * block prevents the next statements are
122 } else if ((!opening || gfm) && character === C_BRACKET_OPEN) {
124 } else if ((!opening || gfm) && character === C_BRACKET_CLOSE) {
128 /* Allow white-space between content and
129 * url in GFM mode. */
131 while (index < length) {
132 character = value.charAt(index + 1);
134 if (!whitespace(character)) {
138 subqueue += character;
143 if (value.charAt(index + 1) !== C_PAREN_OPEN) {
147 subqueue += C_PAREN_OPEN;
160 /* Eat the content closing. */
166 subvalue += queue + subqueue;
169 /* Eat white-space. */
170 while (index < length) {
171 character = value.charAt(index);
173 if (!whitespace(character)) {
177 subvalue += character;
182 character = value.charAt(index);
183 markers = commonmark ? COMMONMARK_LINK_MARKERS : LINK_MARKERS;
185 beforeURL = subvalue;
187 if (character === C_LT) {
191 while (index < length) {
192 character = value.charAt(index);
194 if (character === C_GT) {
198 if (commonmark && character === '\n') {
206 if (value.charAt(index) !== C_GT) {
210 subvalue += C_LT + queue + C_GT;
217 while (index < length) {
218 character = value.charAt(index);
220 if (subqueue && own.call(markers, character)) {
224 if (whitespace(character)) {
229 subqueue += character;
231 if (character === C_PAREN_OPEN) {
233 } else if (character === C_PAREN_CLOSE) {
244 if (character === C_BACKSLASH) {
245 queue += C_BACKSLASH;
246 character = value.charAt(++index);
257 index = subvalue.length;
260 /* Eat white-space. */
263 while (index < length) {
264 character = value.charAt(index);
266 if (!whitespace(character)) {
274 character = value.charAt(index);
278 if (queue && own.call(markers, character)) {
280 subvalue += character;
282 marker = markers[character];
283 beforeTitle = subvalue;
285 /* In commonmark-mode, things are pretty easy: the
286 * marker cannot occur inside the title.
288 * Non-commonmark does, however, support nested
291 while (index < length) {
292 character = value.charAt(index);
294 if (character === marker) {
298 if (character === C_BACKSLASH) {
299 queue += C_BACKSLASH;
300 character = value.charAt(++index);
307 character = value.charAt(index);
309 if (character !== marker) {
314 subvalue += queue + character;
317 while (index < length) {
318 character = value.charAt(index);
320 if (!whitespace(character)) {
324 subvalue += character;
330 while (index < length) {
331 character = value.charAt(index);
333 if (character === marker) {
335 queue += marker + subqueue;
340 } else if (!hasMarker) {
342 } else if (character === C_PAREN_CLOSE) {
343 subvalue += queue + marker + subqueue;
346 } else if (whitespace(character)) {
347 subqueue += character;
349 queue += marker + subqueue + character;
359 if (value.charAt(index) !== C_PAREN_CLOSE) {
363 /* istanbul ignore if - never used (yet) */
368 subvalue += C_PAREN_CLOSE;
370 url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end);
373 beforeTitle = eat(beforeTitle).test().end;
374 title = self.decode.raw(self.unescape(title), beforeTitle);
378 type: isImage ? 'image' : 'link',
379 title: title || null,
384 node.alt = self.decode.raw(self.unescape(content), now) || null;
386 exit = self.enterLink();
387 node.children = self.tokenizeInline(content, now);
391 return eat(subvalue)(node);