package tygoja import ( "go/ast" "go/token" "strings" "golang.org/x/tools/go/packages" ) // PackageGenerator is responsible for generating the code for a single input package. type PackageGenerator struct { conf *Config pkg *packages.Package types []string withPkgDoc bool generatedTypes map[string]struct{} unknownTypes map[string]struct{} imports map[string][]string // path -> []names/aliases } // Generate generates the typings for a single package. func (g *PackageGenerator) Generate() (string, error) { s := new(strings.Builder) namespace := packageNameFromPath(g.pkg.ID) s.WriteString("\n") if g.withPkgDoc { for _, f := range g.pkg.Syntax { if f.Doc == nil || len(f.Doc.List) == 0 { continue } g.writeCommentGroup(s, f.Doc, 0) } } g.writeStartModifier(s, 0) s.WriteString("namespace ") s.WriteString(namespace) s.WriteString(" {\n") // register the aliased imports within the package namespace // (see https://www.typescriptlang.org/docs/handbook/namespaces.html#aliases) loadedAliases := map[string]struct{}{} for _, file := range g.pkg.Syntax { for _, imp := range file.Imports { path := strings.Trim(imp.Path.Value, `"' `) pgkName := packageNameFromPath(path) alias := pgkName if imp.Name != nil && imp.Name.Name != "" && imp.Name.Name != "_" { alias = imp.Name.Name if _, ok := loadedAliases[alias]; ok { continue // already registered } loadedAliases[alias] = struct{}{} g.writeIndent(s, 1) s.WriteString("// @ts-ignore\n") g.writeIndent(s, 1) s.WriteString("import ") s.WriteString(alias) s.WriteString(" = ") s.WriteString(pgkName) s.WriteString("\n") } // register the import to export its package later if !exists(g.imports[path], alias) { if g.imports[path] == nil { g.imports[path] = []string{} } g.imports[path] = append(g.imports[path], alias) } } ast.Inspect(file, func(n ast.Node) bool { switch x := n.(type) { case *ast.FuncDecl: // FuncDecl can be package level function or struct method g.writeFuncDecl(s, x, 1) return false case *ast.GenDecl: // GenDecl can be an import, type, var, or const expression if x.Tok == token.VAR || x.Tok == token.IMPORT { return false // ignore variables and import statements for now } g.writeGroupDecl(s, x, 1) return false } return true }) } s.WriteString("}\n") return s.String(), nil }