Documentation
¶
Overview ¶
Package lint provides a unified SQL and project linting framework.
Architecture ¶
The lint package follows a modular architecture with three layers:
- Root package (pkg/lint/): Contains shared contracts, interfaces, and the unified registry
- SQL subsystem (pkg/lint/sql/): SQL statement analysis with dialect-aware rules
- Project subsystem (pkg/lint/project/): Project-level analysis (DAG, naming, architecture)
Rule Registration ¶
Rules are automatically registered via init() functions when their packages are imported:
// Import SQL rules import _ "github.com/leapstack-labs/leapsql/pkg/lint/sql/rules" // Import project rules import _ "github.com/leapstack-labs/leapsql/pkg/lint/project/rules"
Rule Categories ¶
SQL Rules (statement-level):
- AL (Aliasing): Rules about alias usage and naming
- AM (Ambiguous): Rules about ambiguous SQL constructs
- CV (Convention): Rules about SQL coding conventions
- RF (References): Rules about column and table references
- ST (Structure): Rules about SQL query structure
Project Rules (architecture-level):
- PL (Lineage): Rules about data lineage and dependencies
- PM (Modeling): Rules about model structure and organization
- PS (Structure): Rules about project structure and naming
Using the Registry ¶
Query all registered rules:
rules := lint.AllRules() sqlRules := lint.GetAllSQLRules() projectRules := lint.GetAllProjectRules()
Query rules by ID, group, or dialect:
rule, ok := lint.GetRuleByID("AM01")
sqlRules := lint.GetSQLRulesByDialect("postgres")
groupRules := lint.GetSQLRulesByGroup("ambiguous")
Configuration ¶
Use Config to control which rules are enabled and their severity:
config := lint.NewConfig()
config.Disable("AM01")
config.SetSeverity("CV05", core.SeverityError)
config.SetRuleOptions("AL06", map[string]any{"min_length": 3})
Creating Custom Rules ¶
For SQL rules, implement the SQLRule interface or use RuleDef:
var MyRule = sql.RuleDef{
ID: "MY01",
Name: "my.custom_rule",
Group: "custom",
Description: "My custom rule description",
Severity: core.SeverityWarning,
Check: checkMyRule,
}
func init() {
sql.Register(MyRule)
}
For project rules, implement the ProjectRule interface in the project package.
Index ¶
- Constants
- Variables
- func AllRules() []core.RuleInfo
- func BuildDocURL(ruleID string) string
- func Clear()
- func CountProjectRules() int
- func CountSQLRules() int
- func GetBoolOption(opts map[string]any, key string, defaultVal bool) bool
- func GetIntOption(opts map[string]any, key string, defaultVal int) int
- func GetOption[T any](opts map[string]any, key string, defaultVal T) T
- func GetRuleInfo(r Rule) core.RuleInfo
- func GetStringOption(opts map[string]any, key string, defaultVal string) string
- func GetStringSliceOption(opts map[string]any, key string, defaultVal []string) []string
- func RegisterProjectRule(rule ProjectRule)
- func RegisterSQLRule(rule SQLRule)
- func ResetDocsBaseURL()
- func SetDocsBaseURL(url string)
- type Analyzer
- type CheckFunc
- type Config
- func (c *Config) Disable(ruleID string) *Config
- func (c *Config) GetRuleOptions(ruleID string) map[string]any
- func (c *Config) GetSeverity(ruleID string, defaultSeverity core.Severity) core.Severity
- func (c *Config) IsDisabled(ruleID string) bool
- func (c *Config) SetRuleOptions(ruleID string, opts map[string]any) *Config
- func (c *Config) SetSeverity(ruleID string, severity core.Severity) *Config
- type Diagnostic
- type DialectInfo
- type Fix
- type ImpactLevel
- type ModelInfo
- type ProjectContext
- type ProjectHealthConfig
- type ProjectProvider
- type ProjectRule
- type Provider
- type Registry
- type RelatedInfo
- type Rule
- type RuleDef
- type SQLProvider
- type SQLRule
- type TextEdit
Constants ¶
const DefaultDocsBaseURL = "https://leapsql.dev/docs/rules"
DefaultDocsBaseURL is the hosted documentation site.
Variables ¶
var DocsBaseURL = DefaultDocsBaseURL
DocsBaseURL can be overridden via config for local/offline mode.
Functions ¶
func BuildDocURL ¶
BuildDocURL constructs a documentation URL for a rule.
func CountProjectRules ¶
func CountProjectRules() int
CountProjectRules returns the number of registered project rules.
func CountSQLRules ¶
func CountSQLRules() int
CountSQLRules returns the number of registered SQL rules.
func GetBoolOption ¶
GetBoolOption extracts a bool option.
func GetIntOption ¶
GetIntOption extracts an int option, handling float64 from JSON.
func GetRuleInfo ¶
GetRuleInfo extracts metadata from a Rule for documentation/tooling.
func GetStringOption ¶
GetStringOption extracts a string option.
func GetStringSliceOption ¶
GetStringSliceOption extracts a string slice option.
func RegisterProjectRule ¶
func RegisterProjectRule(rule ProjectRule)
RegisterProjectRule adds a project rule to the registry. Call this from init() functions in rule packages.
func RegisterSQLRule ¶
func RegisterSQLRule(rule SQLRule)
RegisterSQLRule adds an SQL rule to the registry. Call this from init() functions in rule packages.
func ResetDocsBaseURL ¶
func ResetDocsBaseURL()
ResetDocsBaseURL resets to the default documentation URL.
func SetDocsBaseURL ¶
func SetDocsBaseURL(url string)
SetDocsBaseURL overrides the default documentation base URL. Useful for offline mode or custom documentation sites.
Types ¶
type Analyzer ¶
type Analyzer struct {
// contains filtered or unexported fields
}
Analyzer runs lint rules against parsed SQL.
func NewAnalyzer ¶
NewAnalyzer creates a new analyzer with optional configuration.
func NewAnalyzerWithRegistry ¶
NewAnalyzerWithRegistry creates an analyzer that uses registry rules filtered by dialect.
func (*Analyzer) Analyze ¶
func (a *Analyzer) Analyze(stmt any, dialect DialectInfo) []Diagnostic
Analyze runs all rules from the dialect against the statement. The stmt parameter should be *core.SelectStmt.
func (*Analyzer) AnalyzeMultiple ¶
func (a *Analyzer) AnalyzeMultiple(stmts []any, dialect DialectInfo) []Diagnostic
AnalyzeMultiple runs analysis on multiple statements.
func (*Analyzer) AnalyzeWithRegistryRules ¶
func (a *Analyzer) AnalyzeWithRegistryRules(stmt any, dialect DialectInfo) []Diagnostic
AnalyzeWithRegistryRules runs all registered rules against the statement. This is an alias for Analyze for backward compatibility.
type CheckFunc ¶
type CheckFunc func(stmt any, dialect DialectInfo, opts map[string]any) []Diagnostic
CheckFunc analyzes a statement and returns diagnostics. The stmt parameter is *core.SelectStmt passed as any to avoid import cycles. The opts parameter contains rule-specific options from configuration.
type Config ¶
type Config struct {
// DisabledRules contains rule IDs to skip
DisabledRules map[string]bool
// SeverityOverrides changes the default severity of rules
SeverityOverrides map[string]core.Severity
// RuleOptions contains rule-specific configuration
RuleOptions map[string]map[string]any
}
Config controls which rules are enabled and their severity.
func NewConfig ¶
func NewConfig() *Config
NewConfig creates a default configuration with all rules enabled.
func (*Config) GetRuleOptions ¶
GetRuleOptions returns options for a specific rule.
func (*Config) GetSeverity ¶
GetSeverity returns the severity for a rule, applying any override.
func (*Config) IsDisabled ¶
IsDisabled returns true if the rule should be skipped.
func (*Config) SetRuleOptions ¶
SetRuleOptions sets options for a specific rule.
type Diagnostic ¶
type Diagnostic struct {
RuleID string
Severity core.Severity
Message string
Pos token.Position
EndPos token.Position // Optional: end of the problematic range
Fixes []Fix // Optional: suggested fixes (for LSP code actions)
// Remediation metadata
DocumentationURL string // URL to rule documentation, e.g., "https://leapsql.dev/docs/rules/AM01"
ImpactScore int // 0-100, used for health score weighting
AutoFixable bool // true if Fixes can be auto-applied
RelatedInfo []RelatedInfo // Additional locations/context
}
Diagnostic represents a lint finding.
type DialectInfo ¶
type DialectInfo interface {
GetName() string
IsClauseToken(t token.TokenType) bool
NormalizeName(name string) string
IsWindow(name string) bool
}
DialectInfo is a minimal interface to avoid importing the full dialect package. Implemented by core.Dialect.
type ImpactLevel ¶
type ImpactLevel int
ImpactLevel represents predefined impact score ranges.
const ( // ImpactLow for minor issues (0-30) ImpactLow ImpactLevel = 20 // ImpactMedium for moderate issues (31-60) ImpactMedium ImpactLevel = 50 // ImpactHigh for significant issues (61-80) ImpactHigh ImpactLevel = 70 // ImpactCritical for critical issues (81-100) ImpactCritical ImpactLevel = 90 )
type ModelInfo ¶
type ModelInfo struct {
Path string // Model path (e.g., "staging.customers")
Name string // Model name (e.g., "stg_customers")
FilePath string // Absolute path to .sql file
Type core.ModelType // Inferred or explicit model type
Sources []string // Table references (deps)
Columns []core.ColumnInfo // Column-level lineage
Materialized string // table, view, incremental
Tags []string // Metadata tags
Meta map[string]any // Custom metadata
}
ModelInfo represents a model for project-level analysis. This mirrors the data needed from parser.ModelConfig without importing it.
type ProjectContext ¶
type ProjectContext interface {
// GetModels returns all models indexed by path.
GetModels() map[string]ModelInfo
// GetParents returns upstream model paths for a given model.
GetParents(modelPath string) []string
// GetChildren returns downstream model paths for a given model.
GetChildren(modelPath string) []string
// GetConfig returns the project health configuration.
GetConfig() ProjectHealthConfig
}
ProjectContext provides access to project data for project-level rules. This is an interface to avoid import cycles between lint and project packages.
type ProjectHealthConfig ¶
type ProjectHealthConfig struct {
ModelFanoutThreshold int // PM04: default 3
TooManyJoinsThreshold int // PM05: default 7
PassthroughColumnThreshold int // PL01: default 20
StarlarkComplexityThreshold int // PT01: default 10
}
ProjectHealthConfig holds configurable thresholds for project health rules.
func DefaultProjectHealthConfig ¶
func DefaultProjectHealthConfig() ProjectHealthConfig
DefaultProjectHealthConfig returns the default configuration.
type ProjectProvider ¶
type ProjectProvider interface {
Provider
// AnalyzeProject runs project-level rules and returns diagnostics.
// The context parameter provides all project data needed for analysis.
AnalyzeProject(ctx ProjectContext) []Diagnostic
}
ProjectProvider analyzes project-level concerns. Implemented by the project health analyzer for DAG/architecture linting.
type ProjectRule ¶
type ProjectRule interface {
Rule
// CheckProject analyzes the project context and returns diagnostics.
CheckProject(ctx ProjectContext) []Diagnostic
}
ProjectRule analyzes project-level concerns. Implemented by rules that check DAG structure, naming conventions, etc.
func GetAllProjectRules ¶
func GetAllProjectRules() []ProjectRule
GetAllProjectRules returns all registered project rules.
func GetProjectRuleByID ¶
func GetProjectRuleByID(id string) (ProjectRule, bool)
GetProjectRuleByID returns a project rule by its ID.
func GetProjectRulesByGroup ¶
func GetProjectRulesByGroup(group string) []ProjectRule
GetProjectRulesByGroup returns project rules in a specific group.
type Provider ¶
type Provider interface {
Name() string
}
Provider is the base interface for all lint providers.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry stores all registered lint rules (both SQL and project).
type RelatedInfo ¶
RelatedInfo provides additional context for a diagnostic.
type Rule ¶
type Rule interface {
// ID returns the unique identifier, e.g., "AM01" or "PM01"
ID() string
// Name returns the human-readable name, e.g., "ambiguous.distinct"
Name() string
// Group returns the category, e.g., "ambiguous", "structure", "modeling"
Group() string
// Description returns a human-readable description
Description() string
// DefaultSeverity returns the default severity for this rule
DefaultSeverity() core.Severity
// ConfigKeys returns configuration keys this rule accepts
ConfigKeys() []string
// Documentation methods for richer rule documentation
Rationale() string // Why this rule exists, what problems it prevents
BadExample() string // Code showing the anti-pattern
GoodExample() string // Code showing the correct pattern
Fix() string // How to fix violations (when not obvious)
}
Rule is the base interface all lint rules implement. This provides a unified interface for both SQL-level and project-level rules.
func GetRuleByID ¶
GetRuleByID returns any rule by its ID, checking both SQL and project rules.
type RuleDef ¶
type RuleDef struct {
ID string // Unique identifier, e.g., "AM01" or "ansi/select-star"
Name string // Human-readable name, e.g., "ambiguous.distinct"
Group string // Category, e.g., "ambiguous", "structure", "convention"
Description string // Human-readable description
Severity core.Severity // Default severity
Check CheckFunc // The check function
ConfigKeys []string // Configuration keys this rule accepts (for rule-specific options)
Dialects []string // Restrict to specific dialects; nil/empty means all dialects
// Documentation fields for richer rule documentation
Rationale string // Why this rule exists, what problems it prevents
BadExample string // Code showing the anti-pattern
GoodExample string // Code showing the correct pattern
Fix string // How to fix violations (when not obvious)
}
RuleDef is a data-driven rule definition used by dialects for dialect-specific rules. Rules are stateless - all context comes via the Check function parameters. The Check function receives an `any` type that should be *core.SelectStmt. This avoids import cycles between lint -> parser -> dialect -> lint.
type SQLProvider ¶
type SQLProvider interface {
Provider
AnalyzeStatement(stmt any, dialect DialectInfo) []Diagnostic
}
SQLProvider analyzes individual SQL statements. Implemented by the SQL analyzer for statement-level linting.
type SQLRule ¶
type SQLRule interface {
Rule
// CheckSQL analyzes a statement and returns diagnostics.
// The stmt parameter is *core.SelectStmt passed as any to avoid import cycles.
// The opts parameter contains rule-specific options from configuration.
CheckSQL(stmt any, dialect DialectInfo, opts map[string]any) []Diagnostic
// Dialects returns dialect restrictions; nil/empty means all dialects.
Dialects() []string
}
SQLRule analyzes individual SQL statements. Implemented by rules that check SQL syntax and structure.
func GetAllSQLRules ¶
func GetAllSQLRules() []SQLRule
GetAllSQLRules returns all registered SQL rules.
func GetSQLRuleByID ¶
GetSQLRuleByID returns an SQL rule by its ID.
func GetSQLRulesByDialect ¶
GetSQLRulesByDialect returns SQL rules applicable to a specific dialect. Rules with empty/nil Dialects are included (they apply to all dialects).
func GetSQLRulesByGroup ¶
GetSQLRulesByGroup returns SQL rules in a specific group.
func WrapRuleDef ¶
WrapRuleDef wraps a RuleDef to implement SQLRule interface.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package project provides project-level linting for LeapSQL.
|
Package project provides project-level linting for LeapSQL. |
|
rules
Package projectrules registers all project health lint rules.
|
Package projectrules registers all project health lint rules. |
|
Package sql provides SQL statement-level linting rules and analysis.
|
Package sql provides SQL statement-level linting rules and analysis. |
|
internal/ast
Package ast provides AST traversal utilities for SQL lint rules.
|
Package ast provides AST traversal utilities for SQL lint rules. |
|
rules
Package rules contains all SQL lint rules.
|
Package rules contains all SQL lint rules. |