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
//