From 9498203190e37a96114ddc8e861b02ccd94e517b Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Tue, 7 Nov 2023 17:12:47 +0100 Subject: [PATCH 1/3] infra(unicorn): no-negated-condition (#2507) --- .eslintrc.js | 1 - scripts/apidoc/diff.ts | 4 ++-- src/modules/helpers/index.ts | 22 +++++++++++----------- src/modules/image/index.ts | 2 +- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index f2115380033..7e60b795af8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -52,7 +52,6 @@ module.exports = defineConfig({ 'unicorn/no-array-callback-reference': 'off', 'unicorn/no-array-reduce': 'off', 'unicorn/no-await-expression-member': 'off', - 'unicorn/no-negated-condition': 'off', 'unicorn/no-object-as-default-parameter': 'off', 'unicorn/no-useless-switch-case': 'off', 'unicorn/numeric-separators-style': 'off', diff --git a/scripts/apidoc/diff.ts b/scripts/apidoc/diff.ts index 18b8e60fc4d..101200cd93b 100644 --- a/scripts/apidoc/diff.ts +++ b/scripts/apidoc/diff.ts @@ -12,9 +12,9 @@ async function loadRemote(url: string): Promise { throw new Error( `Failed to load remote diff index from ${url}: ${res.statusText}` ); - } else { - return res.json() as Promise; } + + return res.json() as Promise; }); } diff --git a/src/modules/helpers/index.ts b/src/modules/helpers/index.ts index ff93f2caf4c..f7d9538bce1 100644 --- a/src/modules/helpers/index.ts +++ b/src/modules/helpers/index.ts @@ -456,17 +456,7 @@ export class SimpleHelpersModule extends SimpleModuleBase { } while (range != null) { - if (!range[0].includes('-')) { - // handle non-ranges - if (isCaseInsensitive && Number.isNaN(Number(range[0]))) { - rangeCodes.push( - range[0].toUpperCase().charCodeAt(0), - range[0].toLowerCase().charCodeAt(0) - ); - } else { - rangeCodes.push(range[0].charCodeAt(0)); - } - } else { + if (range[0].includes('-')) { // handle ranges const rangeMinMax = range[0].split('-').map((x) => x.charCodeAt(0)); min = rangeMinMax[0]; @@ -490,6 +480,16 @@ export class SimpleHelpersModule extends SimpleModuleBase { rangeCodes.push(i); } } + } else { + // handle non-ranges + if (isCaseInsensitive && Number.isNaN(Number(range[0]))) { + rangeCodes.push( + range[0].toUpperCase().charCodeAt(0), + range[0].toLowerCase().charCodeAt(0) + ); + } else { + rangeCodes.push(range[0].charCodeAt(0)); + } } ranges = ranges.substring(range[0].length); diff --git a/src/modules/image/index.ts b/src/modules/image/index.ts index 915014db07e..f5f24711b3c 100644 --- a/src/modules/image/index.ts +++ b/src/modules/image/index.ts @@ -175,7 +175,7 @@ export class ImageModule extends ModuleBase { const { width = 640, height = 480, category } = options; return `https://loremflickr.com/${width}/${height}${ - category != null ? `/${category}` : '' + category == null ? '' : `/${category}` }?lock=${this.faker.number.int()}`; } From 8542ef30bd4eda3d9f04db2c4a79abf0369d57c3 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Tue, 7 Nov 2023 17:26:27 +0100 Subject: [PATCH 2/3] infra(unicorn): no-array-reduce (#2479) --- .eslintrc.js | 1 - scripts/apidoc/writer.ts | 23 ++++---- src/internal/group-by.ts | 25 ++++++++ .../word/filter-word-list-by-length.ts | 10 +--- test/all-functional.spec.ts | 59 ++++++++++--------- test/scripts/apidoc/verify-jsdoc-tags.spec.ts | 18 +++--- 6 files changed, 76 insertions(+), 60 deletions(-) create mode 100644 src/internal/group-by.ts diff --git a/.eslintrc.js b/.eslintrc.js index 7e60b795af8..16d720b964f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -50,7 +50,6 @@ module.exports = defineConfig({ 'unicorn/consistent-function-scoping': 'off', 'unicorn/import-style': 'off', 'unicorn/no-array-callback-reference': 'off', - 'unicorn/no-array-reduce': 'off', 'unicorn/no-await-expression-member': 'off', 'unicorn/no-object-as-default-parameter': 'off', 'unicorn/no-useless-switch-case': 'off', diff --git a/scripts/apidoc/writer.ts b/scripts/apidoc/writer.ts index b5fa5806df6..0fc7ae78486 100644 --- a/scripts/apidoc/writer.ts +++ b/scripts/apidoc/writer.ts @@ -63,20 +63,17 @@ export async function writeApiDocsModule( text: moduleName, link: `/api/${lowerModuleName}.html`, methods, - diff: methods.reduce( - (data, method) => ({ - ...data, - [method.name]: methodDiffHash(method), + diff: { + moduleHash: diffHash({ + name: moduleName, + field: lowerModuleName, + deprecated, + comment, }), - { - moduleHash: diffHash({ - name: moduleName, - field: lowerModuleName, - deprecated, - comment, - }), - } - ), + ...Object.fromEntries( + methods.map((method) => [method.name, methodDiffHash(method)]) + ), + }, }; } diff --git a/src/internal/group-by.ts b/src/internal/group-by.ts new file mode 100644 index 00000000000..ff3242c9ebb --- /dev/null +++ b/src/internal/group-by.ts @@ -0,0 +1,25 @@ +/** + * Groups the values by the key function. + * + * @internal + * + * @param values The values to group. + * @param keyFunction The function to get the key from the value. + */ +export function groupBy( + values: ReadonlyArray, + keyFunction: (value: TValue) => string | number +): Record { + const result: Record = {}; + + for (const value of values) { + const key = keyFunction(value); + if (result[key] === undefined) { + result[key] = []; + } + + result[key].push(value); + } + + return result; +} diff --git a/src/modules/word/filter-word-list-by-length.ts b/src/modules/word/filter-word-list-by-length.ts index 60c6fae93c9..f3fcd5abfee 100644 --- a/src/modules/word/filter-word-list-by-length.ts +++ b/src/modules/word/filter-word-list-by-length.ts @@ -1,4 +1,5 @@ import { FakerError } from '../../errors/faker-error'; +import { groupBy } from '../../internal/group-by'; /** * The error handling strategies for the `filterWordListByLength` function. @@ -13,14 +14,7 @@ const STRATEGIES = { wordList: ReadonlyArray, length: { min: number; max: number } ): string[] => { - const wordsByLength = wordList.reduce>( - (data, word) => { - (data[word.length] = data[word.length] ?? []).push(word); - return data; - }, - {} - ); - + const wordsByLength = groupBy(wordList, (word) => word.length); const lengths = Object.keys(wordsByLength).map(Number); const min = Math.min(...lengths); const max = Math.max(...lengths); diff --git a/test/all-functional.spec.ts b/test/all-functional.spec.ts index 91c310b2b3d..c5bef114d2c 100644 --- a/test/all-functional.spec.ts +++ b/test/all-functional.spec.ts @@ -10,12 +10,36 @@ const IGNORED_MODULES = new Set([ '_defaultRefDate', ]); -function isTestableModule(mod: string) { - return !IGNORED_MODULES.has(mod); +function getMethodNamesByModules(faker: Faker): { [module: string]: string[] } { + return Object.fromEntries( + Object.keys(faker) + .filter(isTestableModule) + .sort() + .map<[string, string[]]>((moduleName) => [ + moduleName, + getMethodNamesOf(faker[moduleName]), + ]) + .filter(([module, methods]) => { + if (methods.length === 0) { + console.log(`Skipping ${module} - No testable methods`); + return false; + } + + return true; + }) + ); +} + +function isTestableModule(moduleName: string): moduleName is keyof Faker { + return !IGNORED_MODULES.has(moduleName); +} + +function getMethodNamesOf(module: object): string[] { + return Object.keys(module).filter(isMethodOf(module)); } -function isMethodOf(mod: string) { - return (meth: string) => typeof fakerEN[mod][meth] === 'function'; +function isMethodOf(module: object): (method: string) => boolean { + return (method: string) => typeof module[method] === 'function'; } type SkipConfig = Partial< @@ -53,36 +77,17 @@ const BROKEN_LOCALE_METHODS = { }; function isWorkingLocaleForMethod( - mod: string, - meth: string, + module: string, + method: string, locale: string ): boolean { - const broken = BROKEN_LOCALE_METHODS[mod]?.[meth] ?? []; + const broken = BROKEN_LOCALE_METHODS[module]?.[method] ?? []; return broken !== '*' && !broken.includes(locale); } // Basic smoke tests to make sure each method is at least implemented and returns a value. -function modulesList(): { [module: string]: string[] } { - const modules = Object.keys(fakerEN) - .sort() - .filter(isTestableModule) - .reduce((result, mod) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - const methods = Object.keys(fakerEN[mod]).filter(isMethodOf(mod)); - if (methods.length > 0) { - result[mod] = methods; - } else { - console.log(`Skipping ${mod} - No testable methods`); - } - - return result; - }, {}); - - return modules; -} - -const modules = modulesList(); +const modules = getMethodNamesByModules(fakerEN); describe('BROKEN_LOCALE_METHODS test', () => { it('should not contain obsolete configuration (modules)', () => { diff --git a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts index a924c268213..47eca926d97 100644 --- a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts +++ b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts @@ -47,28 +47,24 @@ describe('verify JSDoc tags', () => { } const allowedReferences = new Set( - Object.values(modules).reduce((acc, [module, methods]) => { + Object.values(modules).flatMap(([module, methods]) => { const moduleFieldName = extractModuleFieldName(module); - return [ - ...acc, - ...Object.keys(methods).map( - (methodName) => `faker.${moduleFieldName}.${methodName}` - ), - ]; - }, []) + return Object.keys(methods).map( + (methodName) => `faker.${moduleFieldName}.${methodName}` + ); + }) ); const allowedLinks = new Set( - Object.values(modules).reduce((acc, [module, methods]) => { + Object.values(modules).flatMap(([module, methods]) => { const moduleFieldName = extractModuleFieldName(module); return [ - ...acc, `/api/${moduleFieldName}.html`, ...Object.keys(methods).map( (methodName) => `/api/${moduleFieldName}.html#${methodName.toLowerCase()}` ), ]; - }, []) + }) ); function assertDescription(description: string, isHtml: boolean): void { From e0ba50b37e438503ed1899bff35afc92b4f8f49c Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Tue, 7 Nov 2023 17:42:14 +0100 Subject: [PATCH 3/3] fix(finance): maskedNumber has incorrect defaults (#2494) --- src/modules/finance/index.ts | 2 +- .../__snapshots__/finance.spec.ts.snap | 54 +++++++++---------- test/modules/finance.spec.ts | 6 +++ 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/modules/finance/index.ts b/src/modules/finance/index.ts index ddf3fffe988..4e0d80ed69b 100644 --- a/src/modules/finance/index.ts +++ b/src/modules/finance/index.ts @@ -345,7 +345,7 @@ export class FinanceModule extends ModuleBase { options = { length: options }; } - const { ellipsis, length = 4, parens } = options; + const { ellipsis = true, length = 4, parens = true } = options; let template = this.faker.string.numeric({ length }); diff --git a/test/modules/__snapshots__/finance.spec.ts.snap b/test/modules/__snapshots__/finance.spec.ts.snap index b80380b96e0..324aad22bf9 100644 --- a/test/modules/__snapshots__/finance.spec.ts.snap +++ b/test/modules/__snapshots__/finance.spec.ts.snap @@ -78,23 +78,23 @@ exports[`finance > 42 > iban > with formatted option 1`] = `"GT03 9751 1086 7098 exports[`finance > 42 > litecoinAddress 1`] = `"3XbJMAAara64sSkA9HD24YHQWd1b"`; -exports[`finance > 42 > mask > noArgs 1`] = `"3791"`; +exports[`finance > 42 > mask > noArgs 1`] = `"(...3791)"`; -exports[`finance > 42 > mask > with ellipsis 1`] = `"...3791"`; +exports[`finance > 42 > mask > with ellipsis 1`] = `"(...3791)"`; -exports[`finance > 42 > mask > with length 1`] = `"37917"`; +exports[`finance > 42 > mask > with length 1`] = `"(...37917)"`; exports[`finance > 42 > mask > with length, parenthesis and ellipsis 1`] = `"(...37917)"`; -exports[`finance > 42 > mask > with parenthesis 1`] = `"(3791)"`; +exports[`finance > 42 > mask > with parenthesis 1`] = `"(...3791)"`; -exports[`finance > 42 > maskedNumber > noArgs 1`] = `"3791"`; +exports[`finance > 42 > maskedNumber > noArgs 1`] = `"(...3791)"`; -exports[`finance > 42 > maskedNumber > with length 1`] = `"37917"`; +exports[`finance > 42 > maskedNumber > with length 1`] = `"(...37917)"`; -exports[`finance > 42 > maskedNumber > with length and parenthesis option 1`] = `"37917"`; +exports[`finance > 42 > maskedNumber > with length and parenthesis option 1`] = `"...37917"`; -exports[`finance > 42 > maskedNumber > with length option 1`] = `"37917"`; +exports[`finance > 42 > maskedNumber > with length option 1`] = `"(...37917)"`; exports[`finance > 42 > maskedNumber > with length, parenthesis and ellipsis option 1`] = `"...37917"`; @@ -106,7 +106,7 @@ exports[`finance > 42 > pin > with length option 1`] = `"3791775514"`; exports[`finance > 42 > routingNumber 1`] = `"379177554"`; -exports[`finance > 42 > transactionDescription 1`] = `"invoice transaction at Wiegand, Deckow and Reynolds using card ending with ***8361 for RSD 374.54 in account ***55141004"`; +exports[`finance > 42 > transactionDescription 1`] = `"invoice transaction at Wiegand, Deckow and Reynolds using card ending with ***(...8361) for RSD 374.54 in account ***55141004"`; exports[`finance > 42 > transactionType 1`] = `"withdrawal"`; @@ -188,23 +188,23 @@ exports[`finance > 1211 > iban > with formatted option 1`] = `"TN42 8201 6024 17 exports[`finance > 1211 > litecoinAddress 1`] = `"MTMe8Z3EaFdLqmaGKP1LEEJQVriSZRZds"`; -exports[`finance > 1211 > mask > noArgs 1`] = `"9487"`; +exports[`finance > 1211 > mask > noArgs 1`] = `"(...9487)"`; -exports[`finance > 1211 > mask > with ellipsis 1`] = `"...9487"`; +exports[`finance > 1211 > mask > with ellipsis 1`] = `"(...9487)"`; -exports[`finance > 1211 > mask > with length 1`] = `"94872"`; +exports[`finance > 1211 > mask > with length 1`] = `"(...94872)"`; exports[`finance > 1211 > mask > with length, parenthesis and ellipsis 1`] = `"(...94872)"`; -exports[`finance > 1211 > mask > with parenthesis 1`] = `"(9487)"`; +exports[`finance > 1211 > mask > with parenthesis 1`] = `"(...9487)"`; -exports[`finance > 1211 > maskedNumber > noArgs 1`] = `"9487"`; +exports[`finance > 1211 > maskedNumber > noArgs 1`] = `"(...9487)"`; -exports[`finance > 1211 > maskedNumber > with length 1`] = `"94872"`; +exports[`finance > 1211 > maskedNumber > with length 1`] = `"(...94872)"`; -exports[`finance > 1211 > maskedNumber > with length and parenthesis option 1`] = `"94872"`; +exports[`finance > 1211 > maskedNumber > with length and parenthesis option 1`] = `"...94872"`; -exports[`finance > 1211 > maskedNumber > with length option 1`] = `"94872"`; +exports[`finance > 1211 > maskedNumber > with length option 1`] = `"(...94872)"`; exports[`finance > 1211 > maskedNumber > with length, parenthesis and ellipsis option 1`] = `"...94872"`; @@ -216,7 +216,7 @@ exports[`finance > 1211 > pin > with length option 1`] = `"9487219061"`; exports[`finance > 1211 > routingNumber 1`] = `"948721904"`; -exports[`finance > 1211 > transactionDescription 1`] = `"deposit transaction at Trantow - Satterfield using card ending with ***4316 for SDG 928.52 in account ***19061627"`; +exports[`finance > 1211 > transactionDescription 1`] = `"deposit transaction at Trantow - Satterfield using card ending with ***(...4316) for SDG 928.52 in account ***19061627"`; exports[`finance > 1211 > transactionType 1`] = `"invoice"`; @@ -298,23 +298,23 @@ exports[`finance > 1337 > iban > with formatted option 1`] = `"FO56 1005 0250 09 exports[`finance > 1337 > litecoinAddress 1`] = `"Madhxs2jewAgkYgJi7No6Cn8JZar"`; -exports[`finance > 1337 > mask > noArgs 1`] = `"2512"`; +exports[`finance > 1337 > mask > noArgs 1`] = `"(...2512)"`; -exports[`finance > 1337 > mask > with ellipsis 1`] = `"...2512"`; +exports[`finance > 1337 > mask > with ellipsis 1`] = `"(...2512)"`; -exports[`finance > 1337 > mask > with length 1`] = `"25122"`; +exports[`finance > 1337 > mask > with length 1`] = `"(...25122)"`; exports[`finance > 1337 > mask > with length, parenthesis and ellipsis 1`] = `"(...25122)"`; -exports[`finance > 1337 > mask > with parenthesis 1`] = `"(2512)"`; +exports[`finance > 1337 > mask > with parenthesis 1`] = `"(...2512)"`; -exports[`finance > 1337 > maskedNumber > noArgs 1`] = `"2512"`; +exports[`finance > 1337 > maskedNumber > noArgs 1`] = `"(...2512)"`; -exports[`finance > 1337 > maskedNumber > with length 1`] = `"25122"`; +exports[`finance > 1337 > maskedNumber > with length 1`] = `"(...25122)"`; -exports[`finance > 1337 > maskedNumber > with length and parenthesis option 1`] = `"25122"`; +exports[`finance > 1337 > maskedNumber > with length and parenthesis option 1`] = `"...25122"`; -exports[`finance > 1337 > maskedNumber > with length option 1`] = `"25122"`; +exports[`finance > 1337 > maskedNumber > with length option 1`] = `"(...25122)"`; exports[`finance > 1337 > maskedNumber > with length, parenthesis and ellipsis option 1`] = `"...25122"`; @@ -326,6 +326,6 @@ exports[`finance > 1337 > pin > with length option 1`] = `"2512254032"`; exports[`finance > 1337 > routingNumber 1`] = `"251225401"`; -exports[`finance > 1337 > transactionDescription 1`] = `"withdrawal transaction at Cronin - Effertz using card ending with ***3927 for GIP 262.02 in account ***54032552"`; +exports[`finance > 1337 > transactionDescription 1`] = `"withdrawal transaction at Cronin - Effertz using card ending with ***(...3927) for GIP 262.02 in account ***54032552"`; exports[`finance > 1337 > transactionType 1`] = `"withdrawal"`; diff --git a/test/modules/finance.spec.ts b/test/modules/finance.spec.ts index 93c6a0fcbd4..322e3ba91df 100644 --- a/test/modules/finance.spec.ts +++ b/test/modules/finance.spec.ts @@ -217,6 +217,12 @@ describe('finance', () => { }); describe('maskedNumber()', () => { + it('should return contain parenthesis, ellipsis and have a length of 4 by default', () => { + const actual = faker.finance.maskedNumber(); + + expect(actual).toMatch(/\(\.{3}\d{4}\)/); + }); + it('should set a default length', () => { const expected = 4; // default account mask length const mask = faker.finance.maskedNumber({