Repository navigation
This is Konsist’s biggest release to date. It brings major performance improvements, additional context for AI, official support for nested modules, better Windows support, and a long list of fixes for edge cases.
Some of your Konsist tests may fail after upgrading. In most cases, that doesn’t mean Konsist is broken: many APIs returned incorrect results in edge cases, such as wrong fully qualified names, missing library parents, type checks based on text, or files silently skipped by architecture checks. These issues are now fixed, so the APIs are stricter and some return values have changed. If you think you’ve found a regression, please report it.
Table of Contents
- Community Feedback & What's Next
- Key changes
- Migration guide: 1.0.0-beta.1 breaking changes
- Complete List Of Changes
Community Feedback & What's Next
This beta is the API freeze candidate for 1.0.0. Please upgrade, run your Konsist tests and tell me what broke. Report issues and regressions in the #konsist channel or Github Discussions. Your feedback decides what lands in 1.0.0.
Key changes
Performance
Konsist 1.0.0-beta.1 vs 0.18.1 on ktor (same Kotlin files scanned by both versions):
| Metric | 0.18.1 |
1.0.0-beta.1 |
Change |
|---|---|---|---|
Smallest -Xmx for a typical test suite |
160 MB | 128 MB | −20% |
| Heap retained after the suite | 155.5 MB | 110.8 MB | −29% |
| Suite wall time after warm-up (median) | 0.56 s | 0.49 s | −13% |
sourceDeclaration of all parameter and return types |
37.4 s | 0.24 s | 150× faster |
sourceDeclaration of all property types |
15.8 s | 0.08 s | 190× faster |
sourceDeclaration of all imports |
12.4 s | 0.03 s | 400× faster |
children() |
1.57 s | 0.09 s | 17× faster |
children(indirectChildren = true) |
2.45 s | <0.01 s | >200× faster |
Projects with Kotlin files outside the module src directory (test data, scripts) gain more, because 1.0.0-beta.1 no longer scans these files in project scopes. On ktor as-is, the smallest -Xmx drops from 224 MB to 128 MB for the suite and from 256 MB to 32 MB for module scopes with type resolution.
On the Kotlin repository (15,177 Kotlin files, same files scanned by both versions):
| Metric | 0.18.1 |
1.0.0-beta.1 |
Change |
|---|---|---|---|
Smallest -Xmx for a typical test suite |
1,792 MB | 1,280 MB | −29% |
| Suite run 4 times in one JVM, total (first run includes parsing and type resolution) | 150–156 s | 31 s | 5× faster |
| Suite wall time after warm-up (median) | 6.5–6.7 s | 5.4 s | −18% |
On the Kotlin repository as-is (67,000+ Kotlin files, most of them test data outside src), a single run of the same suite drops from 23.6 minutes to 21 seconds: 1.0.0-beta.1 skips the test data files and resolves types much faster.
Konsist tests now run faster and need less memory, so CI is faster and large projects are less likely to hit OutOfMemoryError:
- Less memory: the directory scope memory leak is fixed (every
scopeFromDirectorycall kept its files in memory), and parsed files that are no longer used are released when memory runs low. - Parse only what is needed:
scopeFromProduction,scopeFromTestandscopeFromPackagefilter files before parsing, and type resolution in a module or directory scope parses only the files it needs instead of the whole project. - Faster queries:
parents(indirectParents = true)for a chain of 20 classes went from 8.5 s to <1 ms,children()of ~3,000 declarations from 211 s to 0.14 s, and resolving all 15,301 ktor imports from >60 s to 0.04 s. - Faster project scan: directories are scanned in parallel (−64% scan time on the Kotlin repository).
Measured with konsist-memory-benchmark.
Nested Modules
Nested modules are now officially supported. Module names accept the .. wildcard (any number of module directories, including none), the same way package names do:
// project modules: :feature, :feature:payment, :feature:payment:api, :feature:auth:data
Konsist.scopeFromModule(":feature..") // feature + all nested modules
Konsist.scopeFromModule("..data") // every module named "data"
Konsist.scopeFromModule("feature..data") // "data" modules nested anywhere under feature
Konsist.scopeFromModule("..") // all modules
Konsist.scopeFromProject().classes().withModule(":feature..")Gradle-style module paths are supported too. All of these mean the same module:
Konsist.scopeFromModule(":feature:auth") // preferred
Konsist.scopeFromModule("feature:auth")
Konsist.scopeFromModule("feature/auth")
Konsist.scopeFromModule("feature\\auth")
// before: Gradle-style paths returned an empty scope
// after: files of the feature/auth moduleThis works everywhere a module name is accepted: scopeFromModule(s), the moduleName parameter of scopeFromProject / scopeFromPackage / scopeFromProduction / scopeFromTest, residesInModule, withModule and withoutModule. A module that does not exist still returns an empty scope.
Module and source set detection was fixed for many project layouts: files outside the src directory, modules located in a directory named src, test fixture projects located in resources or testData, buildSrc, and subfolders with their own Gradle wrapper. See Behaviour changes.
Improved Compatibility
Konsist targets JVM 11 again and publishes kotlin-stdlib 2.0.21, so it works with more projects:
0.18.1 |
1.0.0-beta.1 |
|
|---|---|---|
| Java (JVM) | 17+ |
11+ |
| Kotlin (Android projects with AGP 8) | 2.3+ |
1.9+ |
See the Compatibility page for details.
When another Kotlin compiler is on the test classpath (e.g. kotlin-compiler, Android Lint), the parse error now explains the conflict instead of throwing a cryptic ClassCastException:
KoInternalException: Failed to parse Kotlin file: /project/src/test/kotlin/ReproTest.kt
Multiple Kotlin compilers found on the classpath:
- ~/.gradle/caches/.../kotlin-compiler-2.4.21.jar
- ~/.gradle/caches/.../kotlin-compiler-embeddable-2.4.21.jar
Konsist requires only 'kotlin-compiler-embeddable'.
Windows Support
- Every API that takes a path accepts both
/and\on every OS. Path outputs use the OS separator. moduleNamealways uses/(e.g.feature/data), somoduleName == "feature/data"works on every OS.- File links in failure messages are clickable in IntelliJ on Windows (
file:///C:/project/...). - Files saved with a UTF-8 BOM or with
\rline endings are parsed correctly (before, their package wasnullorlocationthrew).
Context Parameters
Kotlin context parameters can now be verified on functions and properties:
// Snippet
interface UserRepository {
context(logger: Logger)
fun getUser(id: String): User
}
// Konsist test
Konsist
.scopeFromProject()
.interfaces()
.withNameEndingWith("Repository")
.functions()
.assertTrue { it.hasContextParameter { parameter -> parameter.hasTypeOf(Logger::class) } }Context receivers (context(Logger)) are not supported: they were an experimental feature replaced by context parameters, and Kotlin 2.4 no longer compiles them.
Failure Messages That Explain The Rule
Failure messages can now explain what is wrong and how to fix it. This helps developers, and it helps AI agents fix violations without reading the test.
addFailureReason adds a reason for each failing declaration:
Konsist
.scopeFromProject()
.classes()
.withModifier(KoModifier.DATA)
.assertTrue { clazz ->
val ctorParams = clazz.primaryConstructor?.parameters?.map { it.name }.orEmpty().toSet()
val missing = clazz.properties().map { it.name } - ctorParams
if (missing.isNotEmpty()) addFailureReason("Properties outside constructor: ${missing.joinToString()}")
missing.isEmpty()
}Assert 'data classes have all properties in constructor' was violated (2 times). Invalid declarations:
├── Class User file:///.../User.kt:3:1
│ └── Properties outside constructor: createdAt, cache
└── Class Order file:///.../Order.kt:5:1
└── Properties outside constructor: total
KoRule describes the rule itself providing more context for AI to fix it. All assertions and assertArchitecture accept it:
Konsist
.scopeFromProject()
.classes()
.withNameEndingWith("ViewModel")
.assertTrue(
rule = KoRule(
title = "ViewModels must extend BaseViewModel.",
rationale = "Lifecycle handling lives in BaseViewModel.",
howToFix = "Change the parent class to BaseViewModel.",
goodExample = "class LoginViewModel : BaseViewModel()",
badExample = "class LoginViewModel : ViewModel()",
),
) { it.hasParentClassWithName("BaseViewModel") }Assert 'myTest' was violated (1 time).
RULE: ViewModels must extend BaseViewModel.
WHY: Lifecycle handling lives in BaseViewModel.
HOW TO FIX: Change the parent class to BaseViewModel.
GOOD EXAMPLE:
class LoginViewModel : BaseViewModel()
BAD EXAMPLE:
class LoginViewModel : ViewModel()
Invalid declarations:
└── Class LoginViewModel …/LoginViewModel.kt:3:1
Architecture Assertions
assertArchitecture is stricter: before, some files and dependencies were silently not checked.
Every file in the scope must now reside in exactly one layer. Files outside every layer fail by default:
All files are required to reside in a layer, but these files reside in no layer:
├── File .../NoPackageClass.kt
└── File .../util/UtilClass.kt
Declare the missing packages as layers, narrow the scope, or restore the old behaviour:
scope.assertArchitecture(allowFilesOutsideLayers = true) {
domain.dependsOnNothing()
data.dependsOn(domain)
}Other changes:
- Layers that share files (e.g.
com.app..andcom.app.domain..) fail withLayers overlap. Dependencies between overlapping layers were never checked. - A layer with
dependsOn(...)fails again when it depends on a declared layer that is not on its list (regression from0.17.0). - New
Layer(..., optional = true): a layer without files is allowed (e.g. a feature that has nopresentationpackage yet). rootPackagewithout trailing..covers a single package, so a rootapppackage no longer overlaps the layers below it:
val app = Layer("App", "com.example") // com.example only
val domain = Layer("Domain", "com.example.domain..")- Failure output lists only the imports that break the rule, not every import of the file.
- Equal
Layerinstances count as one layer, cycles not including the first layer reportCircular dependency detectedinstead of an internal error, and imports are matched by package (class names no longer match layer packages).
Kotest And JUnit 5 Dynamic Tests
Register the new extensions to get correct test names in failure messages and working @Suppress("konsist.<test name>"), without passing testName to every assertion:
// Kotest 6
class ProjectConfig : AbstractProjectConfig() {
override val extensions = listOf(KoKotestExtension)
}
// JUnit 5 dynamic tests
@ExtendWith(KoJUnitExtension::class)
class UseCaseKonsistTest {
@TestFactory
fun `use case test`() = useCases.map { useCase ->
dynamicTest("${useCase.name} should have test") {
useCase.assertTrue { it.hasTestClasses() } // message: 'MyUseCase should have test'
}
}
}@Suppress is now parsed from the annotation syntax tree, so @Suppress(names = ["konsist.x"]), @Suppress(*arrayOf(...)) and @file:kotlin.Suppress(...) work. Suppression also works for packages, annotations, KDocs and type arguments.
New APIs
- Explicit backing fields:
// Snippet
class SearchViewModel : ViewModel() {
val state: StateFlow<Int>
field = MutableStateFlow(0)
}
// Konsist test
Konsist
.scopeFromProject()
.classes()
.withParentClassOf(ViewModel::class)
.properties()
.withTypeOf(StateFlow::class)
.assertTrue { it.hasExplicitBackingField }- Built-in delegates:
hasLazyDelegate(mode),hasObservableDelegate,hasVetoableDelegate,hasNotNullDelegate,hasPropertyReferenceDelegateand matchingwith*/without*list extensions:
Konsist
.scopeFromProject()
.properties()
.assertFalse { it.hasLazyDelegate(LazyThreadSafetyMode.NONE) }isImmutableTypeandhasImmutableTypeArgument.isMutableTypenow resolves aliases and knows mutable types likeArrayList, arrays andjava.util.*. Classes withvalproperties of mutable types count as mutable:
Konsist
.scopeFromProject()
.classes()
.withNameEndingWith("UiState")
.properties()
.assertTrue { it.type?.isImmutableType == true }bodyon functions, getters and setters (block body without braces, or the expression)hasTestClass { ... }and friends for functions (e.g.@Composablefunctions)files.withName("MyClass.kt"): file name with extension matches
Notable Bug Fixes
- Parents from libraries and the Kotlin standard library are now classes and interfaces:
withParentClassOf(ComponentActivity::class)returns[MainActivity]instead of[], andparents(indirectParents = true)continues through library parents (MyException : IllegalStateException()has parentThrowable) KClasschecks match type aliases (RuntimeException,ArrayList,HashMap,MutableList), import aliases and generic type arguments (hasReturnTypeOf<List<String>>()no longer matchesList<Int>)- Fully qualified names are resolved correctly: project types before Kotlin default imports (
com.app.Resultinstead ofkotlin.Result), types nested in superclasses, nested annotations used without qualifier, no more suffix matching (Testresolved toUnitTest) hasTacitTypeuses the constructor call instead of text search (val x = FooBar()no longer matchesBar)typeof extension properties returns the declared type instead of the receiver typeisGeneric,isNullableandisFunctionTypeuse the syntax tree instead of text (List<Item2>is generic,List<(Int) -> Unit>is not a function type)hasMatchingPackage/hasMatchingPathcompare whole directories (com.appno longer matchescom/application)- KDoc
textanddescriptionkeep all content (e.g.john@example.comno longer cuts the description) scopeFromDirectoryskipsbuild, hidden andnode_modulesdirectories,+=/-=refresh cached scope values, scopes contain each file once, and a cancelled project scan (e.g. JUnit@Timeout) no longer breaks later scopesassertNotNull/assertNotEmptyno longer fail for suppressed declarations, and only@Suppressannotations are skipped during assertions
Migration guide: 1.0.0-beta.1 breaking changes
All APIs deprecated in 0.18.x were either removed or are no longer deprecated, so 1.0.0-beta.1 has no deprecated APIs. Removed APIs fail to compile, so the compiler shows every place to update.
Removed resideIn* methods
The resideIn* / resideOutside* provider methods have been removed. Use the residesIn* / residesOutside* methods instead. Only the name changed; behaviour is the same. residesIn* is new in this release, so there is no deprecation step: builds fail until call sites are renamed.
| Removed | Use instead |
|---|---|
resideInPackage(name) |
residesInPackage(name) |
resideOutsidePackage(name) |
residesOutsidePackage(name) |
resideInPath(path, absolutePath) |
residesInPath(path, absolutePath) |
resideInModule(name) |
residesInModule(name) |
resideInSourceSet(sourceSetName) |
residesInSourceSet(sourceSetName) |
// Before:
Konsist.scopeFromProject().classes().assertTrue { it.resideInPackage("..usecase..") }
// After:
Konsist.scopeFromProject().classes().assertTrue { it.residesInPackage("..usecase..") }Modifier and generic providers
| Removed | Use instead |
|---|---|
KoValModifierProvider, hasValModifier |
KoIsValProvider, isVal |
withValModifier() / withoutValModifier() |
withVal() / withoutVal() |
KoVarModifierProvider, hasVarModifier |
KoIsVarProvider, isVar |
withVarModifier() / withoutVarModifier() |
withVar() / withoutVar() |
KoIsGenericTypeProvider, isGenericType |
KoIsGenericProvider, isGeneric |
withGenericType() / withoutGenericType() |
withGeneric() / withoutGeneric() |
KoSourceAndAliasTypeProvider, isAlias |
KoSourceTypeProvider, isImportAlias |
External type declarations
| Removed | Use instead |
|---|---|
isExternalType |
isExternal |
asExternalTypeDeclaration() |
asExternalDeclaration() |
hasExternalTypeDeclaration { } / hasExternalTypeDeclarationOf(kClass) |
hasExternalDeclaration { } / hasExternalDeclarationOf(kClass) |
withExternalTypeDeclaration { } / withoutExternalTypeDeclaration { } |
withExternalDeclaration { } / withoutExternalDeclaration { } |
withExternalTypeDeclarationOf(...) / withoutExternalTypeDeclarationOf(...) |
withExternalDeclarationOf(...) / withoutExternalDeclarationOf(...) |
Note: the old hasExternalTypeDeclaration(predicate) ignored predicate, so results may change after migrating.
Function type parameters
| Removed | Use instead |
|---|---|
parameterTypes (also on List<KoFunctionTypeDeclarationProvider>) |
parameters |
numParameterTypes |
numParameters |
countParameterTypes { } |
countParameters { } |
hasParameterType { } |
hasParameter { } |
hasAllParameterTypes { } |
hasAllParameters { } |
withParameterType / withoutParameterType |
withParameter / withoutParameter |
withAllParameterTypes / withoutAllParameterTypes |
withAllParameters / withoutAllParameters |
withParameterTypes / withoutParameterTypes |
withParameters / withoutParameters |
Enum constant local declarations and variables
KoEnumConstantDeclaration is no longer a KoLocalClassProvider, KoLocalFunctionProvider, KoLocalDeclarationProvider or KoVariableProvider. Use the class, function, declaration and property providers added in 0.18.0 (the same applies to the List<KoEnumConstantDeclaration> extensions):
| Removed | Use instead |
|---|---|
localClasses, numLocalClasses, countLocalClasses { } |
classes(), numClasses(), countClasses { } |
hasLocalClasses(), hasLocalClass { }, hasAllLocalClasses { } |
hasClasses(), hasClass { }, hasAllClasses { } |
hasLocalClassWithName, hasLocalClassesWithAllNames |
hasClassWithName, hasClassesWithAllNames |
localFunctions, numLocalFunctions, countLocalFunctions { } |
functions(), numFunctions(), countFunctions { } |
hasLocalFunctions(), hasLocalFunction { }, hasAllLocalFunctions { } |
hasFunctions(), hasFunction { }, hasAllFunctions { } |
hasLocalFunctionWithName, hasLocalFunctionsWithAllNames |
hasFunctionWithName, hasFunctionsWithAllNames |
localDeclarations, numLocalDeclarations, countLocalDeclarations { } |
declarations(), numDeclarations(), countDeclarations { } |
hasLocalDeclarations(), hasLocalDeclaration { }, hasAllLocalDeclarations { } |
hasDeclarations(), hasDeclaration { }, hasAllDeclarations { } |
variables, numVariables, countVariables { } |
properties(), numProperties(), countProperties { } |
hasVariables(), hasVariable { }, hasAllVariables { } |
hasProperties(), hasProperty { }, hasAllProperties { } |
hasVariableWithName, hasVariablesWithAllNames |
hasPropertyWithName, hasPropertiesWithAllNames |
withLocalClass* / withoutLocalClass* list extensions |
withClass* / withoutClass* |
withLocalFunction* / withoutLocalFunction* list extensions |
withFunction* / withoutFunction* |
withLocalDeclaration* / withoutLocalDeclaration* list extensions |
withDeclaration* / withoutDeclaration* |
No longer deprecated
These APIs were marked "Will be removed in version 0.19.0". They stay, and the deprecation warnings are gone:
KoTypeDeclarationtype checks and casts:isClass,isInterface,isObject,isKotlinType,isExternal,asClassDeclaration(),hasClassDeclaration { },hasClassDeclarationOf(kClass)and the otheris*/as*/has*Declaration*membersList<KoTypeDeclaration>extensions:classDeclarations(),withClassDeclaration { },withClassDeclarationOf(...)and the other*Declarations()/with*Declaration*/without*Declaration*extensionsList<KoDeclarationCastProvider>properties:classDeclarations,objectDeclarations,interfaceDeclarations,typeAliasDeclarations,importAliasDeclarations,kotlinTypeDeclarations,externalTypeDeclarations
Signature changes
| Change | Migration |
|---|---|
List<KoCompanionObjectProvider>.companionObjects property removed (it returned different results than companionObjects()) |
companionObjects(includeNested = false) for the old result, companionObjects() to include nested companion objects |
typeArguments is non-null (List<KoTypeArgumentDeclaration>) |
Replace typeArguments?. / typeArguments.orEmpty() with typeArguments |
Function type parameters is non-null (List<KoParameterDeclaration>) |
Replace parameters?. with parameters |
The assertTrue / assertFalse lambda is now KoAssertScope.(E) -> Boolean? |
No change for most code. Inside the lambda, this refers to KoAssertScope |
New rule, allowFilesOutsideLayers and Layer.optional parameters |
Source compatible. Libraries compiled against 0.18.x must be recompiled (NoSuchMethodError otherwise) |
Behaviour changes
These APIs return different, more correct results. Tests that relied on the old results may fail:
‼️ assertArchitecturefails for files outside every layer (opt out withallowFilesOutsideLayers = true), for overlapping layers, and for dependencies on declared layers missing fromdependsOn(...)‼️ Project scopes (scopeFromProject,scopeFromModule,scopeFromProduction,scopeFromTest, ...) contain only files located in the modulesrcdirectory. Directory and file scopes still return other files‼️ moduleNameof files outsidesrcis their directory (samples/A.kt→samples, root files →root), source sets are computed from the module directory, and projects located inresourcesor other source set directories belong to the containing module‼️ A folder withgradlewbut withoutsettings.gradle(.kts)is no longer a project root‼️ Parents from libraries and the Kotlin standard library are included inparentClass,parentClasses(),parentInterfaces()andparents(indirectParents = true)‼️ KClasschecks compare fully qualified names (type aliases, import aliases and generic type arguments are taken into account),hasTacitTypeuses the constructor call, extension propertytypeis the declared type‼️ isGeneric,isNullable,isFunctionType,isMutableTypeandisImmutableTypereturn different results for some types;KoTypeParameterDeclaration.namereturns only the name (Tinstead ofout T : Number)‼️ Type argument filters with empty input match only declarations that have type arguments‼️ scopeFromDirectoryskipsbuild, hidden andnode_modulesdirectories‼️ property.valueisnullfor properties with explicit backing fields (useexplicitBackingField?.value)
Complete List Of Changes
⚠️ Breaking API Changes
- Remove deprecated APIs before
1.0.0(see Migration guide)- Change deprecation removal version from 1.0.0-beta.1 to 1.0.0-rc.1 by @igorwojda in #2022
- Remove deprecated KoValModifierProvider by @igorwojda in #2067
- Remove deprecated KoIsGenericTypeProvider by @igorwojda in #2068
- Remove deprecated isExternalType API by @igorwojda in #2069
- Remove deprecated KoFunctionTypeDeclarationProvider.hasParameterType by @igorwojda in #2070
- Remove deprecated List.parameterTypes by @igorwojda in #2071
- Remove deprecated KoVarModifierProvider by @igorwojda in #2072
- Remove deprecated KoSourceAndAliasTypeProvider by @igorwojda in #2073
- Remove deprecated KoFunctionTypeDeclarationProvider parameterTypes APIs by @igorwojda in #2074
- Remove deprecated List parameter type filters by @igorwojda in #2075
- Remove deprecated List local class extensions by @igorwojda in #2077
- Remove deprecated List local declaration extensions by @igorwojda in #2078
- Remove deprecated List local function extensions by @igorwojda in #2079
- Remove deprecated local and variable providers from KoEnumConstantDeclaration by @igorwojda in #2080
- Remove deprecated local and variable provider implementations from KoEnumConstantDeclarationCore by @igorwojda in #2081
- Remove List.companionObjects property in favor of companionObjects() by @igorwojda in #2108
- Rename
resideIn*methods toresidesIn*- Add residesIn* methods and deprecate resideIn* methods by @igorwojda in #1985
- Remove resideIn* methods deprecated for removal in 1.0.0-rc1 by @igorwojda in #2088
- Stricter
assertArchitecture- Fail dependsOn when layer depends on undeclared layer by @igorwojda in #1953
- Fail architecture assertion when a file belongs to more than one layer by @igorwojda in #1988
- Require every file to reside in exactly one layer in assertArchitecture by @igorwojda in #1989
- Make type arguments non-null and align empty-input filters by @igorwojda in #2101
- Use syntax tree instead of text in type providers by @igorwojda in #2094
🐛 API Bug Fixes
- Type resolution
- Fix wrong fully qualified names from suffix matching and external cache by @igorwojda in #1968
- Resolve project types before Kotlin default imports by @igorwojda in #1978
- Resolve types nested in superclasses by @igorwojda in #1981
- Include library and Kotlin parents in parent classes and interfaces by @igorwojda in #1983
- Include library and Kotlin parents of library parents in indirect parents by @igorwojda in #1986
- Match Kotlin type aliases in KClass type checks by @igorwojda in #1963
- Compare generic type arguments in reified type checks by @igorwojda in #1964
- Match KClass by fully qualified name and resolve import aliases by @igorwojda in #2106
- Fix withRepresentedTypeOf(KClass) for parameters and context parameters by @igorwojda in #2105
- Match source type KClass filters by fully qualified name by @igorwojda in #2058
- Compare fully qualified names of Kotlin annotations in hasAnnotationOf by @igorwojda in #1994
- Resolve nested annotations used without qualifier by @igorwojda in #2107
- Fix name, annotations and source declaration of annotated nullable types by @igorwojda in #2112
- Infer tacit type from constructor call instead of text search by @igorwojda in #1982
- Fix KoPropertyDeclaration.type for extension properties by @igorwojda in #2002
- Mutable and immutable types
- Resolve aliases and known mutable types in isMutableType by @igorwojda in #1967
- Treat classes with val properties of mutable types as mutable by @igorwojda in #1997
- Report only known immutable external types as immutable by @igorwojda in #1998
- Treat Any and open types as not immutable by @igorwojda in #2000
- Architecture assertions
- Treat equal Layer instances as the same layer by @igorwojda in #1956
- KON-684 List only violating imports in architecture failure output by @igorwojda in #1957
- Fix circular dependency detection for cycles not including first layer by @igorwojda in #2092
- Match imported declaration package against architecture layers by @igorwojda in #2093
- Suppression
- Fix suppression causing assertNotNull/assertNotEmpty failures by @igorwojda in #2095
- Respect Suppress for packages, annotations, KDocs and type arguments by @igorwojda in #2097
- Skip only @Suppress annotations during assertions by @igorwojda in #2103
- Paths and scopes
- Use OS separator in hasMatchingPackage so it works on Windows by @igorwojda in #1928
- Escape project root path in scope regex so folders with brackets work by @igorwojda in #1930
- Ignore leading and trailing slashes in module and source set scope names by @igorwojda in #1936
- Treat top-level module named like root directory as regular module by @igorwojda in #1940
- Match path patterns that start with a separator by @igorwojda in #1948
- Support project root at drive root or filesystem root by @igorwojda in #1949
- Skip subfolders with own Gradle wrapper when resolving project root by @igorwojda in #2018
- Refresh cached scope values after plusAssign and minusAssign by @igorwojda in #2027
- Skip build, hidden and node_modules directories in directory scopes by @igorwojda in #2098
- Retry project scan after cancelled or failed scan by @igorwojda in #2099
- Deduplicate scope files and normalize scope input paths by @igorwojda in #2100
- Fix hasMatchingPackage and hasMatchingPath matching part of the path by @igorwojda in #2102
- Parsing and KDoc
- Strip UTF-8 BOM before parsing Kotlin files by @igorwojda in #1942
- Normalize CR and CRLF line endings before parsing Kotlin files by @igorwojda in #2104
- Fix KDoc text and description losing content by @igorwojda in #2096
- Skip KDoc tags without value instead of throwing ClassCastException by @igorwojda in #2056
- Ignore nested class properties in hasValidKDocPropertyTags by @igorwojda in #2057
- Pass indirectChildren through in hasChildOf and hasAllChildrenOf vararg overloads by @igorwojda in #2055
- Fix duplicated local declarations in function scope by @igorwojda in #2110
💡 API Improvements
- Nested modules support
- Support Gradle-style paths in module scopes and throw for invalid module names by @igorwojda in #1941
- Return empty scope instead of throwing for invalid module names by @igorwojda in #1952
- Support .. wildcard in module names by @igorwojda in #2034
- Use file directory as module name for files outside src directory by @igorwojda in #2030
- Include files outside src directory in module scopes by @igorwojda in #2033
- Detect modules located in directory named src by @igorwojda in #2040
- Use closest module directory as module of files outside src directory by @igorwojda in #2041
- Use closest module directory as module of files outside source root by @igorwojda in #2042
- Use module directory to compute source set and filter source set scopes by @igorwojda in #2043
- Treat resources directory as source root by @igorwojda in #2044
- Ignore files outside src directory in project scopes by @igorwojda in #2048
- Treat projects located in source set directories as part of the containing module by @igorwojda in #2051
- Ignore build directories of modules located in src directory by @igorwojda in #2052
- Detect buildSrc by directory name relative to project root by @igorwojda in #2032
- Reject module names with more than two consecutive dots by @igorwojda in #2046
- Add nested module scope tests to declaration tester by @igorwojda in #1934
- Add tests for slash-trimmed module names in resideInModule and withModule by @igorwojda in #1946
- Add tests for nested modules by @igorwojda in #1972
- Test sibling nested modules with the same name in module scope by @igorwojda in #2007
- Test parent module with own sources and nested module by @igorwojda in #2031
- Add end-to-end test for module of files outside src directory by @igorwojda in #2045
- Explain assertion failures
- Add addReason to assertTrue and assertFalse by @igorwojda in #1970
- Rename addReason to addFailureReason by @igorwojda in #2083
- Add KoRule parameter to assertions by @igorwojda in #2090
- Add context parameters support
- Add context parameters support by @igorwojda in #1999
- Test context parameters on extension function and property by @igorwojda in #2008
- Kotest and JUnit 5 dynamic test names
- Resolve test name for JUnit 5 dynamic tests and Kotest by @igorwojda in #1955
- Add Kotest/JUnit test name extensions and fix @Suppress parsing by @igorwojda in #1974
- Add Kotest spec suppression tests with and without testName by @igorwojda in #1976
- Add built-in delegate checks
- Add built-in delegate checks to KoDelegateProvider by @igorwojda in #1962
- Add built-in delegate filters to KoDelegateProvider list extensions by @igorwojda in #2039
- Add
isImmutableTypeandhasImmutableTypeArgument- Add isImmutableType and hasImmutableTypeArgument by @igorwojda in #1996
- Keep type cast APIs (deprecation removed)
- Remove deprecation from sourceDeclaration-replaced APIs by @igorwojda in #2087
- Remove 0.19.0 deprecation from declaration cast list extensions by @igorwojda in #2089
- Allow optional layers without files in architecture assertion by @igorwojda in #1987
- Support single package layers by @igorwojda in #2111
- Add explicit backing field support by @igorwojda in #2038
- Add body property to KoBodyProvider by @igorwojda in #1995
- Add test class lookup for functions by @igorwojda in #1984
- Allow file name with extension in hasName and withName by @igorwojda in #1954
💡 Improvements
- Performance and memory
- Reduce memory usage and fix directory scope memory leak by @igorwojda in #1960
- Speed up type resolution, parents and children, and release unused parsed files by @igorwojda in #1975
- Scan project directories in parallel when collecting Kotlin files by @igorwojda in #2023
- Check file name before file system when scanning for Kotlin files by @igorwojda in #2024
- Filter scopeFromProduction and scopeFromTest by source set before parsing by @igorwojda in #2028
- Filter scopeFromPackage files by package before parsing by @igorwojda in #2029
- Cache module name matchers by @igorwojda in #2047
- Windows support
- Normalize moduleName separators to / on Windows by @igorwojda in #1926
- Use clickable file:/// links and / separators in output paths on Windows by @igorwojda in #1927
- Accept / and \ in path inputs and use OS separators in path outputs by @igorwojda in #1935
- Compatibility
- Publish Konsist for JVM 11 again by @igorwojda in #2017
- Publish kotlin-stdlib 2.0.21 to support older consumer Kotlin versions by @igorwojda in #2019
- Explain Kotlin compiler classpath conflicts in parse errors by @igorwojda in #1966
📕 Documentation
- Document separator handling in path and module KDocs by @igorwojda in #1937
- Document case-sensitive path matching in scope creator KDoc by @igorwojda in #1938
- Fix case-sensitivity claims in scope creator KDoc by @igorwojda in #1943
- Fix typos and inaccuracies in KDoc by @igorwojda in #1958
- Rename Snippets to Test Snippets by @igorwojda in #1961
- Fix architecture assertion KDoc for testName and dependsOn by @igorwojda in #1965
- Document that module name is directory path in KDoc by @igorwojda in #1971
- Add hexagonal architecture snippet by @igorwojda in #1973
- Document full-match regex, use-site package and declared return type semantics by @igorwojda in #1979
- Add @see tags to list extension KDocs by @igorwojda in #2015
- Fix outdated and inaccurate KDocs by @igorwojda in #2054
- Add Spring test snippets for endpoints, DDD visibility and domain classes by @igorwojda in #2059
🏗️ Maintenance
- Clean Up Release Docs And Scripts by @igorwojda in #1925
- Run Lib Tests On Windows In CI by @igorwojda in #1929
- Add HyperlinkUtilTest cases for paths with spaces and network paths by @igorwojda in #1932
- Add ModuleUtil and resideInModule unit tests for root and Windows cases by @igorwojda in #1933
- Pass unix separator paths unconverted in path tester tests by @igorwojda in #1939
- Run declaration tester project on Ubuntu by @igorwojda in #1944
- Use literal expected values in HyperlinkUtilTest by @igorwojda in #1945
- Fix order-dependent KoTestClassProvider test failing on Ubuntu by @igorwojda in #1947
- Cache Gradle in CI with setup-gradle by @igorwojda in #1950
- Add absolute path tests for Windows drive-letter paths by @igorwojda in #1951
- Update Kotest Gradle plugin to 6.2.5 in KMP sample by @igorwojda in #1977
- Show assertion messages in starter projects command line output by @igorwojda in #1980
- Move test projects to misc/projects/test-projects by @igorwojda in #1993
- Tighten KDoc Konsist tests by @igorwojda in #2001
- Use withoutName instead of filterNot in ApiKonsistTest by @igorwojda in #2003
- Extract shared provider filter in ApiKonsistTest by @igorwojda in #2004
- Check every api property has explicit type by @igorwojda in #2005
- Move ApiKonsistTest fields to top and rename 'Some' test by @igorwojda in #2006
- Add Maven root path tester project by @igorwojda in #2009
- Run ktlint on build-logic by @igorwojda in #2010
- Enable ktlint for test projects by @igorwojda in #2013
- Bump Konsist version to 1.0.0-alpha.1 by @igorwojda in #2014
- Publish snapshots to Maven Central and test projects against them by @igorwojda in #2016
- Speed up CI: preinstalled Python, earlier snapshot pickup, configuration cache by @igorwojda in #2021
- Give Get Published Snapshot jobs unique names by @igorwojda in #2025
- Rename Konsist Integration Test job to Konsist Integration Test Ubuntu by @igorwojda in #2026
- Check Konsist version is increased in PRs to main by @igorwojda in #2036
- Update KMP starter projects and enable their CI jobs by @igorwojda in #2037
- Update konsist dependency version in README by @igorwojda in #2062
- Add Bum Konsist Version Skill by @igorwojda in #2085
- Bump Konsist version to 1.0.0-beta.1 by @igorwojda in #2091
- Remove leftovers from sourceDeclaration migration by @igorwojda in #2109
- Dependency updates by @renovate
Full Changelog: v0.18.1...v1.0.0-beta.1