whitespace

package
v1.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package whitespace provides linting rules for whitespace and formatting issues.

This package includes 6 whitespace-related rules (L001-L005, L010) that enforce consistent whitespace usage, indentation, and line formatting in SQL code.

Rules in this Package

L001: Trailing Whitespace (auto-fix)

  • Detects and removes unnecessary trailing spaces or tabs at line ends
  • Severity: Warning
  • Common issue: Editor artifacts, copy-paste problems

L002: Mixed Indentation (auto-fix)

  • Enforces consistent use of tabs or spaces for indentation
  • Converts all indentation to spaces (4 spaces per tab)
  • Severity: Error
  • Common issue: Multiple developers with different editor settings

L003: Consecutive Blank Lines (auto-fix)

  • Limits consecutive blank lines to a configurable maximum
  • Default: Maximum 1 blank line between statements
  • Severity: Warning
  • Common issue: Excessive vertical spacing reducing code density

L004: Indentation Depth (no auto-fix)

  • Warns about excessive indentation depth indicating complex queries
  • Configurable maximum depth (default: 4 levels)
  • Severity: Warning
  • Common issue: Deeply nested subqueries needing refactoring

L005: Line Length (no auto-fix)

  • Enforces maximum line length for readability
  • Configurable maximum (default: 100 characters)
  • Skips comment-only lines
  • Severity: Info
  • Common issue: Long lines hard to read in code reviews

L010: Redundant Whitespace (auto-fix)

  • Removes multiple consecutive spaces (preserves indentation and strings)
  • Severity: Info
  • Common issue: Inconsistent spacing between SQL keywords

Usage Examples

Using trailing whitespace rule:

import "github.com/ajitpratap0/GoSQLX/pkg/linter/rules/whitespace"

rule := whitespace.NewTrailingWhitespaceRule()
violations, err := rule.Check(ctx)
if len(violations) > 0 {
    fixed, _ := rule.Fix(sql, violations)
    // Use fixed SQL
}

Using mixed indentation rule:

rule := whitespace.NewMixedIndentationRule()
violations, _ := rule.Check(ctx)
// Converts all tabs to 4 spaces
fixed, _ := rule.Fix(sql, violations)

Using consecutive blank lines with custom limit:

rule := whitespace.NewConsecutiveBlankLinesRule(2)  // Allow max 2 blank lines
violations, _ := rule.Check(ctx)
fixed, _ := rule.Fix(sql, violations)

Using indentation depth with custom settings:

rule := whitespace.NewIndentationDepthRule(5, 4)  // Max 5 levels, 4 spaces per level
violations, _ := rule.Check(ctx)
// No auto-fix available - violations indicate refactoring needed

Using line length with custom maximum:

rule := whitespace.NewLongLinesRule(120)  // Max 120 characters
violations, _ := rule.Check(ctx)
// No auto-fix available - requires manual line breaking

Using redundant whitespace rule:

rule := whitespace.NewRedundantWhitespaceRule()
violations, _ := rule.Check(ctx)
fixed, _ := rule.Fix(sql, violations)  // Multiple spaces become single space

Auto-Fix Behavior

Four rules support auto-fixing (L001, L002, L003, L010):

L001 (Trailing Whitespace):

  • Strips trailing spaces and tabs from each line
  • Preserves line content and newlines
  • Safe to apply without review

L002 (Mixed Indentation):

  • Converts tabs to 4 spaces in leading whitespace only
  • Preserves tabs inside SQL strings and comments
  • Should be reviewed if project uses tabs intentionally

L003 (Consecutive Blank Lines):

  • Reduces consecutive blank lines to configured maximum
  • Trims excess blank lines at file end
  • Safe to apply without review

L010 (Redundant Whitespace):

  • Reduces 2+ consecutive spaces to single space
  • Preserves leading indentation
  • Preserves spaces inside string literals
  • Safe to apply without review

Rules without auto-fix (L004, L005) require manual refactoring or line breaking.

Configuration Recommendations

Production environments:

whitespace.NewTrailingWhitespaceRule()              // Always enable
whitespace.NewMixedIndentationRule()                // Always enable
whitespace.NewConsecutiveBlankLinesRule(1)          // 1 blank line max
whitespace.NewIndentationDepthRule(4, 4)            // Warn at 4 levels
whitespace.NewLongLinesRule(100)                    // 100 char limit
whitespace.NewRedundantWhitespaceRule()             // Always enable

Strict style enforcement:

