Skip to content

Commit

Permalink
Everything except the dash input (#490)
Browse files Browse the repository at this point in the history
* WIP refactoring arg parsing and inputs

# Conflicts:
#	pkg/contract.go
#	pkg/testing/os.go

# Conflicts:
#	internal/os.go

# Conflicts:
#	pkg/cmd/gen.go
#	pkg/input/fs.go
#	pkg/input/reader.go

* WIP getting it all rejiggered

# Conflicts:
#	pkg/cmd/internal/fs.go
#	pkg/cmd/internal/parse.go
#	pkg/cmd/internal/parse_test.go
#	pkg/cmd/internal/reader.go
#	pkg/contract.go

# Conflicts:
#	pkg/contract.go
#	pkg/plugin/aggregate.go
#	pkg/plugin/aggregate_test.go
#	pkg/plugin/github/release.go
#	pkg/plugin/path.go
#	pkg/testing/plugin.go
#	pkg/testing/target.go

# Conflicts:
#	pkg/cmd/internal/fs_test.go

# Conflicts:
#	pkg/cmd/gen.go

* WIP fiddling with mocks

# Conflicts:
#	pkg/cmd/internal/fs.go
#	pkg/cmd/internal/parse.go
#	pkg/cmd/internal/parse_test.go
#	pkg/cmd/internal/reader.go
#	pkg/testing/os.go

# Conflicts:
#	pkg/cmd/internal/fs_test.go

* Input parsing tests

# Conflicts:
#	pkg/cmd/internal/fs_test.go

* dfskjdl

# Conflicts:
#	pkg/cmd/gen.go

* Meh

# Conflicts:
#	pkg/contract.go
#	pkg/plugin/aggregate.go
#	pkg/plugin/github/release.go
#	pkg/plugin/path_test.go

# Conflicts:
#	pkg/cmd/gen.go

* Added panic for unimplemented functions in MockGenerator

The MockGenerator now panics if the StringFunc or ExecuteFunc are not implemented. This change ensures that these methods are properly set before being called, preventing silent failures. The default implementation of ExecuteFunc in NewMockGenerator has been removed as it is no longer needed with this new check.

* Added context to generator function calls

The generator function in the plugin package now accepts a context as its first argument. This change has been reflected across all usages of this function, including tests. Additionally, minor adjustments were made to import statements and method parameters for consistency and readability.

* Updated error messages and plugin search logic

The changes include an update to the error message in e2e tests for better clarity. A new function 'Find' has been added to lookup plugins based on a predicate, improving the plugin search mechanism. The string representation of 'fromPath' has been simplified by removing unnecessary prefix. In typescript.go, the generator now uses the new 'Find' function for searching suitable plugins, enhancing code readability and efficiency. Corresponding test cases have also been updated to reflect these changes.

* Updated TypeScript generator logic

The TypeScript generator logic has been simplified. The 'Choose' function, which was previously used to select a generator from an available list, has been removed. This change simplifies the code and reduces potential error scenarios. Additionally, the declaration of the 'TypeScript' variable has been moved up for better visibility in the code structure.
  • Loading branch information
UnstoppableMango authored Nov 30, 2024
1 parent f566251 commit 88444f8
Show file tree
Hide file tree
Showing 16 changed files with 99 additions and 186 deletions.
9 changes: 9 additions & 0 deletions cmd/ux/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ var _ = Describe("End to end", func() {
})

Describe("gen", func() {
It("should error when input is not provided", func(ctx context.Context) {
cmd := UxCommand(ctx, "gen", "ts")

out, err := cmd.CombinedOutput()

Expect(err).To(HaveOccurred())
Expect(string(out)).To(Equal("no input specified\n"))
})

It("should read spec from yaml file", FlakeAttempts(5), func(ctx context.Context) {
input := filepath.Join(tsSuitePath(), "interface", "source.yml")
output, err := os.ReadFile(filepath.Join(tsSuitePath(), "interface", "target.ts"))
Expand Down
1 change: 1 addition & 0 deletions pkg/cmd/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func NewGen() *cobra.Command {
Short: "Run code generation for TARGET",
Args: cobra.RangeArgs(1, 3),
Run: func(cmd *cobra.Command, args []string) {
// log.SetLevel(log.DebugLevel)
ctx := cmd.Context()
config, err := run.ParseArgs(args)
if err != nil {
Expand Down
2 changes: 0 additions & 2 deletions pkg/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@ type Generator interface {

type Plugin interface {
fmt.Stringer
SinkGenerator(Target) (SinkGenerator, error)
Generator(context.Context, Target) (Generator, error)
}

type Target interface {
fmt.Stringer
Choose([]SinkGenerator) (SinkGenerator, error)
Generator(iter.Seq[Plugin]) (Generator, error)
}

Expand Down
18 changes: 9 additions & 9 deletions pkg/gen/cli/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ import (
tdlv1alpha1 "github.com/unstoppablemango/tdl/pkg/unmango/dev/tdl/v1alpha1"
)

type cli struct {
type generator struct {
name string
args []string
enc tdl.MediaType
stdout bool
}

type Option func(*cli)
type Option func(*generator)

// Execute implements tdl.Generator.
func (c cli) Execute(ctx context.Context, spec *tdlv1alpha1.Spec) (afero.Fs, error) {
func (c generator) Execute(ctx context.Context, spec *tdlv1alpha1.Spec) (afero.Fs, error) {
log.Debug("creating temp directory")
tmp, err := os.MkdirTemp("", "")
if err != nil {
Expand Down Expand Up @@ -63,12 +63,12 @@ func (c cli) Execute(ctx context.Context, spec *tdlv1alpha1.Spec) (afero.Fs, err
}

// String implements fmt.Stringer
func (c cli) String() string {
func (c generator) String() string {
return c.name
}

func New(name string, options ...Option) tdl.Generator {
gen := cli{
gen := generator{
name: name,
enc: mediatype.ApplicationProtobuf,
}
Expand All @@ -78,23 +78,23 @@ func New(name string, options ...Option) tdl.Generator {
}

func WithArgs(args ...string) Option {
return func(c *cli) {
return func(c *generator) {
c.args = args
}
}

func WithEncoding(media tdl.MediaType) Option {
return func(c *cli) {
return func(c *generator) {
c.enc = media
}
}

func ExpectStdout(cli *cli) {
func ExpectStdout(cli *generator) {
cli.stdout = true
}

func WithExpectStdout(stdout bool) Option {
return func(c *cli) {
return func(c *generator) {
c.stdout = stdout
}
}
20 changes: 0 additions & 20 deletions pkg/plugin/aggregate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,6 @@ const UnwrapDepth = 3

type Aggregate []tdl.Plugin

// SinkGenerator implements tdl.Plugin.
func (a Aggregate) SinkGenerator(t tdl.Target) (tdl.SinkGenerator, error) {
if len(a) == 0 {
return nil, errors.New("empty aggregate plugin")
}

errs := []error{}
for _, p := range a.sorted() {
g, err := p.SinkGenerator(t)
if err == nil {
return g, nil
}

log.Error(err, "generator", g)
errs = append(errs, err)
}

return nil, errors.Join(errs...)
}

// Generator implements tdl.Plugin.
func (a Aggregate) Generator(ctx context.Context, t tdl.Target) (tdl.Generator, error) {
if len(a) == 0 {
Expand Down
10 changes: 6 additions & 4 deletions pkg/plugin/aggregate_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package plugin_test

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

Expand All @@ -18,15 +20,15 @@ var _ = Describe("Aggregate", func() {
Expect(result).To(ConsistOf(p))
})

It("should pick the given generator", func() {
g := testing.NewMockGenerator()
It("should pick the given generator", func(ctx context.Context) {
g := &testing.MockGenerator{}
p := (&testing.MockPlugin{}).
WithGenerator(func(tdl.Target) (tdl.SinkGenerator, error) {
WithGenerator(func(tdl.Target) (tdl.Generator, error) {
return g, nil
})
agg := plugin.NewAggregate(p)

result, err := agg.SinkGenerator(&testing.MockTarget{})
result, err := agg.Generator(ctx, &testing.MockTarget{})

Expect(err).NotTo(HaveOccurred())
Expect(result).To(BeIdenticalTo(g))
Expand Down
10 changes: 1 addition & 9 deletions pkg/plugin/github/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/unmango/go/iter"
"github.com/unmango/go/option"
tdl "github.com/unstoppablemango/tdl/pkg"
"github.com/unstoppablemango/tdl/pkg/gen"
"github.com/unstoppablemango/tdl/pkg/plugin/cache"
"github.com/unstoppablemango/tdl/pkg/progress"
)
Expand All @@ -32,14 +31,7 @@ type release struct {

type Option func(*release)

// SinkGenerator implements tdl.Plugin.
func (g *release) SinkGenerator(target tdl.Target) (tdl.SinkGenerator, error) {
return target.Choose([]tdl.SinkGenerator{
gen.NewCli("uml2ts"),
})
}

// SinkGenerator implements tdl.Plugin.
// Generator implements tdl.Plugin.
func (g *release) Generator(ctx context.Context, target tdl.Target) (tdl.Generator, error) {
return target.Generator(iter.Singleton[tdl.Plugin](g))
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/plugin/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"

"github.com/unmango/go/iter"
tdl "github.com/unstoppablemango/tdl/pkg"
"github.com/unstoppablemango/tdl/pkg/plugin/cache"
)
Expand All @@ -25,6 +26,18 @@ func FirstAvailable(target tdl.Target) (tdl.Plugin, error) {
return nil, errors.New("no plugins available")
}

func Find(plugins iter.Seq[tdl.Plugin], pred func(tdl.Plugin) bool) (tdl.Plugin, bool) {
for plugin := range plugins {
for _, nested := range Unwrap(plugin) {
if pred(nested) {
return nested, true
}
}
}

return nil, false
}

func tryCache(p tdl.Plugin) error {
c := cache.XdgBinHome
r, ok := p.(cache.Cachable)
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugin/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (f fromPath) Generator(context.Context, tdl.Target) (tdl.Generator, error)

// String implements tdl.Plugin.
func (f fromPath) String() string {
return fmt.Sprintf("PATH: %s", f.name)
return f.name
}

func (f fromPath) Order() int {
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugin/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var _ = Describe("Path", func() {
It("should stringify", func() {
p := plugin.FromPath("path-thing")

Expect(p.String()).To(Equal("PATH: path-thing"))
Expect(p.String()).To(Equal("path-thing"))
})

Describe("Generator", func() {
Expand Down
4 changes: 2 additions & 2 deletions pkg/target/choose.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
)

type RejectionErr struct {
Generator tdl.SinkGenerator
Generator tdl.Generator
Reason string
}

func (e RejectionErr) Error() string {
return fmt.Sprintf("rejected %s: %s", e.Generator, e.Reason)
}

func Reject(generator tdl.SinkGenerator, reason string) error {
func Reject(generator tdl.Generator, reason string) error {
return &RejectionErr{generator, reason}
}
61 changes: 11 additions & 50 deletions pkg/target/typescript.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,31 @@ package target
import (
"context"
"errors"
"path/filepath"

"github.com/charmbracelet/log"
"github.com/unmango/go/iter"
"github.com/unmango/go/slices"
tdl "github.com/unstoppablemango/tdl/pkg"
"github.com/unstoppablemango/tdl/pkg/gen"
"github.com/unstoppablemango/tdl/pkg/plugin"
)

type typescript string

// Generator implements tdl.Target.
func (t typescript) Generator(available iter.Seq[tdl.Plugin]) (tdl.Generator, error) {
for p := range available {
if p.String() == "uml2ts" {
return p.Generator(context.TODO(), t)
}
}

return nil, errors.New("no suitable plugin")
}

var TypeScript typescript = "TypeScript"

// Choose implements tdl.Target.
func (t typescript) Choose(available []tdl.SinkGenerator) (tdl.SinkGenerator, error) {
if len(available) == 0 {
return nil, errors.New("no generators to choose from")
}

errs := []error{}
for _, g := range available {
if err := supported(g); err != nil {
errs = append(errs, err)
} else {
return g, nil
}
}

return nil, errors.Join(errs...)
}

// Plugins implements tdl.Target.
func (t typescript) Plugins() iter.Seq[tdl.Plugin] {
return slices.Values([]tdl.Plugin{
plugin.Uml2Ts,
// Generator implements tdl.Target.
func (t typescript) Generator(available iter.Seq[tdl.Plugin]) (tdl.Generator, error) {
plugin, ok := plugin.Find(available, func(p tdl.Plugin) bool {
log.Debugf("considering %s", p)
return p.String() == "uml2ts"
})
if !ok {
return nil, errors.New("no suitable plugin")
} else {
return plugin.Generator(context.TODO(), t)
}
}

// String implements tdl.Target.
func (t typescript) String() string {
return string(t)
}

func supported(g tdl.SinkGenerator) error {
cli, ok := g.(*gen.Cli)
if !ok {
return Reject(g, "not a CLI")
}

name := filepath.Base(cli.String())
if name != "uml2ts" {
return Reject(g, "only uml2ts is supported")
}

return nil
}
31 changes: 13 additions & 18 deletions pkg/target/typescript_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,34 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/unmango/go/slices"
"github.com/unmango/go/iter"
tdl "github.com/unstoppablemango/tdl/pkg"
"github.com/unstoppablemango/tdl/pkg/plugin"
"github.com/unstoppablemango/tdl/pkg/target"
"github.com/unstoppablemango/tdl/pkg/testing"
)

var _ = Describe("Typescript", func() {
It("should list the uml2ts plugin", func() {
expected := plugin.NewAggregate(plugin.Uml2Ts)

plugins := target.TypeScript.Plugins()

Expect(slices.Collect(plugins)).To(ConsistOf(expected))
})

Describe("Choose", func() {
Describe("Generator", func() {
It("should choose uml2ts", func() {
expected, err := plugin.Uml2Ts.SinkGenerator(target.TypeScript)
Expect(err).NotTo(HaveOccurred())

chosen, err := target.TypeScript.Choose([]tdl.SinkGenerator{expected})
chosen, err := target.TypeScript.Generator(
iter.Singleton(plugin.Uml2Ts),
)

Expect(err).NotTo(HaveOccurred())
Expect(chosen).To(BeIdenticalTo(expected))
Expect(chosen).NotTo(BeNil()) // TODO
})

It("should ignore unsupported generators", func() {
g := testing.NewMockGenerator()
g := (&testing.MockPlugin{}).WithString(func() string {
return "test"
})

_, err := target.TypeScript.Choose([]tdl.SinkGenerator{g})
_, err := target.TypeScript.Generator(
iter.Singleton[tdl.Plugin](g),
)

Expect(err).To(MatchError(ContainSubstring("not a CLI")))
Expect(err).To(MatchError("no suitable plugin"))
})
})
})
Loading

0 comments on commit 88444f8

Please sign in to comment.