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

@ashnazg/mochadocs

v1.1.0

Published

### 1.1 * Scanning a path for test JS's (including the default path of "test/") now reads mjs and cjs in, not just js.

Downloads

4

Readme

Purpose

I really wanted something like sphinx or doxygen but with the least possible syntax and the most DRY I could think of.

Principles:

  1. Readable code is the best documentation.
  2. Readable tests is the 2nd best documentation.
  3. While real design docs shouldn't be crammed into this format, the unit tests file be a significant (hyperlinked) participant reduces how much pure prose has to be written.

Releases

1.1

  • Scanning a path for test JS's (including the default path of "test/") now reads mjs and cjs in, not just js.

Reads Mocha test files and emits a README.md

Default behavior

reads from ./test/ and writes ./README.md The file you're reading was created by running:

const mochadocs = require('@ashnazg/mochadocs');
await mochadocs();

... and there are asserts on this page because you're reading the unit tests.

what's emitted

  1. Lines that begin with /// are emitted as markdown.
  2. describe(...) is parsed to make h2's
  3. it(...) is parsed to make h3's
  4. Lines of code or vanilla comments are also emitted, but wrapped in a pre-block.

Supports Transclusion

A line that is exactly ///{{filename}} will try to cat that filename in.

big Nota Bene: This is relative to the PWD of the process, NOT relative to the file the transclusion is present in.

The Release section on this page was transcluded from another file by saying: ///{{CHANGELOG.md}}

Options

Defaults

if no params given, defaults to:

await mochadocs({path: 'test'});

if you don't need any other options, you can pass it just the path string:

await mochadocs('test');

the full config format is:

await mochadocs({
	path: 'test',
	to: 'README.md',
	libname: '@ashnazg/mochadocs',
	glossary: { // for auto-linking frequently used terms
		acronym1: 'path1',
	},
	indent: '\t\t'
});

Support for space-indented files

Visible code blocks are defined as non-/// lines that start with conf.indent and are between the opening line of the current it(...) and the it-closer, which is the first line of code with less indentation thatn conf.indent.

so for a 2-space file like:

describe('group', function() {
  it('thing', function() {
    visible_code();
  });
  function invisibleHelper() {
    invisible_code();
  };
});

You'd use:

await mochadocs({
  indent: '    ' // four spaces
});

When the indent drops below the conf.indent, code blocks are not emitted til the next it( -- this is so the invisibleHelper's contents don't pollute the unit test's code printout.

Explicit output

you can write the output to a specific place:

await mochadocs({to: 'different.md'});
{
	const lines = (await fs.promises.readFile('different.md', 'utf8')).split('\n');
	assert(lines[length_of_preamble] === '## Reads Mocha test files and emits a README.md');
}

or pass null as the destination and it'll return the markdown file as a list of lines:

{
	const lines = await mochadocs({to: null});
	assert(lines[length_of_preamble] === '## Reads Mocha test files and emits a README.md');
}

Explicit input, file

path can be a filename:

const lines = await mochadocs({path: 'test/basics.js', to: null});
assert(lines[length_of_preamble] === '## Reads Mocha test files and emits a README.md');

Explicit input, dir

... or a directory, in which it'll read all *.js, including subfolders, and process them after sorting them by 'path/filename'.

const lines = await mochadocs({path: 'test', to: null});
assert(lines[length_of_preamble] === '## Reads Mocha test files and emits a README.md');

Replaces require('..')

since in a library's unit tests, require('..') is useful, but not helpful documentation, This is converted to require('LIBNAME').

const lines = await mochadocs({path: 'test', to: null}); // reading the output of section "default"
const hits = lines.filter(line => line === "const mochadocs = require('@ashnazg/mochadocs');");
assert(hits.length === 1);

Configuring require('..') replacement

By default, mochadocs assumes that ./package.json is available and will use that to know your lib's name. if that's not a useful guess (wrong path or wrong name) you can pass in a library name of your choosing as a third param:

const lines = await mochadocs({path: 'test', to: null, libname: 'custom_lib_name'});
const hits = lines.filter(line => line === "const mochadocs = require('custom_lib_name');");
assert(hits.length === 1);

Automatic Glossary

To allow good linkage to other relevant topics without repetitive writing, you can pass in a glossary map and if that key is found in the non-code blocks, it'll be emitted as a link:

lines = await mochadocs({
	to: null,
	glossary: {
		GLOSSARY: 'https://en.wikipedia.org/wiki/Glossary'
	}
});

Glossary Rules

Only links exact words

Given the above config, the word "GLOSSARY" is now a link.

// search term without creating a false positive:
{
	const key = `[GLOS` + `SARY](https://en.wikipedia.org/wiki/Glossary)`;
	const hits = lines.filter(line => line.includes(key));
	assert(hits.length === 1, `${hits.length} hits`);
}

... but GLOSSARYFOO is not, because the replacer respects word boundaries.

{
	const key = `GLOS` + `SARYFOO`;
	const hits = lines.filter(line => line.includes(key));
	assert(hits.length === 1, `${hits.length} hits`);
}

Longer glossary terms take precedence

await mochadocs({
	glossary: {
		GLOSSARY: 'https://en.wikipedia.org/wiki/Glossary',
		SHORT_NAME: '#glossary-rules',
		SHORT_NAME_IN_LONGER_NAME: '#longer-glossary-terms-take-precedence'
	}
});

SHORT_NAME_IN_LONGER_NAME should be a clean link, and its internals should not be affected by the SHORT_NAME term, as replacement is not allowed to go into recursive expansion.

const lines = (await fs.promises.readFile('README.md', 'utf8')).split('\n');
const key = `[SHORT_NAM` + `E_IN_LONGER_NAME](#longer-glossary-terms-take-precedence) should be a clean link, and its internals should not be affected by the [SHORT_NAME](#glossary-rules) term`;
const hits = lines.filter(line => line.includes(key));
assert(hits.length === 1, `${hits.length} hits`);

Existing links are unaffected

this predefined link SHORT_NAME is not further processed.

const lines = (await fs.promises.readFile('README.md', 'utf8')).split('\n');
// here's the unwanted form:
const key = `[[SHORT` + `_NAME](test1)](#existing-links-are-unaffected)`;
const hits = lines.filter(line => line.includes(key));
assert(hits.length === 0, `${hits.length} hits`);

Release 1.0.2

fixed a bug where a really short input file leaves the code pre unclosed

const lines = await mochadocs({path: 'samples/trailing-pre-missing.js', to: null});
assert(lines[lines.length-1] === '```', 'simple did not close pre');

Release 1.0.1

  1. Suppressed codeblocks that aren't inside an it(...)

Release 1.0

  1. Wrote the thing