@redpanda-data/docs-extensions-and-macros 4.2.5 → 4.3.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 +184 -21
- package/macros/data-template.js +591 -0
- package/package.json +8 -3
package/README.adoc
CHANGED
|
@@ -123,7 +123,7 @@ antora:
|
|
|
123
123
|
- home:ROOT:attachment$custom-file.txt
|
|
124
124
|
----
|
|
125
125
|
|
|
126
|
-
==== Registration
|
|
126
|
+
==== Registration
|
|
127
127
|
|
|
128
128
|
[source,yaml]
|
|
129
129
|
----
|
|
@@ -155,7 +155,7 @@ Any elements, classes, or IDs that you want to exclude from the index.
|
|
|
155
155
|
index-latest-only (optional)::
|
|
156
156
|
Whether to index all versions or just the latest version of a component.
|
|
157
157
|
|
|
158
|
-
==== Registration
|
|
158
|
+
==== Registration
|
|
159
159
|
|
|
160
160
|
```yaml
|
|
161
161
|
antora:
|
|
@@ -246,7 +246,7 @@ This extension does not require any environment variables.
|
|
|
246
246
|
|
|
247
247
|
There are no configurable options for this extension.
|
|
248
248
|
|
|
249
|
-
==== Registration
|
|
249
|
+
==== Registration
|
|
250
250
|
|
|
251
251
|
```yaml
|
|
252
252
|
antora:
|
|
@@ -297,7 +297,7 @@ antora:
|
|
|
297
297
|
upgrade_doc: ROOT:upgrade:index.adoc
|
|
298
298
|
----
|
|
299
299
|
|
|
300
|
-
==== Registration
|
|
300
|
+
==== Registration
|
|
301
301
|
|
|
302
302
|
You can register the extension with a customized configuration for different components in your playbook:
|
|
303
303
|
|
|
@@ -456,7 +456,7 @@ NOTE: If you don't set the environment variable, the latest version of Redpanda
|
|
|
456
456
|
|
|
457
457
|
There are no configurable options for this extension.
|
|
458
458
|
|
|
459
|
-
==== Registration
|
|
459
|
+
==== Registration
|
|
460
460
|
|
|
461
461
|
```yaml
|
|
462
462
|
antora:
|
|
@@ -488,7 +488,7 @@ The following attributes are available to the latest version of the `ROOT` compo
|
|
|
488
488
|
|
|
489
489
|
NOTE: If you don't set the environment variable, the latest versions may not be fetched. 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.
|
|
490
490
|
|
|
491
|
-
==== Registration
|
|
491
|
+
==== Registration
|
|
492
492
|
|
|
493
493
|
```yaml
|
|
494
494
|
antora:
|
|
@@ -508,7 +508,7 @@ This extension does not require any environment variables.
|
|
|
508
508
|
|
|
509
509
|
There are no configurable options for this extension. It operates based on site attributes defined in `add-global-attributes.js` to determine valid categories and subcategories.
|
|
510
510
|
|
|
511
|
-
==== Registration
|
|
511
|
+
==== Registration
|
|
512
512
|
|
|
513
513
|
Register the `validate-attributes` extension in the Antora playbook under the `antora.extensions` key like so:
|
|
514
514
|
|
|
@@ -531,7 +531,7 @@ This extension operates without requiring any specific environment variables.
|
|
|
531
531
|
|
|
532
532
|
This extension does not offer configurable options. It uses the inherent attributes of pages to determine relationships based on `page-categories` and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).
|
|
533
533
|
|
|
534
|
-
==== Registration
|
|
534
|
+
==== Registration
|
|
535
535
|
|
|
536
536
|
To integrate the `related-docs-extension` into your Antora playbook, add it under the `antora.extensions` key as demonstrated below:
|
|
537
537
|
|
|
@@ -554,7 +554,7 @@ This extension does not require any environment variables.
|
|
|
554
554
|
|
|
555
555
|
The extension operates without explicit configuration options. It automatically processes documentation pages to identify and link related labs based on shared `page-categories` attributes and deployment types (`env-kubernetes`, `env-linux`, `env-docker`, `page-cloud`).
|
|
556
556
|
|
|
557
|
-
==== Registration
|
|
557
|
+
==== Registration
|
|
558
558
|
|
|
559
559
|
Include the `related-labs-extension` in the Antora playbook under the `antora.extensions` key as follows:
|
|
560
560
|
|
|
@@ -579,7 +579,7 @@ The extension accepts the following configuration options:
|
|
|
579
579
|
|
|
580
580
|
attributespath (optional):: Specifies the path to a local YAML file that contains global attributes. If this is provided, the extension will load attributes from this file first. If this path is not provided or no valid attributes are found in the file, the extension will fall back to loading attributes from the `shared` component.
|
|
581
581
|
|
|
582
|
-
==== Registration
|
|
582
|
+
==== Registration
|
|
583
583
|
|
|
584
584
|
```yml
|
|
585
585
|
antora:
|
|
@@ -602,7 +602,7 @@ This extension does not require any environment variables.
|
|
|
602
602
|
|
|
603
603
|
There are no configurable options for this extension.
|
|
604
604
|
|
|
605
|
-
==== Registration
|
|
605
|
+
==== Registration
|
|
606
606
|
|
|
607
607
|
```yaml
|
|
608
608
|
antora:
|
|
@@ -640,7 +640,7 @@ data.replacements (required):: An array of replacement configurations. Each conf
|
|
|
640
640
|
|
|
641
641
|
NOTE: Ensure that `file_patterns` accurately reflect the paths of the attachments you want to process. Overly broad patterns may include unintended files, while overly restrictive patterns might exclude necessary resources.
|
|
642
642
|
|
|
643
|
-
==== Registration
|
|
643
|
+
==== Registration
|
|
644
644
|
|
|
645
645
|
This is an example of how to register and configure the `replace-attributes-in-attachments` extension in your Antora playbook. This example demonstrates defining multiple replacement configurations, each targeting different components and specifying their own file patterns and custom replacements.
|
|
646
646
|
|
|
@@ -698,7 +698,7 @@ Term files should follow the following structure:
|
|
|
698
698
|
This is the detailed description of the term.
|
|
699
699
|
```
|
|
700
700
|
|
|
701
|
-
==== Registration
|
|
701
|
+
==== Registration
|
|
702
702
|
|
|
703
703
|
```yml
|
|
704
704
|
antora:
|
|
@@ -729,7 +729,7 @@ Whether to add unlisted pages to the navigation. The default is `false` (unliste
|
|
|
729
729
|
unlistedPagesHeading (optional)::
|
|
730
730
|
The heading under which to list the unlisted pages in the navigation. The default is 'Unlisted Pages'.
|
|
731
731
|
|
|
732
|
-
==== Registration
|
|
732
|
+
==== Registration
|
|
733
733
|
|
|
734
734
|
```yaml
|
|
735
735
|
antora:
|
|
@@ -749,7 +749,7 @@ IMPORTANT: Be sure to register each extension under the `asciidoc.extensions` ke
|
|
|
749
749
|
|
|
750
750
|
This extension adds the necessary classes to make line numbers and line highlighting work with Prism.js.
|
|
751
751
|
|
|
752
|
-
==== Registration
|
|
752
|
+
==== Registration
|
|
753
753
|
|
|
754
754
|
```yaml
|
|
755
755
|
antora:
|
|
@@ -763,6 +763,108 @@ This section documents the Asciidoc macros that are provided by this library and
|
|
|
763
763
|
|
|
764
764
|
IMPORTANT: Be sure to register each extension under the `asciidoc.extensions` key in the playbook, not the `antora.extensions` key.
|
|
765
765
|
|
|
766
|
+
=== data_template
|
|
767
|
+
|
|
768
|
+
The `data_template` block processor lets you render dynamic AsciiDoc content from external or local data sources (JSON, YAML, or plain text) using Handlebars templates.
|
|
769
|
+
|
|
770
|
+
This is useful for generating documentation from structured data like config fields, component metadata, or examples.
|
|
771
|
+
|
|
772
|
+
=== Usage
|
|
773
|
+
|
|
774
|
+
You can use the `data_template` block macro to dynamically generate AsciiDoc content from structured data files such as JSON or YAML. The macro uses a Handlebars template to render the data.
|
|
775
|
+
|
|
776
|
+
[source,asciidoc]
|
|
777
|
+
----
|
|
778
|
+
[data_template, ROOT:example$connect.json]
|
|
779
|
+
--
|
|
780
|
+
== Component: {{{name}}}
|
|
781
|
+
|
|
782
|
+
Summary: {{{summary}}}
|
|
783
|
+
|
|
784
|
+
{{#each fields}}
|
|
785
|
+
=== {{name}}
|
|
786
|
+
|
|
787
|
+
*Type*: `{{type}}`
|
|
788
|
+
|
|
789
|
+
{{{description}}}
|
|
790
|
+
{{/each}}
|
|
791
|
+
--
|
|
792
|
+
----
|
|
793
|
+
|
|
794
|
+
The block content is a Handlebars template. Fields from the data file are injected into this template during site build.
|
|
795
|
+
|
|
796
|
+
The macro accepts one or two positional attributes:
|
|
797
|
+
|
|
798
|
+
1. The first attribute (`dataPath`) is required and should be the resource ID of the data file.
|
|
799
|
+
2. The second attribute (`overrides`) is optional and allows you to override or merge values from a secondary file.
|
|
800
|
+
|
|
801
|
+
You can apply overrides by specifying a second file:
|
|
802
|
+
|
|
803
|
+
[source,asciidoc]
|
|
804
|
+
----
|
|
805
|
+
[data_template, ROOT:example$connect.json, ROOT:example$overrides.json]
|
|
806
|
+
--
|
|
807
|
+
...template content...
|
|
808
|
+
--
|
|
809
|
+
----
|
|
810
|
+
|
|
811
|
+
In this case:
|
|
812
|
+
|
|
813
|
+
- The macro first loads and parses `connect.json`.
|
|
814
|
+
- Then it loads `overrides.json` and **merges** its values into the base file.
|
|
815
|
+
- Arrays of objects (such as fields or processors) are merged by matching objects with the same `name` key.
|
|
816
|
+
- The result is passed into the Handlebars template.
|
|
817
|
+
|
|
818
|
+
This is useful for tweaking content (like updating a `description`) without modifying the original source file.
|
|
819
|
+
|
|
820
|
+
==== Triple mustaches
|
|
821
|
+
|
|
822
|
+
When your data contains AsciiDoc markup (like lists, admonitions, or headings), use triple curly braces:
|
|
823
|
+
|
|
824
|
+
[source,handlebars]
|
|
825
|
+
----
|
|
826
|
+
{{{description}}}
|
|
827
|
+
----
|
|
828
|
+
|
|
829
|
+
This tells Handlebars to not escape the content, so Asciidoctor can render it correctly.
|
|
830
|
+
|
|
831
|
+
==== Handlebars helpers
|
|
832
|
+
|
|
833
|
+
The following helpers are available inside templates:
|
|
834
|
+
|
|
835
|
+
* `eq`, `ne` — Equality helpers.
|
|
836
|
+
* `uppercase` — Converts text to uppercase.
|
|
837
|
+
* `renderConnectFields` — Renders config fields for Redpanda Connect.
|
|
838
|
+
* `renderConnectExamples` — Renders usage examples.
|
|
839
|
+
* `selectByJsonPath` — Selects items from the data using a JSONPath expression.
|
|
840
|
+
|
|
841
|
+
==== Registration
|
|
842
|
+
|
|
843
|
+
To use this macro, register it in your Antora playbook:
|
|
844
|
+
|
|
845
|
+
[source,yaml]
|
|
846
|
+
----
|
|
847
|
+
asciidoc:
|
|
848
|
+
extensions:
|
|
849
|
+
- '@redpanda-data/docs-extensions-and-macros/macros/data-template'
|
|
850
|
+
----
|
|
851
|
+
|
|
852
|
+
==== Example
|
|
853
|
+
|
|
854
|
+
You can use the `selectByJsonPath` helper to filter data. For example, if you want to render only the `redis` processor's fields from a JSON file, you can do it like this:
|
|
855
|
+
|
|
856
|
+
[source,asciidoc]
|
|
857
|
+
----
|
|
858
|
+
[data_template, redpanda-connect:ROOT:example$connect.json]
|
|
859
|
+
--
|
|
860
|
+
{{#selectByJsonPath this "$.processors[?(@.name=='redis')]" }}
|
|
861
|
+
{{renderConnectFields this.config.children}}
|
|
862
|
+
{{/selectByJsonPath}}
|
|
863
|
+
--
|
|
864
|
+
----
|
|
865
|
+
|
|
866
|
+
This will render only the fields for the `redis` processor.
|
|
867
|
+
|
|
766
868
|
=== config_ref
|
|
767
869
|
|
|
768
870
|
This inline macro is used to generate a reference to a configuration value in the Redpanda documentation. The macro's parameters allow for control over the generated reference's format and the type of output produced.
|
|
@@ -798,7 +900,7 @@ For example:
|
|
|
798
900
|
config_ref:example_config,true,tunable-properties[]
|
|
799
901
|
----
|
|
800
902
|
|
|
801
|
-
==== Registration
|
|
903
|
+
==== Registration
|
|
802
904
|
|
|
803
905
|
[,yaml]
|
|
804
906
|
----
|
|
@@ -807,6 +909,67 @@ asciidoc:
|
|
|
807
909
|
- '@redpanda-data/docs-extensions-and-macros/macros/config-ref'
|
|
808
910
|
----
|
|
809
911
|
|
|
912
|
+
=== data_template
|
|
913
|
+
|
|
914
|
+
The `data_template` macro provides a way to dynamically generate AsciiDoc content by combining external or local data sources with Handlebars templates. When you use the `data_template` block macro, the extension performs the following steps:
|
|
915
|
+
|
|
916
|
+
* Resolves the `dataPath` attribute to locate a data file (in JSON, YAML, or raw text format).
|
|
917
|
+
* Fetches and caches external resources or reads local files from the Antora content catalog.
|
|
918
|
+
* Parses the data file.
|
|
919
|
+
* Compiles the block's content as a Handlebars template, injecting the parsed data.
|
|
920
|
+
* Processes the resulting text as AsciiDoc using Asciidoctor to generate the final HTML output.
|
|
921
|
+
|
|
922
|
+
By default, Handlebars escapes HTML to prevent potential security issues. However, if your data includes AsciiDoc markup (such as headings, lists, or formatting directives), escaping it will prevent Asciidoctor from converting the markup correctly.
|
|
923
|
+
|
|
924
|
+
To ensure that your AsciiDoc syntax is preserved during template rendering, **use the triple curly braces syntax** in your Handlebars templates. For example, if your JSON file contains a `description` field with AsciiDoc content, reference it like this:
|
|
925
|
+
|
|
926
|
+
[source,handlebars]
|
|
927
|
+
----
|
|
928
|
+
{{{description}}}
|
|
929
|
+
----
|
|
930
|
+
|
|
931
|
+
This tells Handlebars to output the content unescaped, allowing Asciidoctor to process the raw AsciiDoc markup correctly.
|
|
932
|
+
|
|
933
|
+
==== Usage
|
|
934
|
+
|
|
935
|
+
In an AsciiDoc document, you can invoke the data template macro as follows:
|
|
936
|
+
|
|
937
|
+
[,asciidoc]
|
|
938
|
+
----
|
|
939
|
+
[data_template, ROOT:example$connect.json]
|
|
940
|
+
--
|
|
941
|
+
Version: {{{version}}}
|
|
942
|
+
|
|
943
|
+
{{#each buffers}}
|
|
944
|
+
|
|
945
|
+
=== {{{this.name}}}
|
|
946
|
+
|
|
947
|
+
Status: {{{this.status}}}
|
|
948
|
+
|
|
949
|
+
{{#if (eq this.name 'memory')}}
|
|
950
|
+
This is a custom description for the memory buffer.
|
|
951
|
+
{{else}}
|
|
952
|
+
{{{this.summary}}}
|
|
953
|
+
{{/if}}
|
|
954
|
+
|
|
955
|
+
{{/each}}
|
|
956
|
+
|
|
957
|
+
--
|
|
958
|
+
----
|
|
959
|
+
|
|
960
|
+
==== Registration
|
|
961
|
+
|
|
962
|
+
Register the macro in your Antora playbook under the `asciidoc.extensions` key:
|
|
963
|
+
|
|
964
|
+
[source,yaml]
|
|
965
|
+
----
|
|
966
|
+
asciidoc:
|
|
967
|
+
extensions:
|
|
968
|
+
- require: '@redpanda-data/docs-extensions-and-macros/macros/data-template'
|
|
969
|
+
----
|
|
970
|
+
|
|
971
|
+
This configuration ensures that during the build process, the data template macro is executed to fetch, parse, and render data as part of your docs.
|
|
972
|
+
|
|
810
973
|
=== glossterm
|
|
811
974
|
|
|
812
975
|
The `glossterm` inline macro provides a way to define and reference glossary terms in your AsciiDoc documents.
|
|
@@ -855,7 +1018,7 @@ Whether to enable tooltips for the defined terms. Valid values are:
|
|
|
855
1018
|
|
|
856
1019
|
The last two options are intended to support js/css tooltip solutions such as tippy.js.
|
|
857
1020
|
|
|
858
|
-
==== Registration
|
|
1021
|
+
==== Registration
|
|
859
1022
|
|
|
860
1023
|
[,yaml]
|
|
861
1024
|
----
|
|
@@ -897,7 +1060,7 @@ For default values and documentation for configuration options, see the https://
|
|
|
897
1060
|
|
|
898
1061
|
If you do not specify a Helm reference value, the macro generates a link without specifying a path.
|
|
899
1062
|
|
|
900
|
-
==== Registration
|
|
1063
|
+
==== Registration
|
|
901
1064
|
|
|
902
1065
|
[,yaml]
|
|
903
1066
|
----
|
|
@@ -918,7 +1081,7 @@ The categories are fetched from the `connectCategoriesData` that's generated in
|
|
|
918
1081
|
components_by_category::[<type>]
|
|
919
1082
|
```
|
|
920
1083
|
|
|
921
|
-
==== Registration
|
|
1084
|
+
==== Registration
|
|
922
1085
|
|
|
923
1086
|
```yaml
|
|
924
1087
|
asciidoc:
|
|
@@ -938,7 +1101,7 @@ The types are fetched from the `flatComponentsData` that's generated in the <<Co
|
|
|
938
1101
|
component_table::[]
|
|
939
1102
|
```
|
|
940
1103
|
|
|
941
|
-
==== Registration
|
|
1104
|
+
==== Registration
|
|
942
1105
|
|
|
943
1106
|
```yaml
|
|
944
1107
|
asciidoc:
|
|
@@ -958,7 +1121,7 @@ The types are fetched from the `flatComponentsData` that's generated in the <<Co
|
|
|
958
1121
|
component_type_dropdown::[]
|
|
959
1122
|
```
|
|
960
1123
|
|
|
961
|
-
==== Registration
|
|
1124
|
+
==== Registration
|
|
962
1125
|
|
|
963
1126
|
```yaml
|
|
964
1127
|
asciidoc:
|
|
@@ -0,0 +1,591 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* data_template macro for Asciidoctor.js
|
|
5
|
+
*
|
|
6
|
+
* This module defines a [data_template] block macro that leverages Handlebars templates to allow us to reference data in JSON or YAML files directly inside Asciidoc pages.
|
|
7
|
+
* It processes external or local data sources (in JSON, YAML, or raw text), compiles a Handlebars template
|
|
8
|
+
* provided within the block, and then parses the resulting content as AsciiDoc using Asciidoctor.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// This global Opal object is available because Antora uses Asciidoctor.js (compiled using Opal) to convert AsciiDoc into HTML.
|
|
12
|
+
const loggerLib = require('@antora/logger');
|
|
13
|
+
loggerLib.configure({
|
|
14
|
+
format: 'pretty',
|
|
15
|
+
level: 'error'
|
|
16
|
+
});
|
|
17
|
+
const path = require('path').posix;
|
|
18
|
+
const logger = loggerLib.getLogger('data-template');
|
|
19
|
+
const handlebars = require('handlebars');
|
|
20
|
+
const loadAsciiDoc = require('@antora/asciidoc-loader')
|
|
21
|
+
const jsonpath = require('jsonpath-plus');
|
|
22
|
+
const yaml = require('yaml');
|
|
23
|
+
// For synchronous HTTP fetching.
|
|
24
|
+
const request = require('sync-request');
|
|
25
|
+
const computeOut = require('../util/compute-out.js');
|
|
26
|
+
const createAsciiDocFile = require('../util/create-asciidoc-file.js');
|
|
27
|
+
|
|
28
|
+
// In-memory cache for external resources (avoid repeated network calls)
|
|
29
|
+
const externalCache = new Map();
|
|
30
|
+
|
|
31
|
+
// ========= Handlebars helpers =============
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Converts a string to uppercase.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} str - The string to convert.
|
|
37
|
+
* @returns {string} The uppercase version of the input string.
|
|
38
|
+
*/
|
|
39
|
+
function uppercase(str) {
|
|
40
|
+
return String(str).toUpperCase();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if two values are equal.
|
|
45
|
+
*
|
|
46
|
+
* @param {*} a - The first value.
|
|
47
|
+
* @param {*} b - The second value.
|
|
48
|
+
* @returns {string} True if the values are equal.
|
|
49
|
+
*/
|
|
50
|
+
function eq(a, b) {
|
|
51
|
+
if (a === b) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Checks if two values are not equal.
|
|
59
|
+
*
|
|
60
|
+
* @param {*} a - The first value.
|
|
61
|
+
* @param {*} b - The second value.
|
|
62
|
+
* @returns {string} False if the values are not equal.
|
|
63
|
+
*/
|
|
64
|
+
function ne(a, b) {
|
|
65
|
+
if (a !== b) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Renders the children of a configuration object.
|
|
73
|
+
*
|
|
74
|
+
* @param {Array<Object>} children - An array of child objects.
|
|
75
|
+
* @returns {string} The rendered string containing the configuration details.
|
|
76
|
+
*/
|
|
77
|
+
function renderConnectFields(children, prefix = '') {
|
|
78
|
+
if (!children || !Array.isArray(children) || children.length === 0) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let output = '';
|
|
83
|
+
prefix = typeof prefix === 'string' ? prefix : '';
|
|
84
|
+
|
|
85
|
+
children.forEach(child => {
|
|
86
|
+
const isArray = child.kind === 'array';
|
|
87
|
+
if (!child.name) return;
|
|
88
|
+
const currentPath = prefix ? `${prefix}.${child.name}${isArray ? '[]' : ''}` : `${child.name}${isArray ? '[]' : ''}`;
|
|
89
|
+
|
|
90
|
+
// Section header for the field.
|
|
91
|
+
output += `=== \`${currentPath}\`\n\n`;
|
|
92
|
+
|
|
93
|
+
// Append description if available.
|
|
94
|
+
if (child.description) {
|
|
95
|
+
output += `${child.description}\n\n`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Inject admonition if the config is secret.
|
|
99
|
+
if (child.is_secret === true) {
|
|
100
|
+
output += `include::redpanda-connect:components:partial$secret_warning.adoc[]\n\n`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Insert version requirement if a version is provided.
|
|
104
|
+
if (child.version) {
|
|
105
|
+
output += `Requires version ${child.version} or later.\n\n`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Append type.
|
|
109
|
+
output += `*Type*: \`${child.type}\`\n\n`;
|
|
110
|
+
|
|
111
|
+
// For non-object types, output the default value if present.
|
|
112
|
+
if (child.type !== 'object' && child.default !== undefined) {
|
|
113
|
+
if (child.default === "") {
|
|
114
|
+
output += `*Default*: \`""\`\n\n`;
|
|
115
|
+
} else {
|
|
116
|
+
output += `*Default*: \`${child.default}\`\n\n`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// If annotated_options is present, build the AsciiDoc table.
|
|
121
|
+
if (child.annotated_options && Array.isArray(child.annotated_options) && child.annotated_options.length > 0) {
|
|
122
|
+
output += "[cols=\"1m,2a\"]\n";
|
|
123
|
+
output += "|===\n";
|
|
124
|
+
output += "|Option |Summary\n\n";
|
|
125
|
+
child.annotated_options.forEach(optionPair => {
|
|
126
|
+
// Ensure each optionPair is an array with at least two items:
|
|
127
|
+
if (Array.isArray(optionPair) && optionPair.length >= 2) {
|
|
128
|
+
output += `|${optionPair[0]}\n|${optionPair[1]}\n\n`;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
output += "|===\n\n";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (child.options && Array.isArray(child.options) && child.options.length > 0) {
|
|
135
|
+
output += `*Options*: ${child.options.map(option => `\`${option}\``).join(', ')}\n\n`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
// If examples are provided, add a fenced YAML block.
|
|
140
|
+
if (child.examples) {
|
|
141
|
+
output += "```yaml\n";
|
|
142
|
+
output += "# Examples:\n";
|
|
143
|
+
|
|
144
|
+
// Branch for string fields.
|
|
145
|
+
if (child.type === 'string') {
|
|
146
|
+
// If the field is an array of strings.
|
|
147
|
+
if (child.kind === 'array') {
|
|
148
|
+
child.examples.forEach(exampleGroup => {
|
|
149
|
+
output += `${child.name}:\n`;
|
|
150
|
+
if (Array.isArray(exampleGroup)) {
|
|
151
|
+
exampleGroup.forEach(exampleValue => {
|
|
152
|
+
if (typeof exampleValue === 'string' && exampleValue.includes('\n')) {
|
|
153
|
+
// Use literal block syntax for multi-line strings.
|
|
154
|
+
output += ` - |-\n`;
|
|
155
|
+
let indentedLines = exampleValue
|
|
156
|
+
.split('\n')
|
|
157
|
+
.map(line => ' ' + line)
|
|
158
|
+
.join('\n');
|
|
159
|
+
output += `${indentedLines}\n`;
|
|
160
|
+
} else {
|
|
161
|
+
output += ` - ${exampleValue}\n`;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
// Fallback for single value example group.
|
|
166
|
+
if (typeof exampleGroup === 'string' && exampleGroup.includes('\n')) {
|
|
167
|
+
output += ` - |-\n`;
|
|
168
|
+
let indentedLines = exampleGroup
|
|
169
|
+
.split('\n')
|
|
170
|
+
.map(line => ' ' + line)
|
|
171
|
+
.join('\n');
|
|
172
|
+
output += `${indentedLines}\n`;
|
|
173
|
+
} else {
|
|
174
|
+
output += ` - ${exampleGroup}\n`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
output += "\n";
|
|
178
|
+
});
|
|
179
|
+
} else {
|
|
180
|
+
// For non-array string examples, output them as key/value pairs.
|
|
181
|
+
child.examples.forEach(example => {
|
|
182
|
+
if (example.includes('\n')) {
|
|
183
|
+
output += `${child.name}: |-\n`;
|
|
184
|
+
let indentedLines = example.split('\n').map(line => ' ' + line).join('\n');
|
|
185
|
+
output += `${indentedLines}\n`;
|
|
186
|
+
} else {
|
|
187
|
+
output += `${child.name}: ${example}\n`;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Branch for processor fields.
|
|
193
|
+
else if (child.type === 'processor') {
|
|
194
|
+
if (child.kind === 'array') {
|
|
195
|
+
child.examples.forEach(exampleGroup => {
|
|
196
|
+
output += `${child.name}:\n`;
|
|
197
|
+
if (Array.isArray(exampleGroup)) {
|
|
198
|
+
exampleGroup.forEach(exampleObj => {
|
|
199
|
+
let yamlSnippet = yaml.stringify(exampleObj).trim();
|
|
200
|
+
let lines = yamlSnippet.split('\n');
|
|
201
|
+
let formattedLines = lines.map((line, idx) => {
|
|
202
|
+
return idx === 0 ? " - " + line : " " + line;
|
|
203
|
+
}).join('\n');
|
|
204
|
+
output += formattedLines + "\n";
|
|
205
|
+
});
|
|
206
|
+
} else {
|
|
207
|
+
let yamlSnippet = yaml.stringify(exampleGroup).trim();
|
|
208
|
+
let lines = yamlSnippet.split('\n');
|
|
209
|
+
let formattedLines = lines.map((line, idx) => {
|
|
210
|
+
return idx === 0 ? " - " + line : " " + line;
|
|
211
|
+
}).join('\n');
|
|
212
|
+
output += formattedLines + "\n";
|
|
213
|
+
}
|
|
214
|
+
output += "\n";
|
|
215
|
+
});
|
|
216
|
+
} else {
|
|
217
|
+
child.examples.forEach(example => {
|
|
218
|
+
output += `${child.name}: ${example}\n`;
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Branch for object fields.
|
|
223
|
+
else if (child.type === 'object') {
|
|
224
|
+
// If this object is actually an array of objects.
|
|
225
|
+
if (child.kind === 'array') {
|
|
226
|
+
child.examples.forEach(exampleGroup => {
|
|
227
|
+
output += `${child.name}:\n`;
|
|
228
|
+
if (Array.isArray(exampleGroup)) {
|
|
229
|
+
exampleGroup.forEach(exampleObj => {
|
|
230
|
+
let yamlSnippet = yaml.stringify(exampleObj).trim();
|
|
231
|
+
let lines = yamlSnippet.split('\n');
|
|
232
|
+
let formattedLines = lines.map((line, idx) => {
|
|
233
|
+
return idx === 0 ? " - " + line : " " + line;
|
|
234
|
+
}).join('\n');
|
|
235
|
+
output += formattedLines + "\n";
|
|
236
|
+
});
|
|
237
|
+
} else {
|
|
238
|
+
let yamlSnippet = yaml.stringify(exampleGroup).trim();
|
|
239
|
+
let lines = yamlSnippet.split('\n');
|
|
240
|
+
let formattedLines = lines.map((line, idx) => {
|
|
241
|
+
return idx === 0 ? " - " + line : " " + line;
|
|
242
|
+
}).join('\n');
|
|
243
|
+
output += formattedLines + "\n";
|
|
244
|
+
}
|
|
245
|
+
output += "\n";
|
|
246
|
+
});
|
|
247
|
+
} else {
|
|
248
|
+
// Fallback for non-array object examples.
|
|
249
|
+
child.examples.forEach(example => {
|
|
250
|
+
if (typeof example === 'object') {
|
|
251
|
+
let yamlSnippet = yaml.stringify(example).trim();
|
|
252
|
+
let lines = yamlSnippet.split('\n');
|
|
253
|
+
let formattedLines = lines.map((line, idx) => idx === 0 ? line : " " + line).join('\n');
|
|
254
|
+
output += `${child.name}:\n${formattedLines}\n`;
|
|
255
|
+
} else {
|
|
256
|
+
output += `${child.name}: ${example}\n`;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Fallback for any other field types.
|
|
262
|
+
else {
|
|
263
|
+
child.examples.forEach(example => {
|
|
264
|
+
output += `${child.name}: ${example}\n`;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
output += "```\n\n";
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Recursively render any nested children.
|
|
272
|
+
if (child.children && Array.isArray(child.children) && child.children.length > 0) {
|
|
273
|
+
output += renderConnectFields(child.children, currentPath);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Return a SafeString so that Handlebars doesn't escape special characters.
|
|
278
|
+
return new handlebars.SafeString(output);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Renders a list of examples.
|
|
283
|
+
*
|
|
284
|
+
* @param {Array<Object>} examples - An array of example objects.
|
|
285
|
+
* @returns {string} The rendered string containing the examples.
|
|
286
|
+
*/
|
|
287
|
+
function renderConnectExamples(examples) {
|
|
288
|
+
// If there are no examples, return an empty string.
|
|
289
|
+
if (!examples || !Array.isArray(examples) || examples.length === 0) {
|
|
290
|
+
return '';
|
|
291
|
+
}
|
|
292
|
+
// Start with a level-2 heading for all examples.
|
|
293
|
+
let output = '';
|
|
294
|
+
// Iterate over each example.
|
|
295
|
+
examples.forEach(example => {
|
|
296
|
+
// Render the example title as a level-3 heading.
|
|
297
|
+
if (example.title) {
|
|
298
|
+
output += `=== ${example.title}\n\n`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Render the summary if provided.
|
|
302
|
+
if (example.summary) {
|
|
303
|
+
output += `${example.summary}\n\n`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Render the example config inside an AsciiDoc code block.
|
|
307
|
+
// Using a [source,yaml] block and "----" as delimiters.
|
|
308
|
+
if (example.config) {
|
|
309
|
+
output += `[source,yaml]\n----\n`;
|
|
310
|
+
output += example.config.trim() + "\n";
|
|
311
|
+
output += "----\n\n";
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
// Return as a SafeString so that Handlebars doesn't escape markup.
|
|
315
|
+
return new handlebars.SafeString(output);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Selects data from a JSON object using a JSONPath expression.
|
|
320
|
+
*
|
|
321
|
+
* @param {Object} context - The JSON object to query.
|
|
322
|
+
* @param {string} pathExpression - The JSONPath expression to use for selection.
|
|
323
|
+
* @param {Object} options - Handlebars options object.
|
|
324
|
+
* @returns {string} The rendered string containing the selected data.
|
|
325
|
+
*/
|
|
326
|
+
|
|
327
|
+
function selectByJsonPath(context, pathExpression, options) {
|
|
328
|
+
// Query the context with the provided JSONPath expression.
|
|
329
|
+
pathExpression = (typeof pathExpression === 'string' && pathExpression !== '') ? pathExpression : "$";
|
|
330
|
+
const results = jsonpath.JSONPath({ path: pathExpression, json: context });
|
|
331
|
+
// If no results are found, render the inverse block.
|
|
332
|
+
if (!results || results.length === 0) {
|
|
333
|
+
return options.inverse ? options.inverse(this) : '';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// If exactly one result is found, use that as the context.
|
|
337
|
+
if (results.length === 1) {
|
|
338
|
+
return options.fn(results[0]);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Otherwise, if multiple results are found, iterate over them.
|
|
342
|
+
let resultString = '';
|
|
343
|
+
results.forEach(result => {
|
|
344
|
+
resultString += options.fn(result);
|
|
345
|
+
});
|
|
346
|
+
return resultString;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Register all helpers with Handlebars
|
|
350
|
+
handlebars.registerHelper('uppercase', uppercase);
|
|
351
|
+
handlebars.registerHelper('eq', eq);
|
|
352
|
+
handlebars.registerHelper('ne', ne);
|
|
353
|
+
handlebars.registerHelper('renderConnectFields', renderConnectFields);
|
|
354
|
+
handlebars.registerHelper('renderConnectExamples', renderConnectExamples);
|
|
355
|
+
handlebars.registerHelper('selectByJsonPath', selectByJsonPath);
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
// ============= End of helpers ===========================
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Recursively merges properties from the `overrides` object into the `target` object.
|
|
364
|
+
*
|
|
365
|
+
* - If both `target[key]` and `overrides[key]` are arrays, it matches each item in `target` with an item in `overrides`
|
|
366
|
+
* that has the same `name` property, then merges selected fields and also recursively processes nested objects.
|
|
367
|
+
* - If both `target[key]` and `overrides[key]` are plain objects, it merges them recursively.
|
|
368
|
+
* - Otherwise, it simply replaces `target[key]` with `overrides[key]`.
|
|
369
|
+
*
|
|
370
|
+
* @param {Object} target The object into which overrides will be merged.
|
|
371
|
+
* @param {Object} overrides The object containing override properties.
|
|
372
|
+
* @returns {Object} The updated `target` object.
|
|
373
|
+
*/
|
|
374
|
+
function mergeOverrides(target, overrides) {
|
|
375
|
+
if (!overrides || typeof overrides !== 'object') return target;
|
|
376
|
+
|
|
377
|
+
for (let key in overrides) {
|
|
378
|
+
// Handle arrays by matching items on 'name'
|
|
379
|
+
if (Array.isArray(target[key]) && Array.isArray(overrides[key])) {
|
|
380
|
+
target[key] = target[key].map(item => {
|
|
381
|
+
const overrideItem = overrides[key].find(o => o.name === item.name);
|
|
382
|
+
if (overrideItem) {
|
|
383
|
+
// Only override allowed fields if they are explicitly defined
|
|
384
|
+
['description', 'type'].forEach(field => {
|
|
385
|
+
if (overrideItem.hasOwnProperty(field)) {
|
|
386
|
+
item[field] = overrideItem[field];
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Recursively handle nested children
|
|
391
|
+
item = mergeOverrides(item, overrideItem);
|
|
392
|
+
}
|
|
393
|
+
return item;
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Recurse into nested objects
|
|
397
|
+
} else if (
|
|
398
|
+
typeof target[key] === 'object' &&
|
|
399
|
+
typeof overrides[key] === 'object' &&
|
|
400
|
+
!Array.isArray(target[key]) &&
|
|
401
|
+
!Array.isArray(overrides[key])
|
|
402
|
+
) {
|
|
403
|
+
target[key] = mergeOverrides(target[key], overrides[key]);
|
|
404
|
+
|
|
405
|
+
// Only override top-level description/type if defined in overrides
|
|
406
|
+
} else if (['description', 'type'].includes(key) && overrides.hasOwnProperty(key)) {
|
|
407
|
+
target[key] = overrides[key];
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return target;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
function processData_TemplateBlock(parent, reader, attrs, config, extensionRef) {
|
|
415
|
+
const catalog = config.contentCatalog;
|
|
416
|
+
if (!catalog) {
|
|
417
|
+
logger.error('[data_template] Error: content catalog not found');
|
|
418
|
+
return extensionRef.createBlock(parent, 'paragraph', 'Error: content catalog not found', attrs);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// The dataPath may be an Antora resource ID (for local files)
|
|
422
|
+
// or an external URL (like https://example.com/data.json)
|
|
423
|
+
const resourceId = attrs.dataPath;
|
|
424
|
+
if (!resourceId) {
|
|
425
|
+
const msg = '[data_template] Error: No data resource ID provided.';
|
|
426
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
let contentStr;
|
|
430
|
+
let ext = '';
|
|
431
|
+
|
|
432
|
+
if (resourceId.startsWith('http://') || resourceId.startsWith('https://')) {
|
|
433
|
+
// Handle external resource
|
|
434
|
+
try {
|
|
435
|
+
if (externalCache.has(resourceId)) {
|
|
436
|
+
contentStr = externalCache.get(resourceId);
|
|
437
|
+
} else {
|
|
438
|
+
const res = request('GET', resourceId, { timeout: 5000 });
|
|
439
|
+
contentStr = res.getBody('utf8');
|
|
440
|
+
externalCache.set(resourceId, contentStr);
|
|
441
|
+
}
|
|
442
|
+
// Determine file extension from the URL’s pathname.
|
|
443
|
+
try {
|
|
444
|
+
const urlObj = new URL(resourceId);
|
|
445
|
+
const pathname = urlObj.pathname;
|
|
446
|
+
ext = pathname.substring(pathname.lastIndexOf('.')).toLowerCase();
|
|
447
|
+
} catch (err) {
|
|
448
|
+
ext = '';
|
|
449
|
+
}
|
|
450
|
+
} catch (err) {
|
|
451
|
+
const msg = `[data_template] Error fetching external resource: ${err}`;
|
|
452
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
453
|
+
}
|
|
454
|
+
} else {
|
|
455
|
+
// Handle local resource using Antora's content catalog.
|
|
456
|
+
const fileSrc = config.file && config.file.src;
|
|
457
|
+
const resourceFile = catalog.resolveResource(resourceId, fileSrc);
|
|
458
|
+
if (!resourceFile) {
|
|
459
|
+
const msg = `[data_template] Could not resolve resource: ${resourceId}`;
|
|
460
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
contentStr = resourceFile.contents.toString();
|
|
464
|
+
ext = resourceFile.src.extname.toLowerCase();
|
|
465
|
+
} catch (err) {
|
|
466
|
+
const msg = `[data_template] Error reading local resource: ${err}`;
|
|
467
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Load and parse the data from the resource.
|
|
472
|
+
let dataObj = null;
|
|
473
|
+
try {
|
|
474
|
+
if (ext === '.json') {
|
|
475
|
+
dataObj = JSON.parse(contentStr);
|
|
476
|
+
} else if (ext === '.yaml' || ext === '.yml') {
|
|
477
|
+
dataObj = yaml.parse(contentStr);
|
|
478
|
+
} else {
|
|
479
|
+
// Fallback: try JSON first, then yaml, then default to raw text.
|
|
480
|
+
try {
|
|
481
|
+
dataObj = JSON.parse(contentStr);
|
|
482
|
+
} catch (jsonErr) {
|
|
483
|
+
try {
|
|
484
|
+
dataObj = yaml.parse(contentStr);
|
|
485
|
+
} catch (yamlErr) {
|
|
486
|
+
dataObj = { text: contentStr };
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
} catch (err) {
|
|
491
|
+
const msg = `[data_template] Error parsing data: ${err}`;
|
|
492
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (attrs.overrides) {
|
|
496
|
+
try {
|
|
497
|
+
const overridesFile = catalog.resolveResource(attrs.overrides, config.file.src);
|
|
498
|
+
if (overridesFile) {
|
|
499
|
+
const overridesStr = overridesFile.contents.toString();
|
|
500
|
+
const overridesObj = JSON.parse(overridesStr);
|
|
501
|
+
dataObj = mergeOverrides(dataObj, overridesObj);
|
|
502
|
+
}
|
|
503
|
+
} catch (err) {
|
|
504
|
+
logger.error(`[data_template] Error applying overrides: ${err}`);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
dataObj.__rawYAML = contentStr;
|
|
508
|
+
|
|
509
|
+
// Compile the Handlebars template from the block’s content.
|
|
510
|
+
let templateSource = reader.getLines().join('\n');
|
|
511
|
+
templateSource = templateSource.replace(/@@tab-content@@/g, '--')
|
|
512
|
+
let compiledText = '';
|
|
513
|
+
try {
|
|
514
|
+
const template = handlebars.compile(templateSource);
|
|
515
|
+
compiledText = template(dataObj);
|
|
516
|
+
} catch (err) {
|
|
517
|
+
const msg = `[data_template] Handlebars error: ${err}`;
|
|
518
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// The following block takes the Handlebars-generated AsciiDoc content (`compiledText`)
|
|
522
|
+
// and parses it in the context of the parent document (`doc`). This is important
|
|
523
|
+
// because it allows Antora’s custom include logic and other extensions to be applied
|
|
524
|
+
// to the content as if it were part of the original AsciiDoc source. After parsing
|
|
525
|
+
// and converting the new document, we append the resulting blocks back into the
|
|
526
|
+
// parent node, merging the dynamically generated content into the final
|
|
527
|
+
// output. Any errors during parsing are caught and reported as a paragraph block.
|
|
528
|
+
try {
|
|
529
|
+
const sourceFile = config.file?.src;
|
|
530
|
+
const baseDir = sourceFile?.relative ? path.dirname(sourceFile.relative) : 'fragments';
|
|
531
|
+
const uniqueName = `data_template-${Date.now()}.adoc`;
|
|
532
|
+
const relativePath = path.join(baseDir, uniqueName);
|
|
533
|
+
const doc = parent.getDocument();
|
|
534
|
+
const attributes = doc.getAttributes()
|
|
535
|
+
|
|
536
|
+
const file = {
|
|
537
|
+
contents: Buffer.from(`${compiledText}`),
|
|
538
|
+
src: {
|
|
539
|
+
component: attributes['page-component-name'],
|
|
540
|
+
version: attributes['page-component-version'],
|
|
541
|
+
module: attributes['page-module'],
|
|
542
|
+
family: 'page',
|
|
543
|
+
relative: relativePath,
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
try {
|
|
547
|
+
file.out = computeOut.call(config.contentCatalog, file.src)
|
|
548
|
+
const outFile = createAsciiDocFile(config.contentCatalog, file);
|
|
549
|
+
const newDoc = loadAsciiDoc(outFile, config.contentCatalog, {
|
|
550
|
+
...doc.getOptions(),
|
|
551
|
+
relativizeResourceRefs: true,
|
|
552
|
+
attributes: {
|
|
553
|
+
...(doc.getOptions().attributes || {}),
|
|
554
|
+
...(attributes || {}),
|
|
555
|
+
},
|
|
556
|
+
});
|
|
557
|
+
newDoc.getBlocks().forEach((b) => {
|
|
558
|
+
parent.append(b);
|
|
559
|
+
});
|
|
560
|
+
return null;
|
|
561
|
+
} catch (err) {
|
|
562
|
+
console.warn('❌ loadAsciiDoc threw:', err);
|
|
563
|
+
return extensionRef.createBlock(parent, 'paragraph', `[data_template] loadAsciiDoc error: ${err.message}`, attrs);
|
|
564
|
+
}
|
|
565
|
+
} catch (err) {
|
|
566
|
+
const msg = `[data_template] Error parsing compiled template as AsciiDoc: ${err}`;
|
|
567
|
+
return extensionRef.createBlock(parent, 'paragraph', msg, attrs);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
module.exports.register = (registry, context) => {
|
|
572
|
+
if (!registry && context) return;
|
|
573
|
+
|
|
574
|
+
const toProc = (fn) => Object.defineProperty(fn, '$$arity', { value: fn.length });
|
|
575
|
+
|
|
576
|
+
function createExtensionGroup({ contentCatalog, file }) {
|
|
577
|
+
return function () {
|
|
578
|
+
this.block('data_template', function () {
|
|
579
|
+
this.positionalAttributes(['dataPath', 'overrides']);
|
|
580
|
+
this.onContext('open');
|
|
581
|
+
this.process((parent, reader, attrs) => {
|
|
582
|
+
return processData_TemplateBlock(parent, reader, attrs, { contentCatalog, file }, this);
|
|
583
|
+
});
|
|
584
|
+
});
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
registry.$groups().$store('data-template-ext', toProc(createExtensionGroup(context)));
|
|
589
|
+
return registry
|
|
590
|
+
};
|
|
591
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redpanda-data/docs-extensions-and-macros",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Antora extensions and macros developed for Redpanda documentation.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"antora",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
"./macros/glossary": "./macros/glossary.js",
|
|
51
51
|
"./macros/rp-connect-components": "./macros/rp-connect-components.js",
|
|
52
52
|
"./macros/config-ref": "./macros/config-ref.js",
|
|
53
|
-
"./macros/helm-ref": "./macros/helm-ref.js"
|
|
53
|
+
"./macros/helm-ref": "./macros/helm-ref.js",
|
|
54
|
+
"./macros/data-template": "./macros/data-template.js"
|
|
54
55
|
},
|
|
55
56
|
"files": [
|
|
56
57
|
"extensions",
|
|
@@ -71,15 +72,19 @@
|
|
|
71
72
|
"chalk": "4.1.2",
|
|
72
73
|
"gulp": "^4.0.2",
|
|
73
74
|
"gulp-connect": "^5.7.0",
|
|
75
|
+
"handlebars": "^4.7.8",
|
|
74
76
|
"html-entities": "2.3",
|
|
75
77
|
"js-yaml": "^4.1.0",
|
|
78
|
+
"jsonpath-plus": "^10.3.0",
|
|
76
79
|
"lodash": "^4.17.21",
|
|
77
80
|
"micromatch": "^4.0.8",
|
|
78
81
|
"node-fetch": "^3.3.2",
|
|
79
82
|
"node-html-parser": "5.4.2-0",
|
|
80
83
|
"papaparse": "^5.4.1",
|
|
81
84
|
"semver": "^7.6.0",
|
|
82
|
-
"
|
|
85
|
+
"sync-request": "^6.1.0",
|
|
86
|
+
"tar": "^7.4.3",
|
|
87
|
+
"yaml": "^2.7.0"
|
|
83
88
|
},
|
|
84
89
|
"devDependencies": {
|
|
85
90
|
"@antora/cli": "3.1.4",
|