-
Notifications
You must be signed in to change notification settings - Fork 187
/
collapse_cross_group_refs.go
76 lines (63 loc) · 2.84 KB
/
collapse_cross_group_refs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/*
* Copyright (c) Microsoft Corporation.
* Licensed under the MIT license.
*/
package pipeline
import (
"context"
"github.com/pkg/errors"
"github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel"
)
// CollapseCrossGroupReferencesStageID is the unique identifier for this pipeline stage
const CollapseCrossGroupReferencesStageID = "collapseCrossGroupReferences"
// CollapseCrossGroupReferences finds and removes references between API groups. This isn't particularly common
// but does occur in a few instances, for example from Microsoft.Compute -> Microsoft.Compute.Extensions.
func CollapseCrossGroupReferences(idFactory astmodel.IdentifierFactory) *Stage {
return NewStage(
CollapseCrossGroupReferencesStageID,
"Find and remove cross group references",
func(ctx context.Context, state *State) (*State, error) {
resources := astmodel.FindResourceDefinitions(state.Definitions())
result := make(astmodel.TypeDefinitionSet)
for name, def := range resources {
walker := newTypeWalker(idFactory, state.Definitions(), name)
updatedTypes, err := walker.Walk(def)
if err != nil {
return nil, errors.Wrapf(err, "failed walking definitions")
}
for _, newDef := range updatedTypes {
err := result.AddAllowDuplicates(newDef)
if err != nil {
return nil, err
}
}
}
return state.WithDefinitions(result), nil
})
}
func newTypeWalker(
idFactory astmodel.IdentifierFactory,
definitions astmodel.TypeDefinitionSet,
resourceName astmodel.InternalTypeName,
) *astmodel.TypeWalker[any] {
visitor := astmodel.TypeVisitorBuilder[any]{}.Build()
walker := astmodel.NewTypeWalker(definitions, visitor)
walker.AfterVisit = func(original astmodel.TypeDefinition, updated astmodel.TypeDefinition, ctx interface{}) (astmodel.TypeDefinition, error) {
if !resourceName.PackageReference().Equals(updated.Name().PackageReference()) {
newName := astmodel.MakeInternalTypeName(resourceName.InternalPackageReference(), updated.Name().Name())
if existingDef, ok := definitions[newName]; ok {
if !astmodel.TypeEquals(existingDef.Type(), updated.Type()) {
// There exists a type with this name already and it doesn't match this types shape. This is rare
// but happens in a few instances. One example instance is Fleet + AKS which both have a
// UserAssignedIdentity type that have slightly different shapes.
// We disambiguate by including the name of the cross-resource pkg the type came from in the name of the type
disambiguator := idFactory.CreateIdentifier(updated.Name().InternalPackageReference().Group(), astmodel.Exported)
newName = astmodel.MakeInternalTypeName(resourceName.InternalPackageReference(), disambiguator+updated.Name().Name())
}
}
updated = updated.WithName(newName)
}
return astmodel.IdentityAfterVisit(original, updated, ctx)
}
return walker
}