cssgen

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2026 License: MIT Imports: 20 Imported by: 0

README

cssgen - CSS Constant Generator & Linter

Go Reference Go Report Card CI

Type-safe CSS class constants for Go/templ projects.

cssgen generates Go constants from your CSS files and provides a linter to eliminate hardcoded class strings and catch typos at build time.

Why cssgen?

In modern Go web development with templ, CSS class names are just strings. This creates two problems:

  1. Typos are runtime errors - class="btn btn--primray" fails silently
  2. No refactoring support - Renaming .btn-primary to .btn--brand requires manual find/replace

cssgen solves this with type-safe constants and build-time validation:

// Before: Runtime error waiting to happen
<button class="btn btn--primray">Click</button>

// After: Compile-time safety + IDE autocomplete
<button class={ ui.Btn, ui.BtnBrand }>Click</button>

Features

  • 1:1 CSS-to-Go mapping - One CSS class = One Go constant
  • Rich IDE tooltips - Hover over ui.BtnBrand to see CSS properties, layers, and inheritance
  • Smart linter - Detects typos (errors) and hardcoded strings (warnings)
  • Multiple output formats - Issues, JSON, Markdown reports
  • Zero runtime overhead - Pure compile-time tool
  • Component-based generation - Splits constants into logical files (buttons, cards, etc.)

Installation

go install github.com/yacobolo/cssgen/cmd/cssgen@latest

Requirements: Go 1.21+

Quick Start

1. Generate Constants
cssg -source ./web/styles -output-dir ./internal/ui -package ui

This scans your CSS files and generates:

internal/ui/
├── styles.gen.go              # Main file with AllCSSClasses registry
├── styles_buttons.gen.go      # Button constants
├── styles_cards.gen.go        # Card constants
└── ...                        # Other component files
2. Use in Templates
import "yourproject/internal/ui"

templ Button(text string) {
    <button class={ ui.Btn, ui.BtnBrand, ui.BtnLg }>
        { text }
    </button>
}
// Produces: <button class="btn btn--brand btn--lg">
3. Lint Your Code
# Default: Show errors and warnings (golangci-lint style)
cssg -lint-only

# CI mode: Fail on any issue
cssg -lint-only -strict

# Full report with statistics and Quick Wins
cssg -lint-only -output-format full

Generated Output

Each constant includes rich metadata as Go comments:

const BtnBrand = "btn--brand"

// @layer components
//
// **Base:** .btn
// **Context:** Use with .btn for proper styling
// **Overrides:** 2 properties (background, color)
//
// **Visual:**
// - background: `var(--ui-color-brand)` 🎨
// - color: `var(--ui-color-brand-on)` 🎨
//
// **Pseudo-states:** :hover, :focus, :active

Your IDE shows this when you hover over ui.BtnBrand, giving instant CSS context without leaving your editor.

Linting Philosophy

Soft Gate (Default)
  • Errors → Exit code 1 (typos, invalid classes)
  • Warnings → Exit code 0 (hardcoded strings that should use constants)

This allows gradual migration without blocking development.

cssg -lint-only
# ✓ Passes CI if no typos (warnings are informational)
Strict Mode (Enforce Adoption)
cssg -lint-only -strict
# ✗ Fails CI on any issue (errors OR warnings)

Use strict mode once you've migrated critical templates.

Output Formats

cssgen supports five output formats via -output-format:

issues (default)

Golangci-lint style - errors and warnings only:

internal/web/components/button.templ:12:8: invalid CSS class "btn--primray" (csslint)
    <button class="btn btn--primray">
                   ^
internal/web/components/card.templ:5:8: hardcoded CSS class "card" should use ui.Card constant (csslint)
    <div class="card">
               ^

12 issues (1 errors, 11 warnings):
* csslint: 12

Hint: Run with -output-format full to see statistics and Quick Wins
summary

Statistics and Quick Wins only (no individual issues):

CSS Constant Usage Statistics
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Total constants:         232
Actually used:           8 (3.4%)
Available for migration: 95 (41.0%)
Completely unused:       129 (55.6%)

