turndown 7.2.2 → 7.2.4

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/dist/turndown.js CHANGED
@@ -1,147 +1,108 @@
1
1
  var TurndownService = (function () {
2
2
  'use strict';
3
3
 
4
- function extend (destination) {
4
+ function extend(destination) {
5
5
  for (var i = 1; i < arguments.length; i++) {
6
6
  var source = arguments[i];
7
7
  for (var key in source) {
8
- if (source.hasOwnProperty(key)) destination[key] = source[key];
8
+ if (Object.prototype.hasOwnProperty.call(source, key)) destination[key] = source[key];
9
9
  }
10
10
  }
11
- return destination
11
+ return destination;
12
12
  }
13
-
14
- function repeat (character, count) {
15
- return Array(count + 1).join(character)
13
+ function repeat(character, count) {
14
+ return Array(count + 1).join(character);
16
15
  }
17
-
18
- function trimLeadingNewlines (string) {
19
- return string.replace(/^\n*/, '')
16
+ function trimLeadingNewlines(string) {
17
+ return string.replace(/^\n*/, '');
20
18
  }
21
-
22
- function trimTrailingNewlines (string) {
19
+ function trimTrailingNewlines(string) {
23
20
  // avoid match-at-end regexp bottleneck, see #370
24
21
  var indexEnd = string.length;
25
22
  while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--;
26
- return string.substring(0, indexEnd)
23
+ return string.substring(0, indexEnd);
27
24
  }
28
-
29
- function trimNewlines (string) {
30
- return trimTrailingNewlines(trimLeadingNewlines(string))
25
+ function trimNewlines(string) {
26
+ return trimTrailingNewlines(trimLeadingNewlines(string));
31
27
  }
32
-
33
- var blockElements = [
34
- 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',
35
- 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',
36
- 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',
37
- 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',
38
- 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',
39
- 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'
40
- ];
41
-
42
- function isBlock (node) {
43
- return is(node, blockElements)
28
+ var blockElements = ['ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS', 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES', 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD', 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'];
29
+ function isBlock(node) {
30
+ return is(node, blockElements);
44
31
  }
45
-
46
- var voidElements = [
47
- 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',
48
- 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'
49
- ];
50
-
51
- function isVoid (node) {
52
- return is(node, voidElements)
32
+ var voidElements = ['AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'];
33
+ function isVoid(node) {
34
+ return is(node, voidElements);
53
35
  }
54
-
55
- function hasVoid (node) {
56
- return has(node, voidElements)
36
+ function hasVoid(node) {
37
+ return has(node, voidElements);
57
38
  }
58
-
59
- var meaningfulWhenBlankElements = [
60
- 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',
61
- 'AUDIO', 'VIDEO'
62
- ];
63
-
64
- function isMeaningfulWhenBlank (node) {
65
- return is(node, meaningfulWhenBlankElements)
39
+ var meaningfulWhenBlankElements = ['A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT', 'AUDIO', 'VIDEO'];
40
+ function isMeaningfulWhenBlank(node) {
41
+ return is(node, meaningfulWhenBlankElements);
66
42
  }
67
-
68
- function hasMeaningfulWhenBlank (node) {
69
- return has(node, meaningfulWhenBlankElements)
43
+ function hasMeaningfulWhenBlank(node) {
44
+ return has(node, meaningfulWhenBlankElements);
70
45
  }
71
-
72
- function is (node, tagNames) {
73
- return tagNames.indexOf(node.nodeName) >= 0
46
+ function is(node, tagNames) {
47
+ return tagNames.indexOf(node.nodeName) >= 0;
74
48
  }
75
-
76
- function has (node, tagNames) {
77
- return (
78
- node.getElementsByTagName &&
79
- tagNames.some(function (tagName) {
80
- return node.getElementsByTagName(tagName).length
81
- })
82
- )
49
+ function has(node, tagNames) {
50
+ return node.getElementsByTagName && tagNames.some(function (tagName) {
51
+ return node.getElementsByTagName(tagName).length;
52
+ });
53
+ }
54
+ var markdownEscapes = [[/\\/g, '\\\\'], [/\*/g, '\\*'], [/^-/g, '\\-'], [/^\+ /g, '\\+ '], [/^(=+)/g, '\\$1'], [/^(#{1,6}) /g, '\\$1 '], [/`/g, '\\`'], [/^~~~/g, '\\~~~'], [/\[/g, '\\['], [/\]/g, '\\]'], [/^>/g, '\\>'], [/_/g, '\\_'], [/^(\d+)\. /g, '$1\\. ']];
55
+ function escapeMarkdown(string) {
56
+ return markdownEscapes.reduce(function (accumulator, escape) {
57
+ return accumulator.replace(escape[0], escape[1]);
58
+ }, string);
83
59
  }
84
60
 
85
61
  var rules = {};
86
-
87
62
  rules.paragraph = {
88
63
  filter: 'p',
89
-
90
64
  replacement: function (content) {
91
- return '\n\n' + content + '\n\n'
65
+ return '\n\n' + content + '\n\n';
92
66
  }
93
67
  };
94
-
95
68
  rules.lineBreak = {
96
69
  filter: 'br',
97
-
98
70
  replacement: function (content, node, options) {
99
- return options.br + '\n'
71
+ return options.br + '\n';
100
72
  }
101
73
  };
102
-
103
74
  rules.heading = {
104
75
  filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
105
-
106
76
  replacement: function (content, node, options) {
107
77
  var hLevel = Number(node.nodeName.charAt(1));
108
-
109
78
  if (options.headingStyle === 'setext' && hLevel < 3) {
110
- var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
111
- return (
112
- '\n\n' + content + '\n' + underline + '\n\n'
113
- )
79
+ var underline = repeat(hLevel === 1 ? '=' : '-', content.length);
80
+ return '\n\n' + content + '\n' + underline + '\n\n';
114
81
  } else {
115
- return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
82
+ return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n';
116
83
  }
117
84
  }
118
85
  };
119
-
120
86
  rules.blockquote = {
121
87
  filter: 'blockquote',
122
-
123
88
  replacement: function (content) {
124
89
  content = trimNewlines(content).replace(/^/gm, '> ');
125
- return '\n\n' + content + '\n\n'
90
+ return '\n\n' + content + '\n\n';
126
91
  }
127
92
  };
128
-
129
93
  rules.list = {
130
94
  filter: ['ul', 'ol'],
131
-
132
95
  replacement: function (content, node) {
133
96
  var parent = node.parentNode;
134
97
  if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
135
- return '\n' + content
98
+ return '\n' + content;
136
99
  } else {
137
- return '\n\n' + content + '\n\n'
100
+ return '\n\n' + content + '\n\n';
138
101
  }
139
102
  }
140
103
  };
141
-
142
104
  rules.listItem = {
143
105
  filter: 'li',
144
-
145
106
  replacement: function (content, node, options) {
146
107
  var prefix = options.bulletListMarker + ' ';
147
108
  var parent = node.parentNode;
@@ -153,273 +114,208 @@ var TurndownService = (function () {
153
114
  var isParagraph = /\n$/.test(content);
154
115
  content = trimNewlines(content) + (isParagraph ? '\n' : '');
155
116
  content = content.replace(/\n/gm, '\n' + ' '.repeat(prefix.length)); // indent
156
- return (
157
- prefix + content + (node.nextSibling ? '\n' : '')
158
- )
117
+ return prefix + content + (node.nextSibling ? '\n' : '');
159
118
  }
160
119
  };
161
-
162
120
  rules.indentedCodeBlock = {
163
121
  filter: function (node, options) {
164
- return (
165
- options.codeBlockStyle === 'indented' &&
166
- node.nodeName === 'PRE' &&
167
- node.firstChild &&
168
- node.firstChild.nodeName === 'CODE'
169
- )
122
+ return options.codeBlockStyle === 'indented' && node.nodeName === 'PRE' && node.firstChild && node.firstChild.nodeName === 'CODE';
170
123
  },
171
-
172
124
  replacement: function (content, node, options) {
173
- return (
174
- '\n\n ' +
175
- node.firstChild.textContent.replace(/\n/g, '\n ') +
176
- '\n\n'
177
- )
125
+ return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n';
178
126
  }
179
127
  };
180
-
181
128
  rules.fencedCodeBlock = {
182
129
  filter: function (node, options) {
183
- return (
184
- options.codeBlockStyle === 'fenced' &&
185
- node.nodeName === 'PRE' &&
186
- node.firstChild &&
187
- node.firstChild.nodeName === 'CODE'
188
- )
130
+ return options.codeBlockStyle === 'fenced' && node.nodeName === 'PRE' && node.firstChild && node.firstChild.nodeName === 'CODE';
189
131
  },
190
-
191
132
  replacement: function (content, node, options) {
192
133
  var className = node.firstChild.getAttribute('class') || '';
193
134
  var language = (className.match(/language-(\S+)/) || [null, ''])[1];
194
135
  var code = node.firstChild.textContent;
195
-
196
136
  var fenceChar = options.fence.charAt(0);
197
137
  var fenceSize = 3;
198
138
  var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');
199
-
200
139
  var match;
201
- while ((match = fenceInCodeRegex.exec(code))) {
140
+ while (match = fenceInCodeRegex.exec(code)) {
202
141
  if (match[0].length >= fenceSize) {
203
142
  fenceSize = match[0].length + 1;
204
143
  }
205
144
  }
206
-
207
145
  var fence = repeat(fenceChar, fenceSize);
208
-
209
- return (
210
- '\n\n' + fence + language + '\n' +
211
- code.replace(/\n$/, '') +
212
- '\n' + fence + '\n\n'
213
- )
146
+ return '\n\n' + fence + language + '\n' + code.replace(/\n$/, '') + '\n' + fence + '\n\n';
214
147
  }
215
148
  };
216
-
217
149
  rules.horizontalRule = {
218
150
  filter: 'hr',
219
-
220
151
  replacement: function (content, node, options) {
221
- return '\n\n' + options.hr + '\n\n'
152
+ return '\n\n' + options.hr + '\n\n';
222
153
  }
223
154
  };
224
-
225
155
  rules.inlineLink = {
226
156
  filter: function (node, options) {
227
- return (
228
- options.linkStyle === 'inlined' &&
229
- node.nodeName === 'A' &&
230
- node.getAttribute('href')
231
- )
157
+ return options.linkStyle === 'inlined' && node.nodeName === 'A' && node.getAttribute('href');
232
158
  },
233
-
234
159
  replacement: function (content, node) {
235
- var href = node.getAttribute('href');
236
- if (href) href = href.replace(/([()])/g, '\\$1');
237
- var title = cleanAttribute(node.getAttribute('title'));
238
- if (title) title = ' "' + title.replace(/"/g, '\\"') + '"';
239
- return '[' + content + '](' + href + title + ')'
160
+ var href = escapeLinkDestination(node.getAttribute('href'));
161
+ var title = escapeLinkTitle(cleanAttribute(node.getAttribute('title')));
162
+ var titlePart = title ? ' "' + title + '"' : '';
163
+ return '[' + content + '](' + href + titlePart + ')';
240
164
  }
241
165
  };
242
-
243
166
  rules.referenceLink = {
244
167
  filter: function (node, options) {
245
- return (
246
- options.linkStyle === 'referenced' &&
247
- node.nodeName === 'A' &&
248
- node.getAttribute('href')
249
- )
168
+ return options.linkStyle === 'referenced' && node.nodeName === 'A' && node.getAttribute('href');
250
169
  },
251
-
252
170
  replacement: function (content, node, options) {
253
- var href = node.getAttribute('href');
171
+ var href = escapeLinkDestination(node.getAttribute('href'));
254
172
  var title = cleanAttribute(node.getAttribute('title'));
255
- if (title) title = ' "' + title + '"';
173
+ if (title) title = ' "' + escapeLinkTitle(title) + '"';
256
174
  var replacement;
257
175
  var reference;
258
-
259
176
  switch (options.linkReferenceStyle) {
260
177
  case 'collapsed':
261
178
  replacement = '[' + content + '][]';
262
179
  reference = '[' + content + ']: ' + href + title;
263
- break
180
+ break;
264
181
  case 'shortcut':
265
182
  replacement = '[' + content + ']';
266
183
  reference = '[' + content + ']: ' + href + title;
267
- break
184
+ break;
268
185
  default:
269
186
  var id = this.references.length + 1;
270
187
  replacement = '[' + content + '][' + id + ']';
271
188
  reference = '[' + id + ']: ' + href + title;
272
189
  }
273
-
274
190
  this.references.push(reference);
275
- return replacement
191
+ return replacement;
276
192
  },
277
-
278
193
  references: [],
279
-
280
194
  append: function (options) {
281
195
  var references = '';
282
196
  if (this.references.length) {
283
197
  references = '\n\n' + this.references.join('\n') + '\n\n';
284
198
  this.references = []; // Reset references
285
199
  }
286
- return references
200
+ return references;
287
201
  }
288
202
  };
289
-
290
203
  rules.emphasis = {
291
204
  filter: ['em', 'i'],
292
-
293
205
  replacement: function (content, node, options) {
294
- if (!content.trim()) return ''
295
- return options.emDelimiter + content + options.emDelimiter
206
+ if (!content.trim()) return '';
207
+ return options.emDelimiter + content + options.emDelimiter;
296
208
  }
297
209
  };
298
-
299
210
  rules.strong = {
300
211
  filter: ['strong', 'b'],
301
-
302
212
  replacement: function (content, node, options) {
303
- if (!content.trim()) return ''
304
- return options.strongDelimiter + content + options.strongDelimiter
213
+ if (!content.trim()) return '';
214
+ return options.strongDelimiter + content + options.strongDelimiter;
305
215
  }
306
216
  };
307
-
308
217
  rules.code = {
309
218
  filter: function (node) {
310
219
  var hasSiblings = node.previousSibling || node.nextSibling;
311
220
  var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
312
-
313
- return node.nodeName === 'CODE' && !isCodeBlock
221
+ return node.nodeName === 'CODE' && !isCodeBlock;
314
222
  },
315
-
316
223
  replacement: function (content) {
317
- if (!content) return ''
224
+ if (!content) return '';
318
225
  content = content.replace(/\r?\n|\r/g, ' ');
319
-
320
226
  var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : '';
321
227
  var delimiter = '`';
322
228
  var matches = content.match(/`+/gm) || [];
323
229
  while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
324
-
325
- return delimiter + extraSpace + content + extraSpace + delimiter
230
+ return delimiter + extraSpace + content + extraSpace + delimiter;
326
231
  }
327
232
  };
328
-
329
233
  rules.image = {
330
234
  filter: 'img',
331
-
332
235
  replacement: function (content, node) {
333
- var alt = cleanAttribute(node.getAttribute('alt'));
334
- var src = node.getAttribute('src') || '';
236
+ var alt = escapeMarkdown(cleanAttribute(node.getAttribute('alt')));
237
+ var src = escapeLinkDestination(node.getAttribute('src') || '');
335
238
  var title = cleanAttribute(node.getAttribute('title'));
336
- var titlePart = title ? ' "' + title + '"' : '';
337
- return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
239
+ var titlePart = title ? ' "' + escapeLinkTitle(title) + '"' : '';
240
+ return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '';
338
241
  }
339
242
  };
340
-
341
- function cleanAttribute (attribute) {
342
- return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
243
+ function cleanAttribute(attribute) {
244
+ return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : '';
245
+ }
246
+ function escapeLinkDestination(destination) {
247
+ var escaped = destination.replace(/([<>()])/g, '\\$1');
248
+ return escaped.indexOf(' ') >= 0 ? '<' + escaped + '>' : escaped;
249
+ }
250
+ function escapeLinkTitle(title) {
251
+ return title.replace(/"/g, '\\"');
343
252
  }
344
253
 
345
254
  /**
346
255
  * Manages a collection of rules used to convert HTML to Markdown
347
256
  */
348
257
 
349
- function Rules (options) {
258
+ function Rules(options) {
350
259
  this.options = options;
351
260
  this._keep = [];
352
261
  this._remove = [];
353
-
354
262
  this.blankRule = {
355
263
  replacement: options.blankReplacement
356
264
  };
357
-
358
265
  this.keepReplacement = options.keepReplacement;
359
-
360
266
  this.defaultRule = {
361
267
  replacement: options.defaultReplacement
362
268
  };
363
-
364
269
  this.array = [];
365
270
  for (var key in options.rules) this.array.push(options.rules[key]);
366
271
  }
367
-
368
272
  Rules.prototype = {
369
273
  add: function (key, rule) {
370
274
  this.array.unshift(rule);
371
275
  },
372
-
373
276
  keep: function (filter) {
374
277
  this._keep.unshift({
375
278
  filter: filter,
376
279
  replacement: this.keepReplacement
377
280
  });
378
281
  },
379
-
380
282
  remove: function (filter) {
381
283
  this._remove.unshift({
382
284
  filter: filter,
383
285
  replacement: function () {
384
- return ''
286
+ return '';
385
287
  }
386
288
  });
387
289
  },
388
-
389
290
  forNode: function (node) {
390
- if (node.isBlank) return this.blankRule
291
+ if (node.isBlank) return this.blankRule;
391
292
  var rule;
392
-
393
- if ((rule = findRule(this.array, node, this.options))) return rule
394
- if ((rule = findRule(this._keep, node, this.options))) return rule
395
- if ((rule = findRule(this._remove, node, this.options))) return rule
396
-
397
- return this.defaultRule
293
+ if (rule = findRule(this.array, node, this.options)) return rule;
294
+ if (rule = findRule(this._keep, node, this.options)) return rule;
295
+ if (rule = findRule(this._remove, node, this.options)) return rule;
296
+ return this.defaultRule;
398
297
  },
399
-
400
298
  forEach: function (fn) {
401
299
  for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
402
300
  }
403
301
  };
404
-
405
- function findRule (rules, node, options) {
302
+ function findRule(rules, node, options) {
406
303
  for (var i = 0; i < rules.length; i++) {
407
304
  var rule = rules[i];
408
- if (filterValue(rule, node, options)) return rule
305
+ if (filterValue(rule, node, options)) return rule;
409
306
  }
410
- return void 0
307
+ return undefined;
411
308
  }
412
-
413
- function filterValue (rule, node, options) {
309
+ function filterValue(rule, node, options) {
414
310
  var filter = rule.filter;
415
311
  if (typeof filter === 'string') {
416
- if (filter === node.nodeName.toLowerCase()) return true
312
+ if (filter === node.nodeName.toLowerCase()) return true;
417
313
  } else if (Array.isArray(filter)) {
418
- if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
314
+ if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true;
419
315
  } else if (typeof filter === 'function') {
420
- if (filter.call(rule, node, options)) return true
316
+ if (filter.call(rule, node, options)) return true;
421
317
  } else {
422
- throw new TypeError('`filter` needs to be a string, array, or function')
318
+ throw new TypeError('`filter` needs to be a string, array, or function');
423
319
  }
424
320
  }
425
321
 
@@ -455,46 +351,39 @@ var TurndownService = (function () {
455
351
  *
456
352
  * @param {Object} options
457
353
  */
458
- function collapseWhitespace (options) {
354
+ function collapseWhitespace(options) {
459
355
  var element = options.element;
460
356
  var isBlock = options.isBlock;
461
357
  var isVoid = options.isVoid;
462
358
  var isPre = options.isPre || function (node) {
463
- return node.nodeName === 'PRE'
359
+ return node.nodeName === 'PRE';
464
360
  };
465
-
466
- if (!element.firstChild || isPre(element)) return
467
-
361
+ if (!element.firstChild || isPre(element)) return;
468
362
  var prevText = null;
469
363
  var keepLeadingWs = false;
470
-
471
364
  var prev = null;
472
365
  var node = next(prev, element, isPre);
473
-
474
366
  while (node !== element) {
475
- if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
367
+ if (node.nodeType === 3 || node.nodeType === 4) {
368
+ // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
476
369
  var text = node.data.replace(/[ \r\n\t]+/g, ' ');
477
-
478
- if ((!prevText || / $/.test(prevText.data)) &&
479
- !keepLeadingWs && text[0] === ' ') {
370
+ if ((!prevText || / $/.test(prevText.data)) && !keepLeadingWs && text[0] === ' ') {
480
371
  text = text.substr(1);
481
372
  }
482
373
 
483
374
  // `text` might be empty at this point.
484
375
  if (!text) {
485
376
  node = remove(node);
486
- continue
377
+ continue;
487
378
  }
488
-
489
379
  node.data = text;
490
-
491
380
  prevText = node;
492
- } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
381
+ } else if (node.nodeType === 1) {
382
+ // Node.ELEMENT_NODE
493
383
  if (isBlock(node) || node.nodeName === 'BR') {
494
384
  if (prevText) {
495
385
  prevText.data = prevText.data.replace(/ $/, '');
496
386
  }
497
-
498
387
  prevText = null;
499
388
  keepLeadingWs = false;
500
389
  } else if (isVoid(node) || isPre(node)) {
@@ -507,14 +396,12 @@ var TurndownService = (function () {
507
396
  }
508
397
  } else {
509
398
  node = remove(node);
510
- continue
399
+ continue;
511
400
  }
512
-
513
401
  var nextNode = next(prev, node, isPre);
514
402
  prev = node;
515
403
  node = nextNode;
516
404
  }
517
-
518
405
  if (prevText) {
519
406
  prevText.data = prevText.data.replace(/ $/, '');
520
407
  if (!prevText.data) {
@@ -530,12 +417,10 @@ var TurndownService = (function () {
530
417
  * @param {Node} node
531
418
  * @return {Node} node
532
419
  */
533
- function remove (node) {
420
+ function remove(node) {
534
421
  var next = node.nextSibling || node.parentNode;
535
-
536
422
  node.parentNode.removeChild(node);
537
-
538
- return next
423
+ return next;
539
424
  }
540
425
 
541
426
  /**
@@ -547,25 +432,24 @@ var TurndownService = (function () {
547
432
  * @param {Function} isPre
548
433
  * @return {Node}
549
434
  */
550
- function next (prev, current, isPre) {
551
- if ((prev && prev.parentNode === current) || isPre(current)) {
552
- return current.nextSibling || current.parentNode
435
+ function next(prev, current, isPre) {
436
+ if (prev && prev.parentNode === current || isPre(current)) {
437
+ return current.nextSibling || current.parentNode;
553
438
  }
554
-
555
- return current.firstChild || current.nextSibling || current.parentNode
439
+ return current.firstChild || current.nextSibling || current.parentNode;
556
440
  }
557
441
 
558
442
  /*
559
443
  * Set up window for Node.js
560
444
  */
561
445
 
562
- var root = (typeof window !== 'undefined' ? window : {});
446
+ var root = typeof window !== 'undefined' ? window : {};
563
447
 
564
448
  /*
565
449
  * Parsing HTML strings
566
450
  */
567
451
 
568
- function canParseHTMLNatively () {
452
+ function canParseHTMLNatively() {
569
453
  var Parser = root.DOMParser;
570
454
  var canParse = false;
571
455
 
@@ -577,13 +461,10 @@ var TurndownService = (function () {
577
461
  canParse = true;
578
462
  }
579
463
  } catch (e) {}
580
-
581
- return canParse
464
+ return canParse;
582
465
  }
583
-
584
- function createHTMLParser () {
466
+ function createHTMLParser() {
585
467
  var Parser = function () {};
586
-
587
468
  {
588
469
  if (shouldUseActiveX()) {
589
470
  Parser.prototype.parseFromString = function (string) {
@@ -592,7 +473,7 @@ var TurndownService = (function () {
592
473
  doc.open();
593
474
  doc.write(string);
594
475
  doc.close();
595
- return doc
476
+ return doc;
596
477
  };
597
478
  } else {
598
479
  Parser.prototype.parseFromString = function (string) {
@@ -600,35 +481,31 @@ var TurndownService = (function () {
600
481
  doc.open();
601
482
  doc.write(string);
602
483
  doc.close();
603
- return doc
484
+ return doc;
604
485
  };
605
486
  }
606
487
  }
607
- return Parser
488
+ return Parser;
608
489
  }
609
-
610
- function shouldUseActiveX () {
490
+ function shouldUseActiveX() {
611
491
  var useActiveX = false;
612
492
  try {
613
493
  document.implementation.createHTMLDocument('').open();
614
494
  } catch (e) {
615
495
  if (root.ActiveXObject) useActiveX = true;
616
496
  }
617
- return useActiveX
497
+ return useActiveX;
618
498
  }
619
-
620
499
  var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
621
500
 
622
- function RootNode (input, options) {
501
+ function RootNode(input, options) {
623
502
  var root;
624
503
  if (typeof input === 'string') {
625
504
  var doc = htmlParser().parseFromString(
626
- // DOM parsers arrange elements in the <head> and <body>.
627
- // Wrapping in a custom element ensures elements are reliably arranged in
628
- // a single element.
629
- '<x-turndown id="turndown-root">' + input + '</x-turndown>',
630
- 'text/html'
631
- );
505
+ // DOM parsers arrange elements in the <head> and <body>.
506
+ // Wrapping in a custom element ensures elements are reliably arranged in
507
+ // a single element.
508
+ '<x-turndown id="turndown-root">' + input + '</x-turndown>', 'text/html');
632
509
  root = doc.getElementById('turndown-root');
633
510
  } else {
634
511
  root = input.cloneNode(true);
@@ -639,43 +516,34 @@ var TurndownService = (function () {
639
516
  isVoid: isVoid,
640
517
  isPre: options.preformattedCode ? isPreOrCode : null
641
518
  });
642
-
643
- return root
519
+ return root;
644
520
  }
645
-
646
521
  var _htmlParser;
647
- function htmlParser () {
522
+ function htmlParser() {
648
523
  _htmlParser = _htmlParser || new HTMLParser();
649
- return _htmlParser
524
+ return _htmlParser;
650
525
  }
651
-
652
- function isPreOrCode (node) {
653
- return node.nodeName === 'PRE' || node.nodeName === 'CODE'
526
+ function isPreOrCode(node) {
527
+ return node.nodeName === 'PRE' || node.nodeName === 'CODE';
654
528
  }
655
529
 
656
- function Node (node, options) {
530
+ function Node(node, options) {
657
531
  node.isBlock = isBlock(node);
658
532
  node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode;
659
533
  node.isBlank = isBlank(node);
660
534
  node.flankingWhitespace = flankingWhitespace(node, options);
661
- return node
535
+ return node;
662
536
  }
663
-
664
- function isBlank (node) {
665
- return (
666
- !isVoid(node) &&
667
- !isMeaningfulWhenBlank(node) &&
668
- /^\s*$/i.test(node.textContent) &&
669
- !hasVoid(node) &&
670
- !hasMeaningfulWhenBlank(node)
671
- )
537
+ function isBlank(node) {
538
+ return !isVoid(node) && !isMeaningfulWhenBlank(node) && /^\s*$/i.test(node.textContent) && !hasVoid(node) && !hasMeaningfulWhenBlank(node);
672
539
  }
673
-
674
- function flankingWhitespace (node, options) {
675
- if (node.isBlock || (options.preformattedCode && node.isCode)) {
676
- return { leading: '', trailing: '' }
540
+ function flankingWhitespace(node, options) {
541
+ if (node.isBlock || options.preformattedCode && node.isCode) {
542
+ return {
543
+ leading: '',
544
+ trailing: ''
545
+ };
677
546
  }
678
-
679
547
  var edges = edgeWhitespace(node.textContent);
680
548
 
681
549
  // abandon leading ASCII WS if left-flanked by ASCII WS
@@ -687,27 +555,28 @@ var TurndownService = (function () {
687
555
  if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {
688
556
  edges.trailing = edges.trailingNonAscii;
689
557
  }
690
-
691
- return { leading: edges.leading, trailing: edges.trailing }
558
+ return {
559
+ leading: edges.leading,
560
+ trailing: edges.trailing
561
+ };
692
562
  }
693
-
694
- function edgeWhitespace (string) {
563
+ function edgeWhitespace(string) {
695
564
  var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);
696
565
  return {
697
- leading: m[1], // whole string for whitespace-only strings
566
+ leading: m[1],
567
+ // whole string for whitespace-only strings
698
568
  leadingAscii: m[2],
699
569
  leadingNonAscii: m[3],
700
- trailing: m[4], // empty for whitespace-only strings
570
+ trailing: m[4],
571
+ // empty for whitespace-only strings
701
572
  trailingNonAscii: m[5],
702
573
  trailingAscii: m[6]
703
- }
574
+ };
704
575
  }
705
-
706
- function isFlankedByWhitespace (side, node, options) {
576
+ function isFlankedByWhitespace(side, node, options) {
707
577
  var sibling;
708
578
  var regExp;
709
579
  var isFlanked;
710
-
711
580
  if (side === 'left') {
712
581
  sibling = node.previousSibling;
713
582
  regExp = / $/;
@@ -715,7 +584,6 @@ var TurndownService = (function () {
715
584
  sibling = node.nextSibling;
716
585
  regExp = /^ /;
717
586
  }
718
-
719
587
  if (sibling) {
720
588
  if (sibling.nodeType === 3) {
721
589
  isFlanked = regExp.test(sibling.nodeValue);
@@ -725,29 +593,12 @@ var TurndownService = (function () {
725
593
  isFlanked = regExp.test(sibling.textContent);
726
594
  }
727
595
  }
728
- return isFlanked
596
+ return isFlanked;
729
597
  }
730
598
 
731
599
  var reduce = Array.prototype.reduce;
732
- var escapes = [
733
- [/\\/g, '\\\\'],
734
- [/\*/g, '\\*'],
735
- [/^-/g, '\\-'],
736
- [/^\+ /g, '\\+ '],
737
- [/^(=+)/g, '\\$1'],
738
- [/^(#{1,6}) /g, '\\$1 '],
739
- [/`/g, '\\`'],
740
- [/^~~~/g, '\\~~~'],
741
- [/\[/g, '\\['],
742
- [/\]/g, '\\]'],
743
- [/^>/g, '\\>'],
744
- [/_/g, '\\_'],
745
- [/^(\d+)\. /g, '$1\\. ']
746
- ];
747
-
748
- function TurndownService (options) {
749
- if (!(this instanceof TurndownService)) return new TurndownService(options)
750
-
600
+ function TurndownService(options) {
601
+ if (!(this instanceof TurndownService)) return new TurndownService(options);
751
602
  var defaults = {
752
603
  rules: rules,
753
604
  headingStyle: 'setext',
@@ -762,19 +613,18 @@ var TurndownService = (function () {
762
613
  br: ' ',
763
614
  preformattedCode: false,
764
615
  blankReplacement: function (content, node) {
765
- return node.isBlock ? '\n\n' : ''
616
+ return node.isBlock ? '\n\n' : '';
766
617
  },
767
618
  keepReplacement: function (content, node) {
768
- return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
619
+ return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML;
769
620
  },
770
621
  defaultReplacement: function (content, node) {
771
- return node.isBlock ? '\n\n' + content + '\n\n' : content
622
+ return node.isBlock ? '\n\n' + content + '\n\n' : content;
772
623
  }
773
624
  };
774
625
  this.options = extend({}, defaults, options);
775
626
  this.rules = new Rules(this.options);
776
627
  }
777
-
778
628
  TurndownService.prototype = {
779
629
  /**
780
630
  * The entry point for converting a string or DOM node to Markdown
@@ -786,17 +636,12 @@ var TurndownService = (function () {
786
636
 
787
637
  turndown: function (input) {
788
638
  if (!canConvert(input)) {
789
- throw new TypeError(
790
- input + ' is not a string, or an element/document/fragment node.'
791
- )
639
+ throw new TypeError(input + ' is not a string, or an element/document/fragment node.');
792
640
  }
793
-
794
- if (input === '') return ''
795
-
641
+ if (input === '') return '';
796
642
  var output = process.call(this, new RootNode(input, this.options));
797
- return postProcess.call(this, output)
643
+ return postProcess.call(this, output);
798
644
  },
799
-
800
645
  /**
801
646
  * Add one or more plugins
802
647
  * @public
@@ -811,11 +656,10 @@ var TurndownService = (function () {
811
656
  } else if (typeof plugin === 'function') {
812
657
  plugin(this);
813
658
  } else {
814
- throw new TypeError('plugin must be a Function or an Array of Functions')
659
+ throw new TypeError('plugin must be a Function or an Array of Functions');
815
660
  }
816
- return this
661
+ return this;
817
662
  },
818
-
819
663
  /**
820
664
  * Adds a rule
821
665
  * @public
@@ -827,9 +671,8 @@ var TurndownService = (function () {
827
671
 
828
672
  addRule: function (key, rule) {
829
673
  this.rules.add(key, rule);
830
- return this
674
+ return this;
831
675
  },
832
-
833
676
  /**
834
677
  * Keep a node (as HTML) that matches the filter
835
678
  * @public
@@ -840,9 +683,8 @@ var TurndownService = (function () {
840
683
 
841
684
  keep: function (filter) {
842
685
  this.rules.keep(filter);
843
- return this
686
+ return this;
844
687
  },
845
-
846
688
  /**
847
689
  * Remove a node that matches the filter
848
690
  * @public
@@ -853,9 +695,8 @@ var TurndownService = (function () {
853
695
 
854
696
  remove: function (filter) {
855
697
  this.rules.remove(filter);
856
- return this
698
+ return this;
857
699
  },
858
-
859
700
  /**
860
701
  * Escapes Markdown syntax
861
702
  * @public
@@ -865,9 +706,7 @@ var TurndownService = (function () {
865
706
  */
866
707
 
867
708
  escape: function (string) {
868
- return escapes.reduce(function (accumulator, escape) {
869
- return accumulator.replace(escape[0], escape[1])
870
- }, string)
709
+ return escapeMarkdown(string);
871
710
  }
872
711
  };
873
712
 
@@ -879,20 +718,18 @@ var TurndownService = (function () {
879
718
  * @type String
880
719
  */
881
720
 
882
- function process (parentNode) {
721
+ function process(parentNode) {
883
722
  var self = this;
884
723
  return reduce.call(parentNode.childNodes, function (output, node) {
885
724
  node = new Node(node, self.options);
886
-
887
725
  var replacement = '';
888
726
  if (node.nodeType === 3) {
889
727
  replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
890
728
  } else if (node.nodeType === 1) {
891
729
  replacement = replacementForNode.call(self, node);
892
730
  }
893
-
894
- return join(output, replacement)
895
- }, '')
731
+ return join(output, replacement);
732
+ }, '');
896
733
  }
897
734
 
898
735
  /**
@@ -903,15 +740,14 @@ var TurndownService = (function () {
903
740
  * @type String
904
741
  */
905
742
 
906
- function postProcess (output) {
743
+ function postProcess(output) {
907
744
  var self = this;
908
745
  this.rules.forEach(function (rule) {
909
746
  if (typeof rule.append === 'function') {
910
747
  output = join(output, rule.append(self.options));
911
748
  }
912
749
  });
913
-
914
- return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
750
+ return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '');
915
751
  }
916
752
 
917
753
  /**
@@ -922,16 +758,12 @@ var TurndownService = (function () {
922
758
  * @type String
923
759
  */
924
760
 
925
- function replacementForNode (node) {
761
+ function replacementForNode(node) {
926
762
  var rule = this.rules.forNode(node);
927
763
  var content = process.call(this, node);
928
764
  var whitespace = node.flankingWhitespace;
929
765
  if (whitespace.leading || whitespace.trailing) content = content.trim();
930
- return (
931
- whitespace.leading +
932
- rule.replacement(content, node, this.options) +
933
- whitespace.trailing
934
- )
766
+ return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
935
767
  }
936
768
 
937
769
  /**
@@ -943,13 +775,12 @@ var TurndownService = (function () {
943
775
  * @type String
944
776
  */
945
777
 
946
- function join (output, replacement) {
778
+ function join(output, replacement) {
947
779
  var s1 = trimTrailingNewlines(output);
948
780
  var s2 = trimLeadingNewlines(replacement);
949
781
  var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
950
782
  var separator = '\n\n'.substring(0, nls);
951
-
952
- return s1 + separator + s2
783
+ return s1 + separator + s2;
953
784
  }
954
785
 
955
786
  /**
@@ -960,17 +791,10 @@ var TurndownService = (function () {
960
791
  * @type String|Object|Array|Boolean|Number
961
792
  */
962
793
 
963
- function canConvert (input) {
964
- return (
965
- input != null && (
966
- typeof input === 'string' ||
967
- (input.nodeType && (
968
- input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
969
- ))
970
- )
971
- )
794
+ function canConvert(input) {
795
+ return input != null && (typeof input === 'string' || input.nodeType && (input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11));
972
796
  }
973
797
 
974
798
  return TurndownService;
975
799
 
976
- }());
800
+ })();