diff --git a/src/index.ts b/src/index.ts index 6c1b5ce..fff528e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import peg from 'pegjs'; import { MfmNode } from './node'; +import { stringifyNode, stringifyTree } from './util'; const parser: peg.Parser = require('./parser'); export function parse(input: string): MfmNode[] { @@ -12,95 +13,14 @@ export function parsePlain(input: string): MfmNode[] { return nodes; } -function nodeStringify(node: MfmNode): string { - switch(node.type) { - // block - case 'quote': { - return toString(node.children).split('\n').map(line => `>${line}`).join('\n'); - } - case 'search': { - return node.props.content; - } - case 'blockCode': { - return `\`\`\`${ node.props.lang ?? '' }\n${ node.props.code }\n\`\`\``; - } - case 'mathBlock': { - return `\\[\n${ node.props.formula }\n\\]`; - } - case 'center': { - return `
${ toString(node.children) }
`; - } - // inline - case 'emoji': { - if (node.props.name) { - return `:${ node.props.name }:`; - } - else if (node.props.emoji) { - return node.props.emoji; - } - else { - return ''; - } - } - case 'bold': { - return `**${ toString(node.children) }**`; - } - case 'small': { - return `${ toString(node.children) }`; - } - case 'italic': { - return `${ toString(node.children) }`; - } - case 'strike': { - return `~~${ toString(node.children) }~~`; - } - case 'inlineCode': { - return `\`${ node.props.code }\``; - } - case 'mathInline': { - return `\\(${ node.props.formula }\\)`; - } - case 'mention': { - return node.props.acct; - } - case 'hashtag': { - return `#${ node.props.hashtag }`; - } - case 'url': { - return node.props.url; - } - case 'link': { - const prefix = node.props.silent ? '?' : ''; - return `${ prefix }[${ toString(node.children) }](${ node.props.url })`; - } - case 'fn': { - const argFields = Object.keys(node.props.args).map(key => { - const value = node.props.args[key]; - if (value === true) { - return key; - } - else { - return `${ key }=${ value }`; - } - }); - const args = (argFields.length > 0) ? '.' + argFields.join(',') : ''; - return `[${ node.props.name }${ args } ${ toString(node.children) }]`; - } - case 'text': { - return node.props.text; - } - } - throw new Error('unknown mfm node'); -} - -export function toString(nodes: MfmNode[]): string +export function toString(tree: MfmNode[]): string export function toString(node: MfmNode): string export function toString(node: MfmNode | MfmNode[]): string { if (Array.isArray(node)) { - return node.map(n => nodeStringify(n)).join(''); + return stringifyTree(node); } else { - return nodeStringify(node); + return stringifyNode(node); } } diff --git a/src/util.ts b/src/util.ts index 58a4a6c..8b96d18 100644 --- a/src/util.ts +++ b/src/util.ts @@ -71,6 +71,91 @@ export function mergeText(trees: MfmNode[] | undefined, recursive?: boolean): Mf } } +export function stringifyNode(node: MfmNode): string { + switch(node.type) { + // block + case 'quote': { + return stringifyTree(node.children).split('\n').map(line => `>${line}`).join('\n'); + } + case 'search': { + return node.props.content; + } + case 'blockCode': { + return `\`\`\`${ node.props.lang ?? '' }\n${ node.props.code }\n\`\`\``; + } + case 'mathBlock': { + return `\\[\n${ node.props.formula }\n\\]`; + } + case 'center': { + return `
${ stringifyTree(node.children) }
`; + } + // inline + case 'emoji': { + if (node.props.name) { + return `:${ node.props.name }:`; + } + else if (node.props.emoji) { + return node.props.emoji; + } + else { + return ''; + } + } + case 'bold': { + return `**${ stringifyTree(node.children) }**`; + } + case 'small': { + return `${ stringifyTree(node.children) }`; + } + case 'italic': { + return `${ stringifyTree(node.children) }`; + } + case 'strike': { + return `~~${ stringifyTree(node.children) }~~`; + } + case 'inlineCode': { + return `\`${ node.props.code }\``; + } + case 'mathInline': { + return `\\(${ node.props.formula }\\)`; + } + case 'mention': { + return node.props.acct; + } + case 'hashtag': { + return `#${ node.props.hashtag }`; + } + case 'url': { + return node.props.url; + } + case 'link': { + const prefix = node.props.silent ? '?' : ''; + return `${ prefix }[${ stringifyTree(node.children) }](${ node.props.url })`; + } + case 'fn': { + const argFields = Object.keys(node.props.args).map(key => { + const value = node.props.args[key]; + if (value === true) { + return key; + } + else { + return `${ key }=${ value }`; + } + }); + const args = (argFields.length > 0) ? '.' + argFields.join(',') : ''; + return `[${ node.props.name }${ args } ${ stringifyTree(node.children) }]`; + } + case 'text': { + return node.props.text; + } + } + throw new Error('unknown mfm node'); +} + +export function stringifyTree(tree: MfmNode[]): string { + return tree.map(n => stringifyNode(n)).join(''); +} + // // dynamic consuming //