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-factory

v0.2.0

Published

1. [Markdown Factory](#markdown-factory)

Downloads

5,233

Readme

  1. Markdown Factory

    1. Why?

    2. Getting Started

      1. Installation

      2. Usage

    3. Examples

    4. API

      1. Headers

      2. link

      3. linkToHeader

      4. table

      5. tableOfContents

      6. codeBlock

      7. stripIndents

      8. blockQuote

      9. orderedList

      10. unorderedList

Markdown Factory

Utilities to easily generate valid markdown from within JavaScript

Why?

For static content, this library is mostly unnecessary. However, when generating a report from a dynamic data source this library can be rather useful.

An example of using this library for dynamic data, could be the implementation of the tableOfContents function. Inside it, we parse the headings and then use the utils to generate an appropriate table of contents. You can read more about it here: tableOfContents

Getting Started

Installation

npm install markdown-factory

Usage

Import the functions you need from markdown-factory, they are named based on the markdown they generate. For the most part, they take text content as the first argument, and any additional arguments are treated as sub-elements.

import { h1, h2, h3 } from 'markdown-factory';
h1('Hello World', h2('subheading', h3('sub-subheading', 'foo-bar')))

Examples

Some advanced usages of the library can be found below:

  • The generate-readme script generates this document

  • The implementation file for this library contains tableOfContents which dynamically composes several of these utility functions.

API

Headers

Headers are generated using the h1, h2, h3, h4, h5, and h6 functions. For example, a document with a title and 3 subsections could be generated like this:

h1('Title', 
  h2('Section 1', h3('Subsection 1', 'foo')), 
  h2('Section 2', h3('Subsection 2', 'bar')), 
  h2('Section 3', h3('Subsection 3', 'baz'))
)

link

A link can be generated using the link function. It takes a url and optionally a label as arguments.

link("https://google.com", "Google")

linkToHeader

A link to a header can be generated using the linkToHeader function. It takes a header and optionally a label as arguments.

This differs from link in that the contents of the ref are sanitized and parsed from header text first. This involves removing all non-alphanumeric characters, and replacing spaces with dashes. If this doesn't suit your use case, you should use link directly instead.

linkToHeader("Resources!", "More Resources and Information")
[More Resources and Information](#resources)

table

One of the more useful functions in this library is the table function. It takes an array of objects, and a list of fields to display. The fields are described in one of 3 forms:

  1. A simple string, which will be used as the label and the field name

  2. An object with a label and field property, which will be used as the label and the field name, respectively.

  3. An object with a label and mapFn property, which will be used as the label and a function to map the item to a string value.

These can be mixed and matched within the fields array as needed. For example, if you needed to relabel 1 field, and map another, you could do the following:

table(items, [ {
  label: "First Name", 
  field: "name" 
}, 
"age", 
{ 
  label: "City", 
  mapFn: (item) => item.address.city 
}]);

tableOfContents

The tableOfContents function takes a depth and the contents that it should cover. It will generate a table of contents for the headers up to the specified depth. For example, if you had a document with the following headers:

# Title
## Section 1
### Subsection 1
### Subsection 2
## Section 2
### Subsection 3
#### Subsubsection 1
### Subsection 4

You could generate a table of contents like this:

tableOfContents(3, mrkdwnContents);

The expected output would be:

- [Section 1](#section-1)
  - [Subsection 1](#subsection-1)
  - [Subsection 2](#subsection-2)
- [Section 2](#section-2)
  - [Subsection 3](#subsection-3)
  - [Subsection 4](#subsection-4)

Note: The depth passed into the function is equivalent to the maximum "level" of the headings displayed. e.g., depth=3 would not show any h4 or h5 headings.

codeBlock

The codeBlock function takes a string of code and an optional language. It will wrap the code in a code block, and optionally add syntax highlighting for the language. For example:

import { codeBlock } from 'markdown-factory';
codeBlock('const foo = "bar";', 'typescript');

stripIndents

The stripIndents function is rather unique in terms of this libraries functions. It doesn directly correlate to a markdown element, but is rather a utility function that strips leading whitespace from each line of a string. This doesn't affect the rendered markdown, but can be useful when writing code in a template string. For example, we can write this:

import { codeBlock, stripIndents } from 'markdown-factory';
if(someCondition) {
  if(someOtherCondition) {
    codeBlock(stripIndents`
      const foo = "bar";
      const baz = "qux";
    `, 'typescript');
  }
}

Instead of this:

import { codeBlock } from 'markdown-factory';
if(someCondition) {
  if(someOtherCondition) {
    codeBlock(`const foo = "bar";
const baz = "qux";`, 'typescript');
  }
}

blockQuote

The blockQuote function takes a string of text to render as a quote. For example:

import { blockQuote } from 'markdown-factory';
blockQuote('This is a quote');

orderedList

The orderedList function takes a list of strings to render as an ordered list. For example:

import { h1, orderedList } from 'markdown-factory';
h1('Sandwich Recipe', orderedList(
  'Slice bread',
  'Spread mayo',
  'Add lettuce',
  'Add tomato',
  'Add cheese',
  'Add meat',
  'Add condiments',
  'Eat'
));

You can also pass an options object as the first argument to the orderedList function. The options object can contain the following properties:

  • startIdx - The number to start the list at. Defaults to 1.

  • level - The level of the list (for nesting lists). Defaults to 1.

For example, the following code would produce a nested list that starts at 3:

import { h1, orderedList } from 'markdown-factory';
h1('Sandwich Recipe', orderedList(
  lines(
    'Slice bread', 
    orderedList(
      {startIdx: 3, level: 2}, 
      'Grab knife', 
      'Cut bread', 
      'Place on plate'
    )
  ),
  'Spread mayo'
)

Note - The actual numbers in an ordered list are not used in rendered markdown, but they are visible in the source. This is why the startIdx option is useful. For example, the following two lists are identical once rendered:

# List 1

1. Item 1
2. Item 2
3. Item 3

# List 2

1. Item 1
1. Item 2
1. Item 3

unorderedList

The unorderedList function takes a list of strings to render as an unordered list. For example:

import { h1, unorderedList } from 'markdown-factory';
h1('Sandwich Ingredients', unorderedList(
  'Bread',
  'Mayo',
  'Lettuce',
  'Tomato',
  'Cheese',
  'Meat',
  'Condiments'
));

You can also pass an options object as the first argument to the unorderedList function. The options object can contain the following properties:

  • level - The level of the list (for nesting lists). Defaults to 1.

For example, the following code would produce a nested list:

import { h1, unorderedList } from 'markdown-factory';
h1('Sandwich Ingredients', unorderedList(
  'Bread',
  'Ham',
  lines(
    'Condiments', 
    unorderedList(
      { level: 2 }, 
      'Ketchup', 
      'Mayo', 
      'Mustard'
    )
  ),
  'Spread mayo'
)