@antora/assembler 1.0.0-alpha.9 → 1.0.0-beta.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/README.md +7 -4
- package/adapters/asciidoctor/jsonl-logger.rb +25 -0
- package/lib/assemble-content.js +277 -26
- package/lib/configure.js +93 -0
- package/lib/index.js +2 -2
- package/lib/load-config.js +67 -24
- package/lib/produce-assembly-file.js +825 -0
- package/lib/produce-assembly-files.js +215 -0
- package/lib/util/compute-out.js +57 -0
- package/lib/util/create-asciidoc-file.js +17 -0
- package/lib/util/parse-resource-ref.js +36 -0
- package/package.json +18 -13
- package/lib/asciidoctor/reducer-extension.js +0 -235
- package/lib/produce-aggregate-document.js +0 -599
- package/lib/produce-aggregate-documents.js +0 -145
- package/lib/util/run-command.js +0 -60
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const computeOut = require('./util/compute-out')
|
|
4
|
+
const createAsciiDocFile = require('./util/create-asciidoc-file')
|
|
5
|
+
const filterComponentVersions = require('./filter-component-versions')
|
|
6
|
+
const produceAssemblyFile = require('./produce-assembly-file')
|
|
7
|
+
const selectMutableAttributes = require('./select-mutable-attributes')
|
|
8
|
+
|
|
9
|
+
const ATTR_REF_RX = /\\?\{(\w[\w-]*)\}/g
|
|
10
|
+
const IMAGE_MACRO_RX = /^image::?(.+?)\[(.*?)\]$/
|
|
11
|
+
|
|
12
|
+
function produceAssemblyFiles (loadAsciiDoc, contentCatalog, assemblerConfig, resolveAssemblyModel) {
|
|
13
|
+
const { asciidoc: assemblerAsciiDocConfig, assembly: assemblyConfig } = assemblerConfig
|
|
14
|
+
resolveAssemblyModel ??= (componentVersion) => ({
|
|
15
|
+
doctype: assemblyConfig.doctype,
|
|
16
|
+
insertStartPage: assemblyConfig.insertStartPage,
|
|
17
|
+
rootLevel: assemblyConfig.rootLevel,
|
|
18
|
+
sectionMergeStrategy: assemblyConfig.sectionMergeStrategy,
|
|
19
|
+
navigation: componentVersion.navigation,
|
|
20
|
+
xmlIds: assemblyConfig.xmlIds,
|
|
21
|
+
embedReferenceStyle: assemblyConfig.embedReferenceStyle,
|
|
22
|
+
linkReferenceStyle: assemblyConfig.linkReferenceStyle,
|
|
23
|
+
dropExplicitXrefText: assemblyConfig.dropExplicitXrefText,
|
|
24
|
+
})
|
|
25
|
+
const assemblerAsciiDocAttributes = Object.assign({}, assemblerAsciiDocConfig.attributes)
|
|
26
|
+
const { revdate, 'source-highlighter': sourceHighlighter } = assemblerAsciiDocAttributes
|
|
27
|
+
delete assemblerAsciiDocAttributes.revdate
|
|
28
|
+
delete assemblerAsciiDocAttributes['source-highlighter']
|
|
29
|
+
const publishableFiles = contentCatalog.getFiles().filter((file) => file.out)
|
|
30
|
+
let siteRoot
|
|
31
|
+
const configMdc = assemblerConfig.file ? { file: { path: assemblerConfig.file } } : {}
|
|
32
|
+
return filterComponentVersions(contentCatalog.getComponents(), assemblerConfig.componentVersionFilter.names).reduce(
|
|
33
|
+
(accum, componentVersion) => {
|
|
34
|
+
const assemblyModel = resolveAssemblyModel(componentVersion)
|
|
35
|
+
if (!assemblyModel.navigation) return accum
|
|
36
|
+
const { name: componentName, version, title } = componentVersion
|
|
37
|
+
const componentVersionAsciiDocConfig = getAsciiDocConfigWithAsciidoctorReducerExtension(componentVersion)
|
|
38
|
+
const mergedAsciiDocAttributes = collateAsciiDocAttributes(
|
|
39
|
+
Object.assign({ revdate }, componentVersionAsciiDocConfig.attributes),
|
|
40
|
+
assemblerAsciiDocAttributes,
|
|
41
|
+
{ logger: assemblyModel.logger, mdc: configMdc }
|
|
42
|
+
)
|
|
43
|
+
const mergedAsciiDocConfig = Object.assign({}, componentVersionAsciiDocConfig, {
|
|
44
|
+
attributes: mergedAsciiDocAttributes,
|
|
45
|
+
})
|
|
46
|
+
assemblyModel.outDirname = computeOut.call(contentCatalog, {
|
|
47
|
+
component: componentName,
|
|
48
|
+
version,
|
|
49
|
+
family: 'export',
|
|
50
|
+
relative: '.index.adoc',
|
|
51
|
+
}).dirname
|
|
52
|
+
assemblyModel.filetype = assemblerAsciiDocAttributes['assembler-filetype']
|
|
53
|
+
assemblyModel.siteRoot =
|
|
54
|
+
siteRoot === undefined
|
|
55
|
+
? (siteRoot ??= ((val) => {
|
|
56
|
+
if (!val) return null
|
|
57
|
+
if (val.charAt(val.length - 1) === '/') val = val.slice(0, val.length - 1)
|
|
58
|
+
if (!val || val.charAt() === '/') return { path: val }
|
|
59
|
+
return { url: val, path: extractUrlPath(val) }
|
|
60
|
+
})(mergedAsciiDocAttributes['site-url'] || mergedAsciiDocAttributes['primary-site-url']))
|
|
61
|
+
: siteRoot
|
|
62
|
+
if (assemblyModel.filetype === 'html') {
|
|
63
|
+
let linkRefStyle = assemblyModel.linkReferenceStyle
|
|
64
|
+
if (linkRefStyle === 'absolute' && siteRoot?.url == null) linkRefStyle = 'root-relative'
|
|
65
|
+
if (linkRefStyle === 'root-relative' && siteRoot?.path == null) linkRefStyle = 'relative'
|
|
66
|
+
assemblyModel.linkReferenceStyle = linkRefStyle
|
|
67
|
+
} else {
|
|
68
|
+
assemblyModel.linkReferenceStyle = 'absolute'
|
|
69
|
+
}
|
|
70
|
+
const auxiliaryImages = new Set()
|
|
71
|
+
Object.entries(mergedAsciiDocAttributes).forEach(([name, val]) => {
|
|
72
|
+
const match = name.endsWith('-image') && val.startsWith('image:') && IMAGE_MACRO_RX.exec(val)
|
|
73
|
+
if (!(match && isResourceRef(match[1]))) return
|
|
74
|
+
// Q should we allow image to be resolved relative to component version?
|
|
75
|
+
const image = contentCatalog.resolveResource(match[1], undefined, 'image', ['image'])
|
|
76
|
+
if (!image?.out) return
|
|
77
|
+
mergedAsciiDocAttributes[name] = `image:${image.out.path}[${match[2]}]`
|
|
78
|
+
auxiliaryImages.add(image)
|
|
79
|
+
})
|
|
80
|
+
const rootEntry = { content: title }
|
|
81
|
+
const { navigation, rootLevel } = assemblyModel
|
|
82
|
+
let startPage =
|
|
83
|
+
'startPage' in componentVersion
|
|
84
|
+
? componentVersion.startPage
|
|
85
|
+
: contentCatalog.resolvePage('index.adoc', { component: componentName, version })
|
|
86
|
+
if (startPage && startPage.src.component === componentName && startPage.src.version === version) {
|
|
87
|
+
if (assemblyModel.insertStartPage) {
|
|
88
|
+
const navtitle = startPage.asciidoc?.navtitle || rootEntry.content
|
|
89
|
+
Object.assign(rootEntry, { navtitle, url: startPage.pub.url, urlType: 'internal' })
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
// Q: should we always use a reference page as startPage for computing mutableAttributes?
|
|
93
|
+
startPage = createAsciiDocFile(contentCatalog, {
|
|
94
|
+
src: {
|
|
95
|
+
component: componentVersion.name,
|
|
96
|
+
version: componentVersion.version,
|
|
97
|
+
module: 'ROOT',
|
|
98
|
+
family: 'page',
|
|
99
|
+
relative: '.start-page.adoc',
|
|
100
|
+
origin: (componentVersion.origins || [])[0],
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
const mutableAttributes = selectMutableAttributes(loadAsciiDoc, contentCatalog, startPage, mergedAsciiDocConfig)
|
|
105
|
+
delete mutableAttributes.doctype // Q: should this be in selectMutableAttributes?
|
|
106
|
+
prepareOutlines(navigation, rootEntry, rootLevel).reduce((any, outline) => {
|
|
107
|
+
const assemblyFile = produceAssemblyFile(
|
|
108
|
+
loadAsciiDoc,
|
|
109
|
+
contentCatalog,
|
|
110
|
+
componentVersion,
|
|
111
|
+
outline,
|
|
112
|
+
publishableFiles,
|
|
113
|
+
mergedAsciiDocConfig,
|
|
114
|
+
mutableAttributes,
|
|
115
|
+
assemblyModel
|
|
116
|
+
)
|
|
117
|
+
if (!assemblyFile) return any
|
|
118
|
+
if (!any && auxiliaryImages.size) {
|
|
119
|
+
const assembledAssets = assemblyFile.assembler.assembled.assets
|
|
120
|
+
auxiliaryImages.forEach((asset) => assembledAssets.add(asset))
|
|
121
|
+
}
|
|
122
|
+
accum.push(assemblyFile)
|
|
123
|
+
return true
|
|
124
|
+
}, false)
|
|
125
|
+
sourceHighlighter
|
|
126
|
+
? (mergedAsciiDocAttributes['source-highlighter'] = sourceHighlighter)
|
|
127
|
+
: delete mergedAsciiDocAttributes['source-highlighter']
|
|
128
|
+
return accum
|
|
129
|
+
},
|
|
130
|
+
[]
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getAsciiDocConfigWithAsciidoctorReducerExtension (componentVersion) {
|
|
135
|
+
const asciidoctorReducerExtension = require('@asciidoctor/reducer') // NOTE: must be required lazily
|
|
136
|
+
const asciidocConfig = componentVersion.asciidoc
|
|
137
|
+
const extensions = [asciidoctorReducerExtension]
|
|
138
|
+
const configuredExtensions = asciidocConfig.extensions || []
|
|
139
|
+
if (!configuredExtensions.length) return Object.assign({}, asciidocConfig, { extensions, sourcemap: true })
|
|
140
|
+
return Object.assign({}, asciidocConfig, {
|
|
141
|
+
extensions: configuredExtensions.reduce((accum, candidate) => {
|
|
142
|
+
if (candidate !== asciidoctorReducerExtension) accum.push(candidate)
|
|
143
|
+
return accum
|
|
144
|
+
}, extensions),
|
|
145
|
+
sourcemap: true,
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function includedInNav (items, url) {
|
|
150
|
+
return items.find((it) => it.url === url || includedInNav(it.items || [], url))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function isResourceRef (target) {
|
|
154
|
+
return ~target.indexOf(':') && !(~target.indexOf('://') || (target.startsWith('data:') && ~target.indexOf(',')))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function prepareOutlines (navigation, rootEntry, rootLevel) {
|
|
158
|
+
const singleEntry = navigation.length === 1
|
|
159
|
+
const items = navigation.reduce((accum, it) => {
|
|
160
|
+
if (!it.content || (singleEntry && it.url ? it.url === rootEntry.url : it.content === rootEntry.content)) {
|
|
161
|
+
accum.push(...it.items)
|
|
162
|
+
} else {
|
|
163
|
+
accum.push(it)
|
|
164
|
+
}
|
|
165
|
+
return accum
|
|
166
|
+
}, [])
|
|
167
|
+
if (rootLevel === 0) {
|
|
168
|
+
if (rootEntry.url && includedInNav(items, rootEntry.url)) {
|
|
169
|
+
for (const p of ['url', 'urlType']) delete rootEntry[p]
|
|
170
|
+
}
|
|
171
|
+
return [Object.assign(rootEntry, { index: true, items })]
|
|
172
|
+
}
|
|
173
|
+
if (rootEntry.url && !includedInNav(items, rootEntry.url)) {
|
|
174
|
+
rootEntry.content = singleEntry && rootEntry.url === navigation[0].url ? navigation[0].content : rootEntry.navtitle
|
|
175
|
+
items.unshift(rootEntry)
|
|
176
|
+
}
|
|
177
|
+
return items
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function collateAsciiDocAttributes (collated, additional, { logger, mdc }) {
|
|
181
|
+
Object.entries(additional).forEach(([name, val]) => {
|
|
182
|
+
if (val && val.constructor === String) {
|
|
183
|
+
let alias
|
|
184
|
+
val = val.replace(ATTR_REF_RX, (ref, refname) => {
|
|
185
|
+
if (ref.charAt() === '\\') return ref.substr(1)
|
|
186
|
+
const refval = collated[refname]
|
|
187
|
+
if (refval == null || refval === false) {
|
|
188
|
+
if (refname in collated && ref === val) {
|
|
189
|
+
alias = refval
|
|
190
|
+
} else if (collated['attribute-missing'] === 'warn') {
|
|
191
|
+
if (logger) {
|
|
192
|
+
logger.warn(mdc, "Skipping reference to missing attribute '%s' in value of '%s' attribute", refname, name)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return ref
|
|
196
|
+
}
|
|
197
|
+
if (refval.constructor === String) return refval
|
|
198
|
+
if (ref !== val) return refval.toString()
|
|
199
|
+
alias = refval
|
|
200
|
+
return ref
|
|
201
|
+
})
|
|
202
|
+
if (alias !== undefined) val = alias
|
|
203
|
+
}
|
|
204
|
+
collated[name] = val
|
|
205
|
+
})
|
|
206
|
+
return collated
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function extractUrlPath (url) {
|
|
210
|
+
if (!url) return ''
|
|
211
|
+
const urlPath = new URL(url).pathname
|
|
212
|
+
return urlPath === '/' ? '' : urlPath
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = produceAssemblyFiles
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { posix: path } = require('node:path')
|
|
4
|
+
|
|
5
|
+
function computeOut (src) {
|
|
6
|
+
const { component, version, module: module_ = 'ROOT', family, relative } = src
|
|
7
|
+
const outRelative = family === 'page' ? relative.replace(/\.adoc$/, '.html') : relative
|
|
8
|
+
const { dir: dirname, base: basename } = path.parse(outRelative)
|
|
9
|
+
const componentVersion = this.getComponentVersion(component, version)
|
|
10
|
+
const versionSegment =
|
|
11
|
+
'activeVersionSegment' in componentVersion
|
|
12
|
+
? componentVersion.activeVersionSegment
|
|
13
|
+
: resolveActiveVersionSegment.call(this, component, version)
|
|
14
|
+
const outDirSegments = []
|
|
15
|
+
const moduleRootPathSegments = []
|
|
16
|
+
if (component !== 'ROOT') outDirSegments.push(component)
|
|
17
|
+
if (versionSegment) outDirSegments.push(versionSegment)
|
|
18
|
+
if (module_ !== 'ROOT') outDirSegments.push(module_)
|
|
19
|
+
const outModuleDirSegments = outDirSegments.slice()
|
|
20
|
+
if (family !== 'page') {
|
|
21
|
+
outDirSegments.push(`_${family}s`)
|
|
22
|
+
moduleRootPathSegments.push('..')
|
|
23
|
+
}
|
|
24
|
+
if (dirname) {
|
|
25
|
+
outDirSegments.push(dirname)
|
|
26
|
+
for (const _ of dirname.split('/')) moduleRootPathSegments.push('..')
|
|
27
|
+
}
|
|
28
|
+
const rootPathSegments = moduleRootPathSegments.slice()
|
|
29
|
+
for (const _ of outModuleDirSegments) rootPathSegments.push('..')
|
|
30
|
+
const outDirname = outDirSegments.join('/')
|
|
31
|
+
const result = {
|
|
32
|
+
dirname: outDirname,
|
|
33
|
+
basename,
|
|
34
|
+
path: outDirname + '/' + basename,
|
|
35
|
+
moduleRootPath: moduleRootPathSegments.length ? moduleRootPathSegments.join('/') : '.',
|
|
36
|
+
rootPath: rootPathSegments.length ? rootPathSegments.join('/') : '.',
|
|
37
|
+
}
|
|
38
|
+
return result
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function resolveActiveVersionSegment (component, version) {
|
|
42
|
+
let startPage = this.resolvePage('index.adoc', { component, version })
|
|
43
|
+
let startPageSrc
|
|
44
|
+
if (startPage) {
|
|
45
|
+
startPageSrc = startPage.src
|
|
46
|
+
} else {
|
|
47
|
+
startPageSrc = { component, version, module: 'ROOT', family: 'page', relative: 'index.adoc' }
|
|
48
|
+
this.removeFile((startPage = this.addFile({ src: startPageSrc })))
|
|
49
|
+
}
|
|
50
|
+
const outPathSegments = startPage.out.path.split('/')
|
|
51
|
+
for (const _ of startPage.out.moduleRootPath.split('/')) outPathSegments.pop()
|
|
52
|
+
if (startPageSrc.module !== 'ROOT') outPathSegments.pop()
|
|
53
|
+
if (startPageSrc.component !== 'ROOT') outPathSegments.shift()
|
|
54
|
+
return outPathSegments.length ? outPathSegments[0] : ''
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = computeOut
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const computeOut = require('./compute-out')
|
|
4
|
+
|
|
5
|
+
function createAsciiDocFile (contentCatalog, file) {
|
|
6
|
+
file.mediaType = 'text/asciidoc'
|
|
7
|
+
const src = file.src
|
|
8
|
+
const out = computeOut.call(contentCatalog, src)
|
|
9
|
+
if (src.family === 'export') {
|
|
10
|
+
contentCatalog.removeFile((file = contentCatalog.addFile(Object.assign(file, { path: out.path, out: null }))))
|
|
11
|
+
return file
|
|
12
|
+
}
|
|
13
|
+
const pub = { url: '/' + out.path, moduleRootPath: out.moduleRootPath, rootPath: out.rootPath }
|
|
14
|
+
return { contents: src.contents ?? Buffer.alloc(0), src, out, pub }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = createAsciiDocFile
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
function parseResourceRef (ref, ctx = {}, family = undefined, contentCatalog = undefined) {
|
|
4
|
+
const atIdx = ref.indexOf('@')
|
|
5
|
+
let firstColonIdx = ref.indexOf(':')
|
|
6
|
+
let component, version, module_
|
|
7
|
+
if (~atIdx && (~firstColonIdx ? atIdx < firstColonIdx : true)) {
|
|
8
|
+
if ((version = ref.slice(0, atIdx)) === '_') version = ''
|
|
9
|
+
ref = ref.slice(atIdx + 1)
|
|
10
|
+
if (~firstColonIdx) firstColonIdx -= atIdx + 1
|
|
11
|
+
}
|
|
12
|
+
const addColons = ~firstColonIdx ? (~ref.indexOf(':', firstColonIdx + 1) ? '' : ':') : '::'
|
|
13
|
+
const segments = (addColons + ref).split(':')
|
|
14
|
+
if ((component = segments[0])) {
|
|
15
|
+
module_ = segments[1] || 'ROOT'
|
|
16
|
+
version ??= contentCatalog?.getComponent(component)?.latest.version
|
|
17
|
+
} else {
|
|
18
|
+
component = ctx.component
|
|
19
|
+
version ??= ctx.version
|
|
20
|
+
module_ = segments[1] || ctx.module || 'ROOT'
|
|
21
|
+
}
|
|
22
|
+
let relative = segments.length > 3 ? segments.slice(2).join(':') : segments[2]
|
|
23
|
+
const dollarIdx = relative.indexOf('$')
|
|
24
|
+
if (~dollarIdx) {
|
|
25
|
+
family = relative.slice(0, dollarIdx) || family
|
|
26
|
+
relative = relative.slice(dollarIdx + 1)
|
|
27
|
+
}
|
|
28
|
+
if (relative.charAt() === '.' && relative.charAt(1) === '/') {
|
|
29
|
+
const ctxRelative = ctx.relative
|
|
30
|
+
const topic = ctxRelative ? ctxRelative.slice(0, (ctxRelative.lastIndexOf('/') + 1 || 1) - 1) : undefined
|
|
31
|
+
relative = (topic ? topic + '/' : '') + relative.slice(2)
|
|
32
|
+
}
|
|
33
|
+
return { component, version, module: module_, family, relative }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = parseResourceRef
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antora/assembler",
|
|
3
|
-
"version": "1.0.0-
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0-beta.10",
|
|
4
|
+
"description": "A JavaScript library that merges AsciiDoc content from multiple pages in an Antora site into assembly files and delegates to an exporter to convert those files to another format, such as PDF.",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"author": "OpenDevise Inc. (https://opendevise.com)",
|
|
7
7
|
"contributors": [
|
|
@@ -9,43 +9,51 @@
|
|
|
9
9
|
"Sarah White <sarah@opendevise.com>"
|
|
10
10
|
],
|
|
11
11
|
"homepage": "https://antora.org",
|
|
12
|
-
"repository":
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://gitlab.com/antora/antora-assembler.git",
|
|
15
|
+
"directory": "packages/assembler"
|
|
16
|
+
},
|
|
13
17
|
"bugs": {
|
|
14
18
|
"url": "https://gitlab.com/antora/antora-assembler/issues"
|
|
15
19
|
},
|
|
16
20
|
"scripts": {
|
|
17
|
-
"test": "
|
|
21
|
+
"test": "node --test test/*-test.js",
|
|
18
22
|
"prepublishOnly": "npx -y downdoc --prepublish",
|
|
19
23
|
"postpublish": "npx -y downdoc --postpublish"
|
|
20
24
|
},
|
|
21
25
|
"main": "lib/index.js",
|
|
22
26
|
"exports": {
|
|
23
27
|
".": "./lib/index.js",
|
|
24
|
-
"./asciidoctor/reducer-extension": "./lib/asciidoctor/reducer-extension.js",
|
|
25
28
|
"./filter-component-versions": "./lib/filter-component-versions.js",
|
|
26
29
|
"./load-config": "./lib/load-config.js",
|
|
27
|
-
"./
|
|
28
|
-
"./produce-
|
|
30
|
+
"./parse-resource-ref": "./lib/util/parse-resource-ref.js",
|
|
31
|
+
"./produce-assembly-file": "./lib/produce-assembly-file.js",
|
|
32
|
+
"./produce-assembly-files": "./lib/produce-assembly-files.js",
|
|
29
33
|
"./select-mutable-attributes": "./lib/select-mutable-attributes.js"
|
|
30
34
|
},
|
|
31
35
|
"imports": {
|
|
36
|
+
"#asciidoctor-log-adapter": "./adapters/asciidoctor/jsonl-logger.rb",
|
|
37
|
+
"#run-command": "@antora/run-command-helper",
|
|
32
38
|
"#unconvert-inline-asciidoc": "./lib/util/unconvert-inline-asciidoc.js"
|
|
33
39
|
},
|
|
34
40
|
"dependencies": {
|
|
35
|
-
"@
|
|
41
|
+
"@asciidoctor/reducer": "~1.1",
|
|
42
|
+
"@antora/expand-path-helper": "~3.0",
|
|
36
43
|
"braces": "~3.0",
|
|
37
44
|
"picomatch": "~3.0",
|
|
38
|
-
"vinyl": "~2.2",
|
|
39
45
|
"js-yaml": "~4.1"
|
|
40
46
|
},
|
|
41
47
|
"devDependencies": {
|
|
42
48
|
"@antora/asciidoc-loader": "~3.1",
|
|
49
|
+
"@antora/navigation-builder": "~3.1",
|
|
43
50
|
"@antora/site-publisher": "~3.1"
|
|
44
51
|
},
|
|
45
52
|
"engines": {
|
|
46
53
|
"node": ">=16.0.0"
|
|
47
54
|
},
|
|
48
55
|
"files": [
|
|
56
|
+
"adapters/",
|
|
49
57
|
"lib/"
|
|
50
58
|
],
|
|
51
59
|
"keywords": [
|
|
@@ -53,8 +61,5 @@
|
|
|
53
61
|
"antora-extension",
|
|
54
62
|
"asciidoc",
|
|
55
63
|
"documentation"
|
|
56
|
-
]
|
|
57
|
-
"publishConfig": {
|
|
58
|
-
"access": "public"
|
|
59
|
-
}
|
|
64
|
+
]
|
|
60
65
|
}
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const Opal = global.Opal
|
|
4
|
-
const Asciidoctor = Opal.Asciidoctor
|
|
5
|
-
const $Reducer = function $Reducer () {}
|
|
6
|
-
|
|
7
|
-
const DocumentExt = (() => {
|
|
8
|
-
const parentScope = Opal.module(Asciidoctor, 'Reducer', $Reducer)
|
|
9
|
-
const scope = Opal.module(parentScope, 'DocumentExt', function $DocumentExt () {})
|
|
10
|
-
|
|
11
|
-
Opal.defn(scope, '$save_attributes', function saveAttributes () {
|
|
12
|
-
this.attributes_defined_in_header = this.attributes_modified.$to_a().reduce((accum, name) => {
|
|
13
|
-
accum[name] = this.getAttribute(name)
|
|
14
|
-
return accum
|
|
15
|
-
}, {})
|
|
16
|
-
return Opal.send(this, Opal.find_super_dispatcher(this, 'save_attributes', saveAttributes), [])
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
return scope
|
|
20
|
-
})()
|
|
21
|
-
|
|
22
|
-
const ConditionalDirectiveTracker = (() => {
|
|
23
|
-
const parentScope = Opal.module(Asciidoctor, 'Reducer', $Reducer)
|
|
24
|
-
const scope = Opal.module(parentScope, 'ConditionalDirectiveTracker', function $ConditionalDirectiveTracker () {})
|
|
25
|
-
|
|
26
|
-
Opal.defn(
|
|
27
|
-
scope,
|
|
28
|
-
'$preprocess_conditional_directive',
|
|
29
|
-
function preprocessConditionalDirective (keyword, target, delimiter, text) {
|
|
30
|
-
const skipActive = this.skipping
|
|
31
|
-
const depth = this.conditional_stack.length
|
|
32
|
-
let directiveLineno = this.lineno
|
|
33
|
-
const result = Opal.send(
|
|
34
|
-
this,
|
|
35
|
-
Opal.find_super_dispatcher(this, 'preprocess_conditional_directive', preprocessConditionalDirective),
|
|
36
|
-
[keyword, target, delimiter, text]
|
|
37
|
-
)
|
|
38
|
-
if (this.skipping && skipActive) return result
|
|
39
|
-
const currIncReplacement = this.includeReplacements.$current()
|
|
40
|
-
const drop = currIncReplacement.drop || (currIncReplacement.drop = [])
|
|
41
|
-
directiveLineno -= currIncReplacement.offset || 0
|
|
42
|
-
const depthChange = this.conditional_stack.length - depth
|
|
43
|
-
if (depthChange < 0) {
|
|
44
|
-
if (skipActive) {
|
|
45
|
-
for (let n = drop.pop(); n <= directiveLineno; n++) drop.push(n)
|
|
46
|
-
} else {
|
|
47
|
-
drop.push(directiveLineno)
|
|
48
|
-
}
|
|
49
|
-
} else if (depthChange > 0 || directiveLineno === this.lineno) {
|
|
50
|
-
drop.push(directiveLineno)
|
|
51
|
-
} else {
|
|
52
|
-
drop.push([directiveLineno, text])
|
|
53
|
-
}
|
|
54
|
-
return result
|
|
55
|
-
}
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
return scope
|
|
59
|
-
})()
|
|
60
|
-
|
|
61
|
-
const CurrentPosition = (() => {
|
|
62
|
-
const parentScope = Opal.module(Opal.Asciidoctor, 'Reducer', $Reducer)
|
|
63
|
-
const scope = Opal.module(parentScope, 'CurrentPosition', function $CurrentPosition () {})
|
|
64
|
-
|
|
65
|
-
Opal.defn(Opal.get_singleton_class(scope), '$extended', function $extended (instance) {
|
|
66
|
-
instance.$to_end()
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
Opal.defn(scope, '$current', function $current () {
|
|
70
|
-
return this[this.pointer]
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
Opal.defn(scope, '$to_end', function $toEnd () {
|
|
74
|
-
this.pointer = this.length - 1
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
Opal.defn(scope, '$up', function $up () {
|
|
78
|
-
this.pointer = this.$current().into
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
return scope
|
|
82
|
-
})()
|
|
83
|
-
|
|
84
|
-
const IncludeDirectiveTracker = (() => {
|
|
85
|
-
const parentScope = Opal.module(Opal.Asciidoctor, 'Reducer', $Reducer)
|
|
86
|
-
const scope = Opal.module(parentScope, 'IncludeDirectiveTracker', function $IncludeDirectiveTracker () {})
|
|
87
|
-
|
|
88
|
-
Opal.defn(Opal.get_singleton_class(scope), '$extended', function $extended (instance) {
|
|
89
|
-
instance.includeReplacements = [{}].$extend(CurrentPosition)
|
|
90
|
-
instance.$$reducer = {}
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
Opal.defn(scope, '$preprocess_include_directive', function preprocessIncludeDirective (target, attrlist) {
|
|
94
|
-
this.$$reducer.includeDirectiveLine = `include::${target}[${attrlist}]`
|
|
95
|
-
this.$$reducer.includePushed = false
|
|
96
|
-
const directiveLineno = this.lineno // we're currently on the include line, which is 1-based
|
|
97
|
-
const result = Opal.send(
|
|
98
|
-
this,
|
|
99
|
-
Opal.find_super_dispatcher(this, 'preprocess_include_directive', preprocessIncludeDirective),
|
|
100
|
-
[target, attrlist]
|
|
101
|
-
)
|
|
102
|
-
if (!this.$$reducer.includePushed) {
|
|
103
|
-
let ln = this.peekLine(true)
|
|
104
|
-
let unresolved
|
|
105
|
-
if (
|
|
106
|
-
ln &&
|
|
107
|
-
ln.charAt(ln.length - 1) === ']' &&
|
|
108
|
-
!(unresolved = ln.startsWith('Unresolved directive in ')) &&
|
|
109
|
-
directiveLineno === this.lineno &&
|
|
110
|
-
(unresolved = ln.startsWith('link:'))
|
|
111
|
-
) {
|
|
112
|
-
ln = `${ln.slice(0, ln.length - 1)}role=include]`
|
|
113
|
-
}
|
|
114
|
-
pushIncludeReplacement.call(this, directiveLineno, unresolved ? [ln] : [], 0, unresolved)
|
|
115
|
-
}
|
|
116
|
-
this.$$reducer = {}
|
|
117
|
-
return result
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
Opal.defn(scope, '$push_include', function pushInclude (data, file, path, lineno, attrs) {
|
|
121
|
-
this.$$reducer.includePushed = true
|
|
122
|
-
const directiveLineno = this.lineno - 1 // we're below the include line, which is 1-based
|
|
123
|
-
const prevIncDepth = this.include_stack.length
|
|
124
|
-
let offset = lineno > 1 ? lineno - 1 : 0
|
|
125
|
-
const result = Opal.send(this, Opal.find_super_dispatcher(this, 'push_include', pushInclude), [
|
|
126
|
-
data,
|
|
127
|
-
file,
|
|
128
|
-
path,
|
|
129
|
-
lineno,
|
|
130
|
-
attrs,
|
|
131
|
-
])
|
|
132
|
-
let incLines = []
|
|
133
|
-
if (this.include_stack.length > prevIncDepth) {
|
|
134
|
-
incLines = this.$lines()
|
|
135
|
-
if (attrs['$key?']('leveloffset') && incLines[0].startsWith(':leveloffset: ') && incLines[1] === '') offset -= 2
|
|
136
|
-
}
|
|
137
|
-
pushIncludeReplacement.call(this, directiveLineno, incLines, offset)
|
|
138
|
-
return result
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
Opal.defn(scope, '$pop_include', function popInclude () {
|
|
142
|
-
if (!this.$$reducer.includePushed) this.includeReplacements.$up()
|
|
143
|
-
return Opal.send(this, Opal.find_super_dispatcher(this, 'pop_include', popInclude), [])
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
function pushIncludeReplacement (lineno, lines, offset, unresolved) {
|
|
147
|
-
const incReplacements = this.includeReplacements
|
|
148
|
-
const into = incReplacements.pointer
|
|
149
|
-
const line = this.$$reducer.includeDirectiveLine
|
|
150
|
-
incReplacements.push({ into, lineno: lineno - (incReplacements.$current().offset || 0), line, lines, offset })
|
|
151
|
-
if (!unresolved && lines.length) incReplacements.$to_end()
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return scope
|
|
155
|
-
})()
|
|
156
|
-
|
|
157
|
-
function preprocessor () {
|
|
158
|
-
this.process((doc, reader) =>
|
|
159
|
-
doc.getOptions().preserve_conditionals
|
|
160
|
-
? reader.$extend(IncludeDirectiveTracker)
|
|
161
|
-
: reader.$extend(ConditionalDirectiveTracker, IncludeDirectiveTracker)
|
|
162
|
-
)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function treeProcessor () {
|
|
166
|
-
this.process((doc) => {
|
|
167
|
-
const incReplacements = doc.reader.includeReplacements
|
|
168
|
-
if (incReplacements.length > 1 || (incReplacements[0].drop || []).length) {
|
|
169
|
-
const sourceLines = doc.getSourceLines()
|
|
170
|
-
incReplacements[0].lines = sourceLines.slice()
|
|
171
|
-
incReplacements
|
|
172
|
-
.slice()
|
|
173
|
-
.reverse()
|
|
174
|
-
.forEach(({ into, lineno, lines, line, drop }) => {
|
|
175
|
-
let targetLines, idx
|
|
176
|
-
if (into != null) {
|
|
177
|
-
targetLines = incReplacements[into].lines
|
|
178
|
-
// adds extra assurance that the program is replacing the correct line
|
|
179
|
-
if (targetLines[(idx = lineno - 1)] !== line) {
|
|
180
|
-
const msg = `include directive to reduce not found; expected: "${line}"; got: "${targetLines[idx]}"`
|
|
181
|
-
doc.getLogger().error(msg)
|
|
182
|
-
return
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if ((drop || []).length) {
|
|
186
|
-
drop
|
|
187
|
-
.slice()
|
|
188
|
-
.reverse()
|
|
189
|
-
.forEach((dropIt) => {
|
|
190
|
-
Array.isArray(dropIt) ? (lines[dropIt[0] - 1] = dropIt[1]) : lines.splice(dropIt - 1, 1)
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
if (targetLines) targetLines[idx] = lines
|
|
194
|
-
})
|
|
195
|
-
const reducedSourceLines = flattenDeep(incReplacements[0].lines)
|
|
196
|
-
if (doc.getSourcemap()) {
|
|
197
|
-
const logger = Asciidoctor.LoggerManager.getLogger()
|
|
198
|
-
const opts = Object.assign(doc.getOptions(), { logger: undefined, parse: false, reduced: true })
|
|
199
|
-
if (opts.extension_registry) {
|
|
200
|
-
opts.extension_registry = Asciidoctor.Extensions.Registry.$new(opts.extension_registry.groups)
|
|
201
|
-
}
|
|
202
|
-
const includes = doc.getCatalog().includes
|
|
203
|
-
doc = Asciidoctor.load(reducedSourceLines, opts)
|
|
204
|
-
doc.catalog.$send('[]=', 'includes', includes)
|
|
205
|
-
doc.parse()
|
|
206
|
-
Asciidoctor.LoggerManager.setLogger(logger)
|
|
207
|
-
} else {
|
|
208
|
-
while (reducedSourceLines[reducedSourceLines.length - 1] === '') reducedSourceLines.pop()
|
|
209
|
-
sourceLines.splice(0, sourceLines.length, ...reducedSourceLines)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return doc
|
|
213
|
-
})
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function flattenDeep (array, accum = []) {
|
|
217
|
-
const len = array.length
|
|
218
|
-
for (let i = 0, it; i < len; i++) Array.isArray((it = array[i])) ? flattenDeep(it, accum) : accum.push(it)
|
|
219
|
-
return accum
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function toProc (fn) {
|
|
223
|
-
return Object.defineProperty(fn, '$$arity', { value: fn.length })
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
module.exports.register = (registry) => {
|
|
227
|
-
const extGroup = toProc(function () {
|
|
228
|
-
const doc = this.document
|
|
229
|
-
doc.$extend(DocumentExt)
|
|
230
|
-
if (doc.getOptions().reduced) return
|
|
231
|
-
this.preprocessor(preprocessor)
|
|
232
|
-
this.treeProcessor(treeProcessor)
|
|
233
|
-
})
|
|
234
|
-
registry.groups.$send('[]=', 'reducer', extGroup)
|
|
235
|
-
}
|