accordproject / concerto

Business schema language and runtime
https://concerto.accordproject.org
Apache License 2.0
121 stars 106 forks source link

Define target model element for a decorator #928

Open dselman opened 1 month ago

dselman commented 1 month ago

Feature Request 🛍️

Provide a mechanism to allow the creator of a decorator to indicate (and validate) how it should be used.

Use Case

Decorators are now validated (they must exist and their arguments must be correct) but we do not have a mechanism to ensure that decorators are applied to the correct type of model elements. For example, the author of a decorator may intend that it can be applied to all model elements, only concepts, enumerated values, map keys etc.

Possible Solution

namespace concerto.decorator@1.0.0

/**
 * A decorator that can be applied to decorators to ensure that
 * they are applied to model elements of the correct type
 */
abstract concept Target extends Decorator {
    o String typeFqn optional // the fully-qualified type name of the type that can have this decorator
}

concept TargetDecorator extends Target {} // decorator can only be applied to a decorator!
concept TargetNamespace extends Target {}
concept TargetConcept extends Target {}
concept TargetConceptProperty extends Target {}
concept TargetEnum extends Target {}
concept TargetEnumValue extends Target {}
concept TargetScalar extends Target {}
concept TargetScalarField extends Target {} // decorator can be applied to a scalar the extends a given primitive type
concept TargetMap extends Target {}
concept TargetMapKey extends Target {}
concept TargetMapValue extends Target {}
concept TargetDeclaration extends Target {} // can be applied to any declaration (enum, concept or map)

Example usage (the date decorator should only be added to concept properties or scalars of type DateTime):

import concerto.decorator@1.0.0.{Decorator, TargetConceptProperty, TargetScalarField}
/**
 * Applied to a DateTime property to indicate that only the date portion of the
 * DateTime should be considered for display or computation.
 */
@TargetConceptProperty("DateTime")
@TargetScalarField("DateTime")
concept date extends Decorator {}

Context

Provide increased validation for the correct usage of decorators.

Detailed Description

Extend the concerto.decorators namespace with some "meta decorators" that can be used to indicate to which model elements a decorator applies.

  1. If no decorator targets are found on a decorator then it can be applied to any model element.
  2. If any decorator target is found, then all targets must be listed. An error or warning is raised if a decorator is applied to an unlisted model element.
  3. Extend the decorator validation to check the type of the element that has the decorator applied, generating errors or warning

Note that this feature is similar to the @Target annotation in the Java programming language: https://jenkov.com/tutorials/java/annotations.html

mttrbrts commented 1 month ago

Do we support primitive types as arguments? e.g.

@TargetConceptProperty(DateTime)
@TargetScalarField(DateTime)

Let's mirror the AST hierarchy for the Target definitions. For example,

concept TargetDeclaration extends Target {} 
concept TargetConcept extends TargetDeclaration {}
concept TargetEnum extends TargetDeclaration {}
concept TargetScalar extends TargetDeclaration {}
concept TargetMap extends TargetDeclaration {}

concept TargetProperty extends Target {} 
concept TargetConceptProperty extends TargetProperty {}
concept TargetEnumValue extends TargetProperty {}