Top Migration Opportunities
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. "btn" → ui.Btn (23 occurrences)
2. "card" → ui.Card (18 occurrences)
...
full

Everything (issues + statistics + Quick Wins):

[All issues listed]

[Statistics summary]

[Quick Wins]
json

Machine-readable JSON for tooling integration:

{
  "issues": [...],
  "stats": {...},
  "quickWins": [...]
}
markdown

Shareable reports for GitHub issues, wikis, or documentation:

# CSS Linting Report

## Summary
- **Total Issues:** 225
- **Errors:** 12
- **Warnings:** 213
...

Usage Examples

Basic Workflows
# Generate constants from CSS
cssg

# Generate + lint in one pass
cssg -lint

# Lint only (no generation)
cssg -lint-only

# Quiet mode (exit code only, for pre-commit hooks)
cssg -lint-only -quiet

# Weekly adoption report
cssg -lint-only -output-format summary

# Export Markdown report
cssg -lint-only -output-format markdown > css-report.md
Advanced Options
# Custom source/output directories
cssg -source ./assets/css -output-dir ./pkg/styles -package styles

# Specific file patterns
cssg -include "components/**/*.css,utilities.css"

# Limit linting scope
cssg -lint-only -lint-paths "internal/views/**/*.templ"

# Limit output (CI performance)
cssg -lint-only -max-issues-per-linter 50
CI Integration
GitHub Actions
name: Lint
on: [push, pull_request]

jobs:
  css-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.23'
      
      - name: Install cssg
        run: go install github.com/yacobolo/cssgen/cmd/cssgen@latest
      
      - name: Lint CSS classes
        run: cssg -lint-only
Taskfile (task-runner)
# Taskfile.yml
tasks:
  css:gen:
    desc: Generate CSS constants
    cmds:
      - cssg
  
  css:lint:
    desc: Lint CSS usage (fast - issues only)
    cmds:
      - cssg -lint-only
  
  css:report:
    desc: Weekly CSS adoption report
    cmds:
      - cssg -lint-only -output-format summary
  
  check:
    desc: Run all checks (Go + CSS)
    cmds:
      - task: test
      - task: css:lint
      - golangci-lint run
Makefile
.PHONY: css-gen css-lint check

css-gen:
	cssg

css-lint:
	cssg -lint-only

check: test css-lint
	golangci-lint run

How It Works

Generation Process
  1. Scan - Find CSS files matching glob patterns
  2. Parse - Extract classes using native CSS parser (tdewolff/parse)
  3. Analyze - Detect BEM patterns, build inheritance tree
  4. Generate - Write Go constants with rich comments
Linting Process
  1. Load - Parse generated styles*.gen.go files to build class registry
  2. Scan - Find all class= attributes in .templ and .go files
  3. Match - Check each class against registry (with greedy token matching)
  4. Report - Output issues in golangci-lint format
1:1 Mapping Philosophy

cssgen uses pure 1:1 mapping between CSS classes and Go constants:

.btn { }           →  const Btn = "btn"
.btn--brand { }    →  const BtnBrand = "btn--brand"
.card__header { }  →  const CardHeader = "card__header"

NOT joined constants:

// ❌ WRONG - Creates pollution and false positives
const BtnBrand = "btn btn--brand"

// ✅ CORRECT - Pure 1:1 mapping
const Btn = "btn"
const BtnBrand = "btn--brand"

This ensures:

  • Zero false positives - Linter suggestions are always accurate
  • Composability - Mix and match any classes: { ui.Btn, ui.BtnBrand, ui.Disabled }
  • Clear intent - Each constant represents exactly one CSS class
Smart Token Matching

When the linter sees class="btn btn--brand":

  1. Check if exact match exists for "btn btn--brand" → No
  2. Split into tokens: ["btn", "btn--brand"]
  3. Match each token: btnui.Btn, btn--brandui.BtnBrand
  4. Suggest: { ui.Btn, ui.BtnBrand }

