@redpanda-data/docs-extensions-and-macros 3.0.12 → 3.0.14

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
@@ -40,7 +40,7 @@ npm i @redpanda-data/docs-extensions-and-macros
40
40
 
41
41
  To use the development version instead, refer to the <<development-quickstart,Development Quickstart>>.
42
42
 
43
- == Extensions
43
+ == Antora Extensions
44
44
 
45
45
  This section documents the Antora extensions that are provided by this library and how to configure them.
46
46
 
@@ -170,6 +170,24 @@ antora:
170
170
  unlistedPagesHeading: 'Additional Resources'
171
171
  ```
172
172
 
173
+ == Asciidoc Extensions
174
+
175
+ This section documents the Asciidoc extensions that are provided by this library and how to configure them.
176
+
177
+ IMPORTANT: Be sure to register each extension under the `asciidoc.extensions` key in the playbook, not the `antora.extensions` key.
178
+
179
+ === Add line numbers and highlights
180
+
181
+ This extension adds the necessary classes to make line numbers and line highlighting work with Prism.js.
182
+
183
+ ==== Registration example
184
+
185
+ ```yaml
186
+ antora:
187
+ extensions:
188
+ - '@redpanda-data/docs-extensions-and-macros/asciidoc-extensions/add-line-numbers-highlights'
189
+ ```
190
+
173
191
  == Macros
174
192
 
175
193
  This section documents the Asciidoc macros that are provided by this library and how to configure them.
@@ -0,0 +1,30 @@
1
+ function addLineNumbersAndCodeHighlightingAttributes() {
2
+ this.process((doc) => {
3
+ for (const listingBlock of doc.findBy({ context: 'listing' })) {
4
+ const attributes = listingBlock.getAttributes();
5
+
6
+ // Iterate through all attributes of the listing block
7
+ for (let key in attributes) {
8
+ if (key.startsWith('lines')) {
9
+ let newRoleValue = `${key}-${attributes[key]}`;
10
+
11
+ if (attributes.role) {
12
+ if (!attributes.role.includes('line-numbers')) {
13
+ newRoleValue += ' line-numbers';
14
+ }
15
+ listingBlock.setAttribute('role', attributes.role + ' ' + newRoleValue);
16
+ } else {
17
+ newRoleValue += ' line-numbers';
18
+ listingBlock.setAttribute('role', newRoleValue);
19
+ }
20
+ }
21
+ }
22
+ }
23
+ });
24
+ }
25
+
26
+ function register(registry, { file }) {
27
+ registry.treeProcessor(addLineNumbersAndCodeHighlightingAttributes)
28
+ }
29
+
30
+ module.exports.register = register;
@@ -59,7 +59,7 @@ function generateIndex (playbook, contentCatalog, { indexLatestOnly = false, exc
59
59
  }
60
60
  )
61
61
 
62
- // skip pages marked as "noindex" for "robots"
62
+ // Skip pages marked as "noindex" for "robots"
63
63
  const noindex = root.querySelector('meta[name=robots][content=noindex]')
64
64
  if (noindex) {
65
65
  continue
@@ -104,7 +104,7 @@ function generateIndex (playbook, contentCatalog, { indexLatestOnly = false, exc
104
104
  // Start handling the article content
105
105
  const article = root.querySelector('article.doc')
106
106
  if (!article) {
107
- logger.warn(`Page is not an article...skipping ${page.pub.url}`)
107
+ logger.info(`Page is not an article...skipping ${page.pub.url}`)
108
108
  continue
109
109
  }
110
110
 
@@ -1,17 +1,18 @@
1
1
  'use strict'
2
2
 
3
- const generateIndex = require('./generate-index')
4
- const chalk = require('chalk')
5
- const algoliasearch = require('algoliasearch');
6
- const fs = require('fs');
7
- const path = require('path');
3
+ const generateIndex = require('./generate-index')
4
+ const chalk = require('chalk')
5
+ const algoliasearch = require('algoliasearch')
6
+ const fs = require('fs')
7
+ const path = require('path')
8
+ const _ = require('lodash')
8
9
 
9
10
  /**
10
11
  * Algolia indexing for an Antora documentation site.
11
12
  *
12
13
  * @module antora-algolia-indexer
13
14
  */
14
- function register ({
15
+ function register({
15
16
  config: {
16
17
  indexLatestOnly,
17
18
  excludes,
@@ -22,65 +23,116 @@ function register ({
22
23
 
23
24
  if (!process.env.ALGOLIA_ADMIN_API_KEY || !process.env.ALGOLIA_APP_ID || !process.env.ALGOLIA_INDEX_NAME) return
24
25
 
25
- var client;
26
- var index;
26
+ var client
27
+ var index
27
28
 
28
29
  // Connect and authenticate with Algolia
29
- client = algoliasearch(process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_ADMIN_API_KEY);
30
-
31
- // Create a new index and add a record
32
- index = client.initIndex(process.env.ALGOLIA_INDEX_NAME);
30
+ client = algoliasearch(process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_ADMIN_API_KEY)
31
+ index = client.initIndex(process.env.ALGOLIA_INDEX_NAME)
33
32
 
34
33
  if (Object.keys(unknownOptions).length) {
35
34
  const keys = Object.keys(unknownOptions)
36
35
  throw new Error(`Unrecognized option${keys.length > 1 ? 's' : ''} specified: ${keys.join(', ')}`)
37
36
  }
38
37
 
39
- this.on('beforePublish', ({ playbook, siteCatalog, contentCatalog }) => {
38
+ this.on('beforePublish', async ({ playbook, siteCatalog, contentCatalog }) => {
40
39
  const algolia = generateIndex(playbook, contentCatalog, { indexLatestOnly, excludes, logger })
41
- // write the Algolia indexes
42
- var algoliaCount = 0
43
- Object.keys(algolia).forEach((c) => {
44
- Object.keys(algolia[c]).forEach((v) => {
45
- algoliaCount += algolia[c][v].length
46
- // Save all records to the index
47
- index.saveObjects(algolia[c][v]).then(() => {
48
- console.log(`Indexed ${c} version ${v}`)
49
- }).catch(error => {
50
- console.error(`Error saving objects to Algolia: ${error}`);
51
- });
40
+ let existingObjectsMap = new Map()
41
+
42
+ // Save objects in a local cache to query later.
43
+ // Avoids sending multiple requests.
44
+ // browseObjects does not affect analytics or usage limits.
45
+ // See https://www.algolia.com/doc/api-reference/api-methods/browse/#about-this-method
46
+ try {
47
+ await index.browseObjects({
48
+ query: '',
49
+ batch: batch => {
50
+ for (const obj of batch) {
51
+ existingObjectsMap.set(obj.objectID, obj)
52
+ }
53
+ }
54
+ })
55
+ } catch (err) {
56
+ logger.error(JSON.stringify(err))
57
+ }
58
+
59
+ let totalObjectsToUpdate = 0
60
+ let totalObjectsToAdd = 0
61
+
62
+ for (const c of Object.keys(algolia)) {
63
+ for (const v of Object.keys(algolia[c])) {
64
+ const objectsToUpdate = []
65
+ const objectsToAdd = []
66
+
67
+ for (const obj of algolia[c][v]) {
68
+ const existingObject = existingObjectsMap.get(obj.objectID)
69
+
70
+ if (existingObject) {
71
+ if (!_.isEqual(existingObject, obj)) {
72
+ objectsToUpdate.push(obj)
73
+ totalObjectsToUpdate++
74
+ }
75
+ } else {
76
+ objectsToAdd.push(obj)
77
+ totalObjectsToAdd++
78
+ }
79
+ }
80
+
81
+ // Upload new records only if the objects have been updated or they are new.
82
+ // See https://www.algolia.com/doc/api-reference/api-methods/save-objects/
83
+ if (objectsToUpdate.length) {
84
+ index.saveObjects(objectsToUpdate)
85
+ .then(() => {
86
+ logger.info(`Updated records for ${c} version ${v}`)
87
+ })
88
+ .catch(error => {
89
+ logger.error(`Error updating objects to Algolia: ${error.message}`)
90
+ })
91
+ }
92
+ if (objectsToAdd.length) {
93
+ index.saveObjects(objectsToAdd)
94
+ .then(() => {
95
+ logger.info(`Added records for ${c} version ${v}`)
96
+ })
97
+ .catch(error => {
98
+ logger.error(`Error adding objects to Algolia: ${error.message}`)
99
+ })
100
+ }
101
+
52
102
  siteCatalog.addFile({
53
103
  mediaType: 'application/json',
54
- contents: Buffer.from(
55
- JSON.stringify(algolia[c][v])
56
- ),
104
+ contents: Buffer.from(JSON.stringify(algolia[c][v])),
57
105
  src: { stem: `algolia-${c}` },
58
106
  out: { path: `algolia-${c}-${v}.json` },
59
- pub: { url: `/algolia-${c}-${v}.json`, rootPath: '' },
107
+ pub: { url: `/algolia-${c}-${v}.json`, rootPath: '' }
60
108
  })
61
- })
62
- })
109
+ }
110
+ }
111
+
63
112
  index.setSettings({
64
- attributesForFaceting: [
65
- 'version',
66
- 'product'
67
- ]
113
+ attributesForFaceting: ['version', 'product']
68
114
  })
69
- // Get and print the count of all records in the index
70
- let recordCount = 0;
71
- index
72
- .browseObjects({
73
- query: '', // for all records
115
+
116
+ console.log(chalk.green('Updated records:' + totalObjectsToUpdate))
117
+ console.log(chalk.green('New records:' + totalObjectsToAdd))
118
+
119
+ totalObjectsToAdd === 0 && totalObjectsToUpdate === 0 && console.log(chalk.green('No changes made'))
120
+
121
+ try {
122
+ let recordCount = 0
123
+
124
+ await index.browseObjects({
125
+ query: '',
74
126
  batch: batch => {
75
- recordCount += batch.length;
127
+ recordCount += batch.length
76
128
  }
77
129
  })
78
- .then(() => {
79
- console.log('Total Records:', recordCount);
80
- })
81
- .catch(err => console.log(JSON.stringify(err)));
130
+
131
+ console.log(chalk.green('Total records:', recordCount))
132
+ } catch (err) {
133
+ logger.error(JSON.stringify(err))
134
+ }
82
135
  })
83
136
  }
84
137
 
85
138
  module.exports = { generateIndex, register }
86
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redpanda-data/docs-extensions-and-macros",
3
- "version": "3.0.12",
3
+ "version": "3.0.14",
4
4
  "description": "Antora extensions and macros developed for Redpanda documentation.",
5
5
  "keywords": [
6
6
  "antora",
@@ -23,6 +23,9 @@
23
23
  }
24
24
  ],
25
25
  "exports": {
26
+ "./asciidoc-extensions/add-line-numbers-highlights": {
27
+ "require": "./asciidoc-extensions/add-line-numbers-highlights.js"
28
+ },
26
29
  "./extensions/unlisted-pages": {
27
30
  "require": "./extensions/unlisted-pages.js"
28
31
  },
@@ -37,6 +40,7 @@
37
40
  },
38
41
  "files": [
39
42
  "extensions",
43
+ "asciidoc-extensions",
40
44
  "macros"
41
45
  ],
42
46
  "license": "ISC",