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

latexenc

v1.0.1

Published

TypeScript reimplementation of pylatexenc - LaTeX parser and text converter

Downloads

493

Readme

latexenc (TypeScript)

TypeScript reimplementation of the most commonly used pieces of the pylatexenc toolkit. It provides a LaTeX parser and a configurable text conversion engine that mirror latexwalker and latex2text from the original Python project while exposing a strongly typed API.

Feature Highlights

  • Recursive-descent parser (LatexWalker) that produces an AST of LaTeX nodes.
  • Default parsing and text contexts generated from the upstream pylatexenc specifications (macros, environments, specials).
  • Token parsing that mirrors TeX: mandatory arguments accept bare tokens (so \\hat x and similar constructs work without extra braces).
  • Text conversion engine (LatexNodes2Text) with pluggable handlers, accent and math macro support, and helpers for document metadata (\title, \author, \date).
  • \\verb macros and common verbatim environments (verbatim, lstlisting, …) are detected automatically using metadata from the Python project, so their bodies are preserved exactly.
  • First-class TypeScript types for all nodes, specs, and conversion hooks to make extending behaviour predictable.
  • Source TypeScript in src/ with ESM output in dist/ produced by tsc.

Usage

Convert LaTeX to text

import { LatexNodes2Text } from 'latexenc'

const latex = '\n\\title{Sample Slides}\nFran\\c{c}ais $= \\alpha + \\frac{1}{2}$'

const converter = new LatexNodes2Text({ mathMode: 'text' })
const text = converter.latexToText(latex)

console.log(text)
// Français = α + 1/2
console.log(converter.getDocumentMetadata('title'))
// "Sample Slides"

latexToText() performs the parsing step internally. If you already have nodes from LatexWalker, call nodesToText(nodes) instead.

Customise contexts

import {
  LatexNodes2Text,
  createDefaultParsingContext,
  createDefaultTextContext,
} from 'latexenc'

const parsing = createDefaultParsingContext()
parsing.addMacro({ name: 'vect', arguments: [{ type: 'group' }] })

const textContext = createDefaultTextContext()
textContext.addMacro({
  name: 'vect',
  replacement: ({ toText, node }) => {
    const arg = node.arguments[0]
    return arg?.type === 'group' ? `->${toText(arg.nodes)}` : ''
  },
})

const converter = new LatexNodes2Text({ parsingContext: parsing, textContext })

Contexts can be cloned via .clone() before mutation if you need separate configurations.

Parse without conversion

import { LatexWalker } from 'latexenc'

const walker = new LatexWalker('Hello \\textbf{world}!')
const nodes = walker.getNodes()
// nodes is LatexNode[] that you can analyse or transform directly.

Key conversion options

LatexNodes2Text accepts these notable options:

  • mathMode: 'text' | 'with-delimiters' | 'verbatim' | 'remove' to control math rendering.
  • keepComments: include or drop % comments.
  • strictSpaces: collapse runs of whitespace to a single space/newline.
  • keepBracedGroups and keepBracedGroupsMinLength: preserve braces for groups that meet a minimum length requirement.

Generated default specs

The default parsing/text contexts are derived from the vendored pylatexenc/ source. Re-run the generator whenever upstream specs change:

python3 tools/generate_specs.py

This refreshes src/data/generatedParsingSpec.ts and src/data/generatedTextSpecs.ts, which are consumed by the default context factories. The generator bakes several literal replacements (for example the value returned by \today), so re-run it if you need up-to-date defaults.

Development

  1. Install dependencies (Node.js 18+ recommended):

    npm install
  2. Build the ESM bundle in dist/:

    npm run build
  3. Execute the Vitest suite:

    npm test
  4. Lint the codebase (runs ESLint with the Antfu config; --fix is enabled and will update files in place):

    npm run lint

Limitations & Future Work

  • The project ports a meaningful subset of pylatexenc but not complete parity; complex argument parsers, verbatim environments, and fine-grained spacing rules are simplified.
  • Math mode conversion is heuristic and biased toward plain-text readability.
  • The default specs mirror a snapshot of upstream data. Regenerate them after pulling new changes from the Python project or when date-sensitive macros (for example \today) must reflect the current day.
  • npm install must precede build/test/lint because TypeScript and Vitest are dev dependencies.

Contributions are welcome—extending the default contexts or porting additional pylatexenc features is straightforward thanks to the modular structure.