From 7c70f0ef6f1322b660b24147988e33c500b5c5b7 Mon Sep 17 00:00:00 2001 From: meganwu Date: Thu, 19 Sep 2024 16:26:23 -0400 Subject: [PATCH] add totalmax/min char count support --- README.md | 20 +++++++++++++++ index.ts | 49 ++++++++++++++++++++++++++++++------ package-lock.json | 4 +-- test/randomWordSlugs.test.ts | 33 ++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 534290b..8814ee3 100644 --- a/README.md +++ b/README.md @@ -161,3 +161,23 @@ console.log(totalSlugs); ``` Again, this `1000` is just an example. Importantly, this could help you determine that you're not comfortable with this limited combinatoric space and you can choose to add additional categories. + + +# Character Count Constraints + +You can provide a `totalMax` and/or a `totalMin` to specify the number of characters for the generated slug: + +```javascript +const shortSlug = generateSlug(2, { + categories: { + noun: ["animals"], + adjective: ["color"], + }, + partsOfSpeech: ["adjective", "noun"], + charCount: { + totalMax: 15, + totalMin: 10, + }, +}); +// green-alligator +``` \ No newline at end of file diff --git a/index.ts b/index.ts index d044b0a..df44964 100644 --- a/index.ts +++ b/index.ts @@ -9,14 +9,18 @@ interface FixedLengthArray extends Array { type Case = "kebab" | "camel" | "title" | "lower" | "sentence"; +type CharCountOptions = { + totalMax?: number; + totalMin?: number; +}; + type Options = { partsOfSpeech: FixedLengthArray; - categories: Partial< - { - [K in PartsOfSpeech]: Categories[K][]; - } - >; + categories: Partial<{ + [K in PartsOfSpeech]: Categories[K][]; + }>; format: Case; + charCount?: CharCountOptions; }; export type RandomWordOptions = Partial< @@ -32,13 +36,14 @@ export function generateSlug( partsOfSpeech: getDefaultPartsOfSpeech(numWords), categories: {}, format: "kebab", + charCount: {}, }; const opts: Options = { ...defaultOptions, ...options, }; - const words = []; + let words = []; for (let i = 0; i < numWords; i++) { const partOfSpeech = opts.partsOfSpeech[i]; @@ -50,7 +55,36 @@ export function generateSlug( words.push(rand); } - return formatter(words, opts.format); + let slug = formatter(words, opts.format); + + if ( + opts.charCount?.totalMax !== undefined && + slug.length > opts.charCount.totalMax + ) { + while (slug.length > opts.charCount.totalMax) { + words.pop(); + slug = formatter(words, opts.format); + } + } + if ( + opts.charCount?.totalMin !== undefined && + slug.length < opts.charCount.totalMin + ) { + while (slug.length < opts.charCount.totalMin) { + const partOfSpeech: PartsOfSpeech = + opts.partsOfSpeech[words.length % numWords]; + const candidates: string[] = getWordsByCategory( + partOfSpeech, + opts.categories[partOfSpeech] as Categories[typeof partOfSpeech][] + ); + const rand: string = + candidates[Math.floor(Math.random() * candidates.length)]; + words.push(rand); + slug = formatter(words, opts.format); + } + } + + return slug; } function getDefaultPartsOfSpeech(length: N) { @@ -119,3 +153,4 @@ export function totalUniqueSlugs( } return combos; } + diff --git a/package-lock.json b/package-lock.json index 023b60e..06fc60b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "random-word-slugs", - "version": "0.1.6", + "version": "0.1.7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "random-word-slugs", - "version": "0.1.6", + "version": "0.1.7", "license": "MIT", "devDependencies": { "@types/jest": "^27.0.2", diff --git a/test/randomWordSlugs.test.ts b/test/randomWordSlugs.test.ts index 2d6bc8a..87db963 100644 --- a/test/randomWordSlugs.test.ts +++ b/test/randomWordSlugs.test.ts @@ -62,6 +62,38 @@ describe("wordList", () => { }); }); +describe("generateSlug", () => { + it("respects totalMax character count", () => { + const maxChars = 15; + const slug = generateSlug(2, { + categories: { + noun: ["animals"], + adjective: ["color"], + }, + partsOfSpeech: ["adjective", "noun"], + charCount: { + totalMax: maxChars, + }, + }); + expect(slug.length).toBeLessThanOrEqual(maxChars); + }); + + it("respects totalMin character count", () => { + const minChars = 10; + const slug = generateSlug(2, { + categories: { + noun: ["animals"], + adjective: ["color"], + }, + partsOfSpeech: ["adjective", "noun"], + charCount: { + totalMin: minChars, + }, + }); + expect(slug.length).toBeGreaterThanOrEqual(minChars); + }); +}); + describe("generateSlug", () => { test("generates three random kebab-cased words by default", () => { const slug = generateSlug(); @@ -184,3 +216,4 @@ describe("totalUniqueSlugs", () => { expect(num).toBe(actualTotal); }); }); +