Skip to content

Commit

Permalink
Add an extension to collect Bloblang samples and make them available …
Browse files Browse the repository at this point in the history
…to the UI (#85)

* Add an extension to collect Bloblang samples and make them available to the UI

* Apply suggestions from code review

* Add tests

* Use playground directory
  • Loading branch information
JakeSCahill authored Nov 22, 2024
1 parent 720da55 commit cae7eef
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 3 deletions.
56 changes: 56 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,62 @@ This section documents the Antora extensions provided by this library and how to

IMPORTANT: Ensure you register each extension under the `antora.extensions` key in the playbook, not the `asciidoc.extensions` key.

=== Add Bloblang samples to pages

The `collect-bloblang-samples` extension processes Bloblang examples from YAML files in the `examples` directory of the `redpanda-connect` component. This extension ensures that these examples are accessible as structured data for use in UI components or documentation, such as sample dropdowns in a Bloblang playground.

It validates, sorts, and attaches the processed examples as a JSON object to the Antora page attributes. The extension ensures examples have unique titles, mandatory fields (`input` and `mapping`), and are sorted in alphabetical order.

==== Environment variables

This extension does not require any environment variables.

==== Configuration options

To enable the extension, add it to your Antora playbook under the `antora.extensions` key. No additional configuration is required.

[,yaml]
----
antora:
extensions:
- require: '@redpanda-data/docs-extensions-and-macros/extensions/collect-bloblang-samples'
----

==== Example Bloblang YAML file

The following YAML file is an example of how to define a Bloblang sample:

[,yaml]
----
title: Hello world
input: |
{
"message": "hello world"
}
mapping: |
root.message = this.message.uppercase()
----

==== Sample output

The processed examples are added as JSON to the `page-bloblang-samples` attribute. For example:

[,json]
----
{
"hello-world.yaml": {
"title": "Hello world",
"input": "{\n \"message\": \"hello world\"\n}\n",
"mapping": "root.message = this.message.uppercase()\n"
},
"array-processing.yaml": {
"title": "Array processing",
"input": "{\n \"numbers\": [1, 2, 3, 4, 5]\n}\n",
"mapping": "root.even_numbers = this.numbers.filter(n -> n % 2 == 0)"
}
}
----

=== Add pages to root

The `add-pages-to-root` extension allows you to copy files from your Antora content catalog to the root of the site during the build process. This is particularly useful for files like `llms.txt` or any custom files that need to be directly accessible at the site's root level.
Expand Down
78 changes: 78 additions & 0 deletions extensions/collect-bloblang-samples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const yaml = require('js-yaml');

module.exports.register = function () {
const logger = this.getLogger('collect-bloblang-samples');

this.on('contentClassified', ({ contentCatalog }) => {
const collectExamples = (examples, componentName) => {
const bloblangSamples = [];
const seenTitles = new Set();

examples
.filter((example) => example.src.relative.startsWith('playground/')) // Only include files in the 'bloblang' subdirectory
.forEach((example) => {
try {
const content = example.contents.toString('utf8');
const parsedContent = yaml.load(content);

if (!parsedContent.title) {
logger.warn(`Skipping example '${example.src.basename}' in '${componentName}': Missing title.`);
return;
}

if (seenTitles.has(parsedContent.title)) {
logger.warn(
`Duplicate title found: '${parsedContent.title}' in '${example.src.basename}' (${componentName}). Skipping.`
);
return;
}

if (!parsedContent.input || !parsedContent.mapping) {
logger.warn(
`Skipping example '${example.src.basename}' in '${componentName}': Missing input or mapping.`
);
return;
}

logger.info(`Loaded example: ${example.src.basename} with title: '${parsedContent.title}'`);
seenTitles.add(parsedContent.title);

bloblangSamples.push({ filename: example.src.basename, ...parsedContent });
} catch (error) {
logger.error(`Error processing example '${example.src.basename}' in '${componentName}':`, error);
}
});

bloblangSamples.sort((a, b) => a.title.localeCompare(b.title));

return bloblangSamples.reduce((acc, sample) => {
acc[sample.filename] = sample;
return acc;
}, {});
};

// Fetch examples from both components
const examples = contentCatalog.findBy({ component: 'redpanda-connect', family: 'example' });
const previewExamples = contentCatalog.findBy({ component: 'preview', family: 'example' });

if (!examples.length) logger.warn(`No examples found in the 'redpanda-connect' component.`);

// Get components
const connect = contentCatalog.getComponents().find((c) => c.name === 'redpanda-connect');
const preview = contentCatalog.getComponents().find((c) => c.name === 'preview');

if (connect) {
const connectSamples = collectExamples(examples, 'redpanda-connect');
connect.latest.asciidoc.attributes['page-bloblang-samples'] = JSON.stringify(connectSamples);
logger.debug(`Bloblang samples added to 'redpanda-connect': ${JSON.stringify(connectSamples, null, 2)}`);
} else {
logger.warn(`Component 'redpanda-connect' not found.`);
}

if (preview) {
const previewSamples = collectExamples(previewExamples, 'preview');
preview.latest.asciidoc.attributes['page-bloblang-samples'] = JSON.stringify(previewSamples);
logger.debug(`Bloblang samples added to 'preview': ${JSON.stringify(previewSamples, null, 2)}`);
}
});
};
1 change: 1 addition & 0 deletions local-antora-playbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ antora:
- './extensions/algolia-indexer/index'
- require: './extensions/generate-rp-connect-categories'
- require: './extensions/generate-rp-connect-info'
- require: './extensions/collect-bloblang-samples'
- require: './extensions/add-pages-to-root'
- require: './extensions/unlisted-pages'
- require: './extensions/replace-attributes-in-attachments'
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@redpanda-data/docs-extensions-and-macros",
"version": "3.9.1",
"version": "3.10.0",
"description": "Antora extensions and macros developed for Redpanda documentation.",
"keywords": [
"antora",
Expand Down Expand Up @@ -31,6 +31,7 @@
},
"./extensions/replace-attributes-in-attachments": "./extensions/replace-attributes-in-attachments.js",
"./extensions/add-pages-to-root": "./extensions/add-pages-to-root.js",
"./extensions/collect-bloblang-samples": "./extensions/collect-bloblang-samples.js",
"./extensions/generate-rp-connect-categories": "./extensions/generate-rp-connect-categories.js",
"./extensions/generate-rp-connect-info": "./extensions/generate-rp-connect-info.js",
"./extensions/add-global-attributes": "./extensions/add-global-attributes.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title: Hello world
input: |
{
"message": "hello world"
}
mapping: |
root.message = this.message.uppercase()
7 changes: 7 additions & 0 deletions preview/extensions-and-macros/modules/ROOT/pages/test.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ By default, Antora does not replace attributes in attachment files. Download thi

xref:preview:ROOT:attachment$test.yaml[Download attachment]

== Bloblang samples

[,json,subs="attributes+"]
----
{page-bloblang-samples}
----

== Code highlights

[source,js,lines=1-3+5+6]
Expand Down

0 comments on commit cae7eef

Please sign in to comment.