asciidoctor-chunker
Version:
Creates chunked (multi-page) HTML from Asciidoctor's single HTML file with supporting the fine-tuned splits in chapters, sections and any depth of subsections.
161 lines (142 loc) • 5.11 kB
JavaScript
/*
* This file is a part of Asciidoctor Chunker project.
* Copyright (c) 2021 Wataru Shito (@waterloo_jp)
*/
'use strict';
import { Command } from 'commander';
const commander = new Command();
// __VERSION__ is replaced by webpack DefinePlugin
const version = (typeof __VERSION__) !== 'undefined' ? __VERSION__ : 'dev';
const commaSeparatedList = (value, dummyPrevious) => value.split(',');
/**
*
* @param {Array} argv The reference to `process.argv`.
*/
export const makeConfig = (argv) => {
const [nodejs, script, singleHTML, ...rest] = argv;
const toBeParsed = [nodejs, script, ...rest];
const args = commander.version(version)
.name('node asciidoctor-chunker.js')
.usage('<single.html> [options]')
.option('-o, --outdir <directory>',
'The output directory where the chunked html will be written to.', 'html_chunks')
.option('--depth <depth specifier>', 'See the description above.', '1')
.option('--css <paths>', 'The comma-separated list of css file paths to include. The paths must be accessible from the current directory.', commaSeparatedList)
.option('--no-strictMode', 'Disables strict mode.')
.option('--titlePage <title string>', 'Sets title page TOC string.', 'Titlepage')
.description(`Description:
Splits a single html document generated by Asciidoctor into
multiple chunked html files.
The default output directory is 'html_chunks'. You can override
it via the '-o' option.
The default splits are made by preamble, parts, and chapters.
You can specify the extraction level with the '--depth' option.
If you have any custom elements inserted under <div d=
in the single-source html, asciidoctor-chunker ignores them by
default. If you want them to be included into the chunked html,
set the '--no-strictMode' option. The elements will be copied
to every chunked page.
By default 'asciidoctor-chunker.css' is included in the
output directory. It provides the non-opinionated page
navigation bar at the bottom of every chunked page.
You can override this by giving a comma-separated list
of paths to your custom css files. They will be copied
into the output directory, so their paths must be accessible
to asciidoctor-chunker.
The Depth Specifier:
You can list multiple settings by separating each specifier
with a comma. Each specifier consists of either a single
number or two numbers separated by a colon.
A single number sets the default level of extraction.
Number 1 is the application default and it extracts the
chapter level. Number 2 is for section extraction, 3 for
subsection, and so on, up to 6 which is the maximum section
level of Asciidoctor.
The list of colon-separated numbers, chap:level, can
change the extraction depth for specific chapters.
so 3:2 means chapter 3 is extracted down to 2 levels (i.e.
section level). You can use a hyphen to specify the range
of chapters to set as chapFrom-chapTo:level, so 1-3:5 means
chapter 1 through 5 should be extracted with the depth
level 5.
Example:
--depth 2 Sets default level 2, all the chapters and
sections will be extracted.
--depth 3,1:2,8:5 Sets default level 3, level 2 for Ch. 1,
and level 5 for Ch. 8.
--depth 1,3-8:2 Sets default level 1, and level 2 for Chs. 3 to 8.
--depth 3-8:3 No default is set so default level is 1, and
level 3 for Chs. 3 to 8.`)
.parse(toBeParsed);
const { depth, outdir, strictMode, titlePage, css = ['asciidoctor-chunker.css'] } = args.opts();
const d = parseDepth(depth);
return {
singleHTML,
config: {
depth: d,
outdir,
css,
strictMode,
titlePage,
}
};
}
/**
* Parses the depth specifier as '1,3-5:6,8:4'
* into an object:
* ```
* {
* default: 1,
* depth: {
* '3': 6,
* '4': 6,
* '5': 6,
* '8': 4
* }
* }
* ```
* The default will be set 1 if not specified.
*
* @param {string} depth
*/
export const parseDepth = (depth) =>
depth.split(',')
.map(e => {
const [chap, level] = e.split(':');
return level ? parseSpecifierTerm(chap, level) : { default: +chap };
})
.reduce((accum, e) => accum = { ...accum, ...e }, { default: 1 });
/**
* Parses each term (the comma-separated term) of depth
* specifier and returns the chapter-depth object.
*
* E.g. chap='3-6', level='2' returns
* ```
* {
* '3': 2,
* '4': 2,
* '5': 2,
* '6': 2
* }
* ```
*
*
* @param {string} chap Either 'num' or 'num-num' such as '3-9'
* which means from chapter 3 to 9.
* @param level The level of extraction depth.
* @returns the object with chapter number as a property name
* integer for a value.
*/
const parseSpecifierTerm = (chap, level) => {
const [from, to] = chap.split('-').map(num => parseInt(num));
return to ?
// case with chap='3-6'
new Array(to - from + 1)
.fill(0).reduce((accum, e, i) => ({
...accum,
[]: +level
}), {}) : // case with no hyphen
{
[]: +level
};
};