@antora/assembler 1.0.0-beta.13 → 1.0.0-beta.15

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.
@@ -16,8 +16,6 @@ const PACKAGE_NAME = require('../package.json').name
16
16
  const NEWLINE_RX = /(?:\r?\n)+/
17
17
 
18
18
  async function assembleContent (playbook, contentCatalog, converter, { configSource, navigationCatalog }) {
19
- const assemblerConfig = await loadConfig(playbook, configSource)
20
- if (!assemblerConfig) return [] // TODO consider removing and doing this another way
21
19
  const context = isBound(this)
22
20
  ? this
23
21
  : {
@@ -25,6 +23,8 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
25
23
  getLogger: invariably.void,
26
24
  getVariables: invariably.new,
27
25
  }
26
+ const assemblerConfig = await loadConfig.call(context, playbook, configSource)
27
+ if (assemblerConfig.enabled === false) return []
28
28
  const generatorFunctions = context.getFunctions()
29
29
  const { loadAsciiDoc = require('@antora/asciidoc-loader') } = generatorFunctions
30
30
  const {
@@ -5,6 +5,8 @@ const fsp = require('node:fs/promises')
5
5
  const os = require('node:os')
6
6
  const yaml = require('js-yaml')
7
7
 
8
+ const PACKAGE_NAME = require('../package.json').name
9
+
8
10
  const ASSEMBLY_KEYS = [
9
11
  'rootLevel',
10
12
  'insertStartPage',
@@ -13,25 +15,34 @@ const ASSEMBLY_KEYS = [
13
15
  'dropExplicitXrefText',
14
16
  ]
15
17
 
16
- function loadConfig (playbook, configSource = './antora-assembler.yml') {
18
+ function loadConfig (playbook, configSource) {
19
+ let resolvedConfigSource
17
20
  return (
18
- configSource.constructor === Object
21
+ configSource?.constructor === Object
19
22
  ? Promise.resolve(configSource)
20
23
  : fsp
21
- .access((configSource = expandPath(configSource, { dot: playbook.dir })))
24
+ .access((resolvedConfigSource = expandPath(configSource ?? './antora-assembler.yml', { dot: playbook.dir })))
22
25
  .then(
23
26
  () => true,
24
27
  () => false
25
28
  )
26
- .then((exists) =>
27
- exists
28
- ? fsp
29
- .readFile(configSource)
30
- .then((data) => Object.assign(camelCaseKeys(yaml.load(data), ['asciidoc']), { file: configSource }))
31
- : {}
32
- )
29
+ .then((exists) => {
30
+ if (!exists) {
31
+ let logger
32
+ if (configSource && (logger = this?.getLogger?.(PACKAGE_NAME))) {
33
+ const ctx = { file: { path: configSource } }
34
+ logger.warn(ctx, 'Could not resolve config file; reverting to default settings')
35
+ }
36
+ return {}
37
+ }
38
+ return fsp
39
+ .readFile(resolvedConfigSource)
40
+ .then((data) =>
41
+ Object.assign(camelCaseKeys(yaml.load(data), ['asciidoc']), { file: resolvedConfigSource })
42
+ )
43
+ })
33
44
  ).then((config) => {
34
- if (config.enabled === false) return undefined
45
+ if (config.enabled === false) return config
35
46
  let asciidocAttrs
36
47
  if (!config.asciidoc) {
37
48
  config.asciidoc = { attributes: (asciidocAttrs = {}) }
@@ -121,6 +121,7 @@ function mergeAsciiDoc (
121
121
  outDirname,
122
122
  siteRoot,
123
123
  xmlIds,
124
+ logger,
124
125
  } = assemblyModel
125
126
  // FIXME: ideally, resource ID would be stored in navigation so we can look up the page more efficiently
126
127
  const page = urlType === 'internal' && !unresolved ? pagesInOutline.get(url) : undefined
@@ -142,6 +143,16 @@ function mergeAsciiDoc (
142
143
  Object.assign({}, page, { contents: trimAsciiDoc(contents), mediaType })
143
144
  )
144
145
  const doc = loadAsciiDoc(pageAsAsciiDoc, contentCatalog, asciidocConfig)
146
+ let asciidoctorLogger = doc.getLogger()
147
+ if (logger) {
148
+ asciidoctorLogger = Object.assign(asciidoctorLogger.$dup(), {
149
+ delegate: {
150
+ warn () {
151
+ return logger.warn.apply(logger, arguments)
152
+ },
153
+ },
154
+ })
155
+ }
145
156
  if (doc.hasAttribute('assembly-navtitle')) {
146
157
  navtitleAsciiDoc = doc.getAttribute('assembly-navtitle')
147
158
  navtitlePlain = sanitize((navtitle = doc.$apply_reftext_subs(navtitleAsciiDoc)))
@@ -374,7 +385,7 @@ function mergeAsciiDoc (
374
385
  }
375
386
  if (~line.indexOf('xref:')) {
376
387
  // Q: should we allow : as first character of target?
377
- line = line.replace(/(?<![\\+])xref:((?:\.\/)?[\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
388
+ line = line.replace(/(?<![\\+])xref:((?:\.\/)?[\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (_, target, text) => {
378
389
  let fragment, resource, resourceRef
379
390
  const hashIdx = target.indexOf('#')
380
391
  if (~hashIdx) {
@@ -389,21 +400,23 @@ function mergeAsciiDoc (
389
400
  // Q: should we validate the internal ID here?
390
401
  if (!resourceRef) return `xref:${idPrefix}${fragment}[${text}]`
391
402
  const resourceId = parseResourceRef(resourceRef, page.src, 'page', contentCatalog)
392
- if (resourceId.family !== 'page') {
393
- if (siteRoot && (resource = contentCatalog.getById(resourceId))?.pub) {
394
- text ||= resource.asciidoc?.xreftext || target
395
- return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
396
- }
397
- // TODO: handle unresolved resource better
398
- return m
399
- }
400
- if (!(resource = pagesInOutline.get(createResourceKey(resourceId)))) {
401
- if (siteRoot && (resource = contentCatalog.getById(resourceId))?.pub) {
403
+ if (resourceId.family !== 'page' || !(resource = pagesInOutline.get(createResourceKey(resourceId)))) {
404
+ if ((resource = contentCatalog.getById(resourceId))?.pub) {
402
405
  text ||= resource.asciidoc?.xreftext || target
403
- return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
406
+ if (siteRoot || linkRefStyle === 'relative') {
407
+ return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
408
+ }
409
+ asciidoctorLogger.warn(
410
+ doc.createLogMessage(
411
+ `Cannot create external ${resourceId.family} reference in assembly because site URL is unknown: ${target}`,
412
+ { source_location: { file: relative, lineno: idx + 1 } }
413
+ )
414
+ )
404
415
  }
405
- // TODO: handle unresolved page better
406
- return m
416
+ const linkAttrlist = text
417
+ ? (~text.indexOf(',') ? `"${text}"` : text) + ',role=unresolved'
418
+ : 'role=unresolved'
419
+ return `link:${target}[${linkAttrlist}]`
407
420
  }
408
421
  if (fragment === resource.asciidoc.id) fragment = ''
409
422
  if (
@@ -427,7 +440,7 @@ function mergeAsciiDoc (
427
440
  if (~line.indexOf('link:{attachmentsdir}/')) {
428
441
  line = line.replace(/(?<![\\+])link:\{attachmentsdir\}\/([^\s[]+)\[(|.*?[^\\])\]/g, (m, relative, text) => {
429
442
  const attachment =
430
- siteRoot &&
443
+ (siteRoot || linkRefStyle === 'relative') &&
431
444
  contentCatalog.getById({
432
445
  component: componentVersion.name,
433
446
  version: componentVersion.version,
@@ -441,15 +454,25 @@ function mergeAsciiDoc (
441
454
  }
442
455
  if (~line.indexOf('image:') && !line.startsWith('image::')) {
443
456
  line = line.replace(/(?<![\\+])image:([^:\s[](?:[^[]*[^\s[])?)\[([^\]]*)\]/g, (m, target, attrlist) => {
444
- if (isResourceSpec(target)) {
445
- const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
446
- // TODO: handle (or report) unresolved image better
447
- if (image?.out && (filetype !== 'html' || siteRoot)) {
457
+ let image
458
+ if (
459
+ isResourceSpec(target) &&
460
+ (image = contentCatalog.resolveResource(target, page.src, 'image', ['image']))?.out
461
+ ) {
462
+ if (filetype !== 'html') {
463
+ pagesInOutline.assembled.assets.add(image)
464
+ return `image:${resolveEmbedTarget(image, outDirname, embedRefStyle, true)}[${attrlist}]`
465
+ }
466
+ if (siteRoot || linkRefStyle === 'relative') {
448
467
  pagesInOutline.assembled.assets.add(image)
449
- return filetype === 'html'
450
- ? `image:${resolveLinkTarget(image, siteRoot, pubRoot, linkRefStyle)}[${attrlist}]`
451
- : `image:${resolveEmbedTarget(image, outDirname, embedRefStyle, true)}[${attrlist}]`
468
+ return `image:${resolveLinkTarget(image, siteRoot, pubRoot, linkRefStyle)}[${attrlist}]`
452
469
  }
470
+ asciidoctorLogger.warn(
471
+ doc.createLogMessage(
472
+ `Cannot create external image reference in assembly because site URL is unknown: ${target}`,
473
+ { source_location: { file: relative, lineno: idx + 1 } }
474
+ )
475
+ )
453
476
  }
454
477
  return m
455
478
  })
@@ -21,6 +21,7 @@ function produceAssemblyFiles (loadAsciiDoc, contentCatalog, assemblerConfig, re
21
21
  embedReferenceStyle: assemblyConfig.embedReferenceStyle,
22
22
  linkReferenceStyle: assemblyConfig.linkReferenceStyle,
23
23
  dropExplicitXrefText: assemblyConfig.dropExplicitXrefText,
24
+ logger: assemblyConfig.logger, // for tests
24
25
  })
25
26
  const assemblerAsciiDocAttributes = Object.assign({}, assemblerAsciiDocConfig.attributes)
26
27
  const { revdate, 'source-highlighter': sourceHighlighter } = assemblerAsciiDocAttributes
@@ -64,7 +65,7 @@ function produceAssemblyFiles (loadAsciiDoc, contentCatalog, assemblerConfig, re
64
65
  if (linkRefStyle === 'absolute' && siteRoot?.url == null) linkRefStyle = 'root-relative'
65
66
  if (linkRefStyle === 'root-relative' && siteRoot?.path == null) linkRefStyle = 'relative'
66
67
  assemblyModel.linkReferenceStyle = linkRefStyle
67
- } else {
68
+ } else if (!(assemblyModel.filetype === 'pdf' && assemblyModel.linkReferenceStyle === 'relative')) {
68
69
  assemblyModel.linkReferenceStyle = 'absolute'
69
70
  }
70
71
  const auxiliaryImages = new Set()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antora/assembler",
3
- "version": "1.0.0-beta.13",
3
+ "version": "1.0.0-beta.15",
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)",