Skip to content

Commit

Permalink
feat(go): Improve file layout for types
Browse files Browse the repository at this point in the history
  • Loading branch information
amckinney committed Nov 14, 2024
1 parent ed573cc commit 281816e
Show file tree
Hide file tree
Showing 230 changed files with 18,581 additions and 14,380 deletions.
Binary file added .package.json.swp
Binary file not shown.
137 changes: 74 additions & 63 deletions generators/go/internal/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import (
)

const (
// sharedTypesFilename is the filename for the shared types file.
sharedTypesFilename = "types.go"

// packageDocsFilename represents the standard package documentation filename.
packageDocsFilename = "doc.go"

Expand Down Expand Up @@ -1357,43 +1360,46 @@ func fileInfoToTypes(
continue
}
fileInfo := fileInfoForType(rootPackageName, irService.Name.FernFilepath)
result[fileInfo] = append(result[fileInfo], &typeToGenerate{ID: irEndpoint.Name.OriginalName, FernFilepath: irService.Name.FernFilepath, Endpoint: irEndpoint, Service: irService})
result[fileInfo] = append(
result[fileInfo],
&typeToGenerate{
ID: irEndpoint.Name.OriginalName,
FernFilepath: irService.Name.FernFilepath,
Endpoint: irEndpoint,
Service: irService,
},
)
}
}
if irServiceTypeReferenceInfo == nil {
// If the service type reference info isn't provided, default
// to the file-per-type naming convention.
for _, irType := range irTypes {
fileInfo := fileInfoForType(rootPackageName, irType.Name.FernFilepath)
result[fileInfo] = append(result[fileInfo], &typeToGenerate{ID: irType.Name.TypeId, FernFilepath: irType.Name.FernFilepath, TypeDeclaration: irType})
result[fileInfo] = append(
result[fileInfo],
&typeToGenerate{
ID: irType.Name.TypeId,
FernFilepath: irType.Name.FernFilepath,
TypeDeclaration: irType,
},
)
}
} else {
directories := make(map[fernir.TypeId][]string)
for irTypeId, irType := range irTypes {
var elements []string
for _, packageName := range irType.Name.FernFilepath.PackagePath {
elements = append(elements, strings.ToLower(packageName.CamelCase.SafeName))
}
directories[irTypeId] = elements
}
sharedTypes := irServiceTypeReferenceInfo.SharedTypes
if typeIds, ok := irServiceTypeReferenceInfo.TypesReferencedOnlyByService["service_"]; ok {
// The root service types should be included alongside the other shared types.
sharedTypes = append(sharedTypes, typeIds...)
}
for _, sharedTypeId := range sharedTypes {
typeDeclaration, ok := irTypes[sharedTypeId]
for _, typeId := range sharedTypes {
typeDeclaration, ok := irTypes[typeId]
if !ok {
// Should be unreachable.
return nil, fmt.Errorf("IR ServiceTypeReferenceInfo referenced type %q which doesn't exist", sharedTypeId)
return nil, fmt.Errorf("IR ServiceTypeReferenceInfo referenced type %q which doesn't exist", typeId)
}
fileInfo := fileInfo{
filename: "types.go",
packageName: rootPackageName,
}
if directory := directories[sharedTypeId]; len(directory) > 0 {
fileInfo.filename = filepath.Join(append(directory, fileInfo.filename)...)
fileInfo.packageName = directory[len(directory)-1]
fileInfo := fileInfoForType(rootPackageName, typeDeclaration.Name.FernFilepath)
if isReservedFilename(filepath.Base(fileInfo.filename)) {
fileInfo.filename = filepath.Join(filepath.Dir(fileInfo.filename), sharedTypesFilename)
}
result[fileInfo] = append(
result[fileInfo],
Expand All @@ -1414,56 +1420,18 @@ func fileInfoToTypes(
// Should be unreachable.
return nil, fmt.Errorf("IR ServiceTypeReferenceInfo referenced service %q which doesn't exist", serviceId)
}
fernFilepath := service.Name.FernFilepath
var basename string
if service.Name.FernFilepath.File != nil {
basename = fernFilepath.File.SnakeCase.UnsafeName
} else {
basename = fernFilepath.PackagePath[len(fernFilepath.PackagePath)-1].SnakeCase.UnsafeName
}
var packages []string
for _, packageName := range fernFilepath.PackagePath {
packages = append(packages, strings.ToLower(packageName.CamelCase.SafeName))
}
servicePackageName := rootPackageName
if len(packages) > 0 {
servicePackageName = packages[len(packages)-1]
}
serviceFileInfo := fileInfo{
filename: filepath.Join(append(packages, fmt.Sprintf("%s.go", basename))...),
packageName: servicePackageName,
}
for _, typeId := range typeIds {
typeDeclaration, ok := irTypes[typeId]
if !ok {
// Should be unreachable.
return nil, fmt.Errorf("IR ServiceTypeReferenceInfo referenced type %q which doesn't exist", typeId)
}
typeFilename := "types.go"
typePackageName := rootPackageName
if directory := directories[typeId]; len(directory) > 0 {
typeFilename = filepath.Join(append(directory, typeFilename)...)
typePackageName = directory[len(directory)-1]
fileInfo := fileInfoForType(rootPackageName, typeDeclaration.Name.FernFilepath)
if shouldSetFileInfoToMatchService(typeDeclaration.Name.FernFilepath, service.Name.FernFilepath) {
fileInfo.filename = filepath.Join(filepath.Dir(fileInfo.filename), service.Name.FernFilepath.File.SnakeCase.UnsafeName+".go")
}
if servicePackageName != typePackageName {
// There is only one service referencing this type, but it still
// belongs in the package where it was defined.
typeFileInfo := fileInfo{
filename: typeFilename,
packageName: typePackageName,
}
result[typeFileInfo] = append(
result[typeFileInfo],
&typeToGenerate{
ID: typeId,
FernFilepath: typeDeclaration.Name.FernFilepath,
TypeDeclaration: typeDeclaration,
},
)
continue
}
result[serviceFileInfo] = append(
result[serviceFileInfo],
result[fileInfo] = append(
result[fileInfo],
&typeToGenerate{
ID: typeDeclaration.Name.TypeId,
FernFilepath: typeDeclaration.Name.FernFilepath,
Expand All @@ -1480,6 +1448,36 @@ func fileInfoToTypes(
return result, nil
}

func shouldSetFileInfoToMatchService(
typeFernFilepath *fernir.FernFilepath,
serviceFernFilepath *fernir.FernFilepath,
) bool {
if serviceFernFilepath.File == nil || typeFernFilepath.File != nil {
// If the service is a root client or the type is already defined
// in a particular non-root package, we can leave it as-is.
return false
}
if !packagePathIsEqual(typeFernFilepath, serviceFernFilepath) {
// We only want to set the file info if the type is defined in the
// same package as the service.
return false
}
filename := serviceFernFilepath.File.SnakeCase.UnsafeName
return !isReservedFilename(filename)
}

func packagePathIsEqual(a, b *fernir.FernFilepath) bool {
if len(a.PackagePath) != len(b.PackagePath) {
return false
}
for i := range a.PackagePath {
if a.PackagePath[i].CamelCase.SafeName != b.PackagePath[i].CamelCase.SafeName {
return false
}
}
return true
}

func fileInfoToErrors(
rootPackageName string,
irErrorDeclarations map[fernir.ErrorId]*fernir.ErrorDeclaration,
Expand Down Expand Up @@ -1615,6 +1613,19 @@ func needsPaginationHelpers(ir *fernir.IntermediateRepresentation) bool {
return false
}

func isReservedFilename(filename string) bool {
_, ok := reservedFilenames[filename]
return ok
}

var reservedFilenames = map[string]struct{}{
"environments.go": struct{}{},
"errors.go": struct{}{},
"file_param.go": struct{}{},
"optional.go": struct{}{},
"pointer.go": struct{}{},
}

// pointerFunctionNames enumerates all of the pointer function names.
var pointerFunctionNames = map[string]struct{}{
"Bool": struct{}{},
Expand Down
10 changes: 10 additions & 0 deletions generators/go/sdk/versions.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
- version: 0.31.0
changelogEntry:
- type: feat
summary: >-
Improves type file layout with zero impact on backwards compatibility.
Shared types are now more accurately placed in the `types.go` file,
whereas types referenced by a single service are now placed in a file
that matches the service's filename (e.g. user.go).
irVersion: 53
- version: 0.30.0
changelogEntry:
- type: feat
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4418,12 +4418,12 @@
"service_imdb": [
"type_imdb:MovieId",
"type_imdb:Movie",
"type_imdb:CreateMovieRequest"
"type_imdb:CreateMovieRequest",
"type_imdb:Cast",
"type_imdb:Name"
]
},
"sharedTypes": [
"type_imdb:Cast",
"type_imdb:Name",
"type_webhooks:User"
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1883,12 +1883,11 @@
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_": [
"type_:TelemetryResponse"
"type_:TelemetryResponse",
"type_:TelemetryData"
]
},
"sharedTypes": [
"type_:TelemetryData"
]
"sharedTypes": []
},
"webhookGroups": {},
"websocketChannels": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1491,11 +1491,11 @@
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_": [
"type_:ExampleResponseStatus",
"type_:ExampleResponse"
]
},
"sharedTypes": [
"type_:ExampleResponseStatus",
"type_:GrantTypeEnum"
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1059,14 +1059,13 @@
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_": [
"type_:GetExampleResponse"
"type_:NotFound",
"type_:GetExampleResponse",
"type_:Schema1",
"type_:Schema2"
]
},
"sharedTypes": [
"type_:NotFound",
"type_:Schema1",
"type_:Schema2"
]
"sharedTypes": []
},
"webhookGroups": {},
"websocketChannels": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3203,12 +3203,11 @@
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_telemetry": [
"type_telemetry:TelemetryGetTelemetryDataResponse"
"type_telemetry:TelemetryGetTelemetryDataResponse",
"type_infra/telemetry:TelemetryData"
]
},
"sharedTypes": [
"type_infra/telemetry:TelemetryData"
]
"sharedTypes": []
},
"webhookGroups": {},
"websocketChannels": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1135,11 +1135,11 @@
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_": [
"type_:AliasType"
"type_:AliasType",
"type_:Parent"
]
},
"sharedTypes": [
"type_:Parent",
"type_:Child"
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4202,21 +4202,21 @@
"variables": [],
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_foo": [
"type_commons:Imported",
"type_foo:ImportingType",
"type_foo:OptionalString"
],
"service_folder-a/service": [
"type_folder-a/service:Response"
"type_folder-a/service:Response",
"type_folder-b/common:Foo",
"type_folder-c/common:FolderCFoo"
],
"service_folder-d/service": [
"type_folder-d/service:Response"
],
"service_foo": [
"type_foo:ImportingType",
"type_foo:OptionalString"
]
},
"sharedTypes": [
"type_commons:Imported",
"type_folder-b/common:Foo",
"type_folder-c/common:FolderCFoo",
"type_foo:FilteredType"
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4818,19 +4818,19 @@
"variables": [],
"serviceTypeReferenceInfo": {
"typesReferencedOnlyByService": {
"service_foo": [
"type_commons:Imported",
"type_foo:ImportingType",
"type_foo:OptionalString"
],
"service_folder-a/service": [
"type_folder-a/service:Response"
],
"service_folder-d/service": [
"type_folder-d/service:Response"
],
"service_foo": [
"type_foo:ImportingType",
"type_foo:OptionalString"
]
},
"sharedTypes": [
"type_commons:Imported",
"type_folder-b/common:Foo",
"type_folder-c/common:Foo"
]
Expand Down
Loading

0 comments on commit 281816e

Please sign in to comment.