fileConstraint
Declares a constraint over the files the block around it matched.
The block is stored, not evaluated: it runs when a check that evaluates constraints runs, against the files the one walk of the project found. Building architecture { } therefore reads nothing and runs nothing, the same way layout { } is deferred.
Example 1: a constraint written by hand, without any backend
"UseCase" {
fileConstraint("leaves no TODO") { subject ->
subject.files.filter { it.endsWith(".kt") }.map { FileConstraintFailure(it) }
}
layout { "core/domain/useCase" { "*UseCase.kt".file() } }
}Example 2: point the report somewhere other than the calling line
"UseCase" {
fileConstraint("has an invoke function", DeclarationSite("DomainRules.kt", 12)) { subject ->
emptyList()
}
layout { "core/domain/useCase" { "*UseCase.kt".file() } }
}Parameters
what to call it, shown in the report next to the role. null means it is named by its declaration site alone. It must hold at least one non-whitespace character and no line break, because it is printed on one line of a report block.
where to point the report at. The default is the first stack frame outside me.tbsten.katachi.*, which is the line that called this. A wrapper of your own has to pass its own caller's site, or every report points at the wrapper.
how far below the surrounding directory block it reaches. FileConstraintRange.Subtree, the default, covers the whole subtree; FileConstraintRange.DirectOnly covers only the files the block declares directly.
what to ask of the covered files.
Throws
when name is blank or holds a line break.
when scope is FileConstraintRange.DirectOnly somewhere with no directory of its own: directly on a role, directly under layout { }, or in ":".module { }.
when scope is FileConstraintRange.DirectOnly and the block declares no file directly, so the constraint could never see one.