** Use to add ordering constraints to service configurations.
**
** Constraints are keys of other contributions that this contribution must appear before or after.
**
** pre>
** syntax: fantom
** config["Breakfast"] = eggs
** config["Dinner"] = pie
** ...
** config.set("Lunch", ham).after("breakfast").before("dinner")
** <pre
**
** Constraints become very powerful when used across multiple modules and pods.
@Js
mixin Constraints {
** Specify a key your contribution should appear *before*.
**
** This may be called multiple times to add multiple constraints.
abstract This before(Obj key, Bool optional := false)
** Specify a key your contribution should appear *after*.
**
** This may be called multiple times to add multiple constraints.
abstract This after(Obj key, Bool optional := false)
}
@Js
internal class Contrib : Constraints {
Obj key; Obj? val; Obj? existingKey
Bool unordered
ContribCont[]? befores; ContribCont[]? afters
new make(Obj key, Obj? val, Obj? existingKey := null) {
this.key = key
this.val = val
this.existingKey = existingKey
}
Obj keyFudge() {
existingKey ?: key
}
override This before(Obj key, Bool optional := false) {
if (befores == null)
befores = ContribCont[,]
befores.add(ContribCont(key, optional))
return this
}
override This after(Obj key, Bool optional := false) {
if (afters == null)
afters = ContribCont[,]
afters.add(ContribCont(key, optional))
return this
}
Void findImplied(Obj:Contrib contribs) {
if (!unordered)
return
i := contribs.keys.index(key)
implied := contribs.vals[0..<i].reverse.find { it.unordered }
if (implied == null)
return
if (afters == null)
afters = ContribCont[,]
afters.add(ContribCont(implied.key, false))
}
Void finalise() {
unordered = (befores == null && afters == null)
}
override Str toStr() {
"[$key:$val].before($befores).after($afters)"
}
}
@Js
internal class GroupConstraints : Constraints {
Contrib[] contribs
new make(Contrib[] contribs) {
this.contribs = contribs
}
override This before(Obj key, Bool optional := false) {
contribs.each { it.before(key, optional) }
return this
}
override This after(Obj key, Bool optional := false) {
contribs.each { it.after(key, optional) }
return this
}
}
@Js
internal class ContribCont {
Obj key
Bool optional
new make(Obj key, Bool optional) {
this.key = key
this.optional = optional
}
override Str toStr() { key.toStr }
}