@antora/assembler 1.0.0-beta.5 → 1.0.0-beta.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.
package/lib/assemble-content.js
CHANGED
|
@@ -13,6 +13,7 @@ const { stringify: toJSON } = JSON
|
|
|
13
13
|
|
|
14
14
|
const invariably = { new: () => ({}), void: () => undefined }
|
|
15
15
|
const PACKAGE_NAME = require('../package.json').name
|
|
16
|
+
const NEWLINE_RX = /(?:\r?\n)+/
|
|
16
17
|
|
|
17
18
|
async function assembleContent (playbook, contentCatalog, converter, { configSource, navigationCatalog }) {
|
|
18
19
|
const assemblerConfig = await loadConfig(playbook, configSource)
|
|
@@ -26,10 +27,20 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
26
27
|
}
|
|
27
28
|
const generatorFunctions = context.getFunctions()
|
|
28
29
|
const { loadAsciiDoc = require('@antora/asciidoc-loader') } = generatorFunctions
|
|
29
|
-
const
|
|
30
|
+
const {
|
|
31
|
+
convert = converter,
|
|
32
|
+
getDefaultCommand,
|
|
33
|
+
extname: targetExtname = '',
|
|
34
|
+
backend: targetBackend = targetExtname.slice(1),
|
|
35
|
+
embedReferenceStyle = 'relative',
|
|
36
|
+
mediaType: targetMediaType,
|
|
37
|
+
loggerName = PACKAGE_NAME,
|
|
38
|
+
} = converter ?? {}
|
|
30
39
|
const { assembly: assemblyConfig, build: buildConfig } = assemblerConfig
|
|
40
|
+
assemblyConfig.embedReferenceStyle = embedReferenceStyle
|
|
31
41
|
const { profile = targetBackend } = assemblyConfig
|
|
32
42
|
const intrinsicAttributes = { 'loader-assembler': '' }
|
|
43
|
+
buildConfig.cwd ??= process.cwd()
|
|
33
44
|
if (profile) {
|
|
34
45
|
buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), `build/assembler-${profile}`)
|
|
35
46
|
intrinsicAttributes[`assembler-profile-${profile}`] = ''
|
|
@@ -41,6 +52,11 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
41
52
|
} else {
|
|
42
53
|
buildConfig.dir ??= ospath.join(playbook.dir ?? process.cwd(), 'build/assembler')
|
|
43
54
|
}
|
|
55
|
+
if (targetExtname) {
|
|
56
|
+
const targetFiletype = targetExtname.slice(1)
|
|
57
|
+
intrinsicAttributes[`assembler-filetype-${targetFiletype}`] = ''
|
|
58
|
+
intrinsicAttributes['assembler-filetype'] = targetFiletype
|
|
59
|
+
}
|
|
44
60
|
Object.assign(assemblerConfig.asciidoc.attributes, intrinsicAttributes)
|
|
45
61
|
const assemblyFiles = produceAssemblyFiles(
|
|
46
62
|
loadAsciiDoc,
|
|
@@ -48,21 +64,23 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
48
64
|
assemblerConfig,
|
|
49
65
|
createResolveAssemblyModel(context, contentCatalog, assemblyConfig, intrinsicAttributes, navigationCatalog)
|
|
50
66
|
)
|
|
51
|
-
|
|
52
|
-
if (
|
|
67
|
+
if (!(assemblyFiles.length && typeof convert === 'function')) return assemblyFiles
|
|
68
|
+
if (typeof getDefaultCommand === 'function') {
|
|
69
|
+
buildConfig.command = await getDefaultCommand(buildConfig.cwd)
|
|
70
|
+
}
|
|
53
71
|
const { publishSite: publishFiles = require('@antora/site-publisher') } = generatorFunctions
|
|
54
|
-
await prepareWorkspace(publishFiles, assemblyFiles,
|
|
72
|
+
await prepareWorkspace(publishFiles, assemblyFiles, buildConfig)
|
|
55
73
|
const boundConvert = convert.bind(context)
|
|
56
74
|
return new PromiseQueue({ concurrency: buildConfig.processLimit })
|
|
57
75
|
.add(
|
|
58
76
|
assemblyFiles.map((doc) => async () => {
|
|
59
|
-
const
|
|
77
|
+
const relativeToOutput = embedReferenceStyle === 'output-relative'
|
|
78
|
+
const convertAttributes = prepareConvertAttributes(doc, targetExtname, relativeToOutput, buildConfig)
|
|
60
79
|
if (buildConfig.mkdirs) await fsp.mkdir(convertAttributes.outdir, { recursive: true, force: true })
|
|
61
|
-
return boundConvert(doc, convertAttributes, buildConfig).then(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
)
|
|
80
|
+
return boundConvert(doc, convertAttributes, buildConfig).then((result) => {
|
|
81
|
+
const fileOrContents = resolveFileOrContents.call(context, result, convertAttributes, buildConfig, loggerName)
|
|
82
|
+
return coerceToExportFormat(doc, targetBackend, targetExtname, targetMediaType, fileOrContents)
|
|
83
|
+
})
|
|
66
84
|
})
|
|
67
85
|
)
|
|
68
86
|
.toPromise()
|
|
@@ -99,23 +117,24 @@ async function assembleContent (playbook, contentCatalog, converter, { configSou
|
|
|
99
117
|
})
|
|
100
118
|
}
|
|
101
119
|
|
|
102
|
-
function createResolveAssemblyModel (context, contentCatalog,
|
|
120
|
+
function createResolveAssemblyModel (context, contentCatalog, common, intrinsicAttributes, navigationCatalog) {
|
|
121
|
+
const logger = context.getLogger?.(PACKAGE_NAME)
|
|
103
122
|
const { assemblerProfiles } = context.getVariables()
|
|
104
123
|
if (!assemblerProfiles) {
|
|
105
124
|
return (componentVersion) => {
|
|
106
125
|
const navigation =
|
|
107
126
|
navigationCatalog?.getNavigation(componentVersion.name, componentVersion.version) ?? componentVersion.navigation
|
|
108
|
-
return Object.assign({},
|
|
127
|
+
return Object.assign({ logger }, common, { navigation })
|
|
109
128
|
}
|
|
110
129
|
}
|
|
111
|
-
const boundSendToLog = sendToLog.bind(
|
|
130
|
+
const boundSendToLog = sendToLog.bind(logger)
|
|
112
131
|
const { buildNavigation = require('@antora/navigation-builder') } = context.getFunctions()
|
|
113
132
|
return (componentVersion) => {
|
|
114
133
|
const componentVersionProfiles = assemblerProfiles.get(componentVersion.version + '@' + componentVersion.name)
|
|
115
134
|
const overrides =
|
|
116
135
|
componentVersionProfiles?.get(intrinsicAttributes['assembler-profile']) ?? componentVersionProfiles?.get() ?? {}
|
|
117
136
|
const { navFiles, messages } = overrides
|
|
118
|
-
const model = Object.assign({},
|
|
137
|
+
const model = Object.assign({ logger }, common, overrides)
|
|
119
138
|
delete model.navFiles
|
|
120
139
|
delete model.messages
|
|
121
140
|
const navigationOverride = navigationCatalog?.getNavigation(componentVersion.name, componentVersion.version)
|
|
@@ -144,7 +163,7 @@ function createResolveAssemblyModel (context, contentCatalog, shared, intrinsicA
|
|
|
144
163
|
}
|
|
145
164
|
}
|
|
146
165
|
|
|
147
|
-
function prepareConvertAttributes (doc, targetExtname, buildConfig) {
|
|
166
|
+
function prepareConvertAttributes (doc, targetExtname, relativeToOutput, buildConfig) {
|
|
148
167
|
const {
|
|
149
168
|
asciidoc: { attributes: docAttributes } = { attributes: {} },
|
|
150
169
|
extname: docfilesuffix,
|
|
@@ -154,7 +173,8 @@ function prepareConvertAttributes (doc, targetExtname, buildConfig) {
|
|
|
154
173
|
const { cwd = process.cwd(), dir = cwd } = buildConfig
|
|
155
174
|
const docname = family + '$' + relative.slice(0, relative.length - docfilesuffix.length)
|
|
156
175
|
const docfile = ospath.join(dir, reldocfile)
|
|
157
|
-
const
|
|
176
|
+
const outdir = ospath.dirname(docfile)
|
|
177
|
+
const docdir = relativeToOutput ? dir : outdir
|
|
158
178
|
const imagesdir = ''
|
|
159
179
|
const outfile = docfile.slice(0, docfile.length - docfilesuffix.length) + targetExtname
|
|
160
180
|
const attributes = Object.assign({}, docAttributes, {
|
|
@@ -163,7 +183,7 @@ function prepareConvertAttributes (doc, targetExtname, buildConfig) {
|
|
|
163
183
|
docfilesuffix,
|
|
164
184
|
'docname@': docname,
|
|
165
185
|
imagesdir,
|
|
166
|
-
outdir
|
|
186
|
+
outdir,
|
|
167
187
|
outfile,
|
|
168
188
|
outfilesuffix: targetExtname,
|
|
169
189
|
toArgs (optionFlag, command) {
|
|
@@ -177,7 +197,7 @@ function prepareConvertAttributes (doc, targetExtname, buildConfig) {
|
|
|
177
197
|
} else {
|
|
178
198
|
val = `!${name}${val === false ? '@' : ''}`
|
|
179
199
|
}
|
|
180
|
-
args.push(
|
|
200
|
+
args.push(optionFlag, val)
|
|
181
201
|
}
|
|
182
202
|
return args
|
|
183
203
|
},
|
|
@@ -206,7 +226,7 @@ function findFirstExportWithExtname (extname) {
|
|
|
206
226
|
}
|
|
207
227
|
|
|
208
228
|
// TODO: if no workspace dir is defined, we shouldn't continue
|
|
209
|
-
function prepareWorkspace (publishFiles, assemblyFiles,
|
|
229
|
+
function prepareWorkspace (publishFiles, assemblyFiles, buildConfig) {
|
|
210
230
|
const { dir, clean, keepSource } = buildConfig
|
|
211
231
|
const files = []
|
|
212
232
|
const outPaths = new Set()
|
|
@@ -221,9 +241,42 @@ function prepareWorkspace (publishFiles, assemblyFiles, contentCatalog, buildCon
|
|
|
221
241
|
return publishFiles({ output: { clean, dir } }, { getFiles: () => files })
|
|
222
242
|
}
|
|
223
243
|
|
|
244
|
+
function resolveFileOrContents (convertResult, convertAttributes, buildConfig, loggerName) {
|
|
245
|
+
let fileOrContents
|
|
246
|
+
if (convertResult?.status != null) {
|
|
247
|
+
fileOrContents = 'file' in convertResult ? convertResult.file : convertResult.contents
|
|
248
|
+
let logger, match
|
|
249
|
+
if (buildConfig.stderrSink === 'log' && convertResult.stderr.length && (logger = this.getLogger(loggerName))) {
|
|
250
|
+
const docfile = convertAttributes.docfile
|
|
251
|
+
const command = buildConfig.command
|
|
252
|
+
const stderr = convertResult.stderr.toString().trimEnd()
|
|
253
|
+
stderr.split(NEWLINE_RX).forEach((line) => {
|
|
254
|
+
const ctx = { command, file: { path: docfile } }
|
|
255
|
+
if (line.charAt() === '{' && line.charAt(line.length - 1) === '}') {
|
|
256
|
+
const entry = JSON.parse(line)
|
|
257
|
+
if (entry.name) ctx.program = entry.name
|
|
258
|
+
if (entry.file?.line) ctx.line = entry.file.line
|
|
259
|
+
logger[entry.level](ctx, entry.msg)
|
|
260
|
+
} else if ((match = /^(.+):(\d+): warning: (.+)/.exec(line))) {
|
|
261
|
+
const [, scriptPath, lineno, msg] = match
|
|
262
|
+
ctx.stack = [{ file: { path: scriptPath }, line: parseInt(lineno, 10) }]
|
|
263
|
+
logger.warn(ctx, msg)
|
|
264
|
+
} else {
|
|
265
|
+
logger.info(ctx, line)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
} else if (convertResult !== undefined) {
|
|
270
|
+
return convertResult
|
|
271
|
+
}
|
|
272
|
+
return fileOrContents === undefined
|
|
273
|
+
? new LazyReadable(() => fs.createReadStream(convertAttributes.outfile))
|
|
274
|
+
: fileOrContents
|
|
275
|
+
}
|
|
276
|
+
|
|
224
277
|
function isBound (obj) {
|
|
225
278
|
if (obj == null) return false
|
|
226
|
-
for (const
|
|
279
|
+
for (const _ in obj) return true
|
|
227
280
|
return false
|
|
228
281
|
}
|
|
229
282
|
|
package/lib/load-config.js
CHANGED
|
@@ -5,6 +5,14 @@ const fsp = require('node:fs/promises')
|
|
|
5
5
|
const os = require('node:os')
|
|
6
6
|
const yaml = require('js-yaml')
|
|
7
7
|
|
|
8
|
+
const ASSEMBLY_KEYS = [
|
|
9
|
+
'rootLevel',
|
|
10
|
+
'insertStartPage',
|
|
11
|
+
'sectionMergeStrategy',
|
|
12
|
+
'linkReferenceStyle',
|
|
13
|
+
'dropExplicitXrefText',
|
|
14
|
+
]
|
|
15
|
+
|
|
8
16
|
function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
9
17
|
return (
|
|
10
18
|
configSource.constructor === Object
|
|
@@ -16,7 +24,11 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
16
24
|
() => false
|
|
17
25
|
)
|
|
18
26
|
.then((exists) =>
|
|
19
|
-
exists
|
|
27
|
+
exists
|
|
28
|
+
? fsp
|
|
29
|
+
.readFile(configSource)
|
|
30
|
+
.then((data) => Object.assign(camelCaseKeys(yaml.load(data), ['asciidoc']), { file: configSource }))
|
|
31
|
+
: {}
|
|
20
32
|
)
|
|
21
33
|
).then((config) => {
|
|
22
34
|
if (config.enabled === false) return undefined
|
|
@@ -42,7 +54,7 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
42
54
|
const remapAssemblyKeys = !('assembly' in config)
|
|
43
55
|
const assembly = (config.assembly ??= {})
|
|
44
56
|
if (remapAssemblyKeys) {
|
|
45
|
-
for (const key of
|
|
57
|
+
for (const key of ASSEMBLY_KEYS) {
|
|
46
58
|
if (!(key in config)) continue
|
|
47
59
|
assembly[key] = config[key]
|
|
48
60
|
delete config[key]
|
|
@@ -55,6 +67,12 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
55
67
|
if (['discrete', 'fuse', 'enclose'].indexOf(assembly.sectionMergeStrategy) < 0) {
|
|
56
68
|
assembly.sectionMergeStrategy = 'discrete'
|
|
57
69
|
}
|
|
70
|
+
if (['relative', 'root-relative', 'absolute'].indexOf(assembly.linkReferenceStyle) < 0) {
|
|
71
|
+
assembly.linkReferenceStyle = 'absolute'
|
|
72
|
+
}
|
|
73
|
+
if (['always', 'if-redundant', 'never'].indexOf(assembly.dropExplicitXrefText) < 0) {
|
|
74
|
+
assembly.dropExplicitXrefText = 'never'
|
|
75
|
+
}
|
|
58
76
|
const build = (config.build ??= {})
|
|
59
77
|
if (build.dir === '$' + '{playbook.output.dir}') {
|
|
60
78
|
throw new Error('Not implemented')
|
|
@@ -70,6 +88,14 @@ function loadConfig (playbook, configSource = './antora-assembler.yml') {
|
|
|
70
88
|
if (!build.processLimit) {
|
|
71
89
|
build.processLimit = 'processLimit' in build ? Infinity : Math.round(os.cpus().length * 0.5)
|
|
72
90
|
}
|
|
91
|
+
if ('stderr' in build) {
|
|
92
|
+
if (build.stderr === 'log') {
|
|
93
|
+
build.stderr = 'buffer'
|
|
94
|
+
build.stderrSink = 'log'
|
|
95
|
+
} else if (!['ignore', 'print'].includes(build.stderr)) {
|
|
96
|
+
delete build.stderr
|
|
97
|
+
}
|
|
98
|
+
}
|
|
73
99
|
return config
|
|
74
100
|
})
|
|
75
101
|
}
|
|
@@ -8,7 +8,7 @@ const unconvertInlineAsciiDoc = require('./util/unconvert-inline-asciidoc')
|
|
|
8
8
|
const AttributeEntryRx = /^:([^:-][^:]*):(?: .*)?$/
|
|
9
9
|
const BuiltInNamedEntities = { amp: '&', apos: "'", gt: '>', lt: '<', nbsp: ' ', quot: '"' }
|
|
10
10
|
const CharRefRx = /&(?:([a-z][a-z]+\d{0,2})|#(?:(\d{2,6})|x([a-z\d]{2,5})));/g
|
|
11
|
-
const DiscardAttributes = 'doctype leveloffset assembly-style underscore'.split(' ')
|
|
11
|
+
const DiscardAttributes = 'doctype leveloffset assembly-navtitle assembly-style underscore'.split(' ')
|
|
12
12
|
const ReservedIdNames = 'content header footnotes footer footer-text premable toc toctitle'.split(' ')
|
|
13
13
|
|
|
14
14
|
function produceAssemblyFile (
|
|
@@ -24,11 +24,10 @@ function produceAssemblyFile (
|
|
|
24
24
|
const pagesByUrl = files.reduce((map, it) => (it.src.family === 'page' ? map.set(it.pub.url, it) : map), new Map())
|
|
25
25
|
if (outline.urlType === 'internal' && !pagesByUrl.get(outline.url) && !(outline.items || []).length) return
|
|
26
26
|
const pagesInOutline = selectPagesInOutline(outline, pagesByUrl, componentVersion)
|
|
27
|
-
const navtitle = outline.content
|
|
28
27
|
const buffer = mergeAsciiDoc(
|
|
29
28
|
loadAsciiDoc,
|
|
30
29
|
contentCatalog,
|
|
31
|
-
buildAsciiDocHeader(componentVersion,
|
|
30
|
+
buildAsciiDocHeader(componentVersion, outline.content, assemblyModel),
|
|
32
31
|
componentVersion,
|
|
33
32
|
outline,
|
|
34
33
|
files,
|
|
@@ -38,7 +37,7 @@ function produceAssemblyFile (
|
|
|
38
37
|
assemblyModel
|
|
39
38
|
)
|
|
40
39
|
const rootLevel = assemblyModel.rootLevel
|
|
41
|
-
const stem = rootLevel === 0 ? 'index' : generateSlug(navtitle)
|
|
40
|
+
const stem = rootLevel === 0 ? 'index' : generateSlug(buffer.navtitle)
|
|
42
41
|
const downloadStem = [componentVersion.name, componentVersion.version, rootLevel === 0 ? '' : stem]
|
|
43
42
|
.filter((it) => it)
|
|
44
43
|
.join('-')
|
|
@@ -63,7 +62,7 @@ function buildAsciiDocHeader (componentVersion, navtitle, assemblyModel) {
|
|
|
63
62
|
let doctitle = navtitleAsciiDoc
|
|
64
63
|
if (navtitlePlain !== componentVersion.title) doctitle = `${componentVersion.title}: ${doctitle}`
|
|
65
64
|
const version = componentVersion.version === 'master' ? '' : componentVersion.version
|
|
66
|
-
|
|
65
|
+
const buffer = [
|
|
67
66
|
`= ${doctitle}`,
|
|
68
67
|
...(version ? [`:revnumber: ${version}`] : []),
|
|
69
68
|
...(doctype === 'article' ? [] : [`:doctype: ${doctype ?? 'book'}`]),
|
|
@@ -75,6 +74,7 @@ function buildAsciiDocHeader (componentVersion, navtitle, assemblyModel) {
|
|
|
75
74
|
`:page-component-display-version: ${componentVersion.displayVersion}`,
|
|
76
75
|
`:page-component-title: ${componentVersion.title}`,
|
|
77
76
|
]
|
|
77
|
+
return Object.assign(buffer, { navtitle })
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
function selectPagesInOutline (outlineEntry, pagesByUrl, componentVersion, accum) {
|
|
@@ -106,39 +106,57 @@ function mergeAsciiDoc (
|
|
|
106
106
|
supportsParts = false
|
|
107
107
|
) {
|
|
108
108
|
// TODO: we could try to be smart about it and make sure the page with fragment is included at least once
|
|
109
|
-
if (outlineEntry.hash)
|
|
110
|
-
|
|
109
|
+
if (outlineEntry.hash) {
|
|
110
|
+
buffer.inBody ??= false
|
|
111
|
+
return buffer
|
|
112
|
+
}
|
|
113
|
+
let navtitle = outlineEntry.content
|
|
114
|
+
let navtitlePlain = sanitize(navtitle)
|
|
115
|
+
let navtitleAsciiDoc = unconvertInlineAsciiDoc(navtitle)
|
|
116
|
+
const { items = [], unresolved, urlType, url } = outlineEntry
|
|
117
|
+
const {
|
|
118
|
+
doctype,
|
|
119
|
+
filetype,
|
|
120
|
+
embedReferenceStyle: embedRefStyle,
|
|
121
|
+
linkReferenceStyle: linkRefStyle,
|
|
122
|
+
outDirname,
|
|
123
|
+
siteRoot,
|
|
124
|
+
xmlIds,
|
|
125
|
+
} = assemblyModel
|
|
126
|
+
// FIXME: ideally, resource ID would be stored in navigation so we can look up the page more efficiently
|
|
127
|
+
const page = urlType === 'internal' && !unresolved ? pagesInOutline.get(url) : undefined
|
|
111
128
|
const atDocumentRoot = !buffer.inBody
|
|
112
|
-
const atBookRoot = atDocumentRoot && !level &&
|
|
129
|
+
const atBookRoot = atDocumentRoot && !level && doctype === 'book' && (supportsParts = true)
|
|
113
130
|
const hasItems = items.length > 0
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
const siteUrl = ((val) => {
|
|
117
|
-
if (!val || val === '/') return ''
|
|
118
|
-
return val.charAt(val.length - 1) === '/' ? val.slice(0, val.length - 1) : val
|
|
119
|
-
})(asciidocConfig.attributes['primary-site-url'] || asciidocConfig.attributes['site-url'])
|
|
120
|
-
const idSeparator = assemblyModel.xmlIds ? '-' : ':'
|
|
131
|
+
const pubRoot = outDirname ? '/' + outDirname : ''
|
|
132
|
+
const idSeparator = xmlIds ? '-' : ':'
|
|
121
133
|
const idScopeSeparator = idSeparator.repeat(3)
|
|
122
134
|
const idCoordinateSeparator = idSeparator === '-' ? '----' : idSeparator
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// IMPORTANT: this must not leave behind lines the parser will drop!
|
|
131
|
-
// IDEA: another option is to capture initial lineno of reader and use as offset (but preseves those blank lines)
|
|
132
|
-
contents = Buffer.from(
|
|
133
|
-
contents
|
|
134
|
-
.toString()
|
|
135
|
-
.replace(/^(?:[ \t]*\r\n?|[ \t]*\n)+/, '')
|
|
136
|
-
.trimRight()
|
|
137
|
-
)
|
|
138
|
-
const { component, version, module: module_, relative, origin } = page.src
|
|
135
|
+
if (page && !pagesInOutline.assembled.pages.has(page)) {
|
|
136
|
+
const contents = page.src.contents
|
|
137
|
+
if (contents == null) {
|
|
138
|
+
buffer.inBody ??= false
|
|
139
|
+
return buffer
|
|
140
|
+
}
|
|
141
|
+
const { component, version, module: module_, relative, origin, mediaType } = page.src
|
|
139
142
|
const topicPrefix = ~relative.indexOf('/') ? path.dirname(relative) + '/' : ''
|
|
140
|
-
const pageAsAsciiDoc = new page.constructor(
|
|
143
|
+
const pageAsAsciiDoc = new page.constructor(
|
|
144
|
+
Object.assign({}, page, { contents: trimAsciiDoc(contents), mediaType })
|
|
145
|
+
)
|
|
141
146
|
const doc = loadAsciiDoc(pageAsAsciiDoc, contentCatalog, asciidocConfig)
|
|
147
|
+
if (doc.hasAttribute('assembly-navtitle')) {
|
|
148
|
+
navtitleAsciiDoc = doc.getAttribute('assembly-navtitle')
|
|
149
|
+
navtitlePlain = sanitize((navtitle = doc.$apply_reftext_subs(navtitleAsciiDoc)))
|
|
150
|
+
if (buffer.inBody == null) {
|
|
151
|
+
buffer.navtitle = navtitle
|
|
152
|
+
// Q do we need to assert !level here?
|
|
153
|
+
if (assemblyModel.rootLevel) {
|
|
154
|
+
let doctitle = navtitleAsciiDoc
|
|
155
|
+
if (navtitlePlain !== componentVersion.title) doctitle = `${componentVersion.title}: ${doctitle}`
|
|
156
|
+
buffer[0] = `= ${doctitle}`
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
142
160
|
if (atDocumentRoot) {
|
|
143
161
|
const authors = doc.getAuthors()
|
|
144
162
|
if (authors.length) {
|
|
@@ -198,7 +216,6 @@ function mergeAsciiDoc (
|
|
|
198
216
|
}
|
|
199
217
|
buffer.push(`:page-module: ${module_}`)
|
|
200
218
|
buffer.push(`:page-relative-src-path: ${relative}`)
|
|
201
|
-
//buffer.push(`:page-origin-type: ${origin.type}`)
|
|
202
219
|
buffer.push(`:page-origin-url: ${origin.url}`)
|
|
203
220
|
buffer.push(`:page-origin-start-path:${origin.startPath && ' '}${origin.startPath}`)
|
|
204
221
|
buffer.push(`:page-origin-refname: ${origin.branch || origin.tag}`)
|
|
@@ -371,7 +388,7 @@ function mergeAsciiDoc (
|
|
|
371
388
|
if (~line.indexOf('xref:')) {
|
|
372
389
|
// Q: should we allow : as first character of target?
|
|
373
390
|
line = line.replace(/(?<![\\+])xref:((?:\.\/)?[\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
|
|
374
|
-
let relativePart, fragment,
|
|
391
|
+
let relativePart, fragment, resource, isPage
|
|
375
392
|
const hashIdx = target.indexOf('#')
|
|
376
393
|
const dollarIdx = target.indexOf('$')
|
|
377
394
|
if (~hashIdx) {
|
|
@@ -400,9 +417,9 @@ function mergeAsciiDoc (
|
|
|
400
417
|
if (~hashIdx && !relativePart.endsWith('.adoc')) relativePart += '.adoc'
|
|
401
418
|
}
|
|
402
419
|
if (!isPage || ~relativePart.indexOf('@') || /:.*:/.test(relativePart)) {
|
|
403
|
-
if (
|
|
404
|
-
text ||=
|
|
405
|
-
return `${
|
|
420
|
+
if (siteRoot && (resource = contentCatalog.resolveResource(relativePart, page.src, 'page'))?.pub) {
|
|
421
|
+
text ||= resource.asciidoc?.xreftext || target
|
|
422
|
+
return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
|
|
406
423
|
}
|
|
407
424
|
// TODO: handle unresolved resource better
|
|
408
425
|
return m
|
|
@@ -417,14 +434,10 @@ function mergeAsciiDoc (
|
|
|
417
434
|
targetModule = module_
|
|
418
435
|
}
|
|
419
436
|
const pageResourceRef = targetModule === 'ROOT' ? relativePart : `${targetModule}:${relativePart}`
|
|
420
|
-
if (!(
|
|
421
|
-
if (
|
|
422
|
-
|
|
423
|
-
(
|
|
424
|
-
targetResource.out
|
|
425
|
-
) {
|
|
426
|
-
text ||= targetResource.asciidoc?.xreftext || target
|
|
427
|
-
return `${siteUrl}${targetResource.pub.url}${fragment && '#' + fragment}[${text}]`
|
|
437
|
+
if (!(resource = pagesInOutline.get(pageResourceRef))) {
|
|
438
|
+
if (siteRoot && (resource = contentCatalog.resolvePage(pageResourceRef, page.src)) && resource.out) {
|
|
439
|
+
text ||= resource.asciidoc?.xreftext || target
|
|
440
|
+
return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
|
|
428
441
|
}
|
|
429
442
|
// TODO: handle unresolved page better
|
|
430
443
|
return m
|
|
@@ -434,13 +447,20 @@ function mergeAsciiDoc (
|
|
|
434
447
|
const refid = fragment
|
|
435
448
|
? `${relativePart}${idScopeSeparator}${fragment}`
|
|
436
449
|
: relativePart + (ReservedIdNames.includes(relativePart) ? idScopeSeparator : '')
|
|
437
|
-
|
|
450
|
+
if (
|
|
451
|
+
text &&
|
|
452
|
+
(assemblyModel.dropExplicitXrefText === 'always' ||
|
|
453
|
+
(assemblyModel.dropExplicitXrefText === 'if-redundant' && text === resource.title))
|
|
454
|
+
) {
|
|
455
|
+
text = ''
|
|
456
|
+
}
|
|
457
|
+
return `<<${refid}${text ? ',' + text.replace(/\\]/g, ']') : ''}>>`
|
|
438
458
|
})
|
|
439
459
|
}
|
|
440
460
|
if (~line.indexOf('link:{attachmentsdir}/')) {
|
|
441
461
|
line = line.replace(/(?<![\\+])link:\{attachmentsdir\}\/([^\s[]+)\[(|.*?[^\\])\]/g, (m, relative, text) => {
|
|
442
462
|
const attachment =
|
|
443
|
-
|
|
463
|
+
siteRoot &&
|
|
444
464
|
contentCatalog.getById({
|
|
445
465
|
component: componentVersion.name,
|
|
446
466
|
version: componentVersion.version,
|
|
@@ -449,7 +469,7 @@ function mergeAsciiDoc (
|
|
|
449
469
|
relative,
|
|
450
470
|
})
|
|
451
471
|
// TODO: handle unresolved attachment page
|
|
452
|
-
return attachment?.out ? `${
|
|
472
|
+
return attachment?.out ? `${resolveLinkTarget(attachment, siteRoot, pubRoot, linkRefStyle)}[${text}]` : m
|
|
453
473
|
})
|
|
454
474
|
}
|
|
455
475
|
if (~line.indexOf('image:') && !line.startsWith('image::')) {
|
|
@@ -457,9 +477,11 @@ function mergeAsciiDoc (
|
|
|
457
477
|
if (isResourceSpec(target)) {
|
|
458
478
|
const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
|
|
459
479
|
// TODO: handle (or report) unresolved image better
|
|
460
|
-
if (image?.out) {
|
|
480
|
+
if (image?.out && (filetype !== 'html' || siteRoot)) {
|
|
461
481
|
pagesInOutline.assembled.assets.add(image)
|
|
462
|
-
return
|
|
482
|
+
return filetype === 'html'
|
|
483
|
+
? `image:${resolveLinkTarget(image, siteRoot, pubRoot, linkRefStyle)}[${attrlist}]`
|
|
484
|
+
: `image:${resolveEmbedTarget(image, outDirname, embedRefStyle, true)}[${attrlist}]`
|
|
463
485
|
}
|
|
464
486
|
}
|
|
465
487
|
return m
|
|
@@ -513,10 +535,13 @@ function mergeAsciiDoc (
|
|
|
513
535
|
if (isResourceSpec(target)) {
|
|
514
536
|
const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
|
|
515
537
|
// FIXME: handle (or report) case when image is not resolved
|
|
516
|
-
if (image?.out) {
|
|
517
|
-
const
|
|
538
|
+
if (image?.out && (filetype !== 'html' || siteRoot)) {
|
|
539
|
+
const attrlist = line.slice(line.indexOf('[') + 1, -1)
|
|
518
540
|
pagesInOutline.assembled.assets.add(image)
|
|
519
|
-
lines[idx] =
|
|
541
|
+
lines[idx] =
|
|
542
|
+
filetype === 'html'
|
|
543
|
+
? `${prefix}image::${resolveLinkTarget(image, siteRoot, pubRoot, linkRefStyle, false)}[${attrlist}]`
|
|
544
|
+
: `${prefix}image::${resolveEmbedTarget(image, outDirname, embedRefStyle)}[${attrlist}]`
|
|
520
545
|
}
|
|
521
546
|
}
|
|
522
547
|
lastImageMacroAt = [idx, imageMacroOffset]
|
|
@@ -555,6 +580,7 @@ function mergeAsciiDoc (
|
|
|
555
580
|
}
|
|
556
581
|
} else if (level) {
|
|
557
582
|
if (atDocumentRoot && navtitlePlain === componentVersion.title) {
|
|
583
|
+
buffer.inBody ??= false
|
|
558
584
|
level--
|
|
559
585
|
} else {
|
|
560
586
|
buffer.inBody = true
|
|
@@ -576,9 +602,18 @@ function mergeAsciiDoc (
|
|
|
576
602
|
let sectionTitle = navtitleAsciiDoc
|
|
577
603
|
if (urlType === 'external') {
|
|
578
604
|
sectionTitle = `${url}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
|
|
579
|
-
} else if (urlType === 'internal' && !unresolved
|
|
605
|
+
} else if (urlType === 'internal' && !unresolved) {
|
|
580
606
|
const resource = files.find((it) => it.pub.url === url)
|
|
581
|
-
if (resource)
|
|
607
|
+
if (resource) {
|
|
608
|
+
if (resource.src.family === 'page' && pagesInOutline.has(resource.pub.url)) {
|
|
609
|
+
let refid = resource.src.relative.replace(/\.adoc$/, '').replace(/[/.]/g, '-')
|
|
610
|
+
if (refid.startsWith('./')) refid = topicPrefix + refid.slice(2)
|
|
611
|
+
if (resource.src.module !== 'ROOT') refid = `${resource.src.module}${idCoordinateSeparator}${refid}`
|
|
612
|
+
sectionTitle = `<<${refid},${navtitleAsciiDoc}>>`
|
|
613
|
+
} else if (siteRoot) {
|
|
614
|
+
sectionTitle = `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
|
|
615
|
+
}
|
|
616
|
+
}
|
|
582
617
|
}
|
|
583
618
|
let hlevel = level + 1
|
|
584
619
|
if (hlevel > 6) {
|
|
@@ -663,6 +698,12 @@ function processDocumentHeader (doc, lines, buffer, ignoreLines) {
|
|
|
663
698
|
} else if (belowDoctitle) {
|
|
664
699
|
if (implicitLines.length === 2 || !/[\p{Alpha}0-9]/u.test(chr0)) break
|
|
665
700
|
implicitLines.push(line)
|
|
701
|
+
} else if (chr0 === '[' && line.charAt(line.length - 1) === ']') {
|
|
702
|
+
const attrlist = line
|
|
703
|
+
.slice(1, -1)
|
|
704
|
+
.trim()
|
|
705
|
+
.replace(/(?:^\w[\w-]*(?!=|[\w-]))?([#.%]\w[\w-]*)*/, '')
|
|
706
|
+
if (attrlist) buffer.push('[' + attrlist + ']')
|
|
666
707
|
}
|
|
667
708
|
} else if (belowDoctitle) {
|
|
668
709
|
break
|
|
@@ -685,7 +726,7 @@ function generateSlug (title) {
|
|
|
685
726
|
return String.fromCharCode(dec ? parseInt(dec, 10) : parseInt(hex, 16))
|
|
686
727
|
})
|
|
687
728
|
.replace(/[\x27\u2019]/g, '')
|
|
688
|
-
.replace(/[^\p{Alpha}0-9
|
|
729
|
+
.replace(/[^\p{Alpha}0-9-]/gu, '-')
|
|
689
730
|
.replace(/^-+|-+$|(-)-+/g, '$1')
|
|
690
731
|
}
|
|
691
732
|
|
|
@@ -752,7 +793,19 @@ function isResourceSpec (str) {
|
|
|
752
793
|
}
|
|
753
794
|
|
|
754
795
|
function getObjectId (obj) {
|
|
755
|
-
return global.Opal.
|
|
796
|
+
return global.Opal.id(obj)
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// NOTE: blank lines at top and bottom of document create mismatch when using line numbers to navigate source lines
|
|
800
|
+
// IMPORTANT: this must not leave behind lines the parser will drop!
|
|
801
|
+
// IDEA: another option is to capture initial lineno of reader and use as offset (but preseves those blank lines)
|
|
802
|
+
function trimAsciiDoc (buffer) {
|
|
803
|
+
return Buffer.from(
|
|
804
|
+
buffer
|
|
805
|
+
.toString()
|
|
806
|
+
.replace(/^(?:[ \t]*\r\n?|[ \t]*\n)+/, '')
|
|
807
|
+
.trimRight()
|
|
808
|
+
)
|
|
756
809
|
}
|
|
757
810
|
|
|
758
811
|
function safePush (onto, entries) {
|
|
@@ -765,4 +818,35 @@ function safePush (onto, entries) {
|
|
|
765
818
|
}
|
|
766
819
|
}
|
|
767
820
|
|
|
821
|
+
function resolveEmbedTarget (resource, outDirname, referenceStyle, escapeForInline) {
|
|
822
|
+
const target =
|
|
823
|
+
referenceStyle === 'output-relative' ? resource.out.path : path.relative(outDirname + '/', resource.out.path)
|
|
824
|
+
return escapeForInline ? target.replace(/_/g, '{underscore}') : target
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function resolveLinkTarget (resource, siteRoot, pubRoot, referenceStyle, escapeForInline = true) {
|
|
828
|
+
let target
|
|
829
|
+
if (resource.site?.url) {
|
|
830
|
+
target = ['', resource.pub.url]
|
|
831
|
+
} else {
|
|
832
|
+
switch (referenceStyle) {
|
|
833
|
+
case 'absolute':
|
|
834
|
+
target = ['', siteRoot.url + resource.pub.url]
|
|
835
|
+
break
|
|
836
|
+
case 'root-relative':
|
|
837
|
+
target = ['link:', siteRoot.path + resource.pub.url]
|
|
838
|
+
break
|
|
839
|
+
default:
|
|
840
|
+
target = ['link:', computeRelativeUrl(pubRoot + '/', resource.pub.url)]
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (escapeForInline) target[1] = target[1].replace(/_/g, '{underscore}')
|
|
844
|
+
return target.join('')
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
function computeRelativeUrl (from, to) {
|
|
848
|
+
const rel = path.relative(from, to)
|
|
849
|
+
return to.charAt(to.length - 1) === '/' ? rel + '/' : rel
|
|
850
|
+
}
|
|
851
|
+
|
|
768
852
|
module.exports = produceAssemblyFile
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const computeOut = require('./util/compute-out')
|
|
3
4
|
const createAsciiDocFile = require('./util/create-asciidoc-file')
|
|
4
5
|
const filterComponentVersions = require('./filter-component-versions')
|
|
5
6
|
const produceAssemblyFile = require('./produce-assembly-file')
|
|
6
7
|
const selectMutableAttributes = require('./select-mutable-attributes')
|
|
7
8
|
|
|
9
|
+
const ATTR_REF_RX = /\\?\{(\w[\w-]*)\}/g
|
|
8
10
|
const IMAGE_MACRO_RX = /^image::?(.+?)\[(.*?)\]$/
|
|
9
11
|
|
|
10
12
|
function produceAssemblyFiles (loadAsciiDoc, contentCatalog, assemblerConfig, resolveAssemblyModel) {
|
|
@@ -16,22 +18,55 @@ function produceAssemblyFiles (loadAsciiDoc, contentCatalog, assemblerConfig, re
|
|
|
16
18
|
sectionMergeStrategy: assemblyConfig.sectionMergeStrategy,
|
|
17
19
|
navigation: componentVersion.navigation,
|
|
18
20
|
xmlIds: assemblyConfig.xmlIds,
|
|
21
|
+
embedReferenceStyle: assemblyConfig.embedReferenceStyle,
|
|
22
|
+
linkReferenceStyle: assemblyConfig.linkReferenceStyle,
|
|
23
|
+
dropExplicitXrefText: assemblyConfig.dropExplicitXrefText,
|
|
19
24
|
})
|
|
20
25
|
const assemblerAsciiDocAttributes = Object.assign({}, assemblerAsciiDocConfig.attributes)
|
|
21
26
|
const { revdate, 'source-highlighter': sourceHighlighter } = assemblerAsciiDocAttributes
|
|
22
27
|
delete assemblerAsciiDocAttributes.revdate
|
|
23
28
|
delete assemblerAsciiDocAttributes['source-highlighter']
|
|
24
29
|
const publishableFiles = contentCatalog.getFiles().filter((file) => file.out)
|
|
30
|
+
let siteRoot
|
|
31
|
+
const configMdc = assemblerConfig.file ? { file: { path: assemblerConfig.file } } : {}
|
|
25
32
|
return filterComponentVersions(contentCatalog.getComponents(), assemblerConfig.componentVersionFilter.names).reduce(
|
|
26
33
|
(accum, componentVersion) => {
|
|
27
34
|
const assemblyModel = resolveAssemblyModel(componentVersion)
|
|
28
35
|
if (!assemblyModel.navigation) return accum
|
|
29
36
|
const { name: componentName, version, title } = componentVersion
|
|
30
37
|
const componentVersionAsciiDocConfig = getAsciiDocConfigWithAsciidoctorReducerExtension(componentVersion)
|
|
38
|
+
const mergedAsciiDocAttributes = collateAsciiDocAttributes(
|
|
39
|
+
Object.assign({ revdate }, componentVersionAsciiDocConfig.attributes),
|
|
40
|
+
assemblerAsciiDocAttributes,
|
|
41
|
+
{ logger: assemblyModel.logger, mdc: configMdc }
|
|
42
|
+
)
|
|
31
43
|
const mergedAsciiDocConfig = Object.assign({}, componentVersionAsciiDocConfig, {
|
|
32
|
-
attributes:
|
|
44
|
+
attributes: mergedAsciiDocAttributes,
|
|
33
45
|
})
|
|
34
|
-
|
|
46
|
+
assemblyModel.outDirname = computeOut.call(contentCatalog, {
|
|
47
|
+
component: componentName,
|
|
48
|
+
version,
|
|
49
|
+
family: 'export',
|
|
50
|
+
relative: '.index.adoc',
|
|
51
|
+
}).dirname
|
|
52
|
+
assemblyModel.filetype = assemblerAsciiDocAttributes['assembler-filetype']
|
|
53
|
+
assemblyModel.siteRoot =
|
|
54
|
+
siteRoot === undefined
|
|
55
|
+
? (siteRoot ??= ((val) => {
|
|
56
|
+
if (!val) return null
|
|
57
|
+
if (val.charAt(val.length - 1) === '/') val = val.slice(0, val.length - 1)
|
|
58
|
+
if (!val || val.charAt() === '/') return { path: val }
|
|
59
|
+
return { url: val, path: extractUrlPath(val) }
|
|
60
|
+
})(mergedAsciiDocAttributes['site-url'] || mergedAsciiDocAttributes['primary-site-url']))
|
|
61
|
+
: siteRoot
|
|
62
|
+
if (assemblyModel.filetype === 'html') {
|
|
63
|
+
let linkRefStyle = assemblyModel.linkReferenceStyle
|
|
64
|
+
if (linkRefStyle === 'absolute' && siteRoot?.url == null) linkRefStyle = 'root-relative'
|
|
65
|
+
if (linkRefStyle === 'root-relative' && siteRoot?.path == null) linkRefStyle = 'relative'
|
|
66
|
+
assemblyModel.linkReferenceStyle = linkRefStyle
|
|
67
|
+
} else {
|
|
68
|
+
assemblyModel.linkReferenceStyle = 'absolute'
|
|
69
|
+
}
|
|
35
70
|
const auxiliaryImages = new Set()
|
|
36
71
|
Object.entries(mergedAsciiDocAttributes).forEach(([name, val]) => {
|
|
37
72
|
const match = name.endsWith('-image') && val.startsWith('image:') && IMAGE_MACRO_RX.exec(val)
|
|
@@ -142,4 +177,39 @@ function prepareOutlines (navigation, rootEntry, rootLevel) {
|
|
|
142
177
|
return items
|
|
143
178
|
}
|
|
144
179
|
|
|
180
|
+
function collateAsciiDocAttributes (collated, additional, { logger, mdc }) {
|
|
181
|
+
Object.entries(additional).forEach(([name, val]) => {
|
|
182
|
+
if (val && val.constructor === String) {
|
|
183
|
+
let alias
|
|
184
|
+
val = val.replace(ATTR_REF_RX, (ref, refname) => {
|
|
185
|
+
if (ref.charAt() === '\\') return ref.substr(1)
|
|
186
|
+
const refval = collated[refname]
|
|
187
|
+
if (refval == null || refval === false) {
|
|
188
|
+
if (refname in collated && ref === val) {
|
|
189
|
+
alias = refval
|
|
190
|
+
} else if (collated['attribute-missing'] === 'warn') {
|
|
191
|
+
if (logger) {
|
|
192
|
+
logger.warn(mdc, "Skipping reference to missing attribute '%s' in value of '%s' attribute", refname, name)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return ref
|
|
196
|
+
}
|
|
197
|
+
if (refval.constructor === String) return refval
|
|
198
|
+
if (ref !== val) return refval.toString()
|
|
199
|
+
alias = refval
|
|
200
|
+
return ref
|
|
201
|
+
})
|
|
202
|
+
if (alias !== undefined) val = alias
|
|
203
|
+
}
|
|
204
|
+
collated[name] = val
|
|
205
|
+
})
|
|
206
|
+
return collated
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function extractUrlPath (url) {
|
|
210
|
+
if (!url) return ''
|
|
211
|
+
const urlPath = new URL(url).pathname
|
|
212
|
+
return urlPath === '/' ? '' : urlPath
|
|
213
|
+
}
|
|
214
|
+
|
|
145
215
|
module.exports = produceAssemblyFiles
|
package/lib/util/compute-out.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
const { posix: path } = require('node:path')
|
|
4
4
|
|
|
5
5
|
function computeOut (src) {
|
|
6
|
-
const { component, version, module: module_, family, relative } = src
|
|
6
|
+
const { component, version, module: module_ = 'ROOT', family, relative } = src
|
|
7
7
|
const outRelative = family === 'page' ? relative.replace(/\.adoc$/, '.html') : relative
|
|
8
|
-
const { dir: dirname, base: basename
|
|
8
|
+
const { dir: dirname, base: basename } = path.parse(outRelative)
|
|
9
9
|
const componentVersion = this.getComponentVersion(component, version)
|
|
10
10
|
const versionSegment =
|
|
11
11
|
'activeVersionSegment' in componentVersion
|
|
@@ -48,7 +48,7 @@ function resolveActiveVersionSegment (component, version) {
|
|
|
48
48
|
this.removeFile((startPage = this.addFile({ src: startPageSrc })))
|
|
49
49
|
}
|
|
50
50
|
const outPathSegments = startPage.out.path.split('/')
|
|
51
|
-
for (const
|
|
51
|
+
for (const _ of startPage.out.moduleRootPath.split('/')) outPathSegments.pop()
|
|
52
52
|
if (startPageSrc.module !== 'ROOT') outPathSegments.pop()
|
|
53
53
|
if (startPageSrc.component !== 'ROOT') outPathSegments.shift()
|
|
54
54
|
return outPathSegments.length ? outPathSegments[0] : ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/assembler",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.7",
|
|
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)",
|