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 🙏

© 2024 – Pkg Stats / Ryan Hefner

markdown-manager

v0.1.6

Published

Manage collections of markdown documents with support for file-based structure, snippets, and more

Downloads

5

Readme

Markdown Manager #################

A small library for managing collections of markdown documents with support for enriching with metadata and make it easier to query and structure the data

What it does

Most docs-as-code approaches rely on folders of markdown, with each file turning into one page

These means that a lot of other concerns, like site navigation/structure, search and/or tags, link validation, etc concerns that either are part of static site framework or left up to the user.

Markdown manager takes a different approach and offers the following features:

  • Ingest markdown (in many flavors) and allows for adding metadata via optional plugins (more information below)
  • Frontmatter support, with the ability to query documents based on frontmatter properties
  • Document contents (and metadata) can be extracted for easy ingestion into search index
  • Markdown Manager includes the ability to place documents into a hierarchial tree of "directories", "documents", and "media". These do not need to be physical directories (but can be) and allow for organizing documents into any hierarchy that maps to navigation structure and/or URL structure
  • Fetch and render documents with support for different renders / markdown flavors

Quick Start

Install markdown-manager package

npm install markdown-manager

Create a markdown-manager configuration

markdown-manager is powered by a configuration file which determines the document repositories, etc.

the full configuration options are shown in the configuration options section

export const mdmConfig = {
  repos: {
    "default": { // the name of the repo
      webUrlPattern: "/docs/:id", // a pattern that determines the final url
      validators: [
        {name: "linkChecker", options: {internalLinks: true, externalLink: false}} // configure a set of validators
        {name: "frontmatterFields", options: {
          requiredFields: {
            tags: "array",
          }
        }}
      ],
      extractors: [
        {name: "documentIndex", options: {sections: ['h1', 'h2', 'h3', maxWordsPerSection: 100]}}
      ],
      sources: {
        markdown: {
          source: "files",
          extensions: ['.md'],
          pathRoot: "./docs/",
          markdownFlavor: "markdown"
        },
        markdoc: {
          source: "files",
          extensions: ['.mdoc'],
          pathRoot: "./docs/",
          markdownFlavor: "markdoc"
        }
      }
    }
  }
}

Create the manager instance, validate, etc

// manager.js
import { Manager } from 'markdown-manager'
import { mdmConfig } from './mdm-config'
import { searchIndexer } from './my-search-index'
import { cache } from 'react'

export async function getDefaultRepo() {
  const manager = new Manager(mdmConfig)
  const defaultRepo = await manager.buildRepo('default')

  const validationErrors = await defaultRepo.validate()
  const errorLevel = validationErrors.filter(
    (validationError) =>
      validationError.level === 'error' || validationError.level === 'critical'
  )
  if (errorLevel.length > 0) {
    // handle errors
    throw new Error('critical validation errors')
  }

  // extract data and use as needed (for example, building a search index)
  const extractedData = await defaultRepo.extract()
  await searchIndexer.buildSearchIndex(extractedData.documentIndex)

  return defaultRepo
}

export const getDocById = cache(async (id) => {
  const repo = await getDefaultRepo()

  return repo.getDoc(id)
})

Use a doc repo to fetch and render a document in site like next.js

As an example, we use the repo in a next.js app router page

// app/docs/[...id]/page.js
import {getDefaultRepo, getDocById} from '../../../manager'

const
export async function generateStaticParams() {
  const repo = getDefaultRepo()

  const docs = repo.docs()

  return docs.map((doc) => ({
    id: doc.id
  }))
}

export default async function Doc({params}) {
  const doc = await getDocById(params.id)

  // depending on the doc type, we may get a different output from
  // the render function. In some cases, it is HTML, in other cases, it may be a react component!

  if (doc.renderTarget === 'react') {
    const DocRenderer = doc.render()
    return <DocRenderer />
  } else {
    return (
      <div
        dangerouslySetInnerHTML={{__html: doc.render()}}
      />
    )
  }
}

Concepts

Repos

A repo represents a group of documents where the docs are all intended to fall under the same destination or search index.

A repo can have multiple sources of documentation, but all docs will be treated the same way in terms of validation rules, extraction processes, etc

Sources

A source provides documents from a location (local or remote) with the same flavor of markdown.

Markdown flavors

Markdown has had many variants in syntax over the years with different extensions. Some of these may just be custom tags, like docusaurus admonitions, MDX, and Markdoc

This means that markdown manager cannot perform the same set of actions for all "markdown", for example, markdoc and mdx support partial documents, but the implementations are specific to each flavor. The interface for a flavor does try to create a "generic" markdown file, with additional syntax striped, which is intended for some downstream plugins (like extractors for building a search index)

Tree / Node

Markdown manager exposes files in a directory like structure. We represent this as a tree which can be iterated over

Validator / ValidatorSet

A validator is a single rule which should hold true for all matching documents in a repo. Validation errors do have varying levels of severity to allow for different errors to be handled. For example, in a production build we may throw an exception on a broken link during a build, but in a dev/test environment this would instead just be surfaced to the user.

Some validators may be coupled to a specific flavor of markdown, such as those that inspect a document contents, but other may be generic, like those that simple look at the frontmatter.

A ValidatorSet is the set of validators run over a repo, with validators being run in order.

Extractor

Extractors extract information from the set of documents. Like validators, some validators will be specific to a flavor of markdown, but others are generic.

Configuration Options

TODO