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

rst-compiler

v0.4.0

Published

Parses reStructuredText and generates HTML or VitePress-compatible Markdown

Downloads

28

Readme

RST Compiler

This is a reStructuredText parser and HTML/Markdown generator implemented in pure TypeScript.

Basic Usage

import fs from 'node:fs'
import { RstToHtmlCompiler } from 'rst-compiler'

const rst = fs.readFileSync('./index.rst').toString('utf-8')
const html = new RstToHtmlCompiler().compile(rst)

console.log(html.header) // Content that should be written to <head>
console.log(html.body) // Main document

Multiple Documents Usage

In order to resolve references that may exist in other documents, the compiler uses two-stage compilation:

const compiler = new RstToHtmlCompiler()

// 1. The compiler first needs to parse each document into their respective ASTs
//    References are NOT checked at this stage since the compiler does not know what other documents you may have
const doc1ParserOutput = compiler.parse(':doc:`See Document 2 <./foo>`')
const doc2ParserOutput = compiler.parse('Document 2')

// 2. The compiler then reads all the ASTs for your project in order to resolve references and generate HTML
const doc1Html = compiler.generate({
    basePath: '/blog/', // Any links to other documents will be prefixed with this value
    currentDocPath: 'index', // Relative to basePath
    docs: [
        {
            docPath: 'index',
            parserOutput: doc1ParserOutput,
        },
        {
            docPath: 'foo',
            parserOutput: doc2ParserOutput,
        },
    ],
})

console.log(doc1Html.body) // <a href="/blog/foo">See Document 2</a>

Limitations

Since reStructuredText does not have a formal specification, this program's behavior may deviate slightly from the reference implementation in Python's docutils library due to differences in parsing strategies.

  • Only spaces can be used for indentation

  • Third-party extensions and most directives and interpreted text roles from Sphinx are not available since they are implemented in Python

  • It is not recommended to run the compiler on untrusted input as there is no XSS sanitation on the output. In addition, the compiler makes extensive use of lookahead and lookbehind regular expressions which may cause ReDoS attacks.

Plugins

If you wish to add additional functionality, you should either implement custom Directives (for block-level output) or custom InterpretedTexts (for inline-level output).

import { RstCompilerPlugin } from 'rst-compiler'

const plugin: RstCompilerPlugin = {
    onInstall: (compiler) => {
        compiler.useDirectiveGenerator({
            directives: [
                'custom-directive',
            ],

            generate: (generatorState, node) => {
                generatorState.visitNodes(node.children)
            },
        })
    },
}

const compiler = new RstToHtmlCompiler()
compiler.usePlugin(plugin)

All of the built-in Directives and InterpretedText in the compiler are implemented as plugins as well. Please see the Plugins directory for example code.

InterpretedText Roles Supported

All standard text roles are supported. In addition, the following text roles from Sphinx are supported:

:ref:

See sphinx for more information.

:doc:

See sphinx for more information.

:download:

See :download:`this example script <example.py>`.
const { downloads } = RstToHtmlCompiler.compile(rst)
console.log(downloads[0])
// {
//     srcPath: '/example.py',
//     destPath: '/_downloads/954c614a01144f97fd09b9c1d1dbc574fc10e6c0/example.py',
// }

The output will be an <a> that links to the _downloads directory. You will need to serve it with appropriate Content-Type headers that allow browsers to download the link.

See sphinx for more information.

Directives Supported

attention, caution, danger, error, hint, important, note, tip, warning, admonition

.. danger::

   Beware killer rabbits!

See docutils for more information.

image, figure

.. image:: picture.png

See docutils for more information.

only

.. only:: html and draft

    This text will only appear when html and draft fields in RstGeneratorOptions.outputEnv are true
RstToHtmlCompiler.compile(rst, {}, {
    outputEnv: {
        html: true,
        draft: true,
    },
})

See sphinx for more information.

code, highlight (powered by Shiki)

.. code:: python

   def my_function():
       "just a test"
       print(8/2)

By default, the HTML compiler will simply output plaintext inside <pre> tags. If you wish to enable syntax highlighting, you will need to provide a shiki object in RstGeneratorOptions:

import { getHighlighter } from 'shiki'
import { RstToHtmlCompiler, RstGeneratorOptions } from 'rst-compiler'

const generatorOptions: Partial<RstGeneratorOptions> = {
    shiki: {
        theme: 'github-light',
        highlighter: await createHighlighter({
            langs: ['python', 'js'],
            themes: ['github-light'],
        }),
    },
}

RstToHtmlCompiler.compile(rst, {}, generatorOptions)

See docutils for more information.

math (powered by KaTeX)

.. math::

    \sin(x) = \sum_{n=0}^{\infty} \frac{(-1)^n x^{2n+1}}{(2n+1)!}
const html = RstToHtmlCompiler.compile(rst)
console.log(html.header) // Will contain <link> to katex's css

See docutils for more information.

tabs, tab, code-tab (based on sphinx-tabs)

.. tabs::

    .. tab:: Label A

        Text A

    .. tab:: Label B

        Text B
const html = RstToHtmlCompiler.compile(rst)
console.log(html.header) // Will contain <script> needed to make tabs interactive

See sphinx-tabs for more information.

Note: If you are using the Markdown output in VitePress, you will need to install vitepress-plugin-tabs

Dev Notes

Create ./tests/playground/playground.rst (not tracked by Git) and write test input

  • Run yarn playPy to run docutils (Python reference implementation) on test input

  • Run yarn playJs to run rst-compiler on test input (requires Bun runtime)

    • Press F5 in VSCode to run this command inside the debugger

    • Run yarn server to serve the output at localhost:8080