diff --git a/src/censor/BuiltinStrategies.ts b/src/censor/BuiltinStrategies.ts index 780d7c1..52575c8 100644 --- a/src/censor/BuiltinStrategies.ts +++ b/src/censor/BuiltinStrategies.ts @@ -87,7 +87,7 @@ export function asteriskCensorStrategy() { * @returns A [[TextCensorStrategy]] for use with the [[TextCensor]]. */ export function grawlixCensorStrategy() { - return randomCharFromSetCensorStrategy('%@$&*'); + return randomCharFromSetCensorStrategy('%@$&*', ['@$$']); } /** @@ -152,12 +152,15 @@ export function fixedCharCensorStrategy(char: string): TextCensorStrategy { * be constructed. Must not be empty. * @returns A [[TextCensorStrategy]] for use with the [[TextCensor]]. */ -export function randomCharFromSetCensorStrategy(charset: string): TextCensorStrategy { +export function randomCharFromSetCensorStrategy(charset: string, blacklist?: string[]): TextCensorStrategy { const chars = [...charset]; if (chars.length === 0) throw new Error('The character set passed must not be empty.'); return (ctx: CensorContext) => { - let censored = ''; - for (let i = 0; i < ctx.matchLength; i++) censored += chars[Math.floor(Math.random() * chars.length)]; - return censored; + for (;;) { + let censored = ''; + for (let i = 0; i < ctx.matchLength; i++) censored += chars[Math.floor(Math.random() * chars.length)]; + if (blacklist !== undefined && blacklist.includes(censored)) continue; + return censored; + } }; } diff --git a/test/censor/BuiltinStrategies.test.ts b/test/censor/BuiltinStrategies.test.ts index a95bf64..f5d8c30 100644 --- a/test/censor/BuiltinStrategies.test.ts +++ b/test/censor/BuiltinStrategies.test.ts @@ -144,4 +144,11 @@ describe('randomCharFromSetCensorStrategy()', () => { const strategy = randomCharFromSetCensorStrategy(charset); expect([...strategy({ ...partialCtx, matchLength: 5 })].every((c) => charset.includes(c))).toBeTruthy(); }); + + it('should respect blacklist', () => { + const strategy = randomCharFromSetCensorStrategy('@$', ['@$$']); + for (let i = 0; i < 100; i++) { + expect(strategy({ ...partialCtx, matchLength: 3 })).not.toBe('@$$'); + } + }); });