Skip to content

Commit

Permalink
feat(decorators): improve docs (#61)
Browse files Browse the repository at this point in the history
* feat(decorators): improve docs

Signed-off-by: Dan Selman <[email protected]>
  • Loading branch information
dselman authored Oct 10, 2024
1 parent b249688 commit 8ff0ca1
Show file tree
Hide file tree
Showing 7 changed files with 2,460 additions and 1,422 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

strategy:
matrix:
node-version: [16.x]
node-version: [20.x]

steps:
- name: Checkout code
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20.14.0
Empty file added docs/api/ref-js-api.md
Empty file.
54 changes: 42 additions & 12 deletions docs/design/decoratorcommands.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar_position: 7

Decorator Command Sets are an advanced feature that allow you to externalize the definition of decorators from your model into a JSON file, and then to programmatically apply the Decorator Commands to a model at runtime, to produce a newly decorated model.

Decorator Commands can add/update/remove decorators to targeted elements in the model: concepts, properties etc.
Decorator Commands can add/update/remove decorators to targeted elements in the model: namespace, concepts, properties etc.

Decorator Command Sets are useful to dynamically decorate your models, keeping the models clean, whilst exposing decorated model elements to clients.

Expand All @@ -15,15 +15,33 @@ For example, you can decorate a model with [Vocabulary](/docs/design/vocabulary)
```js
// generate decorators for the 'en-GB' locale
const commandSet = vocabularyManager.generateDecoratorCommands(modelManager, 'en-GB');
// apply to the model
const newModelManager = DecoratorManager.decorateModels( modelManager, commandSet);

// decorator the models, using the default namespace [email protected] for decorator
// commands that do not supply an explicit namespaces for their decorators
const newModelManager = DecoratorManager.decorateModels(modelManager, commandSet,
{
validate: true, validateCommands: true,
migrate: true,
defaultNamespace: '[email protected]'
});
```

Sample input model to decorate:

```js
namespace test
namespace test@1.0.0

// declare decorator commands
import [email protected]
concept New extends Decorator {}
concept Editable extends Decorator {}
concept Custom extends Decorator {}
concept Form extends Decorator {
o String key
o String value
}

// define model and use decorators
@Editable
concept Person {
@Custom
Expand Down Expand Up @@ -56,20 +74,21 @@ Definition of Decorator Command Set:

```json
{
"$class" : "org.accordproject.decoratorcommands.DecoratorCommandSet",
"$class" : "org.accordproject.decoratorcommands@0.4.0.DecoratorCommandSet",
"name" : "web",
"version": "1.0.0",
"commands" : [
{
"$class" : "org.accordproject.decoratorcommands.Command",
"$class" : "org.accordproject.decoratorcommands@0.4.0.Command",
"type" : "UPSERT",
"target" : {
"$class" : "org.accordproject.decoratorcommands.CommandTarget",
"$class" : "org.accordproject.decoratorcommands@0.4.0.CommandTarget",
"type" : "[email protected]"
},
"decorator" : {
"$class" : "[email protected]",
"name" : "Form",
"namespace" : "[email protected]",
"arguments" : [
{
"$class" : "[email protected]",
Expand All @@ -83,30 +102,32 @@ Definition of Decorator Command Set:
}
},
{
"$class" : "org.accordproject.decoratorcommands.Command",
"$class" : "org.accordproject.decoratorcommands@0.4.0.Command",
"type" : "APPEND",
"target" : {
"$class" : "org.accordproject.decoratorcommands.CommandTarget",
"$class" : "org.accordproject.decoratorcommands@0.4.0.CommandTarget",
"type" : "[email protected]"
},
"decorator" : {
"$class" : "[email protected]",
"name" : "New",
"namespace" : "[email protected]",
"arguments" : []
}
},
{
"$class" : "org.accordproject.decoratorcommands.Command",
"$class" : "org.accordproject.decoratorcommands@0.4.0.Command",
"type" : "UPSERT",
"target" : {
"$class" : "org.accordproject.decoratorcommands.CommandTarget",
"$class" : "org.accordproject.decoratorcommands@0.4.0.CommandTarget",
"namespace" : "test",
"declaration" : "Person",
"property" : "bio"
},
"decorator" : {
"$class" : "[email protected]",
"name" : "Form",
"namespace" : "[email protected]",
"arguments" : [
{
"$class" : "[email protected]",
Expand All @@ -126,7 +147,16 @@ Definition of Decorator Command Set:
Model file with decorators applied (output):

```js
namespace test
namespace test@1.0.0
import [email protected]

concept New extends Decorator {}
concept Editable extends Decorator {}
concept Custom extends Decorator {}
concept Form extends Decorator {
o String key
o String value
}

@Editable
concept Person {
Expand Down
78 changes: 71 additions & 7 deletions docs/design/specification/model-decorators.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,91 @@ title: Decorators
sidebar_position: 6
---

Model elements may have arbitrary decorators (aka annotations) placed on them. These are available via API and can be useful for tool vendors to extend the metamodel.
Model elements may have arbitrary decorators (aka annotations) placed on them. These are available via API and can be useful for tool vendors to extend the metamodel, or to add application specific metadata to a model.

A decorator on a namespace:

```
@Hide
namespace [email protected]
```

A decorator on a concept:

```
namespace [email protected]
@Hide
concept Person {
}
```

A decorator on a property of a concept:

```
namespace [email protected]
concept Person {
@Hide
o String ssn
}
```

The structure of decorators is declared by extending the system defined `[email protected]` concept.

```js
@foo("arg1", 2)
// declare the decorator
import [email protected]
concept Hide extends Decorator {
o Boolean hidden optional
}

// use the decorator
@Hide(false)
asset Order identified by orderId {
o String orderId
}
```

Decorators have an arbitrary number of arguments. They support arguments of type:
Decorators have a list of an arbitrary number of arguments. The support arguments types are:
- String
- Boolean
- Number
- Number (Integer, Long, Double)
- Type reference

Resource definitions and properties may be decorated with 0 or more decorations. Note that only a single instance of a decorator is allowed on each element type. I.e. it is invalid to have the @bar decorator listed twice on the same element.
Resource definitions and properties may be decorated with 0 or more decorations. Note that only a single instance of a decorator is allowed on each element type. I.e. it is invalid to have the `@Hide` decorator listed twice on the same element.

Decorators are accessible at runtime via the `ModelManager` introspect APIs. This allows tools and utilities to use Concerto to describe a core model, while decorating it with sufficient metadata for their own purposes.

The example below retrieves the 3rd argument to the foo decorator attached to the myField property of a class declaration:
The example below retrieves the 3rd argument to the `@Hide` decorator attached to the `myField` property of a class declaration:

```js
const val = myField.getDecorator('foo').getArguments()[2];
const val = myField.getDecorator('Hide').getArguments()[2];
```

## Decorator Validation

The ModelManager supports (optional) decorator validation, enforcing that decorators are declared and that the arguments to a decorator matches its declaration.

To configure the ModelManager with decorator validation:

```js
validatedModelManager = new ModelManager({
strict: true, decoratorValidation: {
missingDecorator: 'error',
invalidDecorator: 'error'
}
});
```

The `missingDecorator` option is used to control the validation behavior if an undeclared decorator is used on a model element. While the `invalidDecorator` option controls the validation of decorator aguments. Using these two options the ModelManager can be configured to log warning messages for missing decorators, while producing errors for invalid usage of declared decorators, or other scenarios.

Both the `missingDecorator` and `invalidDecorator` options can be `undefined` (to switch off validation) or may be one of the defined log levels: `error, warn, info` etc. If the log level is set to `error` then a log message will be output and an exception is thrown, ensuring that only valid decorators may be used in the model.

## Vocabulary Manager

The `VocabularyManager` can be used to decorate a model with `@Term` decorations, generated from a Vocabulary.

## Decorator Manager

The `DecoratorManager` is used to externalize decorators from models into JSON Decorator Command Set files, and then to dynamically apply them back onto a `ModelManager`.
Loading

0 comments on commit 8ff0ca1

Please sign in to comment.