Skip to content

Commit

Permalink
Add support for inferring title
Browse files Browse the repository at this point in the history
Resolves thlorenz#64.

The `title` variable in `lib/transform.js` is now populated according to
this logic:

- If the new `--notitle` option is specified:
  - `title = ''`
- If a title was explicitly passed with `--title`:
  - `title` is the user-specified title
- If a TOC exists )as evidencedy by `info.hasStart`:
  - `title = lines[info.startIdx + 2]`
  - This line is assumed to always be the TOC title
- Otherwise:
  - `title` is the standard "**Table of Contents**" title
  • Loading branch information
jez authored and thlorenz committed Jun 12, 2015
1 parent 225be1c commit ce5b416
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 12 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ Running doctoc will insert the toc at that location.

### Specifying a custom TOC title

Use the `--title` option to specify a (Markdown-formatted) custom TOC title; e.g., `doctoc --title '**Contents**' .`
Use the `--title` option to specify a (Markdown-formatted) custom TOC title; e.g., `doctoc --title '**Contents**' .` From then on, you can simply run `doctoc <file>` and doctoc will will keep the title you specified.

Alternatively, to blank out the title with a newline, use the `--notitle` option. This will simply remove the title from the TOC.

### Specifying a maximum heading level for TOC entries

Expand Down
11 changes: 6 additions & 5 deletions doctoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ function cleanPath(path) {
return homeExpanded.replace(/\s/g, '\\ ');
}

function transformAndSave(files, mode, maxHeaderLevel, title) {
function transformAndSave(files, mode, maxHeaderLevel, title, notitle) {
console.log('\n==================\n');

var transformed = files
.map(function (x) {
var content = fs.readFileSync(x.path, 'utf8')
, result = transform(content, mode, maxHeaderLevel, title);
, result = transform(content, mode, maxHeaderLevel, title, notitle);
result.path = x.path;
return result;
});
Expand All @@ -43,7 +43,7 @@ function printUsageAndExit(isErr) {

var outputFunc = isErr ? console.error : console.info;

outputFunc('Usage: doctoc [mode] [--title title] [--maxlevel level] <path> (where path is some path to a directory (e.g., .) or a file (e.g., README.md))');
outputFunc('Usage: doctoc [mode] [--notitle | --title title] [--maxlevel level] <path> (where path is some path to a directory (e.g., .) or a file (e.g., README.md))');
outputFunc('\nAvailable modes are:');
for (var key in modes) {
outputFunc(' --%s\t%s', key, modes[key]);
Expand All @@ -64,7 +64,7 @@ var modes = {
var mode = modes['github'];

var argv = minimist(process.argv.slice(2)
, { boolean: [ 'h', 'help' ].concat(Object.keys(modes))
, { boolean: [ 'h', 'help', 'T', 'notitle' ].concat(Object.keys(modes))
, string: [ 'title', 't', 'maxlevel', 'm' ]
, unknown: function(a) { return (a[0] == '-' ? (console.error('Unknown option(s): ' + a), printUsageAndExit(true)) : true); }
});
Expand All @@ -83,6 +83,7 @@ for (var key in modes) {
}

var title = argv.t || argv.title;
var notitle = argv.T || argv.notitle;

var maxHeaderLevel = argv.m || argv.maxlevel;
if (maxHeaderLevel && isNaN(maxHeaderLevel) || maxHeaderLevel < 0) { console.error('Max. heading level specified is not a positive number: ' + maxHeaderLevel), printUsageAndExit(true); }
Expand All @@ -98,6 +99,6 @@ if (stat.isDirectory()) {
files = [{ path: target }];
}

transformAndSave(files, mode, maxHeaderLevel, title);
transformAndSave(files, mode, maxHeaderLevel, title, notitle);

console.log('\nEverything is OK.');
18 changes: 14 additions & 4 deletions lib/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,25 @@ function getLinesToToc (lines, currentToc, info) {
return lines.slice(tocableStart);
}

exports = module.exports = function transform(content, mode, maxHeaderLevel, title) {
// Use document context as well as command line args to infer the title
function determineTitle(title, notitle, lines, info) {
var defaultTitle = '**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*';

if (notitle) return '';
if (title) return title;
return info.hasStart ? lines[info.startIdx + 2] : defaultTitle;
}

exports = module.exports = function transform(content, mode, maxHeaderLevel, title, notitle) {
mode = mode || 'github.com';
// only limit *HTML* headings by default
var maxHeaderLevelHtml = maxHeaderLevel || 4;
title = title || '**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*';
var maxHeaderLevelHtml = maxHeaderLevel || 4;

var lines = content.split('\n')
, info = updateSection.parse(lines, matchesStart, matchesEnd)

var inferredTitle = determineTitle(title, notitle, lines, info);

var currentToc = info.hasStart && lines.slice(info.startIdx, info.endIdx).join('\n')
, linesToToc = getLinesToToc(lines, currentToc, info);

Expand All @@ -143,7 +153,7 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, tit
var indentation = (mode === 'bitbucket.org' || mode === 'gitlab.com') ? ' ' : ' ';

var toc =
title
inferredTitle
+ '\n\n'
+ linkedHeaders
.map(function (x) {
Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/readme-with-custom-title.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Hello, world!

README to test doctoc with user-specified titles.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Table of Contents

- [Installation](#installation)
- [API](#api)
- [License](#license)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->


## Installation
## API
## License
2 changes: 1 addition & 1 deletion test/fixtures/readme-with-html.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ docker convenience functions on top of dockerode

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Installation](#installation)
- [API](#api)
Expand Down
56 changes: 56 additions & 0 deletions test/transform-title.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';
/*jshint asi: true */

var test = require('tap').test
, transform = require('../lib/transform');

test('\noverwrite existing title', function (t) {
var content = require('fs').readFileSync(__dirname + '/fixtures/readme-with-custom-title.md', 'utf8');
var headers = transform(content, null, null, '## Table of Contents', false);

t.deepEqual(
headers.toc.split('\n')
, [ '## Table of Contents',
'',
'- [Installation](#installation)',
'- [API](#api)',
'- [License](#license)',
'' ]
, 'generates correct toc for when custom --title was passed'
)
t.end()
});

test('\ndo not overwrite existing title', function (t) {
var content = require('fs').readFileSync(__dirname + '/fixtures/readme-with-custom-title.md', 'utf8');
var headers = transform(content, null, null, null, false);

t.deepEqual(
headers.toc.split('\n')
, [ '## Table of Contents',
'',
'- [Installation](#installation)',
'- [API](#api)',
'- [License](#license)',
'' ]
, 'generates correct toc for when custom title exists in README already'
)
t.end()
});

test('\nclobber existing title', function (t) {
var content = require('fs').readFileSync(__dirname + '/fixtures/readme-with-custom-title.md', 'utf8');
var headers = transform(content, null, null, null, true);

t.deepEqual(
headers.toc.split('\n')
, [ '',
'',
'- [Installation](#installation)',
'- [API](#api)',
'- [License](#license)',
'' ]
, 'generates correct toc for when --notitle was passed'
)
t.end()
});
2 changes: 1 addition & 1 deletion test/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function inspect(obj, depth) {
}

function check(md, anchors, mode, maxHeaderLevel, title) {
test('transforming ' + md , function (t) {
test('transforming', function (t) {
var res = transform(md, mode, maxHeaderLevel, title)

// remove wrapper
Expand Down

0 comments on commit ce5b416

Please sign in to comment.