2018-12-20 04:41:04 -06:00
|
|
|
import parser, { plainParser, MfmForest, MfmTree } from './parser';
|
2018-11-20 14:11:00 -06:00
|
|
|
import * as A from '../prelude/array';
|
|
|
|
import * as S from '../prelude/string';
|
2018-12-20 04:41:04 -06:00
|
|
|
import { createTree, createLeaf } from '../prelude/tree';
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
function concatTextTrees(ts: MfmForest): MfmTree {
|
|
|
|
return createLeaf({ type: 'text', props: { text: S.concat(ts.map(x => x.node.props.text)) } });
|
|
|
|
}
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
function concatIfTextTrees(ts: MfmForest): MfmForest {
|
|
|
|
return ts[0].node.type === 'text' ? [concatTextTrees(ts)] : ts;
|
|
|
|
}
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
function concatConsecutiveTextTrees(ts: MfmForest): MfmForest {
|
|
|
|
const us = A.concat(A.groupOn(t => t.node.type, ts).map(concatIfTextTrees));
|
|
|
|
return us.map(t => createTree(t.node, concatConsecutiveTextTrees(t.children)));
|
|
|
|
}
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
function isEmptyTextTree(t: MfmTree): boolean {
|
|
|
|
return t.node.type == 'text' && t.node.props.text === '';
|
|
|
|
}
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
function removeEmptyTextNodes(ts: MfmForest): MfmForest {
|
|
|
|
return ts
|
|
|
|
.filter(t => !isEmptyTextTree(t))
|
|
|
|
.map(t => createTree(t.node, removeEmptyTextNodes(t.children)));
|
|
|
|
}
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
export default (source: string, plainText = false): MfmForest => {
|
|
|
|
if (source == null || source == '') {
|
|
|
|
return null;
|
|
|
|
}
|
2018-11-20 14:11:00 -06:00
|
|
|
|
2018-12-20 04:41:04 -06:00
|
|
|
const raw = plainText ? plainParser.root.tryParse(source) : parser.root.tryParse(source) as MfmForest;
|
|
|
|
return removeEmptyTextNodes(concatConsecutiveTextTrees(raw));
|
2018-11-20 14:11:00 -06:00
|
|
|
};
|