@antora/assembler 1.0.0-rc.6 → 1.0.0-rc.7

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.
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const fs = require('node:fs')
4
- const { promises: fsp } = fs
3
+ const compileConversionAttributes = require('./compile-conversion-attributes')
4
+ const fsp = require('node:fs/promises')
5
5
  const LazyReadable = require('./util/lazy-readable')
6
6
  const loadConfig = require('./load-config')
7
7
  const logCommand = require('./log-command')
@@ -22,12 +22,13 @@ async function assembleContent (playbook, contentCatalog, converter, providers)
22
22
  getDefaultCommand,
23
23
  extname: targetExtname = '',
24
24
  backend: targetBackend = targetExtname.substring(1),
25
+ format: targetFormat = targetBackend,
25
26
  embedReferenceStyle = 'relative',
26
27
  mediaType: targetMediaType,
27
28
  loggerName = `${PACKAGE_NAME} [${targetBackend}-exporter]`,
28
29
  xmlCompliant,
29
30
  } = converter ?? {}
30
- const assemblerConfig = await loadConfig.call(this, configSource, playbook, '-' + targetBackend)
31
+ const assemblerConfig = await loadConfig.call(this, configSource, playbook, targetBackend ? '-' + targetBackend : '')
31
32
  if (assemblerConfig.enabled === false || !contentCatalog.publishableFamilies?.has('export')) return []
32
33
  const context = isBound(this)
33
34
  ? this
@@ -35,9 +36,10 @@ async function assembleContent (playbook, contentCatalog, converter, providers)
35
36
  getFunctions: invariably.new,
36
37
  getLogger: invariably.void,
37
38
  getVariables: invariably.new,
39
+ require,
38
40
  }
39
41
  const generatorFunctions = context.getFunctions()
40
- const { loadAsciiDoc = require('@antora/asciidoc-loader') } = generatorFunctions
42
+ const { loadAsciiDoc = context.require('@antora/asciidoc-loader') } = generatorFunctions
41
43
  const { assembly: assemblyConfig, build: buildConfig } = assemblerConfig
42
44
  assemblyConfig.embedReferenceStyle = embedReferenceStyle
43
45
  if (xmlCompliant) assemblyConfig.xmlIds ??= true
@@ -48,13 +50,17 @@ async function assembleContent (playbook, contentCatalog, converter, providers)
48
50
  buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), `build/assembler/${profile}`)
49
51
  intrinsicAttributes[`assembler-profile-${profile}`] = ''
50
52
  intrinsicAttributes['assembler-profile'] = profile
51
- if (targetBackend) {
52
- intrinsicAttributes[`assembler-backend-${targetBackend}`] = ''
53
- intrinsicAttributes['assembler-backend'] = targetBackend
54
- }
55
53
  } else {
56
54
  buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), 'build/assembler/_')
57
55
  }
56
+ if (targetBackend) {
57
+ intrinsicAttributes[`assembler-backend-${targetBackend}`] = ''
58
+ intrinsicAttributes['assembler-backend'] = targetBackend
59
+ }
60
+ if (targetFormat) {
61
+ intrinsicAttributes[`assembler-format-${targetFormat}`] = ''
62
+ intrinsicAttributes['assembler-format'] = targetFormat
63
+ }
58
64
  if (targetExtname) {
59
65
  const targetFiletype = targetExtname.substring(1)
60
66
  intrinsicAttributes[`assembler-filetype-${targetFiletype}`] = ''
@@ -65,12 +71,12 @@ async function assembleContent (playbook, contentCatalog, converter, providers)
65
71
  loadAsciiDoc,
66
72
  contentCatalog,
67
73
  assemblerConfig,
68
- generateSelectAssemblyProfile(context, contentCatalog, assemblyConfig, intrinsicAttributes, navigationCatalog),
74
+ generateSelectAssemblerProfile(context, contentCatalog, assemblyConfig, intrinsicAttributes, navigationCatalog),
69
75
  typeof componentVersionFilter === 'function' ? componentVersionFilter : undefined
70
76
  )
