@antora/assembler 1.0.0-alpha.4 → 1.0.0-alpha.6
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.
|
@@ -121,6 +121,7 @@ const IncludeDirectiveTracker = (() => {
|
|
|
121
121
|
this.$$reducer.includePushed = true
|
|
122
122
|
const directiveLineno = this.lineno - 1 // we're below the include line, which is 1-based
|
|
123
123
|
const prevIncDepth = this.include_stack.length
|
|
124
|
+
let offset = lineno > 1 ? lineno - 1 : 0
|
|
124
125
|
const result = Opal.send(this, Opal.find_super_dispatcher(this, 'push_include', pushInclude), [
|
|
125
126
|
data,
|
|
126
127
|
file,
|
|
@@ -128,12 +129,12 @@ const IncludeDirectiveTracker = (() => {
|
|
|
128
129
|
lineno,
|
|
129
130
|
attrs,
|
|
130
131
|
])
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
132
|
+
let incLines = []
|
|
133
|
+
if (this.include_stack.length > prevIncDepth) {
|
|
134
|
+
incLines = this.$lines()
|
|
135
|
+
if (attrs['$key?']('leveloffset') && incLines[0].startsWith(':leveloffset: ') && incLines[1] === '') offset -= 2
|
|
136
|
+
}
|
|
137
|
+
pushIncludeReplacement.call(this, directiveLineno, incLines, offset)
|
|
137
138
|
return result
|
|
138
139
|
})
|
|
139
140
|
|
|
@@ -174,8 +175,12 @@ function treeProcessor () {
|
|
|
174
175
|
let targetLines, idx
|
|
175
176
|
if (into != null) {
|
|
176
177
|
targetLines = incReplacements[into].lines
|
|
177
|
-
// adds assurance that
|
|
178
|
-
if (targetLines[(idx = lineno - 1)] !== line)
|
|
178
|
+
// adds extra assurance that the program is replacing the correct line
|
|
179
|
+
if (targetLines[(idx = lineno - 1)] !== line) {
|
|
180
|
+
const msg = `include directive to reduce not found; expected: "${line}"; got: "${targetLines[idx]}"`
|
|
181
|
+
doc.getLogger().error(msg)
|
|
182
|
+
return
|
|
183
|
+
}
|
|
179
184
|
}
|
|
180
185
|
if ((drop || []).length) {
|
|
181
186
|
drop
|
package/lib/load-config.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const camelCaseKeys = require('camelcase-keys')
|
|
4
3
|
const expandPath = require('@antora/expand-path-helper')
|
|
5
4
|
const { promises: fsp } = require('fs')
|
|
6
5
|
const os = require('os')
|
|
7
6
|
const yaml = require('js-yaml')
|
|
8
7
|
|
|
9
|
-
const CAMEL_CASE_KEYS_OPTS = { deep: true, stopPaths: ['asciidoc'] }
|
|
10
|
-
|
|
11
8
|
function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
12
9
|
return (
|
|
13
10
|
configSource.constructor === Object
|
|
@@ -19,21 +16,21 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
19
16
|
() => false
|
|
20
17
|
)
|
|
21
18
|
.then((exists) =>
|
|
22
|
-
exists
|
|
23
|
-
? fsp.readFile(configSource).then((data) => camelCaseKeys(yaml.load(data), CAMEL_CASE_KEYS_OPTS))
|
|
24
|
-
: {}
|
|
19
|
+
exists ? fsp.readFile(configSource).then((data) => camelCaseKeys(yaml.load(data), ['asciidoc'])) : {}
|
|
25
20
|
)
|
|
26
21
|
).then((config) => {
|
|
27
22
|
if (config.enabled === false) return undefined
|
|
28
23
|
let asciidocAttrs
|
|
29
24
|
if (!config.asciidoc) {
|
|
30
|
-
config.asciidoc = { attributes: (asciidocAttrs = {
|
|
25
|
+
config.asciidoc = { attributes: (asciidocAttrs = {}) }
|
|
31
26
|
} else if (!(asciidocAttrs = config.asciidoc.attributes)) {
|
|
32
|
-
config.asciidoc.attributes = asciidocAttrs = {
|
|
27
|
+
config.asciidoc.attributes = asciidocAttrs = {}
|
|
33
28
|
}
|
|
34
|
-
|
|
29
|
+
if (!('doctype' in asciidocAttrs)) asciidocAttrs.doctype = 'book'
|
|
30
|
+
asciidocAttrs.revdate = new Date().toISOString().split('T')[0]
|
|
31
|
+
asciidocAttrs['page-partial'] = null
|
|
35
32
|
if (config.componentVersions == null) {
|
|
36
|
-
config.componentVersions = ['
|
|
33
|
+
config.componentVersions = ['*']
|
|
37
34
|
} else if (typeof config.componentVersions === 'string') {
|
|
38
35
|
config.componentVersions = config.componentVersions.split(', ')
|
|
39
36
|
}
|
|
@@ -59,4 +56,16 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
59
56
|
})
|
|
60
57
|
}
|
|
61
58
|
|
|
59
|
+
function camelCaseKeys (o, stopPaths = [], p) {
|
|
60
|
+
if (Array.isArray(o)) return o.map((it) => camelCaseKeys(it, stopPaths, p))
|
|
61
|
+
if (o == null || o.constructor !== Object) return o
|
|
62
|
+
const pathPrefix = p ? p + '.' : ''
|
|
63
|
+
const accum = {}
|
|
64
|
+
for (const [k, v] of Object.entries(o)) {
|
|
65
|
+
const camelKey = k.charAt() + k.substr(1).replace(/_([a-z])/g, (_, l) => l.toUpperCase())
|
|
66
|
+
accum[camelKey] = ~stopPaths.indexOf(pathPrefix + camelKey) ? v : camelCaseKeys(v, stopPaths, pathPrefix + camelKey)
|
|
67
|
+
}
|
|
68
|
+
return accum
|
|
69
|
+
}
|
|
70
|
+
|
|
62
71
|
module.exports = loadConfig
|
|
@@ -8,6 +8,7 @@ function produceAggregateDocument (
|
|
|
8
8
|
contentCatalog,
|
|
9
9
|
componentVersion,
|
|
10
10
|
outline,
|
|
11
|
+
doctype,
|
|
11
12
|
pages,
|
|
12
13
|
asciidocConfig,
|
|
13
14
|
mutableAttributes,
|
|
@@ -16,7 +17,7 @@ function produceAggregateDocument (
|
|
|
16
17
|
const pagesInOutline = selectPagesInOutline(outline, pages)
|
|
17
18
|
const navtitle = outline.content
|
|
18
19
|
const stem = generateStem(componentVersion, navtitle)
|
|
19
|
-
const header = buildAsciiDocHeader(componentVersion, navtitle)
|
|
20
|
+
const header = buildAsciiDocHeader(componentVersion, navtitle, doctype)
|
|
20
21
|
const body = aggregateAsciiDoc(
|
|
21
22
|
loadAsciiDoc,
|
|
22
23
|
contentCatalog,
|
|
@@ -44,13 +45,13 @@ function produceAggregateDocument (
|
|
|
44
45
|
})
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
function buildAsciiDocHeader (componentVersion, navtitle) {
|
|
48
|
+
function buildAsciiDocHeader (componentVersion, navtitle, doctype = 'book') {
|
|
48
49
|
const doctitle = navtitle === componentVersion.title ? navtitle : `${componentVersion.title}: ${navtitle}`
|
|
49
|
-
const version = componentVersion.version
|
|
50
|
+
const version = componentVersion.version === 'master' ? '' : componentVersion.version
|
|
50
51
|
return [
|
|
51
52
|
`= ${doctitle}`,
|
|
52
53
|
...(version ? [`v${version}`] : []),
|
|
53
|
-
|
|
54
|
+
...(doctype === 'article' ? [] : [`:doctype: ${doctype}`]),
|
|
54
55
|
// Q: should we pass these via the CLI so they cannot be modified?
|
|
55
56
|
`:page-component-name: ${componentVersion.name}`,
|
|
56
57
|
`:page-component-version:${version ? ' ' + version : ''}`,
|
|
@@ -166,14 +167,18 @@ function aggregateAsciiDoc (
|
|
|
166
167
|
buffer.push(`${'='.repeat(hlevel)} ${overviewTitle}`)
|
|
167
168
|
if (toggleSectids) buffer.push(':sectids:')
|
|
168
169
|
}
|
|
169
|
-
const siteUrl =
|
|
170
|
+
const siteUrl = ((val) => {
|
|
171
|
+
if (!val || val === '/') return ''
|
|
172
|
+
return val.charAt(val.length - 1) === '/' ? val.substr(0, val.length - 1) : val
|
|
173
|
+
})(doc.getAttribute('site-url'))
|
|
170
174
|
const lines = doc.getSourceLines()
|
|
171
175
|
const ignoreLines = []
|
|
172
176
|
// TODO: think more about when multipart is allowed; perhaps configurable
|
|
173
177
|
if (doc.hasSections()) fixSectionLevels(doc.getSections(), level === 0)
|
|
174
|
-
const allBlocks = doc.findBy(
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
const allBlocks = doc.findBy({ traverse_documents: true }, (it) =>
|
|
179
|
+
it.getContext() === 'document'
|
|
180
|
+
? it.getDocument().isNested()
|
|
181
|
+
: !(it.getContext() === 'table_cell' && it.getStyle() === 'asciidoc')
|
|
177
182
|
)
|
|
178
183
|
allBlocks.forEach((block) => {
|
|
179
184
|
const contentModel = block.content_model
|
|
@@ -204,6 +209,11 @@ function aggregateAsciiDoc (
|
|
|
204
209
|
for (let idx = 0, len = lines.length; idx < len; idx++) {
|
|
205
210
|
if (~ignoreLines.indexOf(idx)) continue
|
|
206
211
|
let line = lines[idx]
|
|
212
|
+
if (line.charAt() === ':' && /^:(?:leveloffset: .*|!leveloffset:|leveloffset!:)$/.test(line)) {
|
|
213
|
+
if (lines[idx - 1] === '') lines[idx - 1] = undefined
|
|
214
|
+
lines[idx] = undefined
|
|
215
|
+
continue
|
|
216
|
+
}
|
|
207
217
|
if (~line.indexOf('<<')) {
|
|
208
218
|
line = line.replace(/(?<![\\+])<<#?([\p{Alpha}0-9_/.:{][^>,]*?)(?:|, *([^>]+?))?>>/gu, (m, refid, text) => {
|
|
209
219
|
// support natural xref
|
|
@@ -219,7 +229,7 @@ function aggregateAsciiDoc (
|
|
|
219
229
|
}
|
|
220
230
|
if (~line.indexOf('xref:')) {
|
|
221
231
|
// Q: should we allow : as first character of target?
|
|
222
|
-
line = line.replace(/xref:([\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
|
|
232
|
+
line = line.replace(/(?<![\\+])xref:([\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
|
|
223
233
|
let pagePart, fragment, targetPage
|
|
224
234
|
const hashIdx = target.indexOf('#')
|
|
225
235
|
if (~hashIdx) {
|
|
@@ -298,22 +308,20 @@ function aggregateAsciiDoc (
|
|
|
298
308
|
// NOTE: lineno is not defined for preamble
|
|
299
309
|
if (typeof lineno !== 'number') return
|
|
300
310
|
const context = block.getContext()
|
|
301
|
-
|
|
302
|
-
if (context === 'section') {
|
|
311
|
+
let idx = lineno - 1
|
|
312
|
+
if (context === 'section' && !block.getDocument().isNested()) {
|
|
303
313
|
if (block.getSectionName() === 'header') {
|
|
304
|
-
lines
|
|
314
|
+
lines[idx] = undefined
|
|
305
315
|
return
|
|
306
316
|
}
|
|
307
317
|
let blockStyle = sectionMergeStrategy === 'discrete' ? 'discrete' : undefined
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
lines[idx] = lines[idx].replace(/^=+( .+)/, (_, rest) => {
|
|
311
|
-
let targetMarkerLength = block.level + (1 - leveloffset) + level + (enclosed ? 1 : 0)
|
|
318
|
+
lines[idx] = lines[idx].replace(/^=+ (.+)/, (_, rest) => {
|
|
319
|
+
let targetMarkerLength = block.level + 1 + level + (enclosed ? 1 : 0)
|
|
312
320
|
if (targetMarkerLength > 6) {
|
|
313
321
|
targetMarkerLength = 6
|
|
314
322
|
blockStyle = 'discrete'
|
|
315
323
|
}
|
|
316
|
-
return '='.repeat(targetMarkerLength) + rest
|
|
324
|
+
return '='.repeat(targetMarkerLength) + ' ' + rest
|
|
317
325
|
})
|
|
318
326
|
// NOTE: ID will be undefined if sectids are turned off
|
|
319
327
|
if (block.getId()) rewriteStyleAttribute(block, lines, idx, idprefix, blockStyle)
|
|
@@ -323,7 +331,7 @@ function aggregateAsciiDoc (
|
|
|
323
331
|
let prefix = ''
|
|
324
332
|
// Q: can we use startsWith('image::') in certain cases?
|
|
325
333
|
let imageMacroOffset = (
|
|
326
|
-
lastImageMacroAt
|
|
334
|
+
lastImageMacroAt?.[0] === idx ? line.substr(0, lastImageMacroAt[1]) : line
|
|
327
335
|
).lastIndexOf('image::')
|
|
328
336
|
if (imageMacroOffset > 0) {
|
|
329
337
|
if (
|
|
@@ -347,11 +355,14 @@ function aggregateAsciiDoc (
|
|
|
347
355
|
}
|
|
348
356
|
lastImageMacroAt = [idx, imageMacroOffset]
|
|
349
357
|
}
|
|
358
|
+
} else if (context === 'document' && block.hasHeader()) {
|
|
359
|
+
// nested document
|
|
360
|
+
idx = (block.getHeader().getLineNumber() || idx + 1) - 1
|
|
350
361
|
}
|
|
351
362
|
if (block.getId()) rewriteStyleAttribute(block, lines, idx, idprefix)
|
|
352
363
|
}
|
|
353
364
|
})
|
|
354
|
-
buffer.push(...lines)
|
|
365
|
+
buffer.push(...lines.filter((it) => it !== undefined))
|
|
355
366
|
const attributeEntries = Object.entries(doc.attributes_defined_in_header || {})
|
|
356
367
|
if (attributeEntries.length) {
|
|
357
368
|
const resolvedAttributeEntries = attributeEntries.reduce(
|
|
@@ -364,7 +375,7 @@ function aggregateAsciiDoc (
|
|
|
364
375
|
} else if (val !== initialVal) {
|
|
365
376
|
accum.push(`:${name}:${initialVal ? ' ' + initialVal : ''}`)
|
|
366
377
|
}
|
|
367
|
-
} else if (val != null && !doc.isAttributeLocked(name)) {
|
|
378
|
+
} else if (val != null && !(doc.isAttributeLocked(name) || name === 'doctype' || name === 'leveloffset')) {
|
|
368
379
|
accum.push(`:!${name}:`)
|
|
369
380
|
}
|
|
370
381
|
return accum
|
|
@@ -431,7 +442,8 @@ function aggregateAsciiDoc (
|
|
|
431
442
|
|
|
432
443
|
function generateStem (componentVersion, title) {
|
|
433
444
|
const { name, version } = componentVersion
|
|
434
|
-
const segments = [
|
|
445
|
+
const segments = []
|
|
446
|
+
if (name !== 'ROOT') segments.push(name)
|
|
435
447
|
if (version && version !== 'master') segments.push(version)
|
|
436
448
|
segments.push(
|
|
437
449
|
title
|
|
@@ -7,7 +7,9 @@ const selectMutableAttributes = require('./select-mutable-attributes')
|
|
|
7
7
|
function produceAggregateDocuments (loadAsciiDoc, contentCatalog, assemblerConfig) {
|
|
8
8
|
const { insertStartPage, rootLevel, sectionMergeStrategy, asciidoc: assemblerAsciiDocConfig } = assemblerConfig
|
|
9
9
|
const assemblerAsciiDocAttributes = Object.assign({}, assemblerAsciiDocConfig.attributes)
|
|
10
|
-
|
|
10
|
+
const { doctype, 'source-highlighter': sourceHighlighter } = assemblerAsciiDocAttributes
|
|
11
|
+
delete assemblerAsciiDocAttributes.doctype
|
|
12
|
+
delete assemblerAsciiDocAttributes['source-highlighter']
|
|
11
13
|
return filterComponentVersions(contentCatalog.getComponents(), assemblerConfig.componentVersions).reduce(
|
|
12
14
|
(accum, componentVersion) => {
|
|
13
15
|
const { name: componentName, version, title, navigation } = componentVersion
|
|
@@ -30,13 +32,15 @@ function produceAggregateDocuments (loadAsciiDoc, contentCatalog, assemblerConfi
|
|
|
30
32
|
const mutableAttributes = startPage
|
|
31
33
|
? selectMutableAttributes(loadAsciiDoc, contentCatalog, startPage, mergedAsciiDocConfig)
|
|
32
34
|
: {}
|
|
33
|
-
|
|
35
|
+
delete mutableAttributes.doctype
|
|
36
|
+
accum = accum.concat(
|
|
34
37
|
prepareOutlines(navigation, rootEntry, rootLevel).map((outline) =>
|
|
35
38
|
produceAggregateDocument(
|
|
36
39
|
loadAsciiDoc,
|
|
37
40
|
contentCatalog,
|
|
38
41
|
componentVersion,
|
|
39
42
|
outline,
|
|
43
|
+
doctype,
|
|
40
44
|
contentCatalog.getPages((page) => page.out),
|
|
41
45
|
mergedAsciiDocConfig,
|
|
42
46
|
mutableAttributes,
|
|
@@ -44,6 +48,11 @@ function produceAggregateDocuments (loadAsciiDoc, contentCatalog, assemblerConfi
|
|
|
44
48
|
)
|
|
45
49
|
)
|
|
46
50
|
)
|
|
51
|
+
mergedAsciiDocConfig.attributes.doctype = doctype
|
|
52
|
+
sourceHighlighter
|
|
53
|
+
? (mergedAsciiDocConfig.attributes['source-highlighter'] = sourceHighlighter)
|
|
54
|
+
: delete mergedAsciiDocConfig.attributes['source-highlighter']
|
|
55
|
+
return accum
|
|
47
56
|
},
|
|
48
57
|
[]
|
|
49
58
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/assembler",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.6",
|
|
4
4
|
"description": "An extension library for Antora that assembles content from multiple pages into a single AsciiDoc file to converted and publish.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"author": "OpenDevise Inc. (https://opendevise.com)",
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
"./filter-component-versions": "./lib/filter-component-versions.js",
|
|
26
26
|
"./load-config": "./lib/load-config.js",
|
|
27
27
|
"./produce-aggregate-document": "./lib/produce-aggregate-document.js",
|
|
28
|
+
"./produce-aggregate-documents": "./lib/produce-aggregate-documents.js",
|
|
28
29
|
"./select-mutable-attributes": "./lib/select-mutable-attributes.js"
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
31
32
|
"@antora/expand-path-helper": "~2.0",
|
|
32
33
|
"braces": "~3.0",
|
|
33
|
-
"camelcase-keys": "~7.0",
|
|
34
34
|
"picomatch": "~2.3",
|
|
35
35
|
"vinyl": "~2.2",
|
|
36
36
|
"js-yaml": "~4.1"
|