mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
Keeping the deps in sync between this and the primary go.mod is a headache. adds Tailscale generated types
152 lines
4.3 KiB
Go
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,
|
|
})
|
|
}
|
|
})
|
|
}
|