docco-next
Version:
Literate programming parser
459 lines (377 loc) • 191 kB
HTML
<!DOCTYPE html>
<html>
<head>
<title>Docco Next</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div id="container">
<div id="background"></div>
<ul class="sections">
<li id="section-1">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-1">§</a>
</div>
<p><a href="https://github.com/mobily-enterprises/docco-next">Docco Next</a> facilitates
<a href="https://en.wikipedia.org/wiki/Literate_programming">literate programming</a>
in several languages. It’s written in modern Javascript, and runs in Node.</p>
<p>See the <a href="https://mobily-enterprises.github.io/docco-next/">generated documentation as HTML</a></p>
<h2 id="install-and-use">Install and use</h2>
</div>
</li>
<li id="section-2">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-2">§</a>
</div>
<p>To use Docco Next run <code>npm install -g docco-next</code> and run it passing it a list of files
(e.g. <code>docco src/*js</code>)</p>
<p>By default, every file will be converted into formatted HTML and will be placed in the
default destination directory (<code>docs</code> by default). It’s also possible to
convert files to Markdown, rather than HTML. Note that files will
retain their original names and will change their extension to <code>html</code>.</p>
<h2 id="is-it-literate-programming">Is it literate programming?</h2>
</div>
</li>
<li id="section-3">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-3">§</a>
</div>
<p>Formally speaking, literate programs put documentation strictly first.</p>
<p>In simple words, a literate file will look like a Markdown file, and its
code is whichever Markdown code is included in the file.
This means that anything that is not Markdown code (and is therefore indented in) is
considered documentation, and programs are organised so that the documentation
actually makes sense.</p>
<p>A notable example is CoffeeScript, which supports .litcoffee files natively.</p>
<p>However, not many languages support literate programming. Most languages will
need a proprocessor, for example to convert the <code>.js.md</code> file into <code>.js</code>.
<a href="https://github.com/vijithassar/lit">lit</a> is one of such tools. In Node, you
can use Rich Harris’s <a href="https://github.com/Rich-Harris/lit-node">lit-node</a>
to require .md files directly.</p>
<p>Docco Next works with normal source code (such as <code>.js</code> or <code>.c</code>) as well as literate
source code (such as literate CoffeeScript, <code>.litcoffee</code>, or <code>.js.md</code>).</p>
<p>With pure literate style, all you have to do is add the .md extension to your
source file.</p>
<p>When processing source files (such as <code>.js</code> or <code>.c</code>), one line comments are considered
documentation and are parsed using Markdown. The code (that is, anything that is
not a one-line comment) is processed by <a href="https://shiki.matsu.io/">Shiki</a>.</p>
<p>In both cases, the end result is a set of HTML pages with your documentation.</p>
<h2 id="similar-projects">Similar projects</h2>
</div>
</li>
<li id="section-4">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-4">§</a>
</div>
<p>Here is a list of <em>active</em> projects which achieve similar goals:</p>
<ul>
<li><p><a href="https://github.com/jashkenas/docco">Docco</a> by Jeremy Ashkenas (the same
wise author of Underscore and Backbone). The program that
inspired many others (including me) to use literate programming techniques and
implement code that facilitates it</p>
</li>
<li><p><a href="https://github.com/pycco-docs/pycco">pycco</a> by Nick Fitzgerald. A Python
implementation of literate programming</p>
</li>
<li><p><a href="https://github.com/gdeer81/marginalia">Marginalia</a> by Gary Deer. A <strong>Clojure</strong>
implementation of literate programing. The project was originally started by Michael Fogus.</p>
</li>
</ul>
<p>This file is the full source code of Docco Next, and it explains how it works in
pure literate style.</p>
<h2 id="required-files-and-starting-configuration">Required files and starting configuration</h2>
</div>
</li>
<li id="section-5">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-5">§</a>
</div>
<p>The following libraries are required by Docco Next:</p>
<ul>
<li><code>ejs</code>. Used to convert the layout master file into HTML</li>
<li><code>globby</code>. Used to <a href="https://en.wikipedia.org/wiki/Glob_(programming)">glob</a> for filenames when the shell doesn’t otherwise support this</li>
<li><code>fs-extra</code>. Used for all I/O operations</li>
<li><code>marked</code>. Used to convert Markdown into HTML</li>
<li><code>commander</code>. Used to interpret command line parameters</li>
<li><code>shiki</code>. Used to highlight source code</li>
</ul>
<p>In Javascript terms, this becomes:</p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 78;"><span class="line" id="L78"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">path</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'path'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L79"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">ejs</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'ejs'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L80"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">globby</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'globby'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L81"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">fs</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'fs-extra'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L82"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">marked</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'marked'</span><span style="color: #24292EFF">).marked</span></span>
<span class="line" id="L83"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">commander</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'commander'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L84"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">shiki</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'shiki'</span><span style="color: #24292EFF">)</span></span>
<span class="line empty-line" id="L85"></span>
<span class="line empty-line" id="L86"></span></code></pre></div>
</li>
<li id="section-6">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-6">§</a>
</div>
<p>On startup, the <code>version</code> variable is worked out straight from the <code>package.json</code>
file, which is loaded using <code>require</code></p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 88;"><span class="line" id="L88"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">pkg</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'./package.json'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L89"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">version</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">pkg</span><span style="color: #24292EFF">.version</span></span>
<span class="line empty-line" id="L90"></span>
<span class="line empty-line" id="L91"></span></code></pre></div>
</li>
<li id="section-7">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-7">§</a>
</div>
<p>Docco Next manages several languages, stored in <code>layouts/languages.json</code>.
Users can add more languages if desired. However, the list of default languages
(and their relevant information) is stored in <code>layouts/languages.json</code></p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 94;"><span class="line" id="L94"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">defaultLanguages</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'./layouts/languages.json'</span><span style="color: #24292EFF">)</span></span>
<span class="line empty-line" id="L95"></span>
<span class="line empty-line" id="L96"></span></code></pre></div>
</li>
<li id="section-8">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-8">§</a>
</div>
<p>By default, <code>marked</code> is run with very basic options (basically, just turning
<code>smartypants</code> on). Users can add more options, but this is the starting point</p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 98;"><span class="line" id="L98"><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">defaultMarkedOptions</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> { smartypants</span><span style="color: #D32F2F">:</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">true</span><span style="color: #24292EFF"> }</span></span>
<span class="line empty-line" id="L99"></span>
<span class="line empty-line" id="L100"></span></code></pre></div>
</li>
<li id="section-9">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-9">§</a>
</div>
<h2 id="configuration">Configuration</h2>
</div>
</li>
<li id="section-10">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-10">§</a>
</div>
<p>The <code>run</code> function is the entry point of the script when it’s run by the
command line (that is, it’s not being used as a library).
The <code>docco</code> command in <code>bin</code> simply runs <code>require('../docco.js').run()</code>.</p>
<p>The package <code>commander</code> will be used to parse command-line parameters.
Commander will generate a configuration object based on how it’s configured
using its <code>option</code> method.</p>
<p>For example the line:</p>
<pre><code><pre class="shiki" style="background-color: transparent"><code ><span class="line"><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-L, --languages [file]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'use a custom languages.json'</span><span style="color: #24292EFF">)</span></span></code></pre>
</code></pre>
<p>Means that if Docco Next is run with <code>--languages ./some/file.json</code>, the config
object will include <code>{ languages: "./some/file.json"}</code>.</p>
<p>Commander also provides the handy <code>helpInformation()</code> method, which will print
out how the command is used.</p>
<p>This is the full set of options available in Docco Next:</p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 121;"><span class="line" id="L121"><span style="color: #D32F2F">async</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">function</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">run</span><span style="color: #24292EFF"> (args </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">process</span><span style="color: #24292EFF">.argv) {</span></span>
<span class="line" id="L122"><span style="color: #24292EFF"> commander</span></span>
<span class="line" id="L123"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.name</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'docco'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L124"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.version</span><span style="color: #24292EFF">(version)</span></span>
<span class="line" id="L125"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.usage</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'[options] files'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L126"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-L, --languages [file]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'use a custom languages.json'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L127"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span></span>
<span class="line" id="L128"><span style="color: #24292EFF"> </span><span style="color: #22863A">'-l, --layout [name]'</span><span style="color: #212121">,</span></span>
<span class="line" id="L129"><span style="color: #24292EFF"> </span><span style="color: #22863A">'choose a layout (default, parallel or classic)'</span></span>
<span class="line" id="L130"><span style="color: #24292EFF"> )</span></span>
<span class="line" id="L131"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-s, --shiki-theme [shikiTheme]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'choose a shiki theme'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L132"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-o, --output [path]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'output to a given folder'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L133"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-c, --css [file]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'use a custom css file'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L134"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-p, --plugin [file]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'use a custom plugin file'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L135"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-t, --template [file]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'use a custom .ejs template'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L136"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span></span>
<span class="line" id="L137"><span style="color: #24292EFF"> </span><span style="color: #22863A">'-e, --inputExtension [ext]'</span><span style="color: #212121">,</span></span>
<span class="line" id="L138"><span style="color: #24292EFF"> </span><span style="color: #22863A">'assume a file extension for all inputs'</span></span>
<span class="line" id="L139"><span style="color: #24292EFF"> )</span></span>
<span class="line" id="L140"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'-m, --marked [file]'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'use custom marked options'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L141"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.option</span><span style="color: #24292EFF">(</span></span>
<span class="line" id="L142"><span style="color: #24292EFF"> </span><span style="color: #22863A">'-x, --outputExtension [ext]'</span><span style="color: #212121">,</span></span>
<span class="line" id="L143"><span style="color: #24292EFF"> </span><span style="color: #22863A">'set default file extension for all outputs'</span></span>
<span class="line" id="L144"><span style="color: #24292EFF"> )</span></span>
<span class="line" id="L145"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">.parse</span><span style="color: #24292EFF">(args)</span></span>
<span class="line" id="L146"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #1976D2">commander</span><span style="color: #24292EFF">.</span><span style="color: #1976D2">args</span><span style="color: #24292EFF">.</span><span style="color: #1976D2">length</span><span style="color: #24292EFF">) {</span></span>
<span class="line" id="L147"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> { </span><span style="color: #D32F2F">...</span><span style="color: #1976D2">commander</span><span style="color: #6F42C1">.opts</span><span style="color: #24292EFF">()</span><span style="color: #212121">,</span><span style="color: #24292EFF"> args</span><span style="color: #D32F2F">:</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">commander</span><span style="color: #24292EFF">.args }</span></span>
<span class="line" id="L148"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">cmdLineNormalise</span><span style="color: #24292EFF">(config)</span></span>
<span class="line" id="L149"><span style="color: #24292EFF"> </span><span style="color: #6F42C1">configure</span><span style="color: #24292EFF">(config)</span></span>
<span class="line" id="L150"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">cmdLineSanityCheck</span><span style="color: #24292EFF">(config)</span></span>
<span class="line empty-line" id="L151"></span>
<span class="line" id="L152"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">documentAll</span><span style="color: #24292EFF">(config)</span></span>
<span class="line" id="L153"><span style="color: #24292EFF"> } </span><span style="color: #D32F2F">else</span><span style="color: #24292EFF"> {</span></span>
<span class="line" id="L154"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">return</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">console</span><span style="color: #6F42C1">.log</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">commander</span><span style="color: #6F42C1">.helpInformation</span><span style="color: #24292EFF">())</span></span>
<span class="line" id="L155"><span style="color: #24292EFF"> }</span></span>
<span class="line" id="L156"><span style="color: #24292EFF">}</span></span>
<span class="line empty-line" id="L157"></span>
<span class="line empty-line" id="L158"></span></code></pre></div>
</li>
<li id="section-11">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-11">§</a>
</div>
<p>Three configuration functions are called:</p>
<ul>
<li><code>cmdLineNormalise()</code> – expands some command line options to objects</li>
<li><code>configure()</code> – enriches configuration options with full paths etc.</li>
<li><code>cmdLineSanityCheck()</code> – checks that files and folders actually exist.</li>
</ul>
<p>Here is an explanation of what each one does, followed by their source code.</p>
<h3 id="step-1-cmdlinenormalise"><strong>Step 1: <code>cmdLineNormalise()</code></strong></h3>
</div>
</li>
<li id="section-12">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-12">§</a>
</div>
<p>It’s important to understand that Docco Next can be used as a library as well as
a command line program.
Two of the command line options, <code>marked</code> and <code>languages</code>, are external JSON
files. When used as a library, Docco Next will expect <code>marked</code> and <code>languages</code> to be
objects. However, when run as a command line program, those options will
contain a string with a (JSON) file name instead.</p>
<p>The <code>cmdLineNormalise()</code> function is used to convert those strings into
Javascript objects which will depend on the contents of the corresponding
JSON files
The fuction also assigns <code>config.args</code> (which is the list of files to be
converted) to <code>config.sources</code>.</p>
<p>To sum up: when using Docco Next as a library, <code>config.languages</code> and <code>config.maked</code>
will need to be objects. However, from the command line, they will be the paths of
JSON files, and will be converted to objects by <code>cmdLineNormalise()</code>, which
reads:</p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 186;"><span class="line" id="L186"><span style="color: #D32F2F">async</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">function</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">cmdLineNormalise</span><span style="color: #24292EFF"> (config) {</span></span>
<span class="line" id="L187"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages) {</span></span>
<span class="line" id="L188"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #24292EFF">(</span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">fileExists</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages))) {</span></span>
<span class="line" id="L189"><span style="color: #24292EFF"> </span><span style="color: #1976D2">console</span><span style="color: #6F42C1">.error</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'Languages file not found:'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages)</span></span>
<span class="line" id="L190"><span style="color: #24292EFF"> </span><span style="color: #1976D2">process</span><span style="color: #6F42C1">.exit</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">5</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L191"><span style="color: #24292EFF"> }</span></span>
<span class="line" id="L192"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">languages</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">fs</span><span style="color: #6F42C1">.readFile</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages)</span></span>
<span class="line" id="L193"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">JSON</span><span style="color: #6F42C1">.parse</span><span style="color: #24292EFF">(languages)</span></span>
<span class="line" id="L194"><span style="color: #24292EFF"> }</span></span>
<span class="line empty-line" id="L195"></span>
<span class="line" id="L196"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.plugin) {</span></span>
<span class="line" id="L197"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #24292EFF">(</span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">fileExists</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.plugin))) {</span></span>
<span class="line" id="L198"><span style="color: #24292EFF"> </span><span style="color: #1976D2">console</span><span style="color: #6F42C1">.error</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'Plugin file not found:'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.plugin)</span></span>
<span class="line" id="L199"><span style="color: #24292EFF"> </span><span style="color: #1976D2">process</span><span style="color: #6F42C1">.exit</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">5</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L200"><span style="color: #24292EFF"> }</span></span>
<span class="line" id="L201"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.plugin </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">require</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">path</span><span style="color: #6F42C1">.join</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">process</span><span style="color: #6F42C1">.cwd</span><span style="color: #24292EFF">()</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.plugin))</span></span>
<span class="line" id="L202"><span style="color: #24292EFF"> } </span><span style="color: #D32F2F">else</span><span style="color: #24292EFF"> {</span></span>
<span class="line" id="L203"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.plugin </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> {}</span></span>
<span class="line" id="L204"><span style="color: #24292EFF"> }</span></span>
<span class="line empty-line" id="L205"></span>
<span class="line" id="L206"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.outputExtension) </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.outputExtension </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'html'</span></span>
<span class="line empty-line" id="L207"></span>
<span class="line" id="L208"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked) {</span></span>
<span class="line" id="L209"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #24292EFF">(</span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">fileExists</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked))) {</span></span>
<span class="line" id="L210"><span style="color: #24292EFF"> </span><span style="color: #1976D2">console</span><span style="color: #6F42C1">.error</span><span style="color: #24292EFF">(</span><span style="color: #22863A">'Marked file not found:'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked)</span></span>
<span class="line" id="L211"><span style="color: #24292EFF"> </span><span style="color: #1976D2">process</span><span style="color: #6F42C1">.exit</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">6</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L212"><span style="color: #24292EFF"> }</span></span>
<span class="line" id="L213"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">marked</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">fs</span><span style="color: #6F42C1">.readFile</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked)</span></span>
<span class="line" id="L214"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">JSON</span><span style="color: #6F42C1">.parse</span><span style="color: #24292EFF">(marked)</span></span>
<span class="line" id="L215"><span style="color: #24292EFF"> }</span></span>
<span class="line empty-line" id="L216"></span>
<span class="line" id="L217"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.sources </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">await</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">globby</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.args)</span></span>
<span class="line" id="L218"><span style="color: #24292EFF">}</span></span>
<span class="line empty-line" id="L219"></span>
<span class="line empty-line" id="L220"></span></code></pre></div>
</li>
<li id="section-13">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-13">§</a>
</div>
<h3 id="step-2-configure"><strong>Step 2: <code>configure()</code></strong></h3>
</div>
</li>
<li id="section-14">
<div class="annotation">
<div class="sswrap ">
<a class="ss" href="#section-14">§</a>
</div>
<p>This function is different to the other two <code>cmdLineNormalise()</code> and
<code>cmdLineSanityCheck()</code>: rather than being a command line-only normalisation
function, it’s actually a function that is run <em>every time</em> an API call is
invoked. (Note that once it’s run once, it sets the <code>config.configured</code>
property in the <code>config</code> object, and will check this property so that it will
ever do anything only the first time it’s invoked)</p>
<p>This function is responsible to set sane defaults in the <code>config</code> property,
so that each function doesn’t need to worry with wasteful checking.</p>
<p>For example <code>config.output</code> will be set as <code>docs</code> by default.</p>
<p>Also, for passed properties such as <code>languages</code> or <code>marked</code>, this function
makes sure that the passed options are <em>added</em> to sane defaults. For example
by passing the <code>marked</code> property in the config object, this function makes
sure that the default <code>smartypants: true</code> is on, and any configuration
options are added on <em>top</em> of what the user has passed. Or, that the
config.languages contains the used-defined languages, <em>as well as</em> the
default ones.</p>
<p>This function also sets some indirect configuration options that are not meant
to be passed by the developer, but that are a result of the configuration.</p>
<p>Finally, this function also makes sure that the passed config makes sense:
<code>config.sources</code> is scanned and any source with an unknown language (that is,
a language not in the <code>languages</code> array) is filtered out (with a warning).</p>
<p>You can see this function as insurance that there is a solid, valid <code>config</code>
object that every call can use. This is why every single function that uses
<code>config</code> will call <code>configure</code> first.</p>
</div>
<div class="content"><pre class="shiki" style="background-color: transparent"><code style="--line-start-number: 253;"><span class="line" id="L253"><span style="color: #D32F2F">function</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">configure</span><span style="color: #24292EFF"> (config) {</span></span>
<span class="line" id="L254"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.configured) </span><span style="color: #D32F2F">return</span></span>
<span class="line" id="L255"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.configured </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">true</span></span>
<span class="line empty-line" id="L256"></span>
<span class="line" id="L257"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.output </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.output </span><span style="color: #D32F2F">||</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'docs'</span></span>
<span class="line empty-line" id="L258"></span>
<span class="line" id="L259"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">properObjectWithKeys</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages)</span></span>
<span class="line" id="L260"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">?</span><span style="color: #24292EFF"> { </span><span style="color: #D32F2F">...</span><span style="color: #24292EFF">defaultLanguages</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">...</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.languages }</span></span>
<span class="line" id="L261"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">:</span><span style="color: #24292EFF"> defaultLanguages</span></span>
<span class="line empty-line" id="L262"></span>
<span class="line" id="L263"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">properObjectWithKeys</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked)</span></span>
<span class="line" id="L264"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">?</span><span style="color: #24292EFF"> { </span><span style="color: #D32F2F">...</span><span style="color: #24292EFF">defaultMarkedOptions</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">...</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.marked }</span></span>
<span class="line" id="L265"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">:</span><span style="color: #24292EFF"> defaultMarkedOptions</span></span>
<span class="line empty-line" id="L266"></span>
<span class="line" id="L267"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout </span><span style="color: #D32F2F">||</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'default'</span></span>
<span class="line" id="L268"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #1976D2">config</span><span style="color: #6F42C1">.</span><span style="color: #1976D2">layout</span><span style="color: #6F42C1">.match</span><span style="color: #24292EFF">(</span><span style="color: #22863A">/</span><span style="color: #D32F2F">^</span><span style="color: #22863A">[a-zA-Z0-9]</span><span style="color: #D32F2F">+$</span><span style="color: #22863A">/</span><span style="color: #24292EFF">)) {</span></span>
<span class="line" id="L269"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">path</span><span style="color: #6F42C1">.join</span><span style="color: #24292EFF">(__dirname</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'layouts'</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout)</span></span>
<span class="line" id="L270"><span style="color: #24292EFF"> }</span></span>
<span class="line empty-line" id="L271"></span>
<span class="line" id="L272"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.css) </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.css </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">path</span><span style="color: #6F42C1">.join</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'docco.css'</span><span style="color: #24292EFF">)</span></span>
<span class="line empty-line" id="L273"></span>
<span class="line" id="L274"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.public </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">path</span><span style="color: #6F42C1">.join</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'public'</span><span style="color: #24292EFF">)</span></span>
<span class="line empty-line" id="L275"></span>
<span class="line" id="L276"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.template) {</span></span>
<span class="line" id="L277"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.template </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">path</span><span style="color: #6F42C1">.join</span><span style="color: #24292EFF">(</span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.layout</span><span style="color: #212121">,</span><span style="color: #24292EFF"> </span><span style="color: #22863A">'docco.ejs'</span><span style="color: #24292EFF">)</span></span>
<span class="line" id="L278"><span style="color: #24292EFF"> }</span></span>
<span class="line empty-line" id="L279"></span>
<span class="line" id="L280"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.sources </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.sources </span><span style="color: #D32F2F">||</span><span style="color: #24292EFF"> {}</span></span>
<span class="line empty-line" id="L281"></span>
<span class="line" id="L282"><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #24292EFF">.sources </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">config</span><span style="color: #6F42C1">.</span><span style="color: #1976D2">sources</span><span style="color: #6F42C1">.filter</span><span style="color: #24292EFF">((source) </span><span style="color: #D32F2F">=></span><span style="color: #24292EFF"> {</span></span>
<span class="line" id="L283"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">const</span><span style="color: #24292EFF"> </span><span style="color: #1976D2">there</span><span style="color: #24292EFF"> </span><span style="color: #D32F2F">=</span><span style="color: #24292EFF"> </span><span style="color: #6F42C1">getLanguage</span><span style="color: #24292EFF">(source</span><span style="color: #212121">,</span><span style="color: #24292EFF"> config)</span></span>
<span class="line" id="L284"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">if</span><span style="color: #24292EFF"> (</span><span style="color: #D32F2F">!</span><span style="color: #24292EFF">there) {</span></span>
<span class="line" id="L285"><span style="color: #24292EFF"> </span><span style="color: #1976D2">console</span><span style="color: #6F42C1">.warn</span><span style="color: #24292EFF">(</span></span>
<span class="line" id="L286"><span style="color: #24292EFF"> </span><span style="color: #22863A">`docco: file not processed, language not supported: (</span><span style="color: #D32F2F">${</span><span style="color: #1976D2">path</span><span style="color: #6F42C1">.basename</span><span style="color: #24292EFF">(</span></span>
<span class="line" id="L287"><span style="color: #24292EFF"> source</span></span>
<span class="line" id="L288"><span style="color: #24292EFF"> )</span><span style="color: #D32F2F">}</span><span style="color: #22863A">)`</span></span>
<span class="line" id="L289"><span style="color: #24292EFF"> )</span></span>
<span class="line" id="L290"><span style="color: #24292EFF"> }</span></span>
<span class="line" id="L291"><span style="color: #24292EFF"> </span><span style="color: #D32F2F">return</span><span style="color: #24292EFF"> there</span></span>
<span class="line" id="L292"><span style="color: #24292EFF"> })</span></span>
<span class="line" id="L293"><span style="color: #24292EFF">}</span></span>
<span class="line empty-line" id="L294"></span>
<span class="line empty-line" id="L295"></span></code></pre></div>
</li>
<li id="section-15">
<div class="annotatio