@antora/assembler 1.0.0-rc.3 → 1.0.0-rc.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/assemble-content.js +33 -12
- package/lib/configure.js +2 -1
- package/lib/load-config.js +7 -6
- package/lib/produce-assembly-file.js +37 -28
- package/lib/util/generate-scoped-id.js +1 -0
- package/package.json +2 -2
package/lib/assemble-content.js
CHANGED
|
@@ -23,10 +23,11 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
23
23
|
backend: targetBackend = targetExtname.substring(1),
|
|
24
24
|
embedReferenceStyle = 'relative',
|
|
25
25
|
mediaType: targetMediaType,
|
|
26
|
-
loggerName = PACKAGE_NAME
|
|
26
|
+
loggerName = `${PACKAGE_NAME} [${targetBackend}-exporter]`,
|
|
27
|
+
xmlCompliant,
|
|
27
28
|
} = converter ?? {}
|
|
28
|
-
const assemblerConfig = await loadConfig.call(this,
|
|
29
|
-
if (assemblerConfig.enabled === false) return []
|
|
29
|
+
const assemblerConfig = await loadConfig.call(this, configSource, playbook, '-' + targetBackend)
|
|
30
|
+
if (assemblerConfig.enabled === false || !contentCatalog.publishableFamilies?.has('export')) return []
|
|
30
31
|
const context = isBound(this)
|
|
31
32
|
? this
|
|
32
33
|
: {
|
|
@@ -38,9 +39,10 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
38
39
|
const { loadAsciiDoc = require('@antora/asciidoc-loader') } = generatorFunctions
|
|
39
40
|
const { assembly: assemblyConfig, build: buildConfig } = assemblerConfig
|
|
40
41
|
assemblyConfig.embedReferenceStyle = embedReferenceStyle
|
|
42
|
+
if (xmlCompliant) assemblyConfig.xmlIds ??= true
|
|
41
43
|
const profile = (assemblyConfig.profile ??= targetBackend)
|
|
42
|
-
const intrinsicAttributes = { 'loader-assembler': '' }
|
|
43
|
-
buildConfig.cwd ??= process.cwd()
|
|
44
|
+
const intrinsicAttributes = { 'loader-assembler': '', 'assembler-root-level': assemblyConfig.rootLevel }
|
|
45
|
+
const cwd = (buildConfig.cwd ??= process.cwd())
|
|
44
46
|
if (profile) {
|
|
45
47
|
buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), `build/assembler/${profile}`)
|
|
46
48
|
intrinsicAttributes[`assembler-profile-${profile}`] = ''
|
|
@@ -65,7 +67,7 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
65
67
|
generateSelectAssemblyProfile(context, contentCatalog, assemblyConfig, intrinsicAttributes, navigationCatalog)
|
|
66
68
|
)
|
|
67
69
|
if (!(assemblyFiles.length && typeof convert === 'function')) return assemblyFiles
|
|
68
|
-
buildConfig.command ??= typeof getDefaultCommand === 'function' ? await getDefaultCommand(
|
|
70
|
+
buildConfig.command ??= typeof getDefaultCommand === 'function' ? await getDefaultCommand(cwd, playbook) : null
|
|
69
71
|
const { publishSite: publishFiles = require('@antora/site-publisher') } = generatorFunctions
|
|
70
72
|
await prepareWorkspace(publishFiles, assemblyFiles, buildConfig)
|
|
71
73
|
const helpers = { logCommand: logCommand.bind(context, loggerName), runCommand }
|
|
@@ -150,16 +152,21 @@ function generateSelectAssemblyProfile (context, contentCatalog, baseModel, intr
|
|
|
150
152
|
const attributes = Object.assign({}, baseModel.attributes)
|
|
151
153
|
const model = Object.assign({}, baseModel, overrides, { attributes, logger })
|
|
152
154
|
if (!overrides) return Object.assign(model, { navigation: navigation || componentVersion.navigation })
|
|
155
|
+
if ('rootLevel' in overrides) attributes['assembler-root-level'] = overrides.rootLevel
|
|
153
156
|
delete model.navFiles
|
|
154
157
|
delete model.messages
|
|
155
|
-
if (overrides.attributes)
|
|
158
|
+
if (overrides.attributes) {
|
|
159
|
+
for (const [name, val] of Object.entries(overrides.attributes)) {
|
|
160
|
+
if (!(name in intrinsicAttributes)) attributes[name] = val
|
|
161
|
+
}
|
|
162
|
+
}
|
|
156
163
|
if (navigation) return Object.assign(model, { navigation })
|
|
157
164
|
overrides.messages?.forEach(boundSendToLog)
|
|
158
165
|
const navFiles = overrides.navFiles
|
|
159
166
|
if (!navFiles) return Object.assign(model, { navigation: componentVersion.navigation })
|
|
160
167
|
if (!navFiles.length) return Object.assign(model, { navigation: [] })
|
|
161
168
|
model.navigation = buildAlternateNavigation(contentCatalog, componentVersion, navFiles, {
|
|
162
|
-
attributes:
|
|
169
|
+
attributes: model.attributes,
|
|
163
170
|
})
|
|
164
171
|
return model
|
|
165
172
|
}
|
|
@@ -182,7 +189,7 @@ function prepareConvertAttributes (doc, targetExtname, relativeToOutput, assembl
|
|
|
182
189
|
docdir,
|
|
183
190
|
docfile,
|
|
184
191
|
docfilesuffix,
|
|
185
|
-
|
|
192
|
+
docname: `${docname}@`,
|
|
186
193
|
imagesdir: '',
|
|
187
194
|
outdir,
|
|
188
195
|
outfile,
|
|
@@ -206,6 +213,17 @@ function prepareConvertAttributes (doc, targetExtname, relativeToOutput, assembl
|
|
|
206
213
|
return args
|
|
207
214
|
},
|
|
208
215
|
})
|
|
216
|
+
Object.defineProperty(attributes, 'outfilesuffix', {
|
|
217
|
+
get () {
|
|
218
|
+
return ospath.extname(this.outfile)
|
|
219
|
+
},
|
|
220
|
+
set (value) {
|
|
221
|
+
const outfile = this.outfile
|
|
222
|
+
const extname = ospath.extname(outfile)
|
|
223
|
+
if (extname && outfile.endsWith(extname)) this.outfile = outfile.substring(0, outfile.length - extname.length)
|
|
224
|
+
this.outfile += value
|
|
225
|
+
},
|
|
226
|
+
})
|
|
209
227
|
return Object.defineProperty(attributes, 'toArgs', { enumerable: false })
|
|
210
228
|
}
|
|
211
229
|
|
|
@@ -265,12 +283,14 @@ async function resolveFileOrContents (convertResult, convertAttributes, buildCon
|
|
|
265
283
|
fileOrContents = convertResult.stdout
|
|
266
284
|
}
|
|
267
285
|
let logger, match
|
|
268
|
-
if (buildConfig.stderrSink === 'log' && convertResult.stderr
|
|
286
|
+
if (buildConfig.stderrSink === 'log' && convertResult.stderr?.length && (logger = this.getLogger(loggerName))) {
|
|
269
287
|
const docfile = convertAttributes.docfile
|
|
270
288
|
const command = buildConfig.command
|
|
289
|
+
const file = { path: docfile }
|
|
271
290
|
const stderr = convertResult.stderr.toString().trimEnd()
|
|
291
|
+
const additionalLines = ['Additional stderr lines from command:']
|
|
272
292
|
stderr.split(NEWLINE_RX).forEach((line) => {
|
|
273
|
-
const ctx = { command, file
|
|
293
|
+
const ctx = { command, file }
|
|
274
294
|
if (line.charAt() === '{' && line.charAt(line.length - 1) === '}') {
|
|
275
295
|
const entry = JSON.parse(line)
|
|
276
296
|
if (entry.name) ctx.program = entry.name
|
|
@@ -286,9 +306,10 @@ async function resolveFileOrContents (convertResult, convertAttributes, buildCon
|
|
|
286
306
|
if (lineno) ctx.line = parseInt(lineno, 10)
|
|
287
307
|
logger[level === 'WARNING' ? 'warn' : level.toLowerCase()](ctx, msg)
|
|
288
308
|
} else {
|
|
289
|
-
|
|
309
|
+
additionalLines.push(line)
|
|
290
310
|
}
|
|
291
311
|
})
|
|
312
|
+
if (additionalLines.length > 1) logger.info({ command, file }, additionalLines.join('\n'))
|
|
292
313
|
}
|
|
293
314
|
} else if (convertResult !== undefined) {
|
|
294
315
|
return convertResult
|
package/lib/configure.js
CHANGED
|
@@ -17,7 +17,8 @@ function internalConfigure (converter, config = {}, providers = {}) {
|
|
|
17
17
|
|
|
18
18
|
this.once('navigationBuilt', async ({ playbook, contentCatalog }) => {
|
|
19
19
|
const { assembleContent = require('./assemble-content'), ...assembleContentConfig } = providers
|
|
20
|
-
if (
|
|
20
|
+
if (config.configSource?.constructor === Object) {
|
|
21
|
+
assembleContentConfig.configSource = config.configSource
|
|
21
22
|
await assembleContent.call(this, playbook, contentCatalog, converter, assembleContentConfig)
|
|
22
23
|
} else {
|
|
23
24
|
const singleConfig = !('configFiles' in config)
|
package/lib/load-config.js
CHANGED
|
@@ -9,8 +9,9 @@ const yaml = require('js-yaml')
|
|
|
9
9
|
const { LEGACY_ASSEMBLY_KEYS } = require('./constants')
|
|
10
10
|
const CAMEL_CASE_STOP_PATHS = ['asciidoc.attributes', 'assembly.attributes']
|
|
11
11
|
const PACKAGE_NAME = require('../package.json').name
|
|
12
|
+
const YAML_SCHEMA = yaml.CORE_SCHEMA.withTags(yaml.mergeTag)
|
|
12
13
|
|
|
13
|
-
function loadConfig (
|
|
14
|
+
function loadConfig (configSource, playbook, preferredQualifier = '') {
|
|
14
15
|
let resolvedConfigSource
|
|
15
16
|
return (
|
|
16
17
|
configSource?.constructor === Object
|
|
@@ -36,11 +37,11 @@ function loadConfig (playbook, configSource, preferredQualifier = '') {
|
|
|
36
37
|
}
|
|
37
38
|
return {}
|
|
38
39
|
}
|
|
39
|
-
return fsp
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
return fsp.readFile(resolvedConfigSource).then((data) =>
|
|
41
|
+
Object.assign(camelCaseKeys(yaml.load(data, { schema: YAML_SCHEMA }), CAMEL_CASE_STOP_PATHS), {
|
|
42
|
+
file: resolvedConfigSource,
|
|
43
|
+
})
|
|
44
|
+
)
|
|
44
45
|
})
|
|
45
46
|
).then((config) => {
|
|
46
47
|
if (config.enabled === false) return config
|
|
@@ -198,6 +198,7 @@ function mergeAsciiDoc (
|
|
|
198
198
|
Object.assign({}, page, { contents: trimAsciiDoc(contents), mediaType: page.src.mediaType })
|
|
199
199
|
)
|
|
200
200
|
const doc = loadAsciiDoc(pageAsAsciiDoc, contentCatalog, asciidocConfig)
|
|
201
|
+
doc.catalog.syntheticIds = {}
|
|
201
202
|
doc.logger = logger
|
|
202
203
|
? Object.assign(doc.getLogger().$dup(), {
|
|
203
204
|
delegate: {
|
|
@@ -365,10 +366,10 @@ function mergeAsciiDoc (
|
|
|
365
366
|
}
|
|
366
367
|
}
|
|
367
368
|
}
|
|
368
|
-
if (htitleAsciiDoc
|
|
369
|
+
if (htitleAsciiDoc) {
|
|
369
370
|
if (atDocumentRoot) {
|
|
370
|
-
//
|
|
371
|
-
pageFragment =
|
|
371
|
+
// Q: should we use htitleAsciiDoc to generate ID if not {empty} instead of pageStyle
|
|
372
|
+
pageFragment = `#_${idSeparators.coordinate}${pageIdLeader}${pageStyle}`
|
|
372
373
|
buffer.unshift(`[#${pageId}]`)
|
|
373
374
|
} else {
|
|
374
375
|
pageFragment = `#${pageId}`
|
|
@@ -393,31 +394,30 @@ function mergeAsciiDoc (
|
|
|
393
394
|
} else if (atBookRoot) {
|
|
394
395
|
nextSectionLevel = undefined
|
|
395
396
|
}
|
|
396
|
-
let enclosed
|
|
397
397
|
if (heading) {
|
|
398
398
|
const rolesAttr = pageRoles.reduce((str, it) => str + '.' + it, '')
|
|
399
399
|
const notitleAttrs = heading.notitle ? '%notitle,toclevels=0,outlinelevels=0' : ''
|
|
400
400
|
buffer.push(`[${heading.style ?? pageStyle}${pageFragment}${rolesAttr}${notitleAttrs}]`)
|
|
401
401
|
buffer.push(`${'='.repeat(heading.level)} ${heading.title}`)
|
|
402
|
-
} else {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
}
|
|
419
|
-
buffer.push(`${'='.repeat(hlevel)} ${overviewTitle}`)
|
|
402
|
+
} else if (atDocumentRoot) {
|
|
403
|
+
buffer.unshift(`[#${pageId}]`)
|
|
404
|
+
}
|
|
405
|
+
if (sectionMergeStrategy === 'enclose' && hasItems && hasSections && !(atDocumentRoot && heading)) {
|
|
406
|
+
// TODO: make overview section title configurable
|
|
407
|
+
//let overviewTitle = doc.getDocumentTitle()
|
|
408
|
+
//if (overviewTitle === navtitle) overviewTitle = doc.getAttribute('overview-title', 'Overview')
|
|
409
|
+
const overviewTitle = doc.getAttribute('overview-title', 'Overview')
|
|
410
|
+
const syntheticId = idSeparators.generateIdFromTitle(overviewTitle, idSeparators, pageIdLeader)
|
|
411
|
+
if (heading) buffer.push('')
|
|
412
|
+
let hlevel = level + (nextSectionLevel = 2)
|
|
413
|
+
if (hlevel > 6) {
|
|
414
|
+
const blockStyle = `discrete.h${hlevel}`
|
|
415
|
+
hlevel = 6
|
|
416
|
+
buffer.push(`[${blockStyle}#${syntheticId}]`)
|
|
417
|
+
} else {
|
|
418
|
+
buffer.push(`[#${syntheticId}]`)
|
|
420
419
|
}
|
|
420
|
+
buffer.push(`${'='.repeat(hlevel)} ${overviewTitle}`)
|
|
421
421
|
}
|
|
422
422
|
assembled.pages.set(page, pageFragment)
|
|
423
423
|
if (hasSections) fixSectionLevels(doc.getSections(), nextSectionLevel)
|
|
@@ -476,7 +476,7 @@ function mergeAsciiDoc (
|
|
|
476
476
|
if (~ignoreLines.indexOf(idx)) continue
|
|
477
477
|
let line = lines[idx]
|
|
478
478
|
if (line.startsWith('//')) {
|
|
479
|
-
if (line
|
|
479
|
+
if (line.charAt(2) !== '/') continue
|
|
480
480
|
if (line.length > 3 && line === '/'.repeat(line.length)) {
|
|
481
481
|
if (skipping) {
|
|
482
482
|
if (line === skipping) skipping = undefined
|
|
@@ -545,7 +545,7 @@ function mergeAsciiDoc (
|
|
|
545
545
|
if (block.getSectionName() === 'header') return
|
|
546
546
|
let blockStyle = sectionMergeStrategy === 'discrete' ? 'discrete' : undefined
|
|
547
547
|
lines[idx] = lines[idx].replace(/^=+ (.+)/, (_, rest) => {
|
|
548
|
-
let targetMarkerLength = block.level + 1 + level
|
|
548
|
+
let targetMarkerLength = block.level + 1 + level
|
|
549
549
|
if (targetMarkerLength > 6) {
|
|
550
550
|
blockStyle = `discrete.h${targetMarkerLength}`
|
|
551
551
|
targetMarkerLength = 6
|
|
@@ -806,11 +806,20 @@ function safePush (onto, entries) {
|
|
|
806
806
|
}
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
-
function generateIdFromTitle (titleAsciiDoc, idSeparators) {
|
|
809
|
+
function generateIdFromTitle (titleAsciiDoc, idSeparators, idLeader) {
|
|
810
810
|
const Section = this.$class().$const_get('::Asciidoctor::Section')
|
|
811
|
-
const baseId = Section.$generate_id(titleAsciiDoc, this)
|
|
812
|
-
|
|
813
|
-
|
|
811
|
+
const baseId = Section.$generate_id(titleAsciiDoc, this) // refs in catalog will always be empty
|
|
812
|
+
let id = `_${idSeparators.coordinate}${idLeader ?? ''}${baseId}`
|
|
813
|
+
const syntheticIds = (this.catalog.syntheticIds ??= {})
|
|
814
|
+
if (id in syntheticIds) {
|
|
815
|
+
const sep = (this.getAttribute('idseparator') ?? '_').charAt()
|
|
816
|
+
let cnt = this.$class().$const_get('::Asciidoctor::Compliance').unique_id_start_index
|
|
817
|
+
let candidate
|
|
818
|
+
while ((candidate = `${id}${sep}${cnt}`) in syntheticIds) cnt++
|
|
819
|
+
id = candidate
|
|
820
|
+
}
|
|
821
|
+
syntheticIds[id] = true
|
|
822
|
+
return id
|
|
814
823
|
}
|
|
815
824
|
|
|
816
825
|
module.exports = produceAssemblyFile
|
|
@@ -6,6 +6,7 @@ function generateScopedId (componentSrc, componentVersion, separators, filetype,
|
|
|
6
6
|
let { component, module: mod, relative } = componentSrc
|
|
7
7
|
let id = relative.replace(/\.adoc$/, '').replace(/[/.]/g, '-')
|
|
8
8
|
let { coordinate: coordinateSeparator, prefix: prefixSeparator } = separators
|
|
9
|
+
if (mod !== 'ROOT' && ~mod.indexOf('.')) mod = mod.replace(/[.]/g, '-')
|
|
9
10
|
if (component !== componentVersion.name) {
|
|
10
11
|
id = [component, mod === 'ROOT' ? '' : mod, id].join(coordinateSeparator)
|
|
11
12
|
} else if (mod !== 'ROOT') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/assembler",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.5",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"author": "OpenDevise Inc. (https://opendevise.com)",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@asciidoctor/reducer": "~1.1",
|
|
42
42
|
"@antora/expand-path-helper": "~3.0",
|
|
43
43
|
"@antora/run-command-helper": "~1.1",
|
|
44
|
-
"js-yaml": "~
|
|
44
|
+
"js-yaml": "~5.2"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@antora/asciidoc-loader": "3.2.0-rc.2",
|