aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/configuration.kt
blob: 65035d04e4afe56a9bcef5ab9d60e9f92e56086e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package org.jetbrains.dokka

import org.jetbrains.dokka.utilities.cast
import java.io.File
import java.io.Serializable
import java.net.URL

public object DokkaDefaults {
    public val moduleName: String = "root"
    public val moduleVersion: String? = null
    public val outputDir: File = File("./dokka")
    public const val failOnWarning: Boolean = false
    public const val suppressObviousFunctions: Boolean = true
    public const val suppressInheritedMembers: Boolean = false
    public const val offlineMode: Boolean = false

    public const val sourceSetDisplayName: String = "JVM"
    public const val sourceSetName: String = "main"
    public val analysisPlatform: Platform = Platform.DEFAULT

    public const val suppress: Boolean = false
    public const val suppressGeneratedFiles: Boolean = true

    public const val skipEmptyPackages: Boolean = true
    public const val skipDeprecated: Boolean = false

    public const val reportUndocumented: Boolean = false

    public const val noStdlibLink: Boolean = false
    public const val noAndroidSdkLink: Boolean = false
    public const val noJdkLink: Boolean = false
    public const val jdkVersion: Int = 8

    public const val includeNonPublic: Boolean = false
    public val documentedVisibilities: Set<DokkaConfiguration.Visibility> = setOf(DokkaConfiguration.Visibility.PUBLIC)

    public val pluginsConfiguration: List<PluginConfigurationImpl> = mutableListOf()

    public const val delayTemplateSubstitution: Boolean = false

    public val cacheRoot: File? = null
}

public enum class Platform(
    public val key: String
) {
    jvm("jvm"),
    js("js"),
    wasm("wasm"),
    native("native"),
    common("common");

    public companion object {
        public val DEFAULT: Platform = jvm

        public fun fromString(key: String): Platform {
            return when (key.toLowerCase()) {
                jvm.key -> jvm
                js.key -> js
                wasm.key -> wasm
                native.key -> native
                common.key -> common
                "androidjvm", "android" -> jvm
                "metadata" -> common
                else -> throw IllegalArgumentException("Unrecognized platform: $key")
            }
        }
    }
}

public fun interface DokkaConfigurationBuilder<T : Any> {
    public fun build(): T
}

public fun <T : Any> Iterable<DokkaConfigurationBuilder<T>>.build(): List<T> = this.map { it.build() }

public data class DokkaSourceSetID(
    /**
     * Unique identifier of the scope that this source set is placed in.
     * Each scope provide only unique source set names.
     *
     * E.g. One DokkaTask inside the Gradle plugin represents one source set scope, since there cannot be multiple
     * source sets with the same name. However, a Gradle project will not be a proper scope, since there can be
     * multple DokkaTasks that contain source sets with the same name (but different configuration)
     */
    val scopeId: String,
    val sourceSetName: String
) : Serializable {
    override fun toString(): String {
        return "$scopeId/$sourceSetName"
    }
}

/**
 * Global options can be configured and applied to all packages and modules at once, overwriting package configuration.
 *
 * These are handy if we have multiple source sets sharing the same global options as it reduces the size of the
 * boilerplate. Otherwise, the user would be forced to repeat all these options for each source set.
 *
 * @see [apply] to learn how to apply global configuration
 */
public data class GlobalDokkaConfiguration(
    val perPackageOptions: List<PackageOptionsImpl>?,
    val externalDocumentationLinks: List<ExternalDocumentationLinkImpl>?,
    val sourceLinks: List<SourceLinkDefinitionImpl>?
)

public fun DokkaConfiguration.apply(globals: GlobalDokkaConfiguration): DokkaConfiguration = this.apply {
    sourceSets.forEach {
        it.perPackageOptions.cast<MutableList<DokkaConfiguration.PackageOptions>>()
            .addAll(globals.perPackageOptions ?: emptyList())
    }

    sourceSets.forEach {
        it.externalDocumentationLinks.cast<MutableSet<DokkaConfiguration.ExternalDocumentationLink>>()
            .addAll(globals.externalDocumentationLinks ?: emptyList())
    }

    sourceSets.forEach {
        it.sourceLinks.cast<MutableSet<SourceLinkDefinitionImpl>>().addAll(globals.sourceLinks ?: emptyList())
    }
}

