Skip to content
Concerto is a 100% JavaScript schema language and runtime
JavaScript Shell HTML
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github chore(cleanup) Change package.json, README, composer references, etc. Sep 15, 2019
.travis fix(CI) deploy as public package Oct 3, 2019
contrib-notes Fixed some grammatical errors / typos Oct 9, 2019
packages fix(CLI) Print help if no command passed to CLI Oct 12, 2019
scripts chore(*): Move core, tools and cli to monorepo (#69) Sep 26, 2019
.editorconfig Refactor code to make the ModelManager et al a standalone module (#4) Oct 9, 2018
.eslintignore Refactor code to make the ModelManager et al a standalone module (#4) Oct 9, 2018
.eslintrc.yml feat(core): Store remote models on file system (#70) Sep 27, 2019
.gitattributes adding license checking (#3788) Apr 9, 2018
.gitignore Refactor code to make the ModelManager et al a standalone module (#4) Oct 9, 2018
.tern-project Refactor code to make the ModelManager et al a standalone module (#4) Oct 9, 2018
.travis.yml fix(CI) Add code coverage reporting to Travis Build Oct 4, 2019
CHARTER.md (chore) renaming after move from HLF Sep 14, 2019
CONTRIBUTING.md chore(cleanup) Change package.json, README, composer references, etc. Sep 15, 2019
DEVELOPERS.md Fixed lowercase Oct 11, 2019
HEADER chore(cleanup) Change package.json, README, composer references, etc. Sep 15, 2019
HEADER.md chore(license) fixes licchk for markdown Sep 16, 2019
ISSUE_TEMPLATE.md (chore) renaming after move from HLF Sep 14, 2019
LICENSE chore(cleanup) Change package.json, README, composer references, etc. Sep 15, 2019
MAINTAINERS.md (chore) update maintainer list Sep 14, 2019
README.md refactor(README): change README - issue#106 Oct 8, 2019
jsdoc.json (chore) renaming after move from HLF Sep 14, 2019
lerna.json Automatic version bump to 0.81.1 Oct 8, 2019
package-lock.json fix(CLI) Print help if no command passed to CLI Oct 12, 2019
package.json Automatic version bump to 0.81.1 Oct 8, 2019

README.md

Concerto

Build Status Coverage Status GitHub license downloads npm version join slack lerna

Concerto is a lightweight 100% JavaScript schema language and runtime. It works in both a Node.js process and in your browser. The browserified version of Concerto is ±280KB. We are working on making it even smaller.

This is why you should care: https://www.accordproject.org/news/strongly-typed-data-for-javascript-and-beyond/

Things you can do using Concerto:

  • Define an object-oriented model using a domain-specific language that is much easier to read and write than JSON/XML Schema, XMI or equivalents. The metamodel gives you "just enough" expressivity to capture real-world business models, while remaining easy to map to most runtime environments.
  • Optionally edit your models using a powerful VS Code add-on with syntax highlighting and validation
  • Create runtime instances of your model
  • Serialize your instances to JSON
  • Deserialize (and optionally validate) instances from JSON
  • Instances are JS objects so they are easy to pass around your application
  • Introspect the model using a powerful set of APIs
  • Convert the model to other formats: JSON Schema, XML Schema, Java, Go, Typescript, Loopback, PlantUML using concerto-tools.
  • Import models from URLs
  • Publish your reusable models to any website, including the Accord Project Open Source model repository, hosted at: https://models.accordproject.org

Documentation

This mono-repo contains the following packages:

  • concerto-core : core library for model management/parsing/validation/serialization
  • concerto-tools : model converters and tools for Concerto model files
  • concerto-cli : command-line interface for Concerto

Installation

To install the command-line interface:

npm install -g @accordproject/concerto-cli

To install the core model library in your project:

npm install @accordproject/concerto-core --save

To install the tools library in your project:

npm install @accordproject/concerto-tools --save

Create a Concerto File

namespace org.acme.address

/**
 * This is a concept
 */
concept PostalAddress {
  o String streetAddress optional
  o String postalCode optional
  o String postOfficeBoxNumber optional
  o String addressRegion optional
  o String addressLocality optional
  o String addressCountry optional
}

Create a Model Manager

const ModelManager = require('@accordproject/concerto-core').ModelManager;

const modelManager = new ModelManager();
modelManager.addModelFile( concertoFileText, 'filename.cto');

Create an Instance

const Factory = require('@accordproject/concerto-core').Factory;

const factory = new Factory(modelManager);
const postalAddress = factory.newConcept('org.acme.address', 'PostalAddress');
postalAddress.streetAddress = '1 Maine Street';

Serialize an Instance to JSON

const Serializer = require('@accordproject/concerto-core').Serializer;

const serializer = new Serializer(factory, modelManager);
const plainJsObject = serializer.toJSON(postalAddress); // instance will be validated
console.log(JSON.stringify(plainJsObject, null, 4);

Deserialize an Instance from JSON

const postalAddress = serializer.fromJSON(plainJsObject); // JSON will be validated
console.log(postalAddress.streetAddress);

Metamodel

The Concerto metamodel contains:

Namespaces

namespace foo

Every Concerto file starts with the name of a single namespace. All the definitions within a single file therefore belong to the same namespace. The ModelManager will refuse to load two model files that have the same namespace.

Imports

To reference types defined in one namespace in another namespace the types must be imported.

Imports can either be qualified, or can use wildcards.

import org.accordproject.address.PostalAddress
import org.accordproject.address.*

Imports can also use the optional from declaration to import a model files that has been deployed to a URL.

import org.accordproject.address.PostalAddress from https://models.accordproject.org/address.cto

Imports that use a from declaration can be downloaded into the model manager by calling modelManager.updateExternalModels.

The Model Manager will resolve all imports to ensure that the set of declarations that have been loaded are globally consistent.

Concepts

Concepts are similar to class declarations in most object-oriented languages, in that they may have a super-type and a set of typed properties:

abstract concept Animal {
  o DateTime dob
}

concept Dog extends Animal {
 o String breed
}

A concept can be declared abstract is it should not be instantiated (must be subclassed).

Assets

An asset is a class declaration that has a single String property that acts as an identifier. Use the modelManager.getAssetDeclarations API to look up all assets.

asset Vehicle identified by vin {
  o String vin
}

Assets are typically used in your models for the long-lived identifiable Things (or nouns) in the model: cars, orders, shipping containers, products etc.

Participants

A participant is a class declaration that has a single String property that acts as an identifier. Use the modelManager.getParticipantDeclarations API to look up all participants.

participant Customer identified by email {
  o String email
}

Participants are typically used in your models for the identifiable people or organizations in the model: person, customer, company, business, auditor etc.

Transactions

A transaction is a class declaration that has a single String property that acts as an identifier. Use the modelManager.getTransactionDeclarations API to look up all transactions.

transaction Order identified by orderId {
  o String orderId
}

Transactions are typically used in your models for the identifiable business events or messages that are submitted by Participants to change the state of Assets: cart check out, change of address, identity verification, place order etc.

Enumerations & Enumeration Values

Use enumerations to capture lists of domain values.

enum Gender {
  o MALE
  o FEMALE
  o OTHER
  o UNKNOWN
}

Properties and Meta Properties

Class declarations contain properties. Each property has a type which can either be a type defined in the same namespace, an imported type or a primitive type.

Primitive types

Concerto supports the following primitive types:

Type Description
String a UTF8 encoded String.
Double a double precision 64 bit numeric value.
Integer a 32 bit signed whole number.
Long a 64 bit signed whole number.
DateTime an ISO-8601 compatible time instance, with optional time zone and UTZ offset.
Boolean a Boolean value, either true or false.

Meta Properties

Property Description
[] declares that the property is an array
optional declares that the property is not required for the instance to be valid
default declares a default value for the property, if not value is specified
range declares a valid range for numeric properties
regex declares a validation regex for string properties

String fields may include an optional regular expression, which is used to validate the contents of the field. Careful use of field validators allows Concerto to perform rich data validation, leading to fewer errors and less boilerplate application code.

The example below declares that the Farmer participant contains a field postcode that must conform to the regular expression for valid UK postcodes.

participant Farmer extends Participant {
    o String firstName default="Old"
    o String lastName default="McDonald"
    o String address1
    o String address2
    o String county
    o String postcode regex=/(GIR 0AA)|((([A-Z-[QVf]][0-9][0-9]?)|(([A-Z-[QVf]][A-Z-[IJZ]][0-9][0-9]?)|(([A-Z-[QVf]][0-9][A-HJKPSTUW])|([A-Z-[QVf]][A-Z-[IJZ]][0-9][ABEHMNPRVWfY])))) [0-9][A-Z-[CIKMOV]]{2})/
}

Double, Long or Integer fields may include an optional range expression, which is used to validate the contents of the field.

The example below declared that the Vehicle asset has an Integer field year which defaults to 2016 and must be 1990, or higher. Range expressions may omit the lower or upper bound if checking is not required.

asset Vehicle extends Base {
  // An asset contains Fields, each of which can have an optional default value
  o String model default="F150"
  o String make default="FORD"
  o String reg default="ABC123"
  // A numeric field can have a range validation expression
  o Integer year default=2016 range=[1990,] optional // model year must be 1990 or higher
  o Integer[] integerArray
  o State state
  o Double value
  o String colour
  o String V5cID regex=/^[A-z][A-z][0-9]{7}/
  o String LeaseContractID
  o Boolean scrapped default=false
  o DateTime lastUpdate optional
  --> Participant owner //relationship to a Participant, with the field named 'owner'.
  --> Participant[] previousOwners optional // Nary relationship
  o Customer customer
}

Relationships

A property of a class may be declared as a relationship using the --> syntax instead of the o syntax. The o syntax declares that the class contains (has-a) property of that type, whereas the --> syntax declares a typed pointer to an external identifiable instance.

This model declares that an Order has-an array of OrderLine concepts. When the Order is deleted all the OrderLines will also be deleted.

concept OrderLine {
  o String sku
}
asset Order identified by orderId {
  o String orderId
  o OrderLine[] orderlines
}

Whereas this model declares that an Order has-an array of reference to OrderLines. Deleting the Order has no impact on the OrderLine. When the Order is serialized the JSON only the IDs of the OrderLines are stored within the Order, not the OrderLines themselves.

asset OrderLine identified by orderLineId {
  o String orderLineId
  o String sku
}

asset Order identified by orderId {
  o String orderId
  --> OrderLine[] orderlines
}

A relationship is a tuple composed of:

The namespace of the type being referenced The type name of the type being referenced The identifier of the instance being referenced

Hence a relationship could be to: org.example.Vehicle#123456

This would be a relationship to the Vehicle type declared in the org.example namespace with the identifier 123456.

Relationships are unidirectional and deletes do not cascade, ie. removing the relationship has no impact on the thing that is being pointed to. Removing the thing being pointed to does not invalidate the relationship.

Relationships must be resolved to retrieve an instance of the object being referenced. The act of resolution may result in null, if the object no longer exists or the information in the relationship is invalid. Resolution of relationships is outside of the scope of the Model Manager.

Decorators

Model elements may have arbitrary decorators (aka annotations) placed on them. These are available via API and can be useful for tools to extend the model.

@foo("arg1", 2)
asset Order identified by orderId {
  o String orderId
}

Decorators have an arbitrary number of arguments. They support arguments of type:

  • String
  • Boolean
  • Number
  • 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.

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:

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

License

Accord Project source code files are made available under the Apache License, Version 2.0. Accord Project documentation files are made available under the Creative Commons Attribution 4.0 International License (CC-BY-4.0).

Copyright 2018-2019 Clause, Inc. All trademarks are the property of their respective owners. See LF Projects Trademark Policy.

You can’t perform that action at this time.