@bauerpub/bauer-draft-js-export-markdown
Version:
DraftJS: Export ContentState to Markdown
288 lines (265 loc) • 11.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
exports.default = stateToMarkdown;
var _bauerDraftJsUtils = require('@bauerpub/bauer-draft-js-utils');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var BOLD = _bauerDraftJsUtils.INLINE_STYLE.BOLD,
CODE = _bauerDraftJsUtils.INLINE_STYLE.CODE,
ITALIC = _bauerDraftJsUtils.INLINE_STYLE.ITALIC,
STRIKETHROUGH = _bauerDraftJsUtils.INLINE_STYLE.STRIKETHROUGH,
UNDERLINE = _bauerDraftJsUtils.INLINE_STYLE.UNDERLINE;
var CODE_INDENT = ' ';
function swapWhitespace(text, wrapper) {
var _$exec = /(^\s?)(.+)/g.exec(text),
_$exec2 = _slicedToArray(_$exec, 3),
_ = _$exec2[0],
leadingSpace = _$exec2[1],
rest = _$exec2[2];
var suffix = /\s$/.test(rest) ? wrapper + ' ' : wrapper;
var isSingleSpace = text === ' ';
return isSingleSpace ? text : '' + leadingSpace + wrapper + rest.trim() + suffix;
}
var MarkupGenerator = function () {
function MarkupGenerator(contentState) {
_classCallCheck(this, MarkupGenerator);
this.contentState = contentState;
}
_createClass(MarkupGenerator, [{
key: 'generate',
value: function generate() {
this.output = [];
this.blocks = this.contentState.getBlockMap().toArray();
this.totalBlocks = this.blocks.length;
this.currentBlock = 0;
this.listItemCounts = {};
while (this.currentBlock < this.totalBlocks) {
this.processBlock();
}
return this.output.join('');
}
}, {
key: 'processBlock',
value: function processBlock() {
var block = this.blocks[this.currentBlock];
var blockType = block.getType();
switch (blockType) {
case _bauerDraftJsUtils.BLOCK_TYPE.HEADER_ONE:
{
this.insertLineBreaks(1);
this.output.push('# ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.HEADER_TWO:
{
this.insertLineBreaks(1);
if (block.text !== "") {
this.output.push('## ' + this.renderBlockContent(block) + '\n');
}
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.HEADER_THREE:
{
this.insertLineBreaks(1);
this.output.push('### ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.HEADER_FOUR:
{
this.insertLineBreaks(1);
this.output.push('#### ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.HEADER_FIVE:
{
this.insertLineBreaks(1);
this.output.push('##### ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.HEADER_SIX:
{
this.insertLineBreaks(1);
this.output.push('###### ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.UNORDERED_LIST_ITEM:
{
var blockDepth = block.getDepth();
var lastBlock = this.getLastBlock();
var lastBlockType = lastBlock ? lastBlock.getType() : null;
var lastBlockDepth = lastBlock && canHaveDepth(lastBlockType) ? lastBlock.getDepth() : null;
if (lastBlockType !== blockType && lastBlockDepth !== blockDepth - 1) {
this.insertLineBreaks(1);
// Insert an additional line break if following opposite list type.
if (lastBlockType === _bauerDraftJsUtils.BLOCK_TYPE.ORDERED_LIST_ITEM) {
this.insertLineBreaks(1);
}
}
var indent = ' '.repeat(block.depth * 4);
this.output.push(indent + '- ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.ORDERED_LIST_ITEM:
{
var _blockDepth = block.getDepth();
var _lastBlock = this.getLastBlock();
var _lastBlockType = _lastBlock ? _lastBlock.getType() : null;
var _lastBlockDepth = _lastBlock && canHaveDepth(_lastBlockType) ? _lastBlock.getDepth() : null;
if (_lastBlockType !== blockType && _lastBlockDepth !== _blockDepth - 1) {
this.insertLineBreaks(1);
// Insert an additional line break if following opposite list type.
if (_lastBlockType === _bauerDraftJsUtils.BLOCK_TYPE.UNORDERED_LIST_ITEM) {
this.insertLineBreaks(1);
}
}
var _indent = ' '.repeat(_blockDepth * 4);
// TODO: figure out what to do with two-digit numbers
var count = this.getListItemCount(block) % 10;
this.output.push(_indent + (count + '. ') + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.BLOCKQUOTE:
{
this.insertLineBreaks(1);
this.output.push(' > ' + this.renderBlockContent(block) + '\n');
break;
}
case _bauerDraftJsUtils.BLOCK_TYPE.CODE:
{
this.insertLineBreaks(1);
this.output.push(CODE_INDENT + this.renderBlockContent(block) + '\n');
break;
}
default:
{
this.insertLineBreaks(1);
this.output.push(this.renderBlockContent(block) + '\n');
break;
}
}
this.currentBlock += 1;
}
}, {
key: 'getLastBlock',
value: function getLastBlock() {
return this.blocks[this.currentBlock - 1];
}
}, {
key: 'getNextBlock',
value: function getNextBlock() {
return this.blocks[this.currentBlock + 1];
}
}, {
key: 'getListItemCount',
value: function getListItemCount(block) {
var blockType = block.getType();
var blockDepth = block.getDepth();
// To decide if we need to start over we need to backtrack (skipping list
// items that are of greater depth)
var index = this.currentBlock - 1;
var prevBlock = this.blocks[index];
while (prevBlock && canHaveDepth(prevBlock.getType()) && prevBlock.getDepth() > blockDepth) {
index -= 1;
prevBlock = this.blocks[index];
}
if (!prevBlock || prevBlock.getType() !== blockType || prevBlock.getDepth() !== blockDepth) {
this.listItemCounts[blockDepth] = 0;
}
return this.listItemCounts[blockDepth] = this.listItemCounts[blockDepth] + 1;
}
}, {
key: 'insertLineBreaks',
value: function insertLineBreaks() {
if (this.currentBlock > 0) {
this.output.push('\n');
}
}
}, {
key: 'renderBlockContent',
value: function renderBlockContent(block) {
var contentState = this.contentState;
var blockType = block.getType();
var text = block.getText();
if (text === '') {
// Prevent element collapse if completely empty.
// TODO: Replace with constant.
return text;
}
var charMetaList = block.getCharacterList();
var entityPieces = (0, _bauerDraftJsUtils.getEntityRanges)(text, charMetaList);
return entityPieces.map(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
entityKey = _ref2[0],
stylePieces = _ref2[1];
var content = stylePieces.map(function (_ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
text = _ref4[0],
style = _ref4[1];
// Don't allow empty inline elements.
if (!text) {
return '';
}
var content = text;
if (style.has(BOLD)) {
content = swapWhitespace(content, '**');
}
if (style.has(UNDERLINE)) {
// TODO: encode `+`?
content = '++' + content + '++';
}
if (style.has(ITALIC)) {
content = swapWhitespace(content.replace(/\*\*/g, '__'), '_');
}
if (style.has(STRIKETHROUGH)) {
// TODO: encode `~`?
content = '~~' + content + '~~';
}
if (style.has(CODE)) {
content = blockType === _bauerDraftJsUtils.BLOCK_TYPE.CODE ? content : '`' + content + '`';
}
return content;
}).join('');
var entity = entityKey ? contentState.getEntity(entityKey) : null;
if (entity != null && entity.getType() === _bauerDraftJsUtils.ENTITY_TYPE.LINK) {
var data = entity.getData();
var url = data.url || '';
var target = data.target || '_self';
return '[' + content + '](' + encodeURL(url) + ' "' + target + '")';
} else if (entity != null && entity.getType() === _bauerDraftJsUtils.ENTITY_TYPE.IMAGE) {
var _data = entity.getData();
var _url = encodeURL(_data.src || '').replace(/https?\:/, '');
var alt = _data.alt ? '' + escapeTitle(_data.alt) : '';
var title = _data.title ? '"' + escapeTitle(_data.title) + '"' : '';
return '';
} else {
return content;
}
}).join('');
}
}]);
return MarkupGenerator;
}();
function canHaveDepth(blockType) {
switch (blockType) {
case _bauerDraftJsUtils.BLOCK_TYPE.UNORDERED_LIST_ITEM:
case _bauerDraftJsUtils.BLOCK_TYPE.ORDERED_LIST_ITEM:
return true;
default:
return false;
}
}
// Encode chars that would normally be allowed in a URL but would conflict with
// our markdown syntax: `[foo](http://foo/)`
function encodeURL(url) {
return url.replace(/\)/g, '%29');
}
// Escape quotes using backslash.
function escapeTitle(text) {
return text.replace(/"/g, '\\"');
}
function stateToMarkdown(content) {
return new MarkupGenerator(content).generate();
}
;