superlint

package module
v0.0.0-...-719653f Latest Latest
Warning

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

Go to latest
Published: Feb 9, 2022 License: MIT Imports: 11 Imported by: 0

README

superlint

superlint is an experimental, language-agnostic framework for lint rules written in Go.

Go Reference

superlint is designed to be a higher order linter. You can embed other linters or define custom rules. Rules are

  • Codebase-scoped (as opposed to file or block scoped)
  • Defined by arbitary Go code
    • Language-agonstic
    • Fast by default
      • AST is parsed lazily
      • Linters run concurrently
    • Capable of using the network, filesystem, etc.
    • Composable

The vast ecosystem of existing linters can be called by a superlint ruleset. For example, a rule can import an AST parser or execute a linting command.

superlint makes it easy to enforce arbitrary codebase-wide rules. For example, you may enforce that:

  • Each Go binary has an accompanying Make entry
  • Each http.Handler has an accompanying test
  • Bash scripts don't exceed 1000 lines of code
  • TypeScript/JS code is only in the site folder
  • The database package never imports the api package

Basic Usage

  1. Create a rules file in your project (e.g example/rules.go)
package main

import (
	"os"
	"regexp"
	"strings"

	. "github.com/ammario/superlint"
	"github.com/ammario/superlint/lintgo"
	"github.com/coder/flog"
)

// LoadRules is the symbol loaded by superlint to inject rules.
var LoadRules Loader = func(_ *flog.Logger, r *RuleSet) {
  // `no-dog-files` checks if `dog` exists in the filename.
  r.Add("no-dog-files",
    // "Single" here means that the rule does not need codebase-wide state.
    // Omit "Single" to receive all matching files.
    Single(func(fi FileInfo, report ReportFunc) error {
      if strings.Contains(fi.Name(), "dog") {
        report(FileReference{}, "no dogs allowed!")
      }
      return nil
    }),
  )

  // `no-md5` shows how language-awareness is possible in this paradigm.
  r.Add("no-md5",
    // lintgo is a simple wrapper around Go AST parsing.
    Single(lintgo.Validate(func(ps *lintgo.ParseState, _ FileInfo, report ReportFunc) error {
      for _, spec := range ps.File.Imports {
        if spec.Path.Value == "\"crypto/md5\"" {
          report(FileReference{
            Pos: ps.Fset.Position(spec.Path.Pos()).Offset,
            End: ps.Fset.Position(spec.Path.End()).Offset,
          }, "crypto/md5 is insecure")
        }
      }
      return nil
    }),
    ),
  )
}
  1. Run the rules
$ go install ./cmd/superlint && superlint -v example/rules.go
[18:05:36.552] loaded 2 rules
no-dog-files: example/dogs.go: no dogs allowed!
no-md5: example/dogs.go: crypto/md5 is insecure
        example/dogs.go:3       import "crypto/md5"
[18:05:36.560] 2 violations found
exit status 1

Architecture

superlint loads your ruleset as a Go plugin. This is the only way superlint can support arbitrary Go lint rules without direct integration with a build toolchain.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type FileInfo

type FileInfo struct {
	os.FileInfo
	Path string
}

FileInfo is an os.FileInfo combined with a fully qualified path.

type FileMatcherFunc

type FileMatcherFunc func(fi *os.File) bool

FileMatcherFunc describes a function that checks whether a file is relevant to a rule.

func AndMatcher

func AndMatcher(fm ...FileMatcherFunc) FileMatcherFunc

AndMatcher returns true when all match the file.

func OrMatcher

func OrMatcher(fm ...FileMatcherFunc) FileMatcherFunc

OrMatcher returns true when any match the file.

func ShellMatch

func ShellMatch(pattern string) FileMatcherFunc

ShellMatch uses standard shell syntax. E.g "**/*.go" matches all Go files.

type FileReference

type FileReference struct {
	Name string
	// Pos, End are byte indices when specifying a problem within the file.
	Pos, End int
}

FileReference describes a chunk of a file.

type Loader

type Loader func(log *flog.Logger, set *RuleSet)

Loader describes the user-defined rule loader.

type ReportFunc

type ReportFunc func(reference FileReference, message string)

ReportFunc describes a function used to report lint violations.

type Rule

type Rule struct {
	Name string
	// Linter runs when all matched files have been loaded.
	// Linter runs all at once so that cross-codebase checks can be performed.
	// Validators should not return an error for lint violations.
	Linter ValidatorFunc
}

A Rule defines a lint rule. The engine first assue

type RuleSet

type RuleSet []Rule

RuleSet describes a set of rules loaded at linttime.

func (*RuleSet) Add

func (rs *RuleSet) Add(name string, lint ValidatorFunc)

Add adds a new rule to the RuleSet.

type Runner

type Runner struct {
	Matcher     string
	DebugLogger *flog.Logger
	Log         *flog.Logger
	// contains filtered or unexported fields
}

Runner runs the RuleSet.

func (*Runner) Run

func (rn *Runner) Run(rs *RuleSet) error

type SingleValidator

type SingleValidator func(f FileInfo, report ReportFunc) error

SingleValidator a ValidatorFunc for rules that do not perform cross-file checks. SingleValidator populates FileReference.Name in the report automatically.

type ValidatorFunc

type ValidatorFunc func(files map[string]FileInfo, report ReportFunc) error

func Single

func Single(vf SingleValidator) ValidatorFunc

Single forms a new SingleValidator.

Directories

Path Synopsis
cmd
Package main contains an evil dog file
Package main contains an evil dog file
Package lintgo provides very basic Go linting utilities.
Package lintgo provides very basic Go linting utilities.

Jump to

Keyboard shortcuts

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