func (r *Renderer) CreateLayout(dir string) error {
	src := &bytes.Buffer{}
	err := r.WriteLayout(src)
	if err != nil {
		return err
	}
	fmtsrc, err := format.Source(src.Bytes())
	if err != nil {
		return fmt.Errorf("cannot format source, %w", err)
	}
	file, err := r.fs.Create(path.Join(dir, "layout_gen.go"))
	if err != nil {
		return err
	}
	defer file.Close()
	_, err = file.Write(fmtsrc)
	if err != nil {
		return fmt.Errorf("cannot write source, %w", err)
	}
	return nil
}
CreateLayout creates the layout file in the given directory
package generator
import (
	"bytes"
	"embed"
	"fmt"
	"go/format"
	"io"
	"path"
	"sort"
	"strings"
	"text/template"
	"github.com/huandu/xstrings"
)
type Creator interface {
	Create(name string) (io.WriteCloser, error)
}
type Renderer struct {
	tmpl *template.Template
	root *Root
	fs Creator
}
var templates embed.FS
func NewRenderer(fs Creator, root *Root) (*Renderer, error) {
	r := &Renderer{
		root: root,
		fs:   fs,
	}
	tmpl, err := template.New("base").ParseFS(templates, "templates/*.tmpl")
	if err != nil {
		return nil, err
	}
	r.tmpl = tmpl
	return r, nil
}
var doNotEdit = "// Code generated by go-plotly/generator. DO NOT EDIT."
func (r *Renderer) CreateTrace(dir string, name string) error {
	src := &bytes.Buffer{}
	err := r.WriteTrace(name, src)
	if err != nil {
		return err
	}
	fmtsrc, err := format.Source(src.Bytes())
	if err != nil {
		return fmt.Errorf("cannot format source, %w", err)
	}
	file, err := r.fs.Create(path.Join(dir, name+"_gen.go"))
	if err != nil {
		return err
	}
	defer file.Close()
	_, err = file.Write(fmtsrc)
	if err != nil {
		return fmt.Errorf("cannot write source, %w", err)
	}
	return nil
}
func (r *Renderer) WriteTrace(traceName string, w io.Writer) error {
	trace := r.root.Schema.Traces[traceName]
	traceFile := typeFile{
		MainType: sstruct{
			Name:        xstrings.ToCamelCase(trace.Type),
			Description: trace.Meta.Description,
			Fields: []structField{
				{
					Name:        "Type",
					JSONName:    "type",
					Type:        "TraceType",
					Description: []string{"is the type of the plot"},
				},
			},
		},
		Objects:   []sstruct{},
		Enums:     []enumFile{},
		FlagLists: []flagList{},
	}
	fields, err := traceFile.parseAttributes(traceFile.MainType.Name, traceFile.MainType.Name, trace.Attributes.Names)
	if err != nil {
		return fmt.Errorf("cannot parse attributes, %w", err)
	}
	traceFile.MainType.Fields = append(traceFile.MainType.Fields, fields...)
	fmt.Fprintf(w, `package grob
%s
var TraceType%s TraceType = "%s"
func (trace *%s) GetType() TraceType {
	return TraceType%s
}
`,
		doNotEdit,
		traceFile.MainType.Name,
		traceName,
		traceFile.MainType.Name,
		traceFile.MainType.Name,
	)
	err = r.tmpl.ExecuteTemplate(w, "trace.tmpl", traceFile.MainType)
	if err != nil {
		return err
	}
	for i := range traceFile.Objects {
		err := r.tmpl.ExecuteTemplate(w, "trace.tmpl", traceFile.Objects[i])
		if err != nil {
			return err
		}
	}
	for i := range traceFile.Enums {
		err := r.tmpl.ExecuteTemplate(w, "enum.tmpl", traceFile.Enums[i])
		if err != nil {
			return err
		}
	}
	for i := range traceFile.FlagLists {
		err := r.tmpl.ExecuteTemplate(w, "flaglist.tmpl", traceFile.FlagLists[i])
		if err != nil {
			return err
		}
	}
	return nil
}
func (r *Renderer) CreateTraces(dir string) error {
	traceNames := make([]string, 0, len(r.root.Schema.Traces))
	for n := range r.root.Schema.Traces {
		traceNames = append(traceNames, n)
	}
	sort.Strings(traceNames)
	for _, name := range traceNames {
		err := r.CreateTrace(dir, name)
		if err != nil {
			return fmt.Errorf("cannot create trace, %w", err)
		}
	}
	return nil
}