diff --git a/README.md b/README.md index 353fc5b9..56164cdc 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,24 @@ By default, ### Printing to stdout -You can print to stdout by using the `-s` or `--stdout` option. +You can print to stdout by using the `-s` or `--stdout` option. This will print out the TOC to `stdout`, but any extra information provided by doctoc will be printed to `stderr`. Piping or copying the `stdout` will result in a clean TOC. For example: + +``` +$ doctoc readme -s + +DocToccing single file "readme.md" for github.com. + +================== +- [Example](#example) +================== + +"readme.md" should be updated + +Everything is OK. +$ doctoc readme -s > test +... +$ cat test +- [Example](#example) +``` [ack]: http://beyondgrep.com/ diff --git a/doctoc.js b/doctoc.js index 40cb9a1a..19378d01 100755 --- a/doctoc.js +++ b/doctoc.js @@ -17,12 +17,12 @@ function cleanPath(path) { } function transformAndSave(files, mode, maxHeaderLevel, title, notitle, entryPrefix, stdOut) { - console.log('\n==================\n'); + console.error('\n==================\n'); var transformed = files .map(function (x) { var content = fs.readFileSync(x.path, 'utf8') - , result = transform(content, mode, maxHeaderLevel, title, notitle, entryPrefix); + , result = transform(content, mode, maxHeaderLevel, title, notitle, entryPrefix, stdOut); result.path = x.path; return result; }); @@ -37,14 +37,14 @@ function transformAndSave(files, mode, maxHeaderLevel, title, notitle, entryPref } unchanged.forEach(function (x) { - console.log('"%s" is up to date', x.path); + console.error('"%s" is up to date.', x.path); }); changed.forEach(function (x) { if (stdOut) { - console.log('==================\n\n"%s" should be updated', x.path) + console.error('==================\n\n"%s" should be updated', x.path) } else { - console.log('"%s" will be updated', x.path); + console.error('"%s" will be updated', x.path); fs.writeFileSync(x.path, x.data, 'utf8'); } }); @@ -54,7 +54,11 @@ function printUsageAndExit(isErr) { var outputFunc = isErr ? console.error : console.info; - outputFunc('Usage: doctoc [mode] [--entryprefix prefix] [--notitle | --title title] [--maxlevel level] (where path is some path to a directory (e.g., .) or a file (e.g., README.md))'); + outputFunc('Usage: doctoc [--help | -h] [mode] [--maxlevel | -m]\n' + + '[--title | -t] [--notitle | -T] [--stdout | -s]\n' + + '[--entryprefix <prefix>]\n\n' + + "<path> must be 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]); @@ -103,14 +107,14 @@ for (var i = 0; i < argv._.length; i++) { , stat = fs.statSync(target) if (stat.isDirectory()) { - console.log ('\nDocToccing "%s" and its sub directories for %s.', target, mode); + console.error('\nDocToccing "%s" and its sub directories for %s.', target, mode); files = file.findMarkdownFiles(target); } else { - console.log ('\nDocToccing single file "%s" for %s.', target, mode); + console.error('\nDocToccing single file "%s" for %s.', target, mode); files = [{ path: target }]; } transformAndSave(files, mode, maxHeaderLevel, title, notitle, entryPrefix, stdOut); - console.log('\nEverything is OK.'); + console.error('\nEverything is OK.'); } diff --git a/lib/transform.js b/lib/transform.js index ea379d7c..291d7180 100644 --- a/lib/transform.js +++ b/lib/transform.js @@ -98,15 +98,15 @@ function getLinesToToc (lines, currentToc, info) { } // Use document context as well as command line args to infer the title -function determineTitle(title, notitle, lines, info) { +function determineTitle(title, notitle, lines, info, stdOut) { var defaultTitle = '**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*'; - if (notitle) return ''; + if (notitle || stdOut) return ''; if (title) return title; return info.hasStart ? lines[info.startIdx + 2] : defaultTitle; } -exports = module.exports = function transform(content, mode, maxHeaderLevel, title, notitle, entryPrefix) { +exports = module.exports = function transform(content, mode, maxHeaderLevel, title, notitle, entryPrefix, stdOut) { mode = mode || 'github.com'; entryPrefix = entryPrefix || '-'; @@ -116,7 +116,7 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, tit var lines = content.split('\n') , info = updateSection.parse(lines, matchesStart, matchesEnd) - var inferredTitle = determineTitle(title, notitle, lines, info); + var inferredTitle = determineTitle(title, notitle, lines, info, stdOut); var currentToc = info.hasStart && lines.slice(info.startIdx, info.endIdx + 1).join('\n') , linesToToc = getLinesToToc(lines, currentToc, info); @@ -137,18 +137,17 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, tit // 4 spaces required for proper indention on Bitbucket var indentation = (mode === 'bitbucket.org' || mode === 'gitlab.com') ? ' ' : ' '; - var toc = - inferredTitle - + '\n\n' - + linkedHeaders - .map(function (x) { + var toc = linkedHeaders.map(function (x) { var indent = _(_.range(x.rank - lowestRank)) .reduce(function (acc, x) { return acc + indentation; }, ''); return indent + entryPrefix + ' ' + x.anchor; }) .join('\n') - + '\n'; + + if (!stdOut) { + toc = inferredTitle + '\n\n' + toc + '\n'; + } var wrappedToc = start + '\n' + toc + '\n' + end; diff --git a/test/fixtures/stderr.md b/test/fixtures/stderr.md new file mode 100644 index 00000000..7b23a4ed --- /dev/null +++ b/test/fixtures/stderr.md @@ -0,0 +1,10 @@ + +DocToccing single file "test/fixtures/readme-with-custom-title.md" for github.com. + +================== + +================== + +"test/fixtures/readme-with-custom-title.md" should be updated + +Everything is OK. diff --git a/test/fixtures/stdout.md b/test/fixtures/stdout.md index 884a74ce..1ac37edd 100644 --- a/test/fixtures/stdout.md +++ b/test/fixtures/stdout.md @@ -1,16 +1,3 @@ - -DocToccing single file "test/fixtures/readme-with-custom-title.md" for github.com. - -================== - -## Table of Contents - - [Installation](#installation) - [API](#api) - [License](#license) - -================== - -"test/fixtures/readme-with-custom-title.md" should be updated - -Everything is OK. diff --git a/test/transform-stdout.js b/test/transform-stdout.js index 85b4455c..ea807d09 100644 --- a/test/transform-stdout.js +++ b/test/transform-stdout.js @@ -7,29 +7,77 @@ var test = require('tap').test, test('\nshould print to stdout with --stdout option', function (t) { - exec('node doctoc.js test/fixtures/readme-with-custom-title.md --stdout', function (error, stdout, stderr) { - if (error) { - console.error('exec error: ', error); - return; - } - t.deepEqual(stdout - , fs.readFileSync(__dirname + '/fixtures/stdout.md', 'utf8') - , 'spits out the correct table of contents') + exec('node doctoc.js test/fixtures/readme-with-custom-title.md --stdout', function (error, stdout, stderr) { + if (error) { + console.error('exec error: ', error); + return; + } - t.end() - }) + t.deepEqual(stderr + , fs.readFileSync(__dirname + '/fixtures/stderr.md', 'utf8') + , 'spits out extra lines as errors') + + t.deepEqual([ + '- [Installation](#installation)', + '- [API](#api)', + '- [License](#license)', + '' + ].join('\n') + , fs.readFileSync(__dirname + '/fixtures/stdout.md', 'utf8') + , 'logs the correct table of contents' + ) + + t.end() + }) }) test('\nshould print to stdout with -s option', function (t) { - exec('node doctoc.js test/fixtures/readme-with-custom-title.md -s', function (error, stdout, stderr) { + exec('node doctoc.js test/fixtures/readme-with-custom-title.md -s', function (error, stdout, stderr) { + if (error) { + console.error('exec error: ', error); + return; + } + + t.deepEqual(stderr + , fs.readFileSync(__dirname + '/fixtures/stderr.md', 'utf8') + , 'spits out extra lines as errors') + + t.deepEqual([ + '- [Installation](#installation)', + '- [API](#api)', + '- [License](#license)', + '' + ].join('\n') + , fs.readFileSync(__dirname + '/fixtures/stdout.md', 'utf8') + , 'logs the correct table of contents' + ) + + t.end() + }) +}) + +test('\nshould be able to pipe logs from --stdout function to a file', function (t) { + + exec('node doctoc.js test/fixtures/readme-with-custom-title.md --stdout > test/fixtures/stdout.md', function (error, stdout, stderr) { if (error) { console.error('exec error: ', error); return; } - t.deepEqual(stdout + + t.deepEqual(stderr + , fs.readFileSync(__dirname + '/fixtures/stderr.md', 'utf8') + , 'spits out extra lines as errors') + + t.deepEqual([ + '- [Installation](#installation)', + '- [API](#api)', + '- [License](#license)', + '' + ].join('\n') , fs.readFileSync(__dirname + '/fixtures/stdout.md', 'utf8') - , 'spits out the correct table of contents') + , 'logs the correct table of contents' + ) t.end() })