npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lakshyarohilaa/llmforge

v1.0.0

Published

Production-grade, framework-agnostic library for normalizing and transforming LLM responses.

Downloads

5

Readme

LLMForge

A production-grade, framework-agnostic JavaScript/TypeScript library for normalizing and transforming LLM responses.

Tests TypeScript License NPM Size

LLMForge provides a comprehensive, extensible solution for cleaning, formatting, and extracting structured data from Large Language Model (LLM) outputs. It handles common annoyances like markdown wrapping, extra whitespace, emojis, PII, and malformed JSON.

🚀 Key Features

  • Zero dependencies for core functionality
  • Tree-shakeable modular design — only bundle what you use
  • TypeScript-first with full type safety and excellent IntelliSense
  • Dual package support (ESM and CommonJS)
  • Environment agnostic (Works in Node.js, Browsers, React, Vue, Svelte, etc.)
  • Chainable API for intuitive transformation workflows
  • Middleware architecture for easy extensibility
  • Async support for complex transformation pipelines
  • 30+ transformation functions with comprehensive edge case handling

📦 Installation

npm install llmforge
# or
yarn add llmforge
# or
pnpm add llmforge

🛠️ Quick Start

import { normalize } from 'llmforge';

// Basic usage
const cleaned = normalize("  Hello 🌍!  ")
  .trim()
  .removeEmojis()
  .value();
// Output: "Hello !"

// Extract JSON from LLM response
const json = normalize('```json\n{"name": "John"}\n```').getJSON();
// Output: { name: "John" }

// Chain multiple transformations
const result = normalize("**Bold** text with https://example.com")
  .removeMD()
  .removeURLs()
  .trim()
  .value();
// Output: "Bold text with"

📖 Complete API Reference

Core Methods

| Method | Description | Returns | |--------|-------------|---------| | .value() | Returns the current normalized value | string | | .transform(fn) | Applies a custom transformation function | this | | .orDefault(fallback) | Returns fallback if value is empty | this |


Text Transformations (20+ Functions)

Whitespace Management

| Method | Description | Example | |--------|-------------|---------| | .trim() | Removes leading and trailing whitespace | " hello ""hello" | | .collapseSpaces() | Collapses multiple spaces/tabs into one | "a b""a b" | | .normalizeLineBreaks() | Standardizes line endings to \n (handles \r\n, \r) | "a\r\nb""a\nb" | | .removeExtraNewlines() | Collapses multiple newlines into one | "a\n\n\nb""a\nb" |

Markdown & Code

| Method | Description | Example | |--------|-------------|---------| | .removeMD() | Strips markdown formatting (bold, italic, headers, links, code) | "**bold**""bold" | | .removeCodeBlocks() | Removes both fenced and inline code blocks | "text `code` more""text more" |

Direct Functions:

import * as textTransforms from 'llmforge';

textTransforms.extractCodeBlocks(text); // Returns string[] of code blocks

URLs & Citations

| Method | Description | Example | |--------|-------------|---------| | .removeURLs() | Removes HTTP/HTTPS URLs | "Check https://example.com""Check " | | .removeCitations() | Removes citations like [1], (Smith, 2020) | "Text [1]""Text " |

HTML

| Method | Description | Example | |--------|-------------|---------| | .stripHTML() | Removes all HTML tags | "<p>Hello</p>""Hello" | | .escapeHTML() | Escapes HTML special characters | "<div>""&lt;div&gt;" | | .unescapeHTML() | Unescapes HTML entities | "&lt;div&gt;""<div>" |

Case Transformations

| Method | Description | Example | |--------|-------------|---------| | .toTitleCase() | Capitalizes first letter of each word | "hello world""Hello World" | | .toSentenceCase() | Capitalizes only the first letter | "HELLO WORLD""Hello world" |

Punctuation

