Skip to content

Writing Custom Rules

Learn how to write custom lint rules using GritQL for project-specific validation.

  • Understanding of FSH syntax
  • Basic pattern matching concepts
  • GritQL syntax basics (see GritQL Rules)

Create a directory for custom rules:

Terminal window
mkdir custom-rules

Configure FSH Lint to load custom rules:

{
"linter": {
"ruleDirectories": ["./custom-rules"]
}
}

A GritQL rule file (.grit) contains:

  1. Metadata (language, description, severity)
  2. Pattern to match
  3. Conditions (optional)
  4. Message
  5. Fix (optional)

Create custom-rules/profile-naming.grit:

language fsh
description "Profiles must end with 'Profile'"
severity error
pattern {
Profile: $name
}
where {
!ends_with($name, "Profile")
}
message "Profile name '${name}' should end with 'Profile'"
fix {
Profile: `${name}Profile`
}

Create custom-rules/require-ms.grit:

language fsh
description "Required fields must have MS flag"
severity warning
pattern {
Profile: $_
* $path 1..1 $flags
}
where {
!contains($flags, "MS")
}
message "Add MS flag to required field: ${path}"
fix {
* $path 1..1 MS
}

Create custom-rules/require-description.grit:

language fsh
description "All profiles must have descriptions"
severity warning
pattern {
Profile: $name
$...content
}
where {
!any_match($content, "Description:")
}
message "Profile '${name}' is missing a description"

Test your rules before deploying:

Terminal window
# Test on specific files
fsh-lint lint --rule custom/profile-naming test.fsh
# Run only custom rules
fsh-lint lint --only-custom **/*.fsh
pattern {
Profile: $name
* $path from $vs (required)
}
where {
ends_with($path, "code") and
!is_uri($vs)
}
message "Code bindings should use full URI: ${vs}"
pattern {
or {
{ ValueSet: $name }
{ CodeSystem: $name }
}
}
where {
!contains($name, "VS") and
!contains($name, "CS")
}
  1. Start Simple - Begin with basic patterns
  2. Test Thoroughly - Test on various FSH files
  3. Clear Messages - Help users understand violations
  4. Provide Fixes - Automate fixes when possible
  5. Document Rules - Explain the reasoning
  6. Performance - Avoid overly complex patterns

Share rules across projects:

Terminal window
# Create shared rules repository
git clone https://github.com/yourorg/fsh-lint-rules.git
# Reference in config
{
"linter": {
"ruleDirectories": [
"./fsh-lint-rules"
]
}
}