A comprehensive TypeScript/JavaScript library for procedural natural language generation, string manipulation, and grammatical inflection. Originally built to provide utility functions for producing natural-sounding English from component parts, it's perfect for text generators, game development, and formatting data seamlessly.
Full documentation is available at ironarachne.github.io/words.
npm install @ironarachne/words
The library is organized into specialized domains for all your procedural text needs:
Easily change string formats for code, IDs, or display.
capitalize, uncapitalize, title (Title Case)camelCase, snakeCase, kebabCase, swapCaseHelpers for assembling dynamic sentences to keep your procedural text grammatically correct.
a/an) or pronoun based on gender and context.quantify(2, "apple") -> "2 apples"isAre(count), hasHave(count), wasWere(count) to match plurals automatically.possessive("James") -> "James'", possessive("dog") -> "dog's").Robust rules and an expansive irregular dictionary (e.g., radius/radii, goose/geese, deer).
pluralize(word: string)singularize(word: string)detectPlural(word: string)comparative(word: string) -> "big" becomes "bigger", "beautiful" becomes "more beautiful"superlative(word: string) -> "big" becomes "biggest", "beautiful" becomes "most beautiful"Format numbers as text or traditional numeric formats.
getOrdinal(1) -> "1st"ordinalWord(1) -> "first"numberToWords(21) -> "twenty-one"romanize(4) -> "IV"Create clean paragraphs, phrases, and text elements.
buildSentence(parts) automatically capitalizes and fixes terminal punctuation.arrayToPhrase(["apple", "banana"], "or") -> "apple or banana"fixPunctuation(text) fixes double-spaces, space-before-comma, and duplicate punctuation.slugify, truncateWords, squish, stripPunctuationwordCount, readingTimeBuilding grammatically accurate procedural sentences is simple:
import { quantify, isAre, arrayToPhrase, buildSentence } from "@ironarachne/words";
const enemyCount = 3;
const enemyType = "goblin";
const loot = ["gold coin", "rusty dagger"];
// "3 goblins"
const enemies = quantify(enemyCount, enemyType);
// "are"
const copula = isAre(enemyCount);
// "gold coin and rusty dagger"
const lootPhrase = arrayToPhrase(loot);
const parts = [
"there", copula, enemies, "guarding the", lootPhrase
];
// Returns: "There are 3 goblins guarding the gold coin and rusty dagger."
const text = buildSentence(parts);
console.log(text);
This project uses TypeScript, Vitest for testing, and Biome for linting and formatting. Node 20 or newer is required.
# Install dependencies
npm install
# Lint, build, and test — run this before pushing
npm run check
main is protected; every change lands through a pull request with CI green.
See CONTRIBUTING.md for the full workflow and how releases
are cut, and CODE_STYLE.md for the conventions this codebase
follows.
MIT License.