@antora/assembler
Version:
A JavaScript library that merges AsciiDoc content from multiple pages in an Antora site into assembly files and delegates to an exporter to convert those files to another format, such as PDF.
94 lines (88 loc) • 3.83 kB
JavaScript
const expandPath = require('@antora/expand-path-helper')
const fsp = require('node:fs/promises')
const os = require('node:os')
const yaml = require('js-yaml')
function loadConfig (playbook, configSource = './antora-assembler.yml') {
return (
configSource.constructor === Object
? Promise.resolve(configSource)
: fsp
.access((configSource = expandPath(configSource, { dot: playbook.dir })))
.then(
() => true,
() => false
)
.then((exists) =>
exists ? fsp.readFile(configSource).then((data) => camelCaseKeys(yaml.load(data), ['asciidoc'])) : {}
)
).then((config) => {
if (config.enabled === false) return undefined
let asciidocAttrs
if (!config.asciidoc) {
config.asciidoc = { attributes: (asciidocAttrs = {}) }
} else if (!(asciidocAttrs = config.asciidoc.attributes)) {
config.asciidoc.attributes = asciidocAttrs = {}
}
if (!('revdate' in asciidocAttrs)) asciidocAttrs.revdate = getLocalDate()
asciidocAttrs['page-partial'] = null
const remapComponentVersionsKey = !('componentVersionFilter' in config)
const componentVersionFilter = (config.componentVersionFilter ??= {})
if (remapComponentVersionsKey && 'componentVersions' in config) {
componentVersionFilter.names = config.componentVersions
delete config.componentVersions
}
if (componentVersionFilter.names == null) {
componentVersionFilter.names = ['*']
} else if (typeof componentVersionFilter.names === 'string') {
componentVersionFilter.names = componentVersionFilter.names.split(', ')
}
const remapAssemblyKeys = !('assembly' in config)
const assembly = (config.assembly ??= {})
if (remapAssemblyKeys) {
for (const key of ['rootLevel', 'insertStartPage', 'sectionMergeStrategy']) {
if (!(key in config)) continue
assembly[key] = config[key]
delete config[key]
}
}
if (!('doctype' in assembly)) assembly.doctype = 'doctype' in asciidocAttrs ? asciidocAttrs.doctype : 'book'
delete asciidocAttrs.doctype
if (!('rootLevel' in assembly)) assembly.rootLevel = 0
if (!('insertStartPage' in assembly)) assembly.insertStartPage = true
if (['discrete', 'fuse', 'enclose'].indexOf(assembly.sectionMergeStrategy) < 0) {
assembly.sectionMergeStrategy = 'discrete'
}
const build = (config.build ??= {})
if (build.dir === '$' + '{playbook.output.dir}') {
throw new Error('Not implemented')
}
build.dir &&= expandPath(build.dir, { dot: playbook.dir })
build.cwd = playbook.dir // use playbook.dir for finding and loading require scripts
if (!('clean' in build) && 'output' in playbook) build.clean = playbook.output.clean
if (!('publish' in build)) build.publish = true
if ('keepAggregateSource' in build) {
build.keepSource = build.keepAggregateSource
delete build.keepAggregateSource
}
if (!build.processLimit) {
build.processLimit = 'processLimit' in build ? Infinity : Math.round(os.cpus().length * 0.5)
}
return config
})
}
function camelCaseKeys (o, stopPaths = [], p = undefined) {
if (Array.isArray(o)) return o.map((it) => camelCaseKeys(it, stopPaths, p))
if (o == null || o.constructor !== Object) return o
const pathPrefix = p ? p + '.' : ''
const accum = {}
for (const [k, v] of Object.entries(o)) {
const camelKey = k.charAt() + k.slice(1).replace(/_([a-z])/g, (_, l) => l.toUpperCase())
accum[camelKey] = ~stopPaths.indexOf(pathPrefix + camelKey) ? v : camelCaseKeys(v, stopPaths, pathPrefix + camelKey)
}
return accum
}
function getLocalDate (now = new Date()) {
return new Date(now - now.getTimezoneOffset() * 60000).toISOString().split('T')[0]
}
module.exports = loadConfig