whitespace.NewTrailingWhitespaceRule()              // Error on trailing whitespace
whitespace.NewMixedIndentationRule()                // Error on mixed indentation
whitespace.NewConsecutiveBlankLinesRule(1)          // Max 1 blank line
whitespace.NewIndentationDepthRule(3, 4)            // Warn at 3 levels (stricter)
whitespace.NewLongLinesRule(80)                     // 80 char limit (stricter)
whitespace.NewRedundantWhitespaceRule()             // Clean up spacing

Relaxed style (legacy code):

whitespace.NewTrailingWhitespaceRule()              // Still remove trailing whitespace
// Skip L002 if tabs are intentional
whitespace.NewConsecutiveBlankLinesRule(2)          // Allow 2 blank lines
whitespace.NewIndentationDepthRule(6, 4)            // Warn only at 6 levels
whitespace.NewLongLinesRule(120)                    // 120 char limit
// Skip L010 if varied spacing is intentional

Performance Characteristics

All whitespace rules are text-based and do not require tokenization or parsing. They operate on line-by-line scanning with O(n) complexity where n is line count.

Typical performance (lines per second):

  • L001, L002, L003, L010: 100,000+ lines/sec
  • L004: 80,000+ lines/sec (includes depth calculation)
  • L005: 100,000+ lines/sec

Auto-fix operations add minimal overhead (<10% slowdown).

Thread Safety

All rule types in this package are stateless and thread-safe. Rule instances can be shared across goroutines safely.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConsecutiveBlankLinesRule

type ConsecutiveBlankLinesRule struct {
	linter.BaseRule
	// contains filtered or unexported fields
}

ConsecutiveBlankLinesRule (L003) detects and fixes excessive consecutive blank lines.

Excessive blank lines reduce code density and make it harder to view complete queries on screen. This rule enforces a configurable maximum number of consecutive blank lines, improving readability without eliminating vertical spacing entirely.

Rule ID: L003 Severity: Warning Auto-fix: Supported

Example violation (maxConsecutive=1):

SELECT * FROM users

WHERE active = true  <- Two blank lines above (violation)

Fixed output:

SELECT * FROM users

WHERE active = true  <- Single blank line

The rule also removes excessive blank lines at the end of files.

func NewConsecutiveBlankLinesRule

func NewConsecutiveBlankLinesRule(maxConsecutive int) *ConsecutiveBlankLinesRule

NewConsecutiveBlankLinesRule creates a new L003 rule instance.

Parameters:

  • maxConsecutive: Maximum number of consecutive blank lines allowed (minimum 1)

If maxConsecutive is less than 1, defaults to 1.

Returns a configured ConsecutiveBlankLinesRule ready for use with the linter.

func (*ConsecutiveBlankLinesRule) Check

Check performs the consecutive blank lines check on SQL content.

Scans through lines tracking consecutive blank lines. Reports violations when consecutive blank count exceeds maxConsecutive. Also checks for excessive blank lines at file end.

Returns a slice of violations (one per sequence of excessive blank lines) and nil error.

func (*ConsecutiveBlankLinesRule) Fix

func (r *ConsecutiveBlankLinesRule) Fix(content string, violations []linter.Violation) (string, error)

Fix removes excess consecutive blank lines from SQL content.

Processes content line by line, preserving up to maxConsecutive blank lines in any sequence. Additional blank lines beyond the limit are removed. Also trims excess trailing blank lines at file end.

Returns the fixed content with consecutive blank lines reduced to maximum, and nil error.

type IndentationDepthRule

type IndentationDepthRule struct {
	linter.BaseRule
	// contains filtered or unexported fields
}

IndentationDepthRule (L004) detects excessive indentation depth indicating overly complex query structure.

Deep nesting in SQL queries often indicates complex subqueries that may benefit from refactoring into CTEs, views, or application-level logic. This rule helps identify queries that may be hard to understand and maintain.

Rule ID: L004 Severity: Warning Auto-fix: Not supported (requires query restructuring)

Example violation (maxDepth=4, indentSize=4):

