Skip to content

Common CMN syntax

Several CMN declarations share descriptions, labels, stereotypes, properties, and references. This page defines those common forms and separates grammar syntax from names supplied by profiles and facilities.

1. Documentation, descriptions and examples

CMN documentation is model input. Generators can use it for API contracts, source comments, diagrams or other target artifacts. It is different from a source-only comment and from a quoted display label.

1.1 Documentation delimiters

A documentation comment can precede many named model elements:

cmn
package com.example.customer

/**
 * A customer visible through the public API.
 */
type Customer {
}

The conventional leading * on each line is optional. CMN also supports rich documentation delimited by triple apostrophes:

cmn
package com.example.customer

'''
A customer visible through the public API.
'''
type Customer {
}

Both forms create the same normalized model documentation. Prefer triple apostrophes for larger structured blocks and /** ... */ for short prose near a declaration.

// ... and ordinary /* ... */ comments are ignored by the model and are suitable for source-only notes. Do not place contract information in them.

The [[ ... ]] form used in component flows is implementation pseudocode, not a general description delimiter. Use it only in grammar positions that accept component commands.

1.2 Plain and explicit descriptions

Text before the first structured marker is the documentation's description:

cmn
package com.example.customer

'''
Customer data exposed through the public API.
'''
type Customer {
}

Use @description when the description should be separated explicitly from other sections. An explicit @description supplies the effective description; it does not append a second description to preceding top-level prose:

cmn
package com.example.customer

'''
Internal authoring note.
@description Customer data exposed through the public API.
'''
type Customer {
}

The public structured section markers are:

MarkerPurpose
@descriptioneffective description of the documented element
@summaryshort operation summary
@titlehuman-readable title where the consuming generator supports one
@requestrequest-specific description and examples
@responsedescription and examples for the operation's primary CMN result

Write section markers without a trailing colon. For example, use @request, not @request:. The colon form remains a deprecated compatibility alias and produces a warning.

1.3 Examples

An example starts with the keyword example, not an @ marker. The shortest form supplies one unnamed value:

cmn
package com.example.customer

'''
Customer identifier.
example: 00000000-0000-4000-8000-000000000001
'''
type CustomerId specialization of String

Put a stable name between example and : when the generated contract should contain a named example:

cmn
package com.example.customer

'''
Customer identifier.
example standard: 00000000-0000-4000-8000-000000000001
'''
type CustomerId specialization of String

Multiline and structured values

A multiline value normally follows directly below example ...:. The value: boundary is optional; omit it when the example has no separate description. This is the usual form for an object request, including an object that contains another complex type:

cmn
package com.example.customer

import org.joinedworkz.facilities.common.base
import org.joinedworkz.facilities.common.base.api

platform Base

type NotificationSettings {
    emailEnabled*: Boolean
    preferredLanguage*: String
}

type Customer {
    id**: String
    displayName*: String
    notificationSettings*: NotificationSettings
}

resource /customers as Customer[] by id {
'''
@request
    example standard:
        {
          "id": "00000000-0000-4000-8000-000000000001",
          "displayName": "Sample Customer",
          "notificationSettings": {
            "emailEnabled": true,
            "preferredLanguage": "en"
          }
        }
'''
    create() consumes=Customer
}

The example text is not required to use JSON. For an application/json contract, however, use valid JSON as above so that the Base Facility can emit a structured OpenAPI value instead of a string.

Use the explicit value: boundary when the same example has a separate indented, possibly multiline description. Text before the boundary is the example description; text after it is the value:

cmn
package com.example.customer

'''
example standard:
    A complete customer object.
    It represents a normal successful request.
    value:
        {
          "id": "00000000-0000-4000-8000-000000000001"
        }
'''
type Customer {
    id: String
}

A short description can alternatively follow the declaration on the same line, with the value on the following lines. The first line is then the description; value: is still unnecessary:

cmn
package com.example.customer

'''
example standard: A complete customer object.
    {
      "id": "00000000-0000-4000-8000-000000000001"
    }
'''
type Customer {
    id: String
}

Examples can be top-level documentation entries or belong to @request and @response. Section markers align with the normal documentation indentation; their descriptions and examples are indented beneath them. A later section marker ends the preceding section.

The primary CMN result is the operation's normal result inherited from its method type or declared by the concrete operation. A target facility can map it to a concrete success status such as 200 or 201. The term does not mean the OpenAPI default: response key.

@example: is a deprecated compatibility alias. New models use example: or example <name>:. An example value remains text in the canonical model. A facility decides how that text maps to its target representation; the Base OpenAPI contract defines the JSON behavior and precedence used by the Base cartridge.

1.4 Where documentation is consumed

The CMN grammar permits documentation on many declarations, but each target facility defines which metadata affects its generated artifacts. The model transformation retains normalized documentation for the public element kinds used by Base, Java and SpringBoot, including types, fields, services, operations, resources, resource methods, responses, components and provided boundaries.

