Skip to content

Commit a0d25bb

Browse files
authored
feat: allow banned as string (#819)
1 parent 58145dd commit a0d25bb

2 files changed

Lines changed: 167 additions & 6 deletions

File tree

src/modules/random/index.ts

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,85 @@
11
import type { Faker } from '../..';
22
import { FakerError } from '../../errors/faker-error';
33
import { deprecated } from '../../internal/deprecated';
4+
import type { LiteralUnion } from '../../utils/types';
45

56
export type Casing = 'upper' | 'lower' | 'mixed';
67

78
const UPPER_CHARS: readonly string[] = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
89
const LOWER_CHARS: readonly string[] = 'abcdefghijklmnopqrstuvwxyz'.split('');
910
const DIGIT_CHARS: readonly string[] = '0123456789'.split('');
1011

12+
export type LowerAlphaChar =
13+
| 'a'
14+
| 'b'
15+
| 'c'
16+
| 'd'
17+
| 'e'
18+
| 'f'
19+
| 'g'
20+
| 'h'
21+
| 'i'
22+
| 'j'
23+
| 'k'
24+
| 'l'
25+
| 'm'
26+
| 'n'
27+
| 'o'
28+
| 'p'
29+
| 'q'
30+
| 'r'
31+
| 's'
32+
| 't'
33+
| 'u'
34+
| 'v'
35+
| 'w'
36+
| 'x'
37+
| 'y'
38+
| 'z';
39+
40+
export type UpperAlphaChar =
41+
| 'A'
42+
| 'B'
43+
| 'C'
44+
| 'D'
45+
| 'E'
46+
| 'F'
47+
| 'G'
48+
| 'H'
49+
| 'I'
50+
| 'J'
51+
| 'K'
52+
| 'L'
53+
| 'M'
54+
| 'N'
55+
| 'O'
56+
| 'P'
57+
| 'Q'
58+
| 'R'
59+
| 'S'
60+
| 'T'
61+
| 'U'
62+
| 'V'
63+
| 'W'
64+
| 'X'
65+
| 'Y'
66+
| 'Z';
67+
68+
export type NumericChar =
69+
| '0'
70+
| '1'
71+
| '2'
72+
| '3'
73+
| '4'
74+
| '5'
75+
| '6'
76+
| '7'
77+
| '8'
78+
| '9';
79+
80+
export type AlphaChar = LowerAlphaChar | UpperAlphaChar;
81+
export type AlphaNumericChar = AlphaChar | NumericChar;
82+
1183
/**
1284
* Method to reduce array of characters.
1385
*
@@ -172,15 +244,21 @@ export class Random {
172244
*/
173245
upcase?: boolean;
174246
casing?: Casing;
175-
bannedChars?: readonly string[];
247+
bannedChars?: readonly LiteralUnion<AlphaChar>[] | string;
176248
} = {}
177249
): string {
178250
if (typeof options === 'number') {
179251
options = {
180252
count: options,
181253
};
182254
}
183-
const { count = 1, upcase, bannedChars = [] } = options;
255+
256+
const { count = 1, upcase } = options;
257+
let { bannedChars = [] } = options;
258+
259+
if (typeof bannedChars === 'string') {
260+
bannedChars = bannedChars.split('');
261+
}
184262

185263
if (count <= 0) {
186264
return '';
@@ -244,7 +322,7 @@ export class Random {
244322
count: number = 1,
245323
options: {
246324
casing?: Casing;
247-
bannedChars?: readonly string[];
325+
bannedChars?: readonly LiteralUnion<AlphaNumericChar>[] | string;
248326
} = {}
249327
): string {
250328
if (count <= 0) {
@@ -254,8 +332,12 @@ export class Random {
254332
const {
255333
// Switch to 'mixed' with v8.0
256334
casing = 'lower',
257-
bannedChars = [],
258335
} = options;
336+
let { bannedChars = [] } = options;
337+
338+
if (typeof bannedChars === 'string') {
339+
bannedChars = bannedChars.split('');
340+
}
259341

260342
let charsArray = [...DIGIT_CHARS];
261343

@@ -304,14 +386,19 @@ export class Random {
304386
length: number = 1,
305387
options: {
306388
allowLeadingZeros?: boolean;
307-
bannedDigits?: readonly string[];
389+
bannedDigits?: readonly LiteralUnion<NumericChar>[] | string;
308390
} = {}
309391
): string {
310392
if (length <= 0) {
311393
return '';
312394
}
313395

314-
const { allowLeadingZeros = false, bannedDigits = [] } = options;
396+
const { allowLeadingZeros = false } = options;
397+
let { bannedDigits = [] } = options;
398+
399+
if (typeof bannedDigits === 'string') {
400+
bannedDigits = bannedDigits.split('');
401+
}
315402

316403
const allowedDigits = DIGIT_CHARS.filter(
317404
(digit) => !bannedDigits.includes(digit)

test/random.spec.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ describe('random', () => {
213213
expect(actual).toMatch(/^[b-oq-z]{5}$/);
214214
});
215215

216+
it('should be able to ban some characters via string', () => {
217+
const actual = faker.random.alpha({
218+
count: 5,
219+
bannedChars: 'ap',
220+
});
221+
222+
expect(actual).toHaveLength(5);
223+
expect(actual).toMatch(/^[b-oq-z]{5}$/);
224+
});
225+
216226
it('should be able handle mistake in banned characters array', () => {
217227
const alphaText = faker.random.alpha({
218228
count: 5,
@@ -296,6 +306,18 @@ describe('random', () => {
296306
}
297307
});
298308

309+
it('should be able to ban all alphabetic characters via string', () => {
310+
const bannedChars = 'abcdefghijklmnopqrstuvwxyz';
311+
const alphaText = faker.random.alphaNumeric(5, {
312+
bannedChars,
313+
});
314+
315+
expect(alphaText).toHaveLength(5);
316+
for (const bannedChar of bannedChars) {
317+
expect(alphaText).not.includes(bannedChar);
318+
}
319+
});
320+
299321
it('should be able to ban all numeric characters', () => {
300322
const bannedChars = '0123456789'.split('');
301323
const alphaText = faker.random.alphaNumeric(5, {
@@ -308,6 +330,18 @@ describe('random', () => {
308330
}
309331
});
310332

333+
it('should be able to ban all numeric characters via string', () => {
334+
const bannedChars = '0123456789';
335+
const alphaText = faker.random.alphaNumeric(5, {
336+
bannedChars,
337+
});
338+
339+
expect(alphaText).toHaveLength(5);
340+
for (const bannedChar of bannedChars) {
341+
expect(alphaText).not.includes(bannedChar);
342+
}
343+
});
344+
311345
it('should be able to handle mistake in banned characters array', () => {
312346
const alphaText = faker.random.alphaNumeric(5, {
313347
bannedChars: ['a', 'p', 'a'],
@@ -330,6 +364,15 @@ describe('random', () => {
330364
);
331365
});
332366

367+
it('should throw if all possible characters being banned via string', () => {
368+
const bannedChars = 'abcdefghijklmnopqrstuvwxyz0123456789';
369+
expect(() =>
370+
faker.random.alphaNumeric(5, {
371+
bannedChars,
372+
})
373+
).toThrowError();
374+
});
375+
333376
it('should not mutate the input object', () => {
334377
const input: {
335378
bannedChars: string[];
@@ -395,6 +438,15 @@ describe('random', () => {
395438
expect(actual).toBe('0000');
396439
});
397440

441+
it('should allow leading zeros via option and all other digits banned via string', () => {
442+
const actual = faker.random.numeric(4, {
443+
allowLeadingZeros: true,
444+
bannedDigits: '123456789',
445+
});
446+
447+
expect(actual).toBe('0000');
448+
});
449+
398450
it('should fail on leading zeros via option and all other digits banned', () => {
399451
expect(() =>
400452
faker.random.numeric(4, {
@@ -408,6 +460,19 @@ describe('random', () => {
408460
);
409461
});
410462

463+
it('should fail on leading zeros via option and all other digits banned via string', () => {
464+
expect(() =>
465+
faker.random.numeric(4, {
466+
allowLeadingZeros: false,
467+
bannedDigits: '123456789',
468+
})
469+
).toThrowError(
470+
new FakerError(
471+
'Unable to generate numeric string, because all possible digits are banned.'
472+
)
473+
);
474+
});
475+
411476
it('should ban all digits passed via bannedDigits', () => {
412477
const actual = faker.random.numeric(1000, {
413478
bannedDigits: 'c84U1'.split(''),
@@ -416,6 +481,15 @@ describe('random', () => {
416481
expect(actual).toHaveLength(1000);
417482
expect(actual).toMatch(/^[0235679]{1000}$/);
418483
});
484+
485+
it('should ban all digits passed via bannedDigits via string', () => {
486+
const actual = faker.random.numeric(1000, {
487+
bannedDigits: 'c84U1',
488+
});
489+
490+
expect(actual).toHaveLength(1000);
491+
expect(actual).toMatch(/^[0235679]{1000}$/);
492+
});
419493
});
420494
});
421495
});

0 commit comments

Comments
 (0)