Skip to content

Сhecks that the Structes are created by the Factory

License

Notifications You must be signed in to change notification settings

maranqz/gofactory

Repository files navigation

Factory linter

CI Go Report Card MIT License Coverage Status

The linter checks that the Structures are created by the Factory, and not directly.

The checking helps to provide invariants without exclusion and helps avoid creating an invalid object.

Usage

Installation

go install github.com/maranqz/gofactory/cmd/gofactory@latest

Options

  • --packageGlobs – list of glob packages, which can create structures without factories inside the glob package. By default, all structures from another package should be created by factories, tests.
  • --packageGlobsOnly – use a factory to initiate a structure for glob packages only, tests. Doesn't make sense without --packageGlobs.

Example

BadGood
package main

import (
	"fmt"

	"bad"
)

func main() {
	// Use factory for bad.User
	u := &bad.User{
		ID: -1,
	}

	fmt.Println(u.ID) // -1
	fmt.Println(u.CreatedAt) // time.Time{}
}
package bad

import "time"

type User struct {
	ID        int64
	CreatedAt time.Time
}

var sequenceID = int64(0)

func NextID() int64 {
	sequenceID++

	return sequenceID
}
package main

import (
	"fmt"

	"good"
)

func main() {
	u := good.NewUser()
	
	fmt.Println(u.ID)        // auto increment
	fmt.Println(u.CreatedAt) // time.Now()
}
package user

import "time"

type User struct {
	ID        int64
	CreatedAt time.Time
}

func NewUser() *User {
	return &User{
		ID: nextID(),
		CreatedAt: time.Now(),
	}
}

var sequenceID = int64(0)

func nextID() int64 {
	sequenceID++

	return sequenceID
}

False Negative

Linter doesn't catch some cases.

  1. Buffered channel. You can initialize struct in line v, ok := <-bufCh example.
  2. Local initialization, example.
  3. Named return. If you want to block that case, you can use nonamedreturns linter, example.
  4. var declaration, var initilized nested.Struct gives structure without factory, example. To block that case, you can use gopublicfield to prevent fill of structure fields.

TODO

Possible Features

  1. Catch nested struct in the same package, example.
    return Struct{
        Other: OtherStruct{}, // want `Use factory for nested.Struct`
    }
  2. Resolve false negative issue with var declaration.

Features that are difficult to implement and unplanned

  1. Type assertion, type declaration and type underlying, tests.

About

Сhecks that the Structes are created by the Factory

Resources

License

Stars

Watchers

Forks

Packages

No packages published