@redpanda-data/docs-extensions-and-macros 4.11.1 → 4.12.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.
Files changed (31) hide show
  1. package/bin/doc-tools.js +201 -10
  2. package/package.json +3 -1
  3. package/tools/property-extractor/COMPUTED_CONSTANTS.md +173 -0
  4. package/tools/property-extractor/Makefile +12 -1
  5. package/tools/property-extractor/README.adoc +828 -97
  6. package/tools/property-extractor/compare-properties.js +38 -13
  7. package/tools/property-extractor/constant_resolver.py +610 -0
  8. package/tools/property-extractor/file_pair.py +42 -0
  9. package/tools/property-extractor/generate-handlebars-docs.js +41 -8
  10. package/tools/property-extractor/helpers/gt.js +9 -0
  11. package/tools/property-extractor/helpers/includes.js +17 -0
  12. package/tools/property-extractor/helpers/index.js +3 -0
  13. package/tools/property-extractor/helpers/isEnterpriseEnum.js +24 -0
  14. package/tools/property-extractor/helpers/renderPropertyExample.js +6 -5
  15. package/tools/property-extractor/overrides.json +248 -0
  16. package/tools/property-extractor/parser.py +254 -32
  17. package/tools/property-extractor/property_bag.py +40 -0
  18. package/tools/property-extractor/property_extractor.py +1417 -430
  19. package/tools/property-extractor/requirements.txt +1 -0
  20. package/tools/property-extractor/templates/property-backup.hbs +161 -0
  21. package/tools/property-extractor/templates/property.hbs +104 -49
  22. package/tools/property-extractor/templates/topic-property-backup.hbs +148 -0
  23. package/tools/property-extractor/templates/topic-property.hbs +72 -34
  24. package/tools/property-extractor/tests/test_known_values.py +617 -0
  25. package/tools/property-extractor/tests/transformers_test.py +81 -6
  26. package/tools/property-extractor/topic_property_extractor.py +23 -10
  27. package/tools/property-extractor/transformers.py +2191 -369
  28. package/tools/property-extractor/type_definition_extractor.py +669 -0
  29. package/tools/redpanda-connect/helpers/renderConnectFields.js +33 -1
  30. package/tools/redpanda-connect/report-delta.js +132 -9
  31. package/tools/property-extractor/definitions.json +0 -245
@@ -109,8 +109,9 @@ class NeedsRestartTransformerTestCase(unittest.TestCase):
109
109
  )
110
110
  )
111
111
 