71
77
  if (!(assemblyFiles.length && typeof convert === 'function')) return assemblyFiles
72
78
  buildConfig.command ??= typeof getDefaultCommand === 'function' ? await getDefaultCommand(cwd, playbook) : null
73
- const { publishSite: publishFiles = require('@antora/site-publisher') } = generatorFunctions
79
+ const { publishSite: publishFiles = context.require('@antora/site-publisher') } = generatorFunctions
74
80
  await prepareWorkspace(publishFiles, assemblyFiles, buildConfig)
75
81
  const helpers = { logCommand: logCommand.bind(context, loggerName), runCommand }
76
82
  const boundConvert = convert.bind(context)
@@ -79,9 +85,9 @@ async function assembleContent (playbook, contentCatalog, converter, providers)
79
85
  .add(
80
86
  assemblyFiles.map((doc) => async () => {
81
87
  const relativeToOutput = embedReferenceStyle === 'output-relative'
82
- const convertAttributes = await prepareConvertAttributes(doc, targetExtname, relativeToOutput, assemblerConfig)
83
- return boundConvert(doc, convertAttributes, buildConfig, helpers).then((result) =>
84
- boundResolveFileOrContents(result, convertAttributes, buildConfig, loggerName).then((fileOrContents) =>
88
+ const attributes = await compileConversionAttributes(doc, targetExtname, assemblerConfig, relativeToOutput)
89
+ return boundConvert(doc, attributes, buildConfig, helpers).then((result) =>
90
+ boundResolveFileOrContents(result, attributes, buildConfig, loggerName).then((fileOrContents) =>
85
91
  coerceToExportFormat(doc, targetBackend, targetExtname, targetMediaType, fileOrContents)
86
92
  )
87
93
  )
@@ -129,11 +135,11 @@ async function assembleContent (playbook, contentCatalog, converter, providers)
129
135
  }
130
136
 
131
137
  /**
132
- * Generates a function that selects the active assembly profile, initializes an assembly model using
138
+ * Generates a function that selects the active assembler profile, initializes an assembly model using
133
139
  * the keys from the profile as well as any inherited shared keys, builds the navigation for the assembly, and
134
140
  * returns the initialized assembly model. The assembly model is further populated after the call to this function.
135
141
  */
136
- function generateSelectAssemblyProfile (context, contentCatalog, baseModel, intrinsicAttributes, navigationCatalog) {
142
+ function generateSelectAssemblerProfile (context, contentCatalog, baseModel, intrinsicAttributes, navigationCatalog) {
137
143
  const logger = context.getLogger?.(PACKAGE_NAME)
138
144
  const { assemblerProfiles } = context.getVariables()
139
145
  if (!assemblerProfiles) {
@@ -144,7 +150,7 @@ function generateSelectAssemblyProfile (context, contentCatalog, baseModel, intr
144
150
  }
145
151
  }
146
152
  const boundSendToLog = sendToLog.bind(logger)
147
- const { buildAlternateNavigation = require('@antora/navigation-builder').buildAlternateNavigation } =
153
+ const { buildAlternateNavigation = context.require('@antora/navigation-builder').buildAlternateNavigation } =
148
154
  context.getFunctions()
149
155
  return (componentVersion) => {
150
156
  const componentVersionProfiles = assemblerProfiles.get(componentVersion.version + '@' + componentVersion.name)
@@ -173,73 +179,6 @@ function generateSelectAssemblyProfile (context, contentCatalog, baseModel, intr
173
179
  }
174
180
  }
175
181
 
176
- async function prepareConvertAttributes (doc, targetExtname, relativeToOutput, assemblerConfig) {
177
- const {
178
- asciidoc: { attributes: docAttributes } = { attributes: {} },
179
- extname: docfilesuffix,
180
- path: reldocfile,
181
- src: { family, relative },
182
- } = doc
183
- const { cwd = process.cwd(), dir = cwd, mkdirs } = assemblerConfig.build
184
- const docname = family + '$' + relative.substring(0, relative.length - docfilesuffix.length)
185
- const docfile = ospath.join(dir, reldocfile)
186
- const outdir = ospath.dirname(docfile)
187
- const docdir = relativeToOutput ? dir : outdir
188
- const outfile = docfile.substring(0, docfile.length - docfilesuffix.length) + targetExtname
189
- const attributes = Object.assign({ revdate: `${assemblerConfig.assembly.revdate}@` }, docAttributes, {
190
- docdir,
191
- docfile,
192
- docfilesuffix,
193
- docname: `${docname}@`,
194
- imagesdir: '',
195
- outdir,
196
- outfile,
197
- outfilesuffix: targetExtname,
198
- toArgs (attributeOptionFlag, outputOptionFlag) {
199
- const args = []
200
- let requireAsciidoctorLogAdapter
201
- for (const [name, val] of Object.entries(this)) {
202
- let optionValue
203
- if (name === 'asciidoctor-log-integration') {
204
- if ((val ?? false) !== false) requireAsciidoctorLogAdapter = val
205
- continue
206
- } else if ((val ?? false) === false) {
207
- optionValue = `${name}!${val === false ? '=@' : ''}`
208
- } else {
209
- optionValue = val === '' ? name : name + '=' + val
210
- }
211
- args.push(attributeOptionFlag, optionValue)
212
- }
213
- if (requireAsciidoctorLogAdapter) args.push('-r', requireAsciidoctorLogAdapter)
214
- if (outputOptionFlag) args.push(outputOptionFlag, this.outfile)
215
- return args
216
- },
217
- })
218
- Object.defineProperty(attributes, 'outfilesuffix', {
219
- get () {
220
- return ospath.extname(this.outfile)
221
- },
222
- set (value) {
223
- const outfile = this.outfile
224
- const extname = ospath.extname(outfile)
225
- if (extname && outfile.endsWith(extname)) this.outfile = outfile.substring(0, outfile.length - extname.length)
226
- this.outfile += value
227
- },
228
- })
229
- Object.defineProperty(attributes, 'toArgs', { enumerable: false })
230
- if (mkdirs) await fsp.mkdir(outdir, { recursive: true, force: true })
231
- if (attributes['asciidoctor-log-integration'] != null) {
232
- const scriptSourcePath = require.resolve('#asciidoctor-log-adapter')
233
- let scriptTargetPath = scriptSourcePath
234
- if (attributes['asciidoctor-log-integration'] === 'copy-to-build-dir') {
235
- scriptTargetPath = ospath.join(dir, 'asciidoctor-log-adapter.rb')
236
- await fsp.cp(scriptSourcePath, scriptTargetPath, { force: true, recursive: true })
237
- }
238
- attributes['asciidoctor-log-integration'] = scriptTargetPath
239
- }
240
- return attributes
241
- }
242
-
243
182
  function coerceToExportFormat (assemblyFile, targetBackend, targetExtname, targetMediaType, fileOrContents) {
244
183
  const file =
245
184
  fileOrContents == null || Buffer.isBuffer(fileOrContents) || typeof fileOrContents.pipe === 'function'
@@ -287,7 +226,7 @@ function prepareWorkspace (publishFiles, assemblyFiles, buildConfig) {
287
226
  })
288
227
  }
289
228
 
290
- function resolveFileOrContents (convertResult, convertAttributes, buildConfig, loggerName) {
229
+ function resolveFileOrContents (convertResult, attributes, buildConfig, loggerName) {
291
230
  let fileOrContents
292
231
  if (convertResult?.status != null) {
293
232
  if ('file' in convertResult) {
@@ -299,7 +238,7 @@ function resolveFileOrContents (convertResult, convertAttributes, buildConfig, l
299
238
  }
300
239
  let logger, match
301
240
  if (buildConfig.stderrSink === 'log' && convertResult.stderr?.length && (logger = this.getLogger(loggerName))) {
302
- const docfile = convertAttributes.docfile
241
+ const docfile = attributes.docfile
303
242
  const command = buildConfig.command
304
243
  const file = { path: docfile }
305
244
  const stderr = convertResult.stderr.toString().trimEnd()
@@ -330,8 +269,8 @@ function resolveFileOrContents (convertResult, convertAttributes, buildConfig, l
330
269
  return Promise.resolve(convertResult)
331
270
  }
332
271
  if (fileOrContents !== undefined) return Promise.resolve(fileOrContents)
333
- const outfile = convertAttributes.outfile
334
- return fsp.access(outfile).then(() => new LazyReadable(() => fs.createReadStream(outfile)), invariably.null)
272
+ const outfile = attributes.outfile
273
+ return fsp.access(outfile).then(() => new LazyReadable(outfile), invariably.null)
335
274
  }
336
275
 
337
276
  function isBound (obj) {
@@ -0,0 +1,73 @@
1
+ 'use strict'
2
+
3
+ const fsp = require('node:fs/promises')
4
+ const ospath = require('node:path')
5
+
6
+ async function compileConversionAttributes (doc, targetExtname, assemblerConfig, relativeToOutput = false) {
7
+ const {
8
+ asciidoc: { attributes: docAttributes } = { attributes: {} },
9
+ extname: docfilesuffix,
10
+ path: reldocfile,
11
+ src: { family, relative },
12
+ } = doc
13
+ const { cwd = process.cwd(), dir = cwd, mkdirs } = assemblerConfig.build
14
+ const docname = family + '$' + relative.substring(0, relative.length - docfilesuffix.length)
15
+ const docfile = ospath.join(dir, reldocfile)
16
+ const outdir = ospath.dirname(docfile)
17
+ const outfile = docfile.substring(0, docfile.length - docfilesuffix.length) + targetExtname
18
+ const attributes = Object.assign({ revdate: `${assemblerConfig.assembly.revdate}@` }, docAttributes, {
19
+ docdir: relativeToOutput ? dir : outdir,
20
+ docfile,
21
+ docfilesuffix,
22
+ docname: `${docname}@`,
23
+ imagesdir: '',
24
+ imagesoutdir: ospath.join(outdir, '..', '_images'),
25
+ outdir,
26
+ outfile,
27
+ outfilesuffix: targetExtname,
28
+ toArgs (attributeOptionFlag, outputOptionFlag) {
29
+ const args = []
30
+ let requireAsciidoctorLogAdapter
31
+ for (const [name, val] of Object.entries(this)) {
32
+ let optionValue
33
+ if (name === 'asciidoctor-log-integration') {
34
+ if ((val ?? false) !== false) requireAsciidoctorLogAdapter = val
35
+ continue
36
+ } else if ((val ?? false) === false) {
37
+ optionValue = `${name}!${val === false ? '=@' : ''}`
38
+ } else {
39
+ optionValue = val === '' ? name : name + '=' + val
40
+ }
41
+ args.push(attributeOptionFlag, optionValue)
42
+ }
43
+ if (requireAsciidoctorLogAdapter) args.push('-r', requireAsciidoctorLogAdapter)
44
+ if (outputOptionFlag) args.push(outputOptionFlag, this.outfile)
45
+ return args
46
+ },
47
+ })
48
+ Object.defineProperty(attributes, 'outfilesuffix', {
49
+ get () {
50
+ return ospath.extname(this.outfile)
51
+ },
52
+ set (value) {
53
+ const outfile = this.outfile
54
+ const extname = ospath.extname(outfile)
55
+ if (extname && outfile.endsWith(extname)) this.outfile = outfile.substring(0, outfile.length - extname.length)
56
+ this.outfile += value
57
+ },
58
+ })
59
+ Object.defineProperty(attributes, 'toArgs', { enumerable: false })
60
+ if (mkdirs) await fsp.mkdir(outdir, { recursive: true, force: true })
61
+ if (attributes['asciidoctor-log-integration'] != null) {
62
+ const scriptSourcePath = require.resolve('#asciidoctor-log-adapter')
63
+ let scriptTargetPath = scriptSourcePath
64
+ if (attributes['asciidoctor-log-integration'] === 'copy-to-build-dir') {
65
+ scriptTargetPath = ospath.join(dir, 'asciidoctor-log-adapter.rb')
66
+ await fsp.cp(scriptSourcePath, scriptTargetPath, { force: true, recursive: true })
67
+ }
68
+ attributes['asciidoctor-log-integration'] = scriptTargetPath
69
+ }
70
+ return attributes
71
+ }
72
+
73
+ module.exports = compileConversionAttributes
package/lib/configure.js CHANGED
@@ -53,8 +53,9 @@ function getAssemblerProfiles (contentCatalog, assemblerProfiles = new Map()) {
53
53
  [...(componentVersion.origins ?? [])].find((it) => it.descriptor?.ext?.assembler)
54
54
  const assemblerConfig = getAssemblerConfigFromDescriptor(source?.descriptor)
55
55
  if (!assemblerConfig) return
56
- const componentVersionRef = `${componentVersion.version}@${componentVersion.name}`
57
- const filesByPath = componentVersion.files.reduce((accum, it) => accum.set(it.path, it), new Map())
56
+ const { name: componentName, version, files } = componentVersion
57
+ const componentVersionKey = `${version}@${componentName}`
58
+ const filesByPath = files.reduce((accum, it) => accum.set(it.path, it), new Map())
58
59
  const componentVersionProfiles = assemblerConfig.reduce((accum, entry) => {
59
60
  const data = {}
60
61
  const profile = entry.profile ?? undefined
@@ -69,8 +70,9 @@ function getAssemblerProfiles (contentCatalog, assemblerProfiles = new Map()) {
69
70
  data.navFiles = (nav.length ? [...new Set(nav)] : nav).reduce((navFiles, path_) => {
70
71
  const navFile = filesByPath.get(path_)
71
72
  if (navFile) {
72
- navFiles.push(initNavFile(navFile, component.name, componentVersion.version, navFiles.length))
73
+ navFiles.push(initNavFile(navFile, componentName, version, navFiles.length))
73
74
  } else {
75
+ const componentVersionRef = `${version === 'master' ? '' : version}@${componentName}`
74
76
  ;(data.messages ??= []).push([
75
77
  'warn',
76
78
  { source },
@@ -84,7 +86,7 @@ function getAssemblerProfiles (contentCatalog, assemblerProfiles = new Map()) {
84
86
  }
85
87
  return accum.set(profile, data)
86
88
  }, new Map())
87
- assemblerProfiles.set(componentVersionRef, componentVersionProfiles)
89
+ assemblerProfiles.set(componentVersionKey, componentVersionProfiles)
88
90
  })
89
91
  })
90
92
  return assemblerProfiles
package/lib/constants.js CHANGED
@@ -19,4 +19,5 @@ module.exports = Object.freeze({
19
19
  'rootLevel',
20
20
  'sectionMergeStrategy',
21
21
  ],
22
+ CAMEL_CASE_STOP_KEYS: ['asciidoc.attributes', 'assembly.attributes'],
22
23
  })
package/lib/index.js CHANGED
@@ -3,4 +3,4 @@
3
3
  const assembleContent = require('./assemble-content')
4
4
  const configure = require('./configure')
5
5
 
6
- module.exports = { assembleContent, configure, configureAssembler: configure }
6
+ module.exports = { assembleContent, configure }
@@ -1,13 +1,13 @@
1
1
  'use strict'
2
2
 
3
+ const deepClone = require('./util/deep-clone')
3
4
  const expandPath = require('@antora/expand-path-helper')
4
5
  const fsp = require('node:fs/promises')
5
6
  const os = require('node:os')
6
7
  const ospath = require('node:path')
7
8
  const yaml = require('js-yaml')
8
9
 
9
- const { LEGACY_ASSEMBLY_KEYS } = require('./constants')
10
- const CAMEL_CASE_STOP_PATHS = ['asciidoc.attributes', 'assembly.attributes']
10
+ const { CAMEL_CASE_STOP_KEYS, LEGACY_ASSEMBLY_KEYS } = require('./constants')
11
11
  const PACKAGE_NAME = require('../package.json').name
12
12
  const YAML_SCHEMA = yaml.CORE_SCHEMA.withTags(yaml.mergeTag)
13
13
 
@@ -15,7 +15,7 @@ function loadConfig (configSource, playbook, preferredQualifier = '') {
15
15
  let resolvedConfigSource
16
16
  return (
17
17
  configSource?.constructor === Object
18
- ? Promise.resolve(configSource)
18
+ ? Promise.resolve(deepClone(configSource))
19
19
  : fileExists(
20
20
  (resolvedConfigSource = expandPath(configSource ?? `./antora-assembler${preferredQualifier}.yml`, {
21
21
  dot: playbook.dir,
@@ -38,7 +38,7 @@ function loadConfig (configSource, playbook, preferredQualifier = '') {
38
38
  return {}
39
39
  }
40
40
  return fsp.readFile(resolvedConfigSource).then((data) =>
41
- Object.assign(camelCaseKeys(yaml.load(data, { schema: YAML_SCHEMA }), CAMEL_CASE_STOP_PATHS), {
41
+ Object.assign(camelCaseKeys(yaml.load(data, { schema: YAML_SCHEMA }), CAMEL_CASE_STOP_KEYS), {
42
42
  file: resolvedConfigSource,
43
43
  })
44
44
  )
@@ -141,7 +141,7 @@ function camelCaseKeys (o, stopPaths, p = undefined) {
141
141
  const accum = {}
142
142
  for (const [k, v] of Object.entries(o)) {
143
143
  const camelKey = k.charAt() + k.substring(1).replace(/_([a-z])/g, (_, l) => l.toUpperCase())
144
- accum[camelKey] = ~stopPaths.indexOf(pathPrefix + camelKey) ? v : camelCaseKeys(v, stopPaths, pathPrefix + camelKey)
144
+ accum[camelKey] = stopPaths.includes(pathPrefix + camelKey) ? v : camelCaseKeys(v, stopPaths, pathPrefix + camelKey)
145
145
  }
146
146
  return accum
147
147
  }
@@ -1,14 +1,14 @@
1
1
  'use strict'
2
2
 
3
- function logCommand (loggerName, command, extraArgsOrAttributeOptionFlag, file, convertAttributes) {
3
+ function logCommand (loggerName, command, extraArgsOrAttributeOptionFlag, file, attributes) {
4
4
  const logger = this?.getLogger(loggerName)
5
5
  if (!logger?.isLevelEnabled('debug')) return
6
- const { docfile, 'assembler-filetype': filetype } = convertAttributes
6
+ const { docfile, 'assembler-filetype': filetype } = attributes
7
7
  const args = (
8
8
  Array.isArray(extraArgsOrAttributeOptionFlag)
9
9
  ? extraArgsOrAttributeOptionFlag
10
10
  : extraArgsOrAttributeOptionFlag
11
- ? convertAttributes.toArgs(extraArgsOrAttributeOptionFlag)
11
+ ? attributes.toArgs(extraArgsOrAttributeOptionFlag)
12
12
  : []
13
13
  ).map((it) => (~it.indexOf(' ') ? `'${it}'` : it))
14
14
  const ctx = { command: [command].concat(args).join(' '), file: { path: docfile } }