Skip to content

Commit

Permalink
-backend-framework
Browse files Browse the repository at this point in the history
  • Loading branch information
Ujstor committed Feb 2, 2025
1 parent 5bc3105 commit e5b978a
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 97 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ gives the option to integrate with one of the more popular backend and fronted f
- Easy to set up and install
- Have the entire Go structure already established
- Setting up a Go HTTP server (or Fasthttp with Fiber)
- Integrates with a popular backend and frontend frameworks
- Focus on the actual code of your application

## Table of Contents

- [Install](#install)
- [Backend Frameworks](#backends)
- [BackendFramework Frameworks](#backends)
- [Database Support](#database-support)
- [Frontend Frameworks](#frontend)
- [Advanced Features](#advanced-features)
Expand Down Expand Up @@ -76,7 +77,7 @@ Usage:
Flags:
-a, --advanced Get prompts for advanced features
--feature AdvancedFeatures Advanced feature to use. Allowed values: githubaction, websocket, docker
-b, --backend Backend Backend to use. Allowed values: chi, gin, fiber, gorilla/mux, standard-library, echo
-b, --backend-framework BackendFramework Backend framework to use. Allowed values: chi, gin, fiber, gorilla/mux, standard-library, echo
-d, --driver Database Database drivers to use. Allowed values: mysql, postgres, sqlite, mongo, redis, scylla, none
-f, --frontend Get prompts for frontend frameworks
--frontend-framework Frontendframework Frontend framework to use. Allowed values: htmx, react
Expand Down
52 changes: 23 additions & 29 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var (
)

func init() {
var flagBackend flags.Backend
var flagBackendFramework flags.BackendFramework
var flagDBDriver flags.Database
var frontendFrameworks flags.FrontendFramework
var frontendAdvanced flags.FrontendAdvanced
Expand All @@ -50,7 +50,7 @@ func init() {

// Main flags
createCmd.Flags().StringP("name", "n", "", "Name of project to create")
createCmd.Flags().VarP(&flagBackend, "backend", "b", fmt.Sprintf("Backend to use. Allowed values: %s", strings.Join(flags.AllowedBackedTypes, ", ")))
createCmd.Flags().VarP(&flagBackendFramework, "backend-framework", "b", fmt.Sprintf("Backend framework to use. Allowed values: %s", strings.Join(flags.AllowedBackendFrameworkTypes, ", ")))
createCmd.Flags().VarP(&flagDBDriver, "driver", "d", fmt.Sprintf("Database drivers to use. Allowed values: %s", strings.Join(flags.AllowedDBDrivers, ", ")))
createCmd.Flags().VarP(&flagGit, "git", "g", fmt.Sprintf("Git to use. Allowed values: %s", strings.Join(flags.AllowedGitsOptions, ", ")))

Expand All @@ -62,17 +62,11 @@ func init() {
// Advanced features group
createCmd.Flags().BoolP("advanced", "a", false, "Get prompts for advanced features")
createCmd.Flags().Var(&advancedFeatures, "feature", fmt.Sprintf("Advanced feature to use. Allowed values: %s", strings.Join(flags.AllowedAdvancedFeatures, ", ")))

// // Mark dependencies for frontend flags
// createCmd.MarkFlagsRequiredTogether("frontend", "frontend-framework")
//
// // Mark feature flag as requiring --advanced
// createCmd.MarkFlagsRequiredTogether("advanced", "feature")
}

type Options struct {
ProjectName *textinput.Output
ProjectType *multiInput.Selection
BackendFramework *multiInput.Selection
DBDriver *multiInput.Selection
FrontendFramework *multiInput.Selection
FrontendAdvanced *multiSelect.Selection
Expand Down Expand Up @@ -106,14 +100,14 @@ var createCmd = &cobra.Command{

// VarP already validates the contents of the framework flag.
// If this flag is filled, it is always valid
flagBackend := flags.Backend(cmd.Flag("backend").Value.String())
flagBackendFramework := flags.BackendFramework(cmd.Flag("backend-framework").Value.String())
flagDBDriver := flags.Database(cmd.Flag("driver").Value.String())
flagFrontendFremwork := flags.FrontendFramework(cmd.Flag("frontend-framework").Value.String())
flagGit := flags.Git(cmd.Flag("git").Value.String())

options := Options{
ProjectName: &textinput.Output{},
ProjectType: &multiInput.Selection{},
BackendFramework: &multiInput.Selection{},
DBDriver: &multiInput.Selection{},
FrontendFramework: &multiInput.Selection{},
FrontendAdvanced: &multiSelect.Selection{
Expand All @@ -126,18 +120,18 @@ var createCmd = &cobra.Command{
}

project := &program.Project{
ProjectName: flagName,
ProjectType: flagBackend,
DBDriver: flagDBDriver,
BackendMap: make(map[flags.Backend]program.Backend),
DBDriverMap: make(map[flags.Database]program.Driver),
FrontendFramework: flagFrontendFremwork,
FrontendOptions: make(map[string]bool),
AdvancedOptions: make(map[string]bool),
GitOptions: flagGit,
ProjectName: flagName,
BackendFramework: flagBackendFramework,
DBDriver: flagDBDriver,
BackendFrameworkMap: make(map[flags.BackendFramework]program.BackendFramework),
DBDriverMap: make(map[flags.Database]program.Driver),
FrontendFramework: flagFrontendFremwork,
FrontendOptions: make(map[string]bool),
AdvancedOptions: make(map[string]bool),
GitOptions: flagGit,
}

steps := steps.InitSteps(flagBackend, flagDBDriver, flagFrontendFremwork, flagGit)
steps := steps.InitSteps(flagBackendFramework, flagDBDriver, flagFrontendFremwork, flagGit)
fmt.Printf("%s\n", logoStyle.Render(logo))

// Frontend option steps:
Expand Down Expand Up @@ -187,23 +181,23 @@ var createCmd = &cobra.Command{
}
}

if project.ProjectType == "" {
if project.BackendFramework == "" {
isInteractive = true
step := steps.Steps["backend"]
tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.ProjectType, step.Headers, project))
step := steps.Steps["backend-framework"]
tprogram = tea.NewProgram(multiInput.InitialModelMulti(step.Options, options.BackendFramework, step.Headers, project))
if _, err := tprogram.Run(); err != nil {
cobra.CheckErr(textinput.CreateErrorInputModel(err).Err())
}
project.ExitCLI(tprogram)

step.Field = options.ProjectType.Choice
step.Field = options.BackendFramework.Choice

// this type casting is always safe since the user interface can
// only pass strings that can be cast to a flags.Backend instance
project.ProjectType = flags.Backend(strings.ToLower(options.ProjectType.Choice))
err := cmd.Flag("backend").Value.Set(project.ProjectType.String())
// only pass strings that can be cast to a flags.BackendFramework instance
project.BackendFramework = flags.BackendFramework(strings.ToLower(options.BackendFramework.Choice))
err := cmd.Flag("backend-framework").Value.Set(project.BackendFramework.String())
if err != nil {
log.Fatal("failed to set the backend flag value", err)
log.Fatal("failed to set the backendFramework flag value", err)
}
}

Expand Down
34 changes: 17 additions & 17 deletions cmd/flags/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,39 @@ import (
"strings"
)

type Backend string
type BackendFramework string

// These are all the current backends supported. If you want to add one, you
// can simply copy and paste a line here. Do not forget to also add it into the
// AllowedBackedTypes slice too!
// AllowedBackendTypes slice too!
const (
Chi Backend = "chi"
Gin Backend = "gin"
Fiber Backend = "fiber"
GorillaMux Backend = "gorilla/mux"
StandardLibrary Backend = "standard-library"
Echo Backend = "echo"
Chi BackendFramework = "chi"
Gin BackendFramework = "gin"
Fiber BackendFramework = "fiber"
GorillaMux BackendFramework = "gorilla/mux"
StandardLibrary BackendFramework = "standard-library"
Echo BackendFramework = "echo"
)

var AllowedBackedTypes = []string{string(Chi), string(Gin), string(Fiber), string(GorillaMux), string(StandardLibrary), string(Echo)}
var AllowedBackendFrameworkTypes = []string{string(Chi), string(Gin), string(Fiber), string(GorillaMux), string(StandardLibrary), string(Echo)}

func (f Backend) String() string {
func (f BackendFramework) String() string {
return string(f)
}

func (f *Backend) Type() string {
return "Backend"
func (f *BackendFramework) Type() string {
return "BackendFramework"
}

func (f *Backend) Set(value string) error {
func (f *BackendFramework) Set(value string) error {
// Contains isn't available in 1.20 yet
// if AllowedBackedTypes.Contains(value) {
for _, project := range AllowedBackedTypes {
// if AllowedBackendTypes.Contains(value) {
for _, project := range AllowedBackendFrameworkTypes {
if project == value {
*f = Backend(value)
*f = BackendFramework(value)
return nil
}
}

return fmt.Errorf("Backend to use. Allowed values: %s", strings.Join(AllowedBackedTypes, ", "))
return fmt.Errorf("BackendFramework to use. Allowed values: %s", strings.Join(AllowedBackendFrameworkTypes, ", "))
}
4 changes: 2 additions & 2 deletions cmd/program/advanced.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

func (p *Project) CreateWebsocketImports(appDir string) {
websocketDependency := []string{"github.com/coder/websocket"}
if p.ProjectType == flags.Fiber {
if p.BackendFramework == flags.Fiber {
websocketDependency = []string{"github.com/gofiber/contrib/websocket"}
}

Expand All @@ -24,7 +24,7 @@ func (p *Project) CreateWebsocketImports(appDir string) {
log.Fatal(err)
}

importsPlaceHolder := string(p.BackendMap[p.ProjectType].templater.WebsocketImports())
importsPlaceHolder := string(p.BackendFrameworkMap[p.BackendFramework].templater.WebsocketImports())

importTmpl, err := template.New("imports").Parse(importsPlaceHolder)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd/program/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ func (p *Project) CreateHtmxTemplates() {
routesPlaceHolder := ""
importsPlaceHolder := ""
if p.FrontendFramework == flags.Htmx {
routesPlaceHolder += string(p.BackendMap[p.ProjectType].templater.HtmxTemplRoutes())
importsPlaceHolder += string(p.BackendMap[p.ProjectType].templater.HtmxTemplImports())
routesPlaceHolder += string(p.BackendFrameworkMap[p.BackendFramework].templater.HtmxTemplRoutes())
importsPlaceHolder += string(p.BackendFrameworkMap[p.BackendFramework].templater.HtmxTemplImports())
}

routeTmpl, err := template.New("routes").Parse(routesPlaceHolder)
Expand Down
8 changes: 4 additions & 4 deletions cmd/program/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ func (p *Project) CreateFileWithInjection(pathToCreate string, projectPath strin

switch methodName {
case "main":
createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendMap[p.ProjectType].templater.Main())))
createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendFrameworkMap[p.BackendFramework].templater.Main())))
err = createdTemplate.Execute(createdFile, p)
case "server":
createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendMap[p.ProjectType].templater.Server())))
createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendFrameworkMap[p.BackendFramework].templater.Server())))
err = createdTemplate.Execute(createdFile, p)
case "routes":
routeFileBytes := p.BackendMap[p.ProjectType].templater.Routes()
routeFileBytes := p.BackendFrameworkMap[p.BackendFramework].templater.Routes()
createdTemplate := template.Must(template.New(fileName).Parse(string(routeFileBytes)))
err = createdTemplate.Execute(createdFile, p)
case "releaser":
Expand All @@ -92,7 +92,7 @@ func (p *Project) CreateFileWithInjection(pathToCreate string, projectPath strin
createdTemplate := template.Must(template.New(fileName).Parse(string(p.DBDriverMap[p.DBDriver].templater.Tests())))
err = createdTemplate.Execute(createdFile, p)
case "tests":
createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendMap[p.ProjectType].templater.TestHandler())))
createdTemplate := template.Must(template.New(fileName).Parse(string(p.BackendFrameworkMap[p.BackendFramework].templater.TestHandler())))
err = createdTemplate.Execute(createdFile, p)
case "env":
if p.DBDriver != "none" {
Expand Down
64 changes: 32 additions & 32 deletions cmd/program/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ import (
// A Project contains the data for the project folder
// being created, and methods that help with that process
type Project struct {
ProjectName string
Exit bool
AbsolutePath string
ProjectType flags.Backend
DBDriver flags.Database
Docker flags.Database
FrontendFramework flags.FrontendFramework
BackendMap map[flags.Backend]Backend
DBDriverMap map[flags.Database]Driver
DockerMap map[flags.Database]Docker
FrontendTemplates FrontendTemplates
FrontendOptions map[string]bool
AdvancedTemplates AdvancedTemplates
AdvancedOptions map[string]bool
GitOptions flags.Git
OSCheck map[string]bool
ProjectName string
Exit bool
AbsolutePath string
BackendFramework flags.BackendFramework
DBDriver flags.Database
Docker flags.Database
FrontendFramework flags.FrontendFramework
BackendFrameworkMap map[flags.BackendFramework]BackendFramework
DBDriverMap map[flags.Database]Driver
DockerMap map[flags.Database]Docker
FrontendTemplates FrontendTemplates
FrontendOptions map[string]bool
AdvancedTemplates AdvancedTemplates
AdvancedOptions map[string]bool
GitOptions flags.Git
OSCheck map[string]bool
}

type FrontendTemplates struct {
Expand All @@ -51,9 +51,9 @@ type AdvancedTemplates struct {
TemplateImports string
}

// A Backend contains the name and templater for a
// given Backend
type Backend struct {
// A Backend Framework contains the name and templater for a
// given Backend Framework
type BackendFramework struct {
packageName []string
templater Templater
}
Expand All @@ -69,7 +69,7 @@ type Docker struct {
}

// A Templater has the methods that help build the files
// in the Project folder, and is specific to a Backend
// in the Project folder, and is specific to a BackendFramework
type Templater interface {
Main() []byte
Server() []byte
Expand Down Expand Up @@ -137,34 +137,34 @@ func (p *Project) ExitCLI(tprogram *tea.Program) {
}

// createFrameWorkMap adds the current supported
// Backends into a Project's BackendMap
func (p *Project) createBackendMap() {
p.BackendMap[flags.Chi] = Backend{
// BackendFrameworks into a Project's BackendFrameworkMap
func (p *Project) createBackendFrameworkMap() {
p.BackendFrameworkMap[flags.Chi] = BackendFramework{
packageName: chiPackage,
templater: backend.ChiTemplates{},
}

p.BackendMap[flags.StandardLibrary] = Backend{
p.BackendFrameworkMap[flags.StandardLibrary] = BackendFramework{
packageName: []string{},
templater: backend.StandardLibTemplate{},
}

p.BackendMap[flags.Gin] = Backend{
p.BackendFrameworkMap[flags.Gin] = BackendFramework{
packageName: ginPackage,
templater: backend.GinTemplates{},
}

p.BackendMap[flags.Fiber] = Backend{
p.BackendFrameworkMap[flags.Fiber] = BackendFramework{
packageName: fiberPackage,
templater: backend.FiberTemplates{},
}

p.BackendMap[flags.GorillaMux] = Backend{
p.BackendFrameworkMap[flags.GorillaMux] = BackendFramework{
packageName: gorillaPackage,
templater: backend.GorillaTemplates{},
}

p.BackendMap[flags.Echo] = Backend{
p.BackendFrameworkMap[flags.Echo] = BackendFramework{
packageName: echoPackage,
templater: backend.EchoTemplates{},
}
Expand Down Expand Up @@ -254,7 +254,7 @@ func (p *Project) CreateMainFile() error {
p.CheckOS()

// Create the map for our program
p.createBackendMap()
p.createBackendFrameworkMap()

// Create go.mod
err = utils.InitGoMod(p.ProjectName, projectPath)
Expand All @@ -264,8 +264,8 @@ func (p *Project) CreateMainFile() error {
}

// Install the correct package for the selected backend
if p.ProjectType != flags.StandardLibrary {
err = utils.GoGetPackage(projectPath, p.BackendMap[p.ProjectType].packageName)
if p.BackendFramework != flags.StandardLibrary {
err = utils.GoGetPackage(projectPath, p.BackendFrameworkMap[p.BackendFramework].packageName)
if err != nil {
log.Printf("Could not install go dependency for the chosen backend %v\n", err)
return err
Expand Down Expand Up @@ -505,7 +505,7 @@ func (p *Project) CreateMainFile() error {
}
defer efsFile.Close()

if p.ProjectType == "fiber" {
if p.BackendFramework == "fiber" {
helloGoTemplate := template.Must(template.New("efs").Parse((string(frontend.HelloFiberGoTemplate()))))
err = helloGoTemplate.Execute(helloGoFile, p)
if err != nil {
Expand Down
Loading

0 comments on commit e5b978a

Please sign in to comment.