Files
coder/scripts/apitypings/main.go
Steven Masley 13bb4492c9 chore: remove apitypings specific go.mod (#15899)
Keeping the deps in sync between this and the primary go.mod is
a headache. 


adds Tailscale generated types
2024-12-18 07:18:31 -06:00

152 lines
4.3 KiB
Go

package main
import (
"fmt"
"log"
"golang.org/x/xerrors"
"github.com/coder/guts"
"github.com/coder/guts/bindings"
"github.com/coder/guts/config"
)
func main() {
gen, err := guts.NewGolangParser()
if err != nil {
log.Fatalf("new convert: %v", err)
}
generateDirectories := map[string]string{
"github.com/coder/coder/v2/codersdk": "",
"github.com/coder/coder/v2/coderd/healthcheck/health": "Health",
"github.com/coder/coder/v2/codersdk/healthsdk": "",
}
for dir, prefix := range generateDirectories {
err = gen.IncludeGenerateWithPrefix(dir, prefix)
if err != nil {
log.Fatalf("include generate package %q: %v", dir, err)
}
}
// Serpent has some types referenced in the codersdk.
// We want the referenced types generated.
referencePackages := map[string]string{
"github.com/coder/serpent": "Serpent",
"tailscale.com/derp": "",
// Conflicting name "DERPRegion"
"tailscale.com/tailcfg": "Tail",
"tailscale.com/net/netcheck": "Netcheck",
}
for pkg, prefix := range referencePackages {
err = gen.IncludeReference(pkg, prefix)
if err != nil {
log.Fatalf("include reference package %q: %v", pkg, err)
}
}
err = TypeMappings(gen)
if err != nil {
log.Fatalf("type mappings: %v", err)
}
ts, err := gen.ToTypescript()
if err != nil {
log.Fatalf("to typescript: %v", err)
}
TsMutations(ts)
output, err := ts.Serialize()
if err != nil {
log.Fatalf("serialize: %v", err)
}
_, _ = fmt.Println(output)
}
func TsMutations(ts *guts.Typescript) {
ts.ApplyMutations(
FixSerpentStruct,
// Enum list generator
config.EnumLists,
// Export all top level types
config.ExportTypes,
// Readonly interface fields
config.ReadOnly,
// Add ignore linter comments
config.BiomeLintIgnoreAnyTypeParameters,
// Omitempty + null is just '?' in golang json marshal
// number?: number | null --> number?: number
config.SimplifyOmitEmpty,
)
}
// TypeMappings is all the custom types for codersdk
func TypeMappings(gen *guts.GoParser) error {
gen.IncludeCustomDeclaration(config.StandardMappings())
gen.IncludeCustomDeclaration(map[string]guts.TypeOverride{
"github.com/coder/coder/v2/codersdk.NullTime": config.OverrideNullable(config.OverrideLiteral(bindings.KeywordString)),
// opt.Bool can return 'null' if unset
"tailscale.com/types/opt.Bool": config.OverrideNullable(config.OverrideLiteral(bindings.KeywordBoolean)),
})
err := gen.IncludeCustom(map[string]string{
// Serpent fields should be converted to their primitive types
"github.com/coder/serpent.Regexp": "string",
"github.com/coder/serpent.StringArray": "string",
"github.com/coder/serpent.String": "string",
"github.com/coder/serpent.YAMLConfigPath": "string",
"github.com/coder/serpent.Strings": "[]string",
"github.com/coder/serpent.Int64": "int64",
"github.com/coder/serpent.Bool": "bool",
"github.com/coder/serpent.Duration": "int64",
"github.com/coder/serpent.URL": "string",
"github.com/coder/serpent.HostPort": "string",
"encoding/json.RawMessage": "map[string]string",
})
if err != nil {
return xerrors.Errorf("include custom: %w", err)
}
return nil
}
// FixSerpentStruct fixes 'serpent.Struct'.
// 'serpent.Struct' overrides the json.Marshal to use the underlying type,
// so the typescript type should be the underlying type.
func FixSerpentStruct(gen *guts.Typescript) {
gen.ForEach(func(key string, originalNode bindings.Node) {
isInterface, ok := originalNode.(*bindings.Interface)
if ok && isInterface.Name.Ref() == "SerpentStruct" {
// replace it with
// export type SerpentStruct<T> = T
gen.ReplaceNode("SerpentStruct", &bindings.Alias{
Name: isInterface.Name,
Modifiers: nil,
// The RHS expression is just 'T'
Type: bindings.Reference(bindings.Identifier{
Name: "T",
Package: isInterface.Name.Package,
Prefix: "",
}),
// Generic type parameters, T can be anything.
// Do not provide it a type, as it 'extends any'
Parameters: []*bindings.TypeParameter{
{
Name: bindings.Identifier{
Name: "T",
Package: isInterface.Name.Package,
Prefix: "",
},
Modifiers: nil,
Type: nil,
DefaultType: nil,
},
},
Source: isInterface.Source,
})
}
})
}