File header & packages
A CMN file can declare a root package and layer, imports, and a platform before its nested packages and model elements. Project models should normally use a named package and an explicit platform.
Complete header example
api package com.example.customer
import org.joinedworkz.facilities.common.base
import org.joinedworkz.facilities.common.base.api
platform Base
subpackage view {
type CustomerView {
id*: Id
name*: Name
}
}
type Customer {
id**: Id
name*: Name
}The order is fixed:
- optional root package declaration;
- zero or more imports;
- optional platform declaration;
- zero or more nested package blocks;
- root-package model elements.
Nested packages cannot be interleaved with root-package model elements.
1. Root package
package com.example.customerThe package is the technical namespace of the elements declared directly in the model. A qualified package name consists of dot-separated identifiers.
The grammar permits a file without a named root package. This is useful as a container for absolute nested package blocks, but ordinary project models should declare their package explicitly:
package com.example.customer {
type Customer {
}
}
package com.example.order {
type Order {
}
}These two package blocks are absolute: their effective names are com.example.customer and com.example.order.
The grammar also accepts abstract before a root or nested package declaration. JoinedWorkz does not define one universal public generation effect for an abstract package; use it only when the selected facility documents the intended behavior.
Package properties
Properties can follow a package name:
api package com.example.customer vendorSpecificMimeType=trueThe property slot is part of the CMN grammar. vendorSpecificMimeType and its effect are defined by the active platform and generator, not by the package grammar. See Common syntax and the relevant facility reference before adding package properties.
Nested package and subpackage blocks inherit applicable package properties that they do not declare themselves. If the same property occurs at more than one package level, the concrete package wins, followed by its nearest parent and then more distant parents. JoinedWorkz applies this most-specific-first rule consistently; see the upgrade note when migrating models with conflicting parent and subpackage values.
The generic generator defines finalized=true on a root model as an advanced boundary for additional processing through imports. It does not prevent that model from being generated normally with its own Platform. See Finalizing additional import processing.
2. Package uniqueness
Every effective package name must be unique within the model space processed by JoinedWorkz. This applies to root packages in different .cmn files and to nested packages. Do not distribute one package across several model files.
A layer is not part of the package identity and cannot distinguish duplicate package names. During a Maven build, JoinedWorkz checks source and dependency models before generation. A collision stops the build with CMN_DUPLICATE_PACKAGE and reports the conflicting locations; JoinedWorkz does not merge their declarations.
3. Layers
A layer is a free identifier immediately before package:
api package com.example.customerThere is no layer keyword. Names such as core, api, or backend are ordinary identifiers, not a fixed CMN registry.
The declared layer normally becomes the source tag used for outlet routing. A generator can assign a different source tag to a particular generated output. If it does, outlet lookup uses that generator-assigned tag; it does not retry the lookup with the CMN package layer. Facilities can also give selected layer names semantics beyond routing. These are generator or facility rules and must be documented by that facility.
Relative subpackages inherit the layer of their parent because subpackage has no independent layer position.
4. Relative and absolute nested packages
A relative subpackage uses subpackage:
package com.example.customer
subpackage api {
subpackage v1 {
type CustomerV1 {
}
}
type CustomerView {
}
}The effective names are com.example.customer.api and com.example.customer.api.v1. A relative subpackage requires a named parent; otherwise validation reports subpackageWithoutNamedParent.
A nested package declaration remains absolute, even below a named root:
package com.example.customer
package com.example.shared {
type SharedValue {
}
}SharedValue belongs to com.example.shared, not to com.example.customer.com.example.shared. Imports and the platform are declared on the root model and apply to its nested packages.
5. Imports
Imports expose model elements from another package:
import org.joinedworkz.facilities.common.base
import org.joinedworkz.facilities.common.base.apiThe first Base package supplies common types such as String and Id; the second supplies resource method types such as read and create. These names are model elements contributed by the facility, not built-in primitive tokens or CMN keywords.
An import can itself carry properties. The generic generator defines finalized=true to skip additional Cartridge processing through that import; the package remains visible for references. Other import-property meanings must be documented by the selected profile or facility. See Finalizing additional import processing.
Importing a CMN package makes its elements available for references. It does not select a platform; platform selection is a separate declaration.
The imported package remains a separate model with its own namespace, source, validation unit and Platform selection, if present. In an advanced composition, the importing model's Platform can contribute active Cartridge processing without merging the models. See Imported model processing and diagnostics.
6. Aliases and references
An import can define a single-identifier alias:
import com.example.shared as sharedUse the alias before :::
type AuditInfo {
createdAt: shared::Timestamp
}Without an alias, an unambiguous imported element can be referenced by its simple name. Dotted fully qualified references are supported in grammar positions that accept qualified names:
type AuditInfo {
createdAt: com.example.shared.Timestamp
}Do not place a dotted package name before ::; that prefix position is for an alias. Some specialized grammar positions accept only a simple or alias-qualified reference, so use imports and aliases for portable models.
7. Platform selection
platform BaseThe platform determines which profile context and cartridge applications interpret the current model. Platform selection also defines which stereotypes, properties, outlets, and conventions are available.
Base, Java, and SpringBoot are stable public platforms. Quasar is an experimental public platform. Platform names are profile-defined references, not hard-coded CMN keywords beyond the platform declaration itself.
The grammar permits platform properties after the platform reference. Their names and effects are profile-defined; there is no universal set of CMN platform properties.
Excluding cartridges
One or more cartridges can be excluded for the model:
platform Base exclude OpenApiCartridgeplatform Base exclude OpenApiCartridge, DiagramCartridgeThe cartridge names come from the selected profile. An explicit CMN exclusion takes precedence over project configuration that would otherwise enable that cartridge. Nested packages use the platform and exclusions of their root model.
