@redpanda-data/docs-extensions-and-macros 4.8.1 → 4.9.1

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.
@@ -0,0 +1,105 @@
1
+ {{#if cloud_supported}}
2
+ // tag::redpanda-cloud[]
3
+ {{/if}}
4
+ === {{name}}
5
+ {{#if version}}
6
+
7
+ *Introduced in {{version}}*
8
+ {{/if}}
9
+ {{#if description}}
10
+
11
+ {{{description}}}
12
+ {{else}}
13
+
14
+ No description available.
15
+ {{/if}}
16
+ {{#if is_enterprise}}
17
+
18
+ ifndef::env-cloud[]
19
+ *Enterprise license required*: `{{enterprise_value}}` (for license details, see xref:get-started:licensing/index.adoc[Redpanda Licensing])
20
+ endif::[]
21
+ {{/if}}
22
+ {{#if cloud_byoc_only}}
23
+
24
+ NOTE: This property is available only in Redpanda Cloud BYOC deployments.
25
+ {{/if}}
26
+ {{#if units}}
27
+
28
+ *Unit:* {{units}}
29
+ {{else}}
30
+ {{#if (formatUnits name)}}
31
+
32
+ *Unit:* {{formatUnits name}}
33
+ {{/if}}
34
+ {{/if}}
35
+ {{#if (ne defined_in "src/v/config/node_config.cc")}}
36
+ {{#if (ne needs_restart undefined)}}
37
+
38
+ *Requires restart:* {{#if needs_restart}}Yes{{else}}No{{/if}}
39
+ {{/if}}
40
+ {{/if}}
41
+ {{#if visibility}}
42
+
43
+ // tag::self-managed-only[]
44
+ *Visibility:* `{{visibility}}`
45
+ // end::self-managed-only[]
46
+ {{/if}}
47
+ {{#if type}}
48
+
49
+ *Type:* {{type}}
50
+ {{/if}}
51
+ {{#if (and minimum maximum)}}
52
+
53
+ *Accepted values:* [`{{minimum}}`, `{{maximum}}`]
54
+ {{else}}
55
+ {{#if minimum}}
56
+
57
+ *Minimum value:* `{{minimum}}`
58
+ {{/if}}
59
+ {{#if maximum}}
60
+
61
+ *Maximum value:* `{{maximum}}`
62
+ {{/if}}
63
+ {{/if}}
64
+ {{#if (ne default undefined)}}
65
+
66
+ ifdef::env-cloud[]
67
+ *Default:* Available in the Redpanda Cloud Console
68
+ endif::[]
69
+ ifndef::env-cloud[]
70
+ *Default:* `{{formatPropertyValue default type}}`
71
+ endif::[]
72
+ {{/if}}
73
+
74
+ // tag::self-managed-only[]
75
+ *Nullable:* {{#if nullable}}Yes{{else}}No{{/if}}
76
+ // end::self-managed-only[]
77
+ {{#if example}}
78
+
79
+ {{{renderPropertyExample this}}}
80
+ {{/if}}
81
+ {{#if related_topics}}
82
+
83
+ *Related topics:*
84
+
85
+ {{#each related_topics}}
86
+ * {{{this}}}
87
+ {{/each}}
88
+ {{/if}}
89
+ {{#if aliases}}
90
+
91
+ // tag::self-managed-only[]
92
+ *Aliases:* {{join aliases ", "}}
93
+ // end::self-managed-only[]
94
+ {{/if}}
95
+ {{#if is_deprecated}}
96
+
97
+ [WARNING]
98
+ ====
99
+ This property is deprecated.
100
+ ====
101
+ {{/if}}
102
+ ---
103
+ {{#if cloud_supported}}
104
+ // end::redpanda-cloud[]
105
+ {{/if}}
@@ -2,14 +2,21 @@
2
2
 
3
3
  {{#if version}}
4
4
  *Introduced in {{version}}*
5
-
6
5
  {{/if}}
6
+
7
7
  {{#if description}}
8
8
  {{{description}}}
9
9
  {{else}}
10
10
  No description available.
11
11
  {{/if}}
12
12
 
13
+ {{#if is_enterprise}}
14
+ ifndef::env-cloud[]
15
+ *Enterprise license required*: `{{enterprise_value}}` (for license details, see xref:get-started:licensing/index.adoc[Redpanda Licensing])
16
+ endif::[]
17
+
18
+ {{/if}}
19
+
13
20
  {{#if units}}
14
21
  *Unit:* {{units}}
15
22
 
@@ -56,6 +63,14 @@ No description available.
56
63
  {{{renderPropertyExample this}}}
57
64
  {{/if}}
58
65
 
66
+ {{#if related_topics}}
67
+ *Related topics:*
68
+
69
+ {{#each related_topics}}
70
+ * {{{this}}}
71
+ {{/each}}
72
+ {{/if}}
73
+
59
74
  {{#if aliases}}
60
75
  *Aliases:* {{join aliases ", "}}
61
76
 
@@ -0,0 +1,97 @@
1
+ {{#if cloud_supported}}
2
+ // tag::redpanda-cloud[]
3
+ {{/if}}
4
+ === {{name}}
5
+ {{#if version}}
6
+
7
+ *Introduced in {{version}}*
8
+ {{/if}}
9
+ {{#if description}}
10
+
11
+ {{{description}}}
12
+ {{else}}
13
+
14
+ No description available.
15
+ {{/if}}
16
+ {{#if is_enterprise}}
17
+
18
+ ifndef::env-cloud[]
19
+ *Enterprise license required*: `{{enterprise_value}}` (for license details, see xref:get-started:licensing/index.adoc[Redpanda Licensing])
20
+ endif::[]
21
+ {{/if}}
22
+ {{#if cloud_byoc_only}}
23
+
24
+ NOTE: This property is only available in Redpanda Cloud BYOC deployments.
25
+ {{/if}}
26
+ {{#if type}}
27
+
28
+ *Type:* {{type}}
29
+ {{/if}}
30
+ {{#if acceptable_values}}
31
+
32
+ *Accepted values:* {{{acceptable_values}}}
33
+ {{/if}}
34
+ {{#if corresponding_cluster_property}}
35
+
36
+ *Related cluster property:* xref:reference:cluster-properties.adoc#{{corresponding_cluster_property}}[{{corresponding_cluster_property}}]
37
+ {{/if}}
38
+ {{#if (and minimum maximum)}}
39
+
40
+ *Accepted values:* [`{{minimum}}`, `{{maximum}}`]
41
+ {{else}}
42
+ {{#if minimum}}
43
+
44
+ *Minimum value:* `{{minimum}}`
45
+ {{/if}}
46
+ {{#if maximum}}
47
+
48
+ *Maximum value:* `{{maximum}}`
49
+ {{/if}}
50
+ {{/if}}
51
+ {{#if (ne default undefined)}}
52
+ {{#if cloud_supported}}
53
+
54
+ ifdef::env-cloud[]
55
+ *Default:* Available in the Redpanda Cloud Console
56
+ endif::[]
57
+ ifndef::env-cloud[]
58
+ *Default:* `{{formatPropertyValue default type}}`
59
+ endif::[]
60
+ {{else}}
61
+
62
+ *Default:* `{{formatPropertyValue default type}}`
63
+ {{/if}}
64
+ {{/if}}
65
+
66
+ // tag::self-managed-only[]
67
+ *Nullable:* {{#if nullable}}Yes{{else}}No{{/if}}
68
+ // end::self-managed-only[]
69
+ {{#if example}}
70
+
71
+ {{{renderPropertyExample this}}}
72
+ {{/if}}
73
+ {{#if related_topics}}
74
+
75
+ *Related topics:*
76
+
77
+ {{#each related_topics}}
78
+ * {{{this}}}
79
+ {{/each}}
80
+ {{/if}}
81
+ {{#if aliases}}
82
+
83
+ // tag::self-managed-only[]
84
+ *Aliases:* {{join aliases ", "}}
85
+ // end::self-managed-only[]
86
+ {{/if}}
87
+ {{#if is_deprecated}}
88
+
89
+ [WARNING]
90
+ ====
91
+ This property is deprecated.
92
+ ====
93
+ {{/if}}
94
+ ---
95
+ {{#if cloud_supported}}
96
+ // end::redpanda-cloud[]
97
+ {{/if}}
@@ -1,59 +1,73 @@
1
1
  === {{name}}
2
-
3
2
  {{#if version}}
4
- *Introduced in {{version}}*
5
3
 
4
+ *Introduced in {{version}}*
6
5
  {{/if}}
7
6
  {{#if description}}
7
+
8
8
  {{{description}}}
9
9
  {{else}}
10
+
10
11
  No description available.
11
12
  {{/if}}
13
+ {{#if is_enterprise}}
12
14
 
15
+ ifndef::env-cloud[]
16
+ *Enterprise license required*: `{{enterprise_value}}` (for license details, see xref:get-started:licensing/index.adoc[Redpanda Licensing])
17
+ endif::[]
18
+ {{/if}}
13
19
  {{#if type}}
14
- *Type:* {{type}}
15
20
 
21
+ *Type:* {{type}}
16
22
  {{/if}}
17
23
  {{#if acceptable_values}}
18
- *Accepted values:* {{{acceptable_values}}}
19
24
 
25
+ *Accepted values:* {{{acceptable_values}}}
20
26
  {{/if}}
21
27
  {{#if corresponding_cluster_property}}
22
- *Related cluster property:* xref:reference:cluster-properties.adoc#{{corresponding_cluster_property}}[{{corresponding_cluster_property}}]
23
28
 
29
+ *Related cluster property:* xref:reference:cluster-properties.adoc#{{corresponding_cluster_property}}[{{corresponding_cluster_property}}]
24
30
  {{/if}}
25
31
  {{#if (and minimum maximum)}}
26
- *Accepted values:* [`{{minimum}}`, `{{maximum}}`]
27
32
 
33
+ *Accepted values:* [`{{minimum}}`, `{{maximum}}`]
28
34
  {{else}}
29
35
  {{#if minimum}}
30
- *Minimum value:* `{{minimum}}`
31
36
 
37
+ *Minimum value:* `{{minimum}}`
32
38
  {{/if}}
33
39
  {{#if maximum}}
34
- *Maximum value:* `{{maximum}}`
35
40
 
41
+ *Maximum value:* `{{maximum}}`
36
42
  {{/if}}
37
43
  {{/if}}
38
44
  {{#if (ne default undefined)}}
39
- *Default:* `{{formatPropertyValue default type}}`
40
45
 
46
+ *Default:* `{{formatPropertyValue default type}}`
41
47
  {{/if}}
42
- *Nullable:* {{#if nullable}}Yes{{else}}No{{/if}}
43
48
 
49
+ *Nullable:* {{#if nullable}}Yes{{else}}No{{/if}}
44
50
  {{#if example}}
51
+
45
52
  {{{renderPropertyExample this}}}
46
53
  {{/if}}
54
+ {{#if related_topics}}
55
+
56
+ *Related topics:*
47
57
 
58
+ {{#each related_topics}}
59
+ * {{{this}}}
60
+ {{/each}}
61
+ {{/if}}
48
62
  {{#if aliases}}
49
- *Aliases:* {{join aliases ", "}}
50
63
 
64
+ *Aliases:* {{join aliases ", "}}
51
65
  {{/if}}
52
66
  {{#if is_deprecated}}
67
+
53
68
  [WARNING]
54
69
  ====
55
70
  This property is deprecated.
56
71
  ====
57
-
58
72
  {{/if}}
59
73
  ---
@@ -1,13 +1,50 @@
1
1
  import re
2
+ import logging
2
3
  from property_bag import PropertyBag
3
4
  from parser import normalize_string
4
5
 
6
+ # Get logger for this module
7
+ logger = logging.getLogger(__name__)
8
+
9
+ # Import the process_enterprise_value function from property_extractor
10
+ # Note: We import at function level to avoid circular imports since property_extractor
11
+ # imports transformers.py. This pattern allows the EnterpriseTransformer to access
12
+ # the centralized enterprise value processing logic without creating import cycles.
13
+ def get_process_enterprise_value():
14
+ """
15
+ Lazily import and return the centralized `process_enterprise_value` function from `property_extractor`.
16
+
17
+ Attempts to import `process_enterprise_value` and return it to avoid circular-import issues. If the import fails an error message is printed and None is returned.
18
+
19
+ Returns:
20
+ Callable or None: The `process_enterprise_value` callable when available, otherwise `None`.
21
+ """
22
+ try:
23
+ from property_extractor import process_enterprise_value
24
+ return process_enterprise_value
25
+ except ImportError as e:
26
+ logger.error("Cannot import process_enterprise_value from property_extractor: %s", e)
27
+ return None
28
+
5
29
 
6
30
  class BasicInfoTransformer:
7
31
  def accepts(self, info, file_pair):
32
+ """
33
+ Always accepts the provided info and file_pair.
34
+
35
+ Parameters:
36
+ info (dict): Parsed metadata for a property (annotation/params/declaration).
37
+ file_pair (object): Pair of source/implementation file metadata used by transformers.
38
+
39
+ Returns:
40
+ bool: Always returns True, indicating this transformer should be applied.
41
+ """
8
42
  return True
9
43
 
10
44
  def parse(self, property, info, file_pair):
45
+ if not info.get("params") or len(info["params"]) == 0:
46
+ return property
47
+
11
48
  property["name"] = info["params"][0]["value"]
12
49
  property["defined_in"] = re.sub(
13
50
  r"^.*src/", "src/", str(file_pair.implementation)
@@ -427,13 +464,65 @@ class AliasTransformer:
427
464
 
428
465
 
429
466
  class EnterpriseTransformer:
467
+ """
468
+ Transforms enterprise property values from C++ expressions to user-friendly JSON.
469
+
470
+ This transformer processes enterprise values by delegating to the
471
+ centralized process_enterprise_value function which handles the full range of
472
+ C++ expression types found in enterprise property definitions.
473
+ """
430
474
  def accepts(self, info, file_pair):
475
+ """
476
+ Return True if the provided info indicates an enterprise-only property.
477
+
478
+ Parameters:
479
+ info (dict): The metadata dictionary for a property. This function checks for a 'type' key whose string contains 'enterprise'.
480
+ file_pair: Unused; present for transformer interface compatibility.
481
+
482
+ Returns:
483
+ bool: True when info contains a 'type' that includes 'enterprise', otherwise False.
484
+ """
431
485
  return bool(info.get('type') and 'enterprise' in info['type'])
432
486
 
433
487
  def parse(self, property, info, file_pair):
488
+ """
489
+ Mark a property as enterprise-only and attach its enterprise value.
490
+
491
+ If an enterprise value is present in info['params'][0]['value'], this method attempts to process it using the shared
492
+ process_enterprise_value helper (loaded via get_process_enterprise_value()). If the processor is unavailable or raises
493
+ an exception, the raw enterprise value is used.
494
+
495
+ Side effects:
496
+ - Sets property["enterprise_value"] to the processed or raw value.
497
+ - Sets property["is_enterprise"] = True.
498
+ - Removes the first element from info['params'].
499
+
500
+ Parameters:
501
+ property (dict): Property bag to modify and return.
502
+ info (dict): Parsed metadata; must have a non-None 'params' list for processing.
503
+ file_pair: Unused here but accepted for transformer API compatibility.
504
+
505
+ Returns:
506
+ dict: The updated property bag.
507
+ """
434
508
  if info['params'] is not None:
435
509
  enterpriseValue = info['params'][0]['value']
436
- property['enterprise_value'] = enterpriseValue
510
+
511
+ # Get the processing function
512
+ process_enterprise_value = get_process_enterprise_value()
513
+ if process_enterprise_value is None:
514
+ property["enterprise_value"] = enterpriseValue
515
+ property['is_enterprise'] = True
516
+ del info['params'][0]
517
+ return property
518
+
519
+ try:
520
+ processed_value = process_enterprise_value(enterpriseValue)
521
+ property["enterprise_value"] = processed_value
522
+ except Exception:
523
+ # Fallback to raw value if processing fails
524
+ property["enterprise_value"] = enterpriseValue
525
+
437
526
  property['is_enterprise'] = True
438
527
  del info['params'][0]
439
528
  return property
@@ -462,7 +551,14 @@ class MetaParamTransformer:
462
551
  iterable_params = info['params']
463
552
  for param in iterable_params:
464
553
  if isinstance(param['value'], str) and param['value'].startswith("meta{"):
465
- meta_content = param['value'].strip("meta{ }").strip()
554
+ # Extract content between meta{ and } using explicit slicing
555
+ param_value = param['value']
556
+ if param_value.endswith('}'):
557
+ meta_content = param_value[5:-1].strip() # Remove "meta{" and "}"
558
+ else:
559
+ # Handle malformed meta{ without closing }
560
+ meta_content = param_value[5:].strip() # Remove "meta{" only
561
+
466
562
  meta_dict = {}
467
563
  for item in meta_content.split(','):
468
564
  item = item.strip()
@@ -209,6 +209,31 @@ function resolveReferences(obj, root) {
209
209
  * When generating full drafts, components with a `status` of `'deprecated'` are skipped.
210
210
  */
211
211
  async function generateRpcnConnectorDocs(options) {
212
+ // Types and output folders for bloblang function/method partials
213
+ const bloblangTypes = [
214
+ { key: 'bloblang-functions', folder: 'bloblang-functions' },
215
+ { key: 'bloblang-methods', folder: 'bloblang-methods' }
216
+ ];
217
+ // Recursively mark is_beta on any field/component with description starting with BETA:
218
+ function markBeta(obj) {
219
+ if (!obj || typeof obj !== 'object') return;
220
+ if (Array.isArray(obj)) {
221
+ obj.forEach(markBeta);
222
+ return;
223
+ }
224
+ // Mark as beta if description starts with 'BETA:' (case-insensitive, trims leading whitespace)
225
+ if (typeof obj.description === 'string' && /^\s*BETA:\s*/i.test(obj.description)) {
226
+ obj.is_beta = true;
227
+ }
228
+ // Recurse into children/config/fields
229
+ if (Array.isArray(obj.children)) obj.children.forEach(markBeta);
230
+ if (obj.config && Array.isArray(obj.config.children)) obj.config.children.forEach(markBeta);
231
+ // For connector/component arrays
232
+ for (const key of Object.keys(obj)) {
233
+ if (Array.isArray(obj[key])) obj[key].forEach(markBeta);
234
+ }
235
+ }
236
+
212
237
  const {
213
238
  data,
214
239
  overrides,
@@ -216,6 +241,7 @@ async function generateRpcnConnectorDocs(options) {
216
241
  templateIntro,
217
242
  templateFields,
218
243
  templateExamples,
244
+ templateBloblang,
219
245
  writeFullDrafts
220
246
  } = options;
221
247
 
@@ -223,16 +249,38 @@ async function generateRpcnConnectorDocs(options) {
223
249
  const raw = fs.readFileSync(data, 'utf8');
224
250
  const ext = path.extname(data).toLowerCase();
225
251
  const dataObj = ext === '.json' ? JSON.parse(raw) : yaml.parse(raw);
252
+ // Mark beta fields/components before overrides
253
+ markBeta(dataObj);
226
254
 
227
255
  // Apply overrides if provided
228
256
  if (overrides) {
229
257
  const ovRaw = fs.readFileSync(overrides, 'utf8');
230
258
  const ovObj = JSON.parse(ovRaw);
231
-
232
259
  // Resolve any $ref references in the overrides
233
260
  const resolvedOverrides = resolveReferences(ovObj, ovObj);
234
-
235
261
  mergeOverrides(dataObj, resolvedOverrides);
262
+
263
+ // Special: merge bloblang_methods and bloblang_functions from overrides into main data
264
+ for (const [overrideKey, mainKey] of [
265
+ ['bloblang_methods', 'bloblang-methods'],
266
+ ['bloblang_functions', 'bloblang-functions']
267
+ ]) {
268
+ if (Array.isArray(resolvedOverrides[overrideKey])) {
269
+ if (!Array.isArray(dataObj[mainKey])) dataObj[mainKey] = [];
270
+ // Merge by name
271
+ const mainArr = dataObj[mainKey];
272
+ const overrideArr = resolvedOverrides[overrideKey];
273
+ for (const overrideItem of overrideArr) {
274
+ if (!overrideItem.name) continue;
275
+ const idx = mainArr.findIndex(i => i.name === overrideItem.name);
276
+ if (idx !== -1) {
277
+ mainArr[idx] = { ...mainArr[idx], ...overrideItem };
278
+ } else {
279
+ mainArr.push(overrideItem);
280
+ }
281
+ }
282
+ }
283
+ }
236
284
  }
237
285
 
238
286
  // Compile the “main” template (used when writeFullDrafts = true)
@@ -260,6 +308,7 @@ async function generateRpcnConnectorDocs(options) {
260
308
  const fieldsOutRoot = path.join(outputRoot, 'fields');
261
309
  const examplesOutRoot = path.join(outputRoot, 'examples');
262
310
  const draftsRoot = path.join(outputRoot, 'drafts');
311
+ const configExamplesRoot = path.resolve(process.cwd(), 'modules/components/examples');
263
312
 
264
313
  if (!writeFullDrafts) {
265
314
  fs.mkdirSync(fieldsOutRoot, { recursive: true });
@@ -332,6 +381,51 @@ async function generateRpcnConnectorDocs(options) {
332
381
  }
333
382
  }
334
383
 
384
+ // Bloblang function/method partials (only if includeBloblang is true)
385
+ if (options.includeBloblang) {
386
+ for (const { key, folder } of bloblangTypes) {
387
+ const items = dataObj[key];
388
+ if (!Array.isArray(items)) continue;
389
+ const outRoot = path.join(outputRoot, folder);
390
+ fs.mkdirSync(outRoot, { recursive: true });
391
+ // Use custom or default template
392
+ const bloblangTemplatePath = templateBloblang || path.resolve(__dirname, './templates/bloblang-function.hbs');
393
+ const bloblangTemplate = handlebars.compile(fs.readFileSync(bloblangTemplatePath, 'utf8'));
394
+ for (const fn of items) {
395
+ if (!fn.name) continue;
396
+ const adoc = bloblangTemplate(fn);
397
+ const outPath = path.join(outRoot, `${fn.name}.adoc`);
398
+ fs.writeFileSync(outPath, adoc, 'utf8');
399
+ partialsWritten++;
400
+ partialFiles.push(path.relative(process.cwd(), outPath));
401
+ }
402
+ }
403
+ }
404
+
405
+ // Common/Advanced config snippet YAMLs in modules/components/examples
406
+ const commonConfig = helpers.commonConfig;
407
+ const advancedConfig = helpers.advancedConfig;
408
+ for (const [type, items] of Object.entries(dataObj)) {
409
+ if (!Array.isArray(items)) continue;
410
+ for (const item of items) {
411
+ if (!item.name || !item.config || !Array.isArray(item.config.children)) continue;
412
+ // Common config
413
+ const commonYaml = commonConfig(type, item.name, item.config.children);
414
+ const commonPath = path.join(configExamplesRoot, 'common', type, `${item.name}.yaml`);
415
+ fs.mkdirSync(path.dirname(commonPath), { recursive: true });
416
+ fs.writeFileSync(commonPath, commonYaml.toString(), 'utf8');
417
+ partialsWritten++;
418
+ partialFiles.push(path.relative(process.cwd(), commonPath));
419
+ // Advanced config
420
+ const advYaml = advancedConfig(type, item.name, item.config.children);
421
+ const advPath = path.join(configExamplesRoot, 'advanced', type, `${item.name}.yaml`);
422
+ fs.mkdirSync(path.dirname(advPath), { recursive: true });
423
+ fs.writeFileSync(advPath, advYaml.toString(), 'utf8');
424
+ partialsWritten++;
425
+ partialFiles.push(path.relative(process.cwd(), advPath));
426
+ }
427
+ }
428
+
335
429
  return {
336
430
  partialsWritten,
337
431
  draftsWritten,
@@ -0,0 +1,42 @@
1
+ // Bloblang example formatting helper for Handlebars
2
+ function bloblangExample(example) {
3
+ if (typeof example === 'object' && example !== null && example.mapping) {
4
+ let codeBlock = '';
5
+ if (example.summary && example.summary.trim()) {
6
+ codeBlock += `# ${example.summary.trim().replace(/\n/g, '\n# ')}\n\n`;
7
+ }
8
+ if (typeof example.mapping === 'string') {
9
+ codeBlock += example.mapping.trim() + '\n';
10
+ }
11
+ if (Array.isArray(example.results)) {
12
+ for (const pair of example.results) {
13
+ if (Array.isArray(pair) && pair.length === 2) {
14
+ codeBlock += `\n# In: ${pair[0]}\n# Out: ${pair[1]}\n`;
15
+ }
16
+ }
17
+ }
18
+ return `[,coffeescript]\n----\n${codeBlock.trim()}\n----\n`;
19
+ } else {
20
+ let exStr = '';
21
+ if (typeof example === 'string') {
22
+ exStr = example;
23
+ } else if (typeof example === 'object' && example !== null) {
24
+ if (example.code) {
25
+ exStr = example.code;
26
+ } else if (example.example) {
27
+ exStr = example.example;
28
+ } else {
29
+ try {
30
+ exStr = require('yaml').stringify(example).trim();
31
+ } catch {
32
+ exStr = JSON.stringify(example, null, 2);
33
+ }
34
+ }
35
+ } else {
36
+ exStr = String(example);
37
+ }
38
+ return `[source,coffeescript]\n----\n${exStr}\n----\n`;
39
+ }
40
+ }
41
+
42
+ module.exports = bloblangExample;
@@ -4,10 +4,10 @@ module.exports = {
4
4
  uppercase: require('./uppercase.js'),
5
5
  eq: require('./eq.js'),
6
6
  ne: require('./ne.js'),
7
- join: require('./join.js'),
7
+ join: require('./join.js'),
8
8
  or: require('./or.js'),
9
- toYaml: require('./toYaml.js'),
10
- isObject: require('./isObject.js'),
9
+ toYaml: require('./toYaml.js'),
10
+ isObject: require('./isObject.js'),
11
11
  renderYamlList: require('./renderYamlList.js'),
12
12
  renderConnectFields: require('./renderConnectFields.js'),
13
13
  renderConnectExamples: require('./renderConnectExamples.js'),
@@ -16,4 +16,5 @@ module.exports = {
16
16
  buildConfigYaml: require('./buildConfigYaml.js'),
17
17
  commonConfig: require('./commonConfig.js'),
18
18
  advancedConfig: require('./advancedConfig.js'),
19
+ bloblangExample: require('./bloblangExample.js'),
19
20
  };