Split JavaLayoutHtml to separate files
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
new file mode 100644
index 0000000..1db979d
--- /dev/null
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormat.kt
@@ -0,0 +1,111 @@
+package org.jetbrains.dokka.Formats
+
+import com.google.inject.Binder
+import kotlinx.html.*
+import org.jetbrains.dokka.*
+import org.jetbrains.dokka.Utilities.bind
+import org.jetbrains.dokka.Utilities.lazyBind
+import org.jetbrains.dokka.Utilities.toOptional
+import org.jetbrains.dokka.Utilities.toType
+import java.net.URI
+import java.net.URLEncoder
+import kotlin.reflect.KClass
+
+
+abstract class JavaLayoutHtmlFormatDescriptorBase : FormatDescriptor, DefaultAnalysisComponent {
+
+ override fun configureOutput(binder: Binder): Unit = with(binder) {
+ bind<Generator>() toType generatorServiceClass
+ bind<LanguageService>() toType languageServiceClass
+ bind<JavaLayoutHtmlTemplateService>() toType templateServiceClass
+ bind<JavaLayoutHtmlUriProvider>() toType generatorServiceClass
+ lazyBind<JavaLayoutHtmlFormatOutlineFactoryService>() toOptional outlineFactoryClass
+ bind<PackageListService>() toType packageListServiceClass
+ }
+
+ val generatorServiceClass = JavaLayoutHtmlFormatGenerator::class
+ abstract val languageServiceClass: KClass<out LanguageService>
+ abstract val templateServiceClass: KClass<out JavaLayoutHtmlTemplateService>
+ abstract val outlineFactoryClass: KClass<out JavaLayoutHtmlFormatOutlineFactoryService>?
+ abstract val packageListServiceClass: KClass<out PackageListService>
+}
+
+class JavaLayoutHtmlFormatDescriptor : JavaLayoutHtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsKotlin {
+ override val packageListServiceClass: KClass<out PackageListService>
+ get() = TODO("not implemented")
+ override val languageServiceClass = KotlinLanguageService::class
+ override val templateServiceClass = JavaLayoutHtmlTemplateService.Default::class
+ override val outlineFactoryClass = null
+}
+
+interface JavaLayoutHtmlFormatOutlineFactoryService {
+ fun generateOutlines(outputProvider: (URI) -> Appendable, nodes: Iterable<DocumentationNode>)
+}
+
+
+interface JavaLayoutHtmlUriProvider {
+ fun tryGetContainerUri(node: DocumentationNode): URI?
+ fun tryGetMainUri(node: DocumentationNode): URI?
+ fun containerUri(node: DocumentationNode): URI = tryGetContainerUri(node) ?: error("Unsupported ${node.kind}")
+ fun mainUri(node: DocumentationNode): URI = tryGetMainUri(node) ?: error("Unsupported ${node.kind}")
+
+ fun linkTo(to: DocumentationNode, from: URI): String {
+ return mainUri(to).relativeTo(from).toString()
+ }
+
+ fun mainUriOrWarn(node: DocumentationNode): URI? = tryGetMainUri(node) ?: (null).also {
+ AssertionError("Not implemented mainUri for ${node.kind}").printStackTrace()
+ }
+}
+
+
+interface JavaLayoutHtmlTemplateService {
+ fun composePage(
+ nodes: List<DocumentationNode>,
+ tagConsumer: TagConsumer<Appendable>,
+ headContent: HEAD.() -> Unit,
+ bodyContent: BODY.() -> Unit
+ )
+
+ class Default : JavaLayoutHtmlTemplateService {
+ override fun composePage(
+ nodes: List<DocumentationNode>,
+ tagConsumer: TagConsumer<Appendable>,
+ headContent: HEAD.() -> Unit,
+ bodyContent: BODY.() -> Unit
+ ) {
+ tagConsumer.html {
+ head {
+ meta(charset = "UTF-8")
+ headContent()
+ }
+ body(block = bodyContent)
+ }
+ }
+ }
+}
+
+
+fun DocumentationNode.signatureForAnchor(logger: DokkaLogger): String = when (kind) {
+ NodeKind.Function, NodeKind.Constructor -> buildString {
+ detailOrNull(NodeKind.Receiver)?.let {
+ append("(")
+ append(it.detail(NodeKind.Type).qualifiedNameFromType())
+ append(").")
+ }
+ append(name)
+ details(NodeKind.Parameter).joinTo(this, prefix = "(", postfix = ")") { it.detail(NodeKind.Type).qualifiedNameFromType() }
+ }
+ NodeKind.Property ->
+ "$name:${detail(NodeKind.Type).qualifiedNameFromType()}"
+ NodeKind.TypeParameter, NodeKind.Parameter -> owner!!.signatureForAnchor(logger) + "/" + name
+ else -> "Not implemented signatureForAnchor $this".also { logger.warn(it) }
+}
+
+
+fun String.urlEncoded(): String = URLEncoder.encode(this, "UTF-8")
+
+fun DocumentationNode.classNodeNameWithOuterClass(): String {
+ assert(kind in NodeKind.classLike)
+ return path.dropWhile { it.kind == NodeKind.Package || it.kind == NodeKind.Module }.joinToString(separator = ".") { it.name }
+}
\ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
similarity index 60%
rename from core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt
rename to core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
index 446ff9e..84778d0 100644
--- a/core/src/main/kotlin/Formats/JavaLayoutHtmlFormat.kt
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlFormatOutputBuilder.kt
@@ -1,8 +1,5 @@
package org.jetbrains.dokka.Formats
-import com.google.inject.Binder
-import com.google.inject.Inject
-import com.google.inject.name.Named
import kotlinx.html.*
import kotlinx.html.Entities.nbsp
import kotlinx.html.stream.appendHTML
@@ -10,73 +7,10 @@
import org.jetbrains.dokka.LanguageService.RenderMode.FULL
import org.jetbrains.dokka.LanguageService.RenderMode.SUMMARY
import org.jetbrains.dokka.NodeKind.Companion.classLike
-import org.jetbrains.dokka.NodeKind.Companion.memberLike
-import org.jetbrains.dokka.Utilities.bind
-import org.jetbrains.dokka.Utilities.lazyBind
-import org.jetbrains.dokka.Utilities.toOptional
-import org.jetbrains.dokka.Utilities.toType
-import org.jetbrains.kotlin.preprocessor.mkdirsOrFail
-import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
-import java.io.BufferedWriter
-import java.io.File
import java.net.URI
import java.net.URLEncoder
-import kotlin.reflect.KClass
-abstract class JavaLayoutHtmlFormatDescriptorBase : FormatDescriptor, DefaultAnalysisComponent {
-
- override fun configureOutput(binder: Binder): Unit = with(binder) {
- bind<Generator>() toType generatorServiceClass
- bind<LanguageService>() toType languageServiceClass
- bind<JavaLayoutHtmlTemplateService>() toType templateServiceClass
- bind<JavaLayoutHtmlUriProvider>() toType generatorServiceClass
- lazyBind<JavaLayoutHtmlFormatOutlineFactoryService>() toOptional outlineFactoryClass
- }
-
- val generatorServiceClass = JavaLayoutHtmlFormatGenerator::class
- abstract val languageServiceClass: KClass<out LanguageService>
- abstract val templateServiceClass: KClass<out JavaLayoutHtmlTemplateService>
- abstract val outlineFactoryClass: KClass<out JavaLayoutHtmlFormatOutlineFactoryService>?
-}
-
-class JavaLayoutHtmlFormatDescriptor : JavaLayoutHtmlFormatDescriptorBase(), DefaultAnalysisComponentServices by KotlinAsKotlin {
- override val languageServiceClass = KotlinLanguageService::class
- override val templateServiceClass = JavaLayoutHtmlTemplateService.Default::class
- override val outlineFactoryClass = null
-}
-
-
-interface JavaLayoutHtmlTemplateService {
- fun composePage(
- nodes: List<DocumentationNode>,
- tagConsumer: TagConsumer<Appendable>,
- headContent: HEAD.() -> Unit,
- bodyContent: BODY.() -> Unit
- )
-
- class Default : JavaLayoutHtmlTemplateService {
- override fun composePage(
- nodes: List<DocumentationNode>,
- tagConsumer: TagConsumer<Appendable>,
- headContent: HEAD.() -> Unit,
- bodyContent: BODY.() -> Unit
- ) {
- tagConsumer.html {
- head {
- meta(charset = "UTF-8")
- headContent()
- }
- body(block = bodyContent)
- }
- }
- }
-}
-
-interface JavaLayoutHtmlFormatOutlineFactoryService {
- fun generateOutlines(outputProvider: (URI) -> Appendable, nodes: Iterable<DocumentationNode>)
-}
-
class JavaLayoutHtmlFormatOutputBuilder(
val output: Appendable,
val languageService: LanguageService,
@@ -471,192 +405,4 @@
is ContentBlock -> appendContent(content.children)
}
}
-}
-
-
-interface JavaLayoutHtmlUriProvider {
- fun tryGetContainerUri(node: DocumentationNode): URI?
- fun tryGetMainUri(node: DocumentationNode): URI?
- fun containerUri(node: DocumentationNode): URI = tryGetContainerUri(node) ?: error("Unsupported ${node.kind}")
- fun mainUri(node: DocumentationNode): URI = tryGetMainUri(node) ?: error("Unsupported ${node.kind}")
-
- fun linkTo(to: DocumentationNode, from: URI): String {
- return mainUri(to).relativeTo(from).toString()
- }
-
- fun mainUriOrWarn(node: DocumentationNode): URI? = tryGetMainUri(node) ?: (null).also {
- AssertionError("Not implemented mainUri for ${node.kind}").printStackTrace()
- }
-}
-
-class JavaLayoutHtmlFormatGenerator @Inject constructor(
- @Named("outputDir") val root: File,
- val languageService: LanguageService,
- val templateService: JavaLayoutHtmlTemplateService,
- val logger: DokkaLogger
-) : Generator, JavaLayoutHtmlUriProvider {
-
- @set:Inject(optional = true)
- var outlineFactoryService: JavaLayoutHtmlFormatOutlineFactoryService? = null
-
- fun createOutputBuilderForNode(node: DocumentationNode, output: Appendable)
- = JavaLayoutHtmlFormatOutputBuilder(output, languageService, this, templateService, logger, mainUri(node))
-
- override fun tryGetContainerUri(node: DocumentationNode): URI? {
- return when (node.kind) {
- NodeKind.Module -> URI("/").resolve(node.name + "/")
- NodeKind.Package -> tryGetContainerUri(node.owner!!)?.resolve(node.name.replace('.', '/') + '/')
- in classLike -> tryGetContainerUri(node.owner!!)?.resolve("${node.classNodeNameWithOuterClass()}.html")
- else -> null
- }
- }
-
- override fun tryGetMainUri(node: DocumentationNode): URI? {
- return when (node.kind) {
- NodeKind.Package -> tryGetContainerUri(node)?.resolve("package-summary.html")
- in classLike -> tryGetContainerUri(node)?.resolve("#")
- in memberLike -> {
- val owner = if (node.owner?.kind != NodeKind.ExternalClass) node.owner else node.owner?.owner
- tryGetMainUri(owner!!)?.resolveInPage(node)
- }
- NodeKind.TypeParameter, NodeKind.Parameter -> node.path.asReversed().drop(1).firstNotNullResult(this::tryGetMainUri)?.resolveInPage(node)
- NodeKind.AllTypes -> tryGetContainerUri(node.owner!!)?.resolve("classes.html")
- else -> null
- }
- }
-
- fun URI.resolveInPage(node: DocumentationNode): URI = resolve("#${node.signatureUrlEncoded(logger)}")
-
- fun buildClass(node: DocumentationNode, parentDir: File) {
- val fileForClass = parentDir.resolve(node.classNodeNameWithOuterClass() + ".html")
- fileForClass.bufferedWriter().use {
- createOutputBuilderForNode(node, it).appendClassLike(node)
- }
- for (memberClass in node.members.filter { it.kind in classLike }) {
- buildClass(memberClass, parentDir)
- }
- }
-
- fun buildPackage(node: DocumentationNode, parentDir: File) {
- assert(node.kind == NodeKind.Package)
- val members = node.members
- val directoryForPackage = parentDir.resolve(node.name.replace('.', File.separatorChar))
- directoryForPackage.mkdirsOrFail()
-
- directoryForPackage.resolve("package-summary.html").bufferedWriter().use {
- createOutputBuilderForNode(node, it).appendPackage(node)
- }
-
- members.filter { it.kind in classLike }.forEach {
- buildClass(it, directoryForPackage)
- }
- }
-
- fun buildClassIndex(node: DocumentationNode, parentDir: File) {
- val file = parentDir.resolve("classes.html")
- file.bufferedWriter().use {
- createOutputBuilderForNode(node, it).generateClassesIndex(node)
- }
- }
-
- fun buildPackageIndex(nodes: List<DocumentationNode>, parentDir: File) {
- val file = parentDir.resolve("packages.html")
- file.bufferedWriter().use {
- JavaLayoutHtmlFormatOutputBuilder(it, languageService, this, templateService, logger, containerUri(nodes.first().owner!!).resolve("packages.html"))
- .generatePackageIndex(nodes)
- }
- }
-
- override fun buildPages(nodes: Iterable<DocumentationNode>) {
- val module = nodes.single()
-
- val moduleRoot = root.resolve(module.name)
- val packages = module.members.filter { it.kind == NodeKind.Package }
- packages.forEach { buildPackage(it, moduleRoot) }
-
- buildClassIndex(module.members.single { it.kind == NodeKind.AllTypes }, moduleRoot)
- buildPackageIndex(packages, moduleRoot)
- }
-
- override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
- val uriToWriter = mutableMapOf<URI, BufferedWriter>()
-
- fun provideOutput(uri: URI): BufferedWriter {
- val normalized = uri.normalize()
- uriToWriter[normalized]?.let { return it }
- val file = root.resolve(normalized.path.removePrefix("/"))
- val writer = file.bufferedWriter()
- uriToWriter[normalized] = writer
- return writer
- }
-
- outlineFactoryService?.generateOutlines(::provideOutput, nodes)
-
- uriToWriter.values.forEach { it.close() }
- }
-
- override fun buildSupportFiles() {}
-
- override fun buildPackageList(nodes: Iterable<DocumentationNode>) {
-
- }
-}
-
-fun DocumentationNode.signatureForAnchor(logger: DokkaLogger): String = when (kind) {
- NodeKind.Function, NodeKind.Constructor -> buildString {
- detailOrNull(NodeKind.Receiver)?.let {
- append("(")
- append(it.detail(NodeKind.Type).qualifiedNameFromType())
- append(").")
- }
- append(name)
- details(NodeKind.Parameter).joinTo(this, prefix = "(", postfix = ")") { it.detail(NodeKind.Type).qualifiedNameFromType() }
- }
- NodeKind.Property ->
- "$name:${detail(NodeKind.Type).qualifiedNameFromType()}"
- NodeKind.TypeParameter, NodeKind.Parameter -> owner!!.signatureForAnchor(logger) + "/" + name
- else -> "Not implemented signatureForAnchor $this".also { logger.warn(it) }
-}
-
-fun DocumentationNode.signatureUrlEncoded(logger: DokkaLogger) = URLEncoder.encode(signatureForAnchor(logger), "UTF-8")
-
-fun DocumentationNode.classNodeNameWithOuterClass(): String {
- assert(kind in NodeKind.classLike)
- return path.dropWhile { it.kind == NodeKind.Package || it.kind == NodeKind.Module }.joinToString(separator = ".") { it.name }
-}
-
-fun URI.relativeTo(uri: URI): URI {
- // Normalize paths to remove . and .. segments
- val base = uri.normalize()
- val child = this.normalize()
-
- fun StringBuilder.appendRelativePath() {
- // Split paths into segments
- var bParts = base.path.split('/').dropLastWhile { it.isEmpty() }
- val cParts = child.path.split('/').dropLastWhile { it.isEmpty() }
-
- // Discard trailing segment of base path
- if (bParts.isNotEmpty() && !base.path.endsWith("/")) {
- bParts = bParts.dropLast(1)
- }
-
- // Compute common prefix
- val commonPartsSize = bParts.zip(cParts).count { (basePart, childPart) -> basePart == childPart }
- bParts.drop(commonPartsSize).joinTo(this, separator = "") { "../" }
- cParts.drop(commonPartsSize).joinTo(this, separator = "/")
- }
-
- return URI.create(buildString {
- if (base.path != child.path) {
- appendRelativePath()
- }
- child.rawQuery?.let {
- append("?")
- append(it)
- }
- child.rawFragment?.let {
- append("#")
- append(it)
- }
- })
}
\ No newline at end of file
diff --git a/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt
new file mode 100644
index 0000000..fcb26c7
--- /dev/null
+++ b/core/src/main/kotlin/Formats/JavaLayoutHtml/JavaLayoutHtmlGenerator.kt
@@ -0,0 +1,124 @@
+package org.jetbrains.dokka.Formats
+
+import com.google.inject.Inject
+import com.google.inject.name.Named
+import org.jetbrains.dokka.*
+import org.jetbrains.kotlin.preprocessor.mkdirsOrFail
+import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
+import java.io.BufferedWriter
+import java.io.File
+import java.net.URI
+
+
+class JavaLayoutHtmlFormatGenerator @Inject constructor(
+ @Named("outputDir") val root: File,
+ val languageService: LanguageService,
+ val templateService: JavaLayoutHtmlTemplateService,
+ val logger: DokkaLogger
+) : Generator, JavaLayoutHtmlUriProvider {
+
+ @set:Inject(optional = true)
+ var outlineFactoryService: JavaLayoutHtmlFormatOutlineFactoryService? = null
+
+ fun createOutputBuilderForNode(node: DocumentationNode, output: Appendable)
+ = JavaLayoutHtmlFormatOutputBuilder(output, languageService, this, templateService, logger, mainUri(node))
+
+ override fun tryGetContainerUri(node: DocumentationNode): URI? {
+ return when (node.kind) {
+ NodeKind.Module -> URI("/").resolve(node.name + "/")
+ NodeKind.Package -> tryGetContainerUri(node.owner!!)?.resolve(node.name.replace('.', '/') + '/')
+ in NodeKind.classLike -> tryGetContainerUri(node.owner!!)?.resolve("${node.classNodeNameWithOuterClass()}.html")
+ else -> null
+ }
+ }
+
+ override fun tryGetMainUri(node: DocumentationNode): URI? {
+ return when (node.kind) {
+ NodeKind.Package -> tryGetContainerUri(node)?.resolve("package-summary.html")
+ in NodeKind.classLike -> tryGetContainerUri(node)?.resolve("#")
+ in NodeKind.memberLike -> {
+ val owner = if (node.owner?.kind != NodeKind.ExternalClass) node.owner else node.owner?.owner
+ tryGetMainUri(owner!!)?.resolveInPage(node)
+ }
+ NodeKind.TypeParameter, NodeKind.Parameter -> node.path.asReversed().drop(1).firstNotNullResult(this::tryGetMainUri)?.resolveInPage(node)
+ NodeKind.AllTypes -> tryGetContainerUri(node.owner!!)?.resolve("classes.html")
+ else -> null
+ }
+ }
+
+ fun URI.resolveInPage(node: DocumentationNode): URI = resolve("#${node.signatureForAnchor(logger).urlEncoded()}")
+
+ fun buildClass(node: DocumentationNode, parentDir: File) {
+ val fileForClass = parentDir.resolve(node.classNodeNameWithOuterClass() + ".html")
+ fileForClass.bufferedWriter().use {
+ createOutputBuilderForNode(node, it).appendClassLike(node)
+ }
+ for (memberClass in node.members.filter { it.kind in NodeKind.classLike }) {
+ buildClass(memberClass, parentDir)
+ }
+ }
+
+ fun buildPackage(node: DocumentationNode, parentDir: File) {
+ assert(node.kind == NodeKind.Package)
+ val members = node.members
+ val directoryForPackage = parentDir.resolve(node.name.replace('.', File.separatorChar))
+ directoryForPackage.mkdirsOrFail()
+
+ directoryForPackage.resolve("package-summary.html").bufferedWriter().use {
+ createOutputBuilderForNode(node, it).appendPackage(node)
+ }
+
+ members.filter { it.kind in NodeKind.classLike }.forEach {
+ buildClass(it, directoryForPackage)
+ }
+ }
+
+ fun buildClassIndex(node: DocumentationNode, parentDir: File) {
+ val file = parentDir.resolve("classes.html")
+ file.bufferedWriter().use {
+ createOutputBuilderForNode(node, it).generateClassesIndex(node)
+ }
+ }
+
+ fun buildPackageIndex(nodes: List<DocumentationNode>, parentDir: File) {
+ val file = parentDir.resolve("packages.html")
+ file.bufferedWriter().use {
+ JavaLayoutHtmlFormatOutputBuilder(it, languageService, this, templateService, logger, containerUri(nodes.first().owner!!).resolve("packages.html"))
+ .generatePackageIndex(nodes)
+ }
+ }
+
+ override fun buildPages(nodes: Iterable<DocumentationNode>) {
+ val module = nodes.single()
+
+ val moduleRoot = root.resolve(module.name)
+ val packages = module.members.filter { it.kind == NodeKind.Package }
+ packages.forEach { buildPackage(it, moduleRoot) }
+
+ buildClassIndex(module.members.single { it.kind == NodeKind.AllTypes }, moduleRoot)
+ buildPackageIndex(packages, moduleRoot)
+ }
+
+ override fun buildOutlines(nodes: Iterable<DocumentationNode>) {
+ val uriToWriter = mutableMapOf<URI, BufferedWriter>()
+
+ fun provideOutput(uri: URI): BufferedWriter {
+ val normalized = uri.normalize()
+ uriToWriter[normalized]?.let { return it }
+ val file = root.resolve(normalized.path.removePrefix("/"))
+ val writer = file.bufferedWriter()
+ uriToWriter[normalized] = writer
+ return writer
+ }
+
+ outlineFactoryService?.generateOutlines(::provideOutput, nodes)
+
+ uriToWriter.values.forEach { it.close() }
+ }
+
+ override fun buildSupportFiles() {}
+
+ override fun buildPackageList(nodes: Iterable<DocumentationNode>) {
+
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/kotlin/Utilities/Uri.kt b/core/src/main/kotlin/Utilities/Uri.kt
new file mode 100644
index 0000000..5b52018
--- /dev/null
+++ b/core/src/main/kotlin/Utilities/Uri.kt
@@ -0,0 +1,40 @@
+package org.jetbrains.dokka
+
+import java.net.URI
+
+
+fun URI.relativeTo(uri: URI): URI {
+ // Normalize paths to remove . and .. segments
+ val base = uri.normalize()
+ val child = this.normalize()
+
+ fun StringBuilder.appendRelativePath() {
+ // Split paths into segments
+ var bParts = base.path.split('/').dropLastWhile { it.isEmpty() }
+ val cParts = child.path.split('/').dropLastWhile { it.isEmpty() }
+
+ // Discard trailing segment of base path
+ if (bParts.isNotEmpty() && !base.path.endsWith("/")) {
+ bParts = bParts.dropLast(1)
+ }
+
+ // Compute common prefix
+ val commonPartsSize = bParts.zip(cParts).count { (basePart, childPart) -> basePart == childPart }
+ bParts.drop(commonPartsSize).joinTo(this, separator = "") { "../" }
+ cParts.drop(commonPartsSize).joinTo(this, separator = "/")
+ }
+
+ return URI.create(buildString {
+ if (base.path != child.path) {
+ appendRelativePath()
+ }
+ child.rawQuery?.let {
+ append("?")
+ append(it)
+ }
+ child.rawFragment?.let {
+ append("#")
+ append(it)
+ }
+ })
+}
\ No newline at end of file