diff options
Diffstat (limited to 'src/mfm/parse/index.ts')
| -rw-r--r-- | src/mfm/parse/index.ts | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/src/mfm/parse/index.ts b/src/mfm/parse/index.ts new file mode 100644 index 0000000000..2b6a459b1e --- /dev/null +++ b/src/mfm/parse/index.ts @@ -0,0 +1,99 @@ +/** + * Misskey Text Analyzer + */ + +import { TextElementBold } from './elements/bold'; +import { TextElementCode } from './elements/code'; +import { TextElementEmoji } from './elements/emoji'; +import { TextElementHashtag } from './elements/hashtag'; +import { TextElementInlineCode } from './elements/inline-code'; +import { TextElementLink } from './elements/link'; +import { TextElementMention } from './elements/mention'; +import { TextElementQuote } from './elements/quote'; +import { TextElementSearch } from './elements/search'; +import { TextElementTitle } from './elements/title'; +import { TextElementUrl } from './elements/url'; + +const elements = [ + require('./elements/bold'), + require('./elements/title'), + require('./elements/url'), + require('./elements/link'), + require('./elements/mention'), + require('./elements/hashtag'), + require('./elements/code'), + require('./elements/inline-code'), + require('./elements/quote'), + require('./elements/emoji'), + require('./elements/search') +].map(element => element.default as TextElementProcessor); + +export type TextElement = { type: 'text', content: string } + | TextElementBold + | TextElementCode + | TextElementEmoji + | TextElementHashtag + | TextElementInlineCode + | TextElementLink + | TextElementMention + | TextElementQuote + | TextElementSearch + | TextElementTitle + | TextElementUrl; +export type TextElementProcessor = (text: string, i: number) => TextElement | TextElement[]; + +export default (source: string): TextElement[] => { + + if (source == '') { + return null; + } + + const tokens: TextElement[] = []; + + function push(token: TextElement) { + if (token != null) { + tokens.push(token); + source = source.substr(token.content.length); + } + } + + let i = 0; + + // パース + while (source != '') { + const parsed = elements.some(el => { + let _tokens = el(source, i); + if (_tokens) { + if (!Array.isArray(_tokens)) { + _tokens = [_tokens]; + } + _tokens.forEach(push); + return true; + } else { + return false; + } + }); + + if (!parsed) { + push({ + type: 'text', + content: source[0] + }); + } + + i++; + } + + // テキストを纏める + return tokens.reduce((a, b) => { + if (a.length && a[a.length - 1].type == 'text' && b.type == 'text') { + const tail = a.pop(); + return a.concat({ + type: 'text', + content: tail.content + b.content + }); + } else { + return a.concat(b); + } + }, [] as TextElement[]); +}; |