// SPDX-License-Identifier: EUPL-1.2 package api import ( "context" "io" "iter" "maps" "slices" "dappco.re/go/core" coreio "dappco.re/go/core/io" coreerr "dappco.re/go/core/log" coreexec "dappco.re/go/core/process/exec" coreprocess "dappco.re/go/core/process" ) // Supported SDK target languages. var supportedLanguages = map[string]string{ "go": "go", "typescript-fetch": "typescript-fetch", "typescript-axios": "typescript-axios", "python": "python", "java": "java", "csharp": "csharp-netcore", "ruby": "ruby", "swift": "swift5", "kotlin": "kotlin", "rust": "rust", "php": "php", } // SDKGenerator wraps openapi-generator-cli for SDK generation. // // gen := &api.SDKGenerator{SpecPath: "./openapi.json", OutputDir: "./sdk", PackageName: "myapi"} // if gen.Available() { gen.Generate(ctx, "go") } type SDKGenerator struct { // SpecPath is the path to the OpenAPI spec file (JSON or YAML). SpecPath string // OutputDir is the base directory for generated SDK output. OutputDir string // PackageName is the name used for the generated package/module. PackageName string // Stdout receives command output (defaults to io.Discard when nil). Stdout io.Writer // Stderr receives command error output (defaults to io.Discard when nil). Stderr io.Writer } // Generate creates an SDK for the given language using openapi-generator-cli. // The language must be one of the supported languages returned by SupportedLanguages(). // // err := gen.Generate(ctx, "go") // err := gen.Generate(ctx, "python") func (g *SDKGenerator) Generate(ctx context.Context, language string) error { generator, ok := supportedLanguages[language] if !ok { return coreerr.E("SDKGenerator.Generate", core.Sprintf("unsupported language %q: supported languages are %v", language, SupportedLanguages()), nil) } if !coreio.Local.IsFile(g.SpecPath) { return coreerr.E("SDKGenerator.Generate", "spec file not found: "+g.SpecPath, nil) } outputDir := core.Path(g.OutputDir, language) if err := coreio.Local.EnsureDir(outputDir); err != nil { return coreerr.E("SDKGenerator.Generate", "create output directory", err) } args := g.buildArgs(generator, outputDir) stdout := g.Stdout if stdout == nil { stdout = io.Discard } stderr := g.Stderr if stderr == nil { stderr = io.Discard } cmd := coreexec.Command(ctx, "openapi-generator-cli", args...). WithStdout(stdout). WithStderr(stderr) if err := cmd.Run(); err != nil { return coreerr.E("SDKGenerator.Generate", "openapi-generator-cli failed for "+language, err) } return nil } // buildArgs constructs the openapi-generator-cli command arguments. func (g *SDKGenerator) buildArgs(generator, outputDir string) []string { args := []string{ "generate", "-i", g.SpecPath, "-g", generator, "-o", outputDir, } if g.PackageName != "" { args = append(args, "--additional-properties", "packageName="+g.PackageName) } return args } // Available checks if openapi-generator-cli is installed and accessible. // // if gen.Available() { gen.Generate(ctx, "go") } func (g *SDKGenerator) Available() bool { prog := &coreprocess.Program{Name: "openapi-generator-cli"} return prog.Find() == nil } // SupportedLanguages returns the list of supported SDK target languages // in sorted order for deterministic output. // // langs := api.SupportedLanguages() // ["csharp", "go", "java", ...] func SupportedLanguages() []string { return slices.Sorted(maps.Keys(supportedLanguages)) } // SupportedLanguagesIter returns an iterator over supported SDK target languages in sorted order. // // for lang := range api.SupportedLanguagesIter() { fmt.Println(lang) } func SupportedLanguagesIter() iter.Seq[string] { return slices.Values(SupportedLanguages()) }