112
- def test_rejects_without_needs_restart(self):
113
- self.assertFalse(
112
+ def test_accepts_without_needs_restart(self):
113
+ """NeedsRestartTransformer now accepts all properties and applies defaults"""
114
+ self.assertTrue(
114
115
  self.transformer.accepts(
115
116
  create_property_info(
116
117
  "test_property", "test description", "bool", PropertyBag()
@@ -251,21 +252,34 @@ class DeprecatedTransformerTestCase(unittest.TestCase):
251
252
  def setUp(self):
252
253
  self.transformer = DeprecatedTransformer()
253
254
 
254
- def test_accepts_deprecated_visibility(self):
255
+ def test_accepts_deprecated_metadata(self):
256
+ """DeprecatedTransformer accepts properties with .deprecated in meta"""
255
257
  self.assertTrue(
256
258
  self.transformer.accepts(
257
259
  create_property_info(
258
260
  "test_property",
259
261
  "test description",
260
262
  "bool",
261
- PropertyBag(visibility="visibility::deprecated"),
263
+ PropertyBag(deprecated="yes"),
262
264
  ),
263
265
  None,
264
266
  )
265
267
  )
266
268
 
267
- def test_accepts_deprecated_property_type(self):
268
- self.assertTrue(
269
+ def test_rejects_without_deprecated_metadata(self):
270
+ """DeprecatedTransformer rejects properties without .deprecated in meta"""
271
+ self.assertFalse(
272
+ self.transformer.accepts(
273
+ create_property_info(
274
+ "test_property",
275
+ "test description",
276
+ "bool",
277
+ PropertyBag(visibility="visibility::deprecated"),
278
+ ),
279
+ None,
280
+ )
281
+ )
282
+ self.assertFalse(
269
283
  self.transformer.accepts(
270
284
  create_property_info(
271
285
  "test_property",
@@ -372,5 +386,66 @@ class IsSecretTransformerTestCase(unittest.TestCase):
372
386
  self.assertFalse(property["is_secret"])
373
387
 
374
388
 
389
+ class FriendlyDefaultTransformerTestCase(unittest.TestCase):
390
+ def setUp(self):
391
+ self.transformer = FriendlyDefaultTransformer()
392
+
393
+ def test_strips_unsigned_integer_suffix(self):
394
+ """Test that C++ unsigned integer suffixes are stripped from defaults"""
395
+ property = PropertyBag()
396
+ info = create_property_info(
397
+ "test_property",
398
+ "test description",
399
+ "uint32_t",
400
+ PropertyBag(needs_restart="needs_restart::no"),
401
+ default_value="1024u",
402
+ default_value_type="number_literal"
403
+ )
404
+ self.transformer.parse(property, info, FilePair("testfile.h", "testfile.cc"))
405
+ self.assertEqual(1024, property["default"])
406
+
407
+ def test_strips_long_integer_suffix(self):
408
+ """Test that C++ long integer suffixes are stripped from defaults"""
409
+ property = PropertyBag()
410
+ info = create_property_info(
411
+ "test_property",
412
+ "test description",
413
+ "int64_t",
414
+ PropertyBag(needs_restart="needs_restart::no"),
415
+ default_value="42L",
416
+ default_value_type="number_literal"
417
+ )
418
+ self.transformer.parse(property, info, FilePair("testfile.h", "testfile.cc"))
419
+ self.assertEqual(42, property["default"])
420
+
421
+ def test_strips_unsigned_long_long_suffix(self):
422
+ """Test that C++ unsigned long long suffixes are stripped from defaults"""
423
+ property = PropertyBag()
424
+ info = create_property_info(
425
+ "test_property",
426
+ "test description",
427
+ "uint64_t",
428
+ PropertyBag(needs_restart="needs_restart::no"),
429
+ default_value="999ULL",
430
+ default_value_type="number_literal"
431
+ )
432
+ self.transformer.parse(property, info, FilePair("testfile.h", "testfile.cc"))
433
+ self.assertEqual(999, property["default"])
434
+
435
+ def test_strips_float_suffix(self):
436
+ """Test that C++ float suffixes are stripped from defaults"""
437
+ property = PropertyBag()
438
+ info = create_property_info(
439
+ "test_property",
440
+ "test description",
441
+ "float",
442
+ PropertyBag(needs_restart="needs_restart::no"),
443
+ default_value="3.14f",
444
+ default_value_type="number_literal"
445
+ )
446
+ self.transformer.parse(property, info, FilePair("testfile.h", "testfile.cc"))
447
+ self.assertAlmostEqual(3.14, property["default"], places=2)
448
+
449
+
375
450
  if __name__ == "__main__":
376
451
  unittest.main()
@@ -107,7 +107,7 @@ class TopicPropertyExtractor:
107
107
  self.topic_properties[property_name] = {
108
108
  "variable_name": f"topic_property_{var_name}",
109
109
  "property_name": property_name,
110
- "source_file": str(file_path.relative_to(self.source_path)),
110
+ "defined_in": str(file_path.relative_to(self.source_path)),
111
111
  "description": "",
112
112
  "type": self._determine_property_type(property_name),
113
113
  "acceptable_values": None,
@@ -120,6 +120,10 @@ class TopicPropertyExtractor:
120
120
 
121
121
  def _scan_file_for_topic_properties(self, file_path: Path):
122
122
  """Scan any file for topic_property_ constants"""
123
+ # Skip admin proxy files - they contain RPC service definitions, not topic properties
124
+ if 'admin/proxy/' in str(file_path):
125
+ return
126
+
123
127
  try:
124
128
  with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
125
129
  content = f.read()
@@ -156,7 +160,7 @@ class TopicPropertyExtractor:
156
160
  self.topic_properties[property_name] = {
157
161
  "variable_name": f"topic_property_{var_name}",
158
162
  "property_name": property_name,
159
- "source_file": str(file_path.relative_to(self.source_path)),
163
+ "defined_in": str(file_path.relative_to(self.source_path)),
160
164
  "description": "",
161
165
  "type": self._determine_property_type(property_name),
162
166
  "acceptable_values": None,
@@ -231,7 +235,7 @@ class TopicPropertyExtractor:
231
235
  values = self._extract_enum_values(enum_body)
232
236
  if values:
233
237
  self.enum_values[enum_name] = {
234
- "source_file": str(file_path.relative_to(self.source_path)),
238
+ "defined_in": str(file_path.relative_to(self.source_path)),
235
239
  "values": values
236
240
  }
237
241
 
@@ -243,7 +247,7 @@ class TopicPropertyExtractor:
243
247
  values = self._extract_enum_values(enum_body)
244
248
  if values:
245
249
  self.enum_values[enum_name] = {
246
- "source_file": str(file_path.relative_to(self.source_path)),
250
+ "defined_in": str(file_path.relative_to(self.source_path)),
247
251
  "values": values
248
252
  }
249
253
 
@@ -265,7 +269,7 @@ class TopicPropertyExtractor:
265
269
  values = self._extract_enum_values(enum_body)
266
270
  if values:
267
271
  self.enum_values[enum_name] = {
268
- "source_file": str(file_path.relative_to(self.source_path)),
272
+ "defined_in": str(file_path.relative_to(self.source_path)),
269
273
  "values": values
270
274
  }
271
275
  except Exception as e:
@@ -273,14 +277,22 @@ class TopicPropertyExtractor:
273
277
 
274
278
  def _is_valid_topic_property(self, prop_name: str) -> bool:
275
279
  """Validate that a string looks like a real topic property"""
276
-
280
+
277
281
  # Must be non-empty and reasonable length
278
282
  if not prop_name or len(prop_name) < 3 or len(prop_name) > 100:
279
283
  return False
280
-
284
+
281
285
  # Must contain only valid characters for topic properties
282
286
  if not re.match(r'^[a-zA-Z][a-zA-Z0-9._-]*$', prop_name):
283
287
  return False
288
+
289
+ # Reject Java-style package names (e.g., "redpanda.core.admin.Service")
290
+ # Topic properties use lowercase with dots (e.g., "cleanup.policy", "segment.ms")
291
+ # Split by dots and check each segment - reject if any segment after first has uppercase
292
+ segments = prop_name.split('.')
293
+ for i, segment in enumerate(segments):
294
+ if i > 0 and segment and segment[0].isupper():
295
+ return False
284
296
 
285
297
  # Known topic property prefixes/patterns
286
298
  valid_patterns = [
@@ -525,10 +537,11 @@ class TopicPropertyExtractor:
525
537
 
526
538
  elif "timestamp.type" in prop_name:
527
539
  return "[`CreateTime`, `LogAppendTime`]"
528
-
540
+
529
541
  elif prop_data.get("type") == "boolean":
530
- return "[`true`, `false`]"
531
-
542
+ # Boolean properties don't need acceptable_values - it's redundant
543
+ return ""
544
+
532
545
  # For numeric properties, determine format based on type and name
533
546
  elif prop_data.get("type") == "number" and "ratio" in prop_name:
534
547
  return "[`0`, `1.0`]"