@antora/assembler 1.0.0-alpha.1 → 1.0.0-alpha.4

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.
@@ -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 ids = doc.getCatalog().ids
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}//`
@@ -171,22 +171,10 @@ function aggregateAsciiDoc (
171
171
  const ignoreLines = []
172
172
  // TODO: think more about when multipart is allowed; perhaps configurable
173
173
  if (doc.hasSections()) fixSectionLevels(doc.getSections(), level === 0)
174
- // TODO: update / simplify findBy calls when upgrading to Asciidoctor 2
175
- const allBlocks = doc
176
- .findBy((it) => it.getContext() !== 'document')
177
- .reduce((accum, block) => {
178
- accum.push(block)
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
- }, [])
174
+ const allBlocks = doc.findBy(
175
+ { traverse_documents: true },
176
+ (it) => it.getContext() !== 'document' && !(it.getContext() === 'table_cell' && it.getStyle() === 'asciidoc')
177
+ )
190
178
  allBlocks.forEach((block) => {
191
179
  const contentModel = block.content_model
192
180
  if (
@@ -218,11 +206,9 @@ function aggregateAsciiDoc (
218
206
  let line = lines[idx]
219
207
  if (~line.indexOf('<<')) {
220
208
  line = line.replace(/(?<![\\+])<<#?([\p{Alpha}0-9_/.:{][^>,]*?)(?:|, *([^>]+?))?>>/gu, (m, refid, text) => {
221
- // support natural xref; note this logic will change when upgrading to Asciidoctor 2
222
- if (!ids['$key?'](refid) && (~refid.indexOf(' ') || refid.toLowerCase() !== refid)) {
223
- if (!(refid = doc.getCatalog().ids.$key(refid).$to_s())) {
224
- return m
225
- }
209
+ // support natural xref
210
+ if (!refs['$key?'](refid) && (~refid.indexOf(' ') || refid.toLowerCase() !== refid)) {
211
+ if ((refid = doc.$resolve_id(refid))['$nil?']()) return m
226
212
  }
227
213
  return `<<${idprefix}${refid}${text ? ',' + text : ''}>>`
228
214
  })
@@ -233,21 +219,26 @@ function aggregateAsciiDoc (
233
219
  }
234
220
  if (~line.indexOf('xref:')) {
235
221
  // Q: should we allow : as first character of target?
236
- line = line.replace(/xref:([\p{Alpha}#/.{].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
222
+ line = line.replace(/xref:([\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
237
223
  let pagePart, fragment, targetPage
238
224
  const hashIdx = target.indexOf('#')
239
225
  if (~hashIdx) {
240
226
  pagePart = target.substr(0, hashIdx)
241
227
  fragment = target.substr(hashIdx + 1)
242
228
  // TODO: for now, assume .adoc; in the future, consider other file extensions
243
- if (!(pagePart && pagePart.endsWith('.adoc'))) pagePart += '.adoc'
229
+ if (pagePart && !pagePart.endsWith('.adoc')) pagePart += '.adoc'
244
230
  } else if (target.endsWith('.adoc')) {
245
231
  pagePart = target
246
232
  fragment = ''
247
233
  } else {
248
234
  fragment = target
249
235
  }
250
- if (!pagePart) return `<<${idprefix}${fragment}${text ? ',' + text.replace(/\\]/g, ']') : ''}>>`
236
+ if (!pagePart) {
237
+ // Q: should we validate the internal ID here?
238
+ return text && ~text.indexOf('=')
239
+ ? `xref:${idprefix}${fragment}[${text}]`
240
+ : `<<${idprefix}${fragment}${text ? ',' + text.replace(/\\]/g, ']') : ''}>>`
241
+ }
251
242
  if (~pagePart.indexOf('@') || /:.*:/.test(pagePart)) {
252
243
  // TODO: handle unresolved page better
253
244
  return siteUrl && (targetPage = contentCatalog.resolvePage(pagePart, page.src))
@@ -301,6 +292,7 @@ function aggregateAsciiDoc (
301
292
  // NOTE: need to do this last since it modifies the line numbers
302
293
  // we could remap the line numbers to make them resilient
303
294
  // or we could mark which lines to remove and filter them after
295
+ let lastImageMacroAt
304
296
  ;[...allBlocks].reverse().forEach((block) => {
305
297
  const lineno = block.getLineNumber()
306
298
  // NOTE: lineno is not defined for preamble
@@ -327,33 +319,33 @@ function aggregateAsciiDoc (
327
319
  if (block.getId()) rewriteStyleAttribute(block, lines, idx, idprefix, blockStyle)
328
320
  } else {
329
321
  if (context === 'image') {
330
- const atImageMacro = (lines[idx] || '').startsWith('image::')
331
- // NOTE: the following logic is needed only if parser is messing up line number of image block
332
- //let atImageMacro
333
- //// NOTE: account for line number tracking error in parser when image has block anchor
334
- //if (block.getId()) {
335
- // const originalIdx = idx
336
- // let line
337
- // while ((line = lines[idx]) != null && !(atImageMacro = line.startsWith('image::'))) idx++
338
- // if (!atImageMacro) {
339
- // idx = originalIdx
340
- // if ((lines[idx - 1] || '').startsWith('image::')) {
341
- // atImageMacro = true
342
- // idx--
343
- // }
344
- // }
345
- //} else if ((lines[idx] || '').startsWith('image::')) {
346
- // atImageMacro = true
347
- //}
348
- const target = block.getAttribute('target')
349
- if (atImageMacro && isResourceSpec(target)) {
350
- const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
351
- // FIXME: handle (or report) case when image is not resolved
352
- if (image) {
353
- image.out.assembled = true
354
- const line = lines[idx]
355
- lines[idx] = `image::${image.pub.url.substr(1)}${line.substr(line.indexOf('['))}`
322
+ let line = lines[idx] || ''
323
+ let prefix = ''
324
+ // Q: can we use startsWith('image::') in certain cases?
325
+ let imageMacroOffset = (
326
+ lastImageMacroAt && lastImageMacroAt[0] === idx ? line.substr(0, lastImageMacroAt[1]) : line
327
+ ).lastIndexOf('image::')
328
+ if (imageMacroOffset > 0) {
329
+ if (
330
+ block.getDocument().isNested() &&
331
+ (prefix = line.substr(0, imageMacroOffset)).trimRight().endsWith('|')
332
+ ) {
333
+ line = line.substr(prefix.length)
334
+ } else {
335
+ imageMacroOffset = -1
336
+ }
337
+ }
338
+ if (imageMacroOffset >= 0) {
339
+ const target = block.getAttribute('target')
340
+ if (isResourceSpec(target)) {
341
+ const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
342
+ // FIXME: handle (or report) case when image is not resolved
343
+ if (image) {
344
+ lines[idx] = `${prefix}image::${image.pub.url.substr(1)}${line.substr(line.indexOf('['))}`
345
+ image.out.assembled = true
346
+ }
356
347
  }
348
+ lastImageMacroAt = [idx, imageMacroOffset]
357
349
  }
358
350
  }
359
351
  if (block.getId()) rewriteStyleAttribute(block, lines, idx, idprefix)
@@ -6,13 +6,15 @@ const selectMutableAttributes = require('./select-mutable-attributes')
6
6
 
7
7
  function produceAggregateDocuments (loadAsciiDoc, contentCatalog, assemblerConfig) {
8
8
  const { insertStartPage, rootLevel, sectionMergeStrategy, asciidoc: assemblerAsciiDocConfig } = assemblerConfig
9
+ const assemblerAsciiDocAttributes = Object.assign({}, assemblerAsciiDocConfig.attributes)
10
+ delete assemblerAsciiDocAttributes['source-highlighter'] // only used at convert time
9
11
  return filterComponentVersions(contentCatalog.getComponents(), assemblerConfig.componentVersions).reduce(
10
12
  (accum, componentVersion) => {
11
13
  const { name: componentName, version, title, navigation } = componentVersion
12
14
  if (!navigation) return accum
13
15
  const componentVersionAsciiDocConfig = getAsciiDocConfigWithAsciidoctorReducerExtension(componentVersion)
14
16
  const mergedAsciiDocConfig = Object.assign({}, componentVersionAsciiDocConfig, {
15
- attributes: Object.assign({}, componentVersionAsciiDocConfig.attributes, assemblerAsciiDocConfig.attributes),
17
+ attributes: Object.assign({}, componentVersionAsciiDocConfig.attributes, assemblerAsciiDocAttributes),
16
18
  })
17
19
  const rootEntry = { content: title }
18
20
  const startPage = contentCatalog.getComponentVersionStartPage(componentName, version)
@@ -60,6 +62,7 @@ function getAsciiDocConfigWithAsciidoctorReducerExtension (componentVersion) {
60
62
  },
61
63
  [asciidoctorReducerExtension]
62
64
  ),
65
+ sourcemap: true,
63
66
  })
64
67
  }
65
68
  return Object.assign({}, asciidocConfig, { extensions: [asciidoctorReducerExtension], sourcemap: true })
@@ -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 = _read.bind(this)
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
  }
@@ -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
- try {
47
- input instanceof Buffer ? ps.stdin.end(input) : ps.stdin.end()
48
- } catch (err) {
49
- reject(err)
50
- } finally {
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.1",
3
+ "version": "1.0.0-alpha.4",
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)",