fix(docgen): only strip trailing digits from wrapper type names

Previously, add_wrapper_display_names() would add a _display_name field
to ALL types with trailing digits, incorrectly affecting legitimate type
names like Base16, Sha256, or Level3.

Now the function only strips trailing digits from types that are marked
as wrapper types (_wrapper_type: true), leaving other type names intact.

Adds comprehensive tests for both cases:
- Legitimate type names ending in digits remain unchanged
- Wrapper type variants (e.g., PerAnimationPrefixConfig2) get proper
  _display_name fields with digits stripped
This commit is contained in:
LGUG2Z committed 2025-12-22 19:33:22 -08:00
1 parent 6bf0975898
commit 62050f8a24
2 files changed
+155 -22

No files matched your search

+8 -8
View File
@@ -184,7 +184,7 @@
]
},
"float_rule_placement": {
"description": "Determines the `Placement` to be used when spawning a window that matches a\n'floating_applications' rule (default: None)",
"description": "Determines the `Placement` to be used when spawning a window that matches a\n`floating_applications` rule (default: None)",
"anyOf": [
{
"$ref": "#/$defs/Placement"
@@ -283,7 +283,7 @@
"deprecated": true
},
"layered_applications": {
"description": "Identify applications that have the WS_EX_LAYERED extended window style",
"description": "Identify applications that have the `WS_EX_LAYERED` extended window style",
"type": [
"array",
"null"
@@ -349,7 +349,7 @@
]
},
"object_name_change_applications": {
"description": "Identify applications that send EVENT_OBJECT_NAMECHANGE on launch (very rare)",
"description": "Identify applications that send `EVENT_OBJECT_NAMECHANGE` on launch (very rare)",
"type": [
"array",
"null"
@@ -359,7 +359,7 @@
}
},
"object_name_change_title_ignore_list": {
"description": "Do not process EVENT_OBJECT_NAMECHANGE events as Show events for identified applications matching these title regexes",
"description": "Do not process `EVENT_OBJECT_NAMECHANGE` events as Show events for identified applications matching these title regexes",
"type": [
"array",
"null"
@@ -638,11 +638,11 @@
"AppSpecificConfigurationPath": {
"anyOf": [
{
"description": "A single applications.json file",
"description": "A single `applications.json` file",
"$ref": "#/$defs/PathBuf"
},
{
"description": "Multiple applications.json files",
"description": "Multiple `applications.json` files",
"type": "array",
"items": {
"$ref": "#/$defs/PathBuf"
@@ -1290,13 +1290,13 @@
"HidingBehaviour": {
"oneOf": [
{
"description": "END OF LIFE FEATURE: Use the SW_HIDE flag to hide windows when switching workspaces (has issues with Electron apps)",
"description": "END OF LIFE FEATURE: Use the `SW_HIDE` flag to hide windows when switching workspaces (has issues with Electron apps)",
"type": "string",
"const": "Hide",
"deprecated": true
},
{
"description": "Use the SW_MINIMIZE flag to hide windows when switching workspaces (has issues with frequent workspace switching)",
"description": "Use the `SW_MINIMIZE` flag to hide windows when switching workspaces (has issues with frequent workspace switching)",
"type": "string",
"const": "Minimize"
},
+147 -14
View File
@@ -30,25 +30,28 @@ pub fn prepare_for_template(value: &Value) -> Value {
prepared
}
/// Add display names to types by stripping numeric suffixes
/// Add display names to wrapper types by stripping numeric suffixes
///
/// For types like `PerAnimationPrefixConfig2` or `DisplayFormat2`, this adds a
/// `_display_name` field with the base name (e.g., `PerAnimationPrefixConfig`).
/// This applies to all types with trailing digits, not just wrapper types.
/// For wrapper types like `PerAnimationPrefixConfig2` or `PerAnimationPrefixConfig3`,
/// this adds a `_display_name` field with the base name (e.g., `PerAnimationPrefixConfig`).
/// This only applies to types marked with `_wrapper_type: true`, not all types ending in digits.
/// Legitimate type names like `Base16` or `Sha256` are left unchanged.
fn add_wrapper_display_names(schema: &mut Value) {
if let Some(defs) = schema.get_mut("$defs").and_then(|v| v.as_object_mut()) {
for (name, def) in defs.iter_mut() {
// Strip trailing digits from ALL type names (not just wrapper types)
let display_name = name.trim_end_matches(|c: char| c.is_ascii_digit());
// Only strip trailing digits from wrapper types (not all types)
if def.get("_wrapper_type") == Some(&Value::Bool(true)) {
let display_name = name.trim_end_matches(|c: char| c.is_ascii_digit());
// Only add _display_name if it differs from the original name
if display_name != name
&& let Some(obj) = def.as_object_mut()
{
obj.insert(
"_display_name".to_string(),
Value::String(display_name.to_string()),
);
// Only add _display_name if it differs from the original name
if display_name != name
&& let Some(obj) = def.as_object_mut()
{
obj.insert(
"_display_name".to_string(),
Value::String(display_name.to_string()),
);
}
}
}
}
@@ -2307,4 +2310,134 @@ mod tests {
"Object with properties (not additionalProperties) should NOT be wrapper"
);
}
#[test]
fn test_type_names_ending_in_digits_not_stripped() {
// Legitimate type names ending in digits should NOT have _display_name added
let schema = json!({
"$defs": {
"Base16": { "type": "string" },
"Sha256": { "type": "string" },
"Level3": { "type": "object" }
}
});
let prepared = prepare_for_template(&schema);
let defs = prepared.get("$defs").unwrap().as_object().unwrap();
// Type names that legitimately end in digits should NOT have _display_name added
assert!(
defs.get("Base16").unwrap().get("_display_name").is_none(),
"Base16 should not have _display_name"
);
assert!(
defs.get("Sha256").unwrap().get("_display_name").is_none(),
"Sha256 should not have _display_name"
);
assert!(
defs.get("Level3").unwrap().get("_display_name").is_none(),
"Level3 should not have _display_name"
);
}
#[test]
fn test_wrapper_types_get_display_name_stripped() {
// Real-world pattern from komorebi: PerAnimationPrefixConfig<T> generates
// multiple $defs entries for different type parameters:
// - PerAnimationPrefixConfig (bool)
// - PerAnimationPrefixConfig2 (uint64)
// - PerAnimationPrefixConfig3 (AnimationStyle ref)
// All should display as "PerAnimationPrefixConfig"
let schema = json!({
"$defs": {
"AnimationStyle": { "type": "string" },
"PerAnimationPrefixConfig": {
"anyOf": [
{
"type": "object",
"additionalProperties": { "type": "boolean" }
},
{ "type": "boolean" }
]
},
"PerAnimationPrefixConfig2": {
"anyOf": [
{
"type": "object",
"additionalProperties": {
"type": "integer",
"format": "uint64",
"minimum": 0
}
},
{
"type": "integer",
"format": "uint64",
"minimum": 0
}
]
},
"PerAnimationPrefixConfig3": {
"anyOf": [
{
"type": "object",
"additionalProperties": { "$ref": "#/$defs/AnimationStyle" }
},
{ "$ref": "#/$defs/AnimationStyle" }
]
}
}
});
let prepared = prepare_for_template(&schema);
let defs = prepared.get("$defs").unwrap().as_object().unwrap();
// All three should be detected as wrapper types
assert_eq!(
defs.get("PerAnimationPrefixConfig")
.unwrap()
.get("_wrapper_type"),
Some(&json!(true)),
"PerAnimationPrefixConfig should be detected as wrapper type"
);
assert_eq!(
defs.get("PerAnimationPrefixConfig2")
.unwrap()
.get("_wrapper_type"),
Some(&json!(true)),
"PerAnimationPrefixConfig2 should be detected as wrapper type"
);
assert_eq!(
defs.get("PerAnimationPrefixConfig3")
.unwrap()
.get("_wrapper_type"),
Some(&json!(true)),
"PerAnimationPrefixConfig3 should be detected as wrapper type"
);
// The base type has no digits, so no _display_name needed
assert!(
defs.get("PerAnimationPrefixConfig")
.unwrap()
.get("_display_name")
.is_none(),
"Base wrapper type should not have _display_name"
);
// Numbered variants should have display name with digits stripped
assert_eq!(
defs.get("PerAnimationPrefixConfig2")
.unwrap()
.get("_display_name"),
Some(&json!("PerAnimationPrefixConfig")),
"PerAnimationPrefixConfig2 should have digits stripped"
);
assert_eq!(
defs.get("PerAnimationPrefixConfig3")
.unwrap()
.get("_display_name"),
Some(&json!("PerAnimationPrefixConfig")),
"PerAnimationPrefixConfig3 should have digits stripped"
);
}
}