@antora/assembler 1.0.0-beta.17 → 1.0.0-beta.18

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/configure.js CHANGED
@@ -16,8 +16,17 @@ function internalConfigure (converter, config = {}, providers = {}) {
16
16
 
17
17
  this.once('navigationBuilt', async ({ playbook, contentCatalog }) => {
18
18
  const { assembleContent = require('./assemble-content'), ...assembleContentConfig } = providers
19
- assembleContentConfig.configSource ??= config.configFile
20
- await assembleContent.call(this, playbook, contentCatalog, converter, assembleContentConfig)
19
+ if (assembleContentConfig.configSource?.constructor === Object) {
20
+ await assembleContent.call(this, playbook, contentCatalog, converter, assembleContentConfig)
21
+ } else {
22
+ const singleConfig = !('configFiles' in config)
23
+ const configFiles = singleConfig ? config.configFile : config.configFiles
24
+ for (const configSource of Array.isArray(configFiles) ? configFiles : [configFiles]) {
25
+ const assembleContentConfigWithConfigSource = Object.assign({}, assembleContentConfig, { configSource })
26
+ await assembleContent.call(this, playbook, contentCatalog, converter, assembleContentConfigWithConfigSource)
27
+ if (singleConfig) break
28
+ }
29
+ }
21
30
  })
22
31
  }
23
32
 
@@ -2,9 +2,10 @@
2
2
 
3
3
  const createAsciiDocFile = require('./util/create-asciidoc-file')
4
4
  const createResourceKey = require('./util/create-resource-key')
5
- const generateId = require('./util/generate-id')
5
+ const generateScopedId = require('./util/generate-scoped-id')
6
6
  const { resolveLinkTarget } = require('./util/resolver')
7
7
  const { rewriteXrefs, rewriteImageRef, rewriteInlineImages, rewriteStyleAttribute } = require('./util/rewriter')
8
+ const { NamedIdAttrRx } = require('./util/rx')
8
9
  const sanitize = require('./util/sanitize')
9
10
  const unconvertInlineAsciiDoc = require('./util/unconvert-inline-asciidoc')
10
11
 
