AtsGoCodeGenerator.cs (318)
457WriteLine("""
481WriteLine();
493WriteLine("// ============================================================================");
494WriteLine("// Enums");
495WriteLine("// ============================================================================");
496WriteLine();
506WriteLine($"// {enumName} represents {enumType.Name}.");
507WriteLine($"type {enumName} string");
508WriteLine();
509WriteLine("const (");
513WriteLine($"\t{memberName} {enumName} = \"{member}\"");
515WriteLine(")");
516WriteLine();
529WriteLine("// ============================================================================");
530WriteLine("// DTOs");
531WriteLine("// ============================================================================");
532WriteLine();
542WriteLine($"// {dtoName} represents {dto.Name}.");
543WriteLine($"type {dtoName} struct {{");
546WriteLine("}");
547WriteLine();
562WriteLine($"\t{propertyName} {propertyType} {jsonTag}");
564WriteLine("}");
565WriteLine();
567WriteLine($"// ToMap converts the DTO to a map for JSON serialization.");
568WriteLine($"func (d *{dtoName}) ToMap() map[string]any {{");
569WriteLine("\tm := map[string]any{}");
581WriteLine($"\tif d.{propertyName} != nil {{ m[\"{property.Name}\"] = serializeValue(d.{propertyName}) }}");
585WriteLine($"\tm[\"{property.Name}\"] = serializeValue(d.{propertyName})");
588WriteLine("\treturn m");
589WriteLine("}");
590WriteLine();
605WriteLine("// ============================================================================");
606WriteLine("// Exported Values");
607WriteLine("// ============================================================================");
608WriteLine();
612WriteLine($"var {name} = {RenderGoExportedValueType(node, indentLevel: 0)}{RenderGoExportedValueValue(node, dtoTypesById, indentLevel: 0)}");
613WriteLine();
756WriteLine($"// ToMap converts the DTO to a map for JSON serialization.");
757WriteLine($"func (d *{dtoName}) ToMap() map[string]any {{ return map[string]any{{}} }}");
758WriteLine();
784WriteLine("// ============================================================================");
785WriteLine("// Marker interfaces (from interface-metadata types)");
786WriteLine("// ============================================================================");
787WriteLine();
795WriteLine($"// {name} marks types implementing {ExtractTypeName(typeId)}.");
796WriteLine($"// {note}");
797WriteLine($"type {name} interface {{");
798WriteLine("\thandleReference");
799WriteLine("}");
800WriteLine();
814WriteLine("// ============================================================================");
815WriteLine("// Handle wrappers");
816WriteLine("// ============================================================================");
817WriteLine();
887WriteLine($"// {interfaceName} is the public interface for handle type {interfaceName}.");
888WriteLine($"type {interfaceName} interface {{");
889WriteLine("\thandleReference");
900WriteLine($"\t{RenderMethodSignature(typeId, interfaceName, capability)}");
907WriteLine($"\t{methodName}() *{wrapperType}{typeArgs}");
917WriteLine($"\tBuild() ({appInterface}, error)");
924WriteLine("\tGet(name string) (*InteractionInput, error)");
925WriteLine("\tRequired(name string) (*InteractionInput, error)");
926WriteLine("\tValue(name string) (string, error)");
927WriteLine("\tRequiredValue(name string) (string, error)");
931WriteLine("\tErr() error");
933WriteLine("}");
934WriteLine();
942WriteLine($"// {implName} is the unexported impl of {interfaceName}.");
943WriteLine($"type {implName} struct {{");
944WriteLine("\t*resourceBuilderBase");
948WriteLine($"\t{field} *{wrapperType}{typeArgs}");
950WriteLine("}");
951WriteLine();
956WriteLine($"// new{interfaceName}FromHandle wraps an existing handle as {interfaceName}.");
957WriteLine($"func new{interfaceName}FromHandle(h *handle, c *client) {interfaceName} {{");
958WriteLine($"\treturn &{implName}{{resourceBuilderBase: newResourceBuilderBase(h, c)}}");
959WriteLine("}");
960WriteLine();
971WriteLine("// Get returns the input with the specified name, or nil if no input matches.");
972WriteLine($"func (s *{implName}) Get(name string) (*InteractionInput, error) {{");
973WriteLine("\tif s.err != nil { return nil, s.err }");
974WriteLine("\tinputs, err := s.ToArray()");
975WriteLine("\tif err != nil { return nil, err }");
976WriteLine("\tfor _, input := range inputs {");
977WriteLine("\t\tif strings.EqualFold(input.Name, name) { return input, nil }");
978WriteLine("\t}");
979WriteLine("\treturn nil, nil");
980WriteLine("}");
981WriteLine();
983WriteLine("// Required returns the input with the specified name, or an error if no input matches.");
984WriteLine($"func (s *{implName}) Required(name string) (*InteractionInput, error) {{");
985WriteLine("\tinput, err := s.Get(name)");
986WriteLine("\tif err != nil { return nil, err }");
987WriteLine("\tif input == nil { return nil, fmt.Errorf(\"no input with name '%s' was found\", name) }");
988WriteLine("\treturn input, nil");
989WriteLine("}");
990WriteLine();
992WriteLine("// Value returns the value of the input with the specified name, or an empty string if no input matches or it has no value.");
993WriteLine($"func (s *{implName}) Value(name string) (string, error) {{");
994WriteLine("\tinput, err := s.Get(name)");
995WriteLine("\tif err != nil { return \"\", err }");
996WriteLine("\tif input == nil { return \"\", nil }");
997WriteLine("\treturn input.Value, nil");
998WriteLine("}");
999WriteLine();
1001WriteLine("// RequiredValue returns the value of the input with the specified name, or an error if no input matches.");
1002WriteLine($"func (s *{implName}) RequiredValue(name string) (string, error) {{");
1003WriteLine("\tinput, err := s.Required(name)");
1004WriteLine("\tif err != nil { return \"\", err }");
1005WriteLine("\treturn input.Value, nil");
1006WriteLine("}");
1007WriteLine();
1238WriteLine($"func (s *{implName}) {methodName}({paramSig}){returnSig} {{");
1241WriteLine("}");
1242WriteLine();
1249WriteLine($"// {methodName} {firstChar}{rest}");
1271WriteLine("\tif s.err != nil { return s }");
1275WriteLine($"\tif _, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs); err != nil {{ s.setErr(err) }}");
1276WriteLine("\treturn s");
1291WriteLine("\tif s.err != nil { return nil }");
1295WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1296WriteLine("\tif err != nil { s.setErr(err); return nil }");
1297WriteLine($"\ttyped, ok := result.({returnGoType})");
1298WriteLine("\tif !ok {");
1299WriteLine($"\t\ts.setErr(fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result))");
1300WriteLine("\t\treturn nil");
1301WriteLine("\t}");
1302WriteLine("\treturn typed");
1307WriteLine($"\tif s.err != nil {{ return &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)}} }}");
1315WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1316WriteLine("\tif err != nil {");
1317WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
1318WriteLine("\t}");
1319WriteLine("\thref, ok := result.(handleReference)");
1320WriteLine("\tif !ok {");
1321WriteLine($"\t\terr := fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result)");
1322WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
1323WriteLine("\t}");
1324WriteLine($"\treturn &{childImplName}{{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)}}");
1341WriteLine($"\tif s.err != nil {{ var zero {returnGoType}; return zero, s.err }}");
1345WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1346WriteLine("\tif err != nil {");
1347WriteLine($"\t\tvar zero {returnGoType}");
1348WriteLine("\t\treturn zero, err");
1349WriteLine("\t}");
1350WriteLine($"\treturn decodeAs[{returnGoType}](result)");
1363WriteLine("\tif s.err != nil { return s.err }");
1367WriteLine($"\t_, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1368WriteLine("\treturn err");
1389WriteLine($"{indent}if {paramName} != nil {{ if err := {paramName}.Err(); err != nil {{ {errorAction} }} }}");
1404WriteLine($"{indent}ctx := context.Background()");
1405WriteLine($"{indent}reqArgs := map[string]any{{");
1406WriteLine($"{indent}\t\"{targetParamName}\": {targetHandleVar}.ToJSON(),");
1407WriteLine($"{indent}}}");
1425WriteLine($"{indent}if {paramName} != nil {{");
1426WriteLine($"{indent}\tif id := s.client.registerCancellation({paramName}); id != \"\" {{");
1427WriteLine($"{indent}\t\treqArgs[\"{p.Name}\"] = id");
1428WriteLine($"{indent}\t}}");
1429WriteLine($"{indent}}}");
1435WriteLine($"{indent}if {paramName} != nil {{ reqArgs[\"{p.Name}\"] = serializeValue({paramName}) }}");
1439WriteLine($"{indent}reqArgs[\"{p.Name}\"] = serializeValue({paramName})");
1451WriteLine($"{indent}if len(options) > 0 {{");
1452WriteLine($"{indent}\tmerged := &{dtoType}{{}}");
1453WriteLine($"{indent}\tapplied := false");
1454WriteLine($"{indent}\tfor _, opt := range options {{");
1455WriteLine($"{indent}\t\tif opt != nil {{ merged = deepUpdate(merged, opt); applied = true }}");
1456WriteLine($"{indent}\t}}");
1457WriteLine($"{indent}\tif applied {{ reqArgs[\"{directOptionsParam.Name}\"] = serializeValue(merged) }}");
1458WriteLine($"{indent}}}");
1463WriteLine($"{indent}if len(options) > 0 {{");
1464WriteLine($"{indent}\tmerged := &{optionsType}{{}}");
1465WriteLine($"{indent}\tfor _, opt := range options {{");
1466WriteLine($"{indent}\t\tif opt != nil {{ merged = deepUpdate(merged, opt) }}");
1467WriteLine($"{indent}\t}}");
1468WriteLine($"{indent}\tfor k, v := range merged.ToMap() {{ reqArgs[k] = v }}");
1481WriteLine($"{indent}\tif merged.{fieldName} != nil {{");
1482WriteLine($"{indent}\t\tctx = merged.{fieldName}.Context()");
1483WriteLine($"{indent}\t\tif id := s.client.registerCancellation(merged.{fieldName}); id != \"\" {{");
1484WriteLine($"{indent}\t\t\treqArgs[\"{p.Name}\"] = id");
1485WriteLine($"{indent}\t\t}}");
1486WriteLine($"{indent}\t}}");
1488WriteLine($"{indent}}}");
1499WriteLine($"{indent}if {callbackExpr} != nil {{");
1500WriteLine($"{indent}\tcb := {callbackExpr}");
1501WriteLine($"{indent}\tshim := func(args ...any) any {{");
1503WriteLine($"{indent}\t}}");
1504WriteLine($"{indent}\treqArgs[\"{p.Name}\"] = s.client.registerCallback(shim)");
1505WriteLine($"{indent}}}");
1517WriteLine($"\tif d.{propertyName} != nil {{");
1518WriteLine($"\t\tcb := d.{propertyName}");
1519WriteLine($"\t\tm[\"{property.Name}\"] = func(args ...any) any {{");
1521WriteLine($"\t\t}}");
1522WriteLine($"\t}}");
1561WriteLine($"{indent}return {callExpr}");
1566WriteLine($"{indent}return {callExpr}");
1576WriteLine($"{indent}{argName} := callbackArg[{goType}](args, {i})");
1579WriteLine($"{indent}cb({string.Join(", ", argNames)})");
1580WriteLine($"{indent}return map[string]any{{");
1585WriteLine($"{indent}\t\"p{i}\": serializeValue({argNames[i]}),");
1588WriteLine($"{indent}}}");
1592WriteLine($"{indent}{callExpr}");
1593WriteLine($"{indent}return nil");
1610WriteLine($"func (s *{implName}) {g.MethodName}() *{wrapperType}{typeArgs} {{");
1611WriteLine($"\tif s.{g.Field} == nil {{");
1612WriteLine($"\t\ts.{g.Field} = {factory}{typeArgs}(s.handleWrapperBase, \"{g.CapabilityId}\")");
1613WriteLine("\t}");
1614WriteLine($"\treturn s.{g.Field}");
1615WriteLine("}");
1616WriteLine();
1666WriteLine("// ============================================================================");
1667WriteLine("// Options structs");
1668WriteLine("// ============================================================================");
1669WriteLine();
1673WriteLine($"// {name} carries optional parameters for {ToPascalCase(capability.MethodName)}.");
1674WriteLine($"type {name} struct {{");
1686WriteLine($"\t{fieldName} {fieldType} {jsonTag}");
1688WriteLine("}");
1689WriteLine();
1691WriteLine($"func (o *{name}) ToMap() map[string]any {{");
1692WriteLine("\tm := map[string]any{}");
1693WriteLine("\tif o == nil { return m }");
1706WriteLine($"\tif o.{fieldName} != nil {{ m[\"{p.Name}\"] = serializeValue(o.{fieldName}) }}");
1710WriteLine($"\tm[\"{p.Name}\"] = serializeValue(o.{fieldName})");
1713WriteLine("\treturn m");
1714WriteLine("}");
1715WriteLine();
1846WriteLine($"{indent}switch {paramName}.(type) {{");
1847WriteLine($"{indent}case {allowed}:");
1848WriteLine($"{indent}default:");
1849WriteLine($"{indent}\terr := fmt.Errorf(\"aspire: {methodName}: parameter %q must be one of [{allowed}], got %T\", \"{p.Name}\", {paramName})");
1852WriteLine($"{indent}\t{line}");
1854WriteLine($"{indent}}}");
1863WriteLine($"// Allowed types for parameter {p.Name}: {allowed}.");
1911WriteLine("// ============================================================================");
1912WriteLine("// Per-client handle wrapper registration");
1913WriteLine("// ============================================================================");
1914WriteLine();
1915WriteLine("func registerWrappers(c *client) {");
1916WriteLine("\tc.registerHandleWrapper(\"" + AtsConstants.ReferenceExpressionTypeId + "\", func(h *handle, c *client) any {");
1917WriteLine("\t\treturn newHandleBackedReferenceExpression(h, c)");
1918WriteLine("\t})");
1922WriteLine($"\tc.registerHandleWrapper(\"{typeId}\", func(h *handle, c *client) any {{");
1923WriteLine($"\t\treturn new{interfaceName}FromHandle(h, c)");
1924WriteLine("\t})");
1926WriteLine("}");
1927WriteLine();
1946WriteLine("// ============================================================================");
1947WriteLine("// Builder construction & Build()");
1948WriteLine("// ============================================================================");
1949WriteLine();
1959WriteLine($"// {builderInterface} is the entry point to the Aspire SDK.");
1960WriteLine($"type {builderInterface} interface {{");
1961WriteLine("\thandleReference");
1962WriteLine($"\tBuild() ({appInterface}, error)");
1963WriteLine("}");
1964WriteLine();
1966WriteLine($"type {builderImpl} struct {{ *resourceBuilderBase }}");
1967WriteLine();
1972WriteLine($"// {appInterface} is returned by Build(); it represents the running application.");
1973WriteLine($"type {appInterface} interface {{ handleReference }}");
1974WriteLine();
1981WriteLine($"type {ToCamelCase(appInterface)} struct {{ *resourceBuilderBase }}");
1982WriteLine();
1988WriteLine($"// Build invokes the build capability and returns the running application.");
1989WriteLine($"func (b *{builderImpl}) Build() ({appInterface}, error) {{");
1990WriteLine("\tif b.err != nil { return nil, b.err }");
1991WriteLine($"\tresult, err := b.client.invokeCapability(context.Background(), \"{AtsConstants.BuildCapability}\", map[string]any{{");
1992WriteLine("\t\t\"context\": b.handle.ToJSON(),");
1993WriteLine("\t})");
1994WriteLine("\tif err != nil { return nil, err }");
1995WriteLine($"\tapp, ok := result.({appInterface})");
1996WriteLine($"\tif !ok {{ return nil, fmt.Errorf(\"aspire: build returned unexpected type %T\", result) }}");
1997WriteLine("\treturn app, nil");
1998WriteLine("}");
1999WriteLine();
2003WriteLine($"// CreateBuilder establishes a connection to the AppHost and returns a new builder.");
2006WriteLine($"func CreateBuilder(options ...*{createOptionsType}) ({builderInterface}, error) {{");
2010WriteLine($"func CreateBuilder() ({builderInterface}, error) {{");
2012WriteLine("\tsocketPath := os.Getenv(\"REMOTE_APP_HOST_SOCKET_PATH\")");
2013WriteLine("\tif socketPath == \"\" {");
2014WriteLine("\t\treturn nil, fmt.Errorf(\"REMOTE_APP_HOST_SOCKET_PATH environment variable not set. Run this application using `aspire run`\")");
2015WriteLine("\t}");
2016WriteLine("\tc := newClient(socketPath)");
2017WriteLine("\tif err := c.connect(context.Background(), 5*time.Second); err != nil { return nil, err }");
2018WriteLine("\tc.onDisconnect(func() { os.Exit(1) })");
2019WriteLine("\tregisterWrappers(c)");
2020WriteLine();
2021WriteLine("\tresolved := map[string]any{}");
2024WriteLine("\tif len(options) > 0 {");
2025WriteLine($"\t\tmerged := &{createOptionsType}{{}}");
2026WriteLine("\t\tfor _, opt := range options {");
2027WriteLine("\t\t\tif opt != nil { merged = deepUpdate(merged, opt) }");
2028WriteLine("\t\t}");
2029WriteLine("\t\tfor k, v := range merged.ToMap() { resolved[k] = v }");
2030WriteLine("\t}");
2032WriteLine("\tif _, ok := resolved[\"Args\"]; !ok { resolved[\"Args\"] = os.Args[1:] }");
2035WriteLine("\tif projectDirectory, ok := resolved[\"ProjectDirectory\"].(string); !ok || projectDirectory == \"\" {");
2036WriteLine("\t\tif projectDirectory := os.Getenv(\"ASPIRE_PROJECT_DIRECTORY\"); projectDirectory != \"\" {");
2037WriteLine("\t\t\tresolved[\"ProjectDirectory\"] = projectDirectory");
2038WriteLine("\t\t} else if pwd, err := os.Getwd(); err == nil {");
2039WriteLine("\t\t\tresolved[\"ProjectDirectory\"] = pwd");
2040WriteLine("\t\t}");
2041WriteLine("\t}");
2042WriteLine("\tif appHostFilePath, ok := resolved[\"AppHostFilePath\"].(string); !ok || appHostFilePath == \"\" {");
2043WriteLine("\t\tif appHostFilePath := os.Getenv(\"ASPIRE_APPHOST_FILEPATH\"); appHostFilePath != \"\" { resolved[\"AppHostFilePath\"] = appHostFilePath }");
2044WriteLine("\t}");
2045WriteLine("\tif dashboardApplicationName, ok := resolved[\"DashboardApplicationName\"].(string); ok && dashboardApplicationName == \"\" {");
2046WriteLine("\t\tdelete(resolved, \"DashboardApplicationName\")");
2047WriteLine("\t}");
2048WriteLine();
2049WriteLine($"\tresult, err := c.invokeCapability(context.Background(), \"{AtsConstants.CreateBuilderCapability}\", map[string]any{{\"argsOrOptions\": resolved}})");
2050WriteLine("\tif err != nil { return nil, err }");
2051WriteLine("\thref, ok := result.(handleReference)");
2052WriteLine("\tif !ok { return nil, fmt.Errorf(\"aspire: createBuilder returned unexpected type %T\", result) }");
2053WriteLine($"\treturn &{builderImpl}{{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), c)}}, nil");
2054WriteLine("}");
2055WriteLine();