diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2018-11-21 05:11:00 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-21 05:11:00 +0900 |
| commit | 79ffbf95db9d0cc019d06ab93b1bfa6ba0d4f9ae (patch) | |
| tree | 884a18e6735f8557eb392929fcfa2dc1ae09cb6d /src/mfm/parse.ts | |
| parent | Refactor checkMongoDb (#3339) (diff) | |
| download | sharkey-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.ts | 81 |
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; +}; |