diff --git a/src/modules/lorem/index.ts b/src/modules/lorem/index.ts index 4745b0e91f0..ac1ba7563c9 100644 --- a/src/modules/lorem/index.ts +++ b/src/modules/lorem/index.ts @@ -1,4 +1,5 @@ import type { Faker } from '../..'; +import { filterWordListByLength } from '../word/filterWordListByLength'; /** * Module to generate random texts and words. @@ -17,24 +18,43 @@ export class LoremModule { /** * Generates a word of a specified length. * - * @param length length of the word that should be returned. Defaults to a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.lorem.word() // 'temporibus' * faker.lorem.word(5) // 'velit' + * faker.lorem.word({ strategy: 'shortest' }) // 'a' + * faker.lorem.word({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'quaerat' * * @since 3.1.0 */ - word(length?: number): string { - const hasRightLength = (word: string) => word.length === length; - let properLengthWords: readonly string[]; - if (length == null) { - properLengthWords = this.faker.definitions.lorem.words; - } else { - properLengthWords = - this.faker.definitions.lorem.words.filter(hasRightLength); - } - return this.faker.helpers.arrayElement(properLengthWords); + word( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; + return this.faker.helpers.arrayElement( + filterWordListByLength({ + ...opts, + wordList: this.faker.definitions.lorem.words, + }) + ); } /** diff --git a/src/modules/word/filterWordListByLength.ts b/src/modules/word/filterWordListByLength.ts new file mode 100644 index 00000000000..ca3123719dd --- /dev/null +++ b/src/modules/word/filterWordListByLength.ts @@ -0,0 +1,98 @@ +import { FakerError } from '../../errors/faker-error'; + +/** + * The error handling strategies for the `filterWordListByLength` function. + * + * Always returns a new array. + */ +const STRATEGIES = { + fail: () => { + throw new FakerError('No words found that match the given length.'); + }, + closest: ( + wordList: string[], + length: { min: number; max: number } + ): string[] => { + const wordsByLength = wordList.reduce((data, word) => { + (data[word.length] = data[word.length] ?? []).push(word); + return data; + }, {} as Record); + + const lengths = Object.keys(wordsByLength).map(Number); + const min = Math.min(...lengths); + const max = Math.max(...lengths); + + const closestOffset = Math.min(length.min - min, max - length.max); + + return wordList.filter( + (word) => + word.length === length.min - closestOffset || + word.length === length.max + closestOffset + ); + }, + shortest: (wordList: string[]): string[] => { + const minLength = Math.min(...wordList.map((word) => word.length)); + return wordList.filter((word) => word.length === minLength); + }, + longest: (wordList: string[]): string[] => { + const maxLength = Math.max(...wordList.map((word) => word.length)); + return wordList.filter((word) => word.length === maxLength); + }, + 'any-length': (wordList: string[]): string[] => { + return [...wordList]; + }, +} as const; /* +satisfies Record< +string, // Parameters[0]['strategy'] +(wordList: string[], length: { min: number; max: number }) => string[] +>; +*/ + +/** + * Filters a string array for values with a matching length. + * If length is not provided or no values with a matching length are found, + * then the result will be determined using the given error handling strategy. + * + * @param options The options to provide. + * @param options.wordList A list of words to filter. + * @param options.length The exact or the range of lengths the words should have. + * @param options.strategy The strategy to apply when no words with a matching length are found. Defaults to 'any-length'. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a copy of the original word list. + */ +export function filterWordListByLength(options: { + wordList: string[]; + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; +}): string[] { + const { wordList, length, strategy = 'any-length' } = options; + + if (length) { + const filter: (word: string) => boolean = + typeof length === 'number' + ? (word) => word.length === length + : (word) => word.length >= length.min && word.length <= length.max; + + const wordListWithLengthFilter = wordList.filter(filter); + + if (wordListWithLengthFilter.length > 0) { + return wordListWithLengthFilter; + } + + if (typeof length === 'number') { + return STRATEGIES[strategy](wordList, { min: length, max: length }); + } else { + return STRATEGIES[strategy](wordList, length); + } + } else if (strategy === 'shortest' || strategy === 'longest') { + return STRATEGIES[strategy](wordList); + } else { + return [...wordList]; + } +} diff --git a/src/modules/word/index.ts b/src/modules/word/index.ts index 725c0c4263f..9bdf8f069d5 100644 --- a/src/modules/word/index.ts +++ b/src/modules/word/index.ts @@ -1,29 +1,5 @@ import type { Faker } from '../..'; - -/** - * Filters a string array for values with a specific length. - * If length is not provided or no values with this length there found a copy of the original array is returned. - * - * @param options The options to provide - * @param options.wordList A list of word to filter - * @param options.length The exact length words should have - */ -function filterWordListByLength(options: { - wordList: string[]; - length?: number; -}): string[] { - if (!options.length) { - return options.wordList; - } - - const wordListWithLengthFilter = options.wordList.filter( - (word) => word.length === options.length - ); - - return wordListWithLengthFilter.length > 0 - ? wordListWithLengthFilter - : [...options.wordList]; -} +import { filterWordListByLength } from './filterWordListByLength'; /** * Module to return various types of words. @@ -42,20 +18,42 @@ export class WordModule { /** * Returns an adjective of random or optionally specified length. * - * @param length Expected adjective length. If specified length is unresolvable, returns adjective of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.adjective() // 'pungent' * faker.word.adjective(5) // 'slimy' * faker.word.adjective(100) // 'complete' + * faker.word.adjective({ strategy: 'shortest' }) // 'icy' + * faker.word.adjective({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'distant' * * @since 6.0.0 */ - adjective(length?: number): string { + adjective( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.adjective, - length, }) ); } @@ -63,20 +61,42 @@ export class WordModule { /** * Returns an adverb of random or optionally specified length. * - * @param length Expected adverb length. If specified length is unresolvable, returns adverb of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.adverb() // 'quarrelsomely' * faker.word.adverb(5) // 'madly' * faker.word.adverb(100) // 'sadly' + * faker.word.adverb({ strategy: 'shortest' }) // 'too' + * faker.word.adverb({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'sweetly' * * @since 6.0.0 */ - adverb(length?: number): string { + adverb( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.adverb, - length, }) ); } @@ -84,20 +104,42 @@ export class WordModule { /** * Returns a conjunction of random or optionally specified length. * - * @param length Expected conjunction length. If specified length is unresolvable, returns conjunction of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.conjunction() // 'in order that' * faker.word.conjunction(5) // 'since' * faker.word.conjunction(100) // 'as long as' + * faker.word.conjunction({ strategy: 'shortest' }) // 'or' + * faker.word.conjunction({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'hence' * * @since 6.0.0 */ - conjunction(length?: number): string { + conjunction( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.conjunction, - length, }) ); } @@ -105,20 +147,42 @@ export class WordModule { /** * Returns an interjection of random or optionally specified length. * - * @param length Expected interjection length. If specified length is unresolvable, returns interjection of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.interjection() // 'gah' * faker.word.interjection(5) // 'fooey' * faker.word.interjection(100) // 'yowza' + * faker.word.interjection({ strategy: 'shortest' }) // 'hm' + * faker.word.interjection({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'boohoo' * * @since 6.0.0 */ - interjection(length?: number): string { + interjection( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.interjection, - length, }) ); } @@ -126,20 +190,42 @@ export class WordModule { /** * Returns a noun of random or optionally specified length. * - * @param length Expected noun length. If specified length is unresolvable, returns noun of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.noun() // 'external' * faker.word.noun(5) // 'front' * faker.word.noun(100) // 'care' + * faker.word.noun({ strategy: 'shortest' }) // 'ad' + * faker.word.noun({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'average' * * @since 6.0.0 */ - noun(length?: number): string { + noun( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.noun, - length, }) ); } @@ -147,20 +233,42 @@ export class WordModule { /** * Returns a preposition of random or optionally specified length. * - * @param length Expected preposition length. If specified length is unresolvable, returns preposition of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.preposition() // 'without' * faker.word.preposition(5) // 'abaft' * faker.word.preposition(100) // 'an' + * faker.word.preposition({ strategy: 'shortest' }) // 'a' + * faker.word.preposition({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'given' * * @since 6.0.0 */ - preposition(length?: number): string { + preposition( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.preposition, - length, }) ); } @@ -168,20 +276,42 @@ export class WordModule { /** * Returns a verb of random or optionally specified length. * - * @param length Expected verb length. If specified length is unresolvable, returns verb of a random length. + * @param options The expected length of the word or the options to use. + * @param options.length The expected length of the word. + * @param options.strategy The strategy to apply when no words with a matching length are found. + * + * Available error handling strategies: + * + * - `fail`: Throws an error if no words with the given length are found. + * - `shortest`: Returns any of the shortest words. + * - `closest`: Returns any of the words closest to the given length. + * - `longest`: Returns any of the longest words. + * - `any-length`: Returns a word with any length. + * + * Defaults to `'any-length'`. * * @example * faker.word.verb() // 'act' * faker.word.verb(5) // 'tinge' * faker.word.verb(100) // 'mess' + * faker.word.verb({ strategy: 'shortest' }) // 'do' + * faker.word.verb({ length: { min: 5, max: 7 }, strategy: "fail" }) // 'vault' * * @since 6.0.0 */ - verb(length?: number): string { + verb( + options: + | number + | { + length?: number | { min: number; max: number }; + strategy?: 'fail' | 'closest' | 'shortest' | 'longest' | 'any-length'; + } = {} + ): string { + const opts = typeof options === 'number' ? { length: options } : options; return this.faker.helpers.arrayElement( filterWordListByLength({ + ...opts, wordList: this.faker.definitions.word.verb, - length, }) ); } diff --git a/test/__snapshots__/lorem.spec.ts.snap b/test/__snapshots__/lorem.spec.ts.snap index 7cea03ec25c..9d167ea1715 100644 --- a/test/__snapshots__/lorem.spec.ts.snap +++ b/test/__snapshots__/lorem.spec.ts.snap @@ -61,6 +61,12 @@ exports[`lorem > 42 > word > noArgs 1`] = `"voluptas"`; exports[`lorem > 42 > word > with length 1`] = `"blanditiis"`; +exports[`lorem > 42 > word > with options.length 1`] = `"blanditiis"`; + +exports[`lorem > 42 > word > with options.length and options.strategy 1`] = `"exercitationem"`; + +exports[`lorem > 42 > word > with options.strategy 1`] = `"a"`; + exports[`lorem > 42 > words > noArgs 1`] = `"voluptas minus a"`; exports[`lorem > 42 > words > with length 1`] = `"voluptas minus a qui tempore quo perspiciatis perspiciatis quia in"`; @@ -137,6 +143,12 @@ exports[`lorem > 1211 > word > noArgs 1`] = `"recusandae"`; exports[`lorem > 1211 > word > with length 1`] = `"reiciendis"`; +exports[`lorem > 1211 > word > with options.length 1`] = `"reiciendis"`; + +exports[`lorem > 1211 > word > with options.length and options.strategy 1`] = `"necessitatibus"`; + +exports[`lorem > 1211 > word > with options.strategy 1`] = `"a"`; + exports[`lorem > 1211 > words > noArgs 1`] = `"recusandae esse debitis"`; exports[`lorem > 1211 > words > with length 1`] = `"recusandae esse debitis quo amet explicabo repellat accusantium laborum quia"`; @@ -202,6 +214,12 @@ exports[`lorem > 1337 > word > noArgs 1`] = `"eius"`; exports[`lorem > 1337 > word > with length 1`] = `"aspernatur"`; +exports[`lorem > 1337 > word > with options.length 1`] = `"aspernatur"`; + +exports[`lorem > 1337 > word > with options.length and options.strategy 1`] = `"exercitationem"`; + +exports[`lorem > 1337 > word > with options.strategy 1`] = `"a"`; + exports[`lorem > 1337 > words > noArgs 1`] = `"eius molestias quia"`; exports[`lorem > 1337 > words > with length 1`] = `"eius molestias quia dolorem incidunt atque esse accusantium ad consectetur"`; diff --git a/test/__snapshots__/word.spec.ts.snap b/test/__snapshots__/word.spec.ts.snap index 06cb601a3d9..45b1e937515 100644 --- a/test/__snapshots__/word.spec.ts.snap +++ b/test/__snapshots__/word.spec.ts.snap @@ -6,122 +6,248 @@ exports[`word > 42 > adjective > with length = 10 1`] = `"gregarious"`; exports[`word > 42 > adjective > with length = 20 1`] = `"hasty"`; +exports[`word > 42 > adjective > with options.length 1`] = `"gregarious"`; + +exports[`word > 42 > adjective > with options.length and options.strategy 1`] = `"inconsequential"`; + +exports[`word > 42 > adjective > with options.strategy 1`] = `"hot"`; + exports[`word > 42 > adverb > noArgs 1`] = `"jealously"`; exports[`word > 42 > adverb > with length = 10 1`] = `"generously"`; exports[`word > 42 > adverb > with length = 20 1`] = `"jealously"`; +exports[`word > 42 > adverb > with options.length 1`] = `"generously"`; + +exports[`word > 42 > adverb > with options.length and options.strategy 1`] = `"enthusiastically"`; + +exports[`word > 42 > adverb > with options.strategy 1`] = `"not"`; + exports[`word > 42 > conjunction > noArgs 1`] = `"instead"`; exports[`word > 42 > conjunction > with length = 10 1`] = `"instead"`; exports[`word > 42 > conjunction > with length = 20 1`] = `"instead"`; +exports[`word > 42 > conjunction > with options.length 1`] = `"instead"`; + +exports[`word > 42 > conjunction > with options.length and options.strategy 1`] = `"consequently"`; + +exports[`word > 42 > conjunction > with options.strategy 1`] = `"if"`; + exports[`word > 42 > interjection > noArgs 1`] = `"yahoo"`; exports[`word > 42 > interjection > with length = 10 1`] = `"yahoo"`; exports[`word > 42 > interjection > with length = 20 1`] = `"yahoo"`; +exports[`word > 42 > interjection > with options.length 1`] = `"yahoo"`; + +exports[`word > 42 > interjection > with options.length and options.strategy 1`] = `"gadzooks"`; + +exports[`word > 42 > interjection > with options.strategy 1`] = `"ah"`; + exports[`word > 42 > noun > noArgs 1`] = `"galley"`; exports[`word > 42 > noun > with length = 10 1`] = `"extinction"`; exports[`word > 42 > noun > with length = 20 1`] = `"galley"`; +exports[`word > 42 > noun > with options.length 1`] = `"extinction"`; + +exports[`word > 42 > noun > with options.length and options.strategy 1`] = `"cross-contamination"`; + +exports[`word > 42 > noun > with options.strategy 1`] = `"TV"`; + exports[`word > 42 > preposition > noArgs 1`] = `"concerning"`; exports[`word > 42 > preposition > with length = 10 1`] = `"throughout"`; exports[`word > 42 > preposition > with length = 20 1`] = `"concerning"`; +exports[`word > 42 > preposition > with options.length 1`] = `"throughout"`; + +exports[`word > 42 > preposition > with options.length and options.strategy 1`] = `"notwithstanding"`; + +exports[`word > 42 > preposition > with options.strategy 1`] = `"a"`; + exports[`word > 42 > verb > noArgs 1`] = `"function"`; exports[`word > 42 > verb > with length = 10 1`] = `"exasperate"`; exports[`word > 42 > verb > with length = 20 1`] = `"function"`; +exports[`word > 42 > verb > with options.length 1`] = `"exasperate"`; + +exports[`word > 42 > verb > with options.length and options.strategy 1`] = `"institutionalise"`; + +exports[`word > 42 > verb > with options.strategy 1`] = `"cc"`; + exports[`word > 1211 > adjective > noArgs 1`] = `"vibrant"`; exports[`word > 1211 > adjective > with length = 10 1`] = `"unpleasant"`; exports[`word > 1211 > adjective > with length = 20 1`] = `"vibrant"`; +exports[`word > 1211 > adjective > with options.length 1`] = `"unpleasant"`; + +exports[`word > 1211 > adjective > with options.length and options.strategy 1`] = `"well-documented"`; + +exports[`word > 1211 > adjective > with options.strategy 1`] = `"wee"`; + exports[`word > 1211 > adverb > noArgs 1`] = `"viciously"`; exports[`word > 1211 > adverb > with length = 10 1`] = `"unbearably"`; exports[`word > 1211 > adverb > with length = 20 1`] = `"viciously"`; +exports[`word > 1211 > adverb > with options.length 1`] = `"unbearably"`; + +exports[`word > 1211 > adverb > with options.length and options.strategy 1`] = `"enthusiastically"`; + +exports[`word > 1211 > adverb > with options.strategy 1`] = `"too"`; + exports[`word > 1211 > conjunction > noArgs 1`] = `"whoever"`; exports[`word > 1211 > conjunction > with length = 10 1`] = `"whoever"`; exports[`word > 1211 > conjunction > with length = 20 1`] = `"whoever"`; +exports[`word > 1211 > conjunction > with options.length 1`] = `"whoever"`; + +exports[`word > 1211 > conjunction > with options.length and options.strategy 1`] = `"incidentally"`; + +exports[`word > 1211 > conjunction > with options.strategy 1`] = `"so"`; + exports[`word > 1211 > interjection > noArgs 1`] = `"er"`; exports[`word > 1211 > interjection > with length = 10 1`] = `"er"`; exports[`word > 1211 > interjection > with length = 20 1`] = `"er"`; +exports[`word > 1211 > interjection > with options.length 1`] = `"er"`; + +exports[`word > 1211 > interjection > with options.length and options.strategy 1`] = `"gadzooks"`; + +exports[`word > 1211 > interjection > with options.strategy 1`] = `"um"`; + exports[`word > 1211 > noun > noArgs 1`] = `"trigger"`; exports[`word > 1211 > noun > with length = 10 1`] = `"trafficker"`; exports[`word > 1211 > noun > with length = 20 1`] = `"trigger"`; +exports[`word > 1211 > noun > with options.length 1`] = `"trafficker"`; + +exports[`word > 1211 > noun > with options.length and options.strategy 1`] = `"cross-contamination"`; + +exports[`word > 1211 > noun > with options.strategy 1`] = `"ox"`; + exports[`word > 1211 > preposition > noArgs 1`] = `"upon"`; exports[`word > 1211 > preposition > with length = 10 1`] = `"underneath"`; exports[`word > 1211 > preposition > with length = 20 1`] = `"upon"`; +exports[`word > 1211 > preposition > with options.length 1`] = `"underneath"`; + +exports[`word > 1211 > preposition > with options.length and options.strategy 1`] = `"notwithstanding"`; + +exports[`word > 1211 > preposition > with options.strategy 1`] = `"a"`; + exports[`word > 1211 > verb > noArgs 1`] = `"trick"`; exports[`word > 1211 > verb > with length = 10 1`] = `"trampoline"`; exports[`word > 1211 > verb > with length = 20 1`] = `"trick"`; +exports[`word > 1211 > verb > with options.length 1`] = `"trampoline"`; + +exports[`word > 1211 > verb > with options.length and options.strategy 1`] = `"internationalize"`; + +exports[`word > 1211 > verb > with options.strategy 1`] = `"up"`; + exports[`word > 1337 > adjective > noArgs 1`] = `"fair"`; exports[`word > 1337 > adjective > with length = 10 1`] = `"enchanting"`; exports[`word > 1337 > adjective > with length = 20 1`] = `"fair"`; +exports[`word > 1337 > adjective > with options.length 1`] = `"enchanting"`; + +exports[`word > 1337 > adjective > with options.length and options.strategy 1`] = `"black-and-white"`; + +exports[`word > 1337 > adjective > with options.strategy 1`] = `"far"`; + exports[`word > 1337 > adverb > noArgs 1`] = `"frankly"`; exports[`word > 1337 > adverb > with length = 10 1`] = `"enormously"`; exports[`word > 1337 > adverb > with length = 20 1`] = `"frankly"`; +exports[`word > 1337 > adverb > with options.length 1`] = `"enormously"`; + +exports[`word > 1337 > adverb > with options.length and options.strategy 1`] = `"enthusiastically"`; + +exports[`word > 1337 > adverb > with options.strategy 1`] = `"far"`; + exports[`word > 1337 > conjunction > noArgs 1`] = `"how"`; exports[`word > 1337 > conjunction > with length = 10 1`] = `"how"`; exports[`word > 1337 > conjunction > with length = 20 1`] = `"how"`; +exports[`word > 1337 > conjunction > with options.length 1`] = `"how"`; + +exports[`word > 1337 > conjunction > with options.length and options.strategy 1`] = `"consequently"`; + +exports[`word > 1337 > conjunction > with options.strategy 1`] = `"if"`; + exports[`word > 1337 > interjection > noArgs 1`] = `"ew"`; exports[`word > 1337 > interjection > with length = 10 1`] = `"ew"`; exports[`word > 1337 > interjection > with length = 20 1`] = `"ew"`; +exports[`word > 1337 > interjection > with options.length 1`] = `"ew"`; + +exports[`word > 1337 > interjection > with options.length and options.strategy 1`] = `"gadzooks"`; + +exports[`word > 1337 > interjection > with options.strategy 1`] = `"ah"`; + exports[`word > 1337 > noun > noArgs 1`] = `"digit"`; exports[`word > 1337 > noun > with length = 10 1`] = `"depression"`; exports[`word > 1337 > noun > with length = 20 1`] = `"digit"`; +exports[`word > 1337 > noun > with options.length 1`] = `"depression"`; + +exports[`word > 1337 > noun > with options.length and options.strategy 1`] = `"cross-contamination"`; + +exports[`word > 1337 > noun > with options.strategy 1`] = `"TV"`; + exports[`word > 1337 > preposition > noArgs 1`] = `"barring"`; exports[`word > 1337 > preposition > with length = 10 1`] = `"concerning"`; exports[`word > 1337 > preposition > with length = 20 1`] = `"barring"`; +exports[`word > 1337 > preposition > with options.length 1`] = `"concerning"`; + +exports[`word > 1337 > preposition > with options.length and options.strategy 1`] = `"notwithstanding"`; + +exports[`word > 1337 > preposition > with options.strategy 1`] = `"a"`; + exports[`word > 1337 > verb > noArgs 1`] = `"dispense"`; exports[`word > 1337 > verb > with length = 10 1`] = `"demoralize"`; exports[`word > 1337 > verb > with length = 20 1`] = `"dispense"`; + +exports[`word > 1337 > verb > with options.length 1`] = `"demoralize"`; + +exports[`word > 1337 > verb > with options.length and options.strategy 1`] = `"compartmentalize"`; + +exports[`word > 1337 > verb > with options.strategy 1`] = `"be"`; diff --git a/test/lorem.spec.ts b/test/lorem.spec.ts index 846c7ab1d15..f36f7e9b2e5 100644 --- a/test/lorem.spec.ts +++ b/test/lorem.spec.ts @@ -12,8 +12,17 @@ describe('lorem', () => { }); seededTests(faker, 'lorem', (t) => { + t.describe('word', (t) => { + t.it('noArgs') + .it('with length', 10) + .it('with options.length', { length: 10 }) + .it('with options.strategy', { strategy: 'shortest' }) + .it('with options.length and options.strategy', { + length: { min: 18, max: 20 }, + strategy: 'closest', + }); + }); t.describeEach( - 'word', 'words', 'sentence', 'slug', diff --git a/test/word.spec.ts b/test/word.spec.ts index 7689b8b0d67..82bb5699863 100644 --- a/test/word.spec.ts +++ b/test/word.spec.ts @@ -1,5 +1,6 @@ import { afterEach, describe, expect, it } from 'vitest'; import { faker } from '../src'; +import { filterWordListByLength } from '../src/modules/word/filterWordListByLength'; import { seededTests } from './support/seededRuns'; const NON_SEEDED_BASED_RUN = 5; @@ -19,7 +20,96 @@ describe('word', () => { 'preposition', 'verb' )((t) => { - t.it('noArgs').it('with length = 10', 10).it('with length = 20', 20); + t.it('noArgs') + .it('with length = 10', 10) + .it('with length = 20', 20) + .it('with options.length', { length: 10 }) + .it('with options.strategy', { strategy: 'shortest' }) + .it('with options.length and options.strategy', { + length: { min: 18, max: 20 }, + strategy: 'closest', + }); + }); + }); + + describe('filterWordListByLength', () => { + const wordList = ['foo', 'bar', 'baz', 'a', 'very-long', 'almostRight']; + const length = 10; + + it('returns the word list if no options are given', () => { + const result = filterWordListByLength({ wordList }); + expect(result).toEqual(wordList); + }); + + it('returns the words matching the given length', () => { + const result = filterWordListByLength({ + wordList, + length: 3, + }); + expect(result).toEqual(['foo', 'bar', 'baz']); + }); + + it('returns the words matching the given length range', () => { + const result = filterWordListByLength({ + wordList, + length: { min: 1, max: 3 }, + }); + expect(result).toEqual(['foo', 'bar', 'baz', 'a']); + }); + + it('returns the word list if no words match the length', () => { + const result = filterWordListByLength({ + wordList, + length, + }); + // TODO @ST-DDT 2022-10-02: This should throw an error in the next major version. + expect(result).toEqual(wordList); + }); + + it('returns the appropriate words when strategy is "any-length" and no words match the given length', () => { + const result = filterWordListByLength({ + wordList, + length, + strategy: 'any-length', + }); + expect(result).toEqual(wordList); + }); + + it('returns the appropriate words when strategy is "shortest" and no words match the given length', () => { + const result = filterWordListByLength({ + wordList, + length, + strategy: 'shortest', + }); + expect(result).toEqual(['a']); + }); + + it('returns the appropriate words when strategy is "longest" and no words match the given length', () => { + const result = filterWordListByLength({ + wordList, + length, + strategy: 'longest', + }); + expect(result).toEqual(['almostRight']); + }); + + it('returns the appropriate words when strategy is "closest" and no words match the given length', () => { + const result = filterWordListByLength({ + wordList, + length: 10, + strategy: 'closest', + }); + expect(result).toEqual(['very-long', 'almostRight']); + }); + + it('throws an error when strategy is "fail" and no words match the given length', () => { + expect(() => { + filterWordListByLength({ + wordList, + length, + strategy: 'fail', + }); + }).toThrow('No words found that match the given length.'); }); });