From 00e89d23d773768c5906f3ec79207519149b7c9d Mon Sep 17 00:00:00 2001 From: marihachi Date: Sat, 2 Oct 2021 09:26:56 +0900 Subject: [PATCH] Supports white list for function syntax (#77) * support name list for FN syntax * use default parameter Co-authored-by: Johann150 Co-authored-by: Johann150 --- etc/mfm-js.api.md | 4 +++- src/api.ts | 4 ++-- src/internal/parser.pegjs | 10 +++++++++- test/parser.ts | 18 ++++++++++++++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/etc/mfm-js.api.md b/etc/mfm-js.api.md index 3c5101a..d4e14c3 100644 --- a/etc/mfm-js.api.md +++ b/etc/mfm-js.api.md @@ -231,7 +231,9 @@ export const N_URL: (value: string, brackets?: boolean | undefined) => NodeType< export type NodeType = T extends 'quote' ? MfmQuote : T extends 'search' ? MfmSearch : T extends 'blockCode' ? MfmCodeBlock : T extends 'mathBlock' ? MfmMathBlock : T extends 'center' ? MfmCenter : T extends 'unicodeEmoji' ? MfmUnicodeEmoji : T extends 'emojiCode' ? MfmEmojiCode : T extends 'bold' ? MfmBold : T extends 'small' ? MfmSmall : T extends 'italic' ? MfmItalic : T extends 'strike' ? MfmStrike : T extends 'inlineCode' ? MfmInlineCode : T extends 'mathInline' ? MfmMathInline : T extends 'mention' ? MfmMention : T extends 'hashtag' ? MfmHashtag : T extends 'url' ? MfmUrl : T extends 'link' ? MfmLink : T extends 'fn' ? MfmFn : T extends 'text' ? MfmText : never; // @public (undocumented) -export function parse(input: string): MfmNode[]; +export function parse(input: string, opts?: Partial<{ + fnNameList: string[]; +}>): MfmNode[]; // Warning: (ae-forgotten-export) The symbol "MfmPlainNode" needs to be exported by the entry point index.d.ts // diff --git a/src/api.ts b/src/api.ts index 3a72c5c..4124061 100644 --- a/src/api.ts +++ b/src/api.ts @@ -8,8 +8,8 @@ const parser: peg.Parser = require('./internal/parser'); /** * Generates a MfmNode tree from the MFM string. */ -export function parse(input: string): MfmNode[] { - const nodes = parser.parse(input, { startRule: 'fullParser' }); +export function parse(input: string, opts: Partial<{ fnNameList: string[]; }> = {}): MfmNode[] { + const nodes = parser.parse(input, { startRule: 'fullParser', fnNameList: opts.fnNameList }); return nodes; } diff --git a/src/internal/parser.pegjs b/src/internal/parser.pegjs index 9b6e3ac..5e3520c 100644 --- a/src/internal/parser.pegjs +++ b/src/internal/parser.pegjs @@ -56,6 +56,14 @@ return false; } + + function ensureFnName(name) { + if (!options.fnNameList) return true; + if (!Array.isArray(options.fnNameList)) { + error("options.fnNameList must be an array."); + } + return options.fnNameList.includes(name); + } } // @@ -414,7 +422,7 @@ linkUrl // inline: fn fn - = "$[" name:$([a-z0-9_]i)+ args:fnArgs? _ content:(!("]") @inline)+ "]" + = "$[" name:$([a-z0-9_]i)+ &{ return ensureFnName(name); } args:fnArgs? _ content:(!("]") @inline)+ "]" { args = args || {}; return FN(name, args, mergeText(content)); diff --git a/test/parser.ts b/test/parser.ts index b36e505..f084f72 100644 --- a/test/parser.ts +++ b/test/parser.ts @@ -1050,6 +1050,24 @@ hoge`; ]; assert.deepStrictEqual(mfm.parse(input), output); }); + + it('exists name in the fnNameList', () => { + const input = '$[spin.speed=1.1s text]'; + const output = [ + FN('spin', { speed: '1.1s' }, [ + TEXT('text') + ]) + ]; + assert.deepStrictEqual(mfm.parse(input, { fnNameList: ['tada', 'spin'] }), output); + }); + + it('not exists name in the fnNameList', () => { + const input = '$[pope.speed=1.1s text]'; + const output = [ + TEXT('$[pope.speed=1.1s text]') + ]; + assert.deepStrictEqual(mfm.parse(input, { fnNameList: ['tada', 'spin'] }), output); + }); }); it('composite', () => {