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

@shbernal/typography

v0.1.2

Published

Orthotypography rules for French, Spanish and German as data: check text against a national standard, or fix the subset that is safe to fix unattended.

Readme

@shbernal/typography

CI Corpus npm No dependencies

Orthotypography for French, Spanish and German, as data rather than as advice.

pnpm add @shbernal/typography
pnpm dlx @shbernal/typography check --lang fr README.fr.md

Why this exists

Non-English typography is full of rules that are invisible in a diff and wrong in print. French wants a no-break space before ; : ! ? and inside its guillemets. Spanish wants a paired ¿ at the start of a question. Germany sets »Wort« and Switzerland sets «Wort». Get one wrong and nobody on the team can see it, because U+00A0, U+202F and an ordinary space render identically and ' and are a font away from each other.

Three things follow, and they are what this package is:

Rules come from the body that decides them, and each one cites its source. Imprimerie nationale for French, RAE for Spanish, Duden for German. A rule with no citation does not ship. That is the line between a national standard and a house style, and English gets no pack for exactly that reason: the Oxford comma is not a standard.

Checking and fixing are different rule sets. A Spanish sentence ending in ? with no opening ¿ is unambiguously wrong and not safely fixable, because inserting the mark means deciding where the clause began. So check reports everything and fix applies only what is safe unattended. A finding that cannot be fixed is the interesting kind: it means somebody has to decide, not that nobody got round to it.

The pack does not assert what its citation does not fix. The Lexique typesets its own guillemets with U+202F and specifies U+00A0 in its own table, so the French pack rules on the spacing that is wrong under both readings and keeps whichever width a document already uses. The first version did not, and it "corrected" 6,462 guillemets in 2.4M characters of professionally typeset French. How that was found and fixed is the most useful thing in this repo.

What it is good for

Checking documentation and content in CI. typocheck check --lang fr --strict over your French or Spanish Markdown, exiting non-zero on findings. Every finding carries a line, a column, the citation and an escaped excerpt, so a report is readable and a reviewer can see the character.

Normalizing a translation pipeline. pack.normalize is the safe subset and nothing else, and { id, normalize } is the whole contract, so a host binds a pack without either package importing the other. The id is an era stamp: [email protected], moving only when a rule changes, so a corpus records which typography it was set in. If you normalize field by field and the fields must agree with each other, corpus-consistency.md is the part you need.

Giving a coding agent typography it cannot guess at. A Claude Code skill ships inside the package, so the skill and the binary it invokes cannot be different versions. It teaches the four things --help does not, starting with the fact that these findings are invisible and must be quoted escaped.

Reading the rules. A pack is a plain array of rules with summaries and citations. import { fr } from '@shbernal/typography/fr' and print it.

Four conventions, not one with a locale flag

| | French | Spanish | German (DE/AT) | German (CH) | |---|---|---|---|---| | Quotation marks | « … » | «…» | »…« | «…» | | Space inside them | required, U+00A0 or U+202F | forbidden | forbidden | forbidden | | Space before ; : ! ? | required | forbidden | forbidden | forbidden | | Opening marks | none | ¿ ¡, paired | none | none |

French and Spanish use the identical pair of characters with opposite spacing. German points them the other way and Switzerland points them back. So there is one module per convention, and there is no bare de: a pack id gets stamped onto a corpus, and a stamp that cannot tell a Swiss quotation from a German mistake is worse than no stamp at all.

Status

0.1.2, and pre-1.0 is the accurate thing to say. Every language has been run past real published text: 2.4M characters of French, 2.4M of German, 1.1M of Spanish, 311k of Swiss German. French additionally reproduces the implementation it was extracted from byte for byte over 11,058 real values.

docs/evidence.md has the table, what each number is worth, and what is thin. Zero findings can mean the text was set correctly or that it contained nothing the rule could match, so every gate report also counts how many times each character actually occurred.

Documentation

| | | |---|---| | docs/api.md | Library and CLI | | docs/design.md | Why the package is shaped this way | | docs/corpus-consistency.md | Normalizing many values that must agree | | docs/evidence.md | What the numbers are worth | | docs/development.md | Changing a rule, adding a language, cutting a release |

Contributing, and the report worth most

The single most useful issue this project can receive is a false positive: text that was set correctly and that typocheck complained about anyway. Unit tests measure whether a rule fires on text written to make it fire, which is recall, which was never in doubt. Only prose somebody published without a thought for this checker measures the failure mode these rules have, and that is the one thing this repo cannot generate for itself.

MIT, in LICENSE. The license covers this repository; it does not cover the gate corpora, which are third-party published works and are not redistributed here.