aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiem Song <tiem@google.com>2020-03-26 14:19:30 -0700
committerTiem Song <tiem@google.com>2020-03-26 14:19:30 -0700
commitbd3c602d256ea5b5960ee0acb09e855674904318 (patch)
treeaa2926fd59e71419e930676754372ce130e23547
parent3326b13c26bf3911a9ba256446e4c4f30af31153 (diff)
parentaad9a75c6ace63e883c8f737a9c4bd0933688adf (diff)
downloadplatform_external_dokka-dev-0.11.0.tar.gz
platform_external_dokka-dev-0.11.0.tar.bz2
platform_external_dokka-dev-0.11.0.zip
Catching up with upstream-dev-0.11.0dev-0.11.0
git merge --no-ff aosp/upstream-dev-0.11.0 Change-Id: I58300124c7f538ae3ebcb1f5bc1e562a95a46cdd
-rw-r--r--core/src/main/kotlin/CoreExtensions.kt2
-rw-r--r--core/src/main/kotlin/DokkaBootstrapImpl.kt32
-rw-r--r--core/src/main/kotlin/DokkaGenerator.kt77
-rw-r--r--core/src/main/kotlin/configuration.kt6
-rw-r--r--core/src/main/kotlin/defaultConfiguration.kt2
-rw-r--r--core/src/main/kotlin/links/DRI.kt6
-rw-r--r--core/src/main/kotlin/model/Documentable.kt242
-rw-r--r--core/src/main/kotlin/model/aditionalExtras.kt39
-rw-r--r--core/src/main/kotlin/model/defaultValues.kt12
-rw-r--r--core/src/main/kotlin/model/documentableProperties.kt6
-rw-r--r--core/src/main/kotlin/model/documentableUtils.kt23
-rw-r--r--core/src/main/kotlin/model/properties/PropertyContainer.kt4
-rw-r--r--core/src/main/kotlin/model/typeWrappers.kt101
-rw-r--r--core/src/main/kotlin/pages/ContentNodes.kt13
-rw-r--r--core/src/main/kotlin/parsers/HtmlParser.kt6
-rw-r--r--core/src/main/kotlin/parsers/MarkdownParser.kt240
-rw-r--r--core/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt (renamed from core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt)2
-rw-r--r--core/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt (renamed from core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt)2
-rw-r--r--core/src/main/kotlin/plugability/DefaultExtensions.kt0
-rw-r--r--core/src/main/kotlin/plugability/DokkaContext.kt24
-rw-r--r--core/src/main/kotlin/plugability/extensions.kt30
-rw-r--r--core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentableTranslator.kt4
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableMerger.kt4
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableToPageTranslator.kt4
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentableTransformer.kt4
-rw-r--r--core/src/main/kotlin/transformers/documentation/PreMergeDocumentableTransformer.kt8
-rw-r--r--core/src/main/kotlin/transformers/pages/PageTransformerBuilders.kt22
-rw-r--r--core/src/main/kotlin/transformers/psi/PsiToDocumentableTranslator.kt4
-rw-r--r--core/src/main/resources/dokka/images/docs_logo.svg7
-rw-r--r--core/src/main/resources/dokka/scripts/navigationLoader.js41
-rw-r--r--core/src/main/resources/dokka/scripts/search.js10
-rw-r--r--core/src/main/resources/dokka/styles/style.css345
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt54
-rw-r--r--plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt3
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt84
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt1
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt2
-rw-r--r--plugins/base/src/main/kotlin/resolvers/DefaultLocationProvider.kt116
-rw-r--r--plugins/base/src/main/kotlin/resolvers/ExternalLocationProvider.kt99
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/DokkaExternalLocationProviderFactory.kt35
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/ExternalLocationProviderFactory.kt23
-rw-r--r--plugins/base/src/main/kotlin/resolvers/external/JavadocExternalLocationProviderFactory.kt37
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt222
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProviderFactory.kt (renamed from plugins/base/src/main/kotlin/resolvers/DefaultLocationProviderFactory.kt)5
-rw-r--r--plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt (renamed from plugins/base/src/main/kotlin/resolvers/LocationProvider.kt)3
-rw-r--r--plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt134
-rw-r--r--plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt149
-rw-r--r--plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilter.kt317
-rw-r--r--plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt73
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/annotations/DeprecatedStrikethroughTransformer.kt57
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt12
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt308
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultDocumentableToPageTranslator.kt4
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt178
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt25
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt189
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt35
-rw-r--r--plugins/base/src/test/kotlin/basic/DRITest.kt5
-rw-r--r--plugins/base/src/test/kotlin/basic/DokkaBasicTests.kt9
-rw-r--r--plugins/base/src/test/kotlin/enums/EnumsTest.kt31
-rw-r--r--plugins/base/src/test/kotlin/expect/AbstractExpectTest.kt104
-rw-r--r--plugins/base/src/test/kotlin/expect/ExpectGenerator.kt15
-rw-r--r--plugins/base/src/test/kotlin/expect/ExpectTest.kt70
-rw-r--r--plugins/base/src/test/kotlin/expect/ExpectUtils.kt28
-rw-r--r--plugins/base/src/test/kotlin/issues/IssuesTest.kt34
-rw-r--r--plugins/base/src/test/kotlin/markdown/KDocTest.kt10
-rw-r--r--plugins/base/src/test/kotlin/markdown/LinkTest.kt46
-rw-r--r--plugins/base/src/test/kotlin/markdown/ParserTest.kt761
-rw-r--r--plugins/base/src/test/kotlin/model/ClassesTest.kt294
-rw-r--r--plugins/base/src/test/kotlin/model/CommentTest.kt34
-rw-r--r--plugins/base/src/test/kotlin/model/FunctionsTest.kt376
-rw-r--r--plugins/base/src/test/kotlin/model/InheritorsTest.kt94
-rw-r--r--plugins/base/src/test/kotlin/model/JavaTest.kt164
-rw-r--r--plugins/base/src/test/kotlin/model/PackagesTest.kt18
-rw-r--r--plugins/base/src/test/kotlin/model/PropertyTest.kt108
-rw-r--r--plugins/base/src/test/kotlin/multiplatform/BasicMultiplatformTest.kt4
-rw-r--r--plugins/base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt29
-rw-r--r--plugins/base/src/test/kotlin/renderers/RenderingOnlyTestBase.kt44
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/GroupWrappingTest.kt14
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/PlatformDependentHintTest.kt24
-rw-r--r--plugins/base/src/test/kotlin/transformerBuilders/PageTransformerBuilderTest.kt150
-rw-r--r--plugins/base/src/test/kotlin/utils/ModelUtils.kt24
-rw-r--r--plugins/base/src/test/kotlin/utils/TestUtils.kt27
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/arrow_down.svg (renamed from plugins/base/src/test/resources/expect/test/out/images/arrow_down.svg)0
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/logo-icon.svg (renamed from plugins/base/src/test/resources/expect/test/out/images/logo-icon.svg)0
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/images/logo-text.svg (renamed from plugins/base/src/test/resources/expect/test/out/images/logo-text.svg)0
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/scripts.js (renamed from plugins/base/src/test/resources/expect/test/out/scripts/scripts.js)0
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunction/src/annotatedFunction.kt2
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/navigation.html13
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/-init-.html26
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/equals.html26
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/hash-code.html26
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/index.html64
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/-fancy/to-string.html26
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/root/index.html50
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/pages.js10
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/annotatedFunctionWithAnnotationParameters/src/annotatedFunctionWithAnnotationParameters.kt7
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/navigation.html (renamed from plugins/base/src/test/resources/expect/test/out/navigation.html)6
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/root/fn.html27
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/scripts/pages.js (renamed from plugins/base/src/test/resources/expect/test/out/scripts/pages.js)0
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/function/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/function/src/function.kt (renamed from plugins/base/src/test/resources/expect/test/src/function.kt)0
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/navigation.html13
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/-init-.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/equals.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/hash-code.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/index.html51
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/-fancy/to-string.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/function.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/root/index.html50
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/pages.js10
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/functionWithAnnotatedParam/src/functionWithAnnotatedParam.kt7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/functionWithDefaultParameter/src/functionWithDefaultParameter.kt1
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/function.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNoinlineParam/src/functionWithNoinlineParam.kt2
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/functionWithNotDocumentedAnnotation/src/functionWithNotDocumentedAnnotation.kt2
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/root/function.html27
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/functionWithParams/src/functionWithParams.kt8
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/fn.html29
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/root/index.html44
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/functionWithReceiver/src/functionWithReceiver.kt11
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/root/generic.html27
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/genericFunction/src/genericFunction.kt5
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/generic.html27
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/genericFunctionWithConstraints/src/genericFunctionWithConstraints.kt6
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/inlineFunction/src/inlineFunction.kt2
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/inlineSuspendFunction/src/inlineSuspendFunction.kt2
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/-search.html (renamed from plugins/base/src/test/resources/expect/test/out/-search.html)0
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/navigation.html13
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/root/index.html35
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/index.html44
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test.html26
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/root/signatureTest/test2.html26
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/pages.js6
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/navigation.html13
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/root/index.html30
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/index.html36
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/test.html (renamed from plugins/base/src/test/resources/expect/test/out/root/index.html)13
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/out/root/signatureTest/test2.html (renamed from plugins/base/src/test/resources/expect/test/out/root/fn.html)21
-rw-r--r--plugins/base/src/test/resources/expect/signatureTest/src/signature.kt4
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/available-since1.1.html27
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/sinceKotlin/src/sinceKotlin.kt5
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/suspendFunction/src/suspendFunction.kt2
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/-search.html28
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/arrow_down.svg3
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/docs_logo.svg7
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-icon.svg3
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/images/logo-text.svg6
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/navigation.html10
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/f.html26
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/root/index.html38
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/navigationLoader.js41
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/pages.js5
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/scripts.js11
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/scripts/search.js7
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/out/html/styles/style.css417
-rw-r--r--plugins/base/src/test/resources/expect/suspendInlineFunction/src/suspendInlineFunction.kt2
-rw-r--r--plugins/base/src/test/resources/expect/test/out/scripts/navigationLoader.js12
-rw-r--r--plugins/base/src/test/resources/expect/test/out/scripts/search.js5
-rw-r--r--plugins/base/src/test/resources/expect/test/out/styles/style.css353
-rw-r--r--plugins/build.gradle.kts10
-rw-r--r--plugins/gfm/build.gradle.kts8
-rw-r--r--plugins/gfm/src/main/kotlin/GfmPlugin.kt196
-rw-r--r--plugins/gfm/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin1
-rw-r--r--plugins/jekyll/build.gradle.kts8
-rw-r--r--plugins/jekyll/src/main/kotlin/JekyllPlugin.kt182
-rw-r--r--plugins/jekyll/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin1
-rw-r--r--plugins/kotlin-as-java/build.gradle.kts12
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt135
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt56
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt4
-rw-r--r--plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt31
-rw-r--r--runners/cli/src/main/kotlin/cli/main.kt74
-rw-r--r--runners/gradle-plugin/build.gradle.kts1
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt56
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt37
-rw-r--r--runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/main.kt40
-rw-r--r--runners/maven-plugin/build.gradle.kts11
-rw-r--r--runners/maven-plugin/src/main/kotlin/DokkaMojo.kt134
-rw-r--r--testApi/src/main/kotlin/testApi/context/MockContext.kt8
-rw-r--r--testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt7
-rw-r--r--testApi/src/main/kotlin/testApi/testRunner/TestRunner.kt40
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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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>&lt;init&gt;</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/&lt;init&gt;/#kotlin.Int//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="-init-.html">&lt;init&gt;</a>
+ <h1>&lt;init&gt;</h1>
+<div class="symbol monospace">final fun <a href="-init-.html">&lt;init&gt;</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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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>&lt;init&gt;</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/&lt;init&gt;/#//">//<a href="../../index.html">root</a>/<a href="../index.html"></a>/<a href="index.html">Fancy</a>/<a href="-init-.html">&lt;init&gt;</a>
+ <h1>&lt;init&gt;</h1>
+<div class="symbol monospace">final fun <a href="-init-.html">&lt;init&gt;</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">() -&gt; <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">() -&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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">() -&gt; <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">() -&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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 &lt;<a href="generic.html">T</a> : <a href="">Any</a>&gt; <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 &lt;<a href="generic.html">T</a> : <a href="">Any</a>&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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 &lt;<a href="generic.html">T</a> : R, <a href="generic.html">R</a> : <a href="">Any</a>&gt; <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 &lt;<a href="generic.html">T</a> : R, <a href="generic.html">R</a> : <a href="">Any</a>&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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">() -&gt; <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">() -&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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">() -&gt; <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">() -&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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>) -&gt; <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>) -&gt; <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>) -&gt; <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>) -&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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>) -&gt; <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>) -&gt; <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>) -&gt; <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>) -&gt; <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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu&quot;).classList.toggle(&quot;hidden&quot;);"><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(&quot;nav-submenu-0&quot;).classList.toggle(&quot;hidden&quot;);"><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">() -&gt; <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">() -&gt; <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