refactor: explicit locked detekt config (#729)
Migrate detekt to a convention plugin in `buildSrc`, switch the project to a fully explicit YAML config (`buildUponDefaultConfig = false`), fix the real findings that this stricter setup revealed, and remove `@Suppress` annotations that became unnecessary after the rule changes. ## Motivation and Context - Explicit visibility into the rule set - Lock against detekt version upgrades ## Breaking Changes None ## Types of changes - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update ## Checklist - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [x] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [x] I have added appropriate error handling - [x] I have added or updated documentation as needed
This commit is contained in:
parent
a238fc0a2e
commit
64804a05c2
80 changed files with 1106 additions and 507 deletions
|
|
@ -5,40 +5,62 @@ description: "Add KDoc documentation to Kotlin public API. Use whenever the user
|
|||
|
||||
# KDoc Generator
|
||||
|
||||
Add KDoc comments to public Kotlin API declarations.
|
||||
Add KDoc to all public Kotlin declarations (classes, interfaces, objects, functions, properties, enums, type aliases, annotations — including `@Deprecated`). Read the implementation, not just the signature, to write accurate descriptions.
|
||||
|
||||
## What to document
|
||||
## Tag placement
|
||||
|
||||
All public declarations (no explicit `private`/`internal`/`protected`):
|
||||
- Classes, interfaces, objects, sealed classes/interfaces
|
||||
- Functions, extension functions
|
||||
- Properties
|
||||
- Enum classes and entries
|
||||
- Type aliases, annotation classes
|
||||
| Where the declaration lives | Tag |
|
||||
|---|---|
|
||||
| Primary-ctor `val` / `var` (public, internal, or protected) | `@property` in class KDoc |
|
||||
| Primary-ctor `name: Type` (no `val`/`var`) | `@param` in class KDoc |
|
||||
| Primary-ctor `private val` / `private var` | `@param` in class KDoc |
|
||||
| Body of class/object/interface/sealed interface | inline `/** */` above the declaration |
|
||||
| Function parameter | `@param` |
|
||||
| Non-Unit return type | `@return` |
|
||||
|
||||
Include `@Deprecated` elements.
|
||||
## Style
|
||||
|
||||
## Context
|
||||
- Summary: one concise sentence, third-person verb ("Creates", "Returns", "Represents"). Expand to 2-3 sentences only when genuinely complex.
|
||||
- **Example block**: mandatory for DSL builders (show full receiver-scope usage); add for complex functions or non-obvious extension functions; skip for one-liners and simple getters.
|
||||
- KDoc links (`[ClassName]`, `[methodName]`) only where they add navigational value.
|
||||
- Don't write `@throws` or "suspend" notes.
|
||||
- Rewrite existing KDoc if incomplete or low quality.
|
||||
|
||||
Read the implementation, not just the signature, to write accurate descriptions. Understanding what the code actually does prevents superficial or misleading documentation.
|
||||
## Examples
|
||||
|
||||
## KDoc format
|
||||
|
||||
**Class/interface example:**
|
||||
**Class with mixed primary-constructor parameters:**
|
||||
|
||||
````kotlin
|
||||
/**
|
||||
* Manages active client sessions and their lifecycle.
|
||||
*
|
||||
* Sessions are created on first connection and cleaned up
|
||||
* when the transport closes.
|
||||
*
|
||||
* @property maxSessions upper limit on concurrent sessions
|
||||
* @property timeout idle timeout before a session is evicted
|
||||
* @param scope coroutine scope for session lifecycle tasks
|
||||
* @param secret used internally for session token signing
|
||||
*/
|
||||
public class SessionManager(
|
||||
public val maxSessions: Int, // public val → @property
|
||||
scope: CoroutineScope, // no val/var → @param
|
||||
private val secret: ByteArray, // private val → @param
|
||||
)
|
||||
````
|
||||
|
||||
**Function example:**
|
||||
**Body and interface properties (inline `/** */`):**
|
||||
|
||||
````kotlin
|
||||
/** Represents an entity that includes additional metadata. */
|
||||
public interface WithMeta {
|
||||
/** Optional metadata attached to this entity. */
|
||||
public val meta: JsonObject?
|
||||
}
|
||||
|
||||
public class Connection(public val id: String) {
|
||||
/** Capabilities negotiated during the handshake, or `null` before initialize completes. */
|
||||
public val capabilities: ServerCapabilities? get() = ...
|
||||
}
|
||||
````
|
||||
|
||||
**Function with Example block:**
|
||||
|
||||
````kotlin
|
||||
/**
|
||||
|
|
@ -46,10 +68,7 @@ Read the implementation, not just the signature, to write accurate descriptions.
|
|||
*
|
||||
* Example:
|
||||
* ```kotlin
|
||||
* server.addTool(
|
||||
* name = "echo",
|
||||
* description = "Echoes input back",
|
||||
* ) { request ->
|
||||
* server.addTool(name = "echo", description = "Echoes input back") { request ->
|
||||
* CallToolResult(content = listOf(TextContent("Echo: ${request.arguments}")))
|
||||
* }
|
||||
* ```
|
||||
|
|
@ -60,15 +79,3 @@ Read the implementation, not just the signature, to write accurate descriptions.
|
|||
* @return the registered tool definition
|
||||
*/
|
||||
````
|
||||
|
||||
## Rules
|
||||
|
||||
- Summary: concise first sentence starting with a third-person verb ("Creates", "Returns", "Represents"). Expand to 2-3 sentences only when genuinely complex
|
||||
- **@property** in class-level KDoc for all public properties (never as individual KDoc on the property); **@param** for function parameters
|
||||
- **@return** for non-Unit return types
|
||||
- **Example block**: add for DSL builders, complex functions, extension functions with non-obvious usage. Skip for trivial one-liners and simple getters
|
||||
- **DSL builders**: always include an Example showing full usage with the receiver scope — this is critical for discoverability
|
||||
- KDoc links (`[ClassName]`, `[methodName]`): only where it adds clear navigational value
|
||||
- No **@throws** — don't document exceptions
|
||||
- No **suspend** notes — coroutine nature is visible from the signature
|
||||
- **Existing KDoc**: rewrite if incomplete (missing @param/@return/@property) or low quality
|
||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
include:
|
||||
- os: ubuntu-latest
|
||||
job-name: "Linux Tests"
|
||||
gradle-tasks: "ktlintCheck build"
|
||||
gradle-tasks: "build"
|
||||
max-workers: 3
|
||||
|
||||
- os: macos-latest
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import dev.detekt.gradle.extensions.FailOnSeverity
|
||||
|
||||
plugins {
|
||||
id("mcp.dokka")
|
||||
alias(libs.plugins.detekt)
|
||||
alias(libs.plugins.ktlint)
|
||||
alias(libs.plugins.kover)
|
||||
}
|
||||
|
|
@ -23,16 +20,6 @@ dependencies {
|
|||
subprojects {
|
||||
apply(plugin = "org.jlleitschuh.gradle.ktlint")
|
||||
apply(plugin = "org.jetbrains.kotlinx.kover")
|
||||
|
||||
if (name != "conformance-test" && name != "docs") {
|
||||
apply(plugin = "dev.detekt")
|
||||
|
||||
detekt {
|
||||
config = files("$rootDir/config/detekt/detekt.yml")
|
||||
buildUponDefaultConfig = true
|
||||
failOnSeverity.set(FailOnSeverity.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dokka {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.detekt.gradle)
|
||||
implementation(libs.kotlin.gradle)
|
||||
implementation(libs.kotlin.serialization)
|
||||
implementation(libs.kotlinx.atomicfu.gradle)
|
||||
|
|
|
|||
23
buildSrc/src/main/kotlin/mcp.detekt.gradle.kts
Normal file
23
buildSrc/src/main/kotlin/mcp.detekt.gradle.kts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import dev.detekt.gradle.Detekt
|
||||
import dev.detekt.gradle.extensions.FailOnSeverity
|
||||
|
||||
plugins {
|
||||
id("dev.detekt")
|
||||
}
|
||||
|
||||
detekt {
|
||||
config = files("$rootDir/config/detekt/detekt.yml")
|
||||
buildUponDefaultConfig = false
|
||||
parallel = true
|
||||
failOnSeverity = FailOnSeverity.Error
|
||||
}
|
||||
|
||||
tasks.withType<Detekt>().configureEach {
|
||||
exclude("**/generated/**", "**/generated-sources/**", "**/build/**")
|
||||
}
|
||||
|
||||
pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") {
|
||||
tasks.named("detekt").configure {
|
||||
dependsOn("detektMainJvm")
|
||||
}
|
||||
}
|
||||
|
|
@ -57,12 +57,3 @@ kotlin {
|
|||
explicitApi = ExplicitApiMode.Strict
|
||||
jvmToolchain(21)
|
||||
}
|
||||
|
||||
tasks.named("detekt").configure {
|
||||
dependsOn(
|
||||
"detektMainJvm",
|
||||
"detektCommonMainSourceSet",
|
||||
"detektTestJvm",
|
||||
"detektCommonTestSourceSet",
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,41 +3,840 @@ config:
|
|||
warningsAsErrors: false
|
||||
checkExhaustiveness: false
|
||||
|
||||
complexity:
|
||||
LargeClass:
|
||||
excludes: &testFolders
|
||||
- '**/test/**'
|
||||
- '**/commonTest/**'
|
||||
- '**/jvmTest/**'
|
||||
- '**/jsTest/**'
|
||||
- '**/iosTest/**'
|
||||
LongMethod:
|
||||
excludes: *testFolders
|
||||
processors:
|
||||
active: false
|
||||
|
||||
coroutines:
|
||||
InjectDispatcher:
|
||||
excludes: *testFolders
|
||||
|
||||
empty-blocks:
|
||||
EmptyFunctionBlock:
|
||||
excludes: *testFolders
|
||||
console-reports:
|
||||
active: true
|
||||
exclude:
|
||||
- 'ProjectStatisticsReport'
|
||||
- 'ComplexityReport'
|
||||
- 'NotificationReport'
|
||||
- 'IssuesReport'
|
||||
- 'FileBasedIssuesReport'
|
||||
# - 'LiteIssuesReport'
|
||||
|
||||
comments:
|
||||
UndocumentedPublicClass:
|
||||
active: true
|
||||
excludes: &testAndGeneratedFolders
|
||||
- '**/test/**'
|
||||
- '**/commonTest/**'
|
||||
- '**/jvmTest/**'
|
||||
- '**/jsTest/**'
|
||||
- '**/iosTest/**'
|
||||
- '**/generated-sources/**'
|
||||
ignoreDefaultCompanionObject: true
|
||||
UndocumentedPublicFunction:
|
||||
active: true
|
||||
excludes: *testAndGeneratedFolders
|
||||
UndocumentedPublicProperty:
|
||||
active: true
|
||||
excludes: *testAndGeneratedFolders
|
||||
searchProtectedProperty: false
|
||||
ignoreEnumEntries: true
|
||||
active: true
|
||||
AbsentOrWrongFileLicense:
|
||||
active: false
|
||||
licenseTemplateIsRegex: false
|
||||
licenseTemplate: ''
|
||||
DeprecatedBlockTag:
|
||||
active: true
|
||||
DocumentationOverPrivateFunction:
|
||||
active: false
|
||||
DocumentationOverPrivateProperty:
|
||||
active: false
|
||||
EndOfSentenceFormat:
|
||||
active: false
|
||||
endOfSentenceFormat: '([.?!][ \t\n\r\f<])|([.?!:]$)'
|
||||
KDocReferencesNonPublicProperty:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
OutdatedDocumentation:
|
||||
active: false
|
||||
matchTypeParameters: true
|
||||
matchDeclarationsOrder: true
|
||||
allowParamOnConstructorProperties: false
|
||||
UndocumentedPublicClass:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
searchInNestedClass: true
|
||||
searchInInnerClass: true
|
||||
searchInInnerObject: true
|
||||
searchInInnerInterface: true
|
||||
searchInProtectedClass: false
|
||||
ignoreDefaultCompanionObject: true
|
||||
UndocumentedPublicFunction:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
searchProtectedFunction: false
|
||||
UndocumentedPublicProperty:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
searchProtectedProperty: false
|
||||
ignoreEnumEntries: false
|
||||
|
||||
complexity:
|
||||
active: true
|
||||
CognitiveComplexMethod:
|
||||
active: false
|
||||
allowedComplexity: 20
|
||||
ComplexCondition:
|
||||
active: true
|
||||
allowedConditions: 4
|
||||
ComplexInterface:
|
||||
active: false
|
||||
allowedDefinitions: 10
|
||||
includeStaticDeclarations: false
|
||||
includePrivateDeclarations: false
|
||||
ignoreOverloaded: false
|
||||
CyclomaticComplexMethod:
|
||||
active: false
|
||||
allowedComplexity: 15
|
||||
ignoreSingleWhenExpression: false
|
||||
ignoreSimpleWhenEntries: false
|
||||
ignoreNestingFunctions: false
|
||||
ignoreLocalFunctions: false
|
||||
nestingFunctions:
|
||||
- 'also'
|
||||
- 'apply'
|
||||
- 'forEach'
|
||||
- 'isNotNull'
|
||||
- 'ifNull'
|
||||
- 'let'
|
||||
- 'run'
|
||||
- 'use'
|
||||
- 'with'
|
||||
LabeledExpression:
|
||||
active: false
|
||||
ignoredLabels: []
|
||||
LargeClass:
|
||||
active: false
|
||||
allowedLines: 700
|
||||
LongMethod:
|
||||
active: false
|
||||
allowedLines: 110
|
||||
LongParameterList:
|
||||
active: false
|
||||
allowedFunctionParameters: 8
|
||||
allowedConstructorParameters: 8
|
||||
ignoreDefaultParameters: false
|
||||
ignoreDataClasses: true
|
||||
ignoreAnnotatedParameter: []
|
||||
MethodOverloading:
|
||||
active: false
|
||||
allowedOverloads: 6
|
||||
NamedArguments:
|
||||
active: false
|
||||
allowedArguments: 3
|
||||
ignoreMethods: []
|
||||
ignoreArgumentsMatchingNames: false
|
||||
NestedBlockDepth:
|
||||
active: true
|
||||
allowedDepth: 4
|
||||
NestedScopeFunctions:
|
||||
active: false
|
||||
allowedDepth: 1
|
||||
functions:
|
||||
- 'kotlin.apply'
|
||||
- 'kotlin.run'
|
||||
- 'kotlin.with'
|
||||
- 'kotlin.let'
|
||||
- 'kotlin.also'
|
||||
ReplaceSafeCallChainWithRun:
|
||||
active: false
|
||||
StringLiteralDuplication:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
allowedDuplications: 3
|
||||
ignoreAnnotation: true
|
||||
allowedWithLengthLessThan: 5
|
||||
ignoreStringsRegex: '$^'
|
||||
TooManyFunctions:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
allowedFunctionsPerFile: 20
|
||||
allowedFunctionsPerClass: 20
|
||||
allowedFunctionsPerInterface: 20
|
||||
allowedFunctionsPerObject: 20
|
||||
allowedFunctionsPerEnum: 11
|
||||
ignoreDeprecated: true
|
||||
ignorePrivate: true
|
||||
ignoreInternal: true
|
||||
ignoreOverridden: false
|
||||
ignoreAnnotatedFunctions: []
|
||||
|
||||
coroutines:
|
||||
active: true
|
||||
CoroutineLaunchedInTestWithoutRunTest:
|
||||
active: false
|
||||
GlobalCoroutineUsage:
|
||||
active: true
|
||||
InjectDispatcher:
|
||||
active: false
|
||||
dispatcherNames:
|
||||
- 'IO'
|
||||
- 'Default'
|
||||
- 'Unconfined'
|
||||
RedundantSuspendModifier:
|
||||
active: true
|
||||
SleepInsteadOfDelay:
|
||||
active: true
|
||||
SuspendFunInFinallySection:
|
||||
active: false
|
||||
SuspendFunSwallowedCancellation:
|
||||
active: false
|
||||
SuspendFunWithCoroutineScopeReceiver:
|
||||
active: false
|
||||
aliases: ['SuspendFunctionOnCoroutineScope']
|
||||
SuspendFunWithFlowReturnType:
|
||||
active: true
|
||||
|
||||
empty-blocks:
|
||||
active: true
|
||||
EmptyCatchBlock:
|
||||
active: true
|
||||
allowedExceptionNameRegex: '_|(ignore|expected).*'
|
||||
EmptyClassBlock:
|
||||
active: true
|
||||
EmptyDefaultConstructor:
|
||||
active: true
|
||||
EmptyDoWhileBlock:
|
||||
active: true
|
||||
EmptyElseBlock:
|
||||
active: true
|
||||
EmptyFinallyBlock:
|
||||
active: true
|
||||
EmptyForBlock:
|
||||
active: true
|
||||
EmptyFunctionBlock:
|
||||
active: true
|
||||
ignoreOverridden: false
|
||||
EmptyIfBlock:
|
||||
active: true
|
||||
EmptyInitBlock:
|
||||
active: true
|
||||
EmptyKotlinFile:
|
||||
active: true
|
||||
EmptySecondaryConstructor:
|
||||
active: true
|
||||
EmptyTryBlock:
|
||||
active: true
|
||||
EmptyWhenBlock:
|
||||
active: true
|
||||
EmptyWhileBlock:
|
||||
active: true
|
||||
|
||||
exceptions:
|
||||
active: true
|
||||
ErrorUsageWithThrowable:
|
||||
active: false
|
||||
ExceptionRaisedInUnexpectedLocation:
|
||||
active: true
|
||||
methodNames:
|
||||
- 'equals'
|
||||
- 'finalize'
|
||||
- 'hashCode'
|
||||
- 'toString'
|
||||
InstanceOfCheckForException:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
NotImplementedDeclaration:
|
||||
active: true
|
||||
ObjectExtendsThrowable:
|
||||
active: true
|
||||
PrintStackTrace:
|
||||
active: true
|
||||
RethrowCaughtException:
|
||||
active: true
|
||||
ReturnFromFinally:
|
||||
active: true
|
||||
ignoreLabeled: false
|
||||
SwallowedException:
|
||||
active: true
|
||||
ignoredExceptionTypes:
|
||||
- 'InterruptedException'
|
||||
- 'MalformedURLException'
|
||||
- 'NumberFormatException'
|
||||
- 'ParseException'
|
||||
allowedExceptionNameRegex: '_|(ignore|expected).*'
|
||||
ThrowingExceptionFromFinally:
|
||||
active: true
|
||||
ThrowingExceptionInMain:
|
||||
active: false
|
||||
ThrowingExceptionsWithoutMessageOrCause:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
exceptions:
|
||||
- 'ArrayIndexOutOfBoundsException'
|
||||
- 'Exception'
|
||||
- 'IllegalArgumentException'
|
||||
- 'IllegalMonitorStateException'
|
||||
- 'IllegalStateException'
|
||||
- 'IndexOutOfBoundsException'
|
||||
- 'NullPointerException'
|
||||
- 'RuntimeException'
|
||||
- 'Throwable'
|
||||
ThrowingNewInstanceOfSameException:
|
||||
active: true
|
||||
TooGenericExceptionCaught:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
exceptionNames:
|
||||
- 'ArrayIndexOutOfBoundsException'
|
||||
- 'Error'
|
||||
- 'Exception'
|
||||
- 'IllegalMonitorStateException'
|
||||
- 'IndexOutOfBoundsException'
|
||||
- 'NullPointerException'
|
||||
- 'RuntimeException'
|
||||
- 'Throwable'
|
||||
allowedExceptionNameRegex: '_|(ignore|expected).*'
|
||||
TooGenericExceptionThrown:
|
||||
active: false
|
||||
exceptionNames:
|
||||
- 'Error'
|
||||
- 'Exception'
|
||||
- 'RuntimeException'
|
||||
- 'Throwable'
|
||||
|
||||
naming:
|
||||
active: true
|
||||
BooleanPropertyNaming:
|
||||
active: false
|
||||
allowedPattern: '^(is|has|are)'
|
||||
ClassNaming:
|
||||
active: true
|
||||
aliases: ['ClassName']
|
||||
classPattern: '[A-Z][a-zA-Z0-9]*'
|
||||
ConstructorParameterNaming:
|
||||
active: true
|
||||
parameterPattern: '[a-z][A-Za-z0-9]*'
|
||||
privateParameterPattern: '[a-z][A-Za-z0-9]*'
|
||||
excludeClassPattern: '$^'
|
||||
EnumNaming:
|
||||
active: true
|
||||
aliases: ['EnumEntryName']
|
||||
enumEntryPattern: '[A-Z][_a-zA-Z0-9]*'
|
||||
ForbiddenClassName:
|
||||
active: false
|
||||
forbiddenName: []
|
||||
FunctionNameMaxLength:
|
||||
active: false
|
||||
aliases: ['FunctionMaxNameLength']
|
||||
maximumFunctionNameLength: 30
|
||||
FunctionNameMinLength:
|
||||
active: false
|
||||
aliases: ['FunctionMinNameLength']
|
||||
minimumFunctionNameLength: 3
|
||||
FunctionNaming:
|
||||
active: true
|
||||
aliases: ['FunctionName']
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
functionPattern: '[a-z][a-zA-Z0-9]*'
|
||||
excludeClassPattern: '$^'
|
||||
FunctionParameterNaming:
|
||||
active: true
|
||||
parameterPattern: '[a-z][A-Za-z0-9]*'
|
||||
excludeClassPattern: '$^'
|
||||
InvalidPackageDeclaration:
|
||||
active: true
|
||||
aliases: ['PackageDirectoryMismatch']
|
||||
rootPackage: ''
|
||||
requireRootInDeclaration: false
|
||||
LambdaParameterNaming:
|
||||
active: false
|
||||
parameterPattern: '[a-z][A-Za-z0-9]*|_'
|
||||
MatchingDeclarationName:
|
||||
active: false
|
||||
mustBeFirst: true
|
||||
multiplatformTargets:
|
||||
- 'ios'
|
||||
- 'android'
|
||||
- 'js'
|
||||
- 'jvm'
|
||||
- 'native'
|
||||
- 'iosArm64'
|
||||
- 'iosX64'
|
||||
- 'macosX64'
|
||||
- 'mingwX64'
|
||||
- 'linuxX64'
|
||||
MemberNameEqualsClassName:
|
||||
active: true
|
||||
ignoreOverridden: true
|
||||
NoNameShadowing:
|
||||
active: true
|
||||
NonBooleanPropertyPrefixedWithIs:
|
||||
active: true
|
||||
ObjectPropertyNaming:
|
||||
active: true
|
||||
aliases: ['ObjectPropertyName']
|
||||
constantPattern: '[A-Za-z][_A-Za-z0-9]*'
|
||||
propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
|
||||
privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*'
|
||||
PackageNaming:
|
||||
active: true
|
||||
aliases: ['PackageName']
|
||||
packagePattern: '[a-z]+(\.[a-z][A-Za-z0-9]*)*'
|
||||
TopLevelPropertyNaming:
|
||||
active: true
|
||||
constantPattern: '[A-Z][_A-Z0-9]*'
|
||||
propertyPattern: '[A-Za-z][_A-Za-z0-9]*'
|
||||
privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*'
|
||||
VariableMaxLength:
|
||||
active: false
|
||||
maximumVariableNameLength: 64
|
||||
VariableMinLength:
|
||||
active: false
|
||||
minimumVariableNameLength: 1
|
||||
VariableNaming:
|
||||
active: false
|
||||
aliases: ['PropertyName']
|
||||
variablePattern: '[a-z][A-Za-z0-9]*'
|
||||
privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*'
|
||||
excludeClassPattern: '$^'
|
||||
|
||||
performance:
|
||||
active: true
|
||||
ArrayPrimitive:
|
||||
active: true
|
||||
CouldBeSequence:
|
||||
active: false
|
||||
allowedOperations: 3
|
||||
ForEachOnRange:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
SpreadOperator:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
UnnecessaryInitOnArray:
|
||||
active: false
|
||||
UnnecessaryPartOfBinaryExpression:
|
||||
active: true
|
||||
UnnecessaryTemporaryInstantiation:
|
||||
active: true
|
||||
UnnecessaryTypeCasting:
|
||||
active: true
|
||||
|
||||
potential-bugs:
|
||||
active: true
|
||||
AvoidReferentialEquality:
|
||||
active: true
|
||||
forbiddenTypePatterns:
|
||||
- 'kotlin.String'
|
||||
CastNullableToNonNullableType:
|
||||
active: true
|
||||
ignorePlatformTypes: true
|
||||
CastToNullableType:
|
||||
active: false
|
||||
CharArrayToStringCall:
|
||||
active: false
|
||||
Deprecation:
|
||||
active: false
|
||||
aliases: ['DEPRECATION']
|
||||
excludeImportStatements: false
|
||||
DontDowncastCollectionTypes:
|
||||
active: false
|
||||
DoubleMutabilityForCollection:
|
||||
active: true
|
||||
aliases: ['DoubleMutability']
|
||||
mutableTypes:
|
||||
- 'kotlin.collections.MutableList'
|
||||
- 'kotlin.collections.MutableMap'
|
||||
- 'kotlin.collections.MutableSet'
|
||||
- 'java.util.ArrayList'
|
||||
- 'java.util.LinkedHashSet'
|
||||
- 'java.util.HashSet'
|
||||
- 'java.util.LinkedHashMap'
|
||||
- 'java.util.HashMap'
|
||||
ElseCaseInsteadOfExhaustiveWhen:
|
||||
active: false
|
||||
ignoredSubjectTypes: []
|
||||
EqualsAlwaysReturnsTrueOrFalse:
|
||||
active: true
|
||||
EqualsWithHashCodeExist:
|
||||
active: true
|
||||
ExitOutsideMain:
|
||||
active: false
|
||||
ExplicitGarbageCollectionCall:
|
||||
active: true
|
||||
HasPlatformType:
|
||||
active: true
|
||||
IgnoredReturnValue:
|
||||
active: true
|
||||
restrictToConfig: true
|
||||
returnValueAnnotations:
|
||||
- 'CheckResult'
|
||||
- '*.CheckResult'
|
||||
- 'CheckReturnValue'
|
||||
- '*.CheckReturnValue'
|
||||
ignoreReturnValueAnnotations:
|
||||
- 'CanIgnoreReturnValue'
|
||||
- '*.CanIgnoreReturnValue'
|
||||
returnValueTypes:
|
||||
- 'kotlin.Function*'
|
||||
- 'kotlin.sequences.Sequence'
|
||||
- 'kotlinx.coroutines.flow.*Flow'
|
||||
- 'java.util.stream.*Stream'
|
||||
ignoreFunctionCall: []
|
||||
ImplicitDefaultLocale:
|
||||
active: true
|
||||
ImplicitUnitReturnType:
|
||||
active: false
|
||||
ignoreAnnotated: ['Test']
|
||||
allowExplicitReturnType: true
|
||||
InvalidRange:
|
||||
active: true
|
||||
IteratorHasNextCallsNextMethod:
|
||||
active: true
|
||||
IteratorNotThrowingNoSuchElementException:
|
||||
active: true
|
||||
LateinitUsage:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
ignoreOnClassesPattern: ''
|
||||
MapGetWithNotNullAssertionOperator:
|
||||
active: true
|
||||
MissingPackageDeclaration:
|
||||
active: true
|
||||
excludes: ['**/*.kts']
|
||||
MissingSuperCall:
|
||||
active: false
|
||||
mustInvokeSuperAnnotations:
|
||||
- 'androidx.annotation.CallSuper'
|
||||
- 'javax.annotation.OverridingMethodsMustInvokeSuper'
|
||||
MissingUseCall:
|
||||
active: false
|
||||
ignoreClass:
|
||||
- 'java.io.ByteArrayInputStream'
|
||||
- 'java.io.ByteArrayOutputStream'
|
||||
NullCheckOnMutableProperty:
|
||||
active: false
|
||||
NullableToStringCall:
|
||||
active: false
|
||||
PropertyUsedBeforeDeclaration:
|
||||
active: false
|
||||
UnconditionalJumpStatementInLoop:
|
||||
active: false
|
||||
UnnamedParameterUse:
|
||||
active: false
|
||||
allowAdjacentDifferentTypeParams: true
|
||||
allowSingleParamUse: true
|
||||
ignoreArgumentsMatchingNames: true
|
||||
ignoreFunctionCall: []
|
||||
UnnecessaryNotNullCheck:
|
||||
active: false
|
||||
UnnecessaryNotNullOperator:
|
||||
active: true
|
||||
UnnecessarySafeCall:
|
||||
active: true
|
||||
UnreachableCatchBlock:
|
||||
active: true
|
||||
UnreachableCode:
|
||||
active: true
|
||||
UnsafeCallOnNullableType:
|
||||
active: true
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**']
|
||||
UnsafeCast:
|
||||
active: true
|
||||
aliases: ['UNCHECKED_CAST']
|
||||
UnusedUnaryOperator:
|
||||
active: true
|
||||
UselessPostfixExpression:
|
||||
active: true
|
||||
WrongEqualsTypeParameter:
|
||||
active: true
|
||||
|
||||
style:
|
||||
active: true
|
||||
AbstractClassCanBeConcreteClass:
|
||||
active: true
|
||||
AbstractClassCanBeInterface:
|
||||
active: true
|
||||
AlsoCouldBeApply:
|
||||
active: false
|
||||
BracesOnIfStatements:
|
||||
active: false
|
||||
singleLine: 'never'
|
||||
multiLine: 'always'
|
||||
BracesOnWhenStatements:
|
||||
active: false
|
||||
singleLine: 'necessary'
|
||||
multiLine: 'consistent'
|
||||
CanBeNonNullable:
|
||||
active: false
|
||||
CascadingCallWrapping:
|
||||
active: false
|
||||
includeElvis: true
|
||||
ClassOrdering:
|
||||
active: false
|
||||
CollapsibleIfStatements:
|
||||
active: false
|
||||
DataClassContainsFunctions:
|
||||
active: false
|
||||
conversionFunctionPrefix:
|
||||
- 'to'
|
||||
allowOperators: false
|
||||
DataClassShouldBeImmutable:
|
||||
active: false
|
||||
DestructuringDeclarationWithTooManyEntries:
|
||||
active: true
|
||||
maxDestructuringEntries: 3
|
||||
DoubleNegativeExpression:
|
||||
active: false
|
||||
DoubleNegativeLambda:
|
||||
active: false
|
||||
negativeFunctions:
|
||||
- reason: 'Use `takeIf` instead.'
|
||||
value: 'takeUnless'
|
||||
- reason: 'Use `all` instead.'
|
||||
value: 'none'
|
||||
negativeFunctionNameParts:
|
||||
- 'not'
|
||||
- 'non'
|
||||
EqualsNullCall:
|
||||
active: true
|
||||
EqualsOnSignatureLine:
|
||||
active: false
|
||||
ExplicitCollectionElementAccessMethod:
|
||||
active: false
|
||||
ExplicitItLambdaMultipleParameters:
|
||||
active: true
|
||||
ExplicitItLambdaParameter:
|
||||
active: false
|
||||
ExpressionBodySyntax:
|
||||
active: false
|
||||
includeLineWrapping: false
|
||||
ForbiddenAnnotation:
|
||||
active: true
|
||||
annotations:
|
||||
- reason: 'it is a java annotation. Use `Suppress` instead.'
|
||||
value: 'java.lang.SuppressWarnings'
|
||||
- reason: 'it is a java annotation. Use `kotlin.Deprecated` instead.'
|
||||
value: 'java.lang.Deprecated'
|
||||
- reason: 'it is a java annotation. Use `kotlin.annotation.MustBeDocumented` instead.'
|
||||
value: 'java.lang.annotation.Documented'
|
||||
- reason: 'it is a java annotation. Use `kotlin.annotation.Target` instead.'
|
||||
value: 'java.lang.annotation.Target'
|
||||
- reason: 'it is a java annotation. Use `kotlin.annotation.Retention` instead.'
|
||||
value: 'java.lang.annotation.Retention'
|
||||
- reason: 'it is a java annotation. Use `kotlin.annotation.Repeatable` instead.'
|
||||
value: 'java.lang.annotation.Repeatable'
|
||||
ForbiddenComment:
|
||||
active: true
|
||||
comments:
|
||||
- reason: 'Forbidden FIXME todo marker in comment, please fix the problem.'
|
||||
value: 'FIXME:'
|
||||
- reason: 'Forbidden STOPSHIP todo marker in comment, please address the problem before shipping the code.'
|
||||
value: 'STOPSHIP:'
|
||||
- reason: 'Forbidden TODO todo marker in comment, please do the changes.'
|
||||
value: 'TODO:'
|
||||
allowedPatterns: ''
|
||||
ForbiddenImport:
|
||||
active: false
|
||||
forbiddenImports: []
|
||||
allowedImports: []
|
||||
ForbiddenMethodCall:
|
||||
active: true
|
||||
methods:
|
||||
- reason: 'print does not allow you to configure the output stream. Use a logger instead.'
|
||||
value: 'kotlin.io.print'
|
||||
- reason: 'println does not allow you to configure the output stream. Use a logger instead.'
|
||||
value: 'kotlin.io.println'
|
||||
- reason: 'using `BigDecimal(Double)` can result in unexpected floating point precision behavior. Use `BigDecimal.valueOf(Double)` or `String.toBigDecimalOrNull()` instead.'
|
||||
value: 'java.math.BigDecimal.<init>(kotlin.Double)'
|
||||
- reason: 'using `BigDecimal(String)` can result in a `NumberFormatException`. Use `String.toBigDecimalOrNull()`'
|
||||
value: 'java.math.BigDecimal.<init>(kotlin.String)'
|
||||
- reason: 'It is marked as obsolete. Use `kotlin.time.measureTime` instead.'
|
||||
value: 'kotlin.system.measureTimeMillis'
|
||||
ForbiddenNamedParam:
|
||||
active: false
|
||||
methods: []
|
||||
ForbiddenOptIn:
|
||||
active: false
|
||||
markerClasses: []
|
||||
ForbiddenSuppress:
|
||||
active: false
|
||||
rules: []
|
||||
ForbiddenVoid:
|
||||
active: true
|
||||
ignoreOverridden: false
|
||||
ignoreUsageInGenerics: false
|
||||
FunctionOnlyReturningConstant:
|
||||
active: true
|
||||
ignoreOverridableFunction: true
|
||||
ignoreActualFunction: true
|
||||
excludedFunctions: []
|
||||
LoopWithTooManyJumpStatements:
|
||||
active: true
|
||||
maxJumpCount: 1
|
||||
MagicNumber:
|
||||
active: false
|
||||
excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**', '**/*.kts']
|
||||
ignoreNumbers:
|
||||
- '-1'
|
||||
- '0'
|
||||
- '1'
|
||||
- '2'
|
||||
ignoreHashCodeFunction: true
|
||||
ignorePropertyDeclaration: true
|
||||
ignoreLocalVariableDeclaration: true
|
||||
ignoreConstantDeclaration: true
|
||||
ignoreCompanionObjectPropertyDeclaration: true
|
||||
ignoreAnnotation: false
|
||||
ignoreNamedArgument: true
|
||||
ignoreEnums: false
|
||||
ignoreRanges: false
|
||||
ignoreExtensionFunctions: true
|
||||
MandatoryBracesLoops:
|
||||
active: false
|
||||
MaxChainedCallsOnSameLine:
|
||||
active: false
|
||||
maxChainedCalls: 5
|
||||
MaxLineLength:
|
||||
active: false
|
||||
maxLineLength: 120
|
||||
excludePackageStatements: true
|
||||
excludeImportStatements: true
|
||||
excludeCommentStatements: false
|
||||
excludeRawStrings: true
|
||||
MayBeConstant:
|
||||
active: true
|
||||
ModifierOrder:
|
||||
active: true
|
||||
MultilineLambdaItParameter:
|
||||
active: false
|
||||
MultilineRawStringIndentation:
|
||||
active: false
|
||||
indentSize: 4
|
||||
trimmingMethods:
|
||||
- 'trimIndent'
|
||||
- 'trimMargin'
|
||||
NestedClassesVisibility:
|
||||
active: true
|
||||
NewLineAtEndOfFile:
|
||||
active: true
|
||||
NoTabs:
|
||||
active: false
|
||||
NullableBooleanCheck:
|
||||
active: false
|
||||
ObjectLiteralToLambda:
|
||||
active: true
|
||||
OptionalAbstractKeyword:
|
||||
active: true
|
||||
OptionalUnit:
|
||||
active: false
|
||||
ProtectedMemberInFinalClass:
|
||||
active: true
|
||||
RangeUntilInsteadOfRangeTo:
|
||||
active: true
|
||||
RedundantConstructorKeyword:
|
||||
active: false
|
||||
RedundantExplicitType:
|
||||
active: false
|
||||
RedundantHigherOrderMapUsage:
|
||||
active: true
|
||||
RedundantVisibilityModifier:
|
||||
active: false
|
||||
ReturnCount:
|
||||
active: false
|
||||
max: 2
|
||||
excludedFunctions:
|
||||
- 'equals'
|
||||
excludeLabeled: false
|
||||
excludeReturnFromLambda: true
|
||||
excludeGuardClauses: false
|
||||
SafeCast:
|
||||
active: true
|
||||
SerialVersionUIDInSerializableClass:
|
||||
active: true
|
||||
SpacingAfterPackageAndImports:
|
||||
active: false
|
||||
StringShouldBeRawString:
|
||||
active: false
|
||||
maxEscapedCharacterCount: 2
|
||||
ignoredCharacters: []
|
||||
ThrowsCount:
|
||||
active: false
|
||||
max: 2
|
||||
excludeGuardClauses: false
|
||||
TrailingWhitespace:
|
||||
active: false
|
||||
TrimMultilineRawString:
|
||||
active: false
|
||||
trimmingMethods:
|
||||
- 'trimIndent'
|
||||
- 'trimMargin'
|
||||
UnderscoresInNumericLiterals:
|
||||
active: false
|
||||
acceptableLength: 4
|
||||
allowNonStandardGrouping: false
|
||||
UnnecessaryAny:
|
||||
active: false
|
||||
UnnecessaryApply:
|
||||
active: true
|
||||
UnnecessaryBackticks:
|
||||
active: false
|
||||
UnnecessaryBracesAroundTrailingLambda:
|
||||
active: false
|
||||
UnnecessaryFilter:
|
||||
active: true
|
||||
UnnecessaryFullyQualifiedName:
|
||||
active: true
|
||||
UnnecessaryInheritance:
|
||||
active: true
|
||||
UnnecessaryInnerClass:
|
||||
active: false
|
||||
UnnecessaryLet:
|
||||
active: false
|
||||
UnnecessaryParentheses:
|
||||
active: false
|
||||
allowForUnclearPrecedence: false
|
||||
UnnecessaryReversed:
|
||||
active: false
|
||||
UnusedImport:
|
||||
active: false
|
||||
additionalOperatorSet: []
|
||||
UnusedParameter:
|
||||
active: true
|
||||
aliases: ['UNUSED_PARAMETER', 'unused']
|
||||
allowedNames: 'ignored|expected'
|
||||
UnusedPrivateClass:
|
||||
active: true
|
||||
aliases: ['unused']
|
||||
UnusedPrivateFunction:
|
||||
active: true
|
||||
aliases: ['unused']
|
||||
allowedNames: ''
|
||||
UnusedPrivateProperty:
|
||||
active: true
|
||||
aliases: ['unused']
|
||||
allowedNames: 'ignored|expected|serialVersionUID'
|
||||
UnusedVariable:
|
||||
active: true
|
||||
aliases: ['UNUSED_VARIABLE', 'unused']
|
||||
allowedNames: 'ignored|_'
|
||||
UseAnyOrNoneInsteadOfFind:
|
||||
active: true
|
||||
UseArrayLiteralsInAnnotations:
|
||||
active: true
|
||||
UseCheckNotNull:
|
||||
active: true
|
||||
UseCheckOrError:
|
||||
active: true
|
||||
UseDataClass:
|
||||
active: false
|
||||
allowVars: false
|
||||
UseEmptyCounterpart:
|
||||
active: false
|
||||
UseIfEmptyOrIfBlank:
|
||||
active: false
|
||||
UseIfInsteadOfWhen:
|
||||
active: false
|
||||
ignoreWhenContainingVariableDeclaration: false
|
||||
UseIsNullOrEmpty:
|
||||
active: true
|
||||
UseLet:
|
||||
active: false
|
||||
UseOrEmpty:
|
||||
active: true
|
||||
UseRequire:
|
||||
active: true
|
||||
UseRequireNotNull:
|
||||
active: true
|
||||
UseSumOfInsteadOfFlatMapSize:
|
||||
active: false
|
||||
UselessCallOnNotNull:
|
||||
active: true
|
||||
UtilityClassWithPublicConstructor:
|
||||
active: true
|
||||
VarCouldBeVal:
|
||||
active: true
|
||||
aliases: ['CanBeVal']
|
||||
ignoreLateinitVar: false
|
||||
WildcardImport:
|
||||
active: false
|
||||
excludeImports:
|
||||
- 'java.util.*'
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ internal const val WAV_BASE64 = "UklGRiYAAABXQVZFZm10IBAAAAABAAEAQB8AAAB9AAACABA
|
|||
|
||||
private val logger = KotlinLogging.logger {}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
fun Server.registerConformanceTools() {
|
||||
// 1. Simple text
|
||||
addTool(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# plugins version
|
||||
atomicfu = "0.32.1"
|
||||
binaryCompatibilityValidatorPlugin = "0.18.1"
|
||||
detekt = "2.0.0-alpha.2"
|
||||
detekt = "2.0.0-alpha.3"
|
||||
dokka = "2.2.0"
|
||||
kotlin = "2.3.21"
|
||||
kover = "0.9.8"
|
||||
|
|
@ -28,6 +28,7 @@ junit = "5.14.3"
|
|||
|
||||
[libraries]
|
||||
# Plugins
|
||||
detekt-gradle = { module = "dev.detekt:detekt-gradle-plugin", version.ref = "detekt" }
|
||||
dokka-gradle = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
|
||||
kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" }
|
||||
|
|
@ -75,7 +76,6 @@ ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "
|
|||
ktor-server-cio = { group = "io.ktor", name = "ktor-server-cio", version.ref = "ktor" }
|
||||
|
||||
[plugins]
|
||||
detekt = { id = "dev.detekt", version.ref = "detekt" }
|
||||
kotlinx-binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binaryCompatibilityValidatorPlugin" }
|
||||
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
|
||||
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
plugins {
|
||||
id("mcp.multiplatform")
|
||||
id("mcp.detekt")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>AbstractClassCanBeConcreteClass:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$AbstractPromptIntegrationTest</ID>
|
||||
<ID>AbstractClassCanBeConcreteClass:AbstractResourceIntegrationTest.kt:AbstractResourceIntegrationTest$AbstractResourceIntegrationTest</ID>
|
||||
<ID>AbstractClassCanBeConcreteClass:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$AbstractToolIntegrationTest</ID>
|
||||
<ID>AbstractClassCanBeConcreteClass:BaseTransportTest.kt:BaseTransportTest$BaseTransportTest</ID>
|
||||
<ID>CyclomaticComplexMethod:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$private fun setupCalculatorTool</ID>
|
||||
<ID>ForbiddenComment:StdioClientTransportTest.kt:StdioClientTransportTest$// TODO: fix running on windows</ID>
|
||||
<ID>MatchingDeclarationName:PromptIntegrationTestSse.kt:SchemaPromptIntegrationTestSse : AbstractPromptIntegrationTest</ID>
|
||||
<ID>ThrowsCount:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$override fun configureServer</ID>
|
||||
<ID>UseCheckOrError:ClientTest.kt:ClientTest.<no name provided>$throw IllegalStateException("Test error")</ID>
|
||||
<ID>UseOrEmpty:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$(request.params.arguments?.get("tags") as? JsonArray)?.mapNotNull { (it as? JsonPrimitive)?.content } ?: emptyList()</ID>
|
||||
<ID>UseRequire:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$throw IllegalArgumentException("Missing required argument: $argName")</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
|||
|
||||
plugins {
|
||||
id("mcp.multiplatform")
|
||||
id("mcp.detekt")
|
||||
id("mcp.publishing")
|
||||
id("mcp.dokka")
|
||||
alias(libs.plugins.kotlinx.binary.compatibility.validator)
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>CyclomaticComplexMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
|
||||
<ID>LongMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
|
||||
<ID>MaxLineLength:StdioClientTransport.kt:StdioClientTransport$*</ID>
|
||||
<ID>ThrowsCount:SseClientTransport.kt:SseClientTransport$private suspend fun CoroutineScope.collectMessages</ID>
|
||||
<ID>ThrowsCount:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$@Suppress("ReturnCount", "CyclomaticComplexMethod") override suspend fun performSend</ID>
|
||||
<ID>TooGenericExceptionCaught:Client.kt:Client$error: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:SseClientTransport.kt:SseClientTransport$e: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:StdioClientTransport.kt:StdioClientTransport$e: Throwable</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}"""</ID>
|
||||
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"$lastEventIdSent"}}"""</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -2,18 +2,6 @@
|
|||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>CyclomaticComplexMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
|
||||
<ID>InjectDispatcher:StdioClientTransport.kt:StdioClientTransport$Default</ID>
|
||||
<ID>InjectDispatcher:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$Default</ID>
|
||||
<ID>LongMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
|
||||
<ID>MaxLineLength:StdioClientTransport.kt:StdioClientTransport$*</ID>
|
||||
<ID>NoNameShadowing:StdioClientTransport.kt:StdioClientTransport$source</ID>
|
||||
<ID>ThrowsCount:SseClientTransport.kt:SseClientTransport$private suspend fun CoroutineScope.collectMessages</ID>
|
||||
<ID>ThrowsCount:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$@Suppress("ReturnCount", "CyclomaticComplexMethod") override suspend fun performSend</ID>
|
||||
<ID>TooGenericExceptionCaught:Client.kt:Client$error: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:SseClientTransport.kt:SseClientTransport$e: Throwable</ID>
|
||||
<ID>TooGenericExceptionCaught:StdioClientTransport.kt:StdioClientTransport$e: Throwable</ID>
|
||||
<ID>UseCheckOrError:Client.kt:Client$throw IllegalStateException( "Server does not support resource subscriptions (required for $method)", )</ID>
|
||||
<ID>UseCheckOrError:Client.kt:Client$throw IllegalStateException("Client does not support roots capability.")</ID>
|
||||
<ID>LoopWithTooManyJumpStatements:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$while</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<SmellBaseline>
|
||||
<ManuallySuppressedIssues/>
|
||||
<CurrentIssues>
|
||||
<ID>AbstractClassCanBeConcreteClass:AbstractStreamableHttpClientTest.kt:AbstractStreamableHttpClientTest$AbstractStreamableHttpClientTest</ID>
|
||||
<ID>ForbiddenComment:StreamableHttpClientTest.kt:StreamableHttpClientTest$// TODO: how to get notifications via Client API?</ID>
|
||||
<ID>LongParameterList:MockMcp.kt:MockMcp$fun handleJSONRPCRequest</ID>
|
||||
<ID>LongParameterList:MockMcp.kt:MockMcp$fun handleWithResult</ID>
|
||||
<ID>LongParameterList:MockMcp.kt:MockMcp$fun onInitialize</ID>
|
||||
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}"""</ID>
|
||||
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"$lastEventIdSent"}}"""</ID>
|
||||
<ID>UseOrEmpty:ClientMetaParameterTest.kt:ClientMetaParameterTest$exception.message ?: ""</ID>
|
||||
</CurrentIssues>
|
||||
</SmellBaseline>
|
||||
|
|
@ -83,7 +83,7 @@ private val logger = KotlinLogging.logger {}
|
|||
* Options for configuring the MCP client.
|
||||
*
|
||||
* @property capabilities The capabilities this client supports.
|
||||
* @property enforceStrictCapabilities Whether to strictly enforce capabilities when interacting with the server.
|
||||
* @param enforceStrictCapabilities Whether to strictly enforce capabilities when interacting with the server.
|
||||
*/
|
||||
public class ClientOptions(
|
||||
public val capabilities: ClientCapabilities = ClientCapabilities(),
|
||||
|
|
@ -125,7 +125,6 @@ public suspend fun mcpClient(
|
|||
* @param clientInfo Information about the client implementation (name, version).
|
||||
* @param options Configuration options for this client.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
public open class Client(private val clientInfo: Implementation, options: ClientOptions = ClientOptions()) :
|
||||
Protocol(options) {
|
||||
|
||||
|
|
@ -242,7 +241,7 @@ public open class Client(private val clientInfo: Implementation, options: Client
|
|||
Method.Defined.CompletionComplete,
|
||||
-> {
|
||||
checkNotNull(serverCapabilities?.prompts) {
|
||||
throw IllegalStateException("Server does not support prompts (required for $method)")
|
||||
"Server does not support prompts (required for $method)"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -255,10 +254,10 @@ public open class Client(private val clientInfo: Implementation, options: Client
|
|||
val resCaps = serverCapabilities?.resources
|
||||
?: error("Server does not support resources (required for $method)")
|
||||
|
||||
if (method == Method.Defined.ResourcesSubscribe && resCaps.subscribe != true) {
|
||||
throw IllegalStateException(
|
||||
"Server does not support resource subscriptions (required for $method)",
|
||||
)
|
||||
if (method == Method.Defined.ResourcesSubscribe) {
|
||||
check(resCaps.subscribe == true) {
|
||||
"Server does not support resource subscriptions (required for $method)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -556,9 +555,8 @@ public open class Client(private val clientInfo: Implementation, options: Client
|
|||
* @throws IllegalStateException If the client does not support roots.
|
||||
*/
|
||||
public fun removeRoot(uri: String): Boolean {
|
||||
if (capabilities.roots == null) {
|
||||
logger.error { "Failed to remove root '$uri': Client does not support roots capability" }
|
||||
throw IllegalStateException("Client does not support roots capability.")
|
||||
checkNotNull(capabilities.roots) {
|
||||
"Client does not support roots capability."
|
||||
}
|
||||
logger.info { "Removing root: $uri" }
|
||||
val oldMap = roots.getAndUpdate { current -> current.remove(uri) }
|
||||
|
|
@ -636,7 +634,6 @@ public open class Client(private val clientInfo: Implementation, options: Client
|
|||
|
||||
// --- Internal Handlers ---
|
||||
|
||||
@Suppress("ReturnCount")
|
||||
private fun applyElicitationDefaults(request: ElicitRequest, result: ElicitResult): ElicitResult {
|
||||
if (result.action != ElicitResult.Action.Accept) return result
|
||||
val formParams = request.params as? ElicitRequestFormParams ?: return result
|
||||
|
|
|
|||
|
|
@ -227,7 +227,6 @@ public class StdioClientTransport @JvmOverloads public constructor(
|
|||
}
|
||||
|
||||
override suspend fun performSend(message: JSONRPCMessage, options: TransportSendOptions?) {
|
||||
@Suppress("SwallowedException")
|
||||
try {
|
||||
sendChannel.send(message)
|
||||
} catch (e: CancellationException) {
|
||||
|
|
@ -290,7 +289,7 @@ public class StdioClientTransport @JvmOverloads public constructor(
|
|||
) {
|
||||
val buffer = Buffer()
|
||||
try {
|
||||
source.use { source ->
|
||||
source.use {
|
||||
while (isActive) {
|
||||
val bytesRead = source.readAtMostTo(buffer, BUFFER_SIZE)
|
||||
if (bytesRead == -1L) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ private const val MCP_RESUMPTION_TOKEN_HEADER = "Last-Event-ID"
|
|||
* Represents an error from the Streamable HTTP transport.
|
||||
*
|
||||
* @property code HTTP status code associated with the error, or `null` if unavailable
|
||||
* @param message detailed error description appended to the exception message
|
||||
*/
|
||||
public class StreamableHttpError(public val code: Int? = null, message: String? = null) :
|
||||
Exception("Streamable HTTP error: $message")
|
||||
|
|
@ -65,14 +66,17 @@ private sealed interface ConnectResult {
|
|||
}
|
||||
|
||||
/**
|
||||
* Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
|
||||
* It will connect to a server using HTTP POST for sending messages and HTTP GET with Server-Sent Events
|
||||
* for receiving messages.
|
||||
* Client transport implementing the MCP Streamable HTTP transport specification.
|
||||
*
|
||||
* @property sessionId session identifier assigned by the server after initialization, or `null` before connection
|
||||
* @property protocolVersion MCP protocol version negotiated with the server, or `null` before connection
|
||||
* Sends messages via HTTP POST and receives messages via HTTP GET with Server-Sent Events.
|
||||
* Supports automatic SSE reconnection with exponential backoff, stream resumption via the
|
||||
* `Last-Event-ID` header, and explicit session termination.
|
||||
*
|
||||
* @param client Ktor HTTP client used for all requests
|
||||
* @param url MCP endpoint URL
|
||||
* @param reconnectionOptions reconnection backoff and retry-limit settings for the SSE stream
|
||||
* @param requestBuilder builder applied to every outgoing HTTP request, e.g. for adding auth headers
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
public class StreamableHttpClientTransport(
|
||||
private val client: HttpClient,
|
||||
private val url: String,
|
||||
|
|
@ -98,8 +102,11 @@ public class StreamableHttpClientTransport(
|
|||
|
||||
override val logger: KLogger = KotlinLogging.logger {}
|
||||
|
||||
/** Session identifier assigned by the server after initialization, or `null` before connection. */
|
||||
public var sessionId: String? = null
|
||||
private set
|
||||
|
||||
/** MCP protocol version negotiated with the server, or `null` before connection. */
|
||||
public var protocolVersion: String? = null
|
||||
|
||||
private var sseJob: Job? = null
|
||||
|
|
@ -121,7 +128,6 @@ public class StreamableHttpClientTransport(
|
|||
/**
|
||||
* Sends a single message with optional resumption support
|
||||
*/
|
||||
@Suppress("ReturnCount", "CyclomaticComplexMethod", "LongMethod", "TooGenericExceptionCaught", "ThrowsCount")
|
||||
override suspend fun performSend(message: JSONRPCMessage, options: TransportSendOptions?) {
|
||||
logger.debug { "Client sending message via POST to $url: ${McpJson.encodeToString(message)}" }
|
||||
|
||||
|
|
@ -260,7 +266,6 @@ public class StreamableHttpClientTransport(
|
|||
var attempt = 0
|
||||
var needsDelay = initialServerRetryDelay != null
|
||||
|
||||
@Suppress("LoopWithTooManyJumpStatements")
|
||||
while (isActive) {
|
||||
// Delay before (re)connection: skip only for first fresh SSE connection
|
||||
if (needsDelay) {
|
||||
|
|
@ -296,7 +301,6 @@ public class StreamableHttpClientTransport(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
private suspend fun connectSse(lastEventId: String?): ConnectResult {
|
||||
logger.debug { "Client attempting to start SSE session at url: $url" }
|
||||
return try {
|
||||
|
|
@ -363,7 +367,6 @@ public class StreamableHttpClientTransport(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
private suspend fun collectSse(
|
||||
session: ClientSSESession,
|
||||
replayMessageId: RequestId?,
|
||||
|
|
@ -408,7 +411,6 @@ public class StreamableHttpClientTransport(
|
|||
return SseStreamResult(hasPrimingEvent, receivedResponse, localLastEventId, localServerRetryDelay)
|
||||
}
|
||||
|
||||
@Suppress("CyclomaticComplexMethod")
|
||||
private suspend fun handleInlineSse(
|
||||
response: HttpResponse,
|
||||
replayMessageId: RequestId?,
|
||||
|
|
@ -455,7 +457,6 @@ public class StreamableHttpClientTransport(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LoopWithTooManyJumpStatements")
|
||||
while (!channel.isClosedForRead) {
|
||||
val line = channel.readUTF8Line() ?: break
|
||||
if (line.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -834,7 +834,6 @@ class StreamableHttpClientTransportTest {
|
|||
transport.close()
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Test
|
||||
fun testDeprecatedConstructorStillWorks() = runTest {
|
||||
val mockEngine = MockEngine { _ ->
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue