summaryrefslogtreecommitdiff
path: root/src/mfm/parse.ts
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2018-11-21 05:11:00 +0900
committerGitHub <noreply@github.com>2018-11-21 05:11:00 +0900
commit79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae (patch)
tree884a18e6735f8557eb392929fcfa2dc1ae09cb6d /src/mfm/parse.ts
parentRefactor checkMongoDb (#3339) (diff)
downloadsharkey-79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae.tar.gz
sharkey-79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae.tar.bz2
sharkey-79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae.zip
Improve MFM parser (#3337)
* wip * wip * Refactor * Refactor * wip * wip * wip * wip * Refactor * Refactor * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Clean up * Update misskey-flavored-markdown.ts * wip * wip * wip * wip * Update parser.ts * wip * Add new test * wip * Add new test * Add new test * wip * Refactor * Update parse.ts * Refactor * Update parser.ts * wip
Diffstat (limited to 'src/mfm/parse.ts')
-rw-r--r--src/mfm/parse.ts81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/mfm/parse.ts b/src/mfm/parse.ts
new file mode 100644
index 0000000000..e7ae3d012e
--- /dev/null
+++ b/src/mfm/parse.ts
@@ -0,0 +1,81 @@
+import parser, { Node } from './parser';
+import * as A from '../prelude/array';
+import * as S from '../prelude/string';
+
+export default (source: string): Node[] => {
+ if (source == null || source == '') {
+ return null;
+ }
+
+ let nodes: Node[] = parser.root.tryParse(source);
+
+ const combineText = (es: Node[]): Node =>
+ ({ name: 'text', props: { text: S.concat(es.map(e => e.props.text)) } });
+
+ const concatText = (nodes: Node[]): Node[] =>
+ A.concat(A.groupOn(x => x.name, nodes).map(es =>
+ es[0].name === 'text' ? [combineText(es)] : es
+ ));
+
+ const concatTextRecursive = (es: Node[]): void =>
+ es.filter(x => x.children).forEach(x => {
+ x.children = concatText(x.children);
+ concatTextRecursive(x.children);
+ });
+
+ nodes = concatText(nodes);
+ concatTextRecursive(nodes);
+
+ function getBeforeTextNode(node: Node): Node {
+ if (node == null) return null;
+ if (node.name == 'text') return node;
+ if (node.children) return getBeforeTextNode(node.children[node.children.length - 1]);
+ return null;
+ }
+
+ function getAfterTextNode(node: Node): Node {
+ if (node == null) return null;
+ if (node.name == 'text') return node;
+ if (node.children) return getBeforeTextNode(node.children[0]);
+ return null;
+ }
+
+ function isBlockNode(node: Node): boolean {
+ return ['blockCode', 'quote', 'title'].includes(node.name);
+ }
+
+ /**
+ * ブロック要素の前後にある改行を削除します(ブロック要素自体が改行の役割も果たすため、余計に改行されてしまうため)
+ * @param nodes
+ */
+ const removeNeedlessLineBreaks = (nodes: Node[]) => {
+ nodes.forEach((node, i) => {
+ if (node.children) removeNeedlessLineBreaks(node.children);
+ if (isBlockNode(node)) {
+ const before = getBeforeTextNode(nodes[i - 1]);
+ const after = getAfterTextNode(nodes[i + 1]);
+ if (before && before.props.text.endsWith('\n')) {
+ before.props.text = before.props.text.substring(0, before.props.text.length - 1);
+ }
+ if (after && after.props.text.startsWith('\n')) {
+ after.props.text = after.props.text.substring(1);
+ }
+ }
+ });
+ };
+
+ const removeEmptyTextNodes = (nodes: Node[]) => {
+ nodes.forEach(n => {
+ if (n.children) {
+ n.children = removeEmptyTextNodes(n.children);
+ }
+ });
+ return nodes.filter(n => !(n.name == 'text' && n.props.text == ''));
+ };
+
+ removeNeedlessLineBreaks(nodes);
+
+ nodes = removeEmptyTextNodes(nodes);
+
+ return nodes;
+};