./src/index.js annotated source
Back to index1#!/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