Skip to content

Commit

Permalink
refactor: simplify use of NewExtractor and NewDeclExtractor (#1819)
Browse files Browse the repository at this point in the history
Just by using generics to create unique Fact types, removing some
boilerplate.
  • Loading branch information
alecthomas authored Jun 18, 2024
1 parent 22f94f7 commit 0fa133e
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 110 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion bin/lefthook
10 changes: 6 additions & 4 deletions go-runtime/schema/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import (
"reflect"
"strings"

"github.com/alecthomas/types/optional"
"github.com/puzpuzpuz/xsync/v3"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/backend/schema/strcase"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/TBD54566975/golang-tools/go/analysis/passes/inspect"
"github.com/TBD54566975/golang-tools/go/ast/inspector"
"github.com/alecthomas/types/optional"
"github.com/puzpuzpuz/xsync/v3"
)

var (
Expand All @@ -41,7 +42,8 @@ func NewExtractor(name string, factType analysis.Fact, run func(*analysis.Pass)

type ExtractDeclFunc[T schema.Decl, N ast.Node] func(pass *analysis.Pass, node N, object types.Object) optional.Option[T]

func NewDeclExtractor[T schema.Decl, N ast.Node](name string, factType analysis.Fact, extractFunc ExtractDeclFunc[T, N]) *analysis.Analyzer {
func NewDeclExtractor[T schema.Decl, N ast.Node](name string, extractFunc ExtractDeclFunc[T, N]) *analysis.Analyzer {
type Tag struct{} // Tag uniquely identifies the fact type for this extractor.
dType := reflect.TypeFor[T]()
if _, ok := extractorRegistery.Load(dType); ok {
panic(fmt.Sprintf("multiple extractors registered for %s", dType.String()))
Expand All @@ -54,7 +56,7 @@ func NewDeclExtractor[T schema.Decl, N ast.Node](name string, factType analysis.
return optional.None[schema.Decl]()
}
extractorRegistery.Store(dType, wrapped)
return NewExtractor(name, factType, runExtractDeclsFunc[T, N](extractFunc))
return NewExtractor(name, (*DefaultFact[Tag])(nil), runExtractDeclsFunc[T, N](extractFunc))
}

type ExtractorResult struct {
Expand Down
20 changes: 18 additions & 2 deletions go-runtime/schema/common/fact.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"go/types"
"reflect"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/alecthomas/types/optional"
sets "github.com/deckarep/golang-set/v2"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/golang-tools/go/analysis"
)

// SchemaFact is a fact that associates a schema node with a Go object.
Expand All @@ -17,6 +18,21 @@ type SchemaFact interface {
Get() SchemaFactValue
}

// DefaultFact should be used as the base type for all schema facts. Each
// Analyzer needs a uniuqe Fact type that is otherwise identical, and this type
// simply reduces that boilerplate.
//
// Usage:
//
// type Fact = common.DefaultFact[struct{}]
type DefaultFact[T any] struct {
value SchemaFactValue
}

func (*DefaultFact[T]) AFact() {}
func (t *DefaultFact[T]) Set(v SchemaFactValue) { t.value = v }
func (t *DefaultFact[T]) Get() SchemaFactValue { return t.value }

// SchemaFactValue is the value of a SchemaFact.
type SchemaFactValue interface {
schemaFactValue()
Expand Down
13 changes: 3 additions & 10 deletions go-runtime/schema/data/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,21 @@ import (
"strings"
"unicode"

"github.com/alecthomas/types/optional"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/backend/schema/strcase"
"github.com/TBD54566975/ftl/go-runtime/schema/common"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/alecthomas/types/optional"
)

var (
// Extractor extracts schema.Data to the module schema.
Extractor = common.NewDeclExtractor[*schema.Data, *ast.TypeSpec]("data", (*Fact)(nil), Extract)
Extractor = common.NewDeclExtractor[*schema.Data, *ast.TypeSpec]("data", Extract)

aliasFieldTag = "json"
)

type Fact struct {
value common.SchemaFactValue
}

func (t *Fact) AFact() {}
func (t *Fact) Set(v common.SchemaFactValue) { t.value = v }
func (t *Fact) Get() common.SchemaFactValue { return t.value }

func Extract(pass *analysis.Pass, node *ast.TypeSpec, obj types.Object) optional.Option[*schema.Data] {
named, ok := obj.Type().(*types.Named)
if !ok {
Expand Down
3 changes: 2 additions & 1 deletion go-runtime/schema/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package schema
import (
"fmt"

"golang.org/x/exp/maps"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/go-runtime/schema/common"
"github.com/TBD54566975/ftl/go-runtime/schema/data"
Expand All @@ -16,7 +18,6 @@ import (
"github.com/TBD54566975/golang-tools/go/analysis/passes/inspect"
checker "github.com/TBD54566975/golang-tools/go/analysis/programmaticchecker"
"github.com/TBD54566975/golang-tools/go/packages"
"golang.org/x/exp/maps"
)

// Extractors contains all schema extractors that will run.
Expand Down
14 changes: 5 additions & 9 deletions go-runtime/schema/metadata/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,21 @@ import (
"go/token"
"reflect"

"github.com/alecthomas/types/optional"
sets "github.com/deckarep/golang-set/v2"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/go-runtime/schema/common"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/TBD54566975/golang-tools/go/analysis/passes/inspect"
"github.com/TBD54566975/golang-tools/go/ast/inspector"
"github.com/alecthomas/types/optional"
sets "github.com/deckarep/golang-set/v2"
)

// Extractor extracts metadata to the module schema.
var Extractor = common.NewExtractor("metadata", (*Fact)(nil), Extract)

type Fact struct {
value common.SchemaFactValue
}

func (t *Fact) AFact() {}
func (t *Fact) Set(v common.SchemaFactValue) { t.value = v }
func (t *Fact) Get() common.SchemaFactValue { return t.value }
type Tag struct{} // Tag uniquely identifies the fact type for this extractor.
type Fact = common.DefaultFact[Tag]

func Extract(pass *analysis.Pass) (interface{}, error) {
in := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) //nolint:forcetypeassert
Expand Down
12 changes: 4 additions & 8 deletions go-runtime/schema/transitive/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"go/ast"
"go/types"

sets "github.com/deckarep/golang-set/v2"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/go-runtime/schema/common"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/TBD54566975/golang-tools/go/analysis/passes/inspect"
"github.com/TBD54566975/golang-tools/go/ast/inspector"
sets "github.com/deckarep/golang-set/v2"
)

// Extractor extracts transitive schema.Decls to the module schema.
Expand All @@ -18,13 +19,8 @@ import (
// but not themselves explicitly annotated.
var Extractor = common.NewExtractor("transitive", (*Fact)(nil), Extract)

type Fact struct {
value common.SchemaFactValue
}

func (t *Fact) AFact() {}
func (t *Fact) Set(v common.SchemaFactValue) { t.value = v }
func (t *Fact) Get() common.SchemaFactValue { return t.value }
type Tag struct{} // Tag uniquely identifies the fact type for this extractor.
type Fact = common.DefaultFact[Tag]

// Extract traverses all schema type root AST nodes and determines if a node has been marked for extraction.
//
Expand Down
13 changes: 3 additions & 10 deletions go-runtime/schema/typealias/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@ import (
"go/ast"
"go/types"

"github.com/alecthomas/types/optional"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/backend/schema/strcase"
"github.com/TBD54566975/ftl/go-runtime/schema/common"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/alecthomas/types/optional"
)

// Extractor extracts type aliases to the module schema.
var Extractor = common.NewDeclExtractor[*schema.TypeAlias, *ast.TypeSpec]("typealias", (*Fact)(nil), Extract)

type Fact struct {
value common.SchemaFactValue
}

func (t *Fact) AFact() {}
func (t *Fact) Set(v common.SchemaFactValue) { t.value = v }
func (t *Fact) Get() common.SchemaFactValue { return t.value }
var Extractor = common.NewDeclExtractor[*schema.TypeAlias, *ast.TypeSpec]("typealias", Extract)

func Extract(pass *analysis.Pass, node *ast.TypeSpec, obj types.Object) optional.Option[*schema.TypeAlias] {
schType, ok := common.ExtractTypeForNode(pass, obj, node, nil).Get()
Expand Down
13 changes: 3 additions & 10 deletions go-runtime/schema/verb/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,17 @@ import (
"go/ast"
"go/types"

"github.com/alecthomas/types/optional"

"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/backend/schema/strcase"
"github.com/TBD54566975/ftl/go-runtime/schema/common"
"github.com/TBD54566975/ftl/go-runtime/schema/initialize"
"github.com/TBD54566975/golang-tools/go/analysis"
"github.com/alecthomas/types/optional"
)

// Extractor extracts verbs to the module schema.
var Extractor = common.NewDeclExtractor[*schema.Verb, *ast.FuncDecl]("verb", (*Fact)(nil), Extract)

type Fact struct {
value common.SchemaFactValue
}

func (t *Fact) AFact() {}
func (t *Fact) Set(v common.SchemaFactValue) { t.value = v }
func (t *Fact) Get() common.SchemaFactValue { return t.value }
var Extractor = common.NewDeclExtractor[*schema.Verb, *ast.FuncDecl]("verb", Extract)

func Extract(pass *analysis.Pass, root *ast.FuncDecl, obj types.Object) optional.Option[*schema.Verb] {
md, ok := common.GetFactForObject[*common.ExtractedMetadata](pass, obj).Get()
Expand Down
55 changes: 0 additions & 55 deletions renovate.json

This file was deleted.

41 changes: 41 additions & 0 deletions renovate.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
$schema: "https://docs.renovatebot.com/renovate-schema.json",
extends: [
"config:recommended",
":semanticCommits",
":semanticCommitTypeAll(chore)",
":semanticCommitScope(deps)",
"group:allNonMajor",
"schedule:earlyMondays",
],
packageRules: [
{
matchUpdateTypes: ["minor", "patch"],
automerge: true,
},
{
matchPackageNames: [
"jbr",
"ktfmt",
"golangci-lint",
"svu",
"lefthook", // Everything after 1.6.14 is broken
],
matchManagers: ["hermit"],
enabled: false,
},
{
matchFileNames: ["**/testdata/**/go.mod"],
enabled: false,
},
{
matchPackageNames: ["eslint", "codemirror"],
enabled: false,
paths: ["frontend/**", "extensions/**"],
},
{
matchPackageNames: ["connectrpc.com/connect"],
enabled: false,
},
],
}

0 comments on commit 0fa133e

Please sign in to comment.