Skip to content

Commit

Permalink
feat(ui): experimental option aliases generator
Browse files Browse the repository at this point in the history
  • Loading branch information
rotmh committed Oct 9, 2024
1 parent 227a8e0 commit 5aaee2b
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 17 deletions.
11 changes: 11 additions & 0 deletions ui/button/generated_optaliase.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 5 additions & 8 deletions ui/button/root.templ
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,7 @@ func WithSize(s Size) RootOption {
}
}

var (
WithClass = ui.WithClass[*RootProps]
WithAttrs = ui.WithAttrs[*RootProps]
WithAttr = ui.WithAttr[*RootProps]
)
//go:generate go run ../optalias_generator.go -type=RootProps

type RootProps struct {
Type Type
Expand All @@ -111,9 +107,10 @@ type RootProps struct {

func Root(opts ...RootOption) templ.Component {
p := &RootProps{
Type: TypeButton,
Variant: VariantDefault,
Size: SizeDefault,
Type: TypeButton,
Variant: VariantDefault,
Size: SizeDefault,
CoreProps: ui.DefaultCoreProps,
}
for _, opt := range opts {
opt(p)
Expand Down
15 changes: 6 additions & 9 deletions ui/button/root_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

150 changes: 150 additions & 0 deletions ui/optalias_generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
//go:build ignore
// +build ignore

package main

import (
"flag"
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)

const filePath = "../props.go"

func main() {
var typeFlag string
flag.StringVar(&typeFlag, "type", "", "type name to set aliases with as type param")
flag.Parse()

if typeFlag == "" || filePath == "" {
panic("Both type and path parameters must be provided")
}

fset := token.NewFileSet()
node, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)
if err != nil {
panic(err)
}

packageName := node.Name.Name

var functions []string

for _, decl := range node.Decls {
if fn, ok := decl.(*ast.FuncDecl); ok {
log.Println(fn)
// Check if the function return type is of the desired type
if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 {
returnType := fn.Type.Results.List[0].Type
log.Println(returnType)
log.Printf("%T", returnType)
if isMatchingType(returnType) {
functions = append(functions, fn.Name.Name)
}
}
}
}

log.Println(functions)

cwd, err := os.Getwd()
if err != nil {
panic(err)
}
outputFilePath := filepath.Join(cwd, "generated_optaliase.go")
f, err := os.Create(outputFilePath)
if err != nil {
panic(err)
}

log.Println(outputFilePath)

var b strings.Builder
mustWrite(&b, "// Code generated by \"optaliase_generator.go %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
mustWrite(&b, "\n")
mustWrite(&b, "package %s", currPackageName())
mustWrite(&b, "\n")
mustWrite(&b, "var (\n")
for _, function := range functions {
mustWrite(&b, " %s = %s.%s[*%s]\n", function, packageName, function, typeFlag)
}
mustWrite(&b, ")")

if _, err = f.WriteString(b.String()); err != nil {
panic(err)
}

log.Println(b.String())

if err = f.Close(); err != nil {
panic(err)
}

runGoImports(outputFilePath)
}

// panics at any error
func runGoImports(filePath string) {
cmd := exec.Command("goimports", "-w", filePath) // -w flag writes the result back to the file
if err := cmd.Run(); err != nil {
panic(err)
}
}

func mustWrite(b *strings.Builder, f string, a ...any) {
if _, err := b.WriteString(fmt.Sprintf(f, a...)); err != nil {
panic(err)
}
}

// checks if the type is `*Option`
func isMatchingType(typ ast.Expr) bool {
// Handle pointer types
if indexExpr, ok := typ.(*ast.IndexExpr); ok {
if ident, ok := indexExpr.X.(*ast.Ident); ok {
if ident.Name == "Option" {
return true
}
}
}
return false
}

// will panic at any error
func currPackageName() string {
currentDir, err := os.Getwd()
if err != nil {
panic(err)
}

goFiles, err := filepath.Glob(filepath.Join(currentDir, "*.go"))
if err != nil || len(goFiles) == 0 {
panic(err)
}

var firstGoFile string
for _, goFile := range goFiles {
if filepath.Base(goFile) != "generated_optaliase.go" {
firstGoFile = goFile
break
}
}
if firstGoFile == "" {
panic("no files found in cwd")
}

fset := token.NewFileSet()
node, err := parser.ParseFile(fset, firstGoFile, nil, parser.PackageClauseOnly)
if err != nil {
panic(err)
}

return node.Name.Name
}
5 changes: 5 additions & 0 deletions ui/props.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ type CoreProps struct {
attrs templ.Attributes
}

var DefaultCoreProps = CoreProps{
class: "",
attrs: templ.Attributes{},
}

var _ CorePropsInter = (*CoreProps)(nil)

type CorePropsInter interface {
Expand Down

0 comments on commit 5aaee2b

Please sign in to comment.