This produces accurate, predictable suggestions.

Configuration

Default Behavior

Without flags, cssgen uses these defaults:

  • Source: web/ui/src/styles
  • Output: internal/web/ui
  • Package: ui
  • Includes: layers/components/**/*.css, layers/utilities.css, layers/base.css
  • Lint paths: internal/web/features/**/*.{templ,go}
Common Flags

Generation:

  • -source DIR - CSS source directory
  • -output-dir DIR - Go output directory
  • -package NAME - Go package name
  • -include PATTERNS - Comma-separated glob patterns

Linting:

  • -lint - Run linter after generation
  • -lint-only - Run linter without generation
  • -lint-paths PATTERNS - Files to scan
  • -strict - Exit 1 on any issue (CI mode)

Output:

  • -output-format MODE - issues (default), summary, full, json, markdown
  • -quiet - Suppress all output (exit code only)
  • -max-issues-per-linter N - Limit issues shown
  • -color - Force color output

Run cssg -h for complete flag documentation.

FAQ

Why not use a CSS-in-JS library?

cssgen works with existing CSS files and standard build tools. No runtime overhead, no new syntax to learn, works with any CSS framework.

What about utility classes like Tailwind?

cssgen generates constants for any CSS class, including utilities:

const FlexFill = "flex-fill"
const TextCenter = "text-center"

Use them just like component classes: class={ ui.Flex, ui.FlexFill }

Why split into multiple files?

Generated files can be large (1000+ constants). Splitting by component improves:

  • IDE performance (faster autocomplete)
  • Code navigation (logical grouping)
  • Readability (buttons.gen.go vs 3000-line styles.gen.go)
Can I customize the generated code?

The generator supports two formats:

  • markdown (default) - Rich comments with hierarchies and diffs
  • compact - Minimal comments for smaller files

Use -format compact for a lighter output.

Does cssgen work with plain Go html/template?

The linter currently targets templ and Go files. Support for html/template could be added - contributions welcome!

License

MIT License - see LICENSE for details.

Contributing

Issues and pull requests welcome at https://github.com/yacobolo/cssgen


Built with:


Extracted from go-scheduler as a standalone tool.

Documentation

Overview

Package cssgen provides CSS-to-Go code generation for type-safe CSS class constants.

Package cssgen provides CSS constant generation and linting for Go/templ projects.

cssgen generates type-safe Go constants from CSS files and provides a linter to eliminate hardcoded class strings and catch typos at build time.

Generation

Generate Go constants from CSS files:

config := cssgen.Config{
	SourceDir:   "web/styles",
	OutputDir:   "internal/ui",
	PackageName: "ui",
	Includes:    []string{"**/*.css"},
}
result, err := cssgen.Generate(config)

Linting

Lint CSS class usage in Go/templ files:

lintConfig := cssgen.LintConfig{
	SourceDir:      "web/styles",
	OutputDir:      "internal/ui",
	LintPaths:      []string{"internal/**/*.{templ,go}"},
	StrictMode:     false,
}
result, err := cssgen.Lint(lintConfig)

CLI Tool

cssgen also provides a CLI tool. Install with:

go install github.com/yacobolo/cssgen/cmd/cssgen@latest

See cmd/cssgen/README.md for CLI documentation.

Package cssgen provides CSS class constant generation and linting.

Pure 1:1 Class Mapping

The generator creates one Go constant for each CSS class with exact 1:1 mapping:

  • CSS: .btn → Go: Btn = "btn"
  • CSS: .btn--brand → Go: BtnBrand = "btn--brand"
  • CSS: .card__header → Go: CardHeader = "card__header"

Usage in templates:

<button class={ ui.Btn, ui.BtnBrand }>Click</button>
// Produces: <button class="btn btn--brand">

<div class={ ui.Card, ui.CardHeader }>Content</div>
// Produces: <div class="card card__header">

Smart Linter with Greedy Token Matching

