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