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

@eetr/json-2-md

v0.1.0

Published

Utility to convert json to markdown using a json schema description

Readme

json-2-md

Convert JSON to markdown using a JSON Schema. The schema validates the data and supplies human-readable labels (via description) for the generated headings and field names.

Install

npm install @eetr/json-2-md

No runtime dependencies. Works in Node.js and browser.

Quickstart

Define a schema with description on the root and each property. Object schemas must set additionalProperties: false. Pass your data and schema to objectToMd:

import { objectToMd } from "@eetr/json-2-md";

const schema = {
  type: "object",
  description: "User profile",
  properties: {
    name: { type: "string", description: "User name" },
  },
  required: ["name"],
  additionalProperties: false,
};

const data = { name: "Alice" };
const md = objectToMd(data, schema);
console.log(md);

Reusing a loaded schema

If you call objectToMd many times with the same schema, load it once with loadSchema and pass the result as the second argument. That skips re-parsing, $ref resolution, and schema constraint checks on every call (validation still runs per object).

import { objectToMd, loadSchema } from "@eetr/json-2-md";

const processor = loadSchema(schema);
for (const row of rows) {
  console.log(objectToMd(row, processor));
}

You can also use new SchemaProcessor(schema) the same way.

Output:

# User profile

User name: Alice

Examples

Basic object

Same as quickstart: one object, one string field. The root description becomes the document title; each property’s description becomes the label for its value.

Nested object

Nested objects are rendered with numbered sections in the default "document" strategy:

const schema = {
  type: "object",
  description: "Profile",
  properties: {
    name: { type: "string", description: "User name" },
    address: {
      type: "object",
      properties: {
        street: { type: "string", description: "Street" },
        city: { type: "string", description: "City" },
      },
      additionalProperties: false,
    },
  },
  additionalProperties: false,
};

const data = { name: "Alice", address: { street: "Main St", city: "Boston" } };
console.log(objectToMd(data, schema));
# Profile

User name: Alice

## 1. Address

### 1.1. Street: Main St

### 1.2. City: Boston

Array of primitives

Arrays of strings or numbers become numbered lists:

const schema = {
  type: "object",
  description: "Document",
  properties: {
    title: { type: "string", description: "Title" },
    tags: {
      type: "array",
      items: { type: "string", description: "Tag" },
    },
  },
  additionalProperties: false,
};

const data = { title: "My doc", tags: ["a", "b"] };
console.log(objectToMd(data, schema));
# Document

Title: My doc

1. a

2. b

Format strategies

Use formatStrategy: "document" (default) for numbered sections and lists, or "bullets" for nested bullet lists:

objectToMd(data, schema, { formatStrategy: "document" }); // ## 1. Address, ### 1.1. Street...
objectToMd(data, schema, { formatStrategy: "bullets" }); // - **User name**: Alice, - **Address**:,   - **Street**: ...

Options

  • docTitle – Override the document title (instead of root schema description).
  • fieldCopy – Override the label for specific fields: { fieldCopy: { name: "Full name" } }.
  • includeOriginal – Append the original JSON in a fenced ```json ... ``` block at the end.
  • labelFromPath – When a property has no description, use "leaf" (only the last path segment) or "full" for the full path. Default is "leaf".
  • formatStrategy"document" or "bullets" as above.

Example:

objectToMd(data, schema, {
  docTitle: "Custom Title",
  fieldCopy: { name: "Full name" },
  includeOriginal: true,
});

Schema as string

You can pass the schema as a JSON string (e.g. when loaded from a file):

const schemaString = JSON.stringify(schema);
objectToMd(data, schemaString);

Validation

If the data does not match the schema (wrong types, missing required fields, or extra properties), objectToMd throws:

objectToMd({ name: 123 }, schema);  // throws: expected string
objectToMd({}, schema);             // throws: missing required

Schema requirements

  • additionalProperties – Every object schema must set additionalProperties: false.
  • description – Used as the document title (root) and as field labels (properties). Omit for a property to fall back to a label derived from the key (e.g. street_name → "Street name").
  • $ref – Supported; definitions are resolved by the built-in resolver.

API

objectToMd(object, schema, options?)

Converts a validated object to markdown.

  • object – The data to convert (must validate against the schema).
  • schema – A JSON Schema object or JSON string. Object schemas must have additionalProperties: false.
  • options – Optional. See ObjectToMdOptions: includeOriginal, fieldCopy, docTitle, labelFromPath, formatStrategy.

Returns a markdown string. Throws if the object is invalid.

SchemaProcessor

For validation and description lookup without generating markdown: new SchemaProcessor(schema), then .process(json) (returns { valid, validReason, fieldsDescription }) and .describe(path?) for a property description at a given path.

Case helpers

keyToDescription(key) turns a key into a readable label (e.g. camelCase or snake_case). Also exported: detectCase, camelCaseToDescription, snakeCaseToDescription.

Playground

A Vite app in playground/ is not part of the npm package (files only includes dist/).

  1. Install once: cd playground && npm install
  2. Dev (library source) — from repo root: npm run playground:dev, or from playground/: npm run dev. Edits under src/ are picked up without rebuilding the package (Vite resolves @eetr/json-2-md to src/index.ts).
  3. Dev (built package) — run npm run build at the repo root, then npm run playground:dev:pkg (or npm run dev:pkg inside playground/). Uses the same entry as consumers (dist/).

Static build of the demo: npm run playground:build (output: playground/dist/).

Publishing (maintainers)

You need publish rights on the npm org @eetr. From the repo root:

  1. npm login
  2. npm publish — runs prepublishOnly (build + vitest run), then uploads the tarball.

publishConfig.access is public so the scoped package is free to install. Bump with npm version patch|minor|major before a new release.

License

Apache-2.0