LayoutScope

Receiver of layout { }, and of every directory block inside it.

Directly under layout { } the paths are relative to the project root, so a file that belongs to no module is written there as it is.

A key is read one way only: "..." { } is a directory, and a file is always written with one of the file functions. A key may itself spell out several levels ("app/ios" { }), which is the same as nesting one block per level.

LayoutDirectoryScope adds the three things that only make sense inside a directory: description, anyFile() and ignore().

The vocabulary this interface does not hold

What is declared here is the whole of the core: a directory, a file, /, stopping the check, and a named wildcard (capture("...")). Everything else katachi offers — "...".ktFile(), and the Gradle vocabulary ("...".module { }, mainSourceSet, kotlin, modulePackage, wildcards, wildcard("...")) — is written on top of it, as functions that take this scope as a context parameter:

context(layoutScope: LayoutScope)
public fun String.ktFile(): LayoutFile {
val name = this
return with(layoutScope) { "$name.kt".file() }
}

A member extension cannot be added to an interface from the outside, so anything declared here would be katachi's to write and nobody else's. Declared as above, katachi's own utilities and a project's are the same kind of thing and read the same way at the call site. A project that wants "...".protoFile() or featureSources() writes it exactly like the function above, in its own package.

The Gradle vocabulary lives in me.tbsten.katachi.dsl.gradle and is imported as import me.tbsten.katachi.dsl.gradle.*.

What a layout says beyond where files live

FileConstraintScope comes with this one, so fileConstraint { } can be written in any block of a layout { }. What it covers is the block it was written in: the entries of that subtree and nothing else. See FileConstraintScope.fileConstraint.

Example 1: Declaring a file directly under the project root, and a nested one

layout {
".gitignore".file() // <root>/.gitignore
"gradle" { "libs.versions.toml".file() } // <root>/gradle/libs.versions.toml
"src" / "main" / "kotlin" / "*.kt".file() // the same thing, nested with `/`
}

Inheritors

Properties

Link copied to clipboard

currentWildcards by the names the module key gave them, or null outside a module block and inside one whose key named nothing.

Link copied to clipboard

The module this scope is being evaluated for, as katachi prints it (":feature:home"), or null directly under layout { } and inside a plain directory block.

Link copied to clipboard

What the module path's wildcards captured for the module being evaluated, or null outside a module block, where there is no module path to have captured anything.

Functions

Link copied to clipboard
abstract fun capture(name: String): String

Names a wildcard: a marker capture("feature") embeds in a layout key, read back out wherever the key is used and replaced with a plain * before the check ever sees it.

abstract fun capture(name: String, block: LayoutDirectoryScope.() -> Unit): LayoutDirectory

capture opened as a block: capture("feature") { ... } is capture("feature").invoke { ... }, the same String.invoke a whole-level key opens with.

Link copied to clipboard
abstract operator fun String.div(child: String): LayoutDirectory

"src" / "main" is the same as "src" { "main" { } }.

abstract operator fun String.div(child: LayoutDirectory): LayoutDirectory

Nests an already declared directory one level deeper.

abstract operator fun String.div(child: LayoutFile): LayoutFile

"gradle" / "libs.versions.toml".file() is "gradle" { "libs.versions.toml".file() }.

abstract operator fun LayoutDirectory.div(child: String): LayoutDirectory

Continues a / chain with one more directory level.

abstract operator fun LayoutDirectory.div(child: LayoutDirectory): LayoutDirectory

Continues a / chain with a directory block.

abstract operator fun LayoutDirectory.div(child: LayoutFile): LayoutFile

Closes a / chain with the file it leads to.

Link copied to clipboard

Runs block once per module modulePath stands for, below that module's own directory.

Link copied to clipboard
abstract fun String.file(): LayoutFile

Declares a file, named exactly as written: "libs.versions.toml".file().

Link copied to clipboard
abstract fun fileConstraint(name: String? = null, declaredAt: DeclarationSite = captureDeclarationSite(), scope: FileConstraintRange = FileConstraintRange.Subtree, check: FileConstraint)

Declares a constraint over the files the block around it matched.

Link copied to clipboard
abstract fun String.ignore(): LayoutDirectory

Declares a directory and stops the check below it, at any depth.

Link copied to clipboard
abstract operator fun String.invoke(block: LayoutDirectoryScope.() -> Unit): LayoutDirectory

Declares a directory. Nest the blocks to walk down the tree.

abstract operator fun LayoutDirectory.invoke(block: LayoutDirectoryScope.() -> Unit): LayoutDirectory

Opens a block below a directory a / chain or a source set just declared.