Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
documentary
Advanced tools
A Documentation Pre-processor To Generate The Table Of Contents, Embed Examples With Their Output, Make Markdown Tables, Maintain Typedefs For JavaScript And README, Watch Changes To Push, Use Macros And Prettify API Titles.
Documentary is a command-line tool and a library to manage documentation of Node.js packages. Due to the fact that there is usually a lot of manual labour involved in creating and keeping up-to-date a README document, such as copying examples and the output they produce, there is a need for software that can help automate the process and focus on what is really important. Documentary serves as a pre-processor of documentation and enhances every area of the task of making available quality docs for Node.js (and other languages) packages for fellow developers.
yarn add -DE documentary
This section has a quick look at the best features available in Documentary and how they help the documentation process.
Feature | Description | Advantages |
---|---|---|
Tables Of Contents | Compiles an accurate table of contents for the content. | 1. Makes the structure of the document immediately visible to the reader. 2. Allows to navigate across the page easily. 3. Shows problems with incorrect levels structure which otherwise might not be visible. 4. Allows to place anchor links available from the TOC at any level in any place of the README. 5. Can insert section breaks which visually divide the content and allow to navigate back to the top. |
Examples | Allows to embed the source code into documentation. | 1. Increases productivity by eliminating the need to copy and paste the source code manually. 2. Developers can run examples as Node.js scripts to check that they are working correctly and debug them. 3. Examples can also be forked (see below). 4. It is possible to imports and requires such as ../src to be displayed as the name of the package. |
Forks | Makes it possible to run an example and embed its stdout and stderr output directly into documentation. | 1. Enhances productivity by eliminating the need to copy and paste the output by hand. 2. Makes sure the output is always up-to-date with the documented one. 3. Will make it visible if a change to the code base lead to a different output (implicit regression testing). 4. Ensures that examples are actually working. 5. Can print usage of CLI tools by forking them with -h command. |
JSX Components | Performs the compilation of custom-defined JSX components into markdown code. | 1. Lets to define custom components and reuse them across documentation where needed. 2. Provides a modern syntax to combine markdown and JavaScript. |
Tables | Compiles tables from arrays without having to write html or markdown. | 1. Removes the need to manually build tables either by hand, online or using other tools. 2. Provides table macros to reduce repetitive information and substitute only the core data into templates. |
Macros | Reuses a defined template to place the data into placeholders. | 1. Removes the need to copy-paste patterns to different places and change data manually. 2. Maintains an up-to-date version of the template without having to change it everywhere. 3. Reduces the cluttering of the source documentation by noise and helps to focus on important information. |
Live Push | Detects changes to the source documentation files, re-compiles the output README.md and pushes to the remote repository. | 1. The preview is available on-line almost immediately after a change is made. 2. Allows to skip writing a commit message and the push command every time a change is made. |
Typedefs | Maintains a types.xml file to place types definition in it, available both for source code and documentation. | 1. Keeps the types declarations in one place, allowing to quickly update it both in JavaScript JSDoc, and in markdown README. 2. Automatically constructs type tables for documentation. 3. Expands the JSDoc config (options) argument for other developers to have a quick glance at possible options when calling a function. 4. Links all types across the whole documentation for quick navigation. 5. If the types.xml file or directory is published, other packages can embed it into documentation also, by using Documentary. |
API Method Titles | Creates good-looking headers for methods. | 1. By writing each argument on new line, makes it easier to understand the signature of a function. 2. Can maintain a separate title for the table of contents to keep things simple there. |
Type
Definition
@typedef
Organisation
Titles
The doc
client is available after installation. It can be used in a doc
script of package.json
, as follows:
{
"scripts": {
"doc": "doc documentary -o README.md"
}
}
The first argument, documentary
is a path to a directory containing source documentation files, or a path to a single file to be processed, e.g., README-source.md
.
Therefore, to produce an output README.md
, the following command will be used:
yarn doc
When actively working on documentation, it is possible to use the watch
mode with -w
flag, or -p
flag to also automatically push changes to a remote git repository, merging them into a single commit every time.
Table of contents are useful for navigation in a README document. When a %TOC%
placeholder is found in the file, it will be replaced with an extracted structure. Titles appearing in comments and code blocks will be skipped.
By default, top level h1
headers written with #
are ignored, but they can be added by passing -h1
CLI argument.
- [Table Of Contents](#table-of-contents)
- [CLI](#cli)
* [`-j`, `--jsdoc`: Add JSDoc](#-j---jsdoc-add-jsdoc)
- [API](#api)
- [Copyright](#copyright)
To be able to include a link to a specific position in the text (i.e., create an "anchor"), Documentary has a TOC Titles
feature. Any text written as [Toc Title](t)
will generate a relevant position in the table of contents. It will automatically detect the appropriate level and be contained inside the current section.
This feature can be useful when presenting some data in a table in a section, but wanting to include a link to each row in the table of contents so that the structure is immediately visible.
Level TOC Titles: if required, the level can be specified with a number of #
symbols, such as [Specific Level](###)
.
A section break is a small image in the center of the page which indicates the end of a section. With larger sections which also include sub-sections, this feature can help to differentiate when the topic finishes and another one starts. They can also be used to navigate back to the table of contents, or a specified location.
At the moment, there is support for pre-installed section breaks. In future, more support of custom images will be included.
To insert a section brake, the following marker is used:
%~[, number[, attributes]]%
For example:
%~%
%~ 15%
%~ -1%
%~ href="https://hello.world" width="200"%
<p align="center"><a href="#table-of-contents"><img src=".documentary/section-breaks/0.svg?sanitize=true"></a></p>
<p align="center"><a href="#table-of-contents"><img src=".documentary/section-breaks/15.svg?sanitize=true"></a></p>
<p align="center"><a href="#table-of-contents"><img src=".documentary/section-breaks/-1.svg?sanitize=true"></a></p>
<p align="center"><a href="#table-of-contents"><img src=".documentary/section-breaks/16.svg?sanitize=true" href="https://hello.world" width="200"></a></p>
There are 23 available section breaks which will be inserted in incremental order in the document. When the end of the list is reached, the count restarts. There are also 3 ending breaks which can be inserted at the end and do not participate in the rotation, so that they must be inserted manually. To select a specific image, its number can be given.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | |
-1 | -2 | -3 |
---|---|---|
By default, the section brake will link to the table of contents, however this can be changed by setting the href
attribute. The images are also SVGs therefore it is possible to give them any width via the width
attribute and they will stretch without any loss of quality. Documentary will copy images from its source code to the .documentary/section-breaks
directory in the repository. To control the destination, set the to
attribute on section breaks.
One of the most common problem with markdown is that it is hard to write tables. They must be written either as html, or as markdown, which is troublesome and requires effort. Although there are online tools to build markdown tables, with Documentary the process is even simpler: the data just needs to be put into a JSON array.
To describe tabular data (for example, a CLI tool arguments) in a table, but prepare them in a more readable format, Documentary allows to write code blocks with the table
language to be converted into a markdown table. The content of the blocks must be in JSON
format and contain a single array of arrays which represent rows.
```table
[
["arg", "description"],
["-f", "Display only free domains"],
["-z", "A list of zones to check"],
]
```
Result:
arg | description |
---|---|
-f | Display only free domains |
-z | A list of zones to check |
Whenever there's a pattern for presenting data in a table, such as that input fields can be mapped to output columns, a table macro can be defined. The example below defines a macro to print a row containing a link, logo and description of a company. It is then used in a table, where only the actual values are entered, relying on Documentary to substitute them in the template.
%TABLE-MACRO Company
<a href="$2">![$1 Logo](images/logos/$3)</a>, $4, $5\, $6
%
```table Company
[
["Company", "Tag Line", "Evaluation & Exit"],
[
"VWO", "https://vwo.com", "vwo.png", "A/B Testing and Conversion Optimization Platform™", "$10m", "2018"
]
]
```
| Company | Tag Line | Evaluation & Exit |
| --------------------------------------------------------------- | ------------------------------------------------- | ----------------- |
| <a href="https://vwo.com">![VWO Logo](images/logos/vwo.png)</a> | A/B Testing and Conversion Optimization Platform™ | $10m, 2018 |
The values in the macro need to be separated with ,
which allows to substitute them into the correct column of the table row. When a ,
needs to be used as part of the column in the macro, it can be escaped with \
such as \,
as shown in the last column of the example.
Company | Tag Line | Evaluation & Exit |
---|---|---|
A/B Testing and Conversion Optimization Platform™ | $10m, 2018 |
Documentary can be used to embed examples into the documentation. The example file needs to be specified with the following marker:
%EXAMPLE: example/example.js [, ../src => documentary] [, javascript]%
The first argument is the path to the example relative to the working directory of where the command was executed (normally, the project folder). The second optional argument is the replacement for the import
statements (or require
calls). The third optional argument is the markdown language to embed the example in and will be determined from the example extension if not specified.
Given the documentation section:
## API Method
This method allows to generate documentation.
%EXAMPLE: example/example.js, ../src => documentary, javascript%
And the example file examples/example.js
import documentary from '../src'
import Catchment from 'catchment'
(async () => {
await documentary()
})()
The program will produce the following output:
## API Method
This method allows to generate documentation.
```javascript
import documentary from 'documentary'
import Catchment from 'catchment'
(async () => {
await documentary()
})()
```
Whenever only a part of an example needs to be shown (but the full code is still needed to be able to run it), Documentary allows to use start
and end
comments to specify which part to print to the documentation. It will also make sure to adjust the indentation appropriately.
import documentary from '../src'
import Catchment from 'catchment'
(async () => {
/* start example */
await documentary()
/* end example */
})()
await documentary()
When placing examples, it is important to show the output that they produce. This can be achieved using the FORK
marker.
%FORK(-lang)? module ...args%
It will make Documentary fork a Node.js module using the child_process.fork
function. The output is printed in a code block, with optionally given language.
Markdown | JavaScript |
---|---|
|
|
Output | |
|
By default, the FORK
marker will print the stdout
output. To print the stderr
output, there is the FORKERR
marker.
%FORKERR(-lang)? module ...args%
It works exactly the same as %FORK%
but will print the output of the process's stderr
stream.
Markdown | JavaScript |
---|---|
|
|
Output | |
|
Documentary can generate neat titles useful for API documentation. The method signature should be specified in a JSON
array, where every member is an argument written as an array containing its name and type. The type can be either a string, or an object.
For object types, each value is an array which contains the property type and its default value. To mark a property as optional, the ?
symbol can be used at the end of the key.
The last item in the argument array is used when the argument is an object and is a short name to be place in the table of contents (so that a complex object can be referenced to its type).
async runSoftware(
path: string,
config: {
View: Container,
actions: object,
static?: boolean = true,
render?: function,
},
): string
Generated from
```### async runSoftware => string
[
["path", "string"],
["config", {
"View": ["Container"],
"actions": ["object"],
"static?": ["boolean", true],
"render?": ["function"]
}, "Config"]
]
```
async runSoftware(
path: string,
): void
Generated from
```### async runSoftware
[
["path", "string"]
]
```
runSoftware(): string
Generated from
```### runSoftware => string
```
runSoftware(): void
Generated from
```### runSoftware
```
Documentary lets users define their custom components in the .documentary
folder both in the project directory and the user's home directory. The components are written using JSX syntax and exported as named functions from jsx
files. The properties the component receives are extracted from the markdown syntax and passed to the hyperscript constructor (from preact
).
For example, the user can define their own component in the following way:
/**
* Display the sponsor information.
*/
export const Sponsor = ({
name, link, image, children,
}) => {
return <table>
<tr/>
<tr>
<td align="center">
<a href={link}>
<img src={image} alt={name}/>
</a><br/>
Sponsored by <a href={link}>{name}</a>.
</td>
</tr>
{children && <tr><td>{children}</td></tr>}
</table>
}
And then invoke it in the documentation:
<Sponsor name="Tech Nation Visa Sucks"
link="https://www.technation.sucks"
image="sponsor.gif">
Get In Touch To Support Documentary
</Sponsor>
The result will be rendered HTML:
Sponsored by Tech Nation Visa Sucks. |
Get In Touch To Support Documentary |
Since comments found in <!-- comment -->
sections are not visible to users, they will be removed from the compiled output document.
When there this a need to present some data in a repeatable format, macros can be used. First, a macro needs to be defined with the MACRO
rule, and then referenced by the USE-MACRO
rule.
%MACRO example
<details>
<summary>$1</summary>
NPM: _[$1](https://nodejs.tools/$2)_
GitHub: _[$1](https://github.com/artdecocode/$2)_
</details>
%
%USE-MACRO example
<data>Documentary</data>
<data>documentary</data>
%
%USE-MACRO example
<data>Zoroaster</data>
<data>zoroaster</data>
%
<details>
<summary>Documentary</summary>
NPM: _[Documentary](https://nodejs.tools/documentary)_
GitHub: _[Documentary](https://github.com/artdecocode/documentary)_
</details>
<details>
<summary>Zoroaster</summary>
NPM: _[Zoroaster](https://nodejs.tools/zoroaster)_
GitHub: _[Zoroaster](https://github.com/artdecocode/zoroaster)_
</details>
The data will be substituted with into $N
placeholders using the <data>
elements found.
NPM: Documentary GitHub: Documentary
Currently, a macro can only be defined in the same file as its usage. Also, in future, macros will improve my allowing to use named placeholders.
Documentary can read a directory and put files together into a single README
file. The files will be sorted in alphabetical order, and their content merged into a single stream. The index.md
and footer.md
are special in this respect, such that the index.md
of a directory will always go first, and the footer.md
will go last. To print in reverse order, for example when writing a blog and name files by their dates, the --reverse
flag can be passed to the CLI.
Example structure used in this documentation:
documentary
├── 1-installation-and-usage
│ └── index.md
├── 2-features
│ ├── 1-toc.md
│ ├── 1-toc2-section-breaks.md
│ ├── 10-typedef
│ │ ├── 1-js.md
│ │ ├── 2-readme.md
│ │ ├── 3-advanced.md
│ │ ├── 3-imports.md
│ │ ├── 4-schema.md
│ │ ├── 9-migration.md
│ │ └── index.md
│ ├── 2-tables.md
│ ├── 3-examples.md
│ ├── 3-fork.md
│ ├── 3-method-title.md
│ ├── 3.5-jsx-components.md
│ ├── 4-comment-stripping.md
│ ├── 4-macros.md
│ ├── 5-file-splitting.md
│ ├── 6-rules.md
│ ├── 8-gif.md
│ ├── 9-type.md
│ └── footer.md
├── 3-cli.md
├── 4-api
│ ├── 1-toc.md
│ ├── footer.md
│ └── index.md
├── footer.md
└── index.md
There are some other built-in rules for replacements which are listed in this table.
Rule | Description |
---|---|
%NPM: package-name% | Adds an NPM badge, e.g., [![npm version] (https://badge.fury.io/js/documentary.svg)] (https://npmjs.org/package/documentary) |
%TREE directory ...args% | Executes the tree command with given arguments. If tree is not installed, warns and does not replace the match. |
The GIF
rule will inserts a gif animation inside of a <detail>
block. To highlight the summary with background color, <code>
should be used instead of back-ticks. TOC title link also work inside the summary.
%GIF doc/doc.gif
Alt: Generating documentation.
Click to View: [<code>yarn doc</code>](t)
%
yarn doc
The actual html placed in the README
looks like the one below:
<details>
<summary>Summary of the detail: <code>yarn doc</code></summary>
<table>
<tr><td>
<img alt="Alt: Generating documentation." src="doc/doc.gif" />
</td></tr>
</table>
</details>
Type
DefinitionOften, it is required to document a type of an object, which methods can use. To display the information about type's properties in a table, the TYPE
macro can be used. It allows to show all possible properties that an object can contain, show which ones are required, give examples and link them in the table of contents (disabled by default).
Its signature is as follows:
%TYPE addToToc(true|false)
<p name="propertyName" type="propertyType" required>
<d>Property Description.</d>
<d>Property Example.</d>
</p>
%
For example,
%TYPE
<p name="text" type="string" required>
<d>Display text. Required.</d>
<e>
```js
const q = {
text: 'What is your name',
}
```
</e>
</p>
<p name="validation" type="(async) function">
<d>A function which needs to throw an error if validation does not pass.</d>
<e>
```js
const q = {
text: 'What is your name',
validate(v) {
if (!v.length) throw new Error('Name is required.')
},
}
```
</e>
</p>
%
will display the following table:
Property | Type | Description | Example |
---|---|---|---|
text* | string | Display text. Required. |
|
validation | (async) function | A function which needs to throw an error if validation does not pass. |
|
When required to use the markdown syntax in tables (such as __
, links, etc), an extra space should be left after the d
or e
tags like so:
%TYPE true
<p name="skipLevelOne" type="boolean">
<d>
Start the table of contents from level 2, i.e., excluding the `#` title.</d>
</p>
%
Otherwise, the content will not be processed by GitHub
. However, it will add an extra margin to the content of the cell as it will be transformed into a paragraph.
Because examples occupy a lot of space which causes table squeezing on GitHub and scrolling on NPM, Documentary allows to dedicate a special row to an example. It can be achieved by adding a row
attribute to the e
element, like so:
%TYPE
<p name="headers" type="object">
<d>Incoming headers returned by the server.</d>
<e row>
```json
{
"server": "GitHub.com",
"content-type": "application/json",
"content-length": "2",
"connection": "close",
"status": "200 OK"
}
```
</e>
</p>
%
In addition, any properties which do not contain examples will not have an example column at all.
Property | Type | Description | Example |
---|---|---|---|
body | string|object|Buffer | The return from the server. | |
headers | object | Incoming headers returned by the server. | |
| |||
statusCode | number | The status code returned by the server. | 200 |
Finally, when no examples which are not rows are given, there will be no Example
heading.
%TYPE
<p name="data" type="object">
<d>Optional data to send to the server with the request.</d>
<e row>
```js
{
name: 'test',
}
```
</e>
</p>
<p name="method" type="string">
<d>What HTTP method to use to send data (only works when <code>data</code> is set).</d>
</p>
%
Property | Type | Description |
---|---|---|
data | object | Optional data to send to the server with the request. |
| ||
method | string | What HTTP method to use to send data (only works when data is set). |
@typedef
OrganisationFor the purpose of easier maintenance of JSDoc @typedef
declarations, Documentary allows to keep them in a separate XML file, and then place compiled versions into both source code as well as documentation. By doing this, more flexibility is achieved as types are kept in one place but can be reused for various purposes across multiple files. It is different from TypeScript type declarations as Documentary will generate JSDoc comments rather than type definitions which means that a project does not have to be written in TypeScript.
Types are kept in a separate xml
file, for example:
<types>
<import name="ServerResponse" from="http"
link="https://nodejs.org/api/http.html#http_class_http_serverresponse"
/>
<type name="SetHeaders"
type="(res: ServerResponse) => any"
desc="Function to set custom headers on response." />
<type name="RightsConfig"
type="{ location: string, rights: number }[]"
desc="Configuration of read and write access rights." />
<type name="StaticConfig" desc="Options to setup `koa-static`.">
<prop string name="root">
Root directory string.
</prop>
<prop number name="maxage" default="0">
Browser cache max-age in milliseconds.
</prop>
<prop boolean name="hidden" default="false">
Allow transfer of hidden files.
</prop>
<prop string name="index" default="index.html">
Default file name.
</prop>
<prop opt type="SetHeaders" name="setHeaders">
Function to set custom headers on response.
</prop>
<prop opt type="Promise.<RightsConfig>" name="rightsPromise">
The promise which will be resolved with access rights to files.
</prop>
</type>
</types>
They are then included in both JavaScript source code and markdown documentation.
To include a compiled declaration into the source code, the following line should be placed in the .js
file (where the types/static.xml
file exists in the project directory from which the doc
command will be run):
/* documentary types/static.xml */
For example, an unprocessed JavaScript file can look like this:
/* src/config-static.js */
import Static from 'koa-static'
/**
* Configure the middleware.
*/
function configure(config) {
const middleware = Static(config)
return middleware
}
/* documentary types/static.xml */
export default configure
Please note that the types marker must be placed before
export default
is done (or justexport
) as there's currently a bug in VS Code.
The file is then processed with doc src/config-static.js -g
command and updated in place, unless -
is given as an argument, which will print the output to stdout, or the path to the output file is specified. After the processing is done, the source code will be transformed to include all types specified in the XML file. This routine can be repeated whenever types are updated.
/* src/config-static.js */
import Static from 'koa-static'
/**
* Configure the middleware.
*/
function configure(config) {
const middleware = Static(config)
return middleware
}
/* documentary types/static.xml */
/**
* @typedef {import('http').ServerResponse} ServerResponse
*
* @typedef {(res: ServerResponse) => any} SetHeaders Function to set custom headers on response.
*
* @typedef {{ location: string, rights: number }[]} RightsConfig Configuration of read and write access rights.
*
* @typedef {Object} StaticConfig Options to setup `koa-static`.
* @prop {string} root Root directory string.
* @prop {number} [maxage=0] Browser cache max-age in milliseconds. Default `0`.
* @prop {boolean} [hidden=false] Allow transfer of hidden files. Default `false`.
* @prop {string} [index="index.html"] Default file name. Default `index.html`.
* @prop {SetHeaders} [setHeaders] Function to set custom headers on response.
* @prop {Promise.<RightsConfig>} [rightsPromise] The promise which will be resolved with access rights to files.
*/
export default configure
@param
In addition, JSDoc for any method that has got an included type as one of its parameters will be updated to its expanded form so that a preview of options is available.
Therefore, a raw function JSDoc of a function written as
/**
* Configure the middleware.
* @param {StaticConfig} config Options to setup `koa-static`.
*/
function configure(config) {
const middleware = Static(config)
return middleware
}
will be expanded to include the properties of the type:
/**
* Configure the middleware.
* @param {StaticConfig} config Options to setup `koa-static`.
* @param {string} config.root Root directory string.
* @param {number} [config.maxage=0] Browser cache max-age in milliseconds. Default `0`.
* @param {boolean} [config.hidden=false] Allow transfer of hidden files. Default `false`.
* @param {string} [config.index="index.html"] Default file name. Default `index.html`.
* @param {SetHeaders} [config.setHeaders] Function to set custom headers on response.
*/
function configure(config) {
const middleware = Static(config)
return middleware
}
This makes it possible to see the properties of the argument to the configure
function fully:
And the description of each property will be available when passing an argument to the function:
Compare that to the preview without JSDoc expansion:
To prevent the expansion, the noExpand
attribute should be added to the type.
To place a type definition as a table into a README
file, the TYPEDEF
marker can be used, where the first argument is the path to the xml
file containing definitions, and the second one is the name of the type to embed. Moreover, links to the type descriptions will be created in the table of contents using the TOC Titles, but to prevent this, the noToc
attribute should be set for a type.
%TYPEDEF path/definitions.xml [TypeName]%
For example, using the previously defined StaticConfig
type from types/static.xml
file, Documentary will process the following markers:
%TYPEDEF types/static.xml ServerResponse%
%TYPEDEF types/static.xml SetHeaders%
%TYPEDEF types/static.xml StaticConfig%
or a single marker to include all types in order in which they appear in the xml
file:
%TYPEDEF types/static.xml%
and embed resulting type definitions (with the imported type linked to the Node.js documentation due to its link
attribute):
import('http').ServerResponse
ServerResponse
(res: ServerResponse) => any
SetHeaders
: Function to set custom headers on response.
{ location: string, rights: number }[]
RightsConfig
: Configuration of read and write access rights.
StaticConfig
: Options to setup koa-static
.
Name | Type | Description | Default |
---|---|---|---|
root* | string | Root directory string. | - |
maxage | number | Browser cache max-age in milliseconds. | 0 |
hidden | boolean | Allow transfer of hidden files. | false |
index | string | Default file name. | index.html |
setHeaders | SetHeaders | Function to set custom headers on response. | - |
rightsPromise | Promise.<RightsConfig> | The promise which will be resolved with access rights to files. | - |
Documentary wil scan each source file of the documentation first to build a map of all types. Whenever a property appears to be of a known type, it will be automatically linked to the location where it was defined. It is also true for properties described as generic types, such as Promise.<Type>
. This makes it possible to define all types in one place, and then reference them in the API documentation.
The basic functionality of maintaining types in the source JavaScript
and MarkDown
files is mostly enough. In addition, there are some advanced patterns which can be used in JavaScript.
@param
When a type is just an object, it can be spread into a notation which contains its properties for even better visibility. To do that, the spread
attribute must be added to the type definition in the xml
file.
Again, a raw function with JSDoc:
/**
* Configure the middleware.
* @param {StaticConfig} config Options to setup `koa-static`.
*/
function configure(config) {
const middleware = Static(config)
return middleware
}
Can be re-written as spread notation of a type.
/**
* Configure the middleware.
* @param {{ root: string, maxage?: number, hidden?: boolean, index?: string, setHeaders?: SetHeaders }} config Options to setup `koa-static`.
* @param {string} config.root Root directory string.
* @param {number} [config.maxage=0] Browser cache max-age in milliseconds. Default `0`.
* @param {boolean} [config.hidden=false] Allow transfer of hidden files. Default `false`.
* @param {string} [config.index="index.html"] Default file name. Default `index.html`.
* @param {SetHeaders} [config.setHeaders] Function to set custom headers on response.
*/
function configure(config) {
const middleware = Static(config)
return middleware
}
The properties will be visible in the preview:
However, this method has one disadvantage as there will be no descriptions of the properties when trying to use them in a call to function:
Therefore, it must be considered what is the best for developers -- to see descriptions of properties when passing a configuration object to a function, but not see all possible properties, or to see the full list of properties, but have no visibility of what they mean.
It is also not possible to automatically update the spread type in place, because the information about the original type is lost after its converted into the object notation.
Generally, this feature should not be used, because the autocompletion list can be summoned by hitting ctrl .
A special import
element can be used to import a type using VS Code's TypeScript engine. An import is just a typedef which looks like /** @typedef {import('package').Type} Type */
. This makes it easier to reference an external type later in the file. However, it is not supported in older versions of VS Code.
The import will never display in the Table of Contents as its an external type and should be used to document internal API. There are three attributes supported by the import
element:
Attribute | Meaning |
---|---|
from | The package from which to import the type. |
name | The name of the type. |
link | The link to display in the documentation. |
Original Source | Types Definition |
---|---|
|
|
Output | |
|
The XML file should have the following nodes and attributes:
Node | Description | Attributes |
---|---|---|
types | A single root element. | |
import | An imported type definition. |
|
type |
A |
|
prop |
Property of a |
|
A JavaScript file can be scanned for the presence of @typedef
JSDoc comments, which are then extracted to a types.xml
file. This can be done with the doc src/index.js -e types/index.xml
command. This is primarily a tool to migrate older software to using types.xml
files which can be used both for online documentation and editor documentation.
For example, types can be extracted from a JavaScript file which contains JSDoc in form of comments:
async function test() {
process.stdout.write('ttt')
}
/**
* @typedef {import('http').IncomingMessage} IncomingMessage
*/
/**
* @typedef {(m: IncomingMessage)} Test This is test function.
*
* @typedef {Object} SessionConfig Description of Session Config.
* @prop {string} key cookie key.
* @prop {number|'session'} [maxAge=86400000] maxAge in ms. `session` will result in a cookie that expires when session/browser is closed.
* @prop {boolean} [overwrite] Can overwrite or not. Default `true`.
* @prop {boolean} [httpOnly] httpOnly or not or not. Default `true`.
* @prop {boolean} [renew] Renew session when session is nearly expired, so we can always keep user logged in. Default `false`.
*/
export default test
When a description ends with Default `value`
, the default value of a type can also be parsed from there.
<types>
<import name="IncomingMessage" from="http" />
<type name="Test" type="(m: IncomingMessage)" desc="This is test function." />
<type name="SessionConfig" desc="Description of Session Config.">
<prop string name="key">
cookie key.
</prop>
<prop type="number|'session'" name="maxAge" default="86400000">
maxAge in ms. `session` will result in a cookie that expires when session/browser is closed.
</prop>
<prop boolean name="overwrite" default="true">
Can overwrite or not.
</prop>
<prop boolean name="httpOnly" default="true">
httpOnly or not or not.
</prop>
<prop boolean name="renew" default="false">
Renew session when session is nearly expired, so we can always keep user logged in.
</prop>
</type>
</types>
The program is used from the CLI (or package.json
script).
doc README-source.md [-o README.md] [-tgewp]
The arguments it accepts are:
Flag | Meaning | Description |
---|---|---|
-o path | Output Location | Where to save the processed README file. If not specified, the output is written to the stdout . |
-t | Only TOC | Only extract and print the table of contents. |
-g [path] | Generate Types | Insert @typedef JSDoc into JavaScript files. When no path is given, the files are updated in place, and when - is passed, the output is printed to stdout. |
-e [path] | Extract Types | Insert @typedef JSDoc into JavaScript files. When no path is given, the files are updated in place, and when - is passed, the output is printed to stdout. |
-w | Watch Mode | Watch mode: re-run the program when changes to the source file are detected. |
-p 'commit message' | Automatic Push | Watch + push: automatically push changes to a remote git branch by squashing them into a single commit. |
-h1 | h1 In Toc | Include h1 headers in the table of contents. |
-r | Reverse Order | Reverse the output order of files, such as that 2.md will come before 1.md . This could be useful when writing blogs. The index.md and footer.md files will still come first and last respectively. |
When NODE_DEBUG=doc
is set, the program will print debug information, e.g.,
DOC 80734: stripping comment
DOC 80734: could not parse the table
The programmatic use of Documentary is intended for developers who want to use this software in their projects.
Toc
StreamToc
is a transform stream which can generate a table of contents for incoming markdown data. For every title that the transform sees, it will push the appropriate level of the table of contents.
TocConfig
TypeWhen creating a new Toc
instance, it will accept the following configuration object.
Property | Type | Description | Example |
---|---|---|---|
skipLevelOne | boolean | Start the table of contents from level 2, i.e., excluding the # title. | For example, the following code:
will be compiled to
when
when |
constructor(
config?: {
skipLevelOne?: boolean = true,
},
): Toc
Create a new instance of a Toc
stream.
/* yarn example/toc.js */
import { Toc } from 'documentary'
import Catchment from 'catchment'
import { createReadStream } from 'fs'
(async () => {
try {
const md = createReadStream('example/markdown.md')
const rs = new Toc()
md.pipe(rs)
const { promise } = new Catchment({ rs })
const res = await promise
console.log(res)
} catch ({ stack }) {
console.log(stack)
}
})()
- [Table Of Contents](#table-of-contents)
- [CLI](#cli)
* [`-j`, `--jsdoc`: Add JSDoc](#-j---jsdoc-add-jsdoc)
- [API](#api)
- [Copyright](#copyright)
Titles
Titles written as blocks and underlined with any number of either ===
(for H1) and ---
(for H2), will be also displayed in the table of contents. However, the actual title will appear on a single line.
#PRO
Underlined
`Titles`
---
As seen in the Markdown Cheatsheet.
Section breaks from FoglihtenDeH0 font.
© Art Deco 2019 | Tech Nation Visa Sucks |
---|
FAQs
Documentation Compiler To Generate The Table Of Contents, Embed Examples With Their Output, Make Markdown Tables, Maintain Typedefs For JavaScript And README, Watch Changes To Push, Use Macros And Prettify API Titles.
The npm package documentary receives a total of 204 weekly downloads. As such, documentary popularity was classified as not popular.
We found that documentary demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.