@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
|
@@ -11,22 +11,28 @@ const {
|
|
|
11
11
|
rewriteStyleAttribute,
|
|
12
12
|
} = require('./util/rewriter')
|
|
13
13
|
const sanitize = require('./util/sanitize')
|
|
14
|
+
const toHash = require('./util/to-hash')
|
|
14
15
|
const unconvertInlineAsciiDoc = require('./util/unconvert-inline-asciidoc')
|
|
15
16
|
|
|
16
17
|
const ATTR_ENTRY_RX = /^:(!?[\p{Alpha}0-9_][^:]*):(?: |$)/u
|
|
17
18
|
const BUILT_IN_NAMED_ENTITIES = { amp: '&', apos: "'", gt: '>', lt: '<', nbsp: ' ', quot: '"' }
|
|
18
19
|
const CHAR_REF_RX = /&(?:([a-z][a-z]+\d{0,2})|#(?:(\d{2,6})|x([a-z\d]{2,5})));/g
|
|
19
20
|
const DISCARD_ATTRIBUTE_NAMES = [
|
|
20
|
-
'doctype',
|
|
21
|
-
'leveloffset',
|
|
22
|
-
'preface-title',
|
|
21
|
+
'assembly-doctype',
|
|
23
22
|
'assembly-header-attributes',
|
|
23
|
+
'assembly-overview-title',
|
|
24
24
|
'assembly-navtitle',
|
|
25
|
+
'assembly-root-title',
|
|
25
26
|
'assembly-slug',
|
|
26
27
|
'assembly-style',
|
|
28
|
+
'doctype',
|
|
29
|
+
'leveloffset',
|
|
30
|
+
'page-aliases',
|
|
31
|
+
'preface-title',
|
|
27
32
|
'underscore',
|
|
28
33
|
]
|
|
29
34
|
const { NAMED_ID_ATTR_RX } = require('./util/rx')
|
|
35
|
+
const ASSEMBLY_STYLE_SUPPORTS_SECTIONS = ['abstract', 'appendix', 'part', 'preface', 'section']
|
|
30
36
|
|
|
31
37
|
function produceAssemblyFile (
|
|
32
38
|
loadAsciiDoc,
|
|
@@ -39,35 +45,39 @@ function produceAssemblyFile (
|
|
|
39
45
|
assemblyModel
|
|
40
46
|
) {
|
|
41
47
|
const pagesByUrl = files.reduce((map, it) => (it.src.family === 'page' ? map.set(it.pub.url, it) : map), new Map())
|
|
42
|
-
if (outline.urlType === 'internal' && !pagesByUrl.get(outline.url) && !(outline.items || []).length) return
|
|
43
48
|
const pagesInOutline = selectPagesInOutline(outline, pagesByUrl)
|
|
49
|
+
if (outline.urlType === 'internal' && !pagesByUrl.has(outline.pathname) && !outline.items?.length) return
|
|
50
|
+
const { name: component, version } = componentVersion
|
|
44
51
|
const { rootLevel, xmlIds } = assemblyModel
|
|
52
|
+
const scratchDoc = loadAsciiDoc(
|
|
53
|
+
{
|
|
54
|
+
contents: Buffer.alloc(0),
|
|
55
|
+
src: { component, version, module: 'ROOT', family: 'page', relative: '_.adoc', path: '_.adoc' },
|
|
56
|
+
},
|
|
57
|
+
undefined,
|
|
58
|
+
Object.assign({}, asciidocConfig, { antoraResourceRefs: false, extensions: [] })
|
|
59
|
+
)
|
|
45
60
|
const idSeparators = {
|
|
46
61
|
prefix:
|
|
47
62
|
'assembler-idprefix' in asciidocConfig.attributes ? (asciidocConfig.attributes['assembler-idprefix'] ?? '') : '_',
|
|
48
63
|
scope: xmlIds ? '---' : ':::',
|
|
49
64
|
coordinate: xmlIds ? '----' : ':',
|
|
50
|
-
generateIdFromTitle: generateIdFromTitle.bind(
|
|
51
|
-
loadAsciiDoc(
|
|
52
|
-
{ contents: Buffer.alloc(0), src: { family: 'page', relative: 'generate-id-from-title.adoc' } },
|
|
53
|
-
undefined,
|
|
54
|
-
asciidocConfig
|
|
55
|
-
)
|
|
56
|
-
),
|
|
65
|
+
generateIdFromTitle: generateIdFromTitle.bind(scratchDoc),
|
|
57
66
|
}
|
|
58
|
-
const { name: component, version } = componentVersion
|
|
59
67
|
asciidocConfig = prepareAsciiDocConfig(
|
|
60
68
|
contentCatalog,
|
|
61
69
|
{ component, version },
|
|
62
70
|
pagesInOutline,
|
|
63
71
|
asciidocConfig,
|
|
64
72
|
assemblyModel,
|
|
65
|
-
idSeparators
|
|
73
|
+
idSeparators,
|
|
74
|
+
scratchDoc
|
|
66
75
|
)
|
|
67
|
-
const
|
|
76
|
+
const builder = buildAssemblyHeader(componentVersion, outline.content, assemblyModel)
|
|
77
|
+
mergeAsciiDoc(
|
|
68
78
|
loadAsciiDoc,
|
|
69
79
|
contentCatalog,
|
|
70
|
-
|
|
80
|
+
builder,
|
|
71
81
|
componentVersion,
|
|
72
82
|
outline,
|
|
73
83
|
files,
|
|
@@ -78,22 +88,22 @@ function produceAssemblyFile (
|
|
|
78
88
|
assemblyModel
|
|
79
89
|
)
|
|
80
90
|
const stem =
|
|
81
|
-
(
|
|
91
|
+
(builder.slug ? sanitizeSlug(builder.slug) : generateSlug(rootLevel === 0 ? 'index' : builder.baseDoctitle)) ||
|
|
82
92
|
'export-' + (assemblyModel.stemSeq = (assemblyModel.exportSeq ?? 0) + 1)
|
|
83
93
|
const downloadStem = [component, version, stem === 'index' ? '' : stem].filter((it) => it).join('-')
|
|
84
94
|
const file = contentCatalog.createFile({
|
|
85
95
|
asciidoc: asciidocConfig,
|
|
86
96
|
assembler: { assembled: pagesInOutline.assembled, downloadStem, rootLevel },
|
|
87
|
-
contents:
|
|
97
|
+
contents: builder.serialize(),
|
|
88
98
|
src: { component, version, componentVersion, module: 'ROOT', family: 'export', relative: stem + '.adoc' },
|
|
89
99
|
pub: false,
|
|
90
100
|
})
|
|
91
|
-
file.path = file.out.path // use out path as
|
|
101
|
+
file.path = file.out.path // use out path as path so assets can be published to same hierarchy
|
|
92
102
|
delete file.out
|
|
93
103
|
return file
|
|
94
104
|
}
|
|
95
105
|
|
|
96
|
-
function prepareAsciiDocConfig (contentCatalog, ctx, pagesInOutline, asciidocConfig, assemblyModel, idSeparators) {
|
|
106
|
+
function prepareAsciiDocConfig (contentCatalog, ctx, pagesInOutline, asciidocConfig, assemblyModel, idSeparators, doc) {
|
|
97
107
|
let attributesModified
|
|
98
108
|
const configShared = asciidocConfig.$shared
|
|
99
109
|
const sharedAttributes = asciidocConfig.attributes
|
|
@@ -101,7 +111,7 @@ function prepareAsciiDocConfig (contentCatalog, ctx, pagesInOutline, asciidocCon
|
|
|
101
111
|
if (configShared == null) {
|
|
102
112
|
const assets = pagesInOutline.assembled.assets
|
|
103
113
|
for (const [name, val] of Object.entries(sharedAttributes)) {
|
|
104
|
-
if (!(
|
|
114
|
+
if (!(val?.constructor === String && ~val.indexOf(':'))) continue
|
|
105
115
|
let newVal
|
|
106
116
|
if (!name.endsWith('-image') || !(newVal = rewriteImageAttr(val, contentCatalog, assemblyModel, ctx, assets))) {
|
|
107
117
|
if (~(newVal = val).indexOf('image:')) {
|
|
@@ -112,9 +122,19 @@ function prepareAsciiDocConfig (contentCatalog, ctx, pagesInOutline, asciidocCon
|
|
|
112
122
|
}
|
|
113
123
|
}
|
|
114
124
|
for (const [name, val] of Object.entries(sharedAttributes)) {
|
|
115
|
-
if (!(
|
|
125
|
+
if (!(val?.constructor === String && ~val.indexOf(':'))) continue
|
|
116
126
|
if (~val.indexOf('xref:')) {
|
|
117
|
-
const newVal = rewriteXrefs(
|
|
127
|
+
const newVal = rewriteXrefs(
|
|
128
|
+
val,
|
|
129
|
+
contentCatalog,
|
|
130
|
+
assemblyModel,
|
|
131
|
+
ctx,
|
|
132
|
+
false,
|
|
133
|
+
pagesInOutline,
|
|
134
|
+
idSeparators,
|
|
135
|
+
null,
|
|
136
|
+
doc
|
|
137
|
+
)
|
|
118
138
|
if (newVal !== val) (attributesModified ??= {})[name] = newVal
|
|
119
139
|
}
|
|
120
140
|
}
|
|
@@ -123,43 +143,74 @@ function prepareAsciiDocConfig (contentCatalog, ctx, pagesInOutline, asciidocCon
|
|
|
123
143
|
return Object.assign({}, asciidocConfig, { attributes: Object.assign({}, sharedAttributes, attributesModified) })
|
|
124
144
|
}
|
|
125
145
|
|
|
126
|
-
function
|
|
127
|
-
const
|
|
128
|
-
const navtitlePlain = sanitize(navtitle)
|
|
146
|
+
function buildAssemblyHeader (componentVersion, navtitle, assemblyModel) {
|
|
147
|
+
const { name: componentName, version, displayVersion, title } = componentVersion
|
|
129
148
|
const navtitleAsciiDoc = unconvertInlineAsciiDoc(navtitle)
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
149
|
+
const navtitlePlain = sanitize(navtitle)
|
|
150
|
+
const doctitleQualifier = assemblyModel.rootLevel === 0 ? '' : title
|
|
151
|
+
const versioned = !!(version && version !== 'master')
|
|
152
|
+
return {
|
|
153
|
+
header: [
|
|
154
|
+
`= ${doctitleQualifier && doctitleQualifier !== navtitlePlain ? doctitleQualifier + ': ' : ''}${navtitleAsciiDoc}`,
|
|
155
|
+
...(versioned ? [`:revnumber: ${displayVersion}`] : []),
|
|
156
|
+
`:doctype: ${(assemblyModel.doctype ??= 'book')}`,
|
|
157
|
+
':underscore: _',
|
|
158
|
+
`:page-component-name: ${componentName}`,
|
|
159
|
+
`:page-component-version:${versioned ? ' ' + version : ''}`,
|
|
160
|
+
':page-version: {page-component-version}',
|
|
161
|
+
`:page-component-display-version: ${displayVersion}`,
|
|
162
|
+
`:page-component-title: ${title}`,
|
|
163
|
+
],
|
|
164
|
+
currentComponentVersion: componentVersion,
|
|
165
|
+
doctitleQualifier,
|
|
166
|
+
baseDoctitle: navtitle,
|
|
167
|
+
baseDoctitlePlain: navtitlePlain,
|
|
168
|
+
setAuthor (author) {
|
|
169
|
+
this.header.splice(1, 0, author)
|
|
170
|
+
},
|
|
171
|
+
setDoctitle (doctitle, doctitleAsciiDoc, doctitlePlain) {
|
|
172
|
+
this.baseDoctitle = doctitle
|
|
173
|
+
this.baseDoctitlePlain = doctitlePlain
|
|
174
|
+
const qualifyDoctitle = this.doctitleQualifier ? this.doctitleQualifier !== doctitlePlain : false
|
|
175
|
+
this.header[0] = `= ${qualifyDoctitle ? this.doctitleQualifier + ': ' : ''}${doctitleAsciiDoc}`
|
|
176
|
+
},
|
|
177
|
+
matchesDoctitle (candidate) {
|
|
178
|
+
return candidate === this.baseDoctitlePlain
|
|
179
|
+
},
|
|
180
|
+
setDoctype (doctype) {
|
|
181
|
+
this.header[this.header.findIndex((line) => line.startsWith(':doctype: '))] = `:doctype: ${doctype}`
|
|
182
|
+
},
|
|
183
|
+
setDocid (docid) {
|
|
184
|
+
this.header.unshift(`[#${docid}]`)
|
|
185
|
+
},
|
|
186
|
+
serialize () {
|
|
187
|
+
const normalizedHeader = this.header.filter((it) => it !== ':doctype: article')
|
|
188
|
+
return this.body
|
|
189
|
+
? Buffer.from(normalizedHeader.join('\n') + '\n\n' + this.body.join('\n') + '\n')
|
|
190
|
+
: Buffer.from(normalizedHeader.join('\n') + '\n')
|
|
191
|
+
},
|
|
192
|
+
}
|
|
146
193
|
}
|
|
147
194
|
|
|
148
195
|
function selectPagesInOutline (outlineEntry, pagesByUrl, accum) {
|
|
149
196
|
accum ??= Object.assign(new Map(), { assembled: { pages: new Map(), assets: new Set() } })
|
|
150
|
-
const
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
197
|
+
const { urlType, url, hash, unresolved, items = [] } = outlineEntry
|
|
198
|
+
if (urlType === 'internal' && !unresolved) {
|
|
199
|
+
const pathname = (outlineEntry.pathname ??= hash ? url.substring(0, url.length - hash.length) : url)
|
|
200
|
+
let page
|
|
201
|
+
if (!accum.has(pathname) && (page = pagesByUrl.get(pathname))) {
|
|
202
|
+
accum.set(createResourceKey(page.src), page)
|
|
203
|
+
accum.set(pathname, page)
|
|
204
|
+
}
|
|
154
205
|
}
|
|
155
|
-
for (const item of
|
|
206
|
+
for (const item of items) selectPagesInOutline(item, pagesByUrl, accum)
|
|
156
207
|
return accum
|
|
157
208
|
}
|
|
158
209
|
|
|
159
210
|
function mergeAsciiDoc (
|
|
160
211
|
loadAsciiDoc,
|
|
161
212
|
contentCatalog,
|
|
162
|
-
|
|
213
|
+
builder,
|
|
163
214
|
componentVersion,
|
|
164
215
|
outlineEntry,
|
|
165
216
|
files,
|
|
@@ -168,130 +219,101 @@ function mergeAsciiDoc (
|
|
|
168
219
|
asciidocConfig,
|
|
169
220
|
mutableAttributes,
|
|
170
221
|
assemblyModel,
|
|
171
|
-
lastComponentVersion = componentVersion,
|
|
172
222
|
level = 0,
|
|
173
223
|
supportsParts = false
|
|
174
224
|
) {
|
|
225
|
+
const { items = [], roles = [], unresolved, urlType, url, pathname, hash } = outlineEntry
|
|
175
226
|
// TODO: we could try to be smart about it and make sure the page with fragment is included at least once
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
return
|
|
227
|
+
if (roles.includes('site-only') || (urlType === 'external' && !URL.canParse(url))) {
|
|
228
|
+
builder.body ??= []
|
|
229
|
+
return builder
|
|
179
230
|
}
|
|
180
|
-
let navtitle = outlineEntry.navtitle ?? outlineEntry.content
|
|
181
|
-
let navtitlePlain = sanitize(navtitle)
|
|
182
|
-
let navtitleAsciiDoc = unconvertInlineAsciiDoc(navtitle)
|
|
183
|
-
const { items = [], roles = [], unresolved, urlType, url } = outlineEntry
|
|
184
|
-
const { filetype, linkReferenceStyle, pubRoot, siteRoot, logger, rootLevel } = assemblyModel
|
|
185
231
|
const assembled = pagesInOutline.assembled
|
|
186
232
|
// FIXME: ideally, resource ID would be stored in navigation so we can look up the page more efficiently
|
|
187
|
-
const page = urlType === 'internal' && !unresolved ? pagesInOutline.get(
|
|
188
|
-
|
|
189
|
-
|
|
233
|
+
const page = urlType === 'internal' && !unresolved ? pagesInOutline.get(pathname) : undefined
|
|
234
|
+
let navtitle = outlineEntry.navtitle ?? (page && hash ? page.asciidoc.navtitle : outlineEntry.content)
|
|
235
|
+
let navtitleAsciiDoc = unconvertInlineAsciiDoc(navtitle)
|
|
236
|
+
let navtitlePlain = sanitize(navtitle)
|
|
237
|
+
const { doctype, filetype, linkReferenceStyle, pubRoot, siteRoot, logger, rootPageStyle } = assemblyModel
|
|
238
|
+
let sectionMergeStrategy = assemblyModel.sectionMergeStrategy
|
|
239
|
+
const atStartOfBody = !builder.body?.length
|
|
240
|
+
const isRootEntry = atStartOfBody && !level
|
|
241
|
+
let atBookRoot = isRootEntry && doctype === 'book' && (supportsParts = true)
|
|
190
242
|
const hasItems = items.length > 0
|
|
191
243
|
if (page && !assembled.pages.has(page)) {
|
|
192
244
|
const contents = page.src.contents
|
|
193
245
|
if (contents == null) {
|
|
194
|
-
|
|
195
|
-
return
|
|
246
|
+
builder.body ??= []
|
|
247
|
+
return builder
|
|
196
248
|
}
|
|
197
|
-
const isRootPage = atDocumentRoot && !level
|
|
198
|
-
const { component, version, module: module_, relative, origin, mediaType } = page.src
|
|
199
249
|
const pageAsAsciiDoc = new page.constructor(
|
|
200
|
-
Object.assign({}, page, { contents:
|
|
250
|
+
Object.assign({}, page, { contents: Buffer.from(contents.toString().trimEnd()), mediaType: page.src.mediaType })
|
|
201
251
|
)
|
|
202
252
|
const doc = loadAsciiDoc(pageAsAsciiDoc, contentCatalog, asciidocConfig)
|
|
203
|
-
doc.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
253
|
+
if (typeof doc.applyLogger === 'function') doc.applyLogger()
|
|
254
|
+
if (logger) doc.getLogger().delegate = logger
|
|
255
|
+
doc.catalog.syntheticIds = {}
|
|
256
|
+
doc.source_header_attributes ??= toHash()
|
|
257
|
+
const isRootPage = isRootEntry
|
|
258
|
+
const { component, version, module: module_, relative, origin } = page.src
|
|
259
|
+
const doctypeOverride = doc.getAttribute('assembly-doctype')
|
|
260
|
+
if (doctypeOverride) {
|
|
261
|
+
if (doctypeOverride !== doctype) builder.setDoctype(doctypeOverride)
|
|
262
|
+
if (doctypeOverride !== 'book') atBookRoot = supportsParts = false
|
|
263
|
+
}
|
|
264
|
+
if (isRootPage && doc.hasAttribute('assembly-slug')) builder.slug = doc.getAttribute('assembly-slug')
|
|
214
265
|
let hasAssemblyNavtitleAttr
|
|
215
266
|
if ((hasAssemblyNavtitleAttr = !!doc.getAttribute('assembly-navtitle'))) {
|
|
216
267
|
navtitleAsciiDoc = doc.getAttribute('assembly-navtitle')
|
|
217
268
|
navtitlePlain = sanitize((navtitle = doc.$apply_reftext_subs(navtitleAsciiDoc)))
|
|
218
|
-
if (
|
|
219
|
-
buffer.navtitle = navtitle
|
|
220
|
-
if (rootLevel) {
|
|
221
|
-
const doctitle =
|
|
222
|
-
(componentVersion.title === navtitlePlain ? '' : componentVersion.title + ': ') + navtitleAsciiDoc
|
|
223
|
-
buffer[0] = `= ${doctitle}`
|
|
224
|
-
}
|
|
225
|
-
}
|
|
269
|
+
if (isRootPage) builder.setDoctitle(navtitle, navtitleAsciiDoc, navtitlePlain)
|
|
226
270
|
}
|
|
271
|
+
const overviewTitle = doc.getAttribute('assembly-overview-title', 'Overview')
|
|
272
|
+
let overviewTitleAsciiDoc
|
|
227
273
|
// NOTE: in Antora, docname is relative src path from module without file extension
|
|
228
274
|
const docname = doc.getAttribute('docname')
|
|
229
275
|
const pageId = generateScopedId(page.src, componentVersion, idSeparators, filetype)
|
|
230
276
|
const pageIdLeader = pageId + idSeparators.scope
|
|
231
|
-
let pageFragment =
|
|
277
|
+
let pageFragment = `#${pageId}`
|
|
232
278
|
let pageRoles = []
|
|
233
279
|
let pageStyle = doc.getAttribute('assembly-style', '')
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
atBookRoot &&
|
|
237
|
-
rootLevel === 0 &&
|
|
238
|
-
assemblyModel.sectionMergeStrategy === 'fuse' &&
|
|
239
|
-
!doc.source_header_attributes['$key?']('assembly-style')
|
|
240
|
-
) {
|
|
241
|
-
pageStyle = 'preface'
|
|
280
|
+
if (!pageStyle && isRootPage && hasItems && !doc.source_header_attributes['$key?']('assembly-style')) {
|
|
281
|
+
pageStyle = rootPageStyle
|
|
242
282
|
}
|
|
243
283
|
let part
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
284
|
+
if (pageStyle) {
|
|
285
|
+
if (
|
|
286
|
+
pageStyle === 'part' ||
|
|
287
|
+
(pageStyle.endsWith('-part') && (pageStyle = pageStyle.substring(0, pageStyle.length - 5)))
|
|
288
|
+
) {
|
|
289
|
+
part = supportsParts ? true : (pageStyle = undefined)
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
pageStyle = undefined
|
|
250
293
|
}
|
|
251
|
-
|
|
294
|
+
const hasSections = doc.hasSections()
|
|
295
|
+
const supportsSections = pageStyle == null ? true : ASSEMBLY_STYLE_SUPPORTS_SECTIONS.includes(pageStyle)
|
|
296
|
+
const encloseSections = sectionMergeStrategy === 'enclose' && hasItems && hasSections
|
|
297
|
+
let nextSectionLevel = atBookRoot ? undefined : 1 // undefined means allow part or chapter at top level
|
|
252
298
|
const lines = doc.getSourceLines()
|
|
253
299
|
const ignoreLines = []
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
buffer.endHeaderIdx = buffer.length - 1
|
|
257
|
-
}
|
|
258
|
-
buffer.push('')
|
|
259
|
-
buffer.push(`:docname: ${docname}`)
|
|
260
|
-
if (component !== lastComponentVersion.name) {
|
|
261
|
-
const thisComponentVersion =
|
|
262
|
-
component === componentVersion.name && version === componentVersion.version
|
|
263
|
-
? componentVersion
|
|
264
|
-
: contentCatalog.getComponentVersion(component, version)
|
|
265
|
-
if (thisComponentVersion) {
|
|
266
|
-
buffer.push(`:page-component-name: ${thisComponentVersion.name}`)
|
|
267
|
-
buffer.push(`:page-component-version:${thisComponentVersion.version ? ' ' + thisComponentVersion.version : ''}`)
|
|
268
|
-
buffer.push(':page-version: {page-component-version}')
|
|
269
|
-
buffer.push(`:page-component-display-version: ${thisComponentVersion.displayVersion}`)
|
|
270
|
-
buffer.push(`:page-component-title: ${thisComponentVersion.title}`)
|
|
271
|
-
lastComponentVersion = thisComponentVersion
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
buffer.push(`:page-module: ${module_}`)
|
|
275
|
-
buffer.push(`:page-relative-src-path: ${relative}`)
|
|
276
|
-
buffer.push(`:page-origin-url: ${origin.url}`)
|
|
277
|
-
buffer.push(`:page-origin-start-path:${origin.startPath && ' '}${origin.startPath}`)
|
|
278
|
-
buffer.push(`:page-origin-refname: ${origin.branch || origin.tag}`)
|
|
279
|
-
buffer.push(`:page-origin-reftype: ${origin.branch ? 'branch' : 'tag'}`)
|
|
280
|
-
buffer.push(`:page-origin-refhash: ${origin.worktree ? '(worktree)' : origin.refhash}`)
|
|
281
|
-
let headerHasBlockAttrs
|
|
300
|
+
const buffer = (builder.body ??= [])
|
|
301
|
+
if (buffer.length) buffer.push('')
|
|
282
302
|
if (doc.hasHeader()) {
|
|
283
|
-
for (const entry of
|
|
303
|
+
for (const entry of processPageHeader(doc, lines, ignoreLines, isRootPage)) {
|
|
284
304
|
if (entry.type === 'author_line') {
|
|
285
|
-
|
|
286
|
-
buffer.endHeaderIdx += 1
|
|
305
|
+
builder.setAuthor(entry.lines[0])
|
|
287
306
|
} else if (entry.type === 'attribute_entry') {
|
|
288
307
|
const name = entry.name
|
|
289
|
-
if (
|
|
308
|
+
if (entry.negated && name === 'sectnums') {
|
|
309
|
+
// catch sectnums missed by reducer; only allow turned off, not turning on
|
|
310
|
+
doc.source_header_attributes['$[]=']('sectnums', null)
|
|
311
|
+
} else if (!entry.negated && !doc.isAttributeLocked(name)) {
|
|
290
312
|
let val, newVal
|
|
291
313
|
if (
|
|
292
314
|
name.endsWith('-image') &&
|
|
293
315
|
(val = doc.getAttribute(name)) &&
|
|
294
|
-
(newVal = rewriteImageAttr(val, contentCatalog, assemblyModel, page.src, assembled.assets))
|
|
316
|
+
(newVal = rewriteImageAttr(val, contentCatalog, assemblyModel, page.src, assembled.assets)) != null
|
|
295
317
|
) {
|
|
296
318
|
if (newVal !== val) entry.lines = [`:${name}: ${newVal}`]
|
|
297
319
|
} else if (~(val = entry.lines.join('\n').substring(name.length + 3)).indexOf(':')) {
|
|
@@ -324,116 +346,151 @@ function mergeAsciiDoc (
|
|
|
324
346
|
if (newVal !== val) entry.lines = `:${entry.name}: ${newVal}`.split('\n')
|
|
325
347
|
}
|
|
326
348
|
}
|
|
327
|
-
|
|
328
|
-
buffer.splice(buffer.endHeaderIdx + 1, 0, ...entry.lines)
|
|
329
|
-
buffer.endHeaderIdx += entry.lines.length
|
|
330
|
-
} else {
|
|
331
|
-
buffer.push(...entry.lines)
|
|
332
|
-
}
|
|
349
|
+
;(entry.promote ? builder.header : buffer).push(...entry.lines)
|
|
333
350
|
} else {
|
|
334
|
-
if (entry.type === 'attrlist') headerHasBlockAttrs = true
|
|
351
|
+
if (entry.type === 'attrlist') builder.headerHasBlockAttrs = true
|
|
335
352
|
buffer.push(...entry.lines)
|
|
336
353
|
}
|
|
337
354
|
}
|
|
338
355
|
pageRoles = doc.getRoles()
|
|
339
356
|
}
|
|
340
357
|
if (roles.length) pageRoles = pageRoles.concat(roles[0] === 'page' ? roles.slice(1) : roles)
|
|
358
|
+
buffer.push(`:page-docname: ${docname}`)
|
|
359
|
+
if (component !== builder.currentComponentVersion.name) {
|
|
360
|
+
const thisComponentVersion =
|
|
361
|
+
component === componentVersion.name && version === componentVersion.version
|
|
362
|
+
? componentVersion
|
|
363
|
+
: contentCatalog.getComponentVersion(component, version)
|
|
364
|
+
if (thisComponentVersion) {
|
|
365
|
+
buffer.push(`:page-component-name: ${thisComponentVersion.name}`)
|
|
366
|
+
buffer.push(`:page-component-version:${thisComponentVersion.version ? ' ' + thisComponentVersion.version : ''}`)
|
|
367
|
+
buffer.push(':page-version: {page-component-version}')
|
|
368
|
+
buffer.push(`:page-component-display-version: ${thisComponentVersion.displayVersion}`)
|
|
369
|
+
buffer.push(`:page-component-title: ${thisComponentVersion.title}`)
|
|
370
|
+
builder.currentComponentVersion = thisComponentVersion
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
buffer.push(`:page-module: ${module_}`)
|
|
374
|
+
buffer.push(`:page-relative-src-path: ${relative}`)
|
|
375
|
+
buffer.push(`:page-origin-url: ${origin.url}`)
|
|
376
|
+
buffer.push(`:page-origin-start-path:${origin.startPath && ' '}${origin.startPath}`)
|
|
377
|
+
buffer.push(`:page-origin-refname: ${origin.branch || origin.tag}`)
|
|
378
|
+
buffer.push(`:page-origin-reftype: ${origin.branch ? 'branch' : 'tag'}`)
|
|
379
|
+
buffer.push(`:page-origin-refhash: ${origin.worktree ? '(worktree)' : origin.refhash}`)
|
|
341
380
|
let heading
|
|
342
|
-
if (pageStyle
|
|
343
|
-
let htitleAsciiDoc
|
|
344
|
-
let notitle
|
|
381
|
+
if (pageStyle != null && isRootPage) {
|
|
382
|
+
let htitleAsciiDoc, htitleOverride
|
|
345
383
|
if (pageStyle === 'preface') {
|
|
346
384
|
const hasPrefaceTitleAttr =
|
|
347
385
|
doc.isAttribute('preface-title') ||
|
|
348
386
|
doc.source_header_attributes['$key?']('preface-title') ||
|
|
349
387
|
doc.isAttributeLocked('preface-title')
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
388
|
+
if (hasPrefaceTitleAttr) {
|
|
389
|
+
htitleOverride = doc.getAttribute('preface-title', '')
|
|
390
|
+
} else if (!(htitleOverride = doc.getAttribute('assembly-root-title'))) {
|
|
391
|
+
if (encloseSections) {
|
|
392
|
+
htitleOverride = overviewTitle
|
|
393
|
+
} else if (builder.matchesDoctitle(navtitlePlain)) {
|
|
394
|
+
htitleOverride = ''
|
|
395
|
+
} else {
|
|
396
|
+
htitleOverride = undefined // means use navtitleAsciiDoc
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (htitleOverride === '') {
|
|
400
|
+
nextSectionLevel = 2
|
|
401
|
+
if (builder.headerHasBlockAttrs) {
|
|
402
|
+
htitleAsciiDoc = ''
|
|
403
|
+
} else {
|
|
404
|
+
sectionMergeStrategy = 'discrete'
|
|
405
|
+
if (atBookRoot && hasPrefaceTitleAttr) {
|
|
406
|
+
builder.header.push(':preface-title:')
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
htitleAsciiDoc = htitleOverride == null ? navtitleAsciiDoc : unconvertInlineAsciiDoc(htitleOverride)
|
|
411
|
+
if (htitleOverride === overviewTitle) overviewTitleAsciiDoc = htitleAsciiDoc // optimization
|
|
412
|
+
if (atBookRoot && hasPrefaceTitleAttr) {
|
|
413
|
+
if (!builder.headerHasBlockAttrs && (sectionMergeStrategy === 'discrete' || !hasSections)) {
|
|
414
|
+
builder.header.push(`:preface-title: ${htitleAsciiDoc}`)
|
|
362
415
|
htitleAsciiDoc = undefined
|
|
363
416
|
}
|
|
364
|
-
} else if (hasPrefaceTitleAttr && !(headerHasBlockAttrs || doc.hasSections())) {
|
|
365
|
-
buffer.splice(++buffer.endHeaderIdx, 0, `:preface-title: ${unconvertInlineAsciiDoc(htitleOverride)}`)
|
|
366
|
-
htitleAsciiDoc = undefined
|
|
367
|
-
} else {
|
|
368
|
-
htitleAsciiDoc = unconvertInlineAsciiDoc(htitleOverride)
|
|
369
417
|
}
|
|
370
418
|
}
|
|
419
|
+
} else if ((htitleOverride = doc.getAttribute('assembly-root-title', ''))) {
|
|
420
|
+
htitleAsciiDoc = unconvertInlineAsciiDoc(htitleOverride)
|
|
421
|
+
} else if (encloseSections) {
|
|
422
|
+
htitleAsciiDoc = overviewTitleAsciiDoc = unconvertInlineAsciiDoc(overviewTitle)
|
|
423
|
+
} else {
|
|
424
|
+
htitleAsciiDoc = navtitleAsciiDoc
|
|
371
425
|
}
|
|
372
426
|
if (htitleAsciiDoc != null) {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
buffer.unshift(`[#${pageId}]`)
|
|
427
|
+
heading = { title: htitleAsciiDoc, hlevel: part ? 1 : 2 }
|
|
428
|
+
if (pageStyle === 'part') {
|
|
429
|
+
nextSectionLevel = 1
|
|
377
430
|
} else {
|
|
378
|
-
|
|
431
|
+
nextSectionLevel = 2 // next section level is 2, even for special part
|
|
432
|
+
// enable next two lines if we always want to promote ID of root page to docid
|
|
433
|
+
//builder.setDocid(pageId)
|
|
434
|
+
//pageFragment = '#' + idSeparators.generateIdFromTitle(htitleAsciiDoc, idSeparators, pageIdLeader)
|
|
435
|
+
if (pageStyle === 'preface' && doctype !== 'book') {
|
|
436
|
+
heading.style = ''
|
|
437
|
+
if (doc.hasAttribute('sectnums')) {
|
|
438
|
+
doc.source_header_attributes['$[]=']('sectnums', null)
|
|
439
|
+
buffer.push(':!sectnums:')
|
|
440
|
+
}
|
|
441
|
+
}
|
|
379
442
|
}
|
|
380
|
-
heading = { title: htitleAsciiDoc, level: part ? 1 : 2 }
|
|
381
|
-
if (notitle) heading.notitle = true
|
|
382
|
-
nextSectionLevel = 2 // next section level is 2, even for special part
|
|
383
443
|
}
|
|
444
|
+
} else if (part) {
|
|
445
|
+
heading = { title: navtitleAsciiDoc, hlevel: level-- } // NOTE: level will always come in at 1
|
|
446
|
+
nextSectionLevel = pageStyle === 'part' ? 1 : 2
|
|
384
447
|
} else if (level) {
|
|
385
|
-
if (
|
|
448
|
+
if (atStartOfBody && !pageStyle && builder.matchesDoctitle(navtitlePlain)) {
|
|
386
449
|
level--
|
|
387
|
-
} else {
|
|
388
|
-
|
|
389
|
-
if (part && level === 1) level--
|
|
390
|
-
if ((heading = { title: navtitleAsciiDoc, level: level + 1 }).level > 6) {
|
|
391
|
-
Object.assign(heading, { level: 6, style: `discrete.h${heading.level}` })
|
|
392
|
-
}
|
|
450
|
+
} else if ((heading = { title: navtitleAsciiDoc, hlevel: level + 1 }).hlevel > 6) {
|
|
451
|
+
Object.assign(heading, { hlevel: 6, style: `discrete.h${heading.hlevel}` })
|
|
393
452
|
}
|
|
394
|
-
} else if (atDocumentRoot && rootLevel === 0 && hasAssemblyNavtitleAttr) {
|
|
395
|
-
pageFragment = `#${pageId}`
|
|
396
|
-
heading = { title: navtitleAsciiDoc, level: (nextSectionLevel = part ? 1 : 2) }
|
|
397
|
-
} else if (atBookRoot) {
|
|
398
|
-
nextSectionLevel = undefined
|
|
399
453
|
}
|
|
400
|
-
let enclosed
|
|
401
454
|
if (heading) {
|
|
402
455
|
const rolesAttr = pageRoles.reduce((str, it) => str + '.' + it, '')
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
if (assemblyModel.sectionMergeStrategy === 'enclose' && hasItems && doc.hasSections()) {
|
|
409
|
-
enclosed = true
|
|
410
|
-
// TODO: make overview section title configurable
|
|
411
|
-
//let overviewTitle = doc.getDocumentTitle()
|
|
412
|
-
//if (overviewTitle === navtitle) overviewTitle = doc.getAttribute('overview-title', 'Overview')
|
|
413
|
-
const overviewTitle = doc.getAttribute('overview-title', 'Overview')
|
|
414
|
-
const syntheticId = idSeparators.generateIdFromTitle(navtitleAsciiDoc, idSeparators)
|
|
415
|
-
let hlevel = level + 2
|
|
416
|
-
if (hlevel > 6) {
|
|
417
|
-
const blockStyle = `discrete.h${hlevel}`
|
|
418
|
-
hlevel = 6
|
|
419
|
-
buffer.push(`[${blockStyle}#${syntheticId}]`)
|
|
420
|
-
} else {
|
|
421
|
-
buffer.push(`[#${syntheticId}]`)
|
|
422
|
-
}
|
|
423
|
-
buffer.push(`${'='.repeat(hlevel)} ${overviewTitle}`)
|
|
456
|
+
const notitle = (heading.title ||= '{empty}') === '{empty}'
|
|
457
|
+
// remove conditional if we always want to promote ID of root page to docid
|
|
458
|
+
if (notitle) {
|
|
459
|
+
builder.setDocid(pageId)
|
|
460
|
+
pageFragment = '#' + idSeparators.generateIdFromTitle('', idSeparators, pageIdLeader)
|
|
424
461
|
}
|
|
462
|
+
const style = heading.style ?? (pageStyle === 'part' || pageStyle === 'section' ? '' : (pageStyle ?? ''))
|
|
463
|
+
buffer.push(`[${style}${pageFragment}${rolesAttr}${notitle ? '%notitle' : ''}]`)
|
|
464
|
+
buffer.push(`${'='.repeat(heading.hlevel)} ${heading.title}`)
|
|
465
|
+
if (notitle || !supportsSections) sectionMergeStrategy = 'discrete'
|
|
466
|
+
} else if (atStartOfBody) {
|
|
467
|
+
builder.setDocid(pageId)
|
|
425
468
|
}
|
|
469
|
+
if (isRootPage || (atStartOfBody && !heading)) assembled.pages.rootPageFragment = pageFragment
|
|
426
470
|
assembled.pages.set(page, pageFragment)
|
|
427
|
-
if (
|
|
471
|
+
if (encloseSections && !(atStartOfBody && heading)) {
|
|
472
|
+
overviewTitleAsciiDoc ??= unconvertInlineAsciiDoc(overviewTitle)
|
|
473
|
+
const sectionFragment = '#' + idSeparators.generateIdFromTitle(overviewTitleAsciiDoc, idSeparators, pageIdLeader)
|
|
474
|
+
if (heading && buffer.length) buffer.push('')
|
|
475
|
+
let hlevel = level + (nextSectionLevel = 2)
|
|
476
|
+
if (hlevel > 6) {
|
|
477
|
+
buffer.push(`[discrete.h${hlevel}${sectionFragment}]`)
|
|
478
|
+
hlevel = 6
|
|
479
|
+
} else {
|
|
480
|
+
buffer.push(`[${sectionFragment}]`)
|
|
481
|
+
}
|
|
482
|
+
buffer.push(`${'='.repeat(hlevel)} ${overviewTitleAsciiDoc}`)
|
|
483
|
+
}
|
|
484
|
+
if (hasSections) fixSectionLevels(doc.getSections(), nextSectionLevel)
|
|
428
485
|
const allBlocks = doc.findBy({ traverse_documents: true }, (it) =>
|
|
429
486
|
it.getContext() === 'document'
|
|
430
487
|
? it.getDocument().isNested()
|
|
431
488
|
: !(it.getContext() === 'table_cell' && it.getStyle() === 'asciidoc')
|
|
432
489
|
)
|
|
433
490
|
if (doc.getDoctype() === 'manpage') {
|
|
434
|
-
const firstSectionIdx =
|
|
491
|
+
const firstSectionIdx = hasSections ? doc.getSections()[0].getLineNumber() - 1 : lines.length
|
|
435
492
|
for (let idx = 0; idx < firstSectionIdx; idx++) {
|
|
436
|
-
if (
|
|
493
|
+
if (ignoreLines.includes(idx)) continue
|
|
437
494
|
const line = lines[idx]
|
|
438
495
|
if (line.startsWith('== ') && line.length > 3) {
|
|
439
496
|
allBlocks.unshift({
|
|
@@ -477,10 +534,10 @@ function mergeAsciiDoc (
|
|
|
477
534
|
})
|
|
478
535
|
let skipping
|
|
479
536
|
for (let idx = 0, lastIdx = lines.length - 1; idx <= lastIdx; idx++) {
|
|
480
|
-
if (
|
|
537
|
+
if (ignoreLines.includes(idx)) continue
|
|
481
538
|
let line = lines[idx]
|
|
482
539
|
if (line.startsWith('//')) {
|
|
483
|
-
if (line
|
|
540
|
+
if (line.charAt(2) !== '/') continue
|
|
484
541
|
if (line.length > 3 && line === '/'.repeat(line.length)) {
|
|
485
542
|
if (skipping) {
|
|
486
543
|
if (line === skipping) skipping = undefined
|
|
@@ -547,9 +604,9 @@ function mergeAsciiDoc (
|
|
|
547
604
|
let idx = lineno - 1
|
|
548
605
|
if (context === 'section' && !block.getDocument().isNested()) {
|
|
549
606
|
if (block.getSectionName() === 'header') return
|
|
550
|
-
let blockStyle =
|
|
607
|
+
let blockStyle = sectionMergeStrategy === 'discrete' ? 'discrete' : undefined
|
|
551
608
|
lines[idx] = lines[idx].replace(/^=+ (.+)/, (_, rest) => {
|
|
552
|
-
let targetMarkerLength = block.level + 1 + level
|
|
609
|
+
let targetMarkerLength = block.level + 1 + level
|
|
553
610
|
if (targetMarkerLength > 6) {
|
|
554
611
|
blockStyle = `discrete.h${targetMarkerLength}`
|
|
555
612
|
targetMarkerLength = 6
|
|
@@ -593,10 +650,13 @@ function mergeAsciiDoc (
|
|
|
593
650
|
buffer,
|
|
594
651
|
lines.filter((it) => it !== undefined)
|
|
595
652
|
)
|
|
596
|
-
const attributeEntries =
|
|
653
|
+
const attributeEntries = doc.source_header_attributes.$entries()
|
|
597
654
|
if (attributeEntries.length) {
|
|
598
655
|
const resolvedAttributeEntries = attributeEntries.reduce(
|
|
599
656
|
(accum, [name, val]) => {
|
|
657
|
+
if (val) {
|
|
658
|
+
if (val['$nil?']()) val = null
|
|
659
|
+
}
|
|
600
660
|
// Q: couldn't we just check if attribute is locked?
|
|
601
661
|
if (name in mutableAttributes) {
|
|
602
662
|
const initialVal = mutableAttributes[name]
|
|
@@ -614,19 +674,19 @@ function mergeAsciiDoc (
|
|
|
614
674
|
)
|
|
615
675
|
if (resolvedAttributeEntries.length > 1) safePush(buffer, resolvedAttributeEntries)
|
|
616
676
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
677
|
+
if (typeof doc.restoreLogger === 'function') doc.restoreLogger()
|
|
678
|
+
} else if (level && !hash) {
|
|
679
|
+
const buffer = (builder.body ??= [])
|
|
680
|
+
if (atStartOfBody && builder.matchesDoctitle(navtitlePlain)) {
|
|
620
681
|
level--
|
|
621
682
|
} else {
|
|
622
|
-
buffer.
|
|
623
|
-
buffer.push('')
|
|
683
|
+
if (buffer.length) buffer.push('')
|
|
624
684
|
const syntheticId = idSeparators.generateIdFromTitle(navtitleAsciiDoc, idSeparators)
|
|
625
685
|
let sectionTitle = navtitleAsciiDoc
|
|
626
686
|
if (urlType === 'external') {
|
|
627
687
|
sectionTitle = `${url}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
|
|
628
688
|
} else if (urlType === 'internal' && !unresolved) {
|
|
629
|
-
const resource = files.find((it) => it.pub.url ===
|
|
689
|
+
const resource = files.find((it) => it.pub.url === pathname)
|
|
630
690
|
if (resource) {
|
|
631
691
|
if (resource.src.family === 'page' && pagesInOutline.has(resource.pub.url)) {
|
|
632
692
|
const refid = generateScopedId(resource.src, componentVersion, idSeparators, filetype, true)
|
|
@@ -636,41 +696,42 @@ function mergeAsciiDoc (
|
|
|
636
696
|
}
|
|
637
697
|
}
|
|
638
698
|
}
|
|
699
|
+
if (supportsParts && level === 1 && roles.includes('part')) {
|
|
700
|
+
roles.splice(roles.indexOf('part', 1))
|
|
701
|
+
level--
|
|
702
|
+
}
|
|
639
703
|
const hlevel = level > 5 ? 6 : level + 1
|
|
640
704
|
const hroles = urlType === 'internal' ? roles.slice(1) : roles
|
|
641
705
|
buffer.push(`[${hlevel > 6 ? 'discrete' : ''}#${syntheticId}${hroles.reduce((str, it) => str + '.' + it, '')}]`)
|
|
642
706
|
buffer.push(`${'='.repeat(hlevel)} ${sectionTitle}`)
|
|
643
707
|
}
|
|
644
708
|
}
|
|
645
|
-
if (hasItems)
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
})
|
|
669
|
-
}
|
|
670
|
-
return buffer
|
|
709
|
+
if (!hasItems) return
|
|
710
|
+
const nextLevel = level + 1
|
|
711
|
+
// NOTE: drop first child if same as parent; should we keep if content is different?
|
|
712
|
+
;(urlType === 'internal' && items[0].urlType === 'internal' && pathname === items[0].url && !items[0].items?.length
|
|
713
|
+
? items.slice(1)
|
|
714
|
+
: items
|
|
715
|
+
).forEach((item) => {
|
|
716
|
+
mergeAsciiDoc(
|
|
717
|
+
loadAsciiDoc,
|
|
718
|
+
contentCatalog,
|
|
719
|
+
builder,
|
|
720
|
+
componentVersion,
|
|
721
|
+
item,
|
|
722
|
+
files,
|
|
723
|
+
pagesInOutline,
|
|
724
|
+
idSeparators,
|
|
725
|
+
asciidocConfig,
|
|
726
|
+
mutableAttributes,
|
|
727
|
+
assemblyModel,
|
|
728
|
+
nextLevel,
|
|
729
|
+
atBookRoot
|
|
730
|
+
)
|
|
731
|
+
})
|
|
671
732
|
}
|
|
672
733
|
|
|
673
|
-
function
|
|
734
|
+
function processPageHeader (doc, lines, ignoreLines, isRootPage) {
|
|
674
735
|
const entries = []
|
|
675
736
|
let assemblyHeaderAttributes = isRootPage && doc.getAttribute('assembly-header-attributes', '%authors')
|
|
676
737
|
assemblyHeaderAttributes = new Set(assemblyHeaderAttributes ? assemblyHeaderAttributes.split(/, */) : undefined)
|
|
@@ -690,8 +751,7 @@ function processDocumentHeader (doc, lines, ignoreLines, isRootPage) {
|
|
|
690
751
|
}
|
|
691
752
|
assemblyHeaderAttributes.delete('%authors')
|
|
692
753
|
}
|
|
693
|
-
const
|
|
694
|
-
for (const name of assemblyHeaderAttributes) headerAttributes.$delete(name)
|
|
754
|
+
for (const name of assemblyHeaderAttributes) doc.source_header_attributes.$delete(name)
|
|
695
755
|
}
|
|
696
756
|
const doctitleIdx = doc.getHeader().getLineNumber() - 1
|
|
697
757
|
const end = doc.getBlocks()[0]?.getLineNumber() ?? lines.length
|
|
@@ -706,7 +766,7 @@ function processDocumentHeader (doc, lines, ignoreLines, isRootPage) {
|
|
|
706
766
|
}
|
|
707
767
|
const line = lines[idx]
|
|
708
768
|
if (open === ':' || open === '-:') {
|
|
709
|
-
if (open === ':') current.
|
|
769
|
+
if (open === ':') current.appendLine(line)
|
|
710
770
|
if (!line?.endsWith(' \\')) current = open = undefined
|
|
711
771
|
} else if (line) {
|
|
712
772
|
let attributeEntryMatch
|
|
@@ -714,13 +774,14 @@ function processDocumentHeader (doc, lines, ignoreLines, isRootPage) {
|
|
|
714
774
|
if (chr0 === '/' && line.charAt(1) === '/') {
|
|
715
775
|
if (line.startsWith('////') && line === '/'.repeat(line.length)) {
|
|
716
776
|
if (open) {
|
|
717
|
-
current.
|
|
777
|
+
current.appendLine(line)
|
|
718
778
|
if (open === line) current = open = undefined
|
|
719
779
|
} else {
|
|
720
780
|
entries.push((current = { type: 'block_comment', lines: [(open = line)] }))
|
|
781
|
+
current.appendLine = Array.prototype.push.bind(current.lines)
|
|
721
782
|
}
|
|
722
783
|
} else if (open) {
|
|
723
|
-
current.
|
|
784
|
+
current.appendLine(line)
|
|
724
785
|
} else if (belowDoctitle && line.charAt(2) === '/') {
|
|
725
786
|
break
|
|
726
787
|
} else {
|
|
@@ -728,7 +789,7 @@ function processDocumentHeader (doc, lines, ignoreLines, isRootPage) {
|
|
|
728
789
|
current = undefined
|
|
729
790
|
}
|
|
730
791
|
} else if (open) {
|
|
731
|
-
current.
|
|
792
|
+
current.appendLine(line)
|
|
732
793
|
} else if (chr0 === ':' && ~line.indexOf(':', 2) && (attributeEntryMatch = line.match(ATTR_ENTRY_RX))) {
|
|
733
794
|
let name = attributeEntryMatch[1]
|
|
734
795
|
const negated = name.charAt() === '!' || name.charAt(name.length - 1) === '!'
|
|
@@ -737,7 +798,9 @@ function processDocumentHeader (doc, lines, ignoreLines, isRootPage) {
|
|
|
737
798
|
if (line.endsWith(' \\')) open = '-:' // disallow value continuation
|
|
738
799
|
} else {
|
|
739
800
|
if (line.endsWith(' \\')) open = ':'
|
|
740
|
-
entries.push((current = { type: 'attribute_entry', name, negated, lines: [
|
|
801
|
+
entries.push((current = { type: 'attribute_entry', name, negated, lines: [], lineno: idx + 1 }))
|
|
802
|
+
current.lines.push(negated ? `:!${name}:` : line)
|
|
803
|
+
current.appendLine = Array.prototype.push.bind(negated ? [] : current.lines)
|
|
741
804
|
if (assemblyHeaderAttributes.has(name)) current.promote = true
|
|
742
805
|
}
|
|
743
806
|
} else if (belowDoctitle) {
|
|
@@ -788,33 +851,29 @@ function fixSectionLevels (sections, expectedLevel) {
|
|
|
788
851
|
})
|
|
789
852
|
}
|
|
790
853
|
|
|
791
|
-
// NOTE: blank lines at top and bottom of document create mismatch when using line numbers to navigate source lines
|
|
792
|
-
// IMPORTANT: this must not leave behind lines the parser will drop!
|
|
793
|
-
// IDEA: another option is to capture initial lineno of reader and use as offset (but preseves those blank lines)
|
|
794
|
-
function trimAsciiDoc (buffer) {
|
|
795
|
-
return Buffer.from(
|
|
796
|
-
buffer
|
|
797
|
-
.toString()
|
|
798
|
-
.replace(/^(?:[ \t]*\r\n?|[ \t]*\n)+/, '')
|
|
799
|
-
.trimRight()
|
|
800
|
-
)
|
|
801
|
-
}
|
|
802
|
-
|
|
803
854
|
function safePush (onto, entries) {
|
|
804
855
|
try {
|
|
805
856
|
onto.push(...entries)
|
|
806
|
-
} catch
|
|
807
|
-
/* istanbul ignore if */
|
|
808
|
-
if (!(err instanceof RangeError)) throw err
|
|
857
|
+
} catch {
|
|
809
858
|
for (const e of entries) onto.push(e)
|
|
810
859
|
}
|
|
811
860
|
}
|
|
812
861
|
|
|
813
|
-
function generateIdFromTitle (titleAsciiDoc, idSeparators) {
|
|
814
|
-
const Section = this.$class()
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
862
|
+
function generateIdFromTitle (titleAsciiDoc, idSeparators, idLeader) {
|
|
863
|
+
const Section = this.$class().$$base_module.Section
|
|
864
|
+
// NOTE: refs in catalog will always be empty
|
|
865
|
+
const baseId = titleAsciiDoc ? Section.$generate_id(titleAsciiDoc, this) : '_'
|
|
866
|
+
let id = `_${idSeparators.coordinate}${idLeader ?? ''}${baseId}`
|
|
867
|
+
const syntheticIds = (this.catalog.syntheticIds ??= {})
|
|
868
|
+
if (id in syntheticIds) {
|
|
869
|
+
const sep = (this.getAttribute('idseparator') ?? '_').charAt()
|
|
870
|
+
let cnt = this.$class().$$base_module.Compliance.unique_id_start_index
|
|
871
|
+
let candidate
|
|
872
|
+
while ((candidate = `${id}${sep}${cnt}`) in syntheticIds) cnt++
|
|
873
|
+
id = candidate
|
|
874
|
+
}
|
|
875
|
+
syntheticIds[id] = true
|
|
876
|
+
return id
|
|
818
877
|
}
|
|
819
878
|
|
|
820
879
|
module.exports = produceAssemblyFile
|