For API-specific placement, see Representations and responses and OpenAPI documentation and examples.

2. Names and labels

Most declarations have an identifier used for references:

cmn
package com.example.customer

type Customer {
}

Some declarations can additionally have a quoted, human-readable label:

cmn
package com.example.customer

type Customer 'Customer account' {
}

Customer is the technical name; 'Customer account' is the label. Whether a generator emits the label is generator-specific.

Resource path segments can contain dashes and are not ordinary model-element identifiers:

cmn
package com.example.customer

resource /customer-accounts {
}

CMN permits selected grammar words as identifiers in unambiguous positions. Avoid relying on that flexibility for public names when a conventional identifier is clearer. See the language-element index for the keyword boundary.

3. Abstract declarations

The grammar permits abstract on packages, simple types, enums, complex types, services, resources, and widgets:

cmn
package com.example.customer

abstract type Party {
}

abstract service PartyService {
}

abstract resource /parties {
}

abstract is a grammar marker whose transfer and generated effect vary by element and facility. Service abstraction is not transferred to the canonical Core Model. Do not assume that an abstract declaration is omitted from output or becomes a target-language base type unless the selected facility documents and verifies that behavior.

Components and applications do not have an abstract position in the grammar.

4. Stereotypes

A stereotype specification follows the element keyword and precedes its name:

cmn
package com.example.customer

import org.joinedworkz.facilities.common.base

platform Base

type<entity> Customer {
    id**: Id
}

The angle brackets are CMN grammar. entity is a stereotype supplied by the Base profile. A stereotype is usable only on element kinds allowed by its profile declaration.

The grammar permits several stereotypes separated by commas and permits ! before an excluded stereotype:

cmn
package com.example.customer

type<first,!second> CustomerView {
}

first and second are illustrative profile-defined names. They are not provided by CMN itself. JoinedWorkz does not transfer every additional or excluded stereotype reliably to the canonical Core Model. Use a single positive stereotype for public, portable models unless a facility explicitly documents another form.

A stereotype specification can also select a model-defined style after /:

text
<stereotype/styleName>

Style declarations and their generated effect are specialized features. The style selection is parser syntax but is not transferred as a general generation contract; do not rely on it for public output.

5. Properties

Many declarations accept properties after their structural syntax:

cmn
package com.example.customer

type Example
    stringValue='text'
    integerValue=42
    decimalValue=-1.5
    booleanValue=true
    missingValue=undefined
    severalValues='first','second'
    °enabled

This example demonstrates grammar forms; the property names are illustrative. A selected profile must define or otherwise support a property before a model can rely on its semantics.

Property values can be:

  • strings in single or double quotes;
  • integers and decimals, including negative values;
  • true or false;
  • references to model elements, optionally with [] or [KeyType] type cardinality;
  • undefined;
  • comma-separated lists of values.

°enabled is a flag with the implicit Boolean value true. The alternate name:=value form marks the value as constant for property processing:

cmn
package com.example.customer

type CustomerNumber specialization of String maxLength:=32

Property placement is defined by the CMN grammar; the name, expected value type, default, inheritance, and generated effect are profile- or facility-defined.

Facility Profiles can also control whether a model property is copied from a type, included field, stereotype, method type or referenced model element. Facility authors can find the advanced contract in Profile-controlled property propagation. This model-property behavior is unrelated to project keys in joinedworkz.properties.

6. Type arguments

Simple types can declare positional arguments by referencing properties:

cmn
package com.example.types

type Text(maxLength) maxLength=1000

A use of the type supplies values in the same order:

cmn
package com.example.customer

type Address {
    street: Text(200)
}

The declaration and call syntax are core CMN. Which arguments a facility-provided type exposes is part of that type's model definition.

7. References

References can resolve:

  • a simple name in the current or an imported package;
  • an alias-qualified name such as shared::Timestamp;
  • a dotted qualified name where that grammar position accepts it.
cmn
package com.example.customer

import com.example.shared as shared

type AuditInfo {
    createdAt: shared::Timestamp
}

Different constructs restrict the referenced element kind. A field type must resolve to a type, a component dependency to a type, service, or component, and a resource method to a resource method type. A syntactically valid name with the wrong target kind is therefore not a valid linked model.

Imports, aliases, and package rules are described in File header & packages.

8. Cardinality and optionality

The absence of an optional grammar fragment is different from model cardinality:

  • optional declaration clauses can be omitted when the grammar permits;
  • without a suffix, no explicit minimum or maximum is stored in the Core Model; current facilities normally treat this as an optional single value;
  • *, [], ranges, and dictionary cardinalities describe occurrence or collection semantics;
  • key ** is a field marker, not a general mandatory marker.

See Complex types for field cardinalities and Resources & method types for resource, parameter, and response cardinalities.