@antora/assembler 1.0.0-alpha.2 → 1.0.0-alpha.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/load-config.js
CHANGED
|
@@ -27,13 +27,15 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
27
27
|
if (config.enabled === false) return undefined
|
|
28
28
|
let asciidocAttrs
|
|
29
29
|
if (!config.asciidoc) {
|
|
30
|
-
config.asciidoc = { attributes: (asciidocAttrs = {
|
|
30
|
+
config.asciidoc = { attributes: (asciidocAttrs = {}) }
|
|
31
31
|
} else if (!(asciidocAttrs = config.asciidoc.attributes)) {
|
|
32
|
-
config.asciidoc.attributes = asciidocAttrs = {
|
|
32
|
+
config.asciidoc.attributes = asciidocAttrs = {}
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
if (!('doctype' in asciidocAttrs)) asciidocAttrs.doctype = 'book'
|
|
35
|
+
asciidocAttrs.revdate = new Date().toISOString().split('T')[0]
|
|
36
|
+
asciidocAttrs['page-partial'] = null
|
|
35
37
|
if (config.componentVersions == null) {
|
|
36
|
-
config.componentVersions = ['
|
|
38
|
+
config.componentVersions = ['*']
|
|
37
39
|
} else if (typeof config.componentVersions === 'string') {
|
|
38
40
|
config.componentVersions = config.componentVersions.split(', ')
|
|
39
41
|
}
|
|
@@ -105,7 +105,7 @@ function aggregateAsciiDoc (
|
|
|
105
105
|
page = new page.constructor(Object.assign({}, page, { contents, mediaType: 'text/asciidoc' }))
|
|
106
106
|
const { module: module_, relative, origin } = page.src
|
|
107
107
|
const doc = loadAsciiDoc(page, contentCatalog, asciidocConfig)
|
|
108
|
-
const
|
|
108
|
+
const refs = doc.getCatalog().refs
|
|
109
109
|
// NOTE: in Antora, docname is relative src path from module without file extension
|
|
110
110
|
const docname = doc.getAttribute('docname')
|
|
111
111
|
//const idprefix = `${module_ === 'ROOT' ? '' : module_ + ':'}${docname}//`
|
|
@@ -166,27 +166,19 @@ function aggregateAsciiDoc (
|
|
|
166
166
|
buffer.push(`${'='.repeat(hlevel)} ${overviewTitle}`)
|
|
167
167
|
if (toggleSectids) buffer.push(':sectids:')
|
|
168
168
|
}
|
|
169
|
-
const siteUrl =
|
|
169
|
+
const siteUrl = ((val) => {
|
|
170
|
+
if (!val || val === '/') return ''
|
|
171
|
+
return val.charAt(val.length - 1) === '/' ? val.substr(0, val.length - 1) : val
|
|
172
|
+
})(doc.getAttribute('site-url'))
|
|
170
173
|
const lines = doc.getSourceLines()
|
|
171
174
|
const ignoreLines = []
|
|
172
175
|
// TODO: think more about when multipart is allowed; perhaps configurable
|
|
173
176
|
if (doc.hasSections()) fixSectionLevels(doc.getSections(), level === 0)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (block.getContext() === 'table') {
|
|
180
|
-
const rows = block.rows
|
|
181
|
-
;[...rows.body, ...rows.foot].forEach((row) => {
|
|
182
|
-
row.forEach((cell) => {
|
|
183
|
-
if (cell.style !== 'asciidoc') return
|
|
184
|
-
accum.push(...cell.inner_document.findBy((it) => it.getContext() !== 'document'))
|
|
185
|
-
})
|
|
186
|
-
})
|
|
187
|
-
}
|
|
188
|
-
return accum
|
|
189
|
-
}, [])
|
|
177
|
+
const allBlocks = doc.findBy({ traverse_documents: true }, (it) =>
|
|
178
|
+
it.getContext() === 'document'
|
|
179
|
+
? it.getDocument().isNested()
|
|
180
|
+
: !(it.getContext() === 'table_cell' && it.getStyle() === 'asciidoc')
|
|
181
|
+
)
|
|
190
182
|
allBlocks.forEach((block) => {
|
|
191
183
|
const contentModel = block.content_model
|
|
192
184
|
if (
|
|
@@ -218,11 +210,9 @@ function aggregateAsciiDoc (
|
|
|
218
210
|
let line = lines[idx]
|
|
219
211
|
if (~line.indexOf('<<')) {
|
|
220
212
|
line = line.replace(/(?<![\\+])<<#?([\p{Alpha}0-9_/.:{][^>,]*?)(?:|, *([^>]+?))?>>/gu, (m, refid, text) => {
|
|
221
|
-
// support natural xref
|
|
222
|
-
if (!
|
|
223
|
-
if (
|
|
224
|
-
return m
|
|
225
|
-
}
|
|
213
|
+
// support natural xref
|
|
214
|
+
if (!refs['$key?'](refid) && (~refid.indexOf(' ') || refid.toLowerCase() !== refid)) {
|
|
215
|
+
if ((refid = doc.$resolve_id(refid))['$nil?']()) return m
|
|
226
216
|
}
|
|
227
217
|
return `<<${idprefix}${refid}${text ? ',' + text : ''}>>`
|
|
228
218
|
})
|
|
@@ -233,21 +223,26 @@ function aggregateAsciiDoc (
|
|
|
233
223
|
}
|
|
234
224
|
if (~line.indexOf('xref:')) {
|
|
235
225
|
// Q: should we allow : as first character of target?
|
|
236
|
-
line = line.replace(/xref:([\p{Alpha}
|
|
226
|
+
line = line.replace(/xref:([\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
|
|
237
227
|
let pagePart, fragment, targetPage
|
|
238
228
|
const hashIdx = target.indexOf('#')
|
|
239
229
|
if (~hashIdx) {
|
|
240
230
|
pagePart = target.substr(0, hashIdx)
|
|
241
231
|
fragment = target.substr(hashIdx + 1)
|
|
242
232
|
// TODO: for now, assume .adoc; in the future, consider other file extensions
|
|
243
|
-
if (
|
|
233
|
+
if (pagePart && !pagePart.endsWith('.adoc')) pagePart += '.adoc'
|
|
244
234
|
} else if (target.endsWith('.adoc')) {
|
|
245
235
|
pagePart = target
|
|
246
236
|
fragment = ''
|
|
247
237
|
} else {
|
|
248
238
|
fragment = target
|
|
249
239
|
}
|
|
250
|
-
if (!pagePart)
|
|
240
|
+
if (!pagePart) {
|
|
241
|
+
// Q: should we validate the internal ID here?
|
|
242
|
+
return text && ~text.indexOf('=')
|
|
243
|
+
? `xref:${idprefix}${fragment}[${text}]`
|
|
244
|
+
: `<<${idprefix}${fragment}${text ? ',' + text.replace(/\\]/g, ']') : ''}>>`
|
|
245
|
+
}
|
|
251
246
|
if (~pagePart.indexOf('@') || /:.*:/.test(pagePart)) {
|
|
252
247
|
// TODO: handle unresolved page better
|
|
253
248
|
return siteUrl && (targetPage = contentCatalog.resolvePage(pagePart, page.src))
|
|
@@ -301,13 +296,14 @@ function aggregateAsciiDoc (
|
|
|
301
296
|
// NOTE: need to do this last since it modifies the line numbers
|
|
302
297
|
// we could remap the line numbers to make them resilient
|
|
303
298
|
// or we could mark which lines to remove and filter them after
|
|
299
|
+
let lastImageMacroAt
|
|
304
300
|
;[...allBlocks].reverse().forEach((block) => {
|
|
305
301
|
const lineno = block.getLineNumber()
|
|
306
302
|
// NOTE: lineno is not defined for preamble
|
|
307
303
|
if (typeof lineno !== 'number') return
|
|
308
304
|
const context = block.getContext()
|
|
309
|
-
|
|
310
|
-
if (context === 'section') {
|
|
305
|
+
let idx = lineno - 1
|
|
306
|
+
if (context === 'section' && !block.getDocument().isNested()) {
|
|
311
307
|
if (block.getSectionName() === 'header') {
|
|
312
308
|
lines.splice(idx, 1)
|
|
313
309
|
return
|
|
@@ -327,34 +323,37 @@ function aggregateAsciiDoc (
|
|
|
327
323
|
if (block.getId()) rewriteStyleAttribute(block, lines, idx, idprefix, blockStyle)
|
|
328
324
|
} else {
|
|
329
325
|
if (context === 'image') {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
//
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
lines[idx] = `image::${image.pub.url.substr(1)}${line.substr(line.indexOf('['))}`
|
|
326
|
+
let line = lines[idx] || ''
|
|
327
|
+
let prefix = ''
|
|
328
|
+
// Q: can we use startsWith('image::') in certain cases?
|
|
329
|
+
let imageMacroOffset = (
|
|
330
|
+
lastImageMacroAt && lastImageMacroAt[0] === idx ? line.substr(0, lastImageMacroAt[1]) : line
|
|
331
|
+
).lastIndexOf('image::')
|
|
332
|
+
if (imageMacroOffset > 0) {
|
|
333
|
+
if (
|
|
334
|
+
block.getDocument().isNested() &&
|
|
335
|
+
(prefix = line.substr(0, imageMacroOffset)).trimRight().endsWith('|')
|
|
336
|
+
) {
|
|
337
|
+
line = line.substr(prefix.length)
|
|
338
|
+
} else {
|
|
339
|
+
imageMacroOffset = -1
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (imageMacroOffset >= 0) {
|
|
343
|
+
const target = block.getAttribute('target')
|
|
344
|
+
if (isResourceSpec(target)) {
|
|
345
|
+
const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
|
|
346
|
+
// FIXME: handle (or report) case when image is not resolved
|
|
347
|
+
if (image) {
|
|
348
|
+
lines[idx] = `${prefix}image::${image.pub.url.substr(1)}${line.substr(line.indexOf('['))}`
|
|
349
|
+
image.out.assembled = true
|
|
350
|
+
}
|
|
356
351
|
}
|
|
352
|
+
lastImageMacroAt = [idx, imageMacroOffset]
|
|
357
353
|
}
|
|
354
|
+
} else if (context === 'document' && block.hasHeader()) {
|
|
355
|
+
// nested document
|
|
356
|
+
idx = (block.getHeader().getLineNumber() || idx + 1) - 1
|
|
358
357
|
}
|
|
359
358
|
if (block.getId()) rewriteStyleAttribute(block, lines, idx, idprefix)
|
|
360
359
|
}
|
|
@@ -372,7 +371,7 @@ function aggregateAsciiDoc (
|
|
|
372
371
|
} else if (val !== initialVal) {
|
|
373
372
|
accum.push(`:${name}:${initialVal ? ' ' + initialVal : ''}`)
|
|
374
373
|
}
|
|
375
|
-
} else if (val != null && !doc.isAttributeLocked(name)) {
|
|
374
|
+
} else if (val != null && !(doc.isAttributeLocked(name) || name === 'doctype')) {
|
|
376
375
|
accum.push(`:!${name}:`)
|
|
377
376
|
}
|
|
378
377
|
return accum
|
|
@@ -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,7 +32,8 @@ 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,
|
|
@@ -44,6 +47,11 @@ function produceAggregateDocuments (loadAsciiDoc, contentCatalog, assemblerConfi
|
|
|
44
47
|
)
|
|
45
48
|
)
|
|
46
49
|
)
|
|
50
|
+
mergedAsciiDocConfig.attributes.doctype = doctype
|
|
51
|
+
sourceHighlighter
|
|
52
|
+
? (mergedAsciiDocConfig.attributes['source-highlighter'] = sourceHighlighter)
|
|
53
|
+
: delete mergedAsciiDocConfig.attributes['source-highlighter']
|
|
54
|
+
return accum
|
|
47
55
|
},
|
|
48
56
|
[]
|
|
49
57
|
)
|
|
@@ -6,9 +6,8 @@ const { PassThrough } = require('stream')
|
|
|
6
6
|
class LazyReadable extends PassThrough {
|
|
7
7
|
constructor (fn, options) {
|
|
8
8
|
super(options)
|
|
9
|
-
const _read = this._read
|
|
10
9
|
this._read = function () {
|
|
11
|
-
this._read
|
|
10
|
+
delete this._read // restores original method
|
|
12
11
|
fn.call(this, options).on('error', this.emit.bind(this, 'error')).pipe(this)
|
|
13
12
|
return this._read.apply(this, arguments)
|
|
14
13
|
}
|
package/lib/util/run-command.js
CHANGED
|
@@ -43,11 +43,15 @@ async function runCommand (cmd, argv = [], opts = {}) {
|
|
|
43
43
|
ps.on('error', (err) => reject(err.code === 'ENOENT' ? new Error(`Command not found: ${cmdv.join(' ')}`) : err))
|
|
44
44
|
ps.stdout.on('data', (data) => (output ? process.stdout.write(data) : stdout.push(data)))
|
|
45
45
|
ps.stderr.on('data', (data) => stderr.push(data))
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (input instanceof Buffer) {
|
|
47
|
+
try {
|
|
48
|
+
ps.stdin.on('error', () => undefined)
|
|
49
|
+
ps.stdin.end(input)
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (!ps.stdin.writableEnded) ps.stdin.end()
|
|
52
|
+
reject(err)
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
51
55
|
ps.stdin.end()
|
|
52
56
|
}
|
|
53
57
|
})
|
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.5",
|
|
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,6 +25,7 @@
|
|
|
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": {
|