When analyzing class="btn btn--brand", the linter:

  1. Checks if exact match exists for full string
  2. If no match, splits into tokens: ["btn", "btn--brand"]
  3. Matches each token individually: btn → ui.Btn, btn--brand → ui.BtnBrand
  4. Suggests: { ui.Btn, ui.BtnBrand }

This results in predictable, accurate suggestions with zero "pollution."

Match Results

  • Matched: Constant available (e.g., "btn" → ui.Btn)
  • Unmatched: Class exists in CSS but no constant generated (e.g., utility classes)
  • Invalid: Class doesn't exist in CSS (typo or missing)

Index

Constants

View Source
const (
	SeverityError   = "error"
	SeverityWarning = "warning"
	SeverityInfo    = ""
)

IssueSeverity constants

View Source
const (
	IssueInvalidClass   = "invalid CSS class %q not found in stylesheet"
	IssueHardcodedClass = "hardcoded CSS class %q should use %s constant"
	IssueUnusedConstant = "exported constant %s is unused"
)

IssueType constants matching linter categories

Variables

This section is empty.

Functions

func AnalyzeClasses

func AnalyzeClasses(classes []*CSSClass) error

AnalyzeClasses builds inheritance graph and resolves full class names

func GetRelativePath

func GetRelativePath(absPath string) string

GetRelativePath returns a relative path from the current working directory

func ParseGeneratedFile

func ParseGeneratedFile(path string) (map[string]string, map[string]bool, error)

ParseGeneratedFile reads styles.gen.go and all related split files (styles_*.gen.go) and extracts constant definitions and AllCSSClasses

func PrintLintReport

func PrintLintReport(result *LintResult, w io.Writer, verbose bool)

PrintLintReport formats and prints the lint report

func ScanFiles

func ScanFiles(scanPatterns []string, verbose bool) ([]ClassReference, ScanStats, error)

ScanFiles scans files matching the given patterns for CSS class references

func WriteGoFile

func WriteGoFile(publicClasses []*CSSClass, allClasses []*CSSClass, config Config, stats GenerateResult) error

WriteGoFile generates multiple output .go files split by component

func WriteGoFiles

func WriteGoFiles(publicClasses []*CSSClass, allClasses []*CSSClass, config Config, stats GenerateResult) error

WriteGoFiles generates multiple output .go files split by component

func WriteJSON

func WriteJSON(w io.Writer, result *LintResult) error

WriteJSON writes the lint result as JSON

func WriteMarkdown

func WriteMarkdown(w io.Writer, result *LintResult) error

WriteMarkdown generates a Markdown report (shareable in GitHub, Slack, wikis)

func WriteOutput

func WriteOutput(w io.Writer, result *LintResult, format OutputFormat, config LintConfig)

WriteOutput writes the lint result in the specified format

Types

type CSSClass

type CSSClass struct {
	Name   string // "btn--primary"
	GoName string // "BtnPrimary"
	// FullClasses field REMOVED - no longer needed with 1:1 mapping
	Layer                 string                  // "components"
	Properties            map[string]string       // CSS properties (cleaned)
	ParentClass           *CSSClass               // Link to base class (for comments/context only)
	PseudoStates          []string                // [":hover", ":focus"] - included in comments
	PseudoStateProperties []PseudoStateProperties // Property changes in pseudo-states
	PropertyDiff          *PropertyDiff           // Diff vs. parent class
	Intent                string                  // Human intent from @intent comment
	IsUtility             bool                    // True if atomic utility class (no BEM)
	IsInternal            bool                    // True if starts with _ (skip public const)
	SourceFile            string                  // For debugging/conflict resolution
}

CSSClass represents a parsed CSS class with full context

func ParseCSS

func ParseCSS(content string, filename string, inferredLayer string, config Config) ([]*CSSClass, error)

ParseCSS parses CSS content and returns structured classes

type CSSLookup

