Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ by github or other sites via a command line flag.
- [Specifying a custom TOC title](#specifying-a-custom-toc-title)
- [Specifying a minimum heading level for TOC entries](#specifying-a-minimum-heading-level-for-toc-entries)
- [Specifying a maximum heading level for TOC entries](#specifying-a-maximum-heading-level-for-toc-entries)
- [Performing a dry run](#performing-a-dry-run)
- [Printing to stdout](#printing-to-stdout)
- [Only update existing ToC](#only-update-existing-toc)
- [Usage as a `git` hook](#usage-as-a-git-hook)
Expand Down Expand Up @@ -140,6 +141,11 @@ By default,
- no limit is placed on Markdown-formatted headings,
- whereas headings from embedded HTML are limited to 4 levels.

### Performing a dry run

Use the `--dryrun` option to not write changes to files but instead return an exit code of 1 to indicates files are out of date and should be updated.
This is useful CI environments where you want to check if your docs are up to date as part of your build process.

### Printing to stdout

You can print to stdout by using the `-s` or `--stdout` option.
Expand Down
29 changes: 23 additions & 6 deletions doctoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function cleanPath(path) {
return homeExpanded;
}

function transformAndSave(files, mode, maxHeaderLevel, minHeaderLevel, title, notitle, entryPrefix, processAll, stdOut, updateOnly) {
function transformAndSave(files, mode, maxHeaderLevel, minHeaderLevel, title, notitle, entryPrefix, processAll, stdOut, updateOnly, dryRun) {
if (processAll) {
console.log('--all flag is enabled. Including headers before the TOC location.')
}
Expand Down Expand Up @@ -44,17 +44,28 @@ function transformAndSave(files, mode, maxHeaderLevel, minHeaderLevel, title, no
}

unchanged.forEach(function (x) {
console.log('"%s" is up to date', x.path);
if (stdOut) {
console.log('==================\n\n"%s" is up to date', x.path)
}
else {
console.log('"%s" is up to date', x.path);
}
});

changed.forEach(function (x) {
if (stdOut) {
console.log('==================\n\n"%s" should be updated', x.path)
} else {
} else if (dryRun) {
console.log('"%s" should be updated but wasn\'t due to dry run.', x.path);
}
else {
console.log('"%s" will be updated', x.path);
fs.writeFileSync(x.path, x.data, 'utf8');
}
});
if (dryRun && changed.length > 0) {
process.exitCode = 1;
}
}

function printUsageAndExit(isErr) {
Expand Down Expand Up @@ -82,7 +93,7 @@ var modes = {
var mode = modes['github'];

var argv = minimist(process.argv.slice(2)
, { boolean: [ 'h', 'help', 'T', 'notitle', 's', 'stdout', 'all' , 'u', 'update-only'].concat(Object.keys(modes))
, { boolean: [ 'h', 'help', 'T', 'notitle', 's', 'stdout', 'all' , 'u', 'update-only', 'd', 'dryrun'].concat(Object.keys(modes))
, string: [ 'title', 't', 'maxlevel', 'm', 'minlevel', 'n', 'entryprefix' ]
, unknown: function(a) { return (a[0] == '-' ? (console.error('Unknown option(s): ' + a), printUsageAndExit(true)) : true); }
});
Expand All @@ -103,6 +114,7 @@ var entryPrefix = argv.entryprefix || '-';
var processAll = argv.all;
var stdOut = argv.s || argv.stdout
var updateOnly = argv.u || argv['update-only']
var dryRun = argv.d || argv.dryrun || false;

var maxHeaderLevel = argv.m || argv.maxlevel;
if (maxHeaderLevel && isNaN(maxHeaderLevel)) { console.error('Max. heading level specified is not a number: ' + maxHeaderLevel), printUsageAndExit(true); }
Expand All @@ -126,9 +138,14 @@ for (var i = 0; i < argv._.length; i++) {
files = [{ path: target }];
}

transformAndSave(files, mode, maxHeaderLevel, minHeaderLevel, title, notitle, entryPrefix, processAll, stdOut, updateOnly);
transformAndSave(files, mode, maxHeaderLevel, minHeaderLevel, title, notitle, entryPrefix, processAll, stdOut, updateOnly, dryRun);

console.log('\nEverything is OK.');
if (dryRun && process.exitCode === 1) {
console.log('\nDocumentation tables of contents are out of date.');
}
else {
console.log('\nEverything is OK.');
}
}

module.exports.transform = transform;
9 changes: 5 additions & 4 deletions lib/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,11 @@ exports = module.exports = function transform(content, mode, maxHeaderLevel, min

var wrappedToc = start + '\n' + toc + '\n' + end;

if (currentToc === toc) return { transformed: false };

var data = updateSection(lines.join('\n'), wrappedToc, matchesStart, matchesEnd, true);
return { transformed : true, data : data, toc: toc, wrappedToc: wrappedToc };
var data;
if (currentToc != wrappedToc){
data = updateSection(lines.join('\n'), wrappedToc, matchesStart, matchesEnd, true);
}
return { transformed : currentToc != wrappedToc, data : data, toc: toc, wrappedToc: wrappedToc };
};

exports.start = start;
Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/readme-with-out_of_date_toc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 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
## Contributing
## License
2 changes: 1 addition & 1 deletion test/fixtures/stdout.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ DocToccing single file "test/fixtures/readme-with-custom-title.md" for github.co

==================

"test/fixtures/readme-with-custom-title.md" should be updated
"test/fixtures/readme-with-custom-title.md" is up to date

Everything is OK.
55 changes: 55 additions & 0 deletions test/transform-dryrun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';
/*jshint asi: true */

var test = require('tap').test,
fs = require('fs'),
exec = require("child_process").exec;

test('\nshould exit with a error code due to --dryrun option', function (t) {

exec('node doctoc.js test/fixtures/readme-with-out_of_date_toc.md --dryrun', function (error, stdout, stderr) {
if (error) {
t.deepEqual(error.code, 1, 'process exited with error code 1 as expected');
t.end('process did have an error');
} else {
t.fail('process did not produce an error: ' + error);
t.end();
}
})
})

test('\nshould exit with no error code with --dryrun option', function (t) {

exec('node doctoc.js test/fixtures/readme-with-custom-title.md --dryrun', function (error, stdout, stderr) {
if (error) {
t.fail('process produced an unexpected error: ' + error);
t.end()
} else {
t.end('process did not have an error');
}
})
})

test('\nshould exit no error code due to no --dryrun option for out of date toc', function (t) {

exec('node doctoc.js test/fixtures/readme-with-out_of_date_toc.md --stdout', function (error, stdout, stderr) {
if (error) {
t.fail('process produced an unexpected error: ' + error);
t.end()
} else {
t.end('process did not have an error');
}
})
})

test('\nshould exit with no error code', function (t) {

exec('node doctoc.js test/fixtures/readme-with-custom-title.md', function (error, stdout, stderr) {
if (error) {
t.fail('process produced an unexpected error: ' + error);
t.end()
} else {
t.end('process did not have an error');
}
})
})