From ee71acdefb508c81efb8ca007279581d3c35619f Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 27 Apr 2022 11:28:50 -0500 Subject: [PATCH 01/17] feat: Switch packages for typescript generation code --- go.mod | 1 + go.sum | 1 + scripts/apitypings/main.go | 24 +++++- scripts/apitypings/main2.go | 162 ++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 scripts/apitypings/main2.go diff --git a/go.mod b/go.mod index e5c30e4c8493b..b542889f6527c 100644 --- a/go.mod +++ b/go.mod @@ -107,6 +107,7 @@ require ( golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220412211240-33da011f77ad golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 + golang.org/x/tools v0.1.10 golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f google.golang.org/api v0.75.0 google.golang.org/protobuf v1.28.0 diff --git a/go.sum b/go.sum index 95e59befa800b..b2fe8d470604c 100644 --- a/go.sum +++ b/go.sum @@ -2157,6 +2157,7 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index a738e553e01ac..bc1586e992f46 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -1,16 +1,19 @@ package main import ( + "context" "fmt" "go/ast" "go/parser" "go/token" - "log" "os" "path/filepath" "sort" "strings" + "cdr.dev/slog" + "cdr.dev/slog/sloggers/sloghuman" + "golang.org/x/xerrors" ) @@ -19,9 +22,23 @@ const ( ) func main() { - err := run() + ctx := context.Background() + log := slog.Make(sloghuman.Sink(os.Stderr)) + g := Generator{log: log} + err := g.parsePackage(ctx, "./codersdk") + if err != nil { + panic(err) + } + //err = g.generate("ProvisionerJob") + err = g.generateAll() + if err != nil { + panic(err) + } + return + + err = run() if err != nil { - log.Fatal(err) + log.Fatal(ctx, err.Error()) } } @@ -180,6 +197,7 @@ func getIdent(e ast.Expr) (*ast.Ident, string, error) { } func toTsType(fieldType string) string { + fmt.Println(fieldType) switch fieldType { case "bool": return "boolean" diff --git a/scripts/apitypings/main2.go b/scripts/apitypings/main2.go new file mode 100644 index 0000000000000..df202cacb54d4 --- /dev/null +++ b/scripts/apitypings/main2.go @@ -0,0 +1,162 @@ +package main + +import ( + "context" + "fmt" + "go/types" + "reflect" + "strings" + + "golang.org/x/tools/go/packages" + "golang.org/x/xerrors" + + "cdr.dev/slog" +) + +type Generator struct { + pkg *packages.Package // Package we are scanning. + log slog.Logger +} + +// parsePackage takes a list of patterns such as a directory, and parses them. +// All parsed packages will accumulate "foundTypes". +func (g *Generator) parsePackage(ctx context.Context, patterns ...string) error { + cfg := &packages.Config{ + Mode: packages.NeedTypes | packages.NeedName | packages.NeedTypesInfo | + packages.NeedTypesSizes | packages.NeedSyntax, + Tests: false, + Context: ctx, + } + + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + return xerrors.Errorf("load package: %w", err) + } + + if len(pkgs) != 1 { + return xerrors.Errorf("expected 1 package, found %d", len(pkgs)) + } + + g.pkg = pkgs[0] + return nil +} + +// generateAll will generate for all types found in the pkg +func (g *Generator) generateAll() error { + for _, n := range g.pkg.Types.Scope().Names() { + err := g.generate(n) + if err != nil { + return xerrors.Errorf("generate %q: %w", n, err) + } + } + return nil +} + +// generate generates the typescript for a singular Go type. +func (g *Generator) generate(typeName string) error { + obj := g.pkg.Types.Scope().Lookup(typeName) + if obj == nil || obj.Type() == nil { + return xerrors.Errorf("pkg is missing type %q", typeName) + } + + st, ok := obj.Type().Underlying().(*types.Struct) + if !ok { + return nil + //return xerrors.Errorf("only generate for structs, found %q", obj.Type().String()) + } + + return g.buildStruct(obj, st) +} + +// buildStruct just prints the typescript def for a type. +// TODO: Write to a buffer instead +func (g *Generator) buildStruct(obj types.Object, st *types.Struct) error { + var s strings.Builder + s.WriteString("export interface " + obj.Name() + "{\n") + for i := 0; i < st.NumFields(); i++ { + field := st.Field(i) + tag := reflect.StructTag(st.Tag(i)) + jsonName := tag.Get("json") + arr := strings.Split(jsonName, ",") + jsonName = arr[0] + if jsonName == "" { + jsonName = field.Name() + } + + ts, err := g.typescriptType(field.Type()) + if err != nil { + return xerrors.Errorf("typescript type: %w", err) + } + s.WriteString(fmt.Sprintf("\treadonly %s: %s\n", jsonName, ts)) + } + s.WriteString("}") + fmt.Println(s.String()) + return nil +} + +// typescriptType this function returns a typescript type for a given +// golang type. +// Eg: +// []byte returns "string" +func (g *Generator) typescriptType(ty types.Type) (string, error) { + switch ty.(type) { + case *types.Basic: + bs := ty.(*types.Basic) + // All basic literals (string, bool, int, etc). + // TODO: Actually ensure the golang names are ok, otherwise, + // we want to put another switch to capture these types + // and rename to typescript. + return bs.Name(), nil + case *types.Struct: + // TODO: This kinda sucks right now. It just dumps the struct def + return ty.String(), nil + case *types.Map: + // TODO: Typescript dictionary??? Object? + return "map", nil + case *types.Slice, *types.Array: + type hasElem interface { + Elem() types.Type + } + + arr := ty.(hasElem) + // All byte arrays should be strings in typescript? + if arr.Elem().String() == "byte" { + return "string", nil + } + + // Array of underlying type. + underlying, err := g.typescriptType(arr.Elem()) + if err != nil { + return "", xerrors.Errorf("array: %w", err) + } + return underlying + "[]", nil + case *types.Named: + // Named is a named type like + // type EnumExample string + // Use the underlying type + n := ty.(*types.Named) + name := n.Obj().Name() + // If we have the type, just put the name because it will be defined + // elsewhere in the typescript gen. + if obj := g.pkg.Types.Scope().Lookup(n.String()); obj != nil { + return name, nil + } + + // If it's a struct, just use the name for now. + if _, ok := ty.Underlying().(*types.Struct); ok { + return name, nil + } + + // Defer to the underlying type. + return g.typescriptType(ty.Underlying()) + case *types.Pointer: + // Dereference pointers. + // TODO: Nullable fields? + pt := ty.(*types.Pointer) + return g.typescriptType(pt.Elem()) + } + + // These are all the other types we need to support. + // time.Time, uuid, etc. + return "", xerrors.Errorf("unknown type: %s", ty.String()) +} From b0b17d0e57f4eb3f46175b34383707c20ff23c1e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 27 Apr 2022 21:59:13 -0500 Subject: [PATCH 02/17] Add enum functionality --- scripts/apitypings/main.go | 405 ++++++++++++++++++++++-------------- scripts/apitypings/main2.go | 162 --------------- 2 files changed, 248 insertions(+), 319 deletions(-) delete mode 100644 scripts/apitypings/main2.go diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index bc1586e992f46..0b928acb418bc 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -3,18 +3,18 @@ package main import ( "context" "fmt" - "go/ast" - "go/parser" - "go/token" + "go/types" "os" "path/filepath" - "sort" + "reflect" "strings" - "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" + "golang.org/x/tools/go/packages" "golang.org/x/xerrors" + + "cdr.dev/slog" ) const ( @@ -24,203 +24,294 @@ const ( func main() { ctx := context.Background() log := slog.Make(sloghuman.Sink(os.Stderr)) - g := Generator{log: log} - err := g.parsePackage(ctx, "./codersdk") + codeBlocks, err := GenerateFromDirectory(ctx, log, baseDir) if err != nil { - panic(err) + log.Fatal(ctx, err.Error()) } - //err = g.generate("ProvisionerJob") - err = g.generateAll() - if err != nil { - panic(err) + + // Just cat the output to a file to capture it + fmt.Println(codeBlocks.String()) +} + +type TypescriptTypes struct { + // Each entry is the type name, and it's typescript code block. + Types map[string]string + Enums map[string]string +} + +// String just combines all the codeblocks. I store them in a map for unit testing purposes +func (t TypescriptTypes) String() string { + var s strings.Builder + for _, v := range t.Types { + s.WriteString(v) + s.WriteRune('\n') } - return - err = run() - if err != nil { - log.Fatal(ctx, err.Error()) + for _, v := range t.Enums { + s.WriteString(v) + s.WriteRune('\n') } + return s.String() } -func run() error { - var ( - astFiles []*ast.File - enums = make(map[string]string) - ) - fset := token.NewFileSet() - entries, err := os.ReadDir(baseDir) +// GenerateFromDirectory will return all the typescript code blocks for a directory +func GenerateFromDirectory(ctx context.Context, log slog.Logger, directory string) (*TypescriptTypes, error) { + g := Generator{ + log: log, + } + err := g.parsePackage(ctx, directory) if err != nil { - return xerrors.Errorf("reading dir %s: %w", baseDir, err) + return nil, xerrors.Errorf("parse package %q: %w", directory, err) } - // loop each file in directory - for _, entry := range entries { - astFile, err := parser.ParseFile(fset, filepath.Join(baseDir, entry.Name()), nil, 0) - if err != nil { - return xerrors.Errorf("parsing file %s: %w", filepath.Join(baseDir, entry.Name()), err) - } - - astFiles = append(astFiles, astFile) + codeBlocks, err := g.generateAll() + if err != nil { + return nil, xerrors.Errorf("parse package %q: %w", directory, err) } - // TypeSpec case for structs and type alias - loopSpecs(astFiles, func(spec ast.Spec) { - pos := fset.Position(spec.Pos()) - s, ok := spec.(*ast.TypeSpec) - if !ok { - return - } - out, err := handleTypeSpec(s, pos, enums) - if err != nil { - return - } + return codeBlocks, nil +} - _, _ = fmt.Printf(out) - }) +type Generator struct { + // Package we are scanning. + pkg *packages.Package + log slog.Logger +} - // ValueSpec case for loading type alias values into the enum map - loopSpecs(astFiles, func(spec ast.Spec) { - s, ok := spec.(*ast.ValueSpec) - if !ok { - return - } - handleValueSpec(s, enums) - }) +// parsePackage takes a list of patterns such as a directory, and parses them. +func (g *Generator) parsePackage(ctx context.Context, patterns ...string) error { + cfg := &packages.Config{ + // Just accept the fact we need these flags for what we want. Feel free to add + // more, it'll just increase the time it takes to parse. + Mode: packages.NeedTypes | packages.NeedName | packages.NeedTypesInfo | + packages.NeedTypesSizes | packages.NeedSyntax, + Tests: false, + Context: ctx, + } - // sort keys so output is always the same - var keys []string - for k := range enums { - keys = append(keys, k) + pkgs, err := packages.Load(cfg, patterns...) + if err != nil { + return xerrors.Errorf("load package: %w", err) } - sort.Strings(keys) - // write each type alias declaration with possible values - for _, k := range keys { - _, _ = fmt.Printf("%s\n", enums[k]) + // Only support 1 package for now. We can expand it if we need later, we + // just need to hook up multiple packages in the generator. + if len(pkgs) != 1 { + return xerrors.Errorf("expected 1 package, found %d", len(pkgs)) } + g.pkg = pkgs[0] return nil } -func loopSpecs(astFiles []*ast.File, fn func(spec ast.Spec)) { - for _, astFile := range astFiles { - // loop each declaration in file - for _, node := range astFile.Decls { - genDecl, ok := node.(*ast.GenDecl) - if !ok { - continue - } - for _, spec := range genDecl.Specs { - fn(spec) - } - } - } +type Generated struct { } -func handleTypeSpec(typeSpec *ast.TypeSpec, pos token.Position, enums map[string]string) (string, error) { - jsonFields := 0 - s := fmt.Sprintf("// From %s.\n", pos.String()) - switch t := typeSpec.Type.(type) { - // Struct declaration - case *ast.StructType: - s = fmt.Sprintf("%sexport interface %s {\n", s, typeSpec.Name.Name) - for _, field := range t.Fields.List { - i, optional, err := getIdent(field.Type) - if err != nil { - continue - } +// generateAll will generate for all types found in the pkg +func (g *Generator) generateAll() (*TypescriptTypes, error) { + structs := make(map[string]string) + enums := make(map[string]types.Object) + constants := make(map[string][]*types.Const) - fieldType := toTsType(i.Name) - if fieldType == "" { - continue - } + for _, n := range g.pkg.Types.Scope().Names() { + obj := g.pkg.Types.Scope().Lookup(n) + if obj == nil || obj.Type() == nil { + // This would be weird, but it is if the package does not have the type def. + continue + } - fieldName := toJSONField(field) - if fieldName == "" { - continue + switch obj.(type) { + // All named types are type declarations + case *types.TypeName: + named, ok := obj.Type().(*types.Named) + if !ok { + panic("all typename should be named types") + } + switch named.Underlying().(type) { + case *types.Struct: + // Structs are obvious + st := obj.Type().Underlying().(*types.Struct) + codeBlock, err := g.buildStruct(obj, st) + if err != nil { + return nil, xerrors.Errorf("generate %q: %w", obj.Name()) + } + structs[obj.Name()] = codeBlock + case *types.Basic: + // These are enums. Store to expand later. + enums[obj.Name()] = obj + } + case *types.Var: + // TODO: Are any enums var declarations? + v := obj.(*types.Var) + var _ = v + case *types.Const: + c := obj.(*types.Const) + // We only care about named constant types, since they are enums + if named, ok := c.Type().(*types.Named); ok { + name := named.Obj().Name() + constants[name] = append(constants[name], c) } - - s = fmt.Sprintf("%s readonly %s%s: %s\n", s, fieldName, optional, fieldType) - jsonFields++ } + } - // Do not print struct if it has no json fields - if jsonFields == 0 { - return "", xerrors.New("no json fields") + // Write all enums + enumCodeBlocks := make(map[string]string) + for name, v := range enums { + var values []string + for _, elem := range constants[name] { + // TODO: If we have non string constants, we need to handle that + // here. + values = append(values, elem.Val().String()) } + var s strings.Builder + s.WriteString(g.posLine(v)) + s.WriteString(fmt.Sprintf("export type %s = %s\n", + name, strings.Join(values, " | "), + )) + s.WriteRune('\n') - return fmt.Sprintf("%s}\n\n", s), nil - // Type alias declaration - case *ast.Ident: - // save type declaration to map of types - // later we come back and add union types to this declaration - enums[typeSpec.Name.Name] = fmt.Sprintf("%sexport type %s = \n", s, typeSpec.Name.Name) - return "", xerrors.New("enums are not printed at this stage") - default: - return "", xerrors.New("not struct or alias") + enumCodeBlocks[name] = s.String() } + + return &TypescriptTypes{ + Types: structs, + Enums: enumCodeBlocks, + }, nil } -func handleValueSpec(valueSpec *ast.ValueSpec, enums map[string]string) { - valueValue := "" - i, ok := valueSpec.Type.(*ast.Ident) - if !ok { - return - } - valueType := i.Name +func (g *Generator) posLine(obj types.Object) string { + file := g.pkg.Fset.File(obj.Pos()) + position := file.Position(obj.Pos()) + position.Filename = filepath.Join("codersdk", filepath.Base(position.Filename)) + return fmt.Sprintf("// From %s\n", + position.String(), + ) +} - for _, value := range valueSpec.Values { - bl, ok := value.(*ast.BasicLit) - if !ok { - return - } - valueValue = bl.Value - break - } +// buildStruct just prints the typescript def for a type. +func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, error) { + var s strings.Builder + s.WriteString(g.posLine(obj)) - enums[valueType] = fmt.Sprintf("%s | %s\n", enums[valueType], valueValue) -} + s.WriteString(fmt.Sprintf("export interface %s {\n", obj.Name())) + // For each field in the struct, we print 1 line of the typescript interface + for i := 0; i < st.NumFields(); i++ { + field := st.Field(i) + tag := reflect.StructTag(st.Tag(i)) -func getIdent(e ast.Expr) (*ast.Ident, string, error) { - switch t := e.(type) { - case *ast.Ident: - return t, "", nil - case *ast.StarExpr: - i, ok := t.X.(*ast.Ident) - if !ok { - return nil, "", xerrors.New("failed to cast star expr to indent") + // Use the json name if present + jsonName := tag.Get("json") + arr := strings.Split(jsonName, ",") + jsonName = arr[0] + if jsonName == "" { + jsonName = field.Name() } - return i, "?", nil - default: - return nil, "", xerrors.New("unknown expr type") - } -} -func toTsType(fieldType string) string { - fmt.Println(fieldType) - switch fieldType { - case "bool": - return "boolean" - case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "float32", "float64": - return "number" - } + var tsType string + var comment string + // If a `typescript:"string"` exists, we take this, and do not try to infer. + typescriptTag := tag.Get("typescript") + if typescriptTag == "-" { + // Ignore this field + continue + } else if typescriptTag != "" { + tsType = typescriptTag + } else { + var err error + tsType, comment, err = g.typescriptType(obj, field.Type()) + if err != nil { + return "", xerrors.Errorf("typescript type: %w", err) + } + } - return fieldType + if comment != "" { + s.WriteString(fmt.Sprintf("\t// %s\n", comment)) + } + s.WriteString(fmt.Sprintf("\treadonly %s: %s\n", jsonName, tsType)) + } + s.WriteString("}\n") + return s.String(), nil } -func toJSONField(field *ast.Field) string { - if field.Tag != nil && field.Tag.Value != "" { - fieldName := strings.Trim(field.Tag.Value, "`") - for _, pair := range strings.Split(fieldName, " ") { - if strings.Contains(pair, `json:`) { - fieldName := strings.TrimPrefix(pair, `json:`) - fieldName = strings.Trim(fieldName, `"`) - fieldName = strings.Split(fieldName, ",")[0] +// typescriptType this function returns a typescript type for a given +// golang type. +// Eg: +// []byte returns "string" +func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, string, error) { + switch ty.(type) { + case *types.Basic: + bs := ty.(*types.Basic) + // All basic literals (string, bool, int, etc). + // TODO: Actually ensure the golang names are ok, otherwise, + // we want to put another switch to capture these types + // and rename to typescript. + switch { + case bs.Info() == types.IsNumeric: + return "number", "", nil + case bs.Info() == types.IsBoolean: + return "boolean", "", nil + case bs.Kind() == types.Byte: + // TODO: @emyrk What is a byte for typescript? A string? A uint8? + return "byte", "", nil + default: + return bs.Name(), "", nil + } + case *types.Struct: + // TODO: This kinda sucks right now. It just dumps the struct def + return ty.String(), "Unknown struct, this might not work", nil + case *types.Map: + // TODO: Typescript dictionary??? Object? + return "map_not_implemented", "", nil + case *types.Slice, *types.Array: + // Slice/Arrays are pretty much the same. + type hasElem interface { + Elem() types.Type + } - return fieldName + arr := ty.(hasElem) + switch { + // When type checking here, just use the string. You can cast it + // to a types.Basic and get the kind if you want too :shrug: + case arr.Elem().String() == "byte": + // All byte arrays are strings on the typescript. + // Is this ok? + return "string", "", nil + default: + // By default, just do an array of the underlying type. + underlying, comment, err := g.typescriptType(obj, arr.Elem()) + if err != nil { + return "", "", xerrors.Errorf("array: %w", err) } + return underlying + "[]", comment, nil + } + case *types.Named: + n := ty.(*types.Named) + // First see if the type is defined elsewhere. If it is, we can just + // put the name as it will be defined in the typescript codeblock + // we generate. + name := n.Obj().Name() + if obj := g.pkg.Types.Scope().Lookup(n.String()); obj != nil && obj.Name() != name { + // Sweet! Using other typescript types as fields. This could be an + // enum or another struct + return name, "", nil } + + // If it's a struct, just use the name of the struct type + if _, ok := n.Underlying().(*types.Struct); ok { + return name, "Unknown named type, this might not work", nil + } + + // Defer to the underlying type. + return g.typescriptType(obj, ty.Underlying()) + case *types.Pointer: + // Dereference pointers. + // TODO: Nullable fields? We could say these fields can be null in the + // typescript. + pt := ty.(*types.Pointer) + return g.typescriptType(obj, pt.Elem()) } - return "" + // These are all the other types we need to support. + // time.Time, uuid, etc. + return "", "", xerrors.Errorf("unknown type: %s", ty.String()) } diff --git a/scripts/apitypings/main2.go b/scripts/apitypings/main2.go deleted file mode 100644 index df202cacb54d4..0000000000000 --- a/scripts/apitypings/main2.go +++ /dev/null @@ -1,162 +0,0 @@ -package main - -import ( - "context" - "fmt" - "go/types" - "reflect" - "strings" - - "golang.org/x/tools/go/packages" - "golang.org/x/xerrors" - - "cdr.dev/slog" -) - -type Generator struct { - pkg *packages.Package // Package we are scanning. - log slog.Logger -} - -// parsePackage takes a list of patterns such as a directory, and parses them. -// All parsed packages will accumulate "foundTypes". -func (g *Generator) parsePackage(ctx context.Context, patterns ...string) error { - cfg := &packages.Config{ - Mode: packages.NeedTypes | packages.NeedName | packages.NeedTypesInfo | - packages.NeedTypesSizes | packages.NeedSyntax, - Tests: false, - Context: ctx, - } - - pkgs, err := packages.Load(cfg, patterns...) - if err != nil { - return xerrors.Errorf("load package: %w", err) - } - - if len(pkgs) != 1 { - return xerrors.Errorf("expected 1 package, found %d", len(pkgs)) - } - - g.pkg = pkgs[0] - return nil -} - -// generateAll will generate for all types found in the pkg -func (g *Generator) generateAll() error { - for _, n := range g.pkg.Types.Scope().Names() { - err := g.generate(n) - if err != nil { - return xerrors.Errorf("generate %q: %w", n, err) - } - } - return nil -} - -// generate generates the typescript for a singular Go type. -func (g *Generator) generate(typeName string) error { - obj := g.pkg.Types.Scope().Lookup(typeName) - if obj == nil || obj.Type() == nil { - return xerrors.Errorf("pkg is missing type %q", typeName) - } - - st, ok := obj.Type().Underlying().(*types.Struct) - if !ok { - return nil - //return xerrors.Errorf("only generate for structs, found %q", obj.Type().String()) - } - - return g.buildStruct(obj, st) -} - -// buildStruct just prints the typescript def for a type. -// TODO: Write to a buffer instead -func (g *Generator) buildStruct(obj types.Object, st *types.Struct) error { - var s strings.Builder - s.WriteString("export interface " + obj.Name() + "{\n") - for i := 0; i < st.NumFields(); i++ { - field := st.Field(i) - tag := reflect.StructTag(st.Tag(i)) - jsonName := tag.Get("json") - arr := strings.Split(jsonName, ",") - jsonName = arr[0] - if jsonName == "" { - jsonName = field.Name() - } - - ts, err := g.typescriptType(field.Type()) - if err != nil { - return xerrors.Errorf("typescript type: %w", err) - } - s.WriteString(fmt.Sprintf("\treadonly %s: %s\n", jsonName, ts)) - } - s.WriteString("}") - fmt.Println(s.String()) - return nil -} - -// typescriptType this function returns a typescript type for a given -// golang type. -// Eg: -// []byte returns "string" -func (g *Generator) typescriptType(ty types.Type) (string, error) { - switch ty.(type) { - case *types.Basic: - bs := ty.(*types.Basic) - // All basic literals (string, bool, int, etc). - // TODO: Actually ensure the golang names are ok, otherwise, - // we want to put another switch to capture these types - // and rename to typescript. - return bs.Name(), nil - case *types.Struct: - // TODO: This kinda sucks right now. It just dumps the struct def - return ty.String(), nil - case *types.Map: - // TODO: Typescript dictionary??? Object? - return "map", nil - case *types.Slice, *types.Array: - type hasElem interface { - Elem() types.Type - } - - arr := ty.(hasElem) - // All byte arrays should be strings in typescript? - if arr.Elem().String() == "byte" { - return "string", nil - } - - // Array of underlying type. - underlying, err := g.typescriptType(arr.Elem()) - if err != nil { - return "", xerrors.Errorf("array: %w", err) - } - return underlying + "[]", nil - case *types.Named: - // Named is a named type like - // type EnumExample string - // Use the underlying type - n := ty.(*types.Named) - name := n.Obj().Name() - // If we have the type, just put the name because it will be defined - // elsewhere in the typescript gen. - if obj := g.pkg.Types.Scope().Lookup(n.String()); obj != nil { - return name, nil - } - - // If it's a struct, just use the name for now. - if _, ok := ty.Underlying().(*types.Struct); ok { - return name, nil - } - - // Defer to the underlying type. - return g.typescriptType(ty.Underlying()) - case *types.Pointer: - // Dereference pointers. - // TODO: Nullable fields? - pt := ty.(*types.Pointer) - return g.typescriptType(pt.Elem()) - } - - // These are all the other types we need to support. - // time.Time, uuid, etc. - return "", xerrors.Errorf("unknown type: %s", ty.String()) -} From 28c2811acaa86d47e239ac79ee147a0d5ebde83b Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 27 Apr 2022 22:13:37 -0500 Subject: [PATCH 03/17] Handle reused types --- scripts/apitypings/main.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 0b928acb418bc..66b11b4ab3a95 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -21,6 +21,7 @@ const ( baseDir = "./codersdk" ) +// TODO: Handle httpapi.Response and other types func main() { ctx := context.Background() log := slog.Make(sloghuman.Sink(os.Stderr)) @@ -49,7 +50,6 @@ func (t TypescriptTypes) String() string { for _, v := range t.Enums { s.WriteString(v) - s.WriteRune('\n') } return s.String() } @@ -168,7 +168,6 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { s.WriteString(fmt.Sprintf("export type %s = %s\n", name, strings.Join(values, " | "), )) - s.WriteRune('\n') enumCodeBlocks[name] = s.String() } @@ -290,12 +289,21 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, str // put the name as it will be defined in the typescript codeblock // we generate. name := n.Obj().Name() - if obj := g.pkg.Types.Scope().Lookup(n.String()); obj != nil && obj.Name() != name { + if obj := g.pkg.Types.Scope().Lookup(name); obj != nil { // Sweet! Using other typescript types as fields. This could be an // enum or another struct return name, "", nil } + switch n.String() { + case "net/url.URL": + return "string", "", nil + case "time.Time": + return "string", "is this ok for time?", nil + case "github.com/coder/coder/coderd/httpapi.Response": + + } + // If it's a struct, just use the name of the struct type if _, ok := n.Underlying().(*types.Struct); ok { return name, "Unknown named type, this might not work", nil From 710b4271fe8163715c0cdd98d57ff5775caec2dc Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 27 Apr 2022 22:14:09 -0500 Subject: [PATCH 04/17] Add comment --- scripts/apitypings/main.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 66b11b4ab3a95..f4674982209ce 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -295,13 +295,12 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, str return name, "", nil } + // These are special types that we handle uniquely. switch n.String() { case "net/url.URL": return "string", "", nil case "time.Time": return "string", "is this ok for time?", nil - case "github.com/coder/coder/coderd/httpapi.Response": - } // If it's a struct, just use the name of the struct type From 071026deca83f558f9c5be3c70f90cda0105aa82 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Wed, 27 Apr 2022 22:25:17 -0500 Subject: [PATCH 05/17] Allow ignoring types for autogen --- codersdk/client.go | 1 + scripts/apitypings/main.go | 40 +++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/codersdk/client.go b/codersdk/client.go index 0c6f1986d664c..f9b17d5486d65 100644 --- a/codersdk/client.go +++ b/codersdk/client.go @@ -26,6 +26,7 @@ func New(serverURL *url.URL) *Client { } // Client is an HTTP caller for methods to the Coder API. +// @typescript-ignore Client type Client struct { HTTPClient *http.Client SessionToken string diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index f4674982209ce..06e9b570d3fcb 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "reflect" + "regexp" "strings" "cdr.dev/slog/sloggers/sloghuman" @@ -43,13 +44,26 @@ type TypescriptTypes struct { // String just combines all the codeblocks. I store them in a map for unit testing purposes func (t TypescriptTypes) String() string { var s strings.Builder - for _, v := range t.Types { + sortedTypes := make([]string, 0, len(t.Types)) + sortedEnums := make([]string, 0, len(t.Types)) + + for k := range t.Types { + sortedTypes = append(sortedTypes, k) + } + for k := range t.Enums { + sortedEnums = append(sortedEnums, k) + } + + for _, k := range sortedTypes { + v := t.Types[k] s.WriteString(v) s.WriteRune('\n') } - for _, v := range t.Enums { + for _, k := range sortedEnums { + v := t.Enums[k] s.WriteString(v) + s.WriteRune('\n') } return s.String() } @@ -104,15 +118,27 @@ func (g *Generator) parsePackage(ctx context.Context, patterns ...string) error return nil } -type Generated struct { -} - // generateAll will generate for all types found in the pkg func (g *Generator) generateAll() (*TypescriptTypes, error) { structs := make(map[string]string) enums := make(map[string]types.Object) constants := make(map[string][]*types.Const) + ignoredTypes := make(map[string]struct{}) + ignoreRegex := regexp.MustCompile("@typescript-ignore:(?P)") + for _, file := range g.pkg.Syntax { + for _, comment := range file.Comments { + matches := ignoreRegex.FindStringSubmatch(comment.Text()) + ignored := ignoreRegex.SubexpIndex("ignored_types") + if len(matches) >= ignored && matches[ignored] != "" { + arr := strings.Split(matches[ignored], ",") + for _, s := range arr { + ignoredTypes[strings.TrimSpace(s)] = struct{}{} + } + } + } + } + for _, n := range g.pkg.Types.Scope().Names() { obj := g.pkg.Types.Scope().Lookup(n) if obj == nil || obj.Type() == nil { @@ -120,6 +146,10 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { continue } + if _, ok := ignoredTypes[obj.Name()]; ok { + continue + } + switch obj.(type) { // All named types are type declarations case *types.TypeName: From 2741efadd413ba0dee7d0ea59b3323ccd62ec06e Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:10:56 -0500 Subject: [PATCH 06/17] Fix ignore, add optional fields --- scripts/apitypings/main.go | 104 +++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 06e9b570d3fcb..c4460b34e369c 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -35,13 +35,14 @@ func main() { fmt.Println(codeBlocks.String()) } +// TypescriptTypes holds all the code blocks created. type TypescriptTypes struct { // Each entry is the type name, and it's typescript code block. Types map[string]string Enums map[string]string } -// String just combines all the codeblocks. I store them in a map for unit testing purposes +// String just combines all the codeblocks. func (t TypescriptTypes) String() string { var s strings.Builder sortedTypes := make([]string, 0, len(t.Types)) @@ -122,19 +123,25 @@ func (g *Generator) parsePackage(ctx context.Context, patterns ...string) error func (g *Generator) generateAll() (*TypescriptTypes, error) { structs := make(map[string]string) enums := make(map[string]types.Object) - constants := make(map[string][]*types.Const) + enumConsts := make(map[string][]*types.Const) + //constants := make(map[string]string) + // Look for comments that indicate to ignore a type for typescript generation. ignoredTypes := make(map[string]struct{}) - ignoreRegex := regexp.MustCompile("@typescript-ignore:(?P)") + ignoreRegex := regexp.MustCompile("@typescript-ignore[:]?(?P.*)") for _, file := range g.pkg.Syntax { for _, comment := range file.Comments { - matches := ignoreRegex.FindStringSubmatch(comment.Text()) - ignored := ignoreRegex.SubexpIndex("ignored_types") - if len(matches) >= ignored && matches[ignored] != "" { - arr := strings.Split(matches[ignored], ",") - for _, s := range arr { - ignoredTypes[strings.TrimSpace(s)] = struct{}{} + for _, line := range comment.List { + text := line.Text + matches := ignoreRegex.FindStringSubmatch(text) + ignored := ignoreRegex.SubexpIndex("ignored_types") + if len(matches) >= ignored && matches[ignored] != "" { + arr := strings.Split(matches[ignored], ",") + for _, s := range arr { + ignoredTypes[strings.TrimSpace(s)] = struct{}{} + } } + } } } @@ -146,6 +153,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { continue } + // Exclude ignored types if _, ok := ignoredTypes[obj.Name()]; ok { continue } @@ -171,7 +179,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { enums[obj.Name()] = obj } case *types.Var: - // TODO: Are any enums var declarations? + // TODO: Are any enums var declarations? This is also codersdk.Me. v := obj.(*types.Var) var _ = v case *types.Const: @@ -179,8 +187,12 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { // We only care about named constant types, since they are enums if named, ok := c.Type().(*types.Named); ok { name := named.Obj().Name() - constants[name] = append(constants[name], c) + enumConsts[name] = append(enumConsts[name], c) } + case *types.Func: + // Noop + default: + fmt.Println(obj.Name()) } } @@ -188,7 +200,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { enumCodeBlocks := make(map[string]string) for name, v := range enums { var values []string - for _, elem := range constants[name] { + for _, elem := range enumConsts[name] { // TODO: If we have non string constants, we need to handle that // here. values = append(values, elem.Val().String()) @@ -236,37 +248,47 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err jsonName = field.Name() } - var tsType string - var comment string + var tsType TypescriptType // If a `typescript:"string"` exists, we take this, and do not try to infer. typescriptTag := tag.Get("typescript") if typescriptTag == "-" { // Ignore this field continue } else if typescriptTag != "" { - tsType = typescriptTag + tsType.ValueType = typescriptTag } else { var err error - tsType, comment, err = g.typescriptType(obj, field.Type()) + tsType, err = g.typescriptType(obj, field.Type()) if err != nil { return "", xerrors.Errorf("typescript type: %w", err) } } - if comment != "" { - s.WriteString(fmt.Sprintf("\t// %s\n", comment)) + if tsType.Comment != "" { + s.WriteString(fmt.Sprintf("\t// %s\n", tsType.Comment)) + } + optional := "" + if tsType.Optional { + optional = "?" } - s.WriteString(fmt.Sprintf("\treadonly %s: %s\n", jsonName, tsType)) + s.WriteString(fmt.Sprintf("\treadonly %s%s: %s\n", jsonName, optional, tsType.ValueType)) } s.WriteString("}\n") return s.String(), nil } +type TypescriptType struct { + ValueType string + Comment string + // Optional indicates the value is an optional field in typescript. + Optional bool +} + // typescriptType this function returns a typescript type for a given // golang type. // Eg: // []byte returns "string" -func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, string, error) { +func (g *Generator) typescriptType(obj types.Object, ty types.Type) (TypescriptType, error) { switch ty.(type) { case *types.Basic: bs := ty.(*types.Basic) @@ -275,22 +297,22 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, str // we want to put another switch to capture these types // and rename to typescript. switch { - case bs.Info() == types.IsNumeric: - return "number", "", nil - case bs.Info() == types.IsBoolean: - return "boolean", "", nil + case bs.Info()&types.IsNumeric > 0: + return TypescriptType{ValueType: "number"}, nil + case bs.Info()&types.IsBoolean > 0: + return TypescriptType{ValueType: "boolean"}, nil case bs.Kind() == types.Byte: // TODO: @emyrk What is a byte for typescript? A string? A uint8? - return "byte", "", nil + return TypescriptType{ValueType: "number", Comment: "This is a byte in golang"}, nil default: - return bs.Name(), "", nil + return TypescriptType{ValueType: bs.Name()}, nil } case *types.Struct: // TODO: This kinda sucks right now. It just dumps the struct def - return ty.String(), "Unknown struct, this might not work", nil + return TypescriptType{ValueType: ty.String(), Comment: "Unknown struct, this might not work"}, nil case *types.Map: // TODO: Typescript dictionary??? Object? - return "map_not_implemented", "", nil + return TypescriptType{ValueType: "map_not_implemented"}, nil case *types.Slice, *types.Array: // Slice/Arrays are pretty much the same. type hasElem interface { @@ -304,14 +326,14 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, str case arr.Elem().String() == "byte": // All byte arrays are strings on the typescript. // Is this ok? - return "string", "", nil + return TypescriptType{ValueType: "string"}, nil default: // By default, just do an array of the underlying type. - underlying, comment, err := g.typescriptType(obj, arr.Elem()) + underlying, err := g.typescriptType(obj, arr.Elem()) if err != nil { - return "", "", xerrors.Errorf("array: %w", err) + return TypescriptType{}, xerrors.Errorf("array: %w", err) } - return underlying + "[]", comment, nil + return TypescriptType{ValueType: underlying.ValueType + "[]", Comment: underlying.Comment}, nil } case *types.Named: n := ty.(*types.Named) @@ -322,20 +344,21 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, str if obj := g.pkg.Types.Scope().Lookup(name); obj != nil { // Sweet! Using other typescript types as fields. This could be an // enum or another struct - return name, "", nil + return TypescriptType{ValueType: name}, nil } // These are special types that we handle uniquely. switch n.String() { case "net/url.URL": - return "string", "", nil + return TypescriptType{ValueType: "string"}, nil case "time.Time": - return "string", "is this ok for time?", nil + // We really should come up with a standard for time. + return TypescriptType{ValueType: "string"}, nil } // If it's a struct, just use the name of the struct type if _, ok := n.Underlying().(*types.Struct); ok { - return name, "Unknown named type, this might not work", nil + return TypescriptType{ValueType: name, Comment: "Unknown named type, this might not work"}, nil } // Defer to the underlying type. @@ -345,10 +368,15 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (string, str // TODO: Nullable fields? We could say these fields can be null in the // typescript. pt := ty.(*types.Pointer) - return g.typescriptType(obj, pt.Elem()) + resp, err := g.typescriptType(obj, pt.Elem()) + if err != nil { + return TypescriptType{}, xerrors.Errorf("pointer: %w", err) + } + resp.Optional = true + return resp, nil } // These are all the other types we need to support. // time.Time, uuid, etc. - return "", "", xerrors.Errorf("unknown type: %s", ty.String()) + return TypescriptType{}, xerrors.Errorf("unknown type: %s", ty.String()) } From c62feebc09772b363879b4a55664a75fcefe5d30 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:17:43 -0500 Subject: [PATCH 07/17] Add map support --- scripts/apitypings/main.go | 25 +- site/src/api/typesGenerated.ts | 456 +++++++++++++++++++++------------ 2 files changed, 314 insertions(+), 167 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index c4460b34e369c..33366ec429761 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -258,7 +258,7 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err tsType.ValueType = typescriptTag } else { var err error - tsType, err = g.typescriptType(obj, field.Type()) + tsType, err = g.typescriptType(field.Type()) if err != nil { return "", xerrors.Errorf("typescript type: %w", err) } @@ -288,7 +288,7 @@ type TypescriptType struct { // golang type. // Eg: // []byte returns "string" -func (g *Generator) typescriptType(obj types.Object, ty types.Type) (TypescriptType, error) { +func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { switch ty.(type) { case *types.Basic: bs := ty.(*types.Basic) @@ -312,7 +312,20 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (TypescriptT return TypescriptType{ValueType: ty.String(), Comment: "Unknown struct, this might not work"}, nil case *types.Map: // TODO: Typescript dictionary??? Object? - return TypescriptType{ValueType: "map_not_implemented"}, nil + // map[string][string] -> Record + m := ty.(*types.Map) + keyType, err := g.typescriptType(m.Key()) + if err != nil { + return TypescriptType{}, xerrors.Errorf("map key: %w", err) + } + valueType, err := g.typescriptType(m.Elem()) + if err != nil { + return TypescriptType{}, xerrors.Errorf("map key: %w", err) + } + + return TypescriptType{ + ValueType: fmt.Sprintf("Record<%s, %s>", keyType.ValueType, valueType.ValueType), + }, nil case *types.Slice, *types.Array: // Slice/Arrays are pretty much the same. type hasElem interface { @@ -329,7 +342,7 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (TypescriptT return TypescriptType{ValueType: "string"}, nil default: // By default, just do an array of the underlying type. - underlying, err := g.typescriptType(obj, arr.Elem()) + underlying, err := g.typescriptType(arr.Elem()) if err != nil { return TypescriptType{}, xerrors.Errorf("array: %w", err) } @@ -362,13 +375,13 @@ func (g *Generator) typescriptType(obj types.Object, ty types.Type) (TypescriptT } // Defer to the underlying type. - return g.typescriptType(obj, ty.Underlying()) + return g.typescriptType(ty.Underlying()) case *types.Pointer: // Dereference pointers. // TODO: Nullable fields? We could say these fields can be null in the // typescript. pt := ty.(*types.Pointer) - resp, err := g.typescriptType(obj, pt.Elem()) + resp, err := g.typescriptType(pt.Elem()) if err != nil { return TypescriptType{}, xerrors.Errorf("pointer: %w", err) } diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 230e600eeeb18..a34c4966de561 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1,238 +1,372 @@ -// From codersdk/buildinfo.go:10:6. -export interface BuildInfoResponse { - readonly external_url: string - readonly version: string +// From codersdk/parameters.go:38:6 +export interface CreateParameterRequest { + readonly name: string + readonly source_value: string + readonly source_scheme: string + readonly destination_scheme: string } -// From codersdk/files.go:16:6. -export interface UploadResponse { - readonly hash: string +// From codersdk/users.go:76:6 +export interface GenerateAPIKeyResponse { + readonly key: string } -// From codersdk/gitsshkey.go:14:6. -export interface GitSSHKey { - readonly public_key: string +// From codersdk/workspaceagents.go:31:6 +export interface GoogleInstanceIdentityToken { + readonly json_web_token: string } -// From codersdk/gitsshkey.go:21:6. +// From codersdk/provisionerdaemons.go:56:6 +export interface ProvisionerJobLog { + readonly id: string + readonly created_at: string + readonly log_source: string + readonly log_level: string + readonly stage: string + readonly output: string +} + +// From codersdk/templateversions.go:27:6 +export interface TemplateVersionParameterSchema { + readonly id: string + readonly created_at: string + readonly job_id: string + readonly name: string + readonly description: string + readonly default_source_scheme: string + readonly default_source_value: string + readonly allow_override_source: boolean + readonly default_destination_scheme: string + readonly allow_override_destination: boolean + readonly default_refresh: string + readonly redisplay_value: boolean + readonly validation_error: string + readonly validation_condition: string + readonly validation_type_system: string + readonly validation_value_type: string +} + +// From codersdk/gitsshkey.go:21:6 export interface AgentGitSSHKey { - readonly public_key: string - readonly private_key: string + readonly public_key: string + readonly private_key: string } -// From codersdk/organizations.go:17:6. -export interface Organization { - readonly name: string +// From codersdk/users.go:94:6 +export interface AuthMethods { + readonly password: boolean + readonly github: boolean } -// From codersdk/organizations.go:25:6. -export interface CreateTemplateVersionRequest { - readonly storage_source: string +// From codersdk/users.go:39:6 +export interface CreateFirstUserRequest { + readonly email: string + readonly username: string + readonly password: string + readonly organization: string } -// From codersdk/organizations.go:38:6. -export interface CreateTemplateRequest { - readonly name: string +// From codersdk/workspaces.go:94:6 +export interface UpdateWorkspaceAutostartRequest { + readonly schedule: string } -// From codersdk/parameters.go:26:6. -export interface Parameter { - readonly scope: ParameterScope - readonly name: string +// From codersdk/users.go:32:6 +export interface User { + readonly id: string + readonly email: string + readonly created_at: string + readonly username: string } -// From codersdk/parameters.go:38:6. -export interface CreateParameterRequest { - readonly name: string - readonly source_value: string +// From codersdk/provisionerdaemons.go:46:6 +export interface ProvisionerJob { + readonly id: string + readonly created_at: string + readonly started_at?: string + readonly completed_at?: string + readonly error: string + readonly status: ProvisionerJobStatus + readonly worker_id?: string } -// From codersdk/provisionerdaemons.go:46:6. -export interface ProvisionerJob { - readonly error: string - readonly status: ProvisionerJobStatus +// From codersdk/workspaces.go:18:6 +export interface Workspace { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly owner_id: string + readonly template_id: string + readonly template_name: string + readonly latest_build: WorkspaceBuild + readonly outdated: boolean + readonly name: string + readonly autostart_schedule: string + readonly autostop_schedule: string +} + +// From codersdk/workspaceresources.go:33:6 +export interface WorkspaceAgent { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly first_connected_at?: string + readonly last_connected_at?: string + readonly disconnected_at?: string + readonly status: WorkspaceAgentStatus + readonly name: string + readonly resource_id: string + readonly instance_id: string + readonly architecture: string + readonly environment_variables: Record + readonly operating_system: string + readonly startup_script: string +} + +// From codersdk/workspaceagents.go:47:6 +export interface WorkspaceAgentAuthenticateResponse { + readonly session_token: string } -// From codersdk/provisionerdaemons.go:56:6. -export interface ProvisionerJobLog { - readonly stage: string - readonly output: string +// From codersdk/users.go:47:6 +export interface CreateFirstUserResponse { + readonly user_id: string + readonly organization_id: string } -// From codersdk/templates.go:17:6. -export interface Template { - readonly name: string - readonly workspace_owner_count: number +// From codersdk/gitsshkey.go:14:6 +export interface GitSSHKey { + readonly user_id: string + readonly created_at: string + readonly updated_at: string + readonly public_key: string } -// From codersdk/templateversions.go:17:6. -export interface TemplateVersion { - readonly name: string - readonly job: ProvisionerJob +// From codersdk/users.go:71:6 +export interface LoginWithPasswordResponse { + readonly session_token: string } -// From codersdk/users.go:17:6. -export interface UsersRequest { - readonly search: string - readonly limit: number - readonly offset: number +// From codersdk/users.go:59:6 +export interface UpdateUserProfileRequest { + readonly email: string + readonly username: string } -// From codersdk/users.go:32:6. -export interface User { - readonly email: string - readonly username: string +// From codersdk/workspaceresources.go:50:6 +export interface WorkspaceAgentResourceMetadata { + readonly memory_total: number + readonly disk_total: number + readonly cpu_cores: number + readonly cpu_model: string + readonly cpu_mhz: number } -// From codersdk/users.go:39:6. -export interface CreateFirstUserRequest { - readonly email: string - readonly username: string - readonly password: string - readonly organization: string +// From codersdk/workspacebuilds.go:17:6 +export interface WorkspaceBuild { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly workspace_id: string + readonly template_version_id: string + readonly before_id: string + readonly after_id: string + readonly name: string + readonly transition: string + readonly initiator_id: string + readonly job: ProvisionerJob +} + +// From codersdk/workspaceresources.go:23:6 +export interface WorkspaceResource { + readonly id: string + readonly created_at: string + readonly job_id: string + readonly workspace_transition: string + readonly type: string + readonly name: string + readonly agents: WorkspaceAgent[] } -// From codersdk/users.go:52:6. -export interface CreateUserRequest { - readonly email: string - readonly username: string - readonly password: string +// From codersdk/parameters.go:26:6 +export interface Parameter { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly scope: ParameterScope + readonly scope_id: string + readonly name: string + readonly source_scheme: string + readonly destination_scheme: string } -// From codersdk/users.go:59:6. -export interface UpdateUserProfileRequest { - readonly email: string - readonly username: string +// From codersdk/templates.go:17:6 +export interface Template { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly organization_id: string + readonly name: string + readonly provisioner: string + readonly active_version_id: string + readonly workspace_owner_count: number } -// From codersdk/users.go:65:6. -export interface LoginWithPasswordRequest { - readonly email: string - readonly password: string +// From codersdk/templateversions.go:17:6 +export interface TemplateVersion { + readonly id: string + readonly template_id?: string + readonly created_at: string + readonly updated_at: string + readonly name: string + readonly job: ProvisionerJob } -// From codersdk/users.go:71:6. -export interface LoginWithPasswordResponse { - readonly session_token: string +// From codersdk/workspaceagents.go:40:6 +export interface AzureInstanceIdentityToken { + readonly signature: string + readonly encoding: string } -// From codersdk/users.go:76:6. -export interface GenerateAPIKeyResponse { - readonly key: string +// From codersdk/buildinfo.go:10:6 +export interface BuildInfoResponse { + readonly external_url: string + readonly version: string } -// From codersdk/users.go:80:6. -export interface CreateOrganizationRequest { - readonly name: string +// From codersdk/organizations.go:17:6 +export interface Organization { + readonly id: string + readonly name: string + readonly created_at: string + readonly updated_at: string } -// From codersdk/users.go:85:6. -export interface CreateWorkspaceRequest { - readonly name: string +// From codersdk/client.go:117:6 +export interface Error { + // Unknown named type, this might not work + readonly Response: Response + readonly statusCode: number } -// From codersdk/users.go:94:6. -export interface AuthMethods { - readonly password: boolean - readonly github: boolean +// From codersdk/templateversions.go:30:6 +export interface TemplateVersionParameter { + // Unknown named type, this might not work + readonly ParameterValue: ParameterValue + readonly schema_id: string + readonly default_source_value: boolean } -// From codersdk/workspaceagents.go:31:6. -export interface GoogleInstanceIdentityToken { - readonly json_web_token: string +// From codersdk/files.go:16:6 +export interface UploadResponse { + readonly hash: string } -// From codersdk/workspaceagents.go:35:6. -export interface AWSInstanceIdentityToken { - readonly signature: string - readonly document: string +// From codersdk/users.go:80:6 +export interface CreateOrganizationRequest { + readonly name: string } -// From codersdk/workspaceagents.go:40:6. -export interface AzureInstanceIdentityToken { - readonly signature: string - readonly encoding: string +// From codersdk/organizations.go:38:6 +export interface CreateTemplateRequest { + readonly name: string + readonly template_version_id: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaceagents.go:47:6. -export interface WorkspaceAgentAuthenticateResponse { - readonly session_token: string +// From codersdk/users.go:52:6 +export interface CreateUserRequest { + readonly email: string + readonly username: string + readonly password: string + readonly organization_id: string } -// From codersdk/workspacebuilds.go:17:6. -export interface WorkspaceBuild { - readonly name: string - readonly job: ProvisionerJob +// From codersdk/users.go:65:6 +export interface LoginWithPasswordRequest { + readonly email: string + readonly password: string } -// From codersdk/workspaceresources.go:23:6. -export interface WorkspaceResource { - readonly type: string - readonly name: string +// From codersdk/users.go:17:6 +export interface UsersRequest { + readonly after_user: string + readonly search: string + readonly limit: number + readonly offset: number } -// From codersdk/workspaceresources.go:33:6. -export interface WorkspaceAgent { - readonly status: WorkspaceAgentStatus - readonly name: string - readonly instance_id: string - readonly architecture: string - readonly operating_system: string - readonly startup_script: string +// From codersdk/organizations.go:25:6 +export interface CreateTemplateVersionRequest { + readonly template_id: string + readonly storage_method: string + readonly storage_source: string + readonly provisioner: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaceresources.go:50:6. -export interface WorkspaceAgentResourceMetadata { - readonly memory_total: number - readonly disk_total: number - readonly cpu_cores: number - readonly cpu_model: string - readonly cpu_mhz: number +// From codersdk/workspaces.go:33:6 +export interface CreateWorkspaceBuildRequest { + readonly template_version_id: string + readonly transition: string + readonly dry_run: boolean } -// From codersdk/workspaceresources.go:58:6. -export interface WorkspaceAgentInstanceMetadata { - readonly jail_orchestrator: string - readonly operating_system: string - readonly platform: string - readonly platform_family: string - readonly kernel_version: string - readonly kernel_architecture: string - readonly cloud: string - readonly jail: string - readonly vnc: boolean -} - -// From codersdk/workspaces.go:18:6. -export interface Workspace { - readonly template_name: string - readonly latest_build: WorkspaceBuild - readonly outdated: boolean - readonly name: string - readonly autostart_schedule: string - readonly autostop_schedule: string +// From codersdk/users.go:85:6 +export interface CreateWorkspaceRequest { + readonly template_id: string + readonly name: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaces.go:33:6. -export interface CreateWorkspaceBuildRequest { - readonly dry_run: boolean +// From codersdk/workspaceagents.go:35:6 +export interface AWSInstanceIdentityToken { + readonly signature: string + readonly document: string } -// From codersdk/workspaces.go:94:6. -export interface UpdateWorkspaceAutostartRequest { - readonly schedule: string +// From codersdk/templates.go:28:6 +export interface UpdateActiveTemplateVersion { + readonly id: string } -// From codersdk/workspaces.go:114:6. +// From codersdk/workspaces.go:114:6 export interface UpdateWorkspaceAutostopRequest { - readonly schedule: string + readonly schedule: string } -// From codersdk/parameters.go:16:6. +// From codersdk/provisionerdaemons.go:23:6 +export interface ProvisionerDaemon { + readonly id: string + readonly created_at: string + // Unknown named type, this might not work + readonly updated_at: NullTime + // Unknown named type, this might not work + readonly organization_id: NullUUID + readonly name: string + readonly provisioners: string[] +} + +// From codersdk/workspaceresources.go:58:6 +export interface WorkspaceAgentInstanceMetadata { + readonly jail_orchestrator: string + readonly operating_system: string + readonly platform: string + readonly platform_family: string + readonly kernel_version: string + readonly kernel_architecture: string + readonly cloud: string + readonly jail: string + readonly vnc: boolean +} + +// From codersdk/workspaceresources.go:15:6 +export type WorkspaceAgentStatus = "connected" | "connecting" | "disconnected" + +// From codersdk/parameters.go:16:6 export type ParameterScope = "organization" | "template" | "user" | "workspace" -// From codersdk/provisionerdaemons.go:26:6. -export type ProvisionerJobStatus = "pending" | "running" | "succeeded" | "canceling" | "canceled" | "failed" +// From codersdk/provisionerdaemons.go:26:6 +export type ProvisionerJobStatus = "canceled" | "canceling" | "failed" | "pending" | "running" | "succeeded" + -// From codersdk/workspaceresources.go:15:6. -export type WorkspaceAgentStatus = "connecting" | "connected" | "disconnected" From 462ebeb3c9bb930d5e31dc2cd0f9d1f1dc4fd8d6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:25:09 -0500 Subject: [PATCH 08/17] Handle unknown types better --- codersdk/client.go | 1 + scripts/apitypings/main.go | 6 +- site/src/api/typesGenerated.ts | 479 ++++++++++++++++----------------- 3 files changed, 241 insertions(+), 245 deletions(-) diff --git a/codersdk/client.go b/codersdk/client.go index f9b17d5486d65..d13927513ae38 100644 --- a/codersdk/client.go +++ b/codersdk/client.go @@ -114,6 +114,7 @@ func readBodyAsError(res *http.Response) error { } // Error represents an unaccepted or invalid request to the API. +// @typescript-ignore Error type Error struct { httpapi.Response diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 33366ec429761..680a18a0e4fff 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -367,11 +367,15 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { case "time.Time": // We really should come up with a standard for time. return TypescriptType{ValueType: "string"}, nil + case "database/sql.NullTime": + return TypescriptType{ValueType: "string", Optional: true}, nil + case "github.com/google/uuid.NullUUID": + return TypescriptType{ValueType: "string", Optional: true}, nil } // If it's a struct, just use the name of the struct type if _, ok := n.Underlying().(*types.Struct); ok { - return TypescriptType{ValueType: name, Comment: "Unknown named type, this might not work"}, nil + return TypescriptType{ValueType: "any", Comment: fmt.Sprintf("Named type %q unknown, using \"any\"", n.String())}, nil } // Defer to the underlying type. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index a34c4966de561..b41dad41f0342 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1,137 +1,109 @@ -// From codersdk/parameters.go:38:6 -export interface CreateParameterRequest { +// From codersdk/users.go:85:6 +export interface CreateWorkspaceRequest { + readonly template_id: string readonly name: string - readonly source_value: string - readonly source_scheme: string - readonly destination_scheme: string -} - -// From codersdk/users.go:76:6 -export interface GenerateAPIKeyResponse { - readonly key: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaceagents.go:31:6 -export interface GoogleInstanceIdentityToken { - readonly json_web_token: string +// From codersdk/users.go:59:6 +export interface UpdateUserProfileRequest { + readonly email: string + readonly username: string } -// From codersdk/provisionerdaemons.go:56:6 -export interface ProvisionerJobLog { - readonly id: string - readonly created_at: string - readonly log_source: string - readonly log_level: string - readonly stage: string - readonly output: string +// From codersdk/users.go:17:6 +export interface UsersRequest { + readonly after_user: string + readonly search: string + readonly limit: number + readonly offset: number } -// From codersdk/templateversions.go:27:6 -export interface TemplateVersionParameterSchema { - readonly id: string - readonly created_at: string - readonly job_id: string - readonly name: string - readonly description: string - readonly default_source_scheme: string - readonly default_source_value: string - readonly allow_override_source: boolean - readonly default_destination_scheme: string - readonly allow_override_destination: boolean - readonly default_refresh: string - readonly redisplay_value: boolean - readonly validation_error: string - readonly validation_condition: string - readonly validation_type_system: string - readonly validation_value_type: string +// From codersdk/workspaceagents.go:47:6 +export interface WorkspaceAgentAuthenticateResponse { + readonly session_token: string } -// From codersdk/gitsshkey.go:21:6 -export interface AgentGitSSHKey { - readonly public_key: string - readonly private_key: string +// From codersdk/workspaceresources.go:58:6 +export interface WorkspaceAgentInstanceMetadata { + readonly jail_orchestrator: string + readonly operating_system: string + readonly platform: string + readonly platform_family: string + readonly kernel_version: string + readonly kernel_architecture: string + readonly cloud: string + readonly jail: string + readonly vnc: boolean } -// From codersdk/users.go:94:6 -export interface AuthMethods { - readonly password: boolean - readonly github: boolean +// From codersdk/workspaceagents.go:40:6 +export interface AzureInstanceIdentityToken { + readonly signature: string + readonly encoding: string } -// From codersdk/users.go:39:6 -export interface CreateFirstUserRequest { - readonly email: string - readonly username: string - readonly password: string - readonly organization: string +// From codersdk/workspaces.go:33:6 +export interface CreateWorkspaceBuildRequest { + readonly template_version_id: string + readonly transition: string + readonly dry_run: boolean } -// From codersdk/workspaces.go:94:6 -export interface UpdateWorkspaceAutostartRequest { - readonly schedule: string +// From codersdk/users.go:47:6 +export interface CreateFirstUserResponse { + readonly user_id: string + readonly organization_id: string } -// From codersdk/users.go:32:6 -export interface User { +// From codersdk/parameters.go:26:6 +export interface Parameter { readonly id: string - readonly email: string readonly created_at: string - readonly username: string + readonly updated_at: string + readonly scope: ParameterScope + readonly scope_id: string + readonly name: string + readonly source_scheme: string + readonly destination_scheme: string } -// From codersdk/provisionerdaemons.go:46:6 -export interface ProvisionerJob { +// From codersdk/templateversions.go:17:6 +export interface TemplateVersion { readonly id: string + readonly template_id?: string readonly created_at: string - readonly started_at?: string - readonly completed_at?: string - readonly error: string - readonly status: ProvisionerJobStatus - readonly worker_id?: string + readonly updated_at: string + readonly name: string + readonly job: ProvisionerJob } -// From codersdk/workspaces.go:18:6 -export interface Workspace { +// From codersdk/templates.go:28:6 +export interface UpdateActiveTemplateVersion { readonly id: string - readonly created_at: string - readonly updated_at: string - readonly owner_id: string - readonly template_id: string - readonly template_name: string - readonly latest_build: WorkspaceBuild - readonly outdated: boolean - readonly name: string - readonly autostart_schedule: string - readonly autostop_schedule: string } -// From codersdk/workspaceresources.go:33:6 -export interface WorkspaceAgent { +// From codersdk/workspaceresources.go:23:6 +export interface WorkspaceResource { readonly id: string readonly created_at: string - readonly updated_at: string - readonly first_connected_at?: string - readonly last_connected_at?: string - readonly disconnected_at?: string - readonly status: WorkspaceAgentStatus + readonly job_id: string + readonly workspace_transition: string + readonly type: string readonly name: string - readonly resource_id: string - readonly instance_id: string - readonly architecture: string - readonly environment_variables: Record - readonly operating_system: string - readonly startup_script: string + readonly agents: WorkspaceAgent[] } -// From codersdk/workspaceagents.go:47:6 -export interface WorkspaceAgentAuthenticateResponse { - readonly session_token: string +// From codersdk/gitsshkey.go:21:6 +export interface AgentGitSSHKey { + readonly public_key: string + readonly private_key: string } -// From codersdk/users.go:47:6 -export interface CreateFirstUserResponse { - readonly user_id: string - readonly organization_id: string +// From codersdk/buildinfo.go:10:6 +export interface BuildInfoResponse { + readonly external_url: string + readonly version: string } // From codersdk/gitsshkey.go:14:6 @@ -142,158 +114,155 @@ export interface GitSSHKey { readonly public_key: string } -// From codersdk/users.go:71:6 -export interface LoginWithPasswordResponse { - readonly session_token: string -} - -// From codersdk/users.go:59:6 -export interface UpdateUserProfileRequest { - readonly email: string - readonly username: string -} - -// From codersdk/workspaceresources.go:50:6 -export interface WorkspaceAgentResourceMetadata { - readonly memory_total: number - readonly disk_total: number - readonly cpu_cores: number - readonly cpu_model: string - readonly cpu_mhz: number -} - -// From codersdk/workspacebuilds.go:17:6 -export interface WorkspaceBuild { +// From codersdk/provisionerdaemons.go:23:6 +export interface ProvisionerDaemon { readonly id: string readonly created_at: string - readonly updated_at: string - readonly workspace_id: string - readonly template_version_id: string - readonly before_id: string - readonly after_id: string + readonly updated_at?: string + readonly organization_id?: string readonly name: string - readonly transition: string - readonly initiator_id: string - readonly job: ProvisionerJob + readonly provisioners: string[] } -// From codersdk/workspaceresources.go:23:6 -export interface WorkspaceResource { +// From codersdk/templateversions.go:27:6 +export interface TemplateVersionParameterSchema { readonly id: string readonly created_at: string readonly job_id: string - readonly workspace_transition: string - readonly type: string readonly name: string - readonly agents: WorkspaceAgent[] + readonly description: string + readonly default_source_scheme: string + readonly default_source_value: string + readonly allow_override_source: boolean + readonly default_destination_scheme: string + readonly allow_override_destination: boolean + readonly default_refresh: string + readonly redisplay_value: boolean + readonly validation_error: string + readonly validation_condition: string + readonly validation_type_system: string + readonly validation_value_type: string } -// From codersdk/parameters.go:26:6 -export interface Parameter { - readonly id: string - readonly created_at: string - readonly updated_at: string - readonly scope: ParameterScope - readonly scope_id: string +// From codersdk/users.go:80:6 +export interface CreateOrganizationRequest { + readonly name: string +} + +// From codersdk/parameters.go:38:6 +export interface CreateParameterRequest { readonly name: string + readonly source_value: string readonly source_scheme: string readonly destination_scheme: string } -// From codersdk/templates.go:17:6 -export interface Template { +// From codersdk/users.go:76:6 +export interface GenerateAPIKeyResponse { + readonly key: string +} + +// From codersdk/users.go:65:6 +export interface LoginWithPasswordRequest { + readonly email: string + readonly password: string +} + +// From codersdk/users.go:71:6 +export interface LoginWithPasswordResponse { + readonly session_token: string +} + +// From codersdk/users.go:32:6 +export interface User { readonly id: string + readonly email: string readonly created_at: string - readonly updated_at: string - readonly organization_id: string - readonly name: string - readonly provisioner: string - readonly active_version_id: string - readonly workspace_owner_count: number + readonly username: string } -// From codersdk/templateversions.go:17:6 -export interface TemplateVersion { +// From codersdk/workspacebuilds.go:17:6 +export interface WorkspaceBuild { readonly id: string - readonly template_id?: string readonly created_at: string readonly updated_at: string + readonly workspace_id: string + readonly template_version_id: string + readonly before_id: string + readonly after_id: string readonly name: string + readonly transition: string + readonly initiator_id: string readonly job: ProvisionerJob } -// From codersdk/workspaceagents.go:40:6 -export interface AzureInstanceIdentityToken { - readonly signature: string - readonly encoding: string -} - -// From codersdk/buildinfo.go:10:6 -export interface BuildInfoResponse { - readonly external_url: string - readonly version: string +// From codersdk/users.go:39:6 +export interface CreateFirstUserRequest { + readonly email: string + readonly username: string + readonly password: string + readonly organization: string } -// From codersdk/organizations.go:17:6 -export interface Organization { - readonly id: string +// From codersdk/organizations.go:38:6 +export interface CreateTemplateRequest { readonly name: string - readonly created_at: string - readonly updated_at: string -} - -// From codersdk/client.go:117:6 -export interface Error { - // Unknown named type, this might not work - readonly Response: Response - readonly statusCode: number + readonly template_version_id: string + readonly parameter_values: CreateParameterRequest[] } // From codersdk/templateversions.go:30:6 export interface TemplateVersionParameter { - // Unknown named type, this might not work - readonly ParameterValue: ParameterValue + // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" + readonly ParameterValue: any readonly schema_id: string readonly default_source_value: boolean } -// From codersdk/files.go:16:6 -export interface UploadResponse { - readonly hash: string +// From codersdk/workspaceresources.go:50:6 +export interface WorkspaceAgentResourceMetadata { + readonly memory_total: number + readonly disk_total: number + readonly cpu_cores: number + readonly cpu_model: string + readonly cpu_mhz: number } -// From codersdk/users.go:80:6 -export interface CreateOrganizationRequest { - readonly name: string +// From codersdk/workspaceagents.go:35:6 +export interface AWSInstanceIdentityToken { + readonly signature: string + readonly document: string } -// From codersdk/organizations.go:38:6 -export interface CreateTemplateRequest { - readonly name: string - readonly template_version_id: string - readonly parameter_values: CreateParameterRequest[] +// From codersdk/users.go:94:6 +export interface AuthMethods { + readonly password: boolean + readonly github: boolean } -// From codersdk/users.go:52:6 -export interface CreateUserRequest { - readonly email: string - readonly username: string - readonly password: string - readonly organization_id: string +// From codersdk/workspaces.go:94:6 +export interface UpdateWorkspaceAutostartRequest { + readonly schedule: string } -// From codersdk/users.go:65:6 -export interface LoginWithPasswordRequest { - readonly email: string - readonly password: string +// From codersdk/workspaces.go:114:6 +export interface UpdateWorkspaceAutostopRequest { + readonly schedule: string } -// From codersdk/users.go:17:6 -export interface UsersRequest { - readonly after_user: string - readonly search: string - readonly limit: number - readonly offset: number +// From codersdk/workspaces.go:18:6 +export interface Workspace { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly owner_id: string + readonly template_id: string + readonly template_name: string + readonly latest_build: WorkspaceBuild + readonly outdated: boolean + readonly name: string + readonly autostart_schedule: string + readonly autostop_schedule: string } // From codersdk/organizations.go:25:6 @@ -305,68 +274,90 @@ export interface CreateTemplateVersionRequest { readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaces.go:33:6 -export interface CreateWorkspaceBuildRequest { - readonly template_version_id: string - readonly transition: string - readonly dry_run: boolean +// From codersdk/provisionerdaemons.go:46:6 +export interface ProvisionerJob { + readonly id: string + readonly created_at: string + readonly started_at?: string + readonly completed_at?: string + readonly error: string + readonly status: ProvisionerJobStatus + readonly worker_id?: string } -// From codersdk/users.go:85:6 -export interface CreateWorkspaceRequest { - readonly template_id: string - readonly name: string - readonly parameter_values: CreateParameterRequest[] +// From codersdk/provisionerdaemons.go:56:6 +export interface ProvisionerJobLog { + readonly id: string + readonly created_at: string + readonly log_source: string + readonly log_level: string + readonly stage: string + readonly output: string } -// From codersdk/workspaceagents.go:35:6 -export interface AWSInstanceIdentityToken { - readonly signature: string - readonly document: string +// From codersdk/templates.go:17:6 +export interface Template { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly organization_id: string + readonly name: string + readonly provisioner: string + readonly active_version_id: string + readonly workspace_owner_count: number } -// From codersdk/templates.go:28:6 -export interface UpdateActiveTemplateVersion { - readonly id: string +// From codersdk/users.go:52:6 +export interface CreateUserRequest { + readonly email: string + readonly username: string + readonly password: string + readonly organization_id: string } -// From codersdk/workspaces.go:114:6 -export interface UpdateWorkspaceAutostopRequest { - readonly schedule: string +// From codersdk/workspaceagents.go:31:6 +export interface GoogleInstanceIdentityToken { + readonly json_web_token: string } -// From codersdk/provisionerdaemons.go:23:6 -export interface ProvisionerDaemon { +// From codersdk/workspaceresources.go:33:6 +export interface WorkspaceAgent { readonly id: string readonly created_at: string - // Unknown named type, this might not work - readonly updated_at: NullTime - // Unknown named type, this might not work - readonly organization_id: NullUUID + readonly updated_at: string + readonly first_connected_at?: string + readonly last_connected_at?: string + readonly disconnected_at?: string + readonly status: WorkspaceAgentStatus readonly name: string - readonly provisioners: string[] + readonly resource_id: string + readonly instance_id: string + readonly architecture: string + readonly environment_variables: Record + readonly operating_system: string + readonly startup_script: string } -// From codersdk/workspaceresources.go:58:6 -export interface WorkspaceAgentInstanceMetadata { - readonly jail_orchestrator: string - readonly operating_system: string - readonly platform: string - readonly platform_family: string - readonly kernel_version: string - readonly kernel_architecture: string - readonly cloud: string - readonly jail: string - readonly vnc: boolean +// From codersdk/organizations.go:17:6 +export interface Organization { + readonly id: string + readonly name: string + readonly created_at: string + readonly updated_at: string +} + +// From codersdk/files.go:16:6 +export interface UploadResponse { + readonly hash: string } +// From codersdk/provisionerdaemons.go:26:6 +export type ProvisionerJobStatus = "canceled" | "canceling" | "failed" | "pending" | "running" | "succeeded" + // From codersdk/workspaceresources.go:15:6 export type WorkspaceAgentStatus = "connected" | "connecting" | "disconnected" // From codersdk/parameters.go:16:6 export type ParameterScope = "organization" | "template" | "user" | "workspace" -// From codersdk/provisionerdaemons.go:26:6 -export type ProvisionerJobStatus = "canceled" | "canceling" | "failed" | "pending" | "running" | "succeeded" - From 21d1687f29253710172dbe270cba602a12b6fc32 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:38:11 -0500 Subject: [PATCH 09/17] Add comments, run gen --- scripts/apitypings/main.go | 30 ++- site/src/api/typesGenerated.ts | 425 +++++++++++++++++---------------- 2 files changed, 231 insertions(+), 224 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 680a18a0e4fff..688917aaeed75 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -124,7 +124,6 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { structs := make(map[string]string) enums := make(map[string]types.Object) enumConsts := make(map[string][]*types.Const) - //constants := make(map[string]string) // Look for comments that indicate to ignore a type for typescript generation. ignoredTypes := make(map[string]struct{}) @@ -167,7 +166,8 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { } switch named.Underlying().(type) { case *types.Struct: - // Structs are obvious + // type struct + // Structs are obvious. st := obj.Type().Underlying().(*types.Struct) codeBlock, err := g.buildStruct(obj, st) if err != nil { @@ -175,6 +175,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { } structs[obj.Name()] = codeBlock case *types.Basic: + // type string // These are enums. Store to expand later. enums[obj.Name()] = obj } @@ -293,9 +294,6 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { case *types.Basic: bs := ty.(*types.Basic) // All basic literals (string, bool, int, etc). - // TODO: Actually ensure the golang names are ok, otherwise, - // we want to put another switch to capture these types - // and rename to typescript. switch { case bs.Info()&types.IsNumeric > 0: return TypescriptType{ValueType: "number"}, nil @@ -308,10 +306,15 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: bs.Name()}, nil } case *types.Struct: - // TODO: This kinda sucks right now. It just dumps the struct def - return TypescriptType{ValueType: ty.String(), Comment: "Unknown struct, this might not work"}, nil + // This handles anonymous structs. This should never happen really. + // Such as: + // type Name struct { + // Embedded struct { + // Field string `json:"field"` + // } + // } + return TypescriptType{ValueType: "any", Comment: "Embedded struct, please fix by naming it"}, nil case *types.Map: - // TODO: Typescript dictionary??? Object? // map[string][string] -> Record m := ty.(*types.Map) keyType, err := g.typescriptType(m.Key()) @@ -360,7 +363,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: name}, nil } - // These are special types that we handle uniquely. + // These are external named types that we handle uniquely. switch n.String() { case "net/url.URL": return TypescriptType{ValueType: "string"}, nil @@ -379,11 +382,14 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { } // Defer to the underlying type. - return g.typescriptType(ty.Underlying()) + ts, err := g.typescriptType(ty.Underlying()) + if err != nil { + return TypescriptType{}, xerrors.Errorf("named underlying: %w", err) + } + ts.Comment = "This is likely an enum in an external package" + return ts, nil case *types.Pointer: // Dereference pointers. - // TODO: Nullable fields? We could say these fields can be null in the - // typescript. pt := ty.(*types.Pointer) resp, err := g.typescriptType(pt.Elem()) if err != nil { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index b41dad41f0342..7f1bf049ad96c 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1,8 +1,9 @@ -// From codersdk/users.go:85:6 -export interface CreateWorkspaceRequest { - readonly template_id: string - readonly name: string - readonly parameter_values: CreateParameterRequest[] +// From codersdk/templateversions.go:31:6 +export interface TemplateVersionParameter { + // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" + readonly ParameterValue: any + readonly schema_id: string + readonly default_source_value: boolean } // From codersdk/users.go:59:6 @@ -11,99 +12,79 @@ export interface UpdateUserProfileRequest { readonly username: string } -// From codersdk/users.go:17:6 -export interface UsersRequest { - readonly after_user: string - readonly search: string - readonly limit: number - readonly offset: number -} - -// From codersdk/workspaceagents.go:47:6 -export interface WorkspaceAgentAuthenticateResponse { - readonly session_token: string +// From codersdk/parameters.go:38:6 +export interface CreateParameterRequest { + readonly name: string + readonly source_value: string + readonly source_scheme: string + readonly destination_scheme: string } -// From codersdk/workspaceresources.go:58:6 -export interface WorkspaceAgentInstanceMetadata { - readonly jail_orchestrator: string - readonly operating_system: string - readonly platform: string - readonly platform_family: string - readonly kernel_version: string - readonly kernel_architecture: string - readonly cloud: string - readonly jail: string - readonly vnc: boolean +// From codersdk/users.go:52:6 +export interface CreateUserRequest { + readonly email: string + readonly username: string + readonly password: string + readonly organization_id: string } -// From codersdk/workspaceagents.go:40:6 -export interface AzureInstanceIdentityToken { - readonly signature: string - readonly encoding: string +// From codersdk/users.go:76:6 +export interface GenerateAPIKeyResponse { + readonly key: string } -// From codersdk/workspaces.go:33:6 -export interface CreateWorkspaceBuildRequest { - readonly template_version_id: string - readonly transition: string - readonly dry_run: boolean +// From codersdk/users.go:65:6 +export interface LoginWithPasswordRequest { + readonly email: string + readonly password: string } -// From codersdk/users.go:47:6 -export interface CreateFirstUserResponse { - readonly user_id: string - readonly organization_id: string +// From codersdk/users.go:71:6 +export interface LoginWithPasswordResponse { + readonly session_token: string } -// From codersdk/parameters.go:26:6 -export interface Parameter { +// From codersdk/templates.go:17:6 +export interface Template { readonly id: string readonly created_at: string readonly updated_at: string - readonly scope: ParameterScope - readonly scope_id: string + readonly organization_id: string readonly name: string - readonly source_scheme: string - readonly destination_scheme: string + readonly provisioner: string + readonly active_version_id: string + readonly workspace_owner_count: number } -// From codersdk/templateversions.go:17:6 -export interface TemplateVersion { - readonly id: string - readonly template_id?: string - readonly created_at: string - readonly updated_at: string - readonly name: string - readonly job: ProvisionerJob +// From codersdk/workspaces.go:94:6 +export interface UpdateWorkspaceAutostartRequest { + readonly schedule: string } -// From codersdk/templates.go:28:6 -export interface UpdateActiveTemplateVersion { - readonly id: string +// From codersdk/files.go:16:6 +export interface UploadResponse { + readonly hash: string } -// From codersdk/workspaceresources.go:23:6 -export interface WorkspaceResource { +// From codersdk/users.go:32:6 +export interface User { readonly id: string + readonly email: string readonly created_at: string - readonly job_id: string - readonly workspace_transition: string - readonly type: string - readonly name: string - readonly agents: WorkspaceAgent[] -} - -// From codersdk/gitsshkey.go:21:6 -export interface AgentGitSSHKey { - readonly public_key: string - readonly private_key: string + readonly username: string } -// From codersdk/buildinfo.go:10:6 -export interface BuildInfoResponse { - readonly external_url: string - readonly version: string +// From codersdk/workspaceresources.go:58:6 +export interface WorkspaceAgentInstanceMetadata { + readonly jail_orchestrator: string + readonly operating_system: string + readonly platform: string + readonly platform_family: string + readonly kernel_version: string + readonly kernel_architecture: string + readonly cloud: string + readonly jail: string + readonly vnc: boolean } // From codersdk/gitsshkey.go:14:6 @@ -114,86 +95,34 @@ export interface GitSSHKey { readonly public_key: string } -// From codersdk/provisionerdaemons.go:23:6 -export interface ProvisionerDaemon { - readonly id: string - readonly created_at: string - readonly updated_at?: string - readonly organization_id?: string - readonly name: string - readonly provisioners: string[] -} - -// From codersdk/templateversions.go:27:6 -export interface TemplateVersionParameterSchema { +// From codersdk/provisionerdaemons.go:56:6 +export interface ProvisionerJobLog { readonly id: string readonly created_at: string - readonly job_id: string - readonly name: string - readonly description: string - readonly default_source_scheme: string - readonly default_source_value: string - readonly allow_override_source: boolean - readonly default_destination_scheme: string - readonly allow_override_destination: boolean - readonly default_refresh: string - readonly redisplay_value: boolean - readonly validation_error: string - readonly validation_condition: string - readonly validation_type_system: string - readonly validation_value_type: string -} - -// From codersdk/users.go:80:6 -export interface CreateOrganizationRequest { - readonly name: string -} - -// From codersdk/parameters.go:38:6 -export interface CreateParameterRequest { - readonly name: string - readonly source_value: string - readonly source_scheme: string - readonly destination_scheme: string -} - -// From codersdk/users.go:76:6 -export interface GenerateAPIKeyResponse { - readonly key: string -} - -// From codersdk/users.go:65:6 -export interface LoginWithPasswordRequest { - readonly email: string - readonly password: string + readonly log_source: string + readonly log_level: string + readonly stage: string + readonly output: string } -// From codersdk/users.go:71:6 -export interface LoginWithPasswordResponse { - readonly session_token: string +// From codersdk/users.go:17:6 +export interface UsersRequest { + readonly after_user: string + readonly search: string + readonly limit: number + readonly offset: number } -// From codersdk/users.go:32:6 -export interface User { - readonly id: string - readonly email: string - readonly created_at: string - readonly username: string +// From codersdk/workspaceagents.go:35:6 +export interface AWSInstanceIdentityToken { + readonly signature: string + readonly document: string } -// From codersdk/workspacebuilds.go:17:6 -export interface WorkspaceBuild { - readonly id: string - readonly created_at: string - readonly updated_at: string - readonly workspace_id: string - readonly template_version_id: string - readonly before_id: string - readonly after_id: string - readonly name: string - readonly transition: string - readonly initiator_id: string - readonly job: ProvisionerJob +// From codersdk/buildinfo.go:10:6 +export interface BuildInfoResponse { + readonly external_url: string + readonly version: string } // From codersdk/users.go:39:6 @@ -204,45 +133,33 @@ export interface CreateFirstUserRequest { readonly organization: string } -// From codersdk/organizations.go:38:6 -export interface CreateTemplateRequest { +// From codersdk/users.go:85:6 +export interface CreateWorkspaceRequest { + readonly template_id: string readonly name: string - readonly template_version_id: string readonly parameter_values: CreateParameterRequest[] } -// From codersdk/templateversions.go:30:6 -export interface TemplateVersionParameter { - // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" - readonly ParameterValue: any - readonly schema_id: string - readonly default_source_value: boolean -} - -// From codersdk/workspaceresources.go:50:6 -export interface WorkspaceAgentResourceMetadata { - readonly memory_total: number - readonly disk_total: number - readonly cpu_cores: number - readonly cpu_model: string - readonly cpu_mhz: number -} - -// From codersdk/workspaceagents.go:35:6 -export interface AWSInstanceIdentityToken { - readonly signature: string - readonly document: string +// From codersdk/workspaceagents.go:31:6 +export interface GoogleInstanceIdentityToken { + readonly json_web_token: string } -// From codersdk/users.go:94:6 -export interface AuthMethods { - readonly password: boolean - readonly github: boolean +// From codersdk/organizations.go:38:6 +export interface CreateTemplateRequest { + readonly name: string + readonly template_version_id: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaces.go:94:6 -export interface UpdateWorkspaceAutostartRequest { - readonly schedule: string +// From codersdk/templateversions.go:17:6 +export interface TemplateVersion { + readonly id: string + readonly template_id?: string + readonly created_at: string + readonly updated_at: string + readonly name: string + readonly job: ProvisionerJob } // From codersdk/workspaces.go:114:6 @@ -265,6 +182,27 @@ export interface Workspace { readonly autostop_schedule: string } +// From codersdk/workspacebuilds.go:17:6 +export interface WorkspaceBuild { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly workspace_id: string + readonly template_version_id: string + readonly before_id: string + readonly after_id: string + readonly name: string + readonly transition: string + readonly initiator_id: string + readonly job: ProvisionerJob +} + +// From codersdk/users.go:94:6 +export interface AuthMethods { + readonly password: boolean + readonly github: boolean +} + // From codersdk/organizations.go:25:6 export interface CreateTemplateVersionRequest { readonly template_id: string @@ -274,6 +212,26 @@ export interface CreateTemplateVersionRequest { readonly parameter_values: CreateParameterRequest[] } +// From codersdk/organizations.go:17:6 +export interface Organization { + readonly id: string + readonly name: string + readonly created_at: string + readonly updated_at: string +} + +// From codersdk/parameters.go:26:6 +export interface Parameter { + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly scope: ParameterScope + readonly scope_id: string + readonly name: string + readonly source_scheme: string + readonly destination_scheme: string +} + // From codersdk/provisionerdaemons.go:46:6 export interface ProvisionerJob { readonly id: string @@ -285,39 +243,89 @@ export interface ProvisionerJob { readonly worker_id?: string } -// From codersdk/provisionerdaemons.go:56:6 -export interface ProvisionerJobLog { +// From codersdk/templates.go:28:6 +export interface UpdateActiveTemplateVersion { + readonly id: string +} + +// From codersdk/gitsshkey.go:21:6 +export interface AgentGitSSHKey { + readonly public_key: string + readonly private_key: string +} + +// From codersdk/workspaceagents.go:40:6 +export interface AzureInstanceIdentityToken { + readonly signature: string + readonly encoding: string +} + +// From codersdk/workspaceresources.go:50:6 +export interface WorkspaceAgentResourceMetadata { + readonly memory_total: number + readonly disk_total: number + readonly cpu_cores: number + readonly cpu_model: string + readonly cpu_mhz: number +} + +// From codersdk/users.go:47:6 +export interface CreateFirstUserResponse { + readonly user_id: string + readonly organization_id: string +} + +// From codersdk/workspaces.go:33:6 +export interface CreateWorkspaceBuildRequest { + readonly template_version_id: string + readonly transition: string + readonly dry_run: boolean +} + +// From codersdk/provisionerdaemons.go:23:6 +export interface ProvisionerDaemon { readonly id: string readonly created_at: string - readonly log_source: string - readonly log_level: string - readonly stage: string - readonly output: string + readonly updated_at?: string + readonly organization_id?: string + readonly name: string + readonly provisioners: string[] } -// From codersdk/templates.go:17:6 -export interface Template { +// From codersdk/templateversions.go:28:6 +export interface TemplateVersionParameterSchema { readonly id: string readonly created_at: string - readonly updated_at: string - readonly organization_id: string + readonly job_id: string readonly name: string - readonly provisioner: string - readonly active_version_id: string - readonly workspace_owner_count: number + readonly description: string + readonly default_source_scheme: string + readonly default_source_value: string + readonly allow_override_source: boolean + readonly default_destination_scheme: string + readonly allow_override_destination: boolean + readonly default_refresh: string + readonly redisplay_value: boolean + readonly validation_error: string + readonly validation_condition: string + readonly validation_type_system: string + readonly validation_value_type: string } -// From codersdk/users.go:52:6 -export interface CreateUserRequest { - readonly email: string - readonly username: string - readonly password: string - readonly organization_id: string +// From codersdk/workspaceresources.go:23:6 +export interface WorkspaceResource { + readonly id: string + readonly created_at: string + readonly job_id: string + readonly workspace_transition: string + readonly type: string + readonly name: string + readonly agents: WorkspaceAgent[] } -// From codersdk/workspaceagents.go:31:6 -export interface GoogleInstanceIdentityToken { - readonly json_web_token: string +// From codersdk/users.go:80:6 +export interface CreateOrganizationRequest { + readonly name: string } // From codersdk/workspaceresources.go:33:6 @@ -338,26 +346,19 @@ export interface WorkspaceAgent { readonly startup_script: string } -// From codersdk/organizations.go:17:6 -export interface Organization { - readonly id: string - readonly name: string - readonly created_at: string - readonly updated_at: string -} -// From codersdk/files.go:16:6 -export interface UploadResponse { - readonly hash: string +// From codersdk/workspaceagents.go:47:6 +export interface WorkspaceAgentAuthenticateResponse { + readonly session_token: string } -// From codersdk/provisionerdaemons.go:26:6 -export type ProvisionerJobStatus = "canceled" | "canceling" | "failed" | "pending" | "running" | "succeeded" - // From codersdk/workspaceresources.go:15:6 export type WorkspaceAgentStatus = "connected" | "connecting" | "disconnected" // From codersdk/parameters.go:16:6 export type ParameterScope = "organization" | "template" | "user" | "workspace" +// From codersdk/provisionerdaemons.go:26:6 +export type ProvisionerJobStatus = "canceled" | "canceling" | "failed" | "pending" | "running" | "succeeded" + From 9a3d7e39d17a6cb9d4b87dfbe250706622f781ef Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:44:18 -0500 Subject: [PATCH 10/17] Add basic readme --- scripts/apitypings/README.md | 39 ++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 scripts/apitypings/README.md diff --git a/scripts/apitypings/README.md b/scripts/apitypings/README.md new file mode 100644 index 0000000000000..639f5b6f79e00 --- /dev/null +++ b/scripts/apitypings/README.md @@ -0,0 +1,39 @@ +# APITypings + +This main.go generates typescript types from the codersdk types in Go. + +# Features + +- Supports Go types + - [x] Basics (string/int/etc) + - [x] Maps + - [x] Slices + - [x] Enums + - [x] Pointers + - [ ] External Types (uses `any` atm) + - Some custom external types are hardcoded in (eg: time.Time) + + +## Type overrides + +```golang +type Foo struct { + // Force the typescript type to be a number + CreatedAt time.Duration `json:"created_at" typescript:"number"` +} +``` + +## Ignore Types + +Do not generate ignored types. + +```golang +// @typescript-ignore InternalType +type InternalType struct { + // ... +} +``` + +# Future Ideas + +- Should `omitempty` in the `json` tag indicate optional? From 7cfba411be327aa6e6917c1c2500ab688da063d1 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:47:01 -0500 Subject: [PATCH 11/17] Reorder imports --- scripts/apitypings/main.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 688917aaeed75..43f84d2863eab 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -10,12 +10,11 @@ import ( "regexp" "strings" - "cdr.dev/slog/sloggers/sloghuman" - "golang.org/x/tools/go/packages" "golang.org/x/xerrors" "cdr.dev/slog" + "cdr.dev/slog/sloggers/sloghuman" ) const ( From 0127e6d85d336d49605a6ba8e22e4ed4c142367b Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:54:40 -0500 Subject: [PATCH 12/17] Sort all output --- site/src/api/typesGenerated.ts | 650 ++++++++++++++++----------------- 1 file changed, 325 insertions(+), 325 deletions(-) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 061003e42b105..a49a6c2385ca0 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1,412 +1,412 @@ // From codersdk/workspaceagents.go:35:6 export interface AWSInstanceIdentityToken { - readonly signature: string - readonly document: string + readonly signature: string + readonly document: string } -// From codersdk/workspaces.go:33:6 -export interface CreateWorkspaceBuildRequest { - // This is likely an enum in an external package - readonly template_version_id: string - // This is likely an enum in an external package - readonly transition: string - readonly dry_run: boolean -} - -// From codersdk/parameters.go:26:6 -export interface Parameter { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly updated_at: string - readonly scope: ParameterScope - // This is likely an enum in an external package - readonly scope_id: string - readonly name: string - // This is likely an enum in an external package - readonly source_scheme: string - // This is likely an enum in an external package - readonly destination_scheme: string +// From codersdk/gitsshkey.go:21:6 +export interface AgentGitSSHKey { + readonly public_key: string + readonly private_key: string } -// From codersdk/users.go:17:6 -export interface UsersRequest { - // This is likely an enum in an external package - readonly after_user: string - readonly search: string - readonly limit: number - readonly offset: number +// From codersdk/users.go:94:6 +export interface AuthMethods { + readonly password: boolean + readonly github: boolean } -// From codersdk/workspaceresources.go:50:6 -export interface WorkspaceAgentResourceMetadata { - readonly memory_total: number - readonly disk_total: number - readonly cpu_cores: number - readonly cpu_model: string - readonly cpu_mhz: number +// From codersdk/workspaceagents.go:40:6 +export interface AzureInstanceIdentityToken { + readonly signature: string + readonly encoding: string } -// From codersdk/workspacebuilds.go:17:6 -export interface WorkspaceBuild { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly updated_at: string - // This is likely an enum in an external package - readonly workspace_id: string - // This is likely an enum in an external package - readonly template_version_id: string - // This is likely an enum in an external package - readonly before_id: string - // This is likely an enum in an external package - readonly after_id: string - readonly name: string - // This is likely an enum in an external package - readonly transition: string - // This is likely an enum in an external package - readonly initiator_id: string - readonly job: ProvisionerJob +// From codersdk/buildinfo.go:10:6 +export interface BuildInfoResponse { + readonly external_url: string + readonly version: string } // From codersdk/users.go:48:6 export interface CreateFirstUserRequest { - readonly email: string - readonly username: string - readonly password: string - readonly organization: string + readonly email: string + readonly username: string + readonly password: string + readonly organization: string } -// From codersdk/users.go:61:6 -export interface CreateUserRequest { - readonly email: string - readonly username: string - readonly password: string - // This is likely an enum in an external package - readonly organization_id: string +// From codersdk/users.go:56:6 +export interface CreateFirstUserResponse { + // This is likely an enum in an external package + readonly user_id: string + // This is likely an enum in an external package + readonly organization_id: string } -// From codersdk/provisionerdaemons.go:46:6 -export interface ProvisionerJob { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly started_at?: string - readonly completed_at?: string - readonly error: string - readonly status: ProvisionerJobStatus - // This is likely an enum in an external package - readonly worker_id?: string +// From codersdk/users.go:89:6 +export interface CreateOrganizationRequest { + readonly name: string } -// From codersdk/files.go:16:6 -export interface UploadResponse { - readonly hash: string +// From codersdk/parameters.go:38:6 +export interface CreateParameterRequest { + readonly name: string + readonly source_value: string + // This is likely an enum in an external package + readonly source_scheme: string + // This is likely an enum in an external package + readonly destination_scheme: string } -// From codersdk/users.go:39:6 -export interface User { - // This is likely an enum in an external package - readonly id: string - readonly email: string - readonly created_at: string - readonly username: string - readonly status: UserStatus - // This is likely an enum in an external package - readonly organization_ids: string[] +// From codersdk/organizations.go:38:6 +export interface CreateTemplateRequest { + readonly name: string + // This is likely an enum in an external package + readonly template_version_id: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/provisionerdaemons.go:23:6 -export interface ProvisionerDaemon { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly updated_at?: string - readonly organization_id?: string - readonly name: string - // This is likely an enum in an external package - readonly provisioners: string[] +// From codersdk/organizations.go:25:6 +export interface CreateTemplateVersionRequest { + // This is likely an enum in an external package + readonly template_id: string + // This is likely an enum in an external package + readonly storage_method: string + readonly storage_source: string + // This is likely an enum in an external package + readonly provisioner: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/templateversions.go:27:6 -export interface TemplateVersionParameterSchema { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - // This is likely an enum in an external package - readonly job_id: string - readonly name: string - readonly description: string - // This is likely an enum in an external package - readonly default_source_scheme: string - readonly default_source_value: string - readonly allow_override_source: boolean - // This is likely an enum in an external package - readonly default_destination_scheme: string - readonly allow_override_destination: boolean - readonly default_refresh: string - readonly redisplay_value: boolean - readonly validation_error: string - readonly validation_condition: string - // This is likely an enum in an external package - readonly validation_type_system: string - readonly validation_value_type: string +// From codersdk/users.go:61:6 +export interface CreateUserRequest { + readonly email: string + readonly username: string + readonly password: string + // This is likely an enum in an external package + readonly organization_id: string } -// From codersdk/templates.go:28:6 -export interface UpdateActiveTemplateVersion { - // This is likely an enum in an external package - readonly id: string +// From codersdk/workspaces.go:33:6 +export interface CreateWorkspaceBuildRequest { + // This is likely an enum in an external package + readonly template_version_id: string + // This is likely an enum in an external package + readonly transition: string + readonly dry_run: boolean } -// From codersdk/workspaceresources.go:33:6 -export interface WorkspaceAgent { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly updated_at: string - readonly first_connected_at?: string - readonly last_connected_at?: string - readonly disconnected_at?: string - readonly status: WorkspaceAgentStatus - readonly name: string - // This is likely an enum in an external package - readonly resource_id: string - readonly instance_id: string - readonly architecture: string - readonly environment_variables: Record - readonly operating_system: string - readonly startup_script: string +// From codersdk/organizations.go:52:6 +export interface CreateWorkspaceRequest { + // This is likely an enum in an external package + readonly template_id: string + readonly name: string + readonly parameter_values: CreateParameterRequest[] } -// From codersdk/workspaceresources.go:58:6 -export interface WorkspaceAgentInstanceMetadata { - readonly jail_orchestrator: string - readonly operating_system: string - readonly platform: string - readonly platform_family: string - readonly kernel_version: string - readonly kernel_architecture: string - readonly cloud: string - readonly jail: string - readonly vnc: boolean +// From codersdk/users.go:85:6 +export interface GenerateAPIKeyResponse { + readonly key: string } -// From codersdk/users.go:56:6 -export interface CreateFirstUserResponse { - // This is likely an enum in an external package - readonly user_id: string - // This is likely an enum in an external package - readonly organization_id: string +// From codersdk/gitsshkey.go:14:6 +export interface GitSSHKey { + // This is likely an enum in an external package + readonly user_id: string + readonly created_at: string + readonly updated_at: string + readonly public_key: string } -// From codersdk/organizations.go:17:6 -export interface Organization { - // This is likely an enum in an external package - readonly id: string - readonly name: string - readonly created_at: string - readonly updated_at: string +// From codersdk/workspaceagents.go:31:6 +export interface GoogleInstanceIdentityToken { + readonly json_web_token: string } -// From codersdk/provisionerdaemons.go:56:6 -export interface ProvisionerJobLog { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - // This is likely an enum in an external package - readonly log_source: string - // This is likely an enum in an external package - readonly log_level: string - readonly stage: string - readonly output: string +// From codersdk/users.go:74:6 +export interface LoginWithPasswordRequest { + readonly email: string + readonly password: string } -// From codersdk/users.go:68:6 -export interface UpdateUserProfileRequest { - readonly email: string - readonly username: string +// From codersdk/users.go:80:6 +export interface LoginWithPasswordResponse { + readonly session_token: string } -// From codersdk/workspaces.go:18:6 -export interface Workspace { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly updated_at: string - // This is likely an enum in an external package - readonly owner_id: string - // This is likely an enum in an external package - readonly template_id: string - readonly template_name: string - readonly latest_build: WorkspaceBuild - readonly outdated: boolean - readonly name: string - readonly autostart_schedule: string - readonly autostop_schedule: string +// From codersdk/organizations.go:17:6 +export interface Organization { + // This is likely an enum in an external package + readonly id: string + readonly name: string + readonly created_at: string + readonly updated_at: string } -// From codersdk/workspaces.go:114:6 -export interface UpdateWorkspaceAutostopRequest { - readonly schedule: string +// From codersdk/parameters.go:26:6 +export interface Parameter { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly scope: ParameterScope + // This is likely an enum in an external package + readonly scope_id: string + readonly name: string + // This is likely an enum in an external package + readonly source_scheme: string + // This is likely an enum in an external package + readonly destination_scheme: string } -// From codersdk/parameters.go:38:6 -export interface CreateParameterRequest { - readonly name: string - readonly source_value: string - // This is likely an enum in an external package - readonly source_scheme: string - // This is likely an enum in an external package - readonly destination_scheme: string +// From codersdk/provisionerdaemons.go:23:6 +export interface ProvisionerDaemon { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly updated_at?: string + readonly organization_id?: string + readonly name: string + // This is likely an enum in an external package + readonly provisioners: string[] } -// From codersdk/organizations.go:38:6 -export interface CreateTemplateRequest { - readonly name: string - // This is likely an enum in an external package - readonly template_version_id: string - readonly parameter_values: CreateParameterRequest[] +// From codersdk/provisionerdaemons.go:46:6 +export interface ProvisionerJob { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly started_at?: string + readonly completed_at?: string + readonly error: string + readonly status: ProvisionerJobStatus + // This is likely an enum in an external package + readonly worker_id?: string } -// From codersdk/gitsshkey.go:14:6 -export interface GitSSHKey { - // This is likely an enum in an external package - readonly user_id: string - readonly created_at: string - readonly updated_at: string - readonly public_key: string +// From codersdk/provisionerdaemons.go:56:6 +export interface ProvisionerJobLog { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + // This is likely an enum in an external package + readonly log_source: string + // This is likely an enum in an external package + readonly log_level: string + readonly stage: string + readonly output: string } -// From codersdk/templateversions.go:30:6 -export interface TemplateVersionParameter { - // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" - readonly ParameterValue: any - // This is likely an enum in an external package - readonly schema_id: string - readonly default_source_value: boolean +// From codersdk/templates.go:17:6 +export interface Template { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly updated_at: string + // This is likely an enum in an external package + readonly organization_id: string + readonly name: string + // This is likely an enum in an external package + readonly provisioner: string + // This is likely an enum in an external package + readonly active_version_id: string + readonly workspace_owner_count: number } -// From codersdk/workspaces.go:94:6 -export interface UpdateWorkspaceAutostartRequest { - readonly schedule: string +// From codersdk/templateversions.go:17:6 +export interface TemplateVersion { + // This is likely an enum in an external package + readonly id: string + // This is likely an enum in an external package + readonly template_id?: string + readonly created_at: string + readonly updated_at: string + readonly name: string + readonly job: ProvisionerJob } -// From codersdk/gitsshkey.go:21:6 -export interface AgentGitSSHKey { - readonly public_key: string - readonly private_key: string +// From codersdk/templateversions.go:30:6 +export interface TemplateVersionParameter { + // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" + readonly ParameterValue: any + // This is likely an enum in an external package + readonly schema_id: string + readonly default_source_value: boolean } -// From codersdk/users.go:94:6 -export interface AuthMethods { - readonly password: boolean - readonly github: boolean +// From codersdk/templateversions.go:27:6 +export interface TemplateVersionParameterSchema { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + // This is likely an enum in an external package + readonly job_id: string + readonly name: string + readonly description: string + // This is likely an enum in an external package + readonly default_source_scheme: string + readonly default_source_value: string + readonly allow_override_source: boolean + // This is likely an enum in an external package + readonly default_destination_scheme: string + readonly allow_override_destination: boolean + readonly default_refresh: string + readonly redisplay_value: boolean + readonly validation_error: string + readonly validation_condition: string + // This is likely an enum in an external package + readonly validation_type_system: string + readonly validation_value_type: string } -// From codersdk/buildinfo.go:10:6 -export interface BuildInfoResponse { - readonly external_url: string - readonly version: string +// From codersdk/templates.go:28:6 +export interface UpdateActiveTemplateVersion { + // This is likely an enum in an external package + readonly id: string } -// From codersdk/users.go:74:6 -export interface LoginWithPasswordRequest { - readonly email: string - readonly password: string +// From codersdk/users.go:68:6 +export interface UpdateUserProfileRequest { + readonly email: string + readonly username: string } -// From codersdk/workspaceagents.go:47:6 -export interface WorkspaceAgentAuthenticateResponse { - readonly session_token: string +// From codersdk/workspaces.go:94:6 +export interface UpdateWorkspaceAutostartRequest { + readonly schedule: string } -// From codersdk/workspaceresources.go:23:6 -export interface WorkspaceResource { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - // This is likely an enum in an external package - readonly job_id: string - // This is likely an enum in an external package - readonly workspace_transition: string - readonly type: string - readonly name: string - readonly agents: WorkspaceAgent[] +// From codersdk/workspaces.go:114:6 +export interface UpdateWorkspaceAutostopRequest { + readonly schedule: string } -// From codersdk/workspaceagents.go:40:6 -export interface AzureInstanceIdentityToken { - readonly signature: string - readonly encoding: string +// From codersdk/files.go:16:6 +export interface UploadResponse { + readonly hash: string } -// From codersdk/organizations.go:52:6 -export interface CreateWorkspaceRequest { - // This is likely an enum in an external package - readonly template_id: string - readonly name: string - readonly parameter_values: CreateParameterRequest[] +// From codersdk/users.go:39:6 +export interface User { + // This is likely an enum in an external package + readonly id: string + readonly email: string + readonly created_at: string + readonly username: string + readonly status: UserStatus + // This is likely an enum in an external package + readonly organization_ids: string[] } -// From codersdk/workspaceagents.go:31:6 -export interface GoogleInstanceIdentityToken { - readonly json_web_token: string +// From codersdk/users.go:17:6 +export interface UsersRequest { + // This is likely an enum in an external package + readonly after_user: string + readonly search: string + readonly limit: number + readonly offset: number } -// From codersdk/users.go:80:6 -export interface LoginWithPasswordResponse { - readonly session_token: string +// From codersdk/workspaces.go:18:6 +export interface Workspace { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly updated_at: string + // This is likely an enum in an external package + readonly owner_id: string + // This is likely an enum in an external package + readonly template_id: string + readonly template_name: string + readonly latest_build: WorkspaceBuild + readonly outdated: boolean + readonly name: string + readonly autostart_schedule: string + readonly autostop_schedule: string } -// From codersdk/templates.go:17:6 -export interface Template { - // This is likely an enum in an external package - readonly id: string - readonly created_at: string - readonly updated_at: string - // This is likely an enum in an external package - readonly organization_id: string - readonly name: string - // This is likely an enum in an external package - readonly provisioner: string - // This is likely an enum in an external package - readonly active_version_id: string - readonly workspace_owner_count: number +// From codersdk/workspaceresources.go:33:6 +export interface WorkspaceAgent { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly updated_at: string + readonly first_connected_at?: string + readonly last_connected_at?: string + readonly disconnected_at?: string + readonly status: WorkspaceAgentStatus + readonly name: string + // This is likely an enum in an external package + readonly resource_id: string + readonly instance_id: string + readonly architecture: string + readonly environment_variables: Record + readonly operating_system: string + readonly startup_script: string } -// From codersdk/users.go:89:6 -export interface CreateOrganizationRequest { - readonly name: string +// From codersdk/workspaceagents.go:47:6 +export interface WorkspaceAgentAuthenticateResponse { + readonly session_token: string } -// From codersdk/organizations.go:25:6 -export interface CreateTemplateVersionRequest { - // This is likely an enum in an external package - readonly template_id: string - // This is likely an enum in an external package - readonly storage_method: string - readonly storage_source: string - // This is likely an enum in an external package - readonly provisioner: string - readonly parameter_values: CreateParameterRequest[] +// From codersdk/workspaceresources.go:58:6 +export interface WorkspaceAgentInstanceMetadata { + readonly jail_orchestrator: string + readonly operating_system: string + readonly platform: string + readonly platform_family: string + readonly kernel_version: string + readonly kernel_architecture: string + readonly cloud: string + readonly jail: string + readonly vnc: boolean } -// From codersdk/users.go:85:6 -export interface GenerateAPIKeyResponse { - readonly key: string +// From codersdk/workspaceresources.go:50:6 +export interface WorkspaceAgentResourceMetadata { + readonly memory_total: number + readonly disk_total: number + readonly cpu_cores: number + readonly cpu_model: string + readonly cpu_mhz: number } -// From codersdk/templateversions.go:17:6 -export interface TemplateVersion { - // This is likely an enum in an external package - readonly id: string - // This is likely an enum in an external package - readonly template_id?: string - readonly created_at: string - readonly updated_at: string - readonly name: string - readonly job: ProvisionerJob +// From codersdk/workspacebuilds.go:17:6 +export interface WorkspaceBuild { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + readonly updated_at: string + // This is likely an enum in an external package + readonly workspace_id: string + // This is likely an enum in an external package + readonly template_version_id: string + // This is likely an enum in an external package + readonly before_id: string + // This is likely an enum in an external package + readonly after_id: string + readonly name: string + // This is likely an enum in an external package + readonly transition: string + // This is likely an enum in an external package + readonly initiator_id: string + readonly job: ProvisionerJob +} + +// From codersdk/workspaceresources.go:23:6 +export interface WorkspaceResource { + // This is likely an enum in an external package + readonly id: string + readonly created_at: string + // This is likely an enum in an external package + readonly job_id: string + // This is likely an enum in an external package + readonly workspace_transition: string + readonly type: string + readonly name: string + readonly agents: WorkspaceAgent[] } // From codersdk/parameters.go:16:6 From 0d943f1b8cde184c21d081986b3121da1c64bad0 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 09:59:03 -0500 Subject: [PATCH 13/17] Add 'DO NOT EDIT' to the top --- scripts/apitypings/main.go | 14 +++++++++++--- site/src/api/typesGenerated.ts | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 43f84d2863eab..eab2621910d92 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -8,6 +8,7 @@ import ( "path/filepath" "reflect" "regexp" + "sort" "strings" "golang.org/x/tools/go/packages" @@ -19,6 +20,7 @@ import ( const ( baseDir = "./codersdk" + indent = " " ) // TODO: Handle httpapi.Response and other types @@ -44,6 +46,8 @@ type TypescriptTypes struct { // String just combines all the codeblocks. func (t TypescriptTypes) String() string { var s strings.Builder + s.WriteString("// Code generated by 'make coder/scripts/apitypings/main.go'. DO NOT EDIT.\n\n") + sortedTypes := make([]string, 0, len(t.Types)) sortedEnums := make([]string, 0, len(t.Types)) @@ -54,6 +58,9 @@ func (t TypescriptTypes) String() string { sortedEnums = append(sortedEnums, k) } + sort.Strings(sortedTypes) + sort.Strings(sortedEnums) + for _, k := range sortedTypes { v := t.Types[k] s.WriteString(v) @@ -65,7 +72,8 @@ func (t TypescriptTypes) String() string { s.WriteString(v) s.WriteRune('\n') } - return s.String() + + return strings.TrimRight(s.String(), "\n") } // GenerateFromDirectory will return all the typescript code blocks for a directory @@ -265,13 +273,13 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err } if tsType.Comment != "" { - s.WriteString(fmt.Sprintf("\t// %s\n", tsType.Comment)) + s.WriteString(fmt.Sprintf("%s// %s\n", indent, tsType.Comment)) } optional := "" if tsType.Optional { optional = "?" } - s.WriteString(fmt.Sprintf("\treadonly %s%s: %s\n", jsonName, optional, tsType.ValueType)) + s.WriteString(fmt.Sprintf("%sreadonly %s%s: %s\n", indent, jsonName, optional, tsType.ValueType)) } s.WriteString("}\n") return s.String(), nil diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index a49a6c2385ca0..59bb5089a72c4 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1,3 +1,5 @@ +// Code generated by 'make coder/scripts/apitypings/main.go'. DO NOT EDIT. + // From codersdk/workspaceagents.go:35:6 export interface AWSInstanceIdentityToken { readonly signature: string @@ -420,5 +422,3 @@ export type UserStatus = "active" | "suspended" // From codersdk/workspaceresources.go:15:6 export type WorkspaceAgentStatus = "connected" | "connecting" | "disconnected" - - From 2379c21c7afe8f06045c2a199ab957f745f45f90 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 10:07:38 -0500 Subject: [PATCH 14/17] Go linting --- scripts/apitypings/main.go | 50 ++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index eab2621910d92..03830cd53e3bc 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -33,7 +33,7 @@ func main() { } // Just cat the output to a file to capture it - fmt.Println(codeBlocks.String()) + _, _ = fmt.Println(codeBlocks.String()) } // TypescriptTypes holds all the code blocks created. @@ -46,7 +46,7 @@ type TypescriptTypes struct { // String just combines all the codeblocks. func (t TypescriptTypes) String() string { var s strings.Builder - s.WriteString("// Code generated by 'make coder/scripts/apitypings/main.go'. DO NOT EDIT.\n\n") + _, _ = s.WriteString("// Code generated by 'make coder/scripts/apitypings/main.go'. DO NOT EDIT.\n\n") sortedTypes := make([]string, 0, len(t.Types)) sortedEnums := make([]string, 0, len(t.Types)) @@ -63,14 +63,14 @@ func (t TypescriptTypes) String() string { for _, k := range sortedTypes { v := t.Types[k] - s.WriteString(v) - s.WriteRune('\n') + _, _ = s.WriteString(v) + _, _ = s.WriteRune('\n') } for _, k := range sortedEnums { v := t.Enums[k] - s.WriteString(v) - s.WriteRune('\n') + _, _ = s.WriteString(v) + _, _ = s.WriteRune('\n') } return strings.TrimRight(s.String(), "\n") @@ -147,7 +147,6 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { ignoredTypes[strings.TrimSpace(s)] = struct{}{} } } - } } } @@ -164,7 +163,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { continue } - switch obj.(type) { + switch obj := obj.(type) { // All named types are type declarations case *types.TypeName: named, ok := obj.Type().(*types.Named) @@ -175,7 +174,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { case *types.Struct: // type struct // Structs are obvious. - st := obj.Type().Underlying().(*types.Struct) + st, _ := obj.Type().Underlying().(*types.Struct) codeBlock, err := g.buildStruct(obj, st) if err != nil { return nil, xerrors.Errorf("generate %q: %w", obj.Name()) @@ -188,14 +187,11 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { } case *types.Var: // TODO: Are any enums var declarations? This is also codersdk.Me. - v := obj.(*types.Var) - var _ = v case *types.Const: - c := obj.(*types.Const) // We only care about named constant types, since they are enums - if named, ok := c.Type().(*types.Named); ok { + if named, ok := obj.Type().(*types.Named); ok { name := named.Obj().Name() - enumConsts[name] = append(enumConsts[name], c) + enumConsts[name] = append(enumConsts[name], obj) } case *types.Func: // Noop @@ -214,8 +210,8 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { values = append(values, elem.Val().String()) } var s strings.Builder - s.WriteString(g.posLine(v)) - s.WriteString(fmt.Sprintf("export type %s = %s\n", + _, _ = s.WriteString(g.posLine(v)) + _, _ = s.WriteString(fmt.Sprintf("export type %s = %s\n", name, strings.Join(values, " | "), )) @@ -240,9 +236,9 @@ func (g *Generator) posLine(obj types.Object) string { // buildStruct just prints the typescript def for a type. func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, error) { var s strings.Builder - s.WriteString(g.posLine(obj)) + _, _ = s.WriteString(g.posLine(obj)) - s.WriteString(fmt.Sprintf("export interface %s {\n", obj.Name())) + _, _ = s.WriteString(fmt.Sprintf("export interface %s {\n", obj.Name())) // For each field in the struct, we print 1 line of the typescript interface for i := 0; i < st.NumFields(); i++ { field := st.Field(i) @@ -273,15 +269,15 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err } if tsType.Comment != "" { - s.WriteString(fmt.Sprintf("%s// %s\n", indent, tsType.Comment)) + _, _ = s.WriteString(fmt.Sprintf("%s// %s\n", indent, tsType.Comment)) } optional := "" if tsType.Optional { optional = "?" } - s.WriteString(fmt.Sprintf("%sreadonly %s%s: %s\n", indent, jsonName, optional, tsType.ValueType)) + _, _ = s.WriteString(fmt.Sprintf("%sreadonly %s%s: %s\n", indent, jsonName, optional, tsType.ValueType)) } - s.WriteString("}\n") + _, _ = s.WriteString("}\n") return s.String(), nil } @@ -297,9 +293,9 @@ type TypescriptType struct { // Eg: // []byte returns "string" func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { - switch ty.(type) { + switch ty := ty.(type) { case *types.Basic: - bs := ty.(*types.Basic) + bs := ty // All basic literals (string, bool, int, etc). switch { case bs.Info()&types.IsNumeric > 0: @@ -323,7 +319,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: "any", Comment: "Embedded struct, please fix by naming it"}, nil case *types.Map: // map[string][string] -> Record - m := ty.(*types.Map) + m := ty keyType, err := g.typescriptType(m.Key()) if err != nil { return TypescriptType{}, xerrors.Errorf("map key: %w", err) @@ -342,7 +338,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { Elem() types.Type } - arr := ty.(hasElem) + arr, _ := ty.(hasElem) switch { // When type checking here, just use the string. You can cast it // to a types.Basic and get the kind if you want too :shrug: @@ -359,7 +355,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: underlying.ValueType + "[]", Comment: underlying.Comment}, nil } case *types.Named: - n := ty.(*types.Named) + n := ty // First see if the type is defined elsewhere. If it is, we can just // put the name as it will be defined in the typescript codeblock // we generate. @@ -397,7 +393,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return ts, nil case *types.Pointer: // Dereference pointers. - pt := ty.(*types.Pointer) + pt := ty resp, err := g.typescriptType(pt.Elem()) if err != nil { return TypescriptType{}, xerrors.Errorf("pointer: %w", err) From 3865f36c4bf8c2ddfc1c9081cf7bbf1a881675f6 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 10:24:19 -0500 Subject: [PATCH 15/17] Fix typescript linter --- scripts/apitypings/main.go | 34 ++++++++++++---- site/src/api/typesGenerated.ts | 73 ++++++++-------------------------- 2 files changed, 43 insertions(+), 64 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index 03830cd53e3bc..dd18e338f4b04 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -268,8 +268,9 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err } } - if tsType.Comment != "" { - _, _ = s.WriteString(fmt.Sprintf("%s// %s\n", indent, tsType.Comment)) + if tsType.AboveTypeLine != "" { + _, _ = s.WriteString(tsType.AboveTypeLine) + _, _ = s.WriteRune('\n') } optional := "" if tsType.Optional { @@ -283,7 +284,9 @@ func (g *Generator) buildStruct(obj types.Object, st *types.Struct) (string, err type TypescriptType struct { ValueType string - Comment string + // AboveTypeLine lets you put whatever text you want above the typescript + // type line. + AboveTypeLine string // Optional indicates the value is an optional field in typescript. Optional bool } @@ -304,7 +307,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: "boolean"}, nil case bs.Kind() == types.Byte: // TODO: @emyrk What is a byte for typescript? A string? A uint8? - return TypescriptType{ValueType: "number", Comment: "This is a byte in golang"}, nil + return TypescriptType{ValueType: "number", AboveTypeLine: indentedComment("This is a byte in golang")}, nil default: return TypescriptType{ValueType: bs.Name()}, nil } @@ -316,7 +319,13 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { // Field string `json:"field"` // } // } - return TypescriptType{ValueType: "any", Comment: "Embedded struct, please fix by naming it"}, nil + return TypescriptType{ + ValueType: "any", + AboveTypeLine: fmt.Sprintf("%s\n%s", + indentedComment("Embedded struct, please fix by naming it"), + indentedComment("eslint-disable-next-line @typescript-eslint/no-explicit-any"), + ), + }, nil case *types.Map: // map[string][string] -> Record m := ty @@ -352,7 +361,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { if err != nil { return TypescriptType{}, xerrors.Errorf("array: %w", err) } - return TypescriptType{ValueType: underlying.ValueType + "[]", Comment: underlying.Comment}, nil + return TypescriptType{ValueType: underlying.ValueType + "[]", AboveTypeLine: underlying.AboveTypeLine}, nil } case *types.Named: n := ty @@ -377,11 +386,16 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { return TypescriptType{ValueType: "string", Optional: true}, nil case "github.com/google/uuid.NullUUID": return TypescriptType{ValueType: "string", Optional: true}, nil + case "github.com/google/uuid.UUID": + return TypescriptType{ValueType: "string"}, nil } // If it's a struct, just use the name of the struct type if _, ok := n.Underlying().(*types.Struct); ok { - return TypescriptType{ValueType: "any", Comment: fmt.Sprintf("Named type %q unknown, using \"any\"", n.String())}, nil + return TypescriptType{ValueType: "any", AboveTypeLine: fmt.Sprintf("%s\n%s", + indentedComment(fmt.Sprintf("Named type %q unknown, using \"any\"", n.String())), + indentedComment("eslint-disable-next-line @typescript-eslint/no-explicit-any"), + )}, nil } // Defer to the underlying type. @@ -389,7 +403,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { if err != nil { return TypescriptType{}, xerrors.Errorf("named underlying: %w", err) } - ts.Comment = "This is likely an enum in an external package" + ts.AboveTypeLine = indentedComment(fmt.Sprintf("This is likely an enum in an external package (%q)", n.String())) return ts, nil case *types.Pointer: // Dereference pointers. @@ -406,3 +420,7 @@ func (g *Generator) typescriptType(ty types.Type) (TypescriptType, error) { // time.Time, uuid, etc. return TypescriptType{}, xerrors.Errorf("unknown type: %s", ty.String()) } + +func indentedComment(comment string) string { + return fmt.Sprintf("%s// %s", indent, comment) +} diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 59bb5089a72c4..e47bfa7957846 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -40,9 +40,7 @@ export interface CreateFirstUserRequest { // From codersdk/users.go:56:6 export interface CreateFirstUserResponse { - // This is likely an enum in an external package readonly user_id: string - // This is likely an enum in an external package readonly organization_id: string } @@ -55,28 +53,26 @@ export interface CreateOrganizationRequest { export interface CreateParameterRequest { readonly name: string readonly source_value: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterSourceScheme") readonly source_scheme: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterDestinationScheme") readonly destination_scheme: string } // From codersdk/organizations.go:38:6 export interface CreateTemplateRequest { readonly name: string - // This is likely an enum in an external package readonly template_version_id: string readonly parameter_values: CreateParameterRequest[] } // From codersdk/organizations.go:25:6 export interface CreateTemplateVersionRequest { - // This is likely an enum in an external package readonly template_id: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ProvisionerStorageMethod") readonly storage_method: string readonly storage_source: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ProvisionerType") readonly provisioner: string readonly parameter_values: CreateParameterRequest[] } @@ -86,22 +82,19 @@ export interface CreateUserRequest { readonly email: string readonly username: string readonly password: string - // This is likely an enum in an external package readonly organization_id: string } // From codersdk/workspaces.go:33:6 export interface CreateWorkspaceBuildRequest { - // This is likely an enum in an external package readonly template_version_id: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.WorkspaceTransition") readonly transition: string readonly dry_run: boolean } // From codersdk/organizations.go:52:6 export interface CreateWorkspaceRequest { - // This is likely an enum in an external package readonly template_id: string readonly name: string readonly parameter_values: CreateParameterRequest[] @@ -114,7 +107,6 @@ export interface GenerateAPIKeyResponse { // From codersdk/gitsshkey.go:14:6 export interface GitSSHKey { - // This is likely an enum in an external package readonly user_id: string readonly created_at: string readonly updated_at: string @@ -139,7 +131,6 @@ export interface LoginWithPasswordResponse { // From codersdk/organizations.go:17:6 export interface Organization { - // This is likely an enum in an external package readonly id: string readonly name: string readonly created_at: string @@ -148,53 +139,47 @@ export interface Organization { // From codersdk/parameters.go:26:6 export interface Parameter { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly updated_at: string readonly scope: ParameterScope - // This is likely an enum in an external package readonly scope_id: string readonly name: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterSourceScheme") readonly source_scheme: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterDestinationScheme") readonly destination_scheme: string } // From codersdk/provisionerdaemons.go:23:6 export interface ProvisionerDaemon { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly updated_at?: string readonly organization_id?: string readonly name: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ProvisionerType") readonly provisioners: string[] } // From codersdk/provisionerdaemons.go:46:6 export interface ProvisionerJob { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly started_at?: string readonly completed_at?: string readonly error: string readonly status: ProvisionerJobStatus - // This is likely an enum in an external package readonly worker_id?: string } // From codersdk/provisionerdaemons.go:56:6 export interface ProvisionerJobLog { - // This is likely an enum in an external package readonly id: string readonly created_at: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.LogSource") readonly log_source: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.LogLevel") readonly log_level: string readonly stage: string readonly output: string @@ -202,25 +187,20 @@ export interface ProvisionerJobLog { // From codersdk/templates.go:17:6 export interface Template { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly updated_at: string - // This is likely an enum in an external package readonly organization_id: string readonly name: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ProvisionerType") readonly provisioner: string - // This is likely an enum in an external package readonly active_version_id: string readonly workspace_owner_count: number } // From codersdk/templateversions.go:17:6 export interface TemplateVersion { - // This is likely an enum in an external package readonly id: string - // This is likely an enum in an external package readonly template_id?: string readonly created_at: string readonly updated_at: string @@ -231,40 +211,37 @@ export interface TemplateVersion { // From codersdk/templateversions.go:30:6 export interface TemplateVersionParameter { // Named type "github.com/coder/coder/coderd/database.ParameterValue" unknown, using "any" + // eslint-disable-next-line @typescript-eslint/no-explicit-any readonly ParameterValue: any - // This is likely an enum in an external package readonly schema_id: string readonly default_source_value: boolean } // From codersdk/templateversions.go:27:6 export interface TemplateVersionParameterSchema { - // This is likely an enum in an external package readonly id: string readonly created_at: string - // This is likely an enum in an external package readonly job_id: string readonly name: string readonly description: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterSourceScheme") readonly default_source_scheme: string readonly default_source_value: string readonly allow_override_source: boolean - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterDestinationScheme") readonly default_destination_scheme: string readonly allow_override_destination: boolean readonly default_refresh: string readonly redisplay_value: boolean readonly validation_error: string readonly validation_condition: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.ParameterTypeSystem") readonly validation_type_system: string readonly validation_value_type: string } // From codersdk/templates.go:28:6 export interface UpdateActiveTemplateVersion { - // This is likely an enum in an external package readonly id: string } @@ -291,19 +268,16 @@ export interface UploadResponse { // From codersdk/users.go:39:6 export interface User { - // This is likely an enum in an external package readonly id: string readonly email: string readonly created_at: string readonly username: string readonly status: UserStatus - // This is likely an enum in an external package readonly organization_ids: string[] } // From codersdk/users.go:17:6 export interface UsersRequest { - // This is likely an enum in an external package readonly after_user: string readonly search: string readonly limit: number @@ -312,13 +286,10 @@ export interface UsersRequest { // From codersdk/workspaces.go:18:6 export interface Workspace { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly updated_at: string - // This is likely an enum in an external package readonly owner_id: string - // This is likely an enum in an external package readonly template_id: string readonly template_name: string readonly latest_build: WorkspaceBuild @@ -330,7 +301,6 @@ export interface Workspace { // From codersdk/workspaceresources.go:33:6 export interface WorkspaceAgent { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly updated_at: string @@ -339,7 +309,6 @@ export interface WorkspaceAgent { readonly disconnected_at?: string readonly status: WorkspaceAgentStatus readonly name: string - // This is likely an enum in an external package readonly resource_id: string readonly instance_id: string readonly architecture: string @@ -377,34 +346,26 @@ export interface WorkspaceAgentResourceMetadata { // From codersdk/workspacebuilds.go:17:6 export interface WorkspaceBuild { - // This is likely an enum in an external package readonly id: string readonly created_at: string readonly updated_at: string - // This is likely an enum in an external package readonly workspace_id: string - // This is likely an enum in an external package readonly template_version_id: string - // This is likely an enum in an external package readonly before_id: string - // This is likely an enum in an external package readonly after_id: string readonly name: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.WorkspaceTransition") readonly transition: string - // This is likely an enum in an external package readonly initiator_id: string readonly job: ProvisionerJob } // From codersdk/workspaceresources.go:23:6 export interface WorkspaceResource { - // This is likely an enum in an external package readonly id: string readonly created_at: string - // This is likely an enum in an external package readonly job_id: string - // This is likely an enum in an external package + // This is likely an enum in an external package ("github.com/coder/coder/coderd/database.WorkspaceTransition") readonly workspace_transition: string readonly type: string readonly name: string From 176b481fb4dc37ba3583854d25596fe6764f00a8 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 11:29:49 -0500 Subject: [PATCH 16/17] Use correct array size for allocation --- scripts/apitypings/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/apitypings/main.go b/scripts/apitypings/main.go index dd18e338f4b04..529b7ae0f42f2 100644 --- a/scripts/apitypings/main.go +++ b/scripts/apitypings/main.go @@ -23,7 +23,6 @@ const ( indent = " " ) -// TODO: Handle httpapi.Response and other types func main() { ctx := context.Background() log := slog.Make(sloghuman.Sink(os.Stderr)) @@ -49,7 +48,7 @@ func (t TypescriptTypes) String() string { _, _ = s.WriteString("// Code generated by 'make coder/scripts/apitypings/main.go'. DO NOT EDIT.\n\n") sortedTypes := make([]string, 0, len(t.Types)) - sortedEnums := make([]string, 0, len(t.Types)) + sortedEnums := make([]string, 0, len(t.Enums)) for k := range t.Types { sortedTypes = append(sortedTypes, k) @@ -209,6 +208,7 @@ func (g *Generator) generateAll() (*TypescriptTypes, error) { // here. values = append(values, elem.Val().String()) } + sort.Strings(values) var s strings.Builder _, _ = s.WriteString(g.posLine(v)) _, _ = s.WriteString(fmt.Sprintf("export type %s = %s\n", From 0d37eeb49f940f1f02b1503739308facac05ab41 Mon Sep 17 00:00:00 2001 From: Steven Masley Date: Thu, 28 Apr 2022 11:33:13 -0500 Subject: [PATCH 17/17] Update readme --- scripts/apitypings/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/apitypings/README.md b/scripts/apitypings/README.md index 639f5b6f79e00..32451ec77e5df 100644 --- a/scripts/apitypings/README.md +++ b/scripts/apitypings/README.md @@ -37,3 +37,4 @@ type InternalType struct { # Future Ideas - Should `omitempty` in the `json` tag indicate optional? +- Use a yaml config for overriding certain types