type CSSLookup struct {
	// ExactMap: 1:1 mapping - "btn" -> "Btn", "btn--brand" -> "BtnBrand"
	ExactMap map[string]string

	// AllConstants: All constants (unchanged)
	AllConstants map[string]string // ConstName -> CSSClass

	// ConstantParts: Track which classes a constant contains
	// With 1:1 mapping, this is always single-element array
	ConstantParts map[string][]string

	// AllCSSClasses: All classes found in CSS (for static analysis)
	// Used to detect invalid class references (typos)
	AllCSSClasses map[string]bool
}

CSSLookup provides fast lookups for CSS class -> constant mapping

type CategorizedProperty

type CategorizedProperty struct {
	Name     string
	Value    string
	Category PropertyCategory
	IsToken  bool // True if value matches var(--ui-*)
}

CategorizedProperty represents a property with its category

type ClassAnalysis

type ClassAnalysis struct {
	ClassName  string    // "btn--ghost"
	Match      MatchType // MatchModifier
	Suggestion string    // "BtnGhost"
	Context    string    // "included in ui.BtnGhost"
}

ClassAnalysis provides detailed breakdown of how a class was analyzed

type ClassReference

type ClassReference struct {
	ClassName      string       // Individual class: "btn--ghost" (DEPRECATED: use FullClassValue)
	FullClassValue string       // Full attribute: "btn btn--ghost btn--sm"
	Location       FileLocation // Where it was found
	IsConstant     bool         // true if using ui.Foo, false if "foo"
	ConstName      string       // "Foo" if IsConstant is true
	LineContent    string       // The full line for context
}

ClassReference represents a CSS class reference found in code

type ClassificationResult

type ClassificationResult int

ClassificationResult categorizes a class reference

const (
	ClassMatched  ClassificationResult = iota // Has a constant (migration opportunity)
	ClassBypassed                             // Valid CSS, no constant (allow)
	ClassZombie                               // Doesn't exist in CSS (error)
)

type Config

type Config struct {
	SourceDir          string   // "web/ui/src/styles"
	OutputDir          string   // "internal/web/ui" (output directory for generated files)
	PackageName        string   // "ui"
	Includes           []string // ["layers/components/**/*.css", "layers/utilities.css"]
	Verbose            bool     // Enable debug logging
	LayerInferFromPath bool     // Infer layer from file path (default: true)
	Format             string   // Output format: "markdown", "compact" (default: "markdown")
	PropertyLimit      int      // Max properties to show per category (default: 5)
	ShowInternal       bool     // Show -webkit-* properties (default: false)
	ExtractIntent      bool     // Parse @intent comments (default: true)
}

Config holds generator configuration

type ConstantSuggestion

type ConstantSuggestion struct {
	Constants        []string        // ["BtnGhost", "BtnSm"] (deduplicated)
	Analysis         []ClassAnalysis // Per-class breakdown (for verbose mode)
	HasUnmatched     bool            // True if some classes had no match
	UnmatchedClasses []string        // List of classes that didn't match any constant
	HasInvalid       bool            // Contains invalid (non-existent) classes
	InvalidClasses   []string        // List of invalid classes
}

ConstantSuggestion contains the analysis and recommendation for a class string

func ResolveBestConstants

func ResolveBestConstants(classString string, lookup *CSSLookup) ConstantSuggestion

ResolveBestConstants analyzes a full class string and returns the optimal constant combination.

Algorithm (Greedy Token Matching):

  1. Try exact match for entire string
  2. Split into tokens and match each individually (1:1 mapping)
  3. No deduplication needed with 1:1 mapping

Example:

Input:  "btn btn--brand"
Output: ConstantSuggestion{
  Type: SuggestionMultiClass,
  Constants: ["Btn", "BtnBrand"],  // Each token maps exactly
  Analysis: [
    {ClassName: "btn", Match: MatchExact, Suggestion: "Btn"},
    {ClassName: "btn--brand", Match: MatchExact, Suggestion: "BtnBrand"},
  ],
}

type FileLocation

type FileLocation struct {
	File   string
	Line   int
	Column int    // 1-based column (exact start of class name)
	Text   string // Full line content for source display
}

