Skip to content

Commit

Permalink
feat(markdown): Add table of contents support for Markdown mode (#645)
Browse files Browse the repository at this point in the history
Adds a new option, `--no-markdown-toc`, to turn off Table of Contents generation. Table of contents are now generated by default with markdown output, including through the `readme` command.

Fixes #220
  • Loading branch information
tmcw authored Dec 29, 2016
1 parent 2ae5d8f commit 4c66fb1
Show file tree
Hide file tree
Showing 117 changed files with 6,571 additions and 161 deletions.
10 changes: 10 additions & 0 deletions docs/NODE_API.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

- [build](#build)
- [buildSync](#buildsync)
- [lint](#lint)
- [formats](#formats)
- [formats.html](#formatshtml)
- [formats.markdown](#formatsmarkdown)
- [formats.json](#formatsjson)

## build

Generate JavaScript documentation as a list of parsed JSDoc
Expand Down
6 changes: 6 additions & 0 deletions lib/commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ module.exports.builder = extend({},
default: 'json',
choices: ['json', 'md', 'remark', 'html']
},
'no-markdown-toc': {
describe: 'include a table of contents in markdown output',
default: 'stdout',
type: 'boolean'
},
output: {
describe: 'output location. omit for stdout, otherwise is a filename ' +
'for single-file outputs and a directory name for multi-file outputs like html',
Expand Down Expand Up @@ -66,6 +71,7 @@ module.exports.handler = function build(argv, callback) {
version: argv['project-version'] || (argv.package || {}).version,
theme: argv.theme,
paths: argv.paths,
'no-markdown-toc': argv['no-markdown-toc'],
hljs: argv.hljs || {}
};

Expand Down
5 changes: 3 additions & 2 deletions lib/commands/readme.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ module.exports.builder = {
example: 'documentation readme index.js -s "API Docs" --github'
};

function noop() {}

/**
* Insert API documentation into a Markdown readme
* @private
Expand All @@ -53,8 +55,7 @@ module.exports.handler = function readme(argv) {
argv = sharedOptions.expandInputs(argv);
argv.format = 'remark';
/* eslint no-console: 0 */
var log = argv.q ? function () {}
: console.log.bind(console, '[documentation-readme] ');
var log = argv.q ? noop : console.log.bind(console, '[documentation-readme] ');
var readmeFile = argv['readme-file'];

build.handler(argv, onAst);
Expand Down
5 changes: 1 addition & 4 deletions lib/output/markdown.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var remark = require('remark'),
toc = require('remark-toc'),
markdownAST = require('./markdown_ast');

/**
Expand All @@ -26,9 +25,7 @@ var remark = require('remark'),
* });
*/
module.exports = function (comments, options, callback) {
var processor = remark().use(toc);
markdownAST(comments, options, function (err, ast) {
var processedAST = processor.run(ast);
return callback(null, processor.stringify(processedAST));
return callback(null, remark().stringify(ast));
});
};
28 changes: 22 additions & 6 deletions lib/output/markdown_ast.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
var u = require('unist-builder'),
remark = require('remark'),
toc = require('remark-toc'),
hljs = require('highlight.js'),
GithubSlugger = require('github-slugger'),
createLinkerStack = require('./util/linker_stack'),
Expand All @@ -14,7 +16,7 @@ var u = require('unist-builder'),
* @param {Function} callback called with AST
* @returns {undefined} calls callback
*/
function commentsToAST(comments, options, callback) {
function markdownAST(comments, options, callback) {

// Configure code highlighting
var hljsOptions = (options || {}).hljs || {},
Expand All @@ -33,6 +35,10 @@ function commentsToAST(comments, options, callback) {
u('html', '<!-- Generated by documentation.js. Update this documentation by updating the source code. -->')
];

var tableOfContentsHeading = [
u('heading', { depth: 3 }, [u('text', 'Table of Contents')])
];

/**
* Generate an AST chunk for a comment at a given depth: this is
* split from the main function to handle hierarchially nested comments
Expand Down Expand Up @@ -202,10 +208,20 @@ function commentsToAST(comments, options, callback) {
.filter(Boolean);
}

return callback(null, rerouteLinks(linkerStack.link,
u('root', generatorComment.concat(comments.reduce(function (memo, comment) {
return memo.concat(generate(2, comment));
}, [])))));
var root = rerouteLinks(linkerStack.link,
u('root', generatorComment
.concat(options['no-markdown-toc'] ? [] : tableOfContentsHeading)
.concat(comments.reduce(function (memo, comment) {
return memo.concat(generate(2, comment));
}, []))));

if (!options['no-markdown-toc']) {
return remark().use(toc, {
tight: true
}).run(root, callback);
}

return callback(null, root);
}

module.exports = commentsToAST;
module.exports = markdownAST;
4 changes: 4 additions & 0 deletions test/fixture/auto_lang_hljs/multilanguage.output.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

- [multilanguage.input](#multilanguageinput)

## multilanguage.input

**Extends Foo, Bar**
Expand Down
4 changes: 4 additions & 0 deletions test/fixture/boolean-literal-type.output.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

- [f](#f)

## f

**Parameters**
Expand Down
58 changes: 57 additions & 1 deletion test/fixture/boolean-literal-type.output.md.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,53 @@
"type": "html",
"value": "<!-- Generated by documentation.js. Update this documentation by updating the source code. -->"
},
{
"depth": 3,
"type": "heading",
"children": [
{
"type": "text",
"value": "Table of Contents"
}
],
"data": {
"id": "table-of-contents",
"htmlAttributes": {
"id": "table-of-contents"
},
"hProperties": {
"id": "table-of-contents"
}
}
},
{
"type": "list",
"ordered": false,
"children": [
{
"type": "listItem",
"loose": false,
"children": [
{
"type": "paragraph",
"children": [
{
"type": "link",
"title": null,
"url": "#f",
"children": [
{
"type": "text",
"value": "f"
}
]
}
]
}
]
}
]
},
{
"depth": 2,
"type": "heading",
Expand All @@ -13,7 +60,16 @@
"type": "text",
"value": "f"
}
]
],
"data": {
"id": "f",
"htmlAttributes": {
"id": "f"
},
"hProperties": {
"id": "f"
}
}
},
{
"type": "strong",
Expand Down
7 changes: 7 additions & 0 deletions test/fixture/class.config.output.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

- [MyClass](#myclass)
- [getFoo](#getfoo)
- [getUndefined](#getundefined)
- [Hello](#hello)

## MyClass

This is my class, a demo thing.
Expand Down
6 changes: 6 additions & 0 deletions test/fixture/class.output.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->

### Table of Contents

- [MyClass](#myclass)
- [getFoo](#getfoo)
- [getUndefined](#getundefined)

## MyClass

This is my class, a demo thing.
Expand Down
Loading

1 comment on commit 4c66fb1

@DenisCarriere
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tmcw This commit is awesome!! I've been creating Markdown TOC manually before. 👍

Please sign in to comment.