diff options
367 files changed, 15644 insertions, 2625 deletions
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt index be354bc4..d7b0b285 100644 --- a/core/src/main/kotlin/CoreExtensions.kt +++ b/core/src/main/kotlin/CoreExtensions.kt @@ -6,6 +6,7 @@ import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentableTran import org.jetbrains.dokka.transformers.documentation.DocumentableMerger import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer +import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer import org.jetbrains.dokka.transformers.pages.PageTransformer import org.jetbrains.dokka.transformers.psi.PsiToDocumentableTranslator import kotlin.reflect.KProperty @@ -13,6 +14,7 @@ import kotlin.reflect.KProperty object CoreExtensions { val descriptorToDocumentableTranslator by coreExtension<DescriptorToDocumentableTranslator>() val psiToDocumentableTranslator by coreExtension<PsiToDocumentableTranslator>() + val preMergeDocumentableTransformer by coreExtension<PreMergeDocumentableTransformer>() val documentableMerger by coreExtension<DocumentableMerger>() val documentableTransformer by coreExtension<DocumentableTransformer>() val documentableToPageTranslator by coreExtension<DocumentableToPageTranslator>() diff --git a/core/src/main/kotlin/DokkaBootstrapImpl.kt b/core/src/main/kotlin/DokkaBootstrapImpl.kt index fc1b6926..f164a3c1 100644 --- a/core/src/main/kotlin/DokkaBootstrapImpl.kt +++ b/core/src/main/kotlin/DokkaBootstrapImpl.kt @@ -20,7 +20,13 @@ fun parsePerPackageOptions(arg: String): List<PackageOptions> { val reportUndocumented = args.find { it.endsWith("warnUndocumented") }?.startsWith("+") ?: true val privateApi = args.find { it.endsWith("privateApi") }?.startsWith("+") ?: false val suppress = args.find { it.endsWith("suppress") }?.startsWith("+") ?: false - PackageOptionsImpl(prefix, includeNonPublic = privateApi, reportUndocumented = reportUndocumented, skipDeprecated = !deprecated, suppress = suppress) + PackageOptionsImpl( + prefix, + includeNonPublic = privateApi, + reportUndocumented = reportUndocumented, + skipDeprecated = !deprecated, + suppress = suppress + ) } } @@ -52,10 +58,11 @@ class DokkaBootstrapImpl : DokkaBootstrap { override fun report() { if (warningsCount > 0 || errorsCount > 0) { - println("Generation completed with $warningsCount warning" + - (if(DokkaConsoleLogger.warningsCount == 1) "" else "s") + - " and $errorsCount error" + - if(DokkaConsoleLogger.errorsCount == 1) "" else "s" + println( + "Generation completed with $warningsCount warning" + + (if (DokkaConsoleLogger.warningsCount == 1) "" else "s") + + " and $errorsCount error" + + if (DokkaConsoleLogger.errorsCount == 1) "" else "s" ) } else { println("generation completed successfully") @@ -83,10 +90,11 @@ class DokkaBootstrapImpl : DokkaBootstrap { } val configurationWithLinks = - configuration.copy(passesConfigurations = - passesConfigurations - .map { - val links: List<ExternalDocumentationLinkImpl> = it.externalDocumentationLinks + defaultLinks(it) + configuration.copy( + passesConfigurations = + passesConfigurations.map { + val links: List<ExternalDocumentationLinkImpl> = + it.externalDocumentationLinks + defaultLinks(it) it.copy(externalDocumentationLinks = links) } ) @@ -94,8 +102,10 @@ class DokkaBootstrapImpl : DokkaBootstrap { generator = DokkaGenerator(configurationWithLinks, logger) } - override fun configure(logger: BiConsumer<String, String>, serializedConfigurationJSON: String) - = configure(DokkaProxyLogger(logger), gson.fromJson(serializedConfigurationJSON, DokkaConfigurationImpl::class.java)) + override fun configure(logger: BiConsumer<String, String>, serializedConfigurationJSON: String) = configure( + DokkaProxyLogger(logger), + gson.fromJson(serializedConfigurationJSON, DokkaConfigurationImpl::class.java) + ) override fun generate() = generator.generate() } diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index e318e969..d598c773 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -5,7 +5,7 @@ import com.intellij.psi.PsiJavaFile import com.intellij.psi.PsiManager import org.jetbrains.dokka.analysis.AnalysisEnvironment import org.jetbrains.dokka.analysis.DokkaResolutionFacade -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext @@ -29,37 +29,42 @@ class DokkaGenerator( private val configuration: DokkaConfiguration, private val logger: DokkaLogger ) { - fun generate() { - logger.progress("Setting up analysis environments") + fun generate() = timed { + report("Setting up analysis environments") val platforms: Map<PlatformData, EnvironmentAndFacade> = setUpAnalysis(configuration) - logger.progress("Initializing plugins") + report("Initializing plugins") val context = initializePlugins(configuration, logger, platforms) - logger.progress("Creating documentation models") + report("Creating documentation models") val modulesFromPlatforms = createDocumentationModels(platforms, context) - logger.progress("Merging documentation models") - val documentationModel = mergeDocumentationModels(modulesFromPlatforms, context) + report("Transforming documentation model before merging") + val transformedDocumentationBeforeMerge = transformDocumentationModelBeforeMerge(modulesFromPlatforms, context) - logger.progress("Transforming documentation model") - val transformedDocumentation = transformDocumentationModel(documentationModel, context) + report("Merging documentation models") + val documentationModel = mergeDocumentationModels(transformedDocumentationBeforeMerge, context) - logger.progress("Creating pages") + report("Transforming documentation model after merging") + val transformedDocumentation = transformDocumentationModelAfterMerge(documentationModel, context) + + report("Creating pages") val pages = createPages(transformedDocumentation, context) - logger.progress("Transforming pages") + report("Transforming pages") val transformedPages = transformPages(pages, context) - logger.progress("Rendering") + report("Rendering") render(transformedPages, context) + context.unusedPoints.takeIf { it.isNotEmpty() } + ?.also { logger.warn("Unused extension points found: ${it.joinToString(", ")}") } logger.report() - } + }.dump("\n\n === TIME MEASUREMENT ===\n") fun setUpAnalysis(configuration: DokkaConfiguration): Map<PlatformData, EnvironmentAndFacade> = configuration.passesConfigurations.map { - PlatformData(it.moduleName, it.analysisPlatform, it.targets) to createEnvironmentAndFacade(it) + it.platformData to createEnvironmentAndFacade(it) }.toMap() fun initializePlugins( @@ -73,20 +78,25 @@ class DokkaGenerator( platforms: Map<PlatformData, EnvironmentAndFacade>, context: DokkaContext ) = platforms.map { (pdata, _) -> translateDescriptors(pdata, context) } + - platforms.map { (pdata, _) -> translatePsi(pdata, context) } + platforms.map { (pdata, _) -> translatePsi(pdata, context) } + + fun transformDocumentationModelBeforeMerge( + modulesFromPlatforms: List<DModule>, + context: DokkaContext + ) = context[CoreExtensions.preMergeDocumentableTransformer].fold(modulesFromPlatforms) { acc, t -> t(acc, context) } fun mergeDocumentationModels( - modulesFromPlatforms: List<Module>, + modulesFromPlatforms: List<DModule>, context: DokkaContext ) = context.single(CoreExtensions.documentableMerger).invoke(modulesFromPlatforms, context) - fun transformDocumentationModel( - documentationModel: Module, + fun transformDocumentationModelAfterMerge( + documentationModel: DModule, context: DokkaContext ) = context[CoreExtensions.documentableTransformer].fold(documentationModel) { acc, t -> t(acc, context) } fun createPages( - transformedDocumentation: Module, + transformedDocumentation: DModule, context: DokkaContext ) = context.single(CoreExtensions.documentableToPageTranslator).invoke(transformedDocumentation) @@ -119,7 +129,7 @@ class DokkaGenerator( EnvironmentAndFacade(environment, facade) } - private fun translateDescriptors(platformData: PlatformData, context: DokkaContext): Module { + private fun translateDescriptors(platformData: PlatformData, context: DokkaContext): DModule { val (environment, facade) = context.platforms.getValue(platformData) val packageFragments = environment.getSourceFiles().asSequence() @@ -132,13 +142,13 @@ class DokkaGenerator( .invoke(platformData.name, packageFragments, platformData) } - private fun translatePsi(platformData: PlatformData, context: DokkaContext): Module { + private fun translatePsi(platformData: PlatformData, context: DokkaContext): DModule { val (environment, _) = context.platforms.getValue(platformData) val sourceRoots = environment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) ?.filterIsInstance<JavaSourceRoot>() ?.map { it.file } - ?: listOf() + ?: listOf() val localFileSystem = VirtualFileManager.getInstance().getFileSystem("file") val psiFiles = sourceRoots.map { sourceRoot -> @@ -176,4 +186,25 @@ class DokkaGenerator( class EnvironmentAndFacade(val environment: KotlinCoreEnvironment, val facade: DokkaResolutionFacade) { operator fun component1() = environment operator fun component2() = facade -}
\ No newline at end of file +} + +private class Timer(startTime: Long, private val logger: DokkaLogger?) { + private val steps = mutableListOf("" to startTime) + + fun report(name: String) { + logger?.progress(name) + steps += (name to System.currentTimeMillis()) + } + + fun dump(prefix: String = "") { + println(prefix) + val namePad = steps.map { it.first.length }.max() ?: 0 + val timePad = steps.windowed(2).map { (p1, p2) -> p2.second - p1.second }.max()?.toString()?.length ?: 0 + steps.windowed(2).forEach { (p1, p2) -> + println("${p2.first.padStart(namePad)}: ${(p2.second - p1.second).toString().padStart(timePad)}") + } + } +} + +private fun timed(logger: DokkaLogger? = null, block: Timer.() -> Unit): Timer = + Timer(System.currentTimeMillis(), logger).apply(block)
\ No newline at end of file diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index 8c6d35e8..19835fa4 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka +import org.jetbrains.dokka.pages.PlatformData import java.io.File import java.net.URL @@ -31,7 +32,7 @@ interface DokkaConfiguration { val cacheRoot: String? val passesConfigurations: List<PassConfiguration> val impliedPlatforms: List<String> - var pluginsClasspath: List<File> + val pluginsClasspath: List<File> interface PassConfiguration { val moduleName: String @@ -57,6 +58,9 @@ interface DokkaConfiguration { val analysisPlatform: Platform val targets: List<String> val sinceKotlin: String? + + val platformData: PlatformData + get() = PlatformData(moduleName, analysisPlatform, targets) } interface SourceRoot { diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 6c797fcd..b0c12015 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -71,4 +71,4 @@ data class PackageOptionsImpl( data class ExternalDocumentationLinkImpl(override val url: URL, override val packageListUrl: URL -) : DokkaConfiguration.ExternalDocumentationLink
\ No newline at end of file +) : DokkaConfiguration.ExternalDocumentationLink diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt index 57ac96e5..abc88939 100644 --- a/core/src/main/kotlin/links/DRI.kt +++ b/core/src/main/kotlin/links/DRI.kt @@ -56,6 +56,9 @@ data class DRI( } } +val DriOfUnit = DRI("kotlin", "Unit") +val DriOfAny = DRI("kotlin", "Any") + fun DRI.withClass(name: String) = copy(classNames = if (classNames.isNullOrBlank()) name else "$classNames.$name") val DRI.parent: DRI @@ -109,6 +112,8 @@ sealed class TypeReference { fun from(d: ValueParameterDescriptor): TypeReference? = fromPossiblyNullable(d.type) + fun from(p: PsiClass) = TypeReference + private fun fromPossiblyNullable(t: KotlinType, self: KotlinType? = null): TypeReference = from(t, self).let { if (t.isMarkedNullable) Nullable(it) else it } @@ -125,7 +130,6 @@ sealed class TypeReference { ) } - private fun fromProjection(t: TypeProjection, r: KotlinType? = null): TypeReference = if (t.isStarProjection) { StarProjection diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index d073d39a..00a26d90 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -23,17 +23,6 @@ abstract class Documentable { other is Documentable && this.dri == other.dri // TODO: https://github.com/Kotlin/dokka/pull/667#discussion_r382555806 override fun hashCode() = dri.hashCode() - - val briefDocTagString: String by lazy { - // TODO > utils - documentation.values - .firstOrNull() - ?.children - ?.firstOrNull() - ?.root - ?.docTagSummary() - ?.shorten(40) ?: "" - } } data class PlatformDependent<out T>( @@ -43,9 +32,15 @@ data class PlatformDependent<out T>( val prevalentValue: T? get() = map.values.distinct().singleOrNull() + val allValues: Sequence<T> = sequence { + expect?.also { yield(it) } + yieldAll(map.values) + } + companion object { fun <T> empty(): PlatformDependent<T> = PlatformDependent(emptyMap()) fun <T> from(platformData: PlatformData, element: T) = PlatformDependent(mapOf(platformData to element)) + fun <T> expectFrom(element: T) = PlatformDependent(map = emptyMap(), expect = element) } } @@ -54,13 +49,9 @@ interface WithExpectActual { } interface WithScope { - val functions: List<Function> - val properties: List<Property> - val classlikes: List<Classlike> -} - -interface WithPackages { - val packages: List<Package> + val functions: List<DFunction> + val properties: List<DProperty> + val classlikes: List<DClasslike> } interface WithVisibility { @@ -68,11 +59,11 @@ interface WithVisibility { } interface WithType { - val type: TypeWrapper + val type: Bound } interface WithAbstraction { - val modifier: Modifier + val modifier: PlatformDependent<Modifier> } sealed class Modifier(val name: String) @@ -91,15 +82,15 @@ sealed class JavaModifier(name: String) : Modifier(name) { } interface WithCompanion { - val companion: Object? + val companion: DObject? } interface WithConstructors { - val constructors: List<Function> + val constructors: List<DFunction> } interface WithGenerics { - val generics: List<TypeParameter> + val generics: List<DTypeParameter> } interface WithSupertypes { @@ -107,248 +98,255 @@ interface WithSupertypes { } interface Callable : WithVisibility, WithType, WithAbstraction, WithExpectActual { - val receiver: Parameter? + val receiver: DParameter? } -abstract class Classlike : Documentable(), WithScope, WithVisibility, WithExpectActual +abstract class DClasslike : Documentable(), WithScope, WithVisibility, WithExpectActual -data class Module( +data class DModule( override val name: String, - override val packages: List<Package>, + val packages: List<DPackage>, override val documentation: PlatformDependent<DocumentationNode>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Module> = PropertyContainer.empty() -) : Documentable(), WithPackages, WithExtraProperties<Module> { + override val extra: PropertyContainer<DModule> = PropertyContainer.empty() +) : Documentable(), WithExtraProperties<DModule> { override val dri: DRI = DRI.topLevel override val children: List<Documentable> get() = packages - override fun withNewExtras(newExtras: PropertyContainer<Module>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DModule>) = copy(extra = newExtras) } -data class Package( +data class DPackage( override val dri: DRI, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, - override val packages: List<Package>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val documentation: PlatformDependent<DocumentationNode>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Package> = PropertyContainer.empty() -) : Documentable(), WithScope, WithPackages, WithExtraProperties<Package> { + override val extra: PropertyContainer<DPackage> = PropertyContainer.empty() +) : Documentable(), WithScope, WithExtraProperties<DPackage> { override val name = dri.packageName.orEmpty() override val children: List<Documentable> - get() = (properties + functions + classlikes + packages) as List<Documentable> + get() = (properties + functions + classlikes) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<Package>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DPackage>) = copy(extra = newExtras) } -data class Class( +data class DClass( override val dri: DRI, override val name: String, - override val constructors: List<Function>, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, + override val constructors: List<DFunction>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val sources: PlatformDependent<DocumentableSource>, override val visibility: PlatformDependent<Visibility>, - override val companion: Object?, - override val generics: List<TypeParameter>, + override val companion: DObject?, + override val generics: List<DTypeParameter>, override val supertypes: PlatformDependent<List<DRI>>, override val documentation: PlatformDependent<DocumentationNode>, - override val modifier: Modifier, + override val modifier: PlatformDependent<Modifier>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Class> = PropertyContainer.empty() -) : Classlike(), WithAbstraction, WithCompanion, WithConstructors, WithGenerics, WithSupertypes, - WithExtraProperties<Class> { + override val extra: PropertyContainer<DClass> = PropertyContainer.empty() +) : DClasslike(), WithAbstraction, WithCompanion, WithConstructors, WithGenerics, WithSupertypes, + WithExtraProperties<DClass> { override val children: List<Documentable> get() = (functions + properties + classlikes + constructors) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<Class>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DClass>) = copy(extra = newExtras) } -data class Enum( +data class DEnum( override val dri: DRI, override val name: String, - val entries: List<EnumEntry>, + val entries: List<DEnumEntry>, override val documentation: PlatformDependent<DocumentationNode>, override val sources: PlatformDependent<DocumentableSource>, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val visibility: PlatformDependent<Visibility>, - override val companion: Object?, - override val constructors: List<Function>, + override val companion: DObject?, + override val constructors: List<DFunction>, override val supertypes: PlatformDependent<List<DRI>>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Enum> = PropertyContainer.empty() -) : Classlike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties<Enum> { + override val extra: PropertyContainer<DEnum> = PropertyContainer.empty() +) : DClasslike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties<DEnum> { override val children: List<Documentable> get() = (entries + functions + properties + classlikes + constructors) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<Enum>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DEnum>) = copy(extra = newExtras) } -data class EnumEntry( +data class DEnumEntry( override val dri: DRI, override val name: String, override val documentation: PlatformDependent<DocumentationNode>, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<EnumEntry> = PropertyContainer.empty() -) : Documentable(), WithScope, WithExtraProperties<EnumEntry> { + override val extra: PropertyContainer<DEnumEntry> = PropertyContainer.empty() +) : Documentable(), WithScope, WithExtraProperties<DEnumEntry> { override val children: List<Documentable> get() = (functions + properties + classlikes) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<EnumEntry>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DEnumEntry>) = copy(extra = newExtras) } -data class Function( +data class DFunction( override val dri: DRI, override val name: String, val isConstructor: Boolean, - val parameters: List<Parameter>, + val parameters: List<DParameter>, override val documentation: PlatformDependent<DocumentationNode>, override val sources: PlatformDependent<DocumentableSource>, override val visibility: PlatformDependent<Visibility>, - override val type: TypeWrapper, - override val generics: List<TypeParameter>, - override val receiver: Parameter?, - override val modifier: Modifier, + override val type: Bound, + override val generics: List<DTypeParameter>, + override val receiver: DParameter?, + override val modifier: PlatformDependent<Modifier>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Function> = PropertyContainer.empty() -) : Documentable(), Callable, WithGenerics, WithExtraProperties<Function> { + override val extra: PropertyContainer<DFunction> = PropertyContainer.empty() +) : Documentable(), Callable, WithGenerics, WithExtraProperties<DFunction> { override val children: List<Documentable> get() = parameters - override fun withNewExtras(newExtras: PropertyContainer<Function>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DFunction>) = copy(extra = newExtras) } -data class Interface( +data class DInterface( override val dri: DRI, override val name: String, override val documentation: PlatformDependent<DocumentationNode>, override val sources: PlatformDependent<DocumentableSource>, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val visibility: PlatformDependent<Visibility>, - override val companion: Object?, - override val generics: List<TypeParameter>, + override val companion: DObject?, + override val generics: List<DTypeParameter>, override val supertypes: PlatformDependent<List<DRI>>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Interface> = PropertyContainer.empty() -) : Classlike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties<Interface> { + override val extra: PropertyContainer<DInterface> = PropertyContainer.empty() +) : DClasslike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties<DInterface> { override val children: List<Documentable> get() = (functions + properties + classlikes) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<Interface>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DInterface>) = copy(extra = newExtras) } -data class Object( +data class DObject( override val name: String?, override val dri: DRI, override val documentation: PlatformDependent<DocumentationNode>, override val sources: PlatformDependent<DocumentableSource>, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val visibility: PlatformDependent<Visibility>, override val supertypes: PlatformDependent<List<DRI>>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Object> = PropertyContainer.empty() -) : Classlike(), WithSupertypes, WithExtraProperties<Object> { + override val extra: PropertyContainer<DObject> = PropertyContainer.empty() +) : DClasslike(), WithSupertypes, WithExtraProperties<DObject> { override val children: List<Documentable> get() = (functions + properties + classlikes) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<Object>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DObject>) = copy(extra = newExtras) } -data class Annotation( +data class DAnnotation( override val name: String, override val dri: DRI, override val documentation: PlatformDependent<DocumentationNode>, override val sources: PlatformDependent<DocumentableSource>, - override val functions: List<Function>, - override val properties: List<Property>, - override val classlikes: List<Classlike>, + override val functions: List<DFunction>, + override val properties: List<DProperty>, + override val classlikes: List<DClasslike>, override val visibility: PlatformDependent<Visibility>, - override val companion: Object?, - override val constructors: List<Function>, + override val companion: DObject?, + override val constructors: List<DFunction>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Annotation> = PropertyContainer.empty() -) : Classlike(), WithCompanion, WithConstructors, WithExtraProperties<Annotation> { + override val extra: PropertyContainer<DAnnotation> = PropertyContainer.empty() +) : DClasslike(), WithCompanion, WithConstructors, WithExtraProperties<DAnnotation> { override val children: List<Documentable> get() = (functions + properties + classlikes + constructors) as List<Documentable> - override fun withNewExtras(newExtras: PropertyContainer<Annotation>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DAnnotation>) = copy(extra = newExtras) } -data class Property( +data class DProperty( override val dri: DRI, override val name: String, override val documentation: PlatformDependent<DocumentationNode>, override val sources: PlatformDependent<DocumentableSource>, override val visibility: PlatformDependent<Visibility>, - override val type: TypeWrapper, - override val receiver: Parameter?, - val setter: Function?, - val getter: Function?, - override val modifier: Modifier, + override val type: Bound, + override val receiver: DParameter?, + val setter: DFunction?, + val getter: DFunction?, + override val modifier: PlatformDependent<Modifier>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Property> = PropertyContainer.empty() -) : Documentable(), Callable, WithExtraProperties<Property> { + override val extra: PropertyContainer<DProperty> = PropertyContainer.empty() +) : Documentable(), Callable, WithExtraProperties<DProperty> { override val children: List<Nothing> get() = emptyList() - override fun withNewExtras(newExtras: PropertyContainer<Property>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DProperty>) = copy(extra = newExtras) } // TODO: treat named Parameters and receivers differently -data class Parameter( +data class DParameter( override val dri: DRI, override val name: String?, override val documentation: PlatformDependent<DocumentationNode>, - val type: TypeWrapper, + val type: Bound, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<Parameter> = PropertyContainer.empty() -) : Documentable(), WithExtraProperties<Parameter> { + override val extra: PropertyContainer<DParameter> = PropertyContainer.empty() +) : Documentable(), WithExtraProperties<DParameter> { override val children: List<Nothing> get() = emptyList() - override fun withNewExtras(newExtras: PropertyContainer<Parameter>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DParameter>) = copy(extra = newExtras) } -data class TypeParameter( +data class DTypeParameter( override val dri: DRI, override val name: String, override val documentation: PlatformDependent<DocumentationNode>, val bounds: List<Bound>, override val platformData: List<PlatformData>, - override val extra: PropertyContainer<TypeParameter> = PropertyContainer.empty() -) : Documentable(), WithExtraProperties<TypeParameter> { + override val extra: PropertyContainer<DTypeParameter> = PropertyContainer.empty() +) : Documentable(), WithExtraProperties<DTypeParameter> { override val children: List<Nothing> get() = emptyList() - override fun withNewExtras(newExtras: PropertyContainer<TypeParameter>) = copy(extra = newExtras) + override fun withNewExtras(newExtras: PropertyContainer<DTypeParameter>) = copy(extra = newExtras) } sealed class Projection sealed class Bound : Projection() data class OtherParameter(val name: String) : Bound() object Star : Projection() -data class TypeConstructor(val dri: DRI, val projections: List<Projection>) : Bound() +data class TypeConstructor(val dri: DRI, val projections: List<Projection>, val modifier: FunctionModifiers = FunctionModifiers.NONE) : Bound() data class Nullable(val inner: Bound) : Bound() data class Variance(val kind: Kind, val inner: Bound) : Projection() { enum class Kind { In, Out } } +data class PrimitiveJavaType(val name: String): Bound() +object Void : Bound() +object JavaObject : Bound() + +enum class FunctionModifiers { + NONE, FUNCTION, EXTENSION +} enum class ExtraModifiers { STATIC, INLINE, INFIX, SUSPEND, REIFIED, CROSSINLINE, NOINLINE, - OVERRIDE, DATA, CONST, DYNAMIC, EXTERNAL, INNER, LATEINIT, OPERATOR, TAILREC, VARARG + OVERRIDE, DATA, CONST, DYNAMIC, EXTERNAL, INNER, LATEINIT, OPERATOR, TAILREC, VARARG, + NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, TRANSITIVE } private fun String.shorten(maxLength: Int) = lineSequence().first().let { diff --git a/core/src/main/kotlin/model/aditionalExtras.kt b/core/src/main/kotlin/model/aditionalExtras.kt index 69e89a2a..af399745 100644 --- a/core/src/main/kotlin/model/aditionalExtras.kt +++ b/core/src/main/kotlin/model/aditionalExtras.kt @@ -1,11 +1,42 @@ package org.jetbrains.dokka.model +import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.properties.ExtraProperty +import org.jetbrains.dokka.model.properties.MergeStrategy -class AdditionalModifiers(val content: List<ExtraModifiers>) : ExtraProperty<Documentable> { - object AdditionalKey : ExtraProperty.Key<Documentable, AdditionalModifiers> +class AdditionalModifiers(val content: Set<ExtraModifiers>) : ExtraProperty<Documentable> { + companion object : ExtraProperty.Key<Documentable, AdditionalModifiers> { + override fun mergeStrategyFor( + left: AdditionalModifiers, + right: AdditionalModifiers + ): MergeStrategy<Documentable> = MergeStrategy.Replace(AdditionalModifiers(left.content + right.content)) + } + + override fun equals(other: Any?): Boolean = + if (other is AdditionalModifiers) other.content == content else false - override fun equals(other: Any?): Boolean = if (other is AdditionalModifiers) other.content == content else false override fun hashCode() = content.hashCode() - override val key: ExtraProperty.Key<Documentable, *> = AdditionalKey + override val key: ExtraProperty.Key<Documentable, *> = AdditionalModifiers +} + +class Annotations(val content: List<Annotation>) : ExtraProperty<Documentable> { + companion object : ExtraProperty.Key<Documentable, Annotations> { + override fun mergeStrategyFor(left: Annotations, right: Annotations): MergeStrategy<Documentable> = + MergeStrategy.Replace(Annotations((left.content + right.content).distinct())) + } + + override val key: ExtraProperty.Key<Documentable, *> = Annotations + + data class Annotation(val dri: DRI, val params: Map<String, String>) { + override fun equals(other: Any?): Boolean = when(other) { + is Annotation -> dri.equals(other.dri) + else -> false + } + + override fun hashCode(): Int = dri.hashCode() + } +} + +object PrimaryConstructorExtra: ExtraProperty<DFunction>, ExtraProperty.Key<DFunction, PrimaryConstructorExtra> { + override val key: ExtraProperty.Key<DFunction, *> = this }
\ No newline at end of file diff --git a/core/src/main/kotlin/model/defaultValues.kt b/core/src/main/kotlin/model/defaultValues.kt new file mode 100644 index 00000000..10f6d16d --- /dev/null +++ b/core/src/main/kotlin/model/defaultValues.kt @@ -0,0 +1,12 @@ +package org.jetbrains.dokka.model + +import org.jetbrains.dokka.model.properties.ExtraProperty +import org.jetbrains.dokka.model.properties.MergeStrategy +import java.lang.IllegalStateException + +class DefaultValue(val value: String): ExtraProperty<DParameter> { + companion object : ExtraProperty.Key<DParameter, DefaultValue> + + override val key: ExtraProperty.Key<DParameter, *> + get() = Companion +}
\ No newline at end of file diff --git a/core/src/main/kotlin/model/documentableProperties.kt b/core/src/main/kotlin/model/documentableProperties.kt index 38a06451..67e5e88d 100644 --- a/core/src/main/kotlin/model/documentableProperties.kt +++ b/core/src/main/kotlin/model/documentableProperties.kt @@ -3,12 +3,12 @@ package org.jetbrains.dokka.model import org.jetbrains.dokka.model.properties.ExtraProperty import org.jetbrains.dokka.model.properties.MergeStrategy -data class InheritedFunction(val isInherited: Boolean): ExtraProperty<Function> { - object InheritedFunctionKey: ExtraProperty.Key<Function, Boolean> { +data class InheritedFunction(val isInherited: Boolean): ExtraProperty<DFunction> { + object InheritedFunctionKey: ExtraProperty.Key<DFunction, Boolean> { override fun mergeStrategyFor(left: Boolean, right: Boolean) = MergeStrategy.Fail { throw IllegalArgumentException("Function inheritance should be consistent!") } } - override val key: ExtraProperty.Key<Function, Boolean> = + override val key: ExtraProperty.Key<DFunction, Boolean> = InheritedFunctionKey }
\ No newline at end of file diff --git a/core/src/main/kotlin/model/documentableUtils.kt b/core/src/main/kotlin/model/documentableUtils.kt new file mode 100644 index 00000000..7f946344 --- /dev/null +++ b/core/src/main/kotlin/model/documentableUtils.kt @@ -0,0 +1,23 @@ +package org.jetbrains.dokka.model + +import org.jetbrains.dokka.pages.PlatformData + +fun <T> PlatformDependent<T>.filtered(platformDataList: List<PlatformData>) = PlatformDependent( + map.filter { it.key in platformDataList }, + expect +) + +fun DTypeParameter.filter(filteredData: List<PlatformData>) = + if (filteredData.containsAll(platformData)) this + else { + val intersection = filteredData.intersect(platformData).toList() + if (intersection.isEmpty()) null + else DTypeParameter( + dri, + name, + documentation.filtered(intersection), + bounds, + intersection, + extra + ) + }
\ No newline at end of file diff --git a/core/src/main/kotlin/model/properties/PropertyContainer.kt b/core/src/main/kotlin/model/properties/PropertyContainer.kt index 7fa46ccb..107bede5 100644 --- a/core/src/main/kotlin/model/properties/PropertyContainer.kt +++ b/core/src/main/kotlin/model/properties/PropertyContainer.kt @@ -15,9 +15,13 @@ class PropertyContainer<C : Any> internal constructor( } inline fun <reified T : Any> allOfType(): List<T> = map.values.filterIsInstance<T>() + fun <D : C> addAll(extras: Collection<ExtraProperty<D>>): PropertyContainer<D> = + PropertyContainer(map + extras.map { p -> p.key to p }) companion object { fun <T : Any> empty(): PropertyContainer<T> = PropertyContainer(emptyMap()) + fun <T : Any> withAll(vararg extras: ExtraProperty<T>) = empty<T>().addAll(extras.toList()) + fun <T : Any> withAll(extras: Collection<ExtraProperty<T>>) = empty<T>().addAll(extras) } } diff --git a/core/src/main/kotlin/model/typeWrappers.kt b/core/src/main/kotlin/model/typeWrappers.kt index b26a3f6d..e69de29b 100644 --- a/core/src/main/kotlin/model/typeWrappers.kt +++ b/core/src/main/kotlin/model/typeWrappers.kt @@ -1,101 +0,0 @@ -package org.jetbrains.dokka.model - -import com.intellij.psi.PsiArrayType -import com.intellij.psi.PsiEllipsisType -import com.intellij.psi.PsiPrimitiveType -import com.intellij.psi.PsiType -import com.intellij.psi.impl.source.PsiClassReferenceType -import org.jetbrains.dokka.links.DRI -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.types.KotlinType - -interface TypeWrapper { - val constructorFqName: String? - val constructorNamePathSegments: List<String> - val arguments: List<TypeWrapper> - val dri: DRI? -} - -class KotlinTypeWrapper(private val kotlinType: KotlinType) : TypeWrapper { - private val declarationDescriptor = kotlinType.constructor.declarationDescriptor - private val fqNameSafe = declarationDescriptor?.fqNameSafe - override val constructorFqName = fqNameSafe?.asString() - override val constructorNamePathSegments: List<String> = - fqNameSafe?.pathSegments()?.map { it.asString() } ?: emptyList() - override val arguments: List<KotlinTypeWrapper> by lazy { - kotlinType.arguments.map { - KotlinTypeWrapper( - it.type - ) - } - } - override val dri: DRI? by lazy { declarationDescriptor?.let { DRI.from(it) } } -} - -class JavaTypeWrapper : TypeWrapper { - - override val constructorFqName: String? - override val constructorNamePathSegments: List<String> - override val arguments: List<TypeWrapper> - override val dri: DRI? - val isPrimitive: Boolean - - constructor( - constructorNamePathSegments: List<String>, - arguments: List<TypeWrapper>, - dri: DRI?, - isPrimitiveType: Boolean - ) { - this.constructorFqName = constructorNamePathSegments.joinToString(".") - this.constructorNamePathSegments = constructorNamePathSegments - this.arguments = arguments - this.dri = dri - this.isPrimitive = isPrimitiveType - } - - constructor(type: PsiType) { - if (type is PsiClassReferenceType) { - val resolved = type.resolve() - constructorFqName = resolved?.qualifiedName - constructorNamePathSegments = resolved?.qualifiedName?.split('.') ?: emptyList() - arguments = type.parameters.mapNotNull { - if (it is PsiClassReferenceType) JavaTypeWrapper(it) else null - } - dri = fromPsi(type) - this.isPrimitive = false - } else if (type is PsiEllipsisType) { - constructorFqName = type.canonicalText - constructorNamePathSegments = listOf(type.canonicalText) // TODO - arguments = emptyList() - dri = DRI("java.lang", "Object") // TODO - this.isPrimitive = false - } else if (type is PsiArrayType) { - constructorFqName = type.canonicalText - constructorNamePathSegments = listOf(type.canonicalText) - arguments = emptyList() - dri = (type as? PsiClassReferenceType)?.let { fromPsi(it) } // TODO - this.isPrimitive = false - } else { - type as PsiPrimitiveType - constructorFqName = type.name - constructorNamePathSegments = type.name.split('.') - arguments = emptyList() - dri = null - this.isPrimitive = true - } - } - - private fun fromPsi(type: PsiClassReferenceType): DRI { - val className = type.className - val pkg = type.canonicalText.removeSuffix(className).removeSuffix(".") - return DRI(packageName = pkg, classNames = className) - } - - override fun toString(): String { - return constructorFqName.orEmpty() - } - - companion object { - val VOID = JavaTypeWrapper(listOf("void"), listOf(), null, true) - } -} diff --git a/core/src/main/kotlin/pages/ContentNodes.kt b/core/src/main/kotlin/pages/ContentNodes.kt index 2e14dfb9..46a71bc0 100644 --- a/core/src/main/kotlin/pages/ContentNodes.kt +++ b/core/src/main/kotlin/pages/ContentNodes.kt @@ -25,6 +25,15 @@ data class ContentText( override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode = copy(extra = newExtras) } +data class ContentBreakLine( + override val platforms: Set<PlatformData>, + override val dci: DCI = DCI(emptySet(), ContentKind.Empty), + override val style: Set<Style> = emptySet(), + override val extra: PropertyContainer<ContentNode> = PropertyContainer.empty() +): ContentNode { + override fun withNewExtras(newExtras: PropertyContainer<ContentNode>): ContentNode = copy(extra = newExtras) +} + /** Headers */ data class ContentHeader( override val children: List<ContentNode>, @@ -158,11 +167,11 @@ interface Style interface Kind enum class ContentKind : Kind { - Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Symbol, Sample, Main + Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Symbol, Sample, Main, BriefComment, Empty } enum class TextStyle : Style { - Bold, Italic, Strong, Strikethrough, Paragraph, Block + Bold, Italic, Strong, Strikethrough, Paragraph, Block, Monospace, Indented } fun ContentNode.dfs(predicate: (ContentNode) -> Boolean): ContentNode? = if (predicate(this)) { diff --git a/core/src/main/kotlin/parsers/HtmlParser.kt b/core/src/main/kotlin/parsers/HtmlParser.kt index aebdee41..a0652b95 100644 --- a/core/src/main/kotlin/parsers/HtmlParser.kt +++ b/core/src/main/kotlin/parsers/HtmlParser.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.parsers import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.parsers.factories.DocNodesFromStringFactory +import org.jetbrains.dokka.parsers.factories.DocTagsFromStringFactory import org.jsoup.Jsoup import org.jsoup.nodes.Node import org.jsoup.select.NodeFilter @@ -36,12 +36,12 @@ class HtmlParser : Parser() { } val docNode = if(depth < currentDepth) { - DocNodesFromStringFactory.getInstance(nodeName, nodesCache.getOrDefault(currentDepth, mutableListOf()).toList(), params, body).also { + DocTagsFromStringFactory.getInstance(nodeName, nodesCache.getOrDefault(currentDepth, mutableListOf()).toList(), params, body).also { nodesCache[currentDepth] = mutableListOf() currentDepth = depth } } else { - DocNodesFromStringFactory.getInstance(nodeName, emptyList(), params, body) + DocTagsFromStringFactory.getInstance(nodeName, emptyList(), params, body) } nodesCache.getOrDefault(depth, mutableListOf()) += docNode diff --git a/core/src/main/kotlin/parsers/MarkdownParser.kt b/core/src/main/kotlin/parsers/MarkdownParser.kt index 6afcbee6..617d351b 100644 --- a/core/src/main/kotlin/parsers/MarkdownParser.kt +++ b/core/src/main/kotlin/parsers/MarkdownParser.kt @@ -1,8 +1,6 @@ package org.jetbrains.dokka.parsers import com.intellij.psi.PsiElement -import org.intellij.markdown.IElementType -import org.intellij.markdown.MarkdownElementType import org.jetbrains.dokka.model.doc.* import org.intellij.markdown.MarkdownElementTypes import org.intellij.markdown.MarkdownTokenTypes @@ -13,64 +11,67 @@ import org.intellij.markdown.ast.impl.ListItemCompositeNode import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor import org.jetbrains.dokka.analysis.DokkaResolutionFacade import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.parsers.factories.DocNodesFromIElementFactory -import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jetbrains.dokka.parsers.factories.DocTagsFromIElementFactory import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -import org.jetbrains.kotlin.kdoc.psi.impl.KDocImpl import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag import java.net.MalformedURLException import org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser -class MarkdownParser ( +class MarkdownParser( private val resolutionFacade: DokkaResolutionFacade, private val declarationDescriptor: DeclarationDescriptor - ) : Parser() { +) : Parser() { inner class MarkdownVisitor(val text: String, val destinationLinksMap: Map<String, String>) { private fun headersHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance( + DocTagsFromIElementFactory.getInstance( node.type, - visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT } ?: - throw IllegalStateException("Wrong AST Tree. ATX Header does not contain expected content")).children + visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT } + ?: throw IllegalStateException("Wrong AST Tree. ATX Header does not contain expected content")).children ) private fun horizontalRulesHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE) + DocTagsFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE) private fun emphasisHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance( + DocTagsFromIElementFactory.getInstance( node.type, children = listOf(visitNode(node.children[node.children.size / 2])) ) private fun blockquotesHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance(node.type, children = node.children - .filterIsInstance<CompositeASTNode>() - .evaluateChildren()) + DocTagsFromIElementFactory.getInstance( + node.type, children = node.children + .filterIsInstance<CompositeASTNode>() + .evaluateChildren() + ) private fun listsHandler(node: ASTNode): DocTag { val children = node.children.filterIsInstance<ListItemCompositeNode>().flatMap { - if( it.children.last().type in listOf(MarkdownElementTypes.ORDERED_LIST, MarkdownElementTypes.UNORDERED_LIST) ) { + if (it.children.last().type in listOf( + MarkdownElementTypes.ORDERED_LIST, + MarkdownElementTypes.UNORDERED_LIST + ) + ) { val nestedList = it.children.last() (it.children as MutableList).removeAt(it.children.lastIndex) listOf(it, nestedList) - } - else + } else listOf(it) } - return DocNodesFromIElementFactory.getInstance( + return DocTagsFromIElementFactory.getInstance( node.type, children = children .map { - if(it.type == MarkdownElementTypes.LIST_ITEM) - DocNodesFromIElementFactory.getInstance( + if (it.type == MarkdownElementTypes.LIST_ITEM) + DocTagsFromIElementFactory.getInstance( it.type, children = it .children @@ -83,30 +84,41 @@ class MarkdownParser ( params = if (node.type == MarkdownElementTypes.ORDERED_LIST) { val listNumberNode = node.children.first().children.first() - mapOf("start" to text.substring(listNumberNode.startOffset, listNumberNode.endOffset).trim().dropLast(1)) + mapOf( + "start" to text.substring( + listNumberNode.startOffset, + listNumberNode.endOffset + ).trim().dropLast(1) + ) } else emptyMap() ) } - private fun resolveDRI(link: String): DRI? = - try { - java.net.URL(link) - null - } catch(e: MalformedURLException) { - resolveKDocLink( - resolutionFacade.resolveSession.bindingContext, - resolutionFacade, - declarationDescriptor, - null, - link.split('.') - ).also { if (it.size > 1) throw IllegalStateException("Markdown link resolved more than one element: $it") }.firstOrNull()//.single() - ?.let { DRI.from(it) } - } + private fun resolveDRI(mdLink: String): DRI? = + mdLink + .removePrefix("[") + .removeSuffix("]") + .let { link -> + try { + java.net.URL(link) + null + } catch (e: MalformedURLException) { + resolveKDocLink( + resolutionFacade.resolveSession.bindingContext, + resolutionFacade, + declarationDescriptor, + null, + link.split('.') + ).also { if (it.size > 1) throw IllegalStateException("Markdown link resolved more than one element: $it") } + .firstOrNull()//.single() + ?.let { DRI.from(it) } + } + } private fun referenceLinksHandler(node: ASTNode): DocTag { - val linkLabel = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL } ?: - throw IllegalStateException("Wrong AST Tree. Reference link does not contain expected content") + val linkLabel = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL } + ?: throw IllegalStateException("Wrong AST Tree. Reference link does not contain expected content") val linkText = node.children.findLast { it.type == MarkdownElementTypes.LINK_TEXT } ?: linkLabel val linkKey = text.substring(linkLabel.startOffset, linkLabel.endOffset) @@ -117,10 +129,10 @@ class MarkdownParser ( } private fun inlineLinksHandler(node: ASTNode): DocTag { - val linkText = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT } ?: - throw IllegalStateException("Wrong AST Tree. Inline link does not contain expected content") - val linkDestination = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION } ?: - throw IllegalStateException("Wrong AST Tree. Inline link does not contain expected content") + val linkText = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT } + ?: throw IllegalStateException("Wrong AST Tree. Inline link does not contain expected content") + val linkDestination = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION } + ?: throw IllegalStateException("Wrong AST Tree. Inline link does not contain expected content") val linkTitle = node.children.find { it.type == MarkdownElementTypes.LINK_TITLE } val link = text.substring(linkDestination.startOffset, linkDestination.endOffset) @@ -136,12 +148,17 @@ class MarkdownParser ( private fun linksHandler(linkText: ASTNode, link: String, linkTitle: ASTNode? = null): DocTag { val dri: DRI? = resolveDRI(link) - val params = if(linkTitle == null) + val params = if (linkTitle == null) mapOf("href" to link) else mapOf("href" to link, "title" to text.substring(linkTitle.startOffset + 1, linkTitle.endOffset - 1)) - return DocNodesFromIElementFactory.getInstance(MarkdownElementTypes.INLINE_LINK, params = params, children = linkText.children.drop(1).dropLast(1).evaluateChildren(), dri = dri) + return DocTagsFromIElementFactory.getInstance( + MarkdownElementTypes.INLINE_LINK, + params = params, + children = linkText.children.drop(1).dropLast(1).evaluateChildren(), + dri = dri + ) } private fun imagesHandler(node: ASTNode): DocTag { @@ -149,30 +166,34 @@ class MarkdownParser ( node.children.last().children.find { it.type == MarkdownElementTypes.LINK_LABEL }!!.children[1] val link = text.substring(linkNode.startOffset, linkNode.endOffset) val src = mapOf("src" to link) - return DocNodesFromIElementFactory.getInstance(node.type, params = src, children = listOf(visitNode(node.children.last().children.find { it.type == MarkdownElementTypes.LINK_TEXT }!!))) + return DocTagsFromIElementFactory.getInstance( + node.type, + params = src, + children = listOf(visitNode(node.children.last().children.find { it.type == MarkdownElementTypes.LINK_TEXT }!!)) + ) } private fun codeSpansHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance( + DocTagsFromIElementFactory.getInstance( node.type, children = listOf( - DocNodesFromIElementFactory.getInstance( + DocTagsFromIElementFactory.getInstance( MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset+1, node.endOffset-1).replace('\n', ' ').trimIndent() + body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent() ) ) ) private fun codeFencesHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance( + DocTagsFromIElementFactory.getInstance( node.type, children = node .children .dropWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } .dropLastWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } .map { - if(it.type == MarkdownTokenTypes.EOL) + if (it.type == MarkdownTokenTypes.EOL) LeafASTNode(MarkdownTokenTypes.HARD_LINE_BREAK, 0, 0) else it @@ -181,16 +202,17 @@ class MarkdownParser ( .children .find { it.type == MarkdownTokenTypes.FENCE_LANG } ?.let { mapOf("lang" to text.substring(it.startOffset, it.endOffset)) } - ?: emptyMap() + ?: emptyMap() ) private fun codeBlocksHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance(node.type, children = node.children.evaluateChildren()) + DocTagsFromIElementFactory.getInstance(node.type, children = node.children.evaluateChildren()) private fun defaultHandler(node: ASTNode): DocTag = - DocNodesFromIElementFactory.getInstance( + DocTagsFromIElementFactory.getInstance( MarkdownElementTypes.PARAGRAPH, - children = node.children.evaluateChildren()) + children = node.children.evaluateChildren() + ) fun visitNode(node: ASTNode): DocTag = when (node.type) { @@ -199,46 +221,50 @@ class MarkdownParser ( MarkdownElementTypes.ATX_3, MarkdownElementTypes.ATX_4, MarkdownElementTypes.ATX_5, - MarkdownElementTypes.ATX_6 -> headersHandler(node) - MarkdownTokenTypes.HORIZONTAL_RULE -> horizontalRulesHandler(node) + MarkdownElementTypes.ATX_6 -> headersHandler(node) + MarkdownTokenTypes.HORIZONTAL_RULE -> horizontalRulesHandler(node) MarkdownElementTypes.STRONG, - MarkdownElementTypes.EMPH -> emphasisHandler(node) + MarkdownElementTypes.EMPH -> emphasisHandler(node) MarkdownElementTypes.FULL_REFERENCE_LINK, - MarkdownElementTypes.SHORT_REFERENCE_LINK -> referenceLinksHandler(node) - MarkdownElementTypes.INLINE_LINK -> inlineLinksHandler(node) - MarkdownElementTypes.AUTOLINK -> autoLinksHandler(node) - MarkdownElementTypes.BLOCK_QUOTE -> blockquotesHandler(node) + MarkdownElementTypes.SHORT_REFERENCE_LINK -> referenceLinksHandler(node) + MarkdownElementTypes.INLINE_LINK -> inlineLinksHandler(node) + MarkdownElementTypes.AUTOLINK -> autoLinksHandler(node) + MarkdownElementTypes.BLOCK_QUOTE -> blockquotesHandler(node) MarkdownElementTypes.UNORDERED_LIST, - MarkdownElementTypes.ORDERED_LIST -> listsHandler(node) - MarkdownElementTypes.CODE_BLOCK -> codeBlocksHandler(node) - MarkdownElementTypes.CODE_FENCE -> codeFencesHandler(node) - MarkdownElementTypes.CODE_SPAN -> codeSpansHandler(node) - MarkdownElementTypes.IMAGE -> imagesHandler(node) - MarkdownTokenTypes.HARD_LINE_BREAK -> DocNodesFromIElementFactory.getInstance(node.type) + MarkdownElementTypes.ORDERED_LIST -> listsHandler(node) + MarkdownElementTypes.CODE_BLOCK -> codeBlocksHandler(node) + MarkdownElementTypes.CODE_FENCE -> codeFencesHandler(node) + MarkdownElementTypes.CODE_SPAN -> codeSpansHandler(node) + MarkdownElementTypes.IMAGE -> imagesHandler(node) + MarkdownTokenTypes.HARD_LINE_BREAK -> DocTagsFromIElementFactory.getInstance(node.type) MarkdownTokenTypes.CODE_FENCE_CONTENT, MarkdownTokenTypes.CODE_LINE, - MarkdownTokenTypes.TEXT -> DocNodesFromIElementFactory.getInstance( + MarkdownTokenTypes.TEXT -> DocTagsFromIElementFactory.getInstance( MarkdownTokenTypes.TEXT, body = text .substring(node.startOffset, node.endOffset).transform() ) - MarkdownElementTypes.MARKDOWN_FILE -> if(node.children.size == 1) visitNode(node.children.first()) else defaultHandler(node) - else -> defaultHandler(node) + MarkdownElementTypes.MARKDOWN_FILE -> if (node.children.size == 1) visitNode(node.children.first()) else defaultHandler( + node + ) + else -> defaultHandler(node) } private fun List<ASTNode>.evaluateChildren(): List<DocTag> = this.removeUselessTokens().mergeLeafASTNodes().map { visitNode(it) } private fun List<ASTNode>.removeUselessTokens(): List<ASTNode> = - this.filterIndexed { index, node -> !(node.type == MarkdownElementTypes.LINK_DEFINITION || ( - node.type == MarkdownTokenTypes.EOL && - this.getOrNull(index - 1)?.type == MarkdownTokenTypes.HARD_LINE_BREAK - )) } + this.filterIndexed { index, node -> + !(node.type == MarkdownElementTypes.LINK_DEFINITION || ( + node.type == MarkdownTokenTypes.EOL && + this.getOrNull(index - 1)?.type == MarkdownTokenTypes.HARD_LINE_BREAK + )) + } private val notLeafNodes = listOf(MarkdownTokenTypes.HORIZONTAL_RULE, MarkdownTokenTypes.HARD_LINE_BREAK) private fun List<ASTNode>.isNotLeaf(index: Int): Boolean = - if(index in 0..this.lastIndex) + if (index in 0..this.lastIndex) (this[index] is CompositeASTNode) || this[index].type in notLeafNodes else false @@ -246,24 +272,23 @@ class MarkdownParser ( private fun List<ASTNode>.mergeLeafASTNodes(): List<ASTNode> { val children: MutableList<ASTNode> = mutableListOf() var index = 0 - while(index <= this.lastIndex) { - if(this.isNotLeaf(index)) { + while (index <= this.lastIndex) { + if (this.isNotLeaf(index)) { children += this[index] - } - else { + } else { val startOffset = this[index].startOffset - while(index < this.lastIndex ) { - if(this.isNotLeaf(index + 1) || this[index+1].startOffset != this[index].endOffset) { + while (index < this.lastIndex) { + if (this.isNotLeaf(index + 1) || this[index + 1].startOffset != this[index].endOffset) { val endOffset = this[index].endOffset - if(text.substring(startOffset, endOffset).transform().trim().isNotEmpty()) + if (text.substring(startOffset, endOffset).transform().trim().isNotEmpty()) children += LeafASTNode(MarkdownTokenTypes.TEXT, startOffset, endOffset) break } index++ } - if(index == this.lastIndex) { + if (index == this.lastIndex) { val endOffset = this[index].endOffset - if(text.substring(startOffset, endOffset).transform().trim().isNotEmpty()) + if (text.substring(startOffset, endOffset).transform().trim().isNotEmpty()) children += LeafASTNode(MarkdownTokenTypes.TEXT, startOffset, endOffset) } } @@ -280,11 +305,13 @@ class MarkdownParser ( private fun getAllDestinationLinks(text: String, node: ASTNode): List<Pair<String, String>> = - node.children - .filter { it.type == MarkdownElementTypes.LINK_DEFINITION } - .map { text.substring(it.children[0].startOffset, it.children[0].endOffset).toLowerCase() to - text.substring(it.children[2].startOffset, it.children[2].endOffset) } + - node.children.filterIsInstance<CompositeASTNode>().flatMap { getAllDestinationLinks(text, it) } + node.children + .filter { it.type == MarkdownElementTypes.LINK_DEFINITION } + .map { + text.substring(it.children[0].startOffset, it.children[0].endOffset).toLowerCase() to + text.substring(it.children[2].startOffset, it.children[2].endOffset) + } + + node.children.filterIsInstance<CompositeASTNode>().flatMap { getAllDestinationLinks(text, it) } private fun markdownToDocNode(text: String): DocTag { @@ -299,13 +326,17 @@ class MarkdownParser ( override fun preparse(text: String) = text private fun findParent(kDoc: PsiElement): PsiElement = - if(kDoc is KDocSection) findParent(kDoc.parent) else kDoc + if (kDoc is KDocSection) findParent(kDoc.parent) else kDoc private fun getAllKDocTags(kDocImpl: PsiElement): List<KDocTag> = - kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap { getAllKDocTags(it) } + kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap { + getAllKDocTags( + it + ) + } fun parseFromKDocTag(kDocTag: KDocTag?): DocumentationNode { - return if(kDocTag == null) + return if (kDocTag == null) DocumentationNode(emptyList()) else DocumentationNode( @@ -316,16 +347,31 @@ class MarkdownParser ( it.name!! ) KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(it.getContent())) - KDocKnownTag.THROWS -> Throws(parseStringToDocNode(it.getContent()), it.getSubjectName().orEmpty()) - KDocKnownTag.EXCEPTION -> Throws(parseStringToDocNode(it.getContent()), it.getSubjectName().orEmpty()) - KDocKnownTag.PARAM -> Param(parseStringToDocNode(it.getContent()), it.getSubjectName().orEmpty()) + KDocKnownTag.THROWS -> Throws( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) + KDocKnownTag.EXCEPTION -> Throws( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) + KDocKnownTag.PARAM -> Param( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent())) KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent())) KDocKnownTag.SEE -> See(parseStringToDocNode(it.getContent()), it.getSubjectName().orEmpty()) KDocKnownTag.SINCE -> Since(parseStringToDocNode(it.getContent())) KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(it.getContent())) - KDocKnownTag.PROPERTY -> Property(parseStringToDocNode(it.getContent()), it.getSubjectName().orEmpty()) - KDocKnownTag.SAMPLE -> Sample(parseStringToDocNode(it.getContent()), it.getSubjectName().orEmpty()) + KDocKnownTag.PROPERTY -> Property( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) + KDocKnownTag.SAMPLE -> Sample( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(it.getContent())) } } diff --git a/core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt b/core/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt index d4c6e752..e616b9e8 100644 --- a/core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt +++ b/core/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt @@ -7,7 +7,7 @@ import org.intellij.markdown.MarkdownTokenTypes import org.jetbrains.dokka.links.DRI import java.lang.NullPointerException -object DocNodesFromIElementFactory { +object DocTagsFromIElementFactory { fun getInstance(type: IElementType, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null) = when(type) { MarkdownElementTypes.SHORT_REFERENCE_LINK, diff --git a/core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt b/core/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt index 4ff9a9d4..3425f52e 100644 --- a/core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt +++ b/core/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt @@ -4,7 +4,7 @@ import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.links.DRI import java.lang.NullPointerException -object DocNodesFromStringFactory { +object DocTagsFromStringFactory { fun getInstance(name: String, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null) = when(name) { "a" -> A(children, params) diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt index 5d5a8ebf..c5a08a56 100644 --- a/core/src/main/kotlin/plugability/DokkaContext.kt +++ b/core/src/main/kotlin/plugability/DokkaContext.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka.plugability import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.EnvironmentAndFacade import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.utilities.DokkaLogger import java.io.File import java.net.URLClassLoader import java.util.* @@ -22,6 +22,8 @@ interface DokkaContext { val logger: DokkaLogger val configuration: DokkaConfiguration val platforms: Map<PlatformData, EnvironmentAndFacade> + val unusedPoints: Collection<ExtensionPoint<*>> + companion object { fun create( @@ -43,7 +45,7 @@ interface DokkaContext { } } -inline fun <reified T: DokkaPlugin> DokkaContext.plugin(): T = plugin(T::class) +inline fun <reified T : DokkaPlugin> DokkaContext.plugin(): T = plugin(T::class) ?: throw java.lang.IllegalStateException("Plugin ${T::class.qualifiedName} is not present in context.") interface DokkaContextConfiguration { @@ -58,6 +60,10 @@ private class DokkaContextConfigurationImpl( private val plugins = mutableMapOf<KClass<*>, DokkaPlugin>() private val pluginStubs = mutableMapOf<KClass<*>, DokkaPlugin>() internal val extensions = mutableMapOf<ExtensionPoint<*>, MutableList<Extension<*>>>() + val pointsUsed: MutableSet<ExtensionPoint<*>> = mutableSetOf() + val pointsPopulated: MutableSet<ExtensionPoint<*>> = mutableSetOf() + override val unusedPoints: Set<ExtensionPoint<*>> + get() = pointsPopulated - pointsUsed private enum class State { UNVISITED, @@ -74,9 +80,9 @@ private class DokkaContextConfigurationImpl( fun visit(n: Extension<*>) { val state = verticesWithState[n] - if(state == State.VISITED) + if (state == State.VISITED) return - if(state == State.VISITING) + if (state == State.VISITING) throw Error("Detected cycle in plugins graph") verticesWithState[n] = State.VISITING adjacencyList[n]?.forEach { visit(it) } @@ -84,24 +90,26 @@ private class DokkaContextConfigurationImpl( result += n } - for((vertex, state) in verticesWithState) { - if(state == State.UNVISITED) + for ((vertex, state) in verticesWithState) { + if (state == State.UNVISITED) visit(vertex) } result.asReversed().forEach { + pointsPopulated += it.extensionPoint extensions.getOrPut(it.extensionPoint, ::mutableListOf) += it } } @Suppress("UNCHECKED_CAST") override operator fun <T, E> get(point: E) where T : Any, E : ExtensionPoint<T> = - actions(point).orEmpty() as List<T> + actions(point).also { pointsUsed += point }.orEmpty() as List<T> @Suppress("UNCHECKED_CAST") override fun <T, E> single(point: E): T where T : Any, E : ExtensionPoint<T> { fun throwBadArity(substitution: String): Nothing = throw IllegalStateException( "$point was expected to have exactly one extension registered, but $substitution found." ) + pointsUsed += point val extensions = extensions[point].orEmpty() as List<Extension<T>> return when (extensions.size) { @@ -109,7 +117,7 @@ private class DokkaContextConfigurationImpl( 1 -> extensions.single().action.get(this) else -> { val notFallbacks = extensions.filterNot { it.isFallback } - if (notFallbacks.size == 1) notFallbacks.single().action.get(this) else throwBadArity("many were") + if (notFallbacks.size == 1) notFallbacks.single().action.get(this) else throwBadArity("many were") } } } diff --git a/core/src/main/kotlin/plugability/extensions.kt b/core/src/main/kotlin/plugability/extensions.kt index 46c356df..20b60469 100644 --- a/core/src/main/kotlin/plugability/extensions.kt +++ b/core/src/main/kotlin/plugability/extensions.kt @@ -15,7 +15,7 @@ abstract class Extension<T : Any> internal constructor( internal val extensionName: String, internal val action: LazyEvaluated<T>, internal val ordering: (OrderDsl.() -> Unit)? = null, - internal val condition: DokkaConfiguration.() -> Boolean = { true }, + internal val conditions: Array<DokkaConfiguration.() -> Boolean> = emptyArray(), internal val isFallback: Boolean ) { override fun toString() = "Extension: $pluginClass/$extensionName" @@ -26,9 +26,12 @@ abstract class Extension<T : Any> internal constructor( override fun hashCode() = listOf(pluginClass, extensionName).hashCode() - abstract fun setCondition(condition: (DokkaConfiguration.() -> Boolean)): Extension<T> + abstract fun addCondition(condition: (DokkaConfiguration.() -> Boolean)): Extension<T> abstract fun markedAsFallback(): Extension<T> + + open val condition: DokkaConfiguration.() -> Boolean + get() = { conditions.all { it(this) }} } class ExtensionOrdered<T : Any> internal constructor( @@ -37,7 +40,7 @@ class ExtensionOrdered<T : Any> internal constructor( extensionName: String, action: LazyEvaluated<T>, ordering: (OrderDsl.() -> Unit), - condition: DokkaConfiguration.() -> Boolean = { true }, + conditions: Array<DokkaConfiguration.() -> Boolean> = emptyArray(), isFallback: Boolean = false ) : Extension<T>( extensionPoint, @@ -45,14 +48,14 @@ class ExtensionOrdered<T : Any> internal constructor( extensionName, action, ordering, - condition, + conditions, isFallback ) { - override fun setCondition(condition: DokkaConfiguration.() -> Boolean) = - ExtensionOrdered(extensionPoint, pluginClass, extensionName, action, ordering!!, condition) + override fun addCondition(condition: DokkaConfiguration.() -> Boolean) = + ExtensionOrdered(extensionPoint, pluginClass, extensionName, action, ordering!!, conditions + condition) override fun markedAsFallback() = - ExtensionOrdered(extensionPoint, pluginClass, extensionName, action, ordering!!, condition, true) + ExtensionOrdered(extensionPoint, pluginClass, extensionName, action, ordering!!, conditions, true) } class ExtensionUnordered<T : Any> internal constructor( @@ -60,7 +63,7 @@ class ExtensionUnordered<T : Any> internal constructor( pluginClass: String, extensionName: String, action: LazyEvaluated<T>, - condition: DokkaConfiguration.() -> Boolean = { true }, + conditions: Array<DokkaConfiguration.() -> Boolean> = emptyArray(), isFallback: Boolean = false ) : Extension<T>( extensionPoint, @@ -68,14 +71,14 @@ class ExtensionUnordered<T : Any> internal constructor( extensionName, action, null, - condition, + conditions, isFallback ) { - override fun setCondition(condition: DokkaConfiguration.() -> Boolean) = - ExtensionUnordered(extensionPoint, pluginClass, extensionName, action, condition) + override fun addCondition(condition: DokkaConfiguration.() -> Boolean) = + ExtensionUnordered(extensionPoint, pluginClass, extensionName, action, conditions + condition) override fun markedAsFallback() = - ExtensionUnordered(extensionPoint, pluginClass, extensionName, action, condition, true) + ExtensionUnordered(extensionPoint, pluginClass, extensionName, action, conditions, true) } internal data class Ordering(val previous: Set<Extension<*>>, val following: Set<Extension<*>>) @@ -96,7 +99,8 @@ class ExtendingDSL(private val pluginClass: String, private val extensionName: S ExtensionOrdered(extensionPoint, pluginClass, extensionName, action, block) infix fun <T : Any> Extension<T>.applyIf(condition: DokkaConfiguration.() -> Boolean): Extension<T> = - this.setCondition(condition) + this.addCondition(condition) + } @ExtensionsDsl diff --git a/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentableTranslator.kt b/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentableTranslator.kt index d72eeafd..ca66b90a 100644 --- a/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentableTranslator.kt +++ b/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentableTranslator.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.transformers.descriptors -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor @@ -9,5 +9,5 @@ interface DescriptorToDocumentableTranslator { moduleName: String, packageFragments: Iterable<PackageFragmentDescriptor>, platformData: PlatformData - ): Module + ): DModule }
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt b/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt index 5a17bc24..c8ae9c02 100644 --- a/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt @@ -1,8 +1,8 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.plugability.DokkaContext interface DocumentableMerger { - operator fun invoke(modules: Collection<Module>, context: DokkaContext): Module + operator fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule }
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt b/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt index e41e0c84..83456f01 100644 --- a/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt @@ -1,8 +1,8 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.ModulePageNode interface DocumentableToPageTranslator { - operator fun invoke(module: Module): ModulePageNode + operator fun invoke(module: DModule): ModulePageNode }
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt b/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt index 88a1514d..3eb4704e 100644 --- a/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt @@ -1,8 +1,8 @@ package org.jetbrains.dokka.transformers.documentation -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.plugability.DokkaContext interface DocumentableTransformer { - operator fun invoke(original: Module, context: DokkaContext): Module + operator fun invoke(original: DModule, context: DokkaContext): DModule }
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt b/core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt new file mode 100644 index 00000000..dfb1f26b --- /dev/null +++ b/core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt @@ -0,0 +1,8 @@ +package org.jetbrains.dokka.transformers.documentation + +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.plugability.DokkaContext + +interface PreMergeDocumentableTransformer { + operator fun invoke(modules: List<DModule>, context: DokkaContext): List<DModule> +}
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt b/core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt new file mode 100644 index 00000000..291b72ef --- /dev/null +++ b/core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt @@ -0,0 +1,22 @@ +package org.jetbrains.dokka.transformers.pages + +import org.jetbrains.dokka.pages.PageNode +import org.jetbrains.dokka.pages.RootPageNode + +fun pageScanner(block: PageNode.() -> Unit) = object : PageTransformer { + override fun invoke(input: RootPageNode): RootPageNode = input.invokeOnAll(block) as RootPageNode +} + +fun pageMapper(block: PageNode.() -> PageNode) = object : PageTransformer { + override fun invoke(input: RootPageNode): RootPageNode = input.alterChildren(block) as RootPageNode +} + +fun pageStructureTransformer(block: RootPageNode.() -> RootPageNode) = object : PageTransformer { + override fun invoke(input: RootPageNode): RootPageNode = block(input) +} + +fun PageNode.invokeOnAll(block: PageNode.() -> Unit): PageNode = + this.also(block).also { it.children.forEach { it.invokeOnAll(block) } } + +fun PageNode.alterChildren(block: PageNode.() -> PageNode): PageNode = + block(this).modified(children = this.children.map { it.alterChildren(block) })
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/psi/PsiToDocumentableTranslator.kt b/core/src/main/kotlin/transformers/psi/PsiToDocumentableTranslator.kt index 1ea07ff3..6f5025bd 100644 --- a/core/src/main/kotlin/transformers/psi/PsiToDocumentableTranslator.kt +++ b/core/src/main/kotlin/transformers/psi/PsiToDocumentableTranslator.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.transformers.psi import com.intellij.psi.PsiJavaFile -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext @@ -11,5 +11,5 @@ interface PsiToDocumentableTranslator { psiFiles: List<PsiJavaFile>, platformData: PlatformData, context: DokkaContext - ): Module + ): DModule } diff --git a/core/src/main/resources/dokka/images/docs_logo.svg b/core/src/main/resources/dokka/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/core/src/main/resources/dokka/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/core/src/main/resources/dokka/scripts/navigationLoader.js b/core/src/main/resources/dokka/scripts/navigationLoader.js index 99a885a9..5fe52ade 100644 --- a/core/src/main/resources/dokka/scripts/navigationLoader.js +++ b/core/src/main/resources/dokka/scripts/navigationLoader.js @@ -1,12 +1,41 @@ onload = () => { fetch(pathToRoot + "navigation.html") - .then(response => response.text()) - .then(data => { - document.getElementById("sideMenu").innerHTML = data; - }).then(() => { + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { document.querySelectorAll(".overview > a").forEach(link => { - link.setAttribute("href", pathToRoot + link.getAttribute("href")) + link.setAttribute("href", pathToRoot + link.getAttribute("href")); console.log(link.attributes["href"]) }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() }) -}
\ No newline at end of file +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/core/src/main/resources/dokka/scripts/search.js b/core/src/main/resources/dokka/scripts/search.js index 63112ac5..04d88ab5 100644 --- a/core/src/main/resources/dokka/scripts/search.js +++ b/core/src/main/resources/dokka/scripts/search.js @@ -1,5 +1,7 @@ -var query = new URLSearchParams(window.location.search).get("query"); - document.getElementById("searchTitle").innerHTML += '"' + query + '":'; - document.getElementById("searchTable").innerHTML = pages.filter(el => el.name.startsWith(query)).reduce((acc, element) => { return acc + - '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' }, "");
\ No newline at end of file diff --git a/core/src/main/resources/dokka/styles/style.css b/core/src/main/resources/dokka/styles/style.css index 4a76dd96..46a78467 100644 --- a/core/src/main/resources/dokka/styles/style.css +++ b/core/src/main/resources/dokka/styles/style.css @@ -1,26 +1,40 @@ @import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); -#content { - margin-top: 3em; - margin-left: 15em; +#container { + display: flex; + flex-direction: row; + min-height: 100%; } -#navigation { - position: relative +#main { + width: 100%; + padding-left: 12px; } -#sideMenu, #searchBar { - position: absolute; +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } } #sideMenu { - width: 14em; - padding-left: 0.5em; + padding-top: 12px; + padding-right: 12px; } #sideMenu .sideMenuPart { - margin-left: 1em; + padding-left: 1em; } #sideMenu img { @@ -41,13 +55,59 @@ pointer-events: all; } -.sideMenuPart > .navButton { - margin-left:0.25em +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; } -.sideMenuPart > .overview .navButtonContent::after { - float: right; +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol:empty { + padding: 0px; +} +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); } .sideMenuPart.hidden > .navButton .navButtonContent::after { @@ -55,25 +115,31 @@ } .sideMenuPart.hidden > .sideMenuPart { - display: none; + height: 0; + visibility: hidden; } .filtered > a, .filtered > .navButton { display: none; } -body, table{ - font:14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; background: #F4F4F4; - font-weight:300; - margin-left: auto; + font-weight: 300; margin-right: auto; max-width: 1440px; } table { - display: flex; - padding:5px; + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; } td:first-child { @@ -81,273 +147,274 @@ td:first-child { } .keyword { - color:black; - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; - font-size:12px; + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; } .symbol { - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; - font-size:12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; } .identifier { color: darkblue; - font-size:12px; - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } h1, h2, h3, h4, h5, h6 { - color:#222; - margin:0 0 20px; + color: #222; } p, ul, ol, table, pre, dl { - margin:0 0 20px; + margin: 0 0 20px; } h1, h2, h3 { - line-height:1.1; + line-height: 1.1; } h1 { - font-size:28px; + font-size: 28px; } h2 { - color:#393939; + color: #393939; } h3, h4, h5, h6 { - color:#494949; + color: #494949; } a { - color:#258aaf; - font-weight:400; - text-decoration:none; + color: #258aaf; + font-weight: 400; + text-decoration: none; } a:hover { color: inherit; - text-decoration:underline; + text-decoration: underline; } a small { - font-size:11px; - color:#555; - margin-top:-0.6em; - display:block; + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; } .wrapper { - width:860px; - margin:0 auto; + width: 860px; + margin: 0 auto; } blockquote { - border-left:1px solid #e5e5e5; - margin:0; - padding:0 0 0 20px; - font-style:italic; + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; } code, pre { - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; - color:#333; - font-size:12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; } pre { display: block; -/* - padding:8px 8px; - background: #f8f8f8; - border-radius:5px; - border:1px solid #e5e5e5; -*/ + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ overflow-x: auto; } -table { - width:100%; - border-collapse:collapse; -} - th, td { - text-align:left; + text-align: left; vertical-align: top; - padding:5px 10px; + padding: 5px 10px; } dt { - color:#444; - font-weight:700; + color: #444; + font-weight: 700; } th { - color:#444; + color: #444; } img { - max-width:100%; + max-width: 100%; } header { - width:270px; - float:left; - position:fixed; + width: 270px; + float: left; + position: fixed; } header ul { - list-style:none; - height:40px; + list-style: none; + height: 40px; - padding:0; + padding: 0; background: #eee; background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); - background: -webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - background: -o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - background: -ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - background: linear-gradient(top, #f8f8f8 0%,#dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); - border-radius:5px; - border:1px solid #d2d2d2; - box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0; - width:270px; + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; } header li { - width:89px; - float:left; - border-right:1px solid #d2d2d2; - height:40px; + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; } header ul a { - line-height:1; - font-size:11px; - color:#999; - display:block; - text-align:center; - padding-top:6px; - height:40px; + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; } strong { - color:#222; - font-weight:700; + color: #222; + font-weight: 700; } header ul li + li { - width:88px; - border-left:1px solid #fff; + width: 88px; + border-left: 1px solid #fff; } header ul li + li + li { - border-right:none; - width:89px; + border-right: none; + width: 89px; } header ul a strong { - font-size:14px; - display:block; - color:#222; + font-size: 14px; + display: block; + color: #222; } section { - width:500px; - float:right; - padding-bottom:50px; + width: 500px; + float: right; + padding-bottom: 50px; } small { - font-size:11px; + font-size: 11px; } hr { - border:0; - background:#e5e5e5; - height:1px; - margin:0 0 20px; + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; } footer { - width:270px; - float:left; - position:fixed; - bottom:50px; + width: 270px; + float: left; + position: fixed; + bottom: 50px; } @media print, screen and (max-width: 960px) { div.wrapper { - width:auto; - margin:0; + width: auto; + margin: 0; } header, section, footer { - float:none; - position:static; - width:auto; + float: none; + position: static; + width: auto; } header { - padding-right:320px; + padding-right: 320px; } section { - border:1px solid #e5e5e5; - border-width:1px 0; - padding:20px 0; - margin:0 0 20px; + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; } header a small { - display:inline; + display: inline; } header ul { - position:absolute; - right:50px; - top:52px; + position: absolute; + right: 50px; + top: 52px; } } @media print, screen and (max-width: 720px) { body { - word-wrap:break-word; + word-wrap: break-word; } header { - padding:0; + padding: 0; } header ul, header p.view { - position:static; + position: static; } pre, code { - word-wrap:normal; + word-wrap: normal; } } @media print, screen and (max-width: 480px) { body { - padding:15px; + padding: 15px; } header ul { - display:none; + display: none; } } @media print { body { - padding:0.4in; - font-size:12pt; - color:#444; + padding: 0.4in; + font-size: 12pt; + color: #444; } } diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index f2adcbc1..548bcb93 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -3,29 +3,37 @@ package org.jetbrains.dokka.base import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.renderers.FileWriter import org.jetbrains.dokka.base.renderers.OutputWriter +import org.jetbrains.dokka.base.renderers.html.* import org.jetbrains.dokka.base.renderers.html.HtmlRenderer -import org.jetbrains.dokka.base.resolvers.DefaultLocationProviderFactory -import org.jetbrains.dokka.base.resolvers.LocationProviderFactory import org.jetbrains.dokka.base.signatures.KotlinSignatureProvider import org.jetbrains.dokka.base.signatures.SignatureProvider +import org.jetbrains.dokka.base.resolvers.external.* +import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProviderFactory +import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory import org.jetbrains.dokka.base.transformers.documentables.DefaultDocumentableMerger +import org.jetbrains.dokka.base.transformers.documentables.InheritorsExtractorTransformer +import org.jetbrains.dokka.base.transformers.pages.annotations.DeprecatedStrikethroughTransformer +import org.jetbrains.dokka.base.transformers.documentables.DocumentableVisibilityFilter import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter import org.jetbrains.dokka.base.transformers.pages.merger.FallbackPageMergerStrategy import org.jetbrains.dokka.base.transformers.pages.merger.PageMerger import org.jetbrains.dokka.base.transformers.pages.merger.PageMergerStrategy import org.jetbrains.dokka.base.transformers.pages.merger.SameMethodNamePageMergerStrategy -import org.jetbrains.dokka.base.translators.psi.DefaultPsiToDocumentableTranslator import org.jetbrains.dokka.base.translators.descriptors.DefaultDescriptorToDocumentableTranslator import org.jetbrains.dokka.base.translators.documentables.DefaultDocumentableToPageTranslator +import org.jetbrains.dokka.base.translators.psi.DefaultPsiToDocumentableTranslator import org.jetbrains.dokka.plugability.DokkaPlugin +import org.jetbrains.dokka.transformers.pages.PageTransformer class DokkaBase : DokkaPlugin() { val pageMergerStrategy by extensionPoint<PageMergerStrategy>() val commentsToContentConverter by extensionPoint<CommentsToContentConverter>() val signatureProvider by extensionPoint<SignatureProvider>() val locationProviderFactory by extensionPoint<LocationProviderFactory>() + val externalLocationProviderFactory by extensionPoint<ExternalLocationProviderFactory>() val outputWriter by extensionPoint<OutputWriter>() + val htmlPreprocessors by extensionPoint<PageTransformer>() val descriptorToDocumentableTranslator by extending(isFallback = true) { CoreExtensions.descriptorToDocumentableTranslator providing ::DefaultDescriptorToDocumentableTranslator @@ -39,12 +47,20 @@ class DokkaBase : DokkaPlugin() { CoreExtensions.documentableMerger with DefaultDocumentableMerger } + val preMergeDocumentableTransformer by extending(isFallback = true) { + CoreExtensions.preMergeDocumentableTransformer with DocumentableVisibilityFilter + } + val kotlinSignatureProvider by extending(isFallback = true) { signatureProvider providing { ctx -> KotlinSignatureProvider(ctx.single(commentsToContentConverter), ctx.logger) } } + val inheritorsExtractor by extending { + CoreExtensions.documentableTransformer with InheritorsExtractorTransformer() + } + val documentableToPageTranslator by extending(isFallback = true) { CoreExtensions.documentableToPageTranslator providing { ctx -> DefaultDocumentableToPageTranslator( @@ -73,6 +89,10 @@ class DokkaBase : DokkaPlugin() { } } + val deprecatedStrikethroughTransformer by extending { + CoreExtensions.pageTransformer providing ::DeprecatedStrikethroughTransformer + } + val htmlRenderer by extending { CoreExtensions.renderer providing ::HtmlRenderer applyIf { format == "html" } } @@ -81,7 +101,35 @@ class DokkaBase : DokkaPlugin() { locationProviderFactory providing ::DefaultLocationProviderFactory } + val javadocLocationProvider by extending { + externalLocationProviderFactory with JavadocExternalLocationProviderFactory() + } + + val dokkaLocationProvider by extending { + externalLocationProviderFactory with DokkaExternalLocationProviderFactory() + } + val fileWriter by extending(isFallback = true) { outputWriter providing ::FileWriter } + + val rootCreator by extending { + htmlPreprocessors with RootCreator + } + + val navigationPageInstaller by extending { + htmlPreprocessors with NavigationPageInstaller order { after(rootCreator) } + } + + val searchPageInstaller by extending { + htmlPreprocessors with SearchPageInstaller order { after(rootCreator) } + } + + val resourceInstaller by extending { + htmlPreprocessors with ResourceInstaller order { after(rootCreator) } + } + + val styleAndScriptsAppender by extending { + htmlPreprocessors with StyleAndScriptsAppender order { after(rootCreator) } + } }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index 33be5dfe..0ff0511a 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.base.renderers import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.resolvers.LocationProvider +import org.jetbrains.dokka.base.resolvers.local.LocationProvider import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin @@ -81,6 +81,7 @@ abstract class DefaultRenderer<T>( is ContentList -> buildList(node, pageContext, platformRestriction) is ContentTable -> buildTable(node, pageContext, platformRestriction) is ContentGroup -> buildGroup(node, pageContext, platformRestriction) + is ContentBreakLine -> buildNewLine() is PlatformHintedContent -> buildPlatformDependent(node, pageContext) else -> buildError(node) } diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 74bc6fea..53222325 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -2,11 +2,14 @@ package org.jetbrains.dokka.base.renderers.html import kotlinx.html.* import kotlinx.html.stream.createHTML +import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.DefaultRenderer import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.DFunction import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query import java.io.File open class HtmlRenderer( @@ -15,22 +18,21 @@ open class HtmlRenderer( private val pageList = mutableListOf<String>() - override val preprocessors = listOf( - RootCreator, - SearchPageInstaller, - ResourceInstaller, - NavigationPageInstaller, - StyleAndScriptsAppender - ) + override val preprocessors = context.plugin<DokkaBase>().query { htmlPreprocessors } override fun FlowContent.wrapGroup( node: ContentGroup, pageContext: ContentPage, childrenCallback: FlowContent.() -> Unit - ) = when { - node.style.contains(TextStyle.Paragraph) -> p { childrenCallback() } - node.style.contains(TextStyle.Block) -> div { childrenCallback() } - else -> childrenCallback() + ) { + val additionalClasses = node.style.joinToString(" ") { it.toString().toLowerCase() } + return when { + node.dci.kind == ContentKind.Symbol -> div("symbol $additionalClasses") { childrenCallback() } + node.dci.kind == ContentKind.BriefComment -> div("brief $additionalClasses") { childrenCallback() } + node.style.contains(TextStyle.Paragraph) -> p(additionalClasses) { childrenCallback() } + node.style.contains(TextStyle.Block) -> div(additionalClasses) { childrenCallback() } + else -> childrenCallback() + } } override fun FlowContent.buildPlatformDependent(content: PlatformHintedContent, pageContext: ContentPage) { @@ -44,7 +46,7 @@ open class HtmlRenderer( consumer.onTagContentUnsafe { +distinct.keys.single() } else distinct.forEach { text, platforms -> - consumer.onTagContentUnsafe { +platforms.joinToString(prefix = "$text [", postfix = "]") { it.name } } + consumer.onTagContentUnsafe { +platforms.joinToString(prefix = " [", postfix = "] $text") { it.name } } } } @@ -172,10 +174,16 @@ open class HtmlRenderer( language: String, pageContext: ContentPage ) { - buildNewLine() - code.forEach { - +((it as? ContentText)?.text ?: run { context.logger.error("Cannot cast $it as ContentText!"); "" }) - buildNewLine() + span(classes = "code") { + val iterator = code.iterator() + while (iterator.hasNext()) { + val element = iterator.next() + +((element as? ContentText)?.text + ?: run { context.logger.error("Cannot cast $element as ContentText!"); "" }) + if (iterator.hasNext()) { + buildNewLine() + } + } } } @@ -191,6 +199,9 @@ open class HtmlRenderer( } override fun FlowContent.buildText(textNode: ContentText) { + when{ + textNode.style.contains(TextStyle.Indented) -> consumer.onTagContentEntity(Entities.nbsp) + } text(textNode.text) } @@ -202,11 +213,18 @@ open class HtmlRenderer( private fun PageNode.root(path: String) = locationProvider.resolveRoot(this) + path override fun buildPage(page: ContentPage, content: (FlowContent, ContentPage) -> Unit): String = - buildHtml(page, page.embeddedResources) { content(this, page) } + buildHtml(page, page.embeddedResources) { + div { + id = "content" + attributes["pageIds"] = page.dri.first().toString() + content(this, page) + } + } open fun buildHtml(page: PageNode, resources: List<String>, content: FlowContent.() -> Unit) = createHTML().html { head { + meta(name = "viewport", content = "width=device-width, initial-scale=1") title(page.name) with(resources) { filter { it.substringBefore('?').substringAfterLast('.') == "css" } @@ -218,23 +236,29 @@ open class HtmlRenderer( } body { div { - id = "navigation" + id = "container" div { - id = "searchBar" - form(action = page.root("-search.html"), method = FormMethod.get) { - id = "searchForm" - input(type = InputType.search, name = "query") - input(type = InputType.submit) { value = "Search" } + id = "leftColumn" + div { + id = "logo" + } + div { + id = "sideMenu" } } div { - id = "sideMenu" + id = "main" + div { + id = "searchBar" + form(action = page.root("-search.html"), method = FormMethod.get) { + id = "searchForm" + input(type = InputType.search, name = "query") + input(type = InputType.submit) { value = "Search" } + } + } + content() } } - div { - id = "content" - content() - } } } } @@ -245,7 +269,7 @@ private fun PageNode.pageKind() = when (this) { is PackagePageNode -> "package" is ClasslikePageNode -> "class" is MemberPageNode -> when (this.documentable) { - is Function -> "function" + is DFunction -> "function" else -> "other" } else -> "other" diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt index ad574769..4b90cc8a 100644 --- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt @@ -23,6 +23,7 @@ class NavigationPage(val root: NavigationNode) : RendererSpecificPage { with(renderer) { div("sideMenuPart") { id = navId + attributes["pageId"] = node.dri.toString() div("overview") { buildLink(node.dri, node.platforms) { +node.name } if (node.children.isNotEmpty()) { diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index 787f2b69..a72c77ea 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -20,7 +20,7 @@ object SearchPageInstaller : PageTransformer { name = "Search", children = emptyList(), strategy = RenderingStrategy<HtmlRenderer> { - buildHtml(it, listOf("styles/style.css", "scripts/pages.js")) { + buildHtml(it, listOf("styles/style.css", "scripts/pages.js", "scripts/search.js")) { h1 { id = "searchTitle" text("Search results for ") diff --git a/plugins/base/src/main/kotlin/resolvers/DefaultLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/DefaultLocationProvider.kt deleted file mode 100644 index 2238b0c3..00000000 --- a/plugins/base/src/main/kotlin/resolvers/DefaultLocationProvider.kt +++ /dev/null @@ -1,116 +0,0 @@ -package org.jetbrains.dokka.base.resolvers - -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.utilities.htmlEscape -import java.util.* - -private const val PAGE_WITH_CHILDREN_SUFFIX = "index" - -open class DefaultLocationProvider( - protected val pageGraphRoot: RootPageNode, - protected val dokkaContext: DokkaContext -) : LocationProvider { - protected val extension = ".html" - - protected val pagesIndex: Map<DRI, ContentPage> = pageGraphRoot.asSequence().filterIsInstance<ContentPage>() - .map { it.dri.map { dri -> dri to it } }.flatten() - .groupingBy { it.first } - .aggregate { dri, _, (_, page), first -> - if (first) page else throw AssertionError("Multiple pages associated with dri: $dri") - } - - protected val pathsIndex: Map<PageNode, List<String>> = IdentityHashMap<PageNode, List<String>>().apply { - fun registerPath(page: PageNode, prefix: List<String>) { - val newPrefix = prefix + page.pathName - put(page, newPrefix) - page.children.forEach { registerPath(it, newPrefix) } - } - put(pageGraphRoot, emptyList()) - pageGraphRoot.children.forEach { registerPath(it, emptyList()) } - } - - override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String = - pathTo(node, context) + if (!skipExtension) extension else "" - - override fun resolve(dri: DRI, platforms: List<PlatformData>, context: PageNode?): String = - pagesIndex[dri]?.let { resolve(it, context) } ?: - // Not found in PageGraph, that means it's an external link - ExternalLocationProvider.getLocation(dri, - this.dokkaContext.configuration.passesConfigurations - .filter { passConfig -> - platforms.toSet() - .contains(PlatformData(passConfig.moduleName, passConfig.analysisPlatform, passConfig.targets)) - } // TODO: change targets to something better? - .flatMap { it.externalDocumentationLinks }.distinct() - ) - - override fun resolveRoot(node: PageNode): String = - pathTo(pageGraphRoot, node).removeSuffix(PAGE_WITH_CHILDREN_SUFFIX) - - override fun ancestors(node: PageNode): List<PageNode> = - generateSequence(node) { it.parent() }.toList() - - protected open fun pathTo(node: PageNode, context: PageNode?): String { - fun pathFor(page: PageNode) = pathsIndex[page] ?: throw AssertionError( - "${page::class.simpleName}(${page.name}) does not belong to current page graph so it is impossible to compute its path" - ) - - val contextNode = - if (context?.children?.isEmpty() == true && context.parent() != null) context.parent() else context - val nodePath = pathFor(node) - val contextPath = contextNode?.let { pathFor(it) }.orEmpty() - - val commonPathElements = nodePath.asSequence().zip(contextPath.asSequence()) - .takeWhile { (a, b) -> a == b }.count() - - return (List(contextPath.size - commonPathElements) { ".." } + nodePath.drop(commonPathElements) + - if (node.children.isNotEmpty()) listOf(PAGE_WITH_CHILDREN_SUFFIX) else emptyList()).joinToString("/") - } - - private fun PageNode.parent() = pageGraphRoot.parentMap[this] -} - -fun DRI.toJavadocLocation(jdkVersion: Int): String { // TODO: classes without packages? - val packageLink = packageName?.replace(".", "/") - if (classNames == null) { - return "$packageLink/package-summary.html".htmlEscape() - } - val classLink = if (packageLink == null) "$classNames.html" else "$packageLink/$classNames.html" - val callableChecked = callable ?: return classLink.htmlEscape() - - val callableLink = "$classLink#${callableChecked.name}" + when { - jdkVersion < 8 -> "(${callableChecked.params.joinToString(", ")})" - jdkVersion < 10 -> "-${callableChecked.params.joinToString("-")}-" - else -> "(${callableChecked.params.joinToString(",")})" - } - - return callableLink.htmlEscape() -} - -fun DRI.toDokkaLocation(extension: String): String { // TODO: classes without packages? - val classNamesChecked = classNames ?: return "$packageName/index$extension" - - val classLink = if (packageName == null) { - "" - } else { - "$packageName/" - } + classNamesChecked.split('.').joinToString("/", transform = ::identifierToFilename) - - val callableChecked = callable ?: return "$classLink/index$extension" - - return "$classLink/${identifierToFilename(callableChecked.name)}$extension" -} - -private val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out") - -private fun identifierToFilename(name: String): String { - if (name.isEmpty()) return "--root--" - val escaped = name.replace('<', '-').replace('>', '-') - val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() } - return if (lowercase in reservedFilenames) "--$lowercase--" else lowercase -} - -private val PageNode.pathName: String - get() = if (this is PackagePageNode) name else identifierToFilename(name) diff --git a/plugins/base/src/main/kotlin/resolvers/ExternalLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/ExternalLocationProvider.kt deleted file mode 100644 index 7c0e9952..00000000 --- a/plugins/base/src/main/kotlin/resolvers/ExternalLocationProvider.kt +++ /dev/null @@ -1,99 +0,0 @@ -package org.jetbrains.dokka.base.resolvers - -import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink -import org.jetbrains.dokka.links.DRI -import java.net.HttpURLConnection -import java.net.URL -import java.net.URLConnection - -object ExternalLocationProvider { // TODO: Refactor this!!! - private const val DOKKA_PARAM_PREFIX = "\$dokka." - - private val cache: MutableMap<URL, LocationInfo> = mutableMapOf() - - fun getLocation(dri: DRI, externalDocumentationLinks: List<ExternalDocumentationLink>): String { - val toResolve: MutableList<ExternalDocumentationLink> = mutableListOf() - for(link in externalDocumentationLinks){ - val info = cache[link.packageListUrl] - if(info == null) { - toResolve.add(link) - } else if(info.packages.contains(dri.packageName)) { - return link.url.toExternalForm() + getLink(dri, info) - } - } - // Not in cache, resolve packageLists - while (toResolve.isNotEmpty()){ - val link = toResolve.first().also { toResolve.remove(it) } - val locationInfo = loadPackageList(link.packageListUrl) - if(locationInfo.packages.contains(dri.packageName)) { - return link.url.toExternalForm() + getLink(dri, locationInfo) - } - } - return "" - } - - private fun getLink(dri: DRI, locationInfo: LocationInfo): String = when(locationInfo.format) { - "javadoc" -> dri.toJavadocLocation(8) - "kotlin-website-html", "html" -> locationInfo.locations[dri.packageName + "." + dri.classNames] ?: dri.toDokkaLocation(".html") - "markdown" -> locationInfo.locations[dri.packageName + "." + dri.classNames] ?: dri.toDokkaLocation(".md") - // TODO: rework this - else -> throw RuntimeException("Unrecognized format") - } - - - private fun loadPackageList(url: URL): LocationInfo { - val packageListStream = url.doOpenConnectionToReadContent().getInputStream() - val (params, packages) = - packageListStream - .bufferedReader() - .useLines { lines -> lines.partition { it.startsWith(DOKKA_PARAM_PREFIX) } } - - val paramsMap = params.asSequence() - .map { it.removePrefix(DOKKA_PARAM_PREFIX).split(":", limit = 2) } - .groupBy({ (key, _) -> key }, { (_, value) -> value }) - - val format = paramsMap["format"]?.singleOrNull() ?: "javadoc" - - val locations = paramsMap["location"].orEmpty() - .map { it.split("\u001f", limit = 2) } - .map { (key, value) -> key to value } - .toMap() - - val info = LocationInfo(format, packages.toSet(), locations) - cache[url] = info - return info - } - - private fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection { - val connection = this.openConnection().apply { - connectTimeout = timeout - readTimeout = timeout - } - - when (connection) { - is HttpURLConnection -> { - return when (connection.responseCode) { - in 200..299 -> { - connection - } - HttpURLConnection.HTTP_MOVED_PERM, - HttpURLConnection.HTTP_MOVED_TEMP, - HttpURLConnection.HTTP_SEE_OTHER -> { - if (redirectsAllowed > 0) { - val newUrl = connection.getHeaderField("Location") - URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1) - } else { - throw RuntimeException("Too many redirects") - } - } - else -> { - throw RuntimeException("Unhandled http code: ${connection.responseCode}") - } - } - } - else -> return connection - } - } - data class LocationInfo(val format: String, val packages: Set<String>, val locations: Map<String, String>) - -} diff --git a/plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt new file mode 100644 index 00000000..ff9186f7 --- /dev/null +++ b/plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt @@ -0,0 +1,35 @@ +package org.jetbrains.dokka.base.resolvers.external + +import org.jetbrains.dokka.base.resolvers.local.identifierToFilename +import org.jetbrains.dokka.links.DRI + + +class DokkaExternalLocationProviderFactory : ExternalLocationProviderFactory by ExternalLocationProviderFactoryWithCache( + object : ExternalLocationProviderFactory { + override fun getExternalLocationProvider(param: String): ExternalLocationProvider? = + when (param) { + "kotlin-website-html", "html" -> DokkaExternalLocationProvider(param, ".html") + "markdown" -> DokkaExternalLocationProvider(param, ".md") + else -> null + } + } +) + +class DokkaExternalLocationProvider(override val param: String, val extension: String) : ExternalLocationProvider { + + override fun DRI.toLocation(): String { // TODO: classes without packages? + + val classNamesChecked = classNames ?: return "${packageName ?: ""}/index$extension" + + val classLink = (listOfNotNull(packageName) + classNamesChecked.split('.')).joinToString( + "/", + transform = ::identifierToFilename + ) + + val callableChecked = callable ?: return "$classLink/index$extension" + + return "$classLink/${identifierToFilename( + callableChecked.name + )}$extension" + } +} diff --git a/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt new file mode 100644 index 00000000..6fb05024 --- /dev/null +++ b/plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt @@ -0,0 +1,23 @@ +package org.jetbrains.dokka.base.resolvers.external + +import org.jetbrains.dokka.links.DRI + + +interface ExternalLocationProvider { + + val param: String + fun DRI.toLocation(): String +} + +interface ExternalLocationProviderFactory { + + fun getExternalLocationProvider(param: String): ExternalLocationProvider? +} + +class ExternalLocationProviderFactoryWithCache(val ext: ExternalLocationProviderFactory) : ExternalLocationProviderFactory { + + private val locationProviders: MutableList<ExternalLocationProvider> = mutableListOf() + + override fun getExternalLocationProvider(param: String): ExternalLocationProvider? = + locationProviders.find { it.param == param } ?: ext.getExternalLocationProvider(param)?.also { locationProviders.add(it) } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt new file mode 100644 index 00000000..c52c9bbb --- /dev/null +++ b/plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt @@ -0,0 +1,37 @@ +package org.jetbrains.dokka.base.resolvers.external + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.utilities.htmlEscape + +class JavadocExternalLocationProviderFactory : ExternalLocationProviderFactory by ExternalLocationProviderFactoryWithCache( + object : ExternalLocationProviderFactory { + override fun getExternalLocationProvider(param: String): ExternalLocationProvider? = + when(param) { + "javadoc1" -> JavadocExternalLocationProvider(param, "()", ", ") // Covers JDK 1 - 7 + "javadoc8" -> JavadocExternalLocationProvider(param, "--", "-") // Covers JDK 8 - 9 + "javadoc10" -> JavadocExternalLocationProvider(param, "()", ",") // Covers JDK 10 + else -> null + } + } +) + +class JavadocExternalLocationProvider(override val param: String, val brackets: String, val separator: String) : ExternalLocationProvider { + + override fun DRI.toLocation(): String { + + val packageLink = packageName?.replace(".", "/") + if (classNames == null) { + return "$packageLink/package-summary.html".htmlEscape() + } + val classLink = if (packageLink == null) "$classNames.html" else "$packageLink/$classNames.html" + val callableChecked = callable ?: return classLink.htmlEscape() + + val callableLink = "$classLink#" + + callableChecked.name + + "${brackets.first()}" + + callableChecked.params.joinToString(separator) + + "${brackets.last()}" + + return callableLink.htmlEscape() + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt new file mode 100644 index 00000000..736367a9 --- /dev/null +++ b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt @@ -0,0 +1,222 @@ +package org.jetbrains.dokka.base.resolvers.local + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProvider +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import java.lang.IllegalStateException +import java.net.HttpURLConnection +import java.net.URL +import java.net.URLConnection +import java.util.* + +private const val PAGE_WITH_CHILDREN_SUFFIX = "index" +private const val DOKKA_PARAM_PREFIX = "\$dokka." + +open class DefaultLocationProvider( + protected val pageGraphRoot: RootPageNode, + protected val dokkaContext: DokkaContext +) : LocationProvider { + protected val extension = ".html" + + protected val externalLocationProviderFactories = + dokkaContext.plugin<DokkaBase>().query { externalLocationProviderFactory } + + protected val pagesIndex: Map<DRI, ContentPage> = pageGraphRoot.asSequence().filterIsInstance<ContentPage>() + .map { it.dri.map { dri -> dri to it } }.flatten() + .groupingBy { it.first } + .aggregate { dri, _, (_, page), first -> + if (first) page else throw AssertionError("Multiple pages associated with dri: $dri") + } + + protected val pathsIndex: Map<PageNode, List<String>> = IdentityHashMap<PageNode, List<String>>().apply { + fun registerPath(page: PageNode, prefix: List<String>) { + val newPrefix = prefix + page.pathName + put(page, newPrefix) + page.children.forEach { registerPath(it, newPrefix) } + } + put(pageGraphRoot, emptyList()) + pageGraphRoot.children.forEach { registerPath(it, emptyList()) } + } + + override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String = + pathTo(node, context) + if (!skipExtension) extension else "" + + override fun resolve(dri: DRI, platforms: List<PlatformData>, context: PageNode?): String = + pagesIndex[dri]?.let { resolve(it, context) } ?: + // Not found in PageGraph, that means it's an external link + getLocation(dri, + this.dokkaContext.configuration.passesConfigurations + .filter { passConfig -> + platforms.toSet() + .contains(PlatformData(passConfig.moduleName, passConfig.analysisPlatform, passConfig.targets)) + } // TODO: change targets to something better? + .groupBy({ it.jdkVersion }, { it.externalDocumentationLinks }) + .map { it.key to it.value.flatten().distinct() }.toMap() + ) + + override fun resolveRoot(node: PageNode): String = + pathTo(pageGraphRoot, node).removeSuffix(PAGE_WITH_CHILDREN_SUFFIX) + + override fun ancestors(node: PageNode): List<PageNode> = + generateSequence(node) { it.parent() }.toList() + + protected open fun pathTo(node: PageNode, context: PageNode?): String { + fun pathFor(page: PageNode) = pathsIndex[page] ?: throw AssertionError( + "${page::class.simpleName}(${page.name}) does not belong to current page graph so it is impossible to compute its path" + ) + + val contextNode = + if (context?.children?.isEmpty() == true && context.parent() != null) context.parent() else context + val nodePath = pathFor(node) + val contextPath = contextNode?.let { pathFor(it) }.orEmpty() + + val commonPathElements = nodePath.asSequence().zip(contextPath.asSequence()) + .takeWhile { (a, b) -> a == b }.count() + + return (List(contextPath.size - commonPathElements) { ".." } + nodePath.drop(commonPathElements) + + if (node.children.isNotEmpty()) listOf(PAGE_WITH_CHILDREN_SUFFIX) else emptyList()).joinToString("/") + } + + private fun PageNode.parent() = pageGraphRoot.parentMap[this] + + private val cache: MutableMap<URL, LocationInfo> = mutableMapOf() + + private fun getLocation( + dri: DRI, + jdkToExternalDocumentationLinks: Map<Int, List<DokkaConfiguration.ExternalDocumentationLink>> + ): String { + val toResolve: MutableMap<Int, MutableList<DokkaConfiguration.ExternalDocumentationLink>> = mutableMapOf() + for ((jdk, links) in jdkToExternalDocumentationLinks) { + for (link in links) { + val info = cache[link.packageListUrl] + if (info == null) { + toResolve.getOrPut(jdk) { mutableListOf() }.add(link) + } else if (info.packages.contains(dri.packageName)) { + return link.url.toExternalForm() + getLink( + dri, + info + ) + } + } + } + // Not in cache, resolve packageLists + for ((jdk, links) in toResolve) { + for (link in links) { + val locationInfo = + loadPackageList( + jdk, + link.packageListUrl + ) + if (locationInfo.packages.contains(dri.packageName)) { + return link.url.toExternalForm() + getLink( + dri, + locationInfo + ) + } + } + toResolve.remove(jdk) + } + return "" + } + + private fun getLink(dri: DRI, locationInfo: LocationInfo): String = + locationInfo.locations[dri.packageName + "." + dri.classNames] + ?: // Not sure if it can be here, previously it shadowed only kotlin/dokka related sources, here it shadows both dokka/javadoc, cause I cannot distinguish what LocationProvider has been hypothetically chosen + if (locationInfo.externalLocationProvider != null) + with(locationInfo.externalLocationProvider) { + dri.toLocation() + } + else + throw IllegalStateException("Have not found any convenient ExternalLocationProvider for $dri DRI!") + + private fun loadPackageList(jdk: Int, url: URL): LocationInfo { + val packageListStream = url.doOpenConnectionToReadContent().getInputStream() + val (params, packages) = + packageListStream + .bufferedReader() + .useLines { lines -> lines.partition { it.startsWith(DOKKA_PARAM_PREFIX) } } + + val paramsMap = params.asSequence() + .map { it.removePrefix(DOKKA_PARAM_PREFIX).split(":", limit = 2) } + .groupBy({ (key, _) -> key }, { (_, value) -> value }) + + val format = paramsMap["format"]?.singleOrNull() ?: when { + jdk < 8 -> "javadoc1" // Covers JDK 1 - 7 + jdk < 10 -> "javadoc8" // Covers JDK 8 - 9 + else -> "javadoc10" // Covers JDK 10+ + } + + val locations = paramsMap["location"].orEmpty() + .map { it.split("\u001f", limit = 2) } + .map { (key, value) -> key to value } + .toMap() + + val externalLocationProvider = + externalLocationProviderFactories.asSequence().map { it.getExternalLocationProvider(format) } + .filterNotNull().take(1).firstOrNull() + + val info = LocationInfo( + externalLocationProvider, + packages.toSet(), + locations + ) + cache[url] = info + return info + } + + private fun URL.doOpenConnectionToReadContent(timeout: Int = 10000, redirectsAllowed: Int = 16): URLConnection { + val connection = this.openConnection().apply { + connectTimeout = timeout + readTimeout = timeout + } + + when (connection) { + is HttpURLConnection -> { + return when (connection.responseCode) { + in 200..299 -> { + connection + } + HttpURLConnection.HTTP_MOVED_PERM, + HttpURLConnection.HTTP_MOVED_TEMP, + HttpURLConnection.HTTP_SEE_OTHER -> { + if (redirectsAllowed > 0) { + val newUrl = connection.getHeaderField("Location") + URL(newUrl).doOpenConnectionToReadContent(timeout, redirectsAllowed - 1) + } else { + throw RuntimeException("Too many redirects") + } + } + else -> { + throw RuntimeException("Unhandled http code: ${connection.responseCode}") + } + } + } + else -> return connection + } + } + + data class LocationInfo( + val externalLocationProvider: ExternalLocationProvider?, + val packages: Set<String>, + val locations: Map<String, String> + ) +} + +private val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out") + +internal fun identifierToFilename(name: String): String { + if (name.isEmpty()) return "--root--" + val escaped = name.replace("<|>".toRegex(), "-") + val lowercase = escaped.replace("[A-Z]".toRegex()) { matchResult -> "-" + matchResult.value.toLowerCase() } + return if (lowercase in reservedFilenames) "--$lowercase--" else lowercase +} + +private val PageNode.pathName: String + get() = if (this is PackagePageNode) name else identifierToFilename( + name + ) diff --git a/plugins/base/src/main/kotlin/resolvers/DefaultLocationProviderFactory.kt b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProviderFactory.kt index c649e22b..57f53ba6 100644 --- a/plugins/base/src/main/kotlin/resolvers/DefaultLocationProviderFactory.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProviderFactory.kt @@ -1,9 +1,10 @@ -package org.jetbrains.dokka.base.resolvers +package org.jetbrains.dokka.base.resolvers.local import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext class DefaultLocationProviderFactory(private val context: DokkaContext) : LocationProviderFactory { - override fun getLocationProvider(pageNode: RootPageNode) = DefaultLocationProvider(pageNode, context) + override fun getLocationProvider(pageNode: RootPageNode) = + DefaultLocationProvider(pageNode, context) }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/resolvers/LocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt index 13f4563c..0814cb3e 100644 --- a/plugins/base/src/main/kotlin/resolvers/LocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt @@ -1,7 +1,6 @@ -package org.jetbrains.dokka.base.resolvers +package org.jetbrains.dokka.base.resolvers.local import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.pages.RootPageNode diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index c8a5105d..8d8c5f73 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -2,14 +2,18 @@ package org.jetbrains.dokka.base.signatures import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.DriOfAny +import org.jetbrains.dokka.links.DriOfUnit import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Annotation -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.DAnnotation +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.DFunction import org.jetbrains.dokka.pages.ContentKind import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.pages.TextStyle import org.jetbrains.dokka.utilities.DokkaLogger class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider { @@ -18,27 +22,43 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog private val ignoredVisibilities = setOf(JavaVisibility.Default, KotlinVisibility.Public) override fun signature(documentable: Documentable): ContentNode = when (documentable) { - is Function -> signature(documentable) - is Classlike -> signature(documentable) - is TypeParameter -> signature(documentable) + is DFunction -> signature(documentable) + is DProperty -> signature(documentable) + is DClasslike -> signature(documentable) + is DTypeParameter -> signature(documentable) + is DEnumEntry -> signature(documentable) else -> throw NotImplementedError( "Cannot generate signature for ${documentable::class.qualifiedName} ${documentable.name}" ) } - private fun signature(c: Classlike) = contentBuilder.contentFor(c, ContentKind.Symbol) { + private fun signature(e: DEnumEntry)= contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)) + + private fun signature(c: DClasslike) = contentBuilder.contentFor(c, ContentKind.Symbol, setOf(TextStyle.Monospace)) { platformText(c.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } - if (c is Class) { - text(c.modifier.name + " ") + if (c is DClass) { + platformText(c.modifier){ + if (c.extra[AdditionalModifiers]?.content?.contains(ExtraModifiers.DATA) == true && it.name == "final") "data " + else it.name + " " + } } when (c) { - is Class -> text("class ") - is Interface -> text("interface ") - is Enum -> text("enum ") - is Object -> text("object ") - is Annotation -> text("annotation class ") + is DClass -> text("class ") + is DInterface -> text("interface ") + is DEnum -> text("enum ") + is DObject -> text("object ") + is DAnnotation -> text("annotation class ") + } + link(c.name!!, c.dri) + if(c is DClass){ + val pConstructor = c.constructors.singleOrNull() { it.extra[PrimaryConstructorExtra] != null } + list(pConstructor?.parameters.orEmpty(), "(", ")", ",", pConstructor?.platformData.orEmpty().toSet()){ + breakLine() + text(it.name ?: "", styles = mainStyles.plus(TextStyle.Bold).plus(TextStyle.Indented)) + text(": ") + signatureForProjection(it.type) + } } - text(c.name!!) if (c is WithSupertypes) { c.supertypes.map { (p, dris) -> list(dris, prefix = " : ", platformData = setOf(p)) { @@ -48,33 +68,44 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog } } - private fun signature(f: Function) = contentBuilder.contentFor(f, ContentKind.Symbol) { + private fun signature(p: DProperty) = contentBuilder.contentFor(p, ContentKind.Symbol, setOf(TextStyle.Monospace)) { + signatureForProjection(p.type) + } + + private fun signature(f: DFunction) = contentBuilder.contentFor(f, ContentKind.Symbol, setOf(TextStyle.Monospace)) { platformText(f.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } - text(f.modifier.name + " ") + platformText(f.modifier) { it.name + " " } text("fun ") + list(f.generics, prefix = "<", suffix = "> ") { + +buildSignature(it) + } f.receiver?.also { - type(it.type) + signatureForProjection(it.type) text(".") } link(f.name, f.dri) - list(f.generics, prefix = "<", suffix = ">") { - +buildSignature(it) - } text("(") list(f.parameters) { - link(it.name!!, it.dri) + text(it.name!!) text(": ") - type(it.type) + + signatureForProjection(it.type) } text(")") - val returnType = f.type - if (!f.isConstructor && returnType.constructorFqName != Unit::class.qualifiedName) { + if (f.documentReturnType()) { text(": ") - type(returnType) + signatureForProjection(f.type) } } - private fun signature(t: TypeParameter) = contentBuilder.contentFor(t, ContentKind.Symbol) { + private fun DFunction.documentReturnType() = when { + this.isConstructor -> false + this.type is TypeConstructor && (this.type as TypeConstructor).dri == DriOfUnit -> false + this.type is Void -> false + else -> true + } + + private fun signature(t: DTypeParameter) = contentBuilder.contentFor(t) { link(t.name, t.dri) list(t.bounds, prefix = " : ") { signatureForProjection(it) @@ -84,12 +115,15 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection(p: Projection): Unit = when (p) { is OtherParameter -> text(p.name) - is TypeConstructor -> group { - link(p.dri.classNames.orEmpty(), p.dri) - list(p.projections, prefix = "<", suffix = ">") { - signatureForProjection(it) + is TypeConstructor -> if (p.function) + +funType(this.mainDRI, this.mainPlatformData, p) + else + group { + link(p.dri.classNames.orEmpty(), p.dri) + list(p.projections, prefix = "<", suffix = ">") { + signatureForProjection(it) + } } - } is Variance -> group { text(p.kind.toString() + " ") @@ -102,5 +136,41 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog signatureForProjection(p.inner) text("?") } + + is JavaObject -> link("Any", DriOfAny) + is Void -> link("Unit", DriOfUnit) + is PrimitiveJavaType -> signatureForProjection(p.translateToKotlin()) } + + fun funType(dri: DRI, platformData: Set<PlatformData>, type: TypeConstructor) = + contentBuilder.contentFor(dri, platformData, ContentKind.Symbol, setOf(TextStyle.Monospace)) { + if (type.extension) { + signatureForProjection(type.projections.first()) + text(".") + } + + val args = if (type.extension) + type.projections.drop(1) + else + type.projections + + text("(") + args.subList(0, args.size - 1).forEachIndexed { i, arg -> + signatureForProjection(arg) + if (i < args.size - 2) text(", ") + } + text(") -> ") + signatureForProjection(args.last()) + } } + +private fun PrimitiveJavaType.translateToKotlin() = TypeConstructor( + dri = DRI("kotlin", name.capitalize()), + projections = emptyList() +) + +val TypeConstructor.function + get() = modifier == FunctionModifiers.FUNCTION || modifier == FunctionModifiers.EXTENSION + +val TypeConstructor.extension + get() = modifier == FunctionModifiers.EXTENSION diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt index 8ae2065b..c87b5de3 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt @@ -1,10 +1,10 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function -import org.jetbrains.dokka.model.Package -import org.jetbrains.dokka.model.Annotation +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.DFunction +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.model.DAnnotation import org.jetbrains.dokka.model.properties.mergeExtras import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext @@ -12,20 +12,20 @@ import org.jetbrains.dokka.transformers.documentation.DocumentableMerger import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult internal object DefaultDocumentableMerger : DocumentableMerger { - override fun invoke(modules: Collection<Module>, context: DokkaContext): Module { - val name = modules.map { it.name }.distinct().singleOrNull() ?: run { - context.logger.error("All module names need to be the same") - modules.first().name - } + + override fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule { + + val projectName = + modules.fold(modules.first().name) { acc, module -> acc.commonPrefixWith(module.name) }.takeIf { it.isNotEmpty() } + ?: "project" return modules.reduce { left, right -> val list = listOf(left, right) - - Module( - name = name, + DModule( + name = projectName, packages = merge( list.flatMap { it.packages }, - Package::mergeWith + DPackage::mergeWith ), documentation = list.platformDependentFor { documentation }, platformData = list.flatMap { it.platformData }.distinct() @@ -71,12 +71,25 @@ private fun <T> mergeExpectActual( } fun analyzeExpectActual(sameDriElements: List<T>): List<T> { - val (expect, actual) = sameDriElements.partition { it.sources.expect != null } + val pathGrouped: Collection<T> = mutableMapOf<Set<String>, T>().apply { + sameDriElements.forEach { documentable -> + val paths = documentable.sources.allValues.map { it.path }.toSet() + val key = keys.find { it.containsAll(paths) } + if (key == null) { + put(paths, documentable) + } else { + computeIfPresent(key) { _, old -> reducer(old, documentable) } + } + } + }.values + val (expect, actual) = pathGrouped.partition { it.sources.expect != null } val mergedExpect = expect.groupBy { it.sources.expect?.path }.values.map { e -> e.first().platformSetter(e.flatMap { it.platformData }.distinct()) } val groupExpectActual = actual.groupBy { findExpect(it, mergedExpect) } - val pathsToExpects: Set<String> = groupExpectActual.keys.filterIsInstance<Expect.Found<T>>().mapNotNull { it.expect.sources.expect?.path }.toSet() + val pathsToExpects: Set<String> = + groupExpectActual.keys.filterIsInstance<Expect.Found<T>>() + .mapNotNull { it.expect.sources.expect?.path }.toSet() return groupExpectActual.flatMap { reduceExpectActual(it) } + expect.filterNot { it.sources.expect?.path in pathsToExpects } } @@ -93,62 +106,64 @@ private sealed class Expect<out T : Any> { } } -fun Package.mergeWith(other: Package): Package = copy( - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), - packages = merge(packages + other.packages, Package::mergeWith), +fun DPackage.mergeWith(other: DPackage): DPackage = copy( + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), documentation = documentation.mergeWith(other.documentation), platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun Function.mergeWith(other: Function): Function = copy( - parameters = merge(this.parameters + other.parameters, Parameter::mergeWith), +fun DFunction.mergeWith(other: DFunction): DFunction = copy( + parameters = merge(this.parameters + other.parameters, DParameter::mergeWith), receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver, documentation = documentation.mergeWith(other.documentation), sources = sources.mergeWith(other.sources), visibility = visibility.mergeWith(other.visibility), + modifier = modifier.mergeWith(other.modifier), platformData = (platformData + other.platformData).distinct(), - generics = merge(generics + other.generics, TypeParameter::mergeWith) + generics = merge(generics + other.generics, DTypeParameter::mergeWith) ).mergeExtras(this, other) -fun Property.mergeWith(other: Property): Property = copy( +fun DProperty.mergeWith(other: DProperty): DProperty = copy( receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver, documentation = documentation.mergeWith(other.documentation), sources = sources.mergeWith(other.sources), visibility = visibility.mergeWith(other.visibility), + modifier = modifier.mergeWith(other.modifier), platformData = (platformData + other.platformData).distinct(), getter = getter?.let { g -> other.getter?.let { g.mergeWith(it) } ?: g } ?: other.getter, setter = setter?.let { s -> other.setter?.let { s.mergeWith(it) } ?: s } ?: other.setter ).mergeExtras(this, other) -fun Classlike.setPlatformData(platformData: List<PlatformData>): Classlike = when (this) { - is Class -> copy(platformData = platformData) - is Enum -> copy(platformData = platformData) - is Interface -> copy(platformData = platformData) - is Object -> copy(platformData = platformData) +fun DClasslike.setPlatformData(platformData: List<PlatformData>): DClasslike = when (this) { + is DClass -> copy(platformData = platformData) + is DEnum -> copy(platformData = platformData) + is DInterface -> copy(platformData = platformData) + is DObject -> copy(platformData = platformData) else -> throw IllegalStateException("${this::class.qualifiedName} ${this.name} cannot have platform set") } -fun Classlike.mergeWith(other: Classlike): Classlike = when { - this is Class && other is Class -> mergeWith(other) - this is Enum && other is Enum -> mergeWith(other) - this is Interface && other is Interface -> mergeWith(other) - this is Object && other is Object -> mergeWith(other) - this is Annotation && other is Annotation -> mergeWith(other) +fun DClasslike.mergeWith(other: DClasslike): DClasslike = when { + this is DClass && other is DClass -> mergeWith(other) + this is DEnum && other is DEnum -> mergeWith(other) + this is DInterface && other is DInterface -> mergeWith(other) + this is DObject && other is DObject -> mergeWith(other) + this is DAnnotation && other is DAnnotation -> mergeWith(other) else -> throw IllegalStateException("${this::class.qualifiedName} ${this.name} cannot be mergesd with ${other::class.qualifiedName} ${other.name}") } -fun Class.mergeWith(other: Class): Class = copy( +fun DClass.mergeWith(other: DClass): DClass = copy( constructors = mergeExpectActual( constructors + other.constructors, - Function::mergeWith + DFunction::mergeWith ) { copy(platformData = it) }, - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion, - generics = merge(generics + other.generics, TypeParameter::mergeWith), + generics = merge(generics + other.generics, DTypeParameter::mergeWith), + modifier = modifier.mergeWith(other.modifier), supertypes = supertypes.mergeWith(other.supertypes), documentation = documentation.mergeWith(other.documentation), sources = sources.mergeWith(other.sources), @@ -156,15 +171,15 @@ fun Class.mergeWith(other: Class): Class = copy( platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun Enum.mergeWith(other: Enum): Enum = copy( - entries = merge(entries + other.entries, EnumEntry::mergeWith), +fun DEnum.mergeWith(other: DEnum): DEnum = copy( + entries = merge(entries + other.entries, DEnumEntry::mergeWith), constructors = mergeExpectActual( constructors + other.constructors, - Function::mergeWith + DFunction::mergeWith ) { copy(platformData = it) }, - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion, supertypes = supertypes.mergeWith(other.supertypes), documentation = documentation.mergeWith(other.documentation), @@ -173,18 +188,18 @@ fun Enum.mergeWith(other: Enum): Enum = copy( platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun EnumEntry.mergeWith(other: EnumEntry): EnumEntry = copy( - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), +fun DEnumEntry.mergeWith(other: DEnumEntry): DEnumEntry = copy( + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), documentation = documentation.mergeWith(other.documentation), platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun Object.mergeWith(other: Object): Object = copy( - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), +fun DObject.mergeWith(other: DObject): DObject = copy( + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), supertypes = supertypes.mergeWith(other.supertypes), documentation = documentation.mergeWith(other.documentation), sources = sources.mergeWith(other.sources), @@ -192,12 +207,12 @@ fun Object.mergeWith(other: Object): Object = copy( platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun Interface.mergeWith(other: Interface): Interface = copy( - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), +fun DInterface.mergeWith(other: DInterface): DInterface = copy( + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion, - generics = merge(generics + other.generics, TypeParameter::mergeWith), + generics = merge(generics + other.generics, DTypeParameter::mergeWith), supertypes = supertypes.mergeWith(other.supertypes), documentation = documentation.mergeWith(other.documentation), sources = sources.mergeWith(other.sources), @@ -205,14 +220,14 @@ fun Interface.mergeWith(other: Interface): Interface = copy( platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun Annotation.mergeWith(other: Annotation): Annotation = copy( +fun DAnnotation.mergeWith(other: DAnnotation): DAnnotation = copy( constructors = mergeExpectActual( constructors + other.constructors, - Function::mergeWith + DFunction::mergeWith ) { copy(platformData = it) }, - functions = mergeExpectActual(functions + other.functions, Function::mergeWith) { copy(platformData = it) }, - properties = mergeExpectActual(properties + other.properties, Property::mergeWith) { copy(platformData = it) }, - classlikes = mergeExpectActual(classlikes + other.classlikes, Classlike::mergeWith, Classlike::setPlatformData), + functions = mergeExpectActual(functions + other.functions, DFunction::mergeWith) { copy(platformData = it) }, + properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, + classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion, documentation = documentation.mergeWith(other.documentation), sources = sources.mergeWith(other.sources), @@ -220,12 +235,12 @@ fun Annotation.mergeWith(other: Annotation): Annotation = copy( platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun Parameter.mergeWith(other: Parameter): Parameter = copy( +fun DParameter.mergeWith(other: DParameter): DParameter = copy( documentation = documentation.mergeWith(other.documentation), platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) -fun TypeParameter.mergeWith(other: TypeParameter): TypeParameter = copy( +fun DTypeParameter.mergeWith(other: DTypeParameter): DTypeParameter = copy( documentation = documentation.mergeWith(other.documentation), platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other)
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilter.kt b/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilter.kt new file mode 100644 index 00000000..9f86c82a --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilter.kt @@ -0,0 +1,317 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.DAnnotation +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.DFunction +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer + +internal object DocumentableVisibilityFilter : PreMergeDocumentableTransformer { + + override fun invoke(modules: List<DModule>, context: DokkaContext): List<DModule> = modules.map { original -> + val packageOptions = + context.configuration.passesConfigurations.first { original.platformData.contains(it.platformData) } + .perPackageOptions + + DocumentableFilter(packageOptions).processModule(original) + } + + private class DocumentableFilter(val packageOptions: List<DokkaConfiguration.PackageOptions>) { + + fun Visibility.isAllowedInPackage(packageName: String?) = when (this) { + is JavaVisibility.Public, + is JavaVisibility.Default, + is KotlinVisibility.Public -> true + else -> packageName != null && packageOptions.firstOrNull { packageName.startsWith(it.prefix) }?.includeNonPublic == true + } + + fun processModule(original: DModule) = + filterPackages(original.packages).let { (modified, packages) -> + if (!modified) original + else + DModule( + original.name, + packages = packages, + documentation = original.documentation, + platformData = original.platformData, + extra = original.extra + ) + } + + private fun filterPackages(packages: List<DPackage>): Pair<Boolean, List<DPackage>> { + var packagesListChanged = false + val filteredPackages = packages.mapNotNull { + var modified = false + val functions = filterFunctions(it.functions).let { (listModified, list) -> + modified = modified || listModified + list + } + val properties = filterProperties(it.properties).let { (listModified, list) -> + modified = modified || listModified + list + } + val classlikes = filterClasslikes(it.classlikes).let { (listModified, list) -> + modified = modified || listModified + list + } + when { + !modified -> it + functions.isEmpty() && properties.isEmpty() && classlikes.isEmpty() -> null + else -> { + packagesListChanged = true + DPackage( + it.dri, + functions, + properties, + classlikes, + it.documentation, + it.platformData, + it.extra + ) + } + } + } + return Pair(packagesListChanged, filteredPackages) + } + + private fun <T : WithVisibility> alwaysTrue(a: T, p: PlatformData) = true + private fun <T : WithVisibility> alwaysFalse(a: T, p: PlatformData) = false + + private fun WithVisibility.visibilityForPlatform(data: PlatformData): Visibility? = + visibility[data] ?: visibility.expect + + private fun <T> T.filterPlatforms( + additionalCondition: (T, PlatformData) -> Boolean = ::alwaysTrue, + alternativeCondition: (T, PlatformData) -> Boolean = ::alwaysFalse + ) where T : Documentable, T : WithVisibility = + platformData.filter { d -> + visibilityForPlatform(d)?.isAllowedInPackage(dri.packageName) == true && + additionalCondition(this, d) || + alternativeCondition(this, d) + } + + private fun <T> List<T>.transform( + additionalCondition: (T, PlatformData) -> Boolean = ::alwaysTrue, + alternativeCondition: (T, PlatformData) -> Boolean = ::alwaysFalse, + recreate: (T, List<PlatformData>) -> T + ): Pair<Boolean, List<T>> where T : Documentable, T : WithVisibility { + var changed = false + val values = mapNotNull { t -> + val filteredPlatforms = t.filterPlatforms(additionalCondition, alternativeCondition) + when (filteredPlatforms.size) { + t.visibility.size -> t + 0 -> { + changed = true + null + } + else -> { + changed = true + recreate(t, filteredPlatforms) + } + } + } + return Pair(changed, values) + } + + private fun filterFunctions( + functions: List<DFunction>, + additionalCondition: (DFunction, PlatformData) -> Boolean = ::alwaysTrue + ) = + functions.transform(additionalCondition) { original, filteredPlatforms -> + with(original) { + DFunction( + dri, + name, + isConstructor, + parameters, + documentation.filtered(filteredPlatforms), + sources.filtered(filteredPlatforms), + visibility.filtered(filteredPlatforms), + type, + generics.mapNotNull { it.filter(filteredPlatforms) }, + receiver, + modifier, + filteredPlatforms, + extra + ) + } + } + + private fun hasVisibleAccessorsForPlatform(property: DProperty, data: PlatformData) = + property.getter?.visibilityForPlatform(data)?.isAllowedInPackage(property.dri.packageName) == true || + property.setter?.visibilityForPlatform(data)?.isAllowedInPackage(property.dri.packageName) == true + + private fun filterProperties( + properties: List<DProperty>, + additionalCondition: (DProperty, PlatformData) -> Boolean = ::alwaysTrue + ): Pair<Boolean, List<DProperty>> = + properties.transform(additionalCondition, ::hasVisibleAccessorsForPlatform) { original, filteredPlatforms -> + with(original) { + DProperty( + dri, + name, + documentation.filtered(filteredPlatforms), + sources.filtered(filteredPlatforms), + visibility.filtered(filteredPlatforms), + type, + receiver, + setter, + getter, + modifier, + filteredPlatforms, + extra + ) + } + } + + private fun filterEnumEntries(entries: List<DEnumEntry>, filteredPlatforms: List<PlatformData>) = + entries.mapNotNull { entry -> + if (filteredPlatforms.containsAll(entry.platformData)) entry + else { + val intersection = filteredPlatforms.intersect(entry.platformData).toList() + if (intersection.isEmpty()) null + else DEnumEntry( + entry.dri, + entry.name, + entry.documentation.filtered(intersection), + filterFunctions(entry.functions) { _, data -> data in intersection }.second, + filterProperties(entry.properties) { _, data -> data in intersection }.second, + filterClasslikes(entry.classlikes) { _, data -> data in intersection }.second, + intersection, + entry.extra + ) + } + } + + private fun filterClasslikes( + classlikeList: List<DClasslike>, + additionalCondition: (DClasslike, PlatformData) -> Boolean = ::alwaysTrue + ): Pair<Boolean, List<DClasslike>> { + var classlikesListChanged = false + val filteredClasslikes: List<DClasslike> = classlikeList.mapNotNull { + with(it) { + val filteredPlatforms = filterPlatforms(additionalCondition) + if (filteredPlatforms.isEmpty()) { + classlikesListChanged = true + null + } else { + var modified = platformData.size != filteredPlatforms.size + val functions = + filterFunctions(functions) { _, data -> data in filteredPlatforms }.let { (listModified, list) -> + modified = modified || listModified + list + } + val properties = + filterProperties(properties) { _, data -> data in filteredPlatforms }.let { (listModified, list) -> + modified = modified || listModified + list + } + val classlikes = + filterClasslikes(classlikes) { _, data -> data in filteredPlatforms }.let { (listModified, list) -> + modified = modified || listModified + list + } + val companion = + if (this is WithCompanion) filterClasslikes(listOfNotNull(companion)) { _, data -> data in filteredPlatforms }.let { (listModified, list) -> + modified = modified || listModified + list.firstOrNull() as DObject? + } else null + val constructors = if (this is WithConstructors) + filterFunctions(constructors) { _, data -> data in filteredPlatforms }.let { (listModified, list) -> + modified = modified || listModified + list + } else emptyList() + val generics = + if (this is WithGenerics) generics.mapNotNull { param -> param.filter(filteredPlatforms) } else emptyList() + val enumEntries = + if (this is DEnum) filterEnumEntries(entries, filteredPlatforms) else emptyList() + classlikesListChanged = classlikesListChanged || modified + when { + !modified -> this + this is DClass -> DClass( + dri, + name, + constructors, + functions, + properties, + classlikes, + sources.filtered(filteredPlatforms), + visibility.filtered(filteredPlatforms), + companion, + generics, + supertypes.filtered(filteredPlatforms), + documentation.filtered(filteredPlatforms), + modifier, + filteredPlatforms, + extra + ) + this is DAnnotation -> DAnnotation( + name, + dri, + documentation.filtered(filteredPlatforms), + sources.filtered(filteredPlatforms), + functions, + properties, + classlikes, + visibility.filtered(filteredPlatforms), + companion, + constructors, + filteredPlatforms, + extra + ) + this is DEnum -> DEnum( + dri, + name, + enumEntries, + documentation.filtered(filteredPlatforms), + sources.filtered(filteredPlatforms), + functions, + properties, + classlikes, + visibility.filtered(filteredPlatforms), + companion, + constructors, + supertypes.filtered(filteredPlatforms), + filteredPlatforms, + extra + ) + this is DInterface -> DInterface( + dri, + name, + documentation.filtered(filteredPlatforms), + sources.filtered(filteredPlatforms), + functions, + properties, + classlikes, + visibility.filtered(filteredPlatforms), + companion, + generics, + supertypes.filtered(filteredPlatforms), + filteredPlatforms, + extra + ) + this is DObject -> DObject( + name, + dri, + documentation.filtered(filteredPlatforms), + sources.filtered(filteredPlatforms), + functions, + properties, + classlikes, + visibility, + supertypes.filtered(filteredPlatforms), + filteredPlatforms, + extra + ) + else -> null + } + } + } + } + return Pair(classlikesListChanged, filteredClasslikes) + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt new file mode 100644 index 00000000..e372ad9c --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt @@ -0,0 +1,73 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.properties.ExtraProperty +import org.jetbrains.dokka.model.properties.MergeStrategy +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer + +class InheritorsExtractorTransformer : DocumentableTransformer { + override fun invoke(original: DModule, context: DokkaContext): DModule = + original.generateInheritanceMap().let { inheritanceMap -> original.appendInheritors(inheritanceMap) as DModule } + + private fun <T : Documentable> T.appendInheritors(inheritanceMap: Map<PlatformData, Map<DRI, List<DRI>>>): Documentable = + InheritorsInfo(PlatformDependent(inheritanceMap.getForDRI(dri))).let { info -> + when (this) { + is DModule -> copy(packages = packages.map { it.appendInheritors(inheritanceMap) as DPackage }) + is DPackage -> copy(classlikes = classlikes.map { it.appendInheritors(inheritanceMap) as DClasslike }) + is DClass -> copy( + extra = extra + info, + classlikes = classlikes.map { it.appendInheritors(inheritanceMap) as DClasslike }) + is DEnum -> copy( + extra = extra + info, + classlikes = classlikes.map { it.appendInheritors(inheritanceMap) as DClasslike }) + is DInterface -> copy( + extra = extra + info, + classlikes = classlikes.map { it.appendInheritors(inheritanceMap) as DClasslike }) + is DObject -> copy(classlikes = classlikes.map { it.appendInheritors(inheritanceMap) as DClasslike }) + is DAnnotation -> copy(classlikes = classlikes.map { it.appendInheritors(inheritanceMap) as DClasslike }) + else -> this + } + } + + private fun Map<PlatformData, Map<DRI, List<DRI>>>.getForDRI(dri: DRI) = + PlatformDependent(map { (v, k) -> + v to k[dri] + }.map { (k, v) -> k to v.orEmpty() }.toMap()) + + private fun DModule.generateInheritanceMap() = + getInheritanceEntriesRec().filterNot { it.second.isEmpty() }.groupBy({ it.first }) { it.second } + .map { (k, v) -> + k to v.flatMap { p -> p.groupBy({ it.first }) { it.second }.toList() } + .groupBy({ it.first }) { it.second }.map { (k2, v2) -> k2 to v2.flatten() }.toMap() + }.toMap() + + private fun <T : Documentable> T.getInheritanceEntriesRec(): List<Pair<PlatformData, List<Pair<DRI, DRI>>>> = + this.toInheritanceEntries() + children.flatMap { it.getInheritanceEntriesRec() } + + private fun <T : Documentable> T.toInheritanceEntries() = + (this as? WithSupertypes)?.let { + it.supertypes.map.map { (k, v) -> k to v.map { it to dri } } + }.orEmpty() + +} + +class InheritorsInfo(val value: PlatformDependent<List<DRI>>) : ExtraProperty<Documentable> { + companion object : ExtraProperty.Key<Documentable, InheritorsInfo> { + override fun mergeStrategyFor(left: InheritorsInfo, right: InheritorsInfo): MergeStrategy<Documentable> = + MergeStrategy.Replace( + InheritorsInfo( + PlatformDependent( + (left.value.map.entries.toList() + right.value.map.entries.toList()) + .groupBy({ it.key }) { it.value } + .map { (k, v) -> k to v.flatten() }.toMap() + ) + ) + ) + } + + override val key: ExtraProperty.Key<Documentable, *> = InheritorsInfo +} + diff --git a/plugins/base/src/main/kotlin/transformers/pages/annotations/DeprecatedStrikethroughTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/annotations/DeprecatedStrikethroughTransformer.kt new file mode 100644 index 00000000..55f01ad3 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/pages/annotations/DeprecatedStrikethroughTransformer.kt @@ -0,0 +1,57 @@ +package org.jetbrains.dokka.base.transformers.pages.annotations + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.properties.WithExtraProperties +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.pages.PageTransformer + +class DeprecatedStrikethroughTransformer(val context: DokkaContext) : PageTransformer { + override fun invoke(input: RootPageNode): RootPageNode = input.transformContentPagesTree { contentPage -> + if (contentPage.documentable?.isDeprecated() == true || contentPage.documentable?.hasDeprecatedChildren() == true) { + val deprecatedDRIs = + contentPage.dri + + contentPage.documentable?.children + ?.filter { it.isDeprecated() } + ?.map { it.dri } + ?.toSet().orEmpty() + + contentPage.modified(content = contentPage.content.addStrikethroughToSignature(deprecatedDRIs)) + } else { + contentPage + } + } + + private fun ContentNode.addStrikethroughToSignature(deprecatedDRIs: Set<DRI>): ContentNode = when (this) { + is ContentGroup -> if (dci.kind == ContentKind.Symbol && deprecatedDRIs.containsAll(dci.dri)) { + copy(style = this.style + setOf(TextStyle.Strikethrough)) + } else { + copy(children = children.map { it.addStrikethroughToSignature(deprecatedDRIs) }) + } + is ContentTable -> copy(children = children.map { it.addStrikethroughToSignature(deprecatedDRIs) as ContentGroup }) + is PlatformHintedContent -> copy(inner = inner.addStrikethroughToSignature(deprecatedDRIs)) + else -> this + } + + private fun Documentable.isDeprecated(): Boolean = when (this) { + is DClass -> this.isKotlinOrJavaDeprecated() + is DAnnotation -> this.isKotlinOrJavaDeprecated() + is DObject -> this.isKotlinOrJavaDeprecated() + is DInterface -> this.isKotlinOrJavaDeprecated() + is DEnum -> this.isKotlinOrJavaDeprecated() + is DFunction -> this.isKotlinOrJavaDeprecated() + is DProperty -> this.isKotlinOrJavaDeprecated() + is DEnumEntry -> this.isKotlinOrJavaDeprecated() + + else -> false + } + + private fun Documentable.hasDeprecatedChildren() = children.any { it.isDeprecated() } + + private fun <T : Documentable> WithExtraProperties<T>.isKotlinOrJavaDeprecated() = + extra[Annotations]?.content?.any { + it.dri == DRI("kotlin", "Deprecated") + || it.dri == DRI("java.lang", "Deprecated") + } == true +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt index 900f5c19..2eb63504 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt @@ -30,17 +30,22 @@ object DocTagToContentConverter : CommentsToContentConverter { ) ) - fun buildList(ordered: Boolean) = + fun buildList(ordered: Boolean, start: Int = 1) = listOf( ContentList( buildChildren(docTag), ordered, dci, platforms, - styles + styles, + ((PropertyContainer.empty<ContentNode>()) + SimpleAttr("start", start.toString())) ) ) + fun buildNewLine() = listOf(ContentBreakLine( + platforms + )) + return when (docTag) { is H1 -> buildHeader(1) is H2 -> buildHeader(2) @@ -49,8 +54,9 @@ object DocTagToContentConverter : CommentsToContentConverter { is H5 -> buildHeader(5) is H6 -> buildHeader(6) is Ul -> buildList(false) - is Ol -> buildList(true) + is Ol -> buildList(true, docTag.params["start"]?.toInt() ?: 1) is Li -> buildChildren(docTag) + is Br -> buildNewLine() is B -> buildChildren(docTag, setOf(TextStyle.Strong)) is I -> buildChildren(docTag, setOf(TextStyle.Italic)) is P -> buildChildren(docTag, newStyles = setOf(TextStyle.Paragraph)) diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 72ce296d..1c374626 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -5,33 +5,34 @@ import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.parsers.MarkdownParser import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentableTranslator +import org.jetbrains.kotlin.builtins.isExtensionFunctionType +import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.codegen.isJvmStaticInObjectOrClassOrInterface import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.idea.kdoc.findKDoc +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjection -import org.jetbrains.dokka.model.Variance -import org.jetbrains.kotlin.library.metadata.KlibMetadataProtoBuf.fqName -import org.jetbrains.kotlin.idea.kdoc.findKDoc class DefaultDescriptorToDocumentableTranslator( private val context: DokkaContext @@ -47,7 +48,7 @@ class DefaultDescriptorToDocumentableTranslator( DRIWithPlatformInfo(DRI.topLevel, PlatformDependent.empty()) ) } - }.let { Module(moduleName, it, PlatformDependent.empty(), listOf(platformData)) } + }.let { DModule(moduleName, it, PlatformDependent.empty(), listOf(platformData)) } } @@ -69,77 +70,86 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv override fun visitPackageFragmentDescriptor( descriptor: PackageFragmentDescriptor, parent: DRIWithPlatformInfo - ): Package { + ): DPackage { val driWithPlatform = DRI(packageName = descriptor.fqName.asString()).withEmptyInfo() val scope = descriptor.getMemberScope() - return Package( + return DPackage( dri = driWithPlatform.dri, functions = scope.functions(driWithPlatform), properties = scope.properties(driWithPlatform), classlikes = scope.classlikes(driWithPlatform), - packages = scope.packages(driWithPlatform), documentation = descriptor.resolveDescriptorData(platformData), platformData = listOf(platformData) ) } - override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Classlike = + override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClasslike = when (descriptor.kind) { ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent) ClassKind.OBJECT -> objectDescriptor(descriptor, parent) ClassKind.INTERFACE -> interfaceDescriptor(descriptor, parent) + ClassKind.ANNOTATION_CLASS -> annotationDescriptor(descriptor, parent) else -> classDescriptor(descriptor, parent) } - private fun interfaceDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Interface { + private fun interfaceDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DInterface { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope - val info = descriptor.resolveClassDescriptionData(platformData) + val isExpect = descriptor.isExpect + val info = descriptor.resolveClassDescriptionData(if (!isExpect) platformData else null) + - return Interface( + return DInterface( dri = driWithPlatform.dri, name = descriptor.name.asString(), functions = scope.functions(driWithPlatform), properties = scope.properties(driWithPlatform), classlikes = scope.classlikes(driWithPlatform), sources = descriptor.createSources(), - visibility = PlatformDependent.from(platformData, descriptor.visibility.toDokkaVisibility()), - supertypes = PlatformDependent.from(platformData, info.supertypes), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + supertypes = if(isExpect) PlatformDependent.expectFrom(info.supertypes) + else PlatformDependent.from(platformData,info.supertypes), documentation = info.docs, generics = descriptor.typeConstructor.parameters.map { it.toTypeParameter() }, companion = descriptor.companion(driWithPlatform), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } - private fun objectDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Object { + private fun objectDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DObject { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope - val info = descriptor.resolveClassDescriptionData(platformData) + val isExpect = descriptor.isExpect + val info = descriptor.resolveClassDescriptionData(if (!isExpect) platformData else null) - return Object( + + return DObject( dri = driWithPlatform.dri, name = descriptor.name.asString(), functions = scope.functions(driWithPlatform), properties = scope.properties(driWithPlatform), classlikes = scope.classlikes(driWithPlatform), sources = descriptor.createSources(), - visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())), - supertypes = PlatformDependent.from(platformData, info.supertypes), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + supertypes = if(isExpect) PlatformDependent.expectFrom(info.supertypes) + else PlatformDependent.from(platformData,info.supertypes), documentation = info.docs, platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } - private fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Enum { + private fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnum { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope - val info = descriptor.resolveClassDescriptionData(platformData) + val isExpect = descriptor.isExpect + val info = descriptor.resolveClassDescriptionData(if (!isExpect) platformData else null) - return Enum( + return DEnum( dri = driWithPlatform.dri, name = descriptor.name.asString(), entries = scope.enumEntries(driWithPlatform), @@ -148,20 +158,39 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv properties = scope.properties(driWithPlatform), classlikes = scope.classlikes(driWithPlatform), sources = descriptor.createSources(), - visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())), - supertypes = PlatformDependent.from(platformData, info.supertypes), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + supertypes = if(isExpect) PlatformDependent.expectFrom(info.supertypes) + else PlatformDependent.from(platformData,info.supertypes), documentation = info.docs, companion = descriptor.companion(driWithPlatform), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) + ) + } + + private fun enumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnumEntry { + val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() + val scope = descriptor.unsubstitutedMemberScope + val isExpect = descriptor.isExpect + + return DEnumEntry( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + documentation = descriptor.resolveDescriptorData(if (!isExpect) platformData else null), + classlikes = scope.classlikes(driWithPlatform), + functions = scope.functions(driWithPlatform), + properties = scope.properties(driWithPlatform), + platformData = listOf(platformData), + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } - private fun enumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): EnumEntry { + fun annotationDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DAnnotation { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope - return EnumEntry( + return DAnnotation( dri = driWithPlatform.dri, name = descriptor.name.asString(), documentation = descriptor.resolveDescriptorData(platformData), @@ -169,17 +198,22 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv functions = scope.functions(driWithPlatform), properties = scope.properties(driWithPlatform), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()), + companion = descriptor.companionObjectDescriptor?.let { objectDescriptor(it, driWithPlatform) }, + visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())), + constructors = descriptor.constructors.map { visitConstructorDescriptor(it, driWithPlatform) }, + sources = descriptor.createSources() ) } - private fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Class { + private fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DClass { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope - val info = descriptor.resolveClassDescriptionData(platformData) + val isExpect = descriptor.isExpect + val info = descriptor.resolveClassDescriptionData(if (!isExpect) platformData else null) val actual = descriptor.createSources() - return Class( + return DClass( dri = driWithPlatform.dri, name = descriptor.name.asString(), constructors = descriptor.constructors.map { @@ -193,22 +227,26 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv properties = scope.properties(driWithPlatform), classlikes = scope.classlikes(driWithPlatform), sources = actual, - visibility = PlatformDependent.from(platformData, descriptor.visibility.toDokkaVisibility()), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + supertypes = if(isExpect) PlatformDependent.expectFrom(info.supertypes) + else PlatformDependent.from(platformData,info.supertypes), generics = descriptor.typeConstructor.parameters.map { it.toTypeParameter() }, documentation = info.docs, - modifier = descriptor.modifier(), + modifier = if(isExpect) PlatformDependent.expectFrom(descriptor.modifier()) + else PlatformDependent.from(platformData, descriptor.modifier()), companion = descriptor.companion(driWithPlatform), - supertypes = PlatformDependent.from(platformData, info.supertypes), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } - override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): Property { + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): DProperty { val dri = parent.dri.copy(callable = Callable.from(descriptor)) + val isExpect = descriptor.isExpect val actual = descriptor.createSources() - return Property( + return DProperty( dri = dri, name = descriptor.name.asString(), receiver = descriptor.extensionReceiverParameter?.let { @@ -216,25 +254,28 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv }, sources = actual, getter = descriptor.accessors.filterIsInstance<PropertyGetterDescriptor>().singleOrNull()?.let { - visitPropertyAccessorDescriptor(it, descriptor, dri) + visitPropertyAccessorDescriptor(it, descriptor, dri) }, setter = descriptor.accessors.filterIsInstance<PropertySetterDescriptor>().singleOrNull()?.let { visitPropertyAccessorDescriptor(it, descriptor, dri) }, - visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())), - documentation = descriptor.resolveDescriptorData(platformData), - modifier = descriptor.modifier(), - type = KotlinTypeWrapper(descriptor.returnType!!), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + documentation = descriptor.resolveDescriptorData(if (!isExpect) platformData else null), + modifier = if(isExpect) PlatformDependent.expectFrom(descriptor.modifier()) + else PlatformDependent.from(platformData, descriptor.modifier()), + type = descriptor.returnType!!.toBound(), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } - override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): Function { + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): DFunction { val dri = parent.dri.copy(callable = Callable.from(descriptor)) + val isExpect = descriptor.isExpect val actual = descriptor.createSources() - return Function( + return DFunction( dri = dri, name = descriptor.name.asString(), isConstructor = false, @@ -245,20 +286,24 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv parameter(index, desc, DRIWithPlatformInfo(dri, actual)) }, sources = actual, - visibility = PlatformDependent.from(platformData, descriptor.visibility.toDokkaVisibility()), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), generics = descriptor.typeParameters.map { it.toTypeParameter() }, - documentation = descriptor.resolveDescriptorData(platformData), - modifier = descriptor.modifier(), - type = KotlinTypeWrapper(descriptor.returnType!!), + documentation = descriptor.resolveDescriptorData(if (!isExpect) platformData else null), + modifier = if(isExpect) PlatformDependent.expectFrom(descriptor.modifier()) + else PlatformDependent.from(platformData, descriptor.modifier()), + type = descriptor.returnType!!.toBound(), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } - override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): Function { + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): DFunction { val dri = parent.dri.copy(callable = Callable.from(descriptor)) val actual = descriptor.createSources() - return Function( + val isExpect = descriptor.isExpect + + return DFunction( dri = dri, name = "<init>", isConstructor = true, @@ -269,23 +314,27 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv parameter(index, desc, DRIWithPlatformInfo(dri, actual)) }, sources = actual, - visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())), - documentation = descriptor.resolveDescriptorData(platformData), - type = KotlinTypeWrapper(descriptor.returnType), - modifier = descriptor.modifier(), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + documentation = descriptor.resolveDescriptorData(if (!isExpect) platformData else null), + type = descriptor.returnType.toBound(), + modifier = if(isExpect) PlatformDependent.expectFrom(descriptor.modifier()) + else PlatformDependent.from(platformData, descriptor.modifier()), generics = descriptor.typeParameters.map { it.toTypeParameter() }, platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll<DFunction>(descriptor.additionalExtras(), descriptor.getAnnotations()).let { + if(descriptor.isPrimary) { it + PrimaryConstructorExtra } else it + } ) } override fun visitReceiverParameterDescriptor( descriptor: ReceiverParameterDescriptor, parent: DRIWithPlatformInfo - ) = Parameter( + ) = DParameter( dri = parent.dri.copy(target = 0), name = null, - type = KotlinTypeWrapper(descriptor.type), + type = descriptor.type.toBound(), documentation = descriptor.resolveDescriptorData(platformData), platformData = listOf(platformData) ) @@ -294,18 +343,19 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv descriptor: PropertyAccessorDescriptor, propertyDescriptor: PropertyDescriptor, parent: DRI - ): Function { + ): DFunction { val dri = parent.copy(callable = Callable.from(descriptor)) val isGetter = descriptor is PropertyGetterDescriptor + val isExpect = descriptor.isExpect fun PropertyDescriptor.asParameter(parent: DRI) = - Parameter( + DParameter( parent.copy(target = 1), this.name.asString(), - type = KotlinTypeWrapper(this.type), - documentation = descriptor.resolveDescriptorData(platformData), + type = this.type.toBound(), + documentation = descriptor.resolveDescriptorData(if (!isExpect) platformData else null), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) val name = run { @@ -321,16 +371,18 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv listOf(propertyDescriptor.asParameter(dri)) } - return Function( + return DFunction( dri, name, isConstructor = false, parameters = parameters, - visibility = PlatformDependent(mapOf(platformData to descriptor.visibility.toDokkaVisibility())), - documentation = descriptor.resolveDescriptorData(platformData), - type = KotlinTypeWrapper(descriptor.returnType!!), + visibility = if(isExpect) PlatformDependent.expectFrom(descriptor.visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData,descriptor.visibility.toDokkaVisibility()), + documentation = descriptor.resolveDescriptorData(if (!isExpect) platformData else null), + type = descriptor.returnType!!.toBound(), generics = descriptor.typeParameters.map { it.toTypeParameter() }, - modifier = descriptor.modifier(), + modifier = if(isExpect) PlatformDependent.expectFrom(descriptor.modifier()) + else PlatformDependent.from(platformData, descriptor.modifier()), receiver = descriptor.extensionReceiverParameter?.let { visitReceiverParameterDescriptor( it, @@ -339,52 +391,57 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv }, sources = descriptor.createSources(), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) ) } private fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) = - Parameter( + DParameter( dri = parent.dri.copy(target = index + 1), name = descriptor.name.asString(), - type = KotlinTypeWrapper(descriptor.type), + type = descriptor.type.toBound(), documentation = descriptor.resolveDescriptorData(platformData), platformData = listOf(platformData), - extra = descriptor.additionalExtras() + extra = PropertyContainer.withAll( + listOfNotNull( + descriptor.additionalExtras(), + descriptor.getAnnotations(), + descriptor.getDefaultValue()?.let { DefaultValue(it) }) + ) ) - private fun MemberScope.functions(parent: DRIWithPlatformInfo): List<Function> = + private fun MemberScope.functions(parent: DRIWithPlatformInfo): List<DFunction> = getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) { true } .filterIsInstance<FunctionDescriptor>() .map { visitFunctionDescriptor(it, parent) } - private fun MemberScope.properties(parent: DRIWithPlatformInfo): List<Property> = + private fun MemberScope.properties(parent: DRIWithPlatformInfo): List<DProperty> = getContributedDescriptors(DescriptorKindFilter.VALUES) { true } .filterIsInstance<PropertyDescriptor>() .map { visitPropertyDescriptor(it, parent) } - private fun MemberScope.classlikes(parent: DRIWithPlatformInfo): List<Classlike> = + private fun MemberScope.classlikes(parent: DRIWithPlatformInfo): List<DClasslike> = getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) { true } - .filterIsInstance<ClassDescriptor>() - .map { visitClassDescriptor(it, parent) } - .mapNotNull { it as? Classlike } + .filter { it is ClassDescriptor && it.kind != ClassKind.ENUM_ENTRY } + .map { visitClassDescriptor(it as ClassDescriptor, parent) } + .mapNotNull { it as? DClasslike } - private fun MemberScope.packages(parent: DRIWithPlatformInfo): List<Package> = + private fun MemberScope.packages(parent: DRIWithPlatformInfo): List<DPackage> = getContributedDescriptors(DescriptorKindFilter.PACKAGES) { true } .filterIsInstance<PackageFragmentDescriptor>() .map { visitPackageFragmentDescriptor(it, parent) } - private fun MemberScope.enumEntries(parent: DRIWithPlatformInfo): List<EnumEntry> = + private fun MemberScope.enumEntries(parent: DRIWithPlatformInfo): List<DEnumEntry> = this.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) { true } .filterIsInstance<ClassDescriptor>() .filter { it.kind == ClassKind.ENUM_ENTRY } .map { enumEntryDescriptor(it, parent) } - private fun DeclarationDescriptor.resolveDescriptorData(platformData: PlatformData): PlatformDependent<DocumentationNode> = - PlatformDependent.from(platformData, getDocumentation()) + private fun DeclarationDescriptor.resolveDescriptorData(platformData: PlatformData?): PlatformDependent<DocumentationNode> = + if(platformData != null) PlatformDependent.from(platformData, getDocumentation()) else PlatformDependent.expectFrom(getDocumentation()) - private fun ClassDescriptor.resolveClassDescriptionData(platformData: PlatformData): ClassInfo { + private fun ClassDescriptor.resolveClassDescriptionData(platformData: PlatformData?): ClassInfo { return ClassInfo( (getSuperInterfaces() + getAllSuperclassesWithoutAny()).map { DRI.from(it) }, resolveDescriptorData(platformData) @@ -392,22 +449,25 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv } private fun TypeParameterDescriptor.toTypeParameter() = - TypeParameter( + DTypeParameter( DRI.from(this), - fqNameSafe.asString(), + name.identifier, PlatformDependent.from(platformData, getDocumentation()), upperBounds.map { it.toBound() }, listOf(platformData), - extra = additionalExtras() + extra = PropertyContainer.withAll(additionalExtras()) ) - private fun KotlinType.toBound(): Bound = when (constructor.declarationDescriptor) { - is TypeParameterDescriptor -> OtherParameter(fqName.toString()).let { + private fun KotlinType.toBound(): Bound = when (val ctor = constructor.declarationDescriptor) { + is TypeParameterDescriptor -> OtherParameter(ctor.name.asString()).let { if (isMarkedNullable) Nullable(it) else it } else -> TypeConstructor( DRI.from(constructor.declarationDescriptor!!), // TODO: remove '!!' - arguments.map { it.toProjection() } + arguments.map { it.toProjection() }, + if (isExtensionFunctionType) FunctionModifiers.EXTENSION + else if (isFunctionType) FunctionModifiers.FUNCTION + else FunctionModifiers.NONE ) } @@ -429,7 +489,7 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv MarkdownParser(resolutionFacade, this).parseFromKDocTag(it) } - fun ClassDescriptor.companion(dri: DRIWithPlatformInfo): Object? = companionObjectDescriptor?.let { + fun ClassDescriptor.companion(dri: DRIWithPlatformInfo): DObject? = companionObjectDescriptor?.let { objectDescriptor(it, dri) } @@ -446,29 +506,29 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv } else { PlatformDependent(mapOf(platformData to DescriptorDocumentableSource(this))) } - - inline fun <reified D : Documentable> FunctionDescriptor.additionalExtras(): PropertyContainer<D> = listOfNotNull( - ExtraModifiers.DYNAMIC.takeIf { isDynamic() }, - ExtraModifiers.INFIX.takeIf { isInfix }, - ExtraModifiers.INLINE.takeIf { isInline }, - ExtraModifiers.SUSPEND.takeIf { isSuspend }, - ExtraModifiers.OPERATOR.takeIf { isOperator }, - ExtraModifiers.STATIC.takeIf { isJvmStaticInObjectOrClassOrInterface() }, - ExtraModifiers.TAILREC.takeIf { isTailrec }, - ExtraModifiers.EXTERNAL.takeIf { isExternal }, - ExtraModifiers.OVERRIDE.takeIf { DescriptorUtils.isOverride(this) } - ).toContainer() - - inline fun <reified D : Documentable> ClassDescriptor.additionalExtras(): PropertyContainer<D> = listOfNotNull( + + fun FunctionDescriptor.additionalExtras() = listOfNotNull( + ExtraModifiers.DYNAMIC.takeIf { isDynamic() }, + ExtraModifiers.INFIX.takeIf { isInfix }, + ExtraModifiers.INLINE.takeIf { isInline }, + ExtraModifiers.SUSPEND.takeIf { isSuspend }, + ExtraModifiers.OPERATOR.takeIf { isOperator }, + ExtraModifiers.STATIC.takeIf { isJvmStaticInObjectOrClassOrInterface() }, + ExtraModifiers.TAILREC.takeIf { isTailrec }, + ExtraModifiers.EXTERNAL.takeIf { isExternal }, + ExtraModifiers.OVERRIDE.takeIf { DescriptorUtils.isOverride(this) } + ).toProperty() + + fun ClassDescriptor.additionalExtras() = listOfNotNull( ExtraModifiers.DYNAMIC.takeIf { isDynamic() }, ExtraModifiers.INLINE.takeIf { isInline }, ExtraModifiers.EXTERNAL.takeIf { isExternal }, ExtraModifiers.INNER.takeIf { isInner }, ExtraModifiers.DATA.takeIf { isData }, ExtraModifiers.OVERRIDE.takeIf { getSuperInterfaces().isNotEmpty() || getSuperClassNotAny() != null } - ).toContainer() + ).toProperty() - fun ValueParameterDescriptor.additionalExtras(): PropertyContainer<Parameter> = + fun ValueParameterDescriptor.additionalExtras() = listOfNotNull( ExtraModifiers.DYNAMIC.takeIf { isDynamic() }, ExtraModifiers.NOINLINE.takeIf { isNoinline }, @@ -476,27 +536,35 @@ private class DokkaDescriptorVisitor( // TODO: close this class and make it priv ExtraModifiers.CONST.takeIf { isConst }, ExtraModifiers.LATEINIT.takeIf { isLateInit }, ExtraModifiers.VARARG.takeIf { isVararg } - ).toContainer() + ).toProperty() - fun TypeParameterDescriptor.additionalExtras(): PropertyContainer<TypeParameter> = + fun TypeParameterDescriptor.additionalExtras() = listOfNotNull( ExtraModifiers.DYNAMIC.takeIf { isDynamic() }, ExtraModifiers.REIFIED.takeIf { isReified } - ).toContainer() + ).toProperty() - fun PropertyDescriptor.additionalExtras(): PropertyContainer<Property> = listOfNotNull( + fun PropertyDescriptor.additionalExtras() = listOfNotNull( ExtraModifiers.DYNAMIC.takeIf { isDynamic() }, ExtraModifiers.CONST.takeIf { isConst }, ExtraModifiers.LATEINIT.takeIf { isLateInit }, ExtraModifiers.STATIC.takeIf { isJvmStaticInObjectOrClassOrInterface() }, ExtraModifiers.EXTERNAL.takeIf { isExternal }, ExtraModifiers.OVERRIDE.takeIf { DescriptorUtils.isOverride(this) } - ).toContainer() + ).toProperty() + + private fun List<ExtraModifiers>.toProperty() = + AdditionalModifiers(this.toSet()) + + fun DeclarationDescriptor.getAnnotations() = annotations.map { annotation -> + Annotations.Annotation( + annotation.let { it.annotationClass as DeclarationDescriptor }.let { DRI.from(it) }, + annotation.allValueArguments.map { (k, v) -> k.asString() to v.value.toString() }.toMap() + ) + }.let(::Annotations) - inline fun <reified D : Documentable> List<ExtraModifiers>.toContainer( - container: PropertyContainer<D> = PropertyContainer.empty() - ): PropertyContainer<D> = - container + AdditionalModifiers(this) + fun ValueParameterDescriptor.getDefaultValue(): String? = + (source as? KotlinSourceElement)?.psi?.children?.find { it is KtExpression }?.text data class ClassInfo(val supertypes: List<DRI>, val docs: PlatformDependent<DocumentationNode>) diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultDocumentableToPageTranslator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultDocumentableToPageTranslator.kt index 16f9b9b3..04251947 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/DefaultDocumentableToPageTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultDocumentableToPageTranslator.kt @@ -2,7 +2,7 @@ package org.jetbrains.dokka.base.translators.documentables import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.ModulePageNode import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator import org.jetbrains.dokka.utilities.DokkaLogger @@ -12,6 +12,6 @@ class DefaultDocumentableToPageTranslator( private val signatureProvider: SignatureProvider, private val logger: DokkaLogger ) : DocumentableToPageTranslator { - override fun invoke(module: Module): ModulePageNode = + override fun invoke(module: DModule): ModulePageNode = DefaultPageCreator(commentsToContentConverter, signatureProvider, logger).pageForModule(module) }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt index d92bec19..b217117b 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt @@ -1,15 +1,17 @@ package org.jetbrains.dokka.base.translators.documentables import org.jetbrains.dokka.base.signatures.SignatureProvider +import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Annotation -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.DFunction +import org.jetbrains.dokka.model.doc.Property import org.jetbrains.dokka.model.doc.TagWrapper +import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.backend.common.phaser.defaultDumper open class DefaultPageCreator( commentsToContentConverter: CommentsToContentConverter, @@ -18,39 +20,46 @@ open class DefaultPageCreator( ) { protected open val contentBuilder = PageContentBuilder(commentsToContentConverter, signatureProvider, logger) - open fun pageForModule(m: Module) = + open fun pageForModule(m: DModule) = ModulePageNode(m.name.ifEmpty { "<root>" }, contentForModule(m), m, m.packages.map(::pageForPackage)) - open fun pageForPackage(p: Package): PackagePageNode = PackagePageNode( + open fun pageForPackage(p: DPackage): PackagePageNode = PackagePageNode( p.name, contentForPackage(p), setOf(p.dri), p, p.classlikes.map(::pageForClasslike) + - p.functions.map(::pageForFunction) + - p.packages.map(::pageForPackage) + p.functions.map(::pageForFunction) ) - open fun pageForClasslike(c: Classlike): ClasslikePageNode { + open fun pageForEnumEntry(e: DEnumEntry): ClasslikePageNode = + ClasslikePageNode( + e.name.orEmpty(), contentForEnumEntry(e), setOf(e.dri), e, + e.classlikes.map(::pageForClasslike) + + e.functions.map(::pageForFunction) + ) + + open fun pageForClasslike(c: DClasslike): ClasslikePageNode { val constructors = if (c is WithConstructors) c.constructors else emptyList() return ClasslikePageNode( c.name.orEmpty(), contentForClasslike(c), setOf(c.dri), c, constructors.map(::pageForFunction) + c.classlikes.map(::pageForClasslike) + - c.functions.map(::pageForFunction) + c.functions.map(::pageForFunction) + + if (c is DEnum) c.entries.map(::pageForEnumEntry) else emptyList() ) } - open fun pageForFunction(f: Function) = MemberPageNode(f.name, contentForFunction(f), setOf(f.dri), f) + open fun pageForFunction(f: DFunction) = MemberPageNode(f.name, contentForFunction(f), setOf(f.dri), f) - protected open fun contentForModule(m: Module) = contentBuilder.contentFor(m) { + protected open fun contentForModule(m: DModule) = contentBuilder.contentFor(m) { header(1) { text(m.name) } block("Packages", 2, ContentKind.Packages, m.packages, m.platformData.toSet()) { - link(it.name, it.dri) + link(it.name, it.dri) } - text("Index\n") - text("Link to allpage here") +// text("Index\n") TODO +// text("Link to allpage here") } - protected open fun contentForPackage(p: Package) = contentBuilder.contentFor(p) { + protected open fun contentForPackage(p: DPackage) = contentBuilder.contentFor(p) { header(1) { text("Package ${p.name}") } +contentForScope(p, p.dri, p.platformData) } @@ -62,58 +71,143 @@ open class DefaultPageCreator( ) = contentBuilder.contentFor(s as Documentable) { block("Types", 2, ContentKind.Classlikes, s.classlikes, platformData.toSet()) { link(it.name.orEmpty(), it.dri) - +buildSignature(it) - text(it.briefDocTagString) + group { + platformDependentHint(it.dri, it.platformData.toSet()) { + +buildSignature(it) + } + group(kind = ContentKind.BriefComment) { + text(it.briefDocumentation()) + } + } } block("Functions", 2, ContentKind.Functions, s.functions, platformData.toSet()) { link(it.name, it.dri) - +buildSignature(it) - text(it.briefDocTagString) + group { + platformDependentHint(it.dri, it.platformData.toSet()) { + +buildSignature(it) + } + group(kind = ContentKind.BriefComment) { + text(it.briefDocumentation()) + } + } } block("Properties", 2, ContentKind.Properties, s.properties, platformData.toSet()) { link(it.name, it.dri) - text(it.briefDocTagString) + platformDependentHint(it.dri, it.platformData.toSet()) { + +buildSignature(it) + } + group(kind = ContentKind.BriefComment) { + text(it.briefDocumentation()) + } + } + (s as? WithExtraProperties<Documentable>)?.let { it.extra[InheritorsInfo] }?.let { inheritors -> + val map = inheritors.value.map + text("Subclasses:") + platformDependentHint(dri = s.dri, platformData = map.keys) { + map.keys.forEach { pd -> + linkTable(map[pd].orEmpty(), ContentKind.Classlikes, setOf(pd)) + } + } } } - protected open fun contentForClasslike(c: Classlike) = contentBuilder.contentFor(c) { - +buildSignature(c) - +contentForComments(c) + protected open fun contentForEnumEntry(e: DEnumEntry) = contentBuilder.contentFor(e) { + header(1) { text(e.name.orEmpty()) } + +buildSignature(e) + + +contentForComments(e) { it !is Property } + + +contentForScope(e, e.dri, e.platformData) + } + + protected open fun contentForClasslike(c: DClasslike) = contentBuilder.contentFor(c) { + header(1) { text(c.name.orEmpty()) } + platformDependentHint(c.dri, c.platformData.toSet()) { + +buildSignature(c) + } + breakLine() + +contentForComments(c) { it !is Property } if (c is WithConstructors) { - block("Constructors", 2, ContentKind.Constructors, c.constructors, c.platformData.toSet()) { + block( + "Constructors", + 2, + ContentKind.Constructors, + c.constructors.filter { it.extra[PrimaryConstructorExtra] == null }, + c.platformData.toSet() + ) { link(it.name, it.dri) - +buildSignature(it) - text(it.briefDocTagString) + group { + platformDependentHint(it.dri, it.platformData.toSet()) { + +buildSignature(it) + } + group(kind = ContentKind.BriefComment) { + text(it.briefDocumentation()) + } + } + } + } + if (c is DEnum) { + block( + "Entries", 2, ContentKind.Classlikes, c.entries, c.platformData.toSet() + ) { + link(it.name.orEmpty(), it.dri) + group { + +buildSignature(it) + group(kind = ContentKind.BriefComment) { + text(it.briefDocumentation()) + } + } } } +contentForScope(c, c.dri, c.platformData) } - protected open fun contentForComments(d: Documentable) = contentBuilder.contentFor(d) { - // TODO: this probably needs fixing - d.documentation.forEach { _, documentationNode -> - documentationNode.children.forEach { - header(3) { - text(it.toHeaderString()) - d.documentation.keys.joinToString(prefix = "[", postfix = "]", separator = ", ") + protected open fun contentForComments( + d: Documentable, + filtering: (TagWrapper) -> Boolean = { true } + ) = contentBuilder.contentFor(d) { + d.documentation.map{(k,v) -> (k to v.children.filter(filtering).map{p -> (k to p)})}.flatMap { it.second } + .groupBy { it.second.toHeaderString() }.mapValues {(k,v) -> v.groupBy { it.first }} + .forEach{ groupedByHeader -> + header(3) { text(groupedByHeader.key) } + d.documentation.expect?.also{ + it.children.filter(filtering).filter{it.toHeaderString() == groupedByHeader.key} + .forEach { + comment(it.root) + breakLine() + } + } + platformDependentHint(d.dri,groupedByHeader.value.keys){ + groupedByHeader.value.forEach{ + group(d.dri, setOf(it.key)){ + it.value.forEach { + comment(it.second.root) + } + breakLine() + } + } } - comment(it.root) - text("\n") } - } }.children - protected open fun contentForFunction(f: Function) = contentBuilder.contentFor(f) { + protected open fun contentForFunction(f: DFunction) = contentBuilder.contentFor(f) { header(1) { text(f.name) } - +buildSignature(f) - +contentForComments(f) - block("Parameters", 2, ContentKind.Parameters, f.children, f.platformData.toSet()) { - text(it.name ?: "<receiver>") - it.documentation.forEach { it.value.children.forEach { comment(it.root) } } + platformDependentHint(f.dri, f.platformData.toSet()) { + +buildSignature(f) } + +contentForComments(f) } protected open fun TagWrapper.toHeaderString() = this.javaClass.toGenericString().split('.').last() + + //TODO: It isn't platform-aware and produces wrong docs Probably should use platformDependentHint + protected open fun Documentable.briefDocumentation() = " " +// documentation.values +// .firstOrNull() +// ?.children +// ?.firstOrNull() +// ?.root +// ?.docTagSummary() ?: "" }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt index b9e20919..516e5524 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt @@ -3,9 +3,7 @@ package org.jetbrains.dokka.base.translators.documentables import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.Documentable -import org.jetbrains.dokka.model.PlatformDependent -import org.jetbrains.dokka.model.TypeWrapper +import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.doc.DocTag import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* @@ -36,7 +34,7 @@ open class PageContentBuilder( kind: Kind = ContentKind.Main, styles: Set<Style> = emptySet(), extra: PropertyContainer<ContentNode> = PropertyContainer.empty(), - block: DocumentableContentBuilder.() -> Unit + block: DocumentableContentBuilder.() -> Unit = {} ): ContentGroup = DocumentableContentBuilder(d.dri, d.platformData.toSet(), styles, extra) .apply(block) @@ -229,6 +227,10 @@ open class PageContentBuilder( block: DocumentableContentBuilder.() -> Unit ): ContentGroup = contentFor(dri, platformData, kind, styles, extra, block) + fun breakLine(platformData: Set<PlatformData> = mainPlatformData) { + contents += ContentBreakLine(platformData) + } + fun platformDependentHint( dri: DRI = mainDRI, platformData: Set<PlatformData> = mainPlatformData, @@ -252,21 +254,6 @@ open class PageContentBuilder( ) = ContentText(text, DCI(setOf(mainDRI), kind), platformData, styles, extra) - fun type(t: TypeWrapper) { - if (t.constructorNamePathSegments.isNotEmpty() && t.dri != null) - link(t.constructorNamePathSegments.last(), t.dri!!) - else if (t.constructorNamePathSegments.isNotEmpty() && t.dri == null) - text(t.toString()) - else { - logger.error("type $t cannot be resolved") - text("???") - } - list(t.arguments, prefix = "<", suffix = ">") { - type(it) - } - } - - fun <T> platformText( value: PlatformDependent<T>, transform: (T) -> String diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 81de12eb..ee862fb8 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -3,14 +3,11 @@ package org.jetbrains.dokka.base.translators.psi import com.intellij.lang.jvm.JvmModifier import com.intellij.lang.jvm.types.JvmReferenceType import com.intellij.psi.* -import org.jetbrains.dokka.links.Callable +import com.intellij.psi.impl.source.PsiClassReferenceType import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.JavaClassReference +import org.jetbrains.dokka.links.DriOfAny import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Annotation -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext @@ -21,6 +18,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.psiUtil.getChildOfType import org.jetbrains.kotlin.resolve.DescriptorUtils object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { @@ -30,22 +28,23 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { psiFiles: List<PsiJavaFile>, platformData: PlatformData, context: DokkaContext - ): Module { + ): DModule { val docParser = DokkaPsiParser( platformData, context.logger ) - return Module( + return DModule( moduleName, - psiFiles.map { psiFile -> - val dri = DRI(packageName = psiFile.packageName) - Package( + psiFiles.groupBy { it.packageName }.map { (packageName, psiFiles) -> + val dri = DRI(packageName = packageName) + DPackage( dri, emptyList(), emptyList(), - psiFile.classes.map { docParser.parseClasslike(it, dri) }, - emptyList(), + psiFiles.flatMap { psFile -> + psFile.classes.map { docParser.parseClasslike(it, dri) } + }, PlatformDependent.empty(), listOf(platformData) ) @@ -57,11 +56,13 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { class DokkaPsiParser( private val platformData: PlatformData, - logger: DokkaLogger + private val logger: DokkaLogger ) { private val javadocParser: JavaDocumentationParser = JavadocParser(logger) + private val cachedBounds = hashMapOf<String, Bound>() + private fun PsiModifierListOwner.getVisibility() = modifierList?.children?.toList()?.let { ml -> when { ml.any { it.text == PsiKeyword.PUBLIC } -> JavaVisibility.Public @@ -89,18 +90,12 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { private fun <T> T.toPlatformDependant() = PlatformDependent(mapOf(platformData to this)) - fun parseClasslike(psi: PsiClass, parent: DRI): Classlike = with(psi) { + fun parseClasslike(psi: PsiClass, parent: DRI): DClasslike = with(psi) { val dri = parent.withClass(name.toString()) val ancestorsSet = hashSetOf<DRI>() val superMethodsKeys = hashSetOf<Int>() val superMethods = mutableListOf<PsiMethod>() methods.forEach { superMethodsKeys.add(it.hash) } - fun addAncestors(element: PsiClass) { - ancestorsSet.add(element.toDRI()) - element.interfaces.forEach(::addAncestors) - element.superClass?.let(::addAncestors) - } - fun parseSupertypes(superTypes: Array<PsiClassType>) { superTypes.forEach { type -> (type as? PsiClassType)?.takeUnless { type.shouldBeIgnored }?.resolve()?.let { @@ -113,7 +108,7 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { superMethods.add(method) } } - addAncestors(it) + ancestorsSet.add(DRI.from(it)) parseSupertypes(it.superTypes) } } @@ -127,9 +122,10 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { val classlikes = innerClasses.map { parseClasslike(it, dri) } val visibility = getVisibility().toPlatformDependant() val ancestors = ancestorsSet.toList().toPlatformDependant() + val modifiers = getModifier().toPlatformDependant() return when { isAnnotationType -> - Annotation( + DAnnotation( name.orEmpty(), dri, documentation, @@ -140,20 +136,22 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { visibility, null, constructors.map { parseFunction(it, dri, true) }, - listOf(platformData) + listOf(platformData), + PropertyContainer.empty<DAnnotation>() + annotations.toList().toExtra() ) - isEnum -> Enum( + isEnum -> DEnum( dri, name.orEmpty(), fields.filterIsInstance<PsiEnumConstant>().map { entry -> - EnumEntry( + DEnumEntry( dri.withClass("$name.${entry.name}"), entry.name.orEmpty(), javadocParser.parseDocumentation(entry).toPlatformDependant(), emptyList(), emptyList(), emptyList(), - listOf(platformData) + listOf(platformData), + PropertyContainer.empty<DEnumEntry>() + entry.annotations.toList().toExtra() ) }, documentation, @@ -165,9 +163,10 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { null, constructors.map { parseFunction(it, dri, true) }, ancestors, - listOf(platformData) + listOf(platformData), + PropertyContainer.empty<DEnum>() + annotations.toList().toExtra() ) - isInterface -> Interface( + isInterface -> DInterface( dri, name.orEmpty(), documentation, @@ -179,9 +178,10 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { null, mapTypeParameters(dri), ancestors, - listOf(platformData) + listOf(platformData), + PropertyContainer.empty<DInterface>() + annotations.toList().toExtra() ) - else -> Class( + else -> DClass( dri, name.orEmpty(), constructors.map { parseFunction(it, dri, true) }, @@ -194,8 +194,9 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { mapTypeParameters(dri), ancestors, documentation, - getModifier(), - listOf(platformData) + modifiers, + listOf(platformData), + PropertyContainer.empty<DClass>() + annotations.toList().toExtra() ) } } @@ -205,58 +206,95 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { parent: DRI, isConstructor: Boolean = false, isInherited: Boolean = false - ): Function { - val dri = parent.copy( - callable = Callable( - psi.name, - JavaClassReference(psi.containingClass?.name.orEmpty()), - psi.parameterList.parameters.map { parameter -> - JavaClassReference(parameter.type.canonicalText) - }) - ) - return Function( + ): DFunction { + val dri = DRI.from(psi).copy(classNames = parent.classNames) + return DFunction( dri, if (isConstructor) "<init>" else psi.name, isConstructor, psi.parameterList.parameters.mapIndexed { index, psiParameter -> - Parameter( + DParameter( dri.copy(target = index + 1), psiParameter.name, javadocParser.parseDocumentation(psiParameter).toPlatformDependant(), - JavaTypeWrapper(psiParameter.type), + getBound(psiParameter.type), listOf(platformData) ) }, javadocParser.parseDocumentation(psi).toPlatformDependant(), PsiDocumentableSource(psi).toPlatformDependant(), psi.getVisibility().toPlatformDependant(), - psi.returnType?.let { JavaTypeWrapper(type = it) } ?: JavaTypeWrapper.VOID, + psi.returnType?.let { getBound(type = it) } ?: Void, psi.mapTypeParameters(dri), null, - psi.getModifier(), + psi.getModifier().toPlatformDependant(), listOf(platformData), - PropertyContainer.empty<Function>() + InheritedFunction( - isInherited + PropertyContainer.withAll( + InheritedFunction(isInherited), + psi.annotations.toList().toExtra(), + psi.additionalExtras() ) - ) } + private fun PsiMethod.additionalExtras() = AdditionalModifiers( + listOfNotNull( + ExtraModifiers.STATIC.takeIf { hasModifier(JvmModifier.STATIC) }, + ExtraModifiers.NATIVE.takeIf { hasModifier(JvmModifier.NATIVE) }, + ExtraModifiers.SYNCHRONIZED.takeIf { hasModifier(JvmModifier.SYNCHRONIZED) }, + ExtraModifiers.STRICTFP.takeIf { hasModifier(JvmModifier.STRICTFP) }, + ExtraModifiers.TRANSIENT.takeIf { hasModifier(JvmModifier.TRANSIENT) }, + ExtraModifiers.VOLATILE.takeIf { hasModifier(JvmModifier.VOLATILE) }, + ExtraModifiers.TRANSITIVE.takeIf { hasModifier(JvmModifier.TRANSITIVE) } + ).toSet() + ) + + private fun getBound(type: PsiType): Bound = + cachedBounds.getOrPut(type.canonicalText) { + when (type) { + is PsiClassReferenceType -> { + val resolved: PsiClass = type.resolve() + ?: throw IllegalStateException("${type.presentableText} cannot be resolved") + if (resolved.qualifiedName == "java.lang.Object") { + JavaObject + } else { + TypeConstructor(DRI.from(resolved), type.parameters.map { getProjection(it) }) + } + } + is PsiArrayType -> TypeConstructor( + DRI("kotlin", "Array"), + listOf(getProjection(type.componentType)) + ) + is PsiPrimitiveType -> if(type.name == "void") Void else PrimitiveJavaType(type.name) + else -> throw IllegalStateException("${type.presentableText} is not supported by PSI parser") + } + } + + private fun getVariance(type: PsiWildcardType): Projection = when { + type.extendsBound != PsiType.NULL -> Variance(Variance.Kind.Out, getBound(type.extendsBound)) + type.superBound != PsiType.NULL -> Variance(Variance.Kind.In, getBound(type.superBound)) + else -> throw IllegalStateException("${type.presentableText} has incorrect bounds") + } + + private fun getProjection(type: PsiType): Projection = when (type) { + is PsiEllipsisType -> Star + is PsiWildcardType -> getVariance(type) + else -> getBound(type) + } + private fun PsiModifierListOwner.getModifier() = when { hasModifier(JvmModifier.ABSTRACT) -> JavaModifier.Abstract hasModifier(JvmModifier.FINAL) -> JavaModifier.Final else -> JavaModifier.Empty } - private fun PsiTypeParameterListOwner.mapTypeParameters(dri: DRI): List<TypeParameter> { + private fun PsiTypeParameterListOwner.mapTypeParameters(dri: DRI): List<DTypeParameter> { fun mapBounds(bounds: Array<JvmReferenceType>): List<Bound> = if (bounds.isEmpty()) emptyList() else bounds.mapNotNull { - (it as? PsiClassType)?.let { classType -> - Nullable(TypeConstructor(classType.resolve()!!.toDRI(), emptyList())) - } + (it as? PsiClassType)?.let { classType -> Nullable(getBound(classType)) } } return typeParameters.mapIndexed { index, type -> - TypeParameter( + DTypeParameter( dri.copy(genericTarget = index), type.name.orEmpty(), javadocParser.parseDocumentation(type).toPlatformDependant(), @@ -266,14 +304,12 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { } } - private fun PsiQualifiedNamedElement.toDRI() = - DRI(qualifiedName.orEmpty().substringBeforeLast('.', ""), name) - private fun PsiMethod.getPropertyNameForFunction() = getAnnotation(DescriptorUtils.JVM_NAME.asString())?.findAttributeValue("name")?.text ?: when { JvmAbi.isGetterName(name) -> propertyNameByGetMethodName(Name.identifier(name))?.asString() - JvmAbi.isSetterName(name) -> propertyNamesBySetMethodName(Name.identifier(name)).firstOrNull()?.asString() + JvmAbi.isSetterName(name) -> propertyNamesBySetMethodName(Name.identifier(name)).firstOrNull() + ?.asString() else -> null } @@ -292,27 +328,40 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator { return regularMethods to accessors } - private fun parseField(psi: PsiField, parent: DRI, accessors: List<PsiMethod>): Property { - val dri = parent.copy( - callable = Callable( - psi.name!!, // TODO: Investigate if this is indeed nullable - JavaClassReference(psi.containingClass?.name.orEmpty()), - emptyList() - ) - ) - return Property( + private fun parseField(psi: PsiField, parent: DRI, accessors: List<PsiMethod>): DProperty { + val dri = DRI.from(psi) + return DProperty( dri, psi.name!!, // TODO: Investigate if this is indeed nullable javadocParser.parseDocumentation(psi).toPlatformDependant(), PsiDocumentableSource(psi).toPlatformDependant(), psi.getVisibility().toPlatformDependant(), - JavaTypeWrapper(psi.type), + getBound(psi.type), null, accessors.firstOrNull { it.hasParameters() }?.let { parseFunction(it, parent) }, accessors.firstOrNull { it.returnType == psi.type }?.let { parseFunction(it, parent) }, - psi.getModifier(), - listOf(platformData) + psi.getModifier().toPlatformDependant(), + listOf(platformData), + PropertyContainer.empty<DProperty>() + psi.annotations.toList().toExtra() ) } + + private fun Collection<PsiAnnotation>.toExtra() = mapNotNull { annotation -> + val resolved = annotation.getChildOfType<PsiJavaCodeReferenceElement>()?.resolve() ?: run { + logger.error("$annotation cannot be resolved to symbol!") + return@mapNotNull null + } + + Annotations.Annotation( + DRI.from(resolved), + annotation.attributes.mapNotNull { attr -> + if (attr is PsiNameValuePair) { + attr.value?.text?.let { attr.attributeName to it } + } else { + attr.attributeName to "" + } + }.toMap() + ) + }.let(::Annotations) } } diff --git a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt index 5b9af028..0e446e51 100644 --- a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt +++ b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt @@ -5,6 +5,7 @@ import com.intellij.psi.impl.source.javadoc.PsiDocParamRef import com.intellij.psi.impl.source.tree.JavaDocElementType import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.javadoc.* +import com.intellij.psi.tree.java.IJavaDocElementType import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.* @@ -59,7 +60,6 @@ class JavadocParser( is PsiInlineDocTag -> listOfNotNull(convertInlineDocTag(it)) is PsiDocParamRef -> listOfNotNull(it.toDocumentationLink()) is PsiDocTagValue, - is PsiWhiteSpace -> listOfNotNull(Text(it.text)) is LeafPsiElement -> Jsoup.parse(it.text).body().childNodes().mapNotNull { convertHtmlNode(it) } else -> null } @@ -74,7 +74,7 @@ class JavadocParser( private fun createBlock(element: Element): DocTag { val children = element.childNodes().mapNotNull { convertHtmlNode(it) } return when (element.tagName()) { - "p" -> P(children) + "p" -> P(listOf(Br, Br) + children) "b" -> B(children) "strong" -> Strong(children) "i" -> I(children) @@ -84,12 +84,10 @@ class JavadocParser( "ul" -> Ul(children) "ol" -> Ol(children) "li" -> Li(children) - //"a" -> createLink(element, children) // TODO: add proper inline link handling - "br" -> Br + "a" -> createLink(element, children) else -> Text(body = element.ownText()) } } -/* private fun createLink(element: Element, children: List<DocTag>): DocTag { return when { @@ -97,31 +95,20 @@ class JavadocParser( A(children, params = mapOf("docref" to element.attr("docref"))) } element.hasAttr("href") -> { - val href = element.attr("href") - - val uri = try { - A(children, params = mapOf("href" to href)) - } catch (_: Exception) { - null - } - - if (uri?.isAbsolute == false) { - ContentLocalLink(href) - } else { - ContentExternalLink(href) - } - } - element.hasAttr("name") -> { - ContentBookmark(element.attr("name")) + A(children, params = mapOf("href" to element.attr("href"))) } - else -> Text() + else -> Text(children = children) } - }*/ + } + + private fun PsiDocToken.isSharpToken() = tokenType.toString() == "DOC_TAG_VALUE_SHARP_TOKEN" private fun PsiElement.toDocumentationLink(labelElement: PsiElement? = null) = reference?.resolve()?.let { val dri = DRI.from(it) - val label = labelElement ?: children.firstOrNull { it is PsiDocToken && it.text.isNotBlank() } ?: this + val label = labelElement ?: children.firstOrNull { + it is PsiDocToken && it.text.isNotBlank() && !it.isSharpToken() + } ?: this DocumentationLink(dri, convertJavadocElements(listOfNotNull(label))) } diff --git a/plugins/base/src/test/kotlin/basic/DRITest.kt b/plugins/base/src/test/kotlin/basic/DRITest.kt index ca8e4bad..0e1f095e 100644 --- a/plugins/base/src/test/kotlin/basic/DRITest.kt +++ b/plugins/base/src/test/kotlin/basic/DRITest.kt @@ -3,10 +3,11 @@ package basic import org.jetbrains.dokka.links.* import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.asSequence -import org.junit.Assert.assertEquals -import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.junit.jupiter.api.Test + class DRITest : AbstractCoreTest() { @Test fun `#634`() { diff --git a/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt b/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt index 0405b91c..dae1b2be 100644 --- a/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt +++ b/plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt @@ -2,7 +2,8 @@ package basic import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ModulePageNode -import org.junit.Test +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest class DokkaBasicTests : AbstractCoreTest() { @@ -31,11 +32,11 @@ class DokkaBasicTests : AbstractCoreTest() { ) { pagesGenerationStage = { println(it.dri) - assert(it.getClasslikeToMemberMap().filterKeys { it.name == "Test" }.entries.firstOrNull()?.value?.size == 5) + assertTrue(it.getClasslikeToMemberMap().filterKeys { it.name == "Test" }.entries.firstOrNull()?.value?.size == 5) } } } - fun ModulePageNode.getClasslikeToMemberMap() = - this.parentMap.filterValues { it is ClasslikePageNode }.entries.groupBy ({it.value}){it.key} + private fun ModulePageNode.getClasslikeToMemberMap() = + this.parentMap.filterValues { it is ClasslikePageNode }.entries.groupBy({ it.value }) { it.key } }
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/enums/EnumsTest.kt b/plugins/base/src/test/kotlin/enums/EnumsTest.kt index ea3238a5..c9024a72 100644 --- a/plugins/base/src/test/kotlin/enums/EnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/EnumsTest.kt @@ -1,12 +1,11 @@ package enums -import org.jetbrains.dokka.model.Enum +import org.jetbrains.dokka.model.DEnum import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ModulePageNode -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test +import org.junit.jupiter.api.Test import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.junit.jupiter.api.Assertions.* class EnumsTest : AbstractCoreTest() { @@ -35,9 +34,9 @@ class EnumsTest : AbstractCoreTest() { pagesGenerationStage = { val map = it.getClasslikeToMemberMap() val test = map.filterKeys { it.name == "Test" }.values.firstOrNull() - assert(test != null) { "Test not found" } - assert(test!!.any { it.name == "E1" } && test.any { it.name == "E2" }) { "Enum entries missing in parent" } - assert(map.keys.any { it.name == "E1" } && map.keys.any { it.name == "E2" }) { "Enum entries missing" } + assertTrue(test != null) { "Test not found" } + assertTrue(test!!.any { it.name == "E1" } && test.any { it.name == "E2" }) { "Enum entries missing in parent" } + assertTrue(map.keys.any { it.name == "E1" } && map.keys.any { it.name == "E2" }) { "Enum entries missing" } } } } @@ -66,25 +65,25 @@ class EnumsTest : AbstractCoreTest() { configuration ) { documentablesCreationStage = {m -> - assertTrue("Module list cannot be empty", m.isNotEmpty()) + assertTrue(m.isNotEmpty(), "Module list cannot be empty") m.first().packages.let { p -> - assertTrue("Package list cannot be empty", p.isNotEmpty()) + assertTrue(p.isNotEmpty(), "Package list cannot be empty") p.first().classlikes.let { c -> - assertTrue("Classlikes list cannot be empty", c.isNotEmpty()) + assertTrue(c.isNotEmpty(), "Classlikes list cannot be empty") - val enum = c.first() as Enum + val enum = c.first() as DEnum assertEquals(enum.name, "Test") assertEquals(enum.entries.count(), 2) assertNotNull(enum.companion) } } } - pagesGenerationStage = { - val map = it.getClasslikeToMemberMap() + pagesGenerationStage = { module -> + val map = module.getClasslikeToMemberMap() val test = map.filterKeys { it.name == "Test" }.values.firstOrNull() - assert(test != null) { "Test not found" } - assert(test!!.any { it.name == "E1" } && test.any { it.name == "E2" }) { "Enum entries missing in parent" } - assert(map.keys.any { it.name == "E1" } && map.keys.any { it.name == "E2" }) { "Enum entries missing" } + assertNotNull(test, "Test not found") + assertTrue(test!!.any { it.name == "E1" } && test.any { it.name == "E2" }) { "Enum entries missing in parent" } + assertTrue(map.keys.any { it.name == "E1" } && map.keys.any { it.name == "E2" }) { "Enum entries missing" } } } } diff --git a/plugins/base/src/test/kotlin/expect/AbstractExpectTest.kt b/plugins/base/src/test/kotlin/expect/AbstractExpectTest.kt new file mode 100644 index 00000000..ef97b04c --- /dev/null +++ b/plugins/base/src/test/kotlin/expect/AbstractExpectTest.kt @@ -0,0 +1,104 @@ +package expect + +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.junit.jupiter.api.Assertions.assertTrue +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.concurrent.TimeUnit + +abstract class AbstractExpectTest( + val testDir: Path? = Paths.get("src/test", "resources", "expect"), + val formats: List<String> = listOf("html") +) : AbstractCoreTest() { + + protected fun generateOutput(path: Path, outFormat: String): Path? { + val config = dokkaConfiguration { + format = outFormat + passes { + pass { + sourceRoots = listOf(path.asString()) + } + } + } + + var result: Path? = null + testFromData(config, cleanupOutput = false) { + renderingStage = { _, context -> result = Paths.get(context.configuration.outputDir) } + } + return result + } + + protected fun compareOutput(expected: Path, obtained: Path?, gitTimeout: Long = 500) { + obtained?.let { path -> + val gitCompare = ProcessBuilder( + "git", + "--no-pager", + "diff", + expected.asString(), + path.asString() + ).also { logger.info("git diff command: ${it.command().joinToString(" ")}") } + .also { it.redirectErrorStream() }.start() + + assertTrue(gitCompare.waitFor(gitTimeout, TimeUnit.MILLISECONDS)) { "Git timed out after $gitTimeout" } + gitCompare.inputStream.bufferedReader().lines().forEach { logger.info(it) } + assertTrue(gitCompare.exitValue() == 0) { "${path.fileName}: outputs don't match" } + } ?: throw AssertionError("obtained path is null") + } + + protected fun compareOutputWithExcludes( + expected: Path, + obtained: Path?, + excludes: List<String>, + timeout: Long = 500 + ) { + obtained?.let { path -> + val (res, out, err) = runDiff(expected, obtained, excludes, timeout) + assertTrue(res == 0, "Outputs differ:\nstdout - $out\n\nstderr - ${err ?: ""}") + } ?: throw AssertionError("obtained path is null") + } + + protected fun runDiff(exp: Path, obt: Path, excludes: List<String>, timeout: Long): ProcessResult = + ProcessBuilder().command( + listOf("diff", "-ru") + excludes.flatMap { listOf("-x", it) } + listOf("--", exp.asString(), obt.asString()) + ).also { + it.redirectErrorStream() + }.start().also { assertTrue(it.waitFor(timeout, TimeUnit.MILLISECONDS), "diff timed out") }.let { + ProcessResult(it.exitValue(), it.inputStream.bufferResult()) + } + + + protected fun testOutput(p: Path, outFormat: String) { + val expectOut = p.resolve("out/$outFormat") + val testOut = generateOutput(p.resolve("src"), outFormat) + .also { logger.info("Test out: ${it?.asString()}") } + + compareOutput(expectOut.toAbsolutePath(), testOut?.toAbsolutePath()) + testOut?.deleteRecursively() + } + + protected fun testOutputWithExcludes( + p: Path, + outFormat: String, + ignores: List<String> = emptyList(), + timeout: Long = 500 + ) { + val expected = p.resolve("out/$outFormat") + generateOutput(p.resolve("src"), outFormat) + ?.let { obtained -> + compareOutputWithExcludes(expected, obtained, ignores, timeout) + + obtained.deleteRecursively() + } ?: throw AssertionError("Output not generated for ${p.fileName}") + } + + protected fun generateExpect(p: Path, outFormat: String) { + val out = p.resolve("out/$outFormat/") + Files.createDirectories(out) + + val ret = generateOutput(p.resolve("src"), outFormat) + Files.list(out).forEach { it.deleteRecursively() } + ret?.let { Files.list(it).forEach { f -> f.copyRecursively(out.resolve(f.fileName)) } } + } + +}
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/expect/ExpectGenerator.kt b/plugins/base/src/test/kotlin/expect/ExpectGenerator.kt new file mode 100644 index 00000000..667fc249 --- /dev/null +++ b/plugins/base/src/test/kotlin/expect/ExpectGenerator.kt @@ -0,0 +1,15 @@ +package expect + +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import java.nio.file.Files +import java.nio.file.Path + +class ExpectGenerator : AbstractExpectTest() { + + @Disabled + @Test + fun generateAll() = testDir?.dirsWithFormats(formats).orEmpty().forEach { (p, f) -> + generateExpect(p, f) + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/expect/ExpectTest.kt b/plugins/base/src/test/kotlin/expect/ExpectTest.kt index c6c252ed..0423a5b4 100644 --- a/plugins/base/src/test/kotlin/expect/ExpectTest.kt +++ b/plugins/base/src/test/kotlin/expect/ExpectTest.kt @@ -1,62 +1,18 @@ package expect -import org.junit.Test -import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -import java.util.concurrent.TimeUnit - -class ExpectTest : AbstractCoreTest() { - - private fun generateOutput(path: Path): Path? { - val config = dokkaConfiguration { - passes { - pass { - sourceRoots = listOf(path.asString()) - } - } - } - - var result: Path? = null - testFromData(config, cleanupOutput = false) { - renderingStage = { _, context -> result = Paths.get(context.configuration.outputDir) } - } - return result - } - - private fun compareOutput(expected: Path, obtained: Path?, gitTimeout: Long = 500) { - obtained?.let { path -> - val gitCompare = ProcessBuilder( - "git", - "--no-pager", - "diff", - expected.asString(), - path.asString() - ).also { logger.info("git diff command: ${it.command().joinToString(" ")}") } - .start() - - assert(gitCompare.waitFor(gitTimeout, TimeUnit.MILLISECONDS)) { "Git timed out after $gitTimeout" } - gitCompare.inputStream.bufferedReader().lines().forEach { logger.info(it) } - gitCompare.errorStream.bufferedReader().lines().forEach { logger.info(it) } - assert(gitCompare.exitValue() == 0) { "${path.fileName}: outputs don't match" } - } ?: throw AssertionError("obtained path is null") +import org.junit.jupiter.api.DynamicTest.dynamicTest +import org.junit.jupiter.api.TestFactory + +class ExpectTest : AbstractExpectTest() { + private val ignores: List<String> = listOf( + "*.js", + "*.css", + "*.svg" + ) + + @TestFactory + fun expectTest() = testDir?.dirsWithFormats(formats).orEmpty().map { (p, f) -> + dynamicTest("${p.fileName}-$f") { testOutputWithExcludes(p, f, ignores) } } - @Test - fun expectTest() { - val sources = Paths.get("src/test", "resources", "expect") - - Files.list(sources).forEach { p -> - val expectOut = p.resolve("out") - val testOut = generateOutput(p.resolve("src")) - .also { logger.info("Test out: ${it?.asString()}") } - - compareOutput(expectOut, testOut) - testOut?.toFile()?.deleteRecursively() - } - } - - fun Path.asString() = toAbsolutePath().normalize().toString() - }
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/expect/ExpectUtils.kt b/plugins/base/src/test/kotlin/expect/ExpectUtils.kt new file mode 100644 index 00000000..4ea46dda --- /dev/null +++ b/plugins/base/src/test/kotlin/expect/ExpectUtils.kt @@ -0,0 +1,28 @@ +package expect + +import java.io.InputStream +import java.nio.file.Files +import java.nio.file.Path +import kotlin.streams.toList + +data class ProcessResult(val code: Int, val out: String, val err: String? = null) + +internal fun Path.dirsWithFormats(formats: List<String>): List<Pair<Path, String>> = + Files.list(this).toList().flatMap { p -> formats.map { p to it } } + +internal fun Path.asString() = normalize().toString() +internal fun Path.deleteRecursively() = toFile().deleteRecursively() + +internal fun Path.copyRecursively(target: Path) = toFile().copyRecursively(target.toFile()) + +internal fun Path.listRecursively(filter: (Path) -> Boolean): List<Path> = when { + Files.isDirectory(this) -> listOfNotNull(takeIf(filter)) + Files.list(this).toList().flatMap { + it.listRecursively( + filter + ) + } + Files.isRegularFile(this) -> listOfNotNull(this.takeIf(filter)) + else -> emptyList() + } + +internal fun InputStream.bufferResult(): String = this.bufferedReader().lines().toList().joinToString("\n")
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/issues/IssuesTest.kt b/plugins/base/src/test/kotlin/issues/IssuesTest.kt index ea2f0f8e..f67229b7 100644 --- a/plugins/base/src/test/kotlin/issues/IssuesTest.kt +++ b/plugins/base/src/test/kotlin/issues/IssuesTest.kt @@ -1,9 +1,10 @@ package issues -import org.jetbrains.dokka.model.Class -import org.jetbrains.dokka.model.Function -import org.junit.Test +import org.jetbrains.dokka.model.DClass +import org.jetbrains.dokka.model.DFunction +import org.junit.jupiter.api.Test import utils.AbstractModelTest +import utils.name class IssuesTest : AbstractModelTest("/src/main/kotlin/issues/Test.kt", "issues") { @@ -31,18 +32,23 @@ class IssuesTest : AbstractModelTest("/src/main/kotlin/issues/Test.kt", "issues" | | fun doSomething(): String = "Hello" |} - """ + """, + configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/") + classpath = listOfNotNull(jvmStdlibPath) + } + } + } ) { - with((this / "issues" / "Test").cast<Class>()) { - // passes - (this / "working").cast<Function>().type.constructorFqName equals "kotlin.String" - (this / "doSomething").cast<Function>().type.constructorFqName equals "kotlin.String" - - // fails - (this / "brokenGenerics").cast<Function>().type.constructorFqName equals "kotlin.collections.List" - (this / "brokenApply").cast<Function>().type.constructorFqName equals "issues.Test" - (this / "brokenRun").cast<Function>().type.constructorFqName equals "issues.Test" - (this / "brokenLet").cast<Function>().type.constructorFqName equals "issues.Test" + with((this / "issues" / "Test").cast<DClass>()) { + (this / "working").cast<DFunction>().type.name equals "String" + (this / "doSomething").cast<DFunction>().type.name equals "String" + (this / "brokenGenerics").cast<DFunction>().type.name equals "List" + (this / "brokenApply").cast<DFunction>().type.name equals "Test" + (this / "brokenRun").cast<DFunction>().type.name equals "Test" + (this / "brokenLet").cast<DFunction>().type.name equals "Test" } } } diff --git a/plugins/base/src/test/kotlin/markdown/KDocTest.kt b/plugins/base/src/test/kotlin/markdown/KDocTest.kt index e250670a..f9d717b0 100644 --- a/plugins/base/src/test/kotlin/markdown/KDocTest.kt +++ b/plugins/base/src/test/kotlin/markdown/KDocTest.kt @@ -1,12 +1,12 @@ package markdown -import org.jetbrains.dokka.model.Package +import org.jetbrains.dokka.model.DPackage import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.pages.ModulePageNode -import org.junit.Assert +import org.junit.jupiter.api.Assertions.* import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest -open class KDocTest : AbstractCoreTest() { +abstract class KDocTest : AbstractCoreTest() { private val configuration = dokkaConfiguration { passes { @@ -26,7 +26,7 @@ open class KDocTest : AbstractCoreTest() { """.trimMargin() private fun actualDocumentationNode(modulePageNode: ModulePageNode) = - (modulePageNode.documentable?.children?.first() as Package) + (modulePageNode.documentable?.children?.first() as DPackage) .classlikes.single() .documentation.values.single() @@ -37,7 +37,7 @@ open class KDocTest : AbstractCoreTest() { configuration ) { pagesGenerationStage = { - Assert.assertEquals( + assertEquals( expectedDocumentationNode, actualDocumentationNode(it) ) diff --git a/plugins/base/src/test/kotlin/markdown/LinkTest.kt b/plugins/base/src/test/kotlin/markdown/LinkTest.kt new file mode 100644 index 00000000..d38486b5 --- /dev/null +++ b/plugins/base/src/test/kotlin/markdown/LinkTest.kt @@ -0,0 +1,46 @@ +package markdown + +import org.jetbrains.dokka.pages.ContentDRILink +import org.jetbrains.dokka.pages.MemberPageNode +import org.jetbrains.dokka.pages.dfs +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class LinkTest : AbstractCoreTest() { + @Test + fun linkToClassLoader() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/parser") + } + } + } + testInline( + """ + |/src/main/kotlin/parser/Test.kt + |package parser + | + | /** + | * Some docs that link to [ClassLoader.clearAssertionStatus] + | */ + |fun test(x: ClassLoader) = x.clearAssertionStatus() + | + """.trimMargin(), + configuration + ) { + renderingStage = { rootPageNode, _ -> + (rootPageNode.children.single().children.single() as MemberPageNode) + .content + .dfs { node -> node is ContentDRILink } + .let { + assertEquals( + "parser//test/#java.lang.ClassLoader//", + (it as ContentDRILink).address.toString() + ) + } + } + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/markdown/ParserTest.kt b/plugins/base/src/test/kotlin/markdown/ParserTest.kt index dee8e907..332c9766 100644 --- a/plugins/base/src/test/kotlin/markdown/ParserTest.kt +++ b/plugins/base/src/test/kotlin/markdown/ParserTest.kt @@ -2,13 +2,14 @@ package org.jetbrains.dokka.tests import markdown.KDocTest import org.jetbrains.dokka.model.doc.* -import org.junit.Ignore -import org.junit.Test +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test class ParserTest : KDocTest() { - @Test fun `Simple text`() { + @Test + fun `Simple text`() { val kdoc = """ | This is simple test of string | Next line @@ -23,7 +24,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Simple text with new line`() { + @Test + fun `Simple text with new line`() { val kdoc = """ | This is simple test of string\ | Next line @@ -31,18 +33,21 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Text("This is simple test of string"), - Br, - Text("Next line") - )) + P( + listOf( + Text("This is simple test of string"), + Br, + Text("Next line") + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Text with Bold and Emphasis decorators`() { + @Test + fun `Text with Bold and Emphasis decorators`() { val kdoc = """ | This is **simple** test of _string_ | Next **_line_** @@ -66,7 +71,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Text with Colon`() { + @Test + fun `Text with Colon`() { val kdoc = """ | This is simple text with: colon! """.trimMargin() @@ -80,7 +86,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Multilined text`() { + @Test + fun `Multilined text`() { val kdoc = """ | Text | and @@ -96,7 +103,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Paragraphs`() { + @Test + fun `Paragraphs`() { val kdoc = """ | Paragraph number | one @@ -119,7 +127,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Emphasis with star`() { + @Test + fun `Emphasis with star`() { val kdoc = " *text*" val expectedDocumentationNode = DocumentationNode( listOf( @@ -131,7 +140,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Underscores that are not Emphasis`() { + @Test + fun `Underscores that are not Emphasis`() { val kdoc = "text_with_underscores" val expectedDocumentationNode = DocumentationNode( listOf( @@ -143,7 +153,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Emphasis with underscores`() { + @Test + fun `Emphasis with underscores`() { val kdoc = "_text_" val expectedDocumentationNode = DocumentationNode( listOf( @@ -155,7 +166,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Embedded star`() { + @Test + fun `Embedded star`() { val kdoc = "Embedded*Star" val expectedDocumentationNode = DocumentationNode( listOf( @@ -168,7 +180,8 @@ class ParserTest : KDocTest() { } - @Test fun `Unordered list`() { + @Test + fun `Unordered list`() { val kdoc = """ | * list item 1 | * list item 2 @@ -188,7 +201,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Unordered list with multilines`() { + @Test + fun `Unordered list with multilines`() { val kdoc = """ | * list item 1 | continue 1 @@ -210,7 +224,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Unordered list with Bold`() { + @Test + fun `Unordered list with Bold`() { val kdoc = """ | * list **item** 1 | continue 1 @@ -220,25 +235,40 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - Ul(listOf( - Li(listOf(P(listOf( - Text("list "), - B(listOf(Text("item"))), - Text(" 1 continue 1") - )))), - Li(listOf(P(listOf( - Text("list "), - B(listOf(Text("item"))), - Text(" 2 continue 2") - )))) - )) + Ul( + listOf( + Li( + listOf( + P( + listOf( + Text("list "), + B(listOf(Text("item"))), + Text(" 1 continue 1") + ) + ) + ) + ), + Li( + listOf( + P( + listOf( + Text("list "), + B(listOf(Text("item"))), + Text(" 2 continue 2") + ) + ) + ) + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Unordered list with nested bullets`() { + @Test + fun `Unordered list with nested bullets`() { val kdoc = """ | * Outer first | Outer next line @@ -255,29 +285,38 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Ul(listOf( - Li(listOf(P(listOf(Text("Outer first Outer next line"))))), - Li(listOf(P(listOf(Text("Outer second"))))), - Ul(listOf( - Li(listOf(P(listOf(Text("Middle first Middle next line"))))), - Li(listOf(P(listOf(Text("Middle second"))))), - Ul(listOf( - Li(listOf(P(listOf(Text("Inner first Inner next line"))))) - )), - Li(listOf(P(listOf(Text("Middle third"))))) - )), - Li(listOf(P(listOf(Text("Outer third"))))) - )), - P(listOf(Text("New paragraph"))) - )) + P( + listOf( + Ul( + listOf( + Li(listOf(P(listOf(Text("Outer first Outer next line"))))), + Li(listOf(P(listOf(Text("Outer second"))))), + Ul( + listOf( + Li(listOf(P(listOf(Text("Middle first Middle next line"))))), + Li(listOf(P(listOf(Text("Middle second"))))), + Ul( + listOf( + Li(listOf(P(listOf(Text("Inner first Inner next line"))))) + ) + ), + Li(listOf(P(listOf(Text("Middle third"))))) + ) + ), + Li(listOf(P(listOf(Text("Outer third"))))) + ) + ), + P(listOf(Text("New paragraph"))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Ordered list`() { + @Test + fun `Ordered list`() { val kdoc = """ | 1. list item 1 | 2. list item 2 @@ -299,7 +338,8 @@ class ParserTest : KDocTest() { } - @Test fun `Ordered list beginning from other number`() { + @Test + fun `Ordered list beginning from other number`() { val kdoc = """ | 9. list item 1 | 12. list item 2 @@ -320,7 +360,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Ordered list with multilines`() { + @Test + fun `Ordered list with multilines`() { val kdoc = """ | 2. list item 1 | continue 1 @@ -343,7 +384,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Ordered list with Bold`() { + @Test + fun `Ordered list with Bold`() { val kdoc = """ | 1. list **item** 1 | continue 1 @@ -353,17 +395,30 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - Ol(listOf( - Li(listOf(P(listOf( - Text("list "), - B(listOf(Text("item"))), - Text(" 1 continue 1") - )))), - Li(listOf(P(listOf( - Text("list "), - B(listOf(Text("item"))), - Text(" 2 continue 2") - )))) + Ol( + listOf( + Li( + listOf( + P( + listOf( + Text("list "), + B(listOf(Text("item"))), + Text(" 1 continue 1") + ) + ) + ) + ), + Li( + listOf( + P( + listOf( + Text("list "), + B(listOf(Text("item"))), + Text(" 2 continue 2") + ) + ) + ) + ) ), mapOf("start" to "1") ) @@ -373,7 +428,8 @@ class ParserTest : KDocTest() { executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Ordered list with nested bullets`() { + @Test + fun `Ordered list with nested bullets`() { val kdoc = """ | 1. Outer first | Outer next line @@ -390,35 +446,41 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Ol(listOf( - Li(listOf(P(listOf(Text("Outer first Outer next line"))))), - Li(listOf(P(listOf(Text("Outer second"))))), - Ol(listOf( - Li(listOf(P(listOf(Text("Middle first Middle next line"))))), - Li(listOf(P(listOf(Text("Middle second"))))), - Ol(listOf( - Li(listOf(P(listOf(Text("Inner first Inner next line"))))) + P( + listOf( + Ol( + listOf( + Li(listOf(P(listOf(Text("Outer first Outer next line"))))), + Li(listOf(P(listOf(Text("Outer second"))))), + Ol( + listOf( + Li(listOf(P(listOf(Text("Middle first Middle next line"))))), + Li(listOf(P(listOf(Text("Middle second"))))), + Ol( + listOf( + Li(listOf(P(listOf(Text("Inner first Inner next line"))))) + ), + mapOf("start" to "1") + ), + Li(listOf(P(listOf(Text("Middle third"))))) + ), + mapOf("start" to "1") ), - mapOf("start" to "1") - ), - Li(listOf(P(listOf(Text("Middle third"))))) + Li(listOf(P(listOf(Text("Outer third"))))) ), mapOf("start" to "1") ), - Li(listOf(P(listOf(Text("Outer third"))))) - ), - mapOf("start" to "1") - ), - P(listOf(Text("New paragraph"))) - )) + P(listOf(Text("New paragraph"))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Ordered nested in Unordered nested in Ordered list`() { + @Test + fun `Ordered nested in Unordered nested in Ordered list`() { val kdoc = """ | 1. Outer first | Outer next line @@ -435,33 +497,40 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Ol(listOf( - Li(listOf(P(listOf(Text("Outer first Outer next line"))))), - Li(listOf(P(listOf(Text("Outer second"))))), - Ul(listOf( - Li(listOf(P(listOf(Text("Middle first Middle next line"))))), - Li(listOf(P(listOf(Text("Middle second"))))), - Ol(listOf( - Li(listOf(P(listOf(Text("Inner first Inner next line"))))) - ), - mapOf("start" to "1") + P( + listOf( + Ol( + listOf( + Li(listOf(P(listOf(Text("Outer first Outer next line"))))), + Li(listOf(P(listOf(Text("Outer second"))))), + Ul( + listOf( + Li(listOf(P(listOf(Text("Middle first Middle next line"))))), + Li(listOf(P(listOf(Text("Middle second"))))), + Ol( + listOf( + Li(listOf(P(listOf(Text("Inner first Inner next line"))))) + ), + mapOf("start" to "1") + ), + Li(listOf(P(listOf(Text("Middle third"))))) + ) + ), + Li(listOf(P(listOf(Text("Outer third"))))) ), - Li(listOf(P(listOf(Text("Middle third"))))) - )), - Li(listOf(P(listOf(Text("Outer third"))))) - ), - mapOf("start" to "1") - ), - P(listOf(Text("New paragraph"))) - )) + mapOf("start" to "1") + ), + P(listOf(Text("New paragraph"))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Header and two paragraphs`() { + @Test + fun `Header and two paragraphs`() { val kdoc = """ | # Header 1 | Following text @@ -471,19 +540,22 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - H1(listOf(Text("Header 1"))), - P(listOf(Text("Following text"))), - P(listOf(Text("New paragraph"))) - )) + P( + listOf( + H1(listOf(Text("Header 1"))), + P(listOf(Text("Following text"))), + P(listOf(Text("New paragraph"))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Ignore //TODO: ATX_2 to ATX_6 and sometimes ATX_1 from jetbrains parser consumes white space. Need to handle it in their library - @Test fun `All headers`() { + @Disabled //TODO: ATX_2 to ATX_6 and sometimes ATX_1 from jetbrains parser consumes white space. Need to handle it in their library + @Test + fun `All headers`() { val kdoc = """ | # Header 1 | Text 1 @@ -501,27 +573,30 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - H1(listOf(Text("Header 1"))), - P(listOf(Text("Text 1"))), - H2(listOf(Text("Header 2"))), - P(listOf(Text("Text 2"))), - H3(listOf(Text("Header 3"))), - P(listOf(Text("Text 3"))), - H4(listOf(Text("Header 4"))), - P(listOf(Text("Text 4"))), - H5(listOf(Text("Header 5"))), - P(listOf(Text("Text 5"))), - H6(listOf(Text("Header 6"))), - P(listOf(Text("Text 6"))) - )) + P( + listOf( + H1(listOf(Text("Header 1"))), + P(listOf(Text("Text 1"))), + H2(listOf(Text("Header 2"))), + P(listOf(Text("Text 2"))), + H3(listOf(Text("Header 3"))), + P(listOf(Text("Text 3"))), + H4(listOf(Text("Header 4"))), + P(listOf(Text("Text 4"))), + H5(listOf(Text("Header 5"))), + P(listOf(Text("Text 5"))), + H6(listOf(Text("Header 6"))), + P(listOf(Text("Text 6"))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Bold New Line Bold`() { + @Test + fun `Bold New Line Bold`() { val kdoc = """ | **line 1**\ | **line 2** @@ -529,18 +604,21 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - B(listOf(Text("line 1"))), - Br, - B(listOf(Text("line 2"))) - )) + P( + listOf( + B(listOf(Text("line 1"))), + Br, + B(listOf(Text("line 2"))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Horizontal rule`() { + @Test + fun `Horizontal rule`() { val kdoc = """ | *** | text 1 @@ -555,24 +633,27 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - HorizontalRule, - P(listOf(Text("text 1"))), - HorizontalRule, - P(listOf(Text("text 2"))), - HorizontalRule, - P(listOf(Text("text 3"))), - HorizontalRule, - P(listOf(Text("text 4"))), - HorizontalRule - )) + P( + listOf( + HorizontalRule, + P(listOf(Text("text 1"))), + HorizontalRule, + P(listOf(Text("text 2"))), + HorizontalRule, + P(listOf(Text("text 3"))), + HorizontalRule, + P(listOf(Text("text 4"))), + HorizontalRule + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Blockquote`() { + @Test + fun `Blockquote`() { val kdoc = """ | > Blockquotes are very handy in email to emulate reply text. | > This line is part of the same quote. @@ -584,17 +665,25 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - BlockQuote(listOf( - P(listOf( - Text("Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.") - )) - )), - P(listOf(Text("Quote break."))), - BlockQuote(listOf( - P(listOf(Text("Quote"))) - )) - )) + P( + listOf( + BlockQuote( + listOf( + P( + listOf( + Text("Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.") + ) + ) + ) + ), + P(listOf(Text("Quote break."))), + BlockQuote( + listOf( + P(listOf(Text("Quote"))) + ) + ) + ) + ) ) ) ) @@ -602,7 +691,8 @@ class ParserTest : KDocTest() { } - @Test fun `Blockquote nested`() { + @Test + fun `Blockquote nested`() { val kdoc = """ | > text 1 | > text 2 @@ -618,27 +708,36 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - BlockQuote(listOf( - P(listOf(Text("text 1 text 2"))), - BlockQuote(listOf( - P(listOf(Text("text 3 text 4"))) - )), - P(listOf(Text("text 5"))) - )), - P(listOf(Text("Quote break."))), - BlockQuote(listOf( - P(listOf(Text("Quote"))) - )) - )) + P( + listOf( + BlockQuote( + listOf( + P(listOf(Text("text 1 text 2"))), + BlockQuote( + listOf( + P(listOf(Text("text 3 text 4"))) + ) + ), + P(listOf(Text("text 5"))) + ) + ), + P(listOf(Text("Quote break."))), + BlockQuote( + listOf( + P(listOf(Text("Quote"))) + ) + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Ignore //TODO: Again ATX_1 consumes white space - @Test fun `Blockquote nested with fancy text enhancement`() { + @Disabled //TODO: Again ATX_1 consumes white space + @Test + fun `Blockquote nested with fancy text enhancement`() { val kdoc = """ | > text **1** | > text 2 @@ -655,36 +754,51 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - BlockQuote(listOf( - P(listOf( - Text("text "), - B(listOf(Text("1"))), - Text("\ntext 2") - )), - BlockQuote(listOf( - H1(listOf(Text("text 3"))), - Ul(listOf( - Li(listOf(P(listOf(Text("text 4"))))), - Ul(listOf( - Li(listOf(P(listOf(Text("text 5"))))) - ) - ))) - )), - P(listOf(Text("text 6"))) - )), - P(listOf(Text("Quote break."))), - BlockQuote(listOf( - P(listOf(Text("Quote"))) - )) - )) + P( + listOf( + BlockQuote( + listOf( + P( + listOf( + Text("text "), + B(listOf(Text("1"))), + Text("\ntext 2") + ) + ), + BlockQuote( + listOf( + H1(listOf(Text("text 3"))), + Ul( + listOf( + Li(listOf(P(listOf(Text("text 4"))))), + Ul( + listOf( + Li(listOf(P(listOf(Text("text 5"))))) + ) + ) + ) + ) + ) + ), + P(listOf(Text("text 6"))) + ) + ), + P(listOf(Text("Quote break."))), + BlockQuote( + listOf( + P(listOf(Text("Quote"))) + ) + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Simple Code Block`() { + @Test + fun `Simple Code Block`() { val kdoc = """ | `Some code` | Sample text @@ -692,17 +806,20 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Code(listOf(Text("Some code"))), - Text(" Sample text") - )) + P( + listOf( + Code(listOf(Text("Some code"))), + Text(" Sample text") + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Multilined Code Block`() { + @Test + fun `Multilined Code Block`() { val kdoc = """ | ```kotlin | val x: Int = 0 @@ -718,20 +835,22 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Code( - listOf( - Text("val x: Int = 0"), Br, - Text("val y: String = \"Text\""), Br, Br, - Text(" val z: Boolean = true"), Br, - Text("for(i in 0..10) {"), Br, - Text(" println(i)"), Br, - Text("}") + P( + listOf( + Code( + listOf( + Text("val x: Int = 0"), Br, + Text("val y: String = \"Text\""), Br, Br, + Text(" val z: Boolean = true"), Br, + Text("for(i in 0..10) {"), Br, + Text(" println(i)"), Br, + Text("}") + ), + mapOf("lang" to "kotlin") ), - mapOf("lang" to "kotlin") - ), - P(listOf(Text("Sample text"))) - )) + P(listOf(Text("Sample text"))) + ) + ) ) ) ) @@ -739,41 +858,52 @@ class ParserTest : KDocTest() { } - @Test fun `Inline link`() { + @Test + fun `Inline link`() { val kdoc = """ | [I'm an inline-style link](https://www.google.com) """.trimMargin() val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf(A( - listOf(Text("I'm an inline-style link")), - mapOf("href" to "https://www.google.com") - ))) + P( + listOf( + A( + listOf(Text("I'm an inline-style link")), + mapOf("href" to "https://www.google.com") + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Inline link with title`() { + @Test + fun `Inline link with title`() { val kdoc = """ | [I'm an inline-style link with title](https://www.google.com "Google's Homepage") """.trimMargin() val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf(A( - listOf(Text("I'm an inline-style link with title")), - mapOf("href" to "https://www.google.com", "title" to "Google's Homepage") - ))) + P( + listOf( + A( + listOf(Text("I'm an inline-style link with title")), + mapOf("href" to "https://www.google.com", "title" to "Google's Homepage") + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Full reference link`() { + @Test + fun `Full reference link`() { val kdoc = """ | [I'm a reference-style link][Arbitrary case-insensitive reference text] | @@ -782,17 +912,26 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf(P(listOf(A( - listOf(Text("I'm a reference-style link")), - mapOf("href" to "https://www.mozilla.org") - ))))) + P( + listOf( + P( + listOf( + A( + listOf(Text("I'm a reference-style link")), + mapOf("href" to "https://www.mozilla.org") + ) + ) + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Full reference link with number`() { + @Test + fun `Full reference link with number`() { val kdoc = """ | [You can use numbers for reference-style link definitions][1] | @@ -801,17 +940,26 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf(P(listOf(A( - listOf(Text("You can use numbers for reference-style link definitions")), - mapOf("href" to "http://slashdot.org") - ))))) + P( + listOf( + P( + listOf( + A( + listOf(Text("You can use numbers for reference-style link definitions")), + mapOf("href" to "http://slashdot.org") + ) + ) + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Short reference link`() { + @Test + fun `Short reference link`() { val kdoc = """ | Or leave it empty and use the [link text itself]. | @@ -820,21 +968,28 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf(P(listOf( - Text("Or leave it empty and use the "), - A( - listOf(Text("link text itself")), - mapOf("href" to "http://www.reddit.com") - ), - Text(".") - )))) + P( + listOf( + P( + listOf( + Text("Or leave it empty and use the "), + A( + listOf(Text("link text itself")), + mapOf("href" to "http://www.reddit.com") + ), + Text(".") + ) + ) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Autolink`() { + @Test + fun `Autolink`() { val kdoc = """ | URLs and URLs in angle brackets will automatically get turned into links. | http://www.example.com or <http://www.example.com> and sometimes @@ -843,21 +998,24 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Text("URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or "), - A( - listOf(Text("http://www.example.com")), - mapOf("href" to "http://www.example.com") - ), - Text(" and sometimes example.com (but not on Github, for example).") - )) + P( + listOf( + Text("URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or "), + A( + listOf(Text("http://www.example.com")), + mapOf("href" to "http://www.example.com") + ), + Text(" and sometimes example.com (but not on Github, for example).") + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Various links`() { + @Test + fun `Various links`() { val kdoc = """ | [I'm an inline-style link](https://www.google.com) | @@ -882,55 +1040,80 @@ class ParserTest : KDocTest() { val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - P(listOf(A( - listOf(Text("I'm an inline-style link")), - mapOf("href" to "https://www.google.com") - ))), - P(listOf(A( - listOf(Text("I'm an inline-style link with title")), - mapOf("href" to "https://www.google.com", "title" to "Google's Homepage") - ))), - P(listOf(A( - listOf(Text("I'm a reference-style link")), - mapOf("href" to "https://www.mozilla.org") - ))), - P(listOf(A( - listOf(Text("You can use numbers for reference-style link definitions")), - mapOf("href" to "http://slashdot.org") - ))), - P(listOf( - Text("Or leave it empty and use the "), - A( - listOf(Text("link text itself")), - mapOf("href" to "http://www.reddit.com") + P( + listOf( + P( + listOf( + A( + listOf(Text("I'm an inline-style link")), + mapOf("href" to "https://www.google.com") + ) + ) ), - Text(".") - )), - P(listOf( - Text("URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or "), - A( - listOf(Text("http://www.example.com")), - mapOf("href" to "http://www.example.com") + P( + listOf( + A( + listOf(Text("I'm an inline-style link with title")), + mapOf("href" to "https://www.google.com", "title" to "Google's Homepage") + ) + ) ), - Text(" and sometimes example.com (but not on Github, for example).") - )), - P(listOf(Text("Some text to show that the reference links can follow later."))) - )) + P( + listOf( + A( + listOf(Text("I'm a reference-style link")), + mapOf("href" to "https://www.mozilla.org") + ) + ) + ), + P( + listOf( + A( + listOf(Text("You can use numbers for reference-style link definitions")), + mapOf("href" to "http://slashdot.org") + ) + ) + ), + P( + listOf( + Text("Or leave it empty and use the "), + A( + listOf(Text("link text itself")), + mapOf("href" to "http://www.reddit.com") + ), + Text(".") + ) + ), + P( + listOf( + Text("URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or "), + A( + listOf(Text("http://www.example.com")), + mapOf("href" to "http://www.example.com") + ), + Text(" and sometimes example.com (but not on Github, for example).") + ) + ), + P(listOf(Text("Some text to show that the reference links can follow later."))) + ) + ) ) ) ) executeTest(kdoc, expectedDocumentationNode) } - @Test fun `Windows Carriage Return Line Feed`() { + @Test + fun `Windows Carriage Return Line Feed`() { val kdoc = "text\r\ntext" val expectedDocumentationNode = DocumentationNode( listOf( Description( - P(listOf( - Text("text text") - )) + P( + listOf( + Text("text text") + ) + ) ) ) ) diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt index a59174bf..ee109ba1 100644 --- a/plugins/base/src/test/kotlin/model/ClassesTest.kt +++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt @@ -1,11 +1,14 @@ package model +import org.jetbrains.dokka.Platform import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.KotlinModifier.* -import org.jetbrains.dokka.model.Function -import org.junit.Test +import org.jetbrains.dokka.pages.PlatformData +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test import utils.AbstractModelTest import utils.assertNotNull +import utils.name import utils.supers @@ -17,7 +20,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class """ |class Klass {}""" ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" children counts 4 } @@ -31,7 +34,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |object Obj {} """ ) { - with((this / "classes" / "Obj").cast<Object>()) { + with((this / "classes" / "Obj").cast<DObject>()) { name equals "Obj" children counts 3 } @@ -45,7 +48,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |class Klass(name: String) """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" children counts 4 @@ -54,7 +57,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class parameters counts 1 with(parameters.firstOrNull().assertNotNull("Constructor parameter")) { name equals "name" - type.constructorFqName equals "kotlin.String" + type.name equals "String" } } @@ -71,12 +74,12 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" children counts 5 - with((this / "fn").cast<Function>()) { - type.constructorFqName equals "kotlin.Unit" + with((this / "fn").cast<DFunction>()) { + type.name equals "Unit" parameters counts 0 visibility.values allEquals KotlinVisibility.Public } @@ -93,11 +96,11 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" children counts 5 - with((this / "name").cast<Property>()) { + with((this / "name").cast<DProperty>()) { name equals "name" // TODO property name } @@ -117,22 +120,22 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" children counts 5 - with((this / "Companion").cast<Object>()) { + with((this / "Companion").cast<DObject>()) { name equals "Companion" children counts 5 - with((this / "x").cast<Property>()) { + with((this / "x").cast<DProperty>()) { name equals "x" } - with((this / "foo").cast<Function>()) { + with((this / "foo").cast<DFunction>()) { name equals "foo" parameters counts 0 - type.constructorFqName equals "kotlin.Unit" + type.name equals "Unit" } } } @@ -146,23 +149,17 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |data class Klass() {} """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" visibility.values allEquals KotlinVisibility.Public - with(extra[AdditionalModifiers.AdditionalKey].assertNotNull("Extras")) { - content.find{it == ExtraModifiers.DATA}.assertNotNull("data modifier") + with(extra[AdditionalModifiers].assertNotNull("Extras")) { + content counts 1 + content.first() equals ExtraModifiers.DATA } } } } -// @Test fun dataClass() { -// verifyPackageMember("testdata/classes/dataClass.kt", defaultModelConfig) { cls -> -// val modifiers = cls.details(NodeKind.Modifier).map { it.name } -// assertTrue("data" in modifiers) -// } -// } - @Test fun sealedClass() { inlineModelTest( @@ -170,37 +167,32 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |sealed class Klass() {} """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" - modifier equals KotlinModifier.Sealed + modifier.allValues.forEach { it equals Sealed } } } } -// // TODO modifiers -// @Test fun annotatedClassWithAnnotationParameters() { -// checkSourceExistsAndVerifyModel( -// "testdata/classes/annotatedClassWithAnnotationParameters.kt", -// defaultModelConfig -// ) { model -> -// with(model.members.single().members.single()) { -// with(deprecation!!) { -// assertEquals("Deprecated", name) -// assertEquals(Content.Empty, content) -// assertEquals(NodeKind.Annotation, kind) -// assertEquals(1, details.count()) -// with(details[0]) { -// assertEquals(NodeKind.Parameter, kind) -// assertEquals(1, details.count()) -// with(details[0]) { -// assertEquals(NodeKind.Value, kind) -// assertEquals("\"should no longer be used\"", name) -// } -// } -// } -// } -// } -// } + @Test + fun annotatedClassWithAnnotationParameters() { + inlineModelTest( + """ + |@Deprecated("should no longer be used") class Foo() {} + """ + ) { + with((this / "classes" / "Foo").cast<DClass>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + this.content counts 1 + with(content.first()) { + dri.classNames equals "Deprecated" + params.entries counts 1 + params["message"].assertNotNull("message") equals "should no longer be used" + } + } + } + } + } @Test fun notOpenClass() { @@ -215,19 +207,19 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - val C = (this / "classes" / "C").cast<Class>() - val D = (this / "classes" / "D").cast<Class>() + val C = (this / "classes" / "C").cast<DClass>() + val D = (this / "classes" / "D").cast<DClass>() with(C) { - modifier equals Open - with((this / "f").cast<Function>()) { - modifier equals Open + modifier.allValues.forEach { it equals Open } + with((this / "f").cast<DFunction>()) { + modifier.allValues.forEach { it equals Open } } } with(D) { - modifier equals Final - with((this / "f").cast<Function>()) { - modifier equals Open + modifier.allValues.forEach { it equals Final } + with((this / "f").cast<DFunction>()) { + modifier.allValues.forEach { it equals Open } } D.supertypes.flatMap { it.component2() }.firstOrNull() equals C.dri } @@ -249,21 +241,21 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - val C = (this / "classes" / "C").cast<Class>() - val D = (this / "classes" / "D").cast<Class>() - val E = (this / "classes" / "E").cast<Class>() + val C = (this / "classes" / "C").cast<DClass>() + val D = (this / "classes" / "D").cast<DClass>() + val E = (this / "classes" / "E").cast<DClass>() with(C) { - modifier equals Abstract - ((this / "foo").cast<Function>()).modifier equals Abstract + modifier.allValues.forEach { it equals Abstract } + ((this / "foo").cast<DFunction>()).modifier.allValues.forEach { it equals Abstract } } with(D) { - modifier equals Abstract + modifier.allValues.forEach { it equals Abstract } } with(E) { - modifier equals Final + modifier.allValues.forEach { it equals Final } } D.supers.firstOrNull() equals C.dri @@ -271,7 +263,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class } } - @Test // todo inner class + @Test fun innerClass() { inlineModelTest( """ @@ -280,24 +272,18 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - with((this / "classes" / "C").cast<Class>()) { + with((this / "classes" / "C").cast<DClass>()) { - with((this / "D").cast<Class>()) { + with((this / "D").cast<DClass>()) { + with(extra[AdditionalModifiers].assertNotNull("AdditionalModifiers")) { + content counts 1 + content.first() equals ExtraModifiers.INNER + } } } } } -// // TODO modifiers -// @Test fun innerClass() { -// verifyPackageMember("testdata/classes/innerClass.kt", defaultModelConfig) { cls -> -// val innerClass = cls.members.single { it.name == "D" } -// val modifiers = innerClass.details(NodeKind.Modifier) -// assertEquals(3, modifiers.size) -// assertEquals("inner", modifiers[2].name) -// } -// } - @Test fun companionObjectExtension() { inlineModelTest( @@ -312,10 +298,10 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |val Klass.Default.x: Int get() = 1 """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" - with((this / "Default").cast<Object>()) { + with((this / "Default").cast<DObject>()) { name equals "Default" // TODO extensions } @@ -342,7 +328,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - with((this / "classes" / "C").cast<Class>()) { + with((this / "classes" / "C").cast<DClass>()) { name equals "C" constructors counts 2 @@ -356,21 +342,36 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class parameters counts 1 with(parameters.firstOrNull() notNull "Constructor parameter") { name equals "s" - type.constructorFqName equals "kotlin.String" + type.name equals "String" } } } } } - // TODO modifiers -// @Test fun sinceKotlin() { -// checkSourceExistsAndVerifyModel("testdata/classes/sinceKotlin.kt", defaultModelConfig) { model -> -// with(model.members.single().members.single()) { -// assertEquals("1.1", sinceKotlin) -// } -// } -// } + @Test + fun sinceKotlin() { + inlineModelTest( + """ + |/** + | * Useful + | */ + |@SinceKotlin("1.1") + |class C + """ + ) { + with((this / "classes" / "C").cast<DClass>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + this.content counts 1 + with(content.first()) { + dri.classNames equals "SinceKotlin" + params.entries counts 1 + params["version"].assertNotNull("version") equals "1.1" + } + } + } + } + } @Test fun privateCompanionObject() { @@ -384,14 +385,32 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class |} """ ) { - with((this / "classes" / "Klass").cast<Class>()) { + with((this / "classes" / "Klass").cast<DClass>()) { name equals "Klass" + assertNull(companion, "Companion should not be visible by default") + } + } + } - with((this / "Companion").cast<Object>()) { + @Test + fun companionObject() { + inlineModelTest( + """ + |class Klass { + | companion object { + | fun fn() {} + | val a = 0 + | } + |} + """ + ) { + with((this / "classes" / "Klass").cast<DClass>()) { + name equals "Klass" + with((this / "Companion").cast<DObject>()) { name equals "Companion" - visibility.values allEquals KotlinVisibility.Private + visibility.values allEquals KotlinVisibility.Public - with((this / "fn").cast<Function>()) { + with((this / "fn").cast<DFunction>()) { name equals "fn" parameters counts 0 receiver equals null @@ -401,48 +420,45 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class } } - // TODO annotations -// @Test -// fun annotatedClass() { -// verifyPackageMember("testdata/classes/annotatedClass.kt", ModelConfig( -// analysisPlatform = analysisPlatform, -// withKotlinRuntime = true -// ) -// ) { cls -> -// Assert.assertEquals(1, cls.annotations.count()) -// with(cls.annotations[0]) { -// Assert.assertEquals("Strictfp", name) -// Assert.assertEquals(Content.Empty, content) -// Assert.assertEquals(NodeKind.Annotation, kind) -// } -// } -// } - - -// TODO annotations - -// @Test fun javaAnnotationClass() { -// checkSourceExistsAndVerifyModel( -// "testdata/classes/javaAnnotationClass.kt", -// modelConfig = ModelConfig(analysisPlatform = analysisPlatform, withJdk = true) -// ) { model -> -// with(model.members.single().members.single()) { -// Assert.assertEquals(1, annotations.count()) -// with(annotations[0]) { -// Assert.assertEquals("Retention", name) -// Assert.assertEquals(Content.Empty, content) -// Assert.assertEquals(NodeKind.Annotation, kind) -// with(details[0]) { -// Assert.assertEquals(NodeKind.Parameter, kind) -// Assert.assertEquals(1, details.count()) -// with(details[0]) { -// Assert.assertEquals(NodeKind.Value, kind) -// Assert.assertEquals("RetentionPolicy.SOURCE", name) -// } -// } -// } -// } -// } -// } + @Test + fun annotatedClass() { + inlineModelTest( + """@Suppress("abc") class Foo() {}""" + ) { + with((this / "classes" / "Foo").cast<DClass>()) { + with(extra[Annotations]?.content?.firstOrNull().assertNotNull("annotations")) { + dri.toString() equals "kotlin/Suppress////" + with(params["names"].assertNotNull("param")) { + this equals "[\"abc\"]" + } + } + } + } + } + @Test fun javaAnnotationClass() { + inlineModelTest( + """ + |import java.lang.annotation.Retention + |import java.lang.annotation.RetentionPolicy + | + |@Retention(RetentionPolicy.SOURCE) + |public annotation class throws() + """ + ) { + with((this / "classes" / "throws").cast<DAnnotation>()) { + with(extra[AdditionalModifiers].assertNotNull("AdditionalModifiers")) { + content counts 1 + content.first() equals ExtraModifiers.OVERRIDE // ?? + } + with(extra[Annotations].assertNotNull("Annotations")) { + content counts 1 + with(content.first()) { + dri.classNames equals "Retention" + params["value"].assertNotNull("value") equals "(java/lang/annotation/RetentionPolicy, SOURCE)" + } + } + } + } + } }
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/model/CommentTest.kt b/plugins/base/src/test/kotlin/model/CommentTest.kt index d576cf49..b1faa07f 100644 --- a/plugins/base/src/test/kotlin/model/CommentTest.kt +++ b/plugins/base/src/test/kotlin/model/CommentTest.kt @@ -1,9 +1,9 @@ package model -import org.jetbrains.dokka.model.Property +import org.jetbrains.dokka.model.DProperty import org.jetbrains.dokka.model.doc.CustomWrapperTag import org.jetbrains.dokka.model.doc.Text -import org.junit.Test +import org.junit.jupiter.api.Test import utils.* class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comment") { @@ -28,7 +28,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val prop2 = "" """ ) { - with((this / "comment" / "prop1").cast<Property>()) { + with((this / "comment" / "prop1").cast<DProperty>()) { name equals "prop1" with(this.docs().firstOrNull()?.root.assertNotNull("Code")) { (children.firstOrNull() as? Text) @@ -37,7 +37,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme params["lang"] equals "brainfuck" } } - with((this / "comment" / "prop2").cast<Property>()) { + with((this / "comment" / "prop2").cast<DProperty>()) { name equals "prop2" comments() equals "a + b - c" } @@ -51,7 +51,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { name equals "property" comments() equals "" } @@ -68,7 +68,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme """ ) { val p = this - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "" } } @@ -87,7 +87,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "doc1\ndoc2 doc3" } } @@ -107,7 +107,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "doc1\ndoc2 doc3" } } @@ -121,7 +121,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "doc" } } @@ -136,7 +136,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "doc" } } @@ -151,7 +151,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "doc" } } @@ -168,7 +168,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "Summary\none: []" docs().find { it is CustomWrapperTag && it.name == "one" }.let { with(it.assertNotNull("'one' entry")) { @@ -188,7 +188,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals """it's "useful"""" } } @@ -205,7 +205,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "Summary\none: [section one]" } } @@ -224,7 +224,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "Summary\none: [section one]\ntwo: [section two]" } } @@ -243,7 +243,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |val property = "test" """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { comments() equals "Summary\none: [line one line two]" } } @@ -290,7 +290,7 @@ class CommentTest : AbstractModelTest("/src/main/kotlin/comment/Test.kt", "comme |} """ ) { - with((this / "comment" / "property").cast<Property>()) { + with((this / "comment" / "property").cast<DProperty>()) { this } } diff --git a/plugins/base/src/test/kotlin/model/FunctionsTest.kt b/plugins/base/src/test/kotlin/model/FunctionsTest.kt index 9554ad02..e00e51fc 100644 --- a/plugins/base/src/test/kotlin/model/FunctionsTest.kt +++ b/plugins/base/src/test/kotlin/model/FunctionsTest.kt @@ -1,9 +1,11 @@ package model -import org.jetbrains.dokka.model.Function -import org.jetbrains.dokka.model.Package -import org.junit.Test -import utils.* +import org.jetbrains.dokka.model.* +import org.junit.jupiter.api.Test +import utils.AbstractModelTest +import utils.assertNotNull +import utils.comments +import utils.name class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "function") { @@ -17,9 +19,9 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |fun fn() {} """ ) { - with((this / "function" / "fn").cast<Function>()) { + with((this / "function" / "fn").cast<DFunction>()) { name equals "fn" - type.constructorFqName equals "kotlin.Unit" + type.name equals "Unit" this.children.assertCount(0, "Function children: ") } } @@ -39,7 +41,7 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |fun fn(i: Int) {} """ ) { - with((this / "function").cast<Package>()) { + with((this / "function").cast<DPackage>()) { val fn1 = functions.find { it.name == "fn" && it.parameters.isNullOrEmpty() }.assertNotNull("fn()") @@ -55,7 +57,7 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun with(fn2) { name equals "fn" parameters.assertCount(1) - parameters.first().type.constructorFqName equals "kotlin.Int" + parameters.first().type.name equals "Int" } } } @@ -76,7 +78,7 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |fun String.fn(x: Int) {} """ ) { - with((this / "function").cast<Package>()) { + with((this / "function").cast<DPackage>()) { val fn1 = functions.find { it.name == "fn" && it.parameters.isNullOrEmpty() }.assertNotNull("fn()") @@ -94,7 +96,7 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun name equals "fn" parameters counts 1 receiver.assertNotNull("fn(Int) receiver") - parameters.first().type.constructorFqName equals "kotlin.Int" + parameters.first().type.name equals "Int" } } } @@ -114,24 +116,22 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |} """ ) { - with((this / "function" / "function").cast<Function>()) { + with((this / "function" / "function").cast<DFunction>()) { comments() equals "Multiline\nFunction Documentation" name equals "function" parameters counts 1 parameters.firstOrNull().assertNotNull("Parameter: ").also { it.name equals "x" - it.type.constructorFqName equals "kotlin.Int" + it.type.name equals "Int" it.comments() equals "parameter" } - type.assertNotNull("Return type: ").constructorFqName equals "kotlin.Unit" + type.assertNotNull("Return type: ").name equals "Unit" } } } -// TODO add modifiers - start - @Test fun functionWithNotDocumentedAnnotation() { inlineModelTest( @@ -139,20 +139,19 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |@Suppress("FOO") fun f() {} """ ) { - // TODO add annotations - - with((this / "function" / "f").cast<Function>()) { - assert(false) { "No annotation data" } + with((this / "function" / "f").cast<DFunction>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + content counts 1 + with(content.first()) { + dri.classNames equals "Suppress" + params.entries counts 1 + params["names"].assertNotNull("names") equals "[\"FOO\"]" + } + } } } } -// @Test fun functionWithNotDocumentedAnnotation() { -// verifyPackageMember("testdata/functions/functionWithNotDocumentedAnnotation.kt", defaultModelConfig) { func -> -// assertEquals(0, func.annotations.count()) -// } -// } - @Test fun inlineFunction() { inlineModelTest( @@ -160,21 +159,13 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |inline fun f(a: () -> String) {} """ ) { - // TODO add data about inline - - with((this / "function" / "f").cast<Function>()) { - assert(false) { "No inline data" } + with((this / "function" / "f").cast<DFunction>()) { + extra[AdditionalModifiers]?.content counts 1 + extra[AdditionalModifiers]?.content exists ExtraModifiers.INLINE } } } -// @Test fun inlineFunction() { -// verifyPackageMember("testdata/functions/inlineFunction.kt", defaultModelConfig) { func -> -// val modifiers = func.details(NodeKind.Modifier).map { it.name } -// assertTrue("inline" in modifiers) -// } -// } - @Test fun suspendFunction() { inlineModelTest( @@ -182,134 +173,207 @@ class FunctionTest : AbstractModelTest("/src/main/kotlin/function/Test.kt", "fun |suspend fun f() {} """ ) { - // TODO add data about suspend + with((this / "function" / "f").cast<DFunction>()) { + extra[AdditionalModifiers]?.content counts 1 + extra[AdditionalModifiers]?.content exists ExtraModifiers.SUSPEND + } + } + } + + @Test + fun suspendInlineFunctionOrder() { + inlineModelTest( + """ + |suspend inline fun f(a: () -> String) {} + """ + ) { + with((this / "function" / "f").cast<DFunction>()) { + extra[AdditionalModifiers]?.content counts 2 + extra[AdditionalModifiers]?.content exists ExtraModifiers.SUSPEND + extra[AdditionalModifiers]?.content exists ExtraModifiers.INLINE + } + } + } + + @Test + fun inlineSuspendFunctionOrderChanged() { + inlineModelTest( + """ + |inline suspend fun f(a: () -> String) {} + """ + ) { + with((this / "function" / "f").cast<DFunction>()) { + with(extra[AdditionalModifiers].assertNotNull("AdditionalModifiers")) { + content counts 2 + content exists ExtraModifiers.SUSPEND + content exists ExtraModifiers.INLINE + } + } + } + } + + @Test + fun functionWithAnnotatedParam() { + inlineModelTest( + """ + |@Target(AnnotationTarget.VALUE_PARAMETER) + |@Retention(AnnotationRetention.SOURCE) + |@MustBeDocumented + |public annotation class Fancy + | + |fun function(@Fancy notInlined: () -> Unit) {} + """ + ) { + with((this / "function" / "Fancy").cast<DAnnotation>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + content counts 3 + with(content.map { it.dri.classNames to it }.toMap()) { + with(this["Target"].assertNotNull("Target")) { + params["allowedTargets"].assertNotNull("allowedTargets") equals "[AnnotationTarget.VALUE_PARAMETER]" + } + with(this["Retention"].assertNotNull("Retention")) { + params["value"].assertNotNull("value") equals "(kotlin/annotation/AnnotationRetention, SOURCE)" + } + this["MustBeDocumented"].assertNotNull("MustBeDocumented").params.entries counts 0 + } + } - with((this / "function" / "f").cast<Function>()) { - assert(false) { "No suspend data" } + } + with((this / "function" / "function" / "notInlined").cast<DParameter>()) { + with(this.extra[Annotations].assertNotNull("Annotations")) { + content counts 1 + with(content.first()) { + dri.classNames equals "Fancy" + params.entries counts 0 + } + } + } + } + } + + @Test + fun functionWithNoinlineParam() { + inlineModelTest( + """ + |fun f(noinline notInlined: () -> Unit) {} + """ + ) { + with((this / "function" / "f" / "notInlined").cast<DParameter>()) { + extra[AdditionalModifiers]?.content counts 1 + extra[AdditionalModifiers]?.content exists ExtraModifiers.NOINLINE } } } -// @Test fun suspendFunction() { -// verifyPackageMember("testdata/functions/suspendFunction.kt") { func -> -// val modifiers = func.details(NodeKind.Modifier).map { it.name } -// assertTrue("suspend" in modifiers) -// } -// } + @Test + fun annotatedFunctionWithAnnotationParameters() { + inlineModelTest( + """ + |@Target(AnnotationTarget.VALUE_PARAMETER) + |@Retention(AnnotationRetention.SOURCE) + |@MustBeDocumented + |public annotation class Fancy(val size: Int) + | + |@Fancy(1) fun f() {} + """ + ) { + with((this / "function" / "Fancy").cast<DAnnotation>()) { + constructors counts 1 + with(constructors.first()) { + parameters counts 1 + with(parameters.first()) { + type.name equals "Int" + name equals "size" + } + } + + with(extra[Annotations].assertNotNull("Annotations")) { + content counts 3 + with(content.map { it.dri.classNames to it }.toMap()) { + with(this["Target"].assertNotNull("Target")) { + params["allowedTargets"].assertNotNull("allowedTargets") equals "[AnnotationTarget.VALUE_PARAMETER]" + } + with(this["Retention"].assertNotNull("Retention")) { + params["value"].assertNotNull("value") equals "(kotlin/annotation/AnnotationRetention, SOURCE)" + } + this["MustBeDocumented"].assertNotNull("MustBeDocumented").params.entries counts 0 + } + } -// @Test fun suspendInlineFunctionOrder() { -// verifyPackageMember("testdata/functions/suspendInlineFunction.kt") { func -> -// val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter { -// it == "suspend" || it == "inline" -// } -// -// assertEquals(listOf("suspend", "inline"), modifiers) -// } -// } -// -// @Test fun inlineSuspendFunctionOrderChanged() { -// verifyPackageMember("testdata/functions/inlineSuspendFunction.kt") { func -> -// val modifiers = func.details(NodeKind.Modifier).map { it.name }.filter { -// it == "suspend" || it == "inline" -// } -// -// assertEquals(listOf("suspend", "inline"), modifiers) -// } -// } -// -// @Test fun functionWithAnnotatedParam() { -// checkSourceExistsAndVerifyModel("testdata/functions/functionWithAnnotatedParam.kt", defaultModelConfig) { model -> -// with(model.members.single().members.single { it.name == "function" }) { -// with(details(NodeKind.Parameter).first()) { -// assertEquals(1, annotations.count()) -// with(annotations[0]) { -// assertEquals("Fancy", name) -// assertEquals(Content.Empty, content) -// assertEquals(NodeKind.Annotation, kind) -// } -// } -// } -// } -// } -// -// @Test fun functionWithNoinlineParam() { -// verifyPackageMember("testdata/functions/functionWithNoinlineParam.kt", defaultModelConfig) { func -> -// with(func.details(NodeKind.Parameter).first()) { -// val modifiers = details(NodeKind.Modifier).map { it.name } -// assertTrue("noinline" in modifiers) -// } -// } -// } -// -// @Test fun annotatedFunctionWithAnnotationParameters() { -// checkSourceExistsAndVerifyModel( -// "testdata/functions/annotatedFunctionWithAnnotationParameters.kt", -// defaultModelConfig -// ) { model -> -// with(model.members.single().members.single { it.name == "f" }) { -// assertEquals(1, annotations.count()) -// with(annotations[0]) { -// assertEquals("Fancy", name) -// assertEquals(Content.Empty, content) -// assertEquals(NodeKind.Annotation, kind) -// assertEquals(1, details.count()) -// with(details[0]) { -// assertEquals(NodeKind.Parameter, kind) -// assertEquals(1, details.count()) -// with(details[0]) { -// assertEquals(NodeKind.Value, kind) -// assertEquals("1", name) -// } -// } -// } -// } -// } -// } + } + with((this / "function" / "f").cast<DFunction>()) { + with(this.extra[Annotations].assertNotNull("Annotations")) { + content counts 1 + with(content.first()) { + dri.classNames equals "Fancy" + params.entries counts 1 + params["size"] equals "1" + } + } + } + } + } -// TODO add modifiers - end + @Test + fun functionWithDefaultStringParameter() { + inlineModelTest( + """ + |/src/main/kotlin/function/Test.kt + |package function + |fun f(x: String = "") {} + """ + ) { + with((this / "function" / "f").cast<DFunction>()) { + parameters.forEach { p -> + p.name equals "x" + p.type.name.assertNotNull("Parameter type: ") equals "String" + p.extra[DefaultValue]?.value equals "\"\"" + } + } + } + } -// @Test -// fun functionWithDefaultParameter() { -// inlineModelTest( -// """ -// |/src/main/kotlin/function/Test.kt -// |package function -// |fun f(x: String = "") {} -// """ -// ) { -// // TODO add default value data -// -// with(this / "function" / "f" cast Function::class) { -// parameters.forEach { p -> -// p.name equals "x" -// p.type.constructorFqName.assertNotNull("Parameter type: ") equals "kotlin.String" -// assert(false) { "Add default value data" } -// } -// } -// } -// } + @Test + fun functionWithDefaultFloatParameter() { + inlineModelTest( + """ + |/src/main/kotlin/function/Test.kt + |package function + |fun f(x: Float = 3.14f) {} + """ + ) { + with((this / "function" / "f").cast<DFunction>()) { + parameters.forEach { p -> + p.name equals "x" + p.type.name.assertNotNull("Parameter type: ") equals "Float" + p.extra[DefaultValue]?.value equals "3.14f" + } + } + } + } -// @Test fun functionWithDefaultParameter() { -// checkSourceExistsAndVerifyModel("testdata/functions/functionWithDefaultParameter.kt", defaultModelConfig) { model -> -// with(model.members.single().members.single()) { -// with(details.elementAt(3)) { -// val value = details(NodeKind.Value) -// assertEquals(1, value.count()) -// with(value[0]) { -// assertEquals("\"\"", name) -// } -// } -// } -// } -// } -// -// @Test fun sinceKotlin() { -// checkSourceExistsAndVerifyModel("testdata/functions/sinceKotlin.kt", defaultModelConfig) { model -> -// with(model.members.single().members.single()) { -// assertEquals("1.1", sinceKotlin) -// } -// } -// } -//} + @Test + fun sinceKotlin() { + inlineModelTest( + """ + |/** + | * Quite useful [String] + | */ + |@SinceKotlin("1.1") + |fun f(): String = "1.1 rulezz" + """ + ) { + with((this / "function" / "f").cast<DFunction>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + this.content counts 1 + with(content.first()) { + dri.classNames equals "SinceKotlin" + params.entries counts 1 + params["version"].assertNotNull("version") equals "1.1" + } + } + } + } + } }
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/model/InheritorsTest.kt b/plugins/base/src/test/kotlin/model/InheritorsTest.kt new file mode 100644 index 00000000..e1717fe4 --- /dev/null +++ b/plugins/base/src/test/kotlin/model/InheritorsTest.kt @@ -0,0 +1,94 @@ +package model + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.base.transformers.documentables.InheritorsExtractorTransformer +import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo +import org.jetbrains.dokka.model.DInterface +import org.jetbrains.dokka.plugability.DokkaPlugin +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import utils.AbstractModelTest +import utils.assertNotNull + +class InheritorsTest : AbstractModelTest("/src/main/kotlin/inheritors/Test.kt", "inheritors") { + + object InheritorsPlugin : DokkaPlugin() { + val inheritors by extending { + CoreExtensions.documentableTransformer with InheritorsExtractorTransformer() + } + } + + @Test + fun simple() { + inlineModelTest( + """|interface A{} + |class B() : A {} + """.trimMargin(), + pluginsOverrides = listOf(InheritorsPlugin) + ) { + with((this / "inheritors" / "A").cast<DInterface>()) { + val map = extra[InheritorsInfo].assertNotNull("InheritorsInfo").value.map + with(map.keys.also { it counts 1 }.find { it.platformType == Platform.jvm }.assertNotNull("jvm key").let { map[it]!! } + ) { + this counts 1 + first().classNames equals "B" + } + } + } + } + + @Test + fun multiplatform() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("common/src/", "jvm/src/") + analysisPlatform = "jvm" + targets = listOf("jvm") + } + pass { + sourceRoots = listOf("common/src/", "js/src/") + analysisPlatform = "js" + targets = listOf("js") + } + } + } + + testInline( + """ + |/common/src/main/kotlin/inheritors/Test.kt + |package inheritors + |interface A{} + |/jvm/src/main/kotlin/inheritors/Test.kt + |package inheritors + |class B() : A {} + |/js/src/main/kotlin/inheritors/Test.kt + |package inheritors + |class B() : A {} + |class C() : A {} + """.trimMargin(), + configuration, + cleanupOutput = false, + pluginOverrides = listOf(InheritorsPlugin) + ) { + documentablesTransformationStage = { m -> + with((m / "inheritors" / "A").cast<DInterface>()) { + val map = extra[InheritorsInfo].assertNotNull("InheritorsInfo").value.map + with(map.keys.also { it counts 2 }) { + with(find { it.platformType == Platform.jvm }.assertNotNull("jvm key").let { map[it]!! }) { + this counts 1 + first().classNames equals "B" + } + with(find { it.platformType == Platform.js }.assertNotNull("js key").let { map[it]!! }) { + this counts 2 + val classes = listOf("B", "C") + assertTrue(all { classes.contains(it.classNames) }, "One of subclasses missing in js" ) + } + } + + } + } + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt index ea454763..95185ad3 100644 --- a/plugins/base/src/test/kotlin/model/JavaTest.kt +++ b/plugins/base/src/test/kotlin/model/JavaTest.kt @@ -1,12 +1,12 @@ package model +import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function -import org.junit.Assert.assertTrue -import org.junit.Test +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test import utils.AbstractModelTest import utils.assertNotNull +import utils.name class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { @@ -24,10 +24,10 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Test").cast<Class>()) { + with((this / "java" / "Test").cast<DClass>()) { name equals "Test" children counts 1 - with((this / "fn").cast<Function>()) { + with((this / "fn").cast<DFunction>()) { name equals "fn" this } @@ -82,7 +82,7 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Test" / "fn").cast<Function>()) { + with((this / "java" / "Test" / "fn").cast<DFunction>()) { this } } @@ -108,11 +108,11 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |public class Foo extends Exception implements Cloneable {} """ ) { - with((this / "java" / "Foo").cast<Class>()) { + with((this / "java" / "Foo").cast<DClass>()) { val sups = listOf("Exception", "Cloneable") assertTrue( - "Foo must extend ${sups.joinToString(", ")}", sups.all { s -> supertypes.map.values.flatten().any { it.classNames == s } }) + "Foo must extend ${sups.joinToString(", ")}" } } } @@ -128,16 +128,16 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Test").cast<Class>()) { + with((this / "java" / "Test").cast<DClass>()) { name equals "Test" children counts 1 - with((this / "arrayToString").cast<Function>()) { + with((this / "arrayToString").cast<DFunction>()) { name equals "arrayToString" - type.constructorFqName equals "java.lang.String[]" + type.name equals "Array" with(parameters.firstOrNull().assertNotNull("parameters")) { name equals "data" - type.constructorFqName equals "int[]" + type.name equals "Array" } } } @@ -153,8 +153,8 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Foo").cast<Class>()) { - this + with((this / "java" / "Foo").cast<DClass>()) { + generics counts 1 } } } @@ -189,14 +189,14 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Test").cast<Class>()) { + with((this / "java" / "Test").cast<DClass>()) { name equals "Test" constructors counts 2 constructors.find { it.parameters.isNullOrEmpty() }.assertNotNull("Test()") with(constructors.find { it.parameters.isNotEmpty() }.assertNotNull("Test(String)")) { - parameters.firstOrNull()?.type?.constructorFqName equals "java.lang.String" + parameters.firstOrNull()?.type?.name equals "String" } } } @@ -211,9 +211,9 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "InnerClass").cast<Class>()) { + with((this / "java" / "InnerClass").cast<DClass>()) { children counts 1 - with((this / "D").cast<Class>()) { + with((this / "D").cast<DClass>()) { name equals "D" children counts 0 } @@ -230,15 +230,15 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Foo").cast<Class>()) { + with((this / "java" / "Foo").cast<DClass>()) { name equals "Foo" children counts 1 - with((this / "bar").cast<Function>()) { + with((this / "bar").cast<DFunction>()) { name equals "bar" with(parameters.firstOrNull().assertNotNull("parameter")) { name equals "x" - type.constructorFqName equals "java.lang.String..." + type.name equals "Array" } } } @@ -255,18 +255,17 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "Test").cast<Class>()) { + with((this / "java" / "Test").cast<DClass>()) { children counts 2 - with((this / "i").cast<Property>()) { - getter.assertNotNull("i.get") - setter.assertNotNull("i.set") + with((this / "i").cast<DProperty>()) { + getter equals null + setter equals null } - with((this / "s").cast<Property>()) { - getter.assertNotNull("s.get") - setter.assertNotNull("s.set") - + with((this / "s").cast<DProperty>()) { + getter equals null + setter equals null } } } @@ -285,6 +284,24 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { // } // } + @Test + fun staticMethod() { + inlineModelTest( + """ + |class C { + | public static void foo() {} + |} + """ + ) { + with((this / "java" / "C" / "foo").cast<DFunction>()) { + with(extra[AdditionalModifiers].assertNotNull("AdditionalModifiers")) { + content counts 1 + content.first() equals ExtraModifiers.STATIC + } + } + } + } + // @Test fun staticMethod() { todo // verifyJavaPackageMember("testdata/java/staticMethod.java", defaultModelConfig) { cls -> // val m = cls.members(NodeKind.Function).single { it.name == "foo" } @@ -303,31 +320,52 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { // assertEquals(1, cls.members(NodeKind.Function).size) // } // } - // - // @Test fun annotatedAnnotation() { - // verifyJavaPackageMember("testdata/java/annotatedAnnotation.java", defaultModelConfig) { cls -> - // assertEquals(1, cls.annotations.size) - // with(cls.annotations[0]) { - // assertEquals(1, details.count()) - // with(details[0]) { - // assertEquals(NodeKind.Parameter, kind) - // assertEquals(1, details.count()) - // with(details[0]) { - // assertEquals(NodeKind.Value, kind) - // assertEquals("[AnnotationTarget.FIELD, AnnotationTarget.CLASS, AnnotationTarget.FILE, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER]", name) - // } - // } - // } - // } - // } - // + + @Test + fun annotatedAnnotation() { + inlineModelTest( + """ + |import java.lang.annotation.*; + | + |@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) + |public @interface Attribute { + | String value() default ""; + |} + """ + ) { + with((this / "java" / "Attribute").cast<DAnnotation>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + with(content.single()) { + dri.classNames equals "Target" + params["value"].assertNotNull("value") equals "{ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}" + } + } + } + } + } + // @Test fun deprecation() { // verifyJavaPackageMember("testdata/java/deprecation.java", defaultModelConfig) { cls -> // val fn = cls.members(NodeKind.Function).single() // assertEquals("This should no longer be used", fn.deprecation!!.content.toTestString()) // } // } - // + + @Test + fun javaLangObject() { + inlineModelTest( + """ + |class Test { + | public Object fn() { return null; } + |} + """ + ) { + with((this / "java" / "Test" / "fn").cast<DFunction>()) { + assertTrue(type is JavaObject) + } + } + } + // @Test fun javaLangObject() { // verifyJavaPackageMember("testdata/java/javaLangObject.java", defaultModelConfig) { cls -> // val fn = cls.members(NodeKind.Function).single() @@ -344,17 +382,41 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { |} """ ) { - with((this / "java" / "E").cast<Enum>()) { + with((this / "java" / "E").cast<DEnum>()) { name equals "E" entries counts 1 - with((this / "Foo").cast<EnumEntry>()) { + with((this / "Foo").cast<DEnumEntry>()) { name equals "Foo" } } } } + @Test + fun inheritorLinks() { + inlineModelTest( + """ + |public class InheritorLinks { + | public static class Foo {} + | + | public static class Bar extends Foo {} + |} + """ + ) { + with((this / "java" / "InheritorLinks").cast<DClass>()) { + val dri = (this / "Bar").assertNotNull("Foo dri").dri + with((this / "Foo").cast<DClass>()) { + with(extra[InheritorsInfo].assertNotNull("InheritorsInfo")) { + with(value.map.values.flatten().distinct()) { + this counts 1 + first() equals dri + } + } + } + } + } + } // todo // @Test fun inheritorLinks() { diff --git a/plugins/base/src/test/kotlin/model/PackagesTest.kt b/plugins/base/src/test/kotlin/model/PackagesTest.kt index e19cc82d..8885dae0 100644 --- a/plugins/base/src/test/kotlin/model/PackagesTest.kt +++ b/plugins/base/src/test/kotlin/model/PackagesTest.kt @@ -1,7 +1,7 @@ package model -import org.jetbrains.dokka.model.Package -import org.junit.Test +import org.jetbrains.dokka.model.DPackage +import org.junit.jupiter.api.Test import utils.AbstractModelTest class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "packages") { @@ -14,7 +14,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac """.trimIndent(), prependPackage = false ) { - with((this / "").cast<Package>()) { + with((this / "").cast<DPackage>()) { name equals "" children counts 0 } @@ -29,7 +29,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac """.trimIndent(), prependPackage = false ) { - with((this / "simple").cast<Package>()) { + with((this / "simple").cast<DPackage>()) { name equals "simple" children counts 0 } @@ -44,7 +44,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac """.trimIndent(), prependPackage = false ) { - with((this / "dot.name").cast<Package>()) { + with((this / "dot.name").cast<DPackage>()) { name equals "dot.name" children counts 0 } @@ -63,11 +63,11 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac prependPackage = false ) { children counts 2 - with((this / "dot.name").cast<Package>()) { + with((this / "dot.name").cast<DPackage>()) { name equals "dot.name" children counts 0 } - with((this / "simple").cast<Package>()) { + with((this / "simple").cast<DPackage>()) { name equals "simple" children counts 0 } @@ -85,7 +85,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac prependPackage = false ) { children counts 1 - with((this / "simple").cast<Package>()) { + with((this / "simple").cast<DPackage>()) { name equals "simple" children counts 0 } @@ -102,7 +102,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac """.trimIndent(), prependPackage = false ) { - with((this / "simple.name").cast<Package>()) { + with((this / "simple.name").cast<DPackage>()) { name equals "simple.name" children counts 1 } diff --git a/plugins/base/src/test/kotlin/model/PropertyTest.kt b/plugins/base/src/test/kotlin/model/PropertyTest.kt index e4ef0aec..14f7b402 100644 --- a/plugins/base/src/test/kotlin/model/PropertyTest.kt +++ b/plugins/base/src/test/kotlin/model/PropertyTest.kt @@ -1,11 +1,10 @@ package model -import org.jetbrains.dokka.model.KotlinVisibility -import org.jetbrains.dokka.model.Package -import org.jetbrains.dokka.model.Property -import org.junit.Test +import org.jetbrains.dokka.model.* +import org.junit.jupiter.api.Test import utils.AbstractModelTest import utils.assertNotNull +import utils.name class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "property") { @@ -15,13 +14,13 @@ class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "pro """ |val property = "test"""" ) { - with((this / "property" / "property").cast<Property>()) { + with((this / "property" / "property").cast<DProperty>()) { name equals "property" children counts 0 with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.String" + type.name equals "String" } - type.constructorFqName equals "kotlin.String" + type.name equals "String" } } } @@ -33,14 +32,14 @@ class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "pro |var property = "test" """ ) { - with((this / "property" / "property").cast<Property>()) { + with((this / "property" / "property").cast<DProperty>()) { name equals "property" children counts 0 setter.assertNotNull("Setter") with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.String" + type.name equals "String" } - type.constructorFqName equals "kotlin.String" + type.name equals "String" } } } @@ -53,13 +52,13 @@ class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "pro | get() = "test" """ ) { - with((this / "property" / "property").cast<Property>()) { + with((this / "property" / "property").cast<DProperty>()) { name equals "property" children counts 0 with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.String" + type.name equals "String" } - type.constructorFqName equals "kotlin.String" + type.name equals "String" } } } @@ -73,12 +72,12 @@ class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "pro | set(value) {} """ ) { - with((this / "property" / "property").cast<Property>()) { + with((this / "property" / "property").cast<DProperty>()) { name equals "property" children counts 0 setter.assertNotNull("Setter") with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.String" + type.name equals "String" } visibility.values allEquals KotlinVisibility.Public } @@ -93,15 +92,15 @@ class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "pro | get() = size() * 2 """ ) { - with((this / "property" / "property").cast<Property>()) { + with((this / "property" / "property").cast<DProperty>()) { name equals "property" children counts 0 with(receiver.assertNotNull("property receiver")) { name equals null - type.constructorFqName equals "kotlin.String" + type.name equals "String" } with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.Int" + type.name equals "Int" } visibility.values allEquals KotlinVisibility.Public } @@ -120,38 +119,75 @@ class PropertyTest : AbstractModelTest("/src/main/kotlin/property/Test.kt", "pro |} """ ) { - with((this / "property").cast<Package>()) { - with((this / "Foo" / "property").cast<Property>()) { + with((this / "property").cast<DPackage>()) { + with((this / "Foo" / "property").cast<DProperty>()) { name equals "property" children counts 0 with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.Int" + type.name equals "Int" } } - with((this / "Bar" / "property").cast<Property>()) { + with((this / "Bar" / "property").cast<DProperty>()) { name equals "property" children counts 0 with(getter.assertNotNull("Getter")) { - type.constructorFqName equals "kotlin.Int" + type.name equals "Int" } } } } } - // todo -// @Test fun sinceKotlin() { -// checkSourceExistsAndVerifyModel("testdata/properties/sinceKotlin.kt", defaultModelConfig) { model -> -// with(model.members.single().members.single()) { -// assertEquals("1.1", sinceKotlin) -// } -// } -// } -//} -// -//class JSPropertyTest: BasePropertyTest(Platform.js) {} -// -//class JVMPropertyTest : BasePropertyTest(Platform.jvm) { + @Test + fun sinceKotlin() { + inlineModelTest( + """ + |/** + | * Quite useful [String] + | */ + |@SinceKotlin("1.1") + |val prop: String = "1.1 rulezz" + """ + ) { + with((this / "property" / "prop").cast<DProperty>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + this.content counts 1 + with(content.first()) { + dri.classNames equals "SinceKotlin" + params.entries counts 1 + params["version"].assertNotNull("version") equals "1.1" + } + } + } + } + } + + @Test + fun annotatedProperty() { + inlineModelTest( + """ + |@Strictfp var property = "test" + """, + configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/") + classpath = listOfNotNull(jvmStdlibPath) + } + } + } + ) { + with((this / "property" / "property").cast<DProperty>()) { + with(extra[Annotations].assertNotNull("Annotations")) { + this.content counts 1 + with(content.first()) { + dri.classNames equals "Strictfp" + params.entries counts 0 + } + } + } + } + } // @Test // fun annotatedProperty() { // checkSourceExistsAndVerifyModel( diff --git a/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt b/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt index e9605c5f..0111e8fb 100644 --- a/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt +++ b/plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt @@ -1,7 +1,7 @@ package multiplatform -import org.junit.Assert.assertEquals -import org.junit.Test +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest class BasicMultiplatformTest : AbstractCoreTest() { diff --git a/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt b/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt index 4b90604e..6ef38aa9 100644 --- a/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt +++ b/plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt @@ -1,13 +1,10 @@ package pageMerger -import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.PageNode -import org.jetbrains.dokka.plugability.DokkaPlugin -import org.jetbrains.dokka.base.transformers.pages.merger.SameMethodNamePageMergerStrategy -import org.jetbrains.dokka.utilities.DokkaLogger -import org.junit.Ignore -import org.junit.Test +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest class PageNodeMergerTest : AbstractCoreTest() { @@ -70,16 +67,16 @@ class PageNodeMergerTest : AbstractCoreTest() { val testT = allChildren.filter { it.name == "testT" } val test = allChildren.filter { it.name == "test" } - assert(testT.size == 1) { "There can be only one testT page" } - assert(testT.first().dri.size == 2) { "testT page should have 2 DRI, but has ${testT.first().dri.size}" } + assertTrue(testT.size == 1) { "There can be only one testT page" } + assertTrue(testT.first().dri.size == 2) { "testT page should have 2 DRI, but has ${testT.first().dri.size}" } - assert(test.size == 1) { "There can be only one test page" } - assert(test.first().dri.size == 2) { "test page should have 2 DRI, but has ${test.first().dri.size}" } + assertTrue(test.size == 1) { "There can be only one test page" } + assertTrue(test.first().dri.size == 2) { "test page should have 2 DRI, but has ${test.first().dri.size}" } } } } - @Ignore("TODO: reenable when we have infrastructure for turning off extensions") + @Disabled("TODO: reenable when we have infrastructure for turning off extensions") @Test fun defaultStrategyTest() { val strList: MutableList<String> = mutableListOf() @@ -113,13 +110,13 @@ class PageNodeMergerTest : AbstractCoreTest() { val testT = allChildren.filter { it.name == "testT" } val test = allChildren.filter { it.name == "test" } - assert(testT.size == 1) { "There can be only one testT page" } - assert(testT.first().dri.size == 1) { "testT page should have single DRI, but has ${testT.first().dri.size}" } + assertTrue(testT.size == 1) { "There can be only one testT page" } + assertTrue(testT.first().dri.size == 1) { "testT page should have single DRI, but has ${testT.first().dri.size}" } - assert(test.size == 1) { "There can be only one test page" } - assert(test.first().dri.size == 1) { "test page should have single DRI, but has ${test.first().dri.size}" } + assertTrue(test.size == 1) { "There can be only one test page" } + assertTrue(test.first().dri.size == 1) { "test page should have single DRI, but has ${test.first().dri.size}" } - assert(strList.count() == 2) { "Expected 2 warnings, got ${strList.count()}" } + assertTrue(strList.count() == 2) { "Expected 2 warnings, got ${strList.count()}" } } } } diff --git a/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt index a6977258..852ac735 100644 --- a/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt @@ -1,9 +1,12 @@ package renderers import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.resolvers.DefaultLocationProviderFactory -import org.jetbrains.dokka.base.resolvers.LocationProvider -import org.jetbrains.dokka.base.resolvers.LocationProviderFactory +import org.jetbrains.dokka.base.renderers.html.RootCreator +import org.jetbrains.dokka.base.resolvers.external.DokkaExternalLocationProviderFactory +import org.jetbrains.dokka.base.resolvers.external.JavadocExternalLocationProviderFactory +import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProviderFactory +import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory import org.jetbrains.dokka.base.signatures.KotlinSignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder @@ -14,15 +17,26 @@ import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.testApi.context.MockContext import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import org.jsoup.nodes.Node +import org.jsoup.nodes.TextNode import utils.TestOutputWriter abstract class RenderingOnlyTestBase { val files = TestOutputWriter() val context = MockContext( DokkaBase().outputWriter to { _ -> files }, - DokkaBase().locationProviderFactory to ::DefaultLocationProviderFactory + DokkaBase().locationProviderFactory to ::DefaultLocationProviderFactory, + DokkaBase().htmlPreprocessors to { _ -> RootCreator }, + DokkaBase().externalLocationProviderFactory to { _ -> ::JavadocExternalLocationProviderFactory }, + DokkaBase().externalLocationProviderFactory to { _ -> ::DokkaExternalLocationProviderFactory } ) + protected val renderedContent: Element by lazy { + files.contents.getValue("test-page.html").let { Jsoup.parse(it) }.select("#content").single() + } + protected fun linesAfterContentTag() = files.contents.getValue("test-page.html").lines() .dropWhile { !it.contains("""<div id="content">""") } @@ -60,6 +74,28 @@ class TestPage(callback: PageContentBuilder.DocumentableContentBuilder.() -> Uni override fun modified(name: String, children: List<PageNode>) = this } +fun Element.match(vararg matchers: Any): Unit = + childNodes() + .filter { it !is TextNode || it.text().isNotBlank() } + .let { it.drop(it.size - matchers.size) } + .zip(matchers) + .forEach { (n, m) -> m.accepts(n) } + +open class Tag(val name: String, vararg val matchers: Any) +class Div(vararg matchers: Any): Tag("div", *matchers) +class P(vararg matchers: Any): Tag("p", *matchers) + +private fun Any.accepts(n: Node) { + when (this) { + is String -> assert(n is TextNode && n.text().trim() == this.trim()) { "\"$this\" expected but found: $n" } + is Tag -> { + assert(n is Element && n.tagName() == name) { "Tag $name expected but found: $n" } + if (n is Element && matchers.isNotEmpty()) n.match(*matchers) + } + else -> throw IllegalArgumentException("$this is not proper matcher") + } +} + internal object EmptyCommentConverter : CommentsToContentConverter { override fun buildContent( diff --git a/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt b/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt index e98b97c0..eead07a7 100644 --- a/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt @@ -2,9 +2,9 @@ package renderers.html import org.jetbrains.dokka.base.renderers.html.HtmlRenderer import org.jetbrains.dokka.pages.TextStyle -import org.junit.Test -import renderers.RenderingOnlyTestBase -import renderers.TestPage +import org.jsoup.Jsoup +import org.junit.jupiter.api.Test +import renderers.* class GroupWrappingTest: RenderingOnlyTestBase() { @@ -20,7 +20,7 @@ class GroupWrappingTest: RenderingOnlyTestBase() { HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("abc")) + renderedContent.match("abc") } @Test @@ -35,7 +35,7 @@ class GroupWrappingTest: RenderingOnlyTestBase() { HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<p>ab</p>c")) + renderedContent.match(P("ab"), "c") } @Test @@ -50,7 +50,7 @@ class GroupWrappingTest: RenderingOnlyTestBase() { HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>ab</div>c")) + renderedContent.match(Div("ab"), "c") } @Test @@ -70,7 +70,7 @@ class GroupWrappingTest: RenderingOnlyTestBase() { HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>a<div><div>bc</div></div>d</div>")) + renderedContent.match(Div("a", Div(Div("bc")), "d")) } } diff --git a/plugins/base/src/test/kotlin/renderers/html/PlatformDependentHintTest.kt b/plugins/base/src/test/kotlin/renderers/html/PlatformDependentHintTest.kt index 2fda1ee1..f8ba51a6 100644 --- a/plugins/base/src/test/kotlin/renderers/html/PlatformDependentHintTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/PlatformDependentHintTest.kt @@ -3,13 +3,14 @@ package renderers.html import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.renderers.html.HtmlRenderer import org.jetbrains.dokka.pages.PlatformData -import org.jetbrains.dokka.pages.Style import org.jetbrains.dokka.pages.TextStyle -import org.junit.Test +import org.junit.jupiter.api.Test +import renderers.Div import renderers.RenderingOnlyTestBase import renderers.TestPage +import renderers.match -class PlatformDependentHintTest: RenderingOnlyTestBase() { +class PlatformDependentHintTest : RenderingOnlyTestBase() { private val pl1 = PlatformData("pl1", Platform.js, listOf("pl1")) private val pl2 = PlatformData("pl2", Platform.jvm, listOf("pl2")) private val pl3 = PlatformData("pl3", Platform.native, listOf("pl3")) @@ -25,7 +26,7 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>abc</div></div>")) + renderedContent.match(Div("abc")) } @Test @@ -39,7 +40,7 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>a</div> [pl1]<div>b</div> [pl2]<div>c</div> [pl3]</div>")) + renderedContent.match("[pl1]", Div("a"), "[pl2]", Div("b"), "[pl3]", Div("c")) } @Test @@ -53,7 +54,7 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>ab</div> [pl1]<div>bc</div> [pl2]</div>")) + renderedContent.match("[pl1]", Div("ab"), "[pl2]", Div("bc")) } @Test @@ -67,7 +68,7 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>ab</div></div>")) + renderedContent.match(Div("ab")) } @Test @@ -83,13 +84,13 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div><div>ab</div></div> [pl1]<div><div>a</div>b</div> [pl2]</div>")) + renderedContent.match("[pl1]", Div(Div("ab")), "[pl2]", Div(Div("a"), "b")) } @Test fun caseWithGroupNotBreakingSimplification() { val page = TestPage { - platformDependentHint(platformData = setOf(pl1, pl2), styles = setOf(TextStyle.Block)) { + platformDependentHint(platformData = setOf(pl1, pl2)) { group { text("a", platformData = setOf(pl1, pl2)) text("b", platformData = setOf(pl1)) @@ -99,7 +100,8 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>ab</div></div>")) + println(renderedContent) + renderedContent.match("ab") } @Test @@ -113,6 +115,6 @@ class PlatformDependentHintTest: RenderingOnlyTestBase() { } HtmlRenderer(context).render(page) - assert(linesAfterContentTag().contains("<div>a</div> [pl1, pl2]<div>b</div> [pl3]</div>")) + renderedContent.match("[pl1, pl2]", Div("a"), "[pl3]", Div("b")) } }
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt b/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt new file mode 100644 index 00000000..20ee7490 --- /dev/null +++ b/plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt @@ -0,0 +1,150 @@ +package transformerBuilders; + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.pages.PageNode +import org.jetbrains.dokka.pages.RendererSpecificResourcePage +import org.jetbrains.dokka.pages.RenderingStrategy +import org.jetbrains.dokka.plugability.DokkaPlugin +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.dokka.transformers.pages.PageTransformer +import org.jetbrains.dokka.transformers.pages.pageMapper +import org.jetbrains.dokka.transformers.pages.pageScanner +import org.jetbrains.dokka.transformers.pages.pageStructureTransformer +import org.junit.jupiter.api.Test + +class PageTransformerBuilderTest : AbstractCoreTest() { + + class ProxyPlugin(transformer: PageTransformer) : DokkaPlugin() { + val pageTransformer by extending { CoreExtensions.pageTransformer with transformer } + } + + @Test + fun scannerTest() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/transformerBuilder/Test.kt") + } + } + } + val list = mutableListOf<String>() + + var orig: PageNode? = null + + testInline( + """ + |/src/main/kotlin/transformerBuilder/Test.kt + |package transformerBuilder + | + |object Test { + | fun test2(str: String): Unit {println(str)} + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(ProxyPlugin(pageScanner { + list += name + })) + ) { + pagesGenerationStage = { + orig = it + } + pagesTransformationStage = { root -> + list.assertCount(7, "Page list: ") + orig?.let { root.assertTransform(it) } + } + } + } + + @Test + fun mapperTest() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/transformerBuilder/Test.kt") + } + } + } + + var orig: PageNode? = null + + testInline( + """ + |/src/main/kotlin/transformerBuilder/Test.kt + |package transformerBuilder + | + |object Test { + | fun test2(str: String): Unit {println(str)} + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(ProxyPlugin(pageMapper { + modified(name = name + "2") + })) + ) { + pagesGenerationStage = { + orig = it + } + pagesTransformationStage = { + it.let { root -> + root.name.assertEqual("root2", "Root name: ") + orig?.let { + root.assertTransform(it) { node -> node.modified(name = node.name + "2") } + } + } + } + } + } + + @Test + fun structureTransformerTest() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/main/kotlin/transformerBuilder/Test.kt") + } + } + } + + testInline( + """ + |/src/main/kotlin/transformerBuilder/Test.kt + |package transformerBuilder + | + |object Test { + | fun test2(str: String): Unit {println(str)} + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(ProxyPlugin(pageStructureTransformer { + val ch = children.first() + modified( + children = listOf( + ch, + RendererSpecificResourcePage("test", emptyList(), RenderingStrategy.DoNothing) + ) + ) + })) + ) { + pagesTransformationStage = { root -> + root.children.assertCount(2, "Root children: ") + root.children.first().name.assertEqual("transformerBuilder") + root.children[1].name.assertEqual("test") + } + } + } + + private fun <T> Collection<T>.assertCount(n: Int, prefix: String = "") = + assert(count() == n) { "${prefix}Expected $n, got ${count()}" } + + private fun <T> T.assertEqual(expected: T, prefix: String = "") = assert(this == expected) { + "${prefix}Expected $expected, got $this" + } + + private fun PageNode.assertTransform(expected: PageNode, block: (PageNode) -> PageNode = { it }): Unit = this.let { + it.name.assertEqual(block(expected).name) + it.children.zip(expected.children).forEach { (g, e) -> + g.name.assertEqual(block(e).name) + g.assertTransform(e, block) + } + } +} diff --git a/plugins/base/src/test/kotlin/utils/ModelUtils.kt b/plugins/base/src/test/kotlin/utils/ModelUtils.kt index 75c8e008..f65258b1 100644 --- a/plugins/base/src/test/kotlin/utils/ModelUtils.kt +++ b/plugins/base/src/test/kotlin/utils/ModelUtils.kt @@ -1,8 +1,8 @@ package utils -import org.jetbrains.dokka.model.Module -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.dokka.DokkaConfigurationImpl +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.plugability.DokkaPlugin abstract class AbstractModelTest(val path: String? = null, val pkg: String) : ModelDSL(), AssertDSL { @@ -11,9 +11,12 @@ abstract class AbstractModelTest(val path: String? = null, val pkg: String) : Mo platform: String = "jvm", targetList: List<String> = listOf("jvm"), prependPackage: Boolean = true, - block: Module.() -> Unit + cleanupOutput: Boolean = true, + pluginsOverrides: List<DokkaPlugin> = emptyList(), + configuration: DokkaConfigurationImpl? = null, + block: DModule.() -> Unit ) { - val configuration = dokkaConfiguration { + val testConfiguration = configuration ?: dokkaConfiguration { passes { pass { sourceRoots = listOf("src/") @@ -22,12 +25,15 @@ abstract class AbstractModelTest(val path: String? = null, val pkg: String) : Mo } } } - val prepend = path.let { p -> p?.let { "|$it\n" } ?: "" } + if(prependPackage) "|package $pkg" else "" + val prepend = path.let { p -> p?.let { "|$it\n" } ?: "" } + if (prependPackage) "|package $pkg" else "" - testInline(("$prepend\n$query").trim().trimIndent(), configuration) { + testInline( + query = ("$prepend\n$query").trim().trimIndent(), + configuration = testConfiguration, + cleanupOutput = cleanupOutput, + pluginOverrides = pluginsOverrides + ) { documentablesTransformationStage = block } } - - } diff --git a/plugins/base/src/test/kotlin/utils/TestUtils.kt b/plugins/base/src/test/kotlin/utils/TestUtils.kt index 6913ba5b..41c245e6 100644 --- a/plugins/base/src/test/kotlin/utils/TestUtils.kt +++ b/plugins/base/src/test/kotlin/utils/TestUtils.kt @@ -1,13 +1,10 @@ package utils -import org.jetbrains.dokka.model.Class -import org.jetbrains.dokka.model.Documentable -import org.jetbrains.dokka.model.Function -import org.jetbrains.dokka.model.Property +import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest -import kotlin.reflect.KClass -import kotlin.reflect.full.safeCast +import org.junit.jupiter.api.Assertions.assertTrue +import kotlin.collections.orEmpty @DslMarker annotation class TestDSL @@ -26,6 +23,10 @@ interface AssertDSL { infix fun Any?.equals(other: Any?) = this.assertEqual(other) infix fun Collection<Any>?.allEquals(other: Any?) = this?.also { c -> c.forEach { it equals other } } ?: run { assert(false) { "Collection is empty" } } + infix fun <T> Collection<T>?.exists(e: T) { + assertTrue(this.orEmpty().isNotEmpty(), "Collection cannot be null or empty") + assertTrue(this!!.any{it == e}, "Collection doesn't contain $e") + } infix fun <T> Collection<T>?.counts(n: Int) = this.orEmpty().assertCount(n) @@ -64,5 +65,15 @@ fun <T> T?.assertNotNull(name: String = ""): T = this ?: throw AssertionError("$ fun <T : Documentable> T?.docs() = this?.documentation.orEmpty().values.flatMap { it.children } -val Class.supers - get() = supertypes.flatMap{it.component2()}
\ No newline at end of file +val DClass.supers + get() = supertypes.flatMap { it.component2() } + +val Bound.name: String? + get() = when (this) { + is Nullable -> inner.name + is OtherParameter -> name + is PrimitiveJavaType -> name + is TypeConstructor -> dri.classNames + is JavaObject -> "Object" + is Void -> "void" + }
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/-search.html b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/test/out/images/arrow_down.svg b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/arrow_down.svg index 89e7df47..89e7df47 100644 --- a/plugins/base/src/test/resources/expect/test/out/images/arrow_down.svg +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/arrow_down.svg diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/test/out/images/logo-icon.svg b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/logo-icon.svg index 1b3b3670..1b3b3670 100644 --- a/plugins/base/src/test/resources/expect/test/out/images/logo-icon.svg +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/logo-icon.svg diff --git a/plugins/base/src/test/resources/expect/test/out/images/logo-text.svg b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/logo-text.svg index 7bf3e6c5..7bf3e6c5 100644 --- a/plugins/base/src/test/resources/expect/test/out/images/logo-text.svg +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/logo-text.svg diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/navigation.html b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/navigation.html new file mode 100644 index 00000000..a6a421f1 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/f.html b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/f.html new file mode 100644 index 00000000..b212ca00 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>()</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/index.html b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/index.html new file mode 100644 index 00000000..b22194f8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/test/out/scripts/scripts.js b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/scripts.js index c2e29b9f..c2e29b9f 100644 --- a/plugins/base/src/test/resources/expect/test/out/scripts/scripts.js +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/scripts.js diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/out/html/styles/style.css b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/annotatedFunction/src/annotatedFunction.kt b/plugins/base/src/test/resources/expect/annotatedFunction/src/annotatedFunction.kt new file mode 100644 index 00000000..f7abbf6c --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunction/src/annotatedFunction.kt @@ -0,0 +1,2 @@ +@Strictfp fun f() { +} diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/-search.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/navigation.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/navigation.html new file mode 100644 index 00000000..e7b7334a --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/navigation.html @@ -0,0 +1,13 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="/Fancy////"> + <div class="overview"><a href="root//-fancy/index.html">Fancy</a></div> + </div> + <div class="sideMenuPart" id="nav-submenu-0-1" pageId="//f/#//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/-init-.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/-init-.html new file mode 100644 index 00000000..54f356bf --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/-init-.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title><init></title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/<init>/#kotlin.Int//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="-init-.html"><init></a> + <h1><init></h1> +<div class="symbol monospace">final fun <a href="-init-.html"><init></a>(size: <a href="">Int</a>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/equals.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/equals.html new file mode 100644 index 00000000..3047ead0 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/equals.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>equals</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/equals/#kotlin.Any?//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="equals.html">equals</a> + <h1>equals</h1> +<div class="symbol monospace">open fun <a href="equals.html">equals</a>(other: <a href="">Any</a>): <a href="">Boolean</a></div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/hash-code.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/hash-code.html new file mode 100644 index 00000000..aae30759 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/hash-code.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>hashCode</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/hashCode/#//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="hash-code.html">hashCode</a> + <h1>hashCode</h1> +<div class="symbol monospace">open fun <a href="hash-code.html">hashCode</a>(): <a href="">Int</a></div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/index.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/index.html new file mode 100644 index 00000000..e43d5514 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/index.html @@ -0,0 +1,64 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Fancy</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy////">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a> + <h1>Fancy</h1> +<div class="symbol monospace">annotation class <a href="index.html">Fancy</a></div><br> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="equals.html">equals</a></td> + <td><div class="symbol monospace">open fun <a href="equals.html">equals</a>(other: <a href="">Any</a>): <a href="">Boolean</a></div> + <div class="brief "> </div> + </td> + </tr> + <tr> + <td><a href="hash-code.html">hashCode</a></td> + <td><div class="symbol monospace">open fun <a href="hash-code.html">hashCode</a>(): <a href="">Int</a></div> + <div class="brief "> </div> + </td> + </tr> + <tr> + <td><a href="to-string.html">toString</a></td> + <td><div class="symbol monospace">open fun <a href="to-string.html">toString</a>(): <a href="">String</a></div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + <h2>Properties</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="">size</a></td> + <td><div class="symbol monospace"><a href="">Int</a></div></td> + <td> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/to-string.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/to-string.html new file mode 100644 index 00000000..89cc4ecc --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/to-string.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>toString</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/toString/#//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="to-string.html">toString</a> + <h1>toString</h1> +<div class="symbol monospace">open fun <a href="to-string.html">toString</a>(): <a href="">String</a></div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/f.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/f.html new file mode 100644 index 00000000..b212ca00 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>()</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/index.html b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/index.html new file mode 100644 index 00000000..f485569d --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/index.html @@ -0,0 +1,50 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Types</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="-fancy/index.html">Fancy</a></td> + <td><div class="symbol monospace">annotation class <a href="-fancy/index.html">Fancy</a></div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/pages.js new file mode 100644 index 00000000..433d70a5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/pages.js @@ -0,0 +1,10 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "Fancy", "class": "Fancy", "location": "root//-fancy/index.html" }, +{ "name": "<init>", "location": "root//-fancy/-init-.html" }, +{ "name": "equals", "location": "root//-fancy/equals.html" }, +{ "name": "hashCode", "location": "root//-fancy/hash-code.html" }, +{ "name": "toString", "location": "root//-fancy/to-string.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/styles/style.css b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/src/annotatedFunctionWithAnnotationParameters.kt b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/src/annotatedFunctionWithAnnotationParameters.kt new file mode 100644 index 00000000..e559713a --- /dev/null +++ b/plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/src/annotatedFunctionWithAnnotationParameters.kt @@ -0,0 +1,7 @@ +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.SOURCE) +@MustBeDocumented +public annotation class Fancy(val size: Int) + + +@Fancy(1) fun f() {} diff --git a/plugins/base/src/test/resources/expect/function/out/html/-search.html b/plugins/base/src/test/resources/expect/function/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/function/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/function/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/function/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/function/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/function/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/function/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/function/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/function/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/test/out/navigation.html b/plugins/base/src/test/resources/expect/function/out/html/navigation.html index ebff817d..6675ec81 100644 --- a/plugins/base/src/test/resources/expect/test/out/navigation.html +++ b/plugins/base/src/test/resources/expect/function/out/html/navigation.html @@ -1,8 +1,8 @@ -<div class="sideMenuPart" id="nav-submenu"> +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> - <div class="sideMenuPart" id="nav-submenu-0"> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> - <div class="sideMenuPart" id="nav-submenu-0-0"> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//fn/#//"> <div class="overview"><a href="root//fn.html">fn</a></div> </div> </div> diff --git a/plugins/base/src/test/resources/expect/function/out/html/root/fn.html b/plugins/base/src/test/resources/expect/function/out/html/root/fn.html new file mode 100644 index 00000000..600c6f19 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/root/fn.html @@ -0,0 +1,27 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>fn</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//fn/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="fn.html">fn</a> + <h1>fn</h1> +<div class="symbol monospace">final fun <a href="fn.html">fn</a>()</div> <h3>Description</h3> +Function fn<br> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/function/out/html/root/index.html b/plugins/base/src/test/resources/expect/function/out/html/root/index.html new file mode 100644 index 00000000..8c346556 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="fn.html">fn</a></td> + <td><div class="symbol monospace">final fun <a href="fn.html">fn</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/function/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/function/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/test/out/scripts/pages.js b/plugins/base/src/test/resources/expect/function/out/html/scripts/pages.js index c0bd7a2f..c0bd7a2f 100644 --- a/plugins/base/src/test/resources/expect/test/out/scripts/pages.js +++ b/plugins/base/src/test/resources/expect/function/out/html/scripts/pages.js diff --git a/plugins/base/src/test/resources/expect/function/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/function/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/function/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/function/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/function/out/html/styles/style.css b/plugins/base/src/test/resources/expect/function/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/function/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/test/src/function.kt b/plugins/base/src/test/resources/expect/function/src/function.kt index 3ed81dfa..3ed81dfa 100644 --- a/plugins/base/src/test/resources/expect/test/src/function.kt +++ b/plugins/base/src/test/resources/expect/function/src/function.kt diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/-search.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/navigation.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/navigation.html new file mode 100644 index 00000000..247d55ca --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/navigation.html @@ -0,0 +1,13 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="/Fancy////"> + <div class="overview"><a href="root//-fancy/index.html">Fancy</a></div> + </div> + <div class="sideMenuPart" id="nav-submenu-0-1" pageId="//function/#kotlin.Function0[kotlin.Unit]//"> + <div class="overview"><a href="root//function.html">function</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/-init-.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/-init-.html new file mode 100644 index 00000000..51e4544a --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/-init-.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title><init></title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/<init>/#//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="-init-.html"><init></a> + <h1><init></h1> +<div class="symbol monospace">final fun <a href="-init-.html"><init></a>()</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/equals.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/equals.html new file mode 100644 index 00000000..3047ead0 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/equals.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>equals</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/equals/#kotlin.Any?//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="equals.html">equals</a> + <h1>equals</h1> +<div class="symbol monospace">open fun <a href="equals.html">equals</a>(other: <a href="">Any</a>): <a href="">Boolean</a></div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/hash-code.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/hash-code.html new file mode 100644 index 00000000..aae30759 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/hash-code.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>hashCode</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/hashCode/#//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="hash-code.html">hashCode</a> + <h1>hashCode</h1> +<div class="symbol monospace">open fun <a href="hash-code.html">hashCode</a>(): <a href="">Int</a></div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/index.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/index.html new file mode 100644 index 00000000..5c51a927 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/index.html @@ -0,0 +1,51 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Fancy</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy////">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a> + <h1>Fancy</h1> +<div class="symbol monospace">annotation class <a href="index.html">Fancy</a></div><br> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="equals.html">equals</a></td> + <td><div class="symbol monospace">open fun <a href="equals.html">equals</a>(other: <a href="">Any</a>): <a href="">Boolean</a></div> + <div class="brief "> </div> + </td> + </tr> + <tr> + <td><a href="hash-code.html">hashCode</a></td> + <td><div class="symbol monospace">open fun <a href="hash-code.html">hashCode</a>(): <a href="">Int</a></div> + <div class="brief "> </div> + </td> + </tr> + <tr> + <td><a href="to-string.html">toString</a></td> + <td><div class="symbol monospace">open fun <a href="to-string.html">toString</a>(): <a href="">String</a></div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/to-string.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/to-string.html new file mode 100644 index 00000000..89cc4ecc --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/to-string.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>toString</title> + <link href="../../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/Fancy/toString/#//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="to-string.html">toString</a> + <h1>toString</h1> +<div class="symbol monospace">open fun <a href="to-string.html">toString</a>(): <a href="">String</a></div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/function.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/function.html new file mode 100644 index 00000000..ad03758d --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/function.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>function</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//function/#kotlin.Function0[kotlin.Unit]//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="function.html">function</a> + <h1>function</h1> +<div class="symbol monospace">final fun <a href="function.html">function</a>(notInlined: <div class="symbol monospace">() -> <a href="">Unit</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/index.html b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/index.html new file mode 100644 index 00000000..88bff912 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/index.html @@ -0,0 +1,50 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Types</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="-fancy/index.html">Fancy</a></td> + <td><div class="symbol monospace">annotation class <a href="-fancy/index.html">Fancy</a></div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="function.html">function</a></td> + <td><div class="symbol monospace">final fun <a href="function.html">function</a>(notInlined: <div class="symbol monospace">() -> <a href="">Unit</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/pages.js new file mode 100644 index 00000000..6fe4ba6d --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/pages.js @@ -0,0 +1,10 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "Fancy", "class": "Fancy", "location": "root//-fancy/index.html" }, +{ "name": "<init>", "location": "root//-fancy/-init-.html" }, +{ "name": "equals", "location": "root//-fancy/equals.html" }, +{ "name": "hashCode", "location": "root//-fancy/hash-code.html" }, +{ "name": "toString", "location": "root//-fancy/to-string.html" }, +{ "name": "function", "location": "root//function.html" } +] diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/styles/style.css b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/src/functionWithAnnotatedParam.kt b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/src/functionWithAnnotatedParam.kt new file mode 100644 index 00000000..f858e671 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithAnnotatedParam/src/functionWithAnnotatedParam.kt @@ -0,0 +1,7 @@ +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.SOURCE) +@MustBeDocumented +public annotation class Fancy + +fun function(@Fancy notInlined: () -> Unit) { +} diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/-search.html b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/navigation.html b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/navigation.html new file mode 100644 index 00000000..27b3555e --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#kotlin.String//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/f.html b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/f.html new file mode 100644 index 00000000..d2e1ac58 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#kotlin.String//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>(x: <a href="">String</a>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/index.html b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/index.html new file mode 100644 index 00000000..18e45a19 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>(x: <a href="">String</a>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/styles/style.css b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/functionWithDefaultParameter/src/functionWithDefaultParameter.kt b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/src/functionWithDefaultParameter.kt new file mode 100644 index 00000000..3a3a102f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithDefaultParameter/src/functionWithDefaultParameter.kt @@ -0,0 +1 @@ +fun f(x: String = "") {} diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/-search.html b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/navigation.html b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/navigation.html new file mode 100644 index 00000000..66112787 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//function/#kotlin.Function0[kotlin.Unit]//"> + <div class="overview"><a href="root//function.html">function</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/function.html b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/function.html new file mode 100644 index 00000000..ad03758d --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/function.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>function</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//function/#kotlin.Function0[kotlin.Unit]//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="function.html">function</a> + <h1>function</h1> +<div class="symbol monospace">final fun <a href="function.html">function</a>(notInlined: <div class="symbol monospace">() -> <a href="">Unit</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/index.html b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/index.html new file mode 100644 index 00000000..71c9c491 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="function.html">function</a></td> + <td><div class="symbol monospace">final fun <a href="function.html">function</a>(notInlined: <div class="symbol monospace">() -> <a href="">Unit</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/pages.js new file mode 100644 index 00000000..e450fd21 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "function", "location": "root//function.html" } +] diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/styles/style.css b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/functionWithNoinlineParam/src/functionWithNoinlineParam.kt b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/src/functionWithNoinlineParam.kt new file mode 100644 index 00000000..640bec83 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNoinlineParam/src/functionWithNoinlineParam.kt @@ -0,0 +1,2 @@ +fun function(noinline notInlined: () -> Unit) { +} diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/-search.html b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/navigation.html b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/navigation.html new file mode 100644 index 00000000..a6a421f1 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/f.html b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/f.html new file mode 100644 index 00000000..b212ca00 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>()</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/index.html b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/index.html new file mode 100644 index 00000000..b22194f8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/styles/style.css b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/src/functionWithNotDocumentedAnnotation.kt b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/src/functionWithNotDocumentedAnnotation.kt new file mode 100644 index 00000000..3c7e2ff9 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/src/functionWithNotDocumentedAnnotation.kt @@ -0,0 +1,2 @@ +@Suppress("FOO") fun f() { +} diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/-search.html b/plugins/base/src/test/resources/expect/functionWithParams/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/navigation.html b/plugins/base/src/test/resources/expect/functionWithParams/out/html/navigation.html new file mode 100644 index 00000000..977f2a5f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//function/#kotlin.Int//"> + <div class="overview"><a href="root//function.html">function</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/root/function.html b/plugins/base/src/test/resources/expect/functionWithParams/out/html/root/function.html new file mode 100644 index 00000000..02a6de53 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/root/function.html @@ -0,0 +1,27 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>function</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//function/#kotlin.Int//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="function.html">function</a> + <h1>function</h1> +<div class="symbol monospace">final fun <a href="function.html">function</a>(x: <a href="">Int</a>)</div> <h3>Description</h3> +MultilineFunction Documentation<br> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/root/index.html b/plugins/base/src/test/resources/expect/functionWithParams/out/html/root/index.html new file mode 100644 index 00000000..56955a0a --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="function.html">function</a></td> + <td><div class="symbol monospace">final fun <a href="function.html">function</a>(x: <a href="">Int</a>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/pages.js new file mode 100644 index 00000000..e450fd21 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "function", "location": "root//function.html" } +] diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithParams/out/html/styles/style.css b/plugins/base/src/test/resources/expect/functionWithParams/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/functionWithParams/src/functionWithParams.kt b/plugins/base/src/test/resources/expect/functionWithParams/src/functionWithParams.kt new file mode 100644 index 00000000..85c49368 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithParams/src/functionWithParams.kt @@ -0,0 +1,8 @@ +/** + * Multiline + * + * Function + * Documentation + */ +fun function(/** parameter */ x: Int) { +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/-search.html b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/navigation.html b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/navigation.html new file mode 100644 index 00000000..3a6e4ff3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//fn/kotlin.String#//"> + <div class="overview"><a href="root//fn.html">fn</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/fn.html b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/fn.html new file mode 100644 index 00000000..af435bd4 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/fn.html @@ -0,0 +1,29 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>fn</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//fn/kotlin.String#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="fn.html">fn</a> + <h1>fn</h1> +<div class="symbol monospace">final fun <a href="">String</a>.<a href="fn.html">fn</a>()</div> <h3>Description</h3> +Function with receiver<br> <h1>fn</h1> +<div class="symbol monospace">final fun <a href="">String</a>.<a href="fn.html">fn</a>(x: <a href="">Int</a>)</div> <h3>Description</h3> +Function with receiver<br> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/index.html b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/index.html new file mode 100644 index 00000000..ed7c004e --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/index.html @@ -0,0 +1,44 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="fn.html">fn</a></td> + <td><div class="symbol monospace">final fun <a href="">String</a>.<a href="fn.html">fn</a>()</div> + <div class="brief "> </div> + </td> + </tr> + <tr> + <td><a href="fn.html">fn</a></td> + <td><div class="symbol monospace">final fun <a href="">String</a>.<a href="fn.html">fn</a>(x: <a href="">Int</a>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/pages.js new file mode 100644 index 00000000..c0bd7a2f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "fn", "location": "root//fn.html" } +] diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/styles/style.css b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/functionWithReceiver/src/functionWithReceiver.kt b/plugins/base/src/test/resources/expect/functionWithReceiver/src/functionWithReceiver.kt new file mode 100644 index 00000000..c8473251 --- /dev/null +++ b/plugins/base/src/test/resources/expect/functionWithReceiver/src/functionWithReceiver.kt @@ -0,0 +1,11 @@ +/** + * Function with receiver + */ +fun String.fn() { +} + +/** + * Function with receiver + */ +fun String.fn(x: Int) { +} diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/-search.html b/plugins/base/src/test/resources/expect/genericFunction/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/navigation.html b/plugins/base/src/test/resources/expect/genericFunction/out/html/navigation.html new file mode 100644 index 00000000..e363cdda --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//generic/#//"> + <div class="overview"><a href="root//generic.html">generic</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/root/generic.html b/plugins/base/src/test/resources/expect/genericFunction/out/html/root/generic.html new file mode 100644 index 00000000..a86d6f4e --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/root/generic.html @@ -0,0 +1,27 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>generic</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//generic/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="generic.html">generic</a> + <h1>generic</h1> +<div class="symbol monospace">private final fun <<a href="generic.html">T</a> : <a href="">Any</a>> <a href="generic.html">generic</a>()</div> <h3>Description</h3> +generic function<br> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/root/index.html b/plugins/base/src/test/resources/expect/genericFunction/out/html/root/index.html new file mode 100644 index 00000000..eb0ac0fc --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="generic.html">generic</a></td> + <td><div class="symbol monospace">private final fun <<a href="generic.html">T</a> : <a href="">Any</a>> <a href="generic.html">generic</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/pages.js new file mode 100644 index 00000000..0a6d445a --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "generic", "location": "root//generic.html" } +] diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunction/out/html/styles/style.css b/plugins/base/src/test/resources/expect/genericFunction/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/genericFunction/src/genericFunction.kt b/plugins/base/src/test/resources/expect/genericFunction/src/genericFunction.kt new file mode 100644 index 00000000..05a65070 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunction/src/genericFunction.kt @@ -0,0 +1,5 @@ + +/** + * generic function + */ +private fun <T> generic() {}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/-search.html b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/navigation.html b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/navigation.html new file mode 100644 index 00000000..e363cdda --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//generic/#//"> + <div class="overview"><a href="root//generic.html">generic</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/generic.html b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/generic.html new file mode 100644 index 00000000..c9e8ad17 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/generic.html @@ -0,0 +1,27 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>generic</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//generic/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="generic.html">generic</a> + <h1>generic</h1> +<div class="symbol monospace">final fun <<a href="generic.html">T</a> : R, <a href="generic.html">R</a> : <a href="">Any</a>> <a href="generic.html">generic</a>()</div> <h3>Description</h3> +generic function<br> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/index.html b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/index.html new file mode 100644 index 00000000..4b702383 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="generic.html">generic</a></td> + <td><div class="symbol monospace">final fun <<a href="generic.html">T</a> : R, <a href="generic.html">R</a> : <a href="">Any</a>> <a href="generic.html">generic</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/pages.js new file mode 100644 index 00000000..0a6d445a --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "generic", "location": "root//generic.html" } +] diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/styles/style.css b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/src/genericFunctionWithConstraints.kt b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/src/genericFunctionWithConstraints.kt new file mode 100644 index 00000000..5f22f8c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/genericFunctionWithConstraints/src/genericFunctionWithConstraints.kt @@ -0,0 +1,6 @@ + +/** + * generic function + */ +public fun <T : R, R> generic() { +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/-search.html b/plugins/base/src/test/resources/expect/inlineFunction/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/navigation.html b/plugins/base/src/test/resources/expect/inlineFunction/out/html/navigation.html new file mode 100644 index 00000000..7ec4828b --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#kotlin.Function0[kotlin.String]//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/root/f.html b/plugins/base/src/test/resources/expect/inlineFunction/out/html/root/f.html new file mode 100644 index 00000000..8a7bf1dc --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#kotlin.Function0[kotlin.String]//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>(a: <div class="symbol monospace">() -> <a href="">String</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/root/index.html b/plugins/base/src/test/resources/expect/inlineFunction/out/html/root/index.html new file mode 100644 index 00000000..97dfd476 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>(a: <div class="symbol monospace">() -> <a href="">String</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineFunction/out/html/styles/style.css b/plugins/base/src/test/resources/expect/inlineFunction/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/inlineFunction/src/inlineFunction.kt b/plugins/base/src/test/resources/expect/inlineFunction/src/inlineFunction.kt new file mode 100644 index 00000000..64a617a4 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineFunction/src/inlineFunction.kt @@ -0,0 +1,2 @@ +inline fun f(a: () -> String) { +} diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/-search.html b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/navigation.html b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/navigation.html new file mode 100644 index 00000000..7ec4828b --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#kotlin.Function0[kotlin.String]//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/f.html b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/f.html new file mode 100644 index 00000000..8a7bf1dc --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#kotlin.Function0[kotlin.String]//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>(a: <div class="symbol monospace">() -> <a href="">String</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/index.html b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/index.html new file mode 100644 index 00000000..97dfd476 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>(a: <div class="symbol monospace">() -> <a href="">String</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/styles/style.css b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/inlineSuspendFunction/src/inlineSuspendFunction.kt b/plugins/base/src/test/resources/expect/inlineSuspendFunction/src/inlineSuspendFunction.kt new file mode 100644 index 00000000..5f376267 --- /dev/null +++ b/plugins/base/src/test/resources/expect/inlineSuspendFunction/src/inlineSuspendFunction.kt @@ -0,0 +1,2 @@ +inline suspend fun f(a: () -> String) { +} diff --git a/plugins/base/src/test/resources/expect/test/out/-search.html b/plugins/base/src/test/resources/expect/signatureTest/out/-search.html index 1ee812bb..1ee812bb 100644 --- a/plugins/base/src/test/resources/expect/test/out/-search.html +++ b/plugins/base/src/test/resources/expect/signatureTest/out/-search.html diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/-search.html b/plugins/base/src/test/resources/expect/signatureTest/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/navigation.html b/plugins/base/src/test/resources/expect/signatureTest/out/html/navigation.html new file mode 100644 index 00000000..f7cf0041 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/navigation.html @@ -0,0 +1,13 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="signatureTest/////"> + <div class="overview"><a href="root/signatureTest/index.html">signatureTest</a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="signatureTest//test/#kotlin.Function1[kotlin.Int,kotlin.Int]//"> + <div class="overview"><a href="root/signatureTest/test.html">test</a></div> + </div> + <div class="sideMenuPart" id="nav-submenu-0-1" pageId="signatureTest//test2/#kotlin.Function2[kotlin.Int,kotlin.Int,kotlin.Int]//"> + <div class="overview"><a href="root/signatureTest/test2.html">test2</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/root/index.html b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/index.html new file mode 100644 index 00000000..336c1700 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/index.html @@ -0,0 +1,35 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>root</title> + <link href="../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="index.html">root</a> + <h1>root</h1> + <h2>Packages</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="signatureTest/index.html">signatureTest</a></td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/index.html b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/index.html new file mode 100644 index 00000000..851f13f0 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/index.html @@ -0,0 +1,44 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>signatureTest</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="signatureTest/////">//<a href="../index.html">root</a>/<a href="index.html">signatureTest</a> + <h1>Package signatureTest</h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="test.html">test</a></td> + <td><div class="symbol monospace">final fun <a href="test.html">test</a>(i: <div class="symbol monospace">(<a href="">Int</a>) -> <a href="">Int</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + <tr> + <td><a href="test2.html">test2</a></td> + <td><div class="symbol monospace">final fun <a href="test2.html">test2</a>(i: <div class="symbol monospace"><a href="">Int</a>.(<a href="">Int</a>) -> <a href="">Int</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test.html b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test.html new file mode 100644 index 00000000..353c5232 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>test</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="signatureTest//test/#kotlin.Function1[kotlin.Int,kotlin.Int]//">//<a href="../index.html">root</a>/<a href="index.html">signatureTest</a>/<a href="test.html">test</a> + <h1>test</h1> +<div class="symbol monospace">final fun <a href="test.html">test</a>(i: <div class="symbol monospace">(<a href="">Int</a>) -> <a href="">Int</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test2.html b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test2.html new file mode 100644 index 00000000..0b8c6dd4 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test2.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>test2</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="signatureTest//test2/#kotlin.Function2[kotlin.Int,kotlin.Int,kotlin.Int]//">//<a href="../index.html">root</a>/<a href="index.html">signatureTest</a>/<a href="test2.html">test2</a> + <h1>test2</h1> +<div class="symbol monospace">final fun <a href="test2.html">test2</a>(i: <div class="symbol monospace"><a href="">Int</a>.(<a href="">Int</a>) -> <a href="">Int</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/pages.js new file mode 100644 index 00000000..7c74ea83 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/pages.js @@ -0,0 +1,6 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "signatureTest", "location": "root/signatureTest/index.html" }, +{ "name": "test", "location": "root/signatureTest/test.html" }, +{ "name": "test2", "location": "root/signatureTest/test2.html" } +] diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/html/styles/style.css b/plugins/base/src/test/resources/expect/signatureTest/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/images/arrow_down.svg b/plugins/base/src/test/resources/expect/signatureTest/out/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/images/logo-icon.svg b/plugins/base/src/test/resources/expect/signatureTest/out/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/images/logo-text.svg b/plugins/base/src/test/resources/expect/signatureTest/out/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/navigation.html b/plugins/base/src/test/resources/expect/signatureTest/out/navigation.html new file mode 100644 index 00000000..da6b4b0a --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/navigation.html @@ -0,0 +1,13 @@ +<div class="sideMenuPart" id="nav-submenu"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0"> + <div class="overview"><a href="root/signatureTest/index.html">signatureTest</a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0"> + <div class="overview"><a href="root/signatureTest/test.html">test</a></div> + </div> + <div class="sideMenuPart" id="nav-submenu-0-1"> + <div class="overview"><a href="root/signatureTest/test2.html">test2</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/root/index.html b/plugins/base/src/test/resources/expect/signatureTest/out/root/index.html new file mode 100644 index 00000000..9b5327ec --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/root/index.html @@ -0,0 +1,30 @@ +<html> + <head> + <title>root</title> + <link href="../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../";</script> + </head> + <body> + <div id="navigation"> + <div id="searchBar"> + <form action="../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="sideMenu"></div> + </div> + <div id="content">//<a href="index.html">root</a> + <h1>root</h1> + <h2>Packages</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="signatureTest/index.html">signatureTest</a></td> + </tr> + </tbody> + </table> +Index +Link to allpage here</div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/index.html b/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/index.html new file mode 100644 index 00000000..fbee923b --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/index.html @@ -0,0 +1,36 @@ +<html> + <head> + <title>signatureTest</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="navigation"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="sideMenu"></div> + </div> + <div id="content">//<a href="../index.html">root</a>/<a href="index.html">signatureTest</a> + <h1>Package signatureTest</h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="test.html">test</a></td> + <td>final fun <a href="test.html">test</a>(<a href="">i</a>: (<a href="">Int</a>) -> <a href="">Int</a>)</td> + <td></td> + </tr> + <tr> + <td><a href="test2.html">test2</a></td> + <td>final fun <a href="test2.html">test2</a>(<a href="">i</a>: <a href="">Int</a>.(<a href="">Int</a>) -> <a href="">Int</a>)</td> + <td></td> + </tr> + </tbody> + </table> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/test/out/root/index.html b/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/test.html index 25c65b11..fe15c2c5 100644 --- a/plugins/base/src/test/resources/expect/test/out/root/index.html +++ b/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/test.html @@ -1,6 +1,6 @@ <html> <head> - <title></title> + <title>test</title> <link href="../../styles/style.css" rel="Stylesheet"> <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> <script>var pathToRoot = "../../";</script> @@ -12,16 +12,15 @@ </div> <div id="sideMenu"></div> </div> - <div id="content">//<a href="../index.html">root</a>/<a href="index.html"></a> - <h1>Package </h1> - <h2>Functions</h2> + <div id="content">//<a href="../index.html">root</a>/<a href="index.html">signatureTest</a>/<a href="test.html">test</a> + <h1>test</h1> +final fun <a href="test.html">test</a>(<a href="">i</a>: (<a href="">Int</a>) -> <a href="">Int</a>) + <h2>Parameters</h2> <table> <thead></thead> <tbody> <tr> - <td><a href="fn.html">fn</a></td> - <td>final fun <a href="fn.html">fn</a>()</td> - <td>Function fn</td> + <td>i</td> </tr> </tbody> </table> diff --git a/plugins/base/src/test/resources/expect/test/out/root/fn.html b/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/test2.html index e87d7bc4..58dbaf39 100644 --- a/plugins/base/src/test/resources/expect/test/out/root/fn.html +++ b/plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/test2.html @@ -1,6 +1,6 @@ <html> <head> - <title>fn</title> + <title>test2</title> <link href="../../styles/style.css" rel="Stylesheet"> <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> <script>var pathToRoot = "../../";</script> @@ -12,12 +12,19 @@ </div> <div id="sideMenu"></div> </div> - <div id="content">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="fn.html">fn</a> - <h1>fn</h1> -final fun <a href="fn.html">fn</a>() - <h3>Description</h3> -Function fn -</div> + <div id="content">//<a href="../index.html">root</a>/<a href="index.html">signatureTest</a>/<a href="test2.html">test2</a> + <h1>test2</h1> +final fun <a href="test2.html">test2</a>(<a href="">i</a>: <a href="">Int</a>.(<a href="">Int</a>) -> <a href="">Int</a>) + <h2>Parameters</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td>i</td> + </tr> + </tbody> + </table> + </div> </body> </html> diff --git a/plugins/base/src/test/resources/expect/signatureTest/src/signature.kt b/plugins/base/src/test/resources/expect/signatureTest/src/signature.kt new file mode 100644 index 00000000..48e56c47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/signatureTest/src/signature.kt @@ -0,0 +1,4 @@ +package signatureTest + +fun test(i: (Int) -> Int) {} +fun test2(i: Int.(Int) -> Int) {}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/-search.html b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/navigation.html b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/navigation.html new file mode 100644 index 00000000..176e51b8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//availableSince1.1/#//"> + <div class="overview"><a href="root//available-since1.1.html">availableSince1.1</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/available-since1.1.html b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/available-since1.1.html new file mode 100644 index 00000000..7264fbf4 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/available-since1.1.html @@ -0,0 +1,27 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>availableSince1.1</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//availableSince1.1/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="available-since1.1.html">availableSince1.1</a> + <h1>availableSince1.1</h1> +<div class="symbol monospace">final fun <a href="available-since1.1.html">availableSince1.1</a>(): <a href="">String</a></div> <h3>Description</h3> +Quite useful <a href="">String</a><br> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/index.html b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/index.html new file mode 100644 index 00000000..c54e53a5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="available-since1.1.html">availableSince1.1</a></td> + <td><div class="symbol monospace">final fun <a href="available-since1.1.html">availableSince1.1</a>(): <a href="">String</a></div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/pages.js new file mode 100644 index 00000000..76b18c22 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "availableSince1.1", "location": "root//available-since1.1.html" } +] diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/out/html/styles/style.css b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/sinceKotlin/src/sinceKotlin.kt b/plugins/base/src/test/resources/expect/sinceKotlin/src/sinceKotlin.kt new file mode 100644 index 00000000..cdcd3357 --- /dev/null +++ b/plugins/base/src/test/resources/expect/sinceKotlin/src/sinceKotlin.kt @@ -0,0 +1,5 @@ +/** + * Quite useful [String] + */ +@SinceKotlin("1.1") +fun `availableSince1.1`(): String = "1.1 rulezz"
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/-search.html b/plugins/base/src/test/resources/expect/suspendFunction/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/navigation.html b/plugins/base/src/test/resources/expect/suspendFunction/out/html/navigation.html new file mode 100644 index 00000000..a6a421f1 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/root/f.html b/plugins/base/src/test/resources/expect/suspendFunction/out/html/root/f.html new file mode 100644 index 00000000..b212ca00 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>()</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/root/index.html b/plugins/base/src/test/resources/expect/suspendFunction/out/html/root/index.html new file mode 100644 index 00000000..b22194f8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>()</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendFunction/out/html/styles/style.css b/plugins/base/src/test/resources/expect/suspendFunction/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/suspendFunction/src/suspendFunction.kt b/plugins/base/src/test/resources/expect/suspendFunction/src/suspendFunction.kt new file mode 100644 index 00000000..49ecca2a --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendFunction/src/suspendFunction.kt @@ -0,0 +1,2 @@ +suspend fun f() { +} diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/-search.html b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/-search.html new file mode 100644 index 00000000..f32a089f --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/-search.html @@ -0,0 +1,28 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Search</title> + <link href="styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="scripts/pages.js" async="async"></script> + <script type="text/javascript" src="scripts/search.js" async="async"></script> + <script>var pathToRoot = "";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <h1 id="searchTitle">Search results for </h1> + <table> + <tbody id="searchTable"></tbody> + </table> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/arrow_down.svg b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/arrow_down.svg new file mode 100644 index 00000000..89e7df47 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/arrow_down.svg @@ -0,0 +1,3 @@ +<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M9.71824 1.66658L9.01113 0.959473L5.00497 4.96447L1.00008 0.959473L0.292969 1.66658L5.01113 6.38474L9.71824 1.66658Z" fill="#A1AAB4"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/docs_logo.svg b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/docs_logo.svg new file mode 100644 index 00000000..7c1e3ae8 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/docs_logo.svg @@ -0,0 +1,7 @@ +<svg width="125" height="27" viewBox="0 0 125 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M89.1611 7.6297V25.6345V25.6867H103.843V21.8039H93.3589V10.3852H103.843V6.50244H89.1611V7.6297Z" fill="#27282C"/> +<path d="M124.989 21.8039L114.778 10.3852H124.905V6.50244H109.059V10.3852L119.459 21.8039H109.059V25.6867H125V21.8039H124.989Z" fill="#27282C"/> +<path d="M58.2978 7.76556C56.5872 6.46086 54.4463 5.67804 52.1271 5.67804C46.5336 5.67804 42 10.1871 42 15.7503C42 21.3135 46.5336 25.8226 52.1271 25.8226C54.4463 25.8226 56.5872 25.0502 58.2978 23.735V25.7182H62.4955V0H58.2978V7.76556ZM52.1271 21.8041C48.7584 21.8041 46.0298 19.0903 46.0298 15.7399C46.0298 12.3894 48.7584 9.67563 52.1271 9.67563C55.4958 9.67563 58.2243 12.3894 58.2243 15.7399C58.2138 19.0903 55.4853 21.8041 52.1271 21.8041Z" fill="#27282C"/> +<path d="M75.9698 5.8656C70.3763 5.8656 65.8428 10.3746 65.8428 15.9379C65.8428 21.5011 70.3763 26.0101 75.9698 26.0101C81.5633 26.0101 86.0969 21.5011 86.0969 15.9379C86.0969 10.3746 81.5633 5.8656 75.9698 5.8656ZM75.9698 21.9916C72.6012 21.9916 69.8726 19.2779 69.8726 15.9274C69.8726 12.577 72.6012 9.86319 75.9698 9.86319C79.3385 9.86319 82.0671 12.577 82.0671 15.9274C82.0671 19.2779 79.3385 21.9916 75.9698 21.9916Z" fill="#27282C"/> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-icon.svg b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-icon.svg new file mode 100644 index 00000000..1b3b3670 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-icon.svg @@ -0,0 +1,3 @@ +<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M26 26H0V0H26L12.9243 12.9747L26 26Z" fill="#F8873C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-text.svg b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-text.svg new file mode 100644 index 00000000..7bf3e6c5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-text.svg @@ -0,0 +1,6 @@ +<svg width="83" height="27" viewBox="0 0 83 27" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M47.1611 7.6297V25.6345V25.6867H61.8428V21.8039H51.3589V10.3852H61.8428V6.50244H47.1611V7.6297Z" fill="#27282C"/> +<path d="M82.9891 21.8039L72.778 10.3852H82.9051V6.50244H67.0586V10.3852L77.4585 21.8039H67.0586V25.6867H82.9996V21.8039H82.9891Z" fill="#27282C"/> +<path d="M16.2978 7.76556C14.5872 6.46086 12.4463 5.67804 10.1271 5.67804C4.53357 5.67804 0 10.1871 0 15.7503C0 21.3135 4.53357 25.8226 10.1271 25.8226C12.4463 25.8226 14.5872 25.0502 16.2978 23.735V25.7182H20.4955V0H16.2978V7.76556ZM10.1271 21.8041C6.75838 21.8041 4.02984 19.0903 4.02984 15.7399C4.02984 12.3894 6.75838 9.67563 10.1271 9.67563C13.4958 9.67563 16.2243 12.3894 16.2243 15.7399C16.2138 19.0903 13.4853 21.8041 10.1271 21.8041Z" fill="#27282C"/> +<path d="M33.9703 5.86566C28.3768 5.86566 23.8433 10.3747 23.8433 15.9379C23.8433 21.5011 28.3768 26.0102 33.9703 26.0102C39.5638 26.0102 44.0974 21.5011 44.0974 15.9379C44.0974 10.3747 39.5638 5.86566 33.9703 5.86566ZM33.9703 21.9917C30.6016 21.9917 27.8731 19.2779 27.8731 15.9275C27.8731 12.577 30.6016 9.86325 33.9703 9.86325C37.339 9.86325 40.0676 12.577 40.0676 15.9275C40.0676 19.2779 37.339 21.9917 33.9703 21.9917Z" fill="#27282C"/> +</svg> diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/navigation.html b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/navigation.html new file mode 100644 index 00000000..7ec4828b --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/navigation.html @@ -0,0 +1,10 @@ +<div class="sideMenuPart" id="nav-submenu" pageId="/////"> + <div class="overview"><a href="root/index.html">root</a><span class="navButton" onclick="document.getElementById("nav-submenu").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0" pageId="/////"> + <div class="overview"><a href="root//index.html"></a><span class="navButton" onclick="document.getElementById("nav-submenu-0").classList.toggle("hidden");"><span class="navButtonContent"></span></span></div> + <div class="sideMenuPart" id="nav-submenu-0-0" pageId="//f/#kotlin.Function0[kotlin.String]//"> + <div class="overview"><a href="root//f.html">f</a></div> + </div> + </div> +</div> + diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/f.html b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/f.html new file mode 100644 index 00000000..8a7bf1dc --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/f.html @@ -0,0 +1,26 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>f</title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="//f/#kotlin.Function0[kotlin.String]//">//<a href="../index.html">root</a>/<a href="index.html"></a>/<a href="f.html">f</a> + <h1>f</h1> +<div class="symbol monospace">final fun <a href="f.html">f</a>(a: <div class="symbol monospace">() -> <a href="">String</a></div>)</div> </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/index.html b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/index.html new file mode 100644 index 00000000..97dfd476 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/index.html @@ -0,0 +1,38 @@ +<html> + <head> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link href="../../styles/style.css" rel="Stylesheet"> + <script type="text/javascript" src="../../scripts/navigationLoader.js" async="async"></script> + <script>var pathToRoot = "../../";</script> + </head> + <body> + <div id="container"> + <div id="leftColumn"> + <div id="logo"></div> + <div id="sideMenu"></div> + </div> + <div id="main"> + <div id="searchBar"> + <form action="../../-search.html" method="get" id="searchForm"><input type="search" name="query"><input type="submit" value="Search"></form> + </div> + <div id="content" pageIds="/////">//<a href="../index.html">root</a>/<a href="index.html"></a> + <h1>Package </h1> + <h2>Functions</h2> + <table> + <thead></thead> + <tbody> + <tr> + <td><a href="f.html">f</a></td> + <td><div class="symbol monospace">final fun <a href="f.html">f</a>(a: <div class="symbol monospace">() -> <a href="">String</a></div>)</div> + <div class="brief "> </div> + </td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + </body> +</html> + diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/navigationLoader.js new file mode 100644 index 00000000..5fe52ade --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/navigationLoader.js @@ -0,0 +1,41 @@ +onload = () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .then(data => { + document.getElementById("sideMenu").innerHTML = data; + }).then(() => { + document.querySelectorAll(".overview > a").forEach(link => { + link.setAttribute("href", pathToRoot + link.getAttribute("href")); + console.log(link.attributes["href"]) + }) + }).then(() => { + document.querySelectorAll(".sideMenuPart").forEach(nav => { + if (!nav.classList.contains("hidden")) nav.classList.add("hidden") + }) + }).then(() => { + revealNavigationForCurrentPage() + }) +}; + +revealNavigationForCurrentPage = () => { + let pageId = document.getElementById("content").attributes["pageIds"].value.toString(); + let parts = document.querySelectorAll(".sideMenuPart"); + let found = 0; + do { + parts.forEach(part => { + if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) { + found = 1; + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part) + } + }); + pageId = pageId.substring(0, pageId.lastIndexOf("/")) + } while (pageId.indexOf("/") !== -1 && found === 0) +}; + +revealParents = (part) => { + if (part.classList.contains("sideMenuPart")) { + if (part.classList.contains("hidden")) part.classList.remove("hidden"); + revealParents(part.parentNode) + } +};
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/pages.js b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/pages.js new file mode 100644 index 00000000..81ed5cc3 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/pages.js @@ -0,0 +1,5 @@ +var pages = [ +{ "name": "root", "location": "root/index.html" }, +{ "name": "", "location": "root//index.html" }, +{ "name": "f", "location": "root//f.html" } +] diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/scripts.js b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/scripts.js new file mode 100644 index 00000000..c2e29b9f --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/scripts.js @@ -0,0 +1,11 @@ +document.getElementById("navigationFilter").oninput = function (e) { + var input = e.target.value; + var menuParts = document.getElementsByClassName("sideMenuPart") + for (let part of menuParts) { + if(part.querySelector("a").textContent.startsWith(input)) { + part.classList.remove("filtered"); + } else { + part.classList.add("filtered"); + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/search.js b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/search.js new file mode 100644 index 00000000..04d88ab5 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/search.js @@ -0,0 +1,7 @@ +let query = new URLSearchParams(window.location.search).get("query"); +document.getElementById("searchTitle").innerHTML += '"' + query + '":'; +document.getElementById("searchTable").innerHTML = pages + .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) + .reduce((acc, element) => { + return acc + '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' + }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/styles/style.css b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/styles/style.css new file mode 100644 index 00000000..063a9502 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/styles/style.css @@ -0,0 +1,417 @@ +@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); + + +#container { + display: flex; + flex-direction: row; + min-height: 100%; +} + +#main { + width: 100%; + padding-left: 12px; +} + +#leftColumn { + padding-left: 12px; + min-height: 100%; + border-right: 2px solid #DADFE6; +} + +@media screen and (max-width: 600px) { + #container { + flex-direction: column; + } + + #leftColumn { + border-right: none; + } +} + +#sideMenu { + padding-top: 12px; + padding-right: 12px; +} + +#sideMenu .sideMenuPart { + padding-left: 1em; +} + +#sideMenu img { + margin: 1em 0.25em; +} + +#sideMenu hr { + background: #DADFE6; +} + +#searchBar { + width: 100%; + pointer-events: none; +} + +#searchForm { + float: right; + pointer-events: all; +} + +#logo { + padding: 5px; + background-size: 55% 90%; + border-bottom: 2px solid #DADFE6; + background-repeat: no-repeat; + background-image: url(../images/docs_logo.svg); + height: 6vh; +} + +.monospace, +.code { + font-family: monospace; +} + +.strikethrough { + text-decoration: line-through; +} + +.symbol { + padding: 5px; + background-color: #F4F4F4; +} + +.sideMenuPart > .overview { + width: 100%; + display: inline-flex; +} + +.overview > .navButton { + width: 100%; + display: inline-flex; + justify-content: flex-end; +} + +.sideMenuPart > .overview:hover { + background-color: rgba(91, 93, 239, 0.15); +} + +.sideMenuPart .hidden > .overview .navButtonContent::before { + transform: rotate(0deg); +} + +.sideMenuPart > .overview .navButtonContent::before { + content: url("../images/arrow_down.svg"); + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + transform: rotate(180deg); +} + +.sideMenuPart.hidden > .navButton .navButtonContent::after { + content: '\02192'; +} + +.sideMenuPart.hidden > .sideMenuPart { + height: 0; + visibility: hidden; +} + +.filtered > a, .filtered > .navButton { + display: none; +} + +body, table { + font: 14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; + background: #F4F4F4; + font-weight: 300; + margin-right: auto; + max-width: 1440px; +} + +table { + width: 100%; + border-collapse: collapse; + background-color: #ffffff; + padding: 5px; +} + +tbody > tr { + border-bottom: 2px solid #F4F4F4; +} + +td:first-child { + width: 20vw; +} + +.keyword { + color: black; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.symbol { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + font-size: 12px; +} + +.identifier { + color: darkblue; + font-size: 12px; + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; +} + +.brief { + width: 40vw; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +h1, h2, h3, h4, h5, h6 { + color: #222; +} + +p, ul, ol, table, pre, dl { + margin: 0 0 20px; +} + +h1, h2, h3 { + line-height: 1.1; +} + +h1 { + font-size: 28px; +} + +h2 { + color: #393939; +} + +h3, h4, h5, h6 { + color: #494949; +} + +a { + color: #258aaf; + font-weight: 400; + text-decoration: none; +} + +a:hover { + color: inherit; + text-decoration: underline; +} + +a small { + font-size: 11px; + color: #555; + margin-top: -0.6em; + display: block; +} + +.wrapper { + width: 860px; + margin: 0 auto; +} + +blockquote { + border-left: 1px solid #e5e5e5; + margin: 0; + padding: 0 0 0 20px; + font-style: italic; +} + +code, pre { + font-family: Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color: #333; + font-size: 12px; +} + +pre { + display: block; + /* + padding:8px 8px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + */ + overflow-x: auto; +} + +th, td { + text-align: left; + vertical-align: top; + padding: 5px 10px; +} + +dt { + color: #444; + font-weight: 700; +} + +th { + color: #444; +} + +img { + max-width: 100%; +} + +header { + width: 270px; + float: left; + position: fixed; +} + +header ul { + list-style: none; + height: 40px; + + padding: 0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f8f8f8), color-stop(100%, #dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + + border-radius: 5px; + border: 1px solid #d2d2d2; + box-shadow: inset #fff 0 1px 0, inset rgba(0, 0, 0, 0.03) 0 -1px 0; + width: 270px; +} + +header li { + width: 89px; + float: left; + border-right: 1px solid #d2d2d2; + height: 40px; +} + +header ul a { + line-height: 1; + font-size: 11px; + color: #999; + display: block; + text-align: center; + padding-top: 6px; + height: 40px; +} + +strong { + color: #222; + font-weight: 700; +} + +header ul li + li { + width: 88px; + border-left: 1px solid #fff; +} + +header ul li + li + li { + border-right: none; + width: 89px; +} + +header ul a strong { + font-size: 14px; + display: block; + color: #222; +} + +section { + width: 500px; + float: right; + padding-bottom: 50px; +} + +small { + font-size: 11px; +} + +hr { + border: 0; + background: #e5e5e5; + height: 1px; + margin: 0 0 20px; +} + +footer { + width: 270px; + float: left; + position: fixed; + bottom: 50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width: auto; + margin: 0; + } + + header, section, footer { + float: none; + position: static; + width: auto; + } + + header { + padding-right: 320px; + } + + section { + border: 1px solid #e5e5e5; + border-width: 1px 0; + padding: 20px 0; + margin: 0 0 20px; + } + + header a small { + display: inline; + } + + header ul { + position: absolute; + right: 50px; + top: 52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap: break-word; + } + + header { + padding: 0; + } + + header ul, header p.view { + position: static; + } + + pre, code { + word-wrap: normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding: 15px; + } + + header ul { + display: none; + } +} + +@media print { + body { + padding: 0.4in; + font-size: 12pt; + color: #444; + } +} diff --git a/plugins/base/src/test/resources/expect/suspendInlineFunction/src/suspendInlineFunction.kt b/plugins/base/src/test/resources/expect/suspendInlineFunction/src/suspendInlineFunction.kt new file mode 100644 index 00000000..54f65658 --- /dev/null +++ b/plugins/base/src/test/resources/expect/suspendInlineFunction/src/suspendInlineFunction.kt @@ -0,0 +1,2 @@ +suspend inline fun f(a: () -> String) { +} diff --git a/plugins/base/src/test/resources/expect/test/out/scripts/navigationLoader.js b/plugins/base/src/test/resources/expect/test/out/scripts/navigationLoader.js deleted file mode 100644 index 99a885a9..00000000 --- a/plugins/base/src/test/resources/expect/test/out/scripts/navigationLoader.js +++ /dev/null @@ -1,12 +0,0 @@ -onload = () => { - fetch(pathToRoot + "navigation.html") - .then(response => response.text()) - .then(data => { - document.getElementById("sideMenu").innerHTML = data; - }).then(() => { - document.querySelectorAll(".overview > a").forEach(link => { - link.setAttribute("href", pathToRoot + link.getAttribute("href")) - console.log(link.attributes["href"]) - }) - }) -}
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/test/out/scripts/search.js b/plugins/base/src/test/resources/expect/test/out/scripts/search.js deleted file mode 100644 index 63112ac5..00000000 --- a/plugins/base/src/test/resources/expect/test/out/scripts/search.js +++ /dev/null @@ -1,5 +0,0 @@ -var query = new URLSearchParams(window.location.search).get("query"); - document.getElementById("searchTitle").innerHTML += '"' + query + '":'; - document.getElementById("searchTable").innerHTML = pages.filter(el => el.name.startsWith(query)).reduce((acc, element) => { return acc + - '<tr><td><a href="' + element.location + '">' + element.name + '</a></td></tr>' - }, "");
\ No newline at end of file diff --git a/plugins/base/src/test/resources/expect/test/out/styles/style.css b/plugins/base/src/test/resources/expect/test/out/styles/style.css deleted file mode 100644 index 4a76dd96..00000000 --- a/plugins/base/src/test/resources/expect/test/out/styles/style.css +++ /dev/null @@ -1,353 +0,0 @@ -@import url(https://fonts.googleapis.com/css?family=Open+Sans:300i,400,700); - - -#content { - margin-top: 3em; - margin-left: 15em; -} - -#navigation { - position: relative -} - -#sideMenu, #searchBar { - position: absolute; -} - -#sideMenu { - width: 14em; - padding-left: 0.5em; -} - -#sideMenu .sideMenuPart { - margin-left: 1em; -} - -#sideMenu img { - margin: 1em 0.25em; -} - -#sideMenu hr { - background: #DADFE6; -} - -#searchBar { - width: 100%; - pointer-events: none; -} - -#searchForm { - float: right; - pointer-events: all; -} - -.sideMenuPart > .navButton { - margin-left:0.25em -} - -.sideMenuPart > .overview .navButtonContent::after { - float: right; - content: url("../images/arrow_down.svg"); -} - -.sideMenuPart.hidden > .navButton .navButtonContent::after { - content: '\02192'; -} - -.sideMenuPart.hidden > .sideMenuPart { - display: none; -} - -.filtered > a, .filtered > .navButton { - display: none; -} - -body, table{ - font:14px/1.5 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; - background: #F4F4F4; - font-weight:300; - margin-left: auto; - margin-right: auto; - max-width: 1440px; -} - -table { - display: flex; - padding:5px; -} - -td:first-child { - width: 20vw; -} - -.keyword { - color:black; - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; - font-size:12px; -} - -.symbol { - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; - font-size:12px; -} - -.identifier { - color: darkblue; - font-size:12px; - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; -} - -h1, h2, h3, h4, h5, h6 { - color:#222; - margin:0 0 20px; -} - -p, ul, ol, table, pre, dl { - margin:0 0 20px; -} - -h1, h2, h3 { - line-height:1.1; -} - -h1 { - font-size:28px; -} - -h2 { - color:#393939; -} - -h3, h4, h5, h6 { - color:#494949; -} - -a { - color:#258aaf; - font-weight:400; - text-decoration:none; -} - -a:hover { - color: inherit; - text-decoration:underline; -} - -a small { - font-size:11px; - color:#555; - margin-top:-0.6em; - display:block; -} - -.wrapper { - width:860px; - margin:0 auto; -} - -blockquote { - border-left:1px solid #e5e5e5; - margin:0; - padding:0 0 0 20px; - font-style:italic; -} - -code, pre { - font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; - color:#333; - font-size:12px; -} - -pre { - display: block; -/* - padding:8px 8px; - background: #f8f8f8; - border-radius:5px; - border:1px solid #e5e5e5; -*/ - overflow-x: auto; -} - -table { - width:100%; - border-collapse:collapse; -} - -th, td { - text-align:left; - vertical-align: top; - padding:5px 10px; -} - -dt { - color:#444; - font-weight:700; -} - -th { - color:#444; -} - -img { - max-width:100%; -} - -header { - width:270px; - float:left; - position:fixed; -} - -header ul { - list-style:none; - height:40px; - - padding:0; - - background: #eee; - background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); - background: -webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - background: -o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - background: -ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - background: linear-gradient(top, #f8f8f8 0%,#dddddd 100%); - - border-radius:5px; - border:1px solid #d2d2d2; - box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0; - width:270px; -} - -header li { - width:89px; - float:left; - border-right:1px solid #d2d2d2; - height:40px; -} - -header ul a { - line-height:1; - font-size:11px; - color:#999; - display:block; - text-align:center; - padding-top:6px; - height:40px; -} - -strong { - color:#222; - font-weight:700; -} - -header ul li + li { - width:88px; - border-left:1px solid #fff; -} - -header ul li + li + li { - border-right:none; - width:89px; -} - -header ul a strong { - font-size:14px; - display:block; - color:#222; -} - -section { - width:500px; - float:right; - padding-bottom:50px; -} - -small { - font-size:11px; -} - -hr { - border:0; - background:#e5e5e5; - height:1px; - margin:0 0 20px; -} - -footer { - width:270px; - float:left; - position:fixed; - bottom:50px; -} - -@media print, screen and (max-width: 960px) { - - div.wrapper { - width:auto; - margin:0; - } - - header, section, footer { - float:none; - position:static; - width:auto; - } - - header { - padding-right:320px; - } - - section { - border:1px solid #e5e5e5; - border-width:1px 0; - padding:20px 0; - margin:0 0 20px; - } - - header a small { - display:inline; - } - - header ul { - position:absolute; - right:50px; - top:52px; - } -} - -@media print, screen and (max-width: 720px) { - body { - word-wrap:break-word; - } - - header { - padding:0; - } - - header ul, header p.view { - position:static; - } - - pre, code { - word-wrap:normal; - } -} - -@media print, screen and (max-width: 480px) { - body { - padding:15px; - } - - header ul { - display:none; - } -} - -@media print { - body { - padding:0.4in; - font-size:12pt; - color:#444; - } -} diff --git a/plugins/build.gradle.kts b/plugins/build.gradle.kts index a95b612e..c7c29140 100644 --- a/plugins/build.gradle.kts +++ b/plugins/build.gradle.kts @@ -9,6 +9,14 @@ subprojects { implementation(kotlin("stdlib-jdk8")) testImplementation(project(":testApi")) - testImplementation("junit:junit:4.13") + testImplementation("org.junit.jupiter:junit-jupiter:5.6.0") + } + + tasks.test { + useJUnitPlatform() + ignoreFailures = true + testLogging { + events("passed", "skipped", "failed") + } } }
\ No newline at end of file diff --git a/plugins/gfm/build.gradle.kts b/plugins/gfm/build.gradle.kts new file mode 100644 index 00000000..c327b96c --- /dev/null +++ b/plugins/gfm/build.gradle.kts @@ -0,0 +1,8 @@ +publishing { + publications { + register<MavenPublication>("gfm-plugin") { + artifactId = "gfm-plugin" + from(components["java"]) + } + } +}
\ No newline at end of file diff --git a/plugins/gfm/src/main/kotlin/GfmPlugin.kt b/plugins/gfm/src/main/kotlin/GfmPlugin.kt new file mode 100644 index 00000000..64a2cdfc --- /dev/null +++ b/plugins/gfm/src/main/kotlin/GfmPlugin.kt @@ -0,0 +1,196 @@ +package org.jetbrains.dokka.commonmarkrenderer + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.DokkaPlugin +import java.lang.StringBuilder + + +class CommonmarkRendererPlugin : DokkaPlugin() { + + val locationProviderFactory by extensionPoint<LocationProviderFactory>() + val outputWriter by extensionPoint<OutputWriter>() + + val renderer by extending { + CoreExtensions.renderer providing { CommonmarkRenderer(it.single(outputWriter), it) } + } + + val locationProvider by extending { + locationProviderFactory providing { MarkdownLocationProviderFactory(it) } order { + before(renderer) + } + } +} + +class CommonmarkRenderer( + outputWriter: OutputWriter, + context: DokkaContext +) : DefaultRenderer<StringBuilder>(outputWriter, context) { + override fun StringBuilder.buildHeader(level: Int, content: StringBuilder.() -> Unit) { + buildParagraph() + append("#".repeat(level) + " ") + content() + buildNewLine() + } + + override fun StringBuilder.buildLink(address: String, content: StringBuilder.() -> Unit) { + append("[") + content() + append("]($address)") + } + + override fun StringBuilder.buildList(node: ContentList, pageContext: ContentPage, platformRestriction: PlatformData?) { + buildParagraph() + buildListLevel(node, pageContext) + buildParagraph() + } + + private val indent = " ".repeat(4) + + private fun StringBuilder.buildListItem(items: List<ContentNode>, pageContext: ContentPage, bullet: String = "*") { + items.forEach { + if (it is ContentList) { + val builder = StringBuilder() + builder.append(indent) + builder.buildListLevel(it, pageContext) + append(builder.toString().replace(Regex(" \n(?!$)"), " \n$indent")) + } else { + append("$bullet ") + it.build(this, pageContext) + buildNewLine() + } + } + } + + private fun StringBuilder.buildListLevel(node: ContentList, pageContext: ContentPage) { + if (node.ordered) { + buildListItem( + node.children, + pageContext, + "${node.extra.allOfType<SimpleAttr>().find { it.extraKey == "start" }?.extraValue + ?: 1.also { context.logger.error("No starting number specified for ordered list in node ${pageContext.dri.first()}!")}}." + ) + } else { + buildListItem(node.children, pageContext, "*") + } + } + + override fun StringBuilder.buildNewLine() { + append(" \n") + } + + private fun StringBuilder.buildParagraph() { + append("\n\n") + } + + override fun StringBuilder.buildResource(node: ContentEmbeddedResource, pageContext: ContentPage) { + append("Resource") + } + + override fun StringBuilder.buildTable(node: ContentTable, pageContext: ContentPage, platformRestriction: PlatformData?) { + + val size = node.children.firstOrNull()?.children?.size ?: 0 + buildParagraph() + + if (node.header.size > 0) { + node.header.forEach { + it.children.forEach { + append("| ") + it.build(this, pageContext) + } + append("|\n") + } + } else { + append("| ".repeat(size)) + if (size > 0) append("|\n") + } + + append("|---".repeat(size)) + if (size > 0) append("|\n") + + node.children.forEach { + it.children.forEach { + append("| ") + it.build(this, pageContext) + } + append("|\n") + } + } + + override fun StringBuilder.buildText(textNode: ContentText) { + val decorators = decorators(textNode.style) + append(decorators) + append(textNode.text.escapeIllegalCharacters()) + append(decorators.reversed()) + } + + override fun StringBuilder.buildNavigation(page: PageNode) { + locationProvider.ancestors(page).asReversed().forEach { node -> + append("/") + if (node.isNavigable) buildLink(node, page) + else append(node.name) + } + buildParagraph() + } + + override fun buildPage(page: ContentPage, content: (StringBuilder, ContentPage) -> Unit): String = + StringBuilder().apply { + content(this, page) + }.toString() + + override fun buildError(node: ContentNode) { + context.logger.warn("Markdown renderer has encountered problem. The unmatched node is $node") + } + + private fun decorators(styles: Set<Style>) = StringBuilder().apply { + styles.forEach { + when (it) { + TextStyle.Bold -> append("**") + TextStyle.Italic -> append("*") + TextStyle.Strong -> append("**") + TextStyle.Strikethrough -> append("~~") + else -> Unit + } + } + }.toString() + + private val PageNode.isNavigable: Boolean + get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing + + private fun StringBuilder.buildLink(to: PageNode, from: PageNode) = + buildLink(locationProvider.resolve(to, from)) { + append(to.name) + } + + override fun renderPage(page: PageNode) { + val path by lazy { locationProvider.resolve(page, skipExtension = true) } + when (page) { + is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> buildPageContent(c, p) }, ".md") + is RendererSpecificPage -> when (val strategy = page.strategy) { + is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, path) + is RenderingStrategy.Write -> outputWriter.write(path, strategy.text, "") + is RenderingStrategy.Callback -> outputWriter.write(path, strategy.instructions(this, page), ".md") + RenderingStrategy.DoNothing -> Unit + } + else -> throw AssertionError( + "Page ${page.name} cannot be rendered by renderer as it is not renderer specific nor contains content" + ) + } + } +} + +class MarkdownLocationProviderFactory(val context: DokkaContext) : LocationProviderFactory { + + override fun getLocationProvider(pageNode: RootPageNode) = MarkdownLocationProvider(pageNode, context) +} + +class MarkdownLocationProvider( + pageGraphRoot: RootPageNode, + dokkaContext: DokkaContext +) : DefaultLocationProvider( + pageGraphRoot, + dokkaContext +) { + override val extension = ".md" +}
\ No newline at end of file diff --git a/plugins/gfm/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/plugins/gfm/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin new file mode 100644 index 00000000..ae291d68 --- /dev/null +++ b/plugins/gfm/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin @@ -0,0 +1 @@ +org.jetbrains.dokka.gfm.GfmPlugin diff --git a/plugins/jekyll/build.gradle.kts b/plugins/jekyll/build.gradle.kts new file mode 100644 index 00000000..535a0aef --- /dev/null +++ b/plugins/jekyll/build.gradle.kts @@ -0,0 +1,8 @@ +publishing { + publications { + register<MavenPublication>("jekyll-plugin") { + artifactId = "jekyll-plugin" + from(components["java"]) + } + } +}
\ No newline at end of file diff --git a/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt b/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt new file mode 100644 index 00000000..0a0a2cc4 --- /dev/null +++ b/plugins/jekyll/src/main/kotlin/JekyllPlugin.kt @@ -0,0 +1,182 @@ +package org.jetbrains.dokka.jekyll + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.DokkaPlugin +import org.jetbrains.dokka.plugability.single +import org.jetbrains.dokka.renderers.DefaultRenderer +import org.jetbrains.dokka.renderers.OutputWriter +import org.jetbrains.dokka.resolvers.DefaultLocationProvider +import org.jetbrains.dokka.resolvers.LocationProvider +import org.jetbrains.dokka.resolvers.LocationProviderFactory +import java.lang.StringBuilder + + +class JekyllPlugin : DokkaPlugin() { + + val renderer by extending { + CoreExtensions.renderer providing { JekyllRenderer(it.single(CoreExtensions.outputWriter), it) } + } +} + +class JekyllRenderer( + outputWriter: OutputWriter, + context: DokkaContext +) : DefaultRenderer<StringBuilder>(outputWriter, context) { + override fun StringBuilder.buildHeader(level: Int, content: StringBuilder.() -> Unit) { + buildParagraph() + append("${"#".repeat(level)} ") + content() + buildNewLine() + } + + override fun StringBuilder.buildLink(address: String, content: StringBuilder.() -> Unit) { + append("[") + content() + append("]($address)") + } + + override fun StringBuilder.buildList(node: ContentList, pageContext: ContentPage) { + buildListLevel(node, pageContext) + buildParagraph() + } + + private val indent = " ".repeat(4) + + private fun StringBuilder.buildListItem(items: List<ContentNode>, pageContext: ContentPage, bullet: String = "*") { + items.forEach { + if(it is ContentList) { + val builder = StringBuilder() + builder.append(indent) + builder.buildListLevel(it, pageContext) + append(builder.toString().replace(Regex(" \n(?!$)"), " \n$indent")) + } else { + append("$bullet ") + it.build(this, pageContext) + buildNewLine() + } + } + } + + private fun StringBuilder.buildListLevel(node: ContentList, pageContext: ContentPage) { + if(node.ordered) { + buildListItem(node.children, pageContext, "${node.start}.") + } else { + buildListItem(node.children, pageContext, "*") + } + } + + override fun StringBuilder.buildNewLine() { + this.append(" \n") + } + + fun StringBuilder.buildParagraph() { + this.append("\n\n") + } + + override fun StringBuilder.buildResource(node: ContentEmbeddedResource, pageContext: ContentPage) { + this.append("Resource") + } + + override fun StringBuilder.buildTable(node: ContentTable, pageContext: ContentPage) { + + buildParagraph() + + val size = node.children.firstOrNull()?.children?.size ?: 0 + + if(node.header.size > 0) { + node.header.forEach { + it.children.forEach { + append("| ") + it.build(this, pageContext) + } + append("|\n") + } + } else { + append("| ".repeat(size)) + if(size > 0) append("|\n") + } + + append("|---".repeat(size)) + if(size > 0) append("|\n") + + + node.children.forEach { + it.children.forEach { + append("| ") + it.build(this, pageContext) + } + append("|\n") + } + + buildParagraph() + } + + override fun StringBuilder.buildText(textNode: ContentText) { + val decorators = decorators(textNode.style) + this.append(decorators) + this.append(textNode.text.replace(Regex("[<>]"), "")) + this.append(decorators.reversed()) + } + + override fun StringBuilder.buildNavigation(page: PageNode) { + locationProvider.ancestors(page).asReversed().forEach { node -> + append("/") + if (node.isNavigable) buildLink(node, page) + else append(node.name) + } + buildParagraph() + } + + override fun buildPage(page: ContentPage, content: (StringBuilder, ContentPage) -> Unit): String { + val builder = StringBuilder() + builder.append("---\n") + builder.append("title: ${page.name} -\n") + builder.append("---\n") + content(builder, page) + return builder.toString() + } + + override fun buildError(node: ContentNode) { + println("Error") + } + + private fun decorators(styles: Set<Style>): String { + val decorators = StringBuilder() + styles.forEach { + when(it) { + TextStyle.Bold -> decorators.append("**") + TextStyle.Italic -> decorators.append("*") + TextStyle.Strong -> decorators.append("**") + TextStyle.Strikethrough -> decorators.append("~~") + else -> Unit + } + } + return decorators.toString() + } + + private val PageNode.isNavigable: Boolean + get() = this !is RendererSpecificPage || strategy != RenderingStrategy.DoNothing + + private fun StringBuilder.buildLink(to: PageNode, from: PageNode) = + buildLink(locationProvider.resolve(to, from)) { + append(to.name) + } + + override fun renderPage(page: PageNode) { + val path by lazy { locationProvider.resolve(page, skipExtension = true) } + when (page) { + is ContentPage -> outputWriter.write(path, buildPage(page) { c, p -> buildPageContent(c, p) }, ".md") + is RendererSpecificPage -> when (val strategy = page.strategy) { + is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, path) + is RenderingStrategy.Write -> outputWriter.write(path, strategy.text, "") + is RenderingStrategy.Callback -> outputWriter.write(path, strategy.instructions(this, page), ".md") + RenderingStrategy.DoNothing -> Unit + } + else -> throw AssertionError( + "Page ${page.name} cannot be rendered by renderer as it is not renderer specific nor contains content" + ) + } + } +}
\ No newline at end of file diff --git a/plugins/jekyll/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/plugins/jekyll/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin new file mode 100644 index 00000000..92c75544 --- /dev/null +++ b/plugins/jekyll/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin @@ -0,0 +1 @@ +org.jetbrains.dokka.jekyll.JekyllPlugin diff --git a/plugins/kotlin-as-java/build.gradle.kts b/plugins/kotlin-as-java/build.gradle.kts index 32f9c931..0de29557 100644 --- a/plugins/kotlin-as-java/build.gradle.kts +++ b/plugins/kotlin-as-java/build.gradle.kts @@ -1,6 +1,12 @@ +import org.jetbrains.configureBintrayPublication + +plugins { + id("com.jfrog.bintray") +} + publishing { publications { - register<MavenPublication>("kotlin-as-java-plugin") { + register<MavenPublication>("kotlinAsJavaPlugin") { artifactId = "kotlin-as-java-plugin" from(components["java"]) } @@ -9,4 +15,6 @@ publishing { dependencies { implementation(project(":plugins:base")) -}
\ No newline at end of file +} + +configureBintrayPublication("kotlinAsJavaPlugin")
\ No newline at end of file diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt index 4bf75101..dac937c0 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt @@ -4,9 +4,9 @@ import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Annotation -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.DAnnotation +import org.jetbrains.dokka.model.DEnum +import org.jetbrains.dokka.model.DFunction import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.name.ClassId @@ -21,21 +21,21 @@ private fun <T : WithExpectActual> List<T>.groupedByLocation() = } // TODO: first() does not look reasonable }) { it.second } -internal fun Package.asJava(): Package { +internal fun DPackage.asJava(): DPackage { @Suppress("UNCHECKED_CAST") val syntheticClasses = ((properties + functions) as List<WithExpectActual>) .groupedByLocation() .map { (syntheticClassName, nodes) -> - Class( + DClass( dri = dri.withClass(syntheticClassName), name = syntheticClassName, - properties = nodes.filterIsInstance<Property>().map { it.asJava() }, + properties = nodes.filterIsInstance<DProperty>().map { it.asJava() }, constructors = emptyList(), functions = ( - nodes.filterIsInstance<Property>() - .map { it.javaAccessors() } + - nodes.filterIsInstance<Function>() - .map { it.asJava(syntheticClassName) }) as List<Function>, // TODO: methods are static and receiver is a param + nodes.filterIsInstance<DProperty>() + .flatMap { it.javaAccessors() } + + nodes.filterIsInstance<DFunction>() + .map { it.asJava(syntheticClassName) }), // TODO: methods are static and receiver is a param classlikes = emptyList(), sources = PlatformDependent.empty(), visibility = PlatformDependent( @@ -47,7 +47,7 @@ internal fun Package.asJava(): Package { generics = emptyList(), supertypes = PlatformDependent.empty(), documentation = PlatformDependent.empty(), - modifier = JavaModifier.Final, + modifier = PlatformDependent(map = platformData.map{ it to JavaModifier.Final}.toMap()), platformData = platformData, extra = PropertyContainer.empty() ) @@ -56,12 +56,11 @@ internal fun Package.asJava(): Package { return copy( functions = emptyList(), properties = emptyList(), - classlikes = classlikes.map { it.asJava() } + syntheticClasses, - packages = packages.map { it.asJava() } + classlikes = classlikes.map { it.asJava() } + syntheticClasses ) } -internal fun Property.asJava(isTopLevel: Boolean = false, relocateToClass: String? = null) = +internal fun DProperty.asJava(isTopLevel: Boolean = false, relocateToClass: String? = null) = copy( dri = if (relocateToClass.isNullOrBlank()) { dri @@ -69,20 +68,20 @@ internal fun Property.asJava(isTopLevel: Boolean = false, relocateToClass: Strin dri.withClass(relocateToClass) }, modifier = if (setter == null) { - JavaModifier.Final + PlatformDependent(map = platformData.map{it to JavaModifier.Final}.toMap()) } else { - JavaModifier.Empty + PlatformDependent(map = platformData.map{it to JavaModifier.Empty}.toMap()) }, visibility = visibility.copy( map = visibility.mapValues { JavaVisibility.Private } ), - type = type.asJava(isTopLevel), // TODO: check + type = type.asJava(), // TODO: check setter = null, getter = null, // Removing getters and setters as they will be available as functions - extra = if (isTopLevel) extra.plus(extra.mergeAdditionalModifiers(listOf(ExtraModifiers.STATIC))) else extra + extra = if (isTopLevel) extra.plus(extra.mergeAdditionalModifiers(setOf(ExtraModifiers.STATIC))) else extra ) -internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass: String? = null): List<Function> = +internal fun DProperty.javaAccessors(isTopLevel: Boolean = false, relocateToClass: String? = null): List<DFunction> = listOfNotNull( getter?.copy( dri = if (relocateToClass.isNullOrBlank()) { @@ -92,15 +91,15 @@ internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass }, name = "get" + name.capitalize(), modifier = if (setter == null) { - JavaModifier.Final + PlatformDependent(map = platformData.map{it to JavaModifier.Final}.toMap()) } else { - JavaModifier.Empty + PlatformDependent(map = platformData.map{it to JavaModifier.Empty}.toMap()) }, visibility = visibility.copy( map = visibility.mapValues { JavaVisibility.Public } ), - type = type.asJava(isTopLevel), // TODO: check - extra = if (isTopLevel) getter!!.extra.plus(getter!!.extra.mergeAdditionalModifiers(listOf(ExtraModifiers.STATIC))) else getter!!.extra + type = type.asJava(), // TODO: check + extra = if (isTopLevel) getter!!.extra.plus(getter!!.extra.mergeAdditionalModifiers(setOf(ExtraModifiers.STATIC))) else getter!!.extra ), setter?.copy( dri = if (relocateToClass.isNullOrBlank()) { @@ -110,20 +109,20 @@ internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass }, name = "set" + name.capitalize(), modifier = if (setter == null) { - JavaModifier.Final + PlatformDependent(map = platformData.map{it to JavaModifier.Final}.toMap()) } else { - JavaModifier.Empty + PlatformDependent(map = platformData.map{it to JavaModifier.Empty}.toMap()) }, visibility = visibility.copy( map = visibility.mapValues { JavaVisibility.Public } ), - type = type.asJava(isTopLevel), // TODO: check - extra = if (isTopLevel) setter!!.extra.plus(setter!!.extra.mergeAdditionalModifiers(listOf(ExtraModifiers.STATIC))) else setter!!.extra + type = type.asJava(), // TODO: check + extra = if (isTopLevel) setter!!.extra.plus(setter!!.extra.mergeAdditionalModifiers(setOf(ExtraModifiers.STATIC))) else setter!!.extra ) ) -internal fun Function.asJava(containingClassName: String): Function { +internal fun DFunction.asJava(containingClassName: String): DFunction { val newName = when { isConstructor -> containingClassName else -> name @@ -132,22 +131,24 @@ internal fun Function.asJava(containingClassName: String): Function { // dri = dri.copy(callable = dri.callable?.asJava()), name = newName, type = type.asJava(), - modifier = if(modifier is KotlinModifier.Final && isConstructor) JavaModifier.Empty else modifier, + modifier = if(modifier.all{(_,v)-> v is KotlinModifier.Final} && isConstructor) + PlatformDependent(map = platformData.map{it to JavaModifier.Empty}.toMap()) + else PlatformDependent(map = platformData.map{it to modifier.allValues.first()}.toMap()), parameters = listOfNotNull(receiver?.asJava()) + parameters.map { it.asJava() }, receiver = null ) // TODO static if toplevel } -internal fun Classlike.asJava(): Classlike = when (this) { - is Class -> asJava() - is Enum -> asJava() - is Annotation -> asJava() - is Object -> asJava() - is Interface -> asJava() +internal fun DClasslike.asJava(): DClasslike = when (this) { + is DClass -> asJava() + is DEnum -> asJava() + is DAnnotation -> asJava() + is DObject -> asJava() + is DInterface -> asJava() else -> throw IllegalArgumentException("$this shouldn't be here") } -internal fun Class.asJava(): Class = copy( +internal fun DClass.asJava(): DClass = copy( constructors = constructors.map { it.asJava(name) }, functions = (functions + properties.map { it.getter } + properties.map { it.setter }).filterNotNull().map { it.asJava(name) @@ -158,10 +159,11 @@ internal fun Class.asJava(): Class = copy( supertypes = supertypes.copy( map = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } ), - modifier = if (modifier is KotlinModifier.Empty) JavaModifier.Final else modifier + modifier = if (modifier.all{(_,v) -> v is KotlinModifier.Empty}) PlatformDependent(map = platformData.map{it to JavaModifier.Final}.toMap()) + else PlatformDependent(map = platformData.map{it to modifier.allValues.first()}.toMap()) ) -private fun TypeParameter.asJava(): TypeParameter = copy( +private fun DTypeParameter.asJava(): DTypeParameter = copy( dri = dri.possiblyAsJava(), bounds = bounds.map { it.asJava() } ) @@ -176,7 +178,7 @@ private fun Bound.asJava(): Bound = when (this) { else -> this } -internal fun Enum.asJava(): Enum = copy( +internal fun DEnum.asJava(): DEnum = copy( constructors = constructors.map { it.asJava(name) }, functions = (functions + properties.map { it.getter } + properties.map { it.setter }).filterNotNull().map { it.asJava(name) @@ -189,14 +191,14 @@ internal fun Enum.asJava(): Enum = copy( // , entries = entries.map { it.asJava() } ) -internal fun Object.asJava(): Object = copy( +internal fun DObject.asJava(): DObject = copy( functions = (functions + properties.map { it.getter } + properties.map { it.setter }) .filterNotNull() .map { it.asJava(name.orEmpty()) }, properties = properties.map { it.asJava() } + - Property( + DProperty( name = "INSTANCE", - modifier = JavaModifier.Final, + modifier = PlatformDependent(map = platformData.map{it to JavaModifier.Final}.toMap()), dri = dri.copy(callable = Callable("INSTANCE", null, emptyList())), documentation = PlatformDependent.empty(), sources = PlatformDependent.empty(), @@ -205,18 +207,12 @@ internal fun Object.asJava(): Object = copy( it to JavaVisibility.Public }.toMap() ), - type = JavaTypeWrapper( - dri.packageName?.split(".").orEmpty() + - dri.classNames?.split(".").orEmpty(), - emptyList(), - dri, - false - ), + type = TypeConstructor(dri, emptyList()), setter = null, getter = null, platformData = platformData, receiver = null, - extra = PropertyContainer.empty<Property>() + AdditionalModifiers(listOf(ExtraModifiers.STATIC)) + extra = PropertyContainer.empty<DProperty>() + AdditionalModifiers(setOf(ExtraModifiers.STATIC)) ), classlikes = classlikes.map { it.asJava() }, supertypes = supertypes.copy( @@ -224,7 +220,7 @@ internal fun Object.asJava(): Object = copy( ) ) -internal fun Interface.asJava(): Interface = copy( +internal fun DInterface.asJava(): DInterface = copy( functions = (functions + properties.map { it.getter } + properties.map { it.setter }) .filterNotNull() .map { it.asJava(name) }, @@ -236,13 +232,13 @@ internal fun Interface.asJava(): Interface = copy( ) ) -internal fun Annotation.asJava(): Annotation = copy( +internal fun DAnnotation.asJava(): DAnnotation = copy( properties = properties.map { it.asJava() }, constructors = emptyList(), classlikes = classlikes.map { it.asJava() } ) // TODO investigate if annotation class can have methods and properties not from constructor -internal fun Parameter.asJava(): Parameter = copy( +internal fun DParameter.asJava(): DParameter = copy( type = type.asJava(), name = if (name.isNullOrBlank()) "\$self" else name ) @@ -251,36 +247,9 @@ internal fun String.getAsPrimitive(): JvmPrimitiveType? = org.jetbrains.kotlin.b .find { it.typeFqName.asString() == this } ?.let { JvmPrimitiveType.get(it) } -internal fun TypeWrapper.getAsType(classId: ClassId, fqName: String, top: Boolean): TypeWrapper { - val fqNameSplit = fqName - .takeIf { top } - ?.getAsPrimitive() - ?.name?.toLowerCase() - ?.let(::listOf) - ?: classId.asString().split("/") - - return JavaTypeWrapper( - fqNameSplit, - arguments.map { it.asJava(false) }, - classId.toDRI(dri), - fqNameSplit.last()[0].isLowerCase() - ) -} - private fun DRI.partialFqName() = packageName?.let { "$it." } + classNames private fun DRI.possiblyAsJava() = this.partialFqName().mapToJava()?.toDRI(this) ?: this -internal fun TypeWrapper.asJava(top: Boolean = true): TypeWrapper = constructorFqName - ?.let { if (it.endsWith(".Unit")) return VoidTypeWrapper() else it } - ?.let { fqName -> fqName.mapToJava()?.let { getAsType(it, fqName, top) } } ?: this - -private data class VoidTypeWrapper( - override val constructorFqName: String = "void", - override val constructorNamePathSegments: List<String> = listOf("void"), - override val arguments: List<TypeWrapper> = emptyList(), - override val dri: DRI = DRI("java.lang", "Void") -) : TypeWrapper - private fun String.mapToJava(): ClassId? = JavaToKotlinClassMap.mapKotlinToJava(FqName(this).toUnsafe()) @@ -292,11 +261,11 @@ internal fun ClassId.toDRI(dri: DRI?): DRI = DRI( target = null ) -private fun PropertyContainer<out Documentable>.mergeAdditionalModifiers(second: List<ExtraModifiers>) = - this[AdditionalModifiers.AdditionalKey]?.squash(AdditionalModifiers(second)) ?: AdditionalModifiers(second) +private fun PropertyContainer<out Documentable>.mergeAdditionalModifiers(second: Set<ExtraModifiers>) = + this[AdditionalModifiers]?.squash(AdditionalModifiers(second)) ?: AdditionalModifiers(second) private fun AdditionalModifiers.squash(second: AdditionalModifiers) = - AdditionalModifiers((content + second.content).distinct()) + AdditionalModifiers(content + second.content) internal fun ClassId.classNames(): String = shortClassName.identifier + (outerClassId?.classNames()?.let { ".$it" } ?: "")
\ No newline at end of file diff --git a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt index 91e5164d..66328666 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt @@ -3,14 +3,12 @@ package org.jetbrains.dokka.kotlinAsJava.signatures import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Annotation -import org.jetbrains.dokka.model.Enum -import org.jetbrains.dokka.model.Function import org.jetbrains.dokka.pages.ContentKind import org.jetbrains.dokka.pages.ContentNode -import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.pages.TextStyle import org.jetbrains.dokka.utilities.DokkaLogger class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider { @@ -22,29 +20,33 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge override fun signature(documentable: Documentable): ContentNode = when (documentable) { - is Function -> signature(documentable) - is Classlike -> signature(documentable) - is TypeParameter -> signature(documentable) + is DFunction -> signature(documentable) + is DProperty -> signature(documentable) + is DClasslike -> signature(documentable) + is DEnumEntry -> signature(documentable) + is DTypeParameter -> signature(documentable) else -> throw NotImplementedError( "Cannot generate signature for ${documentable::class.qualifiedName} ${documentable.name}" ) } - private fun signature(c: Classlike) = contentBuilder.contentFor(c, ContentKind.Symbol) { + private fun signature(e: DEnumEntry)= contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)) + + private fun signature(c: DClasslike) = contentBuilder.contentFor(c, ContentKind.Symbol, setOf(TextStyle.Monospace)) { platformText(c.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } - if (c is Class) { - text(c.modifier.takeIf { it !in ignoredModifiers }?.name.orEmpty() + " ") + if (c is DClass) { + platformText(c.modifier){ it.takeIf{it !in ignoredModifiers}?.name.orEmpty() + " "} } when (c) { - is Class -> text("class ") - is Interface -> text("interface ") - is Enum -> text("enum ") - is Object -> text("class ") - is Annotation -> text("@interface ") + is DClass -> text("class ") + is DInterface -> text("interface ") + is DEnum -> text("enum ") + is DObject -> text("class ") + is DAnnotation -> text("@interface ") } - text(c.name!!) + link(c.name!!, c.dri) if (c is WithGenerics) { list(c.generics, prefix = "<", suffix = ">") { +buildSignature(it) @@ -59,12 +61,14 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge } } - private fun signature(f: Function) = contentBuilder.contentFor(f, ContentKind.Symbol) { - text(f.modifier.takeIf { it !in ignoredModifiers }?.name.orEmpty() + " ") + private fun signature(p: DProperty) = contentBuilder.contentFor(p, ContentKind.Symbol, setOf(TextStyle.Monospace)) { + signatureForProjection(p.type) + } + + private fun signature(f: DFunction) = contentBuilder.contentFor(f, ContentKind.Symbol, setOf(TextStyle.Monospace)) { + platformText(f.modifier){ it.takeIf{it !in ignoredModifiers}?.name.orEmpty() + " "} val returnType = f.type - if (!f.isConstructor && returnType.constructorFqName != Unit::class.qualifiedName) { - type(returnType) - } + signatureForProjection(returnType) text(" ") link(f.name, f.dri) list(f.generics, prefix = "<", suffix = ">") { @@ -72,14 +76,14 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge } text("(") list(f.parameters) { - type(it.type) + signatureForProjection(it.type) text(" ") link(it.name!!, it.dri) } text(")") } - private fun signature(t: TypeParameter) = contentBuilder.contentFor(t, ContentKind.Symbol) { + private fun signature(t: DTypeParameter) = contentBuilder.contentFor(t) { text(t.name.substringAfterLast(".")) list(t.bounds, prefix = " extends ") { signatureForProjection(it) @@ -98,12 +102,16 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge } is Variance -> group { - text(p.kind.toString() + " ") + text(p.kind.toString() + " ") // TODO: "super" && "extends" signatureForProjection(p.inner) } is Star -> text("?") is Nullable -> signatureForProjection(p.inner) + + is JavaObject -> link("Object", DRI("java.lang", "Object")) + is Void -> text("void") + is PrimitiveJavaType -> text(p.name) } }
\ No newline at end of file diff --git a/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt b/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt index 8f51e105..8b07670f 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt @@ -1,11 +1,11 @@ package org.jetbrains.dokka.kotlinAsJava.transformers import org.jetbrains.dokka.kotlinAsJava.converters.asJava -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer class KotlinAsJavaDocumentableTransformer : DocumentableTransformer { - override fun invoke(original: Module, context: DokkaContext): Module = + override fun invoke(original: DModule, context: DokkaContext): DModule = original.copy(packages = original.packages.map { it.asJava() }) } diff --git a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt index 780f326a..968ab65a 100644 --- a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt +++ b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt @@ -1,11 +1,8 @@ package kotlinAsJavaPlugin -import org.jetbrains.dokka.pages.ContentGroup -import org.jetbrains.dokka.pages.ContentPage -import org.jetbrains.dokka.pages.ContentTable -import org.jetbrains.dokka.pages.children -import org.junit.Test +import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.junit.jupiter.api.Test class KotlinAsJavaPluginTest : AbstractCoreTest() { @@ -38,14 +35,11 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { cleanupOutput = true ) { pagesGenerationStage = { root -> - val content = (root.children.firstOrNull()?.children?.firstOrNull() as? ContentPage)?.content ?: run { - fail("Either children or content is null") - } + val content = (root.children.single().children.first { it.name == "TestKt" } as ContentPage).content - val children = - if (content is ContentGroup) - content.children.filterIsInstance<ContentTable>().filter { it.children.isNotEmpty() } - else emptyList() + val children = content.mainContents + .filterIsInstance<ContentTable>() + .filter { it.children.isNotEmpty() } children.assertCount(2) } @@ -83,9 +77,9 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { .map { it.content } val children = contentList.flatMap { content -> - if (content is ContentGroup) - content.children.filterIsInstance<ContentTable>().filter { it.children.isNotEmpty() } - else emptyList() + content.mainContents + .filterIsInstance<ContentTable>() + .filter { it.children.isNotEmpty() } }.filterNot { it.toString().contains("<init>") } children.assertCount(4) @@ -140,4 +134,9 @@ class KotlinAsJavaPluginTest : AbstractCoreTest() { private fun <T> Collection<T>.assertCount(n: Int, prefix: String = "") = assert(count() == n) { "${prefix}Expected $n, got ${count()}" } -}
\ No newline at end of file +} + +private val ContentNode.mainContents: List<ContentNode> + get() = (this as ContentGroup).children + .filterIsInstance<ContentGroup>() + .single { it.dci.kind == ContentKind.Main }.children diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 5d7ec1f7..644ecee4 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -3,20 +3,37 @@ package org.jetbrains.dokka import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink import org.jetbrains.dokka.utilities.DokkaConsoleLogger import java.io.File +import java.io.FileNotFoundException import java.net.MalformedURLException import java.net.URL import java.net.URLClassLoader +import java.nio.file.Files +import java.nio.file.Paths open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { override val outputDir: String by parser.stringOption( listOf("-output"), "Output directory path", - "") + "" + ) override val format: String by parser.stringOption( listOf("-format"), - "Output format (text, html, markdown, jekyll, kotlin-website)", - "") + "Output format (text, html, gfm, jekyll, kotlin-website)", + "" + ) + + override val pluginsClasspath: List<File> by parser.repeatableOption( + listOf("-dokkaPlugins"), + "List of jars with dokka plugins" + ) { + File(it) + }.also { + Paths.get("./dokka-base.jar").toAbsolutePath().normalize().run { + if (Files.exists(this)) it.value.add(this.toFile()) + else throw FileNotFoundException("Dokka base plugin is not found! Make sure you placed 'dokka-base.jar' containing base plugin along the cli jar file") + } + } override val generateIndexPages: Boolean by parser.singleFlag( listOf("-generateIndexPages"), @@ -26,7 +43,8 @@ open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { override val cacheRoot: String? by parser.stringOption( listOf("-cacheRoot"), "Path to cache folder, or 'default' to use ~/.cache/dokka, if not provided caching is disabled", - null) + null + ) override val impliedPlatforms: List<String> = emptyList() @@ -34,17 +52,16 @@ open class GlobalArguments(parser: DokkaArgumentsParser) : DokkaConfiguration { listOf("-pass"), "Single dokka pass" ) { - Arguments(parser) + Arguments(parser).also { if(it.moduleName.isEmpty()) DokkaConsoleLogger.warn("Not specified module name. It can result in unexpected behaviour while including documentation for module") } } - - override var pluginsClasspath: List<File> = emptyList() } class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfiguration { override val moduleName: String by parser.stringOption( listOf("-module"), "Name of the documentation module", - "") + "" + ) override val classpath: List<String> by parser.repeatableOption( listOf("-classpath"), @@ -68,23 +85,28 @@ class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfi override val includeNonPublic: Boolean by parser.singleFlag( listOf("-includeNonPublic"), - "Include non public") + "Include non public" + ) override val includeRootPackage: Boolean by parser.singleFlag( listOf("-includeRootPackage"), - "Include root package") + "Include root package" + ) override val reportUndocumented: Boolean by parser.singleFlag( listOf("-reportUndocumented"), - "Report undocumented members") + "Report undocumented members" + ) override val skipEmptyPackages: Boolean by parser.singleFlag( listOf("-skipEmptyPackages"), - "Do not create index pages for empty packages") + "Do not create index pages for empty packages" + ) override val skipDeprecated: Boolean by parser.singleFlag( listOf("-skipDeprecated"), - "Do not output deprecated members") + "Do not output deprecated members" + ) override val jdkVersion: Int by parser.singleOption( listOf("-jdkVersion"), @@ -96,7 +118,8 @@ class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfi override val languageVersion: String? by parser.stringOption( listOf("-languageVersion"), "Language Version to pass to Kotlin analysis", - null) + null + ) override val apiVersion: String? by parser.stringOption( listOf("-apiVersion"), @@ -106,11 +129,13 @@ class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfi override val noStdlibLink: Boolean by parser.singleFlag( listOf("-noStdlibLink"), - "Disable documentation link to stdlib") + "Disable documentation link to stdlib" + ) override val noJdkLink: Boolean by parser.singleFlag( listOf("-noJdkLink"), - "Disable documentation link to JDK") + "Disable documentation link to JDK" + ) override val suppressedFiles: List<String> by parser.repeatableOption( listOf("-suppressedFile"), @@ -125,7 +150,8 @@ class Arguments(val parser: DokkaArgumentsParser) : DokkaConfiguration.PassConfi override val collectInheritedExtensionsFromLibraries: Boolean by parser.singleFlag( listOf("-collectInheritedExtensionsFromLibraries"), - "Search for applicable extensions in libraries") + "Search for applicable extensions in libraries" + ) override val analysisPlatform: Platform by parser.singleOption( listOf("-analysisPlatform"), @@ -234,14 +260,18 @@ object MainKt { listOf("-globalPackageOptions"), "List of package passConfiguration in format \"prefix,-deprecated,-privateApi,+warnUndocumented,+suppress;...\" " ) { link -> - configuration.passesConfigurations.all { it.perPackageOptions.addAll(parsePerPackageOptions(link)) } + configuration.passesConfigurations.all { + it.perPackageOptions.toMutableList().addAll(parsePerPackageOptions(link)) + } } parseContext.cli.singleAction( listOf("-globalLinks"), "External documentation links in format url^packageListUrl^^url2..." ) { link -> - configuration.passesConfigurations.all { it.externalDocumentationLinks.addAll(parseLinks(link)) } + configuration.passesConfigurations.all { + it.externalDocumentationLinks.toMutableList().addAll(parseLinks(link)) + } } parseContext.cli.repeatingAction( @@ -252,12 +282,14 @@ object MainKt { listOf(SourceLinkDefinitionImpl.parseSourceLinkDefinition(it)) else { if (it.isNotEmpty()) { - println("Warning: Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") + DokkaConsoleLogger.warn("Invalid -srcLink syntax. Expected: <path>=<url>[#lineSuffix]. No source links will be generated.") } listOf() } - configuration.passesConfigurations.all { it.sourceLinks.addAll(newSourceLinks) } + configuration.passesConfigurations.all { + it.sourceLinks.toMutableList().addAll(newSourceLinks) + } } parser.parseInto(configuration) diff --git a/runners/gradle-plugin/build.gradle.kts b/runners/gradle-plugin/build.gradle.kts index 0d68a525..df4a8738 100644 --- a/runners/gradle-plugin/build.gradle.kts +++ b/runners/gradle-plugin/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { compileOnly("com.android.tools.build:gradle-core:3.0.0") compileOnly("com.android.tools.build:builder-model:3.0.0") compileOnly(gradleApi()) + compileOnly(gradleKotlinDsl()) constraints { val kotlin_version: String by project compileOnly("org.jetbrains.kotlin:kotlin-reflect:${kotlin_version}") { diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt new file mode 100644 index 00000000..f4fa7aaa --- /dev/null +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt @@ -0,0 +1,56 @@ +package org.jetbrains.dokka.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.UnknownTaskException +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.getByName +import java.lang.IllegalStateException + +open class DokkaCollectorTask : DefaultTask() { + + @Input + var modules: List<String> = emptyList() + + @Input + var outputDirectory: String = "" + + private lateinit var configuration: GradleDokkaConfigurationImpl + + @TaskAction + fun collect() { + val passesConfigurations = getProjects(project).filter { it.name in modules }.map { + val task = try { + it.tasks.getByName(DOKKA_TASK_NAME, DokkaTask::class) + } catch (e: UnknownTaskException) { + throw IllegalStateException("No dokka task declared in module ${it.name}") + } + task.getConfiguration() + } + + val initial = GradleDokkaConfigurationImpl().apply { + outputDir = outputDirectory + cacheRoot = passesConfigurations.first().cacheRoot + format = passesConfigurations.first().format + generateIndexPages = passesConfigurations.first().generateIndexPages + } + + configuration = passesConfigurations.fold(initial) { acc, it: GradleDokkaConfigurationImpl -> + if(acc.format != it.format || acc.generateIndexPages != it.generateIndexPages || acc.cacheRoot != it.cacheRoot) + throw IllegalStateException("Dokka task configurations differ on core arguments (format, generateIndexPages, cacheRoot)") + acc.passesConfigurations = acc.passesConfigurations + it.passesConfigurations + acc.pluginsClasspath = (acc.pluginsClasspath + it.pluginsClasspath).distinct() + acc + } + project.tasks.getByName(DOKKA_TASK_NAME).setProperty("config", configuration) + } + + init { + finalizedBy(project.tasks.getByName(DOKKA_TASK_NAME)) + } + + private fun getProjects(project: Project): Set<Project> = + project.subprojects + project.subprojects.flatMap { getProjects(it) } + +}
\ No newline at end of file diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt index 65b0f4b3..4f7b88c4 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt @@ -8,7 +8,6 @@ import org.gradle.api.internal.plugins.DslObject import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.tasks.* import org.jetbrains.dokka.DokkaBootstrap -import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink.Builder import org.jetbrains.dokka.DokkaConfiguration.SourceRoot import org.jetbrains.dokka.Platform @@ -76,10 +75,11 @@ open class DokkaTask : DefaultTask() { @Nested get() = DslObject(this).extensions.getByType(GradlePassConfigurationImpl::class.java) internal set(value) = DslObject(this).extensions.add(CONFIGURATION_EXTENSION_NAME, value) + var config: GradleDokkaConfigurationImpl? = null + // Configure Dokka with closure in Gradle Kotlin DSL fun configuration(action: Action<in GradlePassConfigurationImpl>) = action.execute(configuration) - private val kotlinTasks: List<Task> by lazy { extractKotlinCompileTasks(configuration.collectKotlinTasks ?: { defaultKotlinTasks() }) } private val configExtractor = ConfigurationExtractor(project) @@ -133,6 +133,10 @@ open class DokkaTask : DefaultTask() { @TaskAction fun generate() { + generateForConfig(config ?: getConfiguration()) + } + + internal fun generateForConfig(configuration: GradleDokkaConfigurationImpl) { outputDiagnosticInfo = true val kotlinColorsEnabledBefore = System.getProperty(COLORS_ENABLED_PROPERTY) ?: "false" System.setProperty(COLORS_ENABLED_PROPERTY, "false") @@ -146,20 +150,6 @@ open class DokkaTask : DefaultTask() { val gson = GsonBuilder().setPrettyPrinting().create() - val globalConfig = multiplatform.toList().find { it.name.toLowerCase() == GLOBAL_PLATFORM_NAME } - val passConfigurationList = collectConfigurations() - .map { defaultPassConfiguration(it, globalConfig) } - - val configuration = GradleDokkaConfigurationImpl().apply { - outputDir = outputDirectory - format = outputFormat - generateIndexPages = true - cacheRoot = cacheRoot - impliedPlatforms = impliedPlatforms - passesConfigurations = passConfigurationList - pluginsClasspath = pluginsConfiguration.resolve().toList() - } - bootstrapProxy.configure( BiConsumer { level, message -> when (level) { @@ -180,6 +170,21 @@ open class DokkaTask : DefaultTask() { } } + internal fun getConfiguration(): GradleDokkaConfigurationImpl { + val globalConfig = multiplatform.toList().find { it.name.toLowerCase() == GLOBAL_PLATFORM_NAME } + val defaultModulesConfiguration = collectConfigurations() + .map { defaultPassConfiguration(it, globalConfig) } + return GradleDokkaConfigurationImpl().apply { + outputDir = outputDirectory + format = outputFormat + generateIndexPages = true + cacheRoot = cacheRoot + impliedPlatforms = impliedPlatforms + passesConfigurations = defaultModulesConfiguration + pluginsClasspath = pluginsConfiguration.resolve().toList() + } + } + private fun collectConfigurations() = if (this.isMultiplatformProject()) collectMultiplatform() else listOf(collectSinglePlatform(configuration)) diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt index 71a02843..4efc5010 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt @@ -10,41 +10,61 @@ import java.util.* internal const val CONFIGURATION_EXTENSION_NAME = "configuration" internal const val MULTIPLATFORM_EXTENSION_NAME = "multiplatform" +internal const val DOKKA_TASK_NAME = "dokka" +internal const val DOKKA_COLLECTOR_TASK_NAME = "dokkaCollector" open class DokkaPlugin : Plugin<Project> { - private val taskName = "dokka" override fun apply(project: Project) { loadDokkaVersion() val dokkaRuntimeConfiguration = addConfiguration(project) - val pluginsConfiguration = project.configurations.create("dokkaPlugins") - addTasks(project, dokkaRuntimeConfiguration, pluginsConfiguration, DokkaTask::class.java) + val pluginsConfiguration = project.configurations.create("dokkaPlugins").apply { + defaultDependencies { it.add(project.dependencies.create("org.jetbrains.dokka:dokka-base:${DokkaVersion.version}")) } + } + addDokkaTasks(project, dokkaRuntimeConfiguration, pluginsConfiguration, DokkaTask::class.java) + addDokkaCollectorTasks(project, DokkaCollectorTask::class.java) } - private fun loadDokkaVersion() = DokkaVersion.loadFrom(javaClass.getResourceAsStream("/META-INF/gradle-plugins/org.jetbrains.dokka.properties")) + private fun loadDokkaVersion() = + DokkaVersion.loadFrom(javaClass.getResourceAsStream("/META-INF/gradle-plugins/org.jetbrains.dokka.properties")) private fun addConfiguration(project: Project) = project.configurations.create("dokkaRuntime").apply { - defaultDependencies{ dependencies -> dependencies.add(project.dependencies.create("org.jetbrains.dokka:dokka-core:${DokkaVersion.version}")) } + defaultDependencies { dependencies -> dependencies.add(project.dependencies.create("org.jetbrains.dokka:dokka-core:${DokkaVersion.version}")) } } - private fun addTasks( + private fun addDokkaTasks( project: Project, runtimeConfiguration: Configuration, pluginsConfiguration: Configuration, taskClass: Class<out DokkaTask> ) { - if(GradleVersion.current() >= GradleVersion.version("4.10")) { - project.tasks.register(taskName, taskClass) + if (GradleVersion.current() >= GradleVersion.version("4.10")) { + project.tasks.register(DOKKA_TASK_NAME, taskClass) } else { - project.tasks.create(taskName, taskClass) + project.tasks.create(DOKKA_TASK_NAME, taskClass) } project.tasks.withType(taskClass) { task -> task.multiplatform = project.container(GradlePassConfigurationImpl::class.java) task.configuration = GradlePassConfigurationImpl() task.dokkaRuntime = runtimeConfiguration task.pluginsConfiguration = pluginsConfiguration - task.outputDirectory = File(project.buildDir, taskName).absolutePath + task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath + } + } + + private fun addDokkaCollectorTasks( + project: Project, + taskClass: Class<out DokkaCollectorTask> + ) { + if (GradleVersion.current() >= GradleVersion.version("4.10")) { + project.tasks.register(DOKKA_COLLECTOR_TASK_NAME, taskClass) + } else { + project.tasks.create(DOKKA_COLLECTOR_TASK_NAME, taskClass) + } + project.tasks.withType(taskClass) { task -> + task.modules = emptyList() + task.outputDirectory = File(project.buildDir, DOKKA_TASK_NAME).absolutePath } } } diff --git a/runners/maven-plugin/build.gradle.kts b/runners/maven-plugin/build.gradle.kts index d97e7973..d9fc4f6f 100644 --- a/runners/maven-plugin/build.gradle.kts +++ b/runners/maven-plugin/build.gradle.kts @@ -8,6 +8,7 @@ val mavenBin: Configuration by configurations.creating val mavenVersion = "3.5.0" val mavenPluginToolsVersion = "3.5.2" +val aetherVersion = "1.1.0" dependencies { implementation(project(":core")) @@ -15,8 +16,14 @@ dependencies { implementation("org.apache.maven:maven-plugin-api:$mavenVersion") implementation("org.apache.maven.plugin-tools:maven-plugin-annotations:$mavenPluginToolsVersion") implementation("org.apache.maven:maven-archiver:2.5") - compileOnly(kotlin("stdlib-jdk8")) - + implementation(kotlin("stdlib-jdk8")) + implementation("org.eclipse.aether:aether-api:${aetherVersion}") + implementation("org.eclipse.aether:aether-spi:${aetherVersion}") + implementation("org.eclipse.aether:aether-impl:${aetherVersion}") + implementation("org.eclipse.aether:aether-connector-basic:${aetherVersion}") + implementation("org.eclipse.aether:aether-transport-file:${aetherVersion}") + implementation("org.eclipse.aether:aether-transport-http:${aetherVersion}") + implementation("org.apache.maven:maven-aether-provider:3.3.3") mavenBin(group = "org.apache.maven", name = "apache-maven", version = mavenVersion, classifier = "bin", ext = "zip") } diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index 4ec7e0db..cfe278ce 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -3,17 +3,37 @@ package org.jetbrains.dokka.maven import org.apache.maven.archiver.MavenArchiveConfiguration import org.apache.maven.archiver.MavenArchiver import org.apache.maven.execution.MavenSession +import org.apache.maven.model.Dependency import org.apache.maven.plugin.AbstractMojo import org.apache.maven.plugin.MojoExecutionException import org.apache.maven.plugins.annotations.* import org.apache.maven.project.MavenProject import org.apache.maven.project.MavenProjectHelper +import org.apache.maven.repository.internal.MavenRepositorySystemUtils import org.codehaus.plexus.archiver.Archiver import org.codehaus.plexus.archiver.jar.JarArchiver +import org.eclipse.aether.DefaultRepositorySystemSession +import org.eclipse.aether.RepositorySystem +import org.eclipse.aether.RepositorySystemSession +import org.eclipse.aether.artifact.DefaultArtifact +import org.eclipse.aether.collection.CollectRequest +import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory +import org.eclipse.aether.graph.DependencyNode +import org.eclipse.aether.impl.DefaultServiceLocator +import org.eclipse.aether.repository.LocalRepository +import org.eclipse.aether.repository.RemoteRepository +import org.eclipse.aether.resolution.DependencyRequest +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory +import org.eclipse.aether.spi.connector.transport.TransporterFactory +import org.eclipse.aether.transport.file.FileTransporterFactory +import org.eclipse.aether.transport.http.HttpTransporterFactory +import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator import org.jetbrains.dokka.* +import org.jetbrains.dokka.utilities.DokkaConsoleLogger import java.io.File import java.net.URL + class SourceLinkMapItem { @Parameter(name = "path", required = true) var path: String = "" @@ -29,6 +49,7 @@ class ExternalDocumentationLinkBuilder : DokkaConfiguration.ExternalDocumentatio @Parameter(name = "url", required = true) override var url: URL? = null + @Parameter(name = "packageListUrl", required = true) override var packageListUrl: URL? = null } @@ -39,15 +60,25 @@ abstract class AbstractDokkaMojo : AbstractMojo() { override var path: String = "" } + @Parameter(defaultValue = "\${project}", readonly = true) + private var mavenProject: MavenProject? = null + + @Parameter() + private var session: RepositorySystemSession? = null + class PackageOptions : DokkaConfiguration.PackageOptions { @Parameter override var prefix: String = "" + @Parameter override var includeNonPublic: Boolean = false + @Parameter override var reportUndocumented: Boolean = true + @Parameter override var skipDeprecated: Boolean = false + @Parameter override var suppress: Boolean = false } @@ -81,8 +112,10 @@ abstract class AbstractDokkaMojo : AbstractMojo() { @Parameter var skipDeprecated: Boolean = false + @Parameter var skipEmptyPackages: Boolean = true + @Parameter var reportUndocumented: Boolean = true @@ -114,10 +147,10 @@ abstract class AbstractDokkaMojo : AbstractMojo() { var includeRootPackage: Boolean = false @Parameter - var suppressedFiles: List<String> = emptyList() + var suppressedFiles: List<String> = emptyList() @Parameter - var collectInheritedExtensionsFromLibraries: Boolean = false + var collectInheritedExtensionsFromLibraries: Boolean = false @Parameter var platform: String = "" @@ -134,6 +167,9 @@ abstract class AbstractDokkaMojo : AbstractMojo() { @Parameter var generateIndexPages: Boolean = false + @Parameter + var dokkaPlugins: List<Dependency> = emptyList() + protected abstract fun getOutDir(): String protected abstract fun getOutFormat(): String @@ -168,7 +204,8 @@ abstract class AbstractDokkaMojo : AbstractMojo() { reportUndocumented = it.reportUndocumented, skipDeprecated = it.skipDeprecated, suppress = it.suppress - )}, + ) + }, externalDocumentationLinks = externalDocumentationLinks.map { it.build() as ExternalDocumentationLinkImpl }, noStdlibLink = noStdlibLink, noJdkLink = noJdkLink, @@ -183,23 +220,87 @@ abstract class AbstractDokkaMojo : AbstractMojo() { includeRootPackage = includeRootPackage ) + val logger = MavenDokkaLogger(log) + val configuration = DokkaConfigurationImpl( outputDir = getOutDir(), format = getOutFormat(), impliedPlatforms = impliedPlatforms, cacheRoot = cacheRoot, - passesConfigurations = listOf(passConfiguration), + passesConfigurations = listOf(passConfiguration).also { + if(passConfiguration.moduleName.isEmpty()) logger.warn("Not specified module name. It can result in unexpected behaviour while including documentation for module") + }, generateIndexPages = generateIndexPages, - pluginsClasspath = emptyList() //TODO fix this + pluginsClasspath = getArtifactByAether("org.jetbrains.dokka", "dokka-base", dokkaVersion) + + dokkaPlugins.map { getArtifactByAether(it.groupId, it.artifactId, it.version) }.flatten() ) - val gen = DokkaGenerator(configuration, MavenDokkaLogger(log)) + val gen = DokkaGenerator(configuration, logger) gen.generate() } + + private fun newRepositorySystem(): RepositorySystem { + val locator: DefaultServiceLocator = MavenRepositorySystemUtils.newServiceLocator() + locator.addService(RepositoryConnectorFactory::class.java, BasicRepositoryConnectorFactory::class.java) + locator.addService(TransporterFactory::class.java, FileTransporterFactory::class.java) + locator.addService(TransporterFactory::class.java, HttpTransporterFactory::class.java) + return locator.getService(RepositorySystem::class.java) + } + + private fun newSession(system: RepositorySystem): RepositorySystemSession { + val session: DefaultRepositorySystemSession = + MavenRepositorySystemUtils.newSession() + val localRepo = LocalRepository(System.getProperty("user.home") + "/.m2/repository") + session.localRepositoryManager = system.newLocalRepositoryManager(session, localRepo) + return session + } + + private fun getArtifactByAether( + groupId: String, + artifactId: String, + version: String + ): List<File> { + val repoSystem: RepositorySystem = newRepositorySystem() + val session: RepositorySystemSession = newSession(repoSystem) + val dependency = + org.eclipse.aether.graph.Dependency(DefaultArtifact("$groupId:$artifactId:$version"), "compile") + val collectRequest = CollectRequest() + collectRequest.root = dependency + val repositories: List<RemoteRepository> = + (mavenProject?.remoteProjectRepositories?.plus(mavenProject?.remotePluginRepositories ?: emptyList()) + ?: mavenProject?.remotePluginRepositories ?: emptyList()) + repositories.forEach { + collectRequest.addRepository( + RemoteRepository.Builder( + "repo", + "default", + it.url + ).build() + ) + } + val node: DependencyNode = repoSystem.collectDependencies(session, collectRequest).root + val dependencyRequest = DependencyRequest() + dependencyRequest.root = node + repoSystem.resolveDependencies(session, dependencyRequest) + val nlg = PreorderNodeListGenerator() + node.accept(nlg) + return nlg.files + } + + private val dokkaVersion: String by lazy { + mavenProject?.pluginArtifacts?.filter { it.groupId == "org.jetbrains.dokka" && it.artifactId == "dokka-maven-plugin" } + ?.firstOrNull()?.version ?: throw IllegalStateException("Not found dokka plugin") + } } -@Mojo(name = "dokka", defaultPhase = LifecyclePhase.PRE_SITE, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true) +@Mojo( + name = "dokka", + defaultPhase = LifecyclePhase.PRE_SITE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE, + requiresProject = true +) class DokkaMojo : AbstractDokkaMojo() { @Parameter(required = true, defaultValue = "html") var outputFormat: String = "html" @@ -211,7 +312,13 @@ class DokkaMojo : AbstractDokkaMojo() { override fun getOutDir() = outputDir } -@Mojo(name = "javadoc", defaultPhase = LifecyclePhase.PRE_SITE, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true) +@Mojo( + name = "javadoc", + defaultPhase = LifecyclePhase.PRE_SITE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE, + requiresProject = true +) class DokkaJavadocMojo : AbstractDokkaMojo() { @Parameter(required = true, defaultValue = "\${project.basedir}/target/dokkaJavadoc") var outputDir: String = "" @@ -220,7 +327,13 @@ class DokkaJavadocMojo : AbstractDokkaMojo() { override fun getOutDir() = outputDir } -@Mojo(name = "javadocJar", defaultPhase = LifecyclePhase.PRE_SITE, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true) +@Mojo( + name = "javadocJar", + defaultPhase = LifecyclePhase.PRE_SITE, + threadSafe = true, + requiresDependencyResolution = ResolutionScope.COMPILE, + requiresProject = true +) class DokkaJavadocJarMojo : AbstractDokkaMojo() { @Parameter(required = true, defaultValue = "\${project.basedir}/target/dokkaJavadocJar") var outputDir: String = "" @@ -271,7 +384,7 @@ class DokkaJavadocJarMojo : AbstractDokkaMojo() { override fun execute() { super.execute() - if(!File(outputDir).exists()) { + if (!File(outputDir).exists()) { log.warn("No javadoc generated so no javadoc jar will be generated") return } @@ -295,4 +408,3 @@ class DokkaJavadocJarMojo : AbstractDokkaMojo() { return javadocJar } } - diff --git a/testApi/src/main/kotlin/testApi/context/MockContext.kt b/testApi/src/main/kotlin/testApi/context/MockContext.kt index 758a4311..5236f1f4 100644 --- a/testApi/src/main/kotlin/testApi/context/MockContext.kt +++ b/testApi/src/main/kotlin/testApi/context/MockContext.kt @@ -15,7 +15,8 @@ import kotlin.reflect.full.memberProperties class MockContext( vararg extensions: Pair<ExtensionPoint<*>, (DokkaContext) -> Any>, private val testConfiguration: DokkaConfiguration? = null, - private val testPlatforms: Map<PlatformData, EnvironmentAndFacade>? = null + private val testPlatforms: Map<PlatformData, EnvironmentAndFacade>? = null, + private val unusedExtensionPoints: List<ExtensionPoint<*>>? = null ) : DokkaContext { private val extensionMap by lazy { extensions.groupBy(Pair<ExtensionPoint<*>, (DokkaContext) -> Any>::first) { @@ -29,7 +30,7 @@ class MockContext( kclass.constructors.single { it.parameters.isEmpty() }.call().also { it.injectContext(this) } } as T - override fun <T : Any, E : ExtensionPoint<T>> get(point: E): List<T> = extensionMap[point] as List<T> + override fun <T : Any, E : ExtensionPoint<T>> get(point: E): List<T> = extensionMap[point].orEmpty() as List<T> override fun <T : Any, E : ExtensionPoint<T>> single(point: E): T = get(point).single() @@ -40,6 +41,9 @@ class MockContext( override val platforms: Map<PlatformData, EnvironmentAndFacade> get() = testPlatforms ?: throw IllegalStateException("This mock context doesn't provide platforms data") + override val unusedPoints: Collection<ExtensionPoint<*>> + get() = unusedExtensionPoints + ?: throw IllegalStateException("This mock context doesn't provide unused extension points") } private fun DokkaPlugin.injectContext(context: DokkaContext) { diff --git a/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt b/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt index ddee7083..0e77344d 100644 --- a/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt +++ b/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt @@ -26,10 +26,13 @@ internal class DokkaTestGenerator( val modulesFromPlatforms = dokkaGenerator.createDocumentationModels(platforms, context) documentablesCreationStage(modulesFromPlatforms) - val documentationModel = dokkaGenerator.mergeDocumentationModels(modulesFromPlatforms, context) + val filteredModules = dokkaGenerator.transformDocumentationModelBeforeMerge(modulesFromPlatforms, context) + documentablesFirstTransformationStep(filteredModules) + + val documentationModel = dokkaGenerator.mergeDocumentationModels(filteredModules, context) documentablesMergingStage(documentationModel) - val transformedDocumentation = dokkaGenerator.transformDocumentationModel(documentationModel, context) + val transformedDocumentation = dokkaGenerator.transformDocumentationModelAfterMerge(documentationModel, context) documentablesTransformationStage(transformedDocumentation) val pages = dokkaGenerator.createPages(transformedDocumentation, context) diff --git a/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt b/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt index 641cc5f9..26b9a4b6 100644 --- a/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt +++ b/testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt @@ -1,7 +1,8 @@ package org.jetbrains.dokka.testApi.testRunner +import com.intellij.openapi.application.PathManager import org.jetbrains.dokka.* -import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.pages.ModulePageNode import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.pages.RootPageNode @@ -63,8 +64,9 @@ abstract class AbstractCoreTest { val newConfiguration = configuration.copy( outputDir = testDirPath.toAbsolutePath().toString(), - passesConfigurations = configuration.passesConfigurations - .map { it.copy(sourceRoots = it.sourceRoots.map { it.copy(path = "${testDirPath.toAbsolutePath()}/${it.path}") }) } + passesConfigurations = configuration.passesConfigurations.map { + it.copy(sourceRoots = it.sourceRoots.map { it.copy(path = "${testDirPath.toAbsolutePath()}/${it.path}") }) + } ) DokkaTestGenerator( newConfiguration, @@ -104,9 +106,10 @@ abstract class AbstractCoreTest { protected class TestBuilder { var analysisSetupStage: (Map<PlatformData, EnvironmentAndFacade>) -> Unit = {} var pluginsSetupStage: (DokkaContext) -> Unit = {} - var documentablesCreationStage: (List<Module>) -> Unit = {} - var documentablesMergingStage: (Module) -> Unit = {} - var documentablesTransformationStage: (Module) -> Unit = {} + var documentablesCreationStage: (List<DModule>) -> Unit = {} + var documentablesFirstTransformationStep: (List<DModule>) -> Unit = {} + var documentablesMergingStage: (DModule) -> Unit = {} + var documentablesTransformationStage: (DModule) -> Unit = {} var pagesGenerationStage: (ModulePageNode) -> Unit = {} var pagesTransformationStage: (RootPageNode) -> Unit = {} var renderingStage: (RootPageNode, DokkaContext) -> Unit = { a, b -> } @@ -115,6 +118,7 @@ abstract class AbstractCoreTest { analysisSetupStage, pluginsSetupStage, documentablesCreationStage, + documentablesFirstTransformationStep, documentablesMergingStage, documentablesTransformationStage, pagesGenerationStage, @@ -137,7 +141,6 @@ abstract class AbstractCoreTest { var cacheRoot: String? = null var pluginsClasspath: List<File> = emptyList() private val passesConfigurations = mutableListOf<PassConfigurationImpl>() - fun build() = DokkaConfigurationImpl( outputDir = outputDir, format = format, @@ -211,14 +214,31 @@ abstract class AbstractCoreTest { sourceLinks = sourceLinks ) } + + protected val jvmStdlibPath: String? by lazy { + PathManager.getResourceRoot(Strictfp::class.java, "/kotlin/jvm/Strictfp.class") + } + + protected val jsStdlibPath: String? by lazy { + PathManager.getResourceRoot(Any::class.java, "/kotlin/jquery") + } + + protected val commonStdlibPath: String? by lazy { + // TODO: feels hacky, find a better way to do it + ClassLoader.getSystemResource("kotlin/UInt.kotlin_metadata") + ?.file + ?.replace("file:", "") + ?.replaceAfter(".jar", "") + } } data class TestMethods( val analysisSetupStage: (Map<PlatformData, EnvironmentAndFacade>) -> Unit, val pluginsSetupStage: (DokkaContext) -> Unit, - val documentablesCreationStage: (List<Module>) -> Unit, - val documentablesMergingStage: (Module) -> Unit, - val documentablesTransformationStage: (Module) -> Unit, + val documentablesCreationStage: (List<DModule>) -> Unit, + val documentablesFirstTransformationStep: (List<DModule>) -> Unit, + val documentablesMergingStage: (DModule) -> Unit, + val documentablesTransformationStage: (DModule) -> Unit, val pagesGenerationStage: (ModulePageNode) -> Unit, val pagesTransformationStage: (RootPageNode) -> Unit, val renderingStage: (RootPageNode, DokkaContext) -> Unit |
