PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/files/to-markdown/1.3.0/to-markdown.js

https://gitlab.com/Mirros/jsdelivr
JavaScript | 759 lines | 558 code | 112 blank | 89 comment | 92 complexity | 8134cb0fdc13bc9df4a934a3bd3958e6 MD5 | raw file
  1. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.toMarkdown = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. /*
  3. * to-markdown - an HTML to Markdown converter
  4. *
  5. * Copyright 2011-15, Dom Christie
  6. * Licenced under the MIT licence
  7. *
  8. */
  9. 'use strict';
  10. var toMarkdown;
  11. var converters;
  12. var mdConverters = require('./lib/md-converters');
  13. var gfmConverters = require('./lib/gfm-converters');
  14. var collapse = require('collapse-whitespace');
  15. /*
  16. * Set up window and document for Node.js
  17. */
  18. var _window = (typeof window !== 'undefined' ? window : this), _document;
  19. if (typeof document === 'undefined') {
  20. _document = require('jsdom').jsdom();
  21. }
  22. else {
  23. _document = document;
  24. }
  25. /*
  26. * Utilities
  27. */
  28. function trim(string) {
  29. return string.replace(/^[ \r\n\t]+|[ \r\n\t]+$/g, '');
  30. }
  31. var blocks = ['address', 'article', 'aside', 'audio', 'blockquote', 'body',
  32. 'canvas', 'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
  33. 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4','h5', 'h6',
  34. 'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
  35. 'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
  36. 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
  37. ];
  38. function isBlock(node) {
  39. return blocks.indexOf(node.nodeName.toLowerCase()) !== -1;
  40. }
  41. var voids = [
  42. 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
  43. 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
  44. ];
  45. function isVoid(node) {
  46. return voids.indexOf(node.nodeName.toLowerCase()) !== -1;
  47. }
  48. /*
  49. * Parsing HTML strings
  50. */
  51. function canParseHtml() {
  52. var Parser = _window.DOMParser, canParse = false;
  53. // Adapted from https://gist.github.com/1129031
  54. // Firefox/Opera/IE throw errors on unsupported types
  55. try {
  56. // WebKit returns null on unsupported types
  57. if (new Parser().parseFromString('', 'text/html')) {
  58. canParse = true;
  59. }
  60. } catch (e) {}
  61. return canParse;
  62. }
  63. function createHtmlParser() {
  64. var Parser = function () {};
  65. Parser.prototype.parseFromString = function (string) {
  66. var newDoc = _document.implementation.createHTMLDocument('');
  67. if (string.toLowerCase().indexOf('<!doctype') > -1) {
  68. newDoc.documentElement.innerHTML = string;
  69. }
  70. else {
  71. newDoc.body.innerHTML = string;
  72. }
  73. return newDoc;
  74. };
  75. return Parser;
  76. }
  77. var HtmlParser = canParseHtml() ? _window.DOMParser : createHtmlParser();
  78. function htmlToDom(string) {
  79. var tree = new HtmlParser().parseFromString(string, 'text/html');
  80. collapse(tree, isBlock);
  81. return tree;
  82. }
  83. /*
  84. * Flattens DOM tree into single array
  85. */
  86. function bfsOrder(node) {
  87. var inqueue = [node],
  88. outqueue = [],
  89. elem, children, i;
  90. while (inqueue.length > 0) {
  91. elem = inqueue.shift();
  92. outqueue.push(elem);
  93. children = elem.childNodes;
  94. for (i = 0 ; i < children.length; i++) {
  95. if (children[i].nodeType === 1) { inqueue.push(children[i]); }
  96. }
  97. }
  98. outqueue.shift();
  99. return outqueue;
  100. }
  101. /*
  102. * Contructs a Markdown string of replacement text for a given node
  103. */
  104. function getContent(node) {
  105. var text = '';
  106. for (var i = 0; i < node.childNodes.length; i++) {
  107. if (node.childNodes[i].nodeType === 1) {
  108. text += node.childNodes[i]._replacement;
  109. }
  110. else if (node.childNodes[i].nodeType === 3) {
  111. text += node.childNodes[i].data;
  112. }
  113. else { continue; }
  114. }
  115. return text;
  116. }
  117. /*
  118. * Returns the HTML string of an element with its contents converted
  119. */
  120. function outer(node, content) {
  121. return node.cloneNode(false).outerHTML.replace('><', '>'+ content +'<');
  122. }
  123. function canConvert(node, filter) {
  124. if (typeof filter === 'string') {
  125. return filter === node.nodeName.toLowerCase();
  126. }
  127. if (Array.isArray(filter)) {
  128. return filter.indexOf(node.nodeName.toLowerCase()) !== -1;
  129. }
  130. else if (typeof filter === 'function') {
  131. return filter.call(toMarkdown, node);
  132. }
  133. else {
  134. throw new TypeError('`filter` needs to be a string, array, or function');
  135. }
  136. }
  137. function isFlankedByWhitespace(side, node) {
  138. var sibling, regExp, isFlanked;
  139. if (side === 'left') {
  140. sibling = node.previousSibling;
  141. regExp = / $/;
  142. }
  143. else {
  144. sibling = node.nextSibling;
  145. regExp = /^ /;
  146. }
  147. if (sibling) {
  148. if (sibling.nodeType === 3) {
  149. isFlanked = regExp.test(sibling.nodeValue);
  150. }
  151. else if(sibling.nodeType === 1 && !isBlock(sibling)) {
  152. isFlanked = regExp.test(sibling.textContent);
  153. }
  154. }
  155. return isFlanked;
  156. }
  157. function flankingWhitespace(node) {
  158. var leading = '', trailing = '';
  159. if (!isBlock(node)) {
  160. var hasLeading = /^[ \r\n\t]/.test(node.innerHTML),
  161. hasTrailing = /[ \r\n\t]$/.test(node.innerHTML);
  162. if (hasLeading && !isFlankedByWhitespace('left', node)) {
  163. leading = ' ';
  164. }
  165. if (hasTrailing && !isFlankedByWhitespace('right', node)) {
  166. trailing = ' ';
  167. }
  168. }
  169. return { leading: leading, trailing: trailing };
  170. }
  171. /*
  172. * Finds a Markdown converter, gets the replacement, and sets it on
  173. * `_replacement`
  174. */
  175. function process(node) {
  176. var replacement, content = getContent(node);
  177. // Remove blank nodes
  178. if (!isVoid(node) && !/A/.test(node.nodeName) && /^\s*$/i.test(content)) {
  179. node._replacement = '';
  180. return;
  181. }
  182. for (var i = 0; i < converters.length; i++) {
  183. var converter = converters[i];
  184. if (canConvert(node, converter.filter)) {
  185. if (typeof converter.replacement !== 'function') {
  186. throw new TypeError(
  187. '`replacement` needs to be a function that returns a string'
  188. );
  189. }
  190. var whitespace = flankingWhitespace(node);
  191. if (whitespace.leading || whitespace.trailing) {
  192. content = trim(content);
  193. }
  194. replacement = whitespace.leading +
  195. converter.replacement.call(toMarkdown, content, node) +
  196. whitespace.trailing;
  197. break;
  198. }
  199. }
  200. node._replacement = replacement;
  201. }
  202. toMarkdown = function (input, options) {
  203. options = options || {};
  204. if (typeof input !== 'string') {
  205. throw new TypeError(input + ' is not a string');
  206. }
  207. // Escape potential ol triggers
  208. input = input.replace(/(\d+)\. /g, '$1\\. ');
  209. var clone = htmlToDom(input).body,
  210. nodes = bfsOrder(clone),
  211. output;
  212. converters = mdConverters.slice(0);
  213. if (options.gfm) {
  214. converters = gfmConverters.concat(converters);
  215. }
  216. if (options.converters) {
  217. converters = options.converters.concat(converters);
  218. }
  219. // Process through nodes in reverse (so deepest child elements are first).
  220. for (var i = nodes.length - 1; i >= 0; i--) {
  221. process(nodes[i]);
  222. }
  223. output = getContent(clone);
  224. return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '')
  225. .replace(/\n\s+\n/g, '\n\n')
  226. .replace(/\n{3,}/g, '\n\n');
  227. };
  228. toMarkdown.isBlock = isBlock;
  229. toMarkdown.isVoid = isVoid;
  230. toMarkdown.trim = trim;
  231. toMarkdown.outer = outer;
  232. module.exports = toMarkdown;
  233. },{"./lib/gfm-converters":2,"./lib/md-converters":3,"collapse-whitespace":4,"jsdom":7}],2:[function(require,module,exports){
  234. 'use strict';
  235. function cell(content, node) {
  236. var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node);
  237. var prefix = ' ';
  238. if (index === 0) { prefix = '| '; }
  239. return prefix + content + ' |';
  240. }
  241. var highlightRegEx = /highlight highlight-(\S+)/;
  242. module.exports = [
  243. {
  244. filter: 'br',
  245. replacement: function () {
  246. return '\n';
  247. }
  248. },
  249. {
  250. filter: ['del', 's', 'strike'],
  251. replacement: function (content) {
  252. return '~~' + content + '~~';
  253. }
  254. },
  255. {
  256. filter: function (node) {
  257. return node.type === 'checkbox' && node.parentNode.nodeName === 'LI';
  258. },
  259. replacement: function (content, node) {
  260. return (node.checked ? '[x]' : '[ ]') + ' ';
  261. }
  262. },
  263. {
  264. filter: ['th', 'td'],
  265. replacement: function (content, node) {
  266. return cell(content, node);
  267. }
  268. },
  269. {
  270. filter: 'tr',
  271. replacement: function (content, node) {
  272. var borderCells = '';
  273. var alignMap = { left: ':--', right: '--:', center: ':-:' };
  274. if (node.parentNode.nodeName === 'THEAD') {
  275. for (var i = 0; i < node.childNodes.length; i++) {
  276. var align = node.childNodes[i].attributes.align;
  277. var border = '---';
  278. if (align) { border = alignMap[align.value] || border; }
  279. borderCells += cell(border, node.childNodes[i]);
  280. }
  281. }
  282. return '\n' + content + (borderCells ? '\n' + borderCells : '');
  283. }
  284. },
  285. {
  286. filter: 'table',
  287. replacement: function (content) {
  288. return '\n\n' + content + '\n\n';
  289. }
  290. },
  291. {
  292. filter: ['thead', 'tbody', 'tfoot'],
  293. replacement: function (content) {
  294. return content;
  295. }
  296. },
  297. // Fenced code blocks
  298. {
  299. filter: function (node) {
  300. return node.nodeName === 'PRE' &&
  301. node.firstChild &&
  302. node.firstChild.nodeName === 'CODE';
  303. },
  304. replacement: function(content, node) {
  305. return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n';
  306. }
  307. },
  308. // Syntax-highlighted code blocks
  309. {
  310. filter: function (node) {
  311. return node.nodeName === 'PRE' &&
  312. node.parentNode.nodeName === 'DIV' &&
  313. highlightRegEx.test(node.parentNode.className);
  314. },
  315. replacement: function (content, node) {
  316. var language = node.parentNode.className.match(highlightRegEx)[1];
  317. return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n';
  318. }
  319. },
  320. {
  321. filter: function (node) {
  322. return node.nodeName === 'DIV' &&
  323. highlightRegEx.test(node.className);
  324. },
  325. replacement: function (content) {
  326. return '\n\n' + content + '\n\n';
  327. }
  328. }
  329. ];
  330. },{}],3:[function(require,module,exports){
  331. 'use strict';
  332. module.exports = [
  333. {
  334. filter: 'p',
  335. replacement: function (content) {
  336. return '\n\n' + content + '\n\n';
  337. }
  338. },
  339. {
  340. filter: 'br',
  341. replacement: function () {
  342. return ' \n';
  343. }
  344. },
  345. {
  346. filter: ['h1', 'h2', 'h3', 'h4','h5', 'h6'],
  347. replacement: function(content, node) {
  348. var hLevel = node.nodeName.charAt(1);
  349. var hPrefix = '';
  350. for(var i = 0; i < hLevel; i++) {
  351. hPrefix += '#';
  352. }
  353. return '\n\n' + hPrefix + ' ' + content + '\n\n';
  354. }
  355. },
  356. {
  357. filter: 'hr',
  358. replacement: function () {
  359. return '\n\n* * *\n\n';
  360. }
  361. },
  362. {
  363. filter: ['em', 'i'],
  364. replacement: function (content) {
  365. return '_' + content + '_';
  366. }
  367. },
  368. {
  369. filter: ['strong', 'b'],
  370. replacement: function (content) {
  371. return '**' + content + '**';
  372. }
  373. },
  374. // Inline code
  375. {
  376. filter: function (node) {
  377. var hasSiblings = node.previousSibling || node.nextSibling;
  378. var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
  379. return node.nodeName === 'CODE' && !isCodeBlock;
  380. },
  381. replacement: function(content) {
  382. return '`' + content + '`';
  383. }
  384. },
  385. {
  386. filter: function (node) {
  387. return node.nodeName === 'A' && node.getAttribute('href');
  388. },
  389. replacement: function(content, node) {
  390. var titlePart = node.title ? ' "'+ node.title +'"' : '';
  391. return '[' + content + '](' + node.getAttribute('href') + titlePart + ')';
  392. }
  393. },
  394. {
  395. filter: 'img',
  396. replacement: function(content, node) {
  397. var alt = node.alt || '';
  398. var src = node.getAttribute('src') || '';
  399. var title = node.title || '';
  400. var titlePart = title ? ' "'+ title +'"' : '';
  401. return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '';
  402. }
  403. },
  404. // Code blocks
  405. {
  406. filter: function (node) {
  407. return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE';
  408. },
  409. replacement: function(content, node) {
  410. return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n';
  411. }
  412. },
  413. {
  414. filter: 'blockquote',
  415. replacement: function (content) {
  416. content = this.trim(content);
  417. content = content.replace(/\n{3,}/g, '\n\n');
  418. content = content.replace(/^/gm, '> ');
  419. return '\n\n' + content + '\n\n';
  420. }
  421. },
  422. {
  423. filter: 'li',
  424. replacement: function (content, node) {
  425. content = content.replace(/^\s+/, '').replace(/\n/gm, '\n ');
  426. var prefix = '* ';
  427. var parent = node.parentNode;
  428. var index = Array.prototype.indexOf.call(parent.children, node) + 1;
  429. prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* ';
  430. return prefix + content;
  431. }
  432. },
  433. {
  434. filter: ['ul', 'ol'],
  435. replacement: function (content, node) {
  436. var strings = [];
  437. for (var i = 0; i < node.childNodes.length; i++) {
  438. strings.push(node.childNodes[i]._replacement);
  439. }
  440. if (/li/i.test(node.parentNode.nodeName)) {
  441. return '\n' + strings.join('\n');
  442. }
  443. return '\n\n' + strings.join('\n') + '\n\n';
  444. }
  445. },
  446. {
  447. filter: function (node) {
  448. return this.isBlock(node);
  449. },
  450. replacement: function (content, node) {
  451. return '\n\n' + this.outer(node, content) + '\n\n';
  452. }
  453. },
  454. // Anything else!
  455. {
  456. filter: function () {
  457. return true;
  458. },
  459. replacement: function (content, node) {
  460. return this.outer(node, content);
  461. }
  462. }
  463. ];
  464. },{}],4:[function(require,module,exports){
  465. 'use strict';
  466. var voidElements = require('void-elements');
  467. Object.keys(voidElements).forEach(function (name) {
  468. voidElements[name.toUpperCase()] = 1;
  469. });
  470. var blockElements = {};
  471. require('block-elements').forEach(function (name) {
  472. blockElements[name.toUpperCase()] = 1;
  473. });
  474. /**
  475. * isBlockElem(node) determines if the given node is a block element.
  476. *
  477. * @param {Node} node
  478. * @return {Boolean}
  479. */
  480. function isBlockElem(node) {
  481. return !!(node && blockElements[node.nodeName]);
  482. }
  483. /**
  484. * isVoid(node) determines if the given node is a void element.
  485. *
  486. * @param {Node} node
  487. * @return {Boolean}
  488. */
  489. function isVoid(node) {
  490. return !!(node && voidElements[node.nodeName]);
  491. }
  492. /**
  493. * whitespace(elem [, isBlock]) removes extraneous whitespace from an
  494. * the given element. The function isBlock may optionally be passed in
  495. * to determine whether or not an element is a block element; if none
  496. * is provided, defaults to using the list of block elements provided
  497. * by the `block-elements` module.
  498. *
  499. * @param {Node} elem
  500. * @param {Function} blockTest
  501. */
  502. function collapseWhitespace(elem, isBlock) {
  503. if (!elem.firstChild || elem.nodeName === 'PRE') return;
  504. if (typeof isBlock !== 'function') {
  505. isBlock = isBlockElem;
  506. }
  507. var prevText = null;
  508. var prevVoid = false;
  509. var prev = null;
  510. var node = next(prev, elem);
  511. while (node !== elem) {
  512. if (node.nodeType === 3) {
  513. // Node.TEXT_NODE
  514. var text = node.data.replace(/[ \r\n\t]+/g, ' ');
  515. if ((!prevText || / $/.test(prevText.data)) && !prevVoid && text[0] === ' ') {
  516. text = text.substr(1);
  517. }
  518. // `text` might be empty at this point.
  519. if (!text) {
  520. node = remove(node);
  521. continue;
  522. }
  523. node.data = text;
  524. prevText = node;
  525. } else if (node.nodeType === 1) {
  526. // Node.ELEMENT_NODE
  527. if (isBlock(node) || node.nodeName === 'BR') {
  528. if (prevText) {
  529. prevText.data = prevText.data.replace(/ $/, '');
  530. }
  531. prevText = null;
  532. prevVoid = false;
  533. } else if (isVoid(node)) {
  534. // Avoid trimming space around non-block, non-BR void elements.
  535. prevText = null;
  536. prevVoid = true;
  537. }
  538. } else {
  539. node = remove(node);
  540. continue;
  541. }
  542. var nextNode = next(prev, node);
  543. prev = node;
  544. node = nextNode;
  545. }
  546. if (prevText) {
  547. prevText.data = prevText.data.replace(/ $/, '');
  548. if (!prevText.data) {
  549. remove(prevText);
  550. }
  551. }
  552. }
  553. /**
  554. * remove(node) removes the given node from the DOM and returns the
  555. * next node in the sequence.
  556. *
  557. * @param {Node} node
  558. * @return {Node} node
  559. */
  560. function remove(node) {
  561. var next = node.nextSibling || node.parentNode;
  562. node.parentNode.removeChild(node);
  563. return next;
  564. }
  565. /**
  566. * next(prev, current) returns the next node in the sequence, given the
  567. * current and previous nodes.
  568. *
  569. * @param {Node} prev
  570. * @param {Node} current
  571. * @return {Node}
  572. */
  573. function next(prev, current) {
  574. if (prev && prev.parentNode === current || current.nodeName === 'PRE') {
  575. return current.nextSibling || current.parentNode;
  576. }
  577. return current.firstChild || current.nextSibling || current.parentNode;
  578. }
  579. module.exports = collapseWhitespace;
  580. },{"block-elements":5,"void-elements":6}],5:[function(require,module,exports){
  581. /**
  582. * This file automatically generated from `build.js`.
  583. * Do not manually edit.
  584. */
  585. module.exports = [
  586. "address",
  587. "article",
  588. "aside",
  589. "audio",
  590. "blockquote",
  591. "canvas",
  592. "dd",
  593. "div",
  594. "dl",
  595. "fieldset",
  596. "figcaption",
  597. "figure",
  598. "footer",
  599. "form",
  600. "h1",
  601. "h2",
  602. "h3",
  603. "h4",
  604. "h5",
  605. "h6",
  606. "header",
  607. "hgroup",
  608. "hr",
  609. "main",
  610. "nav",
  611. "noscript",
  612. "ol",
  613. "output",
  614. "p",
  615. "pre",
  616. "section",
  617. "table",
  618. "tfoot",
  619. "ul",
  620. "video"
  621. ];
  622. },{}],6:[function(require,module,exports){
  623. /**
  624. * This file automatically generated from `pre-publish.js`.
  625. * Do not manually edit.
  626. */
  627. module.exports = {
  628. "area": true,
  629. "base": true,
  630. "br": true,
  631. "col": true,
  632. "embed": true,
  633. "hr": true,
  634. "img": true,
  635. "input": true,
  636. "keygen": true,
  637. "link": true,
  638. "menuitem": true,
  639. "meta": true,
  640. "param": true,
  641. "source": true,
  642. "track": true,
  643. "wbr": true
  644. };
  645. },{}],7:[function(require,module,exports){
  646. },{}]},{},[1])(1)
  647. });