FileLocation tracks where a class reference was found

type GenerateResult

type GenerateResult struct {
	ClassesGenerated int
	FilesScanned     int
	IntentsExtracted int // Number of @intent comments extracted
	Warnings         []string
	Errors           []error
}

GenerateResult contains generation stats

func Generate

func Generate(config Config) (*GenerateResult, error)

Generate is the main entry point

type HardcodedString

type HardcodedString struct {
	FullClassValue string             // "btn btn--ghost btn--sm"
	Suggestion     ConstantSuggestion // Smart suggestion with analysis
	Location       FileLocation
	LineContent    string // Full line for context
}

HardcodedString represents a CSS class string that could use a constant

type InvalidClass

type InvalidClass struct {
	ClassName   string       // "btn--outline"
	Location    FileLocation // Where it was found
	LineContent string       // Full line for context
}

InvalidClass represents a class that doesn't exist in CSS

type Issue

type Issue struct {
	FromLinter  string       `json:"FromLinter"`  // "csslint"
	Text        string       `json:"Text"`        // "invalid CSS class \"btn--outline\" not found in stylesheet"
	Severity    string       `json:"Severity"`    // "", "warning", "error"
	SourceLines []string     `json:"SourceLines"` // Lines of code with issue
	Pos         IssuePos     `json:"Pos"`         // File location
	LineRange   *LineRange   `json:"LineRange"`   // Optional range
	Replacement *Replacement `json:"Replacement"` // Optional fix suggestion
}

Issue represents a single linting violation in golangci-lint format

type IssuePos

type IssuePos struct {
	Filename string `json:"Filename"` // "internal/web/features/scheduleview/pages/scheduleview.templ"
	Line     int    `json:"Line"`     // 35
	Column   int    `json:"Column"`   // 15 (1-based, exact start of invalid class)
}

IssuePos specifies the exact location of an issue

type JSONIssue

type JSONIssue struct {
	File     string `json:"file"`
	Line     int    `json:"line"`
	Column   int    `json:"column"`
	Severity string `json:"severity"`
	Message  string `json:"message"`
	Linter   string `json:"linter"`
	Source   string `json:"source,omitempty"` // Optional source line
}

JSONIssue represents a single linting issue

type JSONOutput

type JSONOutput struct {
	Version   string        `json:"version"`
	Timestamp string        `json:"timestamp"`
	Summary   JSONSummary   `json:"summary"`
	Stats     JSONStats     `json:"stats"`
	Issues    []JSONIssue   `json:"issues"`
	QuickWins JSONQuickWins `json:"quick_wins"`
}

JSONOutput represents the structured JSON export schema

type JSONQuickWin

type JSONQuickWin struct {
	Class       string `json:"class"`
	Occurrences int    `json:"occurrences"`
	Suggestion  string `json:"suggestion"`
}

JSONQuickWin represents a high-impact refactoring opportunity

type JSONQuickWins

type JSONQuickWins struct {
	SingleClass []JSONQuickWin `json:"single_class"`
	MultiClass  []JSONQuickWin `json:"multi_class"`
}

JSONQuickWins contains migration opportunities

type JSONStats

type JSONStats struct {
	TotalConstants         int     `json:"total_constants"`
	ActuallyUsed           int     `json:"actually_used"`
	MigrationOpportunities int     `json:"migration_opportunities"`
	CompletelyUnused       int     `json:"completely_unused"`
	UsagePercentage        float64 `json:"usage_percentage"`
	HardcodedClasses       int     `json:"hardcoded_classes"`
	ConstantReferences     int     `json:"constant_references"`
}

JSONStats contains adoption and usage statistics

type JSONSummary

type JSONSummary struct {
	TotalIssues  int `json:"total_issues"`
	Errors       int `json:"errors"`
	Warnings     int `json:"warnings"`
	FilesScanned int `json:"files_scanned"`
}

JSONSummary contains high-level issue counts

type Layer