SELECT *
FROM (
    SELECT *
    FROM (
        SELECT *
        FROM (
            SELECT *
            FROM (
                SELECT * FROM deep_table  <- 5 levels deep (violation)

This rule calculates indentation depth by dividing total leading whitespace by indentSize, treating tabs as indentSize spaces.

func NewIndentationDepthRule

func NewIndentationDepthRule(maxDepth int, indentSize int) *IndentationDepthRule

NewIndentationDepthRule creates a new L004 rule instance.

Parameters:

  • maxDepth: Maximum indentation depth allowed (minimum 1, default 4)
  • indentSize: Number of spaces per indentation level (minimum 1, default 4)

Tabs are counted as indentSize spaces. If parameters are less than 1, defaults are applied.

Returns a configured IndentationDepthRule ready for use with the linter.

func (*IndentationDepthRule) Check

Check performs the indentation depth check on SQL content.

Calculates the indentation depth of each non-empty line by counting leading whitespace (tabs converted to indentSize spaces) and dividing by indentSize. Reports violations for lines exceeding maxDepth.

Empty lines are skipped as they don't contribute to query complexity.

Returns a slice of violations (one per line exceeding maximum depth) and nil error.

func (*IndentationDepthRule) Fix

func (r *IndentationDepthRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is not supported for this rule as it requires semantic query restructuring.

Reducing indentation depth requires understanding query logic and potentially:

  • Converting nested subqueries to CTEs
  • Breaking complex queries into views
  • Simplifying join conditions

These transformations require human judgment and cannot be automated safely.

Returns the content unchanged with nil error.

type LongLinesRule

type LongLinesRule struct {
	linter.BaseRule
	MaxLength int
}

LongLinesRule (L005) detects lines exceeding a configurable maximum length.

Long lines reduce readability, especially in code reviews, side-by-side diffs, and terminal environments. This rule enforces a maximum line length to improve readability across different viewing contexts.

Rule ID: L005 Severity: Info Auto-fix: Not supported (requires semantic understanding)

Example violation (maxLength=80):

SELECT user_id, username, email, created_at, updated_at, last_login FROM users WHERE active = true  <- 95 chars (violation)

The rule skips comment-only lines as they often contain documentation or URLs that shouldn't be broken. Lines with trailing whitespace are measured including the whitespace.

func NewLongLinesRule

func NewLongLinesRule(maxLength int) *LongLinesRule

NewLongLinesRule creates a new L005 rule instance.

Parameters:

  • maxLength: Maximum line length in characters (minimum 1, default 100)

If maxLength is 0 or negative, defaults to 100 characters.

Returns a configured LongLinesRule ready for use with the linter.

func (*LongLinesRule) Check

func (r *LongLinesRule) Check(ctx *linter.Context) ([]linter.Violation, error)

Check performs the long lines check on SQL content.

Measures each line's length and reports violations for lines exceeding MaxLength. Empty lines and comment-only lines (starting with -- or /*) are skipped.

The violation column points to the position just after MaxLength to indicate where the line becomes too long.

Returns a slice of violations (one per line exceeding maximum length) and nil error.

func (*LongLinesRule) Fix

func (r *LongLinesRule) Fix(content string, violations []linter.Violation) (string, error)

Fix is not supported for this rule as it requires semantic understanding.

Breaking long lines requires understanding:

  • SQL clause boundaries (WHERE, AND, OR, etc.)
  • String literal boundaries
  • Appropriate indentation for continuation
  • Logical grouping of conditions

These decisions require human judgment about readability and cannot be automated safely without risk of creating worse formatting.

Returns the content unchanged with nil error.

type MixedIndentationRule

type MixedIndentationRule struct {
	linter.BaseRule
}

MixedIndentationRule (L002) detects and fixes inconsistent use of tabs and spaces for indentation within a file.

Mixed indentation causes display issues across different editors and environments where tab width settings vary. This rule enforces consistent indentation by detecting both line-level mixing (tabs and spaces on the same line) and file-level inconsistency (some lines using tabs, others using spaces).

Rule ID: L002 Severity: Error Auto-fix: Supported (converts all tabs to 4 spaces)

Example violations:

SELECT *        <- Uses spaces
FROM users      <- Uses spaces
	WHERE active  <- Uses tab

Fixed output (all spaces):

SELECT *
FROM users
    WHERE active

The auto-fix converts all leading tabs to 4 spaces, preserving tabs that appear inside SQL strings or after non-whitespace characters.

func NewMixedIndentationRule

func NewMixedIndentationRule() *MixedIndentationRule

NewMixedIndentationRule creates a new L002 rule instance.

The rule detects two types of violations:

  1. Line-level: Tabs and spaces mixed on the same line's indentation
  2. File-level: Different lines using different indentation styles

Auto-fix converts all indentation to spaces (4 spaces per tab).

Returns a configured MixedIndentationRule ready for use with the linter.

func (*MixedIndentationRule) Check

Check performs the mixed indentation check on SQL content.

The check works in two phases:

  1. Detects lines with both tabs and spaces in leading whitespace
  2. Tracks first indentation type seen and reports inconsistency with that style

Only leading whitespace (indentation) is checked; tabs and spaces after content are not considered violations.

Returns a slice of violations (one per inconsistent line) and nil error.

func (*MixedIndentationRule) Fix

func (r *MixedIndentationRule) Fix(content string, violations []linter.Violation) (string, error)

Fix converts all indentation to spaces (4 spaces per tab).

Processes each line by replacing tabs with 4 spaces in the leading whitespace only. Tabs that appear after non-whitespace content (e.g., inside string literals or after SQL keywords) are preserved unchanged.

This is a safe, idempotent transformation that doesn't affect SQL semantics.

Returns the fixed content with consistent space-based indentation, and nil error.

type RedundantWhitespaceRule

type RedundantWhitespaceRule struct {
	linter.BaseRule
}

RedundantWhitespaceRule (L010) detects and removes multiple consecutive spaces outside of string literals and indentation.

Inconsistent spacing between SQL keywords and identifiers reduces readability and can indicate careless formatting. This rule enforces single-space separation while preserving intentional spacing in string literals and line indentation.

Rule ID: L010 Severity: Info Auto-fix: Supported

Example violations:

SELECT  *  FROM  users   <- Multiple spaces between keywords (violation)
WHERE  status  =  'active'

Fixed output:

SELECT * FROM users      <- Single spaces
WHERE status = 'active'

The rule preserves:

  • Leading indentation (not considered redundant)
  • Spaces inside string literals ('multiple spaces')
  • Tabs (not replaced, only consecutive spaces are affected)

func NewRedundantWhitespaceRule

func NewRedundantWhitespaceRule() *RedundantWhitespaceRule

NewRedundantWhitespaceRule creates a new L010 rule instance.

The rule detects sequences of 2 or more consecutive spaces outside of string literals and indentation, supporting automatic fixing by reducing them to single spaces.

Returns a configured RedundantWhitespaceRule ready for use with the linter.

func (*RedundantWhitespaceRule) Check

Check performs the redundant whitespace check on SQL content.

Extracts non-string portions of each line and searches for sequences of 2+ spaces using regex pattern matching. Leading whitespace (indentation) is skipped. For each match, a violation is reported.

Returns a slice of violations (one per redundant whitespace sequence) and nil error.

func (*RedundantWhitespaceRule) Fix

func (r *RedundantWhitespaceRule) Fix(content string, violations []linter.Violation) (string, error)

Fix removes redundant whitespace from SQL content.

Processes content line by line, reducing multiple consecutive spaces to single spaces while preserving leading indentation and spaces inside string literals.

Returns the fixed content with redundant whitespace removed, and nil error.

type TrailingWhitespaceRule

type TrailingWhitespaceRule struct {
	linter.BaseRule
}

TrailingWhitespaceRule (L001) detects and removes unnecessary trailing whitespace at the end of lines.

This rule identifies spaces and tabs at line endings that serve no purpose and can cause issues with version control diffs and some text editors. Trailing whitespace is commonly introduced by text editors, copy-paste operations, or inconsistent formatting practices.

Rule ID: L001 Severity: Warning Auto-fix: Supported

Example violations:

SELECT * FROM users   <- Trailing spaces
WHERE active = true	  <- Trailing tab

Fixed output:

SELECT * FROM users
WHERE active = true

The rule preserves newline characters but removes all trailing spaces and tabs.

func NewTrailingWhitespaceRule

func NewTrailingWhitespaceRule() *TrailingWhitespaceRule

NewTrailingWhitespaceRule creates a new L001 rule instance.

The rule detects trailing spaces and tabs on any line and supports automatic fixing by stripping all trailing whitespace.

Returns a configured TrailingWhitespaceRule ready for use with the linter.

func (*TrailingWhitespaceRule) Check

Check performs the trailing whitespace check on SQL content.

Scans each line for spaces or tabs at the end (excluding newline characters). For each line with trailing whitespace, a violation is reported at the position where the trailing whitespace begins.

Empty lines are skipped as they cannot have meaningful trailing whitespace.

Returns a slice of violations (one per line with trailing whitespace) and nil error.

func (*TrailingWhitespaceRule) Fix

func (r *TrailingWhitespaceRule) Fix(content string, violations []linter.Violation) (string, error)

Fix removes trailing whitespace from all lines in the SQL content.

Processes the content line by line, trimming spaces and tabs from the right side of each line. Newlines are preserved. The violations parameter is ignored since the fix is applied uniformly to all lines.

This operation is safe to apply automatically and doesn't change SQL semantics.

Returns the fixed content with all trailing whitespace removed, and nil error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL