diff --git a/CHANGELOG.md b/CHANGELOG.md index ee44cc8..df6c8ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ --> +## 0.23.2 +### Features +- Supports whitelisting of emoji code names. (#130) + ## 0.23.1 ### Improvements - improve emoji code parsing diff --git a/docs/api.md b/docs/api.md index 9fb5603..e1fc7d1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -9,7 +9,7 @@ console.log(JSON.stringify(nodes)); // => [{"type":"text","props":{"text":"hello "}},{"type":"fn","props":{"name":"tada","args":{}},"children":[{"type":"text","props":{"text":"world"}}]}] ``` -### 利用可能なMFM関数のリストを設定する +### 利用可能なMFM関数やカスタム絵文字のリストを設定する MFM関数の名前をホワイトリストに登録して、登録されたMFM関数以外を通常のテキストノードとして解釈するように設定できます。 デフォルトではすべてのMFM関数名を受け入れるように設定されています。 @@ -26,6 +26,15 @@ console.log(JSON.stringify(nodes)); // => [{"type":"text","props":{"text":"hello $[pope world]"}}] ``` +同様に、カスタム絵文字の名前もホワイトリスト制にできます。 + +例: +```ts +const nodes = mfm.parse(':bap:', { emojiCodeList: ['polarbear', 'bap'] }); +console.log(JSON.stringify(nodes)); +// => [{"type":"emojiCode","props":{"name":"bap"}}] +``` + ### 最大のネストの深さを変更する デフォルトで20に設定されています。 diff --git a/etc/mfm-js.api.md b/etc/mfm-js.api.md index 67cd37d..84667c4 100644 --- a/etc/mfm-js.api.md +++ b/etc/mfm-js.api.md @@ -243,6 +243,7 @@ export type NodeType = T extends 'quote' ? MfmQuote : // @public (undocumented) export function parse(input: string, opts?: Partial<{ fnNameList: string[]; + emojiCodeList: string[]; nestLimit: number; }>): MfmNode[]; diff --git a/package-lock.json b/package-lock.json index 423e834..a6593d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mfm-js", - "version": "0.23.1", + "version": "0.23.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mfm-js", - "version": "0.23.1", + "version": "0.23.2", "license": "MIT", "dependencies": { "twemoji-parser": "14.0.0" diff --git a/package.json b/package.json index d79f770..b552dd3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mfm-js", - "version": "0.23.1", + "version": "0.23.2", "description": "An MFM parser implementation with TypeScript", "main": "./built/index.js", "types": "./built/index.d.ts", diff --git a/src/api.ts b/src/api.ts index f3194a8..3e8244e 100644 --- a/src/api.ts +++ b/src/api.ts @@ -5,9 +5,10 @@ import { MfmNode, MfmSimpleNode } from './node'; /** * Generates a MfmNode tree from the MFM string. */ -export function parse(input: string, opts: Partial<{ fnNameList: string[]; nestLimit: number; }> = {}): MfmNode[] { +export function parse(input: string, opts: Partial<{ fnNameList: string[]; emojiCodeList: string[]; nestLimit: number; }> = {}): MfmNode[] { const nodes = fullParser(input, { fnNameList: opts.fnNameList, + emojiCodeList: opts.emojiCodeList, nestLimit: opts.nestLimit, }); return nodes; diff --git a/src/internal/index.ts b/src/internal/index.ts index 86eb7d8..0ae7223 100644 --- a/src/internal/index.ts +++ b/src/internal/index.ts @@ -5,6 +5,7 @@ import * as P from './core'; export type FullParserOpts = { fnNameList?: string[]; + emojiCodeList?: string[]; nestLimit?: number; }; @@ -12,6 +13,7 @@ export function fullParser(input: string, opts: FullParserOpts): M.MfmNode[] { const result = language.fullParser.handler(input, 0, { nestLimit: (opts.nestLimit != null) ? opts.nestLimit : 20, fnNameList: opts.fnNameList, + emojiCodeList: opts.emojiCodeList, depth: 0, linkLabel: false, trace: false, diff --git a/src/internal/parser.ts b/src/internal/parser.ts index 3d1a04f..dd76352 100644 --- a/src/internal/parser.ts +++ b/src/internal/parser.ts @@ -628,13 +628,23 @@ export const language = P.createLanguage({ emojiCode: r => { const side = P.notMatch(P.regexp(/[a-z0-9]/i)); const mark = P.str(':'); - return P.seq([ + const parser = P.seq([ P.alt([P.lineBegin, side]), mark, P.regexp(/[a-z0-9_+-]+/i), mark, P.alt([P.lineEnd, side]), - ], 2).map(name => M.EMOJI_CODE(name as string)); + ], 2); + return new P.Parser((input, index, state) => { + const result = parser.handler(input, index, state); + if (!result.success) { + return P.failure(); + } + if (state.emojiCodeList != null && !state.emojiCodeList.includes(result.value)) { + return P.failure(); + } + return P.success(result.index, M.EMOJI_CODE(result.value as string)); + }); }, link: r => {