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 🙏

© 2025 – Pkg Stats / Ryan Hefner

noddity-micromark-renderer

v2.0.1

Published

Implementation of Noddity that uses Micromark and mdast to render the Markdown content, and has *no opinion* about non-Markdown content.

Readme

Noddity Micromark Renderer

This is a re-work of Noddity that uses Micromark and mdast to render the Markdown content, and has no opinion about non-Markdown content.

Included is a legacy renderer, if you want to use classic Noddity syntax and the legacy Ractive renderer. (See the demo for an example of it.)

Install

The usual ways:

npm install noddity-micromark-renderer

Using

You'll need to initialize the renderer with several options (all of these are required):

import { noddityRenderer } from 'noddity-micromark-renderer'
const render = noddityRenderer({
	// Noddity-specific functions
	loadFile,
	metadataParser,
	nonMarkdownRenderer,
	urlRenderer,
	// Micromark-specific functions
	hastToHtml,
	markdownToMdast,
	mdastToHast,
})
// for later examples
const NODDITY_FOLDER = '/path/to/noddity/content'
const DOMAIN = 'my-site.com'

If you're using the legacy renderer, which uses Ractive, you don't need nearly as much:

import { noddityRenderer } from 'noddity-micromark-renderer/legacy'
const render = noddityRenderer({
	directory: NODDITY_FOLDER,
	domain: 'site.com',
	pathPrefix: '#!/',
	pagePathPrefix: 'post/',
	name: 'My Cool Website',
})

API of non-legacy noddityRenderer

Each input property is defined here:

loadFile

Typed: (filename: string, options?: Object) => Promise<string>

Used by the renderer to lookup Noddity templates. If you're rendering from disk, you could do:

import { join } from 'node:path'
import { readFile } from 'node:fs/promises'
const loadFile = async filename => readFile(join(NODDITY_FOLDER, filename), 'utf8')

The options object is passed along to your non-Markdown renderer, merged into the overall options.

metadataMdastMutator

Typed: async ({ filename: string, mdastTree: MdastTree }): void

Called by the renderer to mutate the mdast (Markdown Abstract State Tree) to optionally parse the frontmatter section of each file and set it.

After this is called, mdast should have these properties set to properly parse the remaining content:

  • mdast.children[0].metadata - This is the fully parsed file metadata, if present.
  • mdast.children[0].position.end.offset - This is the unist positional information about the character offset at the very end of the metadata, including frontmatter fence characters.

If you want to use js-yaml that would be (defining the schema is not required by this renderer):

import { load, JSON_SCHEMA } from 'js-yaml'
const metadataParser = frontmatter => load(frontmatter, { schema: JSON_SCHEMA })

nonMarkdownRenderer

Typed: ({ filename: string, template: string, string: string, metadata: Object, variables: Array<NoddityVariables> }) => Promise<string>

Where NoddityVariables: { name: string, positional: boolean, value: string }

This is where you would render non-Markdown content. In classic Noddity this means Ractive (at v0.7) styled templates, but for this renderer there are no opinions about what you should use.

The returned value is the fully rendered HTML.

Properties passed to the function:

  • filename: string - The file doing the calling of this as a template, if applicable, e.g. folder/my-file.md.
  • innerHtml?: string - If loading a post, this will be the fully rendered post content, while the templateString will be the surrounding post non-rendered string.
  • metadata?: Object - The parsed metadata from the files frontmatter section.
  • templateName: string - The name of the template, e.g. if the above file had ::img|face.jpg:: this would be img.
  • templateString: string - The string extracted from the Noddity file, e.g. in classic Noddity this would be the Ractive component.
  • variables?: Array<NoddityVariables> - An optional ordered list of variables passed along when calling this template.

Properties on the NoddityVariables objects are:

  • name: string - The name of the variable. For a reference like ::img|face.jpg|size=big:: the first variable's name would be face.jpg and the second would be size.
  • positional: boolean - Set to true if it is not a key=value named variable.
  • value?: string - The value, if it is a named variable.

urlRenderer

Typed: ({ filename: string, link: string }) => Promise<string>

It's up to you to render the correct URL string, but it's usually something like this:

const urlRenderer = ({ link }) => `https://${DOMAIN}/#!/post/${link}`

markdownToMdast

Typed: (markdown: string) => Promise<Mdast>

Async function that resolves to an mdast (Markdown Abstract State Tree), for example mdast-util-from-markdown, and that needs to contain the Noddity-specific nodes defined in mdast-util-noddity.

Here's how you might set this function up:

import { fromMarkdown } from 'mdast-util-from-markdown'
import { frontmatter } from 'micromark-extension-frontmatter'
import { frontmatterFromMarkdown } from 'mdast-util-frontmatter'
import { gfm } from 'micromark-extension-gfm'
import { gfmFromMarkdown } from 'mdast-util-gfm'

const markdownToMdast = string => fromMarkdown(string, {
	extensions: [
		// if you need more extensions, e.g. for additional Markdown functionality, you'd configure it here
		frontmatter([ 'yaml' ]),
		gfm(),
		micromarkFromNoddity(),
	],
	mdastExtensions: [
		// (and here)
		frontmatterFromMarkdown([ 'yaml' ]),
		gfmFromMarkdown(),
		mdastFromNoddity(),
	],
})

The function must return a promise which resolves to an mdast with the Noddity-specific nodes.

mdastToHast

Typed: (tree: MdastTree) => HastTree

Given an mdast tree, return an hast (HTML Abstract State Tree).

Note that, if you use templates of any kind, you'll probably want to allow HTML. Here's one way to do this:

import { toHast } from 'mdast-util-to-hast'
const mdastToHast = mdastTree => toHast(mdastTree, { allowDangerousHtml: true })

hastToHtml

Typed: (tree: HastTree) => string

Given an hast (HTML Abstract State Tree) output an HTML string.

Note that, if you use templates of any kind, the hast will contain text nodes that are HTML (as opposed to a strict hast) so you'll probably want to allow that. Here's one way:

import { toHtml } from 'hast-util-to-html'
const hastToHtml = hastTree => toHtml(hastTree, { allowDangerousHtml: true })

render

An initialized render is an object containing the following properties:

fromString

Typed: (markdown: string, virtualFilename?: string) => Promise<string>

This function is used to render free-hand sections of Markdown as noddity, e.g. instead of rendering a file you can render a chunk of Markdown with not other context.

The virtualFilename is used only for logging purposes, and if not provided will default to VIRTUAL_FILE.md.

loadFile

Typed: (filename: string) => Promise<string>

This is a per-file renderer function. It renders a file by loading the provided filename using the defined loadFile function, which can load files from anywhere, e.g. from disk, database, cloud storage, etc.

It then passes through the flow Markdown -> mdast -> Noddity (templates and links) -> hast -> html

loadMetadata

Typed: (filename: string) => Promise<Object>

This is a convenience method, which will use the defined loadFile to read in a file and parse out the frontmatter metadata section, using your provided metadataParser function to turn that string into an object.

loadPost

Typed: (templateFilename: string, postFilename: string) => Promise<string>

Similar to the loadFile function, except it renders the postFilename inside the context of the templateFilename (inside Noddity, by default this is the content/post file).

License

Published and released under the Very Open License.

If you need a commercial license, contact me here.