@antora/assembler 1.0.0-beta.9 → 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/adapters/asciidoctor/jsonl-logger.rb +25 -0
- package/lib/assemble-content.js +141 -135
- package/lib/compile-conversion-attributes.js +76 -0
- package/lib/configure.js +44 -16
- package/lib/constants.js +24 -0
- package/lib/filter-component-versions.js +25 -62
- package/lib/index.js +1 -1
- package/lib/load-config.js +84 -43
- package/lib/log-command.js +18 -0
- package/lib/produce-assembly-file.js +539 -509
- package/lib/produce-assembly-files.js +128 -157
- package/lib/util/collate-asciidoc-attributes.js +32 -0
- package/lib/util/create-resource-key.js +7 -0
- package/lib/util/deep-clone.js +18 -0
- package/lib/util/generate-scoped-id.js +26 -0
- package/lib/util/identify-mutable-attributes.js +25 -0
- package/lib/util/lazy-readable.js +12 -3
- package/lib/util/matcher.js +150 -0
- package/lib/util/parse-resource-ref.js +36 -0
- package/lib/util/resolver.js +36 -0
- package/lib/util/rewriter.js +231 -0
- package/lib/util/rx.js +5 -0
- package/lib/util/to-hash.js +7 -0
- package/lib/util/unconvert-inline-asciidoc.js +22 -14
- package/package.json +15 -15
- package/lib/select-mutable-attributes.js +0 -26
- package/lib/util/compute-out.js +0 -57
- package/lib/util/create-asciidoc-file.js +0 -17
|
@@ -1,15 +1,38 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const createResourceKey = require('./util/create-resource-key')
|
|
4
|
+
const generateScopedId = require('./util/generate-scoped-id')
|
|
5
|
+
const { resolveLinkTarget } = require('./util/resolver')
|
|
6
|
+
const {
|
|
7
|
+
rewriteXrefs,
|
|
8
|
+
rewriteImageAttr,
|
|
9
|
+
rewriteImageRef,
|
|
10
|
+
rewriteInlineImages,
|
|
11
|
+
rewriteStyleAttribute,
|
|
12
|
+
} = require('./util/rewriter')
|
|
5
13
|
const sanitize = require('./util/sanitize')
|
|
14
|
+
const toHash = require('./util/to-hash')
|
|
6
15
|
const unconvertInlineAsciiDoc = require('./util/unconvert-inline-asciidoc')
|
|
7
16
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
17
|
+
const ATTR_ENTRY_RX = /^:(!?[\p{Alpha}0-9_][^:]*):(?: |$)/u
|
|
18
|
+
const BUILT_IN_NAMED_ENTITIES = { amp: '&', apos: "'", gt: '>', lt: '<', nbsp: ' ', quot: '"' }
|
|
19
|
+
const CHAR_REF_RX = /&(?:([a-z][a-z]+\d{0,2})|#(?:(\d{2,6})|x([a-z\d]{2,5})));/g
|
|
20
|
+
const DISCARD_ATTRIBUTE_NAMES = [
|
|
21
|
+
'assembly-doctype',
|
|
22
|
+
'assembly-header-attributes',
|
|
23
|
+
'assembly-overview-title',
|
|
24
|
+
'assembly-navtitle',
|
|
25
|
+
'assembly-root-title',
|
|
26
|
+
'assembly-slug',
|
|
27
|
+
'assembly-style',
|
|
28
|
+
'doctype',
|
|
29
|
+
'leveloffset',
|
|
30
|
+
'page-aliases',
|
|
31
|
+
'preface-title',
|
|
32
|
+
'underscore',
|
|
33
|
+
]
|
|
34
|
+
const { NAMED_ID_ATTR_RX } = require('./util/rx')
|
|
35
|
+
const ASSEMBLY_STYLE_SUPPORTS_SECTIONS = ['abstract', 'appendix', 'part', 'preface', 'section']
|
|
13
36
|
|
|
14
37
|
function produceAssemblyFile (
|
|
15
38
|
loadAsciiDoc,
|
|
@@ -22,185 +45,318 @@ function produceAssemblyFile (
|
|
|
22
45
|
assemblyModel
|
|
23
46
|
) {
|
|
24
47
|
const pagesByUrl = files.reduce((map, it) => (it.src.family === 'page' ? map.set(it.pub.url, it) : map), new Map())
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
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
|
|
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
|
+
)
|
|
60
|
+
const idSeparators = {
|
|
61
|
+
prefix:
|
|
62
|
+
'assembler-idprefix' in asciidocConfig.attributes ? (asciidocConfig.attributes['assembler-idprefix'] ?? '') : '_',
|
|
63
|
+
scope: xmlIds ? '---' : ':::',
|
|
64
|
+
coordinate: xmlIds ? '----' : ':',
|
|
65
|
+
generateIdFromTitle: generateIdFromTitle.bind(scratchDoc),
|
|
66
|
+
}
|
|
67
|
+
asciidocConfig = prepareAsciiDocConfig(
|
|
68
|
+
contentCatalog,
|
|
69
|
+
{ component, version },
|
|
70
|
+
pagesInOutline,
|
|
71
|
+
asciidocConfig,
|
|
72
|
+
assemblyModel,
|
|
73
|
+
idSeparators,
|
|
74
|
+
scratchDoc
|
|
75
|
+
)
|
|
76
|
+
const builder = buildAssemblyHeader(componentVersion, outline.content, assemblyModel)
|
|
77
|
+
mergeAsciiDoc(
|
|
28
78
|
loadAsciiDoc,
|
|
29
79
|
contentCatalog,
|
|
30
|
-
|
|
80
|
+
builder,
|
|
31
81
|
componentVersion,
|
|
32
82
|
outline,
|
|
33
83
|
files,
|
|
34
84
|
pagesInOutline,
|
|
85
|
+
idSeparators,
|
|
35
86
|
asciidocConfig,
|
|
36
87
|
mutableAttributes,
|
|
37
88
|
assemblyModel
|
|
38
89
|
)
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return createAsciiDocFile(contentCatalog, {
|
|
90
|
+
const stem =
|
|
91
|
+
(builder.slug ? sanitizeSlug(builder.slug) : generateSlug(rootLevel === 0 ? 'index' : builder.baseDoctitle)) ||
|
|
92
|
+
'export-' + (assemblyModel.stemSeq = (assemblyModel.exportSeq ?? 0) + 1)
|
|
93
|
+
const downloadStem = [component, version, stem === 'index' ? '' : stem].filter((it) => it).join('-')
|
|
94
|
+
const file = contentCatalog.createFile({
|
|
45
95
|
asciidoc: asciidocConfig,
|
|
46
96
|
assembler: { assembled: pagesInOutline.assembled, downloadStem, rootLevel },
|
|
47
|
-
contents:
|
|
48
|
-
src: {
|
|
49
|
-
|
|
50
|
-
version: componentVersion.version,
|
|
51
|
-
module: 'ROOT',
|
|
52
|
-
family: 'export',
|
|
53
|
-
relative: stem + '.adoc',
|
|
54
|
-
},
|
|
97
|
+
contents: builder.serialize(),
|
|
98
|
+
src: { component, version, componentVersion, module: 'ROOT', family: 'export', relative: stem + '.adoc' },
|
|
99
|
+
pub: false,
|
|
55
100
|
})
|
|
101
|
+
file.path = file.out.path // use out path as path so assets can be published to same hierarchy
|
|
102
|
+
delete file.out
|
|
103
|
+
return file
|
|
56
104
|
}
|
|
57
105
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
const
|
|
106
|
+
function prepareAsciiDocConfig (contentCatalog, ctx, pagesInOutline, asciidocConfig, assemblyModel, idSeparators, doc) {
|
|
107
|
+
let attributesModified
|
|
108
|
+
const configShared = asciidocConfig.$shared
|
|
109
|
+
const sharedAttributes = asciidocConfig.attributes
|
|
110
|
+
if (!configShared) {
|
|
111
|
+
if (configShared == null) {
|
|
112
|
+
const assets = pagesInOutline.assembled.assets
|
|
113
|
+
for (const [name, val] of Object.entries(sharedAttributes)) {
|
|
114
|
+
if (!(val?.constructor === String && ~val.indexOf(':'))) continue
|
|
115
|
+
let newVal
|
|
116
|
+
if (!name.endsWith('-image') || !(newVal = rewriteImageAttr(val, contentCatalog, assemblyModel, ctx, assets))) {
|
|
117
|
+
if (~(newVal = val).indexOf('image:')) {
|
|
118
|
+
newVal = rewriteInlineImages(newVal, contentCatalog, assemblyModel, ctx, assets)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (newVal !== val) sharedAttributes[name] = newVal
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const [name, val] of Object.entries(sharedAttributes)) {
|
|
125
|
+
if (!(val?.constructor === String && ~val.indexOf(':'))) continue
|
|
126
|
+
if (~val.indexOf('xref:')) {
|
|
127
|
+
const newVal = rewriteXrefs(
|
|
128
|
+
val,
|
|
129
|
+
contentCatalog,
|
|
130
|
+
assemblyModel,
|
|
131
|
+
ctx,
|
|
132
|
+
false,
|
|
133
|
+
pagesInOutline,
|
|
134
|
+
idSeparators,
|
|
135
|
+
null,
|
|
136
|
+
doc
|
|
137
|
+
)
|
|
138
|
+
if (newVal !== val) (attributesModified ??= {})[name] = newVal
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (configShared == null) Object.defineProperty(asciidocConfig, '$shared', { value: attributesModified == null })
|
|
142
|
+
}
|
|
143
|
+
return Object.assign({}, asciidocConfig, { attributes: Object.assign({}, sharedAttributes, attributesModified) })
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function buildAssemblyHeader (componentVersion, navtitle, assemblyModel) {
|
|
147
|
+
const { name: componentName, version, displayVersion, title } = componentVersion
|
|
61
148
|
const navtitleAsciiDoc = unconvertInlineAsciiDoc(navtitle)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
+
}
|
|
78
193
|
}
|
|
79
194
|
|
|
80
|
-
function selectPagesInOutline (outlineEntry, pagesByUrl,
|
|
195
|
+
function selectPagesInOutline (outlineEntry, pagesByUrl, accum) {
|
|
81
196
|
accum ??= Object.assign(new Map(), { assembled: { pages: new Map(), assets: new Set() } })
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
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)
|
|
86
204
|
}
|
|
87
|
-
accum.set(page.pub.url, page)
|
|
88
205
|
}
|
|
89
|
-
for (const item of
|
|
206
|
+
for (const item of items) selectPagesInOutline(item, pagesByUrl, accum)
|
|
90
207
|
return accum
|
|
91
208
|
}
|
|
92
209
|
|
|
93
210
|
function mergeAsciiDoc (
|
|
94
211
|
loadAsciiDoc,
|
|
95
212
|
contentCatalog,
|
|
96
|
-
|
|
213
|
+
builder,
|
|
97
214
|
componentVersion,
|
|
98
215
|
outlineEntry,
|
|
99
216
|
files,
|
|
100
217
|
pagesInOutline,
|
|
218
|
+
idSeparators,
|
|
101
219
|
asciidocConfig,
|
|
102
220
|
mutableAttributes,
|
|
103
221
|
assemblyModel,
|
|
104
|
-
lastComponentVersion = componentVersion,
|
|
105
222
|
level = 0,
|
|
106
223
|
supportsParts = false
|
|
107
224
|
) {
|
|
225
|
+
const { items = [], roles = [], unresolved, urlType, url, pathname, hash } = outlineEntry
|
|
108
226
|
// TODO: we could try to be smart about it and make sure the page with fragment is included at least once
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
return
|
|
227
|
+
if (roles.includes('site-only') || (urlType === 'external' && !URL.canParse(url))) {
|
|
228
|
+
builder.body ??= []
|
|
229
|
+
return builder
|
|
112
230
|
}
|
|
113
|
-
|
|
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
|
|
231
|
+
const assembled = pagesInOutline.assembled
|
|
126
232
|
// 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(
|
|
128
|
-
|
|
129
|
-
|
|
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)
|
|
130
242
|
const hasItems = items.length > 0
|
|
131
|
-
|
|
132
|
-
const idSeparator = xmlIds ? '-' : ':'
|
|
133
|
-
const idScopeSeparator = idSeparator.repeat(3)
|
|
134
|
-
const idCoordinateSeparator = idSeparator === '-' ? '----' : idSeparator
|
|
135
|
-
if (page && !pagesInOutline.assembled.pages.has(page)) {
|
|
243
|
+
if (page && !assembled.pages.has(page)) {
|
|
136
244
|
const contents = page.src.contents
|
|
137
245
|
if (contents == null) {
|
|
138
|
-
|
|
139
|
-
return
|
|
246
|
+
builder.body ??= []
|
|
247
|
+
return builder
|
|
140
248
|
}
|
|
141
|
-
const { component, version, module: module_, relative, origin, mediaType } = page.src
|
|
142
|
-
const topicPrefix = ~relative.indexOf('/') ? path.dirname(relative) + '/' : ''
|
|
143
249
|
const pageAsAsciiDoc = new page.constructor(
|
|
144
|
-
Object.assign({}, page, { contents:
|
|
250
|
+
Object.assign({}, page, { contents: Buffer.from(contents.toString().trimEnd()), mediaType: page.src.mediaType })
|
|
145
251
|
)
|
|
146
252
|
const doc = loadAsciiDoc(pageAsAsciiDoc, contentCatalog, asciidocConfig)
|
|
147
|
-
if (doc.
|
|
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')
|
|
265
|
+
let hasAssemblyNavtitleAttr
|
|
266
|
+
if ((hasAssemblyNavtitleAttr = !!doc.getAttribute('assembly-navtitle'))) {
|
|
148
267
|
navtitleAsciiDoc = doc.getAttribute('assembly-navtitle')
|
|
149
268
|
navtitlePlain = sanitize((navtitle = doc.$apply_reftext_subs(navtitleAsciiDoc)))
|
|
150
|
-
if (
|
|
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
|
-
}
|
|
160
|
-
if (atDocumentRoot) {
|
|
161
|
-
const authors = doc.getAuthors()
|
|
162
|
-
if (authors.length) {
|
|
163
|
-
const authorLine = authors
|
|
164
|
-
.map((author) => {
|
|
165
|
-
const email = author.getEmail()
|
|
166
|
-
return email ? `${author.getName()} <${author.getEmail()}>` : author.getName()
|
|
167
|
-
})
|
|
168
|
-
.join('; ')
|
|
169
|
-
buffer.splice(1, 0, authorLine)
|
|
170
|
-
}
|
|
269
|
+
if (isRootPage) builder.setDoctitle(navtitle, navtitleAsciiDoc, navtitlePlain)
|
|
171
270
|
}
|
|
271
|
+
const overviewTitle = doc.getAttribute('assembly-overview-title', 'Overview')
|
|
272
|
+
let overviewTitleAsciiDoc
|
|
172
273
|
// NOTE: in Antora, docname is relative src path from module without file extension
|
|
173
274
|
const docname = doc.getAttribute('docname')
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
let
|
|
177
|
-
let
|
|
178
|
-
if (qualifyId) {
|
|
179
|
-
idScope = [component, module_ === 'ROOT' ? '' : module_, idScope].join(idCoordinateSeparator)
|
|
180
|
-
} else if (module_ !== 'ROOT') {
|
|
181
|
-
idScope = module_ + idCoordinateSeparator + idScope
|
|
182
|
-
} else if (ReservedIdNames.includes(docnameForId)) {
|
|
183
|
-
idScope = idPrefix = idScope + idScopeSeparator
|
|
184
|
-
}
|
|
185
|
-
idPrefix ??= idScope + idScopeSeparator
|
|
186
|
-
let pageFragment = ''
|
|
187
|
-
let pageRoles = ''
|
|
275
|
+
const pageId = generateScopedId(page.src, componentVersion, idSeparators, filetype)
|
|
276
|
+
const pageIdLeader = pageId + idSeparators.scope
|
|
277
|
+
let pageFragment = `#${pageId}`
|
|
278
|
+
let pageRoles = []
|
|
188
279
|
let pageStyle = doc.getAttribute('assembly-style', '')
|
|
280
|
+
if (!pageStyle && isRootPage && hasItems && !doc.source_header_attributes['$key?']('assembly-style')) {
|
|
281
|
+
pageStyle = rootPageStyle
|
|
282
|
+
}
|
|
189
283
|
let part
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
|
196
293
|
}
|
|
197
|
-
|
|
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
|
|
198
298
|
const lines = doc.getSourceLines()
|
|
199
299
|
const ignoreLines = []
|
|
200
|
-
buffer
|
|
201
|
-
buffer.push('')
|
|
202
|
-
|
|
203
|
-
|
|
300
|
+
const buffer = (builder.body ??= [])
|
|
301
|
+
if (buffer.length) buffer.push('')
|
|
302
|
+
if (doc.hasHeader()) {
|
|
303
|
+
for (const entry of processPageHeader(doc, lines, ignoreLines, isRootPage)) {
|
|
304
|
+
if (entry.type === 'author_line') {
|
|
305
|
+
builder.setAuthor(entry.lines[0])
|
|
306
|
+
} else if (entry.type === 'attribute_entry') {
|
|
307
|
+
const name = entry.name
|
|
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)) {
|
|
312
|
+
let val, newVal
|
|
313
|
+
if (
|
|
314
|
+
name.endsWith('-image') &&
|
|
315
|
+
(val = doc.getAttribute(name)) &&
|
|
316
|
+
(newVal = rewriteImageAttr(val, contentCatalog, assemblyModel, page.src, assembled.assets)) != null
|
|
317
|
+
) {
|
|
318
|
+
if (newVal !== val) entry.lines = [`:${name}: ${newVal}`]
|
|
319
|
+
} else if (~(val = entry.lines.join('\n').substring(name.length + 3)).indexOf(':')) {
|
|
320
|
+
newVal = val
|
|
321
|
+
if (~newVal.indexOf('image:')) {
|
|
322
|
+
newVal = rewriteInlineImages(
|
|
323
|
+
newVal,
|
|
324
|
+
contentCatalog,
|
|
325
|
+
assemblyModel,
|
|
326
|
+
page.src,
|
|
327
|
+
assembled.assets,
|
|
328
|
+
false,
|
|
329
|
+
doc
|
|
330
|
+
)
|
|
331
|
+
}
|
|
332
|
+
if (~newVal.indexOf('xref:')) {
|
|
333
|
+
newVal = rewriteXrefs(
|
|
334
|
+
newVal,
|
|
335
|
+
contentCatalog,
|
|
336
|
+
assemblyModel,
|
|
337
|
+
page.src,
|
|
338
|
+
false,
|
|
339
|
+
pagesInOutline,
|
|
340
|
+
idSeparators,
|
|
341
|
+
pageIdLeader,
|
|
342
|
+
doc,
|
|
343
|
+
{ file: relative, lineno: entry.lineno }
|
|
344
|
+
)
|
|
345
|
+
}
|
|
346
|
+
if (newVal !== val) entry.lines = `:${entry.name}: ${newVal}`.split('\n')
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
;(entry.promote ? builder.header : buffer).push(...entry.lines)
|
|
350
|
+
} else {
|
|
351
|
+
if (entry.type === 'attrlist') builder.headerHasBlockAttrs = true
|
|
352
|
+
buffer.push(...entry.lines)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
pageRoles = doc.getRoles()
|
|
356
|
+
}
|
|
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) {
|
|
204
360
|
const thisComponentVersion =
|
|
205
361
|
component === componentVersion.name && version === componentVersion.version
|
|
206
362
|
? componentVersion
|
|
@@ -211,7 +367,7 @@ function mergeAsciiDoc (
|
|
|
211
367
|
buffer.push(':page-version: {page-component-version}')
|
|
212
368
|
buffer.push(`:page-component-display-version: ${thisComponentVersion.displayVersion}`)
|
|
213
369
|
buffer.push(`:page-component-title: ${thisComponentVersion.title}`)
|
|
214
|
-
|
|
370
|
+
builder.currentComponentVersion = thisComponentVersion
|
|
215
371
|
}
|
|
216
372
|
}
|
|
217
373
|
buffer.push(`:page-module: ${module_}`)
|
|
@@ -221,90 +377,120 @@ function mergeAsciiDoc (
|
|
|
221
377
|
buffer.push(`:page-origin-refname: ${origin.branch || origin.tag}`)
|
|
222
378
|
buffer.push(`:page-origin-reftype: ${origin.branch ? 'branch' : 'tag'}`)
|
|
223
379
|
buffer.push(`:page-origin-refhash: ${origin.worktree ? '(worktree)' : origin.refhash}`)
|
|
224
|
-
if (doc.hasHeader()) pageRoles = processDocumentHeader(doc, lines, buffer, ignoreLines)
|
|
225
380
|
let heading
|
|
226
|
-
if (pageStyle
|
|
227
|
-
let htitleAsciiDoc
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
381
|
+
if (pageStyle != null && isRootPage) {
|
|
382
|
+
let htitleAsciiDoc, htitleOverride
|
|
383
|
+
if (pageStyle === 'preface') {
|
|
384
|
+
const hasPrefaceTitleAttr =
|
|
385
|
+
doc.isAttribute('preface-title') ||
|
|
386
|
+
doc.source_header_attributes['$key?']('preface-title') ||
|
|
387
|
+
doc.isAttributeLocked('preface-title')
|
|
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}`)
|
|
415
|
+
htitleAsciiDoc = undefined
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
} else if ((htitleOverride = doc.getAttribute('assembly-root-title', ''))) {
|
|
234
420
|
htitleAsciiDoc = unconvertInlineAsciiDoc(htitleOverride)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (atDocumentRoot && pageStyle === 'preface' && htitlePlain === componentVersion.title) {
|
|
238
|
-
assemblyModel = Object.assign({}, assemblyModel, { sectionMergeStrategy: 'discrete' })
|
|
421
|
+
} else if (encloseSections) {
|
|
422
|
+
htitleAsciiDoc = overviewTitleAsciiDoc = unconvertInlineAsciiDoc(overviewTitle)
|
|
239
423
|
} else {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
424
|
+
htitleAsciiDoc = navtitleAsciiDoc
|
|
425
|
+
}
|
|
426
|
+
if (htitleAsciiDoc != null) {
|
|
427
|
+
heading = { title: htitleAsciiDoc, hlevel: part ? 1 : 2 }
|
|
428
|
+
if (pageStyle === 'part') {
|
|
429
|
+
nextSectionLevel = 1
|
|
243
430
|
} else {
|
|
244
|
-
|
|
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
|
+
}
|
|
245
442
|
}
|
|
246
|
-
heading = { title: htitleAsciiDoc, level: part ? 1 : 2 }
|
|
247
|
-
nextSectionLevel++
|
|
248
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
|
|
249
447
|
} else if (level) {
|
|
250
|
-
if (
|
|
448
|
+
if (atStartOfBody && !pageStyle && builder.matchesDoctitle(navtitlePlain)) {
|
|
251
449
|
level--
|
|
252
|
-
} else {
|
|
253
|
-
|
|
254
|
-
if (part && level === 1) level--
|
|
255
|
-
if ((heading = { title: navtitleAsciiDoc, level: level + 1 }).level > 6) {
|
|
256
|
-
Object.assign(heading, { level: 6, style: `discrete.h${heading.level}` })
|
|
257
|
-
}
|
|
450
|
+
} else if ((heading = { title: navtitleAsciiDoc, hlevel: level + 1 }).hlevel > 6) {
|
|
451
|
+
Object.assign(heading, { hlevel: 6, style: `discrete.h${heading.hlevel}` })
|
|
258
452
|
}
|
|
259
453
|
}
|
|
260
454
|
if (heading) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (assemblyModel.sectionMergeStrategy === 'enclose' && hasItems && doc.hasSections()) {
|
|
268
|
-
enclosed = true
|
|
269
|
-
// TODO: make overview section title configurable
|
|
270
|
-
//let overviewTitle = doc.getDocumentTitle()
|
|
271
|
-
//if (overviewTitle === navtitle) overviewTitle = doc.getAttribute('overview-title', 'Overview')
|
|
272
|
-
const overviewTitle = doc.getAttribute('overview-title', 'Overview')
|
|
273
|
-
buffer.push('')
|
|
274
|
-
// NOTE: try to toggle sectids; otherwise, fallback to globally unique synthetic ID
|
|
275
|
-
let toggleSectids, syntheticId
|
|
276
|
-
if (doc.isAttribute('sectids')) {
|
|
277
|
-
if (doc.isAttributeLocked('sectids')) {
|
|
278
|
-
syntheticId = `__object-id-${getObjectId(outlineEntry)}`
|
|
279
|
-
} else {
|
|
280
|
-
buffer.push(':!sectids:')
|
|
281
|
-
toggleSectids = true
|
|
282
|
-
}
|
|
455
|
+
const rolesAttr = pageRoles.reduce((str, it) => str + '.' + it, '')
|
|
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)
|
|
283
461
|
}
|
|
284
|
-
|
|
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)
|
|
468
|
+
}
|
|
469
|
+
if (isRootPage || (atStartOfBody && !heading)) assembled.pages.rootPageFragment = pageFragment
|
|
470
|
+
assembled.pages.set(page, pageFragment)
|
|
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)
|
|
285
476
|
if (hlevel > 6) {
|
|
286
|
-
|
|
477
|
+
buffer.push(`[discrete.h${hlevel}${sectionFragment}]`)
|
|
287
478
|
hlevel = 6
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
buffer.push(`[#${syntheticId}]`)
|
|
479
|
+
} else {
|
|
480
|
+
buffer.push(`[${sectionFragment}]`)
|
|
291
481
|
}
|
|
292
|
-
buffer.push(`${'='.repeat(hlevel)} ${
|
|
293
|
-
if (toggleSectids) buffer.push(':sectids:')
|
|
294
|
-
}
|
|
295
|
-
pagesInOutline.assembled.pages.set(page, pageFragment)
|
|
296
|
-
if (doc.hasSections()) {
|
|
297
|
-
fixSectionLevels(doc.getSections(), atBookRoot && !pageStyle ? undefined : nextSectionLevel)
|
|
482
|
+
buffer.push(`${'='.repeat(hlevel)} ${overviewTitleAsciiDoc}`)
|
|
298
483
|
}
|
|
484
|
+
if (hasSections) fixSectionLevels(doc.getSections(), nextSectionLevel)
|
|
299
485
|
const allBlocks = doc.findBy({ traverse_documents: true }, (it) =>
|
|
300
486
|
it.getContext() === 'document'
|
|
301
487
|
? it.getDocument().isNested()
|
|
302
488
|
: !(it.getContext() === 'table_cell' && it.getStyle() === 'asciidoc')
|
|
303
489
|
)
|
|
304
490
|
if (doc.getDoctype() === 'manpage') {
|
|
305
|
-
const firstSectionIdx =
|
|
491
|
+
const firstSectionIdx = hasSections ? doc.getSections()[0].getLineNumber() - 1 : lines.length
|
|
306
492
|
for (let idx = 0; idx < firstSectionIdx; idx++) {
|
|
307
|
-
if (
|
|
493
|
+
if (ignoreLines.includes(idx)) continue
|
|
308
494
|
const line = lines[idx]
|
|
309
495
|
if (line.startsWith('== ') && line.length > 3) {
|
|
310
496
|
allBlocks.unshift({
|
|
@@ -348,10 +534,10 @@ function mergeAsciiDoc (
|
|
|
348
534
|
})
|
|
349
535
|
let skipping
|
|
350
536
|
for (let idx = 0, lastIdx = lines.length - 1; idx <= lastIdx; idx++) {
|
|
351
|
-
if (
|
|
537
|
+
if (ignoreLines.includes(idx)) continue
|
|
352
538
|
let line = lines[idx]
|
|
353
539
|
if (line.startsWith('//')) {
|
|
354
|
-
if (line
|
|
540
|
+
if (line.charAt(2) !== '/') continue
|
|
355
541
|
if (line.length > 3 && line === '/'.repeat(line.length)) {
|
|
356
542
|
if (skipping) {
|
|
357
543
|
if (line === skipping) skipping = undefined
|
|
@@ -366,7 +552,7 @@ function mergeAsciiDoc (
|
|
|
366
552
|
if (
|
|
367
553
|
line.charAt() === ':' &&
|
|
368
554
|
~line.indexOf(':', 2) &&
|
|
369
|
-
(line.match(
|
|
555
|
+
(line.match(ATTR_ENTRY_RX) || ['', ''])[1].replace('!', '') === 'leveloffset'
|
|
370
556
|
) {
|
|
371
557
|
if (lines[idx - 1] === '') lines[idx - 1] = undefined
|
|
372
558
|
lines[idx] = undefined
|
|
@@ -378,111 +564,31 @@ function mergeAsciiDoc (
|
|
|
378
564
|
if (!refs['$key?'](refid) && (~refid.indexOf(' ') || refid.toLowerCase() !== refid)) {
|
|
379
565
|
if ((refid = doc.$resolve_id(refid))['$nil?']()) return m
|
|
380
566
|
}
|
|
381
|
-
return `<<${
|
|
567
|
+
return `<<${pageIdLeader}${refid}${text ? ',' + text : ''}>>`
|
|
382
568
|
})
|
|
383
569
|
}
|
|
384
570
|
// NOTE: the next check takes care of inline and block anchors
|
|
385
571
|
if (~line.indexOf('[[')) {
|
|
386
|
-
line = line.replace(/\[\[([\p{Alpha}_:][\p{Alpha}0-9_\-:.]*)(|, *.+?)\]\]/gu,
|
|
387
|
-
|
|
388
|
-
if (~line.indexOf('xref:')) {
|
|
389
|
-
// Q: should we allow : as first character of target?
|
|
390
|
-
line = line.replace(/(?<![\\+])xref:((?:\.\/)?[\p{Alpha}0-9_/.{#].*?)\[(|.*?[^\\])\]/gu, (m, target, text) => {
|
|
391
|
-
let relativePart, fragment, resource, isPage
|
|
392
|
-
const hashIdx = target.indexOf('#')
|
|
393
|
-
const dollarIdx = target.indexOf('$')
|
|
394
|
-
if (~hashIdx) {
|
|
395
|
-
relativePart = target.slice(0, hashIdx)
|
|
396
|
-
fragment = target.slice(hashIdx + 1)
|
|
397
|
-
} else if (~dollarIdx || target.endsWith('.adoc')) {
|
|
398
|
-
relativePart = target
|
|
399
|
-
fragment = ''
|
|
400
|
-
} else {
|
|
401
|
-
fragment = target
|
|
402
|
-
}
|
|
403
|
-
// Q: should we validate the internal ID here?
|
|
404
|
-
if (!relativePart) return `xref:${idPrefix}${fragment}[${text}]`
|
|
405
|
-
if (~dollarIdx) {
|
|
406
|
-
if (relativePart.slice(dollarIdx).startsWith('$./')) {
|
|
407
|
-
relativePart = relativePart.slice(0, dollarIdx + 1) + topicPrefix + relativePart.slice(dollarIdx + 3)
|
|
408
|
-
}
|
|
409
|
-
if ((isPage = /\bpage\$/.test(relativePart))) relativePart = relativePart.replace('page$', '')
|
|
410
|
-
} else {
|
|
411
|
-
isPage = true
|
|
412
|
-
if (relativePart.startsWith('./')) relativePart = topicPrefix + relativePart.slice(2)
|
|
413
|
-
if (~hashIdx && !relativePart.endsWith('.adoc')) relativePart += '.adoc'
|
|
414
|
-
}
|
|
415
|
-
if (!isPage || ~relativePart.indexOf('@') || /:.*:/.test(relativePart)) {
|
|
416
|
-
if (siteRoot && (resource = contentCatalog.resolveResource(relativePart, page.src, 'page'))?.pub) {
|
|
417
|
-
text ||= resource.asciidoc?.xreftext || target
|
|
418
|
-
return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
|
|
419
|
-
}
|
|
420
|
-
// TODO: handle unresolved resource better
|
|
421
|
-
return m
|
|
422
|
-
}
|
|
423
|
-
let targetModule
|
|
424
|
-
const colonIdx = relativePart.indexOf(':')
|
|
425
|
-
if (~colonIdx) {
|
|
426
|
-
targetModule = relativePart.slice(0, colonIdx)
|
|
427
|
-
relativePart = relativePart.slice(colonIdx + 1)
|
|
428
|
-
if (relativePart.startsWith('./')) relativePart = topicPrefix + relativePart.slice(2)
|
|
429
|
-
} else {
|
|
430
|
-
targetModule = module_
|
|
431
|
-
}
|
|
432
|
-
const pageResourceRef = targetModule === 'ROOT' ? relativePart : `${targetModule}:${relativePart}`
|
|
433
|
-
if (!(resource = pagesInOutline.get(pageResourceRef))) {
|
|
434
|
-
if (siteRoot && (resource = contentCatalog.resolvePage(pageResourceRef, page.src)) && resource.out) {
|
|
435
|
-
text ||= resource.asciidoc?.xreftext || target
|
|
436
|
-
return `${resolveLinkTarget(resource, siteRoot, pubRoot, linkRefStyle)}${fragment && '#' + fragment}[${text}]`
|
|
437
|
-
}
|
|
438
|
-
// TODO: handle unresolved page better
|
|
439
|
-
return m
|
|
440
|
-
}
|
|
441
|
-
if (targetModule !== 'ROOT') relativePart = `${targetModule}${idCoordinateSeparator}${relativePart}`
|
|
442
|
-
relativePart = relativePart.replace(/\.adoc$/, '').replace(/[/.]/g, '-')
|
|
443
|
-
if (fragment === resource.asciidoc.id) fragment = ''
|
|
444
|
-
const refid = fragment
|
|
445
|
-
? `${relativePart}${idScopeSeparator}${fragment}`
|
|
446
|
-
: relativePart + (ReservedIdNames.includes(relativePart) ? idScopeSeparator : '')
|
|
447
|
-
if (
|
|
448
|
-
text &&
|
|
449
|
-
(assemblyModel.dropExplicitXrefText === 'always' ||
|
|
450
|
-
(assemblyModel.dropExplicitXrefText === 'if-redundant' && text === resource.title))
|
|
451
|
-
) {
|
|
452
|
-
text = ''
|
|
453
|
-
}
|
|
454
|
-
return `xref:${refid}[${text}]`
|
|
572
|
+
line = line.replace(/\[\[([\p{Alpha}_:][\p{Alpha}0-9_\-:.]*)(|, *.+?)\]\]/gu, (_, refid, text) => {
|
|
573
|
+
return `[[${pageIdLeader}${refid}${text}]]`
|
|
455
574
|
})
|
|
456
575
|
}
|
|
457
|
-
if (~line.indexOf('
|
|
458
|
-
line =
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
})
|
|
576
|
+
if (~line.indexOf('xref:')) {
|
|
577
|
+
line = rewriteXrefs(
|
|
578
|
+
line,
|
|
579
|
+
contentCatalog,
|
|
580
|
+
assemblyModel,
|
|
581
|
+
page.src,
|
|
582
|
+
true,
|
|
583
|
+
pagesInOutline,
|
|
584
|
+
idSeparators,
|
|
585
|
+
pageIdLeader,
|
|
586
|
+
doc,
|
|
587
|
+
{ file: relative, lineno: idx + 1 }
|
|
588
|
+
)
|
|
471
589
|
}
|
|
472
590
|
if (~line.indexOf('image:') && !line.startsWith('image::')) {
|
|
473
|
-
line = line.
|
|
474
|
-
if (isResourceSpec(target)) {
|
|
475
|
-
const image = contentCatalog.resolveResource(target, page.src, 'image', ['image'])
|
|
476
|
-
// TODO: handle (or report) unresolved image better
|
|
477
|
-
if (image?.out && (filetype !== 'html' || siteRoot)) {
|
|
478
|
-
pagesInOutline.assembled.assets.add(image)
|
|
479
|
-
return filetype === 'html'
|
|
480
|
-
? `image:${resolveLinkTarget(image, siteRoot, pubRoot, linkRefStyle)}[${attrlist}]`
|
|
481
|
-
: `image:${resolveEmbedTarget(image, outDirname, embedRefStyle, true)}[${attrlist}]`
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
return m
|
|
485
|
-
})
|
|
591
|
+
line = rewriteInlineImages(line, contentCatalog, assemblyModel, page.src, assembled.assets, true, doc)
|
|
486
592
|
}
|
|
487
593
|
lines[idx] = line
|
|
488
594
|
}
|
|
@@ -498,9 +604,9 @@ function mergeAsciiDoc (
|
|
|
498
604
|
let idx = lineno - 1
|
|
499
605
|
if (context === 'section' && !block.getDocument().isNested()) {
|
|
500
606
|
if (block.getSectionName() === 'header') return
|
|
501
|
-
let blockStyle =
|
|
607
|
+
let blockStyle = sectionMergeStrategy === 'discrete' ? 'discrete' : undefined
|
|
502
608
|
lines[idx] = lines[idx].replace(/^=+ (.+)/, (_, rest) => {
|
|
503
|
-
let targetMarkerLength = block.level + 1 + level
|
|
609
|
+
let targetMarkerLength = block.level + 1 + level
|
|
504
610
|
if (targetMarkerLength > 6) {
|
|
505
611
|
blockStyle = `discrete.h${targetMarkerLength}`
|
|
506
612
|
targetMarkerLength = 6
|
|
@@ -508,56 +614,49 @@ function mergeAsciiDoc (
|
|
|
508
614
|
return '='.repeat(targetMarkerLength) + ' ' + rest
|
|
509
615
|
})
|
|
510
616
|
// NOTE: ID will be undefined if sectids are turned off
|
|
511
|
-
if (block.getId()) rewriteStyleAttribute(block, lines, idx,
|
|
617
|
+
if (block.getId()) rewriteStyleAttribute(block, lines, idx, pageIdLeader, blockStyle)
|
|
512
618
|
} else {
|
|
513
619
|
if (context === 'image') {
|
|
514
620
|
let line = lines[idx] || ''
|
|
515
621
|
let prefix = ''
|
|
516
622
|
// Q: can we use startsWith('image::') in certain cases?
|
|
517
623
|
let imageMacroOffset = (
|
|
518
|
-
lastImageMacroAt?.[0] === idx ? line.
|
|
624
|
+
lastImageMacroAt?.[0] === idx ? line.substring(0, lastImageMacroAt[1]) : line
|
|
519
625
|
).lastIndexOf('image::')
|
|
520
626
|
if (imageMacroOffset > 0) {
|
|
521
627
|
if (
|
|
522
628
|
block.getDocument().isNested() &&
|
|
523
|
-
(prefix = line.
|
|
629
|
+
(prefix = line.substring(0, imageMacroOffset)).trimRight().endsWith('|')
|
|
524
630
|
) {
|
|
525
|
-
line = line.
|
|
631
|
+
line = line.substring(prefix.length)
|
|
526
632
|
} else {
|
|
527
633
|
imageMacroOffset = -1
|
|
528
634
|
}
|
|
529
635
|
}
|
|
530
|
-
if (imageMacroOffset
|
|
636
|
+
if (~imageMacroOffset) {
|
|
531
637
|
const target = block.getAttribute('target')
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
// FIXME: handle (or report) case when image is not resolved
|
|
535
|
-
if (image?.out && (filetype !== 'html' || siteRoot)) {
|
|
536
|
-
const attrlist = line.slice(line.indexOf('[') + 1, -1)
|
|
537
|
-
pagesInOutline.assembled.assets.add(image)
|
|
538
|
-
lines[idx] =
|
|
539
|
-
filetype === 'html'
|
|
540
|
-
? `${prefix}image::${resolveLinkTarget(image, siteRoot, pubRoot, linkRefStyle, false)}[${attrlist}]`
|
|
541
|
-
: `${prefix}image::${resolveEmbedTarget(image, outDirname, embedRefStyle)}[${attrlist}]`
|
|
542
|
-
}
|
|
543
|
-
}
|
|
638
|
+
const newTarget = rewriteImageRef(target, contentCatalog, assemblyModel, page.src, assembled.assets)
|
|
639
|
+
if (newTarget) lines[idx] = `${prefix}image::${newTarget}${line.substring(line.indexOf('['))}`
|
|
544
640
|
lastImageMacroAt = [idx, imageMacroOffset]
|
|
545
641
|
}
|
|
546
642
|
} else if (context === 'document' && block.hasHeader()) {
|
|
547
643
|
// nested document
|
|
548
644
|
idx = (block.getHeader().getLineNumber() || idx + 1) - 1
|
|
549
645
|
}
|
|
550
|
-
if (block.getId()) rewriteStyleAttribute(block, lines, idx,
|
|
646
|
+
if (block.getId()) rewriteStyleAttribute(block, lines, idx, pageIdLeader)
|
|
551
647
|
}
|
|
552
648
|
})
|
|
553
649
|
safePush(
|
|
554
650
|
buffer,
|
|
555
651
|
lines.filter((it) => it !== undefined)
|
|
556
652
|
)
|
|
557
|
-
const attributeEntries =
|
|
653
|
+
const attributeEntries = doc.source_header_attributes.$entries()
|
|
558
654
|
if (attributeEntries.length) {
|
|
559
655
|
const resolvedAttributeEntries = attributeEntries.reduce(
|
|
560
656
|
(accum, [name, val]) => {
|
|
657
|
+
if (val) {
|
|
658
|
+
if (val['$nil?']()) val = null
|
|
659
|
+
}
|
|
561
660
|
// Q: couldn't we just check if attribute is locked?
|
|
562
661
|
if (name in mutableAttributes) {
|
|
563
662
|
const initialVal = mutableAttributes[name]
|
|
@@ -566,7 +665,7 @@ function mergeAsciiDoc (
|
|
|
566
665
|
} else if (val !== initialVal) {
|
|
567
666
|
accum.push(`:${name}:${initialVal ? ' ' + initialVal : ''}`)
|
|
568
667
|
}
|
|
569
|
-
} else if (!(val == null || doc.isAttributeLocked(name) ||
|
|
668
|
+
} else if (!(val == null || doc.isAttributeLocked(name) || DISCARD_ATTRIBUTE_NAMES.includes(name))) {
|
|
570
669
|
accum.push(`:!${name}:`)
|
|
571
670
|
}
|
|
572
671
|
return accum
|
|
@@ -575,87 +674,88 @@ function mergeAsciiDoc (
|
|
|
575
674
|
)
|
|
576
675
|
if (resolvedAttributeEntries.length > 1) safePush(buffer, resolvedAttributeEntries)
|
|
577
676
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
677
|
+
if (typeof doc.restoreLogger === 'function') doc.restoreLogger()
|
|
678
|
+
} else if (level && !hash) {
|
|
679
|
+
const buffer = (builder.body ??= [])
|
|
680
|
+
if (atStartOfBody && builder.matchesDoctitle(navtitlePlain)) {
|
|
581
681
|
level--
|
|
582
682
|
} else {
|
|
583
|
-
buffer.
|
|
584
|
-
|
|
585
|
-
// NOTE: try to toggle sectids; otherwise, fallback to globally unique synthetic ID
|
|
586
|
-
// Q: should we unset docname, page-module, etc?
|
|
587
|
-
let toggleSectids, syntheticId
|
|
588
|
-
if (!('sectids' in asciidocConfig.attributes)) {
|
|
589
|
-
buffer.push(':!sectids:')
|
|
590
|
-
toggleSectids = true
|
|
591
|
-
} else if (typeof asciidocConfig.attributes.sectids === 'string') {
|
|
592
|
-
if ('sectids' in mutableAttributes) {
|
|
593
|
-
buffer.push(':!sectids:')
|
|
594
|
-
toggleSectids = true
|
|
595
|
-
} else {
|
|
596
|
-
syntheticId = `__object-id-${global.Opal.hash(outlineEntry).$object_id()}`
|
|
597
|
-
}
|
|
598
|
-
}
|
|
683
|
+
if (buffer.length) buffer.push('')
|
|
684
|
+
const syntheticId = idSeparators.generateIdFromTitle(navtitleAsciiDoc, idSeparators)
|
|
599
685
|
let sectionTitle = navtitleAsciiDoc
|
|
600
686
|
if (urlType === 'external') {
|
|
601
687
|
sectionTitle = `${url}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
|
|
602
688
|
} else if (urlType === 'internal' && !unresolved) {
|
|
603
|
-
const resource = files.find((it) => it.pub.url ===
|
|
689
|
+
const resource = files.find((it) => it.pub.url === pathname)
|
|
604
690
|
if (resource) {
|
|
605
691
|
if (resource.src.family === 'page' && pagesInOutline.has(resource.pub.url)) {
|
|
606
|
-
|
|
607
|
-
if (refid.startsWith('./')) refid = topicPrefix + refid.slice(2)
|
|
608
|
-
if (resource.src.module !== 'ROOT') refid = `${resource.src.module}${idCoordinateSeparator}${refid}`
|
|
692
|
+
const refid = generateScopedId(resource.src, componentVersion, idSeparators, filetype, true)
|
|
609
693
|
sectionTitle = `xref:${refid}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
|
|
610
694
|
} else if (siteRoot) {
|
|
611
|
-
sectionTitle = `${resolveLinkTarget(resource, siteRoot, pubRoot,
|
|
695
|
+
sectionTitle = `${resolveLinkTarget(resource, siteRoot, pubRoot, linkReferenceStyle, true)}[${navtitleAsciiDoc.replace(/\]/g, '\\]')}]`
|
|
612
696
|
}
|
|
613
697
|
}
|
|
614
698
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
buffer.push(syntheticId ? `[discrete#${syntheticId}]` : '[discrete]')
|
|
619
|
-
} else if (syntheticId) {
|
|
620
|
-
buffer.push(`[#${syntheticId}]`)
|
|
699
|
+
if (supportsParts && level === 1 && roles.includes('part')) {
|
|
700
|
+
roles.splice(roles.indexOf('part', 1))
|
|
701
|
+
level--
|
|
621
702
|
}
|
|
703
|
+
const hlevel = level > 5 ? 6 : level + 1
|
|
704
|
+
const hroles = urlType === 'internal' ? roles.slice(1) : roles
|
|
705
|
+
buffer.push(`[${hlevel > 6 ? 'discrete' : ''}#${syntheticId}${hroles.reduce((str, it) => str + '.' + it, '')}]`)
|
|
622
706
|
buffer.push(`${'='.repeat(hlevel)} ${sectionTitle}`)
|
|
623
|
-
if (toggleSectids) buffer.push(':sectids:')
|
|
624
707
|
}
|
|
625
708
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
})
|
|
650
|
-
}
|
|
651
|
-
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
|
+
})
|
|
652
732
|
}
|
|
653
733
|
|
|
654
|
-
function
|
|
734
|
+
function processPageHeader (doc, lines, ignoreLines, isRootPage) {
|
|
735
|
+
const entries = []
|
|
736
|
+
let assemblyHeaderAttributes = isRootPage && doc.getAttribute('assembly-header-attributes', '%authors')
|
|
737
|
+
assemblyHeaderAttributes = new Set(assemblyHeaderAttributes ? assemblyHeaderAttributes.split(/, */) : undefined)
|
|
738
|
+
if (assemblyHeaderAttributes.size) {
|
|
739
|
+
if (assemblyHeaderAttributes.has('%authors')) {
|
|
740
|
+
const authors = doc.getAuthors()
|
|
741
|
+
if (authors.length) {
|
|
742
|
+
entries.push({
|
|
743
|
+
type: 'author_line',
|
|
744
|
+
promote: true,
|
|
745
|
+
lines: [
|
|
746
|
+
authors
|
|
747
|
+
.map((author) => (author.getEmail() ? `${author.getName()} <${author.getEmail()}>` : author.getName()))
|
|
748
|
+
.join('; '),
|
|
749
|
+
],
|
|
750
|
+
})
|
|
751
|
+
}
|
|
752
|
+
assemblyHeaderAttributes.delete('%authors')
|
|
753
|
+
}
|
|
754
|
+
for (const name of assemblyHeaderAttributes) doc.source_header_attributes.$delete(name)
|
|
755
|
+
}
|
|
655
756
|
const doctitleIdx = doc.getHeader().getLineNumber() - 1
|
|
656
757
|
const end = doc.getBlocks()[0]?.getLineNumber() ?? lines.length
|
|
657
|
-
let belowDoctitle
|
|
658
|
-
let open
|
|
758
|
+
let belowDoctitle, current, open
|
|
659
759
|
const implicitLines = []
|
|
660
760
|
for (let idx = 0; idx < end; idx++) {
|
|
661
761
|
if (idx === doctitleIdx) {
|
|
@@ -666,41 +766,54 @@ function processDocumentHeader (doc, lines, buffer, ignoreLines) {
|
|
|
666
766
|
}
|
|
667
767
|
const line = lines[idx]
|
|
668
768
|
if (open === ':' || open === '-:') {
|
|
669
|
-
if (line)
|
|
670
|
-
|
|
671
|
-
if (!line.endsWith(' \\')) open = undefined
|
|
672
|
-
} else {
|
|
673
|
-
open = undefined
|
|
674
|
-
}
|
|
769
|
+
if (open === ':') current.appendLine(line)
|
|
770
|
+
if (!line?.endsWith(' \\')) current = open = undefined
|
|
675
771
|
} else if (line) {
|
|
676
|
-
const chr0 = line.charAt()
|
|
677
772
|
let attributeEntryMatch
|
|
773
|
+
const chr0 = line.charAt()
|
|
678
774
|
if (chr0 === '/' && line.charAt(1) === '/') {
|
|
679
|
-
if (line.startsWith('////')) {
|
|
680
|
-
|
|
681
|
-
|
|
775
|
+
if (line.startsWith('////') && line === '/'.repeat(line.length)) {
|
|
776
|
+
if (open) {
|
|
777
|
+
current.appendLine(line)
|
|
778
|
+
if (open === line) current = open = undefined
|
|
779
|
+
} else {
|
|
780
|
+
entries.push((current = { type: 'block_comment', lines: [(open = line)] }))
|
|
781
|
+
current.appendLine = Array.prototype.push.bind(current.lines)
|
|
782
|
+
}
|
|
783
|
+
} else if (open) {
|
|
784
|
+
current.appendLine(line)
|
|
785
|
+
} else if (belowDoctitle && line.charAt(2) === '/') {
|
|
682
786
|
break
|
|
787
|
+
} else {
|
|
788
|
+
entries.push({ type: 'line_comment', lines: [line] })
|
|
789
|
+
current = undefined
|
|
683
790
|
}
|
|
684
|
-
buffer.push(line)
|
|
685
791
|
} else if (open) {
|
|
686
|
-
|
|
687
|
-
} else if (chr0 === ':' && ~line.indexOf(':', 2) && (attributeEntryMatch = line.match(
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
792
|
+
current.appendLine(line)
|
|
793
|
+
} else if (chr0 === ':' && ~line.indexOf(':', 2) && (attributeEntryMatch = line.match(ATTR_ENTRY_RX))) {
|
|
794
|
+
let name = attributeEntryMatch[1]
|
|
795
|
+
const negated = name.charAt() === '!' || name.charAt(name.length - 1) === '!'
|
|
796
|
+
if (negated) name = name.replace('!', '')
|
|
797
|
+
if (DISCARD_ATTRIBUTE_NAMES.includes(name) && !assemblyHeaderAttributes.has(name)) {
|
|
798
|
+
if (line.endsWith(' \\')) open = '-:' // disallow value continuation
|
|
691
799
|
} else {
|
|
692
800
|
if (line.endsWith(' \\')) open = ':'
|
|
693
|
-
|
|
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)
|
|
804
|
+
if (assemblyHeaderAttributes.has(name)) current.promote = true
|
|
694
805
|
}
|
|
695
806
|
} else if (belowDoctitle) {
|
|
696
807
|
if (implicitLines.length === 2 || !/[\p{Alpha}0-9]/u.test(chr0)) break
|
|
697
808
|
implicitLines.push(line)
|
|
698
809
|
} else if (chr0 === '[' && line.charAt(line.length - 1) === ']') {
|
|
810
|
+
current = undefined
|
|
699
811
|
const attrlist = line
|
|
700
|
-
.
|
|
812
|
+
.substring(1, line.length - 1)
|
|
701
813
|
.trim()
|
|
702
|
-
.replace(/(?:^\w[\w-]*(?!=|[\w-]))?([
|
|
703
|
-
|
|
814
|
+
.replace(/(?:^\w[\w-]*(?!=|[\w-]))?([#.]\w[\w-]*)*/, '')
|
|
815
|
+
.replace(NAMED_ID_ATTR_RX, '')
|
|
816
|
+
if (attrlist) entries.push({ type: 'attrlist', lines: ['[' + attrlist + ']'] })
|
|
704
817
|
}
|
|
705
818
|
} else if (belowDoctitle) {
|
|
706
819
|
break
|
|
@@ -708,23 +821,26 @@ function processDocumentHeader (doc, lines, buffer, ignoreLines) {
|
|
|
708
821
|
lines[idx] = undefined
|
|
709
822
|
ignoreLines.push(idx)
|
|
710
823
|
}
|
|
711
|
-
return
|
|
712
|
-
.getRoles()
|
|
713
|
-
.map((role) => '.' + role)
|
|
714
|
-
.join('')
|
|
824
|
+
return entries
|
|
715
825
|
}
|
|
716
826
|
|
|
717
|
-
function generateSlug (
|
|
718
|
-
return
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
827
|
+
function generateSlug (string) {
|
|
828
|
+
if (string === 'index') return string
|
|
829
|
+
return sanitizeSlug(
|
|
830
|
+
string
|
|
831
|
+
.toLowerCase()
|
|
832
|
+
.replace(/<[^>]+>/g, '')
|
|
833
|
+
.replace(CHAR_REF_RX, (_, name, dec, hex) => {
|
|
834
|
+
if (name) return BUILT_IN_NAMED_ENTITIES[name] ?? '?'
|
|
835
|
+
return String.fromCharCode(dec ? parseInt(dec, 10) : parseInt(hex, 16))
|
|
836
|
+
})
|
|
837
|
+
.replace(/[\x27\u2019]/g, '')
|
|
838
|
+
.replace(/[_.]/, '-')
|
|
839
|
+
)
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function sanitizeSlug (slug) {
|
|
843
|
+
return slug.replace(/[^\p{Alpha}0-9_.-]/gu, '-').replace(/^-+|-+$|(-)-+/g, '$1')
|
|
728
844
|
}
|
|
729
845
|
|
|
730
846
|
function fixSectionLevels (sections, expectedLevel) {
|
|
@@ -735,115 +851,29 @@ function fixSectionLevels (sections, expectedLevel) {
|
|
|
735
851
|
})
|
|
736
852
|
}
|
|
737
853
|
|
|
738
|
-
function rewriteStyleAttribute (block, lines, idx, idPrefix, replacementStyle = '') {
|
|
739
|
-
let prevLine = lines[idx - 1]
|
|
740
|
-
const char0 = prevLine?.charAt()
|
|
741
|
-
if (char0) {
|
|
742
|
-
if (
|
|
743
|
-
(char0 === '.' && /^\.\.?[^ \t.]/.test(prevLine)) ||
|
|
744
|
-
(char0 === '[' &&
|
|
745
|
-
prevLine.charAt(1) === '[' &&
|
|
746
|
-
/^\[\[(?:|[\p{Alpha}_:][\p{Alpha}0-9_\-:.]*(?:, *.+)?)\]\]$/u.test(prevLine))
|
|
747
|
-
) {
|
|
748
|
-
return rewriteStyleAttribute(block, lines, idx - 1, idPrefix, replacementStyle)
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
let cellSpec
|
|
752
|
-
if (
|
|
753
|
-
char0 &&
|
|
754
|
-
(char0 === '[' || (block.getDocument().isNested() && (cellSpec = prevLine.match(/^([^[|]*)\| *(\[.+)/)))) &&
|
|
755
|
-
prevLine.charAt(prevLine.length - 1) === ']'
|
|
756
|
-
) {
|
|
757
|
-
if (cellSpec) {
|
|
758
|
-
prevLine = cellSpec[2]
|
|
759
|
-
cellSpec = cellSpec[1]
|
|
760
|
-
}
|
|
761
|
-
let rawStyle
|
|
762
|
-
const commaIdx = prevLine.indexOf(',')
|
|
763
|
-
if (~commaIdx) {
|
|
764
|
-
rawStyle = prevLine.slice(1, commaIdx)
|
|
765
|
-
if (~rawStyle.indexOf('=')) rawStyle = undefined
|
|
766
|
-
} else if (!~prevLine.indexOf('=')) {
|
|
767
|
-
rawStyle = prevLine.slice(1, prevLine.length - 1)
|
|
768
|
-
}
|
|
769
|
-
if (rawStyle) {
|
|
770
|
-
if (~rawStyle.indexOf('#')) {
|
|
771
|
-
prevLine = prevLine.replace(/#[^.%,\]]+/, `#${idPrefix}${block.getId()}`)
|
|
772
|
-
if (replacementStyle) prevLine = prevLine.replace(/^[^#.%,\]]+/, `[${replacementStyle}`)
|
|
773
|
-
} else {
|
|
774
|
-
prevLine = `[${
|
|
775
|
-
replacementStyle ? rawStyle.replace(/^[^.%]*/, replacementStyle) : rawStyle
|
|
776
|
-
}#${idPrefix}${block.getId()}${prevLine.slice(rawStyle.length + 1)}`
|
|
777
|
-
}
|
|
778
|
-
} else {
|
|
779
|
-
prevLine = `[${replacementStyle}#${idPrefix}${block.getId()}${rawStyle == null ? ',' : ''}${prevLine.slice(1)}`
|
|
780
|
-
}
|
|
781
|
-
if (cellSpec) prevLine = `${cellSpec}|${prevLine}`
|
|
782
|
-
lines[idx - 1] = prevLine
|
|
783
|
-
} else {
|
|
784
|
-
lines.splice(idx, 0, `[${replacementStyle}#${idPrefix}${block.getId()}]`)
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
function isResourceSpec (str) {
|
|
789
|
-
return !(~str.indexOf(':') && (~str.indexOf('://') || (str.startsWith('data:') && ~str.indexOf(','))))
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
function getObjectId (obj) {
|
|
793
|
-
return global.Opal.id(obj)
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// NOTE: blank lines at top and bottom of document create mismatch when using line numbers to navigate source lines
|
|
797
|
-
// IMPORTANT: this must not leave behind lines the parser will drop!
|
|
798
|
-
// IDEA: another option is to capture initial lineno of reader and use as offset (but preseves those blank lines)
|
|
799
|
-
function trimAsciiDoc (buffer) {
|
|
800
|
-
return Buffer.from(
|
|
801
|
-
buffer
|
|
802
|
-
.toString()
|
|
803
|
-
.replace(/^(?:[ \t]*\r\n?|[ \t]*\n)+/, '')
|
|
804
|
-
.trimRight()
|
|
805
|
-
)
|
|
806
|
-
}
|
|
807
|
-
|
|
808
854
|
function safePush (onto, entries) {
|
|
809
855
|
try {
|
|
810
856
|
onto.push(...entries)
|
|
811
|
-
} catch
|
|
812
|
-
/* istanbul ignore if */
|
|
813
|
-
if (!(err instanceof RangeError)) throw err
|
|
857
|
+
} catch {
|
|
814
858
|
for (const e of entries) onto.push(e)
|
|
815
859
|
}
|
|
816
860
|
}
|
|
817
861
|
|
|
818
|
-
function
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
case 'absolute':
|
|
831
|
-
target = ['', siteRoot.url + resource.pub.url]
|
|
832
|
-
break
|
|
833
|
-
case 'root-relative':
|
|
834
|
-
target = ['link:', siteRoot.path + resource.pub.url]
|
|
835
|
-
break
|
|
836
|
-
default:
|
|
837
|
-
target = ['link:', computeRelativeUrl(pubRoot + '/', resource.pub.url)]
|
|
838
|
-
}
|
|
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
|
|
839
874
|
}
|
|
840
|
-
|
|
841
|
-
return
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
function computeRelativeUrl (from, to) {
|
|
845
|
-
const rel = path.relative(from, to)
|
|
846
|
-
return to.charAt(to.length - 1) === '/' ? rel + '/' : rel
|
|
875
|
+
syntheticIds[id] = true
|
|
876
|
+
return id
|
|
847
877
|
}
|
|
848
878
|
|
|
849
879
|
module.exports = produceAssemblyFile
|