Purpose Use this skill when creating diagnostics - the error messages, warnings, and hints shown to users. Covers the Diagnostic trait, advice types, and best practices for clear, actionable messages. Prerequisites Read crates/biome_diagnostics/CONTRIBUTING.md for concepts Understand Biome's Technical Principles Follow the "show don't tell" philosophy Diagnostic Principles Explain what - State what the error is (diagnostic message) Explain why - Explain why it's an error (advice notes) Tell how to fix - Provide actionable fixes (code actions, diff advice, command advice) Follow Technical Principles: Informative: Explain, don't just state Concise: Short messages, rich context via advices Actionable: Always suggest how to fix Show don't tell: Prefer code frames over textual explanations Common Workflows Create a Diagnostic Type Use the
[derive(Diagnostic)]
macro: use biome_diagnostics :: { Diagnostic , category } ;
[derive(Debug, Diagnostic)]
[diagnostic(
severity = Error, category = "lint/correctness/noVar" )] struct NoVarDiagnostic {
[location(span)]
span : TextRange ,
[message]
[description]
message : MessageAndDescription ,
[advice]
advice : NoVarAdvice , }
[derive(Debug)]
struct MessageAndDescription ; impl fmt :: Display for MessageAndDescription { fn fmt ( & self , f : & mut fmt :: Formatter < '_
) -> fmt :: Result { write! ( f , "Use 'let' or 'const' instead of 'var'" ) } } Implement Advices Create advice types that implement Advices trait: use biome_diagnostics :: { Advices , Visit } ; use biome_console :: markup ; struct NoVarAdvice { is_const_candidate : bool , } impl Advices for NoVarAdvice { fn record ( & self , visitor : & mut dyn Visit ) -> std :: io :: Result < ( )
{ if self . is_const_candidate { visitor . record_log ( LogCategory :: Info , & markup! { "This variable is never reassigned, use 'const' instead." } ) ? ; } else { visitor . record_log ( LogCategory :: Info , & markup! { "Variables declared with 'var' are function-scoped, use 'let' for block-scoping." } ) ? ; } Ok ( ( ) ) } } Use Built-in Advice Types use biome_diagnostics :: { LogAdvice , CodeFrameAdvice , DiffAdvice , CommandAdvice , LogCategory } ; // Log advice - simple text message LogAdvice { category : LogCategory :: Info , text : markup! { "Consider using arrow functions." } , } // Code frame advice - highlight code location // Fields: path (AsResource), span (AsSpan), source_code (AsSourceCode) CodeFrameAdvice { path : "file.js" , span : node . text_range ( ) , source_code : ctx . source_code ( ) , } // Diff advice - show a TextEdit diff DiffAdvice { diff : text_edit , // must implement AsRef
} // Command advice - suggest CLI command CommandAdvice { command : "biome check --write" , } In practice, most lint rules use the RuleDiagnostic builder pattern instead of constructing advice types directly. See the Add Diagnostic to Rule section below. Add Diagnostic to Rule use biome_analyze :: { Rule , RuleDiagnostic } ; impl Rule for NoVar { fn diagnostic ( ctx : & RuleContext < Self , state : & Self :: State ) -> Option < RuleDiagnostic
{ let node = ctx . query ( ) ; Some ( RuleDiagnostic :: new ( rule_category! ( ) , node . range ( ) , markup! { "Use " < Emphasis
"let" < / Emphasis
" or " < Emphasis
"const" < / Emphasis
" instead of " < Emphasis
"var" < / Emphasis
"." } , ) . note ( markup! { "Variables declared with " < Emphasis
"var" < / Emphasis
" are function-scoped, not block-scoped." } ) . note ( markup! { "See the " < Hyperlink href = "https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/var"
"MDN documentation" < / Hyperlink
" for more details." } ) ) } } Use Markup for Rich Text Biome supports rich markup in diagnostic messages: use biome_console :: markup ; markup! { // Emphasis (bold/colored) "Use " < Emphasis
"const" < / Emphasis
" instead." // Code/identifiers "The variable " < Emphasis
{ variable_name } < / Emphasis
" is never used." // Hyperlinks "See the " < Hyperlink href = "https://example.com"
"documentation" < / Hyperlink
"." // Interpolation "Found " { count } " issues." } Register Diagnostic Category Add new categories to crates/biome_diagnostics_categories/src/categories.rs : define_categories! { // Existing categories... "lint/correctness/noVar" : "https://biomejs.dev/linter/rules/no-var" , "lint/style/useConst" : "https://biomejs.dev/linter/rules/use-const" , } Create Multi-Advice Diagnostics
[derive(Debug, Diagnostic)]
[diagnostic(severity = Warning)]
struct ComplexDiagnostic {
[location(span)]
span : TextRange ,
[message]
message : & 'static str , // Multiple advices
[advice]
first_advice : LogAdvice < MarkupBuf
,
[advice]
code_frame : CodeFrameAdvice < String , TextRange , String
,
[verbose_advice]
verbose_help : LogAdvice < MarkupBuf
, } Add Tags to Diagnostics
[derive(Debug, Diagnostic)]
[diagnostic(
- severity = Warning,
- tags(FIXABLE, DEPRECATED_CODE) // Add diagnostic tags
- )]
- struct
- MyDiagnostic
- {
- // ...
- }
- Available tags:
- FIXABLE
- - Diagnostic has fix information
- INTERNAL
- - Internal error in Biome
- UNNECESSARY_CODE
- - Code is unused
- DEPRECATED_CODE
- - Code uses deprecated features
- Best Practices
- Message Guidelines
- Good messages:
- // Good - specific and actionable
- "Use 'let' or 'const' instead of 'var'"
- // Good - explains why
- "This variable is never reassigned, consider using 'const'"
- // Good - shows what to do
- "Remove the unused import statement"
- Bad messages:
- // Bad - too vague
- "Invalid syntax"
- // Bad - just states the obvious
- "Variable declared with 'var'"
- // Bad - no guidance
- "This code has a problem"
- Advice Guidelines
- Show, don't tell:
- // Good - shows code frame
- CodeFrameAdvice
- {
- path
- :
- "file.js"
- ,
- span
- :
- node
- .
- text_range
- (
- )
- ,
- source_code
- :
- source
- ,
- }
- // Less helpful - just text
- LogAdvice
- {
- category
- :
- LogCategory
- ::
- Info
- ,
- text
- :
- markup!
- {
- "The expression at line 5 is always truthy"
- }
- ,
- }
- Provide actionable fixes:
- // Good - shows exact change
- DiffAdvice
- {
- diff
- :
- text_edit
- ,
- // AsRef
- }
- // Less helpful - describes change
- LogAdvice
- {
- category
- :
- LogCategory
- ::
- Info
- ,
- text
- :
- markup!
- {
- "Change 'var' to 'const'"
- }
- ,
- }
- Severity Levels
- Choose appropriate severity:
- // Fatal - Biome can't continue
- severity
- =
- Fatal
- // Error - Must be fixed (correctness, security, a11y)
- severity
- =
- Error
- // Warning - Should be fixed (suspicious code)
- severity
- =
- Warning
- // Information - Style suggestions
- severity
- =
- Information
- // Hint - Minor improvements
- severity
- =
- Hint
- Common Patterns
- // Pattern 1: Simple diagnostic with note
- RuleDiagnostic
- ::
- new
- (
- rule_category!
- (
- )
- ,
- node
- .
- range
- (
- )
- ,
- markup!
- {
- "Main message"
- }
- ,
- )
- .
- note
- (
- markup!
- {
- "Additional context"
- }
- )
- // Pattern 2: Diagnostic with code frame
- RuleDiagnostic
- ::
- new
- (
- rule_category!
- (
- )
- ,
- node
- .
- range
- (
- )
- ,
- markup!
- {
- "Main message"
- }
- ,
- )
- .
- detail
- (
- node
- .
- syntax
- (
- )
- .
- text_range
- (
- )
- ,
- markup!
- {
- "This part is problematic"
- }
- )
- // Pattern 3: Diagnostic with link
- RuleDiagnostic
- ::
- new
- (
- rule_category!
- (
- )
- ,
- node
- .
- range
- (
- )
- ,
- markup!
- {
- "Main message"
- }
- ,
- )
- .
- note
- (
- markup!
- {
- "See "
- <
- Hyperlink
- href
- =
- "https://biomejs.dev/linter"
- >
- "documentation"
- <
- /
- Hyperlink
- >
- "."
- }
- )
- // Pattern 4: Conditional advice
- impl
- Advices
- for
- MyAdvice
- {
- fn
- record
- (
- &
- self
- ,
- visitor
- :
- &
- mut
- dyn
- Visit
- )
- ->
- std
- ::
- io
- ::
- Result
- <
- (
- )
- >
- {
- if
- self
- .
- show_hint
- {
- visitor
- .
- record_log
- (
- LogCategory
- ::
- Info
- ,
- &
- markup!
- {
- "Hint: ..."
- }
- )
- ?
- ;
- }
- Ok
- (
- (
- )
- )
- }
- }
- Tips
- Category format
-
- Use
- area/group/ruleName
- format (e.g.,
- lint/correctness/noVar
- )
- Markup formatting
-
- Use
- markup!
- macro for all user-facing text
- Hyperlinks
-
- Always link to documentation for more details
- Code frames
-
- Include for spatial context when helpful
- Multiple advices
-
- Chain multiple pieces of information
- Verbose advices
-
- Use for extra details users can opt into
- Description vs Message
-
- Description for plain text contexts (IDE popover), message for rich display
- Register categories
- Don't forget to add to categories.rs References Full guide: crates/biome_diagnostics/CONTRIBUTING.md Technical principles: https://biomejs.dev/internals/philosophy/#technical Diagnostic trait: crates/biome_diagnostics/src/diagnostic.rs Advice types: crates/biome_diagnostics/src/advice.rs Examples: Search for
[derive(Diagnostic)]
in codebase