UNPKG

3.96 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3'use strict';
4
5var path = require('path')
6 , fs = require('fs')
7 , minimist = require('minimist')
8 , file = require('./lib/file')
9 , transform = require('./lib/transform')
10 , files;
11
12function cleanPath(path) {
13 var homeExpanded = (path.indexOf('~') === 0) ? process.env.HOME + path.substr(1) : path;
14
15 // Escape all spaces
16 return homeExpanded.replace(/\s/g, '\\ ');
17}
18
19function transformAndSave(files, mode, maxHeaderLevel, title, notitle, entryPrefix, processAll, stdOut, updateOnly) {
20 if (processAll) {
21 console.log('--all flag is enabled. Including headers before the TOC location.')
22 }
23
24 if (updateOnly) {
25 console.log('--update-only flag is enabled. Only updating files that already have a TOC.')
26 }
27
28 console.log('\n==================\n');
29
30 var transformed = files
31 .map(function (x) {
32 var content = fs.readFileSync(x.path, 'utf8')
33 , result = transform(content, mode, maxHeaderLevel, title, notitle, entryPrefix, processAll, updateOnly);
34 result.path = x.path;
35 return result;
36 });
37 var changed = transformed.filter(function (x) { return x.transformed; })
38 , unchanged = transformed.filter(function (x) { return !x.transformed; })
39 , toc = transformed.filter(function (x) { return x.toc; })
40
41 if (stdOut) {
42 toc.forEach(function (x) {
43 console.log(x.toc)
44 })
45 }
46
47 unchanged.forEach(function (x) {
48 console.log('"%s" is up to date', x.path);
49 });
50
51 changed.forEach(function (x) {
52 if (stdOut) {
53 console.log('==================\n\n"%s" should be updated', x.path)
54 } else {
55 console.log('"%s" will be updated', x.path);
56 fs.writeFileSync(x.path, x.data, 'utf8');
57 }
58 });
59}
60
61function printUsageAndExit(isErr) {
62
63 var outputFunc = isErr ? console.error : console.info;
64
65 outputFunc('Usage: doctoc [mode] [--entryprefix prefix] [--notitle | --title title] [--maxlevel level] [--all] [--update-only] <path> (where path is some path to a directory (e.g., .) or a file (e.g., README.md))');
66 outputFunc('\nAvailable modes are:');
67 for (var key in modes) {
68 outputFunc(' --%s\t%s', key, modes[key]);
69 }
70 outputFunc('Defaults to \'' + mode + '\'.');
71
72 process.exit(isErr ? 2 : 0);
73}
74
75var modes = {
76 bitbucket : 'bitbucket.org'
77 , nodejs : 'nodejs.org'
78 , github : 'github.com'
79 , gitlab : 'gitlab.com'
80 , ghost : 'ghost.org'
81}
82
83var mode = modes['github'];
84
85var argv = minimist(process.argv.slice(2)
86 , { boolean: [ 'h', 'help', 'T', 'notitle', 's', 'stdout', 'all' , 'u', 'update-only'].concat(Object.keys(modes))
87 , string: [ 'title', 't', 'maxlevel', 'm', 'entryprefix' ]
88 , unknown: function(a) { return (a[0] == '-' ? (console.error('Unknown option(s): ' + a), printUsageAndExit(true)) : true); }
89 });
90
91if (argv.h || argv.help) {
92 printUsageAndExit();
93}
94
95for (var key in modes) {
96 if (argv[key]) {
97 mode = modes[key];
98 }
99}
100
101var title = argv.t || argv.title;
102var notitle = argv.T || argv.notitle;
103var entryPrefix = argv.entryprefix || '-';
104var processAll = argv.all;
105var stdOut = argv.s || argv.stdout
106var updateOnly = argv.u || argv['update-only']
107
108var maxHeaderLevel = argv.m || argv.maxlevel;
109if (maxHeaderLevel && isNaN(maxHeaderLevel) || maxHeaderLevel < 0) { console.error('Max. heading level specified is not a positive number: ' + maxHeaderLevel), printUsageAndExit(true); }
110
111for (var i = 0; i < argv._.length; i++) {
112 var target = cleanPath(argv._[i])
113 , stat = fs.statSync(target)
114
115 if (stat.isDirectory()) {
116 console.log ('\nDocToccing "%s" and its sub directories for %s.', target, mode);
117 files = file.findMarkdownFiles(target);
118 } else {
119 console.log ('\nDocToccing single file "%s" for %s.', target, mode);
120 files = [{ path: target }];
121 }
122
123 transformAndSave(files, mode, maxHeaderLevel, title, notitle, entryPrefix, processAll, stdOut, updateOnly);
124
125 console.log('\nEverything is OK.');
126}
127
128module.exports.transform = transform;