Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(helpers): add fromRegExp method #1569

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8ae8530
feat: add character class regexp style string parse (close #1359)
wooneusean Nov 19, 2022
8f7c26a
feat: regexp style parsing add negation and dash (close #1359)
wooneusean Nov 19, 2022
fa46afe
Merge branch 'next' into feat/helpers/regexpStyleStringParse-letter-r…
ST-DDT Nov 19, 2022
8c01f86
docs: update regexpStyleStringParse docs
wooneusean Nov 20, 2022
cef0d5c
test(helpers): added missing test for inverted ranges.
wooneusean Nov 20, 2022
6d25ea0
chore: merge next
wooneusean Dec 18, 2022
13ba7c9
feat: add fromRegExp function
wooneusean Dec 18, 2022
301bed7
Merge branch 'next' into feat/helpers/regexpStyleStringParse-letter-r…
ST-DDT Dec 18, 2022
74a11db
fix: fixed negative index for splice function causing removal from ba…
wooneusean Dec 19, 2022
5094a9b
refactor: cleaned up fromRegExp function
wooneusean Dec 20, 2022
6c47f86
test: added non-seeded tests
wooneusean Jan 7, 2023
ec54405
fix: fix typescript errors
wooneusean Jan 7, 2023
bfe14e7
chore: reverted pnpm-lock.yaml
wooneusean Jan 9, 2023
5019f91
Merge remote-tracking branch 'upstream/next' into feat/helpers/regexp…
wooneusean Jan 9, 2023
2a63823
Merge remote-tracking branch 'upstream/next' into feat/helpers/regexp…
wooneusean Jan 11, 2023
ad88fbc
chore: addressed review and merged next
wooneusean Jan 11, 2023
5cd5408
Merge remote-tracking branch 'upstream/next' into feat/helpers/regexp…
wooneusean Jan 12, 2023
9b81969
chore: address test failure and merge next
wooneusean Jan 12, 2023
97e5a0e
Merge remote-tracking branch 'upstream/next' into feat/helpers/regexp…
wooneusean Jan 17, 2023
a8e9a42
docs: removed unneeded example for fromRegExp
wooneusean Jan 17, 2023
201720b
Merge remote-tracking branch 'upstream/next' into feat/helpers/regexp…
wooneusean Jan 18, 2023
ab948f1
fix: removed unnecessary null check
wooneusean Jan 18, 2023
c45ecd3
Merge branch 'next' into feat/helpers/regexpStyleStringParse-letter-r…
ST-DDT Jan 21, 2023
ff685d8
fix: throw error for invalid quantifiers
wooneusean Jan 23, 2023
82a7129
chore: merge next
wooneusean Jan 23, 2023
dc35d9e
chore: merge next
wooneusean Jan 25, 2023
e31b512
test: rewrote tests for fromRegExp
wooneusean Feb 10, 2023
53ff47b
chore: merged next
wooneusean Feb 10, 2023
c13ef4d
feat: added more quantifier options and wildcard
wooneusean Feb 10, 2023
e16699b
docs: update fromRegExp examples
wooneusean Feb 10, 2023
3efaeb2
Merge branch 'next' into feat/helpers/regexpStyleStringParse-letter-r…
ST-DDT Feb 11, 2023
98fcf9e
chore: merge next
wooneusean Feb 25, 2023
9b2b6a3
Merge branch 'feat/helpers/regexpStyleStringParse-letter-range' of ht…
wooneusean Feb 25, 2023
77e85f9
fix: addressed reviews
wooneusean Feb 25, 2023
81dfcd7
chore: merge next
wooneusean Mar 3, 2023
f9c8a2c
fix: resolved reviews and moved quantifer function out of class.
wooneusean Mar 3, 2023
7836043
test: updated snapshots
wooneusean Mar 3, 2023
3cd1a11
chore: merge next
wooneusean Mar 3, 2023
f3fba4c
refactor: moved duplicate code into one function
wooneusean Mar 3, 2023
3a9f7c7
Merge branch 'next' into feat/helpers/regexpStyleStringParse-letter-r…
ST-DDT Mar 16, 2023
2983a8e
chore: merge next
wooneusean Mar 17, 2023
a232d3d
fix: address review
wooneusean Mar 17, 2023
00a838f
chore: merge next
wooneusean Mar 26, 2023
68cfc9b
fix: changed fallback repetition to 1 instead of 0
wooneusean Mar 26, 2023
d06bc55
fix: corrected typo and clarified character encoding in JSDoc
wooneusean Mar 26, 2023
6360860
Merge branch 'next' into feat/helpers/regexpStyleStringParse-letter-r…
ST-DDT Mar 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 113 additions & 23 deletions src/modules/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,29 +165,137 @@ export class HelpersModule {
* Supported patterns:
* - `.{times}` => Repeat the character exactly `times` times.
* - `.{min,max}` => Repeat the character `min` to `max` times.
* - `[min-max]` => Generate a number between min and max (inclusive).
* - `[x-y]` => Randomly get a character between `x` and `y` (inclusive).
* - `[x-y]{times}` => Randomly get a character between `x` and `y` (inclusive) and repeat it `times` times.
* - `[x-y]{min,max}` => Randomly get a character between `x` and `y` (inclusive) and repeat it `min` to `max` times.
* - `[^...]` => Randomly get a character that is not in the given range. (e.g. `[^0-9]` will get a random non-numeric character)
* - `[-...]` => Include dashes in the range. Must be placed after the negate character `^` and before any character sets if used . (e.g. `[^-0-9]` will not get any numeric characters or dashes)
*
* @param string The template string to to parse.
*
* @example
* faker.helpers.regexpStyleStringParse() // ''
* faker.helpers.regexpStyleStringParse('#{5}') // '#####'
* faker.helpers.regexpStyleStringParse('#{2,9}') // '#######'
* faker.helpers.regexpStyleStringParse('[500-15000]') // '8375'
* faker.helpers.regexpStyleStringParse('[1-7]') // '5'
ST-DDT marked this conversation as resolved.
Show resolved Hide resolved
* faker.helpers.regexpStyleStringParse('#{3}test[1-5]') // '###test3'
* faker.helpers.regexpStyleStringParse('[0-9a-dmno]') // '5' | 'c' | 'o'
* faker.helpers.regexpStyleStringParse('[^a-zA-Z0-8]') // '9'
* faker.helpers.regexpStyleStringParse('[a-d0-6]{2,8}') // 'a0' | 'd6' | 'a0dc45b0'
* faker.helpers.regexpStyleStringParse('[-a-z]{5}') // 'a-zab'
*
* @since 5.0.0
*/
regexpStyleStringParse(string: string = ''): string {
// Deal with range repeat `{min,max}`
const RANGE_REP_REG = /(.)\{(\d+)\,(\d+)\}/;
const REP_REG = /(.)\{(\d+)\}/;
const RANGE_REG = /\[(\d+)\-(\d+)\]/;
const RANGE_ALPHANUMEMRIC_REG =
/\[(\^|)(-|)(.+)\](?:\{(\d+)(?:\,(\d+)|)\}|)/;

let min: number;
let max: number;
let tmp: number;
let repetitions: number;
let token = string.match(RANGE_REP_REG);

// Deal with character classes with quantifiers `[a-z0-9]{min[, max]}`
let token = string.match(RANGE_ALPHANUMEMRIC_REG);
const SINGLE_RANGE_REG = /(\d-\d|\w-\w|\d|\w)/;
while (token != null) {
const isNegated = token[1] === '^';
const includesDash: boolean = token[2] === '-';
const quantifierMin: string = token[4];
const quantifierMax: string = token[5];

const rangeCodes: number[] = [];

if (isNegated) {
// 0-9
for (let i = 48; i <= 57; i++) {
rangeCodes.push(i);
}
// a-z
for (let i = 65; i <= 90; i++) {
rangeCodes.push(i);
}
// A-Z
for (let i = 97; i <= 122; i++) {
rangeCodes.push(i);
}
}

if (!quantifierMin) {
repetitions = 1;
} else {
repetitions = parseInt(quantifierMin);
}

let ranges = token[3];
let range = ranges.match(SINGLE_RANGE_REG);

if (includesDash) {
// 45 is the ascii code for '-'
if (isNegated) {
rangeCodes.splice(rangeCodes.indexOf(45), 1);
} else {
rangeCodes.push(45);
}
}

while (range != null) {
if (range[0].indexOf('-') === -1) {
if (isNegated) {
rangeCodes.splice(rangeCodes.indexOf(range[0].charCodeAt(0)), 1);
} else {
rangeCodes.push(range[0].charCodeAt(0));
}
} else {
const rangeMinMax = range[0].split('-').map((x) => x.charCodeAt(0));
min = rangeMinMax[0];
max = rangeMinMax[1];
// switch min and max
if (min > max) {
tmp = min;
min = max;
max = tmp;
}
for (let i = min; i <= max; i++) {
if (isNegated) {
rangeCodes.splice(rangeCodes.indexOf(i), 1);
} else {
rangeCodes.push(i);
}
}
}

ranges = ranges.substring(range[0].length);
range = ranges.match(SINGLE_RANGE_REG);
}

if (quantifierMax) {
repetitions = this.faker.datatype.number({
min: parseInt(quantifierMin),
max: parseInt(quantifierMax),
});
}

const generatedString = Array.from(Array(repetitions)).reduce(
(acc: string) =>
acc +
String.fromCharCode(
rangeCodes[this.faker.datatype.number(rangeCodes.length - 1)]
),
''
);

string =
string.slice(0, token.index) +
generatedString +
string.slice(token.index + token[0].length);
token = string.match(RANGE_ALPHANUMEMRIC_REG);
}

// Deal with quantifier ranges `{min,max}`
token = string.match(RANGE_REP_REG);
while (token != null) {
min = parseInt(token[2]);
max = parseInt(token[3]);
Expand All @@ -214,25 +322,7 @@ export class HelpersModule {
string.slice(token.index + token[0].length);
token = string.match(REP_REG);
}
// Deal with range `[min-max]` (only works with numbers for now)
//TODO: implement for letters e.g. [0-9a-zA-Z] etc.

token = string.match(RANGE_REG);
while (token != null) {
min = parseInt(token[1]); // This time we are not capturing the char before `[]`
max = parseInt(token[2]);
// switch min and max
if (min > max) {
tmp = max;
max = min;
min = tmp;
}
string =
string.slice(0, token.index) +
this.faker.datatype.number({ min: min, max: max }).toString() +
string.slice(token.index + token[0].length);
token = string.match(RANGE_REG);
}
return string;
}

Expand Down
30 changes: 30 additions & 0 deletions test/__snapshots__/helpers.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,22 @@ exports[`helpers > 42 > objectKey > simple 1`] = `"b"`;

exports[`helpers > 42 > objectValue > simple 1`] = `2`;

exports[`helpers > 42 > regexpStyleStringParse > character class 1`] = `"Hello !#####test685"`;

exports[`helpers > 42 > regexpStyleStringParse > dash 1`] = `"!#####test774"`;

exports[`helpers > 42 > regexpStyleStringParse > negate 1`] = `"!#####testjpF"`;

exports[`helpers > 42 > regexpStyleStringParse > negate and dash 1`] = `"!#####testioF"`;

exports[`helpers > 42 > regexpStyleStringParse > noArgs 1`] = `""`;

exports[`helpers > 42 > regexpStyleStringParse > only symbols 1`] = `"###test2"`;

exports[`helpers > 42 > regexpStyleStringParse > some string 1`] = `"Hello !###test2"`;

exports[`helpers > 42 > regexpStyleStringParse > swap range if start is greater than end 1`] = `"j"`;

exports[`helpers > 42 > replaceCreditCardSymbols > noArgs 1`] = `"6453-3791-7755-1410-0489"`;

exports[`helpers > 42 > replaceCreditCardSymbols > only symbols 1`] = `"7917-6-7563-4"`;
Expand Down Expand Up @@ -193,12 +203,22 @@ exports[`helpers > 1211 > objectKey > simple 1`] = `"c"`;

exports[`helpers > 1211 > objectValue > simple 1`] = `3`;

exports[`helpers > 1211 > regexpStyleStringParse > character class 1`] = `"Hello !###testf86538"`;

exports[`helpers > 1211 > regexpStyleStringParse > dash 1`] = `"!###testf67538"`;

exports[`helpers > 1211 > regexpStyleStringParse > negate 1`] = `"!###testPniHDq"`;

exports[`helpers > 1211 > regexpStyleStringParse > negate and dash 1`] = `"!###testPmiHDp"`;

exports[`helpers > 1211 > regexpStyleStringParse > noArgs 1`] = `""`;

exports[`helpers > 1211 > regexpStyleStringParse > only symbols 1`] = `"###test5"`;

exports[`helpers > 1211 > regexpStyleStringParse > some string 1`] = `"Hello !###test5"`;

exports[`helpers > 1211 > regexpStyleStringParse > swap range if start is greater than end 1`] = `"y"`;

exports[`helpers > 1211 > replaceCreditCardSymbols > noArgs 1`] = `"6453-9487-2190-6162-7434"`;

exports[`helpers > 1211 > replaceCreditCardSymbols > only symbols 1`] = `"4872-9-1927-1"`;
Expand Down Expand Up @@ -331,12 +351,22 @@ exports[`helpers > 1337 > objectKey > simple 1`] = `"a"`;

exports[`helpers > 1337 > objectValue > simple 1`] = `1`;

exports[`helpers > 1337 > regexpStyleStringParse > character class 1`] = `"Hello !###test145"`;

exports[`helpers > 1337 > regexpStyleStringParse > dash 1`] = `"!###test135"`;

exports[`helpers > 1337 > regexpStyleStringParse > negate 1`] = `"!###testTEG"`;

exports[`helpers > 1337 > regexpStyleStringParse > negate and dash 1`] = `"!###testTEG"`;

exports[`helpers > 1337 > regexpStyleStringParse > noArgs 1`] = `""`;

exports[`helpers > 1337 > regexpStyleStringParse > only symbols 1`] = `"###test2"`;

exports[`helpers > 1337 > regexpStyleStringParse > some string 1`] = `"Hello !###test2"`;

exports[`helpers > 1337 > regexpStyleStringParse > swap range if start is greater than end 1`] = `"g"`;

exports[`helpers > 1337 > replaceCreditCardSymbols > noArgs 1`] = `"6453-2512-2540-3255-2399"`;

exports[`helpers > 1337 > replaceCreditCardSymbols > only symbols 1`] = `"5122-5-5424-8"`;
Expand Down
7 changes: 6 additions & 1 deletion test/helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ describe('helpers', () => {
t.describe('regexpStyleStringParse', (t) => {
t.it('noArgs')
.it('only symbols', '#{3}test[1-5]')
.it('some string', 'Hello !#{3}test[1-5]');
.it('some string', 'Hello !#{3}test[1-5]')
.it('character class', 'Hello !#{3,5}test[1-5a-g]{10}[5-8]{2,6}')
.it('dash', '!#{3,5}test[-1-5a-g]{10}[-5-8]{2,6}')
.it('negate', '!#{3,5}test[^1-5a-g]{10}[^-5-8]{2,6}')
.it('negate and dash', '!#{3,5}test[^-1-5a-g]{10}[^-5-8]{2,6}')
.it('swap range if start is greater than end', '[z-a]');
});

t.describe('mustache', (t) => {
Expand Down