type Layer struct {
	Name    string
	Classes []*CSSClass
	Order   int // For priority (base=0, components=1, utilities=2)
}

Layer represents a CSS cascade layer with priority

type LineRange

type LineRange struct {
	From int `json:"From"`
	To   int `json:"To"`
}

LineRange specifies a range of lines

type LintConfig

type LintConfig struct {
	ScanPaths     []string // Patterns to scan (e.g., "internal/web/features/**/*.templ")
	GeneratedFile string   // Path to styles.gen.go
	PackageName   string   // "ui"
	Verbose       bool
	Strict        bool    // Exit with code 1 if issues found
	Threshold     float64 // Minimum adoption percentage (for -strict mode)

	// New golangci-style configuration
	MaxIssuesPerLinter int  // 0 = unlimited (default)
	MaxSameIssues      int  // 0 = unlimited (default)
	ShowStats          bool // Show statistics summary (auto-enabled with Verbose)
	PrintIssuedLines   bool // Show source lines with issues (default: true)
	PrintLinterName    bool // Show (csslint) suffix (default: true)
	UseColors          bool // Enable color output (default: auto-detect)
}

LintConfig holds linting configuration

type LintResult

type LintResult struct {
	// Statistics
	TotalConstants        int     // 229
	ActuallyUsed          int     // Constants referenced via ui.ConstName (e.g., 0)
	AvailableForMigration int     // Constants that match hardcoded strings (e.g., 111)
	CompletelyUnused      int     // No usage, no matches (e.g., 118)
	UsagePercentage       float64 // Percentage of actually used constants (e.g., 0%)

	// Issues in golangci-lint format
	Issues           []Issue            // All issues found
	IssuesByCategory map[string][]Issue // Grouped by type for stats

	// Legacy detailed findings (used for verbose mode only)
	UnusedClasses    []UnusedClass
	HardcodedStrings []HardcodedString
	InvalidClasses   []InvalidClass // Classes that don't exist in CSS
	FilesScanned     int
	ClassesFound     int // Total hardcoded classes found
	ConstantsFound   int // Total ui.Foo references found
	ErrorCount       int // Count of invalid classes
	TruncatedCount   int // Issues removed due to limits

	// Summary
	Warnings    []string
	Suggestions []string
	QuickWins   QuickWinsSummary // Most frequently hardcoded classes
}

LintResult contains linting analysis results

func Lint

func Lint(config LintConfig) (*LintResult, error)

Lint performs linting analysis on the codebase

type MatchType

type MatchType int

MatchType indicates how a class was matched to a constant

const (
	MatchExact MatchType = iota // Direct match in ExactMap
	MatchNone                   // No match found
)

type OutputFormat

type OutputFormat string

OutputFormat represents the linter output format

const (
	// OutputIssues shows only errors/warnings in golangci-lint format (CI-friendly)
	OutputIssues OutputFormat = "issues"
	// OutputSummary shows statistics and Quick Wins only (weekly reports)
	OutputSummary OutputFormat = "summary"
	// OutputFull shows issues + statistics + Quick Wins (interactive development)
	OutputFull OutputFormat = "full"
	// OutputJSON exports structured data in JSON format (tooling integration)
	OutputJSON OutputFormat = "json"
	// OutputMarkdown generates a Markdown report (shareable reports)
	OutputMarkdown OutputFormat = "markdown"
)

func DetermineDefaultOutputFormat

func DetermineDefaultOutputFormat() OutputFormat

DetermineDefaultOutputFormat returns the default output format Following golangci-lint's UX: issues only by default (clean, fast, consistent everywhere)

func DetermineOutputFormat

func DetermineOutputFormat(formatFlag string, quiet bool) OutputFormat

DetermineOutputFormat selects the appropriate output format based on flags and environment

type PropertyCategory

type PropertyCategory string

PropertyCategory groups related CSS properties

