./src/index.js annotated source

Back to index

        
1#!/usr/bin/env node
2

This file is the entry point for the command-line utility, and is focused on handling and processing CLI arguments and figuring out the right options to pass to the docs generator.

6

We use minimist to parse command line arguments (process.argv)

8const path = require('path');
9const minimist = require('minimist');
10const glob = require('glob');
11const DEFAULTS = require('./defaults.js');
12const {generateLitteratePages} = require('./generate.js');
13

Read + parse command line arguments into a dictionary (object)

15const ARGS = minimist(process.argv.slice(2));
16
17if (ARGS.help || ARGS.h) {
18    const helpMessage = `
19    litterate - generate beautiful literate programming-style code annotations
20    Read the full documentation at https://github.com/thesephist/litterate
21
22    Basic usage
23    ---
24    litterate --config your-litterate-config.js
25    litterate [options] [files]
26        (if no files are specified, litterate runs on src/**/*.js)
27
28    Command-line options
29        (these can be customized in a configuration file as well)
30    ---
31    --config    Specify a JS or JSON file for configuration
32
33    -n, --name  Name of your project, shown in the generated site.
34
35    -d, --description
36                Description text for your project, shown in the generated site.
37
38    -w, --wrap  If 0, long lines of source code will never be wrapped.
39                If any other number, litterate will wrap long lines to the given
40                number of characters per line.
41
42    -b, --baseURL
43                By default, the generated website assumes the root URL of the site
44                is '/', but for GitHub Pages and other sites, you may want to set
45                a different base URL for the site. This allows you to set a different
46                site base URL.
47
48    -v, --verbose
49                Verbose output while litterate runs, useful for debugging.
50
51    -o, --output
52                Specify a different destination directory for the generated docs site.
53                By default, litterate writes to ./docs/.
54`;
55    console.log(helpMessage);

It's OK to process.exit() here because it'll always be the top-level execution layer of the app, as the entry point to the CLI.

58    /* eslint-disable-next-line no-process-exit */
59    process.exit(0);
60}
61
62const userConfigPath = ARGS.config;
63const USER_CONFIG = userConfigPath ? require(path.resolve(process.cwd(), userConfigPath)) : {};

This is an easy way to merge two configuration options, with USER_CONFIG overriding anything specified in defaults.

66const CONFIG = Object.assign(
67    {},
68    DEFAULTS,
69    USER_CONFIG,
70);
71

Reconcile ARGS, the command-line arguments, and CONFIG together; ARGS overrides any CONFIG file option.

74for (const [optionName, optionValue] of Object.entries(ARGS)) {
75    switch (optionName) {
76        case 'config':
77            // do nothing -- ignore
78            break;
79        case '_':
80            if (optionValue.length > 0) {
81                CONFIG.files = optionValue;
82            }
83            break;
84        case 'n':
85        case 'name':
86            CONFIG.name = optionValue;
87            break;
88        case 'd':
89        case 'description':
90            CONFIG.description = optionValue;
91            break;
92        case 'w':
93        case 'wrap':
94            CONFIG.wrap = parseInt(optionValue, 10);
95            break;
96        case 'b':
97        case 'baseURL':
98            CONFIG.baseURL = optionValue;
99            break;
100        case 'v':
101        case 'verbose':
102            CONFIG.verbose = optionValue;
103            break;
104        case 'o':
105        case 'output':
106            CONFIG.outputDirectory = optionValue;
107            break;
108        default:
109            throw new Error(`${optionName} is not a valid option, but was set to ${optionValue}`);
110    }
111}
112

File names are given as glob patterns, which we should expand out.

114let sourceFiles = [];
115for (const globPattern of CONFIG.files) {
116    try {

Calling the synchronous API here is find, since this is a CLI with one event in the loop, but it may be faster to switch to the async version later.

119        const files = glob.sync(globPattern, {

This option excludes any directories from the returned match, which we want.

121            nodir: true,

Ignore node modules in matches

123            ignore: [
124                '**/node_modules/',
125            ],
126        });
127        sourceFiles = sourceFiles.concat(files);
128    } catch (err) {
129        console.log(`Error encountered while looking for matching source files: ${err}`);
130    }
131}
132

Ensure that the base URL ends with a /

134CONFIG.baseURL = path.join(CONFIG.baseURL, '/');
135
136if (CONFIG.verbose) {
137    console.log('Using configuration: ', CONFIG);
138}
139
140generateLitteratePages(sourceFiles, CONFIG);
141