public interface DokkaConfiguration : Serializable {
    public val moduleName: String
    public val moduleVersion: String?
    public val outputDir: File
    public val cacheRoot: File?
    public val offlineMode: Boolean
    public val failOnWarning: Boolean
    public val sourceSets: List<DokkaSourceSet>
    public val modules: List<DokkaModuleDescription>
    public val pluginsClasspath: List<File>
    public val pluginsConfiguration: List<PluginConfiguration>
    public val delayTemplateSubstitution: Boolean
    public val suppressObviousFunctions: Boolean
    public val includes: Set<File>
    public val suppressInheritedMembers: Boolean

    /**
     * Whether coroutines dispatchers should be shutdown after
     * generating documentation via [DokkaGenerator.generate].
     *
     * It effectively stops all background threads associated with
     * coroutines in order to make classes unloadable by the JVM,
     * and rejects all new tasks with [RejectedExecutionException]
     *
     * This is primarily useful for multi-module builds where coroutines
     * can be shut down after each module's partial task to avoid
     * possible memory leaks.
     *
     * However, this can lead to problems in specific lifecycles where
     * coroutines are shared and will be reused after documentation generation,
     * and closing it down will leave the build in an inoperable state.
     * One such example is unit tests, for which finalization should be disabled.
     */
    public val finalizeCoroutines: Boolean

    public enum class SerializationFormat : Serializable {
        JSON, XML
    }

    public interface PluginConfiguration : Serializable {
        public val fqPluginName: String
        public val serializationFormat: SerializationFormat
        public val values: String
    }

    public interface DokkaSourceSet : Serializable {
        public val sourceSetID: DokkaSourceSetID
        public val displayName: String
        public val classpath: List<File>
        public val sourceRoots: Set<File>
        public val dependentSourceSets: Set<DokkaSourceSetID>
        public val samples: Set<File>
        public val includes: Set<File>

        @Deprecated(message = "Use [documentedVisibilities] property for a more flexible control over documented visibilities")
        public val includeNonPublic: Boolean
        public val reportUndocumented: Boolean
        public val skipEmptyPackages: Boolean
        public val skipDeprecated: Boolean
        public val jdkVersion: Int
        public val sourceLinks: Set<SourceLinkDefinition>
        public val perPackageOptions: List<PackageOptions>
        public val externalDocumentationLinks: Set<ExternalDocumentationLink>
        public val languageVersion: String?
        public val apiVersion: String?
        public val noStdlibLink: Boolean
        public val noJdkLink: Boolean
        public val suppressedFiles: Set<File>
        public val analysisPlatform: Platform
        public val documentedVisibilities: Set<Visibility>
    }

    public enum class Visibility {
        /**
         * `public` modifier for Java, default visibility for Kotlin
         */
        PUBLIC,

        /**
         * `private` modifier for both Kotlin and Java
         */
        PRIVATE,

        /**
         * `protected` modifier for both Kotlin and Java
         */
        PROTECTED,

        /**
         * Kotlin-specific `internal` modifier
         */
        INTERNAL,

        /**
         * Java-specific package-private visibility (no modifier)
         */
        PACKAGE;

        public companion object {
            public fun fromString(value: String): Visibility = valueOf(value.toUpperCase())
        }
    }

    public interface SourceLinkDefinition : Serializable {
        public val localDirectory: String
        public val remoteUrl: URL
        public val remoteLineSuffix: String?
    }

    public interface DokkaModuleDescription : Serializable {
        public val name: String
        public val relativePathToOutputDirectory: File
        public val sourceOutputDirectory: File
        public val includes: Set<File>
    }

    public interface PackageOptions : Serializable {
        public val matchingRegex: String

        @Deprecated("Use [documentedVisibilities] property for a more flexible control over documented visibilities")
        public val includeNonPublic: Boolean
        public val reportUndocumented: Boolean?
        public val skipDeprecated: Boolean
        public val suppress: Boolean
        public val documentedVisibilities: Set<Visibility>
    }

    public interface ExternalDocumentationLink : Serializable {
        public val url: URL
        public val packageListUrl: URL

        public companion object
    }
}

@Suppress("FunctionName")
public fun ExternalDocumentationLink(
    url: URL? = null,
    packageListUrl: URL? = null
): ExternalDocumentationLinkImpl {
    return if (packageListUrl != null && url != null)
        ExternalDocumentationLinkImpl(url, packageListUrl)
    else if (url != null)
        ExternalDocumentationLinkImpl(url, URL(url, "package-list"))
    else
        throw IllegalArgumentException("url or url && packageListUrl must not be null for external documentation link")
}

@Suppress("FunctionName")
public fun ExternalDocumentationLink(
    url: String, packageListUrl: String? = null
): ExternalDocumentationLinkImpl =
    ExternalDocumentationLink(url.let(::URL), packageListUrl?.let(::URL))