const (
	CategoryVisual     PropertyCategory = "Visual"
	CategoryLayout     PropertyCategory = "Layout"
	CategoryTypography PropertyCategory = "Typography"
	CategoryEffects    PropertyCategory = "Effects"
	CategoryTokens     PropertyCategory = "Tokens"
	CategoryInternal   PropertyCategory = "Internal"
)

Property categories for organizing CSS properties

type PropertyDiff

type PropertyDiff struct {
	Added     map[string]string // New properties in modifier
	Changed   map[string]string // Properties that override base
	Unchanged []string          // Properties inherited as-is
}

PropertyDiff tracks changes between modifier and base

func DiffProperties

func DiffProperties(modifier, base *CSSClass) *PropertyDiff

DiffProperties compares modifier properties to base class

type PseudoStateProperties

type PseudoStateProperties struct {
	PseudoState string            // ":hover", ":focus", etc.
	Changes     map[string]string // Properties that change in this state
}

PseudoStateProperties tracks property changes in pseudo-states

type QuickWin

type QuickWin struct {
	ClassName   string // "btn"
	Occurrences int    // 45
	Suggestion  string // "ui.Btn"
}

QuickWin represents a high-impact refactoring opportunity

type QuickWinsSummary

type QuickWinsSummary struct {
	SingleClass []QuickWin // Single class: "btn" -> ui.Btn
	MultiClass  []QuickWin // Multiple classes: "btn btn--brand" -> { ui.Btn, ui.BtnBrand }
}

QuickWinsSummary categorizes quick wins by refactoring pattern

type Replacement

type Replacement struct {
	NewText      string // "ui.Icon" or "btn--outlined"
	InlineLength int    // Length of text to replace
}

Replacement provides automated fix suggestion (future --fix flag)

type Reporter

type Reporter struct {
	// contains filtered or unexported fields
}

Reporter handles formatting and outputting linting results

func NewReporter

func NewReporter(w io.Writer, config LintConfig) *Reporter

NewReporter creates a new reporter with the given configuration

func (*Reporter) PrintIssues

func (r *Reporter) PrintIssues(issues []Issue)

PrintIssues outputs issues in golangci-lint format

func (*Reporter) PrintSummary

func (r *Reporter) PrintSummary(result LintResult)

PrintSummary outputs the issue count summary

func (*Reporter) UseColors

func (r *Reporter) UseColors() bool

UseColors returns whether colors are enabled

type ScanStats

type ScanStats struct {
	FilesDiscovered int // Total files found by glob patterns
	FilesScanned    int // Files actually scanned (after filtering)
	FilesSkipped    int // Files skipped due to filtering
}

ScanStats tracks file scanning statistics

type UnusedClass

type UnusedClass struct {
	ConstName string // "AppSidebar"
	CSSClass  string // "app-sidebar"
	Layer     string // "components"
	DefinedIn string // "styles.gen.go:123"
}

UnusedClass represents a generated constant with no usage

type VerboseReporter

type VerboseReporter struct {
	// contains filtered or unexported fields
}

VerboseReporter handles detailed statistics and suggestions

func NewVerboseReporter

func NewVerboseReporter(w io.Writer, useColors bool) *VerboseReporter

NewVerboseReporter creates a verbose reporter

func (*VerboseReporter) PrintAdoptionProgress

func (r *VerboseReporter) PrintAdoptionProgress(result LintResult)

PrintAdoptionProgress shows visual progress bar

func (*VerboseReporter) PrintQuickWins

func (r *VerboseReporter) PrintQuickWins(result LintResult)

PrintQuickWins shows migration opportunities

func (*VerboseReporter) PrintStatistics

func (r *VerboseReporter) PrintStatistics(result LintResult)

PrintStatistics outputs detailed linting statistics

func (*VerboseReporter) PrintWarnings

func (r *VerboseReporter) PrintWarnings(result LintResult)

PrintWarnings shows linter warnings

Directories

Path Synopsis
cmd
cssgen command
Package main provides the cssgen CLI tool for generating type-safe CSS constants.
Package main provides the cssgen CLI tool for generating type-safe CSS constants.

Jump to

Keyboard shortcuts

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