AtsGoCodeGenerator.cs (319)
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();
766WriteLine($"// ToMap converts the DTO to a map for JSON serialization.");
767WriteLine($"func (d *{dtoName}) ToMap() map[string]any {{ return map[string]any{{}} }}");
768WriteLine();
794WriteLine("// ============================================================================");
795WriteLine("// Marker interfaces (from interface-metadata types)");
796WriteLine("// ============================================================================");
797WriteLine();
805WriteLine($"// {name} marks types implementing {ExtractTypeName(typeId)}.");
806WriteLine($"// {note}");
807WriteLine($"type {name} interface {{");
808WriteLine("\thandleReference");
809WriteLine("}");
810WriteLine();
824WriteLine("// ============================================================================");
825WriteLine("// Handle wrappers");
826WriteLine("// ============================================================================");
827WriteLine();
897WriteLine($"// {interfaceName} is the public interface for handle type {interfaceName}.");
898WriteLine($"type {interfaceName} interface {{");
899WriteLine("\thandleReference");
910WriteLine($"\t{RenderMethodSignature(typeId, interfaceName, capability)}");
917WriteLine($"\t{methodName}() *{wrapperType}{typeArgs}");
927WriteLine($"\tBuild() ({appInterface}, error)");
934WriteLine("\tGet(name string) (*InteractionInput, error)");
935WriteLine("\tRequired(name string) (*InteractionInput, error)");
936WriteLine("\tValue(name string) (string, error)");
937WriteLine("\tRequiredValue(name string) (string, error)");
941WriteLine("\tErr() error");
943WriteLine("}");
944WriteLine();
952WriteLine($"// {implName} is the unexported impl of {interfaceName}.");
953WriteLine($"type {implName} struct {{");
954WriteLine("\t*resourceBuilderBase");
958WriteLine($"\t{field} *{wrapperType}{typeArgs}");
960WriteLine("}");
961WriteLine();
966WriteLine($"// new{interfaceName}FromHandle wraps an existing handle as {interfaceName}.");
967WriteLine($"func new{interfaceName}FromHandle(h *handle, c *client) {interfaceName} {{");
968WriteLine($"\treturn &{implName}{{resourceBuilderBase: newResourceBuilderBase(h, c)}}");
969WriteLine("}");
970WriteLine();
981WriteLine("// Get returns the input with the specified name, or nil if no input matches.");
982WriteLine($"func (s *{implName}) Get(name string) (*InteractionInput, error) {{");
983WriteLine("\tif s.err != nil { return nil, s.err }");
984WriteLine("\tinputs, err := s.ToArray()");
985WriteLine("\tif err != nil { return nil, err }");
986WriteLine("\tfor _, input := range inputs {");
987WriteLine("\t\tif strings.EqualFold(input.Name, name) { return input, nil }");
988WriteLine("\t}");
989WriteLine("\treturn nil, nil");
990WriteLine("}");
991WriteLine();
993WriteLine("// Required returns the input with the specified name, or an error if no input matches.");
994WriteLine($"func (s *{implName}) Required(name string) (*InteractionInput, error) {{");
995WriteLine("\tinput, err := s.Get(name)");
996WriteLine("\tif err != nil { return nil, err }");
997WriteLine("\tif input == nil { return nil, fmt.Errorf(\"no input with name '%s' was found\", name) }");
998WriteLine("\treturn input, nil");
999WriteLine("}");
1000WriteLine();
1002WriteLine("// Value returns the value of the input with the specified name, or an empty string if no input matches or it has no value.");
1003WriteLine($"func (s *{implName}) Value(name string) (string, error) {{");
1004WriteLine("\tinput, err := s.Get(name)");
1005WriteLine("\tif err != nil { return \"\", err }");
1006WriteLine("\tif input == nil || input.Value == nil { return \"\", nil }");
1007WriteLine("\treturn *input.Value, nil");
1008WriteLine("}");
1009WriteLine();
1011WriteLine("// RequiredValue returns the value of the input with the specified name, or an error if no input matches.");
1012WriteLine($"func (s *{implName}) RequiredValue(name string) (string, error) {{");
1013WriteLine("\tinput, err := s.Required(name)");
1014WriteLine("\tif err != nil { return \"\", err }");
1015WriteLine("\tif input.Value == nil { return \"\", nil }");
1016WriteLine("\treturn *input.Value, nil");
1017WriteLine("}");
1018WriteLine();
1249WriteLine($"func (s *{implName}) {methodName}({paramSig}){returnSig} {{");
1252WriteLine("}");
1253WriteLine();
1260WriteLine($"// {methodName} {firstChar}{rest}");
1282WriteLine("\tif s.err != nil { return s }");
1286WriteLine($"\tif _, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs); err != nil {{ s.setErr(err) }}");
1287WriteLine("\treturn s");
1302WriteLine("\tif s.err != nil { return nil }");
1306WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1307WriteLine("\tif err != nil { s.setErr(err); return nil }");
1308WriteLine($"\ttyped, ok := result.({returnGoType})");
1309WriteLine("\tif !ok {");
1310WriteLine($"\t\ts.setErr(fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result))");
1311WriteLine("\t\treturn nil");
1312WriteLine("\t}");
1313WriteLine("\treturn typed");
1318WriteLine($"\tif s.err != nil {{ return &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)}} }}");
1326WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1327WriteLine("\tif err != nil {");
1328WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
1329WriteLine("\t}");
1330WriteLine("\thref, ok := result.(handleReference)");
1331WriteLine("\tif !ok {");
1332WriteLine($"\t\terr := fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result)");
1333WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
1334WriteLine("\t}");
1335WriteLine($"\treturn &{childImplName}{{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)}}");
1352WriteLine($"\tif s.err != nil {{ var zero {returnGoType}; return zero, s.err }}");
1356WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1357WriteLine("\tif err != nil {");
1358WriteLine($"\t\tvar zero {returnGoType}");
1359WriteLine("\t\treturn zero, err");
1360WriteLine("\t}");
1361WriteLine($"\treturn decodeAs[{returnGoType}](result)");
1374WriteLine("\tif s.err != nil { return s.err }");
1378WriteLine($"\t_, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1379WriteLine("\treturn err");
1400WriteLine($"{indent}if {paramName} != nil {{ if err := {paramName}.Err(); err != nil {{ {errorAction} }} }}");
1415WriteLine($"{indent}ctx := context.Background()");
1416WriteLine($"{indent}reqArgs := map[string]any{{");
1417WriteLine($"{indent}\t\"{targetParamName}\": {targetHandleVar}.ToJSON(),");
1418WriteLine($"{indent}}}");
1436WriteLine($"{indent}if {paramName} != nil {{");
1437WriteLine($"{indent}\tif id := s.client.registerCancellation({paramName}); id != \"\" {{");
1438WriteLine($"{indent}\t\treqArgs[\"{p.Name}\"] = id");
1439WriteLine($"{indent}\t}}");
1440WriteLine($"{indent}}}");
1451WriteLine($"{indent}if {nilGuard} {{ reqArgs[\"{p.Name}\"] = serializeValue({paramName}) }}");
1455WriteLine($"{indent}reqArgs[\"{p.Name}\"] = serializeValue({paramName})");
1467WriteLine($"{indent}if len(options) > 0 {{");
1468WriteLine($"{indent}\tmerged := &{dtoType}{{}}");
1469WriteLine($"{indent}\tapplied := false");
1470WriteLine($"{indent}\tfor _, opt := range options {{");
1471WriteLine($"{indent}\t\tif opt != nil {{ merged = deepUpdate(merged, opt); applied = true }}");
1472WriteLine($"{indent}\t}}");
1473WriteLine($"{indent}\tif applied {{ reqArgs[\"{directOptionsParam.Name}\"] = serializeValue(merged) }}");
1474WriteLine($"{indent}}}");
1479WriteLine($"{indent}if len(options) > 0 {{");
1480WriteLine($"{indent}\tmerged := &{optionsType}{{}}");
1481WriteLine($"{indent}\tfor _, opt := range options {{");
1482WriteLine($"{indent}\t\tif opt != nil {{ merged = deepUpdate(merged, opt) }}");
1483WriteLine($"{indent}\t}}");
1484WriteLine($"{indent}\tfor k, v := range merged.ToMap() {{ reqArgs[k] = v }}");
1497WriteLine($"{indent}\tif merged.{fieldName} != nil {{");
1498WriteLine($"{indent}\t\tctx = merged.{fieldName}.Context()");
1499WriteLine($"{indent}\t\tif id := s.client.registerCancellation(merged.{fieldName}); id != \"\" {{");
1500WriteLine($"{indent}\t\t\treqArgs[\"{p.Name}\"] = id");
1501WriteLine($"{indent}\t\t}}");
1502WriteLine($"{indent}\t}}");
1504WriteLine($"{indent}}}");
1515WriteLine($"{indent}if {callbackExpr} != nil {{");
1516WriteLine($"{indent}\tcb := {callbackExpr}");
1517WriteLine($"{indent}\tshim := func(args ...any) any {{");
1519WriteLine($"{indent}\t}}");
1520WriteLine($"{indent}\treqArgs[\"{p.Name}\"] = s.client.registerCallback(shim)");
1521WriteLine($"{indent}}}");
1533WriteLine($"\tif d.{propertyName} != nil {{");
1534WriteLine($"\t\tcb := d.{propertyName}");
1535WriteLine($"\t\tm[\"{property.Name}\"] = func(args ...any) any {{");
1537WriteLine($"\t\t}}");
1538WriteLine($"\t}}");
1577WriteLine($"{indent}return {callExpr}");
1582WriteLine($"{indent}return {callExpr}");
1592WriteLine($"{indent}{argName} := callbackArg[{goType}](args, {i})");
1595WriteLine($"{indent}cb({string.Join(", ", argNames)})");
1596WriteLine($"{indent}return map[string]any{{");
1601WriteLine($"{indent}\t\"p{i}\": serializeValue({argNames[i]}),");
1604WriteLine($"{indent}}}");
1608WriteLine($"{indent}{callExpr}");
1609WriteLine($"{indent}return nil");
1626WriteLine($"func (s *{implName}) {g.MethodName}() *{wrapperType}{typeArgs} {{");
1627WriteLine($"\tif s.{g.Field} == nil {{");
1628WriteLine($"\t\ts.{g.Field} = {factory}{typeArgs}(s.handleWrapperBase, \"{g.CapabilityId}\")");
1629WriteLine("\t}");
1630WriteLine($"\treturn s.{g.Field}");
1631WriteLine("}");
1632WriteLine();
1682WriteLine("// ============================================================================");
1683WriteLine("// Options structs");
1684WriteLine("// ============================================================================");
1685WriteLine();
1689WriteLine($"// {name} carries optional parameters for {ToPascalCase(capability.MethodName)}.");
1690WriteLine($"type {name} struct {{");
1702WriteLine($"\t{fieldName} {fieldType} {jsonTag}");
1704WriteLine("}");
1705WriteLine();
1707WriteLine($"func (o *{name}) ToMap() map[string]any {{");
1708WriteLine("\tm := map[string]any{}");
1709WriteLine("\tif o == nil { return m }");
1722WriteLine($"\tif o.{fieldName} != nil {{ m[\"{p.Name}\"] = serializeValue(o.{fieldName}) }}");
1726WriteLine($"\tm[\"{p.Name}\"] = serializeValue(o.{fieldName})");
1729WriteLine("\treturn m");
1730WriteLine("}");
1731WriteLine();
1862WriteLine($"{indent}switch {paramName}.(type) {{");
1863WriteLine($"{indent}case {allowed}:");
1864WriteLine($"{indent}default:");
1865WriteLine($"{indent}\terr := fmt.Errorf(\"aspire: {methodName}: parameter %q must be one of [{allowed}], got %T\", \"{p.Name}\", {paramName})");
1868WriteLine($"{indent}\t{line}");
1870WriteLine($"{indent}}}");
1879WriteLine($"// Allowed types for parameter {p.Name}: {allowed}.");
1927WriteLine("// ============================================================================");
1928WriteLine("// Per-client handle wrapper registration");
1929WriteLine("// ============================================================================");
1930WriteLine();
1931WriteLine("func registerWrappers(c *client) {");
1932WriteLine("\tc.registerHandleWrapper(\"" + AtsConstants.ReferenceExpressionTypeId + "\", func(h *handle, c *client) any {");
1933WriteLine("\t\treturn newHandleBackedReferenceExpression(h, c)");
1934WriteLine("\t})");
1938WriteLine($"\tc.registerHandleWrapper(\"{typeId}\", func(h *handle, c *client) any {{");
1939WriteLine($"\t\treturn new{interfaceName}FromHandle(h, c)");
1940WriteLine("\t})");
1942WriteLine("}");
1943WriteLine();
1962WriteLine("// ============================================================================");
1963WriteLine("// Builder construction & Build()");
1964WriteLine("// ============================================================================");
1965WriteLine();
1975WriteLine($"// {builderInterface} is the entry point to the Aspire SDK.");
1976WriteLine($"type {builderInterface} interface {{");
1977WriteLine("\thandleReference");
1978WriteLine($"\tBuild() ({appInterface}, error)");
1979WriteLine("}");
1980WriteLine();
1982WriteLine($"type {builderImpl} struct {{ *resourceBuilderBase }}");
1983WriteLine();
1988WriteLine($"// {appInterface} is returned by Build(); it represents the running application.");
1989WriteLine($"type {appInterface} interface {{ handleReference }}");
1990WriteLine();
1997WriteLine($"type {ToCamelCase(appInterface)} struct {{ *resourceBuilderBase }}");
1998WriteLine();
2004WriteLine($"// Build invokes the build capability and returns the running application.");
2005WriteLine($"func (b *{builderImpl}) Build() ({appInterface}, error) {{");
2006WriteLine("\tif b.err != nil { return nil, b.err }");
2007WriteLine($"\tresult, err := b.client.invokeCapability(context.Background(), \"{AtsConstants.BuildCapability}\", map[string]any{{");
2008WriteLine("\t\t\"context\": b.handle.ToJSON(),");
2009WriteLine("\t})");
2010WriteLine("\tif err != nil { return nil, err }");
2011WriteLine($"\tapp, ok := result.({appInterface})");
2012WriteLine($"\tif !ok {{ return nil, fmt.Errorf(\"aspire: build returned unexpected type %T\", result) }}");
2013WriteLine("\treturn app, nil");
2014WriteLine("}");
2015WriteLine();
2019WriteLine($"// CreateBuilder establishes a connection to the AppHost and returns a new builder.");
2022WriteLine($"func CreateBuilder(options ...*{createOptionsType}) ({builderInterface}, error) {{");
2026WriteLine($"func CreateBuilder() ({builderInterface}, error) {{");
2028WriteLine("\tsocketPath := os.Getenv(\"REMOTE_APP_HOST_SOCKET_PATH\")");
2029WriteLine("\tif socketPath == \"\" {");
2030WriteLine("\t\treturn nil, fmt.Errorf(\"REMOTE_APP_HOST_SOCKET_PATH environment variable not set. Run this application using `aspire run`\")");
2031WriteLine("\t}");
2032WriteLine("\tc := newClient(socketPath)");
2033WriteLine("\tif err := c.connect(context.Background(), 5*time.Second); err != nil { return nil, err }");
2034WriteLine("\tc.onDisconnect(func() { os.Exit(1) })");
2035WriteLine("\tregisterWrappers(c)");
2036WriteLine();
2037WriteLine("\tresolved := map[string]any{}");
2040WriteLine("\tif len(options) > 0 {");
2041WriteLine($"\t\tmerged := &{createOptionsType}{{}}");
2042WriteLine("\t\tfor _, opt := range options {");
2043WriteLine("\t\t\tif opt != nil { merged = deepUpdate(merged, opt) }");
2044WriteLine("\t\t}");
2045WriteLine("\t\tfor k, v := range merged.ToMap() { resolved[k] = v }");
2046WriteLine("\t}");
2048WriteLine("\tif _, ok := resolved[\"Args\"]; !ok { resolved[\"Args\"] = os.Args[1:] }");
2051WriteLine("\tif projectDirectory, ok := resolved[\"ProjectDirectory\"].(string); !ok || projectDirectory == \"\" {");
2052WriteLine("\t\tif projectDirectory := os.Getenv(\"ASPIRE_PROJECT_DIRECTORY\"); projectDirectory != \"\" {");
2053WriteLine("\t\t\tresolved[\"ProjectDirectory\"] = projectDirectory");
2054WriteLine("\t\t} else if pwd, err := os.Getwd(); err == nil {");
2055WriteLine("\t\t\tresolved[\"ProjectDirectory\"] = pwd");
2056WriteLine("\t\t}");
2057WriteLine("\t}");
2058WriteLine("\tif appHostFilePath, ok := resolved[\"AppHostFilePath\"].(string); !ok || appHostFilePath == \"\" {");
2059WriteLine("\t\tif appHostFilePath := os.Getenv(\"ASPIRE_APPHOST_FILEPATH\"); appHostFilePath != \"\" { resolved[\"AppHostFilePath\"] = appHostFilePath }");
2060WriteLine("\t}");
2061WriteLine("\tif dashboardApplicationName, ok := resolved[\"DashboardApplicationName\"].(string); ok && dashboardApplicationName == \"\" {");
2062WriteLine("\t\tdelete(resolved, \"DashboardApplicationName\")");
2063WriteLine("\t}");
2064WriteLine();
2065WriteLine($"\tresult, err := c.invokeCapability(context.Background(), \"{AtsConstants.CreateBuilderCapability}\", map[string]any{{\"argsOrOptions\": resolved}})");
2066WriteLine("\tif err != nil { return nil, err }");
2067WriteLine("\thref, ok := result.(handleReference)");
2068WriteLine("\tif !ok { return nil, fmt.Errorf(\"aspire: createBuilder returned unexpected type %T\", result) }");
2069WriteLine($"\treturn &{builderImpl}{{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), c)}}, nil");
2070WriteLine("}");
2071WriteLine();