@redpanda-data/docs-extensions-and-macros 2.5.0 → 3.0.0
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.adoc
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
= Antora Extensions and Macros for Redpanda Docs
|
|
2
|
-
:url-
|
|
2
|
+
:url-org: https://github.com/redpanda-data
|
|
3
|
+
:url-project: {url-org}/docs-extensions-and-macros
|
|
4
|
+
:url-playbook: {url-org}/docs-site
|
|
3
5
|
:url-git: https://git-scm.com
|
|
4
6
|
:url-git-dl: {url-git}/downloads
|
|
5
7
|
:url-nodejs: https://nodejs.org
|
|
@@ -33,7 +35,7 @@ When you have Node.js installed, use the following command to install the `antor
|
|
|
33
35
|
|
|
34
36
|
[,bash]
|
|
35
37
|
----
|
|
36
|
-
npm i
|
|
38
|
+
npm i @redpanda-data/docs-extensions-and-macros
|
|
37
39
|
----
|
|
38
40
|
|
|
39
41
|
To use the development version instead, refer to the <<development-quickstart,Development Quickstart>>.
|
|
@@ -70,7 +72,7 @@ Whether to index all versions or just the latest version of a component.
|
|
|
70
72
|
```yaml
|
|
71
73
|
antora:
|
|
72
74
|
extensions:
|
|
73
|
-
- require: '
|
|
75
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/algolia-indexer/index'
|
|
74
76
|
excludes: ['.thumbs','script', '.page-versions','.feedback-section','.banner-container']
|
|
75
77
|
index-latest-only: true
|
|
76
78
|
```
|
|
@@ -92,48 +94,19 @@ NOTE: If you don't set the environment variable, the latest versions may not be
|
|
|
92
94
|
```yaml
|
|
93
95
|
antora:
|
|
94
96
|
extensions:
|
|
95
|
-
- '
|
|
97
|
+
- '@redpanda-data/docs-extensions-and-macros/extensions/version-fetcher/set-latest-version'
|
|
96
98
|
```
|
|
97
99
|
|
|
98
100
|
=== Global attributes
|
|
99
101
|
|
|
100
|
-
This extension
|
|
101
|
-
|
|
102
|
-
[IMPORTANT]
|
|
103
|
-
====
|
|
104
|
-
- The GitHub directory that contains the global attributes must be named `global-attributes`.
|
|
105
|
-
- Only YAML files are supported. Other types of files are ignored.
|
|
106
|
-
- If a key is present in both the global attributes and the playbook's `asciidoc.attributes`, the value in the playbook takes precedence.
|
|
107
|
-
====
|
|
108
|
-
|
|
109
|
-
==== Environment variables
|
|
110
|
-
|
|
111
|
-
- `GLOBAL_ATTRIBUTES_GITHUB_TOKEN` (optional): A Personal access token (PAT) that has `repo` permissions for the GitHub organization defined in `org`.
|
|
112
|
-
|
|
113
|
-
NOTE: If you don't set the environment variable, global attributes may not be made available to your build. When the environment variable is not set, the extension sends unauthenticated requests to GitHub. Unauthenticated requests may result in hitting the API rate limit and cause GitHub to reject the request.
|
|
114
|
-
|
|
115
|
-
==== Configuration options
|
|
116
|
-
|
|
117
|
-
The extension accepts the following configuration options:
|
|
118
|
-
|
|
119
|
-
org (required)::
|
|
120
|
-
The GitHub organization that owns the repository.
|
|
121
|
-
|
|
122
|
-
repo (required)::
|
|
123
|
-
The name of the repository.
|
|
124
|
-
|
|
125
|
-
branch (required)::
|
|
126
|
-
The branch in the repository where the global attributes are located.
|
|
102
|
+
This extension collects Asciidoc attributes from the {url-playbook}[`shared` component] and makes them available to all component versions. Having global attributes is useful for consistent configuration of local and production builds.
|
|
127
103
|
|
|
128
104
|
==== Registration example
|
|
129
105
|
|
|
130
106
|
```yaml
|
|
131
107
|
antora:
|
|
132
108
|
extensions:
|
|
133
|
-
- require: '
|
|
134
|
-
org: example
|
|
135
|
-
repo: test
|
|
136
|
-
branch: main
|
|
109
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/add-global-attributes'
|
|
137
110
|
```
|
|
138
111
|
|
|
139
112
|
=== Replace attributes in attachments
|
|
@@ -152,7 +125,28 @@ This extension replaces AsciiDoc attribute placeholders with their respective va
|
|
|
152
125
|
```yaml
|
|
153
126
|
antora:
|
|
154
127
|
extensions:
|
|
155
|
-
- '
|
|
128
|
+
- '@redpanda-data/docs-extensions-and-macros/extensions/replace-attributes-in-attachments'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
=== Aggregate terms
|
|
132
|
+
|
|
133
|
+
This extension aggregates all term pages from the {url-playbook}[`shared` component] and does the following:
|
|
134
|
+
|
|
135
|
+
- Makes all `term-name` and `hover-text` attributes available to the <<glossterm-macro,`glossterm` macro>>.
|
|
136
|
+
- Looks for glossary pages named `reference:glossary.adoc` in all versions of the Redpanda docs and appends the contents of each term file to the glossary in alphabetical order.
|
|
137
|
+
- If a glossary page is found, sets the `glossary-page` attribute of the `glossterm` macro to `reference:glossary.adoc`.
|
|
138
|
+
|
|
139
|
+
[IMPORTANT]
|
|
140
|
+
====
|
|
141
|
+
By default, this extension processes glossary pages for the `ROOT` (redpanda) component only. This behavior is hardcoded and cannot be changed in the configuration.
|
|
142
|
+
====
|
|
143
|
+
|
|
144
|
+
==== Registration example
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
antora:
|
|
148
|
+
extensions:
|
|
149
|
+
- '@redpanda-data/docs-extensions-and-macros/extensions/aggregate-terms'
|
|
156
150
|
```
|
|
157
151
|
|
|
158
152
|
=== Unlisted pages
|
|
@@ -176,7 +170,7 @@ The heading under which to list the unlisted pages in the navigation. The defaul
|
|
|
176
170
|
```yaml
|
|
177
171
|
antora:
|
|
178
172
|
extensions:
|
|
179
|
-
- require: '
|
|
173
|
+
- require: '@redpanda-data/docs-extensions-and-macros/extensions/unlisted-pages'
|
|
180
174
|
addToNavigation: true
|
|
181
175
|
unlistedPagesHeading: 'Additional Resources'
|
|
182
176
|
```
|
|
@@ -228,33 +222,22 @@ config_ref:example_config,true,tunable-properties[]
|
|
|
228
222
|
----
|
|
229
223
|
asciidoc:
|
|
230
224
|
extensions:
|
|
231
|
-
- '
|
|
225
|
+
- '@redpanda-data/docs-extensions-and-macros/macros/config-ref'
|
|
232
226
|
----
|
|
233
227
|
|
|
234
|
-
===
|
|
228
|
+
=== glossterm
|
|
235
229
|
|
|
236
|
-
The
|
|
230
|
+
The `glossterm` inline macro provides a way to define and reference glossary terms in your AsciiDoc documents.
|
|
237
231
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
NOTE: This macro is a customized version of https://gitlab.com/djencks/asciidoctor-glossary[`asciidoctor-glossary`]. We added the ability to define terms globally in <<global-attributes, global attributes>> as well as link to external URLs.
|
|
232
|
+
NOTE: This macro is a customized version of https://gitlab.com/djencks/asciidoctor-glossary[`asciidoctor-glossary`].
|
|
241
233
|
|
|
242
234
|
==== Usage
|
|
243
235
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
[,asciidoc]
|
|
247
|
-
----
|
|
248
|
-
glossary::[]
|
|
249
|
-
----
|
|
250
|
-
|
|
251
|
-
Glossary terms defined in the `glossterm` inline macro before the `glossary` macro is used appear as a definition list, sorted by term.
|
|
252
|
-
|
|
253
|
-
The `glossterm` inline macro is used to reference a term within the text of the document:
|
|
236
|
+
Use the `glossterm` inline macro to reference a term within the text of the document:
|
|
254
237
|
|
|
255
238
|
[,asciidoc]
|
|
256
239
|
----
|
|
257
|
-
glossterm:
|
|
240
|
+
glossterm:my term[myDefinition]
|
|
258
241
|
----
|
|
259
242
|
|
|
260
243
|
It takes two parameters:
|
|
@@ -263,7 +246,7 @@ term::
|
|
|
263
246
|
The term to be defined.
|
|
264
247
|
|
|
265
248
|
definition (optional)::
|
|
266
|
-
The definition of the term. If the term is defined in the
|
|
249
|
+
The definition of the term. If the term is defined in the {url-playbook}[`shared` component] or the `local-terms` object of the `antora.yml` file, you can omit the definition as it will always be replaced by those definitions.
|
|
267
250
|
|
|
268
251
|
==== Configuration options
|
|
269
252
|
|
|
@@ -290,22 +273,13 @@ Whether to enable tooltips for the defined terms. Valid values are:
|
|
|
290
273
|
|
|
291
274
|
The last two options are intended to support js/css tooltip solutions such as tippy.js.
|
|
292
275
|
|
|
293
|
-
[IMPORTANT]
|
|
294
|
-
.Multi-page use
|
|
295
|
-
====
|
|
296
|
-
In Antora, a glossary is constructed for each component-version.
|
|
297
|
-
When the `glossary` block macro is evaluated, only terms known as of the rendering can be included.
|
|
298
|
-
Therefore, it is necessary that the page containing this macro in a component-version be rendered last.
|
|
299
|
-
It may be possible to arrange this by naming the page starting with a lot of 'z’s, such as `zzzzzz-glossary.adoc`.
|
|
300
|
-
====
|
|
301
|
-
|
|
302
276
|
==== Registration example
|
|
303
277
|
|
|
304
278
|
[,yaml]
|
|
305
279
|
----
|
|
306
280
|
asciidoc:
|
|
307
281
|
extensions:
|
|
308
|
-
- '
|
|
282
|
+
- '@redpanda-data/docs-extensions-and-macros/macros/glossary'
|
|
309
283
|
----
|
|
310
284
|
|
|
311
285
|
=== helm_ref
|
|
@@ -347,7 +321,7 @@ If you do not specify a Helm reference value, the macro generates a link without
|
|
|
347
321
|
----
|
|
348
322
|
asciidoc:
|
|
349
323
|
extensions:
|
|
350
|
-
- '
|
|
324
|
+
- '@redpanda-data/docs-extensions-and-macros/macros/helm-ref'
|
|
351
325
|
----
|
|
352
326
|
|
|
353
327
|
== Development quickstart
|
|
@@ -418,5 +392,5 @@ If you want to use the project locally before it is published, you can specify t
|
|
|
418
392
|
asciidoc:
|
|
419
393
|
attributes:
|
|
420
394
|
extensions:
|
|
421
|
-
- '<path-to-local-project>/
|
|
422
|
-
----
|
|
395
|
+
- '<path-to-local-project>/docs-extensions-and-macros/extensions/<extension-name>'
|
|
396
|
+
----
|
|
@@ -2,76 +2,43 @@
|
|
|
2
2
|
* antora:
|
|
3
3
|
extensions:
|
|
4
4
|
* - require: ./extensions/add-global-attributes.js
|
|
5
|
-
org: example
|
|
6
|
-
repo: test
|
|
7
|
-
branch: main
|
|
8
5
|
*/
|
|
9
6
|
|
|
10
|
-
const yaml = require('js-yaml');
|
|
11
|
-
const { Octokit } = require("@octokit/rest");
|
|
12
|
-
const { retry } = require("@octokit/plugin-retry");
|
|
13
|
-
const OctokitWithRetries = Octokit.plugin(retry);
|
|
14
|
-
const chalk = require('chalk')
|
|
15
|
-
|
|
16
|
-
|
|
17
7
|
module.exports.register = function ({ config }) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
this
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const github = new OctokitWithRetries(githubOptions);
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
// Request the contents of the directory from the GitHub API
|
|
40
|
-
const response = await github.request('GET ' + globalAttributesUrl);
|
|
41
|
-
|
|
42
|
-
if (response.status === 200) {
|
|
43
|
-
const directoryContents = response.data;
|
|
44
|
-
|
|
45
|
-
// Filter out only YAML files
|
|
46
|
-
const yamlFiles = directoryContents.filter(file => file.name.endsWith('.yaml') || file.name.endsWith('.yml'));
|
|
47
|
-
|
|
48
|
-
let globalAttributes = {};
|
|
49
|
-
for (let file of yamlFiles) {
|
|
50
|
-
const fileResponse = await github.request('GET ' + file.download_url);
|
|
51
|
-
const fileData = yaml.load(fileResponse.data);
|
|
52
|
-
globalAttributes = {...globalAttributes, ...fileData};
|
|
8
|
+
const yaml = require('js-yaml');
|
|
9
|
+
const _ = require('lodash');
|
|
10
|
+
const logger = this.getLogger('global-attributes-extension');
|
|
11
|
+
const chalk = require('chalk')
|
|
12
|
+
|
|
13
|
+
this.on('contentAggregated', ({ siteCatalog, contentAggregate }) => {
|
|
14
|
+
let attributeFile;
|
|
15
|
+
try {
|
|
16
|
+
for (const component of contentAggregate) {
|
|
17
|
+
if (component.name === 'shared') {
|
|
18
|
+
attributeFile = component.files.find(file => file.path.includes('attributes.yml'));
|
|
19
|
+
if (!attributeFile) {
|
|
20
|
+
logger.warn("No attributes.yml file found in 'shared' component.");
|
|
21
|
+
} else {
|
|
22
|
+
siteCatalog.attributeFile = yaml.load(attributeFile.contents.toString('utf8'));
|
|
23
|
+
console.log(chalk.green('Loaded attributes from shared component.'));
|
|
53
24
|
}
|
|
54
|
-
|
|
55
|
-
let mergedAttributes = {
|
|
56
|
-
...globalAttributes,
|
|
57
|
-
...playbook.asciidoc.attributes
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
playbook.asciidoc.attributes = mergedAttributes;
|
|
61
|
-
|
|
62
|
-
console.log(chalk.green('Merged global attributes into playbook'));
|
|
63
|
-
|
|
64
|
-
} else {
|
|
65
|
-
logger.warn(`Could not fetch global attributes: ${response.statusText}`);
|
|
66
|
-
return null
|
|
67
|
-
}
|
|
68
|
-
} catch(error) {
|
|
69
|
-
if (error.response.url) {
|
|
70
|
-
logger.warn(error.status + ' Could not get ' + error.response.url)
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
logger.warn(error)
|
|
25
|
+
break
|
|
74
26
|
}
|
|
75
27
|
}
|
|
76
|
-
})
|
|
77
|
-
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
logger.error(`Error loading attributes: ${error.message}`);
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
.on('contentClassified', ({ siteCatalog, contentCatalog }) => {
|
|
34
|
+
const components = contentCatalog.getComponents()
|
|
35
|
+
try {
|
|
36
|
+
components.forEach(({asciidoc}) => {
|
|
37
|
+
asciidoc.attributes = _.merge(asciidoc.attributes, siteCatalog.attributeFile);
|
|
38
|
+
});
|
|
39
|
+
console.log(chalk.green('Merged global attributes into each component.'));
|
|
40
|
+
} catch (error) {
|
|
41
|
+
logger.error(`Error merging attributes: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* Example use in the playbook
|
|
2
|
+
* antora:
|
|
3
|
+
extensions:
|
|
4
|
+
* - require: ./extensions/aggregate-terms.js
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports.register = function ({ config }) {
|
|
8
|
+
const logger = this.getLogger('term-aggregation-extension');
|
|
9
|
+
const chalk = require('chalk')
|
|
10
|
+
|
|
11
|
+
this.on('contentAggregated', ({ siteCatalog, contentAggregate }) => {
|
|
12
|
+
try {
|
|
13
|
+
for (const component of contentAggregate) {
|
|
14
|
+
if (component.name === 'shared') {
|
|
15
|
+
const termFiles = component.files.filter(file => file.path.includes('modules/terms/partials/'));
|
|
16
|
+
siteCatalog.terms = {}
|
|
17
|
+
termFiles.forEach(file => {
|
|
18
|
+
const termContent = file.contents.toString('utf8');
|
|
19
|
+
siteCatalog.terms[file.basename] = termContent;
|
|
20
|
+
});
|
|
21
|
+
console.log(chalk.green('Loaded terms from shared component.'));
|
|
22
|
+
break
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
logger.error(`Error loading terms: ${error.message}`);
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
.on('contentClassified', ({ siteCatalog, contentCatalog }) => {
|
|
31
|
+
const components = contentCatalog.getComponents()
|
|
32
|
+
try {
|
|
33
|
+
for (const { versions } of components) {
|
|
34
|
+
for (const { name: component, version, asciidoc, title } of versions) {
|
|
35
|
+
// TODO: will need a better way to filter when we have more content components
|
|
36
|
+
if (component !== 'ROOT') continue;
|
|
37
|
+
const glossaryPage = contentCatalog.resolvePage(`${version?version +'@':''}${component}:reference:glossary.adoc`);
|
|
38
|
+
if (glossaryPage) {
|
|
39
|
+
asciidoc.attributes['glossary-page'] = 'reference:glossary.adoc'
|
|
40
|
+
const glossaryContent = glossaryPage.contents.toString('utf8');
|
|
41
|
+
let newContent = glossaryContent;
|
|
42
|
+
const sortedTerms = Object.keys(siteCatalog.terms).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
43
|
+
for (i = 0; i < sortedTerms.length; i++) {
|
|
44
|
+
const termName = sortedTerms[i];
|
|
45
|
+
const termContent = siteCatalog.terms[termName];
|
|
46
|
+
newContent += '\n\n' + termContent;
|
|
47
|
+
}
|
|
48
|
+
glossaryPage.contents = Buffer.from(newContent, 'utf8');
|
|
49
|
+
|
|
50
|
+
console.log(chalk.green(`Transposed terms into glossary for ${component}.`));
|
|
51
|
+
} else {
|
|
52
|
+
logger.warn(`Skipping ${title} ${version} - No glossary page (reference:glossary.adoc) found`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
logger.error(`Error transposing terms: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -7,6 +7,7 @@ module.exports.register = function ({ config }) {
|
|
|
7
7
|
this.on('documentsConverted', ({playbook, contentCatalog}) => {
|
|
8
8
|
for (const { versions } of contentCatalog.getComponents()) {
|
|
9
9
|
for (const { name: component, version } of versions) {
|
|
10
|
+
// TODO: will need a better way to filter when we have more content components
|
|
10
11
|
if (component !== 'ROOT') continue;
|
|
11
12
|
const attachments = contentCatalog.findBy({ component, version, family });
|
|
12
13
|
for (const attachment of attachments) {
|
package/macros/glossary.js
CHANGED
|
@@ -12,16 +12,47 @@ module.exports.register = function (registry, config = {}) {
|
|
|
12
12
|
function getKey (src) {
|
|
13
13
|
return `${src.version}@${src.component}`
|
|
14
14
|
}
|
|
15
|
-
|
|
16
15
|
const contentCatalog = config.contentCatalog
|
|
17
16
|
if (!contentCatalog[$glossaryContexts]) contentCatalog[$glossaryContexts] = {}
|
|
18
17
|
const glossaryContexts = contentCatalog[$glossaryContexts]
|
|
18
|
+
// Check if the terms have been cached
|
|
19
|
+
const sharedKey = 'sharedTerms'
|
|
20
|
+
if (!glossaryContexts[sharedKey]) {
|
|
21
|
+
// Get the term files from the 'shared' component
|
|
22
|
+
const termFiles = contentCatalog.findBy({ component: 'shared', module: 'terms', family: 'partial' })
|
|
23
|
+
// Extract the term definitions from the files
|
|
24
|
+
const ATTRIBUTE_REGEX = /^:([a-zA-Z0-9_-]+):[ \t]*(.*)$/gm
|
|
25
|
+
|
|
26
|
+
const terms = termFiles.map(file => {
|
|
27
|
+
const content = file.contents.toString()
|
|
28
|
+
const attributes = {}
|
|
29
|
+
|
|
30
|
+
let match
|
|
31
|
+
while ((match = ATTRIBUTE_REGEX.exec(content)) !== null) {
|
|
32
|
+
const [ , name, value ] = match
|
|
33
|
+
attributes[name] = value
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!attributes['term-name'] || !attributes['hover-text']) {
|
|
37
|
+
console.warn(`Skipping file ${file.path} due to missing 'term-name' and/or 'hover-text'.`)
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
term: attributes['term-name'],
|
|
43
|
+
def: attributes['hover-text'],
|
|
44
|
+
content
|
|
45
|
+
}
|
|
46
|
+
}).filter(Boolean)
|
|
47
|
+
|
|
48
|
+
// Store the terms in the cache
|
|
49
|
+
glossaryContexts[sharedKey] = terms
|
|
50
|
+
}
|
|
19
51
|
const key = getKey(config.file.src)
|
|
20
52
|
if (!glossaryContexts[key]) {
|
|
21
53
|
glossaryContexts[key] = {
|
|
22
|
-
gloss: [],
|
|
54
|
+
gloss: glossaryContexts[sharedKey],
|
|
23
55
|
self: undefined,
|
|
24
|
-
dlist: undefined,
|
|
25
56
|
}
|
|
26
57
|
}
|
|
27
58
|
const context = glossaryContexts[key]
|
|
@@ -34,35 +65,7 @@ module.exports.register = function (registry, config = {}) {
|
|
|
34
65
|
const IDRX = /[/ _.-]+/g
|
|
35
66
|
|
|
36
67
|
function termId (term) {
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function dlistItem (context, term, def) {
|
|
41
|
-
const id = termId(term)
|
|
42
|
-
term = `anchor:${id}[${term}]${term}`
|
|
43
|
-
const termItem = context.self.createListItem(context.dlist, term)
|
|
44
|
-
const defItem = context.self.createListItem(context.dlist, def)
|
|
45
|
-
return [[termItem], defItem]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function glossaryBlockMacro () {
|
|
49
|
-
return function () {
|
|
50
|
-
const self = this
|
|
51
|
-
self.named('glossary')
|
|
52
|
-
self.$option('format', 'short') //no target between glossary:: and [params]
|
|
53
|
-
// self.positionalAttributes(['name', 'parameters'])
|
|
54
|
-
self.process(function (parent, target, attributes) {
|
|
55
|
-
const context = vfs.getContext()
|
|
56
|
-
const dlist = self.createList(parent, 'dlist')
|
|
57
|
-
context.self = self
|
|
58
|
-
context.dlist = dlist
|
|
59
|
-
context.gloss
|
|
60
|
-
.forEach(({ term, def }) => {
|
|
61
|
-
dlist.blocks.push(dlistItem(context, term, def))
|
|
62
|
-
})
|
|
63
|
-
return dlist
|
|
64
|
-
})
|
|
65
|
-
}
|
|
68
|
+
return term.toLowerCase().replace(IDRX, '-')
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
const TRX = /(<[a-z]+)([^>]*>.*)/
|
|
@@ -78,23 +81,9 @@ module.exports.register = function (registry, config = {}) {
|
|
|
78
81
|
const term = attributes.term || target
|
|
79
82
|
const document = parent.document
|
|
80
83
|
const context = vfs.getContext()
|
|
81
|
-
// See if a predefined list of terms is available
|
|
82
|
-
const globalTerms = document.getAttribute("terms") || [];
|
|
83
84
|
const localTerms = document.getAttribute("local-terms") || [];
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// Convert globalTerms to a Map for fast look up
|
|
87
|
-
let globalTermsMap = new Map(globalTerms.map(i => [i.term, i]));
|
|
88
|
-
|
|
89
|
-
// Create a new array based on localTerms, but replace items if they exist in globalTerms
|
|
90
|
-
mergedTerms = localTerms.map(item => globalTermsMap.has(item.term) ? globalTermsMap.get(item.term) : item);
|
|
91
|
-
|
|
92
|
-
// Update localTerms with the mergedTerms
|
|
93
|
-
document.setAttribute("terms", mergedTerms);
|
|
94
|
-
console.log(chalk.green('Merged global terms with local terms'))
|
|
95
|
-
}
|
|
96
|
-
const termData = (mergedTerms || []).find((t) => t.term === term) || {};
|
|
97
|
-
const customLink = termData.link;
|
|
85
|
+
const localTermData = (localTerms || []).find((t) => t.term === term) || {};
|
|
86
|
+
const customLink = localTermData.link;
|
|
98
87
|
var tooltip = document.getAttribute('glossary-tooltip')
|
|
99
88
|
if (tooltip === 'true') tooltip = 'data-glossary-tooltip'
|
|
100
89
|
if (tooltip && tooltip !== 'title' && !tooltip.startsWith('data-')) {
|
|
@@ -102,13 +91,17 @@ module.exports.register = function (registry, config = {}) {
|
|
|
102
91
|
tooltip = undefined
|
|
103
92
|
}
|
|
104
93
|
const logTerms = document.hasAttribute('glossary-log-terms')
|
|
105
|
-
var definition
|
|
94
|
+
var definition;
|
|
95
|
+
const index = context.gloss.findIndex((candidate) => candidate.term === term)
|
|
96
|
+
if (index >= 0) {
|
|
97
|
+
definition = context.gloss[index].def
|
|
98
|
+
} else {
|
|
99
|
+
definition = localTermData.definition || attributes.definition;
|
|
100
|
+
}
|
|
106
101
|
if (definition) {
|
|
107
102
|
logTerms && console.log(`${term}:: ${definition}`)
|
|
108
|
-
addItem(context, term, definition)
|
|
109
103
|
} else if (tooltip) {
|
|
110
|
-
|
|
111
|
-
definition = ~index ? context.gloss[index].def : `${term} not yet defined`
|
|
104
|
+
definition = `${term} not yet defined`
|
|
112
105
|
}
|
|
113
106
|
const links = document.getAttribute('glossary-links', 'true') === 'true'
|
|
114
107
|
var glossaryPage = document.getAttribute('glossary-page', '')
|
|
@@ -120,11 +113,15 @@ module.exports.register = function (registry, config = {}) {
|
|
|
120
113
|
}
|
|
121
114
|
const glossaryTermRole = document.getAttribute('glossary-term-role', 'glossary-term')
|
|
122
115
|
const attrs = glossaryTermRole ? { role: glossaryTermRole } : {}
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
var inline;
|
|
117
|
+
const termExistsInContext = context.gloss.some((candidate) => candidate.term === term);
|
|
118
|
+
if (termExistsInContext && links) {
|
|
119
|
+
inline = customLink
|
|
125
120
|
? self.createInline(parent, 'anchor', target, { type: 'link', target: customLink, attributes: attrs })
|
|
126
121
|
: self.createInline(parent, 'anchor', target, { type: 'xref', target: `${glossaryPage}#${termId(term)}`, reftext: target, attributes: attrs })
|
|
127
|
-
|
|
122
|
+
} else {
|
|
123
|
+
inline = self.createInline(parent, 'quoted', target, { attributes: attrs })
|
|
124
|
+
}
|
|
128
125
|
if (tooltip) {
|
|
129
126
|
const a = inline.convert()
|
|
130
127
|
const matches = a.match(TRX)
|
|
@@ -139,27 +136,7 @@ module.exports.register = function (registry, config = {}) {
|
|
|
139
136
|
}
|
|
140
137
|
}
|
|
141
138
|
|
|
142
|
-
function addItem (context, term, def) {
|
|
143
|
-
let i = 0
|
|
144
|
-
let comp = -1
|
|
145
|
-
for (; i < context.gloss.length && ((comp = term.localeCompare(context.gloss[i].term)) > 0); i++) {
|
|
146
|
-
}
|
|
147
|
-
if (comp < 0) {
|
|
148
|
-
context.gloss.splice(i, 0, { term, def })
|
|
149
|
-
if (context.self && context.dlist) {
|
|
150
|
-
context.dlist.blocks.splice(i, 0, dlistItem(context, term, def))
|
|
151
|
-
}
|
|
152
|
-
} else {
|
|
153
|
-
console.log(`duplicate glossary term ${term}`)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
139
|
function doRegister (registry) {
|
|
158
|
-
if (typeof registry.blockMacro === 'function') {
|
|
159
|
-
registry.blockMacro(glossaryBlockMacro())
|
|
160
|
-
} else {
|
|
161
|
-
console.warn('no \'blockMacro\' method on alleged registry')
|
|
162
|
-
}
|
|
163
140
|
if (typeof registry.inlineMacro === 'function') {
|
|
164
141
|
registry.inlineMacro(glossaryInlineMacro())
|
|
165
142
|
} else {
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redpanda-data/docs-extensions-and-macros",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Antora extensions and macros developed for Redpanda documentation.",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"antora",
|
|
7
|
+
"extension",
|
|
8
|
+
"macro",
|
|
9
|
+
"documentation",
|
|
10
|
+
"redpanda"
|
|
11
|
+
],
|
|
6
12
|
"author": {
|
|
7
13
|
"name": "Redpanda Docs Team"
|
|
8
14
|
},
|
|
@@ -12,6 +18,23 @@
|
|
|
12
18
|
"email": "jake@redpanda.com"
|
|
13
19
|
}
|
|
14
20
|
],
|
|
21
|
+
"exports": {
|
|
22
|
+
"./extensions/unlisted-pages": {
|
|
23
|
+
"require": "./extensions/unlisted-pages.js"
|
|
24
|
+
},
|
|
25
|
+
"./extensions/replace-attributes-in-attachments": "./extensions/replace-attributes-in-attachments.js",
|
|
26
|
+
"./extensions/add-global-attributes": "./extensions/add-global-attributes.js",
|
|
27
|
+
"./extensions/version-fetcher/set-latest-version": "./extensions/version-fetcher/set-latest-version.js",
|
|
28
|
+
"./extensions/algolia-indexer/index": "./extensions/algolia-indexer/index.js",
|
|
29
|
+
"./extensions/aggregate-terms": "./extensions/aggregate-terms.js",
|
|
30
|
+
"./macros/glossary": "./macros/glossary.js",
|
|
31
|
+
"./macros/config-ref": "./macros/config-ref.js",
|
|
32
|
+
"./macros/helm-ref": "./macros/helm-ref.js"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"extensions",
|
|
36
|
+
"macros"
|
|
37
|
+
],
|
|
15
38
|
"license": "ISC",
|
|
16
39
|
"repository": {
|
|
17
40
|
"type": "git",
|
|
@@ -23,10 +46,11 @@
|
|
|
23
46
|
"@octokit/rest": "^19.0.7",
|
|
24
47
|
"algoliasearch": "^4.17.0",
|
|
25
48
|
"chalk": "4.1.2",
|
|
26
|
-
"js-yaml": "^4.1.0",
|
|
27
49
|
"gulp": "^4.0.2",
|
|
28
50
|
"gulp-connect": "^5.7.0",
|
|
29
51
|
"html-entities": "2.3",
|
|
52
|
+
"js-yaml": "^4.1.0",
|
|
53
|
+
"lodash": "^4.17.21",
|
|
30
54
|
"node-html-parser": "5.4.2-0"
|
|
31
55
|
}
|
|
32
56
|
}
|