| Method | Description | Example | |--------|-------------|---------| | .normalizeQuotes() | Converts smart quotes to standard quotes | ""smart"""\"smart\"" | | .normalizePunctuation() | Normalizes excessive punctuation | "What!!!!""What!" |

Truncation & Splitting

| Method | Description | Example | |--------|-------------|---------| | .truncate(maxLength, ellipsis?) | Truncates text with optional ellipsis | truncate("Hello World", 8)"Hello..." |

Direct Functions:

import * as textTransforms from 'llmforge';

textTransforms.splitIntoChunks(text, 100); // Returns string[] of chunks

Privacy & Security

| Method | Description | Example | |--------|-------------|---------| | .maskPII() | Masks emails, phones, SSN, credit cards | "[email protected]""[EMAIL]" | | .censor(words) | Censors specified words with asterisks | censor("bad word", ["bad"])"*** word" |


Emoji Transformations (4 Functions)

| Method | Description | Example | |--------|-------------|---------| | .removeEmojis() | Removes all emojis | "Hello 👍""Hello " | | .replaceEmojis(map) | Replaces emojis based on mapping | replaceEmojis("👍", {"👍": "like"})"like" | | .addEmojis(options) | Adds sentiment-based emojis | addEmojis("Great", {sentiment: "positive"})"Great 😊" | | .translateEmojis() | Translates emojis to text | "👍 ❤️""thumbs up heart" |

Supported emoji translations:

  • 👍 → "thumbs up"
  • 👎 → "thumbs down"
  • ❤️ → "heart"
  • 😊 → "smile"
  • 😂 → "laugh"
  • 😢 → "cry"
  • 🔥 → "fire"
  • ✅ → "check"
  • ❌ → "cross"
  • ⚠️ → "warning"
  • 🎉 → "celebration"
  • 💯 → "100"

Structure Transformations (7+ Functions)

JSON Handling

| Method | Description | Example | |--------|-------------|---------| | .extractJSON() | Extracts and stringifies JSON (chainable) | '{"key": "value"}''{"key":"value"}' | | .getJSON() | Extracts and returns parsed JSON (terminator) | '{"key": "value"}'{ key: "value" } |

Direct Functions:

import * as structureTransforms from 'llmforge';

// Validate JSON against schema
structureTransforms.validateJSON(json, { 
  required: ['name', 'email'],
  type: 'object'
});
// Returns: { isValid: boolean, errors: string[] }

JSON extraction handles:

  • JSON wrapped in markdown code blocks (```json ... ```)
  • JSON embedded in surrounding text
  • Nested JSON objects and arrays
  • Malformed JSON (returns null gracefully)

Lists

| Method | Description | Example | |--------|-------------|---------| | .normalizeLists() | Converts numbered lists to bullets | "1. First""• First" | | .convertBulletsToNumbers() | Converts bullets to numbered lists | "• First""1. First" |

Direct Functions:

import * as structureTransforms from 'llmforge';

// Extract list items as array
structureTransforms.extractListItems("• Item 1\n• Item 2");
// Returns: ["Item 1", "Item 2"]

// Extract XML tag contents
structureTransforms.extractXMLTags("<name>John</name>", "name");
// Returns: ["John"]

// Parse structured LLM output (Claude-style)
structureTransforms.parseStructuredOutput("<thinking>...</thinking><answer>42</answer>");
// Returns: { thinking: "...", answer: "42", json?: any }

🧩 Middleware & Extensibility

Create custom processing pipelines with the middleware system.

Basic Middleware Usage

import { createNormalizer, middleware } from 'llmforge';

const pipeline = createNormalizer([
  middleware.trimWhitespace(),
  middleware.removeEmojis(),
  middleware.collapseSpaces(),
  middleware.validateLength({ min: 1, max: 1000 })
]);

const result = pipeline.process("  Hello 🌍  ");
// Output: "Hello"

Built-in Middleware

| Middleware | Description | |------------|-------------| | middleware.trimWhitespace() | Trims leading/trailing whitespace | | middleware.removeEmojis() | Removes all emojis | | middleware.collapseSpaces() | Collapses multiple spaces | | middleware.validateLength(options) | Validates text length (throws on failure) | | middleware.custom(fn, name) | Creates custom middleware |

Custom Middleware

const uppercase = middleware.custom(
  (text) => text.toUpperCase(),
  "uppercase"
);

const normalizer = createNormalizer([uppercase]);
normalizer.process("hello"); // "HELLO"

Presets

Pre-configured middleware for common use cases:

import { presets, createNormalizer } from 'llmforge';

// Chat message normalization
const chatNormalizer = createNormalizer(presets.chatMessage);

// Email formatting (removes emojis, normalizes whitespace)
const emailNormalizer = createNormalizer(presets.emailFormat);

// API response cleaning
const apiNormalizer = createNormalizer(presets.apiResponse);

// Code extraction
const codeNormalizer = createNormalizer(presets.codeExtraction);

// Content moderation
const moderationNormalizer = createNormalizer(presets.contentModeration);

⚡ Async Support

Handle asynchronous transformations with AsyncNormalizer.

import { normalizeAsync } from 'llmforge';

const result = await normalizeAsync("  HELLO  ")
  .transform((text) => text.trim())
  .transform(async (text) => {
    // Simulate async operation (API call, etc.)
    return await Promise.resolve(text.toLowerCase());
  })
  .value();
// Output: "hello"

Async Middleware

import { createNormalizer, middleware } from 'llmforge';

const pipeline = createNormalizer([
  middleware.trimWhitespace(),
  middleware.custom(async (text) => {
    const response = await fetch('/api/process', {
      method: 'POST',
      body: text
    });
    return await response.text();
  }, 'apiProcess')
]);

const result = await pipeline.processAsync(text);

📚 Usage Examples

Extract JSON from LLM Response

import { normalize } from 'llmforge';

const llmResponse = `
Here's the user data:
\`\`\`json
{
  "name": "Alex",
  "email": "[email protected]",
  "age": 30
}
\`\`\`
`;

const userData = normalize(llmResponse).getJSON();
// Output: { name: "Alex", email: "[email protected]", age: 30 }

Clean Chat Messages

function cleanUserMessage(message: string): string {
  return normalize(message)
    .trim()
    .collapseSpaces()
    .normalizePunctuation()
    .truncate(500)
    .value();
}

cleanUserMessage("  Hello!!!   How are you????  ");
// Output: "Hello! How are you?"

Remove PII for Privacy

function sanitizeContent(text: string): string {
  return normalize(text)
    .maskPII()
    .removeURLs()
    .value();
}

sanitizeContent("Contact me at [email protected] or 555-123-4567");
// Output: "Contact me at [EMAIL] or [PHONE]"

Format Email from LLM

import { normalize, presets, createNormalizer } from 'llmforge';

const emailNormalizer = createNormalizer(presets.emailFormat);

function formatEmail(llmResponse: string): string {
  return emailNormalizer.process(llmResponse);
}

Extract Code Blocks

import { textTransforms } from 'llmforge';

const llmResponse = `
Here's the solution:
\`\`\`javascript
console.log('Hello');
\`\`\`
And here's another:
\`\`\`python
print('World')
\`\`\`
`;

const codeBlocks = textTransforms.extractCodeBlocks(llmResponse);
// Output: ["console.log('Hello');", "print('World')"]

Parse Structured Output (Claude-style)

import { structureTransforms } from 'llmforge';

const response = "<thinking>Let me analyze...</thinking><answer>42</answer>";
const parsed = structureTransforms.parseStructuredOutput(response);
// Output: { thinking: "Let me analyze...", answer: "42" }

🧪 Edge Case Handling

llmforge is battle-tested with 51 comprehensive tests covering:

Empty strings - All functions handle empty input gracefully
Very long strings - Tested with 10,000+ character strings
Unicode support - Full support for emojis and international characters
Malformed JSON - Returns null instead of throwing errors
Special characters - Handles null bytes and control characters
Nested structures - Supports deeply nested JSON and HTML
Mixed content - Handles text with multiple formats simultaneously


📊 Direct Transform Functions

All transformations are also available as standalone functions for maximum flexibility:

import * as textTransforms from 'llmforge';
import * as emojiTransforms from 'llmforge';
import * as structureTransforms from 'llmforge';

// Use directly without chaining
const trimmed = textTransforms.trimWhitespace("  hello  ");
const json = structureTransforms.extractJSON('{"key": "value"}');
const noEmojis = emojiTransforms.removeEmojis("Hello 👍");

Complete Function List

Text Transforms:

  • trimWhitespace(text)
  • collapseSpaces(text)
  • normalizeLineBreaks(text)
  • removeExtraNewlines(text)
  • removeMDFormatting(text)
  • removeCodeBlocks(text)
  • extractCodeBlocks(text)string[]
  • removeURLs(text)
  • removeCitations(text)
  • stripHTMLTags(text)
  • escapeHTML(text)
  • unescapeHTML(text)
  • toTitleCase(text)
  • toSentenceCase(text)
  • normalizeQuotes(text)
  • normalizePunctuation(text)
  • truncate(text, maxLength, ellipsis?)
  • splitIntoChunks(text, chunkSize)string[]
  • maskPII(text)
  • censor(text, words[])

Emoji Transforms:

  • removeEmojis(text)
  • replaceEmojis(text, map)
  • addEmojis(text, options?)
  • translateEmojis(text)

Structure Transforms:

  • extractJSON(text)any | null
  • validateJSON(json, schema){isValid, errors}
  • normalizeLists(text)
  • convertBulletsToNumbers(text)
  • extractListItems(text)string[]
  • extractXMLTags(text, tagName)string[]
  • parseStructuredOutput(text){thinking?, answer?, json?}

🎯 TypeScript Support

Full TypeScript support with comprehensive type definitions:

import { 
  Normalizer, 
  AsyncNormalizer,
  NormalizerOptions, 
  TransformFn,
  Middleware,
  ValidationResult 
} from 'llmforge';

const options: NormalizerOptions = {
  strictMode: true,
  onWarning: (warning) => console.warn(warning),
  onError: (error) => console.error(error),
};

const normalizer: Normalizer = normalize("text", options);

🚀 Performance

  • Lazy evaluation - Transformations execute only when .value() is called
  • Optimized regex - Efficient pattern matching for all operations
  • Zero dependencies - Minimal bundle size (<20KB gzipped)
  • Tree-shakeable - Import only what you need

🌐 Browser Support

Works in all modern browsers and Node.js 16+.

<!-- Via CDN -->
<script type="module">
  import { normalize } from 'https://unpkg.com/llmforge';
  
  const result = normalize("  text  ").trim().value();
</script>

📜 License

MIT © 2024


🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


📖 Documentation


🔗 Links