AtsGoCodeGenerator.cs (319)
458WriteLine("""
482WriteLine();
494WriteLine("// ============================================================================");
495WriteLine("// Enums");
496WriteLine("// ============================================================================");
497WriteLine();
507WriteLine($"// {enumName} represents {enumType.Name}.");
508WriteLine($"type {enumName} string");
509WriteLine();
510WriteLine("const (");
514WriteLine($"\t{memberName} {enumName} = \"{member}\"");
516WriteLine(")");
517WriteLine();
530WriteLine("// ============================================================================");
531WriteLine("// DTOs");
532WriteLine("// ============================================================================");
533WriteLine();
543WriteLine($"// {dtoName} represents {dto.Name}.");
544WriteLine($"type {dtoName} struct {{");
547WriteLine("}");
548WriteLine();
563WriteLine($"\t{propertyName} {propertyType} {jsonTag}");
565WriteLine("}");
566WriteLine();
568WriteLine($"// ToMap converts the DTO to a map for JSON serialization.");
569WriteLine($"func (d *{dtoName}) ToMap() map[string]any {{");
570WriteLine("\tm := map[string]any{}");
582WriteLine($"\tif d.{propertyName} != nil {{ m[\"{JsonNamingPolicy.CamelCase.ConvertName(property.Name)}\"] = serializeValue(d.{propertyName}) }}");
586WriteLine($"\tm[\"{JsonNamingPolicy.CamelCase.ConvertName(property.Name)}\"] = serializeValue(d.{propertyName})");
589WriteLine("\treturn m");
590WriteLine("}");
591WriteLine();
606WriteLine("// ============================================================================");
607WriteLine("// Exported Values");
608WriteLine("// ============================================================================");
609WriteLine();
613WriteLine($"var {name} = {RenderGoExportedValueType(node, indentLevel: 0)}{RenderGoExportedValueValue(node, dtoTypesById, indentLevel: 0)}");
614WriteLine();
767WriteLine($"// ToMap converts the DTO to a map for JSON serialization.");
768WriteLine($"func (d *{dtoName}) ToMap() map[string]any {{ return map[string]any{{}} }}");
769WriteLine();
795WriteLine("// ============================================================================");
796WriteLine("// Marker interfaces (from interface-metadata types)");
797WriteLine("// ============================================================================");
798WriteLine();
806WriteLine($"// {name} marks types implementing {ExtractTypeName(typeId)}.");
807WriteLine($"// {note}");
808WriteLine($"type {name} interface {{");
809WriteLine("\thandleReference");
810WriteLine("}");
811WriteLine();
825WriteLine("// ============================================================================");
826WriteLine("// Handle wrappers");
827WriteLine("// ============================================================================");
828WriteLine();
898WriteLine($"// {interfaceName} is the public interface for handle type {interfaceName}.");
899WriteLine($"type {interfaceName} interface {{");
900WriteLine("\thandleReference");
911WriteLine($"\t{RenderMethodSignature(typeId, interfaceName, capability)}");
918WriteLine($"\t{methodName}() *{wrapperType}{typeArgs}");
928WriteLine($"\tBuild() ({appInterface}, error)");
935WriteLine("\tGet(name string) (*InteractionInput, error)");
936WriteLine("\tRequired(name string) (*InteractionInput, error)");
937WriteLine("\tValue(name string) (string, error)");
938WriteLine("\tRequiredValue(name string) (string, error)");
942WriteLine("\tErr() error");
944WriteLine("}");
945WriteLine();
953WriteLine($"// {implName} is the unexported impl of {interfaceName}.");
954WriteLine($"type {implName} struct {{");
955WriteLine("\t*resourceBuilderBase");
959WriteLine($"\t{field} *{wrapperType}{typeArgs}");
961WriteLine("}");
962WriteLine();
967WriteLine($"// new{interfaceName}FromHandle wraps an existing handle as {interfaceName}.");
968WriteLine($"func new{interfaceName}FromHandle(h *handle, c *client) {interfaceName} {{");
969WriteLine($"\treturn &{implName}{{resourceBuilderBase: newResourceBuilderBase(h, c)}}");
970WriteLine("}");
971WriteLine();
982WriteLine("// Get returns the input with the specified name, or nil if no input matches.");
983WriteLine($"func (s *{implName}) Get(name string) (*InteractionInput, error) {{");
984WriteLine("\tif s.err != nil { return nil, s.err }");
985WriteLine("\tinputs, err := s.ToArray()");
986WriteLine("\tif err != nil { return nil, err }");
987WriteLine("\tfor _, input := range inputs {");
988WriteLine("\t\tif strings.EqualFold(input.Name, name) { return input, nil }");
989WriteLine("\t}");
990WriteLine("\treturn nil, nil");
991WriteLine("}");
992WriteLine();
994WriteLine("// Required returns the input with the specified name, or an error if no input matches.");
995WriteLine($"func (s *{implName}) Required(name string) (*InteractionInput, error) {{");
996WriteLine("\tinput, err := s.Get(name)");
997WriteLine("\tif err != nil { return nil, err }");
998WriteLine("\tif input == nil { return nil, fmt.Errorf(\"no input with name '%s' was found\", name) }");
999WriteLine("\treturn input, nil");
1000WriteLine("}");
1001WriteLine();
1003WriteLine("// Value returns the value of the input with the specified name, or an empty string if no input matches or it has no value.");
1004WriteLine($"func (s *{implName}) Value(name string) (string, error) {{");
1005WriteLine("\tinput, err := s.Get(name)");
1006WriteLine("\tif err != nil { return \"\", err }");
1007WriteLine("\tif input == nil || input.Value == nil { return \"\", nil }");
1008WriteLine("\treturn *input.Value, nil");
1009WriteLine("}");
1010WriteLine();
1012WriteLine("// RequiredValue returns the value of the input with the specified name, or an error if no input matches.");
1013WriteLine($"func (s *{implName}) RequiredValue(name string) (string, error) {{");
1014WriteLine("\tinput, err := s.Required(name)");
1015WriteLine("\tif err != nil { return \"\", err }");
1016WriteLine("\tif input.Value == nil { return \"\", nil }");
1017WriteLine("\treturn *input.Value, nil");
1018WriteLine("}");
1019WriteLine();
1250WriteLine($"func (s *{implName}) {methodName}({paramSig}){returnSig} {{");
1253WriteLine("}");
1254WriteLine();
1261WriteLine($"// {methodName} {firstChar}{rest}");
1283WriteLine("\tif s.err != nil { return s }");
1287WriteLine($"\tif _, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs); err != nil {{ s.setErr(err) }}");
1288WriteLine("\treturn s");
1303WriteLine("\tif s.err != nil { return nil }");
1307WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1308WriteLine("\tif err != nil { s.setErr(err); return nil }");
1309WriteLine($"\ttyped, ok := result.({returnGoType})");
1310WriteLine("\tif !ok {");
1311WriteLine($"\t\ts.setErr(fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result))");
1312WriteLine("\t\treturn nil");
1313WriteLine("\t}");
1314WriteLine("\treturn typed");
1319WriteLine($"\tif s.err != nil {{ return &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)}} }}");
1327WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1328WriteLine("\tif err != nil {");
1329WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
1330WriteLine("\t}");
1331WriteLine("\thref, ok := result.(handleReference)");
1332WriteLine("\tif !ok {");
1333WriteLine($"\t\terr := fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result)");
1334WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
1335WriteLine("\t}");
1336WriteLine($"\treturn &{childImplName}{{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), s.client)}}");
1353WriteLine($"\tif s.err != nil {{ var zero {returnGoType}; return zero, s.err }}");
1357WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1358WriteLine("\tif err != nil {");
1359WriteLine($"\t\tvar zero {returnGoType}");
1360WriteLine("\t\treturn zero, err");
1361WriteLine("\t}");
1362WriteLine($"\treturn decodeAs[{returnGoType}](result)");
1375WriteLine("\tif s.err != nil { return s.err }");
1379WriteLine($"\t_, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
1380WriteLine("\treturn err");
1401WriteLine($"{indent}if {paramName} != nil {{ if err := {paramName}.Err(); err != nil {{ {errorAction} }} }}");
1416WriteLine($"{indent}ctx := context.Background()");
1417WriteLine($"{indent}reqArgs := map[string]any{{");
1418WriteLine($"{indent}\t\"{targetParamName}\": {targetHandleVar}.ToJSON(),");
1419WriteLine($"{indent}}}");
1437WriteLine($"{indent}if {paramName} != nil {{");
1438WriteLine($"{indent}\tif id := s.client.registerCancellation({paramName}); id != \"\" {{");
1439WriteLine($"{indent}\t\treqArgs[\"{p.Name}\"] = id");
1440WriteLine($"{indent}\t}}");
1441WriteLine($"{indent}}}");
1452WriteLine($"{indent}if {nilGuard} {{ reqArgs[\"{p.Name}\"] = serializeValue({paramName}) }}");
1456WriteLine($"{indent}reqArgs[\"{p.Name}\"] = serializeValue({paramName})");
1468WriteLine($"{indent}if len(options) > 0 {{");
1469WriteLine($"{indent}\tmerged := &{dtoType}{{}}");
1470WriteLine($"{indent}\tapplied := false");
1471WriteLine($"{indent}\tfor _, opt := range options {{");
1472WriteLine($"{indent}\t\tif opt != nil {{ merged = deepUpdate(merged, opt); applied = true }}");
1473WriteLine($"{indent}\t}}");
1474WriteLine($"{indent}\tif applied {{ reqArgs[\"{directOptionsParam.Name}\"] = serializeValue(merged) }}");
1475WriteLine($"{indent}}}");
1480WriteLine($"{indent}if len(options) > 0 {{");
1481WriteLine($"{indent}\tmerged := &{optionsType}{{}}");
1482WriteLine($"{indent}\tfor _, opt := range options {{");
1483WriteLine($"{indent}\t\tif opt != nil {{ merged = deepUpdate(merged, opt) }}");
1484WriteLine($"{indent}\t}}");
1485WriteLine($"{indent}\tfor k, v := range merged.ToMap() {{ reqArgs[k] = v }}");
1498WriteLine($"{indent}\tif merged.{fieldName} != nil {{");
1499WriteLine($"{indent}\t\tctx = merged.{fieldName}.Context()");
1500WriteLine($"{indent}\t\tif id := s.client.registerCancellation(merged.{fieldName}); id != \"\" {{");
1501WriteLine($"{indent}\t\t\treqArgs[\"{p.Name}\"] = id");
1502WriteLine($"{indent}\t\t}}");
1503WriteLine($"{indent}\t}}");
1505WriteLine($"{indent}}}");
1516WriteLine($"{indent}if {callbackExpr} != nil {{");
1517WriteLine($"{indent}\tcb := {callbackExpr}");
1518WriteLine($"{indent}\tshim := func(args ...any) any {{");
1520WriteLine($"{indent}\t}}");
1521WriteLine($"{indent}\treqArgs[\"{p.Name}\"] = s.client.registerCallback(shim)");
1522WriteLine($"{indent}}}");
1534WriteLine($"\tif d.{propertyName} != nil {{");
1535WriteLine($"\t\tcb := d.{propertyName}");
1536WriteLine($"\t\tm[\"{JsonNamingPolicy.CamelCase.ConvertName(property.Name)}\"] = func(args ...any) any {{");
1538WriteLine($"\t\t}}");
1539WriteLine($"\t}}");
1578WriteLine($"{indent}return {callExpr}");
1583WriteLine($"{indent}return {callExpr}");
1593WriteLine($"{indent}{argName} := callbackArg[{goType}](args, {i})");
1596WriteLine($"{indent}cb({string.Join(", ", argNames)})");
1597WriteLine($"{indent}return map[string]any{{");
1602WriteLine($"{indent}\t\"p{i}\": serializeValue({argNames[i]}),");
1605WriteLine($"{indent}}}");
1609WriteLine($"{indent}{callExpr}");
1610WriteLine($"{indent}return nil");
1627WriteLine($"func (s *{implName}) {g.MethodName}() *{wrapperType}{typeArgs} {{");
1628WriteLine($"\tif s.{g.Field} == nil {{");
1629WriteLine($"\t\ts.{g.Field} = {factory}{typeArgs}(s.handleWrapperBase, \"{g.CapabilityId}\")");
1630WriteLine("\t}");
1631WriteLine($"\treturn s.{g.Field}");
1632WriteLine("}");
1633WriteLine();
1683WriteLine("// ============================================================================");
1684WriteLine("// Options structs");
1685WriteLine("// ============================================================================");
1686WriteLine();
1690WriteLine($"// {name} carries optional parameters for {ToPascalCase(capability.MethodName)}.");
1691WriteLine($"type {name} struct {{");
1703WriteLine($"\t{fieldName} {fieldType} {jsonTag}");
1705WriteLine("}");
1706WriteLine();
1708WriteLine($"func (o *{name}) ToMap() map[string]any {{");
1709WriteLine("\tm := map[string]any{}");
1710WriteLine("\tif o == nil { return m }");
1723WriteLine($"\tif o.{fieldName} != nil {{ m[\"{p.Name}\"] = serializeValue(o.{fieldName}) }}");
1727WriteLine($"\tm[\"{p.Name}\"] = serializeValue(o.{fieldName})");
1730WriteLine("\treturn m");
1731WriteLine("}");
1732WriteLine();
1863WriteLine($"{indent}switch {paramName}.(type) {{");
1864WriteLine($"{indent}case {allowed}:");
1865WriteLine($"{indent}default:");
1866WriteLine($"{indent}\terr := fmt.Errorf(\"aspire: {methodName}: parameter %q must be one of [{allowed}], got %T\", \"{p.Name}\", {paramName})");
1869WriteLine($"{indent}\t{line}");
1871WriteLine($"{indent}}}");
1880WriteLine($"// Allowed types for parameter {p.Name}: {allowed}.");
1928WriteLine("// ============================================================================");
1929WriteLine("// Per-client handle wrapper registration");
1930WriteLine("// ============================================================================");
1931WriteLine();
1932WriteLine("func registerWrappers(c *client) {");
1933WriteLine("\tc.registerHandleWrapper(\"" + AtsConstants.ReferenceExpressionTypeId + "\", func(h *handle, c *client) any {");
1934WriteLine("\t\treturn newHandleBackedReferenceExpression(h, c)");
1935WriteLine("\t})");
1939WriteLine($"\tc.registerHandleWrapper(\"{typeId}\", func(h *handle, c *client) any {{");
1940WriteLine($"\t\treturn new{interfaceName}FromHandle(h, c)");
1941WriteLine("\t})");
1943WriteLine("}");
1944WriteLine();
1963WriteLine("// ============================================================================");
1964WriteLine("// Builder construction & Build()");
1965WriteLine("// ============================================================================");
1966WriteLine();
1976WriteLine($"// {builderInterface} is the entry point to the Aspire SDK.");
1977WriteLine($"type {builderInterface} interface {{");
1978WriteLine("\thandleReference");
1979WriteLine($"\tBuild() ({appInterface}, error)");
1980WriteLine("}");
1981WriteLine();
1983WriteLine($"type {builderImpl} struct {{ *resourceBuilderBase }}");
1984WriteLine();
1989WriteLine($"// {appInterface} is returned by Build(); it represents the running application.");
1990WriteLine($"type {appInterface} interface {{ handleReference }}");
1991WriteLine();
1998WriteLine($"type {ToCamelCase(appInterface)} struct {{ *resourceBuilderBase }}");
1999WriteLine();
2005WriteLine($"// Build invokes the build capability and returns the running application.");
2006WriteLine($"func (b *{builderImpl}) Build() ({appInterface}, error) {{");
2007WriteLine("\tif b.err != nil { return nil, b.err }");
2008WriteLine($"\tresult, err := b.client.invokeCapability(context.Background(), \"{AtsConstants.BuildCapability}\", map[string]any{{");
2009WriteLine("\t\t\"context\": b.handle.ToJSON(),");
2010WriteLine("\t})");
2011WriteLine("\tif err != nil { return nil, err }");
2012WriteLine($"\tapp, ok := result.({appInterface})");
2013WriteLine($"\tif !ok {{ return nil, fmt.Errorf(\"aspire: build returned unexpected type %T\", result) }}");
2014WriteLine("\treturn app, nil");
2015WriteLine("}");
2016WriteLine();
2020WriteLine($"// CreateBuilder establishes a connection to the AppHost and returns a new builder.");
2023WriteLine($"func CreateBuilder(options ...*{createOptionsType}) ({builderInterface}, error) {{");
2027WriteLine($"func CreateBuilder() ({builderInterface}, error) {{");
2029WriteLine("\tsocketPath := os.Getenv(\"REMOTE_APP_HOST_SOCKET_PATH\")");
2030WriteLine("\tif socketPath == \"\" {");
2031WriteLine("\t\treturn nil, fmt.Errorf(\"REMOTE_APP_HOST_SOCKET_PATH environment variable not set. Run this application using `aspire run`\")");
2032WriteLine("\t}");
2033WriteLine("\tc := newClient(socketPath)");
2034WriteLine("\tif err := c.connect(context.Background(), 5*time.Second); err != nil { return nil, err }");
2035WriteLine("\tc.onDisconnect(func() { os.Exit(1) })");
2036WriteLine("\tregisterWrappers(c)");
2037WriteLine();
2038WriteLine("\tresolved := map[string]any{}");
2041WriteLine("\tif len(options) > 0 {");
2042WriteLine($"\t\tmerged := &{createOptionsType}{{}}");
2043WriteLine("\t\tfor _, opt := range options {");
2044WriteLine("\t\t\tif opt != nil { merged = deepUpdate(merged, opt) }");
2045WriteLine("\t\t}");
2046WriteLine("\t\tfor k, v := range merged.ToMap() { resolved[k] = v }");
2047WriteLine("\t}");
2049WriteLine("\tif _, ok := resolved[\"args\"]; !ok { resolved[\"args\"] = os.Args[1:] }");
2052WriteLine("\tif projectDirectory, ok := resolved[\"projectDirectory\"].(string); !ok || projectDirectory == \"\" {");
2053WriteLine("\t\tif projectDirectory := os.Getenv(\"ASPIRE_PROJECT_DIRECTORY\"); projectDirectory != \"\" {");
2054WriteLine("\t\t\tresolved[\"projectDirectory\"] = projectDirectory");
2055WriteLine("\t\t} else if pwd, err := os.Getwd(); err == nil {");
2056WriteLine("\t\t\tresolved[\"projectDirectory\"] = pwd");
2057WriteLine("\t\t}");
2058WriteLine("\t}");
2059WriteLine("\tif appHostFilePath, ok := resolved[\"appHostFilePath\"].(string); !ok || appHostFilePath == \"\" {");
2060WriteLine("\t\tif appHostFilePath := os.Getenv(\"ASPIRE_APPHOST_FILEPATH\"); appHostFilePath != \"\" { resolved[\"appHostFilePath\"] = appHostFilePath }");
2061WriteLine("\t}");
2062WriteLine("\tif dashboardApplicationName, ok := resolved[\"dashboardApplicationName\"].(string); ok && dashboardApplicationName == \"\" {");
2063WriteLine("\t\tdelete(resolved, \"dashboardApplicationName\")");
2064WriteLine("\t}");
2065WriteLine();
2066WriteLine($"\tresult, err := c.invokeCapability(context.Background(), \"{AtsConstants.CreateBuilderCapability}\", map[string]any{{\"argsOrOptions\": resolved}})");
2067WriteLine("\tif err != nil { return nil, err }");
2068WriteLine("\thref, ok := result.(handleReference)");
2069WriteLine("\tif !ok { return nil, fmt.Errorf(\"aspire: createBuilder returned unexpected type %T\", result) }");
2070WriteLine($"\treturn &{builderImpl}{{resourceBuilderBase: newResourceBuilderBase(href.getHandle(), c)}}, nil");
2071WriteLine("}");
2072WriteLine();