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