@@ -25,7 +26,14 @@ function produceAssemblyFile (
25
26
  ) {
26
27
  const pagesByUrl = files.reduce((map, it) => (it.src.family === 'page' ? map.set(it.pub.url, it) : map), new Map())
27
28
  if (outline.urlType === 'internal' && !pagesByUrl.get(outline.url) && !(outline.items || []).length) return
28
- const pagesInOutline = selectPagesInOutline(outline, pagesByUrl, componentVersion)
29
+ const pagesInOutline = selectPagesInOutline(outline, pagesByUrl)
30
+ pagesInOutline.generateIdFromTitle = generateIdFromTitle.bind(
31
+ loadAsciiDoc(
32
+ { contents: Buffer.alloc(0), src: { family: 'page', relative: 'generate-id.adoc' } },
33
+ undefined,
34
+ asciidocConfig
35
+ )
36
+ )
29
37
  const buffer = mergeAsciiDoc(
30
38
  loadAsciiDoc,
31
39
  contentCatalog,
@@ -64,29 +72,30 @@ function buildAsciiDocHeader (componentVersion, navtitle, assemblyModel) {
64
72
  let doctitle = navtitleAsciiDoc
65
73
  if (navtitlePlain !== componentVersion.title) doctitle = `${componentVersion.title}: ${doctitle}`
66
74
  const version = componentVersion.version === 'master' ? '' : componentVersion.version
75
+ const displayVersion = componentVersion.displayVersion
67
76
  const buffer = [
68
77
  `= ${doctitle}`,
69
- ...(version ? [`:revnumber: ${version}`] : []),
78
+ ...(version ? [`:revnumber: ${displayVersion}`] : []),
70
79
  ...(doctype === 'article' ? [] : [`:doctype: ${doctype ?? 'book'}`]),
71
80
  ':underscore: _',
72
81
  // Q: should we pass these via the CLI so they cannot be modified?
73
82
  `:page-component-name: ${componentVersion.name}`,
74
83
  `:page-component-version:${version ? ' ' + version : ''}`,
75
84
  ':page-version: {page-component-version}',
76
- `:page-component-display-version: ${componentVersion.displayVersion}`,
85
+ `:page-component-display-version: ${displayVersion}`,
77
86
  `:page-component-title: ${componentVersion.title}`,
78
87
  ]
79
88
  return Object.assign(buffer, { navtitle })
80
89
  }
81
90
 
82
- function selectPagesInOutline (outlineEntry, pagesByUrl, componentVersion, accum) {
91
+ function selectPagesInOutline (outlineEntry, pagesByUrl, accum) {
83
92
  accum ??= Object.assign(new Map(), { assembled: { pages: new Map(), assets: new Set() } })
84
93
  const page = outlineEntry.urlType === 'internal' ? pagesByUrl.get(outlineEntry.url) : undefined
85
94
  if (page) {
86
95
  accum.set(createResourceKey(page.src), page)
87
96
  accum.set(outlineEntry.url, page)
88
97
  }
89
- for (const item of outlineEntry.items || []) selectPagesInOutline(item, pagesByUrl, componentVersion, accum)
98
+ for (const item of outlineEntry.items || []) selectPagesInOutline(item, pagesByUrl, accum)
90
99
  return accum
91
100
  }
92
101
 
@@ -114,7 +123,7 @@ function mergeAsciiDoc (
114
123
  let navtitlePlain = sanitize(navtitle)
115
124
  let navtitleAsciiDoc = unconvertInlineAsciiDoc(navtitle)
116
125
  const { items = [], unresolved, urlType, url } = outlineEntry
117
- const { doctype, linkReferenceStyle, pubRoot, siteRoot, xmlIds, logger } = assemblyModel
126
+ const { doctype, filetype, linkReferenceStyle, pubRoot, siteRoot, xmlIds, logger } = assemblyModel
118
127
  const assembled = pagesInOutline.assembled
119
128
  // FIXME: ideally, resource ID would be stored in navigation so we can look up the page more efficiently
120
129
  const page = urlType === 'internal' && !unresolved ? pagesInOutline.get(url) : undefined
@@ -173,12 +182,13 @@ function mergeAsciiDoc (
173
182
  }
174
183
  // NOTE: in Antora, docname is relative src path from module without file extension
175
184
  const docname = doc.getAttribute('docname')
176
- const { idLeader, id: idScope } = generateId(
185
+ const { idLeader: idScopeLeader, id: idScope } = generateScopedId(
177
186
  page.src,
178
187
  componentVersion,
179
188
  idCoordinateSeparator,
180
189
  idScopeSeparator,
181
- idPrefix
190
+ idPrefix,
191
+ filetype
182
192
  )
183
193
  let pageFragment = ''
184
194
  let pageRoles = ''
@@ -235,7 +245,7 @@ function mergeAsciiDoc (
235
245
  assemblyModel = Object.assign({}, assemblyModel, { sectionMergeStrategy: 'discrete' })
236
246
  } else {
237
247
  if (atDocumentRoot) {
238
- pageFragment = `#${idLeader}${doc.getId() ?? pageStyle}`
248
+ pageFragment = `#${idScopeLeader}${doc.getId() ?? pageStyle}`
239
249
  buffer.unshift(`[#${idScope}]`)
240
250
  } else {
241
251
  pageFragment = `#${idScope}`
@@ -268,26 +278,16 @@ function mergeAsciiDoc (
268
278
  //if (overviewTitle === navtitle) overviewTitle = doc.getAttribute('overview-title', 'Overview')
269
279
  const overviewTitle = doc.getAttribute('overview-title', 'Overview')
270
280
  buffer.push('')
271
- // NOTE: try to toggle sectids; otherwise, fallback to globally unique synthetic ID
272
- let toggleSectids, syntheticId
273
- if (doc.isAttribute('sectids')) {
274
- if (doc.isAttributeLocked('sectids')) {
275
- syntheticId = `__object-id-${getObjectId(outlineEntry)}`
276
- } else {
277
- buffer.push(':!sectids:')
278
- toggleSectids = true
279
- }
280
- }
281
+ const syntheticId = pagesInOutline.generateIdFromTitle(navtitleAsciiDoc, idCoordinateSeparator)
281
282
  let hlevel = level + 2
282
283
  if (hlevel > 6) {
283
284
  const blockStyle = `discrete.h${hlevel}`
284
285
  hlevel = 6
285
- buffer.push(syntheticId ? `[${blockStyle}#${syntheticId}]` : `[${blockStyle}]`)
286
- } else if (syntheticId) {
286
+ buffer.push(`[${blockStyle}#${syntheticId}]`)
287
+ } else {
287
288
  buffer.push(`[#${syntheticId}]`)
288
289
  }
289
290
  buffer.push(`${'='.repeat(hlevel)} ${overviewTitle}`)
290
- if (toggleSectids) buffer.push(':sectids:')
291
291
  }
292
292
  assembled.pages.set(page, pageFragment)
293
293
  if (doc.hasSections()) {
@@ -375,13 +375,13 @@ function mergeAsciiDoc (
375
375
  if (!refs['$key?'](refid) && (~refid.indexOf(' ') || refid.toLowerCase() !== refid)) {
376
376
  if ((refid = doc.$resolve_id(refid))['$nil?']()) return m
377
377
  }
378
- return `<<${idLeader}${refid}${text ? ',' + text : ''}>>`
378
+ return `<<${idScopeLeader}${refid}${text ? ',' + text : ''}>>`
379
379
  })
380
380
  }
381
381
  // NOTE: the next check takes care of inline and block anchors
382
382
  if (~line.indexOf('[[')) {
383
383
  line = line.replace(/\[\[([\p{Alpha}_:][\p{Alpha}0-9_\-:.]*)(|, *.+?)\]\]/gu, (_, refid, text) => {
384
- return `[[${idLeader}${refid}${text}]]`
384
+ return `[[${idScopeLeader}${refid}${text}]]`
385
385
  })
386
386
  }
387
387
  if (~line.indexOf('xref:')) {
@@ -394,7 +394,7 @@ function mergeAsciiDoc (
394
394
  idCoordinateSeparator,
395
395
  idScopeSeparator,
396
396
  idPrefix,
397
- idLeader,
397
+ idScopeLeader,
398
398
  pagesInOutline,
399
399
  doc,
400
400
  { file: relative, lineno: idx + 1 }
@@ -427,7 +427,7 @@ function mergeAsciiDoc (
427
427
  return '='.repeat(targetMarkerLength) + ' ' + rest
428
428
  })
429
429
  // NOTE: ID will be undefined if sectids are turned off
430
- if (block.getId()) rewriteStyleAttribute(block, lines, idx, idLeader, blockStyle)
430
+ if (block.getId()) rewriteStyleAttribute(block, lines, idx, idScopeLeader, blockStyle)
431
431
  } else {
432
432
  if (context === 'image') {
433
433
  let line = lines[idx] || ''
@@ -456,7 +456,7 @@ function mergeAsciiDoc (
456
456
  // nested document
457
457
  idx = (block.getHeader().getLineNumber() || idx + 1) - 1
458
458
  }
459
- if (block.getId()) rewriteStyleAttribute(block, lines, idx, idLeader)
459
+ if (block.getId()) rewriteStyleAttribute(block, lines, idx, idScopeLeader)
460
460
  }
461
461
  })
462
462
  safePush(
@@ -491,20 +491,7 @@ function mergeAsciiDoc (
491
491
  } else {
492
492
  buffer.inBody = true
493
493
  buffer.push('')
494
- // NOTE: try to toggle sectids; otherwise, fallback to globally unique synthetic ID
495
- // Q: should we unset docname, page-module, etc?
496
- let toggleSectids, syntheticId
497
- if (!('sectids' in asciidocConfig.attributes)) {
498
- buffer.push(':!sectids:')
499
- toggleSectids = true
500
- } else if (typeof asciidocConfig.attributes.sectids === 'string') {
501
- if ('sectids' in mutableAttributes) {
502
- buffer.push(':!sectids:')
503
- toggleSectids = true
504
- } else {
505
- syntheticId = `__object-id-${global.Opal.hash(outlineEntry).$object_id()}`
506
- }
507
- }
494
+ const syntheticId = pagesInOutline.generateIdFromTitle(navtitleAsciiDoc, idCoordinateSeparator)
508
495
  let sectionTitle = navtitleAsciiDoc
509
496
  if (urlType === 'external') {
510
497
  sectionTitle = `${url}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
@@ -512,14 +499,15 @@ function mergeAsciiDoc (
512
499
  const resource = files.find((it) => it.pub.url === url)
513
500
  if (resource) {
514
501
  if (resource.src.family === 'page' && pagesInOutline.has(resource.pub.url)) {
515
- const refid = generateId(
502
+ const { id: refid } = generateScopedId(
516
503
  resource.src,
517
504
  componentVersion,
518
505
  idCoordinateSeparator,
519
506
  idScopeSeparator,
520
507
  idPrefix,
508
+ filetype,
521
509
  true
522
- ).id
510
+ )
523
511
  sectionTitle = `xref:${refid}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
524
512
  } else if (siteRoot) {
525
513
  sectionTitle = `${resolveLinkTarget(resource, siteRoot, pubRoot, linkReferenceStyle, true)}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
@@ -529,12 +517,11 @@ function mergeAsciiDoc (
529
517
  let hlevel = level + 1
530
518
  if (hlevel > 6) {
531
519
  hlevel = 6
532
- buffer.push(syntheticId ? `[discrete#${syntheticId}]` : '[discrete]')
533
- } else if (syntheticId) {
520
+ buffer.push(`[discrete#${syntheticId}]`)
521
+ } else {
534
522
  buffer.push(`[#${syntheticId}]`)
535
523
  }
536
524
  buffer.push(`${'='.repeat(hlevel)} ${sectionTitle}`)
537
- if (toggleSectids) buffer.push(':sectids:')
538
525
  }
539
526
  }
540
527
 
@@ -610,6 +597,7 @@ function processDocumentHeader (doc, lines, buffer, ignoreLines) {
610
597
  .slice(1, -1)
611
598
  .trim()
612
599
  .replace(/(?:^\w[\w-]*(?!=|[\w-]))?([#.%]\w[\w-]*)*/, '')
600
+ .replace(NamedIdAttrRx, '')
613
601
  if (attrlist) buffer.push('[' + attrlist + ']')
614
602
  }
615
603
  } else if (belowDoctitle) {
@@ -645,10 +633,6 @@ function fixSectionLevels (sections, expectedLevel) {
645
633
  })
646
634
  }
647
635
 
648
- function getObjectId (obj) {
649
- return global.Opal.id(obj)
650
- }
651
-
652
636
  // NOTE: blank lines at top and bottom of document create mismatch when using line numbers to navigate source lines
653
637
  // IMPORTANT: this must not leave behind lines the parser will drop!
654
638
  // IDEA: another option is to capture initial lineno of reader and use as offset (but preseves those blank lines)
@@ -671,4 +655,11 @@ function safePush (onto, entries) {
671
655
  }
672
656
  }
673
657
 
658
+ function generateIdFromTitle (titleAsciiDoc, sep) {
659
+ const Section = this.$class().$const_get('::Asciidoctor::Section')
660
+ const baseId = Section.$generate_id(titleAsciiDoc, this)
661
+ this.getCatalog().refs['$[]='](baseId, true)
662
+ return `_${sep}${baseId}`
663
+ }
664
+
674
665
  module.exports = produceAssemblyFile
@@ -2,7 +2,7 @@
2
2
 
3
3
  const ReservedIdNames = 'content header footnotes footer footer-text premable toc toctitle'.split(' ')
4
4
 
5
- function generateId (componentSrc, componentVersion, coordinateSep, scopeSep, prefix, asXrefTarget, fragment) {
5
+ function generateScopedId (componentSrc, componentVersion, coordinateSep, scopeSep, prefix, filetype, asXrefTarget) {
6
6
  let { component, module: mod, relative } = componentSrc
7
7
  let id = relative.replace(/\.adoc$/, '').replace(/[/.]/g, '-')
8
8
  if (component !== componentVersion.name) {
@@ -13,13 +13,13 @@ function generateId (componentSrc, componentVersion, coordinateSep, scopeSep, pr
13
13
  mod = mod.replace(/(?:pass|stem)$/, '\\$&')
14
14
  }
15
15
  id = mod + coordinateSep + id
16
- } else if (ReservedIdNames.includes(id)) {
17
- id += scopeSep
18
- scopeSep = ''
16
+ } else if (filetype === 'html' && ReservedIdNames.includes(id)) {
17
+ id = prefix + id
18
+ prefix = ''
19
19
  }
20
20
  if (prefix && !/^[\p{Alpha}_:]/u.test(id)) id = prefix + id
21
21
  const idLeader = id + scopeSep
22
- return { idLeader, id: fragment ? idLeader + fragment : id }
22
+ return { idLeader, id }
23
23
  }
24
24
 
25
- module.exports = generateId
25
+ module.exports = generateScopedId
@@ -1,9 +1,10 @@
1
1
  'use strict'
2
2
 
3
3
  const createResourceKey = require('./create-resource-key')
4
- const generateId = require('./generate-id')
5
- const { resolveEmbedTarget, resolveLinkTarget } = require('./resolver')
4
+ const generateScopedId = require('./generate-scoped-id')
6
5
  const parseResourceRef = require('./parse-resource-ref')
6
+ const { resolveEmbedTarget, resolveLinkTarget } = require('./resolver')
7
+ const { NamedIdAttrRx } = require('./rx')
7
8
 
8
9
  function rewriteXrefs (
9
10
  line,
@@ -96,16 +97,16 @@ function rewriteXref (
96
97
  text = ''
97
98
  }
98
99
  const componentVersionCtx = { name: ctx.component, version: ctx.version }
99
- const refid = generateId(
100
+ const { idLeader: refidLeader, id: refid } = generateScopedId(
100
101
  resource.src,
101
102
  componentVersionCtx,
102
103
  idCoordinateSep,
103
104
  idScopeSep,
104
105
  idPrefix,
105
- text.length > 0,
106
- fragment
107
- ).id
108
- return `xref:${refid}[${text}]`
106
+ assemblyModel.filetype,
107
+ text.length > 0
108
+ )
109
+ return `xref:${fragment ? refidLeader + fragment : refid}[${text}]`
109
110
  }
110
111
 
111
112
  function rewriteImageAttr (val, contentCatalog, assemblyModel, ctx, assets) {
@@ -160,6 +161,8 @@ function rewriteStyleAttribute (block, lines, idx, idLeader, replacementStyle =
160
161
  if (cellSpec) {
161
162
  prevLine = cellSpec[2]
162
163
  cellSpec = cellSpec[1]
164
+ } else if (~prevLine.indexOf('id=')) {
165
+ prevLine = `[${prevLine.slice(1, -1).replace(NamedIdAttrRx, '')}]`
163
166
  }
164
167
  let rawStyle
165
168
  const commaIdx = prevLine.indexOf(',')
package/lib/util/rx.js ADDED
@@ -0,0 +1,5 @@
1
+ 'use strict'
2
+
3
+ const NamedIdAttrRx = /(?:^|, *)id=(?:("[^"]*"|'[^']*'|[^,]*))/
4
+
5
+ module.exports = { NamedIdAttrRx }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/assembler",
3
- "version": "1.0.0-beta.17",
3
+ "version": "1.0.0-beta.18",
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)",