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

@trevixal/extension-writing

v1.0.5

Published

Writing assistance for the Trevixal editor: readability, passive voice, repeated words, grammar hints and keyword density as decorations and reports.

Downloads

536

Readme

@trevixal/extension-writing

CI npm types license

Documentation · Live editor · Changelog · Issues

The Trevixal editor

Features

  • Readability, passive voice, repeated words and grammar hints
  • Keyword density, as decorations and as a report
  • 8.8 kB minified and gzipped, with TypeScript types in the package

Readability, passive voice, repeated words, long sentences, grammar hints and keyword density, as marks in the margin and as a report.

npm install @trevixal/extension-writing

Usage

import { createWritingAssistant, analyzeText } from '@trevixal/extension-writing'

const assistant = createWritingAssistant(editor, {
  passive: true,
  repeated: true,
  grammar: true,
  longSentences: true,
  debounceMs: 400,
  onReport: (report) => renderIssues(report.issues),
})

assistant.applySuggestion(issue) // apply the fix, keeping the marks around it
assistant.goTo(issue)
assistant.setEnabled('passive', false)

Issues render through a decoration layer, so nothing is written into the document and a check you turn off leaves no trace behind.

At the word itself

A wavy underline tells the reader that something is wrong and not what. The inline UI puts the finding where the finding is:

import { createWritingAssistant, createWritingInlineUI } from '@trevixal/extension-writing'

const assistant = createWritingAssistant(editor)
createWritingInlineUI(editor, assistant)

Point at a flagged word and a small card names the check that fired and what it found. Click it and the same finding opens as a menu: the replacement where there is one, and Ignore this wording where the reader disagrees. Ctrl+. opens that menu for whatever is under the caret, so none of it needs a mouse.

Ignoring is by kind, rule and exact text rather than by position. "Their" waved through in one sentence is waved through in all of them. Dismissing a single occurrence would put the warning straight back the moment anything before it in the block was edited, because the range has moved.

Passive voice and over-long sentences are judgements rather than typos: there is no one replacement to offer, and the menu says so instead of showing an empty list.

Each painted span carries data-trevixal-issue, so a host building its own popovers can find its way from a DOM node back to assistant.issue(id).

The report

analyzeText(text) is pure and needs no editor:

const stats = analyzeText(editor.getText())
// words, sentences, syllables, Flesch reading ease and its label,
// Flesch-Kincaid grade, reading time (238 wpm), speaking time (150 wpm),
// passive matches, repeated words, long sentences, keyword density

Also exported piecemeal: fleschReadingEase, fleschKincaidGrade, readabilityLabel, readingTime, speakingTime, keywordDensity, findPassiveSentences, findRepeatedWords, findLongSentences, sentenceSpans, wordSpans, countSyllables, ENGLISH_STOPWORDS.

Grammar

Eight rules, deliberately: a/an agreement, sentence case, doubled spaces, space before punctuation, missing space after punctuation, repeated words, common errors and misspellings. Each returns a range and a suggestion, so the fix is one click.

They are conservative on purpose. A grammar checker that is wrong a fifth of the time is one people switch off, and then the other four fifths never get seen either.

Spell check

setSpellcheck(editor, enabled) and isSpellcheckEnabled(editor) drive the browser's own checker. A bundled dictionary is out of scope, since browsers ship better ones in more languages than a word list here could match.

Turning it back on does more than flip the attribute: a browser only checks text it has not seen before, so the helper swaps every rendered text node for an identical fresh one. Only text, replacing whole blocks also works but reloads embed iframes, which would restart a playing video on what should be a display-only toggle.

License

Apache-2.0