{"record":{"id":"65a084b63604ca3b","repo":"sxyazi/yazi","slug":"kind-kind-must-be-in-kebab-case","errorCode":null,"errorMessage":"Kind `{kind}` must be in kebab-case","messagePattern":"Kind `(.+?)` must be in kebab-case","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"yazi-dds/src/ember/ember.rs","lineNumber":95,"sourceCode":"\t\t\t\t| \"delete\"\n\t\t\t\t| \"download\"\n\t\t\t\t| \"input\"\n\t\t\t\t| \"mount\"\n\t\t\t\t| \"theme\"\n\t\t) || kind.starts_with(\"key-\")\n\t\t\t|| kind.starts_with(\"ind-\")\n\t\t\t|| kind.starts_with(\"emit-\")\n\t\t\t|| kind.starts_with(\"relay-\")\n\t\t{\n\t\t\tbail!(\"Cannot construct system event\");\n\t\t}\n\n\t\tlet mut it = kind.bytes().peekable();\n\t\tif it.peek() == Some(&b'@') {\n\t\t\tit.next(); // Skip `@` as it's a prefix for static messages\n\t\t}\n\t\tif !it.all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'z' | b'-')) {\n\t\t\tbail!(\"Kind `{kind}` must be in kebab-case\");\n\t\t}\n\n\t\tOk(())\n\t}\n}\n\nimpl<'a> Ember<'a> {\n\tpub fn kind(&self) -> &str {\n\t\tmatch self {\n\t\t\tSelf::Hi(_) => \"hi\",\n\t\t\tSelf::Hey(_) => \"hey\",\n\t\t\tSelf::Bye(_) => \"bye\",\n\t\t\tSelf::Tab(_) => \"tab\",\n\t\t\tSelf::Cd(_) => \"cd\",\n\t\t\tSelf::Load(_) => \"load\",\n\t\t\tSelf::Hover(_) => \"hover\",\n\t\t\tSelf::Rename(_) => \"rename\",\n\t\t\tSelf::BulkRename(_) => \"bulk-rename\",","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/sxyazi/yazi/blob/5f901b886b14de1f17460b6e52e9de5d67f8aba9/yazi-dds/src/ember/ember.rs#L77-L113","documentation":"The same Ember validation (yazi-dds/src/ember/ember.rs:95) enforces that event kinds are kebab-case: after optionally stripping the leading `@` (static-message prefix), every byte must be a digit, lowercase ASCII letter, or `-`. Any uppercase letter, underscore, dot, or other character bails.","triggerScenarios":"Validating an Ember whose kind contains characters outside `0-9 a-z -` (after an optional leading `@`), e.g. `MyEvent`, `my_event`, `plugin.name.event`.","commonSituations":"Plugin authors naming events in camelCase or snake_case out of habit, or programmatically deriving kind names from filenames/identifiers that contain dots or underscores.","solutions":["Rewrite the kind in kebab-case, e.g. `my_event` -> `my-event`, `MyEvent` -> `my-event`.","Sanitize/normalize the kind (lowercase, replace `_`/`.` with `-`) before validation.","If it is a static message, confirm the `@` prefix is present so it is stripped before the kebab-case check."],"exampleFix":"// before\nEmber::validate(\"my_plugin_updated\")?;\n// after\nEmber::validate(\"my-plugin-updated\")?;","handlingStrategy":"validation","validationCode":"fn is_kebab_kind(kind: &str) -> bool {\n    let k = kind.strip_prefix('@').unwrap_or(kind);\n    !k.is_empty()\n        && k.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'z' | b'-'))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize event names to lowercase kebab-case at the plugin boundary (replace `_`/`.`/space with `-`).","Remember to prefix static messages with `@` so it is stripped before the check.","Add a unit test asserting every emitted kind matches ^[a-z0-9-]+$."],"tags":["dds","event-kind","naming-convention","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"5f901b886b14de1f17460b6e52e9de5d67f8aba9","analyzedAt":"2026-09-02T18:38:25.566Z","contentChangedAt":"2026-09-02T18:38:25.566Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}