Skip to content

Commit

Permalink
Add support for 'ref' annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
nimrodshn committed Dec 3, 2024
1 parent 30081e9 commit b8b62a0
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 0 deletions.
14 changes: 14 additions & 0 deletions pkg/annotations/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,17 @@ func GoName(concept concepts.Annotated) string {
}
return fmt.Sprintf("%s", name)
}

// Reference checks if the given concept has a `reference` annotation. If it has it then it returns the value
// of the `path` parameter. It returns an empty string if there is no such annotation or parameter.
func ReferencePath(concept concepts.Annotated) string {
annotation := concept.GetAnnotation("ref")
if annotation == nil {
return ""
}
name := annotation.FindParameter("path")
if name == nil {
return ""
}
return fmt.Sprintf("%s", name)
}
103 changes: 103 additions & 0 deletions pkg/language/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

"github.com/antlr/antlr4/runtime/Go/antlr"

"github.com/openshift-online/ocm-api-metamodel/pkg/annotations"
"github.com/openshift-online/ocm-api-metamodel/pkg/concepts"
"github.com/openshift-online/ocm-api-metamodel/pkg/names"
"github.com/openshift-online/ocm-api-metamodel/pkg/nomenclator"
Expand Down Expand Up @@ -421,6 +422,47 @@ func (r *Reader) ExitClassDecl(ctx *ClassDeclContext) {
// Add the annotations:
r.addAnnotations(typ, ctx.GetAnnotations())

if path := annotations.ReferencePath(typ); path != "" {
if len(r.inputs) > 1 {
panic("refernced service with multiple inputs in undefined")
}

if r.service.Versions().Len() > 1 {
panic("cannot infer which version to add reference with multiple versions")
}

input := r.inputs[0]
currVersion := r.service.Versions()[0]
path = strings.TrimPrefix(path, "/")
components := strings.Split(path, "/")
referencedServiceName := components[0]
referencedVersion := components[1]
referencedType := components[2]

// Create an ad-hoc reader and model for the specific referenced service.
refReader := NewReader().
Reporter(r.reporter)
refReader.model = concepts.NewModel()

// Initialize the indexes of undefined concepts:
refReader.undefinedTypes = make(map[string]*concepts.Type)
refReader.undefinedResources = make(map[string]*concepts.Resource)
refReader.undefinedErrors = make(map[string]*concepts.Error)

// load the ad-hoc service and version referenced and find the correct locator.
refReader.loadService(fmt.Sprintf("%s/%s", input, referencedServiceName))
refVersion := refReader.service.FindVersion(names.ParseUsingSeparator(referencedVersion, "_"))
for _, currType := range refVersion.Types() {
if strings.Compare(currType.Name().String(), referencedType) == 0 {
for _, attributes := range currType.Attributes() {
currVersion.AddType(attributes.Type())
}
currVersion.AddType(currType)
return
}
}
}

// Add the attributes:
memberCtxs := ctx.GetMembers()
if len(memberCtxs) > 0 {
Expand Down Expand Up @@ -737,6 +779,67 @@ func (r *Reader) ExitLocatorDecl(ctx *LocatorDeclContext) {
// Add the annotations:
r.addAnnotations(locator, ctx.GetAnnotations())

if path := annotations.ReferencePath(locator); path != "" {
if len(r.inputs) > 1 {
panic("refernced service with multiple inputs in undefined")
}

if r.service.Versions().Len() > 1 {
panic("cannot infer which version to add reference with multiple versions")
}

input := r.inputs[0]
currVersion := r.service.Versions()[0]
path = strings.TrimPrefix(path, "/")
components := strings.Split(path, "/")
referencedServiceName := components[0]
referencedVersion := components[1]
referencedLocator := components[2]

// Create an ad-hoc reader and model for the specific referenced service.
refReader := NewReader().
Reporter(r.reporter)
refReader.model = concepts.NewModel()

// Initialize the indexes of undefined concepts:
refReader.undefinedTypes = make(map[string]*concepts.Type)
refReader.undefinedResources = make(map[string]*concepts.Resource)
refReader.undefinedErrors = make(map[string]*concepts.Error)

// load the ad-hoc service and version referenced and find the correct locator.
refReader.loadService(fmt.Sprintf("%s/%s", input, referencedServiceName))
refVersion := refReader.service.FindVersion(names.ParseUsingSeparator(referencedVersion, "_"))
for _, currLocator := range refVersion.Root().Locators() {
if strings.Compare(currLocator.Name().String(), referencedLocator) == 0 {
for _, resource := range refVersion.Resources() {
if resource.IsRoot() {
// We do not need to copy over the root resource.
continue
}

// Add any underlying resource to the current version.
currVersion.AddResource(resource)
// Add underlying methods.
for _, method := range resource.Methods() {
currVersion.
FindResource(resource.Name()).
AddMethod(method)
}

// Remove any undefined resources as
// This is a no-op except for the reference target added
// by the locator as the compiler will attempt to compile it
r.removeUndefinedResource(resource)
}

currVersion.AddTypes(refVersion.Types())
locator = currLocator
ctx.SetResult(locator)
return
}
}
}

// Add the members:
membersCtxs := ctx.GetMembers()
if len(membersCtxs) > 0 {
Expand Down

0 comments on commit b8b62a0

Please sign in to comment.