@antora/assembler 1.0.0-rc.1 → 1.0.0-rc.10
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/assemble-content.js +75 -92
- package/lib/compile-conversion-attributes.js +76 -0
- package/lib/configure.js +19 -15
- package/lib/constants.js +2 -0
- package/lib/filter-component-versions.js +1 -1
- package/lib/index.js +1 -1
- package/lib/load-config.js +25 -19
- package/lib/log-command.js +4 -6
- package/lib/produce-assembly-file.js +328 -269
- package/lib/produce-assembly-files.js +124 -144
- package/lib/util/collate-asciidoc-attributes.js +32 -0
- package/lib/util/deep-clone.js +18 -0
- package/lib/util/generate-scoped-id.js +1 -0
- package/lib/util/identify-mutable-attributes.js +25 -0
- package/lib/util/lazy-readable.js +12 -3
- package/lib/util/matcher.js +1 -1
- package/lib/util/rewriter.js +37 -12
- package/lib/util/to-hash.js +7 -0
- package/package.json +8 -10
- package/lib/select-mutable-attributes.js +0 -27
package/lib/assemble-content.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
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')
|
|
@@ -11,47 +11,56 @@ const produceAssemblyFiles = require('./produce-assembly-files')
|
|
|
11
11
|
const PromiseQueue = require('./util/promise-queue')
|
|
12
12
|
const runCommand = require('@antora/run-command-helper')
|
|
13
13
|
|
|
14
|
-
const invariably = { new: () => ({}), void: () => undefined }
|
|
14
|
+
const invariably = { new: () => ({}), null: () => null, void: () => undefined }
|
|
15
15
|
const PACKAGE_NAME = require('../package.json').name
|
|
16
16
|
const NEWLINE_RX = /(?:\r?\n)+/
|
|
17
17
|
|
|
18
|
-
async function assembleContent (playbook, contentCatalog, converter,
|
|
18
|
+
async function assembleContent (playbook, contentCatalog, converter, providers) {
|
|
19
|
+
const { configSource, navigationCatalog, componentVersionFilter } = providers
|
|
19
20
|
const {
|
|
20
21
|
convert = converter,
|
|
21
22
|
getDefaultCommand,
|
|
22
23
|
extname: targetExtname = '',
|
|
23
24
|
backend: targetBackend = targetExtname.substring(1),
|
|
25
|
+
format: targetFormat = targetBackend,
|
|
24
26
|
embedReferenceStyle = 'relative',
|
|
25
27
|
mediaType: targetMediaType,
|
|
26
|
-
loggerName = PACKAGE_NAME
|
|
28
|
+
loggerName = `${PACKAGE_NAME} [${targetBackend}-exporter]`,
|
|
29
|
+
xmlCompliant,
|
|
27
30
|
} = converter ?? {}
|
|
28
|
-
const assemblerConfig = await loadConfig.call(this,
|
|
29
|
-
if (assemblerConfig.enabled === false) return []
|
|
31
|
+
const assemblerConfig = await loadConfig.call(this, configSource, playbook, targetBackend ? '-' + targetBackend : '')
|
|
32
|
+
if (assemblerConfig.enabled === false || !contentCatalog.publishableFamilies?.has('export')) return []
|
|
30
33
|
const context = isBound(this)
|
|
31
34
|
? this
|
|
32
35
|
: {
|
|
33
36
|
getFunctions: invariably.new,
|
|
34
37
|
getLogger: invariably.void,
|
|
35
38
|
getVariables: invariably.new,
|
|
39
|
+
require,
|
|
36
40
|
}
|
|
37
41
|
const generatorFunctions = context.getFunctions()
|
|
38
|
-
const { loadAsciiDoc = require('@antora/asciidoc-loader') } = generatorFunctions
|
|
42
|
+
const { loadAsciiDoc = context.require('@antora/asciidoc-loader') } = generatorFunctions
|
|
39
43
|
const { assembly: assemblyConfig, build: buildConfig } = assemblerConfig
|
|
40
44
|
assemblyConfig.embedReferenceStyle = embedReferenceStyle
|
|
45
|
+
if (xmlCompliant) assemblyConfig.xmlIds ??= true
|
|
41
46
|
const profile = (assemblyConfig.profile ??= targetBackend)
|
|
42
|
-
const intrinsicAttributes = { 'loader-assembler': '' }
|
|
43
|
-
buildConfig.cwd ??= process.cwd()
|
|
47
|
+
const intrinsicAttributes = { 'loader-assembler': '', 'assembler-root-level': assemblyConfig.rootLevel }
|
|
48
|
+
const cwd = (buildConfig.cwd ??= process.cwd())
|
|
44
49
|
if (profile) {
|
|
45
50
|
buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), `build/assembler/${profile}`)
|
|
46
51
|
intrinsicAttributes[`assembler-profile-${profile}`] = ''
|
|
47
52
|
intrinsicAttributes['assembler-profile'] = profile
|
|
48
|
-
if (targetBackend) {
|
|
49
|
-
intrinsicAttributes[`assembler-backend-${targetBackend}`] = ''
|
|
50
|
-
intrinsicAttributes['assembler-backend'] = targetBackend
|
|
51
|
-
}
|
|
52
53
|
} else {
|
|
53
54
|
buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), 'build/assembler/_')
|
|
54
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
|
+
}
|
|
55
64
|
if (targetExtname) {
|
|
56
65
|
const targetFiletype = targetExtname.substring(1)
|
|
57
66
|
intrinsicAttributes[`assembler-filetype-${targetFiletype}`] = ''
|
|
@@ -62,38 +71,45 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
62
71
|
loadAsciiDoc,
|
|
63
72
|
contentCatalog,
|
|
64
73
|
assemblerConfig,
|
|
65
|
-
|
|
74
|
+
generateSelectAssemblerProfile(context, contentCatalog, assemblyConfig, intrinsicAttributes, navigationCatalog),
|
|
75
|
+
typeof componentVersionFilter === 'function' ? componentVersionFilter : undefined
|
|
66
76
|
)
|
|
67
77
|
if (!(assemblyFiles.length && typeof convert === 'function')) return assemblyFiles
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
const { publishSite: publishFiles = require('@antora/site-publisher') } = generatorFunctions
|
|
78
|
+
buildConfig.command ??= typeof getDefaultCommand === 'function' ? await getDefaultCommand(cwd, playbook) : null
|
|
79
|
+
const { publishSite: publishFiles = context.require('@antora/site-publisher') } = generatorFunctions
|
|
72
80
|
await prepareWorkspace(publishFiles, assemblyFiles, buildConfig)
|
|
73
|
-
const helpers = {
|
|
81
|
+
const helpers = { runCommand }
|
|
82
|
+
Object.defineProperty(helpers, 'logger', {
|
|
83
|
+
get: () => context?.getLogger(loggerName),
|
|
84
|
+
})
|
|
85
|
+
Object.defineProperty(helpers, 'logCommand', {
|
|
86
|
+
get: () => logCommand.bind(null, helpers.logger),
|
|
87
|
+
})
|
|
74
88
|
const boundConvert = convert.bind(context)
|
|
89
|
+
const boundResolveFileOrContents = resolveFileOrContents.bind(context)
|
|
75
90
|
return new PromiseQueue({ concurrency: buildConfig.processLimit })
|
|
76
91
|
.add(
|
|
77
92
|
assemblyFiles.map((doc) => async () => {
|
|
78
93
|
const relativeToOutput = embedReferenceStyle === 'output-relative'
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
const attributes = await compileConversionAttributes(doc, targetExtname, assemblerConfig, relativeToOutput)
|
|
95
|
+
return boundConvert(doc, attributes, buildConfig, helpers).then((result) =>
|
|
96
|
+
boundResolveFileOrContents(result, attributes, buildConfig, loggerName).then((fileOrContents) =>
|
|
97
|
+
coerceToExportFormat(doc, targetBackend, targetExtname, targetMediaType, fileOrContents)
|
|
98
|
+
)
|
|
99
|
+
)
|
|
85
100
|
})
|
|
86
101
|
)
|
|
87
102
|
.toPromise()
|
|
88
103
|
.then((files) => {
|
|
89
|
-
|
|
104
|
+
const { publish, qualifyExports } = buildConfig
|
|
105
|
+
if (!publish) {
|
|
90
106
|
for (const file of files) delete file.assembler.assembled
|
|
91
107
|
return files
|
|
92
108
|
}
|
|
93
|
-
const qualifyExports = buildConfig.qualifyExports
|
|
94
109
|
return files.map((file) => {
|
|
95
|
-
const pages = file.assembler.assembled.pages
|
|
110
|
+
const pages = file.isNull() ? undefined : file.assembler.assembled.pages
|
|
96
111
|
delete file.assembler.assembled
|
|
112
|
+
if (!pages) return file
|
|
97
113
|
file = contentCatalog.addFile(file)
|
|
98
114
|
const extname = file.extname
|
|
99
115
|
const download = file.assembler.downloadStem + extname
|
|
@@ -106,6 +122,7 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
106
122
|
const assemblerMeta = (page.assembler ??= {})
|
|
107
123
|
const exports = (assemblerMeta.exports ??= [])
|
|
108
124
|
const exportEntry = { fragment, file }
|
|
125
|
+
if (fragment === pages.rootPageFragment) exportEntry.root = true
|
|
109
126
|
const insertIdx = exports.findIndex(
|
|
110
127
|
({ file: candidate }) =>
|
|
111
128
|
!(candidate.src.component === page.src.component && candidate.src.version === page.src.version)
|
|
@@ -125,11 +142,11 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
125
142
|
}
|
|
126
143
|
|
|
127
144
|
/**
|
|
128
|
-
* Generates a function that selects the active
|
|
145
|
+
* Generates a function that selects the active assembler profile, initializes an assembly model using
|
|
129
146
|
* the keys from the profile as well as any inherited shared keys, builds the navigation for the assembly, and
|
|
130
147
|
* returns the initialized assembly model. The assembly model is further populated after the call to this function.
|
|
131
148
|
*/
|
|
132
|
-
function
|
|
149
|
+
function generateSelectAssemblerProfile (context, contentCatalog, baseModel, intrinsicAttributes, navigationCatalog) {
|
|
133
150
|
const logger = context.getLogger?.(PACKAGE_NAME)
|
|
134
151
|
const { assemblerProfiles } = context.getVariables()
|
|
135
152
|
if (!assemblerProfiles) {
|
|
@@ -140,7 +157,7 @@ function generateSelectAssemblyProfile (context, contentCatalog, baseModel, intr
|
|
|
140
157
|
}
|
|
141
158
|
}
|
|
142
159
|
const boundSendToLog = sendToLog.bind(logger)
|
|
143
|
-
const { buildAlternateNavigation = require('@antora/navigation-builder').buildAlternateNavigation } =
|
|
160
|
+
const { buildAlternateNavigation = context.require('@antora/navigation-builder').buildAlternateNavigation } =
|
|
144
161
|
context.getFunctions()
|
|
145
162
|
return (componentVersion) => {
|
|
146
163
|
const componentVersionProfiles = assemblerProfiles.get(componentVersion.version + '@' + componentVersion.name)
|
|
@@ -148,77 +165,39 @@ function generateSelectAssemblyProfile (context, contentCatalog, baseModel, intr
|
|
|
148
165
|
const navigation = navigationCatalog?.getNavigation(componentVersion.name, componentVersion.version)
|
|
149
166
|
const attributes = Object.assign({}, baseModel.attributes)
|
|
150
167
|
const model = Object.assign({}, baseModel, overrides, { attributes, logger })
|
|
151
|
-
if (!overrides) return
|
|
168
|
+
if (!overrides) return Object.assign(model, { navigation: navigation || componentVersion.navigation })
|
|
169
|
+
if ('rootLevel' in overrides) attributes['assembler-root-level'] = overrides.rootLevel
|
|
152
170
|
delete model.navFiles
|
|
153
171
|
delete model.messages
|
|
154
|
-
if (overrides.attributes)
|
|
172
|
+
if (overrides.attributes) {
|
|
173
|
+
for (const [name, val] of Object.entries(overrides.attributes)) {
|
|
174
|
+
if (!(name in intrinsicAttributes)) attributes[name] = val
|
|
175
|
+
}
|
|
176
|
+
}
|
|
155
177
|
if (navigation) return Object.assign(model, { navigation })
|
|
156
178
|
overrides.messages?.forEach(boundSendToLog)
|
|
157
179
|
const navFiles = overrides.navFiles
|
|
158
180
|
if (!navFiles) return Object.assign(model, { navigation: componentVersion.navigation })
|
|
159
181
|
if (!navFiles.length) return Object.assign(model, { navigation: [] })
|
|
160
182
|
model.navigation = buildAlternateNavigation(contentCatalog, componentVersion, navFiles, {
|
|
161
|
-
attributes:
|
|
183
|
+
attributes: model.attributes,
|
|
162
184
|
})
|
|
163
185
|
return model
|
|
164
186
|
}
|
|
165
187
|
}
|
|
166
188
|
|
|
167
|
-
function
|
|
168
|
-
const {
|
|
169
|
-
asciidoc: { attributes: docAttributes } = { attributes: {} },
|
|
170
|
-
extname: docfilesuffix,
|
|
171
|
-
path: reldocfile,
|
|
172
|
-
src: { family, relative },
|
|
173
|
-
} = doc
|
|
174
|
-
const { cwd = process.cwd(), dir = cwd } = assemblerConfig.build
|
|
175
|
-
const docname = family + '$' + relative.substring(0, relative.length - docfilesuffix.length)
|
|
176
|
-
const docfile = ospath.join(dir, reldocfile)
|
|
177
|
-
const outdir = ospath.dirname(docfile)
|
|
178
|
-
const docdir = relativeToOutput ? dir : outdir
|
|
179
|
-
const outfile = docfile.substring(0, docfile.length - docfilesuffix.length) + targetExtname
|
|
180
|
-
const attributes = Object.assign({ revdate: `${assemblerConfig.assembly.revdate}@` }, docAttributes, {
|
|
181
|
-
docdir,
|
|
182
|
-
docfile,
|
|
183
|
-
docfilesuffix,
|
|
184
|
-
'docname@': docname,
|
|
185
|
-
imagesdir: '',
|
|
186
|
-
outdir,
|
|
187
|
-
outfile,
|
|
188
|
-
outfilesuffix: targetExtname,
|
|
189
|
-
toArgs (optionFlag) {
|
|
190
|
-
const args = []
|
|
191
|
-
for (let [name, val] of Object.entries(this)) {
|
|
192
|
-
if (val) {
|
|
193
|
-
val = name + '=' + val
|
|
194
|
-
} else if (val === '') {
|
|
195
|
-
if (name === 'asciidoctor-log-integration') {
|
|
196
|
-
args.push('-r', require.resolve('#asciidoctor-log-adapter'))
|
|
197
|
-
continue
|
|
198
|
-
}
|
|
199
|
-
val = name
|
|
200
|
-
} else {
|
|
201
|
-
val = `${name}!${val === false ? '@' : ''}`
|
|
202
|
-
}
|
|
203
|
-
args.push(optionFlag, val)
|
|
204
|
-
}
|
|
205
|
-
return args
|
|
206
|
-
},
|
|
207
|
-
})
|
|
208
|
-
return Object.defineProperty(attributes, 'toArgs', { enumerable: false })
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function coerceToExportFormat (originalFile, targetBackend, targetExtname, targetMediaType, fileOrContents) {
|
|
189
|
+
function coerceToExportFormat (assemblyFile, targetBackend, targetExtname, targetMediaType, fileOrContents) {
|
|
212
190
|
const file =
|
|
213
191
|
fileOrContents == null || Buffer.isBuffer(fileOrContents) || typeof fileOrContents.pipe === 'function'
|
|
214
|
-
? Object.assign(
|
|
192
|
+
? Object.assign(assemblyFile, { contents: fileOrContents })
|
|
215
193
|
: fileOrContents
|
|
216
194
|
;(file.assembler ??= {}).backend = targetBackend
|
|
217
195
|
if (file.extname === targetExtname) return file
|
|
218
196
|
const { path: sourcePath, extname: sourceExtname } = file
|
|
219
197
|
const relativeWithoutExtname = file.src.relative.substring(0, file.src.relative.length - sourceExtname.length)
|
|
220
198
|
const newPath = sourcePath.substring(0, sourcePath.length - sourceExtname.length) + targetExtname
|
|
221
|
-
Object.assign(file, { mediaType: (file.src.mediaType = targetMediaType), path: newPath })
|
|
199
|
+
Object.assign(file, { mediaType: (file.src.mediaType = targetMediaType), path: (file.src.path = newPath) })
|
|
200
|
+
delete file.src.abspath
|
|
222
201
|
file.src.basename = path.basename((file.src.relative = relativeWithoutExtname + (file.src.extname = targetExtname)))
|
|
223
202
|
return file
|
|
224
203
|
}
|
|
@@ -241,8 +220,9 @@ function prepareWorkspace (publishFiles, assemblyFiles, buildConfig) {
|
|
|
241
220
|
}
|
|
242
221
|
if (keepSource) {
|
|
243
222
|
for (const file of assemblyFiles) {
|
|
244
|
-
file.src.contents = file.contents
|
|
245
223
|
file.out = { path: file.path }
|
|
224
|
+
file.src.contents = file.contents
|
|
225
|
+
file.src.abspath = ospath.join(dir, file.path)
|
|
246
226
|
files.push(file)
|
|
247
227
|
}
|
|
248
228
|
}
|
|
@@ -253,7 +233,7 @@ function prepareWorkspace (publishFiles, assemblyFiles, buildConfig) {
|
|
|
253
233
|
})
|
|
254
234
|
}
|
|
255
235
|
|
|
256
|
-
function resolveFileOrContents (convertResult,
|
|
236
|
+
function resolveFileOrContents (convertResult, attributes, buildConfig, loggerName) {
|
|
257
237
|
let fileOrContents
|
|
258
238
|
if (convertResult?.status != null) {
|
|
259
239
|
if ('file' in convertResult) {
|
|
@@ -264,12 +244,14 @@ function resolveFileOrContents (convertResult, convertAttributes, buildConfig, l
|
|
|
264
244
|
fileOrContents = convertResult.stdout
|
|
265
245
|
}
|
|
266
246
|
let logger, match
|
|
267
|
-
if (buildConfig.stderrSink === 'log' && convertResult.stderr
|
|
268
|
-
const docfile =
|
|
247
|
+
if (buildConfig.stderrSink === 'log' && convertResult.stderr?.length && (logger = this.getLogger(loggerName))) {
|
|
248
|
+
const docfile = attributes.docfile
|
|
269
249
|
const command = buildConfig.command
|
|
250
|
+
const file = { path: docfile }
|
|
270
251
|
const stderr = convertResult.stderr.toString().trimEnd()
|
|
252
|
+
const additionalLines = ['Additional stderr lines from command:']
|
|
271
253
|
stderr.split(NEWLINE_RX).forEach((line) => {
|
|
272
|
-
const ctx = { command, file
|
|
254
|
+
const ctx = { command, file }
|
|
273
255
|
if (line.charAt() === '{' && line.charAt(line.length - 1) === '}') {
|
|
274
256
|
const entry = JSON.parse(line)
|
|
275
257
|
if (entry.name) ctx.program = entry.name
|
|
@@ -285,16 +267,17 @@ function resolveFileOrContents (convertResult, convertAttributes, buildConfig, l
|
|
|
285
267
|
if (lineno) ctx.line = parseInt(lineno, 10)
|
|
286
268
|
logger[level === 'WARNING' ? 'warn' : level.toLowerCase()](ctx, msg)
|
|
287
269
|
} else {
|
|
288
|
-
|
|
270
|
+
additionalLines.push(line)
|
|
289
271
|
}
|
|
290
272
|
})
|
|
273
|
+
if (additionalLines.length > 1) logger.info({ command, file }, additionalLines.join('\n'))
|
|
291
274
|
}
|
|
292
275
|
} else if (convertResult !== undefined) {
|
|
293
|
-
return convertResult
|
|
276
|
+
return Promise.resolve(convertResult)
|
|
294
277
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
278
|
+
if (fileOrContents !== undefined) return Promise.resolve(fileOrContents)
|
|
279
|
+
const outfile = attributes.outfile
|
|
280
|
+
return fsp.access(outfile).then(() => new LazyReadable(outfile), invariably.null)
|
|
298
281
|
}
|
|
299
282
|
|
|
300
283
|
function isBound (obj) {
|
|
@@ -0,0 +1,76 @@
|
|
|
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 = (doc.src.path = ospath.join(dir, reldocfile))
|
|
16
|
+
const outdir = ospath.dirname(docfile)
|
|
17
|
+
const outfile = docfile.substring(0, docfile.length - docfilesuffix.length) + targetExtname
|
|
18
|
+
const docdir = relativeToOutput ? dir : outdir
|
|
19
|
+
//const imagesoutdir = ospath.join(outdir, '..', '_images/generated')
|
|
20
|
+
const imagesoutdir = outdir
|
|
21
|
+
const attributes = Object.assign({ revdate: `${assemblerConfig.assembly.revdate}@` }, docAttributes, {
|
|
22
|
+
docdir,
|
|
23
|
+
docfile,
|
|
24
|
+
docfilesuffix,
|
|
25
|
+
docname,
|
|
26
|
+
imagesdir: '',
|
|
27
|
+
imagesoutdir,
|
|
28
|
+
outdir,
|
|
29
|
+
outfile,
|
|
30
|
+
outfilesuffix: targetExtname,
|
|
31
|
+
toArgs (attributeOptionFlag, outputOptionFlag) {
|
|
32
|
+
const args = []
|
|
33
|
+
let requireAsciidoctorLogAdapter
|
|
34
|
+
for (const [name, val] of Object.entries(this)) {
|
|
35
|
+
let optionValue
|
|
36
|
+
if (name === 'asciidoctor-log-integration') {
|
|
37
|
+
if ((val ?? false) !== false) requireAsciidoctorLogAdapter = val
|
|
38
|
+
continue
|
|
39
|
+
} else if ((val ?? false) === false) {
|
|
40
|
+
optionValue = `${name}!${val === false ? '=@' : ''}`
|
|
41
|
+
} else {
|
|
42
|
+
optionValue = val === '' ? name : name + '=' + val
|
|
43
|
+
}
|
|
44
|
+
args.push(attributeOptionFlag, optionValue)
|
|
45
|
+
}
|
|
46
|
+
if (requireAsciidoctorLogAdapter) args.push('-r', requireAsciidoctorLogAdapter)
|
|
47
|
+
if (outputOptionFlag) args.push(outputOptionFlag, this.outfile)
|
|
48
|
+
return args
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
Object.defineProperty(attributes, 'outfilesuffix', {
|
|
52
|
+
get () {
|
|
53
|
+
return ospath.extname(this.outfile)
|
|
54
|
+
},
|
|
55
|
+
set (value) {
|
|
56
|
+
const outfile = this.outfile
|
|
57
|
+
const extname = ospath.extname(outfile)
|
|
58
|
+
if (extname && outfile.endsWith(extname)) this.outfile = outfile.substring(0, outfile.length - extname.length)
|
|
59
|
+
this.outfile += value
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
Object.defineProperty(attributes, 'toArgs', { enumerable: false })
|
|
63
|
+
if (mkdirs) await fsp.mkdir(outdir, { recursive: true, force: true })
|
|
64
|
+
if (attributes['asciidoctor-log-integration'] != null) {
|
|
65
|
+
const scriptSourcePath = require.resolve('#asciidoctor-log-adapter')
|
|
66
|
+
let scriptTargetPath = scriptSourcePath
|
|
67
|
+
if (attributes['asciidoctor-log-integration'] === 'copy-to-build-dir') {
|
|
68
|
+
scriptTargetPath = ospath.join(dir, 'asciidoctor-log-adapter.rb')
|
|
69
|
+
await fsp.cp(scriptSourcePath, scriptTargetPath, { force: true, recursive: true })
|
|
70
|
+
}
|
|
71
|
+
attributes['asciidoctor-log-integration'] = scriptTargetPath
|
|
72
|
+
}
|
|
73
|
+
return attributes
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = compileConversionAttributes
|
package/lib/configure.js
CHANGED
|
@@ -7,24 +7,26 @@ function configure (context, ...args) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function internalConfigure (converter, config = {}, providers = {}) {
|
|
10
|
-
this.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
if (!this.listeners('beforeProcess').includes(enableKeepSource)) {
|
|
11
|
+
this.once('componentsRegistered', ({ contentCatalog, assemblerProfiles }) => {
|
|
12
|
+
contentCatalog.publishableFamilies.add('export')
|
|
13
|
+
if (!assemblerProfiles) this.updateVariables({ assemblerProfiles: getAssemblerProfiles(contentCatalog) })
|
|
14
|
+
})
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
this.once('beforeProcess', enableKeepSource)
|
|
17
|
+
}
|
|
17
18
|
|
|
18
19
|
this.once('navigationBuilt', async ({ playbook, contentCatalog }) => {
|
|
19
|
-
const { assembleContent = require('./assemble-content'), ...
|
|
20
|
-
if (
|
|
21
|
-
|
|
20
|
+
const { assembleContent = require('./assemble-content'), ...assembleContentProviders } = providers
|
|
21
|
+
if (config.configSource?.constructor === Object) {
|
|
22
|
+
assembleContentProviders.configSource = config.configSource
|
|
23
|
+
await assembleContent.call(this, playbook, contentCatalog, converter, assembleContentProviders)
|
|
22
24
|
} else {
|
|
23
25
|
const singleConfig = !('configFiles' in config)
|
|
24
26
|
const configFiles = singleConfig ? config.configFile : config.configFiles
|
|
25
27
|
for (const configSource of Array.isArray(configFiles) ? configFiles : [configFiles]) {
|
|
26
|
-
const
|
|
27
|
-
await assembleContent.call(this, playbook, contentCatalog, converter,
|
|
28
|
+
const assembleContentProvidersWithConfigSource = Object.assign({}, assembleContentProviders, { configSource })
|
|
29
|
+
await assembleContent.call(this, playbook, contentCatalog, converter, assembleContentProvidersWithConfigSource)
|
|
28
30
|
if (singleConfig) break
|
|
29
31
|
}
|
|
30
32
|
}
|
|
@@ -51,8 +53,9 @@ function getAssemblerProfiles (contentCatalog, assemblerProfiles = new Map()) {
|
|
|
51
53
|
[...(componentVersion.origins ?? [])].find((it) => it.descriptor?.ext?.assembler)
|
|
52
54
|
const assemblerConfig = getAssemblerConfigFromDescriptor(source?.descriptor)
|
|
53
55
|
if (!assemblerConfig) return
|
|
54
|
-
const
|
|
55
|
-
const
|
|
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())
|
|
56
59
|
const componentVersionProfiles = assemblerConfig.reduce((accum, entry) => {
|
|
57
60
|
const data = {}
|
|
58
61
|
const profile = entry.profile ?? undefined
|
|
@@ -67,8 +70,9 @@ function getAssemblerProfiles (contentCatalog, assemblerProfiles = new Map()) {
|
|
|
67
70
|
data.navFiles = (nav.length ? [...new Set(nav)] : nav).reduce((navFiles, path_) => {
|
|
68
71
|
const navFile = filesByPath.get(path_)
|
|
69
72
|
if (navFile) {
|
|
70
|
-
navFiles.push(initNavFile(navFile,
|
|
73
|
+
navFiles.push(initNavFile(navFile, componentName, version, navFiles.length))
|
|
71
74
|
} else {
|
|
75
|
+
const componentVersionRef = `${version === 'master' ? '' : version}@${componentName}`
|
|
72
76
|
;(data.messages ??= []).push([
|
|
73
77
|
'warn',
|
|
74
78
|
{ source },
|
|
@@ -82,7 +86,7 @@ function getAssemblerProfiles (contentCatalog, assemblerProfiles = new Map()) {
|
|
|
82
86
|
}
|
|
83
87
|
return accum.set(profile, data)
|
|
84
88
|
}, new Map())
|
|
85
|
-
assemblerProfiles.set(
|
|
89
|
+
assemblerProfiles.set(componentVersionKey, componentVersionProfiles)
|
|
86
90
|
})
|
|
87
91
|
})
|
|
88
92
|
return assemblerProfiles
|
package/lib/constants.js
CHANGED
|
@@ -9,6 +9,7 @@ module.exports = Object.freeze({
|
|
|
9
9
|
'insertStartPage',
|
|
10
10
|
'profile',
|
|
11
11
|
'rootLevel',
|
|
12
|
+
'rootPageStyle',
|
|
12
13
|
'sectionMergeStrategy',
|
|
13
14
|
'xmlIds',
|
|
14
15
|
],
|
|
@@ -19,4 +20,5 @@ module.exports = Object.freeze({
|
|
|
19
20
|
'rootLevel',
|
|
20
21
|
'sectionMergeStrategy',
|
|
21
22
|
],
|
|
23
|
+
CAMEL_CASE_STOP_KEYS: ['asciidoc.attributes', 'assembly.attributes'],
|
|
22
24
|
})
|
|
@@ -5,7 +5,7 @@ const { filterCollection, compilePattern } = require('./util/matcher')
|
|
|
5
5
|
const VERSION_SEPARATOR_RX = /@(?!\()(?=(\w)?)/g
|
|
6
6
|
const US = '\x1f'
|
|
7
7
|
|
|
8
|
-
function filterComponentVersions (
|
|
8
|
+
function filterComponentVersions ({ names: patterns, prereleases = true }, components) {
|
|
9
9
|
if (!patterns.length) return []
|
|
10
10
|
const candidateMap = components.reduce((accum, { name: componentName, latest, versions }) => {
|
|
11
11
|
for (const version of versions) {
|
package/lib/index.js
CHANGED
package/lib/load-config.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
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
|
+
const YAML_SCHEMA = yaml.CORE_SCHEMA.withTags(yaml.mergeTag)
|
|
12
13
|
|
|
13
|
-
function loadConfig (
|
|
14
|
+
function loadConfig (configSource, playbook, preferredQualifier = '') {
|
|
14
15
|
let resolvedConfigSource
|
|
15
16
|
return (
|
|
16
17
|
configSource?.constructor === Object
|
|
17
|
-
? Promise.resolve(configSource)
|
|
18
|
+
? Promise.resolve(deepClone(configSource))
|
|
18
19
|
: fileExists(
|
|
19
20
|
(resolvedConfigSource = expandPath(configSource ?? `./antora-assembler${preferredQualifier}.yml`, {
|
|
20
21
|
dot: playbook.dir,
|
|
@@ -36,11 +37,11 @@ function loadConfig (playbook, configSource, preferredQualifier = '') {
|
|
|
36
37
|
}
|
|
37
38
|
return {}
|
|
38
39
|
}
|
|
39
|
-
return fsp
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
return fsp.readFile(resolvedConfigSource).then((data) =>
|
|
41
|
+
Object.assign(camelCaseKeys(yaml.load(data, { schema: YAML_SCHEMA }), CAMEL_CASE_STOP_KEYS), {
|
|
42
|
+
file: resolvedConfigSource,
|
|
43
|
+
})
|
|
44
|
+
)
|
|
44
45
|
})
|
|
45
46
|
).then((config) => {
|
|
46
47
|
if (config.enabled === false) return config
|
|
@@ -52,7 +53,7 @@ function loadConfig (playbook, configSource, preferredQualifier = '') {
|
|
|
52
53
|
}
|
|
53
54
|
if (componentVersionFilter.names == null) {
|
|
54
55
|
componentVersionFilter.names = ['*']
|
|
55
|
-
} else if (
|
|
56
|
+
} else if (componentVersionFilter.names.constructor === String) {
|
|
56
57
|
componentVersionFilter.names = componentVersionFilter.names.split(', ')
|
|
57
58
|
}
|
|
58
59
|
const remapAssemblyKeys = !('assembly' in config)
|
|
@@ -98,14 +99,19 @@ function loadConfig (playbook, configSource, preferredQualifier = '') {
|
|
|
98
99
|
build.dir &&= expandPath(build.dir, { dot: playbook.dir })
|
|
99
100
|
// used as cwd of command (and any scripts it requires)
|
|
100
101
|
build.cwd = build.cwd == null ? playbook.dir : expandPath(build.cwd, { dot: playbook.dir })
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
const command = build.command
|
|
103
|
+
if (command) {
|
|
104
|
+
if (command.constructor !== String) {
|
|
105
|
+
build.command = String(command)
|
|
106
|
+
} else if (~command.indexOf('$')) {
|
|
107
|
+
const vars = {
|
|
108
|
+
$NODE: process.execPath,
|
|
109
|
+
$NPM: ospath.join(process.execPath, '../npm'),
|
|
110
|
+
$NPX: ospath.join(process.execPath, '../npx'),
|
|
111
|
+
$PWD: build.cwd,
|
|
112
|
+
}
|
|
113
|
+
build.command = build.command.replace(/^\$(?:NODE|NP[MX])(?= )|\$PWD\b/g, (ref) => vars[ref])
|
|
107
114
|
}
|
|
108
|
-
build.command = build.command.replace(/^\$(?:NODE|NP[MX])(?= )|\$PWD\b/g, (ref) => vars[ref])
|
|
109
115
|
}
|
|
110
116
|
if (!('clean' in build) && 'output' in playbook) build.clean = playbook.output.clean
|
|
111
117
|
if (!('publish' in build)) build.publish = true
|
|
@@ -128,14 +134,14 @@ function loadConfig (playbook, configSource, preferredQualifier = '') {
|
|
|
128
134
|
})
|
|
129
135
|
}
|
|
130
136
|
|
|
131
|
-
function camelCaseKeys (o, stopPaths
|
|
137
|
+
function camelCaseKeys (o, stopPaths, p = undefined) {
|
|
132
138
|
if (Array.isArray(o)) return o.map((it) => camelCaseKeys(it, stopPaths, p))
|
|
133
139
|
if (o == null || o.constructor !== Object) return o
|
|
134
140
|
const pathPrefix = p ? p + '.' : ''
|
|
135
141
|
const accum = {}
|
|
136
142
|
for (const [k, v] of Object.entries(o)) {
|
|
137
143
|
const camelKey = k.charAt() + k.substring(1).replace(/_([a-z])/g, (_, l) => l.toUpperCase())
|
|
138
|
-
accum[camelKey] =
|
|
144
|
+
accum[camelKey] = stopPaths.includes(pathPrefix + camelKey) ? v : camelCaseKeys(v, stopPaths, pathPrefix + camelKey)
|
|
139
145
|
}
|
|
140
146
|
return accum
|
|
141
147
|
}
|
package/lib/log-command.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
function logCommand (
|
|
4
|
-
const logger = this?.getLogger(loggerName)
|
|
3
|
+
function logCommand (logger, command, extraArgsOrAttributeOptionFlag, file, attributes) {
|
|
5
4
|
if (!logger?.isLevelEnabled('debug')) return
|
|
6
|
-
const { docfile, 'assembler-filetype': filetype } = convertAttributes
|
|
7
5
|
const args = (
|
|
8
6
|
Array.isArray(extraArgsOrAttributeOptionFlag)
|
|
9
7
|
? extraArgsOrAttributeOptionFlag
|
|
10
8
|
: extraArgsOrAttributeOptionFlag
|
|
11
|
-
?
|
|
9
|
+
? attributes.toArgs(extraArgsOrAttributeOptionFlag)
|
|
12
10
|
: []
|
|
13
11
|
).map((it) => (~it.indexOf(' ') ? `'${it}'` : it))
|
|
14
|
-
const ctx = { command: [command].concat(args).join(' '), file:
|
|
12
|
+
const ctx = { command: [command].concat(args).join(' '), file: file.src }
|
|
15
13
|
const msg = `Running external command to export assembly in %s to %s: %s`
|
|
16
14
|
const componentVersionStr = file.src.version ? `${file.src.version}@${file.src.component}` : file.src.component
|
|
17
|
-
logger.debug(ctx, msg, componentVersionStr, filetype, file.src.relative)
|
|
15
|
+
logger.debug(ctx, msg, componentVersionStr, attributes['assembler-filetype'], file.src.relative)
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
module.exports = logCommand
|