diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt index 8f1cf5614ac..7bb34789792 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt @@ -5,8 +5,8 @@ package org.jetbrains.kotlin.gradle -import org.jetbrains.kotlin.gradle.internals.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME -import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromXml +import org.jetbrains.kotlin.gradle.internals.MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME +import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromJson import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleDependencyIdentifier @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.gradle.util.checkedReplace import org.jetbrains.kotlin.gradle.util.modify import java.io.File import java.util.zip.ZipFile -import javax.xml.parsers.DocumentBuilderFactory import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -216,7 +215,7 @@ class HierarchicalMppIT : BaseGradleIT() { ) ).use { publishedMetadataJar -> publishedMetadataJar.checkAllEntryNamesArePresent( - "META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME", + "META-INF/$MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME", "commonMain/default/manifest", "commonMain/default/linkdata/package_com.example/", @@ -254,7 +253,7 @@ class HierarchicalMppIT : BaseGradleIT() { ) ).use { publishedMetadataJar -> publishedMetadataJar.checkAllEntryNamesArePresent( - "META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME", + "META-INF/$MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME", "commonMain/default/manifest", "commonMain/default/linkdata/package_com.example.bar/", @@ -441,10 +440,8 @@ class HierarchicalMppIT : BaseGradleIT() { } private fun ZipFile.getProjectStructureMetadata(): KotlinProjectStructureMetadata { - val documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder() - val document = getInputStream(getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME")) - .use { inputStream -> documentBuilder.parse(inputStream) } - return checkNotNull(parseKotlinSourceSetMetadataFromXml(document)) + val json = getInputStream(getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME")).reader().readText() + return checkNotNull(parseKotlinSourceSetMetadataFromJson(json)) } @Test diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt index b78e49dede1..3f54f846aad 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GenerateProjectStructureMetadata.kt @@ -26,19 +26,15 @@ open class GenerateProjectStructureMetadata : DefaultTask() { @get:OutputFile val resultXmlFile: File - get() = project.buildDir.resolve("kotlinProjectStructureMetadata/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME") + get() = project.buildDir.resolve("kotlinProjectStructureMetadata/$MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME") @TaskAction fun generateMetadataXml() { resultXmlFile.parentFile.mkdirs() - - val document = kotlinProjectStructureMetadata.toXmlDocument() - - TransformerFactory.newInstance().newTransformer().apply { - setOutputProperty(OutputKeys.INDENT, "yes") - setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4") - }.transform(DOMSource(document), StreamResult(resultXmlFile)) + val resultString = kotlinProjectStructureMetadata.toJson() + resultXmlFile.writeText(resultString) } } -internal const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = "kotlin-project-structure-metadata.xml" \ No newline at end of file +internal const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = "kotlin-project-structure-metadata.xml" +internal const val MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME = "kotlin-project-structure-metadata.json" \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index b7904cd240f..006cf3e15da 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope import java.io.File +import java.io.InputStream import java.util.* import java.util.zip.ZipEntry import java.util.zip.ZipFile @@ -344,16 +345,20 @@ private class JarArtifactMppDependencyMetadataExtractor( val metadataArtifactBySourceSet: MutableMap = mutableMapOf() + private fun parseJsonProjectStructureMetadata(input: InputStream) = + parseKotlinSourceSetMetadataFromJson(input.reader().readText()) + + private fun parseXmlProjectStructureMetadata(input: InputStream) = + parseKotlinSourceSetMetadataFromXml(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input)) + override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? { return ZipFile(primaryArtifact).use { zip -> - val metadata = zip.getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME") - ?: return null + val (metadata, parseFunction) = + zip.getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME")?.to(::parseJsonProjectStructureMetadata) + ?: zip.getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME")?.to(::parseXmlProjectStructureMetadata) + ?: return null - val metadataXmlDocument = zip.getInputStream(metadata).use { inputStream -> - DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream) - } - - parseKotlinSourceSetMetadataFromXml(metadataXmlDocument) + zip.getInputStream(metadata).use(parseFunction) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 56bcaacbbab..50cf8d9203f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -5,6 +5,10 @@ package org.jetbrains.kotlin.gradle.plugin.mpp +import com.google.gson.GsonBuilder +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.google.gson.stream.JsonWriter import org.gradle.api.Project import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal @@ -18,6 +22,7 @@ import org.w3c.dom.Document import org.w3c.dom.Element import org.w3c.dom.Node import org.w3c.dom.NodeList +import java.io.StringWriter import javax.xml.parsers.DocumentBuilderFactory data class ModuleDependencyIdentifier( @@ -34,6 +39,8 @@ sealed class SourceSetMetadataLayout( object METADATA : SourceSetMetadataLayout("metadata", "jar") object KLIB : SourceSetMetadataLayout("klib", "klib") + override fun toString(): String = name + companion object { private val values = listOf(METADATA, KLIB) @@ -119,41 +126,40 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec ) } -internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document { - return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().apply { - fun Node.node(name: String, action: Element.() -> Unit) = appendChild(createElement(name).apply(action)) - fun Node.textNode(name: String, value: String) = - appendChild(createElement(name).apply { appendChild(createTextNode(value)) }) +internal fun KotlinProjectStructureMetadata.serialize( + serializer: Serializer, + node: Serializer.(name: String, Serializer.() -> Unit) -> Unit, + multiNodes: Serializer.(name: String, Serializer.() -> Unit) -> Unit, + multiNodesItem: Serializer.(name: String, Serializer.() -> Unit) -> Unit, + value: Serializer.(key: String, value: String) -> Unit, + multiValue: Serializer.(name: String, values: List) -> Unit +) = with(serializer) { + node(ROOT_NODE_NAME) { + value(FORMAT_VERSION_NODE_NAME, formatVersion) - node(ROOT_NODE_NAME) { - textNode(FORMAT_VERSION_NODE_NAME, formatVersion) - - node(VARIANTS_NODE_NAME) { - sourceSetNamesByVariantName.forEach { (variantName, sourceSets) -> - node(VARIANT_NODE_NAME) { - textNode(NAME_NODE_NAME, variantName) - sourceSets.forEach { sourceSetName -> textNode(SOURCE_SET_NODE_NAME, sourceSetName) } - } + multiNodes(VARIANTS_NODE_NAME) { + sourceSetNamesByVariantName.forEach { (variantName, sourceSets) -> + multiNodesItem(VARIANT_NODE_NAME) { + value(NAME_NODE_NAME, variantName) + multiValue(SOURCE_SET_NODE_NAME, sourceSets.toList()) } } + } - node(SOURCE_SETS_NODE_NAME) { - val keys = sourceSetsDependsOnRelation.keys + sourceSetModuleDependencies.keys - for (sourceSet in keys) { - node(SOURCE_SET_NODE_NAME) { - textNode(NAME_NODE_NAME, sourceSet) - sourceSetsDependsOnRelation[sourceSet].orEmpty().forEach { dependsOn -> - textNode(DEPENDS_ON_NODE_NAME, dependsOn) - } - sourceSetModuleDependencies[sourceSet].orEmpty().forEach { moduleDependency -> - textNode(MODULE_DEPENDENCY_NODE_NAME, moduleDependency.groupId + ":" + moduleDependency.moduleId) - } - sourceSetBinaryLayout[sourceSet]?.let { binaryLayout -> - textNode(BINARY_LAYOUT_NODE_NAME, binaryLayout.name) - } - if (sourceSet in hostSpecificSourceSets) { - textNode(HOST_SPECIFIC_NODE_NAME, "true") - } + multiNodes(SOURCE_SETS_NODE_NAME) { + val keys = sourceSetsDependsOnRelation.keys + sourceSetModuleDependencies.keys + for (sourceSet in keys) { + multiNodesItem(SOURCE_SET_NODE_NAME) { + value(NAME_NODE_NAME, sourceSet) + multiValue(DEPENDS_ON_NODE_NAME, sourceSetsDependsOnRelation[sourceSet].orEmpty().toList()) + multiValue(MODULE_DEPENDENCY_NODE_NAME, sourceSetModuleDependencies[sourceSet].orEmpty().map { moduleDependency -> + moduleDependency.groupId + ":" + moduleDependency.moduleId + }) + sourceSetBinaryLayout[sourceSet]?.let { binaryLayout -> + value(BINARY_LAYOUT_NODE_NAME, binaryLayout.name) + } + if (sourceSet in hostSpecificSourceSets) { + value(HOST_SPECIFIC_NODE_NAME, "true") } } } @@ -161,21 +167,76 @@ internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document { } } +internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document { + return DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument().apply { + val node: Node.(String, Node.() -> Unit) -> Unit = { name, content -> appendChild(createElement(name).apply(content)) } + val textNode: Node.(String, String) -> Unit = + { name, value -> appendChild(createElement(name).apply { appendChild(createTextNode(value)) }) } + serialize(this as Node, node, node, node, textNode, { name, values -> for (v in values) textNode(name, v) }) + } +} + +internal fun KotlinProjectStructureMetadata.toJson(): String { + val gson = GsonBuilder().setPrettyPrinting().create() + val stringWriter = StringWriter() + with(gson.newJsonWriter(stringWriter)) { + val obj: JsonWriter.(String, JsonWriter.() -> Unit) -> Unit = + { name, content -> if (name.isNotEmpty()) name(name); beginObject(); content(); endObject() } + val property: JsonWriter.(String, String) -> Unit = { name, value -> name(name); value(value) } + val array: JsonWriter.(String, JsonWriter.() -> Unit) -> Unit = + { name, contents -> name(name); beginArray(); contents(); endArray() } + + beginObject() + serialize(this, obj, array, { _, fn -> obj("", fn) }, property, { key, values -> array(key) { values.forEach { value(it) } } }) + endObject() + } + return stringWriter.toString() +} + private val NodeList.elements: Iterable get() = (0 until length).map { this@elements.item(it) }.filterIsInstance() +internal fun parseKotlinSourceSetMetadataFromJson(string: String): KotlinProjectStructureMetadata? { + @Suppress("DEPRECATION") // The replacement doesn't compile against old dependencies such as AS 4.0 + val json = JsonParser().parse(string).asJsonObject + val nodeNamed: JsonObject.(String) -> JsonObject? = { name -> get(name)?.asJsonObject } + val valueNamed: JsonObject.(String) -> String? = { name -> get(name)?.asString } + val multiObjects: JsonObject.(String?) -> Iterable = { name -> get(name).asJsonArray.map { it.asJsonObject } } + val multiValues: JsonObject.(String?) -> Iterable = { name -> get(name).asJsonArray.map { it.asString } } + + return parseKotlinSourceSetMetadata({ json.get(ROOT_NODE_NAME).asJsonObject }, valueNamed, multiObjects, multiValues) +} + internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? { - val projectStructureNode = document.getElementsByTagName(ROOT_NODE_NAME).elements.single() + val nodeNamed: Element.(String) -> Element? = { name -> getElementsByTagName(name).elements.singleOrNull() } + val valueNamed: Element.(String) -> String? = + { name -> getElementsByTagName(name).run { if (length > 0) item(0).textContent else null } } + val multiObjects: Element.(String) -> Iterable = { name -> nodeNamed(name)?.childNodes?.elements ?: emptyList()} + val multiValues: Element.(String) -> Iterable = { name -> getElementsByTagName(name).elements.map { it.textContent } } - val formatVersion = projectStructureNode.getElementsByTagName(FORMAT_VERSION_NODE_NAME).item(0).textContent + return parseKotlinSourceSetMetadata( + { document.getElementsByTagName(ROOT_NODE_NAME).elements.single() }, + valueNamed, + multiObjects, + multiValues + ) +} - val variantsNode = projectStructureNode.getElementsByTagName(VARIANTS_NODE_NAME).item(0) ?: return null +internal fun parseKotlinSourceSetMetadata( + getRoot: () -> ParsingContext, + valueNamed: ParsingContext.(key: String) -> String?, + multiObjects: ParsingContext.(named: String) -> Iterable, + multiValues: ParsingContext.(named: String) -> Iterable +): KotlinProjectStructureMetadata? { + val projectStructureNode = getRoot() + + val formatVersion = checkNotNull(projectStructureNode.valueNamed(FORMAT_VERSION_NODE_NAME)) + val variantsNode = projectStructureNode.multiObjects(VARIANTS_NODE_NAME) val sourceSetsByVariant = mutableMapOf>() - variantsNode.childNodes.elements.filter { it.tagName == VARIANT_NODE_NAME }.forEach { variantNode -> - val variantName = variantNode.getElementsByTagName(NAME_NODE_NAME).elements.single().textContent - val sourceSets = - variantNode.childNodes.elements.filter { it.tagName == SOURCE_SET_NODE_NAME }.mapTo(mutableSetOf()) { it.textContent } + variantsNode.forEach { variantNode -> + val variantName = requireNotNull(variantNode.valueNamed(NAME_NODE_NAME)) + val sourceSets = variantNode.multiValues(SOURCE_SET_NODE_NAME).toSet() sourceSetsByVariant[variantName] = sourceSets } @@ -185,34 +246,24 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj val sourceSetBinaryLayout = mutableMapOf() val hostSpecificSourceSets = mutableSetOf() - val sourceSetsNode = projectStructureNode.getElementsByTagName(SOURCE_SETS_NODE_NAME).item(0) ?: return null + val sourceSetsNode = projectStructureNode.multiObjects(SOURCE_SETS_NODE_NAME) - sourceSetsNode.childNodes.elements.filter { it.tagName == SOURCE_SET_NODE_NAME }.forEach { sourceSetNode -> - val sourceSetName = sourceSetNode.getElementsByTagName(NAME_NODE_NAME).elements.single().textContent + sourceSetsNode.forEach { sourceSetNode -> + val sourceSetName = checkNotNull(sourceSetNode.valueNamed(NAME_NODE_NAME)) - val dependsOn = mutableSetOf() - val moduleDependencies = mutableSetOf() - - sourceSetNode.childNodes.elements.forEach { node -> - when (node.tagName) { - DEPENDS_ON_NODE_NAME -> dependsOn.add(node.textContent) - MODULE_DEPENDENCY_NODE_NAME -> { - val (groupId, moduleId) = node.textContent.split(":") - moduleDependencies.add(ModuleDependencyIdentifier(groupId, moduleId)) - } - BINARY_LAYOUT_NODE_NAME -> { - SourceSetMetadataLayout.byName(node.textContent)?.let { binaryLayout -> - sourceSetBinaryLayout[sourceSetName] = binaryLayout - } - } - HOST_SPECIFIC_NODE_NAME -> { - if (node.textContent == "true") { - hostSpecificSourceSets.add(sourceSetName) - } - } - } + val dependsOn = sourceSetNode.multiValues(DEPENDS_ON_NODE_NAME).toSet() + val moduleDependencies = sourceSetNode.multiValues(MODULE_DEPENDENCY_NODE_NAME).mapTo(mutableSetOf()) { + val (groupId, moduleId) = it.split(":") + ModuleDependencyIdentifier(groupId, moduleId) } + sourceSetNode.valueNamed(HOST_SPECIFIC_NODE_NAME) + ?.let { if (it.toBoolean()) hostSpecificSourceSets.add(sourceSetName) } + + sourceSetNode.valueNamed(BINARY_LAYOUT_NODE_NAME) + ?.let { SourceSetMetadataLayout.byName(it) } + ?.let { sourceSetBinaryLayout[sourceSetName] = it } + sourceSetDependsOnRelation[sourceSetName] = dependsOn sourceSetModuleDependencies[sourceSetName] = moduleDependencies } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 693c133a6a3..0c14318879e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -197,7 +197,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : allMetadataJar.configure { it.from(generateMetadata.map { it.resultXmlFile }) { spec -> - spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_FILE_NAME } + spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME } } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt index a7c224b5349..0c02d9fc57a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internals/ExposedForIntegrationTests.kt @@ -9,14 +9,13 @@ import org.jetbrains.kotlin.gradle.plugin.KOTLIN_12X_MPP_DEPRECATION_WARNING import org.jetbrains.kotlin.gradle.targets.native.internal.NO_NATIVE_STDLIB_PROPERTY_WARNING import org.jetbrains.kotlin.gradle.targets.native.internal.NO_NATIVE_STDLIB_WARNING import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata -import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME -import org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromXml +import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME +import org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromJson import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter -import org.w3c.dom.Document -fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? = parseKotlinSourceSetMetadataFromXml(document) +fun parseKotlinSourceSetMetadataFromJson(json: String): KotlinProjectStructureMetadata? = parseKotlinSourceSetMetadataFromJson(json) -const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = MULTIPLATFORM_PROJECT_METADATA_FILE_NAME +const val MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME = MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME const val DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME = DisabledNativeTargetsReporter.DISABLE_WARNING_PROPERTY_NAME