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

contentful-rt-utils

v1.2.0

Published

A robust, open-source TypeScript library to minify and convert Contentful Rich Text Documents.

Readme

Contentful Rich Text Utils

A robust, open-source TypeScript library to minify and convert Contentful Rich Text Documents. This library provides utilities to optimize Rich Text JSON for SSG builds and convert Rich Text to Markdown.

Features

  • Minification: Removes unused metadata from Rich Text nodes.
  • Markdown Conversion: Converts Rich Text JSON to Markdown string with frontmatter support.
  • Content Statistics: Calculate reading time, word count, and extract links.
  • Sanitization: Remove empty nodes and strip unwanted formatting.
  • Plain Text: Convert Rich Text to plain text string.
  • Table Generation: Programmatically create Rich Text Tables from data arrays.
  • Extraction: Get all referenced Entry and Asset IDs.
  • Configurable: Specify exactly which fields to keep for embedded Entries and Assets.
  • Custom Transformations: Provide custom callbacks for advanced transformation logic.
  • Type Safe: Built with TypeScript and strict type definitions.
  • Immutable: Returns a new deep copy of the document, leaving the original untouched.
  • Dot Notation Support: Easily select nested fields (e.g., file.url).

Motivation

When using Contentful with Next.js Static Site Generation (SSG), the raw Rich Text JSON returned by the API can be significantly large, especially when it contains many embedded assets and entries with full metadata. This bloated JSON increases the build size of your static pages (HTML/JSON props), leading to slower page loads and higher bandwidth usage.

contentful-rt-utils solves this by stripping away all the unused system metadata (sys, metadata, etc.) and allowing you to pick only the fields you actually need for rendering (e.g., just the image URL and title). This can drastically reduce the footprint of your SSG build artifacts.

Installation

npm install contentful-rt-utils
# or
yarn add contentful-rt-utils
# or
pnpm add contentful-rt-utils

Usage

Minification

import { minifyRichText } from "contentful-rt-utils";
import { Document } from "@contentful/rich-text-types";

const document: Document = {
  // ... your Contentful Rich Text Document
};

const minified = minifyRichText(document);

Advanced Minification with Options

You can configure which fields to keep in embedded entries and assets, or provide custom transformation functions.

import { minifyRichText } from "contentful-rt-utils";

const minified = minifyRichText(document, {
  // Keep specific fields for Entries
  keepEntryFields: ["title", "slug", "category"],

  // Keep specific fields for Assets (supports dot notation)
  keepAssetFields: ["title", "file.url", "file.details.size"],

  // Custom transformation for Entries (overrides keepEntryFields)
  transformEntry: (entry) => ({
    ...entry.fields,
    customProp: true,
  }),

  // Custom transformation for Assets (overrides keepAssetFields)
  transformAsset: (asset) => ({
    url: asset.fields.file.url,
    alt: asset.fields.title,
  }),
});

Markdown Conversion

Convert Rich Text to a Markdown string.

import { richTextToMarkdown } from "contentful-rt-utils";
import { Document } from "@contentful/rich-text-types";

const document: Document = {
  // ... your Contentful Rich Text Document
};

const markdown = richTextToMarkdown(document);
console.log(markdown);

You can also provide custom renderers for embedded entries and assets:

const markdown = richTextToMarkdown(document, {
  renderAsset: (node) =>
    `![${node.data.target.fields.title}](${node.data.target.fields.file.url})`,
  renderEntry: (node) => `[Embedded Entry: ${node.data.target.fields.title}]`,
  // Generate frontmatter
  frontmatter: {
    author: "Arsallan",
  },
  // Custom renderer for specific nodes
  customRenderer: {
    [BLOCKS.EMBEDDED_ENTRY]: (node, next) => {
      return `<div class="embed">${next(node)}</div>`;
    }
  }
});

Content Statistics

import { getReadingTime, getWordCount, extractLinks } from 'contentful-rt-utils';

// Calculate reading time (default 200 wpm)
const minutes = getReadingTime(document);

// Get accurate word count (excludes HTML/metadata and punctuation)
const words = getWordCount(document);

// Extract all external URLs
const links = extractLinks(document);

Sanitization & Cleanup

import { removeEmptyNodes, stripMarks } from 'contentful-rt-utils';

// Recursively remove empty paragraphs
const cleanDoc = removeEmptyNodes(document);

// Strip specific formatting marks (e.g., remove all bold text)
const plainDoc = stripMarks(document, ['bold']);

Extraction Utilities

import { getLinkedEntries, getLinkedAssets } from 'contentful-rt-utils';

// Get all referenced Entry IDs
const entryIds = getLinkedEntries(document);

// Get all referenced Asset IDs
const assetIds = getLinkedAssets(document);

Plain Text Conversion

import { toPlainText } from 'contentful-rt-utils';

// Convert to plain text (default newline separator)
const text = toPlainText(document);

// Custom separator and ignore links
const summary = toPlainText(document, { 
  separator: ' ', 
  ignoreLinks: true 
});

Table Generation

import { createTable } from 'contentful-rt-utils';

const data = [
  ['Name', 'Role'], // First row becomes header
  ['Alice', 'Admin'],
  ['Bob', 'User']
];

const tableNode = createTable(data);

API Reference

minifyRichText(document, options?)

Minifies a Contentful Rich Text Document.

  • document: Document | null - The Rich Text Document to minify.
  • options: MinifyOptions (optional) - Configuration options.

MinifyOptions

| Property | Type | Description | | :---------------- | :-------------------- | :-------------------------------------------------------------------------------------------- | | keepEntryFields | string[] | List of field keys to keep for Entries (e.g., ['slug', 'title']). | | keepAssetFields | string[] | List of field keys to keep for Assets (e.g., ['file.url', 'title']). Supports dot notation. | | transformEntry | (entry: any) => any | Optional callback for custom transformation of Entries. | | transformAsset | (asset: any) => any | Optional callback for custom transformation of Assets. |

richTextToMarkdown(document, options?)

Converts a Contentful Rich Text Document to a Markdown string.

  • document: Document | null - The Rich Text Document to convert.
  • options: MarkdownOptions (optional) - Configuration options.

MarkdownOptions

| Property | Type | Description | | :------------ | :---------------------------------- | :------------------------------------ | | renderEntry | (node: Block \| Inline) => string | Custom renderer for embedded entries. | | renderAsset | (node: Block \| Inline) => string | Custom renderer for embedded assets. |

toPlainText(document, options?)

Converts a Rich Text Document to a plain text string.

  • document: Document | Node | null
  • options: PlainTextOptions

| Property | Type | Default | Description | | :------------ | :-------- | :------ | :----------------------------------------------- | | separator | string | \n | String to join blocks with. | | ignoreLinks | boolean | false | If true, excludes text content within hyperlinks. |

createTable(data)

Creates a Rich Text Table node.

  • data: string[][] - 2D array of strings. First row is treated as header.

Development

Build

npm run build

Test

npm test

License

MIT

Contributing

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

  1. Fork the repository.
  2. Create your feature branch (git checkout -b feature/AmazingFeature).
  3. Commit your changes (git commit -m 'Add some AmazingFeature').
  4. Push to the branch (git push origin feature/AmazingFeature).
  5. Open a Pull Request.