Skip to content

feat: generate typescript types from codersdk structs #1047

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
generate missing types
  • Loading branch information
f0ssel committed Apr 18, 2022
commit 1a04052aec4cc749bae84ca7022ab8ce15e4d8d3
129 changes: 99 additions & 30 deletions coderts/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func main() {
}

func run() error {
var astFiles []*ast.File
fset := token.NewFileSet()
entries, err := os.ReadDir(baseDir)
if err != nil {
Expand All @@ -37,21 +38,34 @@ func run() error {
return err
}

for _, node := range goFile.Decls {
switch node.(type) {
astFiles = append(astFiles, goFile)
}

for _, astFile := range astFiles {
for _, node := range astFile.Decls {
switch node.(type) {
case *ast.GenDecl:
genDecl := node.(*ast.GenDecl)
for _, spec := range genDecl.Specs {
switch spec.(type) {
case *ast.TypeSpec:
typeSpec := spec.(*ast.TypeSpec)
s, err := writeStruct(typeSpec)
s, err := handleTypeSpec(typeSpec)
if err != nil {
break
}

fmt.Printf(s)
break
case *ast.ValueSpec:
valueSpec := spec.(*ast.ValueSpec)
s, err := handleValueSpec(valueSpec)
if err != nil {
continue
break
}

fmt.Printf(s)
break
}
}
}
Expand All @@ -61,51 +75,106 @@ func run() error {
return nil
}

func writeStruct(typeSpec *ast.TypeSpec) (string, error) {
s := fmt.Sprintf("export interface %s {\n", typeSpec.Name.Name)
func handleTypeSpec(typeSpec *ast.TypeSpec) (string, error) {
jsonFields := 0
s := ""
switch typeSpec.Type.(type) {
case *ast.StructType:
s = fmt.Sprintf("export interface %s {\n", typeSpec.Name.Name)
structType := typeSpec.Type.(*ast.StructType)
for _, field := range structType.Fields.List {
i, ok := field.Type.(*ast.Ident)
if !ok {
continue
}
fieldType := i.Name
switch fieldType {
case "bool":
fieldType = "boolean"
case "uint64", "uint32", "float64":
fieldType = "number"
fieldType, err := toTsType(i)
if err != nil {
continue
}

fieldName := ""
if field.Tag != nil && field.Tag.Value != "" {
for _, pair := range strings.Split(field.Tag.Value, " ") {
if strings.HasPrefix(pair, "`json:\"") {
fieldName = strings.TrimPrefix(pair, "`json:\"")
fieldName = strings.Split(fieldName, ",")[0]
fieldName = strings.TrimSuffix(fieldName, "`")
fieldName = strings.TrimSuffix(fieldName, "\"")
break
}
}
}
if fieldName == "" {
break
fieldName, err := toJSONField(field)
if err != nil {
continue
}

s = fmt.Sprintf("%s %s: %s\n", s, fieldName, fieldType)
jsonFields++
}

if jsonFields == 0 {
return "", xerrors.New("no json fields")
}

return fmt.Sprintf("%s}\n\n", s), nil
case *ast.Ident:
ident := typeSpec.Type.(*ast.Ident)

return fmt.Sprintf("type %s = %s\n\n", typeSpec.Name.Name, ident.Name), nil
default:
return "", xerrors.New("not struct")
return "", xerrors.New("not struct or alias")
}
}

func handleValueSpec(valueSpec *ast.ValueSpec) (string, error) {
valueDecl := ""
valueName := ""
valueType := ""
valueValue := ""
for _, name := range valueSpec.Names {
if name.Obj != nil && name.Obj.Kind == ast.Con {
valueDecl = "const"
valueName = name.Name
break
}
}

i, ok := valueSpec.Type.(*ast.Ident)
if !ok {
return "", xerrors.New("failed to cast type")
}
valueType = i.Name

if jsonFields == 0 {
return "", xerrors.New("no json fields")
for _, value := range valueSpec.Values {
bl, ok := value.(*ast.BasicLit)
if !ok {
return "", xerrors.New("failed to cast value")
}
valueValue = bl.Value
break
}

return fmt.Sprintf("%s %s: %s = %s\n\n", valueDecl, valueName, valueType, valueValue), nil
}

func toTsType(e ast.Expr) (string, error) {
i, ok := e.(*ast.Ident)
if !ok {
return "", xerrors.New("not ident")
}
fieldType := i.Name
switch fieldType {
case "bool":
return "boolean", nil
case "uint64", "uint32", "float64":
return "number", nil
}

return fieldType, nil
}

func toJSONField(field *ast.Field) (string, error) {
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]

return fieldName, nil
}
}
}

return fmt.Sprintf("%s}\n\n", s), nil
return "", xerrors.New("no json tag")
}
37 changes: 37 additions & 0 deletions coderts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,40 @@ export interface CreateTemplateRequest {
name: string
}

type ParameterScope = string

const ParameterOrganization: ParameterScope = "organization"

const ParameterTemplate: ParameterScope = "template"

const ParameterUser: ParameterScope = "user"

const ParameterWorkspace: ParameterScope = "workspace"

export interface Parameter {
scope: ParameterScope
name: string
}

export interface CreateParameterRequest {
name: string
source_value: string
}

type ProvisionerJobStatus = string

const ProvisionerJobPending: ProvisionerJobStatus = "pending"

const ProvisionerJobRunning: ProvisionerJobStatus = "running"

const ProvisionerJobSucceeded: ProvisionerJobStatus = "succeeded"

const ProvisionerJobCanceling: ProvisionerJobStatus = "canceling"

const ProvisionerJobCanceled: ProvisionerJobStatus = "canceled"

const ProvisionerJobFailed: ProvisionerJobStatus = "failed"

export interface ProvisionerJob {
error: string
status: ProvisionerJobStatus
Expand Down Expand Up @@ -115,6 +144,14 @@ export interface WorkspaceBuild {
job: ProvisionerJob
}

type WorkspaceAgentStatus = string

const WorkspaceAgentConnecting: WorkspaceAgentStatus = "connecting"

const WorkspaceAgentConnected: WorkspaceAgentStatus = "connected"

const WorkspaceAgentDisconnected: WorkspaceAgentStatus = "disconnected"

export interface WorkspaceResource {
type: string
name: string
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ require (
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
github.com/tinylib/msgp v1.1.2 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tkrajina/go-reflector v0.5.5 // indirect
github.com/tkrajina/typescriptify-golang-structs v0.1.7 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,10 @@ github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ=
github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/tkrajina/typescriptify-golang-structs v0.1.7 h1:72jmiT/brlgtCPpwu4X0HkhMeUMtx8+xDiTMS93rFqY=
github.com/tkrajina/typescriptify-golang-structs v0.1.7/go.mod h1:sjU00nti/PMEOZb07KljFlR+lJ+RotsC0GBQMv9EKls=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
Expand Down