draftwatch 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,800 @@
1
+ var TurndownService = (function () {
2
+ 'use strict';
3
+
4
+ function extend(destination) {
5
+ for (var i = 1; i < arguments.length; i++) {
6
+ var source = arguments[i];
7
+ for (var key in source) {
8
+ if (Object.prototype.hasOwnProperty.call(source, key)) destination[key] = source[key];
9
+ }
10
+ }
11
+ return destination;
12
+ }
13
+ function repeat(character, count) {
14
+ return Array(count + 1).join(character);
15
+ }
16
+ function trimLeadingNewlines(string) {
17
+ return string.replace(/^\n*/, '');
18
+ }
19
+ function trimTrailingNewlines(string) {
20
+ // avoid match-at-end regexp bottleneck, see #370
21
+ var indexEnd = string.length;
22
+ while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--;
23
+ return string.substring(0, indexEnd);
24
+ }
25
+ function trimNewlines(string) {
26
+ return trimTrailingNewlines(trimLeadingNewlines(string));
27
+ }
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);
31
+ }
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);
35
+ }
36
+ function hasVoid(node) {
37
+ return has(node, voidElements);
38
+ }
39
+ var meaningfulWhenBlankElements = ['A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT', 'AUDIO', 'VIDEO'];
40
+ function isMeaningfulWhenBlank(node) {
41
+ return is(node, meaningfulWhenBlankElements);
42
+ }
43
+ function hasMeaningfulWhenBlank(node) {
44
+ return has(node, meaningfulWhenBlankElements);
45
+ }
46
+ function is(node, tagNames) {
47
+ return tagNames.indexOf(node.nodeName) >= 0;
48
+ }
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);
59
+ }
60
+
61
+ var rules = {};
62
+ rules.paragraph = {
63
+ filter: 'p',
64
+ replacement: function (content) {
65
+ return '\n\n' + content + '\n\n';
66
+ }
67
+ };
68
+ rules.lineBreak = {
69
+ filter: 'br',
70
+ replacement: function (content, node, options) {
71
+ return options.br + '\n';
72
+ }
73
+ };
74
+ rules.heading = {
75
+ filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
76
+ replacement: function (content, node, options) {
77
+ var hLevel = Number(node.nodeName.charAt(1));
78
+ if (options.headingStyle === 'setext' && hLevel < 3) {
79
+ var underline = repeat(hLevel === 1 ? '=' : '-', content.length);
80
+ return '\n\n' + content + '\n' + underline + '\n\n';
81
+ } else {
82
+ return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n';
83
+ }
84
+ }
85
+ };
86
+ rules.blockquote = {
87
+ filter: 'blockquote',
88
+ replacement: function (content) {
89
+ content = trimNewlines(content).replace(/^/gm, '> ');
90
+ return '\n\n' + content + '\n\n';
91
+ }
92
+ };
93
+ rules.list = {
94
+ filter: ['ul', 'ol'],
95
+ replacement: function (content, node) {
96
+ var parent = node.parentNode;
97
+ if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
98
+ return '\n' + content;
99
+ } else {
100
+ return '\n\n' + content + '\n\n';
101
+ }
102
+ }
103
+ };
104
+ rules.listItem = {
105
+ filter: 'li',
106
+ replacement: function (content, node, options) {
107
+ var prefix = options.bulletListMarker + ' ';
108
+ var parent = node.parentNode;
109
+ if (parent.nodeName === 'OL') {
110
+ var start = parent.getAttribute('start');
111
+ var index = Array.prototype.indexOf.call(parent.children, node);
112
+ prefix = (start ? Number(start) + index : index + 1) + '. ';
113
+ }
114
+ var isParagraph = /\n$/.test(content);
115
+ content = trimNewlines(content) + (isParagraph ? '\n' : '');
116
+ content = content.replace(/\n/gm, '\n' + ' '.repeat(prefix.length)); // indent
117
+ return prefix + content + (node.nextSibling ? '\n' : '');
118
+ }
119
+ };
120
+ rules.indentedCodeBlock = {
121
+ filter: function (node, options) {
122
+ return options.codeBlockStyle === 'indented' && node.nodeName === 'PRE' && node.firstChild && node.firstChild.nodeName === 'CODE';
123
+ },
124
+ replacement: function (content, node, options) {
125
+ return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n';
126
+ }
127
+ };
128
+ rules.fencedCodeBlock = {
129
+ filter: function (node, options) {
130
+ return options.codeBlockStyle === 'fenced' && node.nodeName === 'PRE' && node.firstChild && node.firstChild.nodeName === 'CODE';
131
+ },
132
+ replacement: function (content, node, options) {
133
+ var className = node.firstChild.getAttribute('class') || '';
134
+ var language = (className.match(/language-(\S+)/) || [null, ''])[1];
135
+ var code = node.firstChild.textContent;
136
+ var fenceChar = options.fence.charAt(0);
137
+ var fenceSize = 3;
138
+ var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');
139
+ var match;
140
+ while (match = fenceInCodeRegex.exec(code)) {
141
+ if (match[0].length >= fenceSize) {
142
+ fenceSize = match[0].length + 1;
143
+ }
144
+ }
145
+ var fence = repeat(fenceChar, fenceSize);
146
+ return '\n\n' + fence + language + '\n' + code.replace(/\n$/, '') + '\n' + fence + '\n\n';
147
+ }
148
+ };
149
+ rules.horizontalRule = {
150
+ filter: 'hr',
151
+ replacement: function (content, node, options) {
152
+ return '\n\n' + options.hr + '\n\n';
153
+ }
154
+ };
155
+ rules.inlineLink = {
156
+ filter: function (node, options) {
157
+ return options.linkStyle === 'inlined' && node.nodeName === 'A' && node.getAttribute('href');
158
+ },
159
+ replacement: function (content, node) {
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 + ')';
164
+ }
165
+ };
166
+ rules.referenceLink = {
167
+ filter: function (node, options) {
168
+ return options.linkStyle === 'referenced' && node.nodeName === 'A' && node.getAttribute('href');
169
+ },
170
+ replacement: function (content, node, options) {
171
+ var href = escapeLinkDestination(node.getAttribute('href'));
172
+ var title = cleanAttribute(node.getAttribute('title'));
173
+ if (title) title = ' "' + escapeLinkTitle(title) + '"';
174
+ var replacement;
175
+ var reference;
176
+ switch (options.linkReferenceStyle) {
177
+ case 'collapsed':
178
+ replacement = '[' + content + '][]';
179
+ reference = '[' + content + ']: ' + href + title;
180
+ break;
181
+ case 'shortcut':
182
+ replacement = '[' + content + ']';
183
+ reference = '[' + content + ']: ' + href + title;
184
+ break;
185
+ default:
186
+ var id = this.references.length + 1;
187
+ replacement = '[' + content + '][' + id + ']';
188
+ reference = '[' + id + ']: ' + href + title;
189
+ }
190
+ this.references.push(reference);
191
+ return replacement;
192
+ },
193
+ references: [],
194
+ append: function (options) {
195
+ var references = '';
196
+ if (this.references.length) {
197
+ references = '\n\n' + this.references.join('\n') + '\n\n';
198
+ this.references = []; // Reset references
199
+ }
200
+ return references;
201
+ }
202
+ };
203
+ rules.emphasis = {
204
+ filter: ['em', 'i'],
205
+ replacement: function (content, node, options) {
206
+ if (!content.trim()) return '';
207
+ return options.emDelimiter + content + options.emDelimiter;
208
+ }
209
+ };
210
+ rules.strong = {
211
+ filter: ['strong', 'b'],
212
+ replacement: function (content, node, options) {
213
+ if (!content.trim()) return '';
214
+ return options.strongDelimiter + content + options.strongDelimiter;
215
+ }
216
+ };
217
+ rules.code = {
218
+ filter: function (node) {
219
+ var hasSiblings = node.previousSibling || node.nextSibling;
220
+ var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
221
+ return node.nodeName === 'CODE' && !isCodeBlock;
222
+ },
223
+ replacement: function (content) {
224
+ if (!content) return '';
225
+ content = content.replace(/\r?\n|\r/g, ' ');
226
+ var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : '';
227
+ var delimiter = '`';
228
+ var matches = content.match(/`+/gm) || [];
229
+ while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
230
+ return delimiter + extraSpace + content + extraSpace + delimiter;
231
+ }
232
+ };
233
+ rules.image = {
234
+ filter: 'img',
235
+ replacement: function (content, node) {
236
+ var alt = escapeMarkdown(cleanAttribute(node.getAttribute('alt')));
237
+ var src = escapeLinkDestination(node.getAttribute('src') || '');
238
+ var title = cleanAttribute(node.getAttribute('title'));
239
+ var titlePart = title ? ' "' + escapeLinkTitle(title) + '"' : '';
240
+ return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '';
241
+ }
242
+ };
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, '\\"');
252
+ }
253
+
254
+ /**
255
+ * Manages a collection of rules used to convert HTML to Markdown
256
+ */
257
+
258
+ function Rules(options) {
259
+ this.options = options;
260
+ this._keep = [];
261
+ this._remove = [];
262
+ this.blankRule = {
263
+ replacement: options.blankReplacement
264
+ };
265
+ this.keepReplacement = options.keepReplacement;
266
+ this.defaultRule = {
267
+ replacement: options.defaultReplacement
268
+ };
269
+ this.array = [];
270
+ for (var key in options.rules) this.array.push(options.rules[key]);
271
+ }
272
+ Rules.prototype = {
273
+ add: function (key, rule) {
274
+ this.array.unshift(rule);
275
+ },
276
+ keep: function (filter) {
277
+ this._keep.unshift({
278
+ filter: filter,
279
+ replacement: this.keepReplacement
280
+ });
281
+ },
282
+ remove: function (filter) {
283
+ this._remove.unshift({
284
+ filter: filter,
285
+ replacement: function () {
286
+ return '';
287
+ }
288
+ });
289
+ },
290
+ forNode: function (node) {
291
+ if (node.isBlank) return this.blankRule;
292
+ var rule;
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;
297
+ },
298
+ forEach: function (fn) {
299
+ for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
300
+ }
301
+ };
302
+ function findRule(rules, node, options) {
303
+ for (var i = 0; i < rules.length; i++) {
304
+ var rule = rules[i];
305
+ if (filterValue(rule, node, options)) return rule;
306
+ }
307
+ return undefined;
308
+ }
309
+ function filterValue(rule, node, options) {
310
+ var filter = rule.filter;
311
+ if (typeof filter === 'string') {
312
+ if (filter === node.nodeName.toLowerCase()) return true;
313
+ } else if (Array.isArray(filter)) {
314
+ if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true;
315
+ } else if (typeof filter === 'function') {
316
+ if (filter.call(rule, node, options)) return true;
317
+ } else {
318
+ throw new TypeError('`filter` needs to be a string, array, or function');
319
+ }
320
+ }
321
+
322
+ /**
323
+ * The collapseWhitespace function is adapted from collapse-whitespace
324
+ * by Luc Thevenard.
325
+ *
326
+ * The MIT License (MIT)
327
+ *
328
+ * Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>
329
+ *
330
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
331
+ * of this software and associated documentation files (the "Software"), to deal
332
+ * in the Software without restriction, including without limitation the rights
333
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
334
+ * copies of the Software, and to permit persons to whom the Software is
335
+ * furnished to do so, subject to the following conditions:
336
+ *
337
+ * The above copyright notice and this permission notice shall be included in
338
+ * all copies or substantial portions of the Software.
339
+ *
340
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
341
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
342
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
343
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
344
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
345
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
346
+ * THE SOFTWARE.
347
+ */
348
+
349
+ /**
350
+ * collapseWhitespace(options) removes extraneous whitespace from an the given element.
351
+ *
352
+ * @param {Object} options
353
+ */
354
+ function collapseWhitespace(options) {
355
+ var element = options.element;
356
+ var isBlock = options.isBlock;
357
+ var isVoid = options.isVoid;
358
+ var isPre = options.isPre || function (node) {
359
+ return node.nodeName === 'PRE';
360
+ };
361
+ if (!element.firstChild || isPre(element)) return;
362
+ var prevText = null;
363
+ var keepLeadingWs = false;
364
+ var prev = null;
365
+ var node = next(prev, element, isPre);
366
+ while (node !== element) {
367
+ if (node.nodeType === 3 || node.nodeType === 4) {
368
+ // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
369
+ var text = node.data.replace(/[ \r\n\t]+/g, ' ');
370
+ if ((!prevText || / $/.test(prevText.data)) && !keepLeadingWs && text[0] === ' ') {
371
+ text = text.substr(1);
372
+ }
373
+
374
+ // `text` might be empty at this point.
375
+ if (!text) {
376
+ node = remove(node);
377
+ continue;
378
+ }
379
+ node.data = text;
380
+ prevText = node;
381
+ } else if (node.nodeType === 1) {
382
+ // Node.ELEMENT_NODE
383
+ if (isBlock(node) || node.nodeName === 'BR') {
384
+ if (prevText) {
385
+ prevText.data = prevText.data.replace(/ $/, '');
386
+ }
387
+ prevText = null;
388
+ keepLeadingWs = false;
389
+ } else if (isVoid(node) || isPre(node)) {
390
+ // Avoid trimming space around non-block, non-BR void elements and inline PRE.
391
+ prevText = null;
392
+ keepLeadingWs = true;
393
+ } else if (prevText) {
394
+ // Drop protection if set previously.
395
+ keepLeadingWs = false;
396
+ }
397
+ } else {
398
+ node = remove(node);
399
+ continue;
400
+ }
401
+ var nextNode = next(prev, node, isPre);
402
+ prev = node;
403
+ node = nextNode;
404
+ }
405
+ if (prevText) {
406
+ prevText.data = prevText.data.replace(/ $/, '');
407
+ if (!prevText.data) {
408
+ remove(prevText);
409
+ }
410
+ }
411
+ }
412
+
413
+ /**
414
+ * remove(node) removes the given node from the DOM and returns the
415
+ * next node in the sequence.
416
+ *
417
+ * @param {Node} node
418
+ * @return {Node} node
419
+ */
420
+ function remove(node) {
421
+ var next = node.nextSibling || node.parentNode;
422
+ node.parentNode.removeChild(node);
423
+ return next;
424
+ }
425
+
426
+ /**
427
+ * next(prev, current, isPre) returns the next node in the sequence, given the
428
+ * current and previous nodes.
429
+ *
430
+ * @param {Node} prev
431
+ * @param {Node} current
432
+ * @param {Function} isPre
433
+ * @return {Node}
434
+ */
435
+ function next(prev, current, isPre) {
436
+ if (prev && prev.parentNode === current || isPre(current)) {
437
+ return current.nextSibling || current.parentNode;
438
+ }
439
+ return current.firstChild || current.nextSibling || current.parentNode;
440
+ }
441
+
442
+ /*
443
+ * Set up window for Node.js
444
+ */
445
+
446
+ var root = typeof window !== 'undefined' ? window : {};
447
+
448
+ /*
449
+ * Parsing HTML strings
450
+ */
451
+
452
+ function canParseHTMLNatively() {
453
+ var Parser = root.DOMParser;
454
+ var canParse = false;
455
+
456
+ // Adapted from https://gist.github.com/1129031
457
+ // Firefox/Opera/IE throw errors on unsupported types
458
+ try {
459
+ // WebKit returns null on unsupported types
460
+ if (new Parser().parseFromString('', 'text/html')) {
461
+ canParse = true;
462
+ }
463
+ } catch (e) {}
464
+ return canParse;
465
+ }
466
+ function createHTMLParser() {
467
+ var Parser = function () {};
468
+ {
469
+ if (shouldUseActiveX()) {
470
+ Parser.prototype.parseFromString = function (string) {
471
+ var doc = new window.ActiveXObject('htmlfile');
472
+ doc.designMode = 'on'; // disable on-page scripts
473
+ doc.open();
474
+ doc.write(string);
475
+ doc.close();
476
+ return doc;
477
+ };
478
+ } else {
479
+ Parser.prototype.parseFromString = function (string) {
480
+ var doc = document.implementation.createHTMLDocument('');
481
+ doc.open();
482
+ doc.write(string);
483
+ doc.close();
484
+ return doc;
485
+ };
486
+ }
487
+ }
488
+ return Parser;
489
+ }
490
+ function shouldUseActiveX() {
491
+ var useActiveX = false;
492
+ try {
493
+ document.implementation.createHTMLDocument('').open();
494
+ } catch (e) {
495
+ if (root.ActiveXObject) useActiveX = true;
496
+ }
497
+ return useActiveX;
498
+ }
499
+ var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
500
+
501
+ function RootNode(input, options) {
502
+ var root;
503
+ if (typeof input === 'string') {
504
+ var doc = htmlParser().parseFromString(
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');
509
+ root = doc.getElementById('turndown-root');
510
+ } else {
511
+ root = input.cloneNode(true);
512
+ }
513
+ collapseWhitespace({
514
+ element: root,
515
+ isBlock: isBlock,
516
+ isVoid: isVoid,
517
+ isPre: options.preformattedCode ? isPreOrCode : null
518
+ });
519
+ return root;
520
+ }
521
+ var _htmlParser;
522
+ function htmlParser() {
523
+ _htmlParser = _htmlParser || new HTMLParser();
524
+ return _htmlParser;
525
+ }
526
+ function isPreOrCode(node) {
527
+ return node.nodeName === 'PRE' || node.nodeName === 'CODE';
528
+ }
529
+
530
+ function Node(node, options) {
531
+ node.isBlock = isBlock(node);
532
+ node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode;
533
+ node.isBlank = isBlank(node);
534
+ node.flankingWhitespace = flankingWhitespace(node, options);
535
+ return node;
536
+ }
537
+ function isBlank(node) {
538
+ return !isVoid(node) && !isMeaningfulWhenBlank(node) && /^\s*$/i.test(node.textContent) && !hasVoid(node) && !hasMeaningfulWhenBlank(node);
539
+ }
540
+ function flankingWhitespace(node, options) {
541
+ if (node.isBlock || options.preformattedCode && node.isCode) {
542
+ return {
543
+ leading: '',
544
+ trailing: ''
545
+ };
546
+ }
547
+ var edges = edgeWhitespace(node.textContent);
548
+
549
+ // abandon leading ASCII WS if left-flanked by ASCII WS
550
+ if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {
551
+ edges.leading = edges.leadingNonAscii;
552
+ }
553
+
554
+ // abandon trailing ASCII WS if right-flanked by ASCII WS
555
+ if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {
556
+ edges.trailing = edges.trailingNonAscii;
557
+ }
558
+ return {
559
+ leading: edges.leading,
560
+ trailing: edges.trailing
561
+ };
562
+ }
563
+ function edgeWhitespace(string) {
564
+ var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);
565
+ return {
566
+ leading: m[1],
567
+ // whole string for whitespace-only strings
568
+ leadingAscii: m[2],
569
+ leadingNonAscii: m[3],
570
+ trailing: m[4],
571
+ // empty for whitespace-only strings
572
+ trailingNonAscii: m[5],
573
+ trailingAscii: m[6]
574
+ };
575
+ }
576
+ function isFlankedByWhitespace(side, node, options) {
577
+ var sibling;
578
+ var regExp;
579
+ var isFlanked;
580
+ if (side === 'left') {
581
+ sibling = node.previousSibling;
582
+ regExp = / $/;
583
+ } else {
584
+ sibling = node.nextSibling;
585
+ regExp = /^ /;
586
+ }
587
+ if (sibling) {
588
+ if (sibling.nodeType === 3) {
589
+ isFlanked = regExp.test(sibling.nodeValue);
590
+ } else if (options.preformattedCode && sibling.nodeName === 'CODE') {
591
+ isFlanked = false;
592
+ } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
593
+ isFlanked = regExp.test(sibling.textContent);
594
+ }
595
+ }
596
+ return isFlanked;
597
+ }
598
+
599
+ var reduce = Array.prototype.reduce;
600
+ function TurndownService(options) {
601
+ if (!(this instanceof TurndownService)) return new TurndownService(options);
602
+ var defaults = {
603
+ rules: rules,
604
+ headingStyle: 'setext',
605
+ hr: '* * *',
606
+ bulletListMarker: '*',
607
+ codeBlockStyle: 'indented',
608
+ fence: '```',
609
+ emDelimiter: '_',
610
+ strongDelimiter: '**',
611
+ linkStyle: 'inlined',
612
+ linkReferenceStyle: 'full',
613
+ br: ' ',
614
+ preformattedCode: false,
615
+ blankReplacement: function (content, node) {
616
+ return node.isBlock ? '\n\n' : '';
617
+ },
618
+ keepReplacement: function (content, node) {
619
+ return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML;
620
+ },
621
+ defaultReplacement: function (content, node) {
622
+ return node.isBlock ? '\n\n' + content + '\n\n' : content;
623
+ }
624
+ };
625
+ this.options = extend({}, defaults, options);
626
+ this.rules = new Rules(this.options);
627
+ }
628
+ TurndownService.prototype = {
629
+ /**
630
+ * The entry point for converting a string or DOM node to Markdown
631
+ * @public
632
+ * @param {String|HTMLElement} input The string or DOM node to convert
633
+ * @returns A Markdown representation of the input
634
+ * @type String
635
+ */
636
+
637
+ turndown: function (input) {
638
+ if (!canConvert(input)) {
639
+ throw new TypeError(input + ' is not a string, or an element/document/fragment node.');
640
+ }
641
+ if (input === '') return '';
642
+ var output = process.call(this, new RootNode(input, this.options));
643
+ return postProcess.call(this, output);
644
+ },
645
+ /**
646
+ * Add one or more plugins
647
+ * @public
648
+ * @param {Function|Array} plugin The plugin or array of plugins to add
649
+ * @returns The Turndown instance for chaining
650
+ * @type Object
651
+ */
652
+
653
+ use: function (plugin) {
654
+ if (Array.isArray(plugin)) {
655
+ for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
656
+ } else if (typeof plugin === 'function') {
657
+ plugin(this);
658
+ } else {
659
+ throw new TypeError('plugin must be a Function or an Array of Functions');
660
+ }
661
+ return this;
662
+ },
663
+ /**
664
+ * Adds a rule
665
+ * @public
666
+ * @param {String} key The unique key of the rule
667
+ * @param {Object} rule The rule
668
+ * @returns The Turndown instance for chaining
669
+ * @type Object
670
+ */
671
+
672
+ addRule: function (key, rule) {
673
+ this.rules.add(key, rule);
674
+ return this;
675
+ },
676
+ /**
677
+ * Keep a node (as HTML) that matches the filter
678
+ * @public
679
+ * @param {String|Array|Function} filter The unique key of the rule
680
+ * @returns The Turndown instance for chaining
681
+ * @type Object
682
+ */
683
+
684
+ keep: function (filter) {
685
+ this.rules.keep(filter);
686
+ return this;
687
+ },
688
+ /**
689
+ * Remove a node that matches the filter
690
+ * @public
691
+ * @param {String|Array|Function} filter The unique key of the rule
692
+ * @returns The Turndown instance for chaining
693
+ * @type Object
694
+ */
695
+
696
+ remove: function (filter) {
697
+ this.rules.remove(filter);
698
+ return this;
699
+ },
700
+ /**
701
+ * Escapes Markdown syntax
702
+ * @public
703
+ * @param {String} string The string to escape
704
+ * @returns A string with Markdown syntax escaped
705
+ * @type String
706
+ */
707
+
708
+ escape: function (string) {
709
+ return escapeMarkdown(string);
710
+ }
711
+ };
712
+
713
+ /**
714
+ * Reduces a DOM node down to its Markdown string equivalent
715
+ * @private
716
+ * @param {HTMLElement} parentNode The node to convert
717
+ * @returns A Markdown representation of the node
718
+ * @type String
719
+ */
720
+
721
+ function process(parentNode) {
722
+ var self = this;
723
+ return reduce.call(parentNode.childNodes, function (output, node) {
724
+ node = new Node(node, self.options);
725
+ var replacement = '';
726
+ if (node.nodeType === 3) {
727
+ replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
728
+ } else if (node.nodeType === 1) {
729
+ replacement = replacementForNode.call(self, node);
730
+ }
731
+ return join(output, replacement);
732
+ }, '');
733
+ }
734
+
735
+ /**
736
+ * Appends strings as each rule requires and trims the output
737
+ * @private
738
+ * @param {String} output The conversion output
739
+ * @returns A trimmed version of the ouput
740
+ * @type String
741
+ */
742
+
743
+ function postProcess(output) {
744
+ var self = this;
745
+ this.rules.forEach(function (rule) {
746
+ if (typeof rule.append === 'function') {
747
+ output = join(output, rule.append(self.options));
748
+ }
749
+ });
750
+ return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '');
751
+ }
752
+
753
+ /**
754
+ * Converts an element node to its Markdown equivalent
755
+ * @private
756
+ * @param {HTMLElement} node The node to convert
757
+ * @returns A Markdown representation of the node
758
+ * @type String
759
+ */
760
+
761
+ function replacementForNode(node) {
762
+ var rule = this.rules.forNode(node);
763
+ var content = process.call(this, node);
764
+ var whitespace = node.flankingWhitespace;
765
+ if (whitespace.leading || whitespace.trailing) content = content.trim();
766
+ return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
767
+ }
768
+
769
+ /**
770
+ * Joins replacement to the current output with appropriate number of new lines
771
+ * @private
772
+ * @param {String} output The current conversion output
773
+ * @param {String} replacement The string to append to the output
774
+ * @returns Joined output
775
+ * @type String
776
+ */
777
+
778
+ function join(output, replacement) {
779
+ var s1 = trimTrailingNewlines(output);
780
+ var s2 = trimLeadingNewlines(replacement);
781
+ var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
782
+ var separator = '\n\n'.substring(0, nls);
783
+ return s1 + separator + s2;
784
+ }
785
+
786
+ /**
787
+ * Determines whether an input can be converted
788
+ * @private
789
+ * @param {String|HTMLElement} input Describe this parameter
790
+ * @returns Describe what it returns
791
+ * @type String|Object|Array|Boolean|Number
792
+ */
793
+
794
+ function canConvert(input) {
795
+ return input != null && (typeof input === 'string' || input.nodeType && (input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11));
796
+ }
797
+
798
+ return TurndownService;
799
+
800
+ })();