Configuration¶
This section provides details on how to configure tasks and plugin settings, how the schema works, default values and more.
YAML?
Amper currently uses "Amper-flavored" YAML as the configuration language. YAML is flexible, and it allowed us to move fast with prototyping solutions, plugins included. However, we are aware of YAML's shortcomings and are exploring the possibility of replacing YAML with a custom language tailored for our needs in the future.
Configurable types¶
Configurable types are types that Amper allows in plugin and task configurations. Their values are set in YAML configurations, and used in Kotlin task actions.
The following table lists the configurable types and their Kotlin and YAML representations:
| Amper type | Kotlin type | YAML structure |
|---|---|---|
string |
kotlin.String |
scalar |
boolean (true | false) |
kotlin.Boolean |
scalar |
integer |
kotlin.Int |
scalar |
path |
java.nio.file.Path |
scalar |
enum E |
enum class E |
scalar |
sequence [T] |
kotlin.collections.List<T> |
sequence |
mapping {string : T} |
kotlin.collections.Map<String, T> |
mapping/sequence of pairs |
object T |
@Configurable interface T |
mapping + others |
T | null |
T? |
"null" scalar |
Task action parameters and properties in @Configurable interfaces are only allowed to be of configurable types.
Note
Currently, any custom configurable type — for example, a @Configurable interface or an enum —
defined in plugin A cannot be reused in plugin B, even if the module of plugin A has module B as its dependency.
The tool will issue an "Unexpected schema type" diagnostic.
This restriction may be lifted in the future.
There are also built‑in variant types, but the mechanism is not yet allowed in user code.
Configurable interfaces¶
A configurable interface is a public Kotlin interface annotated with the @Configurable annotation.
Restrictions apply to this interface:
- methods, superinterfaces, generics are not allowed
- it may only have immutable non-extension (
val) properties of the configurable types. Such a property may have a default getter implementation, depending on a type. - See the defaults section.
@Configurable
interface MySettings {
/**
* Note: KDocs on configurable entities are visible to the tooling
*/
val booleanSetting: Boolean
val intSetting: Int
val stringSetting: String
val nested: Nested
val pathSetting: Path
val mapSetting: Map<String, String>
val listSetting: List<Nested>
}
@Configurable
interface Nested {
val enumSetting: MyEnum
val nullableStringSetting: String?
}
enum class MyEnum { Hello, Bye }
Plugin settings¶
A @Configurable interface may be specified in a plugin's module.yaml to expose it as user‑facing plugin settings:
pluginInfo:
settingsClass: com.example.MyPluginSettings
The property with the name enabled is reserved in such interfaces.
Then the object with this type (e.g., com.example.MyPluginSettings | null) becomes available under plugins.<plugin-id>
in every module in the project.
An additional synthetic boolean enabled shorthand property is present in the object to control
if the plugin is applied to the module or not.
Enums¶
Generally, any enum is allowed in the configuration. You may want to specify custom names for the enum constants to be
used in configuration, using the @EnumValue annotation.
Otherwise, the name of the entry is used in the configuration.
enum class MyEnum {
Hello,
@EnumValue("byeBye")
Bye,
}
myEnum1: Hello
myEnum2: byeBye
Default values¶
Properties and task action parameters are allowed to have default values specified in Kotlin.
Properties use default getter implementation syntax. The getter must have an expression body:
@Configurable interface Settings {
val myBoolean get() = false
val myString get() = "default"
}
Task parameters use the regular default value syntax:
@TaskAction fun myAction(
myBoolean = false,
myString = "default",
) { /*...*/ }
| Amper type | Supported explicit default values |
|---|---|
string, boolean, integer |
Kotlin constant expression of the appropriate type |
enum E |
enum constant references, e.g., E.Constant |
path |
not supported yet |
sequence [T] |
emptyList() |
mapping {string : T} |
emptyMap() |
T | null |
null (not required - implicit default) |
object T |
not supported (instantiated implicitly, see the note) |
Note
Properties of @Configurable interface types can't have explicit defaults specified.
However, all objects are instantiated by default using their default values and the values
provided at the configuration (YAML) side. If some required (with no default at all) values remain
unconfigured, then the error is issued and the configuration is rejected.
Advanced¶
Info
Although these features are present in the typing/configuration system and are used in some built‑in APIs, they are not yet ready to be used by plugin authors in their own Kotlin code.
You may read the following sections at your leisure if you seek to better understand how dependency notation, task actions or "short forms" work in Amper.
Shorthand notation¶
Some built‑in @Configurable interfaces, e.g., Classpath, allow the "shorthand" notation.
They have a property marked with the @Shorthand internal annotation.
This enables objects of the type to be constructed in a "short" form: not from the YAML mapping, but from the
value of the type that the shorthand property has. Other properties are then set to their default values.
For example, classpath: [ "foo:bar:1.0" ] is a short form of
classpath:
dependencies: [ "foo:bar:1.0" ]
dependencies property is marked as a "shorthand".
Warning
Shorthands do not currently work with references.
E.g., if there's a property foo of the sequence[Dependency] type,
then classpath: ${foo} will not work. So, the expanded form classpath: { dependencies: ${foo} } is
required.
The special case for the shorthand notation is when the shorthand property is a boolean.
Then, instead of the true keyword, one needs to write the property name itself, e.g., enabled.
For example, plugin settings have an implicit synthetic enabled property which is a shorthand.
Variant types¶
On the Kotlin side they are modeled as a @Configurable sealed interface.
When a variant type is expected, there is a need to express which exact variant is being provided in the configuration.
This ability to express the exact type is not yet well-designed in Amper and generally looks unintuitive in YAML.
So for the built‑in Dependency { Local, Maven } variant type Amper infers the type based on the @DependencyNotation string contents:
- if the dependency string starts with the
.it is a local dependency - otherwise it is a Maven dependency
Task action types¶
Technically, task's action property also has a variant type.
This type is synthetic, and its variants are also synthetic types
that are based on all the signatures of all the @TaskAction functions in the plugin,
so all the task parameters become properties with the correspodning types.
And in this case an explicit YAML type